|
|
1.1 root 1: #include "univ.h"
2: Selection Selected;
3: Pad *Current;
4: long HostObject;
5: long HostParent;
6: short Scrolly;
7: Point Zpoint;
8: Rectangle ZRectangle;
9: Pad *DirtyPad;
10:
11: Pad Sentinel = { 0, 0, 0, 0, 0, &Sentinel, &Sentinel };
12: Rectangle PadSpace;
13: Rectangle KBDrect;
14: Attrib NewFold;
15:
16: #define ISPAD(p) ((p) != &Sentinel)
17: #define ISLINE(l,p) ((l) != &(p)->sentinel) /* used how much? */
18:
19: Point PickPoint(s)
20: char *s;
21: {
22: char *pick = "pick window: ";
23: Point p;
24: cursswitch(&Bullseye);
25: if( s ) InvertKBDrect( pick, s );
26: while( !button123() ) waitMOUSE();
27: p = (butts==BUTT2 || butts==BUTT3) ? mouse.xy: Zpoint;
28: cursswitch( Pcursor );
29: PaintKBD();
30: return p;
31: }
32:
33: #define MINWD 50
34: #define MINHT 50
35: PadSized( r )
36: Rectangle r;
37: {
38: return r.corner.x-r.origin.x > MINWD && r.corner.y-r.origin.y > MINHT;
39: }
40:
41: #define SWEEP 125
42: int SWEEPTIMEOUT = 1000*15;
43: Rectangle clipgetrect(s)
44: register char *s;
45: {
46: Rectangle r, r1;
47: register long start;
48: Point p1, p2;
49:
50: if( s ) InvertKBDrect( "sweep ", s );
51: for( start = realtime(); ; jnap(2) ){
52: if( ptinrect(mouse.xy, inset(PadSpace,-SWEEP)) )
53: break;
54: if( realtime()>start+SWEEPTIMEOUT ){
55: r = Drect;
56: while( PadSized(r1= inset(r,1)) )
57: r = r1;
58: goto TimedOut;
59: }
60: }
61: r = getrect23();
62: if( r.corner.x && r.corner.x-r.origin.x<=5 && r.corner.y-r.origin.y<=5 )
63: r = Drect; /* from jim */
64: TimedOut:
65: PaintKBD();
66: if( !rectclip( &r, PadSpace ) ) return ZRectangle;
67: return r;
68: }
69:
70: DelLine( l )
71: register Line *l;
72: {
73: assert( l && l->down && l->up );
74:
75: if( Selected.line == l ) Selected.line = 0;
76: l->down->up = l->up;
77: l->up->down = l->down;
78: gcfree( l->text );
79: free( l );
80: }
81:
82: Line *InsAbove(l, t)
83: register Line *l;
84: register Line *t;
85: {
86: register Line *n;
87:
88: assert( l && l->down && l->up );
89: if( !t->text ) return 0; /* || !t->text[0] allow */
90: n = salloc(Line);
91: *n = *t;
92: GCString(&n->text, t->text);
93: n->down = l;
94: n->up = l->up;
95: l->up->down = n;
96: l->up = n;
97: return n;
98: }
99:
100: Line *InsPos(p, tk)
101: register Pad *p;
102: register Line *tk;
103: {
104: register Line *l = &p->sentinel;
105:
106: assert( p && tk );
107: if( (p->attributes&SORTED) && tk->text ){
108: while( ISLINE(l->up,p) && !dictorder(l->up->text,tk->text) )
109: l = l->up;
110: } else {
111: while( ISLINE(l->up,p) && l->up->key > tk->key )
112: l = l->up;
113: }
114: return l;
115: }
116:
117: CreateLine(p)
118: register Pad *p;
119: {
120: register long lo, hi, k;
121: register Line *inspos, *l;
122: Line fake;
123: register char tilde;
124:
125: lo = RcvLong();
126: hi = RcvLong();
127: if( p->sentinel.key || p->attributes&SORTED ) return;
128: tilde = p->attributes&NO_TILDE ? 0 : '~';
129: for( k = lo; k <= hi; ++k ) if( k ){
130: fake.key = k;
131: fake.carte = 0;
132: fake.attributes = FAKELINE;
133: fake.text = itoa(k);
134: *fake.text = tilde;
135: inspos = InsPos(p, &fake);
136: if( inspos->up->key == k )
137: DelLine( inspos->up );
138: InsAbove(inspos, &fake);
139: p->attributes |= FAKELINE;
140: Dirty(p);
141: }
142: }
143:
144: PutLine(p,op)
145: register Pad *p;
146: Protocol op;
147: {
148: static Line prevrcvd;
149: Line rcvd;
150: char text[256]; /* 256 ? */
151: register Line *l, *inspos;
152:
153: rcvd = prevrcvd;
154: rcvd.object = RcvLong();
155: if( op == P_NEXTLINE )
156: rcvd.key = ++prevrcvd.key;
157: else {
158: rcvd.key = RcvLong();
159: rcvd.carte = RcvShort();
160: rcvd.attributes = RcvShort();
161: prevrcvd = rcvd;
162: }
163: RcvString(rcvd.text = text);
164: if( !p ) return;
165: if( p->sentinel.key && rcvd.key>p->sentinel.key ) return;
166: inspos = InsPos(p, &rcvd);
167: {
168: extern Script ObjScript;
169: rcvd.phit = ObjScript.prevhit;
170: rcvd.ptop = ObjScript.prevtop;
171: }
172: if( rcvd.attributes&SELECTLINE ) MakeCurrent(p);
173: for( l = p->sentinel.up; ISLINE(l,p); l = l->up ){
174: if( l->key == rcvd.key ){
175: if( l == Selected.line )
176: rcvd.attributes |= SELECTLINE;
177: if( !strcmp(rcvd.text, l->text)
178: && rcvd.object == l->object
179: && rcvd.carte == l->carte
180: && rcvd.attributes == l->attributes
181: && !(rcvd.attributes&SELECTLINE) )
182: return;
183: inspos = l->down;
184: if( NewFold = l->attributes & (FOLD|TRUNCATE) )
185: FoldToggle( &rcvd.attributes );
186: rcvd.phit = l->phit;
187: rcvd.ptop = l->ptop;
188: DelLine( l );
189: break;
190: }
191: }
192: l = InsAbove(inspos, &rcvd);
193: if( !(rcvd.attributes&DONT_DIRTY) ) Dirty(p);
194: if( l && rcvd.attributes&SELECTLINE ){ /* selected <= "" !! */
195: Selected.line = l;
196: Selected.pad = p;
197: Paint(p);
198: }
199: }
200:
201: SetCurrent( p )
202: register Pad *p;
203: {
204: if( Current ) HeavyBorder(Current);
205: if( Current = p ) HeavyBorder( p );
206: }
207:
208: PaintCurrent()
209: {
210: if( Current ) Paint(Current);
211: }
212:
213: LineXOR( l )
214: Line *l;
215: {
216: rectf( &display, l->rect, F_XOR );
217: }
218:
219: Cover Covered( p ) /* should be smarter */
220: register Pad *p;
221: {
222: register Pad *f;
223:
224: for( f = p->front; ISPAD(f); f = f->front )
225: if( rectinrect( p->rect, f->rect ) ) return COMPLETE;
226: for( f = p->front; ISPAD(f); f = f->front )
227: if( rectXrect( p->rect, f->rect ) ) return PARTIAL;
228: return CLEAR;
229: }
230:
231: Dirty(p)
232: Pad *p;
233: {
234: if( p == DirtyPad ) return;
235: if( DirtyPad && Covered(DirtyPad)!=COMPLETE )
236: if( !ClipPaint(DirtyPad->rect, DirtyPad) )
237: PaintForward( DirtyPad->rect, DirtyPad->front );
238: DirtyPad = p;
239: }
240:
241: Linkin(p)
242: register Pad *p;
243: {
244: SetCurrent( (Pad *) 0 );
245: p->back = Sentinel.back;
246: p->back->front = p;
247: p->front = &Sentinel;
248: Sentinel.back = p;
249: if( PadSized(p->rect) ) SetCurrent(p);
250: }
251:
252: Unlink(p)
253: register Pad *p;
254: {
255: if( p == Current ) SetCurrent( (Pad *) 0 );
256: p->back->front = p->front;
257: p->front->back = p->back;
258: p->front = p->back = 0; /* redundant - but caught an mcc bug! */
259: }
260:
261: FrontLink(p)
262: register Pad *p;
263: {
264: if( !p ) return;
265: Unlink(p);
266: Linkin(p);
267: }
268:
269: PaintForward( r, p )
270: Rectangle r;
271: register Pad *p;
272: {
273: for( ; p != &Sentinel; p = p->front ){
274: if( rectXrect(r, p->rect) && Covered(p)!=COMPLETE ){
275: if( !ClipPaint( r, p ) )
276: r = boundrect(r,p->rect);
277: }
278: jerqsync();
279: }
280: }
281:
282: Refresh( r )
283: Rectangle r;
284: {
285: rectf( &display, r, F_CLR );
286: PaintForward( r, Sentinel.front );
287: }
288:
289: char NewString[] = "<new>";
290:
291: void P_Define( p, o )
292: register Pad *p;
293: long o;
294: {
295: if( !p ){
296: p = salloc(Pad); /* zeros */
297: p->sentinel.up = p->sentinel.down = &p->sentinel;
298: p->sentinel.ptop = 255;
299: Linkin(p);
300: p->object = o;
301: p->name = NewString;
302: p->sentinel.text = NewString;
303: p->tabs = 8;
304: p->selkey = 0;
305: }
306: Dirty(p);
307: }
308:
309: void P_Carte(p)
310: register Pad *p;
311: {
312: register Index i = RcvShort();
313: if( p && p->object ) p->carte = i;
314: }
315:
316: void P_Lines(p)
317: register Pad *p;
318: {
319: register long k = RcvLong();
320: if( p ){
321: if( k < p->sentinel.key ) DelLines(p);
322: p->sentinel.key = k;
323: Dirty(p);
324: }
325: }
326:
327: void P_Banner(p)
328: register Pad *p;
329: {
330: char b[256];
331:
332: RcvString(b);
333: if( p ){
334: if( p->sentinel.text != NewString ) gcfree( p->sentinel.text );
335: GCString( &p->sentinel.text, b );
336: Dirty(p);
337: }
338: }
339:
340: void P_Name(p)
341: register Pad *p;
342: {
343: char n[256];
344:
345: RcvString(n);
346: if( p ){
347: if( p->name != NewString ) gcfree( p->name );
348: GCString( &p->name, n );
349: }
350: }
351:
352: void P_Attributes(p)
353: register Pad *p;
354: {
355: register Attrib a = RcvShort();
356: if( p ) p->attributes = a;
357: }
358:
359: void P_Tabs(p)
360: register Pad *p;
361: {
362: register short t = RcvShort();
363: if( p && t>0 && t<128 ) p->tabs = t;
364: Dirty(p);
365: }
366:
367: void P_RemoveLine(p)
368: register Pad *p;
369: {
370: register long k = RcvLong();
371: register Line *l;
372:
373: if( !p ) return;
374: for( l = p->sentinel.up; ISLINE(l,p); l = l->up ){
375: if( l->key == k ){
376: DelLine( l );
377: Dirty(p);
378: return;
379: }
380: }
381:
382: }
383:
384:
385: Pad *ObjToPad(o)
386: register long o;
387: {
388: register Pad *p;
389:
390: for( p = Sentinel.back; ISPAD(p); p = p->back )
391: if( p->object == o ) return p;
392: return 0;
393: }
394:
395: Cycle()
396: {
397: register Pad *p;
398: int active = 0;
399:
400: for( p = Sentinel.back; ISPAD(p); p = p->back ){
401: if( p->ticks>0 ){
402: active++;
403: if( --p->ticks == 0 ){
404: active--;
405: HostParent = HostObject = p->object;
406: ToHost( P_CYCLE /*, garbage */ );
407: }
408: }
409: }
410: return active;
411: }
412:
413: MakeGap(p)
414: Pad *p;
415: {
416: register Line *l, *lsent = &p->sentinel;
417: register long k = RcvLong();
418: register long gap = RcvLong();
419:
420: for( l = lsent->down; l!=lsent; l = l->down )
421: if( l->key >= k ) l->key += gap;
422: }
423:
424: PadOp(op)
425: Protocol op;
426: {
427: static long LINEobj;
428: register long obj;
429: register Pad *p;
430: register short t;
431:
432: obj = op == P_NEXTLINE ? LINEobj : RcvLong();
433: p = ObjToPad( obj );
434: switch( (int) op ){
435: case P_PADDEF:
436: P_Define(p,obj);
437: break;
438: case P_ATTRIBUTE:
439: P_Attributes(p);
440: break;
441: case P_REMOVELINE:
442: P_RemoveLine(p);
443: break;
444: case P_TABS:
445: P_Tabs(p);
446: break;
447: case P_BANNER:
448: P_Banner(p);
449: break;
450: case P_CARTE:
451: P_Carte(p);
452: break;
453: case P_LINES:
454: P_Lines(p);
455: break;
456: case P_NAME:
457: P_Name(p);
458: break;
459: case P_CLEAR:
460: DelLines(p);
461: Dirty(p);
462: break;
463: case P_MAKECURRENT:
464: MakeCurrent(p);
465: break;
466: case P_LINE:
467: LINEobj = obj;
468: case P_NEXTLINE:
469: PutLine(p,op);
470: break;
471: case P_CREATELINE:
472: CreateLine(p);
473: break;
474: case P_DELETE:
475: if( p ) p->attributes |= USERCLOSE;
476: DeletePad(p);
477: break;
478: case P_MAKEGAP:
479: MakeGap(p);
480: break;
481: case P_ALARM:
482: t = RcvShort();
483: if(p){
484: if( !(p->ticks = t) ){
485: HostParent = HostObject = p->object;
486: ToHost( P_CYCLE /*, garbage */ );
487: }
488: }
489: break;
490: default:
491: ProtoErr( "PadOp(): " );
492: }
493: }
494:
495: PickOp()
496: {
497: register Pad *p;
498: Index i;
499:
500: i = RcvShort();
501: p = PickPad(PickPoint(IndexToStr(i)));
502: MakeCurrent(p);
503: while( butts ) waitMOUSE();
504: if( p && (HostParent = HostObject = p->object) ){
505: FlashBorder(p);
506: PutRemote(P_PICK);
507: HostAction( &i );
508: }
509: }
510:
511: Pad *PickPad(pt)
512: Point pt;
513: {
514: register Pad *p;
515:
516: for( p = Sentinel.back; ISPAD(p); p = p->back )
517: if( PadSized(p->rect) && ptinrect(pt,p->rect) )
518: return p;
519: return 0;
520: }
521:
522: DeletePick()
523: {
524: DeletePad(PickPad(PickPoint(0L)));
525: }
526:
527: DelLines(p)
528: register Pad *p;
529: {
530: if( !p ) return;
531: while( ISLINE(p->sentinel.up,p) )
532: DelLine( p->sentinel.up );
533: }
534:
535: DeletePad(p)
536: register Pad *p;
537: {
538: Rectangle r;
539: register Line *l, *lu;
540:
541: if( !p ) return;
542: if( DirtyPad == p ) Dirty((Pad*) 0);
543: if( p->attributes&USERCLOSE ){
544: HostParent = HostObject = p->object;
545: ToHost( P_USERCLOSE /*, garbage */ );
546: if( p->attributes&DONT_CLOSE ) return;
547: DelLines( p );
548: Unlink( p );
549: if( p->sentinel.text != NewString ) gcfree( p->sentinel.text );
550: if( p->name != NewString ) gcfree( p->name );
551: free(p);
552: } else {
553: if( p->attributes&DONT_CLOSE ) return;
554: for( l = p->sentinel.up; ISLINE(l,p); l = lu ){
555: lu = l->up;
556: if( !(l->attributes&DONT_CUT) ) DelLine(l);
557: }
558: }
559: if( Current == p ) SetCurrent((Pad *) 0);
560: if( Selected.line && Selected.pad == p ) Selected.line = 0;
561: r = p->rect;
562: p->rect = ZRectangle;
563: Refresh( r );
564: }
565:
566: Select(l, p)
567: register Line *l;
568: register Pad *p;
569: {
570: if( Selected.line == l ) return;
571: if( Selected.line ){
572: if( Selected.pad != p )
573: Selected.pad->selkey = Selected.line->key;
574: switch( (int) Covered(Selected.pad) ){
575: case COMPLETE:
576: break;
577: case CLEAR:
578: LineXOR(Selected.line);
579: break;
580: case PARTIAL:
581: Selected.line = 0;
582: Refresh(Selected.pad->rect);
583: }
584: }
585: if( Selected.pad = p )
586: p->selkey = 0;
587: if( Selected.line = l )
588: LineXOR(l);
589: }
590:
591: MakeCurrent(p)
592: register Pad *p;
593: {
594: register paint;
595: register Line *l;
596:
597: if( !p ) return;
598: if( Selected.line && Selected.pad!=p ) Select((Line*)0, (Pad*)0);
599: paint = Covered(p) != CLEAR;
600: if( !PadSized(p->rect) ){
601: if( Selected.line ) Select((Line*)0, (Pad*)0);
602: if( !PadSized(p->rect = clipgetrect(p->sentinel.text))) return;
603: paint = 1;
604: }
605: if( p == Current ) return;
606: FrontLink(p);
607: if( paint ) Paint(p);
608: l = &p->sentinel;
609: if( p->selkey )
610: while( ISLINE(l->up, p) ){
611: l = l->up;
612: if( l->key == p->selkey ){
613: Select(l, p);
614: break;
615: }
616: }
617: }
618:
619: Relocate(p,r)
620: Pad *p;
621: Rectangle r;
622: {
623: Rectangle bounding;
624:
625: if( !PadSized(r) ) return;
626: MakeCurrent(p); /* bug - used to be FrontLink(p); */
627: bounding = boundrect( r, p->rect );
628: p->rect = r;
629: Refresh( bounding );
630: }
631:
632: Move(){
633: register Pad *p = PickPad(PickPoint(0L));
634:
635: if( !p ) return;
636: Relocate( p, moverect(p->rect, PadSpace) );
637: }
638:
639: Reshape()
640: {
641: register Pad *p = PickPad(PickPoint(0L));
642:
643: if( !p ) return;
644: while( button123() ) waitMOUSE();
645: Relocate( p, clipgetrect(0L) );
646: }
647:
648: Rectangle NewSpace;
649: Point Scale( p )
650: Point p;
651: {
652: #define fo PadSpace.origin
653: #define fc PadSpace.corner
654: #define to NewSpace.origin
655: #define tc NewSpace.corner
656: #define SCALE(xy) p.xy = to.xy + muldiv( p.xy-fo.xy, tc.xy-to.xy, fc.xy-fo.xy );
657:
658: SCALE(x);
659: SCALE(y);
660: return p;
661: }
662:
663: #define KBDLEN 90
664: char KBDStr[KBDLEN]= "\1";
665:
666: PadClip()
667: {
668: register Pad *p;
669:
670: KBDrect = NewSpace = display.rect;
671: KBDrect.origin.y = NewSpace.corner.y -= fontheight(&defont);
672: KBDrect.origin.x += 2;
673: for( p = Sentinel.back; ISPAD(p); p = p->back ){
674: p->rect.origin = Scale( p->rect.origin );
675: p->rect.corner = Scale( p->rect.corner );
676: if( !PadSized(p->rect) ){
677: p->rect = ZRectangle;
678: if( p == Selected.pad ){
679: Selected.pad = 0;
680: Selected.line = 0;
681: }
682: }
683: }
684: Refresh( PadSpace = NewSpace );
685: PaintKBD();
686: }
687:
688: InvertKBDrect(s1, s2)
689: char *s1, *s2;
690: {
691: char buf[300];
692:
693: strcpy( buf, s1 );
694: strcat( buf, s2 );
695: rectf( &display, KBDrect, F_CLR );
696: string(&defont, buf, &display, KBDrect.origin, F_XOR);
697: rectf( &display, KBDrect, F_XOR );
698: }
699:
700: PaintKBD()
701: {
702: rectf( &display, KBDrect, F_CLR );
703: string(&defont, KBDStr, &display, KBDrect.origin, F_XOR);
704: }
705:
706: #define PAD_TO_SH (1L)
707: #define LINE_TO_SH (2L)
708: CarriageReturn(obj)
709: register long obj;
710: {
711: register char *kbds = KBDStr;
712: register Line *l, *lsent;
713: register long ct;
714:
715: kbds[strlen(kbds)-1] = '\0';
716: if( obj == LINE_TO_SH ){
717: PutRemote(P_SHELL);
718: SendLong(0L); /* common protocol */
719: SendLong(0L);
720: SendString(kbds+1);
721: SendLong(1L);
722: SendString(Selected.line->text);
723: } else if( obj == PAD_TO_SH ){
724: PutRemote(P_SHELL);
725: SendLong(0L); /* common protocol */
726: SendLong(0L);
727: SendString(kbds+1);
728: lsent = &Current->sentinel;
729: ct = 0;
730: for(l = lsent->down; l != lsent; l = l->down)
731: ++ct;
732: SendLong(ct);
733: for(l = lsent->down; l != lsent; l = l->down)
734: SendString(l->text);
735: } else {
736: PutRemote(P_KBDSTR);
737: SendLong(Current->object);
738: SendLong(obj);
739: SendString(kbds);
740: }
741: kbds[0] = 001;
742: kbds[1] = 000;
743: }
744:
745: LayerReshaped()
746: {
747: if( P->state & (RESHAPED) ){
748: P->state &= ~(RESHAPED);
749: PadClip();
750: }
751: }
752:
753: long LiveKBD()
754: {
755: register Line *sel = Selected.line;
756: register Pad *cur = Current;
757:
758: if( KBDStr[0] == '>' && cur ){
759: if( sel ){
760: DoubleOutline(&display, sel->rect);
761: return LINE_TO_SH;
762: } else {
763: HeavyBorder(cur);
764: return PAD_TO_SH;
765: }
766: }
767: if( sel && (sel->attributes&ACCEPT_KBD) ){
768: DoubleOutline(&display, sel->rect);
769: return sel->object;
770: }
771: if( cur && (cur->attributes&ACCEPT_KBD) ){
772: HeavyBorder(cur);
773: return cur->object;
774: }
775: return 0L;
776: }
777:
778: #define CNTRL_U 025
779: KBDAppend(c)
780: register c;
781: {
782: register char *t;
783: register int len = strlen(t = KBDStr);
784:
785: if( c < 040 || (c&0200) || len >= KBDLEN ){
786: if( c == CNTRL_U ){
787: t[0] = 001;
788: t[1] = 000;
789: }
790: if( c != '\t' ) /* bug: \t when len >= KBDLEN !! */
791: return;
792: }
793: t[len-1] = c;
794: t[len] = 001;
795: t[len+1] = 000;
796: }
797:
798: typedef struct String{
799: char *s; /* pointer to string */
800: short n; /* number used, no terminal null */
801: short size; /* size of allocated area */
802: } String;
803:
804: MuxSnarf()
805: {
806: String hold;
807: register i, c;
808:
809: hold.s = 0;
810: hold.n = hold.size = 0;
811: getmuxbuf(&hold);
812: for( i = 0; i < hold.n; ++i ){
813: c = hold.s[i];
814: if( c == '\n' ) break;
815: KBDAppend(c);
816: }
817: }
818:
819: #define KBD_PAUSE 4
820: #define ESCAPE 033
821: KBDServe()
822: {
823: register char c, *t;
824: register live, lenmake, len;
825:
826: if( P->state & KBD ){
827: live = LiveKBD();
828: while( P->state & KBD ){
829: c = kbdchar();
830: if( c == ESCAPE ){
831: MuxSnarf();
832: break;
833: }
834: if( c == '\r' && live ){
835: CarriageReturn(live);
836: break;
837: }
838: len = strlen(t = KBDStr);
839: if( c == '\b' && len > 1 ){
840: t[len-2] = 001;
841: t[len-1] = 000;
842: continue;
843: }
844: KBDAppend(c);
845: }
846: PaintKBD();
847: LiveKBD();
848: }
849: }
850:
851: FoldToggle(a)
852: Attrib *a;
853: {
854: *a &= ~(TRUNCATE|FOLD);
855: *a |= NewFold;
856: Paint(Current);
857: }
858:
859: Entry *FoldEntry(a)
860: register Attrib *a;
861: {
862: static Entry e = { 0, FoldToggle, 0 };
863:
864: assert(Current);
865: if( ( (*a&(TRUNCATE|FOLD)) ? *a : Current->attributes )&TRUNCATE )
866: e.text = "fold", NewFold = FOLD;
867: else
868: e.text = "truncate", NewFold = TRUNCATE;
869: e.opand = (long) a;
870: return &e;
871: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.