1 |
cebix |
1.1 |
/* |
2 |
|
|
* Display_Be.h - C64 graphics display, emulator window handling, |
3 |
|
|
* Be specific stuff |
4 |
|
|
* |
5 |
cebix |
1.2 |
* Frodo (C) 1994-1997,2002-2003 Christian Bauer |
6 |
cebix |
1.1 |
* |
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 |
|
|
} |