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