· 6 years ago · Apr 22, 2019, 09:32 AM
1/*
2** GP142.c by Neil McKenzie
3**
4** RCS $Id: gp142.c,v 1.17 2000/07/17 22:33:50 boren Exp $
5**
6** Copyright (C) 1994 Neil McKenzie. All rights reserved.
7**
8** Copyright (c) 1994 Corey Anderson.
9**
10** Copyright (c) 1995 Casey Anderson.
11** Revised version 1.5 of October, 1994
12** Revised version 1.61 of December, 1994
13** Revised version 2.00 of January, 1995
14** conversion from callback fns to await_event
15** Revised version 2.01 of July, 1995
16** fixed hotkeys in windows
17** Revised version 2.1 of October, 1995
18** transparent text in windows; float pragma; casts;
19** animation based on wall time elapsed
20** "Fixed" PC window size problem, see FUDGE, below -- brd
21** Includes changes made for port to WIN32 by Shuichi Koga
22** All additions ifdefed by WIN32 -- brd
23**
24** Revised version 2.2 on July, 1997
25** X11R6 Melissa Johnson mjhnsn@u.washington.edu
26** Assembly timer code for Mac replaced with C-based code. (Corey)
27** Removed stack of objects. Replaced with offscreen buffer.
28** Dramatically improves animation quality. (Josh, Melissa, Corey)
29** Set GP142_DATE to indicate when GP142 was last _updated_, not
30** merely last compiled. (Corey)
31**
32** Revised version 2.2.1 of February, 1998
33** Fixed autoKey/GP142_PERIODIC conflict for Mac,
34** and did some cleanup in Mac event handling code (Daniel)
35**
36** Revised February 4, 2000, Dan Boren boren@cs.washington.edu
37** Fixed Windows version of the text window. Implemented double
38** buffering to fix severe redraw bugs.
39**
40** Revised February 4, 2000, Dan Boren boren@cs.washington.edu
41** Minor change to Windows version of GP142_open() -- removed
42** extraneous comma
43**
44** Revised February, 2000, Dan Boren boren@cs.washington.edu
45** Changed Windows message handling in YeildToSystem(). Changed
46** PeekMessage() to GetMessage() in order to reduce CPU usage
47** that was at 100% with PeekMessage().
48**
49** Revised May, 2000, R. Dunn & L. Ruzzo
50** added getDimensions functions to get height/width of text strings.
51**
52** Revised May, 2000 Dan Boren boren@cs.washington.edu
53** Used Shuichi's handling of WinMain/main().
54** Fixed memory leak in DrawTextWnd().
55**
56*/
57
58#include "gp142lib.h" /* Library specific header */
59#define GP142_RCSREV "$Revision: 1.17 $"
60#define GP142_RCSDATE "$Date"
61#define GP142_VERSION "2.2xx"
62#define GP142_DATE "April 2000"
63
64#define TIME_PER_STEP 50
65#define MAXSTRLEN 200 /* max string length for text fns */
66#define UNUSED(parameter) (parameter = parameter)
67
68#if defined(WINDOWS)
69#define GP142_FUNC FAR EXPORT
70#define FUDGE 40 /* On the PC, the window is off by 40 pixels in the */
71 /* Y dimension. Until we find a general fix, we're */
72 /* stuck with this hack. -- brd */
73#elif defined(MACINTOSH)
74#define GP142_FUNC
75#elif defined(X11R6)
76#define GP142_FUNC
77#endif
78
79/* Don't use assembly instructions if we can avoid it. */
80#define USE_ASM_FOR_TIMER 0
81
82
83/************************************************************* global variables ****/
84/* for double buffering. Redraw if true - josh */
85static int need_redraw = 1;
86
87#ifdef MACINTOSH
88
89#if USE_ASM_FOR_TIMER
90typedef struct {
91 TMTask atmTask;
92 long tmWakeUp;
93 long tmReserved;
94 long tmRefCon;
95} TMInfo, *TMInfoPtr;
96
97TMInfo gMyTMInfo;
98#endif
99
100Rect dragRect = { 0, 0, 1024, 1024 };
101Rect winrect = { 50, 20, 50+2*GP142_YMAX+1, 20+2*GP142_XMAX+1 };
102
103RGBColor gRGBColors[MAX_COLORS] = {
104 /* Black used to be 0x1000, 0x1000, 0x1000. Why??? */
105 { 0x0000, 0x0000, 0x0000 }, /* black */
106 { 0xFFFF, 0xFFFF, 0xFFFF }, /* white */
107 { 0xFFFF, 0x0000, 0x0000 }, /* red */
108 { 0x0000, 0xFFFF, 0x0000 }, /* green */
109 { 0x0000, 0x0000, 0xFFFF }, /* blue */
110 { 0xFFFF, 0xFFFF, 0x0000 }, /* yellow */
111 { 0xFFFF, 0x0000, 0xFFFF }, /* magenta */
112 { 0x0000, 0xFFFF, 0xFFFF }, /* cyan */
113 { 0x9999, 0x0000, 0xCCCC }, /* purple */
114 { 0x0000, 0x3333, 0x9999 }, /* navy blue */
115 { 0x9999, 0x6666, 0x9999 }, /* dusty plum */
116 { 0x9999, 0xFFFF, 0xFFFF }, /* ice blue */
117 { 0x9999, 0xFFFF, 0xCCCC }, /* turquoise */
118 { 0xFFFF, 0x6666, 0x0000 }, /* orange */
119 { 0x9999, 0x6666, 0x3333 }, /* brown */
120 { 0xFFFF, 0x9999, 0xCCCC }, /* pink */
121 { 0xFFFF, 0xFFFF, 0x9999 }, /* chalk */
122 { 0xCCCC, 0x9999, 0x3333 }, /* gold */
123 { 0xFFFF, 0x9999, 0x6666 }, /* peach */
124 { 0x0000, 0x6666, 0x3333 }, /* forest green */
125 { 0x3333, 0xCCCC, 0x9999 }, /* sea green */
126 { 0x9999, 0x9999, 0x3333 }, /* olive */
127 { 0x8000, 0x8000, 0x8000 }, /* 50% gray */
128 { 0xCCCC, 0xCCCC, 0xCCCC } /* 20% gray -- 80% white */
129};
130
131enum {
132 mAniRun = 1,
133 mAniHalt,
134 mAniSingle,
135 mLog = 5,
136 mScriptRecord = 7,
137 mScriptPlay,
138 mScriptOne,
139 mQuit = 11};
140
141char Menu_String[] = "\p"
142 "Animate/A;"
143 "Halt animation/H;"
144 "Advance one frame/F;"
145 "(-;"
146 "Logging/L;"
147 "(-;"
148 "Record " kScriptName "/R;"
149 "Playback " kScriptName "/P;"
150 "Playback one event/O;"
151 "(-;"
152 "Quit/Q;"
153 "(-;"
154 "(GP142 v" GP142_VERSION " " GP142_DATE ";"
155 "(mckenzie@cs.washington.edu;"
156 "(corin@cs.washington.edu;"
157 "(casey@cs.washington.edu"
158 ;
159
160MenuHandle RunMenu, DeskMenu;
161CWindowPtr gpWin = (CWindowPtr) 0;
162
163/* The offscreen GWorld where the GP142 graphics are rendered. */
164GWorldPtr gGP142World = NULL;
165
166char gColorFlag = 1; /* true if the target Mac runs color Quickdraw */
167PixPatHandle color_pp[MAX_COLORS];
168
169
170int nrows = 32;
171int ncols = 50;
172
173#elif defined(WINDOWS)
174
175
176/* Structure used to keep around variables we need for initialization,
177 * but the user shouldn't have to see.
178 */
179typedef struct {
180 HINSTANCE hInstance, hPrevInstance;
181 LPSTR lpCmdLine;
182 int nShowCmd;
183} GP142Globals;
184
185/* Only one item of type Global needs to exist. */
186static GP142Globals global;
187
188/* We need to state that there exists a main() apriori. */
189void main();
190
191
192HWND hDrawWnd = (HWND)NULL; /* handles to 2 windows in application */
193HWND hTextWnd = (HWND)NULL;
194HMENU hRunMenu; /* handle to menu */
195HINSTANCE hInst; /* Instance handle to this library */
196
197/* need some stuff for double buffering - josh */
198HBITMAP offscreen_bitmap;
199HDC offscreen_DC, the_hdc;
200
201/* Display context for text window */
202HDC text_hdc;
203
204/* Handle to ring buffer for debug statements. We save the last
205MAX_CONOLE_LINES lines from the debuf window, so we can redraw them when
206the text window receives a WM_PAINT message */
207HANDLE gConsoleLines[MAX_CONSOLE_LINES];
208int gRingFirst = -1; /* -1 indicates that the ring buffer is empty */
209int gRingLast = 0; /* last is the next available position */
210#define RING_INC(i) (i = (i==MAX_CONSOLE_LINES-1)?0:i+1)
211
212COLORREF gRGBColors[MAX_COLORS] = {
213 RGB(0x00, 0x00, 0x00), /* black */
214 RGB(0xFF, 0xFF, 0xFF), /* white */
215 RGB(0xFF, 0x00, 0x00), /* red */
216 RGB(0x00, 0xFF, 0x00), /* green */
217 RGB(0x00, 0x00, 0xFF), /* blue */
218 RGB(0xFF, 0xFF, 0x00), /* yellow */
219 RGB(0xFF, 0x00, 0xFF), /* magenta */
220 RGB(0x00, 0xFF, 0xFF), /* cyan */
221 RGB(0x99, 0x00, 0xCC), /* purple */
222 RGB(0x00, 0x33, 0x99), /* navy blue */
223 RGB(0x99, 0x66, 0x99), /* dusty plum */
224 RGB(0x99, 0xFF, 0xFF), /* ice blue */
225 RGB(0x99, 0xFF, 0xCC), /* turquoise */
226 RGB(0xFF, 0x66, 0x00), /* orange */
227 RGB(0x99, 0x66, 0x33), /* brown */
228 RGB(0xFF, 0x99, 0xCC), /* pink */
229 RGB(0xFF, 0xFF, 0x99), /* chalk */
230 RGB(0xCC, 0x99, 0x33), /* gold */
231 RGB(0xFF, 0x99, 0x66), /* peach */
232 RGB(0x00, 0x66, 0x33), /* forest green */
233 RGB(0x33, 0xCC, 0x99), /* sea green */
234 RGB(0x99, 0x99, 0x33), /* olive */
235 RGB(0x80, 0x80, 0x80), /* 50% gray */
236 RGB(0xCC, 0xCC, 0xCC) /* 20% gray -- 80% white */
237};
238
239#elif defined(X11R6)
240
241#define MAX_FONTS 7
242
243Display *display;
244int screen;
245char *prog_name;
246Window window;
247Window wincomm;
248Window winc[8];
249GC gc;
250GC gccon;
251FontDB* font_info;
252FontDB* current_font;
253XColor color_ids[MAX_COLORS];
254int current_color_id;
255
256/* for double-buffering - josh */
257Pixmap offscreen_buffer;
258
259RGBColor gRGBColors[MAX_COLORS] = {
260 { 0x1000, 0x1000, 0x1000 }, /* black */
261 { 0xFFFF, 0xFFFF, 0xFFFF }, /* white */
262 { 0xFFFF, 0x0000, 0x0000 }, /* red */
263 { 0x0000, 0xFFFF, 0x0000 }, /* green */
264 { 0x0000, 0x0000, 0xFFFF }, /* blue */
265 { 0xFFFF, 0xFFFF, 0x0000 }, /* yellow */
266 { 0xFFFF, 0x0000, 0xFFFF }, /* magenta */
267 { 0x0000, 0xFFFF, 0xFFFF }, /* cyan */
268 { 0x9999, 0x0000, 0xCCCC }, /* purple */
269 { 0x0000, 0x3333, 0x9999 }, /* navy blue */
270 { 0x9999, 0x6666, 0x9999 }, /* dusty plum */
271 { 0x9999, 0xFFFF, 0xFFFF }, /* ice blue */
272 { 0x9999, 0xFFFF, 0xCCCC }, /* turquoise */
273 { 0xFFFF, 0x6666, 0x0000 }, /* orange */
274 { 0x9999, 0x6666, 0x3333 }, /* brown */
275 { 0xFFFF, 0x9999, 0xCCCC }, /* pink */
276 { 0xFFFF, 0xFFFF, 0x9999 }, /* chalk */
277 { 0xCCCC, 0x9999, 0x3333 }, /* gold */
278 { 0xFFFF, 0x9999, 0x6666 }, /* peach */
279 { 0x0000, 0x6666, 0x3333 }, /* forest green */
280 { 0x3333, 0xCCCC, 0x9999 }, /* sea green */
281 { 0x9999, 0x9999, 0x3333 }, /* olive */
282 { 0x8000, 0x8000, 0x8000 }, /* 50% gray */
283 { 0xCCCC, 0xCCCC, 0xCCCC } /* 20% gray -- 80% white */
284};
285
286#endif
287
288static char *gColorName[MAX_COLORS] = {
289 "black",
290 "white",
291 "red",
292 "green",
293 "blue",
294 "yellow",
295 "magenta",
296 "cyan",
297 "purple",
298 "navy blue",
299 "dusty plum",
300 "ice blue",
301 "turquoise",
302 "orange",
303 "brown",
304 "pink",
305 "chalk",
306 "gold",
307 "peach",
308 "forest green",
309 "sea green",
310 "olive",
311 "50% gray",
312 "20% gray"
313};
314
315
316static int gEventAction;
317static GP142_event_t gEventRecord;
318
319/* control flags */
320static char gRunFlag; /* Running animation? */
321static char gSingleStepFlag; /* Single stepping animation? */
322static char gDoneFlag; /* Program concluded? */
323static char gLogging = LOG_ON; /* Log actions to console? */
324static char gRecordingFlag = FALSE; /* Recording user actions for later playback? */
325static char gScriptStepFlag = FALSE; /* Playback one action? */
326static char gScriptPlayFlag = FALSE; /* Continuously playback actions? */
327static int gAnimExpired = FALSE;
328
329/* scripting */
330static FILE *gScriptFP = NULL; /* file pointer to script file (in or out); NULL if not open */
331static int gTaskCount = 0; /* number of consecutive calls to GP142_user_task */
332
333static int gXCenter, gYCenter;
334
335
336/********************************************************* Library Initialization ***/
337#ifdef MACINTOSH
338
339#if USE_ASM_FOR_TIMER
340
341#ifndef __MWERKS__
342
343void timerFlagProc(void)
344{
345 long oldA5;
346 TMInfoPtr recPtr;
347
348 asm { /* The time manager puts the address */
349 move.l a1, recPtr /* of the expired timer in register a1*/
350 }
351
352 oldA5 = SetA5(recPtr->tmRefCon); /* This is so we can touch the global */
353 /* variables of GP142 app*/
354
355 gAnimExpired = TRUE;
356
357 oldA5 = SetA5(oldA5); /* Change global variable start address */
358 /* back to what it was*/
359
360 PrimeTime((QElemPtr)recPtr, TIME_PER_STEP); /* Reprime the timer for another */
361 /* .1 seconds */
362}
363
364#else /* __MWERKS__ */
365
366/*
367** Metrowerks supports asm only for entire functions.
368** This func is equiv to the preceding one:
369** Save A5; restore GP142's A5 from timer record;
370** set global flag; restore A5; requeue timer record.
371** WLR 2/96. Thanks to MAC.
372*/
373static asm void timerFlagProc(void)
374{
375 move.l A5, A0
376 move.l struct(TMInfo_s.tmRefCon)(A1), A5
377 move.w #1, gAnimExpired
378 move.l A0, A5
379 move.l A1, A0
380 move.l #TIME_PER_STEP, D0
381 _PrimeTime
382 rts
383}
384#endif
385
386#endif /* USE_ASM_FOR_TIMER */
387
388extern int GP142_open(void) /* was GP142_main() in GP142 v1.x */
389{
390 int console_flag = /* 0 for either defers opening */
391 nrows!=0 && ncols!=0 ; /* console, but leaves default size. */
392
393 ToolboxInit(); /* Initialize the Mac toolbox */
394#ifdef __MWERKS__
395 if (nrows) SIOUXSettings.rows = nrows;
396 if (ncols) SIOUXSettings.columns= ncols;
397 SIOUXSettings.initializeTB = 0; /* Do we initialize the ToolBox ... */
398 SIOUXSettings.setupmenus = 0; /* Do we draw the SIOUX menus ... */
399 SIOUXSettings.autocloseonquit = 1; /* Do we close the SIOUX window on program termination ... */
400 SIOUXSettings.asktosaveonclose = 0; /* Do we offer to save on a close ... */
401 SIOUXSettings.toppixel = 40; /* The topleft window position (in pixels) */
402 SIOUXSettings.leftpixel = 2; /* (0,0 centers on main screen) ... */
403#else
404 if (nrows) console_options.nrows = nrows;
405 if (ncols) console_options.ncols = ncols;
406#endif
407 if ( console_flag ) { /* don't open console unnecessarily */
408 printf("GP142 graphics package version " GP142_VERSION " (" GP142_DATE ")\n");
409 printf("This is the console window\n");
410 if (!gColorFlag) {
411 printf("This Macintosh does not have Color Quickdraw.\n");
412 printf("All objects will be drawn using black.\n");
413 }
414 }
415
416
417/*Here we initialize a timer, add it to the queue, and prime it*/
418#if USE_ASM_FOR_TIMER
419 gMyTMInfo.atmTask.tmAddr = (TimerUPP)timerFlagProc;
420 gMyTMInfo.tmRefCon = SetCurrentA5(); /* This is so we can access */
421 /* the Global variables later */
422 gMyTMInfo.tmWakeUp = 0;
423 gMyTMInfo.tmReserved = 0;
424 InsTime((QElemPtr)&gMyTMInfo);
425 PrimeTime((QElemPtr)&gMyTMInfo, TIME_PER_STEP);
426#endif
427
428 SelectWindow((void *)gpWin); /* Better to do it once here than every time */
429 /* through the event loop -dia */
430 return GP142_SUCCESS;
431}
432
433/* Initialize Mac stuff */
434static void ToolboxInit(void)
435{
436 int i;
437 long myFeature;
438 Rect r;
439
440#if USES_NEW_HEADERS
441 InitGraf(&qd.thePort);
442#else
443 InitGraf(&thePort);
444#endif
445 InitFonts();
446 InitWindows();
447 InitCursor();
448 InitDialogs(0);
449 TEInit();
450 InitMenus();
451 FlushEvents( everyEvent, 0 );
452
453 /* Desk Accessory menu */
454 DeskMenu = NewMenu(Desk_ID,"\p\024");
455#if USES_NEW_HEADERS
456 AppendResMenu(DeskMenu, 'DRVR');
457#else
458 AddResMenu(DeskMenu, 'DRVR');
459#endif
460 InsertMenu(DeskMenu, 0);
461
462 /* Run menu */
463 RunMenu = NewMenu(Run_ID, "\pRun");
464 AppendMenu(RunMenu, (ConstStr255Param)Menu_String);
465 InsertMenu(RunMenu, 0);
466 CheckItem(RunMenu, 4, (int)gLogging);
467
468 /* Let's see if we can use COLOR */
469 Gestalt(gestaltQuickdrawVersion, &myFeature);
470 if (myFeature < gestalt8BitQD) {
471 gColorFlag = 0;
472 }
473
474 /* Create the window */
475 DrawMenuBar();
476 if (gColorFlag)
477 gpWin = (CWindowPtr) NewCWindow(0,&winrect,"\pGP142 Graphics Window",
478 1,0,(void *)(-1),1,0);
479 else
480 gpWin = (CWindowPtr) NewWindow(0,&winrect,"\pGP142 Graphics Window",
481 1,0,(void *)(-1),1,0);
482
483 gRunFlag = 0;
484 gDoneFlag = 0;
485 gSingleStepFlag = 0;
486
487 /* Make some colors */
488 if (gColorFlag) {
489 for (i=0; i<MAX_COLORS; i++) {
490 color_pp[i] = NewPixPat();
491 MakeRGBPat(color_pp[i], &gRGBColors[i]);
492 }
493 }
494
495 /* Find the offset to the center of the window */
496 gXCenter = (winrect.right - winrect.left) >> 1;
497 gYCenter = (winrect.bottom - winrect.top) >> 1;
498
499 /* Create the offscreen GWorld into which we will render out GP142
500 objects */
501 SetRect(&r, 0, 0, 2*GP142_XMAX+1, 2*GP142_YMAX+1);
502 if (noErr != NewGWorld(&gGP142World, /* The returned offscreen world */
503 8, /* bits per pixel */
504 &r, /* size of buffer */
505 nil, /* Color table. Use the default. */
506 nil, /* I forget why this is nil... */
507 0)) { /* Don't need any flags */
508 SysBeep(10);
509 ExitToShell();
510 return;
511 }
512}
513
514#elif defined(WINDOWS)
515
516/*
517 * Hide the four global variables from the user, permitting them to simply
518 * define a main() function. (idea by Shuichi Koga, implemented by Dan Boren).
519 */
520PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
521{
522 global.hInstance = hInstance;
523 global.hPrevInstance = hPrevInstance;
524 global.lpCmdLine = lpCmdLine;
525 global.nShowCmd = nShowCmd;
526
527 main();
528}
529
530
531void _GP142_pseudocall(void)
532{
533 int a,x,y;
534 char c='a';
535 GP142_point p = {0,0};
536 GP142_event_t t = {0, 0, 0};
537 x = y =a = 0;
538 if (a*a) /* we won't actually call these functions
539 a trick to get rid of compiler warnings */
540 {
541 GP142_clear();
542 GP142_undo();
543 GP142_logging(LOG_OFF);
544 GP142_animate(ANI_HALT);
545 GP142_gets(NULL,NULL);
546 GP142_pixelXY(0,0,0);
547 GP142_lineXY(0,0,0,0,0,0);
548 GP142_rectangleXY(0,0,0,0,0,0);
549 GP142_triangleXY(0,0,0,0,0,0,0,0);
550 GP142_ovalXY(0,0,0,0,0,0);
551 GP142_circleXY(0,0,0,0);
552 GP142_printfXY(0,0,0,0,NULL);
553 GP142_textXY(0,0,0,0,NULL);
554 GP142_await_eventP((GP142_event_t*)NULL);
555 GP142_pixelP(0,p);
556 GP142_lineP(0,p,p,0);
557 GP142_rectangleP(0,p,p,0);
558 GP142_triangleP(0,p,p,p,0);
559 GP142_ovalP(0,p,p,0);
560 GP142_circleP(0,p,0);
561 GP142_printfP(0,p,0,NULL);
562 GP142_textP(0,p,0,NULL);
563 GP142_close();
564 GP142_await_event(&x,&y,&c);
565 PlayFromScript();
566 CloseScript();
567 SaveToScript(0,t);
568 }
569}
570
571extern int GP142_FUNC GP142_open()
572/*GP142_open(HANDLE hInstance, HANDLE hPrevInstance,
573 LPSTR lpszCmdLine, int nCmdShow)*/
574
575
576{
577 WNDCLASS wc;
578 int x, y;
579 /* BOOL done = FALSE; */
580
581 _GP142_pseudocall(); /* let the compiler think all
582 GP142 functions have been
583 called */
584 UNUSED(global.lpCmdLine);
585
586 /************ register window classes ****************/
587 if (!global.hPrevInstance) /* initialize window classes when first run */
588 {
589 /* first, register the graphics window class */
590 wc.hInstance = global.hInstance;
591 wc.hIcon = LoadIcon((HINSTANCE)NULL, IDI_APPLICATION);
592 wc.hCursor = LoadCursor((HINSTANCE)NULL, IDC_ARROW);
593 wc.lpszMenuName = "generic";
594 wc.style = CS_HREDRAW | CS_VREDRAW;
595 wc.cbClsExtra = 0;
596 wc.cbWndExtra = 0;
597 wc.lpfnWndProc = (WNDPROC) DrawWndProc;
598 wc.hbrBackground = CreateSolidBrush(gRGBColors[BKGND_COLOR]),
599 wc.lpszClassName = "DrawWndClass";
600 RegisterClass(&wc);
601
602 /* now, register the text window, child of draw */
603 wc.style = CS_HREDRAW | CS_VREDRAW;
604 wc.lpfnWndProc = (WNDPROC)TextWndProc;
605 wc.lpszClassName = "TextWndClass";
606 RegisterClass(&wc);
607 }
608
609
610 /************* Initialize global variables *******************/
611 x = GetSystemMetrics(SM_CXSCREEN);
612 y = GetSystemMetrics(SM_CYSCREEN);
613 gRunFlag = FALSE;
614 gSingleStepFlag = FALSE;
615
616 /************ Create windows ***************/
617 /* Create our two windows: first graphics, then text */
618 hDrawWnd = CreateWindow("DrawWndClass",
619 "ABC", /* Title of window */
620 WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_BORDER, /* window style */
621 0, /* position in upper left */
622 0,
623 2*GP142_XMAX+1, /* pixels horz.*/
624 2*GP142_YMAX+FUDGE, /* pixels vert.*/
625 (HWND)NULL, /* draw has no parent */
626 (HMENU)NULL, /* use class menu */
627 global.hInstance, /* instance of program */
628 NULL); /* NULL window data */
629 hTextWnd = CreateWindow(
630 "TextWndClass", /* window class name */
631 "GP142 Text", /* Title of window */
632 WS_OVERLAPPEDWINDOW,
633 0, /* all the way to the left */
634 2*GP142_YMAX+FUDGE+10, /* make it abut draw window */
635 2*GP142_XMAX+1,/* x,*/ /* same width as draw window */
636 y/4, /* 1/4 maximum height */
637 (HWND)NULL, /* Text has no parent */
638 (HMENU)NULL, /* no menu */
639 global.hInstance, /* instance of program */
640 NULL); /* NULL window data */
641 SetWindowText(hDrawWnd, TEXT("Paint Brush"));
642 hInst = global.hInstance;
643
644
645 /* init the double-buffer windows - josh */
646 the_hdc = GetDC(hDrawWnd);
647 offscreen_bitmap = CreateCompatibleBitmap(the_hdc, 2*GP142_XMAX+1, 2*GP142_YMAX+FUDGE);
648 offscreen_DC = CreateCompatibleDC(the_hdc);
649 SelectObject (offscreen_DC, offscreen_bitmap);
650
651 ShowWindow(hTextWnd, global.nShowCmd);
652 ShowWindow(hDrawWnd, global.nShowCmd);
653
654 SetTimer(hDrawWnd, 2, TIME_PER_STEP, NULL);
655
656 return GP142_SUCCESS;
657}
658
659#elif defined(X11R6)
660
661void create_GC(Window window, GC *gc, int fid) {
662
663 XGCValues gc_val;
664
665 *gc = XCreateGC(display, window, 0, &gc_val);
666 XSetFont(display, *gc, fid);
667
668 XSetForeground(display, *gc, color_ids[2].pixel);
669 XSetLineAttributes(display, *gc, 3, LineSolid, CapRound, JoinRound);
670 return;
671}
672
673extern int GP142_open(void) {
674
675 char *win_name = "GP142 Graphics Window";
676 char *win_name_comm = "GP142 Control Window";
677 char *icon_name = "GP142";
678 char *icon_name_comm = "GP142 Controls";
679 char *display_name = NULL;
680 int i;
681 unsigned int border_width = 2;
682 XSizeHints *size_hint;
683 XWMHints *wm_hint;
684 XClassHint *class_hint;
685 XTextProperty WinNameComm, WinName, IconNameComm, IconName;
686 Window dummy_win;
687 int dummy_x, dummy_y;
688 unsigned int dummy_width, dummy_height, dummy_border, depth;
689 prog_name = "GP142";
690
691 if (!(size_hint = XAllocSizeHints()) || !(wm_hint = XAllocWMHints())
692 || !(class_hint = XAllocClassHint())
693 || (display = XOpenDisplay (display_name)) == NULL) {
694 fprintf(stderr, "%s: Unable to open X display %s.\n", prog_name,
695 XDisplayName(display_name));
696 exit(0);
697 }
698
699 screen = DefaultScreen(display);
700
701 window = XCreateSimpleWindow(display, RootWindow(display, screen), 10,
702 10, GP142_XMAX*2, GP142_YMAX*2, border_width,
703 BlackPixel(display, screen), WhitePixel(display, screen));
704 wincomm = XCreateSimpleWindow(display, RootWindow(display, screen), 50,
705 50, 200, 105, border_width, BlackPixel(display, screen),
706 WhitePixel(display, screen));
707 /* double buffering - josh */
708 XGetGeometry(display, window, &dummy_win, &dummy_x, &dummy_y, &dummy_width, &dummy_height,
709 &dummy_border, &depth);
710 offscreen_buffer = XCreatePixmap(display, window, GP142_XMAX*2, GP142_YMAX*2, depth);
711
712 gXCenter = GP142_XMAX;
713 gYCenter = GP142_YMAX;
714
715/***TODO***/
716 if (XStringListToTextProperty(&win_name, 1, &WinName) == 0) {
717 fprintf(stderr, "\n%s: Ow.\n\n", prog_name);
718 exit(0);
719 }
720
721 if (XStringListToTextProperty(&icon_name, 1, &IconName) == 0) {
722 fprintf(stderr, "\n%s: Ow.\n\n", prog_name);
723 exit(0);
724 }
725
726 if (XStringListToTextProperty(&win_name_comm, 1, &WinNameComm) == 0) {
727 fprintf(stderr, "\n%s: Ow.\n\n", prog_name);
728 exit(0);
729 }
730
731 if (XStringListToTextProperty(&icon_name_comm, 1, &IconNameComm) == 0) {
732 fprintf(stderr, "\n%s: Ow.\n\n", prog_name);
733 exit(0);
734 }
735
736 gRunFlag = 0;
737 gDoneFlag = 0;
738 gSingleStepFlag = 0;
739
740 /* size hints to keep windows size from changing */
741
742 size_hint -> flags = PSize | PPosition | PMinSize | PMaxSize;
743 size_hint -> min_width = 600;
744 size_hint -> min_height = 500;
745 size_hint -> max_width = 600;
746 size_hint -> max_height = 500;
747 wm_hint -> flags = StateHint | InputHint;
748 wm_hint -> input = True;
749 wm_hint -> initial_state = NormalState;
750 class_hint -> res_name = prog_name;
751 class_hint -> res_class = prog_name;
752 XSetWMProperties(display, window, &WinName, &IconName, 0, 0,
753 size_hint, wm_hint, class_hint);
754
755 size_hint -> min_width = 200;
756 size_hint -> min_height = 105;
757 size_hint -> max_width = 200;
758 size_hint -> max_height = 105;
759 XSetWMProperties(display, wincomm, &WinNameComm, &IconNameComm, 0, 0,
760 size_hint, wm_hint, class_hint);
761
762 XSelectInput(display, window, StructureNotifyMask | ExposureMask |
763 KeyPressMask | ButtonPressMask | EnterWindowMask | LeaveWindowMask);
764 XSelectInput(display, wincomm, StructureNotifyMask | ExposureMask |
765 KeyPressMask | ButtonPressMask | EnterWindowMask | LeaveWindowMask);
766
767 font_info = (FontDB*) malloc (sizeof(FontDB));
768 if ((font_info == NULL) ||
769 (font_info->thefont = XLoadQueryFont(display,
770 "-adobe-times-medium-r-normal--0-150-75-75-p-0-iso8859-1"))
771 == NULL) {
772 fprintf(stderr, "Cannot open adobe-times scalable font.\n\n");
773 exit(0);
774 }
775 font_info -> point_size = 15;
776 font_info -> next = NULL;
777 current_font = font_info;
778
779 for (i = 0; i < MAX_COLORS; i++) {
780 color_ids[i].red = gRGBColors[i].red;
781 color_ids[i].green = gRGBColors[i].green;
782 color_ids[i].blue = gRGBColors[i].blue;
783 color_ids[i].flags = DoRed | DoGreen | DoBlue;
784 XAllocColor(display, DefaultColormap(display, screen), &color_ids[i]);
785 }
786
787 current_color_id = 2;
788
789 create_GC(window, &gc, font_info->thefont->fid);
790 create_GC(window, &gccon, font_info->thefont->fid);
791 XSetForeground(display, gccon, BlackPixel(display, screen));
792
793 XMapWindow(display, window);
794 XMapWindow(display, wincomm);
795
796 for (i = 0; i < 8; i++) {
797 winc[i] = XCreateSimpleWindow(display, wincomm, (i / 4) * 100,
798 ((i % 4) * 25) + 5, 95, 20, 2, BlackPixel(display,
799 screen), WhitePixel(display, screen));
800 XSelectInput(display, winc[i], StructureNotifyMask | ExposureMask |
801 KeyPressMask | ButtonPressMask | EnterWindowMask | LeaveWindowMask);
802 XMapWindow(display,winc[i]);
803 }
804
805 /* We must be open and waiting for drawing commands at this
806 * point. However, X does not guarantee this until we receive the first
807 * XExpose event
808 */
809
810 while(1)
811 {
812 XEvent event;
813 XNextEvent(display, &event);
814 if(event.type == Expose)
815 if (event.xany.window == window)
816 break;
817 else
818 Process_event(event);
819 }
820
821 return GP142_SUCCESS;
822}
823#endif
824
825
826/************************************************************** Library Closure ***/
827#ifdef MACINTOSH
828extern int GP142_close(void)
829{
830#if USE_ASM_FOR_TIMER
831 /* Remove the timer entry from the queue*/
832 RmvTime((QElemPtr)&gMyTMInfo);
833#endif
834
835 /* Is there anything we should do here? */
836 CloseScript();
837
838 return GP142_SUCCESS;
839}
840
841#elif defined (WINDOWS)
842/* Windows Exit Procedure */
843int FAR PASCAL EXPORT WEP (int nParameter)
844{
845 UNUSED(nParameter);
846 return (1);
847}
848
849extern int GP142_FUNC
850GP142_close(void)
851{
852 /* Free the memory used by our offscreen graphics world */
853 ReleaseDC(hDrawWnd, the_hdc);
854 CloseScript();
855
856 return GP142_SUCCESS;
857}
858
859#elif defined(X11R6)
860
861extern int GP142_close(void) {
862
863 CloseScript();
864 while (font_info) {
865 FontDB* temp;
866 XUnloadFont(display, font_info -> thefont -> fid);
867 temp = font_info;
868 font_info = font_info -> next;
869 free(temp); /* no need to free memory at the end of the program
870 * but do it anyway */
871 }
872
873 XFreeGC(display, gc);
874 XCloseDisplay(display);
875
876 return GP142_SUCCESS;
877
878}
879
880#endif
881
882
883
884/******************************************************* Event Handling ***/
885/* Concept: Students will call GP142_await_event() in their own event loop,
886 and handle the returned value accordingly. Possible return values are
887 GP142_MOUSE, GP142_KBD, GP142_SK, and GP142_QUIT */
888
889/*********************************************************** GP142_await_event()
890*/
891extern int GP142_FUNC
892GP142_await_event(int *x, int *y, char *c)
893{
894 GP142_event_t e;
895 int a;
896
897 a = GP142_await_eventP(&e);
898
899 *x = e.x;
900 *y = e.y;
901 *c = e.c;
902
903 return a;
904}
905
906extern int GP142_FUNC
907GP142_await_eventP(GP142_event_t *e)
908{
909 int eventCounter;
910#ifdef WINDOWS
911 BOOL done = FALSE;
912#endif
913
914 /* GP142_await_event() should return only with a message that student
915 might want to handle. That is, only with mouse, keyboard,
916 idle, or quit messages. If we're in animiate mode, we'll pass
917 an idle event after handleing MAX_EVENTS events (or if some
918 user interaction occurs). Otherwise, we won't return until the
919 user does some action. */
920
921 gEventAction = GP142_NONE;
922 gEventRecord.x = gEventRecord.y = gEventRecord.c = 0;
923
924 eventCounter = 0;
925 while ( gEventAction == GP142_NONE ||
926 (gEventAction == GP142_PERIODIC && gAnimExpired == FALSE))
927 {
928 eventCounter = 1;
929 YieldToSystem();
930
931 /* If we're reading from a script file, don't honor user's actions;
932 obey the script instead */
933 if (gScriptStepFlag || gScriptPlayFlag)
934 {
935 gScriptStepFlag = FALSE;
936 /* This will fill in global data */
937 if (PlayFromScript() == GP142_SUCCESS)
938 break;
939 else
940 {
941 gScriptStepFlag = FALSE;
942 gScriptPlayFlag = FALSE;
943 }
944 }
945
946 /* Only pass back a GP142_PERIODIC if we're animating, or
947 single stepping */
948 if ((gSingleStepFlag || gRunFlag) && gEventAction == GP142_NONE)
949 {
950 gEventAction = GP142_PERIODIC;
951 gAnimExpired = FALSE;
952 gSingleStepFlag = FALSE;
953 gScriptStepFlag = FALSE;
954 }
955
956 }
957
958 /* Also, if we're recording to a script, we'll want to save the information */
959 if (gRecordingFlag)
960 {
961 if (gEventAction == GP142_PERIODIC)
962 gTaskCount++;
963 else
964 {
965 if (gTaskCount > 0)
966 {
967 SaveToScript(GP142_PERIODIC, gEventRecord);
968 gTaskCount = 0;
969 }
970 SaveToScript(gEventAction, gEventRecord);
971 }
972 }
973
974 *e = gEventRecord;
975/* UNUSED(done); // there should be a reason we declared
976 // done and eventCounter, just leave them here. */
977 UNUSED(eventCounter);
978 return gDoneFlag?GP142_QUIT:gEventAction;
979}
980
981static void YieldToSystem(void)
982{
983#ifdef MACINTOSH
984 EventRecord event;
985#elif defined(WINDOWS)
986 MSG msg;
987 BOOL done = FALSE;
988#elif defined(X11R6)
989 XEvent event;
990#endif
991
992/* UNUSED(done); */
993#ifdef MACINTOSH
994#if !USE_ASM_FOR_TIMER /* This stuff was moved out of HandleMessage to fix bug */
995 UnsignedWide now; /* concerning autoKey event stopping animation -dia */
996 static UnsignedWide lastExpired = {0,0};
997 unsigned long delta_microseconds;
998
999 /* Has it been long enough since the last animation step? */
1000 Microseconds(&now);
1001
1002 /* Calculate how many microseconds have elapsed since the last time
1003 we set the gAnimExpired flag. */
1004 if (lastExpired.hi == 0 && lastExpired.lo == 0) {
1005 lastExpired = now;
1006 gAnimExpired = TRUE;
1007 } else if (now.hi == lastExpired.hi) {
1008 delta_microseconds = now.lo - lastExpired.lo;
1009 } else if (now.hi == lastExpired.hi + 1) {
1010 delta_microseconds = now.hi + ((unsigned long)(-1) - lastExpired.lo);
1011 } else {
1012 /* It's been a _really_ long time since the last timer overflow. */
1013 delta_microseconds = (unsigned long)(-1);
1014 }
1015
1016 /* !!! The 840 number here is kinda a kludge. TIME_PER_STEP represents
1017 the number of milliseconds between animation steps. Thus, we should
1018 multiply TIME_PER_STEP by 1000 to determine the number of microseconds
1019 between steps. However, I found that doing so didn't give the same time
1020 delay between animation steps as did the original Mac code. So
1021 840 is used, which is pretty close. */
1022 if (delta_microseconds > TIME_PER_STEP * 840) {
1023 gAnimExpired = TRUE;
1024 lastExpired = now;
1025 }
1026#endif
1027/* SelectWindow((void *)gpWin);
1028 GetNextEvent(everyEvent, &event);
1029 SystemTask();*/
1030 if ((!gSingleStepFlag && !gRunFlag) || !gAnimExpired)
1031 {
1032 WaitNextEvent(everyEvent, &event, 1, 0); /* Use WaitNextEvent -dia */
1033 HandleMessage(&event);
1034 }
1035#elif defined(WINDOWS)
1036 /*found_message = PeekMessage(&msg, (HWND)NULL, 0, 0, PM_REMOVE);*/
1037 /* GetMessage() returns 0 if a WM_QUIT message was received */
1038 if (!GetMessage(&msg, (HWND)NULL, 0, 0))
1039 {
1040 gEventAction = GP142_QUIT;
1041 return;
1042 } else {
1043 TranslateMessage(&msg);
1044 DispatchMessage(&msg);
1045 }
1046 if (need_redraw) {
1047 BitBlt (the_hdc,0,0,2*GP142_XMAX+1, 2*GP142_YMAX+FUDGE,
1048 offscreen_DC,0,0,SRCCOPY);
1049 need_redraw = 0;
1050 }
1051#elif defined(X11R6)
1052
1053 if (XPending(display)) {
1054 XNextEvent(display, &event);
1055 Process_event(event);
1056 }
1057 if (need_redraw) {
1058 XCopyArea(display, offscreen_buffer, window, gc, 0, 0, GP142_XMAX*2, GP142_YMAX*2, 0, 0);
1059 XFlush(display);
1060 need_redraw = 0;
1061 }
1062 else {
1063 usleep(30000);
1064 gAnimExpired = TRUE;
1065 }
1066
1067#endif
1068
1069}
1070
1071#ifdef MACINTOSH
1072static void HandleMessage(EventRecord *event)
1073{
1074 short windowcode;
1075 CWindowPtr mouseWindow;
1076 int c;
1077 int console_flag = /* 0 for either defers opening */
1078 nrows!=0 && ncols!=0 ; /* console, but leaves default size. */
1079
1080#ifdef __MWERKS__
1081 /* If we're using the SIOUX console, let it potentially handle an event */
1082 if (SIOUXHandleOneEvent(event))
1083 return;
1084#endif
1085
1086 switch ( event->what )
1087 {
1088 case keyDown:
1089 if ((event->modifiers & cmdKey))
1090 {
1091 DoMenu(MenuKey(event->message));
1092 break;
1093 }
1094 case autoKey:
1095 c = event->message & 0x7f;
1096 if (FrontWindow() == (GrafPtr)gpWin) {
1097 gEventAction = GP142_KBD;
1098 gEventRecord.c = c;
1099 }
1100 break;
1101
1102 case mouseDown:
1103 windowcode = FindWindow(event->where, (void *)&mouseWindow);
1104 switch ( windowcode )
1105 {
1106 case inMenuBar:
1107 DoMenu(MenuSelect(event->where));
1108 break;
1109
1110 case inSysWindow:
1111 SystemClick(event, (void *)mouseWindow);
1112 break;
1113
1114 case inGoAway:
1115 if (TrackGoAway((void *)mouseWindow, event->where))
1116 gEventAction = GP142_QUIT;
1117 break;
1118
1119 case inDrag:
1120 DragWindow( (void *)mouseWindow,
1121 event->where, &dragRect);
1122 break;
1123
1124 case inGrow:
1125 case inContent:
1126 if (mouseWindow != (CWindowPtr) FrontWindow())
1127 {
1128 SelectWindow((void *)mouseWindow);
1129 WaitMouseUp();
1130 }
1131 else
1132 {
1133 DoMouseClick(event, mouseWindow);
1134 }
1135 break;
1136 }
1137 break;
1138
1139 case activateEvt:
1140 break;
1141
1142 case updateEvt:
1143 BeginUpdate((void *)gpWin);
1144 refresh(gpWin);
1145 EndUpdate((void *)gpWin);
1146 break;
1147
1148 default:
1149
1150 if (need_redraw)
1151 refresh(gpWin);
1152 break;
1153 }
1154}
1155
1156
1157static void refresh(CWindowPtr w)
1158{
1159 CGrafPtr saveport;
1160 PixMapHandle pixmap;
1161
1162
1163 GetPort((void *) &saveport);
1164 SetPort((void *) w);
1165
1166 pixmap = GetGWorldPixMap(gGP142World);
1167 LockPixels(pixmap);
1168 CopyBits((BitMap *)*pixmap, &((WindowPtr)w)->portBits,
1169 &(*pixmap)->bounds, &w->portRect, srcCopy, nil);
1170 UnlockPixels(pixmap);
1171
1172 SetPort((void *)saveport);
1173
1174 need_redraw = 0;
1175}
1176
1177/* react to user input */
1178static void DoMenu(long menuresult)
1179{
1180 short menuID, itemNumber;
1181 Str255 AccessoryName;
1182
1183 menuID = HiWord(menuresult);
1184 itemNumber = menuresult;
1185
1186 switch ( menuID ) {
1187 case Desk_ID:
1188#if USES_NEW_HEADERS
1189 GetMenuItemText(DeskMenu, itemNumber, (void *)&AccessoryName);
1190#else
1191 GetItem(DeskMenu, itemNumber, (void *)&AccessoryName);
1192#endif
1193 OpenDeskAcc((void *)&AccessoryName);
1194 EnableItem(RunMenu, 0);
1195 DrawMenuBar();
1196 break;
1197
1198 case Run_ID:
1199 switch ( itemNumber ) {
1200 case mAniRun: /* run */
1201 gRunFlag = TRUE;
1202 break;
1203
1204 case mAniHalt: /* halt */
1205 gSingleStepFlag = FALSE;
1206 gRunFlag = FALSE;
1207 break;
1208
1209 case mAniSingle: /* single step */
1210 gSingleStepFlag = TRUE;
1211 break;
1212
1213 case mLog: /* logging */
1214 gLogging = !gLogging;
1215 CheckItem(RunMenu, mLog, (int)gLogging);
1216 break;
1217
1218 case mScriptRecord: /* record actions */
1219 gRecordingFlag = !gRecordingFlag;
1220 CheckItem(RunMenu, mScriptRecord, (int)gRecordingFlag);
1221 if (!gRecordingFlag)
1222 {
1223 if (gTaskCount > 0)
1224 SaveToScript(GP142_PERIODIC, gEventRecord);
1225 CloseScript();
1226 }
1227 break;
1228
1229 case mScriptPlay: /* playback actions */
1230 gScriptPlayFlag = !gScriptPlayFlag;
1231 CheckItem(RunMenu, mScriptPlay, (int)gScriptPlayFlag);
1232 gRunFlag = FALSE;
1233 gSingleStepFlag = FALSE;
1234 break;
1235
1236 case mScriptOne: /* playback one action */
1237 gRunFlag = FALSE;
1238 gSingleStepFlag = FALSE;
1239 gScriptStepFlag = TRUE;
1240 break;
1241
1242 case mQuit: /* quit */
1243 gEventAction = GP142_QUIT;
1244 break;
1245
1246 default:
1247 SysBeep(1);
1248 break;
1249
1250 } /* end switch (itemNumber) */
1251 break;
1252 } /* end switch (menuID) */
1253 HiliteMenu(0);
1254}
1255
1256
1257static void DoMouseClick(EventRecord *the_event, CWindowPtr theWin)
1258{
1259 Point newPt;
1260 CGrafPtr saveport;
1261
1262 UNUSED(the_event);
1263
1264 /* If the user clicked in the console window, just ignore it */
1265 if (theWin != gpWin)
1266 return;
1267
1268 GetPort((void *)&saveport);
1269 SetPort((void *)theWin);
1270 GetMouse(&newPt);
1271
1272 gEventAction = GP142_MOUSE;
1273 gEventRecord.x = newPt.h - gXCenter;
1274 gEventRecord.y = gYCenter - newPt.v;
1275
1276 SetPort((void *)saveport);
1277}
1278
1279#elif defined(WINDOWS)
1280
1281#ifdef WIN32
1282long FAR PASCAL DrawWndProc(HWND hWnd, UINT message,
1283 WPARAM wParam, LPARAM lParam)
1284#else
1285long FAR PASCAL DrawWndProc(HWND hWnd, WORD message,
1286 WORD wParam, LONG lParam)
1287#endif
1288{
1289#ifndef WIN32
1290 HANDLE hInstance;
1291#endif
1292 RECT rClient;
1293 PAINTSTRUCT ps;
1294 HMENU hMenu;
1295 static BOOL bCtrlDown = FALSE;
1296
1297 int click_x, click_y;
1298
1299 switch(message)
1300 {
1301 case WM_CREATE:
1302/* Shuichi: Why do this? Not used anywhere */
1303#ifndef WIN32
1304 /* get a handle to the instance handle of the window */
1305 hInstance = (HANDLE)GetWindowWord(hWnd, GWW_HINSTANCE);
1306#endif
1307 /* Slap the menu on to the window */
1308 /* In windows, the menu bar is considered to be a 'menu'
1309 and all pull-down things are popup menus. */
1310 hMenu = CreateMenu();
1311 hRunMenu = CreatePopupMenu();
1312 AppendMenu(hRunMenu,
1313 MF_ENABLED | MF_STRING | MF_UNCHECKED, /* menu format */
1314 IDM_ANIMATE, "&Animate\tCtrl+A");
1315 AppendMenu(hRunMenu,
1316 MF_ENABLED | MF_STRING | MF_UNCHECKED,
1317 IDM_HALT, "&Halt animation\tCtrl+H");
1318 AppendMenu(hRunMenu,
1319 MF_ENABLED | MF_STRING | MF_UNCHECKED,
1320 IDM_ADVANCE_ONE, "Advance one &frame\tCtrl+F");
1321
1322 AppendMenu(hRunMenu, MF_SEPARATOR, 0, NULL);
1323
1324 /* Logging is initially TRUE */
1325 AppendMenu(hRunMenu,
1326 MF_ENABLED | MF_STRING | MF_CHECKED,
1327 IDM_LOGGING, "&Logging\tCtrl+L");
1328
1329 AppendMenu(hRunMenu, MF_SEPARATOR, 0, NULL);
1330
1331 AppendMenu(hRunMenu,
1332 MF_ENABLED | MF_STRING | MF_UNCHECKED,
1333 IDM_RECORD_SCRIPT, "&Record Script\tCtrl+R");
1334 AppendMenu(hRunMenu,
1335 MF_ENABLED | MF_STRING | MF_UNCHECKED,
1336 IDM_PLAY_SCRIPT, "&Playback Script\tCtrl+P");
1337 AppendMenu(hRunMenu,
1338 MF_ENABLED | MF_STRING | MF_UNCHECKED,
1339 IDM_STEP_SCRIPT, "Play &One Script\tCtrl+O");
1340
1341 AppendMenu(hRunMenu, MF_SEPARATOR, 0, NULL);
1342
1343 AppendMenu(hRunMenu,
1344 MF_ENABLED | MF_STRING | MF_UNCHECKED,
1345 IDM_QUIT, "&Quit\tCtrl+Q");
1346
1347 AppendMenu(hRunMenu, MF_SEPARATOR, 0, NULL);
1348
1349 AppendMenu(hRunMenu,
1350 MF_STRING | MF_UNCHECKED | MF_GRAYED,
1351 IDM_ABOUT, "GP142 v" GP142_VERSION " " GP142_DATE);
1352 AppendMenu(hRunMenu,
1353 MF_STRING | MF_UNCHECKED | MF_GRAYED,
1354 IDM_ABOUT, "MAC: mckenzie@cs.washington.edu");
1355 AppendMenu(hRunMenu,
1356 MF_STRING | MF_UNCHECKED | MF_GRAYED,
1357 IDM_ABOUT, "WINDOWS: corin@cs.washington.edu");
1358 AppendMenu(hRunMenu,
1359 MF_STRING | MF_UNCHECKED | MF_GRAYED,
1360 IDM_ABOUT, "UPDATES: casey@cs.washington.edu");
1361
1362 AppendMenu(hMenu,
1363 MF_ENABLED | MF_POPUP | MF_UNCHECKED,
1364 (UINT)hRunMenu, "&Run");
1365 SetMenu(hWnd, hMenu);
1366 DrawMenuBar(hWnd);
1367 return 0;
1368
1369
1370 case WM_LBUTTONDOWN:
1371 /* the user has clicked the left button on the window */
1372 click_x = LOWORD(lParam) - gXCenter;
1373 click_y = gYCenter - HIWORD(lParam);
1374
1375 /* For the program to link, the user must have this
1376 function defined in their module, even if it is an
1377 empty definition */
1378 gEventAction = GP142_MOUSE;
1379 gEventRecord.x = click_x;
1380 gEventRecord.y = click_y;
1381 return 0;
1382
1383 case WM_PAINT:
1384 BeginPaint(hWnd, &ps);
1385 /* we'll need to do an offscreen blit here.
1386 - josh */
1387 BitBlt (the_hdc,0,0,2*GP142_XMAX+1, 2*GP142_YMAX+FUDGE,
1388 offscreen_DC,0,0,SRCCOPY);
1389 EndPaint(hWnd, &ps);
1390 need_redraw = 0;
1391 return 0;
1392
1393
1394 case WM_KEYDOWN: /* do things like CTRL-xx shortcuts */
1395 switch(wParam)
1396 {
1397 case VK_CONTROL:
1398 bCtrlDown = TRUE;
1399 break;
1400
1401 case 'H':
1402 case 'h':
1403 if (bCtrlDown == TRUE)
1404 gRunFlag = FALSE;
1405 break;
1406
1407 case 'A':
1408 case 'a':
1409 if (bCtrlDown == TRUE)
1410 gRunFlag = TRUE;
1411 break;
1412
1413 case 'F':
1414 case 'f':
1415 if (bCtrlDown == TRUE)
1416 {
1417 gRunFlag = FALSE;
1418 gSingleStepFlag = TRUE;
1419 }
1420 break;
1421
1422 case 'L':
1423 case 'l':
1424 if (bCtrlDown && gLogging)
1425 {
1426 gLogging = LOG_OFF;
1427 CheckMenuItem(hRunMenu,
1428 IDM_LOGGING,
1429 MF_BYCOMMAND | MF_UNCHECKED);
1430 }
1431 else if (bCtrlDown && !gLogging)
1432 {
1433 gLogging = LOG_ON;
1434 CheckMenuItem(hRunMenu,
1435 IDM_LOGGING,
1436 MF_BYCOMMAND | MF_CHECKED);
1437 }
1438 break;
1439
1440
1441 case 'R':
1442 case 'r':
1443 if (bCtrlDown && gRecordingFlag)
1444 {
1445 gRecordingFlag = FALSE;
1446 CheckMenuItem(hRunMenu,
1447 IDM_RECORD_SCRIPT,
1448 MF_BYCOMMAND | MF_UNCHECKED);
1449 if (gTaskCount > 0)
1450 SaveToScript(GP142_PERIODIC, gEventRecord);
1451 CloseScript();
1452 }
1453 else if (bCtrlDown && !gRecordingFlag)
1454 {
1455 gRecordingFlag = TRUE;
1456 CheckMenuItem(hRunMenu,
1457 IDM_RECORD_SCRIPT,
1458 MF_BYCOMMAND | MF_CHECKED);
1459 }
1460 break;
1461
1462 case 'P':
1463 case 'p':
1464 if (bCtrlDown && gScriptPlayFlag)
1465 {
1466 gScriptPlayFlag = FALSE;
1467 CheckMenuItem(hRunMenu,
1468 IDM_PLAY_SCRIPT,
1469 MF_BYCOMMAND | MF_UNCHECKED);
1470 CloseScript();
1471 }
1472 else if (bCtrlDown && !gScriptPlayFlag)
1473 {
1474 gRunFlag = FALSE;
1475 gSingleStepFlag = FALSE;
1476 gScriptPlayFlag = TRUE;
1477 CheckMenuItem(hRunMenu,
1478 IDM_PLAY_SCRIPT,
1479 MF_BYCOMMAND | MF_CHECKED);
1480 }
1481 break;
1482
1483 case 'O':
1484 case 'o':
1485 if (bCtrlDown)
1486 {
1487 gScriptStepFlag = TRUE;
1488 gRunFlag = FALSE;
1489 gSingleStepFlag = FALSE;
1490 }
1491 break;
1492
1493 case 'Q':
1494 case 'q':
1495 if (bCtrlDown == TRUE)
1496 PostQuitMessage(0);
1497 break;
1498 }
1499 break;
1500
1501 case WM_CHAR:
1502 /* call the user's keyboard handler */
1503 if (bCtrlDown == TRUE)
1504 break;
1505
1506 gEventAction = GP142_KBD;
1507 gEventRecord.c = (char)wParam;
1508 break;
1509
1510
1511 case WM_KEYUP:
1512 switch (wParam)
1513 {
1514 case VK_CONTROL:
1515 bCtrlDown = FALSE;
1516 break;
1517 }
1518 break;
1519
1520
1521
1522 case WM_COMMAND: /* menu item selected */
1523 switch (wParam)
1524 {
1525 case IDM_ANIMATE:
1526 gRunFlag = TRUE;
1527 break;
1528
1529 case IDM_HALT:
1530 gRunFlag = FALSE;
1531 break;
1532
1533 case IDM_ADVANCE_ONE:
1534 gRunFlag = FALSE;
1535 gSingleStepFlag = TRUE;
1536 break;
1537
1538 case IDM_LOGGING:
1539 /* Changed TRUE/FALSE to LOG_ON/LOG_OFF */
1540 if (gLogging == LOG_ON)
1541 {
1542 gLogging = LOG_OFF;
1543 CheckMenuItem(hRunMenu,
1544 IDM_LOGGING,
1545 MF_BYCOMMAND | MF_UNCHECKED);
1546 }
1547 else
1548 {
1549 gLogging = LOG_ON;
1550 CheckMenuItem(hRunMenu,
1551 IDM_LOGGING,
1552 MF_BYCOMMAND | MF_CHECKED);
1553 }
1554 break;
1555
1556 case IDM_RECORD_SCRIPT:
1557 if (gRecordingFlag)
1558 {
1559 gRecordingFlag = FALSE;
1560 CheckMenuItem(hRunMenu,
1561 IDM_RECORD_SCRIPT,
1562 MF_BYCOMMAND | MF_UNCHECKED);
1563 if (gTaskCount > 0)
1564 SaveToScript(GP142_PERIODIC, gEventRecord);
1565 CloseScript();
1566 }
1567 else
1568 {
1569 gRecordingFlag = TRUE;
1570 CheckMenuItem(hRunMenu,
1571 IDM_RECORD_SCRIPT,
1572 MF_BYCOMMAND | MF_CHECKED);
1573 }
1574 break;
1575
1576 case IDM_PLAY_SCRIPT:
1577 if (gScriptPlayFlag)
1578 {
1579 gScriptPlayFlag = FALSE;
1580 CheckMenuItem(hRunMenu,
1581 IDM_PLAY_SCRIPT,
1582 MF_BYCOMMAND | MF_UNCHECKED);
1583 CloseScript();
1584 }
1585 else
1586 {
1587 gRunFlag = FALSE;
1588 gSingleStepFlag = FALSE;
1589 gScriptPlayFlag = TRUE;
1590 CheckMenuItem(hRunMenu,
1591 IDM_PLAY_SCRIPT,
1592 MF_BYCOMMAND | MF_CHECKED);
1593 }
1594 break;
1595
1596 case IDM_STEP_SCRIPT:
1597 gScriptStepFlag = TRUE;
1598 gRunFlag = FALSE;
1599 gSingleStepFlag = FALSE;
1600 break;
1601
1602 case IDM_QUIT:
1603 PostQuitMessage(0);
1604 break;
1605 }
1606 break;
1607
1608 case WM_SIZE: /* Graphics window's size has changed */
1609 /*
1610 ** Hmmm.. As of version 2.1, window size on both PC
1611 ** and Mac should be immutable, so this code is
1612 ** probably unnecessary, but I don't think it's
1613 ** harmful, so I'll leave it in case we ever change
1614 ** back to resizable windows. --- WLR 10/95
1615 */
1616 GetClientRect(hWnd, &rClient);
1617 gXCenter = (rClient.right - rClient.left)/2 +
1618 rClient.left;
1619 gYCenter = (rClient.bottom - rClient.top)/2 +
1620 rClient.top;
1621 break;
1622
1623 case WM_TIMER:
1624 gAnimExpired = TRUE;
1625 break;
1626
1627 case WM_DESTROY:
1628 case WM_QUIT:
1629 KillTimer(hWnd, wParam);
1630 PostQuitMessage(0);
1631 return 0;
1632
1633 default:
1634 return (DefWindowProc(hWnd, message, wParam, lParam));
1635 }
1636#ifndef WIN32
1637 UNUSED(hInstance);
1638#endif
1639 return 0;
1640}
1641
1642
1643/****** TextWndProc() *******************************************/
1644
1645#ifdef WIN32
1646long FAR PASCAL TextWndProc(HWND hWnd, UINT message,
1647 WPARAM wParam, LPARAM lParam)
1648#else
1649long FAR PASCAL TextWndProc(HWND hWnd, WORD message,
1650 WORD wParam, LONG lParam)
1651#endif
1652{
1653
1654 /* Begin addition of Clear Window */
1655 switch (message)
1656 {
1657 /* if user selects a keyboard shortcut while the text window
1658 is active, send the keystroke to the graphics window */
1659 case WM_KEYDOWN:
1660 PostMessage(hDrawWnd, /* send to graphics window */
1661 WM_KEYDOWN, /* message to send */
1662 wParam, /* send same paramaters */
1663 lParam);
1664 break;
1665
1666 case WM_KEYUP:
1667 PostMessage(hDrawWnd, WM_KEYUP, wParam, lParam);
1668 break;
1669
1670 case WM_PAINT:
1671 RedrawTextWnd(hWnd);
1672 return 0;
1673
1674 default:
1675 return DefWindowProc(hWnd, message, wParam, lParam);
1676 }
1677
1678 return 0;
1679}
1680
1681
1682#elif defined(X11R6)
1683
1684void Process_event(XEvent event) {
1685 if (event.xany.window == window) {
1686 switch(event.type) {
1687 int i;
1688 char keybuff[11];
1689 KeySym thekeysym;
1690 XComposeStatus compstat;
1691 case Expose:
1692 XCopyArea(display, offscreen_buffer, window, gc, 0, 0, GP142_XMAX*2, GP142_YMAX*2, 0, 0);
1693 XFlush(display);
1694 need_redraw = 0;
1695 break;
1696 case ButtonPress:
1697 gEventRecord.x = event.xbutton.x - GP142_XMAX;
1698 gEventRecord.y = GP142_YMAX - event.xbutton.y;
1699 gEventAction = GP142_MOUSE;
1700 break;
1701 case KeyPress:
1702 if (XLookupString((XKeyEvent*) &event, keybuff, 10,
1703 &thekeysym, &compstat) == 1) {
1704 if (thekeysym > 31 && thekeysym < 127) {
1705 gEventRecord.c = thekeysym;
1706 gEventAction = GP142_KBD;
1707 }
1708 }
1709 break;
1710 }
1711 }
1712 if (event.xany.window == winc[0]) {
1713 switch (event.type) {
1714 case Expose:
1715 XDrawString(display, winc[0], gccon, 5, 15, "Animate", 7);
1716 break;
1717 case ButtonPress:
1718 gRunFlag=TRUE;
1719 }
1720 }
1721 if (event.xany.window == winc[1]) {
1722 switch (event.type) {
1723 case Expose:
1724 XDrawString(display, winc[1], gccon, 5, 15, "Stop", 4);
1725 break;
1726 case ButtonPress:
1727 gRunFlag=FALSE;
1728 gSingleStepFlag=FALSE;
1729 }
1730 }
1731 if (event.xany.window == winc[2]) {
1732 switch (event.type) {
1733 case Expose:
1734 XDrawString(display, winc[2], gccon, 5, 15, "SingleStep", 10);
1735 break;
1736 case ButtonPress:
1737 gSingleStepFlag=TRUE;
1738 }
1739 }
1740 if (event.xany.window == winc[3]) {
1741 switch (event.type) {
1742 case ButtonPress:
1743 gLogging=!gLogging;
1744 XClearWindow(display,winc[3]);
1745 /* drop through to redraw strings */
1746 case Expose:
1747 if (gLogging)
1748 XDrawString(display, winc[3], gccon, 5, 15, "Logging on", 10);
1749 else
1750 XDrawString(display, winc[3], gccon, 5, 15, "Logging off", 11);
1751 break;
1752 }
1753 }
1754 if (event.xany.window == winc[4]) {
1755 switch (event.type) {
1756 case ButtonPress:
1757 gRecordingFlag=!gRecordingFlag;
1758 XClearWindow(display,winc[4]);
1759 /* drop through to redraw strings */
1760 case Expose:
1761 if (gRecordingFlag)
1762 XDrawString(display, winc[4], gccon, 5, 15, "Recording on", 12);
1763 else
1764 XDrawString(display, winc[4], gccon, 5, 15, "Recording off", 13);
1765 break;
1766 }
1767 }
1768 if (event.xany.window == winc[5]) {
1769 switch (event.type) {
1770 case ButtonPress:
1771 gScriptPlayFlag=!gScriptPlayFlag;
1772 gRunFlag=FALSE;
1773 gSingleStepFlag=FALSE;
1774 XClearWindow(display,winc[5]);
1775 /* drop through to redraw strings */
1776 case Expose:
1777 if (gScriptPlayFlag)
1778 XDrawString(display, winc[5], gccon, 5, 15, "Playback on", 11);
1779 else
1780 XDrawString(display, winc[5], gccon, 5, 15, "Playback off", 12);
1781 break;
1782 }
1783 }
1784 if (event.xany.window == winc[6]) {
1785 switch (event.type) {
1786 case ButtonPress:
1787 gRunFlag = FALSE;
1788 gSingleStepFlag = FALSE;
1789 gScriptStepFlag = TRUE;
1790 break;
1791 case Expose:
1792 XDrawString(display, winc[6], gccon, 5, 15, "SingleScript", 12);
1793 break;
1794 }
1795 }
1796 if (event.xany.window == winc[7]) {
1797 switch (event.type) {
1798 case Expose:
1799 XDrawString(display, winc[7], gccon, 5, 15, "Quit", 4);
1800 break;
1801 case ButtonPress:
1802 gEventAction = GP142_QUIT;
1803 }
1804 }
1805}
1806#endif
1807
1808
1809
1810/*********************************************************** Scripting Functions ***/
1811/* ClearPlayFlag()
1812*/
1813static void ClearPlayFlag(void)
1814{
1815 gScriptPlayFlag = FALSE;
1816 gScriptStepFlag = FALSE;
1817
1818#ifdef MACINTOSH
1819 CheckItem(RunMenu, mScriptPlay, FALSE);
1820#elif defined(WINDOWS)
1821 CheckMenuItem(hRunMenu,
1822 IDM_PLAY_SCRIPT,
1823 MF_BYCOMMAND | MF_UNCHECKED);
1824#elif defined(X11R6)
1825 XClearWindow(display,winc[5]);
1826 XDrawString(display, winc[5], gccon, 5, 15, "Playback off", 12);
1827#endif
1828}
1829
1830
1831/* SaveToScript()
1832*/
1833static void
1834SaveToScript(int a, GP142_event_t e)
1835{
1836 if (gScriptFP == NULL)
1837 if ((gScriptFP = fopen(kScriptName, "wt")) == NULL)
1838 {
1839 printf("Cannot open script file %s for writing\n", kScriptName);
1840 return;
1841 }
1842
1843 switch (a)
1844 {
1845 case GP142_MOUSE:
1846 fprintf(gScriptFP, "GP142_MOUSE(%d, %d);\n", e.x, e.y);
1847 break;
1848
1849 case GP142_KBD:
1850 fprintf(gScriptFP, "GP142_KBD(%d);\n", e.c);
1851 break;
1852
1853 case GP142_PERIODIC:
1854 fprintf(gScriptFP, "GP142_PERIODIC(%d);\n", gTaskCount);
1855 break;
1856
1857 default:
1858 break;
1859 }
1860}
1861
1862/* PlayFromScript()
1863*/
1864static int
1865PlayFromScript(void)
1866{
1867 char buf[512];
1868 char s[12];
1869 int c, i, k;
1870
1871 /* The only way PlayFromScript will be called is if GP142_await_event() is
1872 processing a message. So we can simply fill in the global data structures
1873 gEventAction and gEventRecord. */
1874
1875 if (gScriptFP == NULL)
1876 if ((gScriptFP = fopen(kScriptName, "rt")) == NULL)
1877 {
1878 printf("Cannot open script file %s for reading\n", kScriptName);
1879 ClearPlayFlag();
1880 return GP142_FAILURE;
1881 }
1882
1883 /* See if we're working on a block of user tasks right now */
1884 if (gTaskCount > 0)
1885 {
1886 gEventAction = GP142_PERIODIC;
1887 gTaskCount--;
1888 return GP142_SUCCESS;
1889 }
1890
1891 /* We want to remember to skip over blank lines */
1892 fgets(buf, 512, gScriptFP);
1893 while (!feof(gScriptFP) && buf[0] == '\n')
1894 fgets(buf, 512, gScriptFP);
1895
1896 if (feof(gScriptFP))
1897 {
1898 printf("EOF encountered in script file %s\n", kScriptName);
1899 ClearPlayFlag();
1900 return GP142_FAILURE;
1901 }
1902
1903 /* We don't get fscanf() or sscanf() services with Windows DLLs, so
1904 we'll have to be more sneaky about how we parse the script file */
1905
1906 c = buf[6]; /* buf[] = GP142_%c */
1907 switch (c)
1908 {
1909 case 'M': /* GP142_MOUSE(x, y); */
1910 gEventAction = GP142_MOUSE;
1911
1912 k = 6;
1913 while (!(isdigit(buf[k]) || buf[k] == '-'))
1914 k++;
1915
1916 i = 0;
1917 while (isdigit(s[i] = buf[k+i]) || buf[k+i] == '-')
1918 i++;
1919 s[i] = '\0';
1920 gEventRecord.x = atoi(s);
1921
1922 k += i;
1923 while (!(isdigit(buf[k]) || buf[k] == '-'))
1924 k++;
1925
1926 i = 0;
1927 while (isdigit(s[i] = buf[k+i]) || buf[k+i] == '-')
1928 i++;
1929 s[i] = '\0';
1930 gEventRecord.y = atoi(s);
1931 break;
1932
1933 case 'K': /* GP142_KBD(c); */
1934 gEventAction = GP142_KBD;
1935
1936 k = 6; /* skip over the 'GP142_' */
1937 while (!isdigit(buf[k]))
1938 k++;
1939
1940 i = 0;
1941 while (isdigit(s[i] = buf[k+i]))
1942 i++;
1943 s[i] = '\0';
1944 gEventRecord.c = atoi(s);
1945 break;
1946
1947 case 'P': /* GP142_PERIODIC(i); */
1948 gEventAction = GP142_PERIODIC;
1949
1950 k = 6;
1951 while (!isdigit(buf[k]))
1952 k++;
1953
1954 i = 0;
1955 while (isdigit(s[i] = buf[k+i]))
1956 i++;
1957 s[i] = '\0';
1958
1959 /* we substract 1 because we've already counted
1960 this task */
1961 gTaskCount = atoi(s) - 1;
1962 break;
1963
1964 default:
1965 return GP142_FAILURE;
1966
1967 }
1968 return GP142_SUCCESS;
1969}
1970
1971
1972/* CloseScript()
1973*/
1974static void
1975CloseScript(void)
1976{
1977 if (gScriptFP != NULL)
1978 fclose(gScriptFP);
1979}
1980
1981
1982
1983/********************************************************** API Helper functions ***/
1984#ifdef WINDOWS
1985static void RedrawTextWnd(HWND hWnd)
1986{
1987 PAINTSTRUCT ps;
1988 HBRUSH hBrush, hOldBrush;
1989 HDC our_DC, offscreen_DC;
1990 HBITMAP offscreen_bitmap;
1991 RECT windowRect, lastLineRect;
1992 TEXTMETRIC tm;
1993 int nScrollHeight;
1994 int len,i,j;
1995 char far *pStr;
1996
1997 BeginPaint(hWnd, &ps);
1998
1999 GetClientRect(hWnd, &windowRect);
2000
2001 /* We'll do all the drawing to an off-screen DC and then BitBlt it to the screen */
2002 our_DC = GetDC(hTextWnd);
2003 offscreen_DC = CreateCompatibleDC(our_DC);
2004 offscreen_bitmap = CreateCompatibleBitmap(offscreen_DC, windowRect.right, windowRect.bottom);
2005 SelectObject (offscreen_DC, offscreen_bitmap);
2006
2007 /* First, clear window. Just draw a white rectangle */
2008 hBrush = CreateSolidBrush(GetBkColor(offscreen_DC));
2009 hOldBrush = SelectObject(offscreen_DC, hBrush);
2010 FillRect(offscreen_DC, &windowRect, hBrush);
2011
2012 /* Get ready to draw strings */
2013
2014 /* set the device context's font */
2015 SelectObject(offscreen_DC, GetStockObject(ANSI_FIXED_FONT));
2016
2017 /* we'll need to figure out the height of the font. We'll do this
2018 by asking Windows to fill in a structure telling all about the
2019 default font, which we have just set */
2020 GetTextMetrics(offscreen_DC, &tm);
2021 nScrollHeight = tm.tmHeight + tm.tmExternalLeading;
2022
2023 /* This is the rectangle we'll use to erase the last line of text
2024 that was scrolled up. We now know how big to make it. */
2025 lastLineRect.top = windowRect.bottom-nScrollHeight;
2026 lastLineRect.bottom = windowRect.bottom + 1;
2027 lastLineRect.left = windowRect.left;
2028 lastLineRect.right = windowRect.right;
2029
2030 /* Walk through message ring, printing messages */
2031 for (i=gRingFirst, j=0;
2032 (i!=gRingLast || j==0) && i >= 0;
2033 RING_INC(i), j++)
2034 {
2035 pStr = GlobalLock(gConsoleLines[i]);
2036
2037 /* Move everything that was written so far up one line */
2038 ScrollDC(offscreen_DC,
2039 0, /* no horizontal scrolling */
2040 -nScrollHeight, /* just vertical scrolling; negative means up */
2041 NULL, /* scroll entire client area */
2042 NULL, /* and leave clipping rectangle alone */
2043 (HRGN)NULL, /* Windows needn't compute update region */
2044 NULL); /* or update rectangle */
2045
2046 /* Erase the place where the last line was */
2047 FillRect(offscreen_DC, &lastLineRect, hBrush);
2048
2049 /* omit trailing newlines */
2050 len = far_strlen(pStr);
2051 if (len > 0 && pStr[len-1] == '\n')
2052 {
2053 pStr[len-1] = '\0';
2054 len--;
2055 }
2056
2057 TextOut(offscreen_DC,
2058 windowRect.left + 5, /* leave ~5 pixel left margin */
2059 windowRect.bottom - nScrollHeight, /* new line appears at bottom */
2060 pStr, /* the string to display (far pointer) */
2061 len); /* and the string's length */
2062
2063 GlobalUnlock(gConsoleLines[i]);
2064 }
2065
2066
2067 /* SelectObject(offscreen_DC, hOldBrush); */
2068
2069 BitBlt (our_DC,0,0,windowRect.right, windowRect.bottom,
2070 offscreen_DC,0,0,SRCCOPY);
2071 EndPaint(hWnd, &ps);
2072
2073 DeleteObject(hBrush);
2074 DeleteObject(offscreen_bitmap);
2075
2076 ReleaseDC(hTextWnd, our_DC);
2077 ReleaseDC(hTextWnd, offscreen_DC);
2078 DeleteDC(our_DC);
2079 DeleteDC(offscreen_DC);
2080}
2081
2082
2083/* little function used just inside DLL; no reason to export it */
2084static int far_strlen(char far *s)
2085{
2086 int i=0;
2087
2088 while (*(s+i) != '\0')
2089 i++;
2090 return i;
2091}
2092
2093/*
2094 * The following function, thanks to Chris Anderson, provides
2095 * printint to the text window, essentially just like printf;
2096 * the only main difference is that newlines ("\n") are ignored.
2097 */
2098extern int GP142_FUNC
2099WINprintf(
2100 const char fmt[], /* the printf format string */
2101 ... ) /* list of variables to print */
2102{
2103 va_list vlist; /* Argument list pointer */
2104 char str[1024]; /* Buffer to build string into */
2105 int cnt; /* Result of SPRINTF for return */
2106 char far *pStr;
2107 int i;
2108 RECT rClient;
2109
2110 va_start( vlist, fmt ); /* Initialize va_ functions */
2111
2112 /* prints string to buffer */
2113 cnt = vsprintf(str, fmt, vlist);
2114 va_end( vlist ); /* Close va_ functions */
2115 /* Send string to graphics wind */
2116
2117 /* Save this string to the text window's ring buffer */
2118
2119 /* Determine length of string, and store in i */
2120 i = 0;
2121 while (str[i] != '\0')
2122 i++;
2123
2124 if (gRingFirst == gRingLast) /* ring is full, so overwrite the first */
2125 {
2126 GlobalFree(gConsoleLines[gRingFirst]);
2127 RING_INC(gRingFirst);
2128 }
2129
2130
2131 gConsoleLines[gRingLast] = GlobalAlloc(GMEM_MOVEABLE,
2132 (long unsigned)i+1L);
2133 pStr = GlobalLock(gConsoleLines[gRingLast]);
2134
2135 /* Copy string into globally allocated memory */
2136 i = 0;
2137 while (str[i] != '\0')
2138 {
2139 pStr[i] = str[i];
2140 i++;
2141 }
2142 pStr[i] = '\0';
2143
2144 GlobalUnlock(gConsoleLines[gRingLast]);
2145
2146 /* if this was the first string in the buffer, treat it special */
2147 if (gRingFirst < 0)
2148 gRingFirst = gRingLast;
2149
2150 RING_INC(gRingLast);
2151
2152 /* Display the string */
2153 /* DrawString(str); Commented out by Dan 2/3/00 */
2154
2155 /* Try force the whole text window to be redrawn */
2156 GetClientRect(hTextWnd, &rClient);
2157 InvalidateRect(hTextWnd, &rClient, 1);
2158
2159 return( cnt ); /* Return the conversion count */
2160}
2161#endif
2162
2163
2164/***************************************************************** API functions ***/
2165/* There are two types of API calls: GP142_gggXY() and GP142_gggP, where
2166ggg is the graphics symbol being drawn. The XY indicates that the function
2167uses seperate integer values for the x and y components of the coordinates.
2168The P means that coordinates are specified in a Point structure. In many
2169of the functions, an offset of width/2 has been subtracted from the coords;
2170this is meant to split the width of the object's outline across the logical
2171outline of the object. This seems to make more intuitive sense to new Mac
2172programmers, and increases cross platform (Windows) portability. */
2173
2174
2175/**************************************************************** GP142_gets()
2176** It is assumed that the string s is large enough for whatever string the user
2177** enters.
2178*/
2179/***********TODO*************/
2180#ifdef MACINTOSH
2181extern int
2182GP142_gets(const char prompt[], char result[])
2183{
2184 Str255 pasStr;
2185 DialogPtr dialog;
2186 Handle itemHandle;
2187 char *itemPtr;
2188 Rect itemBox, dialogBounds = {154, 168, 279, 488};
2189 int i;
2190 short itemHit = 0;
2191 short itemType;
2192
2193 for (i=1; i<255 && prompt[i-1] != '\0'; i++)
2194 pasStr[i] = prompt[i-1];
2195 pasStr[0] = i-1;
2196
2197 itemHandle = (Handle)NewHandle(50);
2198 HLock(itemHandle);
2199 itemPtr = *itemHandle;
2200
2201 itemPtr[0] = 0; /* There are 2 + 1 = 3 items in the list */
2202 itemPtr[1] = 2;
2203
2204 /* The Okay button */
2205 itemPtr[2] = 0; /* Parent window pointer */
2206 itemPtr[3] = 0;
2207 itemPtr[4] = 0;
2208 itemPtr[5] = 0;
2209 itemPtr[6] = 0; /* Top of button */
2210 itemPtr[7] = 94;
2211 itemPtr[8] = 0; /* 64 - right of button */
2212 itemPtr[9] = -125;
2213 itemPtr[10] = 0; /* bottom of button */
2214 itemPtr[11] = 114;
2215 itemPtr[12] = 0; /* 64 - left of button */
2216 itemPtr[13] = -67;
2217 itemPtr[14] = btnCtrl + ctrlItem;
2218 itemPtr[15] = 4; /* 4 bytes in variable-length field */
2219 itemPtr[16] = 'O'; /* Variable-length field */
2220 itemPtr[17] = 'k';
2221 itemPtr[18] = 'a';
2222 itemPtr[19] = 'y';
2223
2224 /* The static text region */
2225 itemPtr[20] = 0; /* Parent window pointer */
2226 itemPtr[21] = 0;
2227 itemPtr[22] = 0;
2228 itemPtr[23] = 0;
2229 itemPtr[24] = 0; /* Top of control */
2230 itemPtr[25] = 10;
2231 itemPtr[26] = 0; /* left of control */
2232 itemPtr[27] = 25;
2233 itemPtr[28] = 0; /* bottom of control */
2234 itemPtr[29] = 40;
2235 itemPtr[30] = 1; /* right of control (1*256 + 40)*/
2236 itemPtr[31] = 40;
2237 itemPtr[32] = statText;
2238 itemPtr[33] = 2; /* 2 bytes of additional data */
2239 itemPtr[34] = '^'; /* Additional data */
2240 itemPtr[35] = '0';
2241
2242 /* The edit text region */
2243 itemPtr[36] = 0; /* Parent window pointer */
2244 itemPtr[37] = 0;
2245 itemPtr[38] = 0;
2246 itemPtr[39] = 0;
2247 itemPtr[40] = 0; /* Top of control */
2248 itemPtr[41] = 41;
2249 itemPtr[42] = 0; /* left of control */
2250 itemPtr[43] = 25;
2251 itemPtr[44] = 0; /* bottom of control */
2252 itemPtr[45] = 82;
2253 itemPtr[46] = 1; /* right of control */
2254 itemPtr[47] = 40;
2255 itemPtr[48] = editText;
2256 itemPtr[49] = 0;
2257
2258 HUnlock(itemHandle);
2259
2260 dialog = NewDialog(nil, /* Let the OS allocate memory */
2261 &dialogBounds, /* Bounding box of dialog */
2262 "\pGP142_gets()", /* Title string, pascal style */
2263 FALSE, /* Don't show the dialog, yet */
2264 dBoxProc, /* Dialog Box procedure ID */
2265 (WindowPtr)-1L, /* Dialog will be in front of all windows */
2266 FALSE, /* Don't have a GoAway close box */
2267 0, /* Nothing in the RefCon field */
2268 itemHandle); /* Handle to item list */
2269
2270
2271
2272 ParamText(pasStr, "\p", "\p", "\p");
2273 ShowWindow(dialog);
2274
2275 while (itemHit != ok)
2276 ModalDialog(nil, &itemHit);
2277
2278 /* Get a handle to the edit text of the dialog box */
2279#if USES_NEW_HEADERS
2280 GetDialogItem(dialog, kGetsEditTextID, &itemType, &itemHandle, &itemBox);
2281#else
2282 GetDItem(dialog, kGetsEditTextID, &itemType, &itemHandle, &itemBox);
2283#endif
2284 /* Convert the handle to a pascal string */
2285#if USES_NEW_HEADERS
2286 GetDialogItemText(itemHandle, pasStr);
2287#else
2288 GetIText(itemHandle, pasStr);
2289#endif
2290
2291#if USES_NEW_HEADERS
2292 DisposeDialog(dialog);
2293#else
2294 DisposDialog(dialog);
2295#endif
2296
2297 for (i=0; i<pasStr[0]; i++)
2298 result[i] = pasStr[i+1];
2299 result[i] = '\0';
2300
2301 return GP142_SUCCESS;
2302}
2303
2304#elif defined(WINDOWS)
2305#ifdef WIN32
2306// Win32 version by Zack Ives, 6/19/98
2307//
2308// tested on WinNT 4.0
2309#pragma pack(push,before)
2310#pragma pack(4)
2311#define MAX_PROMPT 79
2312typedef struct {
2313 DLGTEMPLATE dt;
2314 unsigned short
2315 menuarray,
2316 classarray;
2317 WCHAR title[11];
2318
2319 DLGITEMTEMPLATE edit;
2320 unsigned short
2321 editClassArray[2];
2322 WCHAR editTitleArray[1];
2323 unsigned short editCreationArray[2];
2324
2325 DLGITEMTEMPLATE button;
2326 unsigned short
2327 buttonClassArray[2];
2328 WCHAR buttonTitleArray[5];
2329 unsigned short buttonCreationArray[2];
2330
2331 DLGITEMTEMPLATE text;
2332 unsigned short
2333 textClassArray[2];
2334 WCHAR textTitleArray[MAX_PROMPT];
2335 unsigned short textCreationArray[2];
2336
2337} dialogInfo;
2338#pragma pack(pop, before)
2339
2340
2341extern int GP142_FUNC
2342GP142_gets(const char prompt[], char result[])
2343{
2344 unsigned long size;
2345 int promptLen;
2346 dialogInfo d;
2347 dialogInfo far *di;
2348 char title[] = "GP142_gets";
2349
2350 int temp;
2351 long unsigned
2352 dialogStyle = WS_CAPTION | WS_SYSMENU | WS_POPUP | WS_VISIBLE |
2353 DS_MODALFRAME,
2354 okayStyle = WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_DEFPUSHBUTTON,
2355 editStyle = WS_CHILD | WS_VISIBLE | WS_TABSTOP | ES_MULTILINE |
2356 ES_AUTOVSCROLL | WS_BORDER,
2357 staticStyle = WS_CHILD | WS_VISIBLE | SS_LEFT | WS_GROUP;
2358
2359 for (promptLen=0; prompt[promptLen] != '\0'; promptLen++);
2360 promptLen++; /* Add room for NULL terminator */
2361
2362 size = sizeof(dialogInfo);
2363
2364 ZeroMemory(&d, sizeof(dialogInfo));
2365 di = &d;
2366
2367 di->dt.style = dialogStyle;
2368 di->dt.dwExtendedStyle = 0;
2369 di->dt.cdit = 3;
2370 di->dt.x = 50;
2371 di->dt.y = 50;
2372 di->dt.cx = 185;
2373 di->dt.cy = 92;
2374 di->menuarray = 0;
2375 di->classarray = 0;
2376
2377 for (temp = 0; (unsigned)temp < strlen(title); temp++)
2378 di->title[temp] = title[temp];
2379 di->title[temp] = 0;
2380
2381 /* Okay button */
2382 di->button.style = okayStyle;
2383 di->button.x = 67;
2384 di->button.y = 74;
2385 di->button.cx = 50;
2386 di->button.cy = 14;
2387 di->button.id = kOkayID;
2388 di->buttonClassArray[0] = 0xFFFF;
2389 di->buttonClassArray[1] = 0x0080;
2390 di->buttonTitleArray[0] = 'O';
2391 di->buttonTitleArray[1] = 'k';
2392 di->buttonTitleArray[2] = 'a';
2393 di->buttonTitleArray[3] = 'y';
2394 di->buttonTitleArray[4] = 0;
2395 di->buttonCreationArray[0] = 0;
2396
2397 /* Edit text */
2398 di->edit.style = editStyle;
2399 di->edit.x = 8;
2400 di->edit.y = 30;
2401 di->edit.cx = 167;
2402 di->edit.cy = 37;
2403 di->edit.id = kEditID;
2404 di->editClassArray[0] = 0xFFFF;
2405 di->editClassArray[1] = 0x0081;
2406 di->editTitleArray[0] = 0;
2407 di->editCreationArray[0] = 0;
2408
2409 /* Static text */
2410 di->text.style = staticStyle;
2411 di->text.x = 8;
2412 di->text.y = 3;
2413 di->text.cx = 167;
2414 di->text.cy = 24;
2415 di->text.id = kStaticID;
2416 di->textClassArray[0] = 0xFFFF;
2417 di->textClassArray[1] = 0x0082;
2418
2419 for (temp = 0; temp < MAX_PROMPT; temp++)
2420 if ((unsigned)temp < strlen(prompt))
2421 di->textTitleArray[temp] = prompt[temp];
2422 else
2423 di->textTitleArray[temp] = ' ';
2424 di->textTitleArray[temp] = 0;
2425 di->textCreationArray[0] = 0;
2426
2427 /* Display the dialog box */
2428 temp = DialogBoxIndirectParam(hInst, (DLGTEMPLATE *)di,
2429 hDrawWnd, getsDialogProc, (DWORD)result);
2430
2431 return (temp == -1)?GP142_FAILURE:GP142_SUCCESS;
2432}
2433
2434#else
2435GP142_gets(const char prompt[], char result[])
2436{
2437 unsigned long size;
2438 int promptLen;
2439 FARPROC lpDlgProc;
2440 HANDLE hDialogTemplate;
2441 unsigned char far *dialogPtr;
2442 int i, temp;
2443 long unsigned
2444 dialogStyle = WS_CAPTION | WS_SYSMENU | WS_POPUP | WS_VISIBLE |
2445 DS_MODALFRAME,
2446 okayStyle = WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_DEFPUSHBUTTON,
2447 editStyle = WS_CHILD | WS_VISIBLE | WS_TABSTOP | ES_MULTILINE |
2448 ES_AUTOVSCROLL | WS_BORDER,
2449 staticStyle = WS_CHILD | WS_VISIBLE | SS_LEFT | WS_GROUP;
2450
2451
2452 for (promptLen=0; prompt[promptLen] != '\0'; promptLen++);
2453 promptLen++; /* Add room for NULL terminator */
2454
2455 size = 82 + promptLen;
2456
2457 hDialogTemplate = GlobalAlloc(GMEM_MOVEABLE, (long unsigned)size);
2458 dialogPtr = (unsigned char far *)GlobalLock(hDialogTemplate);
2459
2460 dialogPtr[0] = (unsigned char)((dialogStyle & 0x000000FFL) >> 0);
2461 dialogPtr[1] = (unsigned char)((dialogStyle & 0x0000FF00L) >> 8);
2462 dialogPtr[2] = (unsigned char)((dialogStyle & 0x00FF0000L) >> 16);
2463 dialogPtr[3] = (unsigned char)((dialogStyle & 0xFF000000L) >> 24);
2464 dialogPtr[4] = (unsigned char)3; /* number of controls */
2465 dialogPtr[5] = (unsigned char)(((50) & 0x00FF)) >> 0; /* left edge pos, LSB */
2466 dialogPtr[6] = (unsigned char)(((50) & 0xFF00)) >> 8;
2467 dialogPtr[7] = (unsigned char)(((50) & 0x00FF)) >> 0; /* top edge pos, LSB */
2468 dialogPtr[8] = (unsigned char)(((50) & 0xFF00)) >> 8;
2469 dialogPtr[9] = (unsigned char)185; /* width, LSB */
2470 dialogPtr[10] = (unsigned char)0;
2471 dialogPtr[11] = (unsigned char)92; /* height, LSB */
2472 dialogPtr[12] = (unsigned char)0;
2473 dialogPtr[13] = (unsigned char)0; /* menu */
2474 dialogPtr[14] = (unsigned char)0; /* class */
2475 dialogPtr[15] = (unsigned char)'G'; /* caption */
2476 dialogPtr[16] = (unsigned char)'P';
2477 dialogPtr[17] = (unsigned char)'1';
2478 dialogPtr[18] = (unsigned char)'4';
2479 dialogPtr[19] = (unsigned char)'2';
2480 dialogPtr[20] = (unsigned char)'_';
2481 dialogPtr[21] = (unsigned char)'g';
2482 dialogPtr[22] = (unsigned char)'e';
2483 dialogPtr[23] = (unsigned char)'t';
2484 dialogPtr[24] = (unsigned char)'s';
2485 dialogPtr[25] = (unsigned char)'(';
2486 dialogPtr[26] = (unsigned char)')';
2487 dialogPtr[27] = (unsigned char)'\0';
2488
2489 /* Okay button */
2490
2491 dialogPtr[28] = (unsigned char)67; /* left edge of button */
2492 dialogPtr[29] = (unsigned char)0;
2493 dialogPtr[30] = (unsigned char)74; /* top edge of button */
2494 dialogPtr[31] = (unsigned char)0;
2495 dialogPtr[32] = (unsigned char)50; /* width of button */
2496 dialogPtr[33] = (unsigned char)0;
2497 dialogPtr[34] = (unsigned char)14; /* height of button */
2498 dialogPtr[35] = (unsigned char)0;
2499 dialogPtr[36] = (unsigned char)((kOkayID & 0x00FF) >> 0); /* button ID */
2500 dialogPtr[37] = (unsigned char)((kOkayID & 0xFF00) >> 8);
2501 dialogPtr[38] = (unsigned char)((okayStyle & 0x000000FFL) >> 0);/* Button style */
2502 dialogPtr[39] = (unsigned char)((okayStyle & 0x0000FF00L) >> 8);
2503 dialogPtr[40] = (unsigned char)((okayStyle & 0x00FF0000L) >> 16);
2504 dialogPtr[41] = (unsigned char)((okayStyle & 0xFF000000L) >> 24);
2505 dialogPtr[42] = (unsigned char)0x80; /* Button class */
2506 dialogPtr[43] = (unsigned char)'O'; /* Button text */
2507 dialogPtr[44] = (unsigned char)'k';
2508 dialogPtr[45] = (unsigned char)'a';
2509 dialogPtr[46] = (unsigned char)'y';
2510 dialogPtr[47] = (unsigned char)'\0';
2511 dialogPtr[48] = (unsigned char)0; /* size of variable length field */
2512
2513
2514 /* Edit text */
2515 dialogPtr[49] = (unsigned char)8; /* left edge of control */
2516 dialogPtr[50] = (unsigned char)0;
2517 dialogPtr[51] = (unsigned char)30; /* top edge of control */
2518 dialogPtr[52] = (unsigned char)0;
2519 dialogPtr[53] = (unsigned char)167;/* width of control */
2520 dialogPtr[54] = (unsigned char)0;
2521 dialogPtr[55] = (unsigned char)37; /* height of control */
2522 dialogPtr[56] = (unsigned char)0;
2523 dialogPtr[57] = (unsigned char)((kEditID & 0x00FF) >> 0);/* control ID */
2524 dialogPtr[58] = (unsigned char)((kEditID & 0xFF00) >> 8);
2525 dialogPtr[59] = (unsigned char)((editStyle & 0x000000FFL) >> 0);/* control style */
2526 dialogPtr[60] = (unsigned char)((editStyle & 0x0000FF00L) >> 8);
2527 dialogPtr[61] = (unsigned char)((editStyle & 0x00FF0000L) >> 16);
2528 dialogPtr[62] = (unsigned char)((editStyle & 0xFF000000L) >> 24);
2529 dialogPtr[63] = (unsigned char)0x81; /* control class */
2530 dialogPtr[64] = (unsigned char)'\0'; /* control text */
2531 dialogPtr[65] = (unsigned char)0; /* size of variable length field */
2532
2533
2534 /* Static text */
2535 dialogPtr[66] = (unsigned char)8; /* left edge of control */
2536 dialogPtr[67] = (unsigned char)0;
2537 dialogPtr[68] = (unsigned char)3; /* top edge of control */
2538 dialogPtr[69] = (unsigned char)0;
2539 dialogPtr[70] = (unsigned char)167;/* width of control */
2540 dialogPtr[71] = (unsigned char)0;
2541 dialogPtr[72] = (unsigned char)24; /* height of control */
2542 dialogPtr[73] = (unsigned char)0;
2543 dialogPtr[74] = (unsigned char)((kStaticID & 0x00FF) >> 0);/* control ID */
2544 dialogPtr[75] = (unsigned char)((kStaticID & 0xFF00) >> 8);
2545 dialogPtr[76] = (unsigned char)((staticStyle & 0x000000FFL) >> 0);/* control style */
2546 dialogPtr[77] = (unsigned char)((staticStyle & 0x0000FF00L) >> 8);
2547 dialogPtr[78] = (unsigned char)((staticStyle & 0x00FF0000L) >> 16);
2548 dialogPtr[79] = (unsigned char)((staticStyle & 0xFF000000L) >> 24);
2549 dialogPtr[80] = (unsigned char)0x82; /* control class */
2550 for (i=0; i<promptLen; i++)
2551 dialogPtr[81 + i] = (unsigned char)prompt[i];
2552 dialogPtr[81 + promptLen] = (unsigned char)0;
2553
2554 GlobalUnlock(hDialogTemplate);
2555
2556 /* Display the dialog box */
2557 lpDlgProc = MakeProcInstance(getsDialogProc, hInst);
2558 temp = DialogBoxIndirectParam(hInst, hDialogTemplate,
2559 hDrawWnd, lpDlgProc, (DWORD)result);
2560 FreeProcInstance(lpDlgProc);
2561
2562 /* Free the memory */
2563 GlobalFree(hDialogTemplate);
2564
2565 return temp==-1?GP142_FAILURE:GP142_SUCCESS;
2566}
2567#endif
2568
2569#ifdef WIN32
2570BOOL CALLBACK getsDialogProc(HWND hDlg, UINT wMessage, WPARAM wParam, LONG lParam)
2571#else
2572BOOL FAR PASCAL EXPORT getsDialogProc(HWND hDlg, WORD wMessage,
2573 WORD wParam, LONG lParam)
2574#endif
2575{
2576 static char *result;
2577
2578 switch (wMessage)
2579 {
2580 case WM_INITDIALOG:
2581 result = (char *)lParam;
2582 return TRUE;
2583
2584 case WM_COMMAND:
2585 switch (wParam)
2586 {
2587 case kOkayID:
2588 /* Copy the edit text into the result */
2589 GetDlgItemText(hDlg, kEditID, result, 256);
2590 EndDialog(hDlg, TRUE);
2591 return TRUE;
2592 }
2593 break;
2594 }
2595
2596 return FALSE;
2597}
2598#endif /* Windows version of GP142_gets() */
2599
2600
2601
2602/********************************************************* GP142_animate()
2603**
2604** let the user control animation:
2605** f == 0 => halt
2606** f == 1 => single step
2607** f == 2 => run
2608** f == 5 => quit
2609**
2610*/
2611extern int GP142_FUNC
2612GP142_animate(int f)
2613{
2614#ifdef MACINTOSH
2615 if (!gpWin)
2616#elif defined(WINDOWS)
2617 if (!hDrawWnd)
2618#elif defined(X11R6)
2619 if (!display)
2620#endif
2621 return GP142_FAILURE;
2622
2623 switch ( f )
2624 {
2625 case ANI_RUN: /* run */
2626 gRunFlag = TRUE;
2627 break;
2628 case ANI_HALT: /* halt */
2629 gSingleStepFlag = FALSE;
2630 gRunFlag = FALSE;
2631 break;
2632 case ANI_SINGLE_STEP: /* single step */
2633 gSingleStepFlag = TRUE;
2634 break;
2635 case ANI_QUIT: /* quit */
2636 gDoneFlag = TRUE;
2637 break;
2638 default:
2639#ifdef MACINTOSH
2640 SysBeep(1);
2641#endif
2642 break;
2643 }
2644
2645 return GP142_SUCCESS;
2646}
2647
2648
2649
2650/******************************************************** GP142_logging() **
2651** let the user set the logging flag
2652**
2653*/
2654extern int GP142_FUNC
2655GP142_logging(int f)
2656{
2657#ifdef MACINTOSH
2658 if (!gpWin)
2659#elif defined(WINDOWS)
2660 if (!hDrawWnd)
2661#elif defined(X11R6)
2662 if (!display)
2663#endif
2664 return GP142_FAILURE; /* GP142_open hasn't been called yet; do nothing */
2665 gLogging = !!f; /* !! forces value to be either 0 or 1 */
2666#ifdef MACINTOSH
2667 CheckItem(RunMenu, mLog, (int)gLogging);
2668#elif defined(WINDOWS)
2669 if (gLogging)
2670 CheckMenuItem(hRunMenu, IDM_LOGGING, MF_BYCOMMAND | MF_CHECKED);
2671 else
2672 CheckMenuItem(hRunMenu, IDM_LOGGING, MF_BYCOMMAND | MF_UNCHECKED);
2673#elif defined(X11R6)
2674 XClearWindow(display,winc[3]);
2675 if (gLogging)
2676 XDrawString(display, winc[3], gccon, 5, 15, "Logging on", 10);
2677 else
2678 XDrawString(display, winc[3], gccon, 5, 15, "Logging off", 11);
2679#endif
2680 if (gLogging)
2681 GP142_show_text(TRUE);
2682
2683 return GP142_SUCCESS ;
2684}
2685
2686/*
2687** Verify that color is legal; print error and reset if not.
2688** In all cases, return a legal color.
2689*/
2690static int Legalize_Color(int color)
2691{
2692 if ( ! ( 0 <= color && color <= MAX_COLORS ) )
2693 {
2694 printf("Illegal color %d; using RED.\n", color);
2695 color = RED;
2696 }
2697 return (color);
2698}
2699
2700
2701/******************************************************** GP142_pixel() ***/
2702extern int GP142_FUNC
2703GP142_pixelXY (int color, int x, int y)
2704{
2705 GP142_point p;
2706 p.x = x;
2707 p.y = y;
2708
2709 return GP142_pixelP(color, p);
2710}
2711
2712extern int GP142_FUNC
2713GP142_pixelP (int color, GP142_point p)
2714{
2715 Graphics new_item;
2716
2717 color = Legalize_Color(color);
2718 if (gLogging) {
2719 printf("%s pixel at (%d,%d)\n",
2720 gColorName[color], p.x, p.y);
2721 }
2722
2723 new_item.obj_type = obj_pixel;
2724 new_item.g.pixel.p = p;
2725 new_item.color = color;
2726
2727 Draw_Graphic_Item(&new_item);
2728
2729 return GP142_SUCCESS;
2730}
2731
2732
2733/******************************************************* GP142_circle() ***/
2734extern int GP142_FUNC
2735GP142_circleXY (int color, int x, int y, int radius)
2736{
2737 GP142_point p;
2738
2739 p.x = x;
2740 p.y = y;
2741
2742 return GP142_circleP(color, p, radius);
2743}
2744
2745extern int GP142_FUNC
2746GP142_circleP (int color, GP142_point center, int radius)
2747{
2748 Graphics new_item;
2749
2750 color = Legalize_Color(color);
2751 if (radius < 0)
2752 {
2753 printf("Radius of %d not possible, using radius %d\n", radius, -radius);
2754 radius = -radius;
2755 }
2756
2757 if (gLogging) {
2758 printf("%s circle at (%d,%d), radius %d\n",
2759 gColorName[color], center.x, center.y, radius);
2760 }
2761
2762 new_item.obj_type = obj_oval;
2763 new_item.g.oval.upper_left.x = center.x - radius;
2764 new_item.g.oval.upper_left.y = center.y + radius;
2765 new_item.g.oval.lower_right.x = center.x + radius;
2766 new_item.g.oval.lower_right.y =center.y - radius;
2767 new_item.color = color;
2768 new_item.width = 1;
2769
2770 Draw_Graphic_Item(&new_item);
2771
2772 return GP142_SUCCESS;
2773}
2774
2775
2776/***************************************************** GP142_triangle() ***/
2777extern int GP142_FUNC
2778GP142_triangleXY (
2779 int color,
2780 int x1, int y1,
2781 int x2, int y2,
2782 int x3, int y3,
2783 int width)
2784{
2785 GP142_point p1, p2, p3;
2786
2787 p1.x = x1;
2788 p1.y = y1;
2789 p2.x = x2;
2790 p2.y = y2;
2791 p3.x = x3;
2792 p3.y = y3;
2793
2794 return GP142_triangleP(color, p1, p2, p3, width);
2795}
2796
2797extern int GP142_FUNC
2798GP142_triangleP (int color, GP142_point p1,
2799 GP142_point p2, GP142_point p3, int width)
2800{
2801 Graphics new_item;
2802
2803 color = Legalize_Color(color);
2804 if (width < 0)
2805 {
2806 printf("Width of %d not possible, using width %d\n", width, -width);
2807 width = -width;
2808 }
2809
2810 if (gLogging) {
2811 printf("%s triangle at (%d,%d), (%d,%d), (%d,%d)\n",
2812 gColorName[color], p1.x, p1.y, p2.x, p2.y, p3.x, p3.y);
2813 }
2814 new_item.obj_type = obj_triangle;
2815 new_item.g.triangle.p1.x = p1.x;
2816 new_item.g.triangle.p1.y = p1.y;
2817 new_item.g.triangle.p2.x = p2.x;
2818 new_item.g.triangle.p2.y = p2.y;
2819 new_item.g.triangle.p3.x = p3.x;
2820 new_item.g.triangle.p3.y = p3.y;
2821 new_item.color = color;
2822 new_item.width = width;
2823
2824 Draw_Graphic_Item(&new_item);
2825
2826 return GP142_SUCCESS;
2827}
2828
2829/************************************************** GP142_rectangle() ****/
2830extern int GP142_FUNC
2831GP142_rectangleXY (
2832 int color,
2833 int x1, int y1,
2834 int x2, int y2,
2835 int width)
2836{
2837 GP142_point p1, p2;
2838
2839 p1.x = x1;
2840 p1.y = y1;
2841 p2.x = x2;
2842 p2.y = y2;
2843
2844 return GP142_rectangleP(color, p1, p2, width);
2845}
2846
2847extern int GP142_FUNC
2848GP142_rectangleP (
2849 int color, GP142_point p_upper_left, GP142_point p_lower_right,
2850 int width)
2851{
2852 Graphics new_item;
2853 int temp;
2854
2855 /* Determine proper ordering of points */
2856 if (p_upper_left.x > p_lower_right.x)
2857 {
2858 temp = p_upper_left.x;
2859 p_upper_left.x = p_lower_right.x;
2860 p_lower_right.x = temp;
2861 }
2862 if (p_upper_left.y < p_lower_right.y)
2863 {
2864 temp = p_upper_left.y;
2865 p_upper_left.y = p_lower_right.y;
2866 p_lower_right.y = temp;
2867 }
2868
2869 color = Legalize_Color(color);
2870 if (width < 0)
2871 {
2872 printf("Width of %d not possible, using width %d\n", width, -width);
2873 width = -width;
2874 }
2875
2876 if (gLogging) {
2877 if (width == 0)
2878 printf("%s rectangle with bounding box (%d,%d) to (%d,%d)"
2879 ", filled\n",
2880 gColorName[color],
2881 p_upper_left.x, p_upper_left.y,
2882 p_lower_right.x, p_lower_right.y);
2883 else
2884 printf("%s rectangle with bounding box (%d,%d) to (%d,%d)"
2885 " with line width %d\n",
2886 gColorName[color],
2887 p_upper_left.x, p_upper_left.y,
2888 p_lower_right.x, p_lower_right.y, width);
2889 }
2890
2891
2892
2893 new_item.obj_type = obj_rectangle;
2894 new_item.g.rectangle.upper_left.x = p_upper_left.x;
2895 new_item.g.rectangle.upper_left.y = p_upper_left.y;
2896 new_item.g.rectangle.lower_right.x = p_lower_right.x;
2897 new_item.g.rectangle.lower_right.y = p_lower_right.y;
2898 new_item.color = color;
2899 new_item.width = width;
2900
2901 Draw_Graphic_Item(&new_item);
2902
2903 return GP142_SUCCESS;
2904}
2905
2906
2907/********************************************************* GP142_oval() ***/
2908extern int GP142_FUNC
2909GP142_ovalXY (
2910 int color,
2911 int x1, int y1,
2912 int x2, int y2,
2913 int width)
2914{
2915 GP142_point p1, p2;
2916
2917 p1.x = x1;
2918 p1.y = y1;
2919 p2.x = x2;
2920 p2.y = y2;
2921
2922 return GP142_ovalP(color, p1, p2, width);
2923}
2924
2925
2926extern int GP142_FUNC
2927GP142_ovalP (
2928 int color,
2929 GP142_point p_upper_left, GP142_point p_lower_right,
2930 int width)
2931{
2932 Graphics new_item;
2933 int temp;
2934
2935 /* Determine proper ordering of points */
2936 if (p_upper_left.x > p_lower_right.x)
2937 {
2938 temp = p_upper_left.x;
2939 p_upper_left.x = p_lower_right.x;
2940 p_lower_right.x = temp;
2941 }
2942 if (p_upper_left.y < p_lower_right.y)
2943 {
2944 temp = p_upper_left.y;
2945 p_upper_left.y = p_lower_right.y;
2946 p_lower_right.y = temp;
2947 }
2948
2949 if (width < 0)
2950 {
2951 printf("Width of %d not possible, using width %d\n", width, -width);
2952 width = -width;
2953 }
2954
2955 color = Legalize_Color(color);
2956 if (gLogging) {
2957 if (width == 0)
2958 printf("%s oval with bounding box (%d,%d) to (%d,%d), "
2959 "filled\n",
2960 gColorName[color],
2961 p_upper_left.x, p_upper_left.y,
2962 p_lower_right.x, p_lower_right.y);
2963 else
2964 printf("%s oval with bounding box (%d,%d) to (%d,%d), "
2965 "line width %d\n",
2966 gColorName[color],
2967 p_upper_left.x, p_upper_left.y,
2968 p_lower_right.x, p_lower_right.y, width);
2969 }
2970
2971 new_item.obj_type = obj_oval;
2972 new_item.g.oval.upper_left.x = p_upper_left.x;
2973 new_item.g.oval.upper_left.y = p_upper_left.y;
2974 new_item.g.oval.lower_right.x = p_lower_right.x;
2975 new_item.g.oval.lower_right.y = p_lower_right.y;
2976 new_item.color = color;
2977 new_item.width = width;
2978
2979 Draw_Graphic_Item(&new_item);
2980
2981 return GP142_SUCCESS;
2982}
2983
2984
2985/********************************************************* GP142_line() ***/
2986extern int GP142_FUNC
2987GP142_lineXY (int color, int x1, int y1, int x2, int y2, int width)
2988{
2989 GP142_point p1, p2;
2990
2991 p1.x = x1;
2992 p1.y = y1;
2993 p2.x = x2;
2994 p2.y = y2;
2995
2996 return GP142_lineP(color, p1, p2, width);
2997}
2998
2999
3000extern int GP142_FUNC
3001GP142_lineP (int color, GP142_point pUL, GP142_point pLR, int width)
3002{
3003 Graphics new_item;
3004
3005 if (width < 0)
3006 {
3007 printf("Width of %d not possible, using width %d\n", width, -width);
3008 width = -width;
3009 }
3010
3011 color = Legalize_Color(color);
3012 if (gLogging) {
3013 printf("%s line from (%d,%d) to (%d,%d), width %d\n",
3014 gColorName[color], pUL.x, pUL.y, pLR.x, pLR.y, width);
3015 }
3016 new_item.obj_type = obj_line;
3017 new_item.g.line.upper_left.x = pUL.x;
3018 new_item.g.line.upper_left.y = pUL.y;
3019 new_item.g.line.lower_right.x = pLR.x;
3020 new_item.g.line.lower_right.y = pLR.y;
3021 new_item.color = color;
3022 if (width < 1) width = 1;
3023 new_item.width = width;
3024
3025 Draw_Graphic_Item(&new_item);
3026
3027 return GP142_SUCCESS;
3028}
3029
3030
3031/********************************************************* GP142_text() ***/
3032extern int GP142_FUNC
3033GP142_textXY(int color, int x, int y, int ptsize, const char *string)
3034{
3035 GP142_point p;
3036
3037 p.x = x;
3038 p.y = y;
3039
3040 return GP142_textP(color, p, ptsize, string);
3041}
3042
3043
3044extern int GP142_FUNC
3045GP142_textP (int color, GP142_point p, int ptsize, const char string[])
3046{
3047 Graphics new_item;
3048#ifdef MACINTOSH
3049 int len;
3050#elif defined(WINDOWS)
3051 char far *pStr;
3052 int i;
3053#elif defined(X11R6)
3054 int len;
3055#endif
3056
3057 if (ptsize < 0)
3058 {
3059 printf("ptsize of %d not possible, using ptsize %d\n", ptsize, -ptsize);
3060 ptsize = -ptsize;
3061 }
3062 if (ptsize > 127)
3063 {
3064 printf("ptsize of %d not possible, using ptsize %d\n", ptsize, 127);
3065 ptsize = 127;
3066 }
3067
3068 color = Legalize_Color(color);
3069 if (gLogging) {
3070 printf("%s text at (%d,%d), \"%s\"\n",
3071 gColorName[color], p.x, p.y, string);
3072 }
3073 new_item.obj_type = obj_text;
3074 new_item.g.text.p.x = p.x;
3075 new_item.g.text.p.y = p.y;
3076 new_item.color = color;
3077 new_item.g.text.ptsize = ptsize;
3078
3079#ifdef MACINTOSH
3080 len = strlen(string) + 1;
3081 if (len > MAXSTRLEN) len = MAXSTRLEN;
3082 if ((new_item.g.text.the_text = malloc(len)) == NULL) {
3083 printf("GP142 library error: out of memory\n");
3084 return GP142_FAILURE;
3085 }
3086 strncpy(new_item.g.text.the_text, string, len);
3087 new_item.g.text.the_text[len - 1] = 0; /* to be for sure, for sure */
3088 CtoPstr(new_item.g.text.the_text);
3089 Draw_Graphic_Item(&new_item);
3090 free(new_item.g.text.the_text);
3091
3092#elif defined(WINDOWS)
3093
3094 i = 0;
3095 while (string[i] != '\0')
3096 i++;
3097 new_item.g.text.hText =
3098 GlobalAlloc(GMEM_MOVEABLE, (long unsigned)i+1L);
3099 pStr = GlobalLock(new_item.g.text.hText);
3100
3101 i = 0;
3102 while (string[i] != '\0')
3103 {
3104 pStr[i] = string[i];
3105 i++;
3106 }
3107 pStr[i] = '\0';
3108
3109 GlobalUnlock(new_item.g.text.hText);
3110
3111 Draw_Graphic_Item(&new_item);
3112 GlobalFree(new_item.g.text.hText);
3113
3114#elif defined(X11R6)
3115
3116 len = strlen(string) + 1;
3117
3118 if (len > MAXSTRLEN) len = MAXSTRLEN;
3119
3120 if ((new_item.g.text.the_text = (char *) malloc(len)) == NULL) {
3121 printf("GP142 library error: out of memory\n");
3122 return GP142_FAILURE;
3123 }
3124
3125 strncpy(new_item.g.text.the_text, string, len);
3126 new_item.g.text.the_text[len - 1] = 0;
3127 Draw_Graphic_Item(&new_item);
3128 free(new_item.g.text.the_text);
3129
3130#endif
3131
3132 return GP142_SUCCESS;
3133}
3134
3135
3136/****************************************************** GP142_getDimensions() ***/
3137/*
3138 * functions to get the on-screen dimensions of text
3139 */
3140
3141extern int GP142_FUNC
3142GP142_getDimensions2 (int ptsize, int *height, int *width, const char string[])
3143{
3144#ifdef MACINTOSH
3145 int len;
3146 FontInfo fontInfo;
3147 char *theString;
3148#elif defined(WINDOWS)
3149 char far *pStr;
3150 int i;
3151 HFONT hFont, hOldFont;
3152 HANDLE hText;
3153 SIZE textSize;
3154#elif defined(X11R6)
3155 int len;
3156#endif
3157
3158 if (ptsize < 0)
3159 {
3160 printf("ptsize of %d not possible, using ptsize %d\n", ptsize, -ptsize);
3161 ptsize = -ptsize;
3162 }
3163 if (ptsize > 127)
3164 {
3165 printf("ptsize of %d not possible, using ptsize %d\n", ptsize, 127);
3166 ptsize = 127;
3167 }
3168
3169#ifdef MACINTOSH
3170 len = strlen(string) + 1;
3171 if (len > MAXSTRLEN) len = MAXSTRLEN;
3172 if ((theString = malloc(len)) == NULL) {
3173 printf("GP142 library error: out of memory\n");
3174 return GP142_FAILURE;
3175 }
3176 strncpy(theString, string, len);
3177 theString[len - 1] = 0; /* to be for sure, for sure */
3178 CtoPstr(theString);
3179 TextSize(ptsize);
3180 GetFontInfo(&fontInfo);
3181 *width = TextWidth(theString, 1, strlen(string));
3182 *height = fontInfo.ascent + fontInfo.descent + fontInfo.leading;
3183 free(theString);
3184
3185#elif defined(WINDOWS)
3186
3187 i = 0;
3188 while (string[i] != '\0')
3189 i++;
3190 hText =
3191 GlobalAlloc(GMEM_MOVEABLE, (long unsigned)i+1L);
3192 pStr = GlobalLock(hText);
3193
3194 i = 0;
3195 while (string[i] != '\0')
3196 {
3197 pStr[i] = string[i];
3198 i++;
3199 }
3200 pStr[i] = '\0';
3201
3202 GlobalUnlock(hText);
3203
3204 hFont = CreateFont(-ptsize,
3205 0, /* let Windows choose width */
3206 0, /* escapement, in 10ths of degrees */
3207 0, /* orientation, in 10ths of degrees */
3208 FW_NORMAL, /* normal weight */
3209 FALSE, /* no italic */
3210 FALSE, /* no underline */
3211 FALSE, /* no strikeout */
3212 ANSI_CHARSET, /* use ANSI character set */
3213 OUT_DEFAULT_PRECIS, /* output precision */
3214 CLIP_DEFAULT_PRECIS, /* clip precision */
3215 DEFAULT_QUALITY, /* quality */
3216 DEFAULT_PITCH | FF_DONTCARE, /* pitch and family */
3217 "GP142-font"); /* way-cool name of font */
3218
3219 hOldFont = SelectObject(offscreen_DC, hFont);
3220
3221 pStr = GlobalLock(hText);
3222
3223 /* To be compatible with the Mac, we want to bump the
3224 text string 'up' by the height of the string */
3225 GetTextExtentPoint(offscreen_DC,
3226 pStr,
3227 far_strlen(pStr),
3228 &textSize);
3229 *width = textSize.cx;
3230 *height = textSize.cy;
3231
3232 GlobalUnlock(hText);
3233
3234 SelectObject(offscreen_DC, hOldFont);
3235 DeleteObject(hFont);
3236
3237#elif defined(X11R6)
3238
3239 if (ptsize != current_font->point_size) {
3240
3241 FontDB *temp = font_info;
3242
3243 while (temp) {
3244 if (ptsize == temp->point_size)
3245 break;
3246 temp = temp->next;
3247 }
3248
3249 /* Or else add it to the list and load it. */
3250
3251 if (!temp) {
3252 char fontname[100];
3253 temp = (FontDB*) malloc(sizeof(FontDB));
3254 sprintf(fontname, "-adobe-helvetica-medium-r-normal--0-%d-75-75-p-0-iso8859-1", ptsize * 10);
3255 if ((temp == NULL) ||
3256 (temp->thefont = XLoadQueryFont(display,
3257 fontname)) == NULL) {
3258 fprintf(stderr, "Cannot open Adobe scalable font.\n");
3259 exit(0);
3260 }
3261
3262 /* Set font to requested point size and put node at
3263 * the head of the list. */
3264
3265 temp->point_size = ptsize;
3266 temp->next = font_info;
3267 font_info = temp;
3268 }
3269
3270 /* Set gc to new point size */
3271 XSetFont(display, gc, temp->thefont->fid);
3272 current_font = temp;
3273 }
3274
3275 *height = current_font->thefont->ascent + current_font->thefont->descent;
3276 *width = XTextWidth(current_font->thefont, string, strlen(string));
3277
3278#endif
3279
3280 return GP142_SUCCESS;
3281}
3282
3283
3284/****************************************************** GP142_printf() ***/
3285/*
3286 * The following function, thanks to Chris Anderson, subsumes
3287 * GP142_int and GP142_text (from v1.9 and previous), from users
3288 * perspective. It provides formated printout to the graphics window,
3289 * essentially just like printf; newlines ("\n") do advance text to the
3290 * next line.
3291 */
3292extern int GP142_FUNC
3293GP142_printfXY(
3294 int color, /* text color */
3295 int x, int y, /* x, y coords of left end of text */
3296 int point_size, /* text size */
3297 const char fmt[], /* the printf format string */
3298 ... ) /* list of variables to print */
3299{
3300 va_list vlist; /* Argument list pointer */
3301 char str[1024]; /* Buffer to build string into */
3302 int cnt; /* Result of SPRINTF for return */
3303
3304 va_start( vlist, fmt ); /* Initialize va_ functions */
3305
3306 /* prints string to buffer */
3307 cnt = vsprintf( str, fmt, vlist );
3308 va_end( vlist ); /* Close va_ functions */
3309 /* Send string to graphics wind */
3310 GP142_textXY( color,x,y,point_size,str );
3311 return( cnt ); /* Return the conversion count */
3312}
3313
3314extern int GP142_FUNC
3315GP142_printfP(
3316 int color, /* text color */
3317 GP142_point p, /* x, y coords of left end of text */
3318 int point_size, /* text size */
3319 const char fmt[], /* the printf format string */
3320 ... ) /* list of variables to print */
3321{
3322 va_list vlist; /* Argument list pointer */
3323 char str[1024]; /* Buffer to build string into */
3324 int cnt; /* Result of SPRINTF for return */
3325
3326 va_start( vlist, fmt ); /* Initialize va_ functions */
3327
3328 /* prints string to buffer */
3329 cnt = vsprintf( str, fmt, vlist );
3330 va_end( vlist ); /* Close va_ functions */
3331 /* Send string to graphics wind */
3332 GP142_textP( color,p,point_size,str );
3333 return( cnt ); /* Return the conversion count */
3334}
3335
3336extern int GP142_FUNC
3337GP142_getDimensions(
3338 int point_size, /* text size */
3339 int *height,
3340 int *width,
3341 const char fmt[], /* the printf format string */
3342 ... ) /* list of variables to print */
3343{
3344 va_list vlist; /* Argument list pointer */
3345 char str[1024]; /* Buffer to build string into */
3346 int cnt; /* Result of SPRINTF for return */
3347
3348 va_start( vlist, fmt ); /* Initialize va_ functions */
3349
3350 /* prints string to buffer */
3351 cnt = vsprintf( str, fmt, vlist );
3352 va_end( vlist ); /* Close va_ functions */
3353 /* get dimensions of string */
3354 GP142_getDimensions2( point_size,height,width,str );
3355 return ( cnt ); /* Return the conversion count */
3356}
3357
3358
3359/******************************************************** GP142_undo() ***/
3360extern int GP142_FUNC
3361GP142_undo(void)
3362{
3363 printf("GP142_undo is no longer supported.\n");
3364 return GP142_SUCCESS;
3365}
3366
3367/******************************************************* GP142_flush() ***/
3368extern int GP142_FUNC
3369GP142_flush(void)
3370{
3371 if (gLogging) {
3372 printf("Flushing the graphics window\n");
3373 }
3374#ifdef MACINTOSH
3375 refresh(gpWin);
3376
3377#elif defined(WINDOWS)
3378 if (need_redraw) {
3379 BitBlt (the_hdc,0,0,2*GP142_XMAX+1, 2*GP142_YMAX+FUDGE,
3380 offscreen_DC,0,0,SRCCOPY);
3381 need_redraw = 0;
3382 }
3383#elif defined(X11R6)
3384 if (need_redraw) {
3385 XCopyArea(display, offscreen_buffer, window, gc, 0, 0, GP142_XMAX*2, GP142_YMAX*2, 0, 0);
3386 XFlush(display);
3387 need_redraw = 0;
3388 }
3389#endif
3390
3391 return GP142_SUCCESS;
3392}
3393
3394
3395/******************************************************* GP142_clear() ***/
3396extern int GP142_FUNC
3397GP142_clear(void)
3398{
3399 if (gLogging) {
3400 printf("Clearing the graphics window\n");
3401 }
3402
3403 /* Clear the offscreen buffer */
3404 GP_clear();
3405
3406 return GP142_SUCCESS;
3407}
3408
3409
3410static void GP_clear(void)
3411{
3412#ifdef MACINTOSH
3413 GDHandle oldGD;
3414 GWorldPtr oldGWorld;
3415
3416 GetGWorld(&oldGWorld, &oldGD);
3417 LockPixels(gGP142World->portPixMap);
3418 SetGWorld(gGP142World, nil);
3419
3420 EraseRect(&(*gGP142World->portPixMap)->bounds);
3421
3422 SetGWorld(oldGWorld, oldGD);
3423 UnlockPixels(gGP142World->portPixMap);
3424#elif defined(WINDOWS)
3425 /* Just draw a white rectangle */
3426 HBRUSH hBrush, hOldBrush;
3427 hBrush = CreateSolidBrush(gRGBColors[1]);
3428 hOldBrush = SelectObject(offscreen_DC, hBrush);
3429
3430 /* Windows draws lines in a very odd fashion. Windows
3431 will include the first endpoint when drawing a line, but
3432 _exclude_ the next endpoint. I gather that this allows
3433 for poly-lines, but very strange things happen when you
3434 draw single lines this way. That is why we add 1 to the
3435 ending x and y coords in the rectangle, oval, etc. */
3436 Rectangle(offscreen_DC,
3437 0, 0, GP142_XMAX*2+1, GP142_YMAX*2+FUDGE);
3438 SelectObject(offscreen_DC, hOldBrush);
3439 DeleteObject(hBrush);
3440#elif defined(X11R6)
3441 XGCValues gc_val;
3442 GC gc_clear;
3443
3444 gc_clear = XCreateGC(display, window, 0, &gc_val);
3445 XSetForeground(display, gc_clear, WhitePixel(display, screen));
3446 XFillRectangle(display, offscreen_buffer, gc_clear, 0, 0,
3447 GP142_XMAX*2, GP142_YMAX*2);
3448#endif
3449
3450 need_redraw = 1;
3451}
3452
3453
3454/******************************************** Graphics Output function ***/
3455#ifdef MACINTOSH
3456static void
3457Draw_Graphic_Item(Graphics *item)
3458{
3459 GDHandle oldGD;
3460 GWorldPtr oldGWorld;
3461 PolyHandle poly;
3462 Rect r;
3463 int color;
3464 RGBColor savecolor;
3465 int width;
3466 int done, j, line, total, length;
3467 char *s;
3468 FontInfo fontInfo;
3469
3470 /* Save the old graphics world */
3471 GetGWorld(&oldGWorld, &oldGD);
3472
3473 /* Grab the offscreen graphics world buffer, and set it as the current world */
3474 LockPixels(gGP142World->portPixMap);
3475 SetGWorld(gGP142World, nil);
3476
3477 color = Legalize_Color(item->color); /* just in case...*/
3478 if (color == 0 || gColorFlag == 0)
3479 PenPat(&qd.black);
3480 else
3481 PenPixPat(color_pp[color]);
3482 width = item->width;
3483 PenSize(width, width);
3484 switch (item->obj_type) {
3485 case obj_triangle:
3486 /* triangles are very strange beasts. That is, they are polygons, so they don't
3487 behave _exactly_ like rectangles or ovals, which are bound by rects. The problem
3488 has been that filled triangles aren't including their edges. The easiest thing
3489 to fix this is to explicitly draw the frame of the triangle whenever the width
3490 is 0. To do this, we simply change the pen size to 1x1 if the the width is 0,
3491 and _always_ draw the frame. This seems to be working, though I haven't done
3492 much testing yet... */
3493 poly = OpenPoly();
3494 MoveTo(gXCenter+item->g.triangle.p1.x-width/2,
3495 gYCenter-item->g.triangle.p1.y-width/2);
3496 LineTo(gXCenter+item->g.triangle.p2.x-width/2,
3497 gYCenter-item->g.triangle.p2.y-width/2);
3498 LineTo(gXCenter+item->g.triangle.p3.x-width/2,
3499 gYCenter-item->g.triangle.p3.y-width/2);
3500 LineTo(gXCenter+item->g.triangle.p1.x-width/2,
3501 gYCenter-item->g.triangle.p1.y-width/2);
3502 ClosePoly();
3503
3504 if (width == 0)
3505 {
3506 if (gColorFlag)
3507 FillCPoly(poly, color_pp[color]);
3508 else
3509 PaintPoly(poly);
3510 PenSize(1,1); /* force a thin outline */
3511 }
3512 FramePoly(poly);
3513 KillPoly(poly);
3514 break;
3515
3516 case obj_rectangle:
3517 /* As of v1.4 to v1.5, I (Corey) have realized that we have a major inconsistency.
3518 That is, all the GP142 functions which require a bounding box expect the coords
3519 for those boxes in Upper-Left, Lower-Right order. The GP142.h file describes these
3520 functions as taking first the Lower-Left, then Upper-right coords. Luckily, every-
3521 thing is symmetric about the X and Y midpoint lines. But it is just terribly
3522 confusing for maintaing the code. This problem also persists to the WIndows
3523 version. Oh, how I wish that I had found this error when going from v1.3 to v1.4.
3524 Then, I could have corrected everything, and no one would have needed to change
3525 any of their GP142 application code. Ah, well. */
3526
3527 /* left top right bottom! */
3528 SetRect(&r,
3529 gXCenter+item->g.rectangle.upper_left.x-width/2,
3530 gYCenter-item->g.rectangle.upper_left.y-width/2,
3531 gXCenter+item->g.rectangle.lower_right.x+width/2 +1,
3532 gYCenter-item->g.rectangle.lower_right.y+width/2 +1);
3533 if (width == 0)
3534 if (gColorFlag)
3535 FillCRect(&r, color_pp[color]);
3536 else
3537 PaintRect(&r);
3538 else
3539 FrameRect(&r);
3540 break;
3541
3542 case obj_oval:
3543 SetRect(&r,
3544 gXCenter+item->g.oval.upper_left.x-width/2,
3545 gYCenter-item->g.oval.upper_left.y-width/2,
3546 gXCenter+item->g.oval.lower_right.x+width/2 +1,
3547 gYCenter-item->g.oval.lower_right.y+width/2 +1);
3548 if (width == 0)
3549 if (gColorFlag)
3550 FillCOval(&r, color_pp[color]);
3551 else
3552 PaintOval(&r);
3553 else
3554 FrameOval(&r);
3555 break;
3556
3557 case obj_line:
3558 MoveTo( gXCenter+item->g.line.upper_left.x-width/2,
3559 gYCenter-item->g.line.upper_left.y-width/2);
3560 LineTo( gXCenter+item->g.line.lower_right.x-width/2,
3561 gYCenter-item->g.line.lower_right.y-width/2);
3562 break;
3563
3564 case obj_pixel:
3565 PenSize(1,1);
3566 MoveTo( gXCenter+item->g.pixel.p.x,
3567 gYCenter-item->g.pixel.p.y );
3568 LineTo( gXCenter+item->g.pixel.p.x,
3569 gYCenter-item->g.pixel.p.y );
3570 break;
3571
3572 case obj_text:
3573 if (gColorFlag) {
3574 GetForeColor(&savecolor);
3575 if (color != 0)
3576 RGBForeColor(&gRGBColors[color]);
3577 }
3578
3579 TextSize(item->g.text.ptsize);
3580
3581 GetFontInfo(&fontInfo);
3582
3583 /* We want to honor newline characters in the string by
3584 advancing the current line some height */
3585
3586 done = FALSE;
3587 s = item->g.text.the_text;
3588 total = 1; /* skip over the pascal length byte */
3589 length = s[0];
3590 line = 0;
3591 while (done != TRUE)
3592 {
3593 for (j=0; s[total+j] != '\n' && s[total+j] != '\0'
3594 && total+j <= length; j++)
3595 ;
3596 if (total+j >= length || s[total+j] == '\0')
3597 done = TRUE;
3598
3599 MoveTo( gXCenter+item->g.text.p.x,
3600 gYCenter-item->g.text.p.y +
3601 line*(fontInfo.ascent +
3602 fontInfo.descent +
3603 fontInfo.leading));
3604 DrawText(s, total, j);
3605
3606 line++;
3607 total += j+1;
3608 }
3609
3610 if (gColorFlag)
3611 RGBForeColor(&savecolor);
3612 break;
3613 }
3614
3615
3616 SetGWorld(oldGWorld, oldGD);
3617 UnlockPixels(gGP142World->portPixMap);
3618
3619 need_redraw = 1;
3620}
3621
3622
3623
3624#elif defined(WINDOWS)
3625
3626/* The idea here is to actually to the drawing of the object. In fact,
3627when the DrawWndProc() recieves a WM_PAINT message, it will simply loop
3628through the graphics database, calling Draw_Graphic_Item(). For that
3629reason, we don't want to make any Windows API calls that may generate
3630a WM_PAINT message in the graphics window! */
3631static void FAR Draw_Graphic_Item(Graphics *item)
3632{
3633 HBRUSH hBrush, hOldBrush;
3634 HPEN hPen, hOldPen;
3635 HFONT hFont, hOldFont;
3636 POINT pTriPoints[3];
3637 LPSTR pStr;
3638 SIZE textSize;
3639 int done, j, line, total, length, iPrevBackMode;
3640
3641 switch (item->obj_type)
3642 {
3643 case obj_pixel:
3644 SetPixel(offscreen_DC,
3645 gXCenter + item->g.pixel.p.x,
3646 gYCenter - item->g.pixel.p.y,
3647 gRGBColors[item->color]);
3648 break;
3649
3650 case obj_line:
3651 /* If we were using Windows NT, we could call ExtCreatePen,
3652 which would allow for square endcaps of lines. Alas, we're
3653 stuck with Windows 3.1, with round endcaps. Ah, well. */
3654 hPen = CreatePen(PS_SOLID,
3655 item->width,
3656 gRGBColors[item->color]);
3657 /* we want to hold on to the old pen to reset it
3658 after we're done here */
3659 hOldPen = SelectObject(offscreen_DC, hPen);
3660
3661
3662#ifdef WIN32
3663 MoveToEx(offscreen_DC,
3664 gXCenter + item->g.line.upper_left.x,
3665 gYCenter - item->g.line.upper_left.y,
3666 NULL);
3667#else
3668 MoveTo(offscreen_DC,
3669 gXCenter + item->g.line.upper_left.x,
3670 gYCenter - item->g.line.upper_left.y);
3671#endif
3672 LineTo(offscreen_DC,
3673 gXCenter + item->g.line.lower_right.x,
3674 gYCenter - item->g.line.lower_right.y);
3675
3676 SelectObject(offscreen_DC, hOldPen);
3677 DeleteObject(hPen);
3678 break;
3679
3680 case obj_triangle:
3681 hPen = CreatePen(PS_SOLID,
3682 item->width,
3683 gRGBColors[item->color]);
3684 hOldPen = SelectObject(offscreen_DC, hPen);
3685
3686 /* copy the triangle points into a different array */
3687 pTriPoints[0].x = gXCenter + item->g.triangle.p1.x;
3688 pTriPoints[0].y = gYCenter - item->g.triangle.p1.y;
3689 pTriPoints[1].x = gXCenter + item->g.triangle.p2.x;
3690 pTriPoints[1].y = gYCenter - item->g.triangle.p2.y;
3691 pTriPoints[2].x = gXCenter + item->g.triangle.p3.x;
3692 pTriPoints[2].y = gYCenter - item->g.triangle.p3.y;
3693
3694 if (item->width == 0)
3695 hBrush = CreateSolidBrush(gRGBColors[item->color]);
3696 else
3697 hBrush = GetStockObject(HOLLOW_BRUSH);
3698 hOldBrush = SelectObject(offscreen_DC, hBrush);
3699
3700 Polygon(offscreen_DC, pTriPoints, 3);
3701
3702 SelectObject(offscreen_DC, hOldPen);
3703 SelectObject(offscreen_DC, hOldBrush);
3704 DeleteObject(hPen);
3705 DeleteObject(hBrush);
3706 break;
3707
3708 case obj_rectangle:
3709 hPen = CreatePen(PS_SOLID,
3710 item->width,
3711 gRGBColors[item->color]);
3712 /* if width == 0, fill in rectangle */
3713 if (item->width == 0)
3714 hBrush = CreateSolidBrush(gRGBColors[item->color]);
3715 else /* leave rectangle hollow */
3716 hBrush = GetStockObject(HOLLOW_BRUSH);
3717
3718 hOldPen = SelectObject(offscreen_DC, hPen);
3719 hOldBrush = SelectObject(offscreen_DC, hBrush);
3720
3721 /* Windows draws lines in a very odd fashion. Windows
3722 will include the first endpoint when drawing a line, but
3723 _exclude_ the next endpoint. I gather that this allows
3724 for poly-lines, but very strange things happen when you
3725 draw single lines this way. That is why we add 1 to the
3726 ending x and y coords in the rectangle, oval, etc. */
3727 Rectangle(offscreen_DC,
3728 gXCenter + item->g.rectangle.upper_left.x,
3729 gYCenter - item->g.rectangle.upper_left.y,
3730 gXCenter + item->g.rectangle.lower_right.x+1,
3731 gYCenter - item->g.rectangle.lower_right.y+1);
3732
3733 SelectObject(offscreen_DC, hOldPen);
3734 SelectObject(offscreen_DC, hOldBrush);
3735 DeleteObject(hPen);
3736 DeleteObject(hBrush);
3737 break;
3738
3739 case obj_oval:
3740 hPen = CreatePen(PS_SOLID,
3741 item->width,
3742 gRGBColors[item->color]);
3743 /* if width == 0, fill in rectangle */
3744 if (item->width == 0)
3745 hBrush = CreateSolidBrush(gRGBColors[item->color]);
3746 else /* leave rectangle hollow */
3747 hBrush = GetStockObject(HOLLOW_BRUSH);
3748
3749 hOldPen = SelectObject(offscreen_DC, hPen);
3750 hOldBrush = SelectObject(offscreen_DC, hBrush);
3751
3752 Ellipse(offscreen_DC,
3753 gXCenter + item->g.oval.upper_left.x,
3754 gYCenter - item->g.oval.upper_left.y,
3755 gXCenter + item->g.oval.lower_right.x+1,
3756 gYCenter - item->g.oval.lower_right.y+1);
3757
3758 SelectObject(offscreen_DC, hOldPen);
3759 SelectObject(offscreen_DC, hOldBrush);
3760 DeleteObject(hPen);
3761 DeleteObject(hBrush);
3762 break;
3763
3764 case obj_text:
3765 /* Text will be drawn on multiple lines, according to
3766 where newline characters appear. */
3767 /* Text is special in Windows. Text color is set with
3768 a special function, as opposed to the current pen
3769 color. Go figure! */
3770 SetTextColor(offscreen_DC, gRGBColors[item->color]);
3771 /* added by P. Schimpf, v 2.02*/
3772 iPrevBackMode = GetBkMode(offscreen_DC) ;
3773 SetBkMode(offscreen_DC, TRANSPARENT) ;
3774
3775 /* Windows gives us a default font, but the only way
3776 to specify a particular point size is to create a
3777 new font. */
3778 /* the negative number indicates point size as opposed
3779 to pixel size */
3780 hFont = CreateFont(-item->g.text.ptsize,
3781 0, /* let Windows choose width */
3782 0, /* escapement, in 10ths of degrees */
3783 0, /* orientation, in 10ths of degrees */
3784 FW_NORMAL, /* normal weight */
3785 FALSE, /* no italic */
3786 FALSE, /* no underline */
3787 FALSE, /* no strikeout */
3788 ANSI_CHARSET, /* use ANSI character set */
3789 OUT_DEFAULT_PRECIS, /* output precision */
3790 CLIP_DEFAULT_PRECIS, /* clip precision */
3791 DEFAULT_QUALITY, /* quality */
3792 DEFAULT_PITCH | FF_DONTCARE, /* pitch and family */
3793 "GP142-font"); /* way-cool name of font */
3794
3795 hOldFont = SelectObject(offscreen_DC, hFont);
3796
3797 pStr = GlobalLock(item->g.text.hText);
3798
3799 /* To be compatible with the Mac, we want to bump the
3800 text string 'up' by the height of the string */
3801 GetTextExtentPoint(offscreen_DC,
3802 pStr,
3803 far_strlen(pStr),
3804 &textSize);
3805
3806#if 1
3807 /* We want to honor newline characters in the string by
3808 advancing the current line some height */
3809
3810 done = FALSE;
3811 total = 0;
3812 length = far_strlen(pStr);
3813 line = 0;
3814 while (done != TRUE)
3815 {
3816 for (j=0; pStr[total+j] != '\n' &&
3817 pStr[total+j] != '\0' &&
3818 total+j <= length; j++);
3819 if (total+j >= length || pStr[total+j] == '\0')
3820 done = TRUE;
3821
3822 TextOut(offscreen_DC,
3823 gXCenter + item->g.text.p.x,
3824 gYCenter - item->g.text.p.y +
3825 (line-1)*textSize.cy,
3826 pStr + total, j);
3827
3828 line++;
3829 total += j+1;
3830 }
3831#else
3832 TextOut(offscreen_DC,
3833 gXCenter + item->g.text.p.x,
3834 gYCenter - item->g.text.p.y - textSize.cy,
3835 pStr,
3836 far_strlen(pStr));
3837#endif
3838 GlobalUnlock(item->g.text.hText);
3839
3840 SetBkMode(offscreen_DC, iPrevBackMode) ;
3841 SelectObject(offscreen_DC, hOldFont);
3842 DeleteObject(hFont);
3843 break;
3844 }
3845 need_redraw = 1;
3846}
3847
3848#elif defined(X11R6)
3849
3850static void Draw_Graphic_Item(Graphics *item) {
3851
3852 int j, total, line, length, done;
3853 char *s;
3854
3855 if (current_color_id != item->color) {
3856 XSetForeground(display, gc, color_ids[item->color].pixel);
3857 current_color_id = item->color;
3858 }
3859
3860 switch (item->obj_type)
3861 {
3862 case obj_pixel:
3863 XDrawPoint(display, offscreen_buffer, gc,
3864 gXCenter + item->g.pixel.p.x,
3865 gYCenter - item->g.pixel.p.y);
3866 break;
3867
3868 case obj_triangle:
3869 XSetLineAttributes(display, gc, item->width, LineSolid,
3870 CapRound, JoinRound);
3871 if (item->width==0) {
3872 XPoint points[3];
3873 points[0].x = gXCenter+item->g.triangle.p1.x;
3874 points[0].y = gYCenter-item->g.triangle.p1.y;
3875 points[1].x = gXCenter+item->g.triangle.p2.x;
3876 points[1].y = gYCenter-item->g.triangle.p2.y;
3877 points[2].x = gXCenter+item->g.triangle.p3.x;
3878 points[2].y = gYCenter-item->g.triangle.p3.y;
3879 XFillPolygon(display, offscreen_buffer, gc, points, 3,
3880 Convex, CoordModeOrigin);
3881 }
3882
3883 else
3884 XDrawLine(display, offscreen_buffer, gc,
3885 gXCenter+item->g.triangle.p1.x,
3886 gYCenter-item->g.triangle.p1.y,
3887 gXCenter+item->g.triangle.p2.x,
3888 gYCenter-item->g.triangle.p2.y);
3889 XDrawLine(display, offscreen_buffer, gc,
3890 gXCenter+item->g.triangle.p2.x,
3891 gYCenter-item->g.triangle.p2.y,
3892 gXCenter+item->g.triangle.p3.x,
3893 gYCenter-item->g.triangle.p3.y);
3894 XDrawLine(display, offscreen_buffer, gc,
3895 gXCenter+item->g.triangle.p3.x,
3896 gYCenter-item->g.triangle.p3.y,
3897 gXCenter+item->g.triangle.p1.x,
3898 gYCenter-item->g.triangle.p1.y);
3899 break;
3900
3901
3902/* It's a conspiracy. The same problem with excluding the second
3903 * (lower right) endpoint happens in X too for _filled rectangles_.
3904 * Similar solution used, adding 1 to the height and width of the
3905 * filled rectangle drawn. */
3906
3907 case obj_rectangle:
3908 XSetLineAttributes(display, gc, item->width,
3909 LineSolid, CapRound, JoinRound);
3910 if (item->width==0)
3911 XFillRectangle(display, offscreen_buffer, gc,
3912 gXCenter+item->g.rectangle.upper_left.x,
3913 gYCenter-item->g.rectangle.upper_left.y,
3914 item->g.rectangle.lower_right.x
3915 -item->g.rectangle.upper_left.x+1,
3916 item->g.rectangle.upper_left.y
3917 -item->g.rectangle.lower_right.y+1);
3918 else
3919 XDrawRectangle(display, offscreen_buffer, gc,
3920 gXCenter+item->g.rectangle.upper_left.x,
3921 gYCenter-item->g.rectangle.upper_left.y,
3922 item->g.rectangle.lower_right.x
3923 -item->g.rectangle.upper_left.x,
3924 item->g.rectangle.upper_left.y
3925 -item->g.rectangle.lower_right.y);
3926 break;
3927
3928 case obj_line:
3929 XSetLineAttributes(display, gc, item->width,
3930 LineSolid, CapRound, JoinRound);
3931 XDrawLine(display, offscreen_buffer, gc,
3932 gXCenter+item->g.line.upper_left.x,
3933 gYCenter-item->g.line.upper_left.y,
3934 gXCenter+item->g.line.lower_right.x,
3935 gYCenter-item->g.line.lower_right.y);
3936 break;
3937
3938 case obj_oval:
3939 XSetLineAttributes(display, gc, item->width, LineSolid,
3940 CapRound, JoinRound);
3941 if (item->width==0)
3942 XFillArc(display, offscreen_buffer, gc,
3943 gXCenter+item->g.oval.upper_left.x,
3944 gYCenter-item->g.oval.upper_left.y,
3945 item->g.oval.lower_right.x
3946 -item->g.oval.upper_left.x,
3947 item->g.oval.upper_left.y
3948 -item->g.oval.lower_right.y,
3949 0, 23360);
3950 else
3951
3952 /* The 23360 is 365 (degrees) * 64; the angles are signed ints
3953 * in 64ths of a degree. I put 365 degrees for good measure -- it
3954 * automatically truncates anything past 360. */
3955
3956 XDrawArc(display, offscreen_buffer, gc,
3957 gXCenter+item->g.oval.upper_left.x,
3958 gYCenter-item->g.oval.upper_left.y,
3959 item->g.oval.lower_right.x
3960 -item->g.oval.upper_left.x,
3961 item->g.oval.upper_left.y
3962 -item->g.oval.lower_right.y,
3963 0, 23360);
3964 break;
3965
3966 case obj_text:
3967
3968 /* Check to see if the requested font is currently loaded;
3969 * if not, search the list and point temp at it if it's there.
3970 */
3971
3972 if (item->g.text.ptsize != current_font->point_size) {
3973
3974 FontDB *temp = font_info;
3975
3976 while (temp) {
3977 if (item->g.text.ptsize == temp->point_size)
3978 break;
3979 temp = temp->next;
3980 }
3981
3982 /* Or else add it to the list and load it. */
3983
3984 if (!temp) {
3985 char fontname[100];
3986 temp = (FontDB*) malloc(sizeof(FontDB));
3987 sprintf(fontname, "-adobe-helvetica-medium-r-normal--0-%d-75-75-p-0-iso8859-1", item->g.text.ptsize * 10);
3988 if ((temp == NULL) ||
3989 (temp->thefont = XLoadQueryFont(display,
3990 fontname)) == NULL) {
3991 fprintf(stderr, "Cannot open Adobe scalable font.\n");
3992 exit(0);
3993 }
3994
3995 /* Set font to requested point size and put node at
3996 * the head of the list. */
3997
3998 temp->point_size = item->g.text.ptsize;
3999 temp->next = font_info;
4000 font_info = temp;
4001 }
4002
4003 /* Set gc to new point size */
4004
4005 XSetFont(display, gc, temp->thefont->fid);
4006 current_font = temp;
4007 }
4008
4009 /* We want to honor newline characters in the string by
4010 advancing the current line some height */
4011
4012 line = 0, total = 0;
4013 done = FALSE;
4014 s = item->g.text.the_text;
4015 length = strlen(s);
4016 while (done != TRUE) {
4017
4018 for (j = 0; s[total + j] != '\n' && s[total + j] != '\0'
4019 && total + j <= length; j++);
4020
4021 if (total + j >= length || s[total + j] == '\0')
4022 done = TRUE;
4023
4024 XDrawString(display, offscreen_buffer, gc,
4025 gXCenter+item->g.text.p.x,
4026 gYCenter-item->g.text.p.y +
4027 line*(current_font->thefont->ascent+
4028 current_font->thefont->descent),
4029 s+total ,j);
4030 line++;
4031 total += j + 1;
4032 }
4033 break;
4034 }
4035 need_redraw = 1;
4036}
4037
4038#endif
4039
4040/* Show or hide the GP142 text window - zives 6/19/98 */
4041void GP142_show_text(int showit)
4042{
4043#ifdef WINDOWS
4044 ShowWindow(hTextWnd, (showit) ? SW_SHOW : SW_HIDE);
4045#else
4046 showit = 0; /* HACK: kill compiler warnings */
4047#endif
4048}