📄 graphics.c
字号:
#include <math.h>#include <stdlib.h>#include <stdio.h>#include <string.h>#include "util.h"#include "graphics.h"#include "vpr_types.h"/*#include "draw.h" */#ifndef NO_GRAPHICS#include <X11/Xlib.h>#include <X11/Xutil.h>#include <X11/Xos.h>#include <X11/Xatom.h>#endif/* Written by Vaughn Betz at the University of Toronto, Department of * * Electrical and Computer Engineering. Graphics package Version 1.3. * * All rights reserved by U of T, etc. * * * * You may freely use this graphics interface for non-commercial purposes * * as long as you leave the written by Vaughn Betz message in it -- who * * knows, maybe someday an employer will see it and give me a job or large * * sums of money :). * * * * Revision History: * * * * Sept. 19, 1997: Incorporated Zoom Fit code of Haneef Mohammed at * * Cypress. Makes it easy to zoom to a full view of the graphics. * * * * Sept. 11, 1997: Added the create_button and delete_button interface to * * make it easy to add and destroy buttons from user code. Removed the * * bnum parameter to the button functions, since it wasn't really needed. * * * * June 28, 1997: Added filled arc drawing primitive. Minor modifications * * to PostScript driver to make the PostScript output slightly smaller. * * * * April 15, 1997: Added code to init_graphics so it waits for a window * * to be exposed before returning. This ensures that users of non- * * interactive graphics can never draw to a window before it is available. * * * * Feb. 24, 1997: Added code so the package will allocate a private * * colormap if the default colormap doesn't have enough free colours. * * * * June 28, 1996: Converted all internal functions in graphics.c to have * * internal (static) linkage to avoid any conflicts with user routines in * * the rest of the program. * * * * June 12, 1996: Added setfontsize and setlinewidth attributes. Added * * pre-clipping of objects for speed (and compactness of PS output) when * * graphics are zoomed in. Rewrote PostScript engine to shrink the output * * and make it easier to read. Made drawscreen a callback function passed * * in rather than a global. Graphics attribute calls are more efficient -- * * they check if they have to change anything before doing it. * * * * October 27, 1995: Added the message area, a callback function for * * interacting with user button clicks, and implemented a workaround for a * * Sun X Server bug that misdisplays extremely highly zoomed graphics. * * * * Jan. 13, 1995: Modified to incorporate PostScript Support. *//****************** Types and defines local to this module ******************/#ifndef NO_GRAPHICS/* Uncomment the line below if your X11 header files don't define XPointer *//* typedef char *XPointer; *//* Macros for translation from world to PostScript coordinates */#define XPOST(worldx) (((worldx)-xleft)*ps_xmult + ps_left)#define YPOST(worldy) (((worldy)-ybot)*ps_ymult + ps_bot)/* Macros to convert from X Windows Internal Coordinates to my * * World Coordinates. (This macro is used only rarely, so * * the divides don't hurt speed). */#define XTOWORLD(x) (((float) x)/xmult + xleft)#define YTOWORLD(y) (((float) y)/ymult + ytop)#define max(a,b) (((a) > (b))? (a) : (b))#define min(a,b) ((a) > (b)? (b) : (a))#define MWIDTH 104 /* width of menu window */#define T_AREA_HEIGHT 24 /* Height of text window */#define MAX_FONT_SIZE 40 /* Largest point size of text */#define PI 3.141592654#define BUTTON_TEXT_LEN 20typedef struct{ int width; int height; int xleft; int ytop; void (*fcn) (void (*drawscreen) (void)); Window win; int istext; char text[BUTTON_TEXT_LEN]; int ispoly; int poly[3][2]; int ispressed;}t_button;/********************* Static variables local to this module ****************/static const int menu_font_size = 14; /* Font for menus and dialog boxes. */static t_button *button; /* [0..num_buttons-1] */static int num_buttons; /* Number of menu buttons */static int disp_type; /* Selects SCREEN or POSTSCRIPT */static Display *display;static int screen_num;static GC gc, gcxor, gc_menus;static XFontStruct *font_info[MAX_FONT_SIZE + 1]; /* Data for each size */static int font_is_loaded[MAX_FONT_SIZE + 1]; /* 1: loaded, 0: not */static unsigned int display_width, display_height; /* screen size */static unsigned int top_width, top_height; /* window size */static Window toplevel, menu, textarea; /* various windows */static float xleft, xright, ytop, ybot; /* world coordinates *//* Initial world coordinates */static float saved_xleft, saved_xright, saved_ytop, saved_ybot;static float ps_left, ps_right, ps_top, ps_bot; /* Figure boundaries for * * * PostScript output, in PostScript coordinates. */static float ps_xmult, ps_ymult; /* Transformation for PostScript. */static float xmult, ymult; /* Transformation factors */static Colormap private_cmap; /* "None" unless a private cmap was allocated. *//* Graphics state. Set start-up defaults here. */static int currentcolor = BLACK;static int currentlinestyle = SOLID;static int currentlinewidth = 0;static int currentfontsize = 10;static char message[BUFSIZE] = "\0"; /* User message to display *//* Color indices passed back from X Windows. */static int colors[NUM_COLOR];/* For PostScript output */static FILE *ps;/* MAXPIXEL and MINPIXEL are set to prevent what appears to be * * overflow with very large pixel values on the Sun X Server. */#define MAXPIXEL 15000#define MINPIXEL -15000/********************** Subroutines local to this module ********************//* Function declarations for button responses */static void translate_up(void (*drawscreen) (void));static void translate_left(void (*drawscreen) (void));static void translate_right(void (*drawscreen) (void));static void translate_down(void (*drawscreen) (void));static void zoom_in(void (*drawscreen) (void));static void zoom_out(void (*drawscreen) (void));static void zoom_fit(void (*drawscreen) (void));static void adjustwin(void (*drawscreen) (void));static void postscript(void (*drawscreen) (void));static void proceed(void (*drawscreen) (void));static void quit(void (*drawscreen) (void));static Bool test_if_exposed(Display * disp, XEvent * event_ptr, XPointer dummy);static void map_button(int bnum);static void unmap_button(int bnum);/********************** Subroutine definitions ******************************/static intxcoord(float worldx){/* Translates from my internal coordinates to X Windows coordinates * * in the x direction. Add 0.5 at end for extra half-pixel accuracy. */ int winx; winx = (int)((worldx - xleft) * xmult + 0.5);/* Avoid overflow in the X Window routines. This will allow horizontal * * and vertical lines to be drawn correctly regardless of zooming, but * * will cause diagonal lines that go way off screen to change their * * slope as you zoom in. The only way I can think of to completely fix * * this problem is to do all the clipping in advance in floating point, * * then convert to integers and call X Windows. This is a lot of extra * * coding, and means that coordinates will be clipped twice, even though * * this "Super Zoom" problem won't occur unless users zoom way in on * * the graphics. */ winx = max(winx, MINPIXEL); winx = min(winx, MAXPIXEL); return (winx);}static intycoord(float worldy){/* Translates from my internal coordinates to X Windows coordinates * * in the y direction. Add 0.5 at end for extra half-pixel accuracy. */ int winy; winy = (int)((worldy - ytop) * ymult + 0.5);/* Avoid overflow in the X Window routines. */ winy = max(winy, MINPIXEL); winy = min(winy, MAXPIXEL); return (winy);}static voidload_font(int pointsize){/* Makes sure the font of the specified size is loaded. Point_size * * MUST be between 1 and MAX_FONT_SIZE -- no check is performed here. *//* Use proper point-size medium-weight upright helvetica font */ char fontname[44]; sprintf(fontname, "-*-helvetica-medium-r-*--*-%d0-*-*-*-*-*-*", pointsize);#ifdef VERBOSE printf("Loading font: point size: %d, fontname: %s\n", pointsize, fontname);#endif/* Load font and get font information structure. */ if((font_info[pointsize] = XLoadQueryFont(display, fontname)) == NULL) { fprintf(stderr, "Cannot open desired font\n"); exit(-1); }}static voidforce_setcolor(int cindex){ static char *ps_cnames[NUM_COLOR] = { "white", "black", "grey55", "grey75", "blue", "green", "yellow", "cyan", "red", "darkgreen", "magenta" }; currentcolor = cindex; if(disp_type == SCREEN) { XSetForeground(display, gc, colors[cindex]); } else { fprintf(ps, "%s\n", ps_cnames[cindex]); }}voidsetcolor(int cindex){ if(currentcolor != cindex) force_setcolor(cindex);}static voidforce_setlinestyle(int linestyle){/* Note SOLID is 0 and DASHED is 1 for linestyle. *//* PostScript and X commands needed, respectively. */ static char *ps_text[2] = { "linesolid", "linedashed" }; static int x_vals[2] = { LineSolid, LineOnOffDash }; currentlinestyle = linestyle; if(disp_type == SCREEN) { XSetLineAttributes(display, gc, currentlinewidth, x_vals[linestyle], CapButt, JoinMiter); } else { fprintf(ps, "%s\n", ps_text[linestyle]); }}voidsetlinestyle(int linestyle){ if(linestyle != currentlinestyle) force_setlinestyle(linestyle);}static voidforce_setlinewidth(int linewidth){/* linewidth should be greater than or equal to 0 to make any sense. *//* Note SOLID is 0 and DASHED is 1 for linestyle. */ static int x_vals[2] = { LineSolid, LineOnOffDash }; currentlinewidth = linewidth; if(disp_type == SCREEN) { XSetLineAttributes(display, gc, linewidth, x_vals[currentlinestyle], CapButt, JoinMiter); } else { fprintf(ps, "%d setlinewidth\n", linewidth); }}voidsetlinewidth(int linewidth){ if(linewidth != currentlinewidth) force_setlinewidth(linewidth);}static voidforce_setfontsize(int pointsize){/* Valid point sizes are between 1 and MAX_FONT_SIZE */ if(pointsize < 1) pointsize = 1; else if(pointsize > MAX_FONT_SIZE) pointsize = MAX_FONT_SIZE; currentfontsize = pointsize; if(disp_type == SCREEN) { if(!font_is_loaded[pointsize]) { load_font(pointsize); font_is_loaded[pointsize] = 1; } XSetFont(display, gc, font_info[pointsize]->fid); } else { /* PostScript: set up font and centering function */ fprintf(ps, "%d setfontsize\n", pointsize); }}voidsetfontsize(int pointsize){/* For efficiency, this routine doesn't do anything if no change is * * implied. If you want to force the graphics context or PS file * * to have font info set, call force_setfontsize (this is necessary * * in initialization and X11 / Postscript switches). */ if(pointsize != currentfontsize) force_setfontsize(pointsize);}static voidbuild_textarea(void){/* Creates a small window at the top of the graphics area for text messages */ XSetWindowAttributes menu_attributes; unsigned long valuemask; textarea = XCreateSimpleWindow(display, toplevel, 0, top_height - T_AREA_HEIGHT, display_width, T_AREA_HEIGHT - 4, 2, colors[BLACK], colors[LIGHTGREY]); menu_attributes.event_mask = ExposureMask; /* ButtonPresses in this area are ignored. */ menu_attributes.do_not_propagate_mask = ButtonPressMask; /* Keep text area on bottom left */ menu_attributes.win_gravity = SouthWestGravity; valuemask = CWWinGravity | CWEventMask | CWDontPropagate; XChangeWindowAttributes(display, textarea, valuemask, &menu_attributes); XMapWindow(display, textarea);}static voidsetpoly(int bnum, int xc, int yc, int r, float theta){/* Puts a triangle in the poly array for button[bnum] */ int i; button[bnum].istext = 0; button[bnum].ispoly = 1; for(i = 0; i < 3; i++) { button[bnum].poly[i][0] = (int)(xc + r * cos(theta) + 0.5); button[bnum].poly[i][1] = (int)(yc + r * sin(theta) + 0.5); theta += 2 * PI / 3; }}static voidbuild_default_menu(void){/* Sets up the default menu buttons on the right hand side of the window. */ XSetWindowAttributes menu_attributes; unsigned long valuemask; int i, xcen, x1, y1, bwid, bheight, space; menu = XCreateSimpleWindow(display, toplevel, top_width - MWIDTH, 0, MWIDTH - 4, display_height, 2, colors[BLACK], colors[LIGHTGREY]); menu_attributes.event_mask = ExposureMask; /* Ignore button presses on the menu background. */ menu_attributes.do_not_propagate_mask = ButtonPressMask; /* Keep menu on top right */ menu_attributes.win_gravity = NorthEastGravity; valuemask = CWWinGravity | CWEventMask | CWDontPropagate; XChangeWindowAttributes(display, menu, valuemask, &menu_attributes); XMapWindow(display, menu); num_buttons = 11; button = (t_button *) my_malloc(num_buttons * sizeof(t_button));/* Now do the arrow buttons */ bwid = 28; space = 3; y1 = 10; xcen = 51; x1 = xcen - bwid / 2; button[0].xleft = x1; button[0].ytop = y1; setpoly(0, bwid / 2, bwid / 2, bwid / 3, -PI / 2.); /* Up */ button[0].fcn = translate_up; y1 += bwid + space; x1 = xcen - 3 * bwid / 2 - space; button[1].xleft = x1; button[1].ytop = y1; setpoly(1, bwid / 2, bwid / 2, bwid / 3, PI); /* Left */ button[1].fcn = translate_left; x1 = xcen + bwid / 2 + space; button[2].xleft = x1; button[2].ytop = y1; setpoly(2, bwid / 2, bwid / 2, bwid / 3, 0); /* Right */ button[2].fcn = translate_right; y1 += bwid + space; x1 = xcen - bwid / 2; button[3].xleft = x1; button[3].ytop = y1; setpoly(3, bwid / 2, bwid / 2, bwid / 3, +PI / 2.); /* Down */ button[3].fcn = translate_down; for(i = 0; i < 4; i++) { button[i].width = bwid; button[i].height = bwid; }/* Rectangular buttons */ y1 += bwid + space + 6; space = 8; bwid = 90; bheight = 26; x1 = xcen - bwid / 2; for(i = 4; i < num_buttons; i++) { button[i].xleft = x1; button[i].ytop = y1; y1 += bheight + space; button[i].istext = 1; button[i].ispoly = 0; button[i].width = bwid; button[i].height = bheight; } strcpy(button[4].text, "Zoom In"); strcpy(button[5].text, "Zoom Out"); strcpy(button[6].text, "Zoom Fit"); strcpy(button[7].text, "Window"); strcpy(button[8].text, "PostScript"); strcpy(button[9].text, "Proceed"); strcpy(button[10].text, "Exit"); button[4].fcn = zoom_in; button[5].fcn = zoom_out; button[6].fcn = zoom_fit; button[7].fcn = adjustwin; button[8].fcn = postscript; button[9].fcn = proceed; button[10].fcn = quit; for(i = 0; i < num_buttons; i++) map_button(i);}static voidmap_button(int bnum){/* Maps a button onto the screen and set it up for input, etc. */ button[bnum].win = XCreateSimpleWindow(display, menu, button[bnum].xleft, button[bnum].ytop, button[bnum].width, button[bnum].height, 0, colors[WHITE], colors[LIGHTGREY]);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -