VPR-6.0
|
00001 #include <math.h> 00002 #include <stdlib.h> 00003 #include <stdio.h> 00004 #include <string.h> 00005 00006 #include "util.h" 00007 #include "graphics.h" 00008 #include "vpr_types.h" 00009 /*#include "draw.h" */ 00010 00011 #ifndef NO_GRAPHICS 00012 00013 #include <X11/Xlib.h> 00014 #include <X11/Xutil.h> 00015 #include <X11/Xos.h> 00016 #include <X11/Xatom.h> 00017 00018 #endif 00019 00020 00021 /** 00022 * @file 00023 * 00024 * Written by Vaughn Betz at the University of Toronto, Department of 00025 * Electrical and Computer Engineering. Graphics package Version 1.3. 00026 * All rights reserved by U of T, etc. 00027 * 00028 * You may freely use this graphics interface for non-commercial purposes 00029 * as long as you leave the written by Vaughn Betz message in it -- who 00030 * knows, maybe someday an employer will see it and give me a job or large 00031 * sums of money :). 00032 * 00033 * Revision History: 00034 * 00035 * Sept. 19, 1997: Incorporated Zoom Fit code of Haneef Mohammed at 00036 * Cypress. Makes it easy to zoom to a full view of the graphics. 00037 * 00038 * Sept. 11, 1997: Added the create_button and delete_button interface to 00039 * make it easy to add and destroy buttons from user code. Removed the 00040 * bnum parameter to the button functions, since it wasn't really needed. 00041 * 00042 * June 28, 1997: Added filled arc drawing primitive. Minor modifications 00043 * to PostScript driver to make the PostScript output slightly smaller. 00044 * 00045 * April 15, 1997: Added code to init_graphics so it waits for a window 00046 * to be exposed before returning. This ensures that users of non- 00047 * interactive graphics can never draw to a window before it is available. 00048 * 00049 * Feb. 24, 1997: Added code so the package will allocate a private 00050 * colormap if the default colormap doesn't have enough free colours. 00051 * 00052 * June 28, 1996: Converted all internal functions in graphics.c to have 00053 * internal (static) linkage to avoid any conflicts with user routines in 00054 * the rest of the program. 00055 * 00056 * June 12, 1996: Added setfontsize and setlinewidth attributes. Added 00057 * pre-clipping of objects for speed (and compactness of PS output) when 00058 * graphics are zoomed in. Rewrote PostScript engine to shrink the output 00059 * and make it easier to read. Made drawscreen a callback function passed 00060 * in rather than a global. Graphics attribute calls are more efficient -- 00061 * they check if they have to change anything before doing it. 00062 * 00063 * October 27, 1995: Added the message area, a callback function for 00064 * interacting with user button clicks, and implemented a workaround for a 00065 * Sun X Server bug that misdisplays extremely highly zoomed graphics. 00066 * 00067 * Jan. 13, 1995: Modified to incorporate PostScript Support. 00068 */ 00069 00070 00071 /****************** Types and defines local to this module ******************/ 00072 00073 #ifndef NO_GRAPHICS 00074 00075 /* Uncomment the line below if your X11 header files don't define XPointer */ 00076 /* typedef char *XPointer; */ 00077 00078 /**@{*/ 00079 /** Macros for translation from world to PostScript coordinates */ 00080 #define XPOST(worldx) (((worldx)-xleft)*ps_xmult + ps_left) 00081 #define YPOST(worldy) (((worldy)-ybot)*ps_ymult + ps_bot) 00082 /**@}*/ 00083 00084 /**@{*/ 00085 /** Macros to convert from X Windows Internal Coordinates to my 00086 * World Coordinates. (This macro is used only rarely, so 00087 * the divides don't hurt speed). 00088 */ 00089 #define XTOWORLD(x) (((float) x)/xmult + xleft) 00090 #define YTOWORLD(y) (((float) y)/ymult + ytop) 00091 /**@}*/ 00092 00093 #define max(a,b) (((a) > (b))? (a) : (b)) 00094 #define min(a,b) ((a) > (b)? (b) : (a)) 00095 00096 #define MWIDTH 104 /**< width of menu window */ 00097 #define T_AREA_HEIGHT 24 /**< Height of text window */ 00098 #define MAX_FONT_SIZE 40 /**< Largest point size of text */ 00099 #define PI 3.141592654 00100 00101 #define BUTTON_TEXT_LEN 20 00102 00103 typedef struct 00104 { 00105 int width; 00106 int height; 00107 int xleft; 00108 int ytop; 00109 void (*fcn) (void (*drawscreen) (void)); 00110 Window win; 00111 int istext; 00112 char text[BUTTON_TEXT_LEN]; 00113 int ispoly; 00114 int poly[3][2]; 00115 int ispressed; 00116 } 00117 t_button; 00118 00119 00120 00121 00122 /********************* Static variables local to this module ****************/ 00123 00124 static const int menu_font_size = 14; /**< Font for menus and dialog boxes. */ 00125 00126 static t_button *button; /**< [0..num_buttons-1] */ 00127 static int num_buttons; /**< Number of menu buttons */ 00128 00129 static int disp_type; /**< Selects SCREEN or POSTSCRIPT */ 00130 static Display *display; 00131 static int screen_num; 00132 static GC gc, gcxor, gc_menus; 00133 static XFontStruct *font_info[MAX_FONT_SIZE + 1]; /**< Data for each size */ 00134 static int font_is_loaded[MAX_FONT_SIZE + 1]; /**< 1: loaded, 0: not */ 00135 static unsigned int display_width, display_height; /**< screen size */ 00136 static unsigned int top_width, top_height; /**< window size */ 00137 static Window toplevel, menu, textarea; /**< various windows */ 00138 static float xleft, xright, ytop, ybot; /**< world coordinates */ 00139 00140 /** Initial world coordinates */ 00141 static float saved_xleft, saved_xright, saved_ytop, saved_ybot; 00142 00143 static float ps_left, ps_right, ps_top, ps_bot; /**< Figure boundaries for 00144 PostScript output, in PostScript coordinates. */ 00145 static float ps_xmult, ps_ymult; /**< Transformation for PostScript. */ 00146 static float xmult, ymult; /**< Transformation factors */ 00147 static Colormap private_cmap; /**< "None" unless a private cmap was allocated. */ 00148 00149 /**@{*/ 00150 /** Graphics state. Set start-up defaults here. */ 00151 static int currentcolor = BLACK; 00152 static int currentlinestyle = SOLID; 00153 static int currentlinewidth = 0; 00154 static int currentfontsize = 10; 00155 /**@}*/ 00156 00157 static char message[BUFSIZE] = "\0"; /**< User message to display */ 00158 00159 /** Color indices passed back from X Windows. */ 00160 static int colors[NUM_COLOR]; 00161 00162 /** For PostScript output */ 00163 static FILE *ps; 00164 00165 /** MAXPIXEL and MINPIXEL are set to prevent what appears to be 00166 * overflow with very large pixel values on the Sun X Server. */ 00167 #define MAXPIXEL 15000 00168 #define MINPIXEL -15000 00169 00170 00171 /********************** Subroutines local to this module ********************/ 00172 00173 /* Function declarations for button responses */ 00174 00175 static void translate_up(void (*drawscreen) (void)); 00176 static void translate_left(void (*drawscreen) (void)); 00177 static void translate_right(void (*drawscreen) (void)); 00178 static void translate_down(void (*drawscreen) (void)); 00179 static void zoom_in(void (*drawscreen) (void)); 00180 static void zoom_out(void (*drawscreen) (void)); 00181 static void zoom_fit(void (*drawscreen) (void)); 00182 static void adjustwin(void (*drawscreen) (void)); 00183 static void postscript(void (*drawscreen) (void)); 00184 static void proceed(void (*drawscreen) (void)); 00185 static void quit(void (*drawscreen) (void)); 00186 00187 static Bool test_if_exposed(Display * disp, 00188 XEvent * event_ptr, 00189 XPointer dummy); 00190 static void map_button(int bnum); 00191 static void unmap_button(int bnum); 00192 00193 00194 00195 /********************** Subroutine definitions ******************************/ 00196 00197 00198 /** Translates from my internal coordinates to X Windows coordinates * 00199 * in the x direction. Add 0.5 at end for extra half-pixel accuracy. */ 00200 static int 00201 xcoord(float worldx) 00202 { 00203 int winx; 00204 00205 winx = (int)((worldx - xleft) * xmult + 0.5); 00206 00207 /* Avoid overflow in the X Window routines. This will allow horizontal * 00208 * and vertical lines to be drawn correctly regardless of zooming, but * 00209 * will cause diagonal lines that go way off screen to change their * 00210 * slope as you zoom in. The only way I can think of to completely fix * 00211 * this problem is to do all the clipping in advance in floating point, * 00212 * then convert to integers and call X Windows. This is a lot of extra * 00213 * coding, and means that coordinates will be clipped twice, even though * 00214 * this "Super Zoom" problem won't occur unless users zoom way in on * 00215 * the graphics. */ 00216 00217 winx = max(winx, MINPIXEL); 00218 winx = min(winx, MAXPIXEL); 00219 00220 return (winx); 00221 } 00222 00223 00224 /** Translates from my internal coordinates to X Windows coordinates 00225 * in the y direction. Add 0.5 at end for extra half-pixel accuracy. 00226 */ 00227 static int 00228 ycoord(float worldy) 00229 { 00230 int winy; 00231 00232 winy = (int)((worldy - ytop) * ymult + 0.5); 00233 00234 /* Avoid overflow in the X Window routines. */ 00235 winy = max(winy, MINPIXEL); 00236 winy = min(winy, MAXPIXEL); 00237 00238 return (winy); 00239 } 00240 00241 00242 /** Makes sure the font of the specified size is loaded. Point_size 00243 * MUST be between 1 and MAX_FONT_SIZE -- no check is performed here. 00244 * Use proper point-size medium-weight upright helvetica font */ 00245 static void 00246 load_font(int pointsize) 00247 { 00248 char fontname[44]; 00249 00250 sprintf(fontname, "-*-helvetica-medium-r-*--*-%d0-*-*-*-*-*-*", 00251 pointsize); 00252 00253 #ifdef VERBOSE 00254 printf("Loading font: point size: %d, fontname: %s\n", pointsize, 00255 fontname); 00256 #endif 00257 00258 /* Load font and get font information structure. */ 00259 00260 if((font_info[pointsize] = XLoadQueryFont(display, fontname)) == NULL) 00261 { 00262 fprintf(stderr, "Cannot open desired font\n"); 00263 exit(-1); 00264 } 00265 } 00266 00267 00268 static void 00269 force_setcolor(int cindex) 00270 { 00271 00272 static char *ps_cnames[NUM_COLOR] = 00273 { "white", "black", "grey55", "grey75", 00274 "blue", "green", "yellow", "cyan", "red", "darkgreen", "magenta", 00275 "bisque", "lightblue", "thistle", "plum", "khaki", 00276 "coral", "turquoise", "mediumpurple", "darkslateblue", "darkkhaki" 00277 }; 00278 00279 currentcolor = cindex; 00280 00281 if(disp_type == SCREEN) 00282 { 00283 XSetForeground(display, gc, colors[cindex]); 00284 } 00285 else 00286 { 00287 fprintf(ps, "%s\n", ps_cnames[cindex]); 00288 } 00289 } 00290 00291 00292 void 00293 setcolor(int cindex) 00294 { 00295 00296 if(currentcolor != cindex) 00297 force_setcolor(cindex); 00298 } 00299 00300 int getcolor() 00301 { 00302 return currentcolor; 00303 } 00304 00305 static void 00306 force_setlinestyle(int linestyle) 00307 { 00308 00309 /* Note SOLID is 0 and DASHED is 1 for linestyle. */ 00310 00311 /* PostScript and X commands needed, respectively. */ 00312 00313 static char *ps_text[2] = { "linesolid", "linedashed" }; 00314 static int x_vals[2] = { LineSolid, LineOnOffDash }; 00315 00316 currentlinestyle = linestyle; 00317 00318 if(disp_type == SCREEN) 00319 { 00320 XSetLineAttributes(display, gc, currentlinewidth, 00321 x_vals[linestyle], CapButt, JoinMiter); 00322 } 00323 else 00324 { 00325 fprintf(ps, "%s\n", ps_text[linestyle]); 00326 } 00327 } 00328 00329 00330 void 00331 setlinestyle(int linestyle) 00332 { 00333 00334 if(linestyle != currentlinestyle) 00335 force_setlinestyle(linestyle); 00336 } 00337 00338 00339 static void 00340 force_setlinewidth(int linewidth) 00341 { 00342 00343 /* linewidth should be greater than or equal to 0 to make any sense. */ 00344 /* Note SOLID is 0 and DASHED is 1 for linestyle. */ 00345 00346 static int x_vals[2] = { LineSolid, LineOnOffDash }; 00347 00348 currentlinewidth = linewidth; 00349 00350 if(disp_type == SCREEN) 00351 { 00352 XSetLineAttributes(display, gc, linewidth, 00353 x_vals[currentlinestyle], CapButt, JoinMiter); 00354 } 00355 else 00356 { 00357 fprintf(ps, "%d setlinewidth\n", linewidth); 00358 } 00359 } 00360 00361 00362 void 00363 setlinewidth(int linewidth) 00364 { 00365 00366 if(linewidth != currentlinewidth) 00367 force_setlinewidth(linewidth); 00368 } 00369 00370 00371 static void 00372 force_setfontsize(int pointsize) 00373 { 00374 00375 /* Valid point sizes are between 1 and MAX_FONT_SIZE */ 00376 00377 if(pointsize < 1) 00378 pointsize = 1; 00379 else if(pointsize > MAX_FONT_SIZE) 00380 pointsize = MAX_FONT_SIZE; 00381 00382 currentfontsize = pointsize; 00383 00384 00385 if(disp_type == SCREEN) 00386 { 00387 if(!font_is_loaded[pointsize]) 00388 { 00389 load_font(pointsize); 00390 font_is_loaded[pointsize] = 1; 00391 } 00392 XSetFont(display, gc, font_info[pointsize]->fid); 00393 } 00394 00395 else 00396 { 00397 /* PostScript: set up font and centering function */ 00398 00399 fprintf(ps, "%d setfontsize\n", pointsize); 00400 } 00401 } 00402 00403 00404 /** For efficiency, this routine doesn't do anything if no change is 00405 * implied. If you want to force the graphics context or PS file 00406 * to have font info set, call force_setfontsize (this is necessary 00407 * in initialization and X11 / Postscript switches). 00408 */ 00409 void 00410 setfontsize(int pointsize) 00411 { 00412 if(pointsize != currentfontsize) 00413 force_setfontsize(pointsize); 00414 } 00415 00416 00417 /** Creates a small window at the top of the graphics area for text messages */ 00418 static void 00419 build_textarea(void) 00420 { 00421 XSetWindowAttributes menu_attributes; 00422 unsigned long valuemask; 00423 00424 textarea = XCreateSimpleWindow(display, toplevel, 00425 0, top_height - T_AREA_HEIGHT, 00426 display_width, T_AREA_HEIGHT - 4, 2, 00427 colors[BLACK], colors[LIGHTGREY]); 00428 menu_attributes.event_mask = ExposureMask; 00429 /* ButtonPresses in this area are ignored. */ 00430 menu_attributes.do_not_propagate_mask = ButtonPressMask; 00431 /* Keep text area on bottom left */ 00432 menu_attributes.win_gravity = SouthWestGravity; 00433 valuemask = CWWinGravity | CWEventMask | CWDontPropagate; 00434 XChangeWindowAttributes(display, textarea, valuemask, &menu_attributes); 00435 XMapWindow(display, textarea); 00436 } 00437 00438 00439 /** Puts a triangle in the poly array for button[bnum] */ 00440 static void 00441 setpoly(int bnum, 00442 int xc, 00443 int yc, 00444 int r, 00445 float theta) 00446 { 00447 int i; 00448 00449 button[bnum].istext = 0; 00450 button[bnum].ispoly = 1; 00451 for(i = 0; i < 3; i++) 00452 { 00453 button[bnum].poly[i][0] = (int)(xc + r * cos(theta) + 0.5); 00454 button[bnum].poly[i][1] = (int)(yc + r * sin(theta) + 0.5); 00455 theta += 2 * PI / 3; 00456 } 00457 } 00458 00459 00460 /** Sets up the default menu buttons on the right hand side of the window. */ 00461 static void 00462 build_default_menu(void) 00463 { 00464 XSetWindowAttributes menu_attributes; 00465 unsigned long valuemask; 00466 int i, xcen, x1, y1, bwid, bheight, space; 00467 00468 00469 menu = XCreateSimpleWindow(display, toplevel, 00470 top_width - MWIDTH, 0, MWIDTH - 4, 00471 display_height, 2, colors[BLACK], 00472 colors[LIGHTGREY]); 00473 menu_attributes.event_mask = ExposureMask; 00474 /* Ignore button presses on the menu background. */ 00475 menu_attributes.do_not_propagate_mask = ButtonPressMask; 00476 /* Keep menu on top right */ 00477 menu_attributes.win_gravity = NorthEastGravity; 00478 valuemask = CWWinGravity | CWEventMask | CWDontPropagate; 00479 XChangeWindowAttributes(display, menu, valuemask, &menu_attributes); 00480 XMapWindow(display, menu); 00481 00482 num_buttons = 11; 00483 button = (t_button *) my_malloc(num_buttons * sizeof(t_button)); 00484 00485 /* Now do the arrow buttons */ 00486 bwid = 28; 00487 space = 3; 00488 y1 = 10; 00489 xcen = 51; 00490 x1 = xcen - bwid / 2; 00491 button[0].xleft = x1; 00492 button[0].ytop = y1; 00493 setpoly(0, bwid / 2, bwid / 2, bwid / 3, -PI / 2.); /* Up */ 00494 button[0].fcn = translate_up; 00495 00496 y1 += bwid + space; 00497 x1 = xcen - 3 * bwid / 2 - space; 00498 button[1].xleft = x1; 00499 button[1].ytop = y1; 00500 setpoly(1, bwid / 2, bwid / 2, bwid / 3, PI); /* Left */ 00501 button[1].fcn = translate_left; 00502 00503 x1 = xcen + bwid / 2 + space; 00504 button[2].xleft = x1; 00505 button[2].ytop = y1; 00506 setpoly(2, bwid / 2, bwid / 2, bwid / 3, 0); /* Right */ 00507 button[2].fcn = translate_right; 00508 00509 y1 += bwid + space; 00510 x1 = xcen - bwid / 2; 00511 button[3].xleft = x1; 00512 button[3].ytop = y1; 00513 setpoly(3, bwid / 2, bwid / 2, bwid / 3, +PI / 2.); /* Down */ 00514 button[3].fcn = translate_down; 00515 00516 for(i = 0; i < 4; i++) 00517 { 00518 button[i].width = bwid; 00519 button[i].height = bwid; 00520 } 00521 00522 /* Rectangular buttons */ 00523 00524 y1 += bwid + space + 6; 00525 space = 8; 00526 bwid = 90; 00527 bheight = 26; 00528 x1 = xcen - bwid / 2; 00529 for(i = 4; i < num_buttons; i++) 00530 { 00531 button[i].xleft = x1; 00532 button[i].ytop = y1; 00533 y1 += bheight + space; 00534 button[i].istext = 1; 00535 button[i].ispoly = 0; 00536 button[i].width = bwid; 00537 button[i].height = bheight; 00538 } 00539 00540 strcpy(button[4].text, "Zoom In"); 00541 strcpy(button[5].text, "Zoom Out"); 00542 strcpy(button[6].text, "Zoom Fit"); 00543 strcpy(button[7].text, "Window"); 00544 strcpy(button[8].text, "PostScript"); 00545 strcpy(button[9].text, "Proceed"); 00546 strcpy(button[10].text, "Exit"); 00547 00548 button[4].fcn = zoom_in; 00549 button[5].fcn = zoom_out; 00550 button[6].fcn = zoom_fit; 00551 button[7].fcn = adjustwin; 00552 button[8].fcn = postscript; 00553 button[9].fcn = proceed; 00554 button[10].fcn = quit; 00555 00556 for(i = 0; i < num_buttons; i++) 00557 map_button(i); 00558 } 00559 00560 00561 /** Maps a button onto the screen and set it up for input, etc. */ 00562 static void 00563 map_button(int bnum) 00564 { 00565 button[bnum].win = XCreateSimpleWindow(display, menu, 00566 button[bnum].xleft, 00567 button[bnum].ytop, 00568 button[bnum].width, 00569 button[bnum].height, 0, 00570 colors[WHITE], colors[LIGHTGREY]); 00571 XMapWindow(display, button[bnum].win); 00572 XSelectInput(display, button[bnum].win, ButtonPressMask); 00573 button[bnum].ispressed = 1; 00574 } 00575 00576 00577 /** Unmaps a button from the screen. */ 00578 static void 00579 unmap_button(int bnum) 00580 { 00581 XUnmapWindow(display, button[bnum].win); 00582 } 00583 00584 00585 /** Creates a new button below the button containing prev_button_text. 00586 * The text and button function are set according to button_text and 00587 * button_func, respectively. 00588 */ 00589 void 00590 create_button(char *prev_button_text, 00591 char *button_text, 00592 void (*button_func) (void (*drawscreen) (void))) 00593 { 00594 int i, bnum, space; 00595 00596 space = 8; 00597 00598 /* Only allow new buttons that are text (not poly) types. */ 00599 00600 bnum = -1; 00601 for(i = 4; i < num_buttons; i++) 00602 { 00603 if(button[i].istext == 1 && 00604 strcmp(button[i].text, prev_button_text) == 0) 00605 { 00606 bnum = i + 1; 00607 break; 00608 } 00609 } 00610 00611 if(bnum == -1) 00612 { 00613 printf 00614 ("Error in create_button: button with text %s not found.\n", 00615 prev_button_text); 00616 exit(1); 00617 } 00618 00619 num_buttons++; 00620 button = (t_button *) my_realloc(button, num_buttons * sizeof(t_button)); 00621 00622 /* NB: Requirement that you specify the button that this button goes under * 00623 * guarantees that button[num_buttons-2] exists and is a text button. */ 00624 00625 button[num_buttons - 1].xleft = button[num_buttons - 2].xleft; 00626 button[num_buttons - 1].ytop = button[num_buttons - 2].ytop + 00627 button[num_buttons - 2].height + space; 00628 button[num_buttons - 1].height = button[num_buttons - 2].height; 00629 button[num_buttons - 1].width = button[num_buttons - 2].width; 00630 map_button(num_buttons - 1); 00631 00632 00633 for(i = num_buttons - 1; i > bnum; i--) 00634 { 00635 button[i].ispoly = button[i - 1].ispoly; 00636 /* No poly copy for now, as I'm only providing the ability to create text * 00637 * buttons. */ 00638 00639 button[i].istext = button[i - 1].istext; 00640 strcpy(button[i].text, button[i - 1].text); 00641 button[i].fcn = button[i - 1].fcn; 00642 button[i].ispressed = button[i - 1].ispressed; 00643 } 00644 00645 button[bnum].istext = 1; 00646 button[bnum].ispoly = 0; 00647 my_strncpy(button[bnum].text, button_text, BUTTON_TEXT_LEN); 00648 button[bnum].fcn = button_func; 00649 button[bnum].ispressed = 1; 00650 } 00651 00652 00653 /** Destroys the button with text button_text. */ 00654 void 00655 destroy_button(char *button_text) 00656 { 00657 int i, bnum; 00658 00659 bnum = -1; 00660 for(i = 4; i < num_buttons; i++) 00661 { 00662 if(button[i].istext == 1 && 00663 strcmp(button[i].text, button_text) == 0) 00664 { 00665 bnum = i; 00666 break; 00667 } 00668 } 00669 00670 if(bnum == -1) 00671 { 00672 printf 00673 ("Error in destroy_button: button with text %s not found.\n", 00674 button_text); 00675 exit(1); 00676 } 00677 00678 for(i = bnum + 1; i < num_buttons; i++) 00679 { 00680 button[i - 1].ispoly = button[i].ispoly; 00681 /* No poly copy for now, as I'm only providing the ability to create text * 00682 * buttons. */ 00683 00684 button[i - 1].istext = button[i].istext; 00685 strcpy(button[i - 1].text, button[i].text); 00686 button[i - 1].fcn = button[i].fcn; 00687 button[i - 1].ispressed = button[i].ispressed; 00688 } 00689 00690 unmap_button(num_buttons - 1); 00691 num_buttons--; 00692 button = (t_button *) my_realloc(button, num_buttons * sizeof(t_button)); 00693 } 00694 00695 00696 /** Open the toplevel window, get the colors, 2 graphics 00697 * contexts, load a font, and set up the toplevel window 00698 * Calls build_default_menu to set up the default menu. 00699 */ 00700 void 00701 init_graphics(char *window_name) 00702 { 00703 00704 char *display_name = NULL; 00705 int x, y; /* window position */ 00706 unsigned int border_width = 2; /* ignored by OpenWindows */ 00707 XTextProperty windowName; 00708 00709 /* X Windows' names for my colours. */ 00710 char *cnames[NUM_COLOR] = { "white", "black", "grey55", "grey75", "blue", 00711 "green", "yellow", "cyan", "red", "RGBi:0.0/0.5/0.0", "magenta", 00712 "bisque", "lightblue", "thistle", "plum", "khaki", 00713 "coral", "turquoise", "mediumpurple", "darkslateblue", "darkkhaki" 00714 }; 00715 00716 XColor exact_def; 00717 Colormap cmap; 00718 int i; 00719 unsigned long valuemask = 0; /* ignore XGCvalues and use defaults */ 00720 XGCValues values; 00721 XEvent event; 00722 00723 00724 disp_type = SCREEN; /* Graphics go to screen, not ps */ 00725 00726 for(i = 0; i <= MAX_FONT_SIZE; i++) 00727 font_is_loaded[i] = 0; /* No fonts loaded yet. */ 00728 00729 /* connect to X server */ 00730 if((display = XOpenDisplay(display_name)) == NULL) 00731 { 00732 fprintf(stderr, "Cannot connect to X server %s\n", 00733 XDisplayName(display_name)); 00734 exit(-1); 00735 } 00736 00737 /* get screen size from display structure macro */ 00738 screen_num = DefaultScreen(display); 00739 display_width = DisplayWidth(display, screen_num); 00740 display_height = DisplayHeight(display, screen_num); 00741 00742 x = y = 0; 00743 00744 top_width = 2 * display_width / 3; 00745 top_height = 4 * display_height / 5; 00746 00747 cmap = DefaultColormap(display, screen_num); 00748 private_cmap = None; 00749 00750 for(i = 0; i < NUM_COLOR; i++) 00751 { 00752 if(!XParseColor(display, cmap, cnames[i], &exact_def)) 00753 { 00754 fprintf(stderr, "Color name %s not in database", 00755 cnames[i]); 00756 exit(-1); 00757 } 00758 if(!XAllocColor(display, cmap, &exact_def)) 00759 { 00760 fprintf(stderr, "Couldn't allocate color %s.\n", 00761 cnames[i]); 00762 00763 if(private_cmap == None) 00764 { 00765 fprintf(stderr, 00766 "Will try to allocate a private colourmap.\n"); 00767 fprintf(stderr, 00768 "Colours will only display correctly when your " 00769 "cursor is in the graphics window.\n" 00770 "Exit other colour applications and rerun this " 00771 "program if you don't like that.\n\n"); 00772 00773 private_cmap = 00774 XCopyColormapAndFree(display, cmap); 00775 cmap = private_cmap; 00776 if(!XAllocColor(display, cmap, &exact_def)) 00777 { 00778 fprintf(stderr, 00779 "Couldn't allocate color %s as private.\n", 00780 cnames[i]); 00781 exit(1); 00782 } 00783 } 00784 00785 else 00786 { 00787 fprintf(stderr, 00788 "Couldn't allocate color %s as private.\n", 00789 cnames[i]); 00790 exit(1); 00791 } 00792 } 00793 colors[i] = exact_def.pixel; 00794 } 00795 00796 toplevel = 00797 XCreateSimpleWindow(display, RootWindow(display, screen_num), x, y, 00798 top_width, top_height, border_width, 00799 colors[BLACK], colors[WHITE]); 00800 00801 if(private_cmap != None) 00802 XSetWindowColormap(display, toplevel, private_cmap); 00803 00804 /* hints stuff deleted. */ 00805 00806 XSelectInput(display, toplevel, ExposureMask | StructureNotifyMask | 00807 ButtonPressMask); 00808 00809 00810 /* Create default Graphics Contexts. valuemask = 0 -> use defaults. */ 00811 gc = XCreateGC(display, toplevel, valuemask, &values); 00812 gc_menus = XCreateGC(display, toplevel, valuemask, &values); 00813 00814 /* Create XOR graphics context for Rubber Banding */ 00815 values.function = GXxor; 00816 values.foreground = colors[BLACK]; 00817 gcxor = XCreateGC(display, toplevel, (GCFunction | GCForeground), 00818 &values); 00819 00820 /* specify font for menus. */ 00821 load_font(menu_font_size); 00822 font_is_loaded[menu_font_size] = 1; 00823 XSetFont(display, gc_menus, font_info[menu_font_size]->fid); 00824 00825 /* Set drawing defaults for user-drawable area. Use whatever the * 00826 * initial values of the current stuff was set to. */ 00827 force_setfontsize(currentfontsize); 00828 force_setcolor(currentcolor); 00829 force_setlinestyle(currentlinestyle); 00830 force_setlinewidth(currentlinewidth); 00831 00832 XStringListToTextProperty(&window_name, 1, &windowName); 00833 XSetWMName(display, toplevel, &windowName); 00834 /* Uncomment to set icon name */ 00835 /* XSetWMIconName (display, toplevel, &windowName); */ 00836 00837 /* XStringListToTextProperty copies the window_name string into * 00838 * windowName.value. Free this memory now. */ 00839 00840 free(windowName.value); 00841 00842 XMapWindow(display, toplevel); 00843 build_textarea(); 00844 build_default_menu(); 00845 00846 /* The following is completely unnecessary if the user is using the * 00847 * interactive (event_loop) graphics. It waits for the first Expose * 00848 * event before returning so that I can tell the window manager has got * 00849 * the top-level window up and running. Thus the user can start drawing * 00850 * into this window immediately, and there's no danger of the window not * 00851 * being ready and output being lost. */ 00852 00853 XPeekIfEvent(display, &event, test_if_exposed, NULL); 00854 } 00855 00856 00857 /** Returns True if the event passed in is an exposure event. Note that 00858 * the bool type returned by this function is defined in Xlib.h. 00859 */ 00860 static Bool 00861 test_if_exposed(Display * disp, 00862 XEvent * event_ptr, 00863 XPointer dummy) 00864 { 00865 00866 if(event_ptr->type == Expose) 00867 { 00868 return (True); 00869 } 00870 00871 return (False); 00872 } 00873 00874 00875 /** draws text center at xc, yc -- used only by menu drawing stuff */ 00876 static void 00877 menutext(Window win, 00878 int xc, 00879 int yc, 00880 char *text) 00881 { 00882 int len, width; 00883 00884 len = strlen(text); 00885 width = XTextWidth(font_info[menu_font_size], text, len); 00886 XDrawString(display, win, gc_menus, xc - width / 2, yc + 00887 (font_info[menu_font_size]->ascent - 00888 font_info[menu_font_size]->descent) / 2, text, len); 00889 } 00890 00891 00892 /** Draws button bnum in either its pressed or unpressed state. */ 00893 static void 00894 drawbut(int bnum) 00895 { 00896 int width, height, thick, i, ispressed; 00897 XPoint mypoly[6]; 00898 00899 ispressed = button[bnum].ispressed; 00900 thick = 2; 00901 width = button[bnum].width; 00902 height = button[bnum].height; 00903 /* Draw top and left edges of 3D box. */ 00904 if(ispressed) 00905 { 00906 XSetForeground(display, gc_menus, colors[BLACK]); 00907 } 00908 else 00909 { 00910 XSetForeground(display, gc_menus, colors[WHITE]); 00911 } 00912 00913 /* Note: X Windows doesn't appear to draw the bottom pixel of * 00914 * a polygon with XFillPolygon, so I make this 1 pixel thicker * 00915 * to compensate. */ 00916 mypoly[0].x = 0; 00917 mypoly[0].y = height; 00918 mypoly[1].x = 0; 00919 mypoly[1].y = 0; 00920 mypoly[2].x = width; 00921 mypoly[2].y = 0; 00922 mypoly[3].x = width - thick; 00923 mypoly[3].y = thick; 00924 mypoly[4].x = thick; 00925 mypoly[4].y = thick; 00926 mypoly[5].x = thick; 00927 mypoly[5].y = height - thick; 00928 XFillPolygon(display, button[bnum].win, gc_menus, mypoly, 6, Convex, 00929 CoordModeOrigin); 00930 00931 /* Draw bottom and right edges of 3D box. */ 00932 if(ispressed) 00933 { 00934 XSetForeground(display, gc_menus, colors[WHITE]); 00935 } 00936 else 00937 { 00938 XSetForeground(display, gc_menus, colors[BLACK]); 00939 } 00940 mypoly[0].x = 0; 00941 mypoly[0].y = height; 00942 mypoly[1].x = width; 00943 mypoly[1].y = height; 00944 mypoly[2].x = width; 00945 mypoly[2].y = 0; 00946 mypoly[3].x = width - thick; 00947 mypoly[3].y = thick; 00948 mypoly[4].x = width - thick; 00949 mypoly[4].y = height - thick; 00950 mypoly[5].x = thick; 00951 mypoly[5].y = height - thick; 00952 XFillPolygon(display, button[bnum].win, gc_menus, mypoly, 6, Convex, 00953 CoordModeOrigin); 00954 00955 /* Draw background */ 00956 if(ispressed) 00957 { 00958 XSetForeground(display, gc_menus, colors[DARKGREY]); 00959 } 00960 else 00961 { 00962 XSetForeground(display, gc_menus, colors[LIGHTGREY]); 00963 } 00964 00965 /* Give x,y of top corner and width and height */ 00966 XFillRectangle(display, button[bnum].win, gc_menus, thick, thick, 00967 width - 2 * thick, height - 2 * thick); 00968 00969 /* Draw polygon, if there is one */ 00970 if(button[bnum].ispoly) 00971 { 00972 for(i = 0; i < 3; i++) 00973 { 00974 mypoly[i].x = button[bnum].poly[i][0]; 00975 mypoly[i].y = button[bnum].poly[i][1]; 00976 } 00977 XSetForeground(display, gc_menus, colors[BLACK]); 00978 XFillPolygon(display, button[bnum].win, gc_menus, mypoly, 3, 00979 Convex, CoordModeOrigin); 00980 } 00981 00982 /* Draw text, if there is any */ 00983 if(button[bnum].istext) 00984 { 00985 XSetForeground(display, gc_menus, colors[BLACK]); 00986 menutext(button[bnum].win, button[bnum].width / 2, 00987 button[bnum].height / 2, button[bnum].text); 00988 } 00989 } 00990 00991 00992 /** Shows when the menu is active or inactive by colouring the 00993 * buttons. 00994 */ 00995 static void 00996 turn_on_off(int pressed) 00997 { 00998 00999 int i; 01000 01001 for(i = 0; i < num_buttons; i++) 01002 { 01003 button[i].ispressed = pressed; 01004 drawbut(i); 01005 } 01006 } 01007 01008 01009 static int 01010 which_button(Window win) 01011 { 01012 int i; 01013 01014 for(i = 0; i < num_buttons; i++) 01015 { 01016 if(button[i].win == win) 01017 return (i); 01018 } 01019 printf("Error: Unknown button ID in which_button.\n"); 01020 return (0); 01021 } 01022 01023 01024 static void 01025 drawmenu(void) 01026 { 01027 int i; 01028 01029 for(i = 0; i < num_buttons; i++) 01030 { 01031 drawbut(i); 01032 } 01033 } 01034 01035 01036 /** Set up the factors for transforming from the user world to X Windows 01037 * coordinates. 01038 */ 01039 static void 01040 update_transform(void) 01041 { 01042 float mult, y1, y2, x1, x2; 01043 01044 /* X Window coordinates go from (0,0) to (width-1,height-1) */ 01045 xmult = ((float)top_width - 1. - MWIDTH) / (xright - xleft); 01046 ymult = ((float)top_height - 1. - T_AREA_HEIGHT) / (ybot - ytop); 01047 /* Need to use same scaling factor to preserve aspect ratio */ 01048 if(fabs(xmult) <= fabs(ymult)) 01049 { 01050 mult = fabs(ymult / xmult); 01051 y1 = ytop - (ybot - ytop) * (mult - 1.) / 2.; 01052 y2 = ybot + (ybot - ytop) * (mult - 1.) / 2.; 01053 ytop = y1; 01054 ybot = y2; 01055 } 01056 else 01057 { 01058 mult = fabs(xmult / ymult); 01059 x1 = xleft - (xright - xleft) * (mult - 1.) / 2.; 01060 x2 = xright + (xright - xleft) * (mult - 1.) / 2.; 01061 xleft = x1; 01062 xright = x2; 01063 } 01064 xmult = ((float)top_width - 1. - MWIDTH) / (xright - xleft); 01065 ymult = ((float)top_height - 1. - T_AREA_HEIGHT) / (ybot - ytop); 01066 } 01067 01068 01069 /** Postscript coordinates start at (0,0) for the lower left hand corner 01070 * of the page and increase upwards and to the right. For 8.5 x 11 01071 * sheet, coordinates go from (0,0) to (612,792). Spacing is 1/72 inch. 01072 * I'm leaving a minimum of half an inch (36 units) of border around 01073 * each edge. 01074 */ 01075 static void 01076 update_ps_transform(void) 01077 { 01078 float ps_width, ps_height; 01079 01080 ps_width = 540.; /* 72 * 7.5 */ 01081 ps_height = 720.; /* 72 * 10 */ 01082 01083 ps_xmult = ps_width / (xright - xleft); 01084 ps_ymult = ps_height / (ytop - ybot); 01085 /* Need to use same scaling factor to preserve aspect ratio. * 01086 * I show exactly as much on paper as the screen window shows, * 01087 * or the user specifies. */ 01088 if(fabs(ps_xmult) <= fabs(ps_ymult)) 01089 { 01090 ps_left = 36.; 01091 ps_right = 36. + ps_width; 01092 ps_bot = 396. - fabs(ps_xmult * (ytop - ybot)) / 2.; 01093 ps_top = 396. + fabs(ps_xmult * (ytop - ybot)) / 2.; 01094 /* Maintain aspect ratio but watch signs */ 01095 ps_ymult = (ps_xmult * ps_ymult < 0) ? -ps_xmult : ps_xmult; 01096 } 01097 else 01098 { 01099 ps_bot = 36.; 01100 ps_top = 36. + ps_height; 01101 ps_left = 306. - fabs(ps_ymult * (xright - xleft)) / 2.; 01102 ps_right = 306. + fabs(ps_ymult * (xright - xleft)) / 2.; 01103 /* Maintain aspect ratio but watch signs */ 01104 ps_xmult = (ps_xmult * ps_ymult < 0) ? -ps_ymult : ps_ymult; 01105 } 01106 } 01107 01108 01109 /** The program's main event loop. Must be passed a user routine 01110 * drawscreen which redraws the screen. It handles all window resizing 01111 * zooming etc. itself. If the user clicks a button in the graphics 01112 * (toplevel) area, the act_on_button routine passed in is called. 01113 */ 01114 void 01115 event_loop(void (*act_on_button) (float x, 01116 float y), 01117 void (*drawscreen) (void)) 01118 { 01119 XEvent report; 01120 int bnum; 01121 float x, y; 01122 01123 #define OFF 1 01124 #define ON 0 01125 01126 turn_on_off(ON); 01127 while(1) 01128 { 01129 XNextEvent(display, &report); 01130 switch (report.type) 01131 { 01132 case Expose: 01133 #ifdef VERBOSE 01134 printf("Got an expose event.\n"); 01135 printf("Count is: %d.\n", report.xexpose.count); 01136 printf("Window ID is: %d.\n", report.xexpose.window); 01137 #endif 01138 if(report.xexpose.count != 0) 01139 break; 01140 if(report.xexpose.window == menu) 01141 drawmenu(); 01142 else if(report.xexpose.window == toplevel) 01143 drawscreen(); 01144 else if(report.xexpose.window == textarea) 01145 draw_message(); 01146 break; 01147 case ConfigureNotify: 01148 top_width = report.xconfigure.width; 01149 top_height = report.xconfigure.height; 01150 update_transform(); 01151 #ifdef VERBOSE 01152 printf("Got a ConfigureNotify.\n"); 01153 printf("New width: %d New height: %d.\n", top_width, 01154 top_height); 01155 #endif 01156 break; 01157 case ButtonPress: 01158 #ifdef VERBOSE 01159 printf("Got a buttonpress.\n"); 01160 printf("Window ID is: %d.\n", report.xbutton.window); 01161 #endif 01162 if(report.xbutton.window == toplevel) 01163 { 01164 x = XTOWORLD(report.xbutton.x); 01165 y = YTOWORLD(report.xbutton.y); 01166 act_on_button(x, y); 01167 } 01168 else 01169 { /* A menu button was pressed. */ 01170 bnum = which_button(report.xbutton.window); 01171 #ifdef VERBOSE 01172 printf("Button number is %d\n", bnum); 01173 #endif 01174 button[bnum].ispressed = 1; 01175 drawbut(bnum); 01176 XFlush(display); /* Flash the button */ 01177 button[bnum].fcn(drawscreen); 01178 button[bnum].ispressed = 0; 01179 drawbut(bnum); 01180 if(button[bnum].fcn == proceed) 01181 { 01182 turn_on_off(OFF); 01183 flushinput(); 01184 return; /* Rather clumsy way of returning * 01185 * control to the simulator */ 01186 } 01187 } 01188 break; 01189 } 01190 } 01191 } 01192 01193 01194 01195 void 01196 clearscreen(void) 01197 { 01198 int savecolor; 01199 01200 if(disp_type == SCREEN) 01201 { 01202 XClearWindow(display, toplevel); 01203 } 01204 else 01205 { 01206 /* erases current page. Don't use erasepage, since this will erase * 01207 * everything, (even stuff outside the clipping path) causing * 01208 * problems if this picture is incorporated into a larger document. */ 01209 savecolor = currentcolor; 01210 setcolor(WHITE); 01211 fprintf(ps, "clippath fill\n\n"); 01212 setcolor(savecolor); 01213 } 01214 } 01215 01216 /** Return 1 if I can quarantee no part of this rectangle will 01217 * lie within the user drawing area. Otherwise return 0. 01218 * Note: this routine is only used to help speed (and to shrink ps 01219 * files) -- it will be highly effective when the graphics are zoomed 01220 * in and lots are off-screen. I don't have to pre-clip for 01221 * correctness. 01222 */ 01223 static int 01224 rect_off_screen(float x1, 01225 float y1, 01226 float x2, 01227 float y2) 01228 { 01229 float xmin, xmax, ymin, ymax; 01230 01231 xmin = min(xleft, xright); 01232 if(x1 < xmin && x2 < xmin) 01233 return (1); 01234 01235 xmax = max(xleft, xright); 01236 if(x1 > xmax && x2 > xmax) 01237 return (1); 01238 01239 ymin = min(ytop, ybot); 01240 if(y1 < ymin && y2 < ymin) 01241 return (1); 01242 01243 ymax = max(ytop, ybot); 01244 if(y1 > ymax && y2 > ymax) 01245 return (1); 01246 01247 return (0); 01248 } 01249 01250 01251 /** Draw a line from (x1,y1) to (x2,y2) in the user-drawable area. 01252 * Coordinates are in world (user) space. 01253 */ 01254 void 01255 drawline(float x1, 01256 float y1, 01257 float x2, 01258 float y2) 01259 { 01260 if(rect_off_screen(x1, y1, x2, y2)) 01261 return; 01262 01263 if(disp_type == SCREEN) 01264 { 01265 /* Xlib.h prototype has x2 and y1 mixed up. */ 01266 XDrawLine(display, toplevel, gc, xcoord(x1), ycoord(y1), 01267 xcoord(x2), ycoord(y2)); 01268 } 01269 else 01270 { 01271 fprintf(ps, "%.2f %.2f %.2f %.2f drawline\n", XPOST(x1), 01272 YPOST(y1), XPOST(x2), YPOST(y2)); 01273 } 01274 } 01275 01276 /** (x1,y1) and (x2,y2) are diagonally opposed corners, in world coords. */ 01277 void 01278 drawrect(float x1, 01279 float y1, 01280 float x2, 01281 float y2) 01282 { 01283 unsigned int width, height; 01284 int xw1, yw1, xw2, yw2, xl, yt; 01285 01286 if(rect_off_screen(x1, y1, x2, y2)) 01287 return; 01288 01289 if(disp_type == SCREEN) 01290 { 01291 /* translate to X Windows calling convention. */ 01292 xw1 = xcoord(x1); 01293 xw2 = xcoord(x2); 01294 yw1 = ycoord(y1); 01295 yw2 = ycoord(y2); 01296 xl = min(xw1, xw2); 01297 yt = min(yw1, yw2); 01298 width = abs(xw1 - xw2); 01299 height = abs(yw1 - yw2); 01300 XDrawRectangle(display, toplevel, gc, xl, yt, width, height); 01301 } 01302 else 01303 { 01304 fprintf(ps, "%.2f %.2f %.2f %.2f drawrect\n", XPOST(x1), 01305 YPOST(y1), XPOST(x2), YPOST(y2)); 01306 } 01307 } 01308 01309 01310 /** (x1,y1) and (x2,y2) are diagonally opposed corners in world coords. */ 01311 void 01312 fillrect(float x1, 01313 float y1, 01314 float x2, 01315 float y2) 01316 { 01317 unsigned int width, height; 01318 int xw1, yw1, xw2, yw2, xl, yt; 01319 01320 if(rect_off_screen(x1, y1, x2, y2)) 01321 return; 01322 01323 if(disp_type == SCREEN) 01324 { 01325 /* translate to X Windows calling convention. */ 01326 xw1 = xcoord(x1); 01327 xw2 = xcoord(x2); 01328 yw1 = ycoord(y1); 01329 yw2 = ycoord(y2); 01330 xl = min(xw1, xw2); 01331 yt = min(yw1, yw2); 01332 width = abs(xw1 - xw2); 01333 height = abs(yw1 - yw2); 01334 XFillRectangle(display, toplevel, gc, xl, yt, width, height); 01335 } 01336 else 01337 { 01338 fprintf(ps, "%.2f %.2f %.2f %.2f fillrect\n", XPOST(x1), 01339 YPOST(y1), XPOST(x2), YPOST(y2)); 01340 } 01341 } 01342 01343 01344 /** Normalizes an angle to be between 0 and 360 degrees. */ 01345 static float 01346 angnorm(float ang) 01347 { 01348 int scale; 01349 01350 if(ang < 0) 01351 { 01352 scale = (int)(ang / 360. - 1); 01353 } 01354 else 01355 { 01356 scale = (int)(ang / 360.); 01357 } 01358 ang = ang - scale * 360.; 01359 return (ang); 01360 } 01361 01362 01363 /** Draws a circular arc. X11 can do elliptical arcs quite simply, and 01364 * PostScript could do them by scaling the coordinate axes. Too much 01365 * work for now, and probably too complex an object for users to draw 01366 * much, so I'm just doing circular arcs. Startang is relative to the 01367 * Window's positive x direction. Angles in degrees. 01368 */ 01369 void 01370 drawarc(float xc, 01371 float yc, 01372 float rad, 01373 float startang, 01374 float angextent) 01375 { 01376 int xl, yt; 01377 unsigned int width, height; 01378 01379 /* Conservative (but fast) clip test -- check containing rectangle of * 01380 * a circle. */ 01381 01382 if(rect_off_screen(xc - rad, yc - rad, xc + rad, yc + rad)) 01383 return; 01384 01385 /* X Windows has trouble with very large angles. (Over 360). * 01386 * Do following to prevent its inaccurate (overflow?) problems. */ 01387 if(fabs(angextent) > 360.) 01388 angextent = 360.; 01389 01390 startang = angnorm(startang); 01391 01392 if(disp_type == SCREEN) 01393 { 01394 xl = (int)(xcoord(xc) - fabs(xmult * rad)); 01395 yt = (int)(ycoord(yc) - fabs(ymult * rad)); 01396 width = (unsigned int)(2 * fabs(xmult * rad)); 01397 height = width; 01398 XDrawArc(display, toplevel, gc, xl, yt, width, height, 01399 (int)(startang * 64), (int)(angextent * 64)); 01400 } 01401 else 01402 { 01403 fprintf(ps, "%.2f %.2f %.2f %.2f %.2f %s stroke\n", XPOST(xc), 01404 YPOST(yc), fabs(rad * ps_xmult), startang, 01405 startang + angextent, 01406 (angextent < 0) ? "drawarcn" : "drawarc"); 01407 } 01408 } 01409 01410 01411 /** Fills a circular arc. Startang is relative to the Window's positive x 01412 * direction. Angles in degrees. 01413 */ 01414 void 01415 fillarc(float xc, 01416 float yc, 01417 float rad, 01418 float startang, 01419 float angextent) 01420 { 01421 01422 int xl, yt; 01423 unsigned int width, height; 01424 01425 /* Conservative (but fast) clip test -- check containing rectangle of * 01426 * a circle. */ 01427 01428 if(rect_off_screen(xc - rad, yc - rad, xc + rad, yc + rad)) 01429 return; 01430 01431 /* X Windows has trouble with very large angles. (Over 360). * 01432 * Do following to prevent its inaccurate (overflow?) problems. */ 01433 01434 if(fabs(angextent) > 360.) 01435 angextent = 360.; 01436 01437 startang = angnorm(startang); 01438 01439 if(disp_type == SCREEN) 01440 { 01441 xl = (int)(xcoord(xc) - fabs(xmult * rad)); 01442 yt = (int)(ycoord(yc) - fabs(ymult * rad)); 01443 width = (unsigned int)(2 * fabs(xmult * rad)); 01444 height = width; 01445 XFillArc(display, toplevel, gc, xl, yt, width, height, 01446 (int)(startang * 64), (int)(angextent * 64)); 01447 } 01448 else 01449 { 01450 fprintf(ps, "%.2f %.2f %.2f %.2f %.2f %s\n", fabs(rad * ps_xmult), 01451 startang, startang + angextent, XPOST(xc), YPOST(yc), 01452 (angextent < 0) ? "fillarcn" : "fillarc"); 01453 } 01454 } 01455 01456 01457 void 01458 fillpoly(t_point * points, 01459 int npoints) 01460 { 01461 01462 XPoint transpoints[MAXPTS]; 01463 int i; 01464 float xmin, ymin, xmax, ymax; 01465 01466 if(npoints > MAXPTS) 01467 { 01468 printf 01469 ("Error in fillpoly: Only %d points allowed per polygon.\n", 01470 MAXPTS); 01471 printf("%d points were requested. Polygon is not drawn.\n", 01472 npoints); 01473 return; 01474 } 01475 01476 /* Conservative (but fast) clip test -- check containing rectangle of * 01477 * polygon. */ 01478 01479 xmin = xmax = points[0].x; 01480 ymin = ymax = points[0].y; 01481 01482 for(i = 1; i < npoints; i++) 01483 { 01484 xmin = min(xmin, points[i].x); 01485 xmax = max(xmax, points[i].x); 01486 ymin = min(ymin, points[i].y); 01487 ymax = max(ymax, points[i].y); 01488 } 01489 01490 if(rect_off_screen(xmin, ymin, xmax, ymax)) 01491 return; 01492 01493 if(disp_type == SCREEN) 01494 { 01495 for(i = 0; i < npoints; i++) 01496 { 01497 transpoints[i].x = (short)xcoord(points[i].x); 01498 transpoints[i].y = (short)ycoord(points[i].y); 01499 } 01500 XFillPolygon(display, toplevel, gc, transpoints, npoints, Complex, 01501 CoordModeOrigin); 01502 } 01503 else 01504 { 01505 fprintf(ps, "\n"); 01506 01507 for(i = npoints - 1; i >= 0; i--) 01508 fprintf(ps, "%.2f %.2f\n", XPOST(points[i].x), 01509 YPOST(points[i].y)); 01510 01511 fprintf(ps, "%d fillpoly\n", npoints); 01512 } 01513 } 01514 01515 /** Draws text centered on xc,yc if it fits in boundx */ 01516 void 01517 drawtext(float xc, 01518 float yc, 01519 const char *text, 01520 float boundx) 01521 { 01522 int len, width, xw_off, yw_off; 01523 01524 len = strlen(text); 01525 width = XTextWidth(font_info[currentfontsize], text, len); 01526 if(width > fabs(boundx * xmult)) 01527 return; /* Don't draw if it won't fit */ 01528 01529 xw_off = width / (2. * xmult); /* NB: sign doesn't matter. */ 01530 01531 /* NB: 2 * descent makes this slightly conservative but simplifies code. */ 01532 yw_off = (font_info[currentfontsize]->ascent + 01533 2 * font_info[currentfontsize]->descent) / (2. * ymult); 01534 01535 /* Note: text can be clipped when a little bit of it would be visible * 01536 * right now. Perhaps X doesn't return extremely accurate width and * 01537 * ascent values, etc? Could remove this completely by multiplying * 01538 * xw_off and yw_off by, 1.2 or 1.5. */ 01539 01540 if(rect_off_screen(xc - xw_off, yc - yw_off, xc + xw_off, yc + yw_off)) 01541 return; 01542 01543 if(disp_type == SCREEN) 01544 { 01545 XDrawString(display, toplevel, gc, xcoord(xc) - width / 2, 01546 ycoord(yc) + (font_info[currentfontsize]->ascent - 01547 font_info[currentfontsize]->descent) / 01548 2, text, len); 01549 } 01550 else 01551 { 01552 fprintf(ps, "(%s) %.2f %.2f censhow\n", text, XPOST(xc), 01553 YPOST(yc)); 01554 } 01555 } 01556 01557 01558 void 01559 flushinput(void) 01560 { 01561 if(disp_type != SCREEN) 01562 return; 01563 XFlush(display); 01564 } 01565 01566 01567 /** Sets the coordinate system the user wants to draw into. */ 01568 void 01569 init_world(float x1, 01570 float y1, 01571 float x2, 01572 float y2) 01573 { 01574 xleft = x1; 01575 xright = x2; 01576 ytop = y1; 01577 ybot = y2; 01578 01579 saved_xleft = xleft; /* Save initial world coordinates to allow full */ 01580 saved_xright = xright; /* view button to zoom all the way out. */ 01581 saved_ytop = ytop; 01582 saved_ybot = ybot; 01583 01584 if(disp_type == SCREEN) 01585 { 01586 update_transform(); 01587 } 01588 else 01589 { 01590 update_ps_transform(); 01591 } 01592 } 01593 01594 01595 /** Draw the current message in the text area at the screen bottom. */ 01596 void 01597 draw_message(void) 01598 { 01599 int len, width, savefontsize, savecolor; 01600 float ylow; 01601 01602 if(disp_type == SCREEN) 01603 { 01604 XClearWindow(display, textarea); 01605 len = strlen(message); 01606 width = XTextWidth(font_info[menu_font_size], message, len); 01607 01608 XSetForeground(display, gc_menus, colors[BLACK]); 01609 XDrawString(display, textarea, gc_menus, 01610 (top_width - MWIDTH - width) / 2, 01611 (T_AREA_HEIGHT - 4) / 2 + 01612 (font_info[menu_font_size]->ascent - 01613 font_info[menu_font_size]->descent) / 2, message, 01614 len); 01615 } 01616 01617 else 01618 { 01619 /* Draw the message in the bottom margin. Printer's generally can't * 01620 * print on the bottom 1/4" (area with y < 18 in PostScript coords.) */ 01621 01622 savecolor = currentcolor; 01623 setcolor(BLACK); 01624 savefontsize = currentfontsize; 01625 setfontsize(menu_font_size - 2); /* Smaller OK on paper */ 01626 ylow = ps_bot - 8.; 01627 fprintf(ps, "(%s) %.2f %.2f censhow\n", message, 01628 (ps_left + ps_right) / 2., ylow); 01629 setcolor(savecolor); 01630 setfontsize(savefontsize); 01631 } 01632 } 01633 01634 01635 /** Changes the message to be displayed on screen. */ 01636 void 01637 update_message(char *msg) 01638 { 01639 my_strncpy(message, msg, BUFSIZE); 01640 draw_message(); 01641 } 01642 01643 01644 /** Zooms in by a factor of 1.666. */ 01645 static void 01646 zoom_in(void (*drawscreen) (void)) 01647 { 01648 float xdiff, ydiff; 01649 01650 xdiff = xright - xleft; 01651 ydiff = ybot - ytop; 01652 xleft += xdiff / 5.; 01653 xright -= xdiff / 5.; 01654 ytop += ydiff / 5.; 01655 ybot -= ydiff / 5.; 01656 01657 update_transform(); 01658 drawscreen(); 01659 } 01660 01661 01662 /** Zooms out by a factor of 1.666. */ 01663 static void 01664 zoom_out(void (*drawscreen) (void)) 01665 { 01666 float xdiff, ydiff; 01667 01668 xdiff = xright - xleft; 01669 ydiff = ybot - ytop; 01670 xleft -= xdiff / 3.; 01671 xright += xdiff / 3.; 01672 ytop -= ydiff / 3.; 01673 ybot += ydiff / 3.; 01674 01675 update_transform(); 01676 drawscreen(); 01677 } 01678 01679 01680 /** Sets the view back to the initial view set by init_world (i.e. a full 01681 * view) of all the graphics. 01682 */ 01683 static void 01684 zoom_fit(void (*drawscreen) (void)) 01685 { 01686 01687 xleft = saved_xleft; 01688 xright = saved_xright; 01689 ytop = saved_ytop; 01690 ybot = saved_ybot; 01691 01692 update_transform(); 01693 drawscreen(); 01694 } 01695 01696 01697 /** Moves view 1/2 screen up. */ 01698 static void 01699 translate_up(void (*drawscreen) (void)) 01700 { 01701 float ystep; 01702 01703 ystep = (ybot - ytop) / 2.; 01704 ytop -= ystep; 01705 ybot -= ystep; 01706 update_transform(); 01707 drawscreen(); 01708 } 01709 01710 01711 /** Moves view 1/2 screen down. */ 01712 static void 01713 translate_down(void (*drawscreen) (void)) 01714 { 01715 float ystep; 01716 01717 ystep = (ybot - ytop) / 2.; 01718 ytop += ystep; 01719 ybot += ystep; 01720 update_transform(); 01721 drawscreen(); 01722 } 01723 01724 01725 /** Moves view 1/2 screen left. */ 01726 static void 01727 translate_left(void (*drawscreen) (void)) 01728 { 01729 float xstep; 01730 01731 xstep = (xright - xleft) / 2.; 01732 xleft -= xstep; 01733 xright -= xstep; 01734 update_transform(); 01735 drawscreen(); 01736 } 01737 01738 01739 /** Moves view 1/2 screen right. */ 01740 static void 01741 translate_right(void (*drawscreen) (void)) 01742 { 01743 float xstep; 01744 01745 xstep = (xright - xleft) / 2.; 01746 xleft += xstep; 01747 xright += xstep; 01748 update_transform(); 01749 drawscreen(); 01750 } 01751 01752 01753 static void 01754 update_win(int x[2], 01755 int y[2], 01756 void (*drawscreen) (void)) 01757 { 01758 float x1, x2, y1, y2; 01759 01760 x[0] = min(x[0], top_width - MWIDTH); /* Can't go under menu */ 01761 x[1] = min(x[1], top_width - MWIDTH); 01762 y[0] = min(y[0], top_height - T_AREA_HEIGHT); /* Can't go under text area */ 01763 y[1] = min(y[1], top_height - T_AREA_HEIGHT); 01764 01765 if((x[0] == x[1]) || (y[0] == y[1])) 01766 { 01767 printf("Illegal (zero area) window. Window unchanged.\n"); 01768 return; 01769 } 01770 x1 = XTOWORLD(min(x[0], x[1])); 01771 x2 = XTOWORLD(max(x[0], x[1])); 01772 y1 = YTOWORLD(min(y[0], y[1])); 01773 y2 = YTOWORLD(max(y[0], y[1])); 01774 xleft = x1; 01775 xright = x2; 01776 ytop = y1; 01777 ybot = y2; 01778 update_transform(); 01779 drawscreen(); 01780 } 01781 01782 01783 /** The window button was pressed. Let the user click on the two 01784 * diagonally opposed corners, and zoom in on this area. 01785 */ 01786 static void 01787 adjustwin(void (*drawscreen) (void)) 01788 { 01789 XEvent report; 01790 int corner, xold, yold, x[2], y[2]; 01791 01792 corner = 0; 01793 xold = -1; 01794 yold = -1; /* Don't need to init yold, but stops compiler warning. */ 01795 01796 while(corner < 2) 01797 { 01798 XNextEvent(display, &report); 01799 switch (report.type) 01800 { 01801 case Expose: 01802 #ifdef VERBOSE 01803 printf("Got an expose event.\n"); 01804 printf("Count is: %d.\n", report.xexpose.count); 01805 printf("Window ID is: %d.\n", report.xexpose.window); 01806 #endif 01807 if(report.xexpose.count != 0) 01808 break; 01809 if(report.xexpose.window == menu) 01810 drawmenu(); 01811 else if(report.xexpose.window == toplevel) 01812 { 01813 drawscreen(); 01814 xold = -1; /* No rubber band on screen */ 01815 } 01816 else if(report.xexpose.window == textarea) 01817 draw_message(); 01818 break; 01819 case ConfigureNotify: 01820 top_width = report.xconfigure.width; 01821 top_height = report.xconfigure.height; 01822 update_transform(); 01823 #ifdef VERBOSE 01824 printf("Got a ConfigureNotify.\n"); 01825 printf("New width: %d New height: %d.\n", top_width, 01826 top_height); 01827 #endif 01828 break; 01829 case ButtonPress: 01830 #ifdef VERBOSE 01831 printf("Got a buttonpress.\n"); 01832 printf("Window ID is: %d.\n", report.xbutton.window); 01833 printf("Location (%d, %d).\n", report.xbutton.x, 01834 report.xbutton.y); 01835 #endif 01836 if(report.xbutton.window != toplevel) 01837 break; 01838 x[corner] = report.xbutton.x; 01839 y[corner] = report.xbutton.y; 01840 if(corner == 0) 01841 { 01842 XSelectInput(display, toplevel, ExposureMask | 01843 StructureNotifyMask | ButtonPressMask 01844 | PointerMotionMask); 01845 } 01846 else 01847 { 01848 update_win(x, y, drawscreen); 01849 } 01850 corner++; 01851 break; 01852 case MotionNotify: 01853 #ifdef VERBOSE 01854 printf("Got a MotionNotify Event.\n"); 01855 printf("x: %d y: %d\n", report.xmotion.x, 01856 report.xmotion.y); 01857 #endif 01858 if(xold >= 0) 01859 { /* xold set -ve before we draw first box */ 01860 XDrawRectangle(display, toplevel, gcxor, 01861 min(x[0], xold), min(y[0], yold), 01862 abs(x[0] - xold), 01863 abs(y[0] - yold)); 01864 } 01865 /* Don't allow user to window under menu region */ 01866 xold = min(report.xmotion.x, top_width - 1 - MWIDTH); 01867 yold = report.xmotion.y; 01868 XDrawRectangle(display, toplevel, gcxor, min(x[0], xold), 01869 min(y[0], yold), abs(x[0] - xold), 01870 abs(y[0] - yold)); 01871 break; 01872 } 01873 } 01874 XSelectInput(display, toplevel, ExposureMask | StructureNotifyMask 01875 | ButtonPressMask); 01876 } 01877 01878 01879 /** Takes a snapshot of the screen and stores it in pic?.ps. The 01880 * first picture goes in pic1.ps, the second in pic2.ps, etc. 01881 */ 01882 static void 01883 postscript(void (*drawscreen) (void)) 01884 { 01885 static int piccount = 1; 01886 int success; 01887 char fname[20]; 01888 01889 sprintf(fname, "pic%d.ps", piccount); 01890 success = init_postscript(fname); 01891 01892 if(success == 0) 01893 return; /* Couldn't open file, abort. */ 01894 01895 drawscreen(); 01896 close_postscript(); 01897 piccount++; 01898 } 01899 01900 01901 /** Dummy routine. Just exit the event loop. */ 01902 static void 01903 proceed(void (*drawscreen) (void)) 01904 { 01905 01906 /* Dummy routine. Just exit the event loop. */ 01907 01908 } 01909 01910 01911 static void 01912 quit(void (*drawscreen) (void)) 01913 { 01914 01915 close_graphics(); 01916 exit(0); 01917 } 01918 01919 01920 /** Release all my drawing structures (through the X server) and 01921 * close down the connection. 01922 */ 01923 void 01924 close_graphics(void) 01925 { 01926 int i; 01927 01928 for(i = 1; i <= MAX_FONT_SIZE; i++) 01929 if(font_is_loaded[i]) 01930 XFreeFont(display, font_info[i]); 01931 01932 XFreeGC(display, gc); 01933 XFreeGC(display, gcxor); 01934 XFreeGC(display, gc_menus); 01935 01936 if(private_cmap != None) 01937 XFreeColormap(display, private_cmap); 01938 01939 XCloseDisplay(display); 01940 free(button); 01941 } 01942 01943 01944 /** Opens a file for PostScript output. The header information, 01945 * clipping path, etc. are all dumped out. If the file could 01946 * not be opened, the routine returns 0; otherwise it returns 1. 01947 */ 01948 int 01949 init_postscript(char *fname) 01950 { 01951 ps = fopen(fname, "w"); 01952 if(ps == NULL) 01953 { 01954 printf("Error: could not open %s for PostScript output.\n", 01955 fname); 01956 printf("Drawing to screen instead.\n"); 01957 return (0); 01958 } 01959 disp_type = POSTSCRIPT; /* Graphics go to postscript file now. */ 01960 01961 /* Header for minimal conformance with the Adobe structuring convention */ 01962 fprintf(ps, "%%!PS-Adobe-1.0\n"); 01963 fprintf(ps, "%%%%DocumentFonts: Helvetica\n"); 01964 fprintf(ps, "%%%%Pages: 1\n"); 01965 /* Set up postscript transformation macros and page boundaries */ 01966 update_ps_transform(); 01967 /* Bottom margin is at ps_bot - 15. to leave room for the on-screen message. */ 01968 fprintf(ps, "%%%%BoundingBox: %d %d %d %d\n", 01969 (int)ps_left, (int)(ps_bot - 15.), (int)ps_right, (int)ps_top); 01970 fprintf(ps, "%%%%EndComments\n"); 01971 01972 fprintf(ps, "/censhow %%draw a centered string\n"); 01973 fprintf(ps, " { moveto %% move to proper spot\n"); 01974 fprintf(ps, " dup stringwidth pop %% get x length of string\n"); 01975 fprintf(ps, " -2 div %% Proper left start\n"); 01976 fprintf(ps, 01977 " yoff rmoveto %% Move left that much and down half font height\n"); 01978 fprintf(ps, " show newpath } def %% show the string\n\n"); 01979 01980 fprintf(ps, "/setfontsize %% set font to desired size and compute " 01981 "centering yoff\n"); 01982 fprintf(ps, " { /Helvetica findfont\n"); 01983 fprintf(ps, " exch scalefont\n"); 01984 fprintf(ps, " setfont %% Font size set ...\n\n"); 01985 fprintf(ps, " 0 0 moveto %% Get vertical centering offset\n"); 01986 fprintf(ps, " (Xg) true charpath\n"); 01987 fprintf(ps, " flattenpath pathbbox\n"); 01988 fprintf(ps, " /ascent exch def pop -1 mul /descent exch def pop\n"); 01989 fprintf(ps, " newpath\n"); 01990 fprintf(ps, " descent ascent sub 2 div /yoff exch def } def\n\n"); 01991 01992 fprintf(ps, "%% Next two lines for debugging only.\n"); 01993 fprintf(ps, "/str 20 string def\n"); 01994 fprintf(ps, "/pnum {str cvs print ( ) print} def\n"); 01995 01996 fprintf(ps, "/drawline %% draw a line from (x2,y2) to (x1,y1)\n"); 01997 fprintf(ps, " { moveto lineto stroke } def\n\n"); 01998 01999 fprintf(ps, "/rect %% outline a rectangle \n"); 02000 fprintf(ps, " { /y2 exch def /x2 exch def /y1 exch def /x1 exch def\n"); 02001 fprintf(ps, " x1 y1 moveto\n"); 02002 fprintf(ps, " x2 y1 lineto\n"); 02003 fprintf(ps, " x2 y2 lineto\n"); 02004 fprintf(ps, " x1 y2 lineto\n"); 02005 fprintf(ps, " closepath } def\n\n"); 02006 02007 fprintf(ps, "/drawrect %% draw outline of a rectanagle\n"); 02008 fprintf(ps, " { rect stroke } def\n\n"); 02009 02010 fprintf(ps, "/fillrect %% fill in a rectanagle\n"); 02011 fprintf(ps, " { rect fill } def\n\n"); 02012 02013 fprintf(ps, "/drawarc { arc stroke } def %% draw an arc\n"); 02014 fprintf(ps, "/drawarcn { arcn stroke } def " 02015 " %% draw an arc in the opposite direction\n\n"); 02016 02017 fprintf(ps, "%%Fill a counterclockwise or clockwise arc sector, " 02018 "respectively.\n"); 02019 fprintf(ps, 02020 "/fillarc { moveto currentpoint 5 2 roll arc closepath fill } " 02021 "def\n"); 02022 fprintf(ps, 02023 "/fillarcn { moveto currentpoint 5 2 roll arcn closepath fill } " 02024 "def\n\n"); 02025 02026 fprintf(ps, 02027 "/fillpoly { 3 1 roll moveto %% move to first point\n" 02028 " 2 exch 1 exch {pop lineto} for %% line to all other points\n" 02029 " closepath fill } def\n\n"); 02030 02031 02032 fprintf(ps, "%%Color Definitions:\n"); 02033 fprintf(ps, "/white { 1 setgray } def\n"); 02034 fprintf(ps, "/black { 0 setgray } def\n"); 02035 fprintf(ps, "/grey55 { .55 setgray } def\n"); 02036 fprintf(ps, "/grey75 { .75 setgray } def\n"); 02037 fprintf(ps, "/blue { 0 0 1 setrgbcolor } def\n"); 02038 fprintf(ps, "/green { 0 1 0 setrgbcolor } def\n"); 02039 fprintf(ps, "/yellow { 1 1 0 setrgbcolor } def\n"); 02040 fprintf(ps, "/cyan { 0 1 1 setrgbcolor } def\n"); 02041 fprintf(ps, "/red { 1 0 0 setrgbcolor } def\n"); 02042 fprintf(ps, "/darkgreen { 0 0.5 0 setrgbcolor } def\n"); 02043 fprintf(ps, "/magenta { 1 0 1 setrgbcolor } def\n"); 02044 fprintf(ps, "/bisque { 1 0.9 0.8 setrgbcolor } def\n"); 02045 fprintf(ps, "/lightblue { 0.7 0.8 0.9 setrgbcolor } def\n"); 02046 fprintf(ps, "/thistle { 0.8 0.7 0.8 setrgbcolor } def\n"); 02047 fprintf(ps, "/plum {0.8 0.6 0.8 setrgbcolor } def\n"); 02048 fprintf(ps, "/khaki { 1 0.9 0.6 setrgbcolor } def\n"); 02049 fprintf(ps, "/coral { 1 0.7 0.6 setrgbcolor } def\n"); 02050 fprintf(ps, "/turquoise { 0.5 0.6 0.9 setrgbcolor } def\n"); 02051 fprintf(ps, "/mediumpurple { 0.7 0.6 0.7 setrgbcolor } def\n"); 02052 fprintf(ps, "/darkslateblue { 0.7 0.5 0.7 setrgbcolor } def\n"); 02053 fprintf(ps, "/darkkhaki { 0.9 0.7 0.4 setrgbcolor } def\n"); 02054 02055 fprintf(ps, "\n%%Solid and dashed line definitions:\n"); 02056 fprintf(ps, "/linesolid {[] 0 setdash} def\n"); 02057 fprintf(ps, "/linedashed {[3 3] 0 setdash} def\n"); 02058 02059 fprintf(ps, "\n%%%%EndProlog\n"); 02060 fprintf(ps, "%%%%Page: 1 1\n\n"); 02061 02062 /* Set up PostScript graphics state to match current one. */ 02063 force_setcolor(currentcolor); 02064 force_setlinestyle(currentlinestyle); 02065 force_setlinewidth(currentlinewidth); 02066 force_setfontsize(currentfontsize); 02067 02068 /* Draw this in the bottom margin -- must do before the clippath is set */ 02069 draw_message(); 02070 02071 /* Set clipping on page. */ 02072 fprintf(ps, "%.2f %.2f %.2f %.2f rect ", ps_left, ps_bot, ps_right, 02073 ps_top); 02074 fprintf(ps, "clip newpath\n\n"); 02075 02076 return (1); 02077 } 02078 02079 /** Properly ends postscript output and redirects output to screen. */ 02080 void 02081 close_postscript(void) 02082 { 02083 fprintf(ps, "showpage\n"); 02084 fprintf(ps, "\n%%%%Trailer\n"); 02085 fclose(ps); 02086 disp_type = SCREEN; 02087 update_transform(); /* Ensure screen world reflects any changes * 02088 * made while printing. */ 02089 02090 /* Need to make sure that we really set up the graphics context -- * 02091 * don't want the change requested to match the current setting and * 02092 * do nothing -> force the changes. */ 02093 02094 force_setcolor(currentcolor); 02095 force_setlinestyle(currentlinestyle); 02096 force_setlinewidth(currentlinewidth); 02097 force_setfontsize(currentfontsize); 02098 } 02099 02100 #else /* NO_GRAPHICS build -- rip out graphics */ 02101 02102 void 02103 event_loop(void (*act_on_button) (float x, 02104 float y), 02105 void (*drawscreen) (void)) 02106 { 02107 } 02108 02109 void 02110 init_graphics(char *window_name) 02111 { 02112 } 02113 void 02114 close_graphics(void) 02115 { 02116 } 02117 void 02118 update_message(char *msg) 02119 { 02120 } 02121 void 02122 draw_message(void) 02123 { 02124 } 02125 void 02126 init_world(float xl, 02127 float yt, 02128 float xr, 02129 float yb) 02130 { 02131 } 02132 void 02133 flushinput(void) 02134 { 02135 } 02136 void 02137 setcolor(int cindex) 02138 { 02139 } 02140 int 02141 getcolor(int cindex) 02142 { 02143 return 0; 02144 } 02145 void 02146 setlinestyle(int linestyle) 02147 { 02148 } 02149 void 02150 setlinewidth(int linewidth) 02151 { 02152 } 02153 void 02154 setfontsize(int pointsize) 02155 { 02156 } 02157 void 02158 drawline(float x1, 02159 float y1, 02160 float x2, 02161 float y2) 02162 { 02163 } 02164 void 02165 drawrect(float x1, 02166 float y1, 02167 float x2, 02168 float y2) 02169 { 02170 } 02171 void 02172 fillrect(float x1, 02173 float y1, 02174 float x2, 02175 float y2) 02176 { 02177 } 02178 void 02179 fillpoly(t_point * points, 02180 int npoints) 02181 { 02182 } 02183 void 02184 drawarc(float xcen, 02185 float ycen, 02186 float rad, 02187 float startang, 02188 float angextent) 02189 { 02190 } 02191 02192 void 02193 fillarc(float xcen, 02194 float ycen, 02195 float rad, 02196 float startang, 02197 float angextent) 02198 { 02199 } 02200 02201 void 02202 drawtext(float xc, 02203 float yc, 02204 const char *text, 02205 float boundx) 02206 { 02207 } 02208 void 02209 clearscreen(void) 02210 { 02211 } 02212 02213 void 02214 create_button(char *prev_button_text, 02215 char *button_text, 02216 void (*button_func) (void (*drawscreen) (void))) 02217 { 02218 } 02219 02220 void 02221 destroy_button(char *button_text) 02222 { 02223 } 02224 02225 int 02226 init_postscript(char *fname) 02227 { 02228 return (1); 02229 } 02230 02231 void 02232 close_postscript(void) 02233 { 02234 } 02235 02236 #endif