📄 gview.c
字号:
r.min.x = screen->r.max.x - rt_border + framewd; r.max.y = y0 + dy; r.max.x = screen->r.max.x; for (i=0; i<n; i++) { draw(screen, r, clrtab[i].im, display->opaque, r.min); r.min.y = r.max.y; r.max.y += dy; } return dy;}Image* palette_color(Point pt, int dy, int n){ /* mouse at pt, patch size dy, n colors */ int yy; if (screen->r.max.x - pt.x > rt_border - framewd) return 0; yy = pt.y - (screen->r.min.y + top_border); if (yy<0 || yy>=n*dy) return 0; return clrtab[yy/dy].im;}void all_set_clr(fpolygons* fps, Image* clr){ fpolygon* p; for (p=fps->p; p!=0; p=p->link) p->clr = clr;} void do_recolor(int but, Mouse* m, int alluniv){ int nclr = clr_id(DWhite); int dy = draw_palette(nclr); Image* clr; if (!get_1click(but, m, 0)) { eresized(0); return; } clr = palette_color(m->xy, dy, nclr); if (clr != 0) { if (alluniv) all_set_clr(&univ, clr); else cur_sel.fp->clr = clr; } eresized(0); lift_button(but, m, Never);}/****************************** Move and rotate ******************************/void prepare_mv(const fpolygon* fp){ Rectangle r = screen->r; Image* scr0; int dt = 1 + fp->thick; r.min.x+=lft_border-dt; r.min.y+=top_border-dt; r.max.x-=rt_border-dt; r.max.y-=bot_border-dt; if (mv_bkgd!=0 && mv_bkgd->repl==0) freeimage(mv_bkgd); mv_bkgd = allocimage(display, r, CMAP8, 0, DNofill); if (mv_bkgd==0) mv_bkgd = display->white; else { transform tr = cur_trans(); draw(mv_bkgd, r, screen, display->opaque, r.min); draw(mv_bkgd, sel_dot_box(&tr), sel_bkg, display->opaque, ZP); scr0 = screen; screen = mv_bkgd; draw_fpoly(fp, &tr, display->white); screen = scr0; }}void move_fp(fpolygon* fp, double dx, double dy){ fpoint *p, *pn=fp->p+fp->n; for (p=fp->p; p<=pn; p++) { (p->x) += dx; (p->y) += dy; } (fp->bb.min.x)+=dx; (fp->bb.min.y)+=dy; (fp->bb.max.x)+=dx; (fp->bb.max.y)+=dy;}void rotate_fp(fpolygon* fp, fpoint o, double theta){ double s=sin(theta), c=cos(theta); fpoint *p, *pn=fp->p+fp->n; for (p=fp->p; p<=pn; p++) { double x=p->x-o.x, y=p->y-o.y; (p->x) = o.x + c*x - s*y; (p->y) = o.y + s*x + c*y; } set_fbb(fp);}/* Move the selected fpolygon so the selected point tracks the mouse, and return the total amount of movement. Button but has already been held down for at least Mv_delay milliseconds and the mouse might have moved some distance.*/fpoint do_move(int but, Mouse* m){ transform tr = cur_trans(); int bbit = Button_bit(but); fpolygon* fp = cur_sel.fp; fpoint loc, loc0=cur_sel.p; double tsav = cur_sel.t; unselect(&tr); do { latest_mouse(but, m); (fp->thick)++; /* line() DISAGREES WITH ITSELF */ draw_fpoly(fp, &tr, mv_bkgd); (fp->thick)--; do_untransform(&loc, &tr, &m->xy); move_fp(fp, loc.x-cur_sel.p.x, loc.y-cur_sel.p.y); cur_sel.p = loc; draw_fpoly(fp, &tr, fp->clr); } while (m->buttons & bbit); cur_sel.t = tsav; reselect(&tr); loc.x -= loc0.x; loc.y -= loc0.y; return loc;}double dir_angle(const Point* pt, const transform* tr){ fpoint p; double dy, dx; do_untransform(&p, tr, pt); dy=p.y-cur_sel.p.y; dx=p.x-cur_sel.p.x; return (dx==0 && dy==0) ? 0.0 : atan2(dy, dx);}/* Rotate the selected fpolygon around the selection point so as to track the direction angle from the selected point to m->xy. Stop when button but goes up and return the total amount of rotation in radians.*/double do_rotate(int but, Mouse* m){ transform tr = cur_trans(); int bbit = Button_bit(but); fpolygon* fp = cur_sel.fp; double theta0 = dir_angle(&m->xy, &tr); double th, theta = theta0; do { latest_mouse(but, m); (fp->thick)++; /* line() DISAGREES WITH ITSELF */ draw_fpoly(fp, &tr, mv_bkgd); (fp->thick)--; th = dir_angle(&m->xy, &tr); rotate_fp(fp, cur_sel.p, th-theta); theta = th; draw_fpoly(fp, &tr, fp->clr); } while (m->buttons & bbit); unselect(&tr); cur_sel = prev_sel; reselect(&tr); return theta - theta0;}/********************************* Edit menu *********************************/typedef enum e_index { Erecolor, Ethick, Edelete, Eundo, Erotate, Eoptions, Emove} e_index;char* e_items[Eoptions+1];Menu e_menu = {e_items, 0, 0};typedef struct e_action { e_index typ; /* What type of action */ fpolygon* fp; /* fpolygon the action applies to */ Image* clr; /* color to use if typ==Erecolor */ double amt; /* rotation angle or line thickness */ fpoint pt; /* movement vector or rotation center */ struct e_action* link; /* next in a stack */} e_action;e_action* unact = 0; /* heads a linked list of actions */e_action* do_undo(e_action*); /* pop off an e_action and (un)do it */e_action* save_act(e_action*,e_index); /* append new e_action for status quo */void save_mv(fpoint movement){ unact = save_act(unact, Emove); unact->pt = movement;}void init_e_menu(void){ char* u = "can't undo"; e_items[Erecolor] = "recolor"; e_items[Edelete] = "delete"; e_items[Erotate] = "rotate"; e_items[Eoptions-cantmv] = 0; e_items[Ethick] = (cur_sel.fp->thick >0) ? "thin" : "thick"; if (unact!=0) switch (unact->typ) { case Erecolor: u="uncolor"; break; case Ethick: u=(unact->fp->thick==0) ? "unthin" : "unthicken"; break; case Edelete: u="undelete"; break; case Emove: u="unmove"; break; case Erotate: u="unrotate"; break; } e_items[Eundo] = u;}void do_emenu(int but, Mouse* m){ int h; if (cur_sel.t < 0) return; init_e_menu(); h = emenuhit(but, m, &e_menu); switch(h) { case Ethick: unact = save_act(unact, h); cur_sel.fp->thick ^= 1; eresized(0); break; case Edelete: unact = save_act(unact, h); fp_remove(&univ, cur_sel.fp); unselect(0); eresized(0); break; case Erecolor: unact = save_act(unact, h); do_recolor(but, m, 0); break; case Erotate: unact = save_act(unact, h); prepare_mv(cur_sel.fp); if (get_1click(but, m, 0)) { unact->pt = cur_sel.p; unact->amt = do_rotate(but, m); } break; case Eundo: unact = do_undo(unact); break; }}/******************************* Undoing edits *******************************/e_action* save_act(e_action* a0, e_index typ){ /* append new e_action for status quo */ e_action* a = malloc(sizeof(e_action)); a->link = a0; a->pt.x = a->pt.y = 0.0; a->amt = cur_sel.fp->thick; a->clr = cur_sel.fp->clr; a->fp = cur_sel.fp; a->typ = typ; return a;}/* This would be trivial except it's nice to preserve the selection in order to make it easy to undo a series of moves. (There's no do_unrotate() because it's harder and less important to preserve the selection in that case.)*/void do_unmove(e_action* a){ double tsav = cur_sel.t; unselect(0); move_fp(a->fp, -a->pt.x, -a->pt.y); if (a->fp == cur_sel.fp) { cur_sel.p.x -= a->pt.x; cur_sel.p.y -= a->pt.y; } cur_sel.t = tsav; reselect(0);}e_action* do_undo(e_action* a0) /* pop off an e_action and (un)do it */{ e_action* a = a0; if (a==0) return 0; switch(a->typ) { case Ethick: a->fp->thick = a->amt; eresized(0); break; case Erecolor: a->fp->clr = a->clr; eresized(0); break; case Edelete: a->fp->link = univ.p; univ.p = a->fp; grow_bb(&univ.bb, &a->fp->bb); eresized(0); break; case Emove: do_unmove(a); eresized(0); break; case Erotate: unselect(0); rotate_fp(a->fp, a->pt, -a->amt); eresized(0); break; } a0 = a->link; free(a); return a0;}/********************************* Main menu *********************************/enum m_index { Mzoom_in, Mzoom_out, Munzoom, Mslant, Munslant, Msquare_up, Mrecenter, Mrecolor, Mrestack, Mread, Mwrite, Mexit};char* m_items[] = {"zoom in", "zoom out", "unzoom", "slant", "unslant", "square up", "recenter", "recolor", "restack", "read", "write", "exit", 0};Menu m_menu = {m_items, 0, 0};void do_mmenu(int but, Mouse* m){ int e, h = emenuhit(but, m, &m_menu); switch (h) { case Mzoom_in: disp_zoomin(egetrect(but,m)); eresized(0); break; case Mzoom_out: disp_zoomout(egetrect(but,m)); eresized(0); break; case Msquare_up: disp_squareup(); eresized(0); break; case Munzoom: init_disp(); eresized(0); break; case Mrecenter: if (get_1click(but, m, &bullseye)) { recenter_disp(m->xy); eresized(0); lift_button(but, m, Never); } break; case Mslant: if (cur_sel.t>=0 && prev_sel.t>=0) { slant_disp(prev_sel.p, cur_sel.p); eresized(0); } break; case Munslant: univ.slant_ht = univ.disp.max.y - univ.disp.min.y; eresized(0); break; case Mrecolor: do_recolor(but, m, 1); break; case Mrestack: fps_invert(&univ); eresized(0); break; case Mread: e = doinput(prompt_text("File:")); if (e==0) eresized(0); else if (e<0) show_mytext(" - can't read"); else { char ebuf[80]; snprintf(ebuf, 80, " - error line %d", e); show_mytext(ebuf); } break; case Mwrite: if (!dooutput(prompt_text("File:"))) show_mytext(" - can't write"); break; case Mexit: exits(""); }}/****************************** Handling events ******************************/void doevent(void){ ulong etype; int mobile; ulong mvtime; Event ev; etype = eread(Emouse|Ekeyboard, &ev); if(etype & Emouse) { if (ev.mouse.buttons & But1) { do_select(ev.mouse.xy); mvtime = Never; mobile = !cantmv && cur_sel.t>=0; if (mobile) { mvtime = ev.mouse.msec + Mv_delay; prepare_mv(cur_sel.fp); } if (!lift_button(1, &ev.mouse, mvtime) && mobile) save_mv(do_move(1, &ev.mouse)); } else if (ev.mouse.buttons & But2) do_emenu(2, &ev.mouse); else if (ev.mouse.buttons & But3) do_mmenu(3, &ev.mouse); } /* no need to check (etype & Ekeyboard)--there are no keyboard commands */}/******************************** Main program ********************************/extern char* argv0;void usage(void){ int i; fprintf(stderr,"Usage %s [options] [infile]\n", argv0); fprintf(stderr,"option ::= -l logfile | -m | -p\n""\n""Read a polygonal line graph in an ASCII format (one x y pair per line, delimited\n""by spaces with a label after each polyline), and view it interactively. Use\n""standard input if no infile is specified.\n""Option -l specifies a file in which to log the coordinates of each point selected.\n""(Clicking a point with button one selects it and displays its coordinates and\n""the label of its polylone.) Option -m allows polylines to be moved and rotated.\n""The -p option plots only the vertices of the polygons.\n""The polyline labels can use the following color names:" ); for (i=0; clrtab[i].c!=DNofill; i++) fprintf(stderr,"%s%8s", (i%8==0 ? "\n" : " "), clrtab[i].nam); fputc('\n', stderr); exits("usage");}void main(int argc, char *argv[]){ int e; ARGBEGIN { case 'm': cantmv=0; break; case 'l': logfil = fopen(ARGF(),"w"); break; case 'p': plotdots++; break; default: usage(); } ARGEND; if(initdraw(0, 0, "gview") < 0) exits("initdraw"); einit(Emouse|Ekeyboard); do { e = doinput(*argv ? *argv : "-"); if (e < 0) { fprintf(stderr,"Cannot read input file %s\n", *argv); exits("no valid input file"); } else if (e > 0) { fprintf(stderr,"Bad syntax at line %d of file %s\n", e, *argv ? *argv : "-"); exits("bad syntax in input"); } } while (*argv && *++argv); init_disp(); init_clrtab(); set_default_clrs(&univ, 0); adjust_border(display->defaultfont); cur_sel.t = prev_sel.t = -1; eresized(0); for(;;) doevent();}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -