1 |
/* |
2 |
* Display_Be.h - C64 graphics display, emulator window handling, |
3 |
* Be specific stuff |
4 |
* |
5 |
* Frodo (C) 1994-1997,2002 Christian Bauer |
6 |
* |
7 |
* This program is free software; you can redistribute it and/or modify |
8 |
* it under the terms of the GNU General Public License as published by |
9 |
* the Free Software Foundation; either version 2 of the License, or |
10 |
* (at your option) any later version. |
11 |
* |
12 |
* This program is distributed in the hope that it will be useful, |
13 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15 |
* GNU General Public License for more details. |
16 |
* |
17 |
* You should have received a copy of the GNU General Public License |
18 |
* along with this program; if not, write to the Free Software |
19 |
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
20 |
*/ |
21 |
|
22 |
#include <AppKit.h> |
23 |
#include <InterfaceKit.h> |
24 |
#include <GameKit.h> |
25 |
#include <string.h> |
26 |
|
27 |
#include "C64.h" |
28 |
#include "main.h" |
29 |
|
30 |
|
31 |
// Window thread messages |
32 |
const uint32 MSG_REDRAW = 1; |
33 |
|
34 |
|
35 |
// C64 display and window frame |
36 |
const BRect DisplayFrame = BRect(0, 0, DISPLAY_X-1, DISPLAY_Y-1); |
37 |
const BRect WindowFrame = BRect(0, 0, DISPLAY_X-1, DISPLAY_Y-1 + 16); |
38 |
|
39 |
|
40 |
// Background color |
41 |
const rgb_color fill_gray = {208, 208, 208, 0}; |
42 |
const rgb_color shine_gray = {232, 232, 232, 0}; |
43 |
const rgb_color shadow_gray = {152, 152, 152, 0}; |
44 |
|
45 |
|
46 |
/* |
47 |
C64 keyboard matrix: |
48 |
|
49 |
Bit 7 6 5 4 3 2 1 0 |
50 |
0 CUD F5 F3 F1 F7 CLR RET DEL |
51 |
1 SHL E S Z 4 A W 3 |
52 |
2 X T F C 6 D R 5 |
53 |
3 V U H B 8 G Y 7 |
54 |
4 N O K M 0 J I 9 |
55 |
5 , @ : . - L P + |
56 |
6 / ^ = SHR HOM ; * £ |
57 |
7 R/S Q C= SPC 2 CTL <- 1 |
58 |
*/ |
59 |
|
60 |
|
61 |
/* |
62 |
Tables for key translation |
63 |
Bit 0..2: row/column in C64 keyboard matrix |
64 |
Bit 3 : implicit shift |
65 |
Bit 5 : joystick emulation (bit 0..4: mask) |
66 |
*/ |
67 |
|
68 |
const int key_byte[128] = { |
69 |
-1, 7, 0,8+0, 0,8+0, 0, 8+0, |
70 |
0, 8+0, -1, -1, -1, -1, -1, -1, |
71 |
|
72 |
7, 7, 7, 7, 1, 1, 2, 2, |
73 |
3, 3, 4, 4, 5, 5, 0, 8+0, |
74 |
|
75 |
6, 6, -1, -1, -1, -1, -1, 7, |
76 |
1, 1, 2, 2, 3, 3, 4, 4, |
77 |
|
78 |
5, 5, 6, 6, 0, 6, 6,0x25, |
79 |
0x21,0x29, -1, 1, 1, 1, 2, 2, |
80 |
|
81 |
3, 3, 4, 4, 5, 5, 6, 0, |
82 |
0x24,0x30,0x28, 1, 1, 2, 2, 3, |
83 |
|
84 |
3, 4, 4, 5, 5, 6, 6, 8+0, |
85 |
0x26,0x22,0x2a, 0, 7, -1, 7, -1, |
86 |
|
87 |
7, 8+0, 0, 0,0x30, -1, 7, 7, |
88 |
-1, -1, -1, -1, -1, -1, -1, -1, |
89 |
|
90 |
-1, -1, -1, -1, -1, -1, -1, -1, |
91 |
-1, -1, -1, -1, -1, -1, -1, -1 |
92 |
}; |
93 |
|
94 |
const int key_bit[128] = { |
95 |
-1, 7, 4, 4, 5, 5, 6, 6, |
96 |
3, 3, -1, -1, -1, -1, -1, -1, |
97 |
|
98 |
7, 1, 0, 3, 0, 3, 0, 3, |
99 |
0, 3, 0, 3, 0, 3, 0, 0, |
100 |
|
101 |
3, 0, -1, -1, -1, -1, -1, 6, |
102 |
1, 6, 1, 6, 1, 6, 1, 6, |
103 |
|
104 |
1, 6, 1, 6, 0, 0, 5, -1, |
105 |
-1, -1, -1, 7, 2, 5, 2, 5, |
106 |
|
107 |
2, 5, 2, 5, 2, 5, 2, 1, |
108 |
-1, -1, -1, 7, 4, 7, 4, 7, |
109 |
|
110 |
4, 7, 4, 7, 4, 7, 4, 7, |
111 |
-1, -1, -1, 1, 2, -1, 4, -1, |
112 |
|
113 |
5, 2, 7, 2, -1, -1, 5, 5, |
114 |
-1, -1, -1, -1, -1, -1, -1, -1, |
115 |
|
116 |
-1, -1, -1, -1, -1, -1, -1, -1, |
117 |
-1, -1, -1, -1, -1, -1, -1, -1 |
118 |
}; |
119 |
|
120 |
|
121 |
/* |
122 |
* A simple view class for blitting a bitmap on the screen |
123 |
*/ |
124 |
|
125 |
class BitmapView : public BView { |
126 |
public: |
127 |
BitmapView(BRect frame, BBitmap *bitmap); |
128 |
virtual void Draw(BRect update); |
129 |
virtual void KeyDown(const char *bytes, int32 numBytes); |
130 |
void ChangeBitmap(BBitmap *bitmap); |
131 |
|
132 |
private: |
133 |
BBitmap *the_bitmap; |
134 |
}; |
135 |
|
136 |
|
137 |
/* |
138 |
* Class for the main C64 display window |
139 |
*/ |
140 |
|
141 |
class SpeedoView; |
142 |
class LEDView; |
143 |
|
144 |
class C64Window : public BWindow { |
145 |
public: |
146 |
C64Window(); |
147 |
|
148 |
virtual bool QuitRequested(void); |
149 |
virtual void MessageReceived(BMessage *msg); |
150 |
|
151 |
BBitmap *TheBitmap[2]; |
152 |
SpeedoView *Speedometer; |
153 |
LEDView *LED[4]; |
154 |
|
155 |
private: |
156 |
BitmapView *main_view; |
157 |
}; |
158 |
|
159 |
|
160 |
/* |
161 |
* Class for the main C64 display using the GameKit |
162 |
*/ |
163 |
|
164 |
class C64Screen : public BWindowScreen { |
165 |
public: |
166 |
C64Screen(C64Display *display) : BWindowScreen("Frodo", B_8_BIT_640x480, &error), the_display(display) |
167 |
{ |
168 |
Lock(); |
169 |
BitmapView *main_view = new BitmapView(Bounds(), NULL); |
170 |
AddChild(main_view); |
171 |
main_view->MakeFocus(); |
172 |
Connected = false; |
173 |
Unlock(); |
174 |
} |
175 |
|
176 |
virtual void ScreenConnected(bool active); |
177 |
virtual void DispatchMessage(BMessage *msg, BHandler *handler); |
178 |
void DrawLED(int i, int state); |
179 |
void DrawSpeedometer(void); |
180 |
void FillRect(int x1, int y1, int x2, int y2, int color); |
181 |
|
182 |
bool Connected; // Flag: screen connected |
183 |
int Speed; |
184 |
char SpeedoStr[16]; // Speedometer value converted to a string |
185 |
|
186 |
private: |
187 |
C64Display *the_display; |
188 |
status_t error; |
189 |
}; |
190 |
|
191 |
|
192 |
/* |
193 |
* Class for speedometer |
194 |
*/ |
195 |
|
196 |
class SpeedoView : public BView { |
197 |
public: |
198 |
SpeedoView(BRect frame); |
199 |
virtual void Draw(BRect update); |
200 |
virtual void Pulse(void); |
201 |
void SetValue(int percent); |
202 |
|
203 |
private: |
204 |
char speedostr[16]; // Speedometer value converted to a string |
205 |
BRect bounds; |
206 |
}; |
207 |
|
208 |
|
209 |
/* |
210 |
* Class for drive LED |
211 |
*/ |
212 |
|
213 |
class LEDView : public BView { |
214 |
public: |
215 |
LEDView(BRect frame, const char *label); |
216 |
virtual void Draw(BRect update); |
217 |
virtual void Pulse(void); |
218 |
void DrawLED(void); |
219 |
void SetState(int state); |
220 |
|
221 |
private: |
222 |
int current_state; |
223 |
const char *the_label; |
224 |
BRect bounds; |
225 |
}; |
226 |
|
227 |
|
228 |
/* |
229 |
* Display constructor: Create window/screen |
230 |
*/ |
231 |
|
232 |
C64Display::C64Display(C64 *the_c64) : TheC64(the_c64) |
233 |
{ |
234 |
// LEDs off |
235 |
for (int i=0; i<4; i++) |
236 |
led_state[i] = old_led_state[i] = LED_OFF; |
237 |
|
238 |
// Open window/screen |
239 |
draw_bitmap = 1; |
240 |
if (ThePrefs.DisplayType == DISPTYPE_SCREEN) { |
241 |
using_screen = true; |
242 |
the_screen = new C64Screen(this); |
243 |
the_screen->Show(); |
244 |
while (!the_screen->Connected) |
245 |
snooze(20000); |
246 |
} else { |
247 |
using_screen = false; |
248 |
the_window = new C64Window(); |
249 |
the_window->Show(); |
250 |
} |
251 |
|
252 |
// Prepare key_info buffer |
253 |
get_key_info(&old_key_info); |
254 |
} |
255 |
|
256 |
|
257 |
/* |
258 |
* Display destructor |
259 |
*/ |
260 |
|
261 |
C64Display::~C64Display() |
262 |
{ |
263 |
if (using_screen) { |
264 |
the_screen->Lock(); |
265 |
the_screen->Quit(); |
266 |
} else { |
267 |
the_window->Lock(); |
268 |
the_window->Quit(); |
269 |
} |
270 |
} |
271 |
|
272 |
|
273 |
/* |
274 |
* Prefs may have changed |
275 |
*/ |
276 |
|
277 |
void C64Display::NewPrefs(Prefs *prefs) |
278 |
{ |
279 |
if (prefs->DisplayType == DISPTYPE_SCREEN) { |
280 |
if (!using_screen) { |
281 |
// Switch to full screen display |
282 |
using_screen = true; |
283 |
the_window->Lock(); |
284 |
the_window->Quit(); |
285 |
the_screen = new C64Screen(this); |
286 |
the_screen->Show(); |
287 |
while (!the_screen->Connected) |
288 |
snooze(20000); |
289 |
} |
290 |
} else { |
291 |
if (using_screen) { |
292 |
// Switch to window display |
293 |
using_screen = false; |
294 |
the_screen->Lock(); |
295 |
the_screen->Quit(); |
296 |
the_window = new C64Window(); |
297 |
the_window->Show(); |
298 |
} |
299 |
} |
300 |
} |
301 |
|
302 |
|
303 |
/* |
304 |
* Redraw bitmap (let the window thread do it) |
305 |
*/ |
306 |
|
307 |
void C64Display::Update(void) |
308 |
{ |
309 |
if (using_screen) { |
310 |
|
311 |
// Update LEDs/speedometer |
312 |
for (int i=0; i<4; i++) |
313 |
the_screen->DrawLED(i, led_state[i]); |
314 |
the_screen->DrawSpeedometer(); |
315 |
|
316 |
} else { |
317 |
|
318 |
// Update C64 display |
319 |
BMessage msg(MSG_REDRAW); |
320 |
msg.AddInt32("bitmap", draw_bitmap); |
321 |
the_window->PostMessage(&msg); |
322 |
draw_bitmap ^= 1; |
323 |
|
324 |
// Update LEDs |
325 |
for (int i=0; i<4; i++) |
326 |
if (led_state[i] != old_led_state[i]) { |
327 |
the_window->LED[i]->SetState(led_state[i]); |
328 |
old_led_state[i] = led_state[i]; |
329 |
} |
330 |
} |
331 |
} |
332 |
|
333 |
|
334 |
/* |
335 |
* Set value displayed by the speedometer |
336 |
*/ |
337 |
|
338 |
void C64Display::Speedometer(int speed) |
339 |
{ |
340 |
if (using_screen) { |
341 |
the_screen->Speed = speed; |
342 |
sprintf(the_screen->SpeedoStr, "%3d%%", speed); |
343 |
} else |
344 |
the_window->Speedometer->SetValue(speed); |
345 |
} |
346 |
|
347 |
|
348 |
/* |
349 |
* Return pointer to bitmap data |
350 |
*/ |
351 |
|
352 |
uint8 *C64Display::BitmapBase(void) |
353 |
{ |
354 |
if (using_screen) |
355 |
return (uint8 *)the_screen->CardInfo()->frame_buffer; |
356 |
else |
357 |
return (uint8 *)the_window->TheBitmap[draw_bitmap]->Bits(); |
358 |
} |
359 |
|
360 |
|
361 |
/* |
362 |
* Return number of bytes per row |
363 |
*/ |
364 |
|
365 |
int C64Display::BitmapXMod(void) |
366 |
{ |
367 |
if (using_screen) |
368 |
return the_screen->CardInfo()->bytes_per_row; |
369 |
else |
370 |
return the_window->TheBitmap[draw_bitmap]->BytesPerRow(); |
371 |
} |
372 |
|
373 |
|
374 |
/* |
375 |
* Poll the keyboard |
376 |
*/ |
377 |
|
378 |
void C64Display::PollKeyboard(uint8 *key_matrix, uint8 *rev_matrix, uint8 *joystick) |
379 |
{ |
380 |
key_info the_key_info; |
381 |
int be_code, be_byte, be_bit, c64_byte, c64_bit; |
382 |
bool shifted; |
383 |
|
384 |
// Window must be active, command key must be up |
385 |
if (using_screen) { |
386 |
if (!the_screen->Connected) |
387 |
return; |
388 |
} else |
389 |
if (!the_window->IsActive()) |
390 |
return; |
391 |
if (!(modifiers() & B_COMMAND_KEY)) { |
392 |
|
393 |
// Read the state of all keys |
394 |
get_key_info(&the_key_info); |
395 |
|
396 |
// Did anything change at all? |
397 |
if (!memcmp(&old_key_info, &the_key_info, sizeof(key_info))) |
398 |
return; |
399 |
|
400 |
// Loop to convert BeOS keymap to C64 keymap |
401 |
for (be_code=0; be_code<0x68; be_code++) { |
402 |
be_byte = be_code >> 3; |
403 |
be_bit = 1 << (~be_code & 7); |
404 |
|
405 |
// Key state changed? |
406 |
if ((the_key_info.key_states[be_byte] & be_bit) |
407 |
!= (old_key_info.key_states[be_byte] & be_bit)) { |
408 |
|
409 |
c64_byte = key_byte[be_code]; |
410 |
c64_bit = key_bit[be_code]; |
411 |
if (c64_byte != -1) { |
412 |
if (!(c64_byte & 0x20)) { |
413 |
|
414 |
// Normal keys |
415 |
shifted = c64_byte & 8; |
416 |
c64_byte &= 7; |
417 |
if (the_key_info.key_states[be_byte] & be_bit) { |
418 |
|
419 |
// Key pressed |
420 |
if (shifted) { |
421 |
key_matrix[6] &= 0xef; |
422 |
rev_matrix[4] &= 0xbf; |
423 |
} |
424 |
key_matrix[c64_byte] &= ~(1 << c64_bit); |
425 |
rev_matrix[c64_bit] &= ~(1 << c64_byte); |
426 |
} else { |
427 |
|
428 |
// Key released |
429 |
if (shifted) { |
430 |
key_matrix[6] |= 0x10; |
431 |
rev_matrix[4] |= 0x40; |
432 |
} |
433 |
key_matrix[c64_byte] |= (1 << c64_bit); |
434 |
rev_matrix[c64_bit] |= (1 << c64_byte); |
435 |
} |
436 |
} else { |
437 |
|
438 |
// Joystick emulation |
439 |
c64_byte &= 0x1f; |
440 |
if (the_key_info.key_states[be_byte] & be_bit) |
441 |
*joystick &= ~c64_byte; |
442 |
else |
443 |
*joystick |= c64_byte; |
444 |
} |
445 |
} |
446 |
} |
447 |
} |
448 |
|
449 |
old_key_info = the_key_info; |
450 |
} |
451 |
} |
452 |
|
453 |
|
454 |
/* |
455 |
* Check if NumLock is down (for switching the joystick keyboard emulation) |
456 |
*/ |
457 |
|
458 |
bool C64Display::NumLock(void) |
459 |
{ |
460 |
return modifiers() & B_NUM_LOCK; |
461 |
} |
462 |
|
463 |
|
464 |
/* |
465 |
* Allocate C64 colors |
466 |
*/ |
467 |
|
468 |
void C64Display::InitColors(uint8 *colors) |
469 |
{ |
470 |
BScreen scr(using_screen ? (BWindow *)the_screen : the_window); |
471 |
for (int i=0; i<256; i++) |
472 |
colors[i] = scr.IndexForColor(palette_red[i & 0x0f], palette_green[i & 0x0f], palette_blue[i & 0x0f]); |
473 |
} |
474 |
|
475 |
|
476 |
/* |
477 |
* Pause display (GameKit only) |
478 |
*/ |
479 |
|
480 |
void C64Display::Pause(void) |
481 |
{ |
482 |
if (using_screen) |
483 |
the_screen->Hide(); |
484 |
} |
485 |
|
486 |
|
487 |
/* |
488 |
* Resume display (GameKit only) |
489 |
*/ |
490 |
|
491 |
void C64Display::Resume(void) |
492 |
{ |
493 |
if (using_screen) |
494 |
the_screen->Show(); |
495 |
} |
496 |
|
497 |
|
498 |
/* |
499 |
* Window constructor |
500 |
*/ |
501 |
|
502 |
C64Window::C64Window() : BWindow(WindowFrame, "Frodo", B_TITLED_WINDOW, B_NOT_RESIZABLE | B_NOT_ZOOMABLE) |
503 |
{ |
504 |
// Move window to right position |
505 |
Lock(); |
506 |
MoveTo(80, 60); |
507 |
|
508 |
// Set up menus |
509 |
BMenuBar *bar = new BMenuBar(Bounds(), ""); |
510 |
BMenu *menu = new BMenu("Frodo"); |
511 |
menu->AddItem(new BMenuItem("About Frodo" B_UTF8_ELLIPSIS, new BMessage(B_ABOUT_REQUESTED))); |
512 |
menu->AddItem(new BSeparatorItem); |
513 |
menu->AddItem(new BMenuItem("Preferences" B_UTF8_ELLIPSIS, new BMessage(MSG_PREFS), 'P')); |
514 |
menu->AddItem(new BSeparatorItem); |
515 |
menu->AddItem(new BMenuItem("Reset C64", new BMessage(MSG_RESET))); |
516 |
menu->AddItem(new BMenuItem("Insert next disk", new BMessage(MSG_NEXTDISK), 'D')); |
517 |
menu->AddItem(new BMenuItem("SAM" B_UTF8_ELLIPSIS, new BMessage(MSG_SAM), 'M')); |
518 |
menu->AddItem(new BSeparatorItem); |
519 |
menu->AddItem(new BMenuItem("Load snapshot" B_UTF8_ELLIPSIS, new BMessage(MSG_OPEN_SNAPSHOT), 'O')); |
520 |
menu->AddItem(new BMenuItem("Save snapshot" B_UTF8_ELLIPSIS, new BMessage(MSG_SAVE_SNAPSHOT), 'S')); |
521 |
menu->AddItem(new BSeparatorItem); |
522 |
menu->AddItem(new BMenuItem("Quit Frodo", new BMessage(B_QUIT_REQUESTED), 'Q')); |
523 |
menu->SetTargetForItems(be_app); |
524 |
bar->AddItem(menu); |
525 |
AddChild(bar); |
526 |
SetKeyMenuBar(bar); |
527 |
int mbar_height = bar->Frame().bottom + 1; |
528 |
|
529 |
// Resize window to fit menu bar |
530 |
ResizeBy(0, mbar_height); |
531 |
|
532 |
// Allocate bitmaps |
533 |
TheBitmap[0] = new BBitmap(DisplayFrame, B_COLOR_8_BIT); |
534 |
TheBitmap[1] = new BBitmap(DisplayFrame, B_COLOR_8_BIT); |
535 |
|
536 |
// Create top view |
537 |
BRect b = Bounds(); |
538 |
BView *top = new BView(BRect(0, mbar_height, b.right, b.bottom), "top", B_FOLLOW_NONE, 0); |
539 |
AddChild(top); |
540 |
|
541 |
// Create bitmap view |
542 |
main_view = new BitmapView(DisplayFrame, TheBitmap[0]); |
543 |
top->AddChild(main_view); |
544 |
main_view->MakeFocus(); |
545 |
|
546 |
// Create speedometer |
547 |
Speedometer = new SpeedoView(BRect(0, DISPLAY_Y, DISPLAY_X/5-1, DISPLAY_Y+15)); |
548 |
top->AddChild(Speedometer); |
549 |
|
550 |
// Create drive LEDs |
551 |
LED[0] = new LEDView(BRect(DISPLAY_X/5, DISPLAY_Y, DISPLAY_X*2/5-1, DISPLAY_Y+15), "Drive 8"); |
552 |
top->AddChild(LED[0]); |
553 |
LED[1] = new LEDView(BRect(DISPLAY_X*2/5, DISPLAY_Y, DISPLAY_X*3/5-1, DISPLAY_Y+15), "Drive 9"); |
554 |
top->AddChild(LED[1]); |
555 |
LED[2] = new LEDView(BRect(DISPLAY_X*3/5, DISPLAY_Y, DISPLAY_X*4/5-1, DISPLAY_Y+15), "Drive 10"); |
556 |
top->AddChild(LED[2]); |
557 |
LED[3] = new LEDView(BRect(DISPLAY_X*4/5, DISPLAY_Y, DISPLAY_X-1, DISPLAY_Y+15), "Drive 11"); |
558 |
top->AddChild(LED[3]); |
559 |
|
560 |
// Set pulse rate to 0.4 seconds for blinking drive LEDs |
561 |
SetPulseRate(400000); |
562 |
Unlock(); |
563 |
} |
564 |
|
565 |
|
566 |
/* |
567 |
* Closing the window quits Frodo |
568 |
*/ |
569 |
|
570 |
bool C64Window::QuitRequested(void) |
571 |
{ |
572 |
be_app->PostMessage(B_QUIT_REQUESTED); |
573 |
return false; |
574 |
} |
575 |
|
576 |
|
577 |
/* |
578 |
* Handles redraw messages |
579 |
*/ |
580 |
|
581 |
void C64Window::MessageReceived(BMessage *msg) |
582 |
{ |
583 |
BMessage *msg2; |
584 |
|
585 |
switch (msg->what) { |
586 |
case MSG_REDRAW: // Redraw bitmap |
587 |
MessageQueue()->Lock(); |
588 |
while ((msg2 = MessageQueue()->FindMessage(MSG_REDRAW, 0)) != NULL) |
589 |
MessageQueue()->RemoveMessage(msg2); |
590 |
MessageQueue()->Unlock(); |
591 |
main_view->ChangeBitmap(TheBitmap[msg->FindInt32("bitmap")]); |
592 |
Lock(); |
593 |
main_view->Draw(DisplayFrame); |
594 |
Unlock(); |
595 |
break; |
596 |
|
597 |
default: |
598 |
BWindow::MessageReceived(msg); |
599 |
} |
600 |
} |
601 |
|
602 |
|
603 |
/* |
604 |
* Workspace activated/deactivated |
605 |
*/ |
606 |
|
607 |
void C64Screen::ScreenConnected(bool active) |
608 |
{ |
609 |
if (active) { |
610 |
FillRect(0, 0, 639, 479, 0); // Clear screen |
611 |
the_display->TheC64->Resume(); |
612 |
Connected = true; |
613 |
} else { |
614 |
the_display->TheC64->Pause(); |
615 |
Connected = false; |
616 |
} |
617 |
BWindowScreen::ScreenConnected(active); |
618 |
} |
619 |
|
620 |
|
621 |
/* |
622 |
* Simulate menu commands |
623 |
*/ |
624 |
|
625 |
void C64Screen::DispatchMessage(BMessage *msg, BHandler *handler) |
626 |
{ |
627 |
switch (msg->what) { |
628 |
case B_KEY_DOWN: { |
629 |
uint32 mods = msg->FindInt32("modifiers"); |
630 |
if (mods & B_COMMAND_KEY) { |
631 |
uint32 key = msg->FindInt32("raw_char"); |
632 |
switch (key) { |
633 |
case 'p': |
634 |
be_app->PostMessage(MSG_PREFS); |
635 |
break; |
636 |
case 'd': |
637 |
be_app->PostMessage(MSG_NEXTDISK); |
638 |
break; |
639 |
case 'm': |
640 |
be_app->PostMessage(MSG_SAM); |
641 |
break; |
642 |
} |
643 |
} |
644 |
BWindowScreen::DispatchMessage(msg, handler); |
645 |
break; |
646 |
} |
647 |
|
648 |
default: |
649 |
BWindowScreen::DispatchMessage(msg, handler); |
650 |
} |
651 |
} |
652 |
|
653 |
|
654 |
/* |
655 |
* Draw drive LEDs |
656 |
*/ |
657 |
|
658 |
void C64Screen::DrawLED(int i, int state) |
659 |
{ |
660 |
switch (state) { |
661 |
case LED_ON: |
662 |
FillRect(10+i*20, DISPLAY_Y-20, 20+i*20, DISPLAY_Y-12, 54); |
663 |
break; |
664 |
case LED_ERROR_ON: |
665 |
FillRect(10+i*20, DISPLAY_Y-20, 20+i*20, DISPLAY_Y-12, 44); |
666 |
break; |
667 |
} |
668 |
} |
669 |
|
670 |
|
671 |
/* |
672 |
* Draw speedometer |
673 |
*/ |
674 |
|
675 |
static const int8 Digits[11][8] = { // Digit images |
676 |
{0x3c, 0x66, 0x6e, 0x76, 0x66, 0x66, 0x3c, 0x00}, |
677 |
{0x18, 0x18, 0x38, 0x18, 0x18, 0x18, 0x7e, 0x00}, |
678 |
{0x3c, 0x66, 0x06, 0x0c, 0x30, 0x60, 0x7e, 0x00}, |
679 |
{0x3c, 0x66, 0x06, 0x1c, 0x06, 0x66, 0x3c, 0x00}, |
680 |
{0x06, 0x0e, 0x1e, 0x66, 0x7f, 0x06, 0x06, 0x00}, |
681 |
{0x7e, 0x60, 0x7c, 0x06, 0x06, 0x66, 0x3c, 0x00}, |
682 |
{0x3c, 0x66, 0x60, 0x7c, 0x66, 0x66, 0x3c, 0x00}, |
683 |
{0x7e, 0x66, 0x0c, 0x18, 0x18, 0x18, 0x18, 0x00}, |
684 |
{0x3c, 0x66, 0x66, 0x3c, 0x66, 0x66, 0x3c, 0x00}, |
685 |
{0x3c, 0x66, 0x66, 0x3e, 0x06, 0x66, 0x3c, 0x00}, |
686 |
{0x62, 0x66, 0x0c, 0x18, 0x30, 0x66, 0x46, 0x00}, |
687 |
}; |
688 |
|
689 |
void C64Screen::DrawSpeedometer() |
690 |
{ |
691 |
// Don't display speedometer if we're running at about 100% |
692 |
if (Speed >= 99 && Speed <= 101) |
693 |
return; |
694 |
|
695 |
char *s = SpeedoStr; |
696 |
char c; |
697 |
long xmod = CardInfo()->bytes_per_row; |
698 |
uint8 *p = (uint8 *)CardInfo()->frame_buffer + DISPLAY_X - 8*8 + (DISPLAY_Y-20) * xmod; |
699 |
while (c = *s++) { |
700 |
if (c == ' ') |
701 |
continue; |
702 |
if (c == '%') |
703 |
c = 10; |
704 |
else |
705 |
c -= '0'; |
706 |
uint8 *q = p; |
707 |
for (int y=0; y<8; y++) { |
708 |
uint8 data = Digits[c][y]; |
709 |
for (int x=0; x<8; x++) { |
710 |
if (data & (1 << (7-x))) |
711 |
q[x] = 255; |
712 |
else |
713 |
q[x] = 0; |
714 |
} |
715 |
q += xmod; |
716 |
} |
717 |
p += 8; |
718 |
} |
719 |
} |
720 |
|
721 |
|
722 |
/* |
723 |
* Fill rectangle |
724 |
*/ |
725 |
|
726 |
void C64Screen::FillRect(int x1, int y1, int x2, int y2, int color) |
727 |
{ |
728 |
long xmod = CardInfo()->bytes_per_row; |
729 |
uint8 *p = (uint8 *)CardInfo()->frame_buffer + y1 * xmod + x1; |
730 |
int n = x2 - x1 + 1; |
731 |
for(int y=y1; y<=y2; y++) { |
732 |
memset_nc(p, color, n); |
733 |
p += xmod; |
734 |
} |
735 |
} |
736 |
|
737 |
|
738 |
/* |
739 |
* Bitmap view constructor |
740 |
*/ |
741 |
|
742 |
BitmapView::BitmapView(BRect frame, BBitmap *bitmap) : BView(frame, "", B_FOLLOW_NONE, B_WILL_DRAW) |
743 |
{ |
744 |
ChangeBitmap(bitmap); |
745 |
} |
746 |
|
747 |
|
748 |
/* |
749 |
* Blit the bitmap |
750 |
*/ |
751 |
|
752 |
void BitmapView::Draw(BRect update) |
753 |
{ |
754 |
if (the_bitmap != NULL) |
755 |
DrawBitmapAsync(the_bitmap, update, update); |
756 |
} |
757 |
|
758 |
|
759 |
/* |
760 |
* Receive special key-down events (main C64 keyboard handling is done in PollKeyboard) |
761 |
*/ |
762 |
|
763 |
void BitmapView::KeyDown(const char *bytes, int32 numBytes) |
764 |
{ |
765 |
if (bytes[0] == B_FUNCTION_KEY || bytes[0] == '+' || bytes[0] == '-' || bytes[0] == '*' || bytes[0] == '/') { |
766 |
BMessage *msg = Window()->CurrentMessage(); |
767 |
long key; |
768 |
if (msg->FindInt32("key", &key) == B_NO_ERROR) { |
769 |
switch (key) { |
770 |
|
771 |
case B_F11_KEY: // F11: NMI (Restore) |
772 |
be_app->PostMessage(MSG_NMI); |
773 |
break; |
774 |
|
775 |
case B_F12_KEY: // F12: Reset |
776 |
be_app->PostMessage(MSG_RESET); |
777 |
break; |
778 |
|
779 |
case 0x3a: // '+' on keypad: Increase SkipFrames |
780 |
ThePrefs.SkipFrames++; |
781 |
break; |
782 |
|
783 |
case 0x25: // '-' on keypad: Decrease SkipFrames |
784 |
if (ThePrefs.SkipFrames > 1) |
785 |
ThePrefs.SkipFrames--; |
786 |
break; |
787 |
|
788 |
case 0x24: // '*' on keypad: Toggle speed limiter |
789 |
ThePrefs.LimitSpeed = !ThePrefs.LimitSpeed; |
790 |
break; |
791 |
|
792 |
case 0x23: // '/' on keypad: Toggle processor-level 1541 emulation |
793 |
be_app->PostMessage(MSG_TOGGLE_1541); |
794 |
break; |
795 |
} |
796 |
} |
797 |
} |
798 |
} |
799 |
|
800 |
|
801 |
/* |
802 |
* Change view bitmap |
803 |
*/ |
804 |
|
805 |
void BitmapView::ChangeBitmap(BBitmap *bitmap) |
806 |
{ |
807 |
the_bitmap = bitmap; |
808 |
} |
809 |
|
810 |
|
811 |
/* |
812 |
* Speedometer constructor |
813 |
*/ |
814 |
|
815 |
SpeedoView::SpeedoView(BRect frame) : BView(frame, "", B_FOLLOW_NONE, B_WILL_DRAW | B_PULSE_NEEDED) |
816 |
{ |
817 |
speedostr[0] = 0; |
818 |
bounds = Bounds(); |
819 |
SetViewColor(fill_gray); |
820 |
SetFont(be_plain_font); |
821 |
} |
822 |
|
823 |
|
824 |
/* |
825 |
* Draw speedometer |
826 |
*/ |
827 |
|
828 |
void SpeedoView::Draw(BRect update) |
829 |
{ |
830 |
// Draw bevelled border |
831 |
SetHighColor(shine_gray); |
832 |
StrokeLine(BPoint(0, bounds.bottom), BPoint(0, 0)); |
833 |
StrokeLine(BPoint(bounds.right, 0)); |
834 |
SetHighColor(shadow_gray); |
835 |
StrokeLine(BPoint(bounds.right, bounds.bottom), BPoint(bounds.right, 1)); |
836 |
|
837 |
// Draw text |
838 |
SetHighColor(0, 0, 0); |
839 |
DrawString(speedostr, BPoint(24, 12)); |
840 |
} |
841 |
|
842 |
|
843 |
/* |
844 |
* Update speedometer at regular intervals |
845 |
*/ |
846 |
|
847 |
void SpeedoView::Pulse(void) |
848 |
{ |
849 |
Invalidate(BRect(1, 1, bounds.right-1, 15)); |
850 |
} |
851 |
|
852 |
|
853 |
/* |
854 |
* Set new speedometer value |
855 |
*/ |
856 |
|
857 |
void SpeedoView::SetValue(int speed) |
858 |
{ |
859 |
sprintf(speedostr, "%d%%", speed); |
860 |
} |
861 |
|
862 |
|
863 |
/* |
864 |
* LED view constructor |
865 |
*/ |
866 |
|
867 |
LEDView::LEDView(BRect frame, const char *label) : BView(frame, "", B_FOLLOW_NONE, B_WILL_DRAW | B_PULSE_NEEDED) |
868 |
{ |
869 |
current_state = 0; |
870 |
the_label = label; |
871 |
bounds = Bounds(); |
872 |
SetViewColor(fill_gray); |
873 |
SetFont(be_plain_font); |
874 |
} |
875 |
|
876 |
|
877 |
/* |
878 |
* Draw drive LED |
879 |
*/ |
880 |
|
881 |
void LEDView::Draw(BRect update) |
882 |
{ |
883 |
// Draw bevelled border |
884 |
SetHighColor(shine_gray); |
885 |
StrokeLine(BPoint(0, bounds.bottom), BPoint(0, 0)); |
886 |
StrokeLine(BPoint(bounds.right, 0)); |
887 |
SetHighColor(shadow_gray); |
888 |
StrokeLine(BPoint(bounds.right, bounds.bottom), BPoint(bounds.right, 1)); |
889 |
|
890 |
// Draw label |
891 |
SetHighColor(0, 0, 0); |
892 |
SetLowColor(fill_gray); |
893 |
DrawString(the_label, BPoint(8, 12)); |
894 |
|
895 |
// Draw LED |
896 |
SetHighColor(shadow_gray); |
897 |
StrokeLine(BPoint(bounds.right-24, 12), BPoint(bounds.right-24, 4)); |
898 |
StrokeLine(BPoint(bounds.right-8, 4)); |
899 |
SetHighColor(shine_gray); |
900 |
StrokeLine(BPoint(bounds.right-23, 12), BPoint(bounds.right-8, 12)); |
901 |
StrokeLine(BPoint(bounds.right-8, 5)); |
902 |
DrawLED(); |
903 |
} |
904 |
|
905 |
|
906 |
/* |
907 |
* Redraw just the LED |
908 |
*/ |
909 |
|
910 |
void LEDView::DrawLED(void) |
911 |
{ |
912 |
Window()->Lock(); |
913 |
switch (current_state) { |
914 |
case LED_OFF: |
915 |
case LED_ERROR_OFF: |
916 |
SetHighColor(32, 32, 32); |
917 |
break; |
918 |
case LED_ON: |
919 |
SetHighColor(0, 240, 0); |
920 |
break; |
921 |
case LED_ERROR_ON: |
922 |
SetHighColor(240, 0, 0); |
923 |
break; |
924 |
} |
925 |
FillRect(BRect(bounds.right-23, 5, bounds.right-9, 11)); |
926 |
Window()->Unlock(); |
927 |
} |
928 |
|
929 |
|
930 |
/* |
931 |
* Set LED state |
932 |
*/ |
933 |
|
934 |
void LEDView::SetState(int state) |
935 |
{ |
936 |
if (state != current_state) { |
937 |
current_state = state; |
938 |
DrawLED(); |
939 |
} |
940 |
} |
941 |
|
942 |
|
943 |
/* |
944 |
* Toggle red error LED |
945 |
*/ |
946 |
|
947 |
void LEDView::Pulse(void) |
948 |
{ |
949 |
switch (current_state) { |
950 |
case LED_ERROR_ON: |
951 |
current_state = LED_ERROR_OFF; |
952 |
DrawLED(); |
953 |
break; |
954 |
case LED_ERROR_OFF: |
955 |
current_state = LED_ERROR_ON; |
956 |
DrawLED(); |
957 |
break; |
958 |
} |
959 |
} |
960 |
|
961 |
|
962 |
/* |
963 |
* Show a requester |
964 |
*/ |
965 |
|
966 |
long ShowRequester(char *str, char *button1, char *button2) |
967 |
{ |
968 |
BAlert *the_alert; |
969 |
|
970 |
the_alert = new BAlert("", str, button1, button2, NULL, B_WIDTH_AS_USUAL, B_STOP_ALERT); |
971 |
return the_alert->Go(); |
972 |
} |