|
|
1.1 root 1: #ifdef X11
2: #include "xjerq.h"
3:
4: #else
5: #ifdef TTY630
6: #include <dmd.h>
7: #include <5620.h>
8: #define Texture Texture16
9:
10: #else
11: #include <jerq.h>
12: #include <font.h>
13: #endif
14: #endif
15:
16: #include "anim.h"
17:
18: #ifndef X11
19: Texture deadmouse = {
20: 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x000C, 0x0082, 0x0441,
21: 0xFFE1, 0x5FF1, 0x3FFE, 0x17F0, 0x03E0, 0x0000, 0x0000, 0x0000, };
22: Texture skull ={
23: 0x0000, 0x0000, 0x0000, 0xC003, 0xE7E7, 0x3FFC, 0x0FF0, 0x0DB0,
24: 0x07E0, 0x0660, 0x37EC, 0xE427, 0xC3C3, 0x0000, 0x0000, 0x0000, };
25: #else /* X11 */
26: short deadmouse_bits[] = {
27: 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x000C, 0x0082, 0x0441,
28: 0xFFE1, 0x5FF1, 0x3FFE, 0x17F0, 0x03E0, 0x0000, 0x0000, 0x0000, };
29: short skull_bits[] ={
30: 0x0000, 0x0000, 0x0000, 0xC003, 0xE7E7, 0x3FFC, 0x0FF0, 0x0DB0,
31: 0x07E0, 0x0660, 0x37EC, 0xE427, 0xC3C3, 0x0000, 0x0000, 0x0000, };
32: Cursor deadmouse, skull;
33: initcursors()
34: {
35: deadmouse = ToCursor(deadmouse_bits, deadmouse_bits, 7, 7);
36: skull = ToCursor(skull_bits, deadmouse_bits, 7, 7);
37: }
38: #undef Texture
39: #define Texture Cursor
40: #define sleep(n) usleep(16666*n)
41: #define V9 1
42: /* X emulator lib uses V9 kind of blit library */
43: #endif X11
44:
45: #define PTR (Texture *)0
46:
47: #define Do Drect.origin
48: #define Dc Drect.corner
49: #define kbdrect Rect(Do.x+4, Do.y+4, Dc.x+4, Do.y+16+4)
50:
51: char kbdline[100]; /* keyboard input collects here */
52: char *pkbd = kbdline;
53:
54: typedef unsigned char uchar;
55:
56: int errline;
57: #define PUT { char __buf[100]; errline = 0; sprintf(__buf,
58: #define END ); putstring(__buf); }
59: #define ERRPUT { char __buf[100]; errline = 1; sprintf(__buf,
60: #define NAP sleep(100)
61: #define readpoint(p) { p.x = readint(); p.y = readint(); }
62: #define readpair(p1,p2) { readpoint(p1); readpoint(p2); }
63:
64: /* holds data for all input objects */
65:
66: unsigned memsize; /* bytes */
67: uchar *inbuf; /* input collected here */
68: uchar *input; /* leave a null at front */
69: uchar *inp; /* next free slot in input */
70: int nobj = 0; /* number of objects in input */
71: int overflow = 0; /* 1 => too much input */
72:
73: long slot[2000]; /* slots */
74: int slotnum;
75:
76: extern uchar *savechar(), *read_obj(), *draw_obj(), *click_obj(), *step_obj();
77: extern uchar *prev_obj(), *next_obj();
78:
79: extern Point readpt(), fetchpt(), scalept();
80: int xmax, ymax;
81:
82: #define MAXVIEW 20
83: char *viewname[MAXVIEW];
84: typedef struct {
85: Rectangle vr;
86: int xmax;
87: int ymax;
88: } View;
89: View viewpt[MAXVIEW];
90: int curview = 0;
91: int nview = 0;
92: #define INSET 4 /* picture inset from frame */
93:
94: #define AW 8 /* arrowhead width and height */
95: #define AH 10
96:
97: #define MARGINPCT 6
98: int margin = MARGINPCT; /* percent margin around edges */
99:
100: #define MAXCLICK 20
101: char *clickname[MAXCLICK]; /* click names */
102: int clickval[MAXCLICK]; /* 1 => click on this */
103: int clicking = 0; /* number of active clicks */
104: int nclick = 0;
105:
106: char buf[200];
107: char *pbuf;
108:
109: #define Again 0 /* Menu items -- must be 0.. */
110: #define Faster (Again+1)
111: #define Slower (Faster+1)
112: #define Step (Slower+1)
113: #define Forward (Step+1)
114: #define Fatter (Forward+1)
115: #define Thinner (Fatter+1)
116: #define Xor (Thinner+1)
117: #define File (Xor+1)
118: #define Quit (File+1) /* ... down this far */
119: #define Backward (Quit+1) /* subsequent names are arbitrary */
120: #define Proceed (Backward+1)
121: #define Hit (Proceed+1)
122:
123: int delay = 1; /* how long to delay between things */
124: int singstep = 0; /* single step if 1 */
125: #define Fwd 1
126: #define Back 0
127: int dir = Fwd; /* 1 = fwd, 0 = backward */
128: int fatness = 0; /* n => draw with 2n+1 lines */
129: Code xormode = F_XOR; /* otherwise OR/CLR */
130:
131: char *m3[] = { "again", "faster", "slower", "1 step", "backward",
132: "fatter", "thinner", "or mode", "new file", "Quit?", 0 };
133: char *stepmenu[] = { "1 step", "run" };
134: char *dirmenu[] = { "forward", "backward" };
135: char *modemenu[] = { "or mode", "xor mode" };
136:
137: char *m3gen(n)
138: {
139: static char buf[50];
140: extern int delay;
141:
142: if (n < 0 || n > Quit)
143: return 0;
144: else if (n == Faster) {
145: sprintf(buf, "faster %d", delay);
146: return buf;
147: } else if (n == Slower) {
148: sprintf(buf, "slower %d", delay);
149: return buf;
150: } else if (n == Step) {
151: return stepmenu[singstep];
152: } else if (n == Forward) {
153: return dirmenu[dir];
154: } else if (n == Fatter) {
155: sprintf(buf, "fatter %d", fatness+1);
156: return buf;
157: } else if (n == Thinner) {
158: sprintf(buf, "thinner %d", fatness+1);
159: return buf;
160: } else if (n == Xor) {
161: return xormode == F_XOR ? modemenu[0] : modemenu[1];
162: } else
163: return m3[n];
164: }
165:
166: char *m2gen(n)
167: {
168: static char buf[50];
169:
170: if (n < 0 || n >= nview+nclick)
171: return 0;
172: else if (n < nview) {
173: sprintf(buf, "view %s", viewname[n]);
174: return buf;
175: } else {
176: sprintf(buf, "click %s%s",
177: clickname[n-nview], clickval[n-nview] ? "*" : "");
178: return buf;
179: }
180: }
181:
182: #ifdef V9
183: Menu mbut3 = { (char **) 0, m3gen };
184: Menu mbut2 = { (char **) 0, m2gen };
185: #else
186: Menu mbut3 = { (char **) 0, 0,0,m3gen };
187: Menu mbut2 = { (char **) 0, 0,0,m2gen };
188: #endif
189: int last_hit;
190: int last_but;
191:
192: init_params()
193: {
194: int i;
195:
196: for (i = 0; i < MAXCLICK; i++)
197: if (clickname[i]) {
198: free(clickname[i]);
199: clickname[i] = 0;
200: clickval[i] = 0;
201: }
202: for (i = 0; i < MAXVIEW; i++)
203: if (viewname[i]) {
204: free(viewname[i]);
205: viewname[i] = 0;
206: }
207: nclick = nview = curview = nobj = clicking = overflow = slotnum = 0;
208: }
209:
210: main(argc, argv)
211: char *argv[];
212: {
213: uchar *ip;
214: int i, n, c;
215:
216: #ifdef X11
217: initdisplay(argc, argv);
218: initcursors();
219: #endif X11
220:
221: request(KBD|MOUSE|SEND|RCV);
222: top:
223: clear();
224: init_params();
225: putstring("terminal alive");
226: memsize = readint();
227: if (inbuf == (uchar*)NULL && (inbuf = (uchar *) alloc(memsize)) == (uchar*)NULL) {
228: ERRPUT "can't allocate %u bytes", memsize END; NAP;
229: exit();
230: }
231: input = inbuf+1; /* leave a null at front */
232: inp = inbuf+1; /* next free slot in input */
233:
234: cursswitch(&deadmouse);
235: do_rcv();
236: PUT "%d objects, %u/%u bytes", nobj, inp-input, memsize END
237: cursswitch(PTR);
238:
239: dir = Fwd;
240: ip = inp; /* pointing at the end */
241: again:
242: for ( ; ip; wait(CPU)) {
243: #ifdef X11
244: wait(MOUSE);
245: #endif
246: while (checkmouse() == 0)
247: wait(CPU);
248: n = domouse();
249: if (n == Quit) {
250: send1char(P_QUIT);
251: flushproto();
252: exit();
253: }
254: if (n == Hit) /* wait for another mouse hit */
255: continue;
256: if (n == Forward) { /* change from fwd to back -- fiddle ip */
257: ip = next_obj(ip);
258: continue;
259: }
260: if (n == Backward) {
261: ip = prev_obj(ip);
262: continue;
263: }
264: if (n == File) {
265: static char prevkbd[100];
266: putstring("filename? ");
267: if (do_kbd() == 0)
268: continue;
269: send1char(P_FILE);
270: if (kbdline[0] == '\0') /* RETURN only */
271: strcpy(kbdline, prevkbd);
272: strcpy(prevkbd, kbdline);
273: sendstring(kbdline);
274: if ((c = readchar()) == P_FILE)
275: goto top;
276: assert(c == P_ERROR, "char is not P_ERROR");
277: ERRPUT "can't open file %s", kbdline END;
278: continue;
279: }
280: if (n == Again) {
281: if (P->state & RESHAPED) {
282: view_setup(nview);
283: P->state &= ~RESHAPED;
284: }
285: clear();
286: dir = Fwd;
287: ip = input;
288: }
289: if (singstep) {
290: if (clicking > 0)
291: ip = click_obj(ip, xormode, dir);
292: else
293: ip = step_obj(ip, xormode, dir);
294: } else { /* free running */
295: while (ip) {
296: if (clicking > 0)
297: ip = click_obj(ip, xormode, dir);
298: else
299: ip = step_obj(ip, xormode, dir);
300: if (checkmouse())
301: break; /* back round main loop */
302: sleep(delay-1);
303: wait(CPU);
304: }
305: }
306: }
307: if (ip == 0)
308: ip = dir == Fwd ? inp : input;
309: goto again;
310: }
311:
312: domouse()
313: {
314: int n;
315:
316: if (last_but == 1)
317: return Proceed;
318: if (last_but == 3) {
319: switch (last_hit) {
320: case Again:
321: return Again;
322: case Faster:
323: if (delay > 1)
324: delay /= 2;
325: return Hit;
326: case Slower:
327: delay *= 2;
328: return Hit;
329: case Step:
330: singstep = 1 - singstep;
331: n = Step;
332: return Hit;
333: case Forward:
334: dir = 1 - dir;
335: if (xormode == F_OR)
336: xormode = F_CLR;
337: else if (xormode == F_CLR)
338: xormode = F_OR;
339: return dir == Fwd ? Forward : Backward;
340: case Fatter:
341: fatness++;
342: return Hit;
343: case Thinner:
344: if (fatness > 0)
345: fatness--;
346: return Hit;
347: case Xor:
348: if (xormode == F_OR || xormode == F_CLR)
349: xormode = F_XOR;
350: else if (dir == Fwd)
351: xormode = F_OR;
352: else
353: xormode = F_CLR;
354: return Hit;
355: case File:
356: return File;
357: case Quit:
358: return Quit;
359: default:
360: return Hit;
361: }
362: } else if (last_but == 2) {
363: Rectangle r, shrink();
364: if (last_hit == -1)
365: return Hit;
366: else if (last_hit < nview) {
367: #ifdef V9
368: r = getrect23();
369: #else
370: r = getrect();
371: #endif
372: if (r.origin.x == 0 && r.corner.x == 0) /* bailed out */
373: return Hit;
374: if (eqpt(r.origin, r.corner))
375: r = Drect;
376: drawrect(inset(viewpt[last_hit].vr, -(INSET+fatness)), F_CLR);
377: drawrect(r, F_OR);
378: viewpt[last_hit].vr = r = inset(r, INSET+fatness);
379: viewpt[last_hit].xmax = r.corner.x - r.origin.x;
380: viewpt[last_hit].ymax = r.corner.y - r.origin.y;
381: return Hit;
382: } else { /* a click */
383: if (clickval[last_hit-nview]) { /* was on, so turn off */
384: clickval[last_hit-nview] = 0;
385: clicking--;
386: } else {
387: clickval[last_hit-nview] = 1;
388: clicking++;
389: }
390: return Hit;
391: }
392: }
393: }
394:
395: Point pt(x, y) { Point p; p.x = x; p.y = y; return p; }
396:
397: Rectangle shrink(r, pct) /* shrink rectangle by 2*pct */
398: Rectangle r;
399: {
400: int dx = muldiv(r.corner.x-r.origin.x, pct, 100);
401: int dy = muldiv(r.corner.y-r.origin.y, pct, 100);
402: r.origin = add(r.origin, Pt(dx,dy));
403: r.corner = sub(r.corner, Pt(dx,dy));
404: return r;
405: }
406:
407: view_setup(n)
408: int n;
409: {
410: int i, j, v, dx, dy, r, c;
411:
412: switch (n) {
413: case 1: r = 1; c = 1; break;
414: case 2: r = 2; c = 1; break;
415: case 3: case 4: r = 2; c = 2; break;
416: case 5: case 6: r = 3; c = 2; break;
417: case 7: case 8: case 9: r = 3; c = 3; break;
418: default: r = (n+2)/3; c = 3; break; /* finking out */
419: }
420: dx = (Dc.x - Do.x) / c;
421: dy = (Dc.y - Do.y) / r;
422: v = 0;
423: for (i = 0; i < r && v < n; i++)
424: for (j = 0; j < c && v < n; j++) {
425: viewpt[v].vr = Drect;
426: viewpt[v].vr.origin.x = Do.x + j * dx;
427: viewpt[v].vr.corner.x = Do.x + (j+1) * dx;
428: viewpt[v].vr.origin.y = Do.y + i * dy;
429: viewpt[v].vr.corner.y = Do.y + (i+1) * dy;
430: v++;
431: }
432: for (i = 0; i < n; i++) {
433: viewpt[i].vr = shrink(viewpt[i].vr, MARGINPCT);
434: viewpt[i].xmax = viewpt[i].vr.corner.x - viewpt[i].vr.origin.x;
435: viewpt[i].ymax = viewpt[i].vr.corner.y - viewpt[i].vr.origin.y;
436: }
437: }
438:
439: drawrect(r, mode)
440: Rectangle r;
441: {
442: segment(&display, r.origin, Pt(r.origin.x,r.corner.y), mode);
443: segment(&display, r.origin, Pt(r.corner.x,r.origin.y), mode);
444: segment(&display, r.corner, Pt(r.origin.x,r.corner.y), mode);
445: segment(&display, r.corner, Pt(r.corner.x,r.origin.y), mode);
446: }
447:
448: do_rcv()
449: {
450: int c, n, b, m, i;
451: uchar *ip;
452:
453: top:
454: switch (c = readchar()) {
455: case P_INIT: /* initialize */
456: break;
457: case P_ENDFILE:
458: *inp = 0;
459: return;
460: case P_CLEAR:
461: clear();
462: break;
463: case P_DEFINE:
464: /* view, click, ... */
465: c = readchar();
466: assert(c == 'c' || c == 'v', "illegal define");
467: i = readint();
468: readstring(buf);
469: if (c == 'c') {
470: clickname[i] = alloc(strlen(buf)+1);
471: strcpy(clickname[i], buf);
472: nclick++;
473: } else { /* c == 'v' */
474: viewname[i] = alloc(strlen(buf)+1);
475: strcpy(viewname[i], buf);
476: nview++;
477: }
478: break;
479: case P_OBJECT: /* read an object */
480: if (nobj++ == 0)
481: view_setup(nview);
482: if (nobj % 100 == 0)
483: PUT "%d objects, %u/%u bytes", nobj, inp-input, memsize END
484: ip = read_obj();
485: draw_obj(ip, F_XOR, Fwd);
486: break;
487: case P_PRINT: /* print a string */
488: readstring(buf);
489: putstring(buf);
490: break;
491: case P_ERRPRINT: /* print an error string */
492: readstring(buf);
493: ERRPUT buf END;
494: break;
495: default:
496: if (overflow)
497: break;
498: putstring("do_rcv error; unrecognized command: ");
499: for (pbuf = buf; c != '\n'; c = readchar())
500: *pbuf++ = c;
501: *pbuf = 0;
502: putstring(buf);
503: break;
504: }
505: goto top;
506: }
507:
508: clear()
509: {
510: rectf(&display, Drect, F_CLR); /* clear screen */
511: }
512:
513:
514: uchar *read_obj() /* read an object, stick it in input[] */
515: {
516: int c, n, m;
517: uchar *p, *oinp = inp;
518:
519: if (inp > input+memsize-50) { /* eat up at least one */
520: ERRPUT "overflow at %u bytes, limit %u", inp - input, memsize END;
521: /* overflow++; */
522: /* return; */
523: oinp = inp = input; /* reset to see end of picture */
524: }
525: c = readchar();
526: switch (c) {
527: case ' ':
528: case '\n':
529: break;
530: case 'b':
531: case 'l':
532: slotnum = readint();
533: slot[slotnum] = inp-input;
534: p = savechar(c);
535: savechar(curview = readint());
536: savechar(readint()); /* options */
537: savept(readpt());
538: savept(readpt());
539: savect(inp-p);
540: break;
541: case 'o':
542: slotnum = readint();
543: slot[slotnum] = inp-input;
544: p = savechar(c);
545: savechar(curview = readint());
546: savechar(readint()); /* options */
547: savept(readpt());
548: saveint(readint()); /* radius */
549: savect(inp-p);
550: break;
551: case 't':
552: slotnum = readint();
553: slot[slotnum] = inp-input;
554: p = savechar(c);
555: savechar(curview = readint());
556: savechar(readint()); /* options */
557: savept(readpt());
558: n = readstring(inp+1); /* +1 leaves a hole */
559: *inp = n; /* insert count before string */
560: inp += n + 2; /* +2 = count before and \0 on end */
561: savect(inp-p);
562: break;
563: case 'e':
564: p = savechar(c);
565: savelong(slot[readint()]);
566: savect(inp-p);
567: break;
568: case 'c':
569: p = savechar(c);
570: savechar(readint());
571: savect(inp-p);
572: break;
573: }
574: return oinp;
575: }
576:
577: Point readpt() /* read a Point */
578: {
579: Point p;
580:
581: p.x = readint();
582: p.y = readint();
583: return p;
584: }
585:
586: uchar *savechar(c)
587: {
588: *inp++ = c;
589: return inp-1;
590: }
591:
592: savect(n)
593: {
594: if (n > 255)
595: putstring("text string too long");
596: *inp++ = n;
597: }
598:
599: saveint(n)
600: {
601: *inp++ = n >> 8;
602: *inp++ = n & 0377;
603: }
604:
605: savelong(n)
606: long n;
607: {
608: *inp++ = n >> 24;
609: *inp++ = n >> 16;
610: *inp++ = n >> 8;
611: *inp++ = n;
612: }
613:
614: savept(p)
615: Point p;
616: {
617: *inp++ = p.x >> 8;
618: *inp++ = p.x & 0377;
619: *inp++ = p.y >> 8;
620: *inp++ = p.y & 0377;
621: }
622:
623: getpoint(ip)
624: uchar *ip;
625: {
626: return *ip << 8 | *(ip+1);
627: }
628:
629: long getlong(ip)
630: uchar *ip;
631: {
632: return *ip << 24 | *(ip+1) << 16 | *(ip+2) << 8 | *(ip+3);
633: }
634:
635: Point scalept(v, p)
636: Point p;
637: {
638: p.x = muldiv(p.x, viewpt[v].xmax, 10000);
639: p.y = viewpt[v].ymax - muldiv(p.y, viewpt[v].ymax, 10000);
640: return p;
641: }
642:
643: scalex(v, n)
644: {
645: return muldiv(n, viewpt[v].xmax, 10000);
646: }
647:
648: Point fetchpt(v, ip)
649: int v;
650: uchar *ip;
651: {
652: Point pt;
653:
654: pt.x = *ip << 8 | *(ip+1);
655: pt.y = *(ip+2) << 8 | *(ip+3);
656: pt = scalept(v, pt);
657: return add(pt, viewpt[v].vr.origin);
658: }
659:
660: /*
661: Encoding: type, view#, opts, coords, chars, etc., # = length of group
662: bvoxxyyxxyy#
663: lvoxxyyxxyy#
664: ovoxxyyrr#
665: tvoxxyynccc0#
666: ennnn#
667: cn#
668:
669: */
670:
671: uchar *prev_obj(ip)
672: uchar *ip;
673: {
674: if (ip <= input)
675: return 0;
676: return ip - ip[-1] - 1;
677: }
678:
679: uchar *next_obj(ip)
680: uchar *ip;
681: {
682: if (ip < input || ip >= inp)
683: return 0;
684: switch (*ip) {
685: case 0:
686: return 0;
687: case 'b':
688: case 'l':
689: return ip + 12;
690: case 'o':
691: return ip + 10;
692: case 't':
693: return ip + ip[7] + 10;
694: case 'c':
695: return ip + 3;
696: case 'e':
697: return ip + 6;
698: default:
699: return 0;
700: }
701: }
702:
703: uchar *step_obj(ip, mode, dir) /* draw objs until one that changes something */
704: uchar *ip;
705: {
706: int c;
707:
708: while (ip) {
709: c = *ip;
710: ip = draw_obj(ip, mode, dir);
711: if (c == 'b' || c == 'l' || c == 't' || c == 'e' || c == 'o')
712: return ip;
713: }
714: return ip;
715: }
716:
717: uchar *click_obj(ip, mode, dir) /* draw objs until matching click */
718: uchar *ip;
719: {
720: int c;
721: uchar *oip;
722:
723: for (;;) {
724: oip = ip;
725: ip = draw_obj(ip, mode, dir);
726: if (ip == 0 || (oip && *oip == 'c' && clickval[oip[1]]))
727: return ip;
728: }
729: }
730:
731: uchar *draw_obj(ip, mode, dir) /* draw obj from coords at ip */
732: uchar *ip;
733: int mode, dir;
734: {
735: int c, r, thick, n, shift, head;
736: Point p0, p1, p2;
737:
738: if (ip < input || ip >= inp)
739: return 0;
740: switch (c = *ip++) {
741: case 'b':
742: p0 = fetchpt(*ip, ip+2);
743: p1 = fetchpt(*ip, ip+6);
744: if (ip[1] == Bfill) {
745: if (p0.y < p1.y)
746: rectf(&display, Rpt(p0, p1), mode);
747: else
748: rectf(&display, Rect(p0.x,p1.y,p1.x,p0.y), mode);
749: } else {
750: segment(&display, p0, Pt(p0.x,p1.y), mode);
751: segment(&display, Pt(p0.x,p1.y), p1, mode);
752: segment(&display, p1, Pt(p1.x,p0.y), mode);
753: segment(&display, Pt(p1.x,p0.y), p0, mode);
754: }
755: if (dir == Fwd)
756: ip += 1+9+1;
757: else
758: ip -= (*(ip-2) + 2);
759: break;
760: case 'l':
761: p0 = fetchpt(*ip, ip+2);
762: p1 = fetchpt(*ip, ip+6);
763: thick = ip[1]/10; /* ought to be a macro! */
764: if (thick == Ldotted/10 || thick == Ldashed/10)
765: thick = 1;
766: thick = 2 * thick - 1; /* 1,3,5 */
767: fatline(p0, p1, mode, thick);
768: head = ip[1]%10; /* ditto */
769: if (head == Larrow1 || head == Larrow3)
770: arrow(p0, p1, AW, AH, mode);
771: if (head == Larrow2 || head == Larrow3)
772: arrow(p1, p0, AW, AH, mode);
773: if (dir == Fwd)
774: ip += 1+9+1;
775: else
776: ip -= (*(ip-2) + 2);
777: break;
778: case 'o':
779: p0 = fetchpt(*ip, ip+2);
780: r = scalex(*ip, getpoint(ip+6));
781: if (ip[1] == Cnofill)
782: fatcircle(p0, r, mode, 1);
783: else
784: disc(&display, p0, r + fatness, mode);
785: if (dir == Fwd)
786: ip += 1+7+1;
787: else
788: ip -= (*(ip-2) + 2);
789: break;
790: case 't':
791: p0 = fetchpt(*ip, ip+2);
792: n = ip[6];
793: shift = (ip[1]/10) * 10; /* ought to be a macro! */
794: if (shift == Tljust)
795: shift = 0;
796: else if (shift == Tcenter)
797: shift = (9 * n) / 2; /* 9 = char width */
798: else
799: shift = 9 * n;
800: string(&defont, ip+7, &display, sub(p0, Pt(shift,8)), mode);
801: if (dir == Fwd)
802: ip += 1+5 + *(ip+6)+2 + 1;
803: else
804: ip -= (*(ip-2) + 2);
805: break;
806: case 'e':
807: erase(ip-1);
808: if (dir == Fwd)
809: ip += 5;
810: else
811: ip -= (*(ip-2) + 2);
812: break;
813: case 'c':
814: if (dir == Fwd)
815: ip += 2;
816: else
817: ip -= (*(ip-2) + 2);
818: break;
819: default:
820: ip = 0;
821: break;
822: }
823: return ip;
824: }
825:
826: erase(ip)
827: uchar *ip;
828: {
829: long target = getlong(ip+1); /* target label index */
830: int mode = F_XOR;
831:
832: if (xormode == F_OR || xormode == F_CLR)
833: mode = dir == Fwd ? F_CLR : F_OR;
834: draw_obj(input+target, mode, Fwd);
835: }
836:
837: #define abs(x) ((x) >= 0 ? (x) : -(x))
838:
839: fatline(p0, p1, mode, thick)
840: Point p0, p1;
841: {
842: int i, fat, beg, nl;
843:
844: fat = thick * (2 * fatness + 1);
845: beg = fat / 2;
846: if (abs(p1.x-p0.x) >= abs(p1.y-p0.y)) { /* horizontal */
847: for (nl = 0, i = -beg; nl < fat; nl++, i++)
848: segment(&display, add(p0, Pt(0,i)), add(p1, Pt(0,i)), mode);
849: } else {
850: for (nl = 0, i = -beg; nl < fat; nl++, i++)
851: segment(&display, add(p0, Pt(i,0)), add(p1, Pt(i,0)), mode);
852: }
853: }
854:
855: fatcircle(p0, r, mode, thick)
856: Point p0;
857: int r, mode, thick;
858: {
859: int i, fat, beg, nl;
860:
861: fat = thick * (2 * fatness + 1);
862: beg = fat / 2;
863: for (nl = 0, i = -beg; nl < fat; nl++, i++)
864: circle(&display, p0, r+i, mode);
865: }
866:
867: arrow(p1, p2, w, h, c)
868: Point p1, p2;
869: int w, h, c;
870: /*
871: ** draw arrow of height,width (h,w) at p2 of segment p1,p2.
872: */
873: {
874: Point d;
875: int norm, qx, qy, lx, ly;
876:
877: d = sub(p2, p1);
878: norm = sqrt((long)d.x*d.x + (long)d.y*d.y);
879: if (norm == 0) /* shouldn't happen, but ... */
880: return;
881: qx = p2.x - muldiv(h, d.x, norm);
882: qy = p2.y - muldiv(h, d.y, norm);
883: lx = muldiv(w/2, -d.y, norm);
884: ly = muldiv(w/2, d.x, norm);
885: /* segment(&display, p1, p2, c); */
886: segment(&display, Pt(qx+lx, qy+ly), p2, c);
887: segment(&display, Pt(qx-lx, qy-ly), p2, c);
888: }
889:
890: but(n) /* parameterize button1(), etc. */
891: int n;
892: {
893: switch (n) {
894: case 1: return button1();
895: case 2: return button2();
896: case 3: return button3();
897: case 12: return button12();
898: case 13: return button1()|button3(); /* not built in */
899: case 23: return button23();
900: case 123: return button123();
901: default: return 0;
902: }
903: }
904:
905: checkmouse() /* return button touched if any */
906: {
907: int c, b;
908: char *p = NULL;
909: Point dp;
910: Texture *tp;
911:
912: if (!(own()&MOUSE) || !button123())
913: return 0; /* no hit at all */
914: tp = cursswitch(PTR);
915: last_but = 0;
916: last_hit = -1;
917: c = 0;
918: if (button3()) {
919: last_hit = menuhit(&mbut3, 3);
920: last_but = 3;
921: } else if (button2()) {
922: last_hit = menuhit(&mbut2, 2);
923: last_but = 2;
924: } else { /* button1() */
925: last_but = 1;
926: }
927: while (button123())
928: wait(MOUSE);
929: if (last_but == 3 && last_hit>=0) {
930: p = m3[last_hit];
931: c = p[strlen(p) - 1];
932: }
933: if (c == '?' && !confirm(last_but))
934: last_hit = -1;
935: cursswitch(tp);
936: return last_but;
937: }
938:
939: confirm(but) /* ask for confirmation if menu item ends with '?' */
940: {
941: int c;
942: static int but_cvt[8] = { 0, 3, 2, 0, 1, 0, 0, 0 };
943: Texture *tp;
944:
945: tp = cursswitch(&skull);
946: while (!button123())
947: wait(MOUSE);
948: c = mouse.buttons & 7;
949: while (button123())
950: wait(MOUSE);
951: cursswitch(tp);
952: return but == but_cvt[c];
953: }
954:
955: putstring(a1, a2, a3, a4, a5)
956: char *a1, *a2, *a3, *a4, *a5;
957: {
958: static Point p = {0, 0};
959: static int jmax = 0, l;
960: char buf[100], *s;
961:
962: p = Drect.origin;
963: if (errline)
964: p.y += 16;
965: sprintf(buf, a1, a2, a3, a4, a5);
966: rectf(&display, Rect(p.x,p.y,p.x+jmax,p.y+16), F_CLR);
967: string(&defont, buf, &display, p, F_OR);
968: if ((l = jstrwidth(buf)) > jmax)
969: jmax = l;
970: errline = 0;
971: }
972:
973: assert(c, s) /* poor man's assertion */
974: char *s;
975: {
976: if (!c) {
977: putstring("assertion %s failed\n", s);
978: sleep(60);
979: }
980: }
981:
982: readbyte()
983: {
984: int c;
985:
986: if ((c = rcvchar()) == -1) {
987: wait(RCV);
988: c = rcvchar();
989: }
990: return c;
991: }
992:
993: sendbuf(buf, p)
994: char *buf, *p;
995: {
996: sendnchars((int) (p-buf), buf);
997: }
998:
999: do_kbd()
1000: {
1001: int c;
1002:
1003: pkbd = kbdline;
1004: for (wait(KBD); (c = kbdchar()) != -1; wait(KBD)) {
1005: if (c == '\b' && pkbd > kbdline)
1006: --pkbd;
1007: else if (c == '@')
1008: pkbd = kbdline;
1009: else
1010: *pkbd++ = c;
1011: *pkbd = '\0';
1012: rectf(&display, Rect(Do.x,Do.y,Dc.x,Do.y+16), F_CLR);
1013: string(&defont, kbdline, &display, Do, F_STORE);
1014: if (c == '\n' || c == '\r') {
1015: pkbd[-1] = '\0';
1016: return '\n';
1017: }
1018: }
1019: }
1020:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.