|
|
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 10
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, dx, dy;
411:
412: dx = (Dc.x - Do.x) / 2;
413: dy = (Dc.y - Do.y) / 2;
414: viewpt[0].vr = Drect;
415: switch (n) {
416: case 2:
417: viewpt[1].vr = Drect;
418: viewpt[0].vr.corner.y -= dy;
419: viewpt[1].vr.origin.y += dy;
420: break;
421: case 3: case 4:
422: viewpt[0].vr.corner = add(Drect.origin, Pt(dx,dy));
423: viewpt[1].vr = raddp(viewpt[0].vr, Pt(0,dy));
424: viewpt[2].vr = raddp(viewpt[0].vr, Pt(dx,0));
425: viewpt[3].vr = raddp(viewpt[0].vr, Pt(dx,dy));
426: break;
427: }
428: for (i = 0; i < n; i++) {
429: viewpt[i].vr = shrink(viewpt[i].vr, MARGINPCT);
430: viewpt[i].xmax = viewpt[i].vr.corner.x - viewpt[i].vr.origin.x;
431: viewpt[i].ymax = viewpt[i].vr.corner.y - viewpt[i].vr.origin.y;
432: }
433: }
434:
435: drawrect(r, mode)
436: Rectangle r;
437: {
438: segment(&display, r.origin, Pt(r.origin.x,r.corner.y), mode);
439: segment(&display, r.origin, Pt(r.corner.x,r.origin.y), mode);
440: segment(&display, r.corner, Pt(r.origin.x,r.corner.y), mode);
441: segment(&display, r.corner, Pt(r.corner.x,r.origin.y), mode);
442: }
443:
444: do_rcv()
445: {
446: int c, n, b, m, i;
447: uchar *ip;
448:
449: top:
450: switch (c = readchar()) {
451: case P_INIT: /* initialize */
452: break;
453: case P_ENDFILE:
454: *inp = 0;
455: return;
456: case P_CLEAR:
457: clear();
458: break;
459: case P_DEFINE:
460: /* view, click, ... */
461: c = readchar();
462: assert(c == 'c' || c == 'v', "illegal define");
463: i = readint();
464: readstring(buf);
465: if (c == 'c') {
466: clickname[i] = alloc(strlen(buf)+1);
467: strcpy(clickname[i], buf);
468: nclick++;
469: } else { /* c == 'v' */
470: viewname[i] = alloc(strlen(buf)+1);
471: strcpy(viewname[i], buf);
472: nview++;
473: }
474: break;
475: case P_OBJECT: /* read an object */
476: if (nobj++ == 0)
477: view_setup(nview);
478: if (nobj % 100 == 0)
479: PUT "%d objects, %u/%u bytes", nobj, inp-input, memsize END
480: ip = read_obj();
481: draw_obj(ip, F_XOR, Fwd);
482: break;
483: case P_PRINT: /* print a string */
484: readstring(buf);
485: putstring(buf);
486: break;
487: case P_ERRPRINT: /* print an error string */
488: readstring(buf);
489: ERRPUT buf END;
490: break;
491: default:
492: if (overflow)
493: break;
494: putstring("do_rcv error; unrecognized command: ");
495: for (pbuf = buf; c != '\n'; c = readchar())
496: *pbuf++ = c;
497: *pbuf = 0;
498: putstring(buf);
499: break;
500: }
501: goto top;
502: }
503:
504: clear()
505: {
506: rectf(&display, Drect, F_CLR); /* clear screen */
507: }
508:
509:
510: uchar *read_obj() /* read an object, stick it in input[] */
511: {
512: int c, n, m;
513: uchar *p, *oinp = inp;
514:
515: if (inp > input+memsize-50) { /* eat up at least one */
516: ERRPUT "overflow at %u bytes, limit %u", inp - input, memsize END;
517: /* overflow++; */
518: /* return; */
519: oinp = inp = input; /* reset to see end of picture */
520: }
521: c = readchar();
522: switch (c) {
523: case ' ':
524: case '\n':
525: break;
526: case 'b':
527: case 'l':
528: slotnum = readint();
529: slot[slotnum] = inp-input;
530: p = savechar(c);
531: savechar(curview = readint());
532: savechar(readint()); /* options */
533: savept(readpt());
534: savept(readpt());
535: savect(inp-p);
536: break;
537: case 'o':
538: slotnum = readint();
539: slot[slotnum] = inp-input;
540: p = savechar(c);
541: savechar(curview = readint());
542: savechar(readint()); /* options */
543: savept(readpt());
544: saveint(readint()); /* radius */
545: savect(inp-p);
546: break;
547: case 't':
548: slotnum = readint();
549: slot[slotnum] = inp-input;
550: p = savechar(c);
551: savechar(curview = readint());
552: savechar(readint()); /* options */
553: savept(readpt());
554: n = readstring(inp+1); /* +1 leaves a hole */
555: *inp = n; /* insert count before string */
556: inp += n + 2; /* +2 = count before and \0 on end */
557: savect(inp-p);
558: break;
559: case 'e':
560: p = savechar(c);
561: savelong(slot[readint()]);
562: savect(inp-p);
563: break;
564: case 'c':
565: p = savechar(c);
566: savechar(readint());
567: savect(inp-p);
568: break;
569: }
570: return oinp;
571: }
572:
573: Point readpt() /* read a Point */
574: {
575: Point p;
576:
577: p.x = readint();
578: p.y = readint();
579: return p;
580: }
581:
582: uchar *savechar(c)
583: {
584: *inp++ = c;
585: return inp-1;
586: }
587:
588: savect(n)
589: {
590: if (n > 255)
591: putstring("text string too long");
592: *inp++ = n;
593: }
594:
595: saveint(n)
596: {
597: *inp++ = n >> 8;
598: *inp++ = n & 0377;
599: }
600:
601: savelong(n)
602: long n;
603: {
604: *inp++ = n >> 24;
605: *inp++ = n >> 16;
606: *inp++ = n >> 8;
607: *inp++ = n;
608: }
609:
610: savept(p)
611: Point p;
612: {
613: *inp++ = p.x >> 8;
614: *inp++ = p.x & 0377;
615: *inp++ = p.y >> 8;
616: *inp++ = p.y & 0377;
617: }
618:
619: getpoint(ip)
620: uchar *ip;
621: {
622: return *ip << 8 | *(ip+1);
623: }
624:
625: long getlong(ip)
626: uchar *ip;
627: {
628: return *ip << 24 | *(ip+1) << 16 | *(ip+2) << 8 | *(ip+3);
629: }
630:
631: Point scalept(v, p)
632: Point p;
633: {
634: p.x = muldiv(p.x, viewpt[v].xmax, 10000);
635: p.y = viewpt[v].ymax - muldiv(p.y, viewpt[v].ymax, 10000);
636: return p;
637: }
638:
639: scalex(v, n)
640: {
641: return muldiv(n, viewpt[v].xmax, 10000);
642: }
643:
644: Point fetchpt(v, ip)
645: int v;
646: uchar *ip;
647: {
648: Point pt;
649:
650: pt.x = *ip << 8 | *(ip+1);
651: pt.y = *(ip+2) << 8 | *(ip+3);
652: pt = scalept(v, pt);
653: return add(pt, viewpt[v].vr.origin);
654: }
655:
656: /*
657: Encoding: type, view#, opts, coords, chars, etc., # = length of group
658: bvoxxyyxxyy#
659: lvoxxyyxxyy#
660: ovoxxyyrr#
661: tvoxxyynccc0#
662: ennnn#
663: cn#
664:
665: */
666:
667: uchar *prev_obj(ip)
668: uchar *ip;
669: {
670: if (ip <= input)
671: return 0;
672: return ip - ip[-1] - 1;
673: }
674:
675: uchar *next_obj(ip)
676: uchar *ip;
677: {
678: if (ip < input || ip >= inp)
679: return 0;
680: switch (*ip) {
681: case 0:
682: return 0;
683: case 'b':
684: case 'l':
685: return ip + 12;
686: case 'o':
687: return ip + 10;
688: case 't':
689: return ip + ip[7] + 10;
690: case 'c':
691: return ip + 3;
692: case 'e':
693: return ip + 6;
694: default:
695: return 0;
696: }
697: }
698:
699: uchar *step_obj(ip, mode, dir) /* draw objs until one that changes something */
700: uchar *ip;
701: {
702: int c;
703:
704: while (ip) {
705: c = *ip;
706: ip = draw_obj(ip, mode, dir);
707: if (c == 'b' || c == 'l' || c == 't' || c == 'e' || c == 'o')
708: return ip;
709: }
710: return ip;
711: }
712:
713: uchar *click_obj(ip, mode, dir) /* draw objs until matching click */
714: uchar *ip;
715: {
716: int c;
717: uchar *oip;
718:
719: for (;;) {
720: oip = ip;
721: ip = draw_obj(ip, mode, dir);
722: if (ip == 0 || (oip && *oip == 'c' && clickval[oip[1]]))
723: return ip;
724: }
725: }
726:
727: uchar *draw_obj(ip, mode, dir) /* draw obj from coords at ip */
728: uchar *ip;
729: int mode, dir;
730: {
731: int c, r, thick, n, shift, head;
732: Point p0, p1, p2;
733:
734: if (ip < input || ip >= inp)
735: return 0;
736: switch (c = *ip++) {
737: case 'b':
738: p0 = fetchpt(*ip, ip+2);
739: p1 = fetchpt(*ip, ip+6);
740: if (ip[1] == Bfill) {
741: if (p0.y < p1.y)
742: rectf(&display, Rpt(p0, p1), mode);
743: else
744: rectf(&display, Rect(p0.x,p1.y,p1.x,p0.y), mode);
745: } else {
746: segment(&display, p0, Pt(p0.x,p1.y), mode);
747: segment(&display, Pt(p0.x,p1.y), p1, mode);
748: segment(&display, p1, Pt(p1.x,p0.y), mode);
749: segment(&display, Pt(p1.x,p0.y), p0, mode);
750: }
751: if (dir == Fwd)
752: ip += 1+9+1;
753: else
754: ip -= (*(ip-2) + 2);
755: break;
756: case 'l':
757: p0 = fetchpt(*ip, ip+2);
758: p1 = fetchpt(*ip, ip+6);
759: thick = ip[1]/10; /* ought to be a macro! */
760: if (thick == Ldotted/10 || thick == Ldashed/10)
761: thick = 1;
762: thick = 2 * thick - 1; /* 1,3,5 */
763: fatline(p0, p1, mode, thick);
764: head = ip[1]%10; /* ditto */
765: if (head == Larrow1 || head == Larrow3)
766: arrow(p0, p1, AW, AH, mode);
767: if (head == Larrow2 || head == Larrow3)
768: arrow(p1, p0, AW, AH, mode);
769: if (dir == Fwd)
770: ip += 1+9+1;
771: else
772: ip -= (*(ip-2) + 2);
773: break;
774: case 'o':
775: p0 = fetchpt(*ip, ip+2);
776: r = scalex(*ip, getpoint(ip+6));
777: if (ip[1] == Cnofill)
778: fatcircle(p0, r, mode, 1);
779: else
780: disc(&display, p0, r + fatness, mode);
781: if (dir == Fwd)
782: ip += 1+7+1;
783: else
784: ip -= (*(ip-2) + 2);
785: break;
786: case 't':
787: p0 = fetchpt(*ip, ip+2);
788: n = ip[6];
789: shift = (ip[1]/10) * 10; /* ought to be a macro! */
790: if (shift == Tljust)
791: shift = 0;
792: else if (shift == Tcenter)
793: shift = (9 * n) / 2; /* 9 = char width */
794: else
795: shift = 9 * n;
796: string(&defont, ip+7, &display, sub(p0, Pt(shift,8)), mode);
797: if (dir == Fwd)
798: ip += 1+5 + *(ip+6)+2 + 1;
799: else
800: ip -= (*(ip-2) + 2);
801: break;
802: case 'e':
803: erase(ip-1);
804: if (dir == Fwd)
805: ip += 5;
806: else
807: ip -= (*(ip-2) + 2);
808: break;
809: case 'c':
810: if (dir == Fwd)
811: ip += 2;
812: else
813: ip -= (*(ip-2) + 2);
814: break;
815: default:
816: ip = 0;
817: break;
818: }
819: return ip;
820: }
821:
822: erase(ip)
823: uchar *ip;
824: {
825: long target = getlong(ip+1); /* target label index */
826: int mode = F_XOR;
827:
828: if (xormode == F_OR || xormode == F_CLR)
829: mode = dir == Fwd ? F_CLR : F_OR;
830: draw_obj(input+target, mode, Fwd);
831: }
832:
833: #define abs(x) ((x) >= 0 ? (x) : -(x))
834:
835: fatline(p0, p1, mode, thick)
836: Point p0, p1;
837: {
838: int i, fat, beg, nl;
839:
840: fat = thick * (2 * fatness + 1);
841: beg = fat / 2;
842: if (abs(p1.x-p0.x) >= abs(p1.y-p0.y)) { /* horizontal */
843: for (nl = 0, i = -beg; nl < fat; nl++, i++)
844: segment(&display, add(p0, Pt(0,i)), add(p1, Pt(0,i)), mode);
845: } else {
846: for (nl = 0, i = -beg; nl < fat; nl++, i++)
847: segment(&display, add(p0, Pt(i,0)), add(p1, Pt(i,0)), mode);
848: }
849: }
850:
851: fatcircle(p0, r, mode, thick)
852: Point p0;
853: int r, mode, thick;
854: {
855: int i, fat, beg, nl;
856:
857: fat = thick * (2 * fatness + 1);
858: beg = fat / 2;
859: for (nl = 0, i = -beg; nl < fat; nl++, i++)
860: circle(&display, p0, r+i, mode);
861: }
862:
863: arrow(p1, p2, w, h, c)
864: Point p1, p2;
865: int w, h, c;
866: /*
867: ** draw arrow of height,width (h,w) at p2 of segment p1,p2.
868: */
869: {
870: Point d;
871: int norm, qx, qy, lx, ly;
872:
873: d = sub(p2, p1);
874: norm = sqrt((long)d.x*d.x + (long)d.y*d.y);
875: if (norm == 0) /* shouldn't happen, but ... */
876: return;
877: qx = p2.x - muldiv(h, d.x, norm);
878: qy = p2.y - muldiv(h, d.y, norm);
879: lx = muldiv(w/2, -d.y, norm);
880: ly = muldiv(w/2, d.x, norm);
881: /* segment(&display, p1, p2, c); */
882: segment(&display, Pt(qx+lx, qy+ly), p2, c);
883: segment(&display, Pt(qx-lx, qy-ly), p2, c);
884: }
885:
886: but(n) /* parameterize button1(), etc. */
887: int n;
888: {
889: switch (n) {
890: case 1: return button1();
891: case 2: return button2();
892: case 3: return button3();
893: case 12: return button12();
894: case 13: return button1()|button3(); /* not built in */
895: case 23: return button23();
896: case 123: return button123();
897: default: return 0;
898: }
899: }
900:
901: checkmouse() /* return button touched if any */
902: {
903: int c, b;
904: char *p = NULL;
905: Point dp;
906: Texture *tp;
907:
908: if (!(own()&MOUSE) || !button123())
909: return 0; /* no hit at all */
910: tp = cursswitch(PTR);
911: last_but = 0;
912: last_hit = -1;
913: c = 0;
914: if (button3()) {
915: last_hit = menuhit(&mbut3, 3);
916: last_but = 3;
917: } else if (button2()) {
918: last_hit = menuhit(&mbut2, 2);
919: last_but = 2;
920: } else { /* button1() */
921: last_but = 1;
922: }
923: while (button123())
924: wait(MOUSE);
925: if (last_but == 3 && last_hit>=0) {
926: p = m3[last_hit];
927: c = p[strlen(p) - 1];
928: }
929: if (c == '?' && !confirm(last_but))
930: last_hit = -1;
931: cursswitch(tp);
932: return last_but;
933: }
934:
935: confirm(but) /* ask for confirmation if menu item ends with '?' */
936: {
937: int c;
938: static int but_cvt[8] = { 0, 3, 2, 0, 1, 0, 0, 0 };
939: Texture *tp;
940:
941: tp = cursswitch(&skull);
942: while (!button123())
943: wait(MOUSE);
944: c = mouse.buttons & 7;
945: while (button123())
946: wait(MOUSE);
947: cursswitch(tp);
948: return but == but_cvt[c];
949: }
950:
951: putstring(a1, a2, a3, a4, a5)
952: char *a1, *a2, *a3, *a4, *a5;
953: {
954: static Point p = {0, 0};
955: static int jmax = 0, l;
956: char buf[100], *s;
957:
958: p = Drect.origin;
959: if (errline)
960: p.y += 16;
961: sprintf(buf, a1, a2, a3, a4, a5);
962: rectf(&display, Rect(p.x,p.y,p.x+jmax,p.y+16), F_CLR);
963: string(&defont, buf, &display, p, F_OR);
964: if ((l = jstrwidth(buf)) > jmax)
965: jmax = l;
966: errline = 0;
967: }
968:
969: assert(c, s) /* poor man's assertion */
970: char *s;
971: {
972: if (!c) {
973: putstring("assertion %s failed\n", s);
974: sleep(60);
975: }
976: }
977:
978: readbyte()
979: {
980: int c;
981:
982: if ((c = rcvchar()) == -1) {
983: wait(RCV);
984: c = rcvchar();
985: }
986: return c;
987: }
988:
989: sendbuf(buf, p)
990: char *buf, *p;
991: {
992: sendnchars((int) (p-buf), buf);
993: }
994:
995: do_kbd()
996: {
997: int c;
998:
999: pkbd = kbdline;
1000: for (wait(KBD); (c = kbdchar()) != -1; wait(KBD)) {
1001: if (c == '\b' && pkbd > kbdline)
1002: --pkbd;
1003: else if (c == '@')
1004: pkbd = kbdline;
1005: else
1006: *pkbd++ = c;
1007: *pkbd = '\0';
1008: rectf(&display, Rect(Do.x,Do.y,Dc.x,Do.y+16), F_CLR);
1009: string(&defont, kbdline, &display, Do, F_STORE);
1010: if (c == '\n' || c == '\r') {
1011: pkbd[-1] = '\0';
1012: return '\n';
1013: }
1014: }
1015: }
1016:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.