VPR-7.0
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros
graphics.c
Go to the documentation of this file.
1 /*
2 * Easygl Version 2.0.1
3 * Written by Vaughn Betz at the University of Toronto, Department of *
4 * Electrical and Computer Engineering, with additions by Paul Leventis *
5 * and William Chow of Altera, and Guy Lemieux of the University of *
6 * Brish Columbia. *
7 * All rights reserved by U of T, etc. *
8 * *
9 * You may freely use this graphics interface for non-commercial purposes *
10 * as long as you leave the author info above in it.
11 * *
12 * Revision History: *
13 * *
14 * V2.0.1 Sept. 2012 (Vaughn Betz)
15 * - Fixed a bug in Win32 where postscript output would make the graphics
16 * crash when you redrew.
17 * - Made a cleaner makefile to simplify platform selection.
18 * - Commented and reorganized some of the code. Started cleaning up some of the
19 * win32 code. Win32 looks inefficient; it is saving and updating graphics contexts
20 * all the time even though we know when the context is valid vs. not-valid.
21 * TODO: make win32 work more like X11 (minimize gc updates).
22 *
23 * V2.0: Nov. 21, 2011 (Vaughn Betz)
24 * - Updated example code, and some cleanup and bug fixes to win32 code.
25 * - Removed some win32 code that had no X11 equivalent or wasn't well
26 * documented.
27 * - Used const char * where appropriate to get rid of g++ warnings.
28 * - Made interface to things like xor drawing more consistent, and added to
29 * example program.
30 * - Made a simpler (easygl.cpp) interface to the graphics library for
31 * use by undergraduate students.
32 *
33 * V1.06 : July 23, 2003 : (Guy Lemieux)
34 * - added some typecasts to cleanly compile with g++ and MS c++ tools
35 * - if WIN32 not defined, it defines X11 automatically
36 * - fixed X11 compilation; WIN32 broke some things
37 *
38 * V1.05 : July 26, 2001 : (William) *
39 * - changed keyboard detect function to accept an int (virtual key) *
40 * *
41 * V1.04 : June 29, 2001 : (William) *
42 * - added drawcurve(), fillcurve() using Bezier curves *
43 * (support WIN32 screen / ps) *
44 * - added pt on object capability : using a memory buffer to draw an *
45 * graphics objects, then query if a point fall on the object (bear the *
46 * object's colour) : object_start(), object_end(), pt_on_object() *
47 * - added drawellipticarc(), fillellipticarc() *
48 * - added findfontsize() to help find a pointsize of a given height *
49 * - extended t_report to keep xleft, xright, ytop, ybot *
50 * - added update_window() to set the window bb *
51 * *
52 * V1.03 : June 18, 2001 : (William) *
53 * - added change_button_text() *
54 * *
55 * V1.02 : June 13, 2001 : (William) *
56 * - extension to mouse click function : can tell if ctrl/shift keys are *
57 * pressed *
58 * *
59 * V1.01 : June 1, 2001 : (William) *
60 * - add tooltip support *
61 * *
62 * V1.0 : May 14, 2001 : (William) *
63 * - fixed a problem with line styles, initial release on the internet *
64 * *
65 * March 27, 2001 : (William) *
66 * - added setcolor_by_colorref to make more colors available (in Win32) *
67 * *
68 * February 16, 2001 : (William) *
69 * - added quick zoom using right mouse clicks *
70 * *
71 * February 11, 2001 : (William) *
72 * - can define cleanup(), passed in when calling init_graphics(), and *
73 * called when shutting down *
74 * *
75 * February 1, 2001 : (William) *
76 * - fix xor mode redraw problem *
77 * *
78 * September 19, 2000 : (William) *
79 * - can define mouse_move callback function *
80 * - can add separators in between buttons *
81 * *
82 * September 8, 2000 : (William) *
83 * - added result_structure(), *
84 * - can define background color in init_graphics *
85 * *
86 * August 10, 2000 : (William Chow, choww@eecg.utoronto.ca) *
87 * - Finished all Win32 support functions *
88 * - use XOR mode for window zooming box *
89 * - added double buffering feature *
90 * *
91 * January 12, 1999: (Paul) *
92 * - Fixed a bunch of stuff with the Win32 support (memory leaks, etc) *
93 * - Made the clipping function using the update rectangle for Win32 *
94 * *
95 * January 9, 1999: (Paul Leventis, leventi@eecg.utoronto.ca) *
96 * - Added Win32 support. Should work under Windows98/95/NT 4.0/NT 5.0. *
97 * - Added a check to deselect_all to determine whether the screen needs to *
98 * be updated or not. Should elminate flicker from mouse clicks *
99 * - Added invalidate_screen() call to graphics.c that in turn calls *
100 * update_screen, so this function was made non-static and added to the *
101 * header file. This is due to differences in the structure of Win32 *
102 * windowing apps. *
103 * - Win32 needs clipping (though done automatically, could be faster) *
104 * *
105 * Sept. 19, 1997: Incorporated Zoom Fit code of Haneef Mohammed at *
106 * Cypress. Makes it easy to zoom to a full view of the graphics. *
107 * *
108 * Sept. 11, 1997: Added the create_and destroy_button interface to *
109 * make it easy to add and destroy buttons from user code. Removed the *
110 * bnum parameter to the button functions, since it wasn't really needed. *
111 * *
112 * June 28, 1997: Added filled arc drawing primitive. Minor modifications *
113 * to PostScript driver to make the PostScript output slightly smaller. *
114 * *
115 * April 15, 1997: Added code to init_graphics so it waits for a window *
116 * to be exposed before returning. This ensures that users of non- *
117 * interactive graphics can never draw to a window before it is available. *
118 * *
119 * Feb. 24, 1997: Added code so the package will allocate a private *
120 * colormap if the default colormap doesn't have enough free colours. *
121 * *
122 * June 28, 1996: Converted all internal functions in graphics.c to have *
123 * internal (static) linkage to avoid any conflicts with user routines in *
124 * the rest of the program. *
125 * *
126 * June 12, 1996: Added setfontsize and setlinewidth attributes. Added *
127 * pre-clipping of objects for speed (and compactness of PS output) when *
128 * graphics are zoomed in. Rewrote PostScript engine to shrink the output *
129 * and make it easier to read. Made drawscreen a callback function passed *
130 * in rather than a global. Graphics attribute calls are more efficient -- *
131 * they check if they have to change anything before doing it. *
132 * *
133 * October 27, 1995: Added the message area, a callback function for *
134 * interacting with user button clicks, and implemented a workaround for a *
135 * Sun X Server bug that misdisplays extremely highly zoomed graphics. *
136 * *
137 * Jan. 13, 1995: Modified to incorporate PostScript Support. */
138 
139 #ifndef NO_GRAPHICS // Strip everything out and just put in stubs if NO_GRAPHICS defined
140 
141 /**********************************
142  * Common Preprocessor Directives *
143  **********************************/
144 
145 #define TRUE 1
146 #define FALSE 0
147 
148 #include <math.h>
149 #include <stdlib.h>
150 #include <stdio.h>
151 #include <string.h>
152 #include <string>
153 #include <iostream>
154 #include "graphics.h"
155 using namespace std;
156 
157 
158 #if defined(X11) || defined(WIN32)
159 
160 /* Macros for translation from world to PostScript coordinates */
161 #define XPOST(worldx) (((worldx)-xleft)*ps_xmult + ps_left)
162 #define YPOST(worldy) (((worldy)-ybot)*ps_ymult + ps_bot)
163 
164 /* Macros to convert from X Windows Internal Coordinates to my *
165 * World Coordinates. (This macro is used only rarely, so *
166 * the divides don't hurt speed). */
167 #define XTOWORLD(x) (((float) x)*xdiv + xleft)
168 #define YTOWORLD(y) (((float) y)*ydiv + ytop)
169 
170 #ifndef max
171 #define max(a,b) (((a) > (b))? (a) : (b))
172 #endif
173 #ifndef min
174 #define min(a,b) ((a) > (b)? (b) : (a))
175 #endif
176 
177 #define MWIDTH 104 /* width of menu window */
178 #define T_AREA_HEIGHT 24 /* Height of text window */
179 #define MAX_FONT_SIZE 24 /* Largest point size of text. */
180  // Some computers only have up to 24 point
181 #define PI 3.141592654
182 
183 #define BUTTON_TEXT_LEN 100
184 #define BUFSIZE 1000
185 #endif
186 
187 /*********************************************
188 * X-Windows Specific Preprocessor Directives *
189 *********************************************/
190 #ifdef X11
191 
192 #include <X11/Xlib.h>
193 #include <X11/Xutil.h>
194 #include <X11/Xos.h>
195 #include <X11/Xatom.h>
196 
197 /* Uncomment the line below if your X11 header files don't define XPointer */
198 /* typedef char *XPointer; */
199 
200 // Really large pixel values cna make some X11 implementations draw crazy things
201 // (internal overflow in the X11 library). Use these constants to clip.
202 #define MAXPIXEL 15000
203 #define MINPIXEL -15000
204 
205 #endif /* X11 Preprocessor Directives */
206 
207 
208 /*************************************************************
209  * Microsoft Windows (WIN32) Specific Preprocessor Directives *
210  *************************************************************/
211 #ifdef WIN32
212 #pragma warning(disable : 4996) // Turn off annoying warnings about strcmp.
213 
214 #include <windows.h>
215 
216 // Lines below are for displaying errors in a message box on windows.
217 #define SELECT_ERROR() { char msg[BUFSIZE]; sprintf (msg, "Error %i: Couldn't select graphics object on line %d of graphics.c\n", GetLastError(), __LINE__); MessageBox(NULL, msg, NULL, MB_OK); exit(-1); }
218 #define DELETE_ERROR() { char msg[BUFSIZE]; sprintf (msg, "Error %i: Couldn't delete graphics object on line %d of graphics.c\n", GetLastError(), __LINE__); MessageBox(NULL, msg, NULL, MB_OK); exit(-1); }
219 #define CREATE_ERROR() { char msg[BUFSIZE]; sprintf (msg, "Error %i: Couldn't create graphics object on line %d of graphics.c\n", GetLastError(), __LINE__); MessageBox(NULL, msg, NULL, MB_OK); exit(-1); }
220 #define DRAW_ERROR() { char msg[BUFSIZE]; sprintf (msg, "Error %i: Couldn't draw graphics object on line %d of graphics.c\n", GetLastError(), __LINE__); MessageBox(NULL, msg, NULL, MB_OK); exit(-1); }
221 
222 /* Avoid funny clipping problems under windows that I suspect are caused by round-off
223  * in the Win32 libraries.
224  */
225 #define MAXPIXEL 3000
226 #define MINPIXEL -3000
227 
228 #define DEGTORAD(x) ((x)/180.*PI)
229 #define FONTMAG 1.3
230 #endif /* Win32 preprocessor Directives */
231 
232 
233 /*************************************************************
234  * Common Type Definitions *
235  *************************************************************/
236 
237 /* Used to define where the output of drawscreen (graphics primitives in the user-controlled
238  * area) currently goes to: the screen or a postscript file.
239  */
240 typedef enum {
241  SCREEN = 0,
244 
245 
246 /* Indicates if this button displays text, a polygon or is just a separator.
247  */
248 typedef enum {
252 } t_button_type;
253 
254 
255 /* Structure used to define the buttons on the right hand side of the main window (menu region).
256  * width, height: button size, in pixels.
257  * xleft, ytop: coordinates, in pixels, of the top-left corner of the button relative to its
258  * containing (menu) window.
259  * fcn: a callback function that is called when the button is pressed. This function takes one
260  * argument, a function pointer to the routine that can draw the graphics area (user routine).
261  * win, hwnd: X11 and Win32 data pointer to the window, respectively.
262  * button_type: indicates if this button displays text, a polygon or is just a separator.
263  * text: the text to display if this is a text button.
264  * poly: the polygon (up to 3 points right now) to display if this is a polygon button
265  * is_pressed: has the button been pressed, and is currently executing its callback?
266  * is_enabled: can you press this button right now? Visually will look "pushed in" when
267  * not enabled, and won't respond to clicks.
268  */
269 typedef struct {
270  int width;
271  int height;
272  int xleft;
273  int ytop;
274  void (*fcn) (void (*drawscreen) (void));
275 #ifdef X11
276  Window win;
277 #else
278  HWND hwnd;
279 #endif
281  char text[BUTTON_TEXT_LEN];
282  int poly[3][2];
283  bool ispressed;
284  bool enabled;
285 } t_button;
286 
287 
288 /* Structure used to store overall graphics state variables.
289  * TODO: Gradually move more file scope variables in here.
290  * initialized: true if the graphics window & state have been
291  * created and initialized, false otherwise.
292  * disp_type: Selects SCREEN or POSTSCRIPT
293  * background_cindex: index of the window (or page for PS) background colour
294  */
295 typedef struct {
299 } t_gl_state;
300 
301 
302 /*********************************************************************
303  * File scope variables. TODO: group in structs *
304  *********************************************************************/
305 
306 // Need to initialize graphics_loaded to false, since checking it is
307 // how we avoid multiple construction or destruction of the graphics
308 // window.
309 static t_gl_state gl_state = {false, SCREEN, 0};
310 
311 static const int menu_font_size = 12; /* Font for menus and dialog boxes. */
312 
313 static t_button *button = NULL; /* [0..num_buttons-1] */
314 static int num_buttons = 0; /* Number of menu buttons */
315 
316 static int display_width, display_height; /* screen size */
317 static int top_width, top_height; /* window size */
318 static float xleft, xright, ytop, ybot; /* world coordinates */
320 
321 static float ps_left, ps_right, ps_top, ps_bot; /* Figure boundaries for *
322 * PostScript output, in PostScript coordinates. */
323 static float ps_xmult, ps_ymult; /* Transformation for PostScript. */
324 static float xmult, ymult; /* Transformation factors */
325 static float xdiv, ydiv;
326 
327 static int currentcolor;
328 static int currentlinestyle;
329 static int currentlinewidth;
330 static int currentfontsize;
332 
333 /* For PostScript output */
334 static FILE *ps;
335 
336 static int ProceedPressed;
337 
338 static char statusMessage[BUFSIZE] = ""; /* User message to display */
339 
340 static bool font_is_loaded[MAX_FONT_SIZE + 1];
342 static const char *ps_cnames[NUM_COLOR] = {"white", "black", "grey55", "grey75",
343  "blue", "green", "yellow", "cyan", "red", "darkgreen", "magenta",
344  "bisque", "lightblue", "thistle", "plum", "khaki", "coral",
345  "turquoise", "mediumpurple", "darkslateblue", "darkkhaki"};
346 
347 
348 /*********************************************
349  * Common Subroutine Declarations *
350  *********************************************/
351 
352 static void *my_malloc(int ibytes);
353 static void *my_realloc(void *memblk, int ibytes);
354 static int xcoord (float worldx);
355 static int ycoord (float worldy);
356 static void force_setcolor(int cindex);
357 static void force_setlinestyle(int linestyle);
358 static void force_setlinewidth(int linewidth);
359 static void force_setfontsize (int pointsize);
360 static void load_font(int pointsize);
361 
362 static void reset_common_state ();
363 static void build_default_menu (void);
364 
365 /* Function declarations for button responses */
366 static void translate_up (void (*drawscreen) (void));
367 static void translate_left (void (*drawscreen) (void));
368 static void translate_right (void (*drawscreen) (void));
369 static void translate_down (void (*drawscreen) (void));
370 static void zoom_in (void (*drawscreen) (void));
371 static void zoom_out (void (*drawscreen) (void));
372 static void zoom_fit (void (*drawscreen) (void));
373 static void adjustwin (void (*drawscreen) (void));
374 static void postscript (void (*drawscreen) (void));
375 static void proceed (void (*drawscreen) (void));
376 static void quit (void (*drawscreen) (void));
377 static void map_button (int bnum);
378 static void unmap_button (int bnum);
379 
380 #ifdef X11
381 
382 /*************************************************
383 * X-Windows Specific File-scope Variables *
384 **************************************************/
385 static Display *display;
386 static int screen_num;
388 static XFontStruct *font_info[MAX_FONT_SIZE+1]; /* Data for each size */
389 static Window toplevel, menu, textarea; /* various windows */
390 static Colormap private_cmap; /* "None" unless a private cmap was allocated. */
391 
392 /* Color indices passed back from X Windows. */
393 static int colors[NUM_COLOR];
394 
395 
396 /****************************************************
397 * X-Windows Specific Subroutine Declarations *
398 *****************************************************/
399 
400 static Bool test_if_exposed (Display *disp, XEvent *event_ptr,
401  XPointer dummy);
402 static void build_textarea (void);
403 static void drawbut (int bnum);
404 static int which_button (Window win);
405 
406 static void turn_on_off (int pressed);
407 static void drawmenu(void);
408 
409 #endif /* X11 Declarations */
410 
411 
412 
413 #ifdef WIN32
414 
415 /*****************************************************
416  * Microsoft Windows (Win32) File Scope Variables *
417  *****************************************************/
418 static const int win32_line_styles[2] = { PS_SOLID, PS_DASH };
419 
420 static const COLORREF win32_colors[NUM_COLOR] = { RGB(255, 255, 255),
421 RGB(0, 0, 0), RGB(128, 128, 128), RGB(192, 192, 192), RGB(0, 0, 255),
422 RGB(0, 255, 0), RGB(255, 255, 0), RGB(0, 255, 255), RGB(255, 0, 0), RGB(0, 128, 0),
423 RGB(255, 0, 255), RGB(255, 228, 196), RGB(173, 216, 230), RGB(216, 191, 216), RGB(221, 160, 221),
424 RGB(240, 230, 140), RGB(255, 127, 80), RGB(64, 224, 208), RGB(147, 112, 219), RGB(72, 61, 139),
425 RGB(189, 183, 107)};
426 
427 static TCHAR szAppName[256],
428 szGraphicsName[] = TEXT("VPR Graphics"),
429 szStatusName[] = TEXT("VPR Status"),
430 szButtonsName[] = TEXT("VPR Buttons");
431 static HPEN hGraphicsPen;
432 static HBRUSH hGraphicsBrush, hGrayBrush;
433 static HDC hGraphicsDC, hForegroundDC, hBackgroundDC,
434 hCurrentDC, /* WC : double-buffer */
435 hObjtestDC, hAllObjtestDC; /* object test */
436 
437 /* WC */
438 static HFONT hGraphicsFont;
439 static LOGFONT *font_info[MAX_FONT_SIZE+1]; /* Data for each size */
440 
441 /* Handles to the top level window and 3 subwindows. */
442 static HWND hMainWnd, hGraphicsWnd, hButtonsWnd, hStatusWnd;
443 
444 static int cxClient, cyClient;
445 
446 /* These are used for the "Window" graphics button. They keep track of whether we're entering
447  * the window rectangle to zoom to, etc.
448  */
449 static int windowAdjustFlag = 0, adjustButton = -1;
450 static RECT adjustRect, updateRect;
451 
452 static boolean InEventLoop = FALSE;
453 
454 //static HBITMAP buttonImages[4];
455 
456 
457 /*******************************************************************
458  * Win32-specific subroutine declarations *
459  *******************************************************************/
460 
461 /* Callback functions for the top-level window and 3 sub-windows.
462  * Windows uses an odd mix of events and callbacks, so it needs these.
463  */
464 static LRESULT CALLBACK GraphicsWND(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
465 static LRESULT CALLBACK StatusWND(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
466 static LRESULT CALLBACK ButtonsWND(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
467 static LRESULT CALLBACK MainWND(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
468 
469 
470 // For Win32, need to save pointers to these callback functions at file
471 // scope, since windows has a bizarre event loop structure where you poll
472 // for events, but then dispatch the event and get called via a callback
473 // from windows (GraphicsWND, below). I can't figure out why windows
474 // does things this way, but it is what makes saving these function pointers
475 // necessary. VB.
476 
477 static void (*mouseclick_ptr)(float x, float y);
478 static void (*mousemove_ptr)(float x, float y);
479 static void (*keypress_ptr)(char entered_char);
480 static void (*drawscreen_ptr)(void);
481 
482 static void invalidate_screen();
483 
484 static void reset_win32_state ();
485 static void win32_drain_message_queue ();
486 
487 void drawtoscreen();
488 void displaybuffer();
489 
490 
491 #endif /* Win32 Declarations */
492 
493 /*********************************************************
494  * Common Subroutine Definitions *
495  *********************************************************/
496 
497 
498 /* safer malloc */
499 static void *my_malloc(int ibytes) {
500  void *mem;
501 
502  mem = (void*)malloc(ibytes);
503  if (mem == NULL) {
504  printf("memory allocation failed!");
505  exit(-1);
506  }
507 
508  return mem;
509 }
510 
511 /* safer realloc */
512 static void *my_realloc(void *memblk, int ibytes) {
513  void *mem;
514 
515  mem = (void*)realloc(memblk, ibytes);
516  if (mem == NULL) {
517  printf("memory allocation failed!");
518  exit(-1);
519  }
520 
521  return mem;
522 }
523 
524 
525 /* Translates from my internal coordinates to real-world coordinates *
526 * in the x direction. Add 0.5 at end for extra half-pixel accuracy. */
527 static int xcoord (float worldx)
528 {
529  int winx;
530 
531  winx = (int) ((worldx-xleft)*xmult + 0.5);
532 
533  /* Avoids overflow in the Window routines. This will allow horizontal *
534  * and vertical lines to be drawn correctly regardless of zooming, but *
535  * will cause diagonal lines that go way off screen to change their *
536  * slope as you zoom in. The only way I can think of to completely fix *
537  * this problem is to do all the clipping in advance in floating point, *
538  * then convert to integers and call Windows. This is a lot of extra *
539  * coding, and means that coordinates will be clipped twice, even though *
540  * this "Super Zoom" problem won't occur unless users zoom way in on *
541  * the graphics. */
542 
543  winx = max (winx, MINPIXEL);
544  winx = min (winx, MAXPIXEL);
545 
546  return (winx);
547 }
548 
549 
550 /* Translates from my internal coordinates to real-world coordinates *
551 * in the y direction. Add 0.5 at end for extra half-pixel accuracy. */
552 static int ycoord (float worldy)
553 {
554  int winy;
555 
556  winy = (int) ((worldy-ytop)*ymult + 0.5);
557 
558  /* Avoid overflow in the X/Win32 Window routines. */
559  winy = max (winy, MINPIXEL);
560  winy = min (winy, MAXPIXEL);
561 
562  return (winy);
563 }
564 
565 
566 #ifdef WIN32
567 static void invalidate_screen(void)
568 {
569 /* Tells the graphics engine to redraw the graphics display since information has changed */
570 
571  if(!InvalidateRect(hGraphicsWnd, NULL, FALSE))
572  DRAW_ERROR();
573  if(!UpdateWindow(hGraphicsWnd))
574  DRAW_ERROR();
575 }
576 #endif
577 
578 /* Sets the current graphics context colour to cindex, regardless of whether we think it is
579  * needed or not.
580  */
581 static void force_setcolor (int cindex)
582 {
583  currentcolor = cindex;
584 
585  if (gl_state.disp_type == SCREEN) {
586 #ifdef X11
587  XSetForeground (display, current_gc, colors[cindex]);
588 #else /* Win32 */
589  int win_linestyle;
590  LOGBRUSH lb;
591  lb.lbStyle = BS_SOLID;
592  lb.lbColor = win32_colors[cindex];
593  lb.lbHatch = (LONG)NULL;
594  win_linestyle = win32_line_styles[currentlinestyle];
595 
596  if(!DeleteObject(hGraphicsPen))
597  DELETE_ERROR();
598 
599  int linewidth = max (currentlinewidth, 1); // Win32 won't draw 0 width dashed lines.
600  hGraphicsPen = ExtCreatePen(PS_GEOMETRIC | win_linestyle |
601  PS_ENDCAP_FLAT, linewidth, &lb, (LONG)NULL, NULL);
602  if(!hGraphicsPen)
603  CREATE_ERROR();
604 
605  if(!DeleteObject(hGraphicsBrush))
606  DELETE_ERROR();
607  hGraphicsBrush = CreateSolidBrush(win32_colors[currentcolor]);
608  if(!hGraphicsBrush)
609  CREATE_ERROR();
610 #endif
611  }
612  else {
613  fprintf (ps,"%s\n", ps_cnames[cindex]);
614  }
615 }
616 
617 
618 /* Sets the current graphics context colour to cindex if it differs from the old colour */
619 void setcolor (int cindex)
620 {
621  if (currentcolor != cindex)
622  force_setcolor (cindex);
623 
624 }
625 
626 
627 /* Sets the current graphics context color to the index that corresponds to the
628  * string name passed in. Slower, but maybe more convenient for simple
629  * client code.
630  */
631 void setcolor (string cname) {
632  int icolor = -1;
633  for (int i = 0; i < NUM_COLOR; i++) {
634  if (cname == ps_cnames[i]) {
635  icolor = i;
636  break;
637  }
638  }
639  if (icolor == -1) {
640  cout << "Error: unknown color " << cname << endl;
641  }
642  else {
643  setcolor (icolor);
644  }
645 }
646 
647 int getcolor() {
648  return currentcolor;
649 }
650 
651 /* Sets the current linestyle to linestyle in the graphics context.
652  * Note SOLID is 0 and DASHED is 1 for linestyle.
653  */
654 static void force_setlinestyle (int linestyle)
655 {
656  currentlinestyle = linestyle;
657 
658  if (gl_state.disp_type == SCREEN) {
659 
660 #ifdef X11
661  static int x_vals[2] = {LineSolid, LineOnOffDash};
662  XSetLineAttributes (display, current_gc, currentlinewidth, x_vals[linestyle],
663  CapButt, JoinMiter);
664 #else // Win32
665  LOGBRUSH lb;
666  lb.lbStyle = BS_SOLID;
667  lb.lbColor = win32_colors[currentcolor];
668  lb.lbHatch = (LONG)NULL;
669  int win_linestyle = win32_line_styles[linestyle];
670 
671  if(!DeleteObject(hGraphicsPen))
672  DELETE_ERROR();
673  int linewidth = max (currentlinewidth, 1); // Win32 won't draw 0 width dashed lines.
674  hGraphicsPen = ExtCreatePen(PS_GEOMETRIC | win_linestyle |
675  PS_ENDCAP_FLAT, linewidth, &lb, (LONG)NULL, NULL);
676  if(!hGraphicsPen)
677  CREATE_ERROR();
678 #endif
679  }
680 
681  else {
682  if (linestyle == SOLID)
683  fprintf (ps,"linesolid\n");
684  else if (linestyle == DASHED)
685  fprintf (ps, "linedashed\n");
686  else {
687  printf ("Error: invalid linestyle: %d\n", linestyle);
688  exit (1);
689  }
690  }
691 }
692 
693 
694 /* Change the linestyle in the graphics context only if it differs from the current
695  * linestyle.
696  */
697 void setlinestyle (int linestyle)
698 {
699  if (linestyle != currentlinestyle)
700  force_setlinestyle (linestyle);
701 }
702 
703 
704 /* Sets current linewidth in the graphics context.
705  * linewidth should be greater than or equal to 0 to make any sense.
706  */
707 static void force_setlinewidth (int linewidth)
708 {
709  currentlinewidth = linewidth;
710 
711  if (gl_state.disp_type == SCREEN) {
712 
713 #ifdef X11
714  static int x_vals[2] = {LineSolid, LineOnOffDash};
715  XSetLineAttributes (display, current_gc, linewidth, x_vals[currentlinestyle],
716  CapButt, JoinMiter);
717 #else /* Win32 */
718  LOGBRUSH lb;
719  lb.lbStyle = BS_SOLID;
720  lb.lbColor = win32_colors[currentcolor];
721  lb.lbHatch = (LONG)NULL;
722  int win_linestyle = win32_line_styles[currentlinestyle];
723 
724  if(!DeleteObject(hGraphicsPen))
725  DELETE_ERROR();
726  if (linewidth == 0)
727  linewidth = 1; // Win32 won't draw dashed 0 width lines.
728  hGraphicsPen = ExtCreatePen(PS_GEOMETRIC | win_linestyle |
729  PS_ENDCAP_FLAT, linewidth, &lb, (LONG)NULL, NULL);
730  if(!hGraphicsPen)
731  CREATE_ERROR();
732 #endif
733  }
734 
735  else {
736  fprintf(ps,"%d setlinewidth\n", linewidth);
737  }
738 }
739 
740 
741 /* Sets the linewidth in the grahpics context, if it differs from the current value.
742  */
743 void setlinewidth (int linewidth)
744 {
745  if (linewidth != currentlinewidth)
746  force_setlinewidth (linewidth);
747 }
748 
749 
750 /* Force the selected fontsize to be applied to the graphics context,
751  * whether or not it appears to match the current fontsize. This is necessary
752  * when switching between postscript and window out, for example.
753  * Valid point sizes are between 1 and MAX_FONT_SIZE.
754  */
755 static void force_setfontsize (int pointsize)
756 {
757 
758  if (pointsize < 1)
759  pointsize = 1;
760 #ifdef WIN32
761  pointsize = (int)((float)pointsize * FONTMAG);
762 #endif
763  if (pointsize > MAX_FONT_SIZE)
764  pointsize = MAX_FONT_SIZE;
765 
766  currentfontsize = pointsize;
767 
768  if (gl_state.disp_type == SCREEN) {
769  load_font (pointsize);
770 #ifdef X11
771  XSetFont(display, current_gc, font_info[pointsize]->fid);
772 #else /* Win32 */
773  if(!DeleteObject(hGraphicsFont))
774  DELETE_ERROR();
775  hGraphicsFont = CreateFontIndirect(font_info[pointsize]);
776  if(!hGraphicsFont)
777  CREATE_ERROR();
778  if(!SelectObject(hGraphicsDC, hGraphicsFont) )
779  SELECT_ERROR();
780 
781 #endif
782  }
783 
784  else {
785  /* PostScript: set up font and centering function */
786  fprintf(ps,"%d setfontsize\n",pointsize);
787  }
788 }
789 
790 
791 /* For efficiency, this routine doesn't do anything if no change is
792  * implied. If you want to force the graphics context or PS file
793  * to have font info set, call force_setfontsize (this is necessary
794  * in initialization and X11 / Postscript switches).
795  */
796 void setfontsize (int pointsize)
797 {
798 
799  if (pointsize != currentfontsize)
800  force_setfontsize (pointsize);
801 }
802 
803 
804 /* Puts a triangle in the poly array for button[bnum]. Haven't made this work for
805  * win32 yet and instead put "U", "D" excetra on the arrow buttons.
806  * VB To-do: make work for win32 someday.
807  */
808 #ifdef X11
809 static void setpoly (int bnum, int xc, int yc, int r, float theta)
810 {
811  int i;
812 
813  button[bnum].type = BUTTON_POLY;
814  for (i=0;i<3;i++) {
815  button[bnum].poly[i][0] = (int) (xc + r*cos(theta) + 0.5);
816  button[bnum].poly[i][1] = (int) (yc + r*sin(theta) + 0.5);
817  theta += (float)(2*PI/3);
818  }
819 }
820 #endif // X11
821 
822 
823 /* Maps a button onto the screen and set it up for input, etc. */
824 static void map_button (int bnum)
825 {
826  button[bnum].ispressed = 0;
827 
828  if (button[bnum].type != BUTTON_SEPARATOR) {
829 #ifdef X11
830  button[bnum].win = XCreateSimpleWindow(display,menu,
831  button[bnum].xleft, button[bnum].ytop, button[bnum].width,
832  button[bnum].height, 0, colors[WHITE], colors[LIGHTGREY]);
833  XMapWindow (display, button[bnum].win);
834  XSelectInput (display, button[bnum].win, ButtonPressMask);
835 #else
836  button[bnum].hwnd = CreateWindow( TEXT("button"), TEXT(button[bnum].text),
837  WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, button[bnum].xleft, button[bnum].ytop,
838  button[bnum].width, button[bnum].height, hButtonsWnd, (HMENU)(200+bnum),
839  (HINSTANCE) GetWindowLong(hMainWnd, GWL_HINSTANCE), NULL);
840  if(!InvalidateRect(hButtonsWnd, NULL, TRUE))
841  DRAW_ERROR();
842  if(!UpdateWindow(hButtonsWnd))
843  DRAW_ERROR();
844 #endif
845  }
846  else { // Separator, not a button.
847 #ifdef X11
848  button[bnum].win = -1;
849 #else // WIN32
850  button[bnum].hwnd = NULL;
851  if(!InvalidateRect(hButtonsWnd, NULL, TRUE))
852  DRAW_ERROR();
853  if(!UpdateWindow(hButtonsWnd))
854  DRAW_ERROR();
855 #endif
856  }
857 }
858 
859 
860 static void unmap_button (int bnum)
861 {
862  /* Unmaps (removes) a button from the screen. */
863  if (button[bnum].type != BUTTON_SEPARATOR) {
864 #ifdef X11
865  XUnmapWindow (display, button[bnum].win);
866 #else
867  if(!DestroyWindow(button[bnum].hwnd))
868  DRAW_ERROR();
869  if(!InvalidateRect(hButtonsWnd, NULL, TRUE))
870  DRAW_ERROR();
871  if(!UpdateWindow(hButtonsWnd))
872  DRAW_ERROR();
873 #endif
874  }
875 }
876 
877 
878 /* Creates a new button below the button containing prev_button_text. *
879 * The text and button function are set according to button_text and *
880 * button_func, respectively. */
881 void create_button (const char *prev_button_text , const char *button_text,
882  void (*button_func) (void (*drawscreen) (void)))
883 {
884  int i, bnum, space, bheight;
885  t_button_type button_type = BUTTON_TEXT;
886 
887  space = 8;
888 
889  /* Only allow new buttons that are text or separator (not poly) types.
890  * They can also only go after buttons that are text buttons.
891  */
892 
893  bnum = -1;
894 
895  for (i=0; i < num_buttons;i++) {
896  if (button[i].type == BUTTON_TEXT &&
897  strcmp (button[i].text, prev_button_text) == 0) {
898  bnum = i + 1;
899  break;
900  }
901  }
902 
903  if (bnum == -1) {
904  printf ("Error in create_button: button with text %s not found.\n",
905  prev_button_text);
906  exit (1);
907  }
908 
909  button = (t_button *) my_realloc (button, (num_buttons+1) * sizeof (t_button));
910  /* NB: Requirement that you specify the button that this button goes under *
911  * guarantees that button[num_buttons-2] exists and is a text button. */
912 
913  /* Special string to make a separator. */
914  if (!strncmp(button_text, "---", 3)) {
915  bheight = 2;
916  button_type = BUTTON_SEPARATOR;
917  }
918  else
919  bheight = 26;
920 
921  for (i=num_buttons;i>bnum;i--) {
922  button[i].xleft = button[i-1].xleft;
923  button[i].ytop = button[i-1].ytop + bheight + space;
924  button[i].height = button[i-1].height;
925  button[i].width = button[i-1].width;
926  button[i].type = button[i-1].type;
927  strcpy (button[i].text, button[i-1].text);
928  button[i].fcn = button[i-1].fcn;
929  button[i].ispressed = button[i-1].ispressed;
930  button[i].enabled = button[i-1].enabled;
931  unmap_button (i-1);
932  }
933 
934  i = bnum;
935  button[i].xleft = 6;
936  button[i].ytop = button[i-1].ytop + button[i-1].height + space;
937  button[i].height = bheight;
938  button[i].width = 90;
939  button[i].type = button_type;
940  strncpy (button[i].text, button_text, BUTTON_TEXT_LEN);
941  button[i].fcn = button_func;
942  button[i].ispressed = false;
943  button[i].enabled = true;
944 
945  num_buttons++;
946 
947  for (i = 0; i<num_buttons;i++)
948  map_button (i);
949 }
950 
951 
952 /* Destroys the button with text button_text. */
953 void
954 destroy_button (const char *button_text)
955 {
956  int i, bnum, space, bheight;
957 
958  bnum = -1;
959  space = 8;
960  for (i = 0; i < num_buttons; i++) {
961  if (button[i].type == BUTTON_TEXT &&
962  strcmp (button[i].text, button_text) == 0) {
963  bnum = i;
964  break;
965  }
966  }
967 
968  if (bnum == -1) {
969  printf ("Error in destroy_button: button with text %s not found.\n",
970  button_text);
971  exit (1);
972  }
973 
974  bheight = button[bnum].height;
975 
976  for (i=bnum+1;i<num_buttons;i++) {
977  button[i-1].xleft = button[i].xleft;
978  button[i-1].ytop = button[i].ytop - bheight - space;
979  button[i-1].height = button[i].height;
980  button[i-1].width = button[i].width;
981  button[i-1].type = button[i].type;
982  strcpy (button[i-1].text, button[i].text);
983  button[i-1].fcn = button[i].fcn;
984  button[i-1].ispressed = button[i].ispressed;
985  button[i-1].enabled = button[i].enabled;
986  unmap_button (i);
987  }
988  unmap_button(bnum);
989 
990  button = (t_button *) my_realloc (button, (num_buttons-1) * sizeof (t_button));
991 
992  num_buttons--;
993 
994  for (i=bnum; i<num_buttons;i++)
995  map_button (i);
996 }
997 
998 
999 /* Open the toplevel window, get the colors, 2 graphics *
1000 * contexts, load a font, and set up the toplevel window *
1001 * Calls build_default_menu to set up the default menu. */
1002 void
1003 init_graphics (const char *window_name, int cindex)
1004 {
1005  if (gl_state.initialized) // Singleton graphics.
1006  return;
1007 
1008  reset_common_state ();
1009 #ifdef WIN32
1010  reset_win32_state ();
1011 #endif
1012 
1014  gl_state.background_cindex = cindex;
1015 
1016 
1017 #ifdef X11
1018  char *display_name = NULL;
1019  int x, y; /* window position */
1020  unsigned int border_width = 2; /* ignored by OpenWindows */
1021  XTextProperty windowName;
1022 
1023  /* X Windows' names for my colours. */
1024  const char *cnames[NUM_COLOR] = {"white", "black", "grey55", "grey75", "blue",
1025  "green", "yellow", "cyan", "red", "RGBi:0.0/0.5/0.0", "magenta",
1026  "bisque", "lightblue", "thistle", "plum", "khaki", "coral",
1027  "turquoise", "mediumpurple", "darkslateblue", "darkkhaki" };
1028 
1029  XColor exact_def;
1030  Colormap cmap;
1031  unsigned long valuemask = 0; /* ignore XGCvalues and use defaults */
1032  XGCValues values;
1033  XEvent event;
1034 
1035  /* connect to X server */
1036  if ( (display=XOpenDisplay(display_name)) == NULL )
1037  {
1038  fprintf( stderr, "Cannot connect to X server %s\n",
1039  XDisplayName(display_name));
1040  exit( -1 );
1041  }
1042 
1043  /* get screen size from display structure macro */
1044  screen_num = DefaultScreen(display);
1045  display_width = DisplayWidth(display, screen_num);
1046  display_height = DisplayHeight(display, screen_num);
1047 
1048  x = 0;
1049  y = 0;
1050 
1051  top_width = 2 * display_width / 3;
1052  top_height = 4 * display_height / 5;
1053 
1054  cmap = DefaultColormap(display, screen_num);
1055  private_cmap = None;
1056 
1057  for (int i=0;i<NUM_COLOR;i++) {
1058  if (!XParseColor(display,cmap,cnames[i],&exact_def)) {
1059  fprintf(stderr, "Color name %s not in database", cnames[i]);
1060  exit(-1);
1061  }
1062  if (!XAllocColor(display, cmap, &exact_def)) {
1063  fprintf(stderr, "Couldn't allocate color %s.\n",cnames[i]);
1064 
1065  if (private_cmap == None) {
1066  fprintf(stderr, "Will try to allocate a private colourmap.\n");
1067  fprintf(stderr, "Colours will only display correctly when your "
1068  "cursor is in the graphics window.\n"
1069  "Exit other colour applications and rerun this "
1070  "program if you don't like that.\n\n");
1071 
1072  private_cmap = XCopyColormapAndFree (display, cmap);
1073  cmap = private_cmap;
1074  if (!XAllocColor (display, cmap, &exact_def)) {
1075  fprintf (stderr, "Couldn't allocate color %s as private.\n",
1076  cnames[i]);
1077  exit (1);
1078  }
1079  }
1080 
1081  else {
1082  fprintf (stderr, "Couldn't allocate color %s as private.\n",
1083  cnames[i]);
1084  exit (1);
1085  }
1086  }
1087  colors[i] = exact_def.pixel;
1088  } // End setting up colours
1089 
1090  toplevel = XCreateSimpleWindow(display,RootWindow(display,screen_num),
1091  x, y, top_width, top_height, border_width, colors[BLACK],
1092  colors[cindex]);
1093 
1094  if (private_cmap != None)
1095  XSetWindowColormap (display, toplevel, private_cmap);
1096 
1097  XSelectInput (display, toplevel, ExposureMask | StructureNotifyMask |
1098  ButtonPressMask | PointerMotionMask | KeyPressMask);
1099 
1100  /* Create default Graphics Contexts. valuemask = 0 -> use defaults. */
1101  current_gc = gc = XCreateGC(display, toplevel, valuemask, &values);
1102  gc_menus = XCreateGC(display, toplevel, valuemask, &values);
1103 
1104  /* Create XOR graphics context for Rubber Banding */
1105  values.function = GXxor;
1106  values.foreground = colors[cindex];
1107  gcxor = XCreateGC(display, toplevel, (GCFunction | GCForeground),
1108  &values);
1109 
1110  /* specify font for menus. */
1112  XSetFont(display, gc_menus, font_info[menu_font_size]->fid);
1113 
1114  /* Set drawing defaults for user-drawable area. Use whatever the *
1115  * initial values of the current stuff was set to. */
1120 
1121  // Need a non-const name to pass to XStringListTo...
1122  // (even though X11 won't change it).
1123  char *window_name_copy = (char *) my_malloc (BUFSIZE * sizeof (char));
1124  strncpy (window_name_copy, window_name, BUFSIZE);
1125  XStringListToTextProperty(&window_name_copy, 1, &windowName);
1126  free (window_name_copy);
1127  window_name_copy = NULL;
1128 
1129  XSetWMName (display, toplevel, &windowName);
1130  /* XSetWMIconName (display, toplevel, &windowName); */
1131 
1132  /* XStringListToTextProperty copies the window_name string into *
1133  * windowName.value. Free this memory now. */
1134 
1135  free (windowName.value);
1136 
1137  XMapWindow (display, toplevel);
1138  build_textarea ();
1139  build_default_menu ();
1140 
1141  /* The following is completely unnecessary if the user is using the *
1142  * interactive (event_loop) graphics. It waits for the first Expose *
1143  * event before returning so that I can tell the window manager has got *
1144  * the top-level window up and running. Thus the user can start drawing *
1145  * into this window immediately, and there's no danger of the window not *
1146  * being ready and output being lost. */
1147  XPeekIfEvent (display, &event, test_if_exposed, NULL);
1148 
1149 #else /* WIN32 */
1150  WNDCLASS wndclass;
1151  HINSTANCE hInstance = GetModuleHandle(NULL);
1152  int x, y;
1153  LOGBRUSH lb;
1154  lb.lbStyle = BS_SOLID;
1155  lb.lbColor = win32_colors[currentcolor];
1156  lb.lbHatch = (LONG)NULL;
1157  x = 0;
1158  y = 0;
1159 
1160  /* get screen size from display structure macro */
1161  display_width = GetSystemMetrics( SM_CXSCREEN );
1162  if (!(display_width))
1163  CREATE_ERROR();
1164  display_height = GetSystemMetrics( SM_CYSCREEN );
1165  if (!(display_height))
1166  CREATE_ERROR();
1167  top_width = 2*display_width/3;
1168  top_height = 4*display_height/5;
1169 
1170  /* Grab the Application name */
1171  wsprintf(szAppName, TEXT(window_name));
1172 
1173  //hGraphicsPen = CreatePen(win32_line_styles[SOLID], 1, win32_colors[BLACK]);
1174  hGraphicsPen = ExtCreatePen(PS_GEOMETRIC | win32_line_styles[currentlinestyle] |
1175  PS_ENDCAP_FLAT, 1, &lb, (LONG)NULL, NULL);
1176  if(!hGraphicsPen)
1177  CREATE_ERROR();
1178  hGraphicsBrush = CreateSolidBrush(win32_colors[DARKGREY]);
1179  if(!hGraphicsBrush)
1180  CREATE_ERROR();
1181  hGrayBrush = CreateSolidBrush(win32_colors[LIGHTGREY]);
1182  if(!hGrayBrush)
1183  CREATE_ERROR();
1184 
1186  hGraphicsFont = CreateFontIndirect(font_info[currentfontsize]);
1187  if (!hGraphicsFont)
1188  CREATE_ERROR();
1189 
1190  /* Register the Main Window class */
1191  wndclass.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
1192  wndclass.lpfnWndProc = MainWND;
1193  wndclass.cbClsExtra = 0;
1194  wndclass.cbWndExtra = 0;
1195  wndclass.hInstance = hInstance;
1196  wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION);
1197  wndclass.hCursor = LoadCursor( NULL, IDC_ARROW);
1198  wndclass.hbrBackground = (HBRUSH) CreateSolidBrush(win32_colors[cindex]);
1199  wndclass.lpszMenuName = NULL;
1200  wndclass.lpszClassName = szAppName;
1201 
1202  if (!RegisterClass(&wndclass)) {
1203  printf ("Error code: %d\n", GetLastError());
1204  MessageBox(NULL, TEXT("Initialization of Windows graphics (init_graphics) failed."),
1205  szAppName, MB_ICONERROR);
1206  exit(-1);
1207  }
1208 
1209  /* Register the Graphics Window class */
1210  wndclass.lpfnWndProc = GraphicsWND;
1211  wndclass.hIcon = NULL;
1212  wndclass.lpszClassName = szGraphicsName;
1213 
1214  if(!RegisterClass(&wndclass))
1215  DRAW_ERROR();
1216 
1217  /* Register the Status Window class */
1218  wndclass.lpfnWndProc = StatusWND;
1219  wndclass.hIcon = NULL;
1220  wndclass.lpszClassName = szStatusName;
1221  wndclass.hbrBackground = hGrayBrush;
1222 
1223  if(!RegisterClass(&wndclass))
1224  DRAW_ERROR();
1225 
1226  /* Register the Buttons Window class */
1227  wndclass.lpfnWndProc = ButtonsWND;
1228  wndclass.hIcon = NULL;
1229  wndclass.lpszClassName = szButtonsName;
1230  wndclass.hbrBackground = hGrayBrush;
1231 
1232  if (!RegisterClass(&wndclass))
1233  DRAW_ERROR();
1234 
1235  hMainWnd = CreateWindow(szAppName, TEXT(window_name),
1236  WS_OVERLAPPEDWINDOW, x, y, top_width, top_height,
1237  NULL, NULL, hInstance, NULL);
1238 
1239  if(!hMainWnd)
1240  DRAW_ERROR();
1241 
1242  /* Set drawing defaults for user-drawable area. Use whatever the *
1243  * initial values of the current stuff was set to. */
1244 
1245  if (ShowWindow(hMainWnd, SW_SHOWNORMAL))
1246  DRAW_ERROR();
1248  if (!UpdateWindow(hMainWnd))
1249  DRAW_ERROR();
1250  win32_drain_message_queue ();
1251 #endif
1252  gl_state.initialized = true;
1253 }
1254 
1255 
1256 static void reset_common_state () {
1257  currentcolor = BLACK;
1259  currentlinewidth = 0;
1260  currentfontsize = 12;
1262 
1263  for (int i=0;i<=MAX_FONT_SIZE;i++)
1264  font_is_loaded[i] = false; /* No fonts loaded yet. */
1265 
1266  ProceedPressed = false;
1267  get_keypress_input = false;
1268  get_mouse_move_input = false;
1269 }
1270 
1271 
1272 static void
1274 {
1275 /* Set up the factors for transforming from the user world to X Windows *
1276  * coordinates. */
1277 
1278  float mult, y1, y2, x1, x2;
1279 
1280  /* X Window coordinates go from (0,0) to (width-1,height-1) */
1281  xmult = (top_width - 1 - MWIDTH) / (xright - xleft);
1282  ymult = (top_height - 1 - T_AREA_HEIGHT)/ (ybot - ytop);
1283 
1284  /* Need to use same scaling factor to preserve aspect ratio */
1285  if (fabs(xmult) <= fabs(ymult)) {
1286  mult = (float)(fabs(ymult/xmult));
1287  y1 = ytop - (ybot-ytop)*(mult-1)/2;
1288  y2 = ybot + (ybot-ytop)*(mult-1)/2;
1289  ytop = y1;
1290  ybot = y2;
1291  }
1292  else {
1293  mult = (float)(fabs(xmult/ymult));
1294  x1 = xleft - (xright-xleft)*(mult-1)/2;
1295  x2 = xright + (xright-xleft)*(mult-1)/2;
1296  xleft = x1;
1297  xright = x2;
1298  }
1299  xmult = (top_width - 1 - MWIDTH) / (xright - xleft);
1300  ymult = (top_height - 1 - T_AREA_HEIGHT)/ (ybot - ytop);
1301 
1302  xdiv = 1/xmult;
1303  ydiv = 1/ymult;
1304 }
1305 
1306 
1307 static void
1309 {
1310 
1311 /* Postscript coordinates start at (0,0) for the lower left hand corner *
1312 * of the page and increase upwards and to the right. For 8.5 x 11 *
1313 * sheet, coordinates go from (0,0) to (612,792). Spacing is 1/72 inch.*
1314 * I'm leaving a minimum of half an inch (36 units) of border around *
1315  * each edge. */
1316 
1317  float ps_width, ps_height;
1318 
1319  ps_width = 540.; /* 72 * 7.5 */
1320  ps_height = 720.; /* 72 * 10 */
1321 
1322  ps_xmult = ps_width / (xright - xleft);
1323  ps_ymult = ps_height / (ytop - ybot);
1324  /* Need to use same scaling factor to preserve aspect ratio. *
1325  * I show exactly as much on paper as the screen window shows, *
1326  * or the user specifies. */
1327  if (fabs(ps_xmult) <= fabs(ps_ymult)) {
1328  ps_left = 36.;
1329  ps_right = (float)(36. + ps_width);
1330  ps_bot = (float)(396. - fabs(ps_xmult * (ytop - ybot))/2);
1331  ps_top = (float)(396. + fabs(ps_xmult * (ytop - ybot))/2);
1332  /* Maintain aspect ratio but watch signs */
1334  }
1335  else {
1336  ps_bot = 36.;
1337  ps_top = (float)(36. + ps_height);
1338  ps_left = (float)(306. - fabs(ps_ymult * (xright - xleft))/2);
1339  ps_right = (float)(306. + fabs(ps_ymult * (xright - xleft))/2);
1340  /* Maintain aspect ratio but watch signs */
1342  }
1343 }
1344 
1345 
1346 /* The program's main event loop. Must be passed a user routine
1347 * drawscreen which redraws the screen. It handles all window resizing
1348 * zooming etc. itself. If the user clicks a mousebutton in the graphics
1349 * (toplevel) area, the act_on_mousebutton routine passed in is called.
1350 */
1351 void
1352 event_loop (void (*act_on_mousebutton)(float x, float y),
1353  void (*act_on_mousemove)(float x, float y),
1354  void (*act_on_keypress)(char key_pressed),
1355  void (*drawscreen) (void))
1356 {
1357 #ifdef X11
1358  XEvent report;
1359  int bnum;
1360  float x, y;
1361 
1362 #define OFF 1
1363 #define ON 0
1364 
1365  turn_on_off (ON);
1366  while (1) {
1367  XNextEvent (display, &report);
1368  switch (report.type) {
1369  case Expose:
1370 #ifdef VERBOSE
1371  printf("Got an expose event.\n");
1372  printf("Count is: %d.\n",report.xexpose.count);
1373  printf("Window ID is: %d.\n",report.xexpose.window);
1374 #endif
1375  if (report.xexpose.count != 0)
1376  break;
1377  if (report.xexpose.window == menu)
1378  drawmenu();
1379  else if (report.xexpose.window == toplevel)
1380  drawscreen();
1381  else if (report.xexpose.window == textarea)
1382  draw_message();
1383  break;
1384  case ConfigureNotify:
1385  top_width = report.xconfigure.width;
1386  top_height = report.xconfigure.height;
1387  update_transform();
1388  drawmenu();
1389  draw_message();
1390 #ifdef VERBOSE
1391  printf("Got a ConfigureNotify.\n");
1392  printf("New width: %d New height: %d.\n",top_width,top_height);
1393 #endif
1394  break;
1395  case ButtonPress:
1396 #ifdef VERBOSE
1397  printf("Got a buttonpress.\n");
1398  printf("Window ID is: %d.\n",report.xbutton.window);
1399 #endif
1400  if (report.xbutton.window == toplevel) {
1401  x = XTOWORLD(report.xbutton.x);
1402  y = YTOWORLD(report.xbutton.y);
1403  act_on_mousebutton (x, y);
1404  }
1405  else { /* A menu button was pressed. */
1406  bnum = which_button(report.xbutton.window);
1407 #ifdef VERBOSE
1408  printf("Button number is %d\n",bnum);
1409 #endif
1410  if (button[bnum].enabled) {
1411  button[bnum].ispressed = 1;
1412  drawbut(bnum);
1413  XFlush(display); /* Flash the button */
1414  button[bnum].fcn (drawscreen);
1415  button[bnum].ispressed = 0;
1416  drawbut(bnum);
1417  if (button[bnum].fcn == proceed) {
1418  turn_on_off(OFF);
1419  flushinput ();
1420  return; /* Rather clumsy way of returning *
1421  * control to the simulator */
1422  }
1423  }
1424  }
1425  break;
1426  case MotionNotify:
1427 #ifdef VERBOSE
1428  printf("Got a MotionNotify Event.\n");
1429  printf("x: %d y: %d\n",report.xmotion.x,report.xmotion.y);
1430 #endif
1431  if (get_mouse_move_input &&
1432  report.xmotion.x <= top_width-MWIDTH &&
1433  report.xmotion.y <= top_height-T_AREA_HEIGHT)
1434  act_on_mousemove(XTOWORLD(report.xmotion.x), YTOWORLD(report.xmotion.y));
1435  break;
1436  case KeyPress:
1437 #ifdef VERBOSE
1438  printf("Got a KeyPress Event.\n");
1439 #endif
1440  if (get_keypress_input)
1441  {
1442  char keyb_buffer[20];
1443  XComposeStatus composestatus;
1444  KeySym keysym;
1445  int length, max_bytes;
1446 
1447  max_bytes = 1;
1448 
1449  length = XLookupString( &report.xkey, keyb_buffer, max_bytes, &keysym,
1450  &composestatus );
1451 
1452  keyb_buffer[length] = '\0'; /* terminating NULL */
1453  act_on_keypress(keyb_buffer[0]);
1454  }
1455 
1456  break;
1457  }
1458  }
1459 #else /* Win32 */
1460  MSG msg;
1461 
1462  mouseclick_ptr = act_on_mousebutton;
1463  mousemove_ptr = act_on_mousemove;
1464  keypress_ptr = act_on_keypress;
1465  drawscreen_ptr = drawscreen;
1467  InEventLoop = TRUE;
1468 
1469  invalidate_screen();
1470 
1471  while(!ProceedPressed && GetMessage(&msg, NULL, 0, 0)) {
1472  //TranslateMessage(&msg);
1473  if (msg.message == WM_CHAR) { // only the top window can get keyboard events
1474  msg.hwnd = hMainWnd;
1475  }
1476  DispatchMessage(&msg);
1477  }
1478  InEventLoop = FALSE;
1479 #endif
1480 }
1481 
1482 void
1484 {
1485  int savecolor;
1486  if (gl_state.disp_type == SCREEN) {
1487 #ifdef X11
1488  XClearWindow (display, toplevel);
1489 #else /* Win32 */
1490  savecolor = currentcolor;
1492  fillrect (xleft, ytop, xright, ybot);
1493  setcolor(savecolor);
1494 #endif
1495  }
1496  else { // Postscript
1497  /* erases current page. Don't use erasepage, since this will erase *
1498  * everything, (even stuff outside the clipping path) causing *
1499  * problems if this picture is incorporated into a larger document. */
1500  savecolor = currentcolor;
1502  fprintf(ps,"clippath fill\n\n");
1503  setcolor (savecolor);
1504  }
1505 }
1506 
1507 /* Return 1 if I can quarantee no part of this rectangle will *
1508 * lie within the user drawing area. Otherwise return 0. *
1509 * Note: this routine is only used to help speed (and to shrink ps *
1510 * files) -- it will be highly effective when the graphics are zoomed *
1511 * in and lots are off-screen. I don't have to pre-clip for *
1512 * correctness. */
1513 static int
1514 rect_off_screen (float x1, float y1, float x2, float y2)
1515 {
1516 
1517  float xmin, xmax, ymin, ymax;
1518 
1519  xmin = min (xleft, xright);
1520  if (x1 < xmin && x2 < xmin)
1521  return (1);
1522 
1523  xmax = max (xleft, xright);
1524  if (x1 > xmax && x2 > xmax)
1525  return (1);
1526 
1527  ymin = min (ytop, ybot);
1528  if (y1 < ymin && y2 < ymin)
1529  return (1);
1530 
1531  ymax = max (ytop, ybot);
1532  if (y1 > ymax && y2 > ymax)
1533  return (1);
1534 
1535  return (0);
1536 }
1537 
1538 void
1539 drawline (float x1, float y1, float x2, float y2)
1540 {
1541 /* Draw a line from (x1,y1) to (x2,y2) in the user-drawable area. *
1542  * Coordinates are in world (user) space. */
1543 
1544 #ifdef WIN32
1545  HPEN hOldPen;
1546 #endif
1547 
1548  if (rect_off_screen(x1,y1,x2,y2))
1549  return;
1550 
1551  if (gl_state.disp_type == SCREEN) {
1552 #ifdef X11
1553  /* Xlib.h prototype has x2 and y1 mixed up. */
1554  XDrawLine(display, toplevel, current_gc, xcoord(x1), ycoord(y1), xcoord(x2), ycoord(y2));
1555 #else /* Win32 */
1556  hOldPen = (HPEN)SelectObject(hGraphicsDC, hGraphicsPen);
1557  if(!(hOldPen))
1558  SELECT_ERROR();
1559  if (!BeginPath(hGraphicsDC))
1560  DRAW_ERROR();
1561  if(!MoveToEx (hGraphicsDC, xcoord(x1), ycoord(y1), NULL))
1562  DRAW_ERROR();
1563  if(!LineTo (hGraphicsDC, xcoord(x2), ycoord(y2)))
1564  DRAW_ERROR();
1565  if (!EndPath(hGraphicsDC))
1566  DRAW_ERROR();
1567  if (!StrokePath(hGraphicsDC))
1568  DRAW_ERROR();
1569  if(!SelectObject(hGraphicsDC, hOldPen))
1570  SELECT_ERROR();
1571 #endif
1572  }
1573  else {
1574  fprintf(ps,"%.2f %.2f %.2f %.2f drawline\n",XPOST(x1),YPOST(y1),
1575  XPOST(x2),YPOST(y2));
1576  }
1577 }
1578 
1579 /* (x1,y1) and (x2,y2) are diagonally opposed corners, in world coords. */
1580 void
1581 drawrect (float x1, float y1, float x2, float y2)
1582 {
1583  int xw1, yw1, xw2, yw2;
1584 #ifdef WIN32
1585  HPEN hOldPen;
1586  HBRUSH hOldBrush;
1587 #else
1588  unsigned int width, height;
1589  int xl, yt;
1590 #endif
1591 
1592  if (rect_off_screen(x1,y1,x2,y2))
1593  return;
1594 
1595  if (gl_state.disp_type == SCREEN) {
1596  /* translate to X Windows calling convention. */
1597  xw1 = xcoord(x1);
1598  xw2 = xcoord(x2);
1599  yw1 = ycoord(y1);
1600  yw2 = ycoord(y2);
1601 #ifdef X11
1602  xl = min(xw1,xw2);
1603  yt = min(yw1,yw2);
1604  width = abs (xw1-xw2);
1605  height = abs (yw1-yw2);
1606  XDrawRectangle(display, toplevel, current_gc, xl, yt, width, height);
1607 #else /* Win32 */
1608  if(xw1 > xw2) {
1609  int temp = xw1;
1610  xw1 = xw2;
1611  xw2 = temp;
1612  }
1613  if(yw1 > yw2) {
1614  int temp = yw1;
1615  yw1 = yw2;
1616  yw2 = temp;
1617  }
1618 
1619  hOldPen = (HPEN)SelectObject(hGraphicsDC, hGraphicsPen);
1620  if(!(hOldPen))
1621  SELECT_ERROR();
1622  hOldBrush = (HBRUSH)SelectObject(hGraphicsDC, GetStockObject(NULL_BRUSH));
1623  if(!(hOldBrush))
1624  SELECT_ERROR();
1625  if(!Rectangle(hGraphicsDC, xw1, yw1, xw2, yw2))
1626  DRAW_ERROR();
1627  if(!SelectObject(hGraphicsDC, hOldPen))
1628  SELECT_ERROR();
1629  if(!SelectObject(hGraphicsDC, hOldBrush))
1630  SELECT_ERROR();
1631 #endif
1632 
1633  }
1634  else {
1635  fprintf(ps,"%.2f %.2f %.2f %.2f drawrect\n",XPOST(x1),YPOST(y1),
1636  XPOST(x2),YPOST(y2));
1637  }
1638 }
1639 
1640 
1641 /* (x1,y1) and (x2,y2) are diagonally opposed corners in world coords. */
1642 void
1643 fillrect (float x1, float y1, float x2, float y2)
1644 {
1645  int xw1, yw1, xw2, yw2;
1646 #ifdef WIN32
1647  HPEN hOldPen;
1648  HBRUSH hOldBrush;
1649 #else
1650  unsigned int width, height;
1651  int xl, yt;
1652 #endif
1653 
1654  if (rect_off_screen(x1,y1,x2,y2))
1655  return;
1656 
1657  if (gl_state.disp_type == SCREEN) {
1658  /* translate to X Windows calling convention. */
1659  xw1 = xcoord(x1);
1660  xw2 = xcoord(x2);
1661  yw1 = ycoord(y1);
1662  yw2 = ycoord(y2);
1663 #ifdef X11
1664  xl = min(xw1,xw2);
1665  yt = min(yw1,yw2);
1666  width = abs (xw1-xw2);
1667  height = abs (yw1-yw2);
1668  XFillRectangle(display, toplevel, current_gc, xl, yt, width, height);
1669 #else /* Win32 */
1670  if(xw1 > xw2) {
1671  int temp = xw1;
1672  xw1 = xw2;
1673  xw2 = temp;
1674  }
1675  if(yw1 > yw2) {
1676  int temp = yw1;
1677  yw1 = yw2;
1678  yw2 = temp;
1679  }
1680 
1681  hOldPen = (HPEN)SelectObject(hGraphicsDC, hGraphicsPen);
1682  if(!(hOldPen))
1683  SELECT_ERROR();
1684  hOldBrush = (HBRUSH)SelectObject(hGraphicsDC, hGraphicsBrush);
1685  if(!(hOldBrush))
1686  SELECT_ERROR();
1687  if(!Rectangle(hGraphicsDC, xw1, yw1, xw2, yw2))
1688  DRAW_ERROR();
1689  if(!SelectObject(hGraphicsDC, hOldPen))
1690  SELECT_ERROR();
1691  if(!SelectObject(hGraphicsDC, hOldBrush))
1692  SELECT_ERROR();
1693 #endif
1694  }
1695  else {
1696  fprintf(ps,"%.2f %.2f %.2f %.2f fillrect\n",XPOST(x1),YPOST(y1),
1697  XPOST(x2),YPOST(y2));
1698  }
1699 }
1700 
1701 
1702 /* Normalizes an angle to be between 0 and 360 degrees. */
1703 static float
1704 angnorm (float ang)
1705 {
1706  int scale;
1707 
1708  if (ang < 0) {
1709  scale = (int) (ang / 360. - 1);
1710  }
1711  else {
1712  scale = (int) (ang / 360.);
1713  }
1714  ang = ang - scale * 360;
1715  return (ang);
1716 }
1717 
1718 void
1719 drawellipticarc (float xc, float yc, float radx, float rady, float startang, float angextent)
1720 {
1721  int xl, yt;
1722  unsigned int width, height;
1723 #ifdef WIN32
1724  HPEN hOldPen;
1725  int p1, p2, p3, p4;
1726 #endif
1727 
1728  /* Conservative (but fast) clip test -- check containing rectangle of *
1729  * an ellipse. */
1730 
1731  if (rect_off_screen (xc-radx,yc-rady,xc+radx,yc+rady))
1732  return;
1733 
1734  /* X Windows has trouble with very large angles. (Over 360). *
1735  * Do following to prevent its inaccurate (overflow?) problems. */
1736  if (fabs(angextent) > 360.)
1737  angextent = 360.;
1738 
1739  startang = angnorm (startang);
1740 
1741  if (gl_state.disp_type == SCREEN) {
1742  xl = (int) (xcoord(xc) - fabs(xmult*radx));
1743  yt = (int) (ycoord(yc) - fabs(ymult*rady));
1744  width = (unsigned int) (2*fabs(xmult*radx));
1745  height = (unsigned int) (2*fabs(ymult*rady));
1746 #ifdef X11
1747  XDrawArc (display, toplevel, current_gc, xl, yt, width, height,
1748  (int) (startang*64), (int) (angextent*64));
1749 #else // Win32
1750  /* set arc direction */
1751  if (angextent > 0) {
1752  p1 = (int)(xcoord(xc) + fabs(xmult*radx)*cos(DEGTORAD(startang)));
1753  p2 = (int)(ycoord(yc) - fabs(ymult*rady)*sin(DEGTORAD(startang)));
1754  p3 = (int)(xcoord(xc) + fabs(xmult*radx)*cos(DEGTORAD(startang+angextent-.001)));
1755  p4 = (int)(ycoord(yc) - fabs(ymult*rady)*sin(DEGTORAD(startang+angextent-.001)));
1756  }
1757  else {
1758  p1 = (int)(xcoord(xc) + fabs(xmult*radx)*cos(DEGTORAD(startang+angextent+.001)));
1759  p2 = (int)(ycoord(yc) - fabs(ymult*rady)*sin(DEGTORAD(startang+angextent+.001)));
1760  p3 = (int)(xcoord(xc) + fabs(xmult*radx)*cos(DEGTORAD(startang)));
1761  p4 = (int)(ycoord(yc) - fabs(ymult*rady)*sin(DEGTORAD(startang)));
1762  }
1763 
1764  hOldPen = (HPEN)SelectObject(hGraphicsDC, hGraphicsPen);
1765  if(!(hOldPen))
1766  SELECT_ERROR();
1767  if(!Arc(hGraphicsDC, xl, yt, xl+width, yt+height, p1, p2, p3, p4))
1768  DRAW_ERROR();
1769  if(!SelectObject(hGraphicsDC, hOldPen))
1770  SELECT_ERROR();
1771 #endif
1772  }
1773  else {
1774  fprintf(ps, "gsave\n");
1775  fprintf(ps, "%.2f %.2f translate\n", XPOST(xc), YPOST(yc));
1776  fprintf(ps, "%.2f 1 scale\n", fabs(radx*ps_xmult)/fabs(rady*ps_ymult));
1777  fprintf(ps, "0 0 %.2f %.2f %.2f %s\n", /*XPOST(xc)*/
1778  /*YPOST(yc)*/ fabs(rady*ps_xmult), startang, startang+angextent,
1779  (angextent < 0) ? "drawarcn" : "drawarc") ;
1780  fprintf(ps, "grestore\n");
1781  }
1782 }
1783 
1784 /* Startang is relative to the Window's positive x direction. Angles in degrees.
1785  */
1786 void
1787 drawarc (float xc, float yc, float rad, float startang,
1788  float angextent)
1789 {
1790  drawellipticarc(xc, yc, rad, rad, startang, angextent);
1791 }
1792 
1793 
1794 /* Fills a elliptic arc. Startang is relative to the Window's positive x
1795  * direction. Angles in degrees.
1796  */
1797 void
1798 fillellipticarc (float xc, float yc, float radx, float rady, float startang,
1799  float angextent)
1800 {
1801  int xl, yt;
1802  unsigned int width, height;
1803 #ifdef WIN32
1804  HPEN hOldPen;
1805  HBRUSH hOldBrush;
1806  int p1, p2, p3, p4;
1807 #endif
1808 
1809  /* Conservative (but fast) clip test -- check containing rectangle of *
1810  * a circle. */
1811 
1812  if (rect_off_screen (xc-radx,yc-rady,xc+radx,yc+rady))
1813  return;
1814 
1815  /* X Windows has trouble with very large angles. (Over 360). *
1816  * Do following to prevent its inaccurate (overflow?) problems. */
1817 
1818  if (fabs(angextent) > 360.)
1819  angextent = 360.;
1820 
1821  startang = angnorm (startang);
1822 
1823  if (gl_state.disp_type == SCREEN) {
1824  xl = (int) (xcoord(xc) - fabs(xmult*radx));
1825  yt = (int) (ycoord(yc) - fabs(ymult*rady));
1826  width = (unsigned int) (2*fabs(xmult*radx));
1827  height = (unsigned int) (2*fabs(ymult*rady));
1828 #ifdef X11
1829  XFillArc (display, toplevel, current_gc, xl, yt, width, height,
1830  (int) (startang*64), (int) (angextent*64));
1831 #else // Win32
1832  /* set pie direction */
1833  if (angextent > 0) {
1834  p1 = (int)(xcoord(xc) + fabs(xmult*radx)*cos(DEGTORAD(startang)));
1835  p2 = (int)(ycoord(yc) - fabs(ymult*rady)*sin(DEGTORAD(startang)));
1836  p3 = (int)(xcoord(xc) + fabs(xmult*radx)*cos(DEGTORAD(startang+angextent-.001)));
1837  p4 = (int)(ycoord(yc) - fabs(ymult*rady)*sin(DEGTORAD(startang+angextent-.001)));
1838  }
1839  else {
1840  p1 = (int)(xcoord(xc) + fabs(xmult*radx)*cos(DEGTORAD(startang+angextent+.001)));
1841  p2 = (int)(ycoord(yc) - fabs(ymult*rady)*sin(DEGTORAD(startang+angextent+.001)));
1842  p3 = (int)(xcoord(xc) + fabs(xmult*radx)*cos(DEGTORAD(startang)));
1843  p4 = (int)(ycoord(yc) - fabs(ymult*rady)*sin(DEGTORAD(startang)));
1844  }
1845 
1846  hOldPen = (HPEN)SelectObject(hGraphicsDC, GetStockObject(NULL_PEN));
1847  if(!(hOldPen))
1848  SELECT_ERROR();
1849  hOldBrush = (HBRUSH)SelectObject(hGraphicsDC, hGraphicsBrush);
1850  if(!(hOldBrush))
1851  SELECT_ERROR();
1852 // Win32 API says a zero return value indicates an error, but it seems to always
1853 // return zero. Don't check for an error on Pie.
1854  Pie(hGraphicsDC, xl, yt, xl+width, yt+height, p1, p2, p3, p4);
1855 
1856 // if(!Pie(hGraphicsDC, xl, yt, xl+width, yt+height, p1, p2, p3, p4));
1857 // DRAW_ERROR();
1858  if(!SelectObject(hGraphicsDC, hOldPen))
1859  SELECT_ERROR();
1860  if(!SelectObject(hGraphicsDC, hOldBrush))
1861  SELECT_ERROR();
1862 #endif
1863  }
1864  else {
1865  fprintf(ps, "gsave\n");
1866  fprintf(ps, "%.2f %.2f translate\n", XPOST(xc), YPOST(yc));
1867  fprintf(ps, "%.2f 1 scale\n", fabs(radx*ps_xmult)/fabs(rady*ps_ymult));
1868  fprintf(ps, "%.2f %.2f %.2f 0 0 %s\n", /*XPOST(xc)*/
1869  /*YPOST(yc)*/ fabs(rady*ps_xmult), startang, startang+angextent,
1870  (angextent < 0) ? "fillarcn" : "fillarc") ;
1871  fprintf(ps, "grestore\n");
1872  }
1873 }
1874 
1875 void
1876 fillarc (float xc, float yc, float rad, float startang, float angextent) {
1877  fillellipticarc(xc, yc, rad, rad, startang, angextent);
1878 }
1879 
1880 void
1881 fillpoly (t_point *points, int npoints)
1882 {
1883 #ifdef X11
1884  XPoint transpoints[MAXPTS];
1885 #else
1886  POINT transpoints[MAXPTS];
1887  HPEN hOldPen;
1888  HBRUSH hOldBrush;
1889 #endif
1890  int i;
1891  float xmin, ymin, xmax, ymax;
1892 
1893  if (npoints > MAXPTS) {
1894  printf("Error in fillpoly: Only %d points allowed per polygon.\n",
1895  MAXPTS);
1896  printf("%d points were requested. Polygon is not drawn.\n",npoints);
1897  return;
1898  }
1899 
1900  /* Conservative (but fast) clip test -- check containing rectangle of *
1901  * polygon. */
1902 
1903  xmin = xmax = points[0].x;
1904  ymin = ymax = points[0].y;
1905 
1906  for (i=1;i<npoints;i++) {
1907  xmin = min (xmin,points[i].x);
1908  xmax = max (xmax,points[i].x);
1909  ymin = min (ymin,points[i].y);
1910  ymax = max (ymax,points[i].y);
1911  }
1912 
1913  if (rect_off_screen(xmin,ymin,xmax,ymax))
1914  return;
1915 
1916  if (gl_state.disp_type == SCREEN) {
1917  for (i=0;i<npoints;i++) {
1918  transpoints[i].x = (short) xcoord (points[i].x);
1919  transpoints[i].y = (short) ycoord (points[i].y);
1920  }
1921 #ifdef X11
1922  XFillPolygon(display, toplevel, current_gc, transpoints, npoints, Complex,
1923  CoordModeOrigin);
1924 #else
1925  hOldPen = (HPEN)SelectObject(hGraphicsDC, GetStockObject(NULL_PEN));
1926  if(!(hOldPen))
1927  SELECT_ERROR();
1928  hOldBrush = (HBRUSH)SelectObject(hGraphicsDC, hGraphicsBrush);
1929  if(!(hOldBrush))
1930  SELECT_ERROR();
1931  if(!Polygon (hGraphicsDC, transpoints, npoints))
1932  DRAW_ERROR();
1933  if(!SelectObject(hGraphicsDC, hOldPen))
1934  SELECT_ERROR();
1935  if(!SelectObject(hGraphicsDC, hOldBrush))
1936  SELECT_ERROR();
1937 #endif
1938  }
1939  else {
1940  fprintf(ps,"\n");
1941 
1942  for (i=npoints-1;i>=0;i--)
1943  fprintf (ps, "%.2f %.2f\n", XPOST(points[i].x), YPOST(points[i].y));
1944 
1945  fprintf (ps, "%d fillpoly\n", npoints);
1946  }
1947 }
1948 
1949 
1950 /* Draws text centered on xc,yc if it fits in boundx */
1951 void
1952 drawtext (float xc, float yc, const char *text, float boundx)
1953 {
1954  int len, width, xw_off, yw_off, font_ascent, font_descent;
1955 
1956 #ifdef X11
1957  len = strlen(text);
1958  width = XTextWidth(font_info[currentfontsize], text, len);
1959  font_ascent = font_info[currentfontsize]->ascent;
1960  font_descent = font_info[currentfontsize]->descent;
1961 #else /* WC : WIN32 */
1962  HFONT hOldFont;
1963  SIZE textsize;
1964  TEXTMETRIC textmetric;
1965 
1966  hOldFont = (HFONT)SelectObject(hGraphicsDC, hGraphicsFont);
1967  if(!(hOldFont))
1968  SELECT_ERROR();
1969  if(SetTextColor(hGraphicsDC, win32_colors[currentcolor]) == CLR_INVALID)
1970  DRAW_ERROR();
1971 
1972  len = strlen(text);
1973  if (!GetTextExtentPoint32(hGraphicsDC, text, len, &textsize))
1974  DRAW_ERROR();
1975  width = textsize.cx;
1976  if (!GetTextMetrics(hGraphicsDC, &textmetric))
1977  DRAW_ERROR();
1978  font_ascent = textmetric.tmAscent;
1979  font_descent = textmetric.tmDescent;
1980 #endif
1981  if (width > fabs(boundx*xmult)) {
1982 #ifdef WIN32
1983  if(!SelectObject(hGraphicsDC, hOldFont))
1984  SELECT_ERROR();
1985 #endif
1986  return; /* Don't draw if it won't fit */
1987  }
1988 
1989  xw_off = (int)(width/(2.*xmult)); /* NB: sign doesn't matter. */
1990 
1991  /* NB: 2 * descent makes this slightly conservative but simplifies code. */
1992  yw_off = (int)((font_ascent + 2 * font_descent)/(2.*ymult));
1993 
1994  /* Note: text can be clipped when a little bit of it would be visible *
1995  * right now. Perhaps X doesn't return extremely accurate width and *
1996  * ascent values, etc? Could remove this completely by multiplying *
1997  * xw_off and yw_off by, 1.2 or 1.5. */
1998  if (rect_off_screen(xc-xw_off, yc-yw_off, xc+xw_off, yc+yw_off)) {
1999 #ifdef WIN32
2000  if(!SelectObject(hGraphicsDC, hOldFont))
2001  SELECT_ERROR();
2002 #endif
2003  return;
2004  }
2005 
2006  if (gl_state.disp_type == SCREEN) {
2007 #ifdef X11
2008  XDrawString(display, toplevel, current_gc, xcoord(xc)-width/2, ycoord(yc) +
2009  (font_info[currentfontsize]->ascent - font_info[currentfontsize]->descent)/2,
2010  text, len);
2011 #else /* Win32 */
2012  SetBkMode(hGraphicsDC, TRANSPARENT);
2013  if(!TextOut (hGraphicsDC, xcoord(xc)-width/2, ycoord(yc) - (font_ascent + font_descent)/2,
2014  text, len))
2015  DRAW_ERROR();
2016  if(!SelectObject(hGraphicsDC, hOldFont))
2017  SELECT_ERROR();
2018 #endif
2019  }
2020  else {
2021  fprintf(ps,"(%s) %.2f %.2f censhow\n",text,XPOST(xc),YPOST(yc));
2022  }
2023 }
2024 
2025 
2026 void
2027 flushinput (void)
2028 {
2029  if (gl_state.disp_type != SCREEN)
2030  return;
2031 #ifdef X11
2032  XFlush(display);
2033 #endif
2034 }
2035 
2036 
2037 void
2038 init_world (float x1, float y1, float x2, float y2)
2039 {
2040  /* Sets the coordinate system the user wants to draw into. */
2041 
2042  xleft = x1;
2043  xright = x2;
2044  ytop = y1;
2045  ybot = y2;
2046 
2047  saved_xleft = xleft; /* Save initial world coordinates to allow full */
2048  saved_xright = xright; /* view button to zoom all the way out. */
2049  saved_ytop = ytop;
2050  saved_ybot = ybot;
2051 
2052  if (gl_state.disp_type == SCREEN) {
2053  update_transform();
2054  }
2055  else {
2057  }
2058 }
2059 
2060 
2061 /* Draw the current message in the text area at the screen bottom. */
2062 void
2064 {
2065  int savefontsize, savecolor;
2066  float ylow;
2067 #ifdef X11
2068  int len, width;
2069 #endif
2070 
2071  if (gl_state.disp_type == SCREEN) {
2072 #ifdef X11
2073  XClearWindow (display, textarea);
2074  len = strlen (statusMessage);
2075  width = XTextWidth(font_info[menu_font_size], statusMessage, len);
2076  XSetForeground(display, gc_menus,colors[WHITE]);
2077  XDrawRectangle(display, textarea, gc_menus, 0, 0, top_width - MWIDTH, T_AREA_HEIGHT);
2078  XSetForeground(display, gc_menus,colors[BLACK]);
2081 
2082  XDrawString(display, textarea, gc_menus,
2083  (top_width - MWIDTH - width)/2,
2084  T_AREA_HEIGHT/2 + (font_info[menu_font_size]->ascent -
2085  font_info[menu_font_size]->descent)/2, statusMessage, len);
2086 #else
2087  if(!InvalidateRect(hStatusWnd, NULL, TRUE))
2088  DRAW_ERROR();
2089  if(!UpdateWindow(hStatusWnd))
2090  DRAW_ERROR();
2091 #endif
2092  }
2093 
2094  else {
2095  /* Draw the message in the bottom margin. Printer's generally can't *
2096  * print on the bottom 1/4" (area with y < 18 in PostScript coords.) */
2097 
2098  savecolor = currentcolor;
2099  setcolor (BLACK);
2100  savefontsize = currentfontsize;
2101  setfontsize (menu_font_size - 2); /* Smaller OK on paper */
2102  ylow = ps_bot - 8;
2103  fprintf(ps,"(%s) %.2f %.2f censhow\n",statusMessage,(ps_left+ps_right)/2.,
2104  ylow);
2105  setcolor (savecolor);
2106  setfontsize (savefontsize);
2107  }
2108 }
2109 
2110 
2111 /* Changes the message to be displayed on screen. */
2112 void
2113 update_message (const char *msg)
2114 {
2115  strncpy (statusMessage, msg, BUFSIZE);
2116  draw_message ();
2117 #ifdef X11
2118 // Make this appear immediately. Win32 does that automaticaly.
2119  XFlush (display);
2120 #endif // X11
2121 }
2122 
2123 
2124 /* Zooms in by a factor of 1.666. */
2125 static void
2126 zoom_in (void (*drawscreen) (void))
2127 {
2128  float xdiff, ydiff;
2129 
2130  xdiff = xright - xleft;
2131  ydiff = ybot - ytop;
2132  xleft += xdiff/5;
2133  xright -= xdiff/5;
2134  ytop += ydiff/5;
2135  ybot -= ydiff/5;
2136 
2137  update_transform ();
2138  drawscreen();
2139 }
2140 
2141 
2142 /* Zooms out by a factor of 1.666. */
2143 static void
2144 zoom_out (void (*drawscreen) (void))
2145 {
2146  float xdiff, ydiff;
2147 
2148  xdiff = xright - xleft;
2149  ydiff = ybot - ytop;
2150  xleft -= xdiff/3;
2151  xright += xdiff/3;
2152  ytop -= ydiff/3;
2153  ybot += ydiff/3;
2154 
2155  update_transform ();
2156  drawscreen();
2157 }
2158 
2159 
2160 /* Sets the view back to the initial view set by init_world (i.e. a full *
2161 * view) of all the graphics. */
2162 static void
2163 zoom_fit (void (*drawscreen) (void))
2164 {
2165  xleft = saved_xleft;
2166  xright = saved_xright;
2167  ytop = saved_ytop;
2168  ybot = saved_ybot;
2169 
2170  update_transform ();
2171  drawscreen();
2172 }
2173 
2174 
2175 /* Moves view 1/2 screen up. */
2176 static void
2177 translate_up (void (*drawscreen) (void))
2178 {
2179  float ystep;
2180 
2181  ystep = (ybot - ytop)/2;
2182  ytop -= ystep;
2183  ybot -= ystep;
2184  update_transform();
2185  drawscreen();
2186 }
2187 
2188 
2189 /* Moves view 1/2 screen down. */
2190 static void
2191 translate_down (void (*drawscreen) (void))
2192 {
2193  float ystep;
2194 
2195  ystep = (ybot - ytop)/2;
2196  ytop += ystep;
2197  ybot += ystep;
2198  update_transform();
2199  drawscreen();
2200 }
2201 
2202 
2203 /* Moves view 1/2 screen left. */
2204 static void
2205 translate_left (void (*drawscreen) (void))
2206 {
2207 
2208  float xstep;
2209 
2210  xstep = (xright - xleft)/2;
2211  xleft -= xstep;
2212  xright -= xstep;
2213  update_transform();
2214  drawscreen();
2215 }
2216 
2217 
2218 /* Moves view 1/2 screen right. */
2219 static void
2220 translate_right (void (*drawscreen) (void))
2221 {
2222  float xstep;
2223 
2224  xstep = (xright - xleft)/2;
2225  xleft += xstep;
2226  xright += xstep;
2227  update_transform();
2228  drawscreen();
2229 }
2230 
2231 
2232 static void
2233 update_win (int x[2], int y[2], void (*drawscreen)(void))
2234 {
2235  float x1, x2, y1, y2;
2236 
2237  x[0] = min(x[0],top_width-MWIDTH); /* Can't go under menu */
2238  x[1] = min(x[1],top_width-MWIDTH);
2239  y[0] = min(y[0],top_height-T_AREA_HEIGHT); /* Can't go under text area */
2240  y[1] = min(y[1],top_height-T_AREA_HEIGHT);
2241 
2242  if ((x[0] == x[1]) || (y[0] == y[1])) {
2243  printf("Illegal (zero area) window. Window unchanged.\n");
2244  return;
2245  }
2246  x1 = XTOWORLD(min(x[0],x[1]));
2247  x2 = XTOWORLD(max(x[0],x[1]));
2248  y1 = YTOWORLD(min(y[0],y[1]));
2249  y2 = YTOWORLD(max(y[0],y[1]));
2250  xleft = x1;
2251  xright = x2;
2252  ytop = y1;
2253  ybot = y2;
2254  update_transform();
2255  drawscreen();
2256 }
2257 
2258 
2259 /* The window button was pressed. Let the user click on the two *
2260 * diagonally opposed corners, and zoom in on this area. */
2261 static void
2262 adjustwin (void (*drawscreen) (void))
2263 {
2264 #ifdef X11
2265 
2266  XEvent report;
2267  int corner, xold, yold, x[2], y[2];
2268 
2269  corner = 0;
2270  xold = -1;
2271  yold = -1; /* Don't need to init yold, but stops compiler warning. */
2272 
2273  while (corner<2) {
2274  XNextEvent (display, &report);
2275  switch (report.type) {
2276  case Expose:
2277 #ifdef VERBOSE
2278  printf("Got an expose event.\n");
2279  printf("Count is: %d.\n",report.xexpose.count);
2280  printf("Window ID is: %d.\n",report.xexpose.window);
2281 #endif
2282  if (report.xexpose.count != 0)
2283  break;
2284  if (report.xexpose.window == menu)
2285  drawmenu();
2286  else if (report.xexpose.window == toplevel) {
2287  drawscreen();
2288  xold = -1; /* No rubber band on screen */
2289  }
2290  else if (report.xexpose.window == textarea)
2291  draw_message();
2292  break;
2293  case ConfigureNotify:
2294  top_width = report.xconfigure.width;
2295  top_height = report.xconfigure.height;
2296  update_transform();
2297  drawmenu();
2298  draw_message();
2299 #ifdef VERBOSE
2300  printf("Got a ConfigureNotify.\n");
2301  printf("New width: %d New height: %d.\n",top_width,top_height);
2302 #endif
2303  break;
2304  case ButtonPress:
2305 #ifdef VERBOSE
2306  printf("Got a buttonpress.\n");
2307  printf("Window ID is: %d.\n",report.xbutton.window);
2308  printf("Location (%d, %d).\n", report.xbutton.x,
2309  report.xbutton.y);
2310 #endif
2311  if (report.xbutton.window != toplevel) break;
2312  x[corner] = report.xbutton.x;
2313  y[corner] = report.xbutton.y;
2314  if (corner == 0) {
2315  /* XSelectInput (display, toplevel, ExposureMask |
2316  StructureNotifyMask | ButtonPressMask | PointerMotionMask); */
2317  }
2318  else {
2319  update_win(x,y,drawscreen);
2320  }
2321  corner++;
2322  break;
2323  case MotionNotify:
2324  if (corner) {
2325 #ifdef VERBOSE
2326  printf("Got a MotionNotify Event.\n");
2327  printf("x: %d y: %d\n",report.xmotion.x,report.xmotion.y);
2328 #endif
2329  if (xold >= 0) { /* xold set -ve before we draw first box */
2330  // Erase prior box.
2332  XDrawRectangle(display,toplevel,gcxor,min(x[0],xold),
2333  min(y[0],yold),abs(x[0]-xold),abs(y[0]-yold));
2335  }
2336  /* Don't allow user to window under menu region */
2337  xold = min(report.xmotion.x,top_width-1-MWIDTH);
2338  yold = report.xmotion.y;
2340 
2341  // Use forcing versions, as we want these modes to apply
2342  // to the xor drawing context, and the regular versions
2343  // won't update the drawing context if there is no change in line
2344  // width etc. (but they might only be on the normal context)
2345  force_setlinewidth(1);
2348 
2349  // Draw rubber band box.
2350  XDrawRectangle(display,toplevel,gcxor,min(x[0],xold),
2351  min(y[0],yold),abs(x[0]-xold),abs(y[0]-yold));
2353  }
2354  break;
2355  }
2356  }
2357  /* XSelectInput (display, toplevel, ExposureMask | StructureNotifyMask
2358  | ButtonPressMask); */
2359 #else /* Win32 */
2360  /* Implemented as WM_LB... events */
2361 
2362  /* Begin window adjust */
2363  if (!windowAdjustFlag) {
2364  windowAdjustFlag = 1;
2365  }
2366 #endif
2367 }
2368 
2369 
2370 static void
2371 postscript (void (*drawscreen) (void))
2372 {
2373 /* Takes a snapshot of the screen and stores it in pic?.ps. The *
2374  * first picture goes in pic1.ps, the second in pic2.ps, etc. */
2375 
2376  static int piccount = 1;
2377  int success;
2378  char fname[BUFSIZE];
2379 
2380  sprintf(fname,"pic%d.ps",piccount);
2381  printf("Writing postscript output to file %s\n", fname);
2382  success = init_postscript (fname);
2383 
2384  if (success) {
2385 
2386  drawscreen();
2387  close_postscript ();
2388  piccount++;
2389  }
2390  else {
2391  printf ("Error initializing for postscript output.\n");
2392 #ifdef WIN32
2393  MessageBox(hMainWnd, "Error initializing postscript output.", NULL, MB_OK);
2394 #endif
2395  }
2396 }
2397 
2398 
2399 static void
2400 proceed (void (*drawscreen) (void))
2401 {
2402  ProceedPressed = TRUE;
2403 }
2404 
2405 
2406 static void
2407 quit (void (*drawscreen) (void))
2408 {
2409  close_graphics();
2410  exit(0);
2411 }
2412 
2413 
2414 /* Release all my drawing structures (through the X server) and *
2415 * close down the connection. */
2416 void
2418 {
2419  if (!gl_state.initialized)
2420  return;
2421 #ifdef X11
2422  int i;
2423  for (i=0;i<=MAX_FONT_SIZE;i++) {
2424  if (font_is_loaded[i])
2425  XFreeFont(display,font_info[i]);
2426  }
2427 
2428  XFreeGC(display,gc);
2429  XFreeGC(display,gcxor);
2430  XFreeGC(display,gc_menus);
2431 
2432  if (private_cmap != None)
2433  XFreeColormap (display, private_cmap);
2434 
2435  XCloseDisplay(display);
2436 #else /* Win32 */
2437  int i;
2438  // Free the font data structure for each loaded font.
2439  for (i = 0; i <= MAX_FONT_SIZE; i++) {
2440  if (font_is_loaded[i]) {
2441  free (font_info[i]);
2442  }
2443  }
2444 
2445  // Destroy the window
2446  if(!DestroyWindow(hMainWnd))
2447  DRAW_ERROR();
2448 
2449  // free the window class (type information held by MS Windows)
2450  // for each of the four window types we created. Otherwise a
2451  // later call to init_graphics to open the graphics window up again
2452  // will fail.
2453  if (!UnregisterClass (szAppName, GetModuleHandle(NULL)) )
2454  DRAW_ERROR();
2455  if (!UnregisterClass (szGraphicsName, GetModuleHandle(NULL)) )
2456  DRAW_ERROR();
2457  if (!UnregisterClass (szStatusName, GetModuleHandle(NULL)) )
2458  DRAW_ERROR();
2459  if (!UnregisterClass (szButtonsName, GetModuleHandle(NULL)) )
2460  DRAW_ERROR();
2461 #endif
2462 
2463  free(button);
2464  button = NULL;
2465 
2466  for (i = 0; i <= MAX_FONT_SIZE; i++) {
2467  font_is_loaded[i] = false;
2468  font_info[i] = NULL;
2469  }
2470  gl_state.initialized = false;
2471 }
2472 
2473 
2474 /* Opens a file for PostScript output. The header information, *
2475 * clipping path, etc. are all dumped out. If the file could *
2476 * not be opened, the routine returns 0; otherwise it returns 1. */
2477 int init_postscript (const char *fname)
2478 {
2479 
2480  ps = fopen (fname,"w");
2481  if (ps == NULL) {
2482  printf("Error: could not open %s for PostScript output.\n",fname);
2483  printf("Drawing to screen instead.\n");
2484  return (0);
2485  }
2486  gl_state.disp_type = POSTSCRIPT; /* Graphics go to postscript file now. */
2487 
2488  /* Header for minimal conformance with the Adobe structuring convention */
2489  fprintf(ps,"%%!PS-Adobe-1.0\n");
2490  fprintf(ps,"%%%%DocumentFonts: Helvetica\n");
2491  fprintf(ps,"%%%%Pages: 1\n");
2492  /* Set up postscript transformation macros and page boundaries */
2494  /* Bottom margin is at ps_bot - 15. to leave room for the on-screen message. */
2495  fprintf(ps,"%%%%HiResBoundingBox: %.2f %.2f %.2f %.2f\n",
2496  ps_left, ps_bot - 15., ps_right, ps_top);
2497  fprintf(ps,"%%%%EndComments\n");
2498 
2499  fprintf(ps,"/censhow %%draw a centered string\n");
2500  fprintf(ps," { moveto %% move to proper spot\n");
2501  fprintf(ps," dup stringwidth pop %% get x length of string\n");
2502  fprintf(ps," -2 div %% Proper left start\n");
2503  fprintf(ps," yoff rmoveto %% Move left that much and down half font height\n");
2504  fprintf(ps," show newpath } def %% show the string\n\n");
2505 
2506  fprintf(ps,"/setfontsize %% set font to desired size and compute "
2507  "centering yoff\n");
2508  fprintf(ps," { /Helvetica findfont\n");
2509  fprintf(ps," 8 scalefont\n");
2510  fprintf(ps," setfont %% Font size set ...\n\n");
2511  fprintf(ps," 0 0 moveto %% Get vertical centering offset\n");
2512  fprintf(ps," (Xg) true charpath\n");
2513  fprintf(ps," flattenpath pathbbox\n");
2514  fprintf(ps," /ascent exch def pop -1 mul /descent exch def pop\n");
2515  fprintf(ps," newpath\n");
2516  fprintf(ps," descent ascent sub 2 div /yoff exch def } def\n\n");
2517 
2518  fprintf(ps,"%% Next two lines for debugging only.\n");
2519  fprintf(ps,"/str 20 string def\n");
2520  fprintf(ps,"/pnum {str cvs print ( ) print} def\n");
2521 
2522  fprintf(ps,"/drawline %% draw a line from (x2,y2) to (x1,y1)\n");
2523  fprintf(ps," { moveto lineto stroke } def\n\n");
2524 
2525  fprintf(ps,"/rect %% outline a rectangle \n");
2526  fprintf(ps," { /y2 exch def /x2 exch def /y1 exch def /x1 exch def\n");
2527  fprintf(ps," x1 y1 moveto\n");
2528  fprintf(ps," x2 y1 lineto\n");
2529  fprintf(ps," x2 y2 lineto\n");
2530  fprintf(ps," x1 y2 lineto\n");
2531  fprintf(ps," closepath } def\n\n");
2532 
2533  fprintf(ps,"/drawrect %% draw outline of a rectanagle\n");
2534  fprintf(ps," { rect stroke } def\n\n");
2535 
2536  fprintf(ps,"/fillrect %% fill in a rectanagle\n");
2537  fprintf(ps," { rect fill } def\n\n");
2538 
2539  fprintf (ps,"/drawarc { arc stroke } def %% draw an arc\n");
2540  fprintf (ps,"/drawarcn { arcn stroke } def "
2541  " %% draw an arc in the opposite direction\n\n");
2542 
2543  fprintf (ps,"%%Fill a counterclockwise or clockwise arc sector, "
2544  "respectively.\n");
2545  fprintf (ps,"/fillarc { moveto currentpoint 5 2 roll arc closepath fill } "
2546  "def\n");
2547  fprintf (ps,"/fillarcn { moveto currentpoint 5 2 roll arcn closepath fill } "
2548  "def\n\n");
2549 
2550  fprintf (ps,"/fillpoly { 3 1 roll moveto %% move to first point\n"
2551  " 2 exch 1 exch {pop lineto} for %% line to all other points\n"
2552  " closepath fill } def\n\n");
2553 
2554 
2555  fprintf(ps,"%%Color Definitions:\n");
2556  fprintf(ps,"/white { 1 setgray } def\n");
2557  fprintf(ps,"/black { 0 setgray } def\n");
2558  fprintf(ps,"/grey55 { .55 setgray } def\n");
2559  fprintf(ps,"/grey75 { .75 setgray } def\n");
2560  fprintf(ps,"/blue { 0 0 1 setrgbcolor } def\n");
2561  fprintf(ps,"/green { 0 1 0 setrgbcolor } def\n");
2562  fprintf(ps,"/yellow { 1 1 0 setrgbcolor } def\n");
2563  fprintf(ps,"/cyan { 0 1 1 setrgbcolor } def\n");
2564  fprintf(ps,"/red { 1 0 0 setrgbcolor } def\n");
2565  fprintf(ps,"/darkgreen { 0 0.5 0 setrgbcolor } def\n");
2566  fprintf(ps,"/magenta { 1 0 1 setrgbcolor } def\n");
2567  fprintf(ps,"/bisque { 1 0.89 0.77 setrgbcolor } def\n");
2568  fprintf(ps,"/lightblue { 0.68 0.85 0.9 setrgbcolor } def\n");
2569  fprintf(ps,"/thistle { 0.85 0.75 0.85 setrgbcolor } def\n");
2570  fprintf(ps,"/plum { 0.87 0.63 0.87 setrgbcolor } def\n");
2571  fprintf(ps,"/khaki { 0.94 0.9 0.55 setrgbcolor } def\n");
2572  fprintf(ps,"/coral { 1 0.5 0.31 setrgbcolor } def\n");
2573  fprintf(ps,"/turquoise { 0.25 0.88 0.82 setrgbcolor } def\n");
2574  fprintf(ps,"/mediumpurple { 0.58 0.44 0.86 setrgbcolor } def\n");
2575  fprintf(ps,"/darkslateblue { 0.28 0.24 0.55 setrgbcolor } def\n");
2576  fprintf(ps,"/darkkhaki { 0.74 0.72 0.42 setrgbcolor } def\n");
2577 
2578  fprintf(ps,"\n%%Solid and dashed line definitions:\n");
2579  fprintf(ps,"/linesolid {[] 0 setdash} def\n");
2580  fprintf(ps,"/linedashed {[3 3] 0 setdash} def\n");
2581 
2582  fprintf(ps,"\n%%%%EndProlog\n");
2583  fprintf(ps,"%%%%Page: 1 1\n\n");
2584 
2585  /* Set up PostScript graphics state to match current one. */
2590 
2591  /* Draw this in the bottom margin -- must do before the clippath is set */
2592  draw_message ();
2593 
2594  /* Set clipping on page. */
2595  fprintf(ps,"%.2f %.2f %.2f %.2f rect ",ps_left, ps_bot,ps_right,ps_top);
2596  fprintf(ps,"clip newpath\n\n");
2597 
2598  return (1);
2599 }
2600 
2601 /* Properly ends postscript output and redirects output to screen. */
2602 void close_postscript (void)
2603 {
2604 
2605  fprintf(ps,"showpage\n");
2606  fprintf(ps,"\n%%%%Trailer\n");
2607  fclose (ps);
2609  update_transform(); /* Ensure screen world reflects any changes *
2610  * made while printing. */
2611 
2612  /* Need to make sure that we really set up the graphics context.
2613  * The current font set indicates the last font used in a postscript call,
2614  * etc., *NOT* the font set in the X11 or Win32 graphics context. Force the
2615  * current font, colour etc. to be applied to the graphics context, so
2616  * subsequent drawing commands work properly.
2617  */
2618 
2623 }
2624 
2625 
2626 /* Sets up the default menu buttons on the right hand side of the window. */
2627 static void
2629 {
2630  int i, xcen, x1, y1, bwid, bheight, space;
2631  const int NUM_ARROW_BUTTONS = 4, NUM_STANDARD_BUTTONS = 12, SEPARATOR_BUTTON_INDEX = 8;
2632 
2633 
2634 #ifdef X11
2635  unsigned long valuemask;
2636  XSetWindowAttributes menu_attributes;
2637 
2638  menu = XCreateSimpleWindow(display,toplevel,
2641  menu_attributes.event_mask = ExposureMask;
2642  /* Ignore button presses on the menu background. */
2643  menu_attributes.do_not_propagate_mask = ButtonPressMask;
2644  /* Keep menu on top right */
2645  menu_attributes.win_gravity = NorthEastGravity;
2646  valuemask = CWWinGravity | CWEventMask | CWDontPropagate;
2647  XChangeWindowAttributes(display, menu, valuemask, &menu_attributes);
2648  XMapWindow (display, menu);
2649 #endif
2650 
2651  button = (t_button *) my_malloc (NUM_STANDARD_BUTTONS * sizeof (t_button));
2652 
2653  /* Now do the arrow buttons */
2654  bwid = 28;
2655  space = 3;
2656  y1 = 10;
2657  xcen = 51;
2658  x1 = xcen - bwid/2;
2659  button[0].xleft = x1;
2660  button[0].ytop = y1;
2661 #ifdef X11
2662  setpoly (0, bwid/2, bwid/2, bwid/3, -PI/2.); /* Up */
2663 #else
2664  button[0].type = BUTTON_TEXT;
2665  strcpy(button[0].text, "U");
2666 #endif
2667  button[0].fcn = translate_up;
2668 
2669  y1 += bwid + space;
2670  x1 = xcen - 3*bwid/2 - space;
2671  button[1].xleft = x1;
2672  button[1].ytop = y1;
2673 #ifdef X11
2674  setpoly (1, bwid/2, bwid/2, bwid/3, PI); /* Left */
2675 #else
2676  button[1].type = BUTTON_TEXT;
2677  strcpy(button[1].text, "L");
2678 #endif
2679  button[1].fcn = translate_left;
2680 
2681  x1 = xcen + bwid/2 + space;
2682  button[2].xleft = x1;
2683  button[2].ytop = y1;
2684 #ifdef X11
2685  setpoly (2, bwid/2, bwid/2, bwid/3, 0); /* Right */
2686 #else
2687  button[2].type = BUTTON_TEXT;
2688  strcpy(button[2].text, "R");
2689 #endif
2690  button[2].fcn = translate_right;
2691 
2692  y1 += bwid + space;
2693  x1 = xcen - bwid/2;
2694  button[3].xleft = x1;
2695  button[3].ytop = y1;
2696 #ifdef X11
2697  setpoly (3, bwid/2, bwid/2, bwid/3, +PI/2.); /* Down */
2698 #else
2699  button[3].type = BUTTON_TEXT;
2700  strcpy(button[3].text, "D");
2701 #endif
2702  button[3].fcn = translate_down;
2703 
2704  for (i = 0; i < NUM_ARROW_BUTTONS; i++) {
2705  button[i].width = bwid;
2706  button[i].height = bwid;
2707  button[i].enabled = 1;
2708  }
2709 
2710  /* Rectangular buttons */
2711 
2712  y1 += bwid + space + 6;
2713  space = 8;
2714  bwid = 90;
2715  bheight = 26;
2716  x1 = xcen - bwid/2;
2717  for (i = NUM_ARROW_BUTTONS; i < NUM_STANDARD_BUTTONS; i++) {
2718  button[i].xleft = x1;
2719  button[i].ytop = y1;
2720  button[i].type = BUTTON_TEXT;
2721  button[i].width = bwid;
2722  button[i].enabled = 1;
2723  if (i != SEPARATOR_BUTTON_INDEX) {
2724  button[i].height = bheight;
2725  y1 += bheight + space;
2726  }
2727  else {
2728  button[i].height = 2;
2730  y1 += 2 + space;
2731  }
2732  }
2733 
2734  strcpy (button[4].text,"Zoom In");
2735  strcpy (button[5].text,"Zoom Out");
2736  strcpy (button[6].text,"Zoom Fit");
2737  strcpy (button[7].text,"Window");
2738  strcpy (button[8].text,"---1");
2739  strcpy (button[9].text,"PostScript");
2740  strcpy (button[10].text,"Proceed");
2741  strcpy (button[11].text,"Exit");
2742 
2743  button[4].fcn = zoom_in;
2744  button[5].fcn = zoom_out;
2745  button[6].fcn = zoom_fit;
2746  button[7].fcn = adjustwin; // see 'adjustButton' below in WIN32 section
2747  button[8].fcn = NULL;
2748  button[9].fcn = postscript;
2749  button[10].fcn = proceed;
2750  button[11].fcn = quit;
2751 
2752  for (i = 0; i < NUM_STANDARD_BUTTONS; i++)
2753  map_button (i);
2754  num_buttons = NUM_STANDARD_BUTTONS;
2755 
2756 #ifdef WIN32
2757  adjustButton = 7;
2758  if(!InvalidateRect(hButtonsWnd, NULL, TRUE))
2759  DRAW_ERROR();
2760  if(!UpdateWindow(hButtonsWnd))
2761  DRAW_ERROR();
2762 #endif
2763 }
2764 
2765 /* Makes sure the font of the specified size is loaded. Point_size *
2766 * MUST be between 1 and MAX_FONT_SIZE. */
2767 static void
2768 load_font(int pointsize)
2769 {
2770 
2771  if (pointsize > MAX_FONT_SIZE || pointsize < 1) {
2772  printf ("Error: font size %d is out of valid range, 1 to %d.\n",
2773  pointsize, MAX_FONT_SIZE);
2774  return;
2775  }
2776 
2777  if (font_is_loaded[pointsize]) // Nothing to do.
2778  return;
2779 
2780 #ifdef X11
2781  #define NUM_FONT_TYPES 3
2782  char fontname[NUM_FONT_TYPES][BUFSIZE];
2783  int ifont;
2784  bool success = false;
2785 
2786  /* Use proper point-size medium-weight upright helvetica font */
2787  // Exists on most X11 systems.
2788  // Backup font: lucidasans, in the new naming style.
2789  sprintf(fontname[0],"-*-helvetica-medium-r-*--*-%d0-*-*-*-*-*-*",
2790  pointsize);
2791  sprintf(fontname[1], "lucidasans-%d", pointsize);
2792  sprintf(fontname[2],"-schumacher-clean-medium-r-*--*-%d0-*-*-*-*-*-*",
2793  pointsize);
2794 
2795 
2796 
2797 
2798  for (ifont = 0; ifont < NUM_FONT_TYPES; ifont++) {
2799 #ifdef VERBOSE
2800  printf ("Loading font: point size: %d, fontname: %s\n",pointsize,
2801  fontname[ifont]);
2802 #endif
2803  /* Load font and get font information structure. */
2804  if ((font_info[pointsize] = XLoadQueryFont(display,fontname[ifont])) == NULL) {
2805 #ifdef VERBOSE
2806  fprintf( stderr, "Cannot open font %s\n", fontname[ifont]);
2807 #endif
2808  }
2809  else {
2810  success = true;
2811  break;
2812  }
2813  }
2814  if (!success) {
2815  printf ("Error in load_font: cannot load any font of pointsize %d.\n",
2816  pointsize);
2817  printf ("Use xlsfonts to list available fonts, and modify load_font\n");
2818  printf ("in graphics.cpp.\n");
2819  exit (1);
2820  }
2821 #else /* WIN32 */
2822  LOGFONT *lf = font_info[pointsize] = (LOGFONT*)my_malloc(sizeof(LOGFONT));
2823  ZeroMemory(lf, sizeof(LOGFONT));
2824  lf->lfHeight = pointsize;
2825  lf->lfWeight = FW_NORMAL;
2826  lf->lfCharSet = ANSI_CHARSET;
2827  lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
2828  lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
2829  lf->lfQuality = PROOF_QUALITY;
2830  lf->lfPitchAndFamily = VARIABLE_PITCH | FF_SWISS;
2831  strcpy(lf->lfFaceName, "Arial");
2832 #endif
2833 
2834  font_is_loaded[pointsize] = true;
2835 }
2836 
2837 
2838 /* Return information useful for debugging.
2839  * Used to return the top-level window object too, but that made graphics.h
2840  * export all windows and X11 headers to the client program, so VB deleted
2841  * that object (mainwnd) from this structure.
2842  */
2844  report->xmult = xmult;
2845  report->ymult = ymult;
2846  report->xleft = xleft;
2847  report->xright = xright;
2848  report->ytop = ytop;
2849  report->ybot = ybot;
2850  report->ps_xmult = ps_xmult;
2851  report->ps_ymult = ps_ymult;
2852  report->top_width = top_width;
2853  report->top_height = top_height;
2854 }
2855 
2856 
2857 void set_mouse_move_input (bool enable) {
2858  get_mouse_move_input = enable;
2859 }
2860 
2861 
2862 void set_keypress_input (bool enable) {
2863  get_keypress_input = enable;
2864 }
2865 
2866 
2867 void enable_or_disable_button (int ibutton, bool enabled) {
2868 
2869  if (button[ibutton].type != BUTTON_SEPARATOR) {
2870  button[ibutton].enabled = enabled;
2871 #ifdef WIN32
2872  EnableWindow(button[ibutton].hwnd, button[ibutton].enabled);
2873 #else // X11
2874  drawbut(ibutton);
2875  XFlush(display);
2876 #endif
2877  }
2878 }
2879 
2880 
2881 void set_draw_mode (enum e_draw_mode draw_mode) {
2882 /* Set normal (overwrite) or xor (useful for rubber-banding)
2883  * drawing mode.
2884  */
2885 
2886  if (draw_mode == DRAW_NORMAL) {
2887 #ifdef X11
2888  current_gc = gc;
2889 #else
2890  if (!SetROP2(hGraphicsDC, R2_COPYPEN))
2891  SELECT_ERROR();
2892 #endif
2893  }
2894  else { // DRAW_XOR
2895 #ifdef X11
2896  current_gc = gcxor;
2897 #else
2898  if (!SetROP2(hGraphicsDC, R2_XORPEN))
2899  SELECT_ERROR();
2900 #endif
2901  }
2902  current_draw_mode = draw_mode;
2903 }
2904 
2905 
2906 void change_button_text(const char *button_name, const char *new_button_text) {
2907 /* Change the text on a button with button_name to new_button_text.
2908  * Not a strictly necessary function, since you could intead just
2909  * destroy button_name and make a new buton.
2910  */
2911  int i, bnum;
2912 
2913  bnum = -1;
2914 
2915  for (i=4;i<num_buttons;i++) {
2916  if (button[i].type == BUTTON_TEXT &&
2917  strcmp (button[i].text, button_name) == 0) {
2918  bnum = i;
2919  break;
2920  }
2921  }
2922 
2923  if (bnum != -1) {
2924  strncpy (button[i].text, new_button_text, BUTTON_TEXT_LEN);
2925 #ifdef X11
2926  drawbut (i);
2927 #else // Win32
2928  SetWindowText(button[bnum].hwnd, new_button_text);
2929 #endif
2930  }
2931 }
2932 
2933 
2934 
2935 
2936 /**********************************
2937 * X-Windows Specific Definitions *
2938 *********************************/
2939 #ifdef X11
2940 
2941 /* Creates a small window at the top of the graphics area for text messages */
2942 static void build_textarea (void)
2943 {
2944  XSetWindowAttributes menu_attributes;
2945  unsigned long valuemask;
2946 
2947  textarea = XCreateSimpleWindow(display,toplevel,
2950  menu_attributes.event_mask = ExposureMask;
2951  /* ButtonPresses in this area are ignored. */
2952  menu_attributes.do_not_propagate_mask = ButtonPressMask;
2953  /* Keep text area on bottom left */
2954  menu_attributes.win_gravity = SouthWestGravity;
2955  valuemask = CWWinGravity | CWEventMask | CWDontPropagate;
2956  XChangeWindowAttributes(display, textarea, valuemask, &menu_attributes);
2957  XMapWindow (display, textarea);
2958 }
2959 
2960 
2961 
2962 static Bool test_if_exposed (Display *disp, XEvent *event_ptr, XPointer dummy)
2963 /* Returns True if the event passed in is an exposure event. Note that
2964  * the bool type returned by this function is defined in Xlib.h.
2965  */
2966 {
2967 
2968 
2969  if (event_ptr->type == Expose) {
2970  return (True);
2971  }
2972 
2973  return (False);
2974 }
2975 
2976 
2977 static void menutext(Window win, int xc, int yc, const char *text)
2978 {
2979 
2980  /* draws text center at xc, yc -- used only by menu drawing stuff */
2981 
2982  int len, width;
2983 
2984  len = strlen(text);
2985  width = XTextWidth(font_info[menu_font_size], text, len);
2986  XDrawString(display, win, gc_menus, xc-width/2, yc +
2987  (font_info[menu_font_size]->ascent - font_info[menu_font_size]->descent)/2,
2988  text, len);
2989 }
2990 
2991 
2992 static void drawbut (int bnum)
2993 {
2994 
2995  /* Draws button bnum in either its pressed or unpressed state. */
2996 
2997  int width, height, thick, i, ispressed;
2998  XPoint mypoly[6];
2999 
3000  width = button[bnum].width;
3001  height = button[bnum].height;
3002 
3003  if (button[bnum].type == BUTTON_SEPARATOR) {
3004  int x,y;
3005 
3006  x = button[bnum].xleft;
3007  y = button[bnum].ytop;
3008  XSetForeground(display, gc_menus,colors[WHITE]);
3009  XDrawLine(display, menu, gc_menus, x, y+1, x+width, y+1);
3010  XSetForeground(display, gc_menus,colors[BLACK]);
3011  XDrawLine(display, menu, gc_menus, x, y, x+width, y);
3012  return;
3013  }
3014 
3015  ispressed = button[bnum].ispressed;
3016  thick = 2;
3017  /* Draw top and left edges of 3D box. */
3018  if (ispressed) {
3019  XSetForeground(display, gc_menus,colors[BLACK]);
3020  }
3021  else {
3022  XSetForeground(display, gc_menus,colors[WHITE]);
3023  }
3024 
3025  /* Note: X Windows doesn't appear to draw the bottom pixel of *
3026  * a polygon with XFillPolygon, so I make this 1 pixel thicker *
3027  * to compensate. */
3028  mypoly[0].x = 0;
3029  mypoly[0].y = height;
3030  mypoly[1].x = 0;
3031  mypoly[1].y = 0;
3032  mypoly[2].x = width;
3033  mypoly[2].y = 0;
3034  mypoly[3].x = width-thick;
3035  mypoly[3].y = thick;
3036  mypoly[4].x = thick;
3037  mypoly[4].y = thick;
3038  mypoly[5].x = thick;
3039  mypoly[5].y = height-thick;
3040  XFillPolygon(display,button[bnum].win,gc_menus,mypoly,6,Convex,
3041  CoordModeOrigin);
3042 
3043  /* Draw bottom and right edges of 3D box. */
3044  if (ispressed) {
3045  XSetForeground(display, gc_menus,colors[WHITE]);
3046  }
3047  else {
3048  XSetForeground(display, gc_menus,colors[BLACK]);
3049  }
3050  mypoly[0].x = 0;
3051  mypoly[0].y = height;
3052  mypoly[1].x = width;
3053  mypoly[1].y = height;
3054  mypoly[2].x = width;
3055  mypoly[2].y = 0;
3056  mypoly[3].x = width-thick;
3057  mypoly[3].y = thick;
3058  mypoly[4].x = width-thick;
3059  mypoly[4].y = height-thick;
3060  mypoly[5].x = thick;
3061  mypoly[5].y = height-thick;
3062  XFillPolygon(display,button[bnum].win,gc_menus,mypoly,6,Convex,
3063  CoordModeOrigin);
3064 
3065  /* Draw background */
3066  if (ispressed) {
3067  XSetForeground(display, gc_menus,colors[DARKGREY]);
3068  }
3069  else {
3070  XSetForeground(display, gc_menus,colors[LIGHTGREY]);
3071  }
3072 
3073  /* Give x,y of top corner and width and height */
3074  XFillRectangle (display,button[bnum].win,gc_menus,thick,thick,
3075  width-2*thick, height-2*thick);
3076 
3077  /* Draw polygon, if there is one */
3078  if (button[bnum].type == BUTTON_POLY) {
3079  for (i=0;i<3;i++) {
3080  mypoly[i].x = button[bnum].poly[i][0];
3081  mypoly[i].y = button[bnum].poly[i][1];
3082  }
3083  XSetForeground(display, gc_menus,colors[BLACK]);
3084  XFillPolygon(display,button[bnum].win,gc_menus,mypoly,3,Convex,
3085  CoordModeOrigin);
3086  }
3087 
3088  /* Draw text, if there is any */
3089  if (button[bnum].type == BUTTON_TEXT) {
3090  if (button[bnum].enabled)
3091  XSetForeground(display, gc_menus,colors[BLACK]);
3092  else
3093  XSetForeground(display, gc_menus,colors[DARKGREY]);
3094  menutext(button[bnum].win,button[bnum].width/2,
3095  button[bnum].height/2,button[bnum].text);
3096  }
3097 }
3098 
3099 
3100 static int which_button (Window win)
3101 {
3102  int i;
3103 
3104  for (i=0;i<num_buttons;i++) {
3105  if (button[i].win == win)
3106  return(i);
3107  }
3108  printf("Error: Unknown button ID in which_button.\n");
3109  return(0);
3110 }
3111 
3112 
3113 static void turn_on_off (int pressed) {
3114 /* Shows when the menu is active or inactive by colouring the
3115  * buttons.
3116  */
3117  int i;
3118 
3119  for (i=0;i<num_buttons;i++) {
3120  button[i].ispressed = pressed;
3121  drawbut(i);
3122  }
3123 }
3124 
3125 
3126 static void drawmenu(void)
3127 {
3128  int i;
3129 
3130  XClearWindow (display, menu);
3131  XSetForeground(display, gc_menus,colors[WHITE]);
3132  XDrawRectangle(display, menu, gc_menus, 0, 0, MWIDTH, top_height);
3133  XSetForeground(display, gc_menus,colors[BLACK]);
3134  XDrawLine(display, menu, gc_menus, 0, top_height-1, MWIDTH, top_height-1);
3135  XDrawLine(display, menu, gc_menus, MWIDTH-1, top_height, MWIDTH-1, 0);
3136 
3137  for (i=0;i<num_buttons;i++) {
3138  drawbut(i);
3139  }
3140 }
3141 
3142 #endif /* X-Windows Specific Definitions */
3143 
3144 
3145 
3146 /*************************************************
3147 * Microsoft Windows (WIN32) Specific Definitions *
3148 *************************************************/
3149 #ifdef WIN32
3150 
3151 static LRESULT CALLBACK
3152 MainWND(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3153 {
3154  MINMAXINFO FAR *lpMinMaxInfo;
3155 
3156  switch(message)
3157  {
3158 
3159  case WM_CREATE:
3160  hStatusWnd = CreateWindow(szStatusName, NULL, WS_CHILDWINDOW | WS_VISIBLE,
3161  0, 0, 0, 0, hwnd, (HMENU) 102, (HINSTANCE) GetWindowLong(hwnd, GWL_HINSTANCE), NULL);
3162  hButtonsWnd = CreateWindow(szButtonsName, NULL, WS_CHILDWINDOW | WS_VISIBLE,
3163  0, 0, 0, 0, hwnd, (HMENU) 103, (HINSTANCE) GetWindowLong(hwnd, GWL_HINSTANCE), NULL);
3164  hGraphicsWnd = CreateWindow(szGraphicsName, NULL, WS_CHILDWINDOW | WS_VISIBLE,
3165  0, 0, 0, 0, hwnd, (HMENU) 101, (HINSTANCE) GetWindowLong(hwnd, GWL_HINSTANCE), NULL);
3166  return 0;
3167 
3168  case WM_SIZE:
3169  /* Window has been resized. Save the new client dimensions */
3170  top_width = LOWORD (lParam);
3171  top_height = HIWORD (lParam);
3172 
3173  /* Resize the children windows */
3174  if(!MoveWindow(hGraphicsWnd, 1, 1, top_width - MWIDTH - 1, top_height - T_AREA_HEIGHT - 1, TRUE))
3175  DRAW_ERROR();
3176 // if (drawscreen_ptr)
3177 // zoom_fit(drawscreen_ptr);
3178  if(!MoveWindow(hStatusWnd, 0, top_height - T_AREA_HEIGHT, top_width - MWIDTH, T_AREA_HEIGHT, TRUE))
3179  DRAW_ERROR();
3180  if(!MoveWindow(hButtonsWnd, top_width - MWIDTH, 0, MWIDTH, top_height, TRUE))
3181  DRAW_ERROR();
3182 
3183  return 0;
3184 
3185  // WC : added to solve window resizing problem
3186  case WM_GETMINMAXINFO:
3187  // set the MINMAXINFO structure pointer
3188  lpMinMaxInfo = (MINMAXINFO FAR *) lParam;
3189  lpMinMaxInfo->ptMinTrackSize.x = display_width / 2;
3190  lpMinMaxInfo->ptMinTrackSize.y = display_height / 2;
3191 
3192  return 0;
3193 
3194 
3195  case WM_DESTROY:
3196  if(!DeleteObject(hGrayBrush))
3197  DELETE_ERROR();
3198  PostQuitMessage(0);
3199  return 0;
3200 
3201  case WM_KEYDOWN:
3202  if (get_keypress_input)
3203  keypress_ptr((char) wParam);
3204  return 0;
3205  }
3206 
3207  return DefWindowProc(hwnd, message, wParam, lParam);
3208 }
3209 
3210 
3211 static LRESULT CALLBACK
3212 GraphicsWND(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3213 {
3214  static TEXTMETRIC tm;
3215 
3216  PAINTSTRUCT ps;
3217  static RECT oldAdjustRect;
3218  static HPEN hDotPen = 0;
3219  static HBITMAP hbmBuffer = 0, hbmObjtest, hbmAllObjtest;
3220  static int X, Y, i;
3221 
3222  switch(message)
3223  {
3224  case WM_CREATE:
3225 
3226  /* Get the text metrics once upon creation (system font cannot change) */
3227  hCurrentDC = hGraphicsDC = hForegroundDC = GetDC (hwnd);
3228  if(!hGraphicsDC)
3229  DRAW_ERROR();
3230 
3231  hBackgroundDC = CreateCompatibleDC(hForegroundDC);
3232  if (!hBackgroundDC)
3233  CREATE_ERROR();
3234  if (!SetMapMode(hBackgroundDC, MM_TEXT))
3235  CREATE_ERROR();
3236  hbmBuffer = CreateCompatibleBitmap(hForegroundDC, display_width, display_height);
3237  if (!(hbmBuffer))
3238  CREATE_ERROR();
3239  if (!SelectObject(hBackgroundDC, hbmBuffer))
3240  SELECT_ERROR();
3241 
3242  // monochrome bitmap
3243  hObjtestDC = CreateCompatibleDC(hForegroundDC);
3244  if (!hObjtestDC)
3245  CREATE_ERROR();
3246  if (!SetMapMode(hObjtestDC, MM_TEXT))
3247  CREATE_ERROR();
3248  hbmObjtest = CreateCompatibleBitmap(hObjtestDC, display_width, display_height);
3249  if (!(hbmObjtest))
3250  CREATE_ERROR();
3251  if (!SelectObject(hObjtestDC, hbmObjtest))
3252  SELECT_ERROR();
3253 
3254  // monochrome bitmap
3255  hAllObjtestDC = CreateCompatibleDC(hForegroundDC);
3256  if (!hObjtestDC)
3257  CREATE_ERROR();
3258  if (!SetMapMode(hAllObjtestDC, MM_TEXT))
3259  CREATE_ERROR();
3260  hbmAllObjtest = CreateCompatibleBitmap(hAllObjtestDC, display_width, display_height);
3261  if (!(hbmAllObjtest))
3262  CREATE_ERROR();
3263  if (!SelectObject(hAllObjtestDC, hbmAllObjtest))
3264  SELECT_ERROR();
3265 
3266  //if(!GetTextMetrics (hGraphicsDC, &tm))
3267  // DRAW_ERROR();
3268  if(!SetBkMode(hGraphicsDC, TRANSPARENT))
3269  DRAW_ERROR();
3270 
3271  /* Setup the pens, etc */
3273  currentcolor = BLACK;
3274  currentlinewidth = 1;
3275 
3276  /*
3277  if(!ReleaseDC (hwnd, hGraphicsDC))
3278  DRAW_ERROR();
3279 
3280  hGraphicsDC = 0;
3281  */ currentfontsize = 12;
3282  return 0;
3283 
3284  case WM_PAINT:
3285  // was in xor mode, but got a general redraw.
3286  // switch to normal drawing so we repaint properly.
3287  if (current_draw_mode == DRAW_XOR) {
3289  invalidate_screen();
3290  return 0;
3291  }
3292  hCurrentDC = hGraphicsDC;
3293  drawtoscreen();
3294  /*hGraphicsDC =*/ BeginPaint(hwnd, &ps);
3295  if(!hGraphicsDC)
3296  DRAW_ERROR();
3297 
3298  if (InEventLoop) {
3299  if(!GetUpdateRect(hwnd, &updateRect, FALSE)) {
3300  updateRect.left = 0;
3301  updateRect.right = top_width;
3302  updateRect.top = 0;
3303  updateRect.bottom = top_height;
3304  }
3305 
3306  if(windowAdjustFlag > 1) {
3307  hDotPen = CreatePen(PS_DASH, 1, win32_colors[gl_state.background_cindex]);
3308  if(!hDotPen)
3309  CREATE_ERROR();
3310  if (!SetROP2(hGraphicsDC, R2_XORPEN))
3311  SELECT_ERROR();
3312  if(!SelectObject(hGraphicsDC, GetStockObject(NULL_BRUSH)))
3313  SELECT_ERROR();
3314  if(!SelectObject(hGraphicsDC, hDotPen))
3315  SELECT_ERROR();
3316  if(!Rectangle(hGraphicsDC, oldAdjustRect.left, oldAdjustRect.top,
3317  oldAdjustRect.right, oldAdjustRect.bottom))
3318  DRAW_ERROR();
3319  if(!Rectangle(hGraphicsDC, adjustRect.left, adjustRect.top, adjustRect.right,
3320  adjustRect.bottom))
3321  DRAW_ERROR();
3322  oldAdjustRect = adjustRect;
3323  if (!SetROP2(hGraphicsDC, R2_COPYPEN))
3324  SELECT_ERROR();
3325  if(!SelectObject(hGraphicsDC, GetStockObject(NULL_PEN)))
3326  SELECT_ERROR();
3327  if(!DeleteObject(hDotPen))
3328  DELETE_ERROR();
3329  }
3330  else
3331  drawscreen_ptr();
3332  }
3333  EndPaint(hwnd, &ps);
3334  hGraphicsDC = hCurrentDC;
3335 
3336  /* Crash hard if called at wrong time */
3337  /* hGraphicsDC = NULL;*/
3338  return 0;
3339 
3340  case WM_SIZE:
3341  /* Window has been resized. Save the new client dimensions */
3342  cxClient = LOWORD (lParam);
3343  cyClient = HIWORD (lParam);
3344  update_transform();
3345 
3346  return 0;
3347 
3348  case WM_DESTROY:
3349  if(!DeleteObject(hGraphicsPen))
3350  DELETE_ERROR();
3351  if(!DeleteObject(hGraphicsBrush))
3352  DELETE_ERROR();
3353  if(!DeleteObject(hGraphicsFont))
3354  DELETE_ERROR();
3355  if (!DeleteObject(hbmBuffer))
3356  DELETE_ERROR();
3357  if (!DeleteObject(hbmObjtest))
3358  DELETE_ERROR();
3359  if (!DeleteObject(hbmAllObjtest))
3360  DELETE_ERROR();
3361  if(!DeleteDC(hBackgroundDC))
3362  DELETE_ERROR();
3363  if(!DeleteDC(hObjtestDC))
3364  DELETE_ERROR();
3365  if(!DeleteDC(hAllObjtestDC))
3366  DELETE_ERROR();
3367  if(!ReleaseDC(hwnd, hForegroundDC))
3368  DELETE_ERROR();
3369  PostQuitMessage(0);
3370  return 0;
3371 
3372  case WM_LBUTTONDOWN:
3373  if (!windowAdjustFlag) {
3374  mouseclick_ptr(XTOWORLD(LOWORD(lParam)), YTOWORLD(HIWORD(lParam)));
3375  }
3376  else {
3377  // Special handling for the "Window" command, which takes multiple clicks.
3378  // First you push the button, then you click for one corner, then you click for the other
3379  // corner.
3380  if(windowAdjustFlag == 1) {
3381  windowAdjustFlag ++;
3382  X = adjustRect.left = adjustRect.right = LOWORD(lParam);
3383  Y = adjustRect.top = adjustRect.bottom = HIWORD(lParam);
3384  oldAdjustRect = adjustRect;
3385  }
3386  else {
3387  int i;
3388  int adjustx[2], adjusty[2];
3389 
3390  windowAdjustFlag = 0;
3391  button[adjustButton].ispressed = 0;
3392  SendMessage(button[adjustButton].hwnd, BM_SETSTATE, 0, 0);
3393 
3394  for (i=0; i<num_buttons; i++) {
3395  if (button[i].type != BUTTON_SEPARATOR && button[i].enabled) {
3396  if(!EnableWindow (button[i].hwnd, TRUE))
3397  DRAW_ERROR();
3398  }
3399  }
3400  adjustx[0] = adjustRect.left;
3401  adjustx[1] = adjustRect.right;
3402  adjusty[0] = adjustRect.top;
3403  adjusty[1] = adjustRect.bottom;
3404 
3405  update_win(adjustx, adjusty, invalidate_screen);
3406  }
3407  }
3408  return 0;
3409 
3410  // right click : a quick way to zoom in
3411  case WM_RBUTTONDOWN:
3412  if (!windowAdjustFlag) {
3413  // first disable some buttons
3414  //adjustButton = LOWORD(wParam) - 200;
3415  button[adjustButton].ispressed = 1;
3416  for (i=0; i<num_buttons; i++) {
3417  EnableWindow(button[i].hwnd, FALSE);
3418  SendMessage(button[i].hwnd, BM_SETSTATE, button[i].ispressed, 0);
3419  }
3420 
3421  windowAdjustFlag = 2;
3422  X = adjustRect.left = adjustRect.right = LOWORD(lParam);
3423  Y = adjustRect.top = adjustRect.bottom = HIWORD(lParam);
3424  oldAdjustRect = adjustRect;
3425  }
3426  else {
3427  int i;
3428  int adjustx[2], adjusty[2];
3429 
3430  windowAdjustFlag = 0;
3431  button[adjustButton].ispressed = 0;
3432  SendMessage(button[adjustButton].hwnd, BM_SETSTATE, 0, 0);
3433 
3434  for (i=0; i<num_buttons; i++) {
3435  if (button[i].type != BUTTON_SEPARATOR && button[i].enabled) {
3436  if(!EnableWindow (button[i].hwnd, TRUE))
3437  DRAW_ERROR();
3438  }
3439  }
3440  adjustx[0] = adjustRect.left;
3441  adjustx[1] = adjustRect.right;
3442  adjusty[0] = adjustRect.top;
3443  adjusty[1] = adjustRect.bottom;
3444 
3445  update_win(adjustx, adjusty, invalidate_screen);
3446  }
3447  return 0;
3448 
3449  case WM_MOUSEMOVE:
3450  if(windowAdjustFlag == 1) {
3451  return 0;
3452  }
3453  else if (windowAdjustFlag >= 2) {
3454  if ( X > LOWORD(lParam)) {
3455  adjustRect.left = LOWORD(lParam);
3456  adjustRect.right = X;
3457  }
3458  else {
3459  adjustRect.left = X;
3460  adjustRect.right = LOWORD(lParam);
3461  }
3462  if ( Y > HIWORD(lParam)) {
3463  adjustRect.top = HIWORD(lParam);
3464  adjustRect.bottom = Y;
3465  }
3466  else {
3467  adjustRect.top = Y;
3468  adjustRect.bottom = HIWORD(lParam);
3469  }
3470  if(!InvalidateRect(hGraphicsWnd, &oldAdjustRect, FALSE))
3471  DRAW_ERROR();
3472  if(!InvalidateRect(hGraphicsWnd, &adjustRect, FALSE))
3473  DRAW_ERROR();
3474  if(!UpdateWindow(hGraphicsWnd))
3475  DRAW_ERROR();
3476 
3477  return 0;
3478  }
3479  else if (get_mouse_move_input)
3480  mousemove_ptr(XTOWORLD(LOWORD(lParam)), YTOWORLD(HIWORD(lParam)));
3481 
3482  return 0;
3483  }
3484 
3485  return DefWindowProc(hwnd, message, wParam, lParam);
3486 }
3487 
3488 
3489 static LRESULT CALLBACK
3490 StatusWND(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3491 {
3492  HDC hdc;
3493  PAINTSTRUCT ps;
3494  RECT rect;
3495 
3496  switch(message)
3497  {
3498  case WM_CREATE:
3499  hdc = GetDC(hwnd);
3500  if(!hdc)
3501  DRAW_ERROR();
3502  if(!SetBkMode(hdc, TRANSPARENT))
3503  DRAW_ERROR();
3504  if(!ReleaseDC(hwnd, hdc))
3505  DRAW_ERROR();
3506  return 0;
3507 
3508  case WM_PAINT:
3509  hdc = BeginPaint(hwnd, &ps);
3510  if(!hdc)
3511  DRAW_ERROR();
3512 
3513  if(!GetClientRect(hwnd, &rect))
3514  DRAW_ERROR();
3515 
3516  if(!SelectObject(hdc, GetStockObject(NULL_BRUSH)))
3517  SELECT_ERROR();
3518  if(!SelectObject(hdc, GetStockObject(WHITE_PEN)))
3519  SELECT_ERROR();
3520  if(!Rectangle(hdc, rect.left, rect.top, rect.right, rect.bottom))
3521  DRAW_ERROR();
3522  if(!SelectObject(hdc, GetStockObject(BLACK_PEN)))
3523  SELECT_ERROR();
3524  if(!MoveToEx(hdc, rect.left, rect.bottom-1, NULL))
3525  DRAW_ERROR();
3526  if(!LineTo(hdc, rect.right-1, rect.bottom-1))
3527  DRAW_ERROR();
3528  if(!LineTo(hdc, rect.right-1, rect.top))
3529  DRAW_ERROR();
3530 
3531  if(!DrawText(hdc, TEXT(statusMessage), -1, &rect, DT_CENTER | DT_VCENTER | DT_SINGLELINE))
3532  DRAW_ERROR();
3533 
3534  if(!EndPaint(hwnd, &ps))
3535  DRAW_ERROR();
3536  return 0;
3537 
3538  case WM_SIZE:
3539  return 0;
3540 
3541  case WM_DESTROY:
3542  PostQuitMessage(0);
3543  return 0;
3544  }
3545 
3546  return DefWindowProc(hwnd, message, wParam, lParam);
3547 }
3548 
3549 
3550 static LRESULT CALLBACK
3551 ButtonsWND(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
3552 {
3553  HDC hdc;
3554  PAINTSTRUCT ps;
3555  RECT rect;
3556  static HBRUSH hBrush;
3557  int i;
3558 
3559  switch(message)
3560  {
3561  case WM_COMMAND:
3562  if (!windowAdjustFlag) {
3563  button[LOWORD(wParam) - 200].fcn(invalidate_screen);
3564  if (windowAdjustFlag) {
3565  adjustButton = LOWORD(wParam) - 200;
3566  button[adjustButton].ispressed = 1;
3567  for (i=0; i<num_buttons; i++) {
3568  EnableWindow(button[i].hwnd, FALSE);
3569  SendMessage(button[i].hwnd, BM_SETSTATE, button[i].ispressed, 0);
3570  }
3571  }
3572  }
3573  SetFocus(hMainWnd);
3574  return 0;
3575 
3576  case WM_CREATE:
3577  hdc = GetDC(hwnd);
3578  if(!hdc)
3579  DRAW_ERROR();
3580  hBrush = CreateSolidBrush(win32_colors[LIGHTGREY]);
3581  if(!hBrush)
3582  CREATE_ERROR();
3583  if(!SelectObject(hdc, hBrush))
3584  SELECT_ERROR();
3585  if(!SetBkMode(hdc, TRANSPARENT))
3586  DRAW_ERROR();
3587  if(!ReleaseDC(hwnd, hdc))
3588  DRAW_ERROR();
3589 
3590  return 0;
3591 
3592  case WM_PAINT:
3593  hdc = BeginPaint(hwnd, &ps);
3594  if(!hdc)
3595  DRAW_ERROR();
3596 
3597  if(!GetClientRect(hwnd, &rect))
3598  DRAW_ERROR();
3599 
3600  if(!SelectObject(hdc, GetStockObject(NULL_BRUSH)))
3601  SELECT_ERROR();
3602  if(!SelectObject(hdc, GetStockObject(WHITE_PEN)))
3603  SELECT_ERROR();
3604  if(!Rectangle(hdc, rect.left, rect.top, rect.right, rect.bottom))
3605  DRAW_ERROR();
3606  if(!SelectObject(hdc, GetStockObject(BLACK_PEN)))
3607  SELECT_ERROR();
3608  if(!MoveToEx(hdc, rect.left, rect.bottom-1, NULL))
3609  DRAW_ERROR();
3610  if(!LineTo(hdc, rect.right-1, rect.bottom-1))
3611  DRAW_ERROR();
3612  if(!LineTo(hdc, rect.right-1, rect.top))
3613  DRAW_ERROR();
3614 
3615  for (i=0; i < num_buttons; i++) {
3616  if(button[i].type == BUTTON_SEPARATOR) {
3617  int x, y, w;
3618 
3619  x = button[i].xleft;
3620  y = button[i].ytop;
3621  w = button[i].width;
3622 
3623  if(!MoveToEx (hdc, x, y, NULL))
3624  DRAW_ERROR();
3625  if(!LineTo (hdc, x + w, y))
3626  DRAW_ERROR();
3627  if(!SelectObject(hdc, GetStockObject(WHITE_PEN)))
3628  SELECT_ERROR();
3629  if(!MoveToEx (hdc, x, y+1, NULL))
3630  DRAW_ERROR();
3631  if(!LineTo (hdc, x + w, y+1))
3632  DRAW_ERROR();
3633  if(!SelectObject(hdc, GetStockObject(BLACK_PEN)))
3634  SELECT_ERROR();
3635  }
3636  }
3637  if(!EndPaint(hwnd, &ps))
3638  DRAW_ERROR();
3639  return 0;
3640 
3641  case WM_DESTROY:
3642  for (i=0; i<num_buttons; i++) {
3643  }
3644  if(!DeleteObject(hBrush))
3645  DELETE_ERROR();
3646  PostQuitMessage(0);
3647  return 0;
3648  }
3649 
3650  return DefWindowProc(hwnd, message, wParam, lParam);
3651 }
3652 
3653 
3654 void reset_win32_state () {
3655  // Not sure exactly what needs to be reset to NULL etc.
3656  // Resetting everthing to be safe.
3657  hGraphicsPen = 0;
3658  hGraphicsBrush = 0;
3659  hGrayBrush = 0;
3660  hGraphicsDC = 0;
3661  hForegroundDC = 0;
3662  hBackgroundDC = 0;
3663  hCurrentDC = 0, /* WC : double-buffer */
3664  hObjtestDC = 0;
3665  hAllObjtestDC = 0; /* object test */
3666 
3667  hGraphicsFont = 0;
3668 
3669  /* These are used for the "Window" graphics button. They keep track of whether we're entering
3670  * the window rectangle to zoom to, etc.
3671  */
3672  windowAdjustFlag = 0;
3673  adjustButton = -1;
3674  InEventLoop = FALSE;
3675 }
3676 
3677 
3678 void win32_drain_message_queue () {
3679  // Drain the message queue, so we don't have a quit message lying around
3680  // that will stop us from re-opening a window later if desired.
3681  MSG msg;
3682  while (PeekMessage(&msg, hMainWnd, 0, 0, PM_REMOVE)) {
3683  if (msg.message == WM_QUIT) {
3684  printf ("Got the quit message.\n");
3685  }
3686  }
3687 }
3688 
3689 
3690 void drawtobuffer(void) {
3691  hGraphicsDC = hBackgroundDC;
3692 }
3693 
3694 
3695 void drawtoscreen(void) {
3696  hGraphicsDC = hForegroundDC;
3697 }
3698 
3699 
3700 void displaybuffer(void) {
3701  if (!BitBlt(hForegroundDC, xcoord(xleft), ycoord(ytop),
3702  xcoord(xright)-xcoord(xleft), ycoord(ybot)-ycoord(ytop), hBackgroundDC,//hAllObjtestDC,
3703  0, 0, SRCCOPY))
3704  DRAW_ERROR();
3705 }
3706 
3707 
3708 static void _drawcurve(t_point *points, int npoints, int fill) {
3709 /* Draw a beizer curve.
3710  * Must have 3I+1 points, since each Beizer curve needs 3 points and we also
3711  * need an initial starting point
3712  */
3713  HPEN hOldPen;
3714  HBRUSH hOldBrush;
3715  float xmin, ymin, xmax, ymax;
3716  int i;
3717 
3718  if ((npoints - 1) % 3 != 0 || npoints > MAXPTS)
3719  DRAW_ERROR();
3720 
3721  /* Conservative (but fast) clip test -- check containing rectangle of *
3722  * polygon. */
3723 
3724  xmin = xmax = points[0].x;
3725  ymin = ymax = points[0].y;
3726 
3727  for (i=1;i<npoints;i++) {
3728  xmin = min (xmin,points[i].x);
3729  xmax = max (xmax,points[i].x);
3730  ymin = min (ymin,points[i].y);
3731  ymax = max (ymax,points[i].y);
3732  }
3733 
3734  if (rect_off_screen(xmin,ymin,xmax,ymax))
3735  return;
3736 
3737  if (gl_state.disp_type == SCREEN) {
3738 #ifdef X11
3739  /* implement X11 version here */
3740 #else /* Win32 */
3741  // create POINT array
3742  POINT pts[MAXPTS];
3743  int i;
3744 
3745  for (i = 0; i < npoints; i++) {
3746  pts[i].x = xcoord(points[i].x);
3747  pts[i].y = ycoord(points[i].y);
3748  }
3749 
3750  if (!fill) {
3751  hOldPen = (HPEN)SelectObject(hGraphicsDC, hGraphicsPen);
3752  if(!(hOldPen))
3753  SELECT_ERROR();
3754  }
3755  else {
3756  hOldPen = (HPEN)SelectObject(hGraphicsDC, GetStockObject(NULL_PEN));
3757  if(!(hOldPen))
3758  SELECT_ERROR();
3759  hOldBrush = (HBRUSH)SelectObject(hGraphicsDC, hGraphicsBrush);
3760  if(!(hOldBrush))
3761  SELECT_ERROR();
3762  }
3763 
3764  if (!BeginPath(hGraphicsDC))
3765  DRAW_ERROR();
3766  if(!PolyBezier(hGraphicsDC, pts, npoints))
3767  DRAW_ERROR();
3768  if (!EndPath(hGraphicsDC))
3769  DRAW_ERROR();
3770 
3771  if (!fill) {
3772  if (!StrokePath(hGraphicsDC))
3773  DRAW_ERROR();
3774  }
3775  else {
3776  if (!FillPath(hGraphicsDC))
3777  DRAW_ERROR();
3778  }
3779 
3780  if(!SelectObject(hGraphicsDC, hOldPen))
3781  SELECT_ERROR();
3782 
3783  if (fill) {
3784  if(!SelectObject(hGraphicsDC, hOldBrush))
3785  SELECT_ERROR();
3786  }
3787 #endif
3788  }
3789  else {
3790  int i;
3791 
3792  fprintf(ps, "newpath\n");
3793  fprintf(ps, "%.2f %.2f moveto\n", XPOST(points[0].x), YPOST(points[0].y));
3794  for (i = 1; i < npoints; i+= 3)
3795  fprintf(ps,"%.2f %.2f %.2f %.2f %.2f %.2f curveto\n", XPOST(points[i].x), YPOST(points[i].y),
3796  XPOST(points[i+1].x), YPOST(points[i+1].y), XPOST(points[i+2].x), YPOST(points[i+2].y));
3797  if (!fill)
3798  fprintf(ps, "stroke\n");
3799  else
3800  fprintf(ps, "fill\n");
3801  }
3802 }
3803 
3804 
3805 void drawcurve(t_point *points,
3806  int npoints) {
3807  _drawcurve(points, npoints, 0);
3808 }
3809 
3810 
3811 void fillcurve(t_point *points,
3812  int npoints) {
3813  _drawcurve(points, npoints, 1);
3814 }
3815 
3816 
3817 void object_start(int all) {
3818  if (all)
3819  hGraphicsDC = hAllObjtestDC;
3820  else
3821  hGraphicsDC = hObjtestDC;
3822  setcolor(WHITE);
3823  fillrect (xleft, ytop, xright, ybot);
3824  setcolor(BLACK);
3825 }
3826 
3827 
3828 void object_end() {
3829  hGraphicsDC = hCurrentDC;
3830 
3831 }
3832 
3833 
3834 int pt_on_object(int all, float x, float y) {
3835  COLORREF c;
3836 
3837  if (all)
3838  c = GetPixel(hAllObjtestDC, xcoord(x), ycoord(y));
3839  else
3840  c = GetPixel(hObjtestDC, xcoord(x), ycoord(y));
3841 
3842 // printf("c = %x\n", c);
3843 
3844  return c == win32_colors[BLACK];
3845 }
3846 
3847 static int check_fontsize(int pointsize,
3848  float ymax) {
3849  // return 0 if matches, 1 if font too big, -1 if font too small
3850  // a font matches if it's height is 90-100% of ymax tall
3851  float height;
3852  TEXTMETRIC textmetric;
3853  HFONT hOldFont;
3854  int ret;
3855 
3856  setfontsize(pointsize);
3857 
3858  hOldFont = (HFONT)SelectObject(hGraphicsDC, hGraphicsFont);
3859  if(!(hOldFont))
3860  SELECT_ERROR();
3861 
3862  if (!GetTextMetrics(hGraphicsDC, &textmetric))
3863  DRAW_ERROR();
3864  height = (textmetric.tmAscent + 2 * textmetric.tmDescent) / ymult;
3865 
3866  if (height >= ymax * 0.9) {
3867  if (height <= ymax)
3868  ret = 0;
3869  else
3870  ret = 1;
3871  }
3872  else
3873  ret = -1;
3874 
3875  if(!SelectObject(hGraphicsDC, hOldFont))
3876  SELECT_ERROR();
3877 
3878  return ret;
3879 }
3880 
3881 int findfontsize(float ymax) {
3882 // find the correct point size which will fit in the specified ymax as the max
3883 // height of the font, using a binary search
3884  int bot = 1;
3885  int top = MAX_FONT_SIZE;
3886  int mid, check;
3887 
3888  while (bot <= top) {
3889  mid = (bot+top)/2;
3890 
3891  check = check_fontsize(mid, ymax);
3892  if (!(check))
3893  return mid;
3894  else if (check > 0) // too big
3895  top = mid - 1;
3896  else // too small
3897  bot = mid + 1;
3898  }
3899  if (bot > MAX_FONT_SIZE)
3900  return MAX_FONT_SIZE;
3901 
3902  return -1; // can't fit
3903 }
3904 
3905 #endif /******** Win32 Specific Definitions ********************/
3906 
3907 
3908 #else /***** NO_GRAPHICS *******/
3909 /* No graphics at all. Stub everything out so calling program doesn't have to change
3910  * but of course graphics won't do anything.
3911  */
3912 
3913 #include "graphics.h"
3914 
3915 void event_loop (void (*act_on_mousebutton) (float x, float y),
3916  void (*act_on_mousemove) (float x, float y),
3917  void (*act_on_keypress) (char key_pressed),
3918  void (*drawscreen) (void)) { }
3919 
3920 void init_graphics (const char *window_name, int cindex) { }
3921 void close_graphics (void) { }
3922 void update_message (const char *msg) { }
3923 void draw_message (void) { }
3924 void init_world (float xl, float yt, float xr, float yb) { }
3925 void flushinput (void) { }
3926 void setcolor (int cindex) { }
3927 int getcolor (void) { return 0; }
3928 void setlinestyle (int linestyle) { }
3929 void setlinewidth (int linewidth) { }
3930 void setfontsize (int pointsize) { }
3931 void drawline (float x1, float y1, float x2, float y2) { }
3932 void drawrect (float x1, float y1, float x2, float y2) { }
3933 void fillrect (float x1, float y1, float x2, float y2) { }
3934 void fillpoly (t_point *points, int npoints) { }
3935 void drawarc (float xcen, float ycen, float rad, float startang,
3936  float angextent) { }
3937 void drawellipticarc (float xc, float yc, float radx, float rady, float startang, float angextent) { }
3938 
3939 void fillarc (float xcen, float ycen, float rad, float startang,
3940  float angextent) { }
3941 void fillellipticarc (float xc, float yc, float radx, float rady, float startang, float angextent) { }
3942 
3943 void drawtext (float xc, float yc, const char *text, float boundx) { }
3944 void clearscreen (void) { }
3945 
3946 void create_button (const char *prev_button_text , const char *button_text,
3947  void (*button_func) (void (*drawscreen) (void))) { }
3948 
3949 void destroy_button (const char *button_text) { }
3950 
3951 int init_postscript (const char *fname) {
3952  return (1);
3953 }
3954 
3955 void close_postscript (void) { }
3956 
3957 void report_structure(t_report*) { }
3958 
3959 void set_mouse_move_input (bool) { }
3960 
3961 void set_keypress_input (bool) { }
3962 
3963 void set_draw_mode (enum e_draw_mode draw_mode) { }
3964 
3965 void enable_or_disable_button(int ibutton, bool enabled) { }
3966 
3967 void change_button_text(const char *button_text, const char *new_button_text) { }
3968 
3969 #ifdef WIN32
3970 void drawtobuffer(void) { }
3971 
3972 void drawtoscreen(void) { }
3973 
3974 void displaybuffer(void) { }
3975 
3976 void drawcurve(t_point *points, int npoints) { }
3977 
3978 void fillcurve(t_point *points, int npoints) { }
3979 
3980 void object_start(int all) { }
3981 
3982 void object_end() { }
3983 
3984 int pt_on_object(float x, float y) { }
3985 
3986 int findfontsize(float ymax) { }
3987 
3988 
3989 #endif // WIN32 (subset of commands)
3990 
3991 #endif // NO_GRAPHICS
#define MAXPTS
static t_gl_state gl_state
Definition: graphics.c:309
static Bool test_if_exposed(Display *disp, XEvent *event_ptr, XPointer dummy)
Definition: graphics.c:2962
static XFontStruct * font_info[MAX_FONT_SIZE+1]
Definition: graphics.c:388
static void reset_common_state()
Definition: graphics.c:1256
void init_world(float x1, float y1, float x2, float y2)
Definition: graphics.c:2038
t_button_type type
Definition: graphics.c:280
#define YTOWORLD(y)
Definition: graphics.c:168
#define BUTTON_TEXT_LEN
Definition: graphics.c:183
#define MWIDTH
Definition: graphics.c:177
float ps_ymult
Definition: graphics.h:38
static void update_win(int x[2], int y[2], void(*drawscreen)(void))
Definition: graphics.c:2233
void close_graphics(void)
Definition: graphics.c:2417
static Display * display
Definition: graphics.c:385
void fillpoly(t_point *points, int npoints)
Definition: graphics.c:1881
static void zoom_out(void(*drawscreen)(void))
Definition: graphics.c:2144
static void translate_up(void(*drawscreen)(void))
Definition: graphics.c:2177
static GC current_gc
Definition: graphics.c:387
static int num_buttons
Definition: graphics.c:314
static const char * ps_cnames[NUM_COLOR]
Definition: graphics.c:342
void clearscreen(void)
Definition: graphics.c:1483
static float ymult
Definition: graphics.c:324
static const int menu_font_size
Definition: graphics.c:311
static char statusMessage[BUFSIZE]
Definition: graphics.c:338
static void proceed(void(*drawscreen)(void))
Definition: graphics.c:2400
static float ps_ymult
Definition: graphics.c:323
void drawrect(float x1, float y1, float x2, float y2)
Definition: graphics.c:1581
float ymult
Definition: graphics.h:37
bool initialized
Definition: graphics.c:296
static Window textarea
Definition: graphics.c:389
static float xdiv
Definition: graphics.c:325
static void update_transform(void)
Definition: graphics.c:1273
t_button_type
Definition: graphics.c:248
static int display_height
Definition: graphics.c:316
static void force_setcolor(int cindex)
Definition: graphics.c:581
static void postscript(void(*drawscreen)(void))
Definition: graphics.c:2371
#define XPOST(worldx)
Definition: graphics.c:161
static bool get_mouse_move_input
Definition: graphics.c:341
void(* fcn)(void(*drawscreen)(void))
Definition: graphics.c:274
void report_structure(t_report *report)
Definition: graphics.c:2843
static int ycoord(float worldy)
Definition: graphics.c:552
void destroy_button(const char *button_text)
Definition: graphics.c:954
static float xleft
Definition: graphics.c:318
#define FALSE
Definition: graphics.c:146
static bool get_keypress_input
Definition: graphics.c:341
static float saved_ytop
Definition: graphics.c:319
static int currentlinewidth
Definition: graphics.c:329
#define BUFSIZE
Definition: graphics.c:184
int background_cindex
Definition: graphics.c:298
static void load_font(int pointsize)
Definition: graphics.c:2768
static void unmap_button(int bnum)
Definition: graphics.c:860
static t_button * button
Definition: graphics.c:313
static int currentfontsize
Definition: graphics.c:330
void drawline(float x1, float y1, float x2, float y2)
Definition: graphics.c:1539
static void force_setfontsize(int pointsize)
Definition: graphics.c:755
static void drawscreen(void)
Definition: draw.c:212
static GC gcxor
Definition: graphics.c:387
void draw_message(void)
Definition: graphics.c:2063
#define min(a, b)
Definition: graphics.c:174
void enable_or_disable_button(int ibutton, bool enabled)
Definition: graphics.c:2867
void create_button(const char *prev_button_text, const char *button_text, void(*button_func)(void(*drawscreen)(void)))
Definition: graphics.c:881
void set_keypress_input(bool enable)
Definition: graphics.c:2862
void drawtext(float xc, float yc, const char *text, float boundx)
Definition: graphics.c:1952
float xright
Definition: graphics.h:39
void init_graphics(const char *window_name, int cindex)
Definition: graphics.c:1003
static Window toplevel
Definition: graphics.c:389
static float saved_xleft
Definition: graphics.c:319
static int which_button(Window win)
Definition: graphics.c:3100
void fillellipticarc(float xc, float yc, float radx, float rady, float startang, float angextent)
Definition: graphics.c:1798
static Colormap private_cmap
Definition: graphics.c:390
static float saved_ybot
Definition: graphics.c:319
void fillrect(float x1, float y1, float x2, float y2)
Definition: graphics.c:1643
#define YPOST(worldy)
Definition: graphics.c:162
static void drawbut(int bnum)
Definition: graphics.c:2992
static void * my_malloc(int ibytes)
Definition: graphics.c:499
float xmult
Definition: graphics.h:37
static void drawmenu(void)
Definition: graphics.c:3126
static float ydiv
Definition: graphics.c:325
static int ProceedPressed
Definition: graphics.c:336
int poly[3][2]
Definition: graphics.c:282
static Window menu
Definition: graphics.c:389
#define max(a, b)
Definition: graphics.c:171
#define XTOWORLD(x)
Definition: graphics.c:167
static void adjustwin(void(*drawscreen)(void))
Definition: graphics.c:2262
void setfontsize(int pointsize)
Definition: graphics.c:796
static int top_height
Definition: graphics.c:317
int init_postscript(const char *fname)
Definition: graphics.c:2477
static void force_setlinewidth(int linewidth)
Definition: graphics.c:707
static void quit(void(*drawscreen)(void))
Definition: graphics.c:2407
int xleft
Definition: graphics.c:272
void drawarc(float xc, float yc, float rad, float startang, float angextent)
Definition: graphics.c:1787
static int screen_num
Definition: graphics.c:386
#define OFF
#define TRUE
Definition: graphics.c:145
static float xright
Definition: graphics.c:318
int top_width
Definition: graphics.h:40
void setlinewidth(int linewidth)
Definition: graphics.c:743
static int rect_off_screen(float x1, float y1, float x2, float y2)
Definition: graphics.c:1514
int getcolor()
Definition: graphics.c:647
static void translate_right(void(*drawscreen)(void))
Definition: graphics.c:2220
bool enabled
Definition: graphics.c:284
static float ybot
Definition: graphics.c:318
static void build_textarea(void)
Definition: graphics.c:2942
void fillarc(float xc, float yc, float rad, float startang, float angextent)
Definition: graphics.c:1876
static void menutext(Window win, int xc, int yc, const char *text)
Definition: graphics.c:2977
static FILE * ps
Definition: graphics.c:334
void event_loop(void(*act_on_mousebutton)(float x, float y), void(*act_on_mousemove)(float x, float y), void(*act_on_keypress)(char key_pressed), void(*drawscreen)(void))
Definition: graphics.c:1352
#define NUM_FONT_TYPES
int height
Definition: graphics.c:271
static void map_button(int bnum)
Definition: graphics.c:824
bool ispressed
Definition: graphics.c:283
static float xmult
Definition: graphics.c:324
static void turn_on_off(int pressed)
Definition: graphics.c:3113
static float ps_xmult
Definition: graphics.c:323
static float angnorm(float ang)
Definition: graphics.c:1704
static int currentlinestyle
Definition: graphics.c:328
static void zoom_fit(void(*drawscreen)(void))
Definition: graphics.c:2163
void setlinestyle(int linestyle)
Definition: graphics.c:697
static void * my_realloc(void *memblk, int ibytes)
Definition: graphics.c:512
static float ps_right
Definition: graphics.c:321
void change_button_text(const char *button_name, const char *new_button_text)
Definition: graphics.c:2906
static int top_width
Definition: graphics.c:317
float ybot
Definition: graphics.h:39
int ytop
Definition: graphics.c:273
Window win
Definition: graphics.c:276
static void translate_down(void(*drawscreen)(void))
Definition: graphics.c:2191
static int currentcolor
Definition: graphics.c:327
static float saved_xright
Definition: graphics.c:319
int disp_type
Definition: graphics.c:297
int top_height
Definition: graphics.h:40
#define MAX_FONT_SIZE
Definition: graphics.c:179
static void force_setlinestyle(int linestyle)
Definition: graphics.c:654
#define ON
#define PI
Definition: graphics.c:181
static void setpoly(int bnum, int xc, int yc, int r, float theta)
Definition: graphics.c:809
t_display_type
Definition: graphics.c:240
static GC gc_menus
Definition: graphics.c:387
static int colors[NUM_COLOR]
Definition: graphics.c:393
void flushinput(void)
Definition: graphics.c:2027
static float ps_top
Definition: graphics.c:321
static void translate_left(void(*drawscreen)(void))
Definition: graphics.c:2205
static float ps_left
Definition: graphics.c:321
#define MINPIXEL
Definition: graphics.c:203
void set_draw_mode(enum e_draw_mode draw_mode)
Definition: graphics.c:2881
void update_message(const char *msg)
Definition: graphics.c:2113
float xleft
Definition: graphics.h:39
static void zoom_in(void(*drawscreen)(void))
Definition: graphics.c:2126
static int display_width
Definition: graphics.c:316
int width
Definition: graphics.c:270
void drawellipticarc(float xc, float yc, float radx, float rady, float startang, float angextent)
Definition: graphics.c:1719
#define T_AREA_HEIGHT
Definition: graphics.c:178
static float ytop
Definition: graphics.c:318
static void build_default_menu(void)
Definition: graphics.c:2628
static GC gc
Definition: graphics.c:387
void set_mouse_move_input(bool enable)
Definition: graphics.c:2857
float ps_xmult
Definition: graphics.h:38
float ytop
Definition: graphics.h:39
#define MAXPIXEL
Definition: graphics.c:202
static int xcoord(float worldx)
Definition: graphics.c:527
e_draw_mode
Definition: graphics.h:209
static bool font_is_loaded[MAX_FONT_SIZE+1]
Definition: graphics.c:340
static float ps_bot
Definition: graphics.c:321
static void update_ps_transform(void)
Definition: graphics.c:1308
void setcolor(int cindex)
Definition: graphics.c:619
void close_postscript(void)
Definition: graphics.c:2602
static e_draw_mode current_draw_mode
Definition: graphics.c:331