|
|
1.1 root 1: #include <suntool/sunview.h>
2: #include <suntool/canvas.h>
3: #include <fcntl.h>
4:
5:
6: /* from jerq.h... */
7:
8: typedef struct Point {
9: short x;
10: short y;
11: } Point;
12:
13: int muldiv(x,y,d) { return (x * y) / d; }
14:
15: Point pt(x, y) { Point p; p.x = x; p.y = y; return p; }
16: Point Pt(x, y) { Point p; p.x = x; p.y = y; return p; }
17: Point add(p1, p2) Point p1, p2; { p1.x += p2.x; p1.y += p2.y; return p1; }
18: Point sub(p1, p2) Point p1, p2; { p1.x -= p2.x; p1.y -= p2.y; return p1; }
19:
20: typedef struct Rectangle {
21: Point origin;
22: Point corner;
23: } Rectangle;
24:
25: Rectangle raddp(r, p) Rectangle r; Point p;
26: {
27: r.origin = add(r.origin, p);
28: r.corner = add(r.corner, p);
29: return r;
30: }
31:
32: Rectangle Rpt(p1,p2) Point p1, p2;
33: {
34: Rectangle r;
35: r.origin.x = p1.x; r.origin.y = p1.y;
36: r.corner.x = p2.x; r.corner.y = p2.y;
37: return r;
38: }
39:
40: Rectangle Rect4(x1,y1,x2,y2)
41: {
42: Rectangle r;
43: r.origin.x = x1; r.origin.y = y1;
44: r.corner.x = x2; r.corner.y = y2;
45: return r;
46: }
47:
48: Rectangle inset(r, n) Rectangle r;
49: {
50: r.origin.x += n; r.origin.y += n;
51: r.corner.x -= n; r.corner.y -= n;
52: return r;
53: }
54:
55: int eqpt(p1, p2) Point p1, p2; { return p1.x == p2.x && p1.y == p2.y; }
56:
57: Rectangle Drect;
58: #define Do Drect.origin
59: #define Dc Drect.corner
60:
61: Rectangle getrect23();
62: Rectangle display; /* not used */
63: int defont;
64:
65: /* bitblt function codes */
66: #define F_STORE (PIX_SRC) /* target = source */
67: #define F_OR (PIX_SRC|PIX_DST) /* target |= source */
68: #define F_CLR (PIX_NOT(PIX_SRC)&(PIX_DST)) /* target &= ~source */
69: #define F_XOR (PIX_SRC^PIX_DST) /* target ^= source */
70:
71: Cursor *cursor,normalcursor,bullseye,coffeecup,sweep,deadmouse,lockarrow;
72:
73: #include "anim.h"
74:
75: typedef unsigned char uchar;
76:
77: #define PUT { char buf[100]; sprintf(buf,
78: #define END ); putstring(buf); }
79: #define readpoint(p) { p.x = readint(); p.y = readint(); }
80: #define readpair(p1,p2) { readpoint(p1); readpoint(p2); }
81:
82: /* holds data for all input objects */
83:
84: unsigned memsize; /* bytes */
85: uchar *inbuf; /* input collected here */
86: uchar *input; /* leave a null at front */
87: uchar *inp; /* next free slot in input */
88: int nobj = 0; /* number of objects in input */
89: int overflow = 0; /* 1 => too much input */
90:
91: long slot[2000]; /* slots */
92: int slotnum;
93:
94: extern uchar *savechar(), *draw_obj(), *click_obj(), *step_obj();
95: extern uchar *prev_obj(), *next_obj();
96:
97: extern Point readpt(), fetchpt(), scalept();
98: int xmax, ymax;
99:
100: #define MAXVIEW 10
101: char *viewname[MAXVIEW];
102: typedef struct {
103: Rectangle vr;
104: int xmax;
105: int ymax;
106: } View;
107: View viewpt[MAXVIEW];
108: int curview = 0;
109: int nview = 0;
110: #define INSET 4 /* picture inset from frame */
111:
112: #define AW 8 /* arrowhead width and height */
113: #define AH 10
114:
115: #define MARGINPCT 6
116: int margin = MARGINPCT; /* percent margin around edges */
117:
118: #define MAXCLICK 20
119: char *clickname[MAXCLICK]; /* click names */
120: int clickval[MAXCLICK]; /* 1 => click on this */
121: int clicking = 0; /* number of active clicks */
122: int nclick = 0;
123:
124: char buf[200];
125: char *pbuf;
126:
127: #define Again 0 /* Menu items -- must be 0.. */
128: #define Faster (Again+1)
129: #define Slower (Faster+1)
130: #define Step (Slower+1)
131: #define Forward (Step+1)
132: #define Fatter (Forward+1)
133: #define Thinner (Fatter+1)
134: #define Xor (Thinner+1)
135: #define File (Xor+1)
136: #define Quit (File+1) /* ... down this far */
137: #define Backward (Quit+1) /* subsequent names are arbitrary */
138: #define Proceed (Backward+1)
139: #define Hit (Proceed+1)
140: #define FreeRun (Hit+1)
141:
142: int delay = 1; /* how long to delay between things */
143: int singstep = 0; /* single step if 1 */
144: #define Fwd 1
145: #define Back 0
146: int dir = Fwd; /* 1 = fwd, 0 = backward */
147: int fatness = 0; /* n => draw with 2n+1 lines */
148: int xormode = F_XOR; /* otherwise OR/CLR */
149:
150: char *m3[] = { "again", "faster", "slower", "1 step", "backward",
151: "fatter", "thinner", "or mode", "new file", "Quit?", 0 };
152: char *stepmenu[] = { "1 step", "run" };
153: char *dirmenu[] = { "forward", "backward" };
154: char *modemenu[] = { "or mode", "xor mode" };
155:
156: char *m3gen(n)
157: {
158: static char buf[20][20];
159: extern int delay;
160:
161: if (n < 0 || n > Quit)
162: return 0;
163: else if (n == Faster) {
164: sprintf(buf[n], "faster %d", delay);
165: return buf[n];
166: } else if (n == Slower) {
167: sprintf(buf[n], "slower %d", delay);
168: return buf[n];
169: } else if (n == Step) {
170: return stepmenu[singstep];
171: } else if (n == Forward) {
172: return dirmenu[dir];
173: } else if (n == Fatter) {
174: sprintf(buf[n], "fatter %d", fatness+1);
175: return buf[n];
176: } else if (n == Thinner) {
177: sprintf(buf[n], "thinner %d", fatness+1);
178: return buf[n];
179: } else if (n == Xor) {
180: return xormode == F_XOR ? modemenu[0] : modemenu[1];
181: } else
182: return m3[n];
183: }
184:
185: char *m2gen(n)
186: {
187: static char buf[20][50];
188:
189: if (n < 0 || n >= nview+nclick)
190: return 0;
191: else if (n < nview) {
192: sprintf(buf[n], "view %s", viewname[n]);
193: return buf[n];
194: } else {
195: sprintf(buf[n], "click %s%s",
196: clickname[n-nview], clickval[n-nview] ? "*" : "");
197: return buf[n];
198: }
199: }
200:
201: Menu mbut3;
202: Menu mbut2;
203: int last_hit;
204: int last_but;
205:
206: void inevent();
207:
208: Canvas canvas;
209: Pixwin *pw;
210: int canvasfd;
211: int height, width; /* screen window */
212:
213: init_params()
214: {
215: int i;
216:
217: for (i = 0; i < MAXCLICK; i++)
218: if (clickname[i]) {
219: free(clickname[i]);
220: clickname[i] = 0;
221: clickval[i] = 0;
222: }
223: for (i = 0; i < MAXVIEW; i++)
224: if (viewname[i]) {
225: free(viewname[i]);
226: viewname[i] = 0;
227: }
228: nclick = nview = curview = nobj = clicking = overflow = slotnum = 0;
229: }
230:
231: main()
232: {
233: int i, n;
234: Frame baseframe;
235:
236: baseframe = window_create(NULL, FRAME, FRAME_LABEL, "Anim",
237: WIN_ERROR_MSG, "Can't create Anim base window", 0);
238: canvas = window_create(baseframe, CANVAS, 0);
239: pw = canvas_pixwin(canvas);
240: canvasfd = (int)window_get(canvas, WIN_FD);
241: fcntl(canvasfd, F_SETFL, FNDELAY); /* allow nonblocking reads */
242: width = (int)window_get(canvas, CANVAS_WIDTH);
243: height = (int)window_get(canvas, CANVAS_HEIGHT);
244: Drect.origin = pt(0,0);
245: Drect.corner = add(Drect.origin, pt(width,height));
246:
247: do_rcv();
248:
249: initmenus();
250: initcursors();
251: /* get these events by default: LOC_WINENTER, LOC_WINEXIT, LOC_MOVE,
252: MS_LEFT, MS_MIDDLE, MS_RIGHT */
253: window_set(canvas,
254: WIN_CONSUME_KBD_EVENT, WIN_ASCII_EVENTS,
255: WIN_EVENT_PROC, inevent, 0);
256: window_main_loop(baseframe);
257: send1char(P_QUIT); /* tell host part we're done */
258: flushproto();
259: }
260:
261: initmenus()
262: {
263: int i;
264: char *s;
265:
266: mbut2 = menu_create(MENU_DEFAULT, 1, 0);
267: for (i = 0; s = m2gen(i); i++)
268: menu_set(mbut2, MENU_STRING_ITEM, s, i+1, 0);
269: mbut3 = menu_create(MENU_DEFAULT, 1, 0);
270: for (i = 0; m3[i]; i++)
271: menu_set(mbut3, MENU_STRING_ITEM, m3[i], i+1, 0);
272: }
273:
274: char kbdline[100]; /* collect keyboard input here */
275: int kbdi = 0; /* kbdline index */
276:
277: void inevent(c, e)
278: Canvas c;
279: Event *e;
280: {
281: int n, i, eid, ch;
282: char *s;
283:
284: eid = event_id(e);
285: switch (eid) {
286: default:
287: if (!event_is_ascii(e))
288: return;
289: if (eid != '\n' && eid != '\r') { /* which do we get? */
290: if (eid == '\b' && kbdi > 0)
291: kbdi--;
292: else
293: kbdline[kbdi++] = eid;
294: kbdline[kbdi] = '\0';
295: putstring(kbdline);
296: return;
297: }
298: kbdline[kbdi] = '\0';
299: kbdi = 0;
300: /* now we have a filename */
301: send1char(P_FILE);
302: sendstring(kbdline);
303: if ((ch = readchar()) == P_FILE) {
304: do_rcv();
305: } else {
306: PUT "can't open file %s", kbdline END;
307: }
308: return;
309: case WIN_RESIZE:
310: /* doesn't do much right now */
311: width=(int)window_get(canvas, CANVAS_WIDTH);
312: height=(int)window_get(canvas, CANVAS_HEIGHT);
313: Drect.origin = pt(0,0);
314: Drect.corner = add(Drect.origin, pt(width,height));
315: view_setup(nview);
316: return;
317: case MS_LEFT: /* button 1 */
318: if (event_is_up(e))
319: return;
320: last_but = 1;
321: last_hit = 0;
322: n = domouse();
323: break;
324: case MS_MIDDLE:
325: if (event_is_up(e))
326: return;
327: last_but = 2;
328: last_hit = (int) menu_show(mbut2, canvas, e, 0) - 1;
329: n = domouse();
330: for (i = 0; s = m2gen(i); i++)
331: menu_set(menu_get(mbut2, MENU_NTH_ITEM, i+1),
332: MENU_STRING, s, 0);
333: if (last_hit >= 0) /* start with this selected next time */
334: menu_set(mbut2, MENU_DEFAULT, last_hit+1, 0);
335: break;
336: case MS_RIGHT:
337: if (event_is_up(e))
338: return;
339: last_but = 3;
340: last_hit = (int) menu_show(mbut3, canvas, e, 0) - 1;
341: n = domouse();
342: for (i = 0; s = m3gen(i); i++)
343: menu_set(menu_get(mbut3, MENU_NTH_ITEM, i+1),
344: MENU_STRING, s, 0);
345: if (last_hit >= 0) /* start with this selected next time */
346: menu_set(mbut3, MENU_DEFAULT, last_hit+1, 0);
347: break;
348: }
349: run_one(n);
350: }
351:
352: run_one(n)
353: {
354: static uchar *ip;
355: int i;
356: char *s;
357: Event ev;
358: Event *e= &ev;
359:
360: again:
361: if (ip == 0) {
362: ip = dir == Fwd ? input : inp;
363: clear();
364: }
365: if (n == Quit) {
366: window_done(canvas);
367: return;
368: }
369: if (n == Hit) /* wait for another mouse hit */
370: return;
371: if (n == Forward) { /* change from fwd to back -- fiddle ip */
372: ip = next_obj(ip);
373: return;
374: }
375: if (n == Backward) {
376: ip = prev_obj(ip);
377: return;
378: }
379: if (n == File) {
380: putstring("filename? ");
381: return;
382: }
383: if (n == Again) {
384: clear();
385: dir = Fwd;
386: ip = input;
387: }
388: if (singstep) {
389: if (clicking > 0)
390: ip = click_obj(ip, xormode, dir);
391: else
392: ip = step_obj(ip, xormode, dir);
393: } else { /* free running */
394: while (ip) {
395: if (clicking > 0)
396: ip = click_obj(ip, xormode, dir);
397: else
398: ip = step_obj(ip, xormode, dir);
399: if (ip && window_read_event(canvas,e)==0) {
400: /* this just about duplicates inevent */
401: switch (event_id(e)) {
402: case WIN_RESIZE:
403: width=(int)window_get(canvas,
404: CANVAS_WIDTH);
405: height=(int)window_get(canvas,
406: CANVAS_HEIGHT);
407: Drect.origin = pt(0,0);
408: Drect.corner = add(Drect.origin,
409: pt(width,height));
410: view_setup(nview);
411: break;
412: case WIN_REPAINT:
413: pw_repairretained(pw);
414: break;
415: case MS_LEFT: /* button 1 */
416: if (event_is_up(e))
417: break;
418: last_but = 1;
419: last_hit = 0;
420: return; /* interrupt run */
421: case MS_MIDDLE:
422: if (event_is_up(e))
423: break;
424: last_but = 2;
425: last_hit = (int) menu_show(mbut2,
426: canvas, e, 0) - 1;
427: n = domouse();
428: for (i = 0; s = m2gen(i); i++)
429: menu_set(menu_get(mbut2,
430: MENU_NTH_ITEM, i+1),
431: MENU_STRING, s, 0);
432: if (last_hit >= 0)
433: menu_set(mbut2, MENU_DEFAULT
434: , last_hit+1, 0);
435: goto again;
436: case MS_RIGHT:
437: if (event_is_up(e))
438: break;
439: last_but = 3;
440: last_hit = (int) menu_show(mbut3,
441: canvas, e, 0) - 1;
442: n = domouse();
443: for (i = 0; s = m3gen(i); i++)
444: menu_set(menu_get(mbut3,
445: MENU_NTH_ITEM, i+1),
446: MENU_STRING, s, 0);
447: if (last_hit >= 0)
448: menu_set(mbut3, MENU_DEFAULT
449: , last_hit+1, 0);
450: goto again;
451: }
452: }
453: sleephz(delay-1);
454: }
455: }
456: }
457:
458: domouse()
459: {
460: int n;
461:
462: if (last_but == 1)
463: return Proceed;
464: if (last_but == 3) {
465: switch (last_hit) {
466: case Again:
467: return Again;
468: case Faster:
469: if (delay > 1)
470: delay /= 2;
471: return Hit;
472: case Slower:
473: delay *= 2;
474: return Hit;
475: case Step:
476: singstep = 1 - singstep;
477: n = Step;
478: return Hit;
479: case Forward:
480: dir = 1 - dir;
481: if (xormode == F_OR)
482: xormode = F_CLR;
483: else if (xormode == F_CLR)
484: xormode = F_OR;
485: return dir == Fwd ? Forward : Backward;
486: case Fatter:
487: fatness++;
488: return Hit;
489: case Thinner:
490: if (fatness > 0)
491: fatness--;
492: return Hit;
493: case Xor:
494: if (xormode == F_OR || xormode == F_CLR)
495: xormode = F_XOR;
496: else if (dir == Fwd)
497: xormode = F_OR;
498: else
499: xormode = F_CLR;
500: return Hit;
501: case File:
502: return File;
503: case Quit:
504: return Quit;
505: default:
506: return Hit;
507: }
508: } else if (last_but == 2) {
509: Rectangle r, shrink();
510: if (last_hit == -1)
511: return Hit;
512: else if (last_hit < nview) {
513: r = getrect23();
514: if (r.origin.x == 0 && r.corner.x == 0) /* bailed out */
515: return Hit;
516: if (eqpt(r.origin, r.corner))
517: r = Drect;
518: drawrect(inset(viewpt[last_hit].vr, -(INSET+fatness)), F_CLR);
519: drawrect(r, F_OR);
520: viewpt[last_hit].vr = r = inset(r, INSET+fatness);
521: viewpt[last_hit].xmax = r.corner.x - r.origin.x;
522: viewpt[last_hit].ymax = r.corner.y - r.origin.y;
523: return Hit;
524:
525: } else { /* a click */
526: if (clickval[last_hit-nview]) { /* was on, so turn off */
527: clickval[last_hit-nview] = 0;
528: clicking--;
529: } else {
530: clickval[last_hit-nview] = 1;
531: clicking++;
532: }
533: return Hit;
534: }
535: }
536: }
537:
538: Rectangle shrink(r, pct) /* shrink rectangle by 2*pct */
539: Rectangle r;
540: {
541: int dx = muldiv(r.corner.x-r.origin.x, pct, 100);
542: int dy = muldiv(r.corner.y-r.origin.y, pct, 100);
543: r.origin = add(r.origin, Pt(dx,dy));
544: r.corner = sub(r.corner, Pt(dx,dy));
545: return r;
546: }
547:
548: view_setup(n)
549: int n;
550: {
551: int i, dx, dy;
552:
553: dx = (Dc.x - Do.x) / 2;
554: dy = (Dc.y - Do.y) / 2;
555: viewpt[0].vr = Drect;
556: switch (n) {
557: case 2:
558: viewpt[1].vr = Drect;
559: viewpt[0].vr.corner.y -= dy;
560: viewpt[1].vr.origin.y += dy;
561: break;
562: case 3: case 4:
563: viewpt[0].vr.corner = add(Drect.origin, Pt(dx,dy));
564: viewpt[1].vr = raddp(viewpt[0].vr, Pt(0,dy));
565: viewpt[2].vr = raddp(viewpt[0].vr, Pt(dx,0));
566: viewpt[3].vr = raddp(viewpt[0].vr, Pt(dx,dy));
567: break;
568: }
569: for (i = 0; i < n; i++) {
570: viewpt[i].vr = shrink(viewpt[i].vr, MARGINPCT);
571: viewpt[i].xmax = viewpt[i].vr.corner.x - viewpt[i].vr.origin.x;
572: viewpt[i].ymax = viewpt[i].vr.corner.y - viewpt[i].vr.origin.y;
573: }
574: }
575:
576: drawrect(r, mode)
577: Rectangle r;
578: {
579: segment(&display, r.origin, Pt(r.origin.x,r.corner.y), mode);
580: segment(&display, r.origin, Pt(r.corner.x,r.origin.y), mode);
581: segment(&display, r.corner, Pt(r.origin.x,r.corner.y), mode);
582: segment(&display, r.corner, Pt(r.corner.x,r.origin.y), mode);
583: }
584:
585: segment(dp, p1, p2, mode)
586: Rectangle *dp; /* fake */
587: Point p1, p2;
588: int mode;
589: {
590: pw_vector(pw, p1.x, p1.y, p2.x, p2.y, mode, 1);
591: }
592:
593: point(dp, p, mode)
594: Rectangle *dp;
595: Point p;
596: int mode;
597: {
598: register int val;
599: val = (mode==F_XOR)? pw_get(pw, p.x, p.y)^1 :
600: ((mode==F_OR)? 1 : 0);
601: pw_put(pw, p.x, p.y, val);
602: }
603:
604: /* return the raster op that f needs to be when SRC is inverted */
605: invsrc(f)
606: register int f;
607: {
608: if(f==F_XOR) f=PIX_NOT(PIX_SRC)^PIX_DST;
609: else if(f==F_OR) f=PIX_NOT(PIX_SRC)|PIX_DST;
610: else if(f==F_STORE) f=PIX_NOT(PIX_SRC);
611: else if(f==F_CLR) f=PIX_SRC&PIX_DST;
612: return f;
613: }
614:
615: rectf(dp, r, mode)
616: Rectangle *dp;
617: Rectangle r;
618: int mode;
619: {
620: pw_writebackground(pw,r.origin.x, r.origin.y,
621: r.corner.x-r.origin.x, r.corner.y-r.origin.y, invsrc(mode));
622: }
623: circle(dp, p, r, mode)
624: Rectangle *dp;
625: Point p;
626: int r, mode;
627: {
628: int x1=p.x;
629: register y1=p.y;
630: register eps = 0; /* x^2 + y^2 - r^2 */
631: register dxsq = 1; /* (x+dx)^2-x^2*/
632: register dysq = 1 - 2*r;
633: register exy;
634: int x0 = x1;
635: register y0 = y1 - r;
636: y1 += r;
637: pw_batch_on(pw);
638: if (mode == F_XOR) { /* endpoints coincide */
639: point(dp,Pt(x0,y0),mode);
640: point(dp,Pt(x0,y1),mode);
641: }
642: while(y1 > y0) {
643: point(dp,Pt(x0,y0),mode);
644: point(dp,Pt(x0,y1),mode);
645: point(dp,Pt(x1,y0),mode);
646: point(dp,Pt(x1,y1),mode);
647: exy = eps + dxsq + dysq;
648: if(-exy <= eps+dxsq) {
649: y1--;
650: y0++;
651: eps += dysq;
652: dysq += 2;
653: }
654: if(exy <= -eps) {
655: x1++;
656: x0--;
657: eps += dxsq;
658: dxsq += 2;
659: }
660: }
661: point(dp,Pt(x0,y0),mode);
662: point(dp,Pt(x1,y0),mode);
663: pw_batch_off(pw);
664: }
665:
666: disc(dp, p, r, mode)
667: Rectangle *dp;
668: Point p;
669: int r, mode;
670: {
671: register x1=p.x, y1=p.y;
672: register eps = 0; /* x^2 + y^2 - r^2 */
673: int dxsq = 1; /* (x+dx)^2-x^2*/
674: int dysq = 1 - 2*r;
675: int exy;
676: register x0 = x1;
677: register y0 = y1 - r;
678: x1++; /* to offset jerq's half-open lines*/
679: y1 += r;
680: pw_batch_on(pw);
681: while(y1 > y0) {
682: exy = eps + dxsq + dysq;
683: if(-exy <= eps+dxsq) {
684: rectf(dp, Rect4(x0, y0, x1, y0+1), mode);
685: rectf(dp, Rect4(x0, y1, x1, y1+1), mode);
686: y1--;
687: y0++;
688: eps += dysq;
689: dysq += 2;
690: }
691: if(exy <= -eps) {
692: x1++;
693: x0--;
694: eps += dxsq;
695: dxsq += 2;
696: }
697: }
698: rectf(dp, Rect4(x0, y0, x1, y0+1), mode);
699: pw_batch_off(pw);
700: }
701:
702: string(fp, s, dp, p, mode)
703: int *fp; /* actually a font pointer */
704: uchar *s;
705: Rectangle *dp;
706: Point p;
707: int mode;
708: {
709: pw_text(pw, p.x, p.y+16, mode, 0, s);
710: }
711:
712: do_rcv()
713: {
714: int c, n, b, m, i;
715: uchar *ip;
716:
717: init_params();
718: clear();
719: memsize = readint();
720: if ((inbuf = (uchar *) malloc(memsize)) == (uchar *) NULL) {
721: PUT "can't allocate %d bytes", memsize END
722: sleephz(60);
723: termabort();
724: }
725: input = inbuf+1; /* leave a null at front */
726: inp = inbuf+1; /* next free slot in input */
727: dir = Fwd;
728: PUT "%d bytes, limit %d", inp - input, memsize END
729:
730: top:
731: switch (c = readchar()) {
732: case P_INIT: /* initialize */
733: break;
734: case P_ENDFILE:
735: *inp = 0;
736: return;
737: case P_CLEAR:
738: clear();
739: break;
740: case P_DEFINE:
741: /* view, click, ... */
742: c = readchar();
743: assert(c == 'c' || c == 'v', "illegal define");
744: i = readint();
745: readstring(buf);
746: if (c == 'c') {
747: clickname[i] = (char *) malloc(strlen(buf)+1);
748: strcpy(clickname[i], buf);
749: nclick++;
750: } else { /* c == 'v' */
751: viewname[i] = (char *) malloc(strlen(buf)+1);
752: strcpy(viewname[i], buf);
753: nview++;
754: }
755: break;
756: case P_OBJECT: /* read an object */
757: ip = inp;
758: if (nobj++ == 0)
759: view_setup(nview);
760: if (nobj % 100 == 0)
761: PUT "%d", nobj END
762: read_obj();
763: draw_obj(ip, F_XOR, Fwd);
764: break;
765: case P_PRINT: /* print a string */
766: readstring(buf);
767: putstring(buf);
768: break;
769: case P_ERROR: /* host is going to exit */
770: termabort();
771: default:
772: if (overflow)
773: break;
774: putstring("do_rcv error; unrecognized command: ");
775: for (pbuf = buf; c != '\n'; c = readchar())
776: *pbuf++ = c;
777: *pbuf = 0;
778: putstring(buf);
779: break;
780: }
781: goto top;
782: }
783:
784: clear()
785: {
786: rectf(&display, Drect, F_CLR); /* clear screen */
787: }
788:
789: read_obj() /* read an object, stick it in input[] */
790: {
791: int c, n, m;
792: uchar *p;
793:
794: if (inp > input+memsize-50) { /* eat up at least one */
795: PUT "overflow at %d bytes, limit %d", inp - input, memsize END
796: overflow++;
797: return;
798: }
799: c = readchar();
800: switch (c) {
801: case ' ':
802: case '\n':
803: break;
804: case 'b':
805: case 'l':
806: slotnum = readint();
807: slot[slotnum] = inp-input;
808: p = savechar(c);
809: savechar(curview = readint());
810: savechar(readint()); /* options */
811: savept(readpt());
812: savept(readpt());
813: savect(inp-p);
814: break;
815: case 'o':
816: slotnum = readint();
817: slot[slotnum] = inp-input;
818: p = savechar(c);
819: savechar(curview = readint());
820: savechar(readint()); /* options */
821: savept(readpt());
822: saveint(readint()); /* radius */
823: savect(inp-p);
824: break;
825: case 't':
826: slotnum = readint();
827: slot[slotnum] = inp-input;
828: p = savechar(c);
829: savechar(curview = readint());
830: savechar(readint()); /* options */
831: savept(readpt());
832: n = readstring(inp+1); /* +1 leaves a hole */
833: *inp = n; /* insert count before string */
834: inp += n + 2; /* +2 = count before and \0 on end */
835: savect(inp-p);
836: break;
837: case 'e':
838: p = savechar(c);
839: savelong(slot[readint()]);
840: savect(inp-p);
841: break;
842: case 'c':
843: p = savechar(c);
844: savechar(readint());
845: savect(inp-p);
846: break;
847: }
848: }
849:
850: Point readpt() /* read a Point */
851: {
852: Point p;
853:
854: p.x = readint();
855: p.y = readint();
856: return p;
857: }
858:
859: uchar *savechar(c)
860: {
861: *inp++ = c;
862: return inp-1;
863: }
864:
865: savect(n)
866: {
867: if (n > 255)
868: putstring("text string too long");
869: *inp++ = n;
870: }
871:
872: saveint(n)
873: {
874: *inp++ = n >> 8;
875: *inp++ = n & 0377;
876: }
877:
878: savelong(n)
879: long n;
880: {
881: *inp++ = n >> 24;
882: *inp++ = n >> 16;
883: *inp++ = n >> 8;
884: *inp++ = n;
885: }
886:
887: savept(p)
888: Point p;
889: {
890: *inp++ = p.x >> 8;
891: *inp++ = p.x & 0377;
892: *inp++ = p.y >> 8;
893: *inp++ = p.y & 0377;
894: }
895:
896: getpoint(ip)
897: uchar *ip;
898: {
899: return *ip << 8 | *(ip+1);
900: }
901:
902: long getlong(ip)
903: uchar *ip;
904: {
905: return *ip << 24 | *(ip+1) << 16 | *(ip+2) << 8 | *(ip+3);
906: }
907:
908: Point scalept(v, p)
909: Point p;
910: {
911: p.x = p.x * viewpt[v].xmax / 10000;
912: p.y = viewpt[v].ymax - p.y * viewpt[v].ymax / 10000;
913: return p;
914: }
915:
916: scalex(v, n)
917: {
918: return n * viewpt[v].xmax / 10000;
919: }
920:
921: Point fetchpt(v, ip)
922: int v;
923: uchar *ip;
924: {
925: Point pt;
926:
927: pt.x = *ip << 8 | *(ip+1);
928: pt.y = *(ip+2) << 8 | *(ip+3);
929: pt = scalept(v, pt);
930: return add(pt, viewpt[v].vr.origin);
931: }
932:
933: /*
934: Encoding: type, view#, opts, coords, chars, etc., # = length of group
935: bvoxxyyxxyy#
936: lvoxxyyxxyy#
937: ovoxxyyrr#
938: tvoxxyynccc0#
939: ennnn#
940: cn#
941:
942: */
943:
944: uchar *prev_obj(ip)
945: uchar *ip;
946: {
947: if (ip <= input)
948: return 0;
949: return ip - ip[-1] - 1;
950: }
951:
952: uchar *next_obj(ip)
953: uchar *ip;
954: {
955: if (ip < input || ip >= inp)
956: return 0;
957: switch (*ip) {
958: case 0:
959: return 0;
960: case 'b':
961: case 'l':
962: return ip + 12;
963: case 'o':
964: return ip + 10;
965: case 't':
966: return ip + ip[7] + 10;
967: case 'c':
968: return ip + 3;
969: case 'e':
970: return ip + 6;
971: default:
972: return 0;
973: }
974: }
975:
976: uchar *step_obj(ip, mode, dir) /* draw objs until one that changes something */
977: uchar *ip;
978: {
979: int c;
980:
981: while (ip) {
982: c = *ip;
983: ip = draw_obj(ip, mode, dir);
984: if (c == 'b' || c == 'l' || c == 't' || c == 'e' || c == 'o')
985: return ip;
986: }
987: return ip;
988: }
989:
990: uchar *click_obj(ip, mode, dir) /* draw objs until matching click */
991: uchar *ip;
992: {
993: int c;
994: uchar *oip;
995:
996: for (;;) {
997: oip = ip;
998: ip = draw_obj(ip, mode, dir);
999: if (ip == 0 || (oip && *oip == 'c' && clickval[oip[1]]))
1000: return ip;
1001: }
1002: }
1003:
1004: uchar *draw_obj(ip, mode, dir) /* draw obj from coords at ip */
1005: uchar *ip;
1006: int mode, dir;
1007: {
1008: int c, r, thick, n, shift, head;
1009: Point p0, p1, p2;
1010:
1011: if (ip < input || ip >= inp)
1012: return 0;
1013: switch (c = *ip++) {
1014: case 'b':
1015: p0 = fetchpt(*ip, ip+2);
1016: p1 = fetchpt(*ip, ip+6);
1017: if (ip[1] == Bfill) {
1018: if (p0.y < p1.y)
1019: rectf(&display, Rpt(p0, p1), mode);
1020: else
1021: rectf(&display, Rect4(p0.x,p1.y,p1.x,p0.y), mode);
1022: } else {
1023: segment(&display, p0, Pt(p0.x,p1.y), mode);
1024: segment(&display, Pt(p0.x,p1.y), p1, mode);
1025: segment(&display, p1, Pt(p1.x,p0.y), mode);
1026: segment(&display, Pt(p1.x,p0.y), p0, mode);
1027: }
1028: if (dir == Fwd)
1029: ip += 1+9+1;
1030: else
1031: ip -= (*(ip-2) + 2);
1032: break;
1033: case 'l':
1034: p0 = fetchpt(*ip, ip+2);
1035: p1 = fetchpt(*ip, ip+6);
1036: thick = ip[1]/10; /* ought to be a macro! */
1037: if (thick == Ldotted/10 || thick == Ldashed/10)
1038: thick = 1;
1039: thick = 2 * thick - 1; /* 1,3,5 */
1040: fatline(p0, p1, mode, thick);
1041: head = ip[1]%10; /* ditto */
1042: if (head == Larrow1 || head == Larrow3)
1043: arrow(p0, p1, AW, AH, mode);
1044: if (head == Larrow2 || head == Larrow3)
1045: arrow(p1, p0, AW, AH, mode);
1046: if (dir == Fwd)
1047: ip += 1+9+1;
1048: else
1049: ip -= (*(ip-2) + 2);
1050: break;
1051: case 'o':
1052: p0 = fetchpt(*ip, ip+2);
1053: r = scalex(*ip, getpoint(ip+6));
1054: if (ip[1] == Cnofill)
1055: circle(&display, p0, r, mode);
1056: else
1057: disc(&display, p0, r, mode);
1058: if (dir == Fwd)
1059: ip += 1+7+1;
1060: else
1061: ip -= (*(ip-2) + 2);
1062: break;
1063: case 't':
1064: p0 = fetchpt(*ip, ip+2);
1065: n = ip[6];
1066: shift = (ip[1]/10) * 10; /* ought to be a macro! */
1067: if (shift == Tljust)
1068: shift = 0;
1069: else if (shift == Tcenter)
1070: shift = (9 * n) / 2; /* 9 = char width */
1071: else
1072: shift = 9 * n;
1073: string(&defont, ip+7, &display, sub(p0, Pt(shift,8)), mode);
1074: if (dir == Fwd)
1075: ip += 1+5 + *(ip+6)+2 + 1;
1076: else
1077: ip -= (*(ip-2) + 2);
1078: break;
1079: case 'e':
1080: erase(ip-1);
1081: if (dir == Fwd)
1082: ip += 5;
1083: else
1084: ip -= (*(ip-2) + 2);
1085: break;
1086: case 'c':
1087: if (dir == Fwd)
1088: ip += 2;
1089: else
1090: ip -= (*(ip-2) + 2);
1091: break;
1092: default:
1093: ip = 0;
1094: break;
1095: }
1096: return ip;
1097: }
1098:
1099: erase(ip)
1100: uchar *ip;
1101: {
1102: long target = getlong(ip+1); /* target label index */
1103: int mode = F_XOR;
1104:
1105: if (xormode == F_OR || xormode == F_CLR)
1106: mode = dir == Fwd ? F_CLR : F_OR;
1107: draw_obj(input+target, mode, Fwd);
1108: }
1109:
1110: #define abs(x) ((x) >= 0 ? (x) : -(x))
1111:
1112: fatline(p0, p1, mode, thick)
1113: Point p0, p1;
1114: {
1115: int i, fat, beg, nl;
1116:
1117: fat = thick * (2 * fatness + 1);
1118: beg = fat / 2;
1119: if (abs(p1.x-p0.x) >= abs(p1.y-p0.y)) { /* horizontal */
1120: for (nl = 0, i = -beg; nl < fat; nl++, i++)
1121: segment(&display, add(p0, Pt(0,i)), add(p1, Pt(0,i)), mode);
1122: } else {
1123: for (nl = 0, i = -beg; nl < fat; nl++, i++)
1124: segment(&display, add(p0, Pt(i,0)), add(p1, Pt(i,0)), mode);
1125: }
1126: }
1127:
1128: arrow(p1, p2, w, h, c)
1129: Point p1, p2;
1130: int w, h, c;
1131: /*
1132: ** draw arrow of height,width (h,w) at p2 of segment p1,p2.
1133: */
1134: {
1135: Point d;
1136: int norm, qx, qy, lx, ly;
1137:
1138: d = sub(p2, p1);
1139: /* norm = sqrt((long)d.x*d.x + (long)d.y*d.y); */
1140: norm = ((long)d.x*d.x + (long)d.y*d.y) / 2;
1141: if (norm == 0) /* shouldn't happen, but ... */
1142: return;
1143: qx = p2.x - h*d.x/norm;
1144: qy = p2.y - h*d.y/norm;
1145: lx = w/2 * -d.y/norm;
1146: ly = w/2 * d.x/norm;
1147: /* segment(&display, p1, p2, c); */
1148: segment(&display, Pt(qx+lx, qy+ly), p2, c);
1149: segment(&display, Pt(qx-lx, qy-ly), p2, c);
1150: }
1151:
1152:
1153: putstring(a1, a2, a3, a4, a5)
1154: char *a1, *a2, *a3, *a4, *a5;
1155: {
1156: char buf[100];
1157:
1158: sprintf(buf, "%50s", " "); /* cheap clear */
1159: pw_text(pw, 20, 20, F_STORE, 0, buf);
1160: sprintf(buf, a1, a2, a3, a4, a5);
1161: pw_text(pw, 20, 20, F_STORE, 0, buf);
1162: }
1163:
1164: assert(c, s) /* poor man's assertion */
1165: char *s;
1166: {
1167: if (!c) {
1168: putstring("assertion %s failed\n", s);
1169: sleephz(60);
1170: termabort();
1171: }
1172: }
1173:
1174: termabort()
1175: {
1176: send1char(P_QUIT);
1177: flushproto();
1178: window_done(canvas);
1179: exit(1);
1180: }
1181:
1182: readbyte()
1183: {
1184: char c;
1185:
1186: read(0, &c, 1);
1187: return c;
1188: }
1189:
1190: sendbuf(buf, p)
1191: char *buf, *p;
1192: {
1193: write(1, buf, p-buf);
1194: }
1195:
1196:
1197: short bullseye_bits[]={
1198: 0x07E0, 0x1FF8, 0x399C, 0x63C6, 0x6FF6, 0xCDB3, 0xD99B, 0xFFFF,
1199: 0xFFFF, 0xD99B, 0xCDB3, 0x6FF6, 0x63C6, 0x399C, 0x1FF8, 0x07E0,
1200: };
1201: short coffeecup_bits[]={
1202: 0x0100, 0x00E0, 0x0010, 0x03E0, 0x0400, 0x0FE0, 0x123C, 0x1FE2,
1203: 0x101A, 0x101A, 0x1002, 0x103C, 0x1810, 0x6FEC, 0x4004, 0x3FF8,
1204: };
1205: short sweep_bits[]={
1206: 0x43FF, 0xE001, 0x7001, 0x3801, 0x1D01, 0x0F01, 0x8701, 0x8F01,
1207: 0x8001, 0x8001, 0x8001, 0x8001, 0x8001, 0x8001, 0x8001, 0xFFFF,
1208: };
1209: short deadmouse_bits[]={
1210: 0x0000, 0x0114, 0xA208, 0x4100, 0x0000, 0x0008, 0x0004, 0x0082,
1211: 0x0441, 0xFFE1, 0x5FF1, 0x3FFE, 0x17F0, 0x03E0, 0x0000, 0x0000,
1212: };
1213: short darkgrey_bits[]={
1214: 0xDDDD, 0x7777, 0xDDDD, 0x7777, 0xDDDD, 0x7777, 0xDDDD, 0x7777,
1215: 0xDDDD, 0x7777, 0xDDDD, 0x7777, 0xDDDD, 0x7777, 0xDDDD, 0x7777,
1216: };
1217: short lockarrow_bits[]={
1218: 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0FC0, 0x0FC0,
1219: 0x03C0, 0x07C0, 0x0EC0, 0x1CC0, 0x3800, 0x7000, 0xE0DB, 0xC0DB,
1220: };
1221: mpr_static(bullseye_pr, 16, 16, 1, bullseye_bits);
1222: mpr_static(coffeecup_pr, 16, 16, 1, coffeecup_bits);
1223: mpr_static(sweep_pr, 16, 16, 1, sweep_bits);
1224: mpr_static(deadmouse_pr, 16, 16, 1, deadmouse_bits);
1225: mpr_static(lockarrow_pr, 16, 16, 1, lockarrow_bits);
1226: mpr_static(darkgrey, 16, 16, 1, darkgrey_bits);
1227:
1228: initcursors()
1229: {
1230: normalcursor=cursor_copy(window_get(canvas,WIN_CURSOR));
1231: cursor_set(normalcursor,CURSOR_OP,F_XOR,0);
1232: bullseye=cursor_create(CURSOR_IMAGE,&bullseye_pr,
1233: CURSOR_XHOT,7,CURSOR_YHOT,7,CURSOR_OP,F_XOR,0);
1234: coffeecup=cursor_create(CURSOR_IMAGE,&coffeecup_pr,
1235: CURSOR_XHOT,7,CURSOR_YHOT,7,CURSOR_OP,F_XOR,0);
1236: sweep=cursor_create(CURSOR_IMAGE,&sweep_pr,
1237: CURSOR_XHOT,7,CURSOR_YHOT,7,CURSOR_OP,F_XOR,0);
1238: deadmouse=cursor_create(CURSOR_IMAGE,&deadmouse_pr,
1239: CURSOR_XHOT,7,CURSOR_YHOT,7,CURSOR_OP,F_XOR,0);
1240: lockarrow=cursor_create(CURSOR_IMAGE,&lockarrow_pr,
1241: CURSOR_XHOT,0,CURSOR_YHOT,0,CURSOR_OP,F_XOR,0);
1242: cursor= &normalcursor;
1243: }
1244:
1245:
1246: Rectangle getrect23()
1247: {
1248: static Rectangle r;
1249: static Event ev;
1250: register Event *e= &ev;
1251: register int sweepstate=0;
1252: r.origin.x=r.origin.y=r.corner.x=r.corner.y=0;
1253: cursswitch(&sweep);
1254: window_set(canvas, WIN_CONSUME_PICK_EVENT, LOC_DRAG, 0, 0);
1255: window_release_event_lock(canvas);
1256: while(sweepstate<=1){
1257: if(window_read_event(canvas,e)!=0)
1258: ; /* non-blocking read */
1259: switch (event_id(e)) {
1260: case MS_LEFT:
1261: if(sweepstate) showr(&r); /*erase box*/
1262: sweepstate=2;
1263: break;
1264: case MS_MIDDLE:
1265: case MS_RIGHT:
1266: if(!sweepstate && event_is_down(e)){
1267: r.origin.x=r.corner.x=event_x(e);
1268: r.origin.y=r.corner.y=event_y(e);
1269: sweepstate=1;
1270: showr(&r);
1271: }
1272: else if(sweepstate && event_is_up(e)){
1273: r.corner.x=event_x(e);
1274: r.corner.y=event_y(e);
1275: showr(&r);
1276: sweepstate=2;
1277: }
1278: break;
1279: case LOC_DRAG:
1280: showr(&r); /* erase old one */
1281: r.corner.x=event_x(e);
1282: r.corner.y=event_y(e);
1283: showr(&r);
1284: break;
1285: case LOC_WINEXIT:
1286: if(sweepstate){
1287: showr(&r);
1288: r.corner.x=event_x(e);
1289: r.corner.y=event_y(e);
1290: showr(&r);
1291: sweepstate=2;
1292: }
1293: break;
1294: }
1295: }
1296: window_set(canvas, WIN_IGNORE_PICK_EVENT, LOC_DRAG, 0);
1297: cursswitch(&normalcursor);
1298: return r;
1299: }
1300: showr(rp)
1301: register Rectangle *rp;
1302: {
1303: register int x0=rp->origin.x;
1304: register int y0=rp->origin.y;
1305: register int x1=rp->corner.x;
1306: register int y1=rp->corner.y;
1307: pw_batch_on(pw);
1308: pw_vector(pw, x0, y0, x1, y0, PIX_SRC^PIX_DST, 1);
1309: if(y1>y0) y0++; /*avoid redoing corner*/
1310: else y0--;
1311: pw_vector(pw, x1, y0, x1, y1, PIX_SRC^PIX_DST, 1);
1312: if(x1>x0) x1--;
1313: else x1++;
1314: pw_vector(pw, x1, y1, x0, y1, PIX_SRC^PIX_DST, 1);
1315: pw_vector(pw, x0, y1, x0, y0, PIX_SRC^PIX_DST, 1);
1316: pw_batch_off(pw);
1317: }
1318:
1319: cursswitch(cp)
1320: Cursor *cp;
1321: {
1322: window_set(canvas, WIN_CURSOR, cp? *cp : normalcursor, 0);
1323: }
1324:
1325:
1326: /* sleep, but in 1/60's of second */
1327: /* #include <sys/time.h> */
1328: #include <signal.h>
1329:
1330: #define mask(s) (1<<((s)-1))
1331: #define setvec(vec, a) \
1332: vec.sv_handler = a; vec.sv_mask = vec.sv_onstack = 0
1333:
1334: static int ringring;
1335:
1336: sleephz(n)
1337: unsigned n;
1338: {
1339: int sleepx(), omask;
1340: struct itimerval itv, oitv;
1341: register struct itimerval *itp = &itv;
1342: struct sigvec vec, ovec;
1343:
1344: if (n == 0)
1345: return;
1346: timerclear(&itp->it_interval);
1347: timerclear(&itp->it_value);
1348: if (setitimer(ITIMER_REAL, itp, &oitv) < 0)
1349: return;
1350: setvec(ovec, SIG_DFL);
1351: omask = sigblock(0);
1352: n *= 16666;
1353: itp->it_value.tv_sec = n / 1000000;
1354: itp->it_value.tv_usec = n % 1000000;
1355: if (timerisset(&oitv.it_value)) {
1356: if (timercmp(&oitv.it_value, &itp->it_value, >))
1357: oitv.it_value.tv_sec -= itp->it_value.tv_sec;
1358: else {
1359: itp->it_value = oitv.it_value;
1360: /*
1361: * This is a hack, but we must have time to
1362: * return from the setitimer after the alarm
1363: * or else it'll be restarted. And, anyway,
1364: * sleep never did anything more than this before.
1365: */
1366: oitv.it_value.tv_sec = 1;
1367: oitv.it_value.tv_usec = 0;
1368: }
1369: }
1370: setvec(vec, sleepx);
1371: (void) sigvec(SIGALRM, &vec, &ovec);
1372: ringring = 0;
1373: (void) setitimer(ITIMER_REAL, itp, (struct itimerval *)0);
1374: while (!ringring)
1375: sigpause(omask &~ mask(SIGALRM));
1376: (void) sigvec(SIGALRM, &ovec, (struct sigvec *)0);
1377: (void) setitimer(ITIMER_REAL, &oitv, (struct itimerval *)0);
1378: }
1379:
1380: static
1381: sleepx()
1382: {
1383:
1384: ringring = 1;
1385: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.