📄 graphics.c
字号:
turn_on_off(ON); while(1) { XNextEvent(display, &report); switch (report.type) { case Expose:#ifdef VERBOSE printf("Got an expose event.\n"); printf("Count is: %d.\n", report.xexpose.count); printf("Window ID is: %d.\n", report.xexpose.window);#endif if(report.xexpose.count != 0) break; if(report.xexpose.window == menu) drawmenu(); else if(report.xexpose.window == toplevel) drawscreen(); else if(report.xexpose.window == textarea) draw_message(); break; case ConfigureNotify: top_width = report.xconfigure.width; top_height = report.xconfigure.height; update_transform();#ifdef VERBOSE printf("Got a ConfigureNotify.\n"); printf("New width: %d New height: %d.\n", top_width, top_height);#endif break; case ButtonPress:#ifdef VERBOSE printf("Got a buttonpress.\n"); printf("Window ID is: %d.\n", report.xbutton.window);#endif if(report.xbutton.window == toplevel) { x = XTOWORLD(report.xbutton.x); y = YTOWORLD(report.xbutton.y); act_on_button(x, y); } else { /* A menu button was pressed. */ bnum = which_button(report.xbutton.window);#ifdef VERBOSE printf("Button number is %d\n", bnum);#endif button[bnum].ispressed = 1; drawbut(bnum); XFlush(display); /* Flash the button */ button[bnum].fcn(drawscreen); button[bnum].ispressed = 0; drawbut(bnum); if(button[bnum].fcn == proceed) { turn_on_off(OFF); flushinput(); return; /* Rather clumsy way of returning * * control to the simulator */ } } break; } }}voidclearscreen(void){ int savecolor; if(disp_type == SCREEN) { XClearWindow(display, toplevel); } else {/* erases current page. Don't use erasepage, since this will erase * * everything, (even stuff outside the clipping path) causing * * problems if this picture is incorporated into a larger document. */ savecolor = currentcolor; setcolor(WHITE); fprintf(ps, "clippath fill\n\n"); setcolor(savecolor); }}static intrect_off_screen(float x1, float y1, float x2, float y2){/* Return 1 if I can quarantee no part of this rectangle will * * lie within the user drawing area. Otherwise return 0. * * Note: this routine is only used to help speed (and to shrink ps * * files) -- it will be highly effective when the graphics are zoomed * * in and lots are off-screen. I don't have to pre-clip for * * correctness. */ float xmin, xmax, ymin, ymax; xmin = min(xleft, xright); if(x1 < xmin && x2 < xmin) return (1); xmax = max(xleft, xright); if(x1 > xmax && x2 > xmax) return (1); ymin = min(ytop, ybot); if(y1 < ymin && y2 < ymin) return (1); ymax = max(ytop, ybot); if(y1 > ymax && y2 > ymax) return (1); return (0);}voiddrawline(float x1, float y1, float x2, float y2){/* Draw a line from (x1,y1) to (x2,y2) in the user-drawable area. * * Coordinates are in world (user) space. */ if(rect_off_screen(x1, y1, x2, y2)) return; if(disp_type == SCREEN) { /* Xlib.h prototype has x2 and y1 mixed up. */ XDrawLine(display, toplevel, gc, xcoord(x1), ycoord(y1), xcoord(x2), ycoord(y2)); } else { fprintf(ps, "%.2f %.2f %.2f %.2f drawline\n", XPOST(x1), YPOST(y1), XPOST(x2), YPOST(y2)); }}voiddrawrect(float x1, float y1, float x2, float y2){/* (x1,y1) and (x2,y2) are diagonally opposed corners, in world coords. */ unsigned int width, height; int xw1, yw1, xw2, yw2, xl, yt; if(rect_off_screen(x1, y1, x2, y2)) return; if(disp_type == SCREEN) {/* translate to X Windows calling convention. */ xw1 = xcoord(x1); xw2 = xcoord(x2); yw1 = ycoord(y1); yw2 = ycoord(y2); xl = min(xw1, xw2); yt = min(yw1, yw2); width = abs(xw1 - xw2); height = abs(yw1 - yw2); XDrawRectangle(display, toplevel, gc, xl, yt, width, height); } else { fprintf(ps, "%.2f %.2f %.2f %.2f drawrect\n", XPOST(x1), YPOST(y1), XPOST(x2), YPOST(y2)); }}voidfillrect(float x1, float y1, float x2, float y2){/* (x1,y1) and (x2,y2) are diagonally opposed corners in world coords. */ unsigned int width, height; int xw1, yw1, xw2, yw2, xl, yt; if(rect_off_screen(x1, y1, x2, y2)) return; if(disp_type == SCREEN) {/* translate to X Windows calling convention. */ xw1 = xcoord(x1); xw2 = xcoord(x2); yw1 = ycoord(y1); yw2 = ycoord(y2); xl = min(xw1, xw2); yt = min(yw1, yw2); width = abs(xw1 - xw2); height = abs(yw1 - yw2); XFillRectangle(display, toplevel, gc, xl, yt, width, height); } else { fprintf(ps, "%.2f %.2f %.2f %.2f fillrect\n", XPOST(x1), YPOST(y1), XPOST(x2), YPOST(y2)); }}static floatangnorm(float ang){/* Normalizes an angle to be between 0 and 360 degrees. */ int scale; if(ang < 0) { scale = (int)(ang / 360. - 1); } else { scale = (int)(ang / 360.); } ang = ang - scale * 360.; return (ang);}voiddrawarc(float xc, float yc, float rad, float startang, float angextent){/* Draws a circular arc. X11 can do elliptical arcs quite simply, and * * PostScript could do them by scaling the coordinate axes. Too much * * work for now, and probably too complex an object for users to draw * * much, so I'm just doing circular arcs. Startang is relative to the * * Window's positive x direction. Angles in degrees. */ int xl, yt; unsigned int width, height;/* Conservative (but fast) clip test -- check containing rectangle of * * a circle. */ if(rect_off_screen(xc - rad, yc - rad, xc + rad, yc + rad)) return;/* X Windows has trouble with very large angles. (Over 360). * * Do following to prevent its inaccurate (overflow?) problems. */ if(fabs(angextent) > 360.) angextent = 360.; startang = angnorm(startang); if(disp_type == SCREEN) { xl = (int)(xcoord(xc) - fabs(xmult * rad)); yt = (int)(ycoord(yc) - fabs(ymult * rad)); width = (unsigned int)(2 * fabs(xmult * rad)); height = width; XDrawArc(display, toplevel, gc, xl, yt, width, height, (int)(startang * 64), (int)(angextent * 64)); } else { fprintf(ps, "%.2f %.2f %.2f %.2f %.2f %s stroke\n", XPOST(xc), YPOST(yc), fabs(rad * ps_xmult), startang, startang + angextent, (angextent < 0) ? "drawarcn" : "drawarc"); }}voidfillarc(float xc, float yc, float rad, float startang, float angextent){/* Fills a circular arc. Startang is relative to the Window's positive x * * direction. Angles in degrees. */ int xl, yt; unsigned int width, height;/* Conservative (but fast) clip test -- check containing rectangle of * * a circle. */ if(rect_off_screen(xc - rad, yc - rad, xc + rad, yc + rad)) return;/* X Windows has trouble with very large angles. (Over 360). * * Do following to prevent its inaccurate (overflow?) problems. */ if(fabs(angextent) > 360.) angextent = 360.; startang = angnorm(startang); if(disp_type == SCREEN) { xl = (int)(xcoord(xc) - fabs(xmult * rad)); yt = (int)(ycoord(yc) - fabs(ymult * rad)); width = (unsigned int)(2 * fabs(xmult * rad)); height = width; XFillArc(display, toplevel, gc, xl, yt, width, height, (int)(startang * 64), (int)(angextent * 64)); } else { fprintf(ps, "%.2f %.2f %.2f %.2f %.2f %s\n", fabs(rad * ps_xmult), startang, startang + angextent, XPOST(xc), YPOST(yc), (angextent < 0) ? "fillarcn" : "fillarc"); }}voidfillpoly(t_point * points, int npoints){ XPoint transpoints[MAXPTS]; int i; float xmin, ymin, xmax, ymax; if(npoints > MAXPTS) { printf ("Error in fillpoly: Only %d points allowed per polygon.\n", MAXPTS); printf("%d points were requested. Polygon is not drawn.\n", npoints); return; }/* Conservative (but fast) clip test -- check containing rectangle of * * polygon. */ xmin = xmax = points[0].x; ymin = ymax = points[0].y; for(i = 1; i < npoints; i++) { xmin = min(xmin, points[i].x); xmax = max(xmax, points[i].x); ymin = min(ymin, points[i].y); ymax = max(ymax, points[i].y); } if(rect_off_screen(xmin, ymin, xmax, ymax)) return; if(disp_type == SCREEN) { for(i = 0; i < npoints; i++) { transpoints[i].x = (short)xcoord(points[i].x); transpoints[i].y = (short)ycoord(points[i].y); } XFillPolygon(display, toplevel, gc, transpoints, npoints, Complex, CoordModeOrigin); } else { fprintf(ps, "\n"); for(i = npoints - 1; i >= 0; i--) fprintf(ps, "%.2f %.2f\n", XPOST(points[i].x), YPOST(points[i].y)); fprintf(ps, "%d fillpoly\n", npoints); }}voiddrawtext(float xc, float yc, const char *text, float boundx){/* Draws text centered on xc,yc if it fits in boundx */ int len, width, xw_off, yw_off; len = strlen(text); width = XTextWidth(font_info[currentfontsize], text, len); if(width > fabs(boundx * xmult)) return; /* Don't draw if it won't fit */ xw_off = width / (2. * xmult); /* NB: sign doesn't matter. *//* NB: 2 * descent makes this slightly conservative but simplifies code. */ yw_off = (font_info[currentfontsize]->ascent + 2 * font_info[currentfontsize]->descent) / (2. * ymult);/* Note: text can be clipped when a little bit of it would be visible * * right now. Perhaps X doesn't return extremely accurate width and * * ascent values, etc? Could remove this completely by multiplying * * xw_off and yw_off by, 1.2 or 1.5. */ if(rect_off_screen(xc - xw_off, yc - yw_off, xc + xw_off, yc + yw_off)) return; if(disp_type == SCREEN) { XDrawString(display, toplevel, gc, xcoord(xc) - width / 2, ycoord(yc) + (font_info[currentfontsize]->ascent - font_info[currentfontsize]->descent) / 2, text, len); } else { fprintf(ps, "(%s) %.2f %.2f censhow\n", text, XPOST(xc), YPOST(yc)); }}voidflushinput(void){ if(disp_type != SCREEN) return; XFlush(display);}voidinit_world(float x1, float y1, float x2, float y2){/* Sets the coordinate system the user wants to draw into. */ xleft = x1; xright = x2; ytop = y1; ybot = y2; saved_xleft = xleft; /* Save initial world coordinates to allow full */ saved_xright = xright; /* view button to zoom all the way out. */ saved_ytop = ytop; saved_ybot = ybot; if(disp_type == SCREEN) { update_transform(); } else { update_ps_transform(); }}voiddraw_message(void){/* Draw the current message in the text area at the screen bottom. */ int len, width, savefontsize, savecolor; float ylow; if(disp_type == SCREEN) { XClearWindow(display, textarea); len = strlen(message); width = XTextWidth(font_info[menu_font_size], message, len); XSetForeground(display, gc_menus, colors[BLACK]); XDrawString(display, textarea, gc_menus, (top_width - MWIDTH - width) / 2, (T_AREA_HEIGHT - 4) / 2 + (font_info[menu_font_size]->ascent - font_info[menu_font_size]->descent) / 2, message, len); } else {/* Draw the message in the bottom margin. Printer's generally can't * * print on the bottom 1/4" (area with y < 18 in PostScript coords.) */ savecolor = currentcolor; setcolor(BLACK); savefontsize = currentfontsize; setfontsize(menu_font_size - 2); /* Smaller OK on paper */ ylow = ps_bot - 8.; fprintf(ps, "(%s) %.2f %.2f censhow\n", message, (ps_left + ps_right) / 2., ylow); setcolor(savecolor); setfontsize(savefontsize); }}voidupdate_message(char *msg){/* Changes the message to be displayed on screen. */ my_strncpy(message, msg, BUFSIZE); draw_message();}static voidzoom_in(void (*drawscreen) (void)){/* Zooms in by a factor of 1.666. */ float xdiff, ydiff; xdiff = xright - xleft; ydiff = ybot - ytop; xleft += xdiff / 5.; xright -= xdiff / 5.; ytop += ydiff / 5.; ybot -= ydiff / 5.; update_transform(); drawscreen();}static voidzoom_out(void (*drawscreen) (void)){/* Zooms out by a factor of 1.666. */ float xdiff, ydiff; xdiff = xright - xleft; ydiff = ybot - ytop; xleft -= xdiff / 3.;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -