ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/Frodo4/Src/Display_Be.h
Revision: 1.1
Committed: 2003-07-01T17:32:13Z (20 years, 9 months ago) by cebix
Content type: text/plain
Branch: MAIN
Log Message:
imported files

File Contents

# User Rev Content
1 cebix 1.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     }