#include <suntool/sunview.h> #include <suntool/canvas.h> #include <fcntl.h> /* from jerq.h... */ typedef struct Point { short x; short y; } Point; int muldiv(x,y,d) { return (x * y) / d; } Point pt(x, y) { Point p; p.x = x; p.y = y; return p; } Point Pt(x, y) { Point p; p.x = x; p.y = y; return p; } Point add(p1, p2) Point p1, p2; { p1.x += p2.x; p1.y += p2.y; return p1; } Point sub(p1, p2) Point p1, p2; { p1.x -= p2.x; p1.y -= p2.y; return p1; } typedef struct Rectangle { Point origin; Point corner; } Rectangle; Rectangle raddp(r, p) Rectangle r; Point p; { r.origin = add(r.origin, p); r.corner = add(r.corner, p); return r; } Rectangle Rpt(p1,p2) Point p1, p2; { Rectangle r; r.origin.x = p1.x; r.origin.y = p1.y; r.corner.x = p2.x; r.corner.y = p2.y; return r; } Rectangle Rect4(x1,y1,x2,y2) { Rectangle r; r.origin.x = x1; r.origin.y = y1; r.corner.x = x2; r.corner.y = y2; return r; } Rectangle inset(r, n) Rectangle r; { r.origin.x += n; r.origin.y += n; r.corner.x -= n; r.corner.y -= n; return r; } int eqpt(p1, p2) Point p1, p2; { return p1.x == p2.x && p1.y == p2.y; } Rectangle Drect; #define Do Drect.origin #define Dc Drect.corner Rectangle getrect23(); Rectangle display; /* not used */ int defont; /* bitblt function codes */ #define F_STORE (PIX_SRC) /* target = source */ #define F_OR (PIX_SRC|PIX_DST) /* target |= source */ #define F_CLR (PIX_NOT(PIX_SRC)&(PIX_DST)) /* target &= ~source */ #define F_XOR (PIX_SRC^PIX_DST) /* target ^= source */ Cursor *cursor,normalcursor,bullseye,coffeecup,sweep,deadmouse,lockarrow; #include "anim.h" typedef unsigned char uchar; #define PUT { char buf[100]; sprintf(buf, #define END ); putstring(buf); } #define readpoint(p) { p.x = readint(); p.y = readint(); } #define readpair(p1,p2) { readpoint(p1); readpoint(p2); } /* holds data for all input objects */ unsigned memsize; /* bytes */ uchar *inbuf; /* input collected here */ uchar *input; /* leave a null at front */ uchar *inp; /* next free slot in input */ int nobj = 0; /* number of objects in input */ int overflow = 0; /* 1 => too much input */ long slot[2000]; /* slots */ int slotnum; extern uchar *savechar(), *draw_obj(), *click_obj(), *step_obj(); extern uchar *prev_obj(), *next_obj(); extern Point readpt(), fetchpt(), scalept(); int xmax, ymax; #define MAXVIEW 10 char *viewname[MAXVIEW]; typedef struct { Rectangle vr; int xmax; int ymax; } View; View viewpt[MAXVIEW]; int curview = 0; int nview = 0; #define INSET 4 /* picture inset from frame */ #define AW 8 /* arrowhead width and height */ #define AH 10 #define MARGINPCT 6 int margin = MARGINPCT; /* percent margin around edges */ #define MAXCLICK 20 char *clickname[MAXCLICK]; /* click names */ int clickval[MAXCLICK]; /* 1 => click on this */ int clicking = 0; /* number of active clicks */ int nclick = 0; char buf[200]; char *pbuf; #define Again 0 /* Menu items -- must be 0.. */ #define Faster (Again+1) #define Slower (Faster+1) #define Step (Slower+1) #define Forward (Step+1) #define Fatter (Forward+1) #define Thinner (Fatter+1) #define Xor (Thinner+1) #define File (Xor+1) #define Quit (File+1) /* ... down this far */ #define Backward (Quit+1) /* subsequent names are arbitrary */ #define Proceed (Backward+1) #define Hit (Proceed+1) #define FreeRun (Hit+1) int delay = 1; /* how long to delay between things */ int singstep = 0; /* single step if 1 */ #define Fwd 1 #define Back 0 int dir = Fwd; /* 1 = fwd, 0 = backward */ int fatness = 0; /* n => draw with 2n+1 lines */ int xormode = F_XOR; /* otherwise OR/CLR */ char *m3[] = { "again", "faster", "slower", "1 step", "backward", "fatter", "thinner", "or mode", "new file", "Quit?", 0 }; char *stepmenu[] = { "1 step", "run" }; char *dirmenu[] = { "forward", "backward" }; char *modemenu[] = { "or mode", "xor mode" }; char *m3gen(n) { static char buf[20][20]; extern int delay; if (n < 0 || n > Quit) return 0; else if (n == Faster) { sprintf(buf[n], "faster %d", delay); return buf[n]; } else if (n == Slower) { sprintf(buf[n], "slower %d", delay); return buf[n]; } else if (n == Step) { return stepmenu[singstep]; } else if (n == Forward) { return dirmenu[dir]; } else if (n == Fatter) { sprintf(buf[n], "fatter %d", fatness+1); return buf[n]; } else if (n == Thinner) { sprintf(buf[n], "thinner %d", fatness+1); return buf[n]; } else if (n == Xor) { return xormode == F_XOR ? modemenu[0] : modemenu[1]; } else return m3[n]; } char *m2gen(n) { static char buf[20][50]; if (n < 0 || n >= nview+nclick) return 0; else if (n < nview) { sprintf(buf[n], "view %s", viewname[n]); return buf[n]; } else { sprintf(buf[n], "click %s%s", clickname[n-nview], clickval[n-nview] ? "*" : ""); return buf[n]; } } Menu mbut3; Menu mbut2; int last_hit; int last_but; void inevent(); Canvas canvas; Pixwin *pw; int canvasfd; int height, width; /* screen window */ init_params() { int i; for (i = 0; i < MAXCLICK; i++) if (clickname[i]) { free(clickname[i]); clickname[i] = 0; clickval[i] = 0; } for (i = 0; i < MAXVIEW; i++) if (viewname[i]) { free(viewname[i]); viewname[i] = 0; } nclick = nview = curview = nobj = clicking = overflow = slotnum = 0; } main() { int i, n; Frame baseframe; baseframe = window_create(NULL, FRAME, FRAME_LABEL, "Anim", WIN_ERROR_MSG, "Can't create Anim base window", 0); canvas = window_create(baseframe, CANVAS, 0); pw = canvas_pixwin(canvas); canvasfd = (int)window_get(canvas, WIN_FD); fcntl(canvasfd, F_SETFL, FNDELAY); /* allow nonblocking reads */ width = (int)window_get(canvas, CANVAS_WIDTH); height = (int)window_get(canvas, CANVAS_HEIGHT); Drect.origin = pt(0,0); Drect.corner = add(Drect.origin, pt(width,height)); do_rcv(); initmenus(); initcursors(); /* get these events by default: LOC_WINENTER, LOC_WINEXIT, LOC_MOVE, MS_LEFT, MS_MIDDLE, MS_RIGHT */ window_set(canvas, WIN_CONSUME_KBD_EVENT, WIN_ASCII_EVENTS, WIN_EVENT_PROC, inevent, 0); window_main_loop(baseframe); send1char(P_QUIT); /* tell host part we're done */ flushproto(); } initmenus() { int i; char *s; mbut2 = menu_create(MENU_DEFAULT, 1, 0); for (i = 0; s = m2gen(i); i++) menu_set(mbut2, MENU_STRING_ITEM, s, i+1, 0); mbut3 = menu_create(MENU_DEFAULT, 1, 0); for (i = 0; m3[i]; i++) menu_set(mbut3, MENU_STRING_ITEM, m3[i], i+1, 0); } char kbdline[100]; /* collect keyboard input here */ int kbdi = 0; /* kbdline index */ void inevent(c, e) Canvas c; Event *e; { int n, i, eid, ch; char *s; eid = event_id(e); switch (eid) { default: if (!event_is_ascii(e)) return; if (eid != '\n' && eid != '\r') { /* which do we get? */ if (eid == '\b' && kbdi > 0) kbdi--; else kbdline[kbdi++] = eid; kbdline[kbdi] = '\0'; putstring(kbdline); return; } kbdline[kbdi] = '\0'; kbdi = 0; /* now we have a filename */ send1char(P_FILE); sendstring(kbdline); if ((ch = readchar()) == P_FILE) { do_rcv(); } else { PUT "can't open file %s", kbdline END; } return; case WIN_RESIZE: /* doesn't do much right now */ width=(int)window_get(canvas, CANVAS_WIDTH); height=(int)window_get(canvas, CANVAS_HEIGHT); Drect.origin = pt(0,0); Drect.corner = add(Drect.origin, pt(width,height)); view_setup(nview); return; case MS_LEFT: /* button 1 */ if (event_is_up(e)) return; last_but = 1; last_hit = 0; n = domouse(); break; case MS_MIDDLE: if (event_is_up(e)) return; last_but = 2; last_hit = (int) menu_show(mbut2, canvas, e, 0) - 1; n = domouse(); for (i = 0; s = m2gen(i); i++) menu_set(menu_get(mbut2, MENU_NTH_ITEM, i+1), MENU_STRING, s, 0); if (last_hit >= 0) /* start with this selected next time */ menu_set(mbut2, MENU_DEFAULT, last_hit+1, 0); break; case MS_RIGHT: if (event_is_up(e)) return; last_but = 3; last_hit = (int) menu_show(mbut3, canvas, e, 0) - 1; n = domouse(); for (i = 0; s = m3gen(i); i++) menu_set(menu_get(mbut3, MENU_NTH_ITEM, i+1), MENU_STRING, s, 0); if (last_hit >= 0) /* start with this selected next time */ menu_set(mbut3, MENU_DEFAULT, last_hit+1, 0); break; } run_one(n); } run_one(n) { static uchar *ip; int i; char *s; Event ev; Event *e= &ev; again: if (ip == 0) { ip = dir == Fwd ? input : inp; clear(); } if (n == Quit) { window_done(canvas); return; } if (n == Hit) /* wait for another mouse hit */ return; if (n == Forward) { /* change from fwd to back -- fiddle ip */ ip = next_obj(ip); return; } if (n == Backward) { ip = prev_obj(ip); return; } if (n == File) { putstring("filename? "); return; } if (n == Again) { clear(); dir = Fwd; ip = input; } if (singstep) { if (clicking > 0) ip = click_obj(ip, xormode, dir); else ip = step_obj(ip, xormode, dir); } else { /* free running */ while (ip) { if (clicking > 0) ip = click_obj(ip, xormode, dir); else ip = step_obj(ip, xormode, dir); if (ip && window_read_event(canvas,e)==0) { /* this just about duplicates inevent */ switch (event_id(e)) { case WIN_RESIZE: width=(int)window_get(canvas, CANVAS_WIDTH); height=(int)window_get(canvas, CANVAS_HEIGHT); Drect.origin = pt(0,0); Drect.corner = add(Drect.origin, pt(width,height)); view_setup(nview); break; case WIN_REPAINT: pw_repairretained(pw); break; case MS_LEFT: /* button 1 */ if (event_is_up(e)) break; last_but = 1; last_hit = 0; return; /* interrupt run */ case MS_MIDDLE: if (event_is_up(e)) break; last_but = 2; last_hit = (int) menu_show(mbut2, canvas, e, 0) - 1; n = domouse(); for (i = 0; s = m2gen(i); i++) menu_set(menu_get(mbut2, MENU_NTH_ITEM, i+1), MENU_STRING, s, 0); if (last_hit >= 0) menu_set(mbut2, MENU_DEFAULT , last_hit+1, 0); goto again; case MS_RIGHT: if (event_is_up(e)) break; last_but = 3; last_hit = (int) menu_show(mbut3, canvas, e, 0) - 1; n = domouse(); for (i = 0; s = m3gen(i); i++) menu_set(menu_get(mbut3, MENU_NTH_ITEM, i+1), MENU_STRING, s, 0); if (last_hit >= 0) menu_set(mbut3, MENU_DEFAULT , last_hit+1, 0); goto again; } } sleephz(delay-1); } } } domouse() { int n; if (last_but == 1) return Proceed; if (last_but == 3) { switch (last_hit) { case Again: return Again; case Faster: if (delay > 1) delay /= 2; return Hit; case Slower: delay *= 2; return Hit; case Step: singstep = 1 - singstep; n = Step; return Hit; case Forward: dir = 1 - dir; if (xormode == F_OR) xormode = F_CLR; else if (xormode == F_CLR) xormode = F_OR; return dir == Fwd ? Forward : Backward; case Fatter: fatness++; return Hit; case Thinner: if (fatness > 0) fatness--; return Hit; case Xor: if (xormode == F_OR || xormode == F_CLR) xormode = F_XOR; else if (dir == Fwd) xormode = F_OR; else xormode = F_CLR; return Hit; case File: return File; case Quit: return Quit; default: return Hit; } } else if (last_but == 2) { Rectangle r, shrink(); if (last_hit == -1) return Hit; else if (last_hit < nview) { r = getrect23(); if (r.origin.x == 0 && r.corner.x == 0) /* bailed out */ return Hit; if (eqpt(r.origin, r.corner)) r = Drect; drawrect(inset(viewpt[last_hit].vr, -(INSET+fatness)), F_CLR); drawrect(r, F_OR); viewpt[last_hit].vr = r = inset(r, INSET+fatness); viewpt[last_hit].xmax = r.corner.x - r.origin.x; viewpt[last_hit].ymax = r.corner.y - r.origin.y; return Hit; } else { /* a click */ if (clickval[last_hit-nview]) { /* was on, so turn off */ clickval[last_hit-nview] = 0; clicking--; } else { clickval[last_hit-nview] = 1; clicking++; } return Hit; } } } Rectangle shrink(r, pct) /* shrink rectangle by 2*pct */ Rectangle r; { int dx = muldiv(r.corner.x-r.origin.x, pct, 100); int dy = muldiv(r.corner.y-r.origin.y, pct, 100); r.origin = add(r.origin, Pt(dx,dy)); r.corner = sub(r.corner, Pt(dx,dy)); return r; } view_setup(n) int n; { int i, dx, dy; dx = (Dc.x - Do.x) / 2; dy = (Dc.y - Do.y) / 2; viewpt[0].vr = Drect; switch (n) { case 2: viewpt[1].vr = Drect; viewpt[0].vr.corner.y -= dy; viewpt[1].vr.origin.y += dy; break; case 3: case 4: viewpt[0].vr.corner = add(Drect.origin, Pt(dx,dy)); viewpt[1].vr = raddp(viewpt[0].vr, Pt(0,dy)); viewpt[2].vr = raddp(viewpt[0].vr, Pt(dx,0)); viewpt[3].vr = raddp(viewpt[0].vr, Pt(dx,dy)); break; } for (i = 0; i < n; i++) { viewpt[i].vr = shrink(viewpt[i].vr, MARGINPCT); viewpt[i].xmax = viewpt[i].vr.corner.x - viewpt[i].vr.origin.x; viewpt[i].ymax = viewpt[i].vr.corner.y - viewpt[i].vr.origin.y; } } drawrect(r, mode) Rectangle r; { segment(&display, r.origin, Pt(r.origin.x,r.corner.y), mode); segment(&display, r.origin, Pt(r.corner.x,r.origin.y), mode); segment(&display, r.corner, Pt(r.origin.x,r.corner.y), mode); segment(&display, r.corner, Pt(r.corner.x,r.origin.y), mode); } segment(dp, p1, p2, mode) Rectangle *dp; /* fake */ Point p1, p2; int mode; { pw_vector(pw, p1.x, p1.y, p2.x, p2.y, mode, 1); } point(dp, p, mode) Rectangle *dp; Point p; int mode; { register int val; val = (mode==F_XOR)? pw_get(pw, p.x, p.y)^1 : ((mode==F_OR)? 1 : 0); pw_put(pw, p.x, p.y, val); } /* return the raster op that f needs to be when SRC is inverted */ invsrc(f) register int f; { if(f==F_XOR) f=PIX_NOT(PIX_SRC)^PIX_DST; else if(f==F_OR) f=PIX_NOT(PIX_SRC)|PIX_DST; else if(f==F_STORE) f=PIX_NOT(PIX_SRC); else if(f==F_CLR) f=PIX_SRC&PIX_DST; return f; } rectf(dp, r, mode) Rectangle *dp; Rectangle r; int mode; { pw_writebackground(pw,r.origin.x, r.origin.y, r.corner.x-r.origin.x, r.corner.y-r.origin.y, invsrc(mode)); } circle(dp, p, r, mode) Rectangle *dp; Point p; int r, mode; { int x1=p.x; register y1=p.y; register eps = 0; /* x^2 + y^2 - r^2 */ register dxsq = 1; /* (x+dx)^2-x^2*/ register dysq = 1 - 2*r; register exy; int x0 = x1; register y0 = y1 - r; y1 += r; pw_batch_on(pw); if (mode == F_XOR) { /* endpoints coincide */ point(dp,Pt(x0,y0),mode); point(dp,Pt(x0,y1),mode); } while(y1 > y0) { point(dp,Pt(x0,y0),mode); point(dp,Pt(x0,y1),mode); point(dp,Pt(x1,y0),mode); point(dp,Pt(x1,y1),mode); exy = eps + dxsq + dysq; if(-exy <= eps+dxsq) { y1--; y0++; eps += dysq; dysq += 2; } if(exy <= -eps) { x1++; x0--; eps += dxsq; dxsq += 2; } } point(dp,Pt(x0,y0),mode); point(dp,Pt(x1,y0),mode); pw_batch_off(pw); } disc(dp, p, r, mode) Rectangle *dp; Point p; int r, mode; { register x1=p.x, y1=p.y; register eps = 0; /* x^2 + y^2 - r^2 */ int dxsq = 1; /* (x+dx)^2-x^2*/ int dysq = 1 - 2*r; int exy; register x0 = x1; register y0 = y1 - r; x1++; /* to offset jerq's half-open lines*/ y1 += r; pw_batch_on(pw); while(y1 > y0) { exy = eps + dxsq + dysq; if(-exy <= eps+dxsq) { rectf(dp, Rect4(x0, y0, x1, y0+1), mode); rectf(dp, Rect4(x0, y1, x1, y1+1), mode); y1--; y0++; eps += dysq; dysq += 2; } if(exy <= -eps) { x1++; x0--; eps += dxsq; dxsq += 2; } } rectf(dp, Rect4(x0, y0, x1, y0+1), mode); pw_batch_off(pw); } string(fp, s, dp, p, mode) int *fp; /* actually a font pointer */ uchar *s; Rectangle *dp; Point p; int mode; { pw_text(pw, p.x, p.y+16, mode, 0, s); } do_rcv() { int c, n, b, m, i; uchar *ip; init_params(); clear(); memsize = readint(); if ((inbuf = (uchar *) malloc(memsize)) == (uchar *) NULL) { PUT "can't allocate %d bytes", memsize END sleephz(60); termabort(); } input = inbuf+1; /* leave a null at front */ inp = inbuf+1; /* next free slot in input */ dir = Fwd; PUT "%d bytes, limit %d", inp - input, memsize END top: switch (c = readchar()) { case P_INIT: /* initialize */ break; case P_ENDFILE: *inp = 0; return; case P_CLEAR: clear(); break; case P_DEFINE: /* view, click, ... */ c = readchar(); assert(c == 'c' || c == 'v', "illegal define"); i = readint(); readstring(buf); if (c == 'c') { clickname[i] = (char *) malloc(strlen(buf)+1); strcpy(clickname[i], buf); nclick++; } else { /* c == 'v' */ viewname[i] = (char *) malloc(strlen(buf)+1); strcpy(viewname[i], buf); nview++; } break; case P_OBJECT: /* read an object */ ip = inp; if (nobj++ == 0) view_setup(nview); if (nobj % 100 == 0) PUT "%d", nobj END read_obj(); draw_obj(ip, F_XOR, Fwd); break; case P_PRINT: /* print a string */ readstring(buf); putstring(buf); break; case P_ERROR: /* host is going to exit */ termabort(); default: if (overflow) break; putstring("do_rcv error; unrecognized command: "); for (pbuf = buf; c != '\n'; c = readchar()) *pbuf++ = c; *pbuf = 0; putstring(buf); break; } goto top; } clear() { rectf(&display, Drect, F_CLR); /* clear screen */ } read_obj() /* read an object, stick it in input[] */ { int c, n, m; uchar *p; if (inp > input+memsize-50) { /* eat up at least one */ PUT "overflow at %d bytes, limit %d", inp - input, memsize END overflow++; return; } c = readchar(); switch (c) { case ' ': case '\n': break; case 'b': case 'l': slotnum = readint(); slot[slotnum] = inp-input; p = savechar(c); savechar(curview = readint()); savechar(readint()); /* options */ savept(readpt()); savept(readpt()); savect(inp-p); break; case 'o': slotnum = readint(); slot[slotnum] = inp-input; p = savechar(c); savechar(curview = readint()); savechar(readint()); /* options */ savept(readpt()); saveint(readint()); /* radius */ savect(inp-p); break; case 't': slotnum = readint(); slot[slotnum] = inp-input; p = savechar(c); savechar(curview = readint()); savechar(readint()); /* options */ savept(readpt()); n = readstring(inp+1); /* +1 leaves a hole */ *inp = n; /* insert count before string */ inp += n + 2; /* +2 = count before and \0 on end */ savect(inp-p); break; case 'e': p = savechar(c); savelong(slot[readint()]); savect(inp-p); break; case 'c': p = savechar(c); savechar(readint()); savect(inp-p); break; } } Point readpt() /* read a Point */ { Point p; p.x = readint(); p.y = readint(); return p; } uchar *savechar(c) { *inp++ = c; return inp-1; } savect(n) { if (n > 255) putstring("text string too long"); *inp++ = n; } saveint(n) { *inp++ = n >> 8; *inp++ = n & 0377; } savelong(n) long n; { *inp++ = n >> 24; *inp++ = n >> 16; *inp++ = n >> 8; *inp++ = n; } savept(p) Point p; { *inp++ = p.x >> 8; *inp++ = p.x & 0377; *inp++ = p.y >> 8; *inp++ = p.y & 0377; } getpoint(ip) uchar *ip; { return *ip << 8 | *(ip+1); } long getlong(ip) uchar *ip; { return *ip << 24 | *(ip+1) << 16 | *(ip+2) << 8 | *(ip+3); } Point scalept(v, p) Point p; { p.x = p.x * viewpt[v].xmax / 10000; p.y = viewpt[v].ymax - p.y * viewpt[v].ymax / 10000; return p; } scalex(v, n) { return n * viewpt[v].xmax / 10000; } Point fetchpt(v, ip) int v; uchar *ip; { Point pt; pt.x = *ip << 8 | *(ip+1); pt.y = *(ip+2) << 8 | *(ip+3); pt = scalept(v, pt); return add(pt, viewpt[v].vr.origin); } /* Encoding: type, view#, opts, coords, chars, etc., # = length of group bvoxxyyxxyy# lvoxxyyxxyy# ovoxxyyrr# tvoxxyynccc0# ennnn# cn# */ uchar *prev_obj(ip) uchar *ip; { if (ip <= input) return 0; return ip - ip[-1] - 1; } uchar *next_obj(ip) uchar *ip; { if (ip < input || ip >= inp) return 0; switch (*ip) { case 0: return 0; case 'b': case 'l': return ip + 12; case 'o': return ip + 10; case 't': return ip + ip[7] + 10; case 'c': return ip + 3; case 'e': return ip + 6; default: return 0; } } uchar *step_obj(ip, mode, dir) /* draw objs until one that changes something */ uchar *ip; { int c; while (ip) { c = *ip; ip = draw_obj(ip, mode, dir); if (c == 'b' || c == 'l' || c == 't' || c == 'e' || c == 'o') return ip; } return ip; } uchar *click_obj(ip, mode, dir) /* draw objs until matching click */ uchar *ip; { int c; uchar *oip; for (;;) { oip = ip; ip = draw_obj(ip, mode, dir); if (ip == 0 || (oip && *oip == 'c' && clickval[oip[1]])) return ip; } } uchar *draw_obj(ip, mode, dir) /* draw obj from coords at ip */ uchar *ip; int mode, dir; { int c, r, thick, n, shift, head; Point p0, p1, p2; if (ip < input || ip >= inp) return 0; switch (c = *ip++) { case 'b': p0 = fetchpt(*ip, ip+2); p1 = fetchpt(*ip, ip+6); if (ip[1] == Bfill) { if (p0.y < p1.y) rectf(&display, Rpt(p0, p1), mode); else rectf(&display, Rect4(p0.x,p1.y,p1.x,p0.y), mode); } else { segment(&display, p0, Pt(p0.x,p1.y), mode); segment(&display, Pt(p0.x,p1.y), p1, mode); segment(&display, p1, Pt(p1.x,p0.y), mode); segment(&display, Pt(p1.x,p0.y), p0, mode); } if (dir == Fwd) ip += 1+9+1; else ip -= (*(ip-2) + 2); break; case 'l': p0 = fetchpt(*ip, ip+2); p1 = fetchpt(*ip, ip+6); thick = ip[1]/10; /* ought to be a macro! */ if (thick == Ldotted/10 || thick == Ldashed/10) thick = 1; thick = 2 * thick - 1; /* 1,3,5 */ fatline(p0, p1, mode, thick); head = ip[1]%10; /* ditto */ if (head == Larrow1 || head == Larrow3) arrow(p0, p1, AW, AH, mode); if (head == Larrow2 || head == Larrow3) arrow(p1, p0, AW, AH, mode); if (dir == Fwd) ip += 1+9+1; else ip -= (*(ip-2) + 2); break; case 'o': p0 = fetchpt(*ip, ip+2); r = scalex(*ip, getpoint(ip+6)); if (ip[1] == Cnofill) circle(&display, p0, r, mode); else disc(&display, p0, r, mode); if (dir == Fwd) ip += 1+7+1; else ip -= (*(ip-2) + 2); break; case 't': p0 = fetchpt(*ip, ip+2); n = ip[6]; shift = (ip[1]/10) * 10; /* ought to be a macro! */ if (shift == Tljust) shift = 0; else if (shift == Tcenter) shift = (9 * n) / 2; /* 9 = char width */ else shift = 9 * n; string(&defont, ip+7, &display, sub(p0, Pt(shift,8)), mode); if (dir == Fwd) ip += 1+5 + *(ip+6)+2 + 1; else ip -= (*(ip-2) + 2); break; case 'e': erase(ip-1); if (dir == Fwd) ip += 5; else ip -= (*(ip-2) + 2); break; case 'c': if (dir == Fwd) ip += 2; else ip -= (*(ip-2) + 2); break; default: ip = 0; break; } return ip; } erase(ip) uchar *ip; { long target = getlong(ip+1); /* target label index */ int mode = F_XOR; if (xormode == F_OR || xormode == F_CLR) mode = dir == Fwd ? F_CLR : F_OR; draw_obj(input+target, mode, Fwd); } #define abs(x) ((x) >= 0 ? (x) : -(x)) fatline(p0, p1, mode, thick) Point p0, p1; { int i, fat, beg, nl; fat = thick * (2 * fatness + 1); beg = fat / 2; if (abs(p1.x-p0.x) >= abs(p1.y-p0.y)) { /* horizontal */ for (nl = 0, i = -beg; nl < fat; nl++, i++) segment(&display, add(p0, Pt(0,i)), add(p1, Pt(0,i)), mode); } else { for (nl = 0, i = -beg; nl < fat; nl++, i++) segment(&display, add(p0, Pt(i,0)), add(p1, Pt(i,0)), mode); } } arrow(p1, p2, w, h, c) Point p1, p2; int w, h, c; /* ** draw arrow of height,width (h,w) at p2 of segment p1,p2. */ { Point d; int norm, qx, qy, lx, ly; d = sub(p2, p1); /* norm = sqrt((long)d.x*d.x + (long)d.y*d.y); */ norm = ((long)d.x*d.x + (long)d.y*d.y) / 2; if (norm == 0) /* shouldn't happen, but ... */ return; qx = p2.x - h*d.x/norm; qy = p2.y - h*d.y/norm; lx = w/2 * -d.y/norm; ly = w/2 * d.x/norm; /* segment(&display, p1, p2, c); */ segment(&display, Pt(qx+lx, qy+ly), p2, c); segment(&display, Pt(qx-lx, qy-ly), p2, c); } putstring(a1, a2, a3, a4, a5) char *a1, *a2, *a3, *a4, *a5; { char buf[100]; sprintf(buf, "%50s", " "); /* cheap clear */ pw_text(pw, 20, 20, F_STORE, 0, buf); sprintf(buf, a1, a2, a3, a4, a5); pw_text(pw, 20, 20, F_STORE, 0, buf); } assert(c, s) /* poor man's assertion */ char *s; { if (!c) { putstring("assertion %s failed\n", s); sleephz(60); termabort(); } } termabort() { send1char(P_QUIT); flushproto(); window_done(canvas); exit(1); } readbyte() { char c; read(0, &c, 1); return c; } sendbuf(buf, p) char *buf, *p; { write(1, buf, p-buf); } short bullseye_bits[]={ 0x07E0, 0x1FF8, 0x399C, 0x63C6, 0x6FF6, 0xCDB3, 0xD99B, 0xFFFF, 0xFFFF, 0xD99B, 0xCDB3, 0x6FF6, 0x63C6, 0x399C, 0x1FF8, 0x07E0, }; short coffeecup_bits[]={ 0x0100, 0x00E0, 0x0010, 0x03E0, 0x0400, 0x0FE0, 0x123C, 0x1FE2, 0x101A, 0x101A, 0x1002, 0x103C, 0x1810, 0x6FEC, 0x4004, 0x3FF8, }; short sweep_bits[]={ 0x43FF, 0xE001, 0x7001, 0x3801, 0x1D01, 0x0F01, 0x8701, 0x8F01, 0x8001, 0x8001, 0x8001, 0x8001, 0x8001, 0x8001, 0x8001, 0xFFFF, }; short deadmouse_bits[]={ 0x0000, 0x0114, 0xA208, 0x4100, 0x0000, 0x0008, 0x0004, 0x0082, 0x0441, 0xFFE1, 0x5FF1, 0x3FFE, 0x17F0, 0x03E0, 0x0000, 0x0000, }; short darkgrey_bits[]={ 0xDDDD, 0x7777, 0xDDDD, 0x7777, 0xDDDD, 0x7777, 0xDDDD, 0x7777, 0xDDDD, 0x7777, 0xDDDD, 0x7777, 0xDDDD, 0x7777, 0xDDDD, 0x7777, }; short lockarrow_bits[]={ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0FC0, 0x0FC0, 0x03C0, 0x07C0, 0x0EC0, 0x1CC0, 0x3800, 0x7000, 0xE0DB, 0xC0DB, }; mpr_static(bullseye_pr, 16, 16, 1, bullseye_bits); mpr_static(coffeecup_pr, 16, 16, 1, coffeecup_bits); mpr_static(sweep_pr, 16, 16, 1, sweep_bits); mpr_static(deadmouse_pr, 16, 16, 1, deadmouse_bits); mpr_static(lockarrow_pr, 16, 16, 1, lockarrow_bits); mpr_static(darkgrey, 16, 16, 1, darkgrey_bits); initcursors() { normalcursor=cursor_copy(window_get(canvas,WIN_CURSOR)); cursor_set(normalcursor,CURSOR_OP,F_XOR,0); bullseye=cursor_create(CURSOR_IMAGE,&bullseye_pr, CURSOR_XHOT,7,CURSOR_YHOT,7,CURSOR_OP,F_XOR,0); coffeecup=cursor_create(CURSOR_IMAGE,&coffeecup_pr, CURSOR_XHOT,7,CURSOR_YHOT,7,CURSOR_OP,F_XOR,0); sweep=cursor_create(CURSOR_IMAGE,&sweep_pr, CURSOR_XHOT,7,CURSOR_YHOT,7,CURSOR_OP,F_XOR,0); deadmouse=cursor_create(CURSOR_IMAGE,&deadmouse_pr, CURSOR_XHOT,7,CURSOR_YHOT,7,CURSOR_OP,F_XOR,0); lockarrow=cursor_create(CURSOR_IMAGE,&lockarrow_pr, CURSOR_XHOT,0,CURSOR_YHOT,0,CURSOR_OP,F_XOR,0); cursor= &normalcursor; } Rectangle getrect23() { static Rectangle r; static Event ev; register Event *e= &ev; register int sweepstate=0; r.origin.x=r.origin.y=r.corner.x=r.corner.y=0; cursswitch(&sweep); window_set(canvas, WIN_CONSUME_PICK_EVENT, LOC_DRAG, 0, 0); window_release_event_lock(canvas); while(sweepstate<=1){ if(window_read_event(canvas,e)!=0) ; /* non-blocking read */ switch (event_id(e)) { case MS_LEFT: if(sweepstate) showr(&r); /*erase box*/ sweepstate=2; break; case MS_MIDDLE: case MS_RIGHT: if(!sweepstate && event_is_down(e)){ r.origin.x=r.corner.x=event_x(e); r.origin.y=r.corner.y=event_y(e); sweepstate=1; showr(&r); } else if(sweepstate && event_is_up(e)){ r.corner.x=event_x(e); r.corner.y=event_y(e); showr(&r); sweepstate=2; } break; case LOC_DRAG: showr(&r); /* erase old one */ r.corner.x=event_x(e); r.corner.y=event_y(e); showr(&r); break; case LOC_WINEXIT: if(sweepstate){ showr(&r); r.corner.x=event_x(e); r.corner.y=event_y(e); showr(&r); sweepstate=2; } break; } } window_set(canvas, WIN_IGNORE_PICK_EVENT, LOC_DRAG, 0); cursswitch(&normalcursor); return r; } showr(rp) register Rectangle *rp; { register int x0=rp->origin.x; register int y0=rp->origin.y; register int x1=rp->corner.x; register int y1=rp->corner.y; pw_batch_on(pw); pw_vector(pw, x0, y0, x1, y0, PIX_SRC^PIX_DST, 1); if(y1>y0) y0++; /*avoid redoing corner*/ else y0--; pw_vector(pw, x1, y0, x1, y1, PIX_SRC^PIX_DST, 1); if(x1>x0) x1--; else x1++; pw_vector(pw, x1, y1, x0, y1, PIX_SRC^PIX_DST, 1); pw_vector(pw, x0, y1, x0, y0, PIX_SRC^PIX_DST, 1); pw_batch_off(pw); } cursswitch(cp) Cursor *cp; { window_set(canvas, WIN_CURSOR, cp? *cp : normalcursor, 0); } /* sleep, but in 1/60's of second */ /* #include <sys/time.h> */ #include <signal.h> #define mask(s) (1<<((s)-1)) #define setvec(vec, a) \ vec.sv_handler = a; vec.sv_mask = vec.sv_onstack = 0 static int ringring; sleephz(n) unsigned n; { int sleepx(), omask; struct itimerval itv, oitv; register struct itimerval *itp = &itv; struct sigvec vec, ovec; if (n == 0) return; timerclear(&itp->it_interval); timerclear(&itp->it_value); if (setitimer(ITIMER_REAL, itp, &oitv) < 0) return; setvec(ovec, SIG_DFL); omask = sigblock(0); n *= 16666; itp->it_value.tv_sec = n / 1000000; itp->it_value.tv_usec = n % 1000000; if (timerisset(&oitv.it_value)) { if (timercmp(&oitv.it_value, &itp->it_value, >)) oitv.it_value.tv_sec -= itp->it_value.tv_sec; else { itp->it_value = oitv.it_value; /* * This is a hack, but we must have time to * return from the setitimer after the alarm * or else it'll be restarted. And, anyway, * sleep never did anything more than this before. */ oitv.it_value.tv_sec = 1; oitv.it_value.tv_usec = 0; } } setvec(vec, sleepx); (void) sigvec(SIGALRM, &vec, &ovec); ringring = 0; (void) setitimer(ITIMER_REAL, itp, (struct itimerval *)0); while (!ringring) sigpause(omask &~ mask(SIGALRM)); (void) sigvec(SIGALRM, &ovec, (struct sigvec *)0); (void) setitimer(ITIMER_REAL, &oitv, (struct itimerval *)0); } static sleepx() { ringring = 1; }