First Commit of my working state
[simh.git] / Ibm1130 / ibm1130_gui.c
1 /* ibm1130_gui.c: IBM 1130 CPU simulator Console Display
2 *
3 * Based on the SIMH package written by Robert M Supnik
4 *
5 * (C) Copyright 2002, Brian Knittel.
6 * You may freely use this program, but: it offered strictly on an AS-IS, AT YOUR OWN
7 * RISK basis, there is no warranty of fitness for any purpose, and the rest of the
8 * usual yada-yada. Please keep this notice and the copyright in any distributions
9 * or modifications.
10 *
11 * This is not a supported product, but I welcome bug reports and fixes.
12 * Mail to simh@ibm1130.org
13 *
14 * 30-Dec-05 BLK Fixed mask for IAR and SAR register display and added display
15 * of Arithmetic Factor, per Carl Claunch.
16 *
17 * 09-Apr-04 BLK Changed code to use stock windows cursor IDC_HAND if available
18 *
19 * 02-Dec-02 BLK Changed display, added printer and card reader icons
20 * Added drag and drop support for scripts and card decks
21 * Added support for physical card reader and printer (hides icons)
22 *
23 * 17-May-02 BLK Pulled out of ibm1130_cpu.c
24 */
25
26 /* ------------------------------------------------------------------------
27 * Definitions
28 * ------------------------------------------------------------------------ */
29
30 #include <stdarg.h>
31 #include <math.h>
32
33 #include "ibm1130_defs.h"
34 #include "ibm1130res.h"
35
36 #define UPDATE_BY_TIMER
37
38 #ifdef UPDATE_BY_TIMER
39 # define UPDATE_INTERVAL 20 /* set to desired number of updates/second */
40 #else
41 # define UPDATE_INTERVAL 5000 /* GUI: set to 100000/f where f = desired updates/second of 1130 time */
42 #endif
43
44 #define UNIT_V_CR_EMPTY (UNIT_V_UF + 5) /* NOTE: THESE MUST MATCH THE DEFINITION IN ibm1130_cr.c */
45 #define UNIT_CR_EMPTY (1u << UNIT_V_CR_EMPTY)
46 #define UNIT_V_PHYSICAL (UNIT_V_UF + 9)
47 #define UNIT_PHYSICAL (1u << UNIT_V_PHYSICAL)
48
49 #define UNIT_V_PHYSICAL_PTR (UNIT_V_UF + 10) /* NOTE: THESE MUST MATCH THE DEFINITION IN ibm1130_prt.c */
50 #define UNIT_PHYSICAL_PTR (1u << UNIT_V_PHYSICAL_PTR)
51
52 /* I think I had it wrong; Program Load actually does start the processor after
53 * reading in the card?
54 */
55
56 #define PROGRAM_LOAD_STARTS_CPU
57
58 /* ------------------------------------------------------------------------
59 * Function declarations
60 * ------------------------------------------------------------------------ */
61
62 t_stat console_reset (DEVICE *dptr);
63
64 /* ------------------------------------------------------------------------
65 * Console display - on Windows builds (only) this code displays the 1130 console
66 * and toggle switches. It really enhances the experience.
67 *
68 * Currently, when the IPS throttle is nonzero, I update the display after every
69 * UPDATE_INTERVAL instructions, plus or minus a random amount to avoid aliased
70 * sampling in loops. When UPDATE_INTERVAL is defined as zero, we update every
71 * instruction no matter what the throttle. This makes the simulator too slow
72 * but it's cool and helpful during development.
73 * ------------------------------------------------------------------------ */
74
75 #define UNIT_V_DISPLAY (UNIT_V_UF + 0)
76 #define UNIT_DISPLAY (1u << UNIT_V_DISPLAY)
77
78 MTAB console_mod[] = {
79 { UNIT_DISPLAY, 0, "off", "OFF", NULL },
80 { UNIT_DISPLAY, UNIT_DISPLAY, "on", "ON", NULL },
81 { 0 }
82 };
83
84 UNIT console_unit = {UDATA (NULL, UNIT_DISABLE|UNIT_DISPLAY, 0) };
85
86 DEVICE console_dev = {
87 "GUI", &console_unit, NULL, console_mod,
88 1, 16, 16, 1, 16, 16,
89 NULL, NULL, console_reset,
90 NULL, NULL, NULL
91 };
92
93 /* reset for the "console" display device */
94
95 extern char *read_line (char *cptr, int size, FILE *stream);
96 extern FILE *sim_log;
97 extern DEVICE *find_unit (char *cptr, UNIT **uptr);
98
99 extern UNIT cr_unit; /* pointers to 1442 and 1132 (1403) printers */
100 extern UNIT prt_unit;
101
102 #ifndef GUI_SUPPORT
103 void update_gui (int force) {} /* stubs for non-GUI builds */
104 void forms_check (int set) {}
105 void print_check (int set) {}
106 void keyboard_select (int select) {}
107 void keyboard_selected (int select) {}
108 void disk_ready (int ready) {}
109 void disk_unlocked (int unlocked) {}
110 void gui_run (int running) {}
111 static void init_console_window (void) {}
112 static void destroy_console_window (void) {}
113
114 t_stat console_reset (DEVICE *dptr) {return SCPE_OK;}
115 void stuff_cmd (char *cmd) {}
116 t_bool stuff_and_wait (char *cmd, int timeout, int delay) {return FALSE;}
117 char *read_cmdline (char *ptr, int size, FILE *stream) {return read_line(ptr, size, stream);}
118 void remark_cmd (char *remark) {printf("%s\n", remark); if (sim_log) fprintf(sim_log, "%s\n", remark);}
119 #else
120
121 t_stat console_reset (DEVICE *dptr)
122 {
123 if (! sim_gui) {
124 SETBIT(console_unit.flags, UNIT_DIS); /* disable the GUI */
125 CLRBIT(console_unit.flags, UNIT_DISPLAY); /* turn the GUI off */
126 }
127
128 update_gui(FALSE);
129 return SCPE_OK;
130 }
131
132 /* scp_panic - report fatal internal programming error */
133
134 void scp_panic (char *msg)
135 {
136 fprintf(stderr, "%s\n", msg);
137 exit(1);
138 }
139
140 #ifdef _WIN32
141 /* only _WIN32 is defined right now */
142
143 #include <windows.h>
144
145 #define BUTTON_WIDTH 90
146 #define BUTTON_HEIGHT 50
147
148 #define IDC_KEYBOARD_SELECT 0
149 #define IDC_DISK_UNLOCK 1
150 #define IDC_RUN 2
151 #define IDC_PARITY_CHECK 3
152 #define IDC_UNUSED 4
153 #define IDC_FILE_READY 5
154 #define IDC_FORMS_CHECK 6
155 #define IDC_POWER_ON 7
156 #define IDC_POWER 8
157 #define IDC_PROGRAM_START 9
158 #define IDC_PROGRAM_STOP 10
159 #define IDC_LOAD_IAR 11
160 #define IDC_KEYBOARD 12
161 #define IDC_IMM_STOP 13
162 #define IDC_RESET 14
163 #define IDC_PROGRAM_LOAD 15
164
165 #define IDC_TEAR 16 /* standard button */
166 #define IDC_1442 17 /* device images */
167 #define IDC_1132 18
168
169 #define LAMPTIME 500 /* 500 msec delay on updating */
170 #define FLASH_TIMER_ID 1
171 #define UPDATE_TIMER_ID 2
172
173 #define RUNSWITCH_X 689 /* center of the run mode switch dial */
174 #define RUNSWITCH_Y 107
175 #define TOGGLES_X 122 /* left edge of series of toggle switches */
176
177 #define TXTBOX_X 200 /* text labels showing attached devices */
178 #define TXTBOX_Y 300
179 #define TXTBOX_WIDTH 195
180 #define TXTBOX_HEIGHT 12
181
182 static BOOL class_defined = FALSE;
183 static HWND hConsoleWnd = NULL;
184 static HBITMAP hBitmap = NULL;
185 static HFONT hFont = NULL;
186 static HFONT hBtnFont = NULL;
187 static HFONT hTinyFont = NULL;
188 static HBRUSH hbLampOut = NULL;
189 static HBRUSH hbWhite = NULL;
190 static HBRUSH hbBlack = NULL;
191 static HBRUSH hbGray = NULL;
192 static HPEN hSwitchPen = NULL;
193 static HPEN hWhitePen = NULL;
194 static HPEN hBlackPen = NULL;
195 static HPEN hLtGreyPen = NULL;
196 static HPEN hGreyPen = NULL;
197 static HPEN hDkGreyPen = NULL;
198 static int hUpdateTimer = 0;
199 static int hFlashTimer = 0;
200
201 static HCURSOR hcArrow = NULL;
202 static HCURSOR hcHand = NULL;
203 static HINSTANCE hInstance;
204 static HDC hCDC = NULL;
205 static char szConsoleClassName[] = "1130CONSOLE";
206 static DWORD PumpID = 0;
207 static HANDLE hPump = INVALID_HANDLE_VALUE;
208 static int bmwid, bmht;
209 static HANDLE hbm1442_full, hbm1442_empty, hbm1442_eof, hbm1442_middle;
210 static HANDLE hbm1132_full, hbm1132_empty;
211
212 static struct tag_btn {
213 int x, y, wx, wy;
214 char *txt;
215 BOOL pushable, state;
216 COLORREF clr;
217 HBRUSH hbrLit, hbrDark;
218 HWND hBtn;
219 BOOL subclassed;
220
221 } btn[] = {
222 0, 0, BUTTON_WIDTH, BUTTON_HEIGHT, "KEYBOARD\nSELECT", FALSE, FALSE, RGB(255,255,180), NULL, NULL, NULL, TRUE,
223 0, 1, BUTTON_WIDTH, BUTTON_HEIGHT, "DISK\nUNLOCK", FALSE, TRUE, RGB(255,255,180), NULL, NULL, NULL, TRUE,
224 0, 2, BUTTON_WIDTH, BUTTON_HEIGHT, "RUN", FALSE, FALSE, RGB(0,255,0), NULL, NULL, NULL, TRUE,
225 0, 3, BUTTON_WIDTH, BUTTON_HEIGHT, "PARITY\nCHECK", FALSE, FALSE, RGB(255,0,0), NULL, NULL, NULL, TRUE,
226
227 1, 0, BUTTON_WIDTH, BUTTON_HEIGHT, "", FALSE, FALSE, RGB(255,255,180), NULL, NULL, NULL, TRUE,
228 1, 1, BUTTON_WIDTH, BUTTON_HEIGHT, "FILE\nREADY", FALSE, FALSE, RGB(0,255,0), NULL, NULL, NULL, TRUE,
229 1, 2, BUTTON_WIDTH, BUTTON_HEIGHT, "FORMS\nCHECK", FALSE, FALSE, RGB(255,255,0), NULL, NULL, NULL, TRUE,
230 1, 3, BUTTON_WIDTH, BUTTON_HEIGHT, "POWER\nON", FALSE, TRUE, RGB(255,255,180), NULL, NULL, NULL, TRUE,
231
232 2, 0, BUTTON_WIDTH, BUTTON_HEIGHT, "POWER", TRUE, FALSE, RGB(255,255,180), NULL, NULL, NULL, TRUE,
233 2, 1, BUTTON_WIDTH, BUTTON_HEIGHT, "PROGRAM\nSTART", TRUE, FALSE, RGB(0,255,0), NULL, NULL, NULL, TRUE,
234 2, 2, BUTTON_WIDTH, BUTTON_HEIGHT, "PROGRAM\nSTOP", TRUE, FALSE, RGB(255,0,0), NULL, NULL, NULL, TRUE,
235 2, 3, BUTTON_WIDTH, BUTTON_HEIGHT, "LOAD\nIAR", TRUE, FALSE, RGB(0,0,255), NULL, NULL, NULL, TRUE,
236
237 3, 0, BUTTON_WIDTH, BUTTON_HEIGHT, "KEYBOARD", TRUE, FALSE, RGB(255,255,180), NULL, NULL, NULL, TRUE,
238 3, 1, BUTTON_WIDTH, BUTTON_HEIGHT, "IMM\nSTOP", TRUE, FALSE, RGB(255,0,0), NULL, NULL, NULL, TRUE,
239 3, 2, BUTTON_WIDTH, BUTTON_HEIGHT, "CHECK\nRESET", TRUE, FALSE, RGB(0,0,255), NULL, NULL, NULL, TRUE,
240 3, 3, BUTTON_WIDTH, BUTTON_HEIGHT, "PROGRAM\nLOAD", TRUE, FALSE, RGB(0,0,255), NULL, NULL, NULL, TRUE,
241
242 TXTBOX_X+40, TXTBOX_Y+25, 35, 12, "Tear", TRUE, FALSE, 0, NULL, NULL, NULL, FALSE,
243 635, 238, 110, 110, "EMPTY_1442", TRUE, FALSE, 0, NULL, NULL, NULL, FALSE,
244 635, 366, 110, 110, "EMPTY_1132", TRUE, FALSE, 0, NULL, NULL, NULL, FALSE,
245 };
246 #define NBUTTONS (sizeof(btn) / sizeof(btn[0]))
247
248 #define STATE_1442_EMPTY 0 /* no cards (no file attached) */
249 #define STATE_1442_FULL 1 /* cards in hopper (file attached at BOF) */
250 #define STATE_1442_MIDDLE 2 /* cards in hopper and stacker (file attached, neither EOF nor BOF) */
251 #define STATE_1442_EOF 3 /* cards in stacker (file attached, at EOF) */
252 #define STATE_1442_HIDDEN 4 /* simulator is attached to physical card reader */
253
254 #define STATE_1132_EMPTY 0 /* no paper hanging out of printer */
255 #define STATE_1132_FULL 1 /* paper hanging out of printer */
256 #define STATE_1132_HIDDEN 2 /* printer is attached to physical printer */
257
258 static struct tag_txtbox {
259 int x, y;
260 char *txt;
261 char *unitname;
262 int idctrl;
263 } txtbox[] = {
264 TXTBOX_X, TXTBOX_Y, "Card Reader", "CR", -1,
265 TXTBOX_X, TXTBOX_Y+ 25, "Printer", "PRT", IDC_1132,
266 TXTBOX_X, TXTBOX_Y+ 50, "Disk 1", "DSK0", -1,
267 TXTBOX_X, TXTBOX_Y+ 75, "Disk 2", "DSK1", -1,
268 TXTBOX_X, TXTBOX_Y+100, "Disk 3", "DSK2", -1,
269 TXTBOX_X, TXTBOX_Y+125, "Disk 4", "DSK3", -1,
270 TXTBOX_X, TXTBOX_Y+150, "Disk 5", "DSK4", -1,
271 };
272 #define NTXTBOXES (sizeof(txtbox) / sizeof(txtbox[0]))
273
274 #define TXTBOX_BOTTOM (TXTBOX_Y+150)
275
276 static void init_console_window (void);
277 static void destroy_console_window (void);
278 LRESULT CALLBACK ConsoleWndProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
279 static DWORD WINAPI Pump (LPVOID arg);
280 static void accept_dropped_file (HANDLE hDrop);
281 static void tear_printer (void);
282
283 #define NIXOBJECT(hObj) if (hObj != NULL) {DeleteObject(hObj); hObj = NULL;}
284
285 /* ------------------------------------------------------------------------
286 * init_console_window - display the 1130 console. Actually just creates a thread
287 * to run the Pump routine which does the actual work.
288 * ------------------------------------------------------------------------ */
289
290 static void init_console_window (void)
291 {
292 static BOOL did_atexit = FALSE;
293
294 if (hConsoleWnd != NULL)
295 return;
296
297 if (PumpID == 0)
298 hPump = CreateThread(NULL, 0, Pump, 0, 0, &PumpID);
299
300 if (! did_atexit) {
301 atexit(destroy_console_window);
302 did_atexit = TRUE;
303 }
304 }
305
306 /* ------------------------------------------------------------------------
307 * destroy_console_window - delete GDI objects.
308 * ------------------------------------------------------------------------ */
309
310 static void destroy_console_window (void)
311 {
312 int i;
313
314 if (hConsoleWnd != NULL)
315 SendMessage(hConsoleWnd, WM_CLOSE, 0, 0); /* cross thread call is OK */
316
317 if (hPump != INVALID_HANDLE_VALUE) { /* this is not the most graceful way to do it */
318 TerminateThread(hPump, 0);
319 hPump = INVALID_HANDLE_VALUE;
320 PumpID = 0;
321 hConsoleWnd = NULL;
322 }
323 if (hCDC != NULL) {
324 DeleteDC(hCDC);
325 hCDC = NULL;
326 }
327
328 NIXOBJECT(hBitmap)
329 NIXOBJECT(hbLampOut)
330 NIXOBJECT(hFont)
331 NIXOBJECT(hBtnFont);
332 NIXOBJECT(hTinyFont);
333 NIXOBJECT(hcHand)
334 NIXOBJECT(hSwitchPen)
335 NIXOBJECT(hLtGreyPen)
336 NIXOBJECT(hGreyPen)
337 NIXOBJECT(hDkGreyPen)
338
339 for (i = 0; i < NBUTTONS; i++) {
340 NIXOBJECT(btn[i].hbrLit);
341 NIXOBJECT(btn[i].hbrDark);
342 }
343
344 /* if (class_defined) {
345 UnregisterClass(hInstance, szConsoleClassName);
346 class_defined = FALSE;
347 }
348 */
349 }
350
351 /* ------------------------------------------------------------------------
352 * these variables hold the displayed versions of the system registers
353 * ------------------------------------------------------------------------ */
354
355 static int shown_iar = 0, shown_sar = 0, shown_sbr = 0, shown_afr = 0, shown_acc = 0, shown_ext = 0;
356 static int shown_op = 0, shown_tag = 0, shown_irq = 0, shown_ccc = 0, shown_cnd = 0, shown_wait = 0;
357 static int shown_ces = 0, shown_arf = 0, shown_runmode = MODE_RUN;
358 static int CND;
359
360 /* ------------------------------------------------------------------------
361 * RedrawRegion - mark a region for redrawing without background erase
362 * ------------------------------------------------------------------------ */
363
364 static void RedrawRegion (HWND hWnd, int left, int top, int right, int bottom)
365 {
366 RECT r;
367
368 r.left = left;
369 r.top = top;
370 r.right = right;
371 r.bottom = bottom;
372
373 InvalidateRect(hWnd, &r, FALSE);
374 }
375
376 /* ------------------------------------------------------------------------
377 * RepaintRegion - mark a region for redrawing with background erase
378 * ------------------------------------------------------------------------ */
379
380 static void RepaintRegion (HWND hWnd, int left, int top, int right, int bottom)
381 {
382 RECT r;
383
384 r.left = left;
385 r.top = top;
386 r.right = right;
387 r.bottom = bottom;
388
389 InvalidateRect(hWnd, &r, TRUE);
390 }
391
392 /* ------------------------------------------------------------------------
393 * update_gui - sees if anything on the console display has changed, and invalidates
394 * the changed regions. Then it calls UpdateWindow to force an immediate repaint. This
395 * function (update_gui) should probably not be called every time through the main
396 * instruction loop but it should be called at least whenever wait_state or int_req change, and then
397 * every so many instructions. It's also called after every simh command so manual changes are
398 * reflected instantly.
399 * ------------------------------------------------------------------------ */
400
401 void update_gui (BOOL force)
402 {
403 int i;
404 BOOL state;
405 static int in_here = FALSE;
406 static int32 displayed = 0;
407 RECT xin;
408
409 if ((int32)(console_unit.flags & UNIT_DISPLAY) != displayed) { /* setting has changed */
410 displayed = console_unit.flags & UNIT_DISPLAY;
411 if (displayed)
412 init_console_window();
413 else
414 destroy_console_window();
415 }
416
417 if (hConsoleWnd == NULL)
418 return;
419
420 GUI_BEGIN_CRITICAL_SECTION /* only one thread at a time, please */
421 if (in_here) {
422 GUI_END_CRITICAL_SECTION
423 return;
424 }
425 in_here = TRUE;
426 GUI_END_CRITICAL_SECTION
427
428 CND = 0; /* combine carry and V as two bits */
429 if (C)
430 CND |= 2;
431 if (V)
432 CND |= 1;
433
434 int_lamps |= int_req;
435 if (ipl >= 0)
436 int_lamps |= (0x20 >> ipl);
437
438 if (RUNMODE == MODE_LOAD)
439 SBR = CES; /* in load mode, SBR follows the console switches */
440
441 if (IAR != shown_iar)
442 {shown_iar = IAR; RedrawRegion(hConsoleWnd, 75, 8, 364, 32);} /* lamps: don't bother erasing bkgnd */
443 if (SAR != shown_sar)
444 {shown_sar = SAR; RedrawRegion(hConsoleWnd, 75, 42, 364, 65);}
445 if (ARF != shown_arf)
446 {shown_arf = ARF; RedrawRegion(hConsoleWnd, 75, 114, 364, 136);}
447 if (ACC != shown_acc)
448 {shown_acc = ACC; RedrawRegion(hConsoleWnd, 75, 141, 364, 164);}
449 if (EXT != shown_ext)
450 {shown_ext = EXT; RedrawRegion(hConsoleWnd, 75, 174, 364, 197);}
451 if (SBR != shown_sbr)
452 {shown_sbr = SBR; RedrawRegion(hConsoleWnd, 75, 77, 364, 97);}
453 if (OP != shown_op)
454 {shown_op = OP; RedrawRegion(hConsoleWnd, 501, 8, 595, 32);}
455 if (TAG != shown_tag)
456 {shown_tag = TAG; RedrawRegion(hConsoleWnd, 501, 77, 595, 97);}
457
458 if (int_lamps != shown_irq)
459 {shown_irq = int_lamps; RedrawRegion(hConsoleWnd, 501, 108, 595, 130);}
460
461 if (CCC != shown_ccc)
462 {shown_ccc = CCC; RedrawRegion(hConsoleWnd, 501, 141, 595, 164);}
463 if (CND != shown_cnd)
464 {shown_cnd = CND; RedrawRegion(hConsoleWnd, 501, 174, 595, 197);}
465 if ((wait_state|wait_lamp) != shown_wait)
466 {shown_wait= (wait_state|wait_lamp); RedrawRegion(hConsoleWnd, 380, 77, 414, 97);}
467 if (CES != shown_ces)
468 {shown_ces = CES; RepaintRegion(hConsoleWnd, TOGGLES_X-7, 230, TOGGLES_X+360, 275);} /* console entry sw: do erase bkgnd */
469 if (RUNMODE != shown_runmode)
470 {shown_runmode = RUNMODE;RepaintRegion(hConsoleWnd, RUNSWITCH_X-50, RUNSWITCH_Y-50, RUNSWITCH_X+50, RUNSWITCH_Y+50);}
471
472 int_lamps = 0;
473
474 /* this loop works with lamp buttons that are calculated on-the-fly only */
475 for (i = 0; i < NBUTTONS; i++) {
476 if (btn[i].pushable)
477 continue;
478
479 switch (i) {
480 case IDC_RUN:
481 state = hFlashTimer || (running && ! wait_state);
482 break;
483
484 /* this button is always off
485 case IDC_PARITY_CHECK
486 */
487
488 /* these buttons are enabled/disabled directly
489 case IDC_POWER_ON:
490 case IDC_FILE_READY:
491 case IDC_FORMS_CHECK:
492 case IDC_KEYBOARD_SELECT:
493 case IDC_DISK_UNLOCK:
494 */
495 default:
496 continue;
497 }
498
499 if (state != btn[i].state) { /* state has changed */
500 EnableWindow(btn[i].hBtn, state);
501 btn[i].state = state;
502 }
503 }
504
505 if (force) { /* if force flag is set, update text region */
506 SetRect(&xin, TXTBOX_X, TXTBOX_Y, TXTBOX_X+TXTBOX_WIDTH, TXTBOX_BOTTOM+2*TXTBOX_HEIGHT);
507 InvalidateRect(hConsoleWnd, &xin, TRUE);
508 }
509
510 state = ((cr_unit.flags & UNIT_ATT) == 0) ? STATE_1442_EMPTY :
511 (cr_unit.flags & UNIT_PHYSICAL) ? STATE_1442_HIDDEN :
512 (cr_unit.flags & UNIT_CR_EMPTY) ? STATE_1442_EOF :
513 cr_unit.pos ? STATE_1442_MIDDLE :
514 STATE_1442_FULL;
515
516 if (state != btn[IDC_1442].state) {
517 if (state == STATE_1442_HIDDEN)
518 ShowWindow(btn[IDC_1442].hBtn, SW_HIDE);
519 else {
520 if (btn[IDC_1442].state == STATE_1442_HIDDEN)
521 ShowWindow(btn[IDC_1442].hBtn, SW_SHOWNA);
522
523 SendMessage(btn[IDC_1442].hBtn, STM_SETIMAGE, IMAGE_BITMAP,
524 (LPARAM) (
525 (state == STATE_1442_FULL) ? hbm1442_full :
526 (state == STATE_1442_MIDDLE) ? hbm1442_middle :
527 (state == STATE_1442_EOF) ? hbm1442_eof :
528 hbm1442_empty));
529 }
530
531 btn[IDC_1442].state = state;
532 }
533
534 state = ((prt_unit.flags & UNIT_ATT) == 0) ? STATE_1132_EMPTY :
535 (prt_unit.flags & UNIT_PHYSICAL_PTR) ? STATE_1132_HIDDEN :
536 prt_unit.pos ? STATE_1132_FULL :
537 STATE_1132_EMPTY;
538
539 if (state != btn[IDC_1132].state) {
540 if (state == STATE_1132_HIDDEN)
541 ShowWindow(btn[IDC_1132].hBtn, SW_HIDE);
542 else {
543 if (btn[IDC_1132].state == STATE_1132_HIDDEN)
544 ShowWindow(btn[IDC_1132].hBtn, SW_SHOWNA);
545
546 SendMessage(btn[IDC_1132].hBtn, STM_SETIMAGE, IMAGE_BITMAP,
547 (LPARAM) (
548 (state == STATE_1132_FULL) ? hbm1132_full : hbm1132_empty));
549 }
550
551 btn[IDC_1132].state = state;
552 }
553
554 in_here = FALSE;
555 }
556
557 WNDPROC oldButtonProc = NULL;
558
559 /* ------------------------------------------------------------------------
560 * ------------------------------------------------------------------------ */
561
562 LRESULT CALLBACK ButtonProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
563 {
564 int i;
565
566 i = GetWindowLong(hWnd, GWL_ID);
567
568 if (! btn[i].pushable) {
569 if (uMsg == WM_LBUTTONDOWN || uMsg == WM_LBUTTONUP || uMsg == WM_LBUTTONDBLCLK)
570 return 0;
571
572 if (uMsg == WM_CHAR)
573 if ((TCHAR) wParam == ' ')
574 return 0;
575 }
576
577 return CallWindowProc(oldButtonProc, hWnd, uMsg, wParam, lParam);
578 }
579
580 /* ------------------------------------------------------------------------
581 * ------------------------------------------------------------------------ */
582
583 static int occurs (char *txt, char ch)
584 {
585 int count = 0;
586
587 while (*txt)
588 if (*txt++ == ch)
589 count++;
590
591 return count;
592 }
593
594 /* ------------------------------------------------------------------------
595 * turns out to get properly colored buttons you have to paint them yourself. Sheesh.
596 * On the plus side, this lets do a better job of aligning the button text than
597 * the button would by itself.
598 * ------------------------------------------------------------------------ */
599
600 void PaintButton (LPDRAWITEMSTRUCT dis)
601 {
602 int i = dis->CtlID, nc, nlines, x, y, dy;
603 BOOL down = dis->itemState & ODS_SELECTED;
604 HPEN hOldPen;
605 HFONT hOldFont;
606 UINT oldAlign;
607 COLORREF oldBk;
608 char *txt, *tstart;
609
610 if (! BETWEEN(i, 0, NBUTTONS-1))
611 return;
612
613 if (! btn[i].subclassed)
614 return;
615
616 FillRect(dis->hDC, &dis->rcItem, ((btn[i].pushable || power) && IsWindowEnabled(btn[i].hBtn)) ? btn[i].hbrLit : btn[i].hbrDark);
617
618 if (! btn[i].pushable) {
619 hOldPen = SelectObject(dis->hDC, hBlackPen);
620 MoveToEx(dis->hDC, dis->rcItem.left, dis->rcItem.top, NULL);
621 LineTo(dis->hDC, dis->rcItem.right-1, dis->rcItem.top);
622 LineTo(dis->hDC, dis->rcItem.right-1, dis->rcItem.bottom-1);
623 LineTo(dis->hDC, dis->rcItem.left, dis->rcItem.bottom-1);
624 LineTo(dis->hDC, dis->rcItem.left, dis->rcItem.top);
625 }
626 else if (down) {
627 /* do the three-D thing */
628 hOldPen = SelectObject(dis->hDC, hDkGreyPen);
629 MoveToEx(dis->hDC, dis->rcItem.left, dis->rcItem.bottom-2, NULL);
630 LineTo(dis->hDC, dis->rcItem.left, dis->rcItem.top);
631 LineTo(dis->hDC, dis->rcItem.right-1, dis->rcItem.top);
632
633 SelectObject(dis->hDC, hWhitePen);
634 MoveToEx(dis->hDC, dis->rcItem.left, dis->rcItem.bottom-1, NULL);
635 LineTo(dis->hDC, dis->rcItem.right-1, dis->rcItem.bottom-1);
636 LineTo(dis->hDC, dis->rcItem.right-1, dis->rcItem.top);
637
638 SelectObject(dis->hDC, hGreyPen);
639 MoveToEx(dis->hDC, dis->rcItem.left+1, dis->rcItem.bottom-3, NULL);
640 LineTo(dis->hDC, dis->rcItem.left+1, dis->rcItem.top+1);
641 LineTo(dis->hDC, dis->rcItem.right-3, dis->rcItem.top+1);
642 }
643 else {
644 hOldPen = SelectObject(dis->hDC, hWhitePen);
645 MoveToEx(dis->hDC, dis->rcItem.left, dis->rcItem.bottom-2, NULL);
646 LineTo(dis->hDC, dis->rcItem.left, dis->rcItem.top);
647 LineTo(dis->hDC, dis->rcItem.right-1, dis->rcItem.top);
648
649 SelectObject(dis->hDC, hDkGreyPen);
650 MoveToEx(dis->hDC, dis->rcItem.left, dis->rcItem.bottom-1, NULL);
651 LineTo(dis->hDC, dis->rcItem.right-1, dis->rcItem.bottom-1);
652 LineTo(dis->hDC, dis->rcItem.right-1, dis->rcItem.top);
653
654 SelectObject(dis->hDC, hGreyPen);
655 MoveToEx(dis->hDC, dis->rcItem.left+1, dis->rcItem.bottom-2, NULL);
656 LineTo(dis->hDC, dis->rcItem.right-2, dis->rcItem.bottom-2);
657 LineTo(dis->hDC, dis->rcItem.right-2, dis->rcItem.top+1);
658 }
659
660 SelectObject(dis->hDC, hOldPen);
661
662 hOldFont = SelectObject(dis->hDC, hBtnFont);
663 oldAlign = SetTextAlign(dis->hDC, TA_CENTER|TA_TOP);
664 oldBk = SetBkMode(dis->hDC, TRANSPARENT);
665
666 txt = btn[i].txt;
667 nlines = occurs(txt, '\n')+1;
668 x = (dis->rcItem.left + dis->rcItem.right) / 2;
669 y = (dis->rcItem.top + dis->rcItem.bottom) / 2;
670
671 dy = 14;
672 y = y - (nlines*dy)/2;
673
674 if (down) {
675 x += 1;
676 y += 1;
677 }
678
679 for (;;) {
680 for (nc = 0, tstart = txt; *txt && *txt != '\n'; txt++, nc++)
681 ;
682
683 TextOut(dis->hDC, x, y, tstart, nc);
684
685 if (*txt == '\0')
686 break;
687
688 txt++;
689 y += dy;
690 }
691
692 SetTextAlign(dis->hDC, oldAlign);
693 SetBkMode(dis->hDC, oldBk);
694 SelectObject(dis->hDC, hOldFont);
695 }
696
697 /* ------------------------------------------------------------------------
698 * ------------------------------------------------------------------------ */
699
700 HWND CreateSubclassedButton (HWND hwParent, int i)
701 {
702 HWND hBtn;
703 int x, y;
704 int r, g, b;
705
706 y = bmht - (4*BUTTON_HEIGHT) + BUTTON_HEIGHT * btn[i].y;
707 x = (btn[i].x < 2) ? (btn[i].x*BUTTON_WIDTH) : (598 - (4-btn[i].x)*BUTTON_WIDTH);
708
709 if ((hBtn = CreateWindow("BUTTON", btn[i].txt, WS_CHILD|WS_VISIBLE|BS_CENTER|BS_MULTILINE|BS_OWNERDRAW,
710 x, y, BUTTON_WIDTH, BUTTON_HEIGHT, hwParent, (HMENU) i, hInstance, NULL)) == NULL)
711 return NULL;
712
713 btn[i].hBtn = hBtn;
714
715 if (oldButtonProc == NULL)
716 oldButtonProc = (WNDPROC) GetWindowLong(hBtn, GWL_WNDPROC);
717
718 btn[i].hbrLit = CreateSolidBrush(btn[i].clr);
719
720 if (! btn[i].pushable) {
721 r = GetRValue(btn[i].clr) / 4;
722 g = GetGValue(btn[i].clr) / 4;
723 b = GetBValue(btn[i].clr) / 4;
724
725 btn[i].hbrDark = CreateSolidBrush(RGB(r,g,b));
726 EnableWindow(hBtn, FALSE);
727 }
728
729 SetWindowLong(hBtn, GWL_WNDPROC, (LONG) ButtonProc);
730 return hBtn;
731 }
732
733 /* ------------------------------------------------------------------------
734 * Pump - thread that takes care of the console window. It has to be a separate thread so that it gets
735 * execution time even when the simulator is compute-bound or IO-blocked. This routine creates the window
736 * and runs a standard Windows message pump. The window function does the actual display work.
737 * ------------------------------------------------------------------------ */
738
739 static DWORD WINAPI Pump (LPVOID arg)
740 {
741 MSG msg;
742 int wx, wy, i;
743 RECT r, ra;
744 BITMAP bm;
745 WNDCLASS cd;
746 HDC hDC;
747 HWND hActWnd;
748
749 hActWnd = GetForegroundWindow();
750
751 if (! class_defined) { /* register Window class */
752 hInstance = GetModuleHandle(NULL);
753
754 memset(&cd, 0, sizeof(cd));
755 cd.style = CS_NOCLOSE;
756 cd.lpfnWndProc = ConsoleWndProc;
757 cd.cbClsExtra = 0;
758 cd.cbWndExtra = 0;
759 cd.hInstance = hInstance;
760 cd.hIcon = NULL;
761 cd.hCursor = hcArrow;
762 cd.hbrBackground = NULL;
763 cd.lpszMenuName = NULL;
764 cd.lpszClassName = szConsoleClassName;
765
766 if (! RegisterClass(&cd)) {
767 PumpID = 0;
768 return 0;
769 }
770
771 class_defined = TRUE;
772 }
773
774 hbWhite = GetStockObject(WHITE_BRUSH); /* create or fetch useful GDI objects */
775 hbBlack = GetStockObject(BLACK_BRUSH); /* create or fetch useful GDI objects */
776 hbGray = GetStockObject(GRAY_BRUSH);
777 hSwitchPen = CreatePen(PS_SOLID, 5, RGB(255,255,255));
778
779 hWhitePen = GetStockObject(WHITE_PEN);
780 hBlackPen = GetStockObject(BLACK_PEN);
781 hLtGreyPen = CreatePen(PS_SOLID, 1, RGB(190,190,190));
782 hGreyPen = CreatePen(PS_SOLID, 1, RGB(128,128,128));
783 hDkGreyPen = CreatePen(PS_SOLID, 1, RGB(64,64,64));
784
785 hcArrow = LoadCursor(NULL, IDC_ARROW);
786 #ifdef IDC_HAND
787 hcHand = LoadCursor(NULL, IDC_HAND); /* use stock object provided by Windows */
788 if (hcHand == NULL)
789 hcHand = LoadCursor(hInstance, MAKEINTRESOURCE(IDC_MYHAND));
790 #else
791 hcHand = LoadCursor(hInstance, MAKEINTRESOURCE(IDC_MYHAND));
792 #endif
793
794 if (hBitmap == NULL)
795 hBitmap = LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_CONSOLE));
796 if (hbLampOut == NULL)
797 hbLampOut = CreateSolidBrush(RGB(50,50,50));
798 if (hFont == NULL)
799 hFont = CreateFont(-10, 0, 0, 0, FW_NORMAL, 0, 0, 0, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, FIXED_PITCH, FF_SWISS, "Arial");
800 if (hBtnFont == NULL)
801 hBtnFont = CreateFont(-12, 0, 0, 0, FW_NORMAL, 0, 0, 0, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, FIXED_PITCH, FF_SWISS, "Arial");
802 if (hTinyFont == NULL)
803 hTinyFont = CreateFont(-10, 0, 0, 0, FW_NORMAL, 0, 0, 0, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, FIXED_PITCH, FF_SWISS, "Arial");
804
805 if (hConsoleWnd == NULL) { /* create window */
806 if ((hConsoleWnd = CreateWindow(szConsoleClassName, "IBM 1130", WS_OVERLAPPED|WS_CLIPCHILDREN, 0, 0, 200, 200, NULL, NULL, hInstance, NULL)) == NULL) {
807 PumpID = 0;
808 return 0;
809 }
810
811 DragAcceptFiles(hConsoleWnd, TRUE); /* let it accept dragged files (scripts) */
812 }
813
814 GetObject(hBitmap, sizeof(bm), &bm); /* get bitmap size */
815 bmwid = bm.bmWidth;
816 bmht = bm.bmHeight;
817
818 for (i = 0; i < NBUTTONS; i++) {
819 if (! btn[i].subclassed)
820 continue;
821
822 CreateSubclassedButton(hConsoleWnd, i);
823 if (! btn[i].pushable)
824 EnableWindow(btn[i].hBtn, btn[i].state);
825 }
826
827 /* This isn't needed anymore, now that we have the big printer icon -- it acts like a button now
828 * i = IDC_TEAR;
829 * btn[i].hBtn = CreateWindow("BUTTON", btn[i].txt, WS_CHILD|WS_VISIBLE|BS_CENTER,
830 * btn[i].x, btn[i].y, btn[i].wx, btn[i].wy, hConsoleWnd, (HMENU) i, hInstance, NULL);
831 *
832 * SendMessage(btn[i].hBtn, WM_SETFONT, (WPARAM) hTinyFont, TRUE);
833 */
834
835 hbm1442_full = LoadBitmap(hInstance, "FULL_1442");
836 hbm1442_empty = LoadBitmap(hInstance, "EMPTY_1442");
837 hbm1442_eof = LoadBitmap(hInstance, "EOF_1442");
838 hbm1442_middle = LoadBitmap(hInstance, "MIDDLE_1442");
839 hbm1132_full = LoadBitmap(hInstance, "FULL_1132");
840 hbm1132_empty = LoadBitmap(hInstance, "EMPTY_1132");
841
842 i = IDC_1442;
843
844 btn[i].hBtn = CreateWindow("STATIC", btn[i].txt, WS_CHILD|WS_VISIBLE|SS_BITMAP|SS_SUNKEN|WS_BORDER|SS_REALSIZEIMAGE|SS_NOTIFY,
845 btn[i].x, btn[i].y, btn[i].wx, btn[i].wy, hConsoleWnd, (HMENU) i, hInstance, NULL);
846 btn[i].state = STATE_1442_EMPTY;
847
848 wx = SendMessage(btn[i].hBtn, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM) hbm1442_empty);
849
850 i = IDC_1132;
851
852 btn[i].hBtn = CreateWindow("STATIC", btn[i].txt, WS_CHILD|WS_VISIBLE|SS_BITMAP|SS_SUNKEN|WS_BORDER|SS_REALSIZEIMAGE|SS_NOTIFY,
853 btn[i].x, btn[i].y, btn[i].wx, btn[i].wy, hConsoleWnd, (HMENU) i, hInstance, NULL);
854 btn[i].state = FALSE;
855
856 wx = SendMessage(btn[i].hBtn, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM) hbm1132_empty);
857
858 GetWindowRect(hConsoleWnd, &r); /* get window size as created */
859 wx = r.right - r.left + 1;
860 wy = r.bottom - r.top + 1;
861
862 if (hCDC == NULL) { /* get a memory DC and select the bitmap into ti */
863 hDC = GetDC(hConsoleWnd);
864 hCDC = CreateCompatibleDC(hDC);
865 SelectObject(hCDC, hBitmap);
866 ReleaseDC(hConsoleWnd, hDC);
867 }
868
869 GetClientRect(hConsoleWnd, &r);
870 wx = (wx - r.right - 1) + bmwid; /* compute new desired size based on how client area came out */
871 wy = (wy - r.bottom - 1) + bmht;
872 MoveWindow(hConsoleWnd, 0, 0, wx, wy, FALSE); /* resize window */
873
874 ShowWindow(hConsoleWnd, SW_SHOWNOACTIVATE); /* display it */
875 UpdateWindow(hConsoleWnd);
876
877 if (hActWnd != NULL) { /* bring console (sim) window back to top */
878 GetWindowRect(hConsoleWnd, &r);
879 ShowWindow(hActWnd, SW_NORMAL); /* and move it just below the display window */
880 SetWindowPos(hActWnd, HWND_TOP, 0, r.bottom, 0, 0, SWP_NOSIZE);
881 GetWindowRect(hActWnd, &ra);
882 if (ra.bottom >= GetSystemMetrics(SM_CYSCREEN)) { /* resize if it goes of bottom of screen */
883 ra.bottom = GetSystemMetrics(SM_CYSCREEN) - 1;
884 SetWindowPos(hActWnd, 0, 0, 0, ra.right-ra.left+1, ra.bottom-ra.top+1, SWP_NOZORDER|SWP_NOMOVE);
885 }
886 }
887
888 if (running) /* if simulator is already running, start update timer */
889 gui_run(TRUE);
890
891 while (GetMessage(&msg, hConsoleWnd, 0, 0)) { /* message pump - this basically loops forevermore */
892 TranslateMessage(&msg);
893 DispatchMessage(&msg);
894 }
895
896 if (hConsoleWnd != NULL) {
897 DragAcceptFiles(hConsoleWnd, FALSE); /* unregister as drag/drop target */
898 DestroyWindow(hConsoleWnd); /* but if a quit message got posted, clean up */
899 hConsoleWnd = NULL;
900 }
901
902 PumpID = 0;
903 return 0;
904 }
905
906 /* ------------------------------------------------------------------------
907 * DrawBits - starting at position (x,y), draw lamps for nbits bits of word 'bits', looking only at masked bits
908 * ------------------------------------------------------------------------ */
909
910 static void DrawBits (HDC hDC, int x, int y, int bits, int nbits, int mask, char *syms)
911 {
912 int i, b = 0x0001 << (nbits-1);
913
914 for (i = 0; i < nbits; i++, b >>= 1) {
915 if (mask & b) { /* select white or black lettering then write 2 chars */
916 SetTextColor(hDC, (b & bits && power) ? RGB(255,255,255) : RGB(0,0,0));
917 TextOut(hDC, x, y, syms, 2);
918 }
919 syms += 2; /* go to next symbol pair */
920
921 if (i < 10)
922 x += 15; /* step between lamps */
923 else
924 x += 19;
925
926 if (x < 500) {
927 if (b & 0x1110)
928 x += 10; /* step over nibble divisions on left side */
929 else if (b & 0x0001)
930 x += 9;
931 }
932 }
933 }
934
935 /* ------------------------------------------------------------------------
936 * DrawToggles - display the console sense switches
937 * ------------------------------------------------------------------------ */
938
939
940 static void DrawToggles (HDC hDC, int bits)
941 {
942 int b, x;
943
944 for (b = 0x8000, x = TOGGLES_X; b != 0; b >>= 1) {
945 if (shown_ces & b) { /* up */
946 SelectObject(hDC, hbWhite);
947 Rectangle(hDC, x, 232, x+9, 240);
948 SelectObject(hDC, hbGray);
949 Rectangle(hDC, x, 239, x+9, 255);
950 }
951 else { /* down */
952 SelectObject(hDC, hbWhite);
953 Rectangle(hDC, x, 263, x+9, 271);
954 SelectObject(hDC, hbGray);
955 Rectangle(hDC, x, 248, x+9, 264);
956 }
957
958 x += (b & 0x1111) ? 31 : 21;
959 }
960 }
961
962 /* ------------------------------------------------------------------------
963 * DrawRunmode - draw the run mode rotary switch's little tip
964 * ------------------------------------------------------------------------ */
965
966 void DrawRunmode (HDC hDC, int mode)
967 {
968 double angle = (mode*45. + 90.) * 3.1415926 / 180.; /* convert mode position to angle in radians */
969 double ca, sa; /* sine and cosine */
970 int x0, y0, x1, y1;
971 HPEN hOldPen;
972
973 ca = cos(angle);
974 sa = sin(angle);
975
976 x0 = RUNSWITCH_X + (int) (20.*ca + 0.5); /* inner radius */
977 y0 = RUNSWITCH_Y - (int) (20.*sa + 0.5);
978 x1 = RUNSWITCH_X + (int) (25.*ca + 0.5); /* outer radius */
979 y1 = RUNSWITCH_Y - (int) (25.*sa + 0.5);
980
981 hOldPen = SelectObject(hDC, hSwitchPen);
982
983 MoveToEx(hDC, x0, y0, NULL);
984 LineTo(hDC, x1, y1);
985
986 SelectObject(hDC, hOldPen);
987 }
988
989 /* ------------------------------------------------------------------------
990 * HandleClick - handle mouse clicks on the console window. Now we just
991 * look at the console sense switches. Actual says this is a real click, rather
992 * than a mouse-region test. Return value TRUE means the cursor is over a hotspot.
993 * ------------------------------------------------------------------------ */
994
995 static BOOL HandleClick (HWND hWnd, int xh, int yh, BOOL actual, BOOL rightclick)
996 {
997 int b, x, r, ang, i;
998
999 for (b = 0x8000, x = TOGGLES_X; b != 0; b >>= 1) {
1000 if (BETWEEN(xh, x-3, x+8+3) && BETWEEN(yh, 230, 275)) {
1001 if (actual) {
1002 CES ^= b; /* a hit. Invert the bit and redisplay */
1003 update_gui(TRUE);
1004 }
1005 return TRUE;
1006 }
1007 x += (b & 0x1111) ? 31 : 21;
1008 }
1009
1010 if (BETWEEN(xh, RUNSWITCH_X-50, RUNSWITCH_X+50) && BETWEEN(yh, RUNSWITCH_Y-50, RUNSWITCH_Y+50)) { /* hit near rotary switch */
1011 ang = (int) (atan2(RUNSWITCH_X-xh, RUNSWITCH_Y-yh)*180./3.1415926); /* this does implicit 90 deg rotation by the way */
1012 r = (int) sqrt((xh-RUNSWITCH_X)*(xh-RUNSWITCH_X)+(yh-RUNSWITCH_Y)*(yh-RUNSWITCH_Y));
1013 if (r > 12) {
1014 for (i = MODE_LOAD; i <= MODE_INT_RUN; i++) {
1015 if (BETWEEN(ang, i*45-12, i*45+12)) {
1016 if (actual) {
1017 RUNMODE = i;
1018 update_gui(TRUE);
1019 }
1020 return TRUE;
1021 }
1022 }
1023
1024 }
1025 }
1026
1027 return FALSE;
1028 }
1029
1030 /* ------------------------------------------------------------------------
1031 * DrawConsole - refresh the console display. (This routine could be sped up by intersecting
1032 * the various components' bounding rectangles with the repaint rectangle. The bounding rects
1033 * could be put into an array and used both here and in the refresh routine).
1034 *
1035 * RedrawRegion -> force repaint w/o background redraw. used for lamps which are drawn in the same place in either state
1036 * RepaintRegion-> repaint with background redraw. Used for toggles which change position.
1037 * ------------------------------------------------------------------------ */
1038
1039 static void DrawConsole (HDC hDC, PAINTSTRUCT *ps)
1040 {
1041 static char digits[] = " 0 1 2 3 4 5 6 7 8 9101112131415";
1042 static char cccs[] = "3216 8 4 2 1";
1043 static char cnds[] = " C V";
1044 static char waits[] = " W";
1045 HFONT hOldFont, hOldBrush;
1046 RECT xout, xin;
1047 int i, n;
1048 DEVICE *dptr;
1049 UNIT *uptr;
1050 t_bool enab;
1051 char nametemp[50], *dispname;
1052
1053 hOldFont = SelectObject(hDC, hFont); /* use that tiny font */
1054 hOldBrush = SelectObject(hDC, hbWhite);
1055
1056 SetBkMode(hDC, TRANSPARENT); /* overlay letters w/o changing background */
1057
1058 DrawBits(hDC, 76, 15, shown_iar, 16, mem_mask, digits); /* register holds only 15 bits */
1059 DrawBits(hDC, 76, 48, shown_sar, 16, mem_mask, digits); /* but let's display only used bits */
1060 DrawBits(hDC, 76, 81, shown_sbr, 16, 0xFFFF, digits);
1061 DrawBits(hDC, 76, 114, shown_arf, 16, 0xFFFF, digits);
1062 DrawBits(hDC, 76, 147, shown_acc, 16, 0xFFFF, digits);
1063 DrawBits(hDC, 76, 180, shown_ext, 16, 0xFFFF, digits);
1064
1065 DrawBits(hDC, 506, 15, shown_op, 5, 0x001F, digits);
1066 DrawBits(hDC, 506, 81, shown_tag, 4, 0x0007, digits);
1067 DrawBits(hDC, 506, 114, shown_irq, 6, 0x003F, digits);
1068 DrawBits(hDC, 506, 147, shown_ccc, 6, 0x003F, cccs);
1069 DrawBits(hDC, 506, 180, shown_cnd, 2, 0x0003, cnds);
1070
1071 DrawBits(hDC, 390, 81, shown_wait?1:0,1, 0x0001, waits);
1072
1073 DrawToggles(hDC, shown_ces);
1074
1075 DrawRunmode(hDC, shown_runmode);
1076
1077 SelectObject(hDC, hOldFont);
1078 SelectObject(hDC, hOldBrush);
1079
1080 SetBkColor(hDC, RGB(0,0,0));
1081
1082 SetRect(&xin, TXTBOX_X, TXTBOX_Y, TXTBOX_X+TXTBOX_WIDTH, TXTBOX_BOTTOM+TXTBOX_HEIGHT);
1083 if (IntersectRect(&xout, &xin, &ps->rcPaint)) {
1084 hOldFont = SelectObject(hDC, hTinyFont);
1085
1086 for (i = 0; i < NTXTBOXES; i++) {
1087 enab = FALSE;
1088
1089 dptr = find_unit(txtbox[i].unitname, &uptr);
1090 if (dptr != NULL && uptr != NULL) {
1091 if (uptr->flags & UNIT_DIS) {
1092 SetTextColor(hDC, RGB(128,0,0));
1093 }
1094 else if (uptr->flags & UNIT_ATT) {
1095 SetTextColor(hDC, RGB(0,0,255));
1096 if ((n = strlen(uptr->filename)) > 30) {
1097 strcpy(nametemp, "...");
1098 strcpy(nametemp+3, uptr->filename+n-30);
1099 dispname = nametemp;
1100 }
1101 else
1102 dispname = uptr->filename;
1103
1104 TextOut(hDC, txtbox[i].x+25, txtbox[i].y+TXTBOX_HEIGHT, dispname, strlen(dispname));
1105 SetTextColor(hDC, RGB(255,255,255));
1106 enab = TRUE;
1107 }
1108 else {
1109 SetTextColor(hDC, RGB(128,128,128));
1110 }
1111 TextOut(hDC, txtbox[i].x, txtbox[i].y, txtbox[i].txt, strlen(txtbox[i].txt));
1112 }
1113
1114 if (txtbox[i].idctrl >= 0)
1115 EnableWindow(btn[txtbox[i].idctrl].hBtn, enab);
1116 }
1117
1118 SelectObject(hDC, hOldFont);
1119 }
1120 }
1121
1122 /* ------------------------------------------------------------------------
1123 * Handles button presses. Remember that this occurs in the context of
1124 * the Pump thread, not the simulator thread.
1125 * ------------------------------------------------------------------------ */
1126
1127 void flash_run (void)
1128 {
1129 EnableWindow(btn[IDC_RUN].hBtn, TRUE); /* enable the run lamp */
1130
1131 if (hFlashTimer != 0)
1132 KillTimer(hConsoleWnd, FLASH_TIMER_ID); /* (re)schedule lamp update */
1133
1134 hFlashTimer = SetTimer(hConsoleWnd, FLASH_TIMER_ID, LAMPTIME, NULL);
1135 }
1136
1137 void gui_run (int running)
1138 {
1139 if (running && hUpdateTimer == 0 && hConsoleWnd != NULL) {
1140 hUpdateTimer = SetTimer(hConsoleWnd, UPDATE_TIMER_ID, 1000/UPDATE_INTERVAL, NULL);
1141 }
1142 else if (hUpdateTimer != 0 && ! running) {
1143 KillTimer(hConsoleWnd, UPDATE_TIMER_ID);
1144 hUpdateTimer = 0;
1145 }
1146 flash_run(); /* keep run lamp active for a while after we stop running */
1147 }
1148
1149 void HandleCommand (HWND hWnd, WORD wNotify, WORD idCtl, HWND hwCtl)
1150 {
1151 int i;
1152
1153 switch (idCtl) {
1154 case IDC_POWER: /* toggle system power */
1155 power = ! power;
1156 reset_all(0);
1157 if (running && ! power) { /* turning off */
1158 reason = STOP_POWER_OFF;
1159 /* wait for execution thread to exit */
1160 /* this prevents message pump from running, which unfortunately locks up
1161 * the emulator thread when it calls gui_run(FALSE) which calls EnableWindow on the Run lamp
1162 * while (running)
1163 * Sleep(10);
1164 */
1165 }
1166
1167 btn[IDC_POWER_ON].state = power;
1168 EnableWindow(btn[IDC_POWER_ON].hBtn, power);
1169
1170 for (i = 0; i < NBUTTONS; i++) /* repaint all of the lamps */
1171 if (! btn[i].pushable)
1172 InvalidateRect(btn[i].hBtn, NULL, TRUE);
1173
1174 break;
1175
1176 case IDC_PROGRAM_START: /* begin execution */
1177 if (! running) {
1178 switch (RUNMODE) {
1179 case MODE_INT_RUN:
1180 case MODE_RUN:
1181 case MODE_SI:
1182 stuff_cmd("cont");
1183 break;
1184
1185 case MODE_DISP: /* display core and advance IAR */
1186 ReadW(IAR);
1187 IAR = IAR+1;
1188 flash_run(); /* illuminate run lamp for .5 sec */
1189 break;
1190
1191 case MODE_LOAD: /* store to core and advance IAR */
1192 WriteW(IAR, CES);
1193 IAR = IAR+1;
1194 flash_run();
1195 break;
1196 }
1197 }
1198 break;
1199
1200 case IDC_PROGRAM_STOP:
1201 if (running) { /* potential race condition here */
1202 GUI_BEGIN_CRITICAL_SECTION
1203 SETBIT(con_dsw, CPU_DSW_PROGRAM_STOP);
1204 SETBIT(ILSW[5], ILSW_5_INT_RUN_PROGRAM_STOP);
1205 int_req |= INT_REQ_5; /* note: calc_ints() is not needed in this case */
1206 int_lamps |= INT_REQ_5;
1207 GUI_END_CRITICAL_SECTION
1208 }
1209 break;
1210
1211 case IDC_LOAD_IAR:
1212 if (! running) {
1213 IAR = CES & mem_mask; /* set IAR from console entry switches */
1214 }
1215 break;
1216
1217 case IDC_KEYBOARD: /* toggle between console/keyboard mode */
1218 break;
1219
1220 case IDC_IMM_STOP:
1221 if (running) {
1222 reason = STOP_IMMEDIATE; /* terminate execution without setting wait_mode */
1223 /* wait for execution thread to exit */
1224 /* this prevents message pump from running, which unfortunately locks up
1225 * the emulator thread when it calls gui_run(FALSE) which calls EnableWindow on the Run lamp
1226 * while (running)
1227 * Sleep(10);
1228 */
1229 }
1230 break;
1231
1232 case IDC_RESET:
1233 if (! running) { /* check-reset is disabled while running */
1234 reset_all(0);
1235 forms_check(0); /* clear forms-check status */
1236 print_check(0);
1237 }
1238 break;
1239
1240 case IDC_PROGRAM_LOAD:
1241 if (! running) { /* if card reader is attached to a file, do cold start read of one card */
1242 IAR = 0; /* reset IAR */
1243 #ifdef PROGRAM_LOAD_STARTS_CPU
1244 stuff_cmd("boot cr");
1245 #else
1246 if (cr_boot(0, NULL) != SCPE_OK) /* load boot card */
1247 remark_cmd("IPL failed");
1248 #endif
1249 }
1250 break;
1251
1252 case IDC_TEAR: /* "tear off printer output" */
1253 case IDC_1132: /* do same if they click on the printer icon */
1254 if (btn[IDC_1132].state && (wNotify == STN_CLICKED || wNotify == STN_DBLCLK))
1255 tear_printer();
1256 break;
1257
1258 case IDC_1442:
1259 if (btn[IDC_1442].state == STATE_1442_FULL || wNotify == STN_DBLCLK)
1260 stuff_cmd("detach cr");
1261 else if (btn[IDC_1442].state != STATE_1442_EMPTY && wNotify == STN_CLICKED) {
1262 cr_rewind();
1263 update_gui(TRUE);
1264 }
1265 break;
1266 }
1267
1268 update_gui(FALSE);
1269 }
1270
1271 /* ------------------------------------------------------------------------
1272 * ConsoleWndProc - window process for the console display
1273 * ------------------------------------------------------------------------ */
1274
1275 LRESULT CALLBACK ConsoleWndProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1276 {
1277 HDC hDC;
1278 PAINTSTRUCT ps;
1279 POINT p;
1280 RECT clip, xsect, rbmp;
1281 int i;
1282
1283 switch (uMsg) {
1284 case WM_CLOSE:
1285 DestroyWindow(hWnd);
1286 break;
1287
1288 case WM_DESTROY:
1289 gui_run(FALSE);
1290 hConsoleWnd = NULL;
1291 break;
1292
1293 case WM_ERASEBKGND:
1294 hDC = (HDC) wParam;
1295 GetClipBox(hDC, &clip);
1296 SetRect(&rbmp, 0, 0, bmwid, bmht);
1297 if (IntersectRect(&xsect, &clip, &rbmp))
1298 BitBlt(hDC, xsect.left, xsect.top, xsect.right-xsect.left+1, xsect.bottom-xsect.top+1, hCDC, xsect.left, xsect.top, SRCCOPY);
1299 return TRUE; /* let Paint do this so we know what the update region is (ps.rcPaint) */
1300
1301 case WM_PAINT:
1302 hDC = BeginPaint(hWnd, &ps);
1303 DrawConsole(hDC, &ps);
1304 EndPaint(hWnd, &ps);
1305 break;
1306
1307 case WM_COMMAND: /* button click */
1308 HandleCommand(hWnd, HIWORD(wParam), LOWORD(wParam), (HWND) lParam);
1309 break;
1310
1311 case WM_CTLCOLOREDIT: /* text color for edit controls */
1312 SetBkColor((HDC) wParam, RGB(0,0,0));
1313 SetTextColor((HDC) wParam, RGB(255,255,255));
1314 break;
1315
1316 case WM_DRAWITEM:
1317 PaintButton((LPDRAWITEMSTRUCT) lParam);
1318 break;
1319
1320 case WM_SETCURSOR:
1321 GetCursorPos(&p);
1322 ScreenToClient(hWnd, &p);
1323 SetCursor(HandleClick(hWnd, p.x, p.y, FALSE, FALSE) ? hcHand : hcArrow);
1324 return TRUE;
1325
1326 case WM_LBUTTONDOWN:
1327 HandleClick(hWnd, LOWORD(lParam), HIWORD(lParam), TRUE, FALSE);
1328 break;
1329
1330 case WM_RBUTTONDOWN:
1331 HandleClick(hWnd, LOWORD(lParam), HIWORD(lParam), TRUE, TRUE);
1332 break;
1333
1334 case WM_CTLCOLORBTN:
1335 i = GetWindowLong((HWND) lParam, GWL_ID);
1336 if (BETWEEN(i, 0, NBUTTONS-1))
1337 return (LRESULT) (power && IsWindowEnabled((HWND) lParam) ? btn[i].hbrLit : btn[i].hbrDark);
1338
1339 case WM_TIMER:
1340 if (wParam == FLASH_TIMER_ID && hFlashTimer != 0) {
1341 KillTimer(hWnd, FLASH_TIMER_ID);
1342 hFlashTimer = 0;
1343 }
1344 update_gui(FALSE);
1345 break;
1346
1347 case WM_DROPFILES:
1348 accept_dropped_file((HANDLE) wParam); /* console window - dragged file is a script or card deck */
1349 break;
1350
1351 default:
1352 return DefWindowProc(hWnd, uMsg, wParam, lParam);
1353 }
1354
1355 return 0;
1356 }
1357
1358 enum {PRINTER_OK = 0, FORMS_CHECK = 1, PRINT_CHECK = 2, BOTH_CHECK = 3} printerstatus = PRINTER_OK;
1359
1360 void forms_check (int set)
1361 {
1362 COLORREF oldcolor = btn[IDC_FORMS_CHECK].clr;
1363
1364 if (set)
1365 SETBIT(printerstatus, FORMS_CHECK);
1366 else
1367 CLRBIT(printerstatus, FORMS_CHECK);
1368
1369 btn[IDC_FORMS_CHECK].clr = (printerstatus & PRINT_CHECK) ? RGB(255,0,0) : RGB(255,255,0);
1370
1371 btn[IDC_FORMS_CHECK].state = printerstatus;
1372
1373 if (btn[IDC_FORMS_CHECK].hBtn != NULL) {
1374 EnableWindow(btn[IDC_FORMS_CHECK].hBtn, printerstatus);
1375
1376 if (btn[IDC_FORMS_CHECK].clr != oldcolor)
1377 InvalidateRect(btn[IDC_FORMS_CHECK].hBtn, NULL, TRUE); /* change color in any case */
1378 }
1379 }
1380
1381 void print_check (int set)
1382 {
1383 COLORREF oldcolor = btn[IDC_FORMS_CHECK].clr;
1384
1385 if (set)
1386 SETBIT(printerstatus, PRINT_CHECK);
1387 else
1388 CLRBIT(printerstatus, PRINT_CHECK);
1389
1390 btn[IDC_FORMS_CHECK].clr = (printerstatus & PRINT_CHECK) ? RGB(255,0,0) : RGB(255,255,0);
1391
1392 btn[IDC_FORMS_CHECK].state = printerstatus;
1393
1394 if (btn[IDC_FORMS_CHECK].hBtn != NULL) {
1395 EnableWindow(btn[IDC_FORMS_CHECK].hBtn, printerstatus);
1396
1397 if (btn[IDC_FORMS_CHECK].clr != oldcolor)
1398 InvalidateRect(btn[IDC_FORMS_CHECK].hBtn, NULL, TRUE); /* change color in any case */
1399 }
1400 }
1401
1402 void keyboard_selected (int select)
1403 {
1404 btn[IDC_KEYBOARD_SELECT].state = select;
1405
1406 if (btn[IDC_KEYBOARD_SELECT].hBtn != NULL)
1407 EnableWindow(btn[IDC_KEYBOARD_SELECT].hBtn, select);
1408 }
1409
1410 void disk_ready (int ready)
1411 {
1412 btn[IDC_FILE_READY].state = ready;
1413
1414 if (btn[IDC_FILE_READY].hBtn != NULL)
1415 EnableWindow(btn[IDC_FILE_READY].hBtn, ready);
1416 }
1417
1418 void disk_unlocked (int unlocked)
1419 {
1420 btn[IDC_DISK_UNLOCK].state = unlocked;
1421
1422 if (btn[IDC_DISK_UNLOCK].hBtn != NULL)
1423 EnableWindow(btn[IDC_DISK_UNLOCK].hBtn, unlocked);
1424 }
1425
1426 static void accept_dropped_file (HANDLE hDrop)
1427 {
1428 int nfiles;
1429 char fname[MAX_PATH], cmd[MAX_PATH+50], *deckfile;
1430 BOOL cardreader;
1431 POINT pt;
1432 HWND hWndDrop;
1433
1434 nfiles = DragQueryFile(hDrop, 0xFFFFFFFF, NULL, 0); /* get file count, */
1435 DragQueryFile(hDrop, 0, fname, sizeof(fname)); /* get first filename */
1436 DragQueryPoint(hDrop, &pt); /* get location of drop */
1437 DragFinish(hDrop);
1438
1439 if (nfiles <= 0) /* hmm, this seems unlikely to occur, but better check */
1440 return;
1441
1442 if (running) { /* can only accept a drop while processor is stopped */
1443 MessageBeep(0);
1444 return;
1445 }
1446
1447 if ((hWndDrop = ChildWindowFromPoint(hConsoleWnd, pt)) == btn[IDC_1442].hBtn)
1448 cardreader = TRUE; /* file was dropped onto 1442 card reader */
1449 else if (hWndDrop == NULL || hWndDrop == hConsoleWnd)
1450 cardreader = FALSE; /* file was dropped onto console window, not a button */
1451 else {
1452 MessageBeep(0); /* file was dropped onto another button */
1453 return;
1454 }
1455
1456 if (nfiles > 1) { /* oops, we wouldn't know what order to read them in */
1457 MessageBox(hConsoleWnd, "You may only drop one file at a time", "", MB_OK);
1458 return;
1459 }
1460
1461 /* if shift key is down, prepend @ to name (make it a deck file) */
1462 deckfile = ((GetKeyState(VK_SHIFT) & 0x8000) && cardreader) ? "@" : "";
1463
1464 sprintf(cmd, "%s \"%s%s\"", cardreader ? "attach cr" : "do", deckfile, fname);
1465 stuff_cmd(cmd);
1466 }
1467
1468 static void tear_printer (void)
1469 {
1470 char cmd[MAX_PATH+100], filename[MAX_PATH];
1471
1472 if ((prt_unit.flags & UNIT_ATT) == 0)
1473 return;
1474
1475 strcpy(filename, prt_unit.filename); /* save current attached filename */
1476
1477 if (! stuff_and_wait("detach prt", 1000, 0)) /* detach it */
1478 return;
1479
1480 sprintf(cmd, "view \"%s\"", filename); /* spawn notepad to view it */
1481 if (! stuff_and_wait(cmd, 3000, 500))
1482 return;
1483
1484 remove(filename); /* delete the file */
1485
1486 sprintf(cmd, "attach prt \"%s\"", filename); /* reattach */
1487 stuff_cmd(cmd);
1488 }
1489
1490 #ifdef XXX
1491 if ((hBtn = CreateWindow("BUTTON", btn[i].txt, WS_CHILD|WS_VISIBLE|BS_CENTER|BS_MULTILINE|BS_OWNERDRAW,
1492 x, y, BUTTON_WIDTH, BUTTON_HEIGHT, hwParent, (HMENU) i, hInstance, NULL)) == NULL)
1493 return NULL;
1494
1495 #endif
1496
1497 CRITICAL_SECTION critsect;
1498
1499 void begin_critical_section (void)
1500 {
1501 static BOOL mustinit = TRUE;
1502
1503 if (mustinit) {
1504 InitializeCriticalSection(&critsect);
1505 mustinit = FALSE;
1506 }
1507
1508 EnterCriticalSection(&critsect);
1509 }
1510
1511 void end_critical_section (void)
1512 {
1513 LeaveCriticalSection(&critsect);
1514 }
1515
1516 #ifndef MIN
1517 # define MIN(a,b) (((a) <= (b)) ? (a) : (b))
1518 #endif
1519
1520 /* win32 - use a separate thread to read command lines so the GUI
1521 * can insert commands as well */
1522
1523 static HANDLE hCmdThread = NULL;
1524 static DWORD iCmdThreadID = 0;
1525 static HANDLE hCmdReadEvent = NULL;
1526 static HANDLE hCmdReadyEvent = NULL;
1527 static BOOL scp_stuffed = FALSE, scp_reading = FALSE;
1528 static char cmdbuffer[256];
1529
1530 /* CmdThread - separate thread to read commands from stdin upon request */
1531
1532 static DWORD WINAPI CmdThread (LPVOID arg)
1533 {
1534 for (;;) {
1535 WaitForSingleObject(hCmdReadEvent, INFINITE); /* wait for request */
1536 read_line(cmdbuffer, sizeof(cmdbuffer), stdin); /* read one line */
1537 scp_stuffed = FALSE; /* say how we got it */
1538 scp_reading = FALSE;
1539 SetEvent(hCmdReadyEvent); /* notify main thread a line is ready */
1540 }
1541 return 0;
1542 }
1543
1544 char *read_cmdline (char *ptr, int size, FILE *stream)
1545 {
1546 char *cptr;
1547
1548 if (hCmdThread == NULL) { /* set up command-reading thread */
1549 if ((hCmdReadEvent = CreateEvent(NULL, FALSE, FALSE, NULL)) == NULL)
1550 scp_panic("Can't create command line read event");
1551
1552 if ((hCmdReadyEvent = CreateEvent(NULL, FALSE, FALSE, NULL)) == NULL)
1553 scp_panic("Can't create command line ready event");
1554 /* start up the command thread */
1555 if ((hCmdThread = CreateThread(NULL, 0, CmdThread, NULL, 0, &iCmdThreadID)) == NULL)
1556 scp_panic("Unable to create command line reading thread");
1557 }
1558
1559 scp_reading = TRUE;
1560
1561 SetEvent(hCmdReadEvent); /* let read thread get one line */
1562 WaitForSingleObject(hCmdReadyEvent, INFINITE); /* wait for read thread or GUI to respond */
1563 strncpy(ptr, cmdbuffer, MIN(size, sizeof(cmdbuffer))); /* copy line to caller's buffer */
1564
1565 for (cptr = ptr; isspace(*cptr); cptr++) /* absorb spaces */
1566 ;
1567
1568 if (scp_stuffed) { /* stuffed command needs to be echoed */
1569 printf("%s\n", cptr);
1570 if (sim_log) fprintf(sim_log, "%s\n", cptr);
1571 }
1572
1573 return cptr;
1574 }
1575
1576 /* stuff_cmd - force a command into the read_cmdline output buffer. Called asynchronously by GUI */
1577
1578 void stuff_cmd (char *cmd)
1579 {
1580 strcpy(cmdbuffer, cmd); /* save the string */
1581 scp_stuffed = TRUE; /* note where it came from */
1582 scp_reading = FALSE;
1583 ResetEvent(hCmdReadEvent); /* clear read request event */
1584 SetEvent(hCmdReadyEvent); /* notify main thread a line is ready */
1585 }
1586
1587 /* my_yield - process GUI messages. It's not apparent why stuff_and_wait would block,
1588 * since it sleeps in the GUI thread while scp runs in the main thread. However,
1589 * at the end of every command scp calls update_gui, which can result in messages
1590 * being sent to the GUI thread. So, the GUI thread has to process messages while
1591 * stuff_and_wait is waiting.
1592 */
1593 static void my_yield (void)
1594 {
1595 MSG msg;
1596 /* multitask */
1597 while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
1598 TranslateMessage(&msg);
1599 DispatchMessage(&msg);
1600 }
1601 }
1602
1603 /* stuff_and_wait -- stuff a command and wait for the emulator to process the command
1604 * and come back to prompt for another
1605 */
1606
1607 t_bool stuff_and_wait (char *cmd, int timeout, int delay)
1608 {
1609 scp_reading = FALSE;
1610
1611 stuff_cmd(cmd);
1612
1613 while (! scp_reading) {
1614 if (timeout < 0)
1615 return FALSE;
1616
1617 my_yield();
1618 if (scp_reading)
1619 break;
1620
1621 Sleep(50);
1622 if (timeout)
1623 if ((timeout -= 50) <= 0)
1624 timeout = -1;
1625
1626 my_yield();
1627 }
1628
1629 if (delay)
1630 Sleep(delay);
1631
1632 return TRUE;
1633 }
1634
1635 /* remark_cmd - print a remark from inside a command processor. This routine takes
1636 * into account the possiblity that the command might have been stuffed, in which
1637 * case the sim> prompt needs to be reprinted.
1638 */
1639
1640 void remark_cmd (char *remark)
1641 {
1642 if (scp_reading) {
1643 putchar('\n');
1644 if (sim_log) putc('\n', sim_log);
1645 }
1646
1647 printf("%s\n", remark);
1648 if (sim_log) fprintf(sim_log, "%s\n", remark);
1649
1650 if (scp_reading) {
1651 printf("sim> ");
1652 if (sim_log) fprintf(sim_log, "sim> ");
1653 }
1654 }
1655
1656 #endif /* _WIN32 defined */
1657 #endif /* GUI_SUPPORT defined */