|
|
1.1 ! root 1: #include <jerq.h> ! 2: #include <layer.h> ! 3: #include <font.h> ! 4: #include <queue.h> ! 5: #include <jerqproc.h> ! 6: #include <setup.h> ! 7: #include "frame/frame.h" ! 8: #include "../msgs.h" ! 9: ! 10: #define ECHO (tp->flags0&TECHO) ! 11: #define RAW (tp->flags0&TRAW) ! 12: #define CBREAK (tp->flags0&TCBREAK) ! 13: #define CRMOD (tp->flags0&TCRMOD) ! 14: ! 15: /* ! 16: * Keyboard-dependent things ! 17: */ ! 18: #ifdef BLITKBD ! 19: #define BREAKKEY 0xE0 ! 20: #define SCROLLKEY 0xB0 /* Why not NO SCRL? */ ! 21: #undef ringbell ! 22: #define ringbell() DUART->b_data=0x02 ! 23: #else ! 24: #define BREAKKEY 0x80 ! 25: #define SCROLLKEY 0xB2 /* Why not NUM LOCK? */ ! 26: #endif ! 27: ! 28: #define CTRLW 0x17 ! 29: #define NSCRL 2 ! 30: int HIWATER; /* #chars max to save off top of screen */ ! 31: int LOWATER; ! 32: int doubleclickOK; ! 33: ! 34: typedef struct Type{ ! 35: Frame *frame; /* Frame being typed at */ ! 36: short start; /* start pos. of text to be sent to host */ ! 37: short nchars; /* number of chars typed */ ! 38: String old; /* old text scrolled off top */ ! 39: char scroll; ! 40: }Type; ! 41: ! 42: String buf; ! 43: short scrltimeout; ! 44: #define M 3 /* margin around frame */ ! 45: ! 46: windowproc(){ ! 47: register Frame *f; ! 48: register got; ! 49: String rcvstr; ! 50: static String zerostr; ! 51: Type current; ! 52: if((current.frame=f=fralloc(P->layer->rect, M))==0){ ! 53: mesg("can't allocate frame"); ! 54: for(;;) ! 55: sleep(1000); ! 56: } ! 57: frinit(f); ! 58: setborder(P); /* frames always draw them black */ ! 59: muxmesg((int)(P-proctab), C_POPLD); ! 60: current.start=0; ! 61: current.nchars=0; ! 62: current.scroll=0; ! 63: current.old=zerostr; ! 64: insure(¤t.old, 128, P); ! 65: rcvstr=zerostr; ! 66: insure(&rcvstr, 128, P); ! 67: Urequest(RCV|KBD|MOUSE); ! 68: Ucursswitch((Texture *)0); ! 69: setscroll(¤t); ! 70: for(;;){ ! 71: linecurse(f); /* cursor is off, so turn it on */ ! 72: do{ ! 73: if(P->state&RESHAPED){ ! 74: frsetrects(f, P->layer->rect); ! 75: drawframe(f); /* sets complete */ ! 76: setborder(P); ! 77: if(!complete && current.scroll) ! 78: advance(¤t); ! 79: P->state&=~(RESHAPED|MOVED|BLOCKED); ! 80: linecurse(f); /* put it back */ ! 81: } ! 82: }while((got=Uwait((P->state&BLOCKED)? ! 83: KBD|MOUSE|ALARM : KBD|MOUSE|RCV|ALARM))==MOUSE ! 84: && button123()==0); ! 85: linecurse(f); /* turn it off */ ! 86: if(got&ALARM){ ! 87: setscroll(¤t); ! 88: P->state&=~ALARMREQD; ! 89: } ! 90: if(got&MOUSE && button123()) ! 91: wbuttons(¤t); ! 92: else if(got&KBD) ! 93: kbd(¤t, Ukbdchar()); ! 94: else if(got&RCV) ! 95: rcv(¤t, &rcvstr); ! 96: } ! 97: } ! 98: bufinit(){ ! 99: strzero(&buf); ! 100: if(VALMAXADDR) ! 101: HIWATER=10000, LOWATER=8000; ! 102: else ! 103: HIWATER=2500, LOWATER=1500; ! 104: } ! 105: getmuxbuf(s) ! 106: register String *s; ! 107: { ! 108: insure(s, buf.n, P); ! 109: movstring(buf.n, buf.s, s->s); ! 110: s->n=buf.n; ! 111: } ! 112: setmuxbuf(s) ! 113: String *s; ! 114: { ! 115: snarf(s, 0, s->n); ! 116: } ! 117: rcv(t, rcvstr) ! 118: Type *t; ! 119: register String *rcvstr; ! 120: { ! 121: register char *p; ! 122: register Frame *f=t->frame; ! 123: register i, posn, c; ! 124: int compl; ! 125: struct ttychars *tp=&P->ttychars; ! 126: /* Read the string */ ! 127: c=Urcvchar(); ! 128: loop: ! 129: while(c=='\b'){ ! 130: if(t->start > 0) ! 131: deltype(t, t->start-1, t->start); ! 132: c=Urcvchar(); ! 133: } ! 134: p=rcvstr->s; ! 135: for(i=0; c!=-1; c=Urcvchar()){ /*aplterm1*/ ! 136: c&=0x7F; ! 137: if(c == '\b') break; ! 138: if(c=='\7') ! 139: ringbell(); /* smashes keyclick? */ ! 140: if(c && c!='\r' && c<P->defaultfont->n){ ! 141: *p++=c; ! 142: if(++i==rcvstr->size) ! 143: break; ! 144: } ! 145: } ! 146: rcvstr->n=i; ! 147: posn=t->start; ! 148: if(f->s1<posn && posn<f->s2){ ! 149: t->start=posn=f->s1; /* before selected text; avoids problems */ ! 150: t->nchars=0; ! 151: } ! 152: /* Undraw selection if necessary */ ! 153: if(posn<f->s2 && f->s2>f->s1) ! 154: selectf(f, F_XOR); ! 155: /* Find where it goes */ ! 156: instext(f, rcvstr, posn); ! 157: compl=inscomplete; ! 158: /* Adjust the selection and typing location */ ! 159: if(posn<f->s2 || (f->s1==f->s2 && posn==f->s2)){ ! 160: f->s1+=i; ! 161: f->s2+=i; ! 162: } ! 163: t->start+=i; ! 164: if(posn+i<f->s2 && f->s2>f->s1) ! 165: selectf(f, F_XOR); ! 166: if(!compl){ ! 167: if(t->scroll) ! 168: advance(t); ! 169: else ! 170: P->state|=BLOCKED; /* so cat hugefile is safe */ ! 171: } ! 172: if(c=='\b') ! 173: goto loop; ! 174: alarm(scrltimeout); ! 175: } ! 176: linecurse(t) ! 177: register Frame *t; ! 178: { ! 179: Point p; ! 180: if(t && t->str.s && t->s1==t->s2){ ! 181: p=ptofchar(t, t->s1); ! 182: Rectf(Rpt(p, Pt(p.x+1, p.y+newlnsz)), F_XOR); ! 183: } ! 184: } ! 185: mesg(s) ! 186: char *s; ! 187: { ! 188: string(&defont, s, P->layer, add(P->rect.origin, Pt(2, 2)), F_STORE); ! 189: } ! 190: kbd(t, ac) ! 191: register Type *t; ! 192: char ac; ! 193: { ! 194: static int raw, echo, cbreak, crmod; /* can be static; we don't sleep here */ ! 195: register Frame *f=t->frame; ! 196: register struct ttychars *tp=&P->ttychars; ! 197: int tounix; ! 198: unsigned char c; ! 199: c=ac; ! 200: if(c==SCROLLKEY){ ! 201: scrlf(t, charofpt(f, ! 202: Pt(f->rect.origin.x, f->rect.origin.y+newlnsz*f->nlines/2))); ! 203: return; ! 204: } ! 205: if(f->s2>f->s1) ! 206: cut(t, 1); ! 207: if(f->s2>=t->start){ ! 208: tounix=TRUE; ! 209: raw=RAW; ! 210: cbreak=CBREAK; ! 211: crmod=CRMOD; ! 212: echo=ECHO; ! 213: }else{ ! 214: tounix=FALSE; ! 215: raw=FALSE; ! 216: cbreak=FALSE; ! 217: crmod=TRUE; ! 218: echo=TRUE; ! 219: } ! 220: if(raw && c!=BREAKKEY){ /* break goes, even in raw mode */ ! 221: /* flush input */ ! 222: t->start+=t->nchars; ! 223: t->nchars=0; ! 224: Noecho: ! 225: Usendchar(c); ! 226: return; /* no echo in raw mode */ ! 227: } ! 228: if(c==BREAKKEY) ! 229: c=tp->intrc; ! 230: if(c==tp->intrc || c==tp->quitc){ /* always kill */ ! 231: /* flush input */ ! 232: t->start=f->str.n; ! 233: t->nchars=0; ! 234: muxkill(c==tp->intrc? 2 : 3, P); ! 235: return; ! 236: } ! 237: /* never raw mode */ ! 238: if(!echo && t->nchars>0){ /* send off what's already there */ ! 239: sendsubstr(f->str.s, t->start, t->nchars-t->start); ! 240: t->nchars=0; ! 241: t->start=f->str.n; ! 242: } ! 243: c&=0x7F; /* strip off sign bit from keypad */ /*aplterm2*/ ! 244: if(c==tp->eofc && !cbreak){ ! 245: if(tounix) ! 246: goto Send; /* throw away eofc */ ! 247: return; ! 248: } ! 249: if(c=='\r' && crmod) ! 250: c='\n'; ! 251: if(!echo) ! 252: goto Noecho; ! 253: if(f->s2>0 && f->str.s[f->s2-1]=='\\' && ! 254: (c==tp->erase || (c==tp->kill&&tounix) || c==CTRLW || ! 255: c==tp->stopc || c==tp->startc)){ ! 256: deltype(t, f->s2-1, f->s2); /* throw away \ */ ! 257: goto Ordinary; ! 258: } ! 259: if(c==tp->erase || c==CTRLW){ ! 260: if(f->s1 > (tounix? t->start : 0)) ! 261: deltype(t, f->s1-nback(f, c, tounix? t->start : 0), f->s1); ! 262: return; ! 263: } ! 264: if(c==tp->kill && tounix){ ! 265: f->s2=f->str.n; ! 266: inschar(t, '@'); ! 267: inschar(t, '\n'); ! 268: t->start=f->s2; ! 269: t->nchars=0; ! 270: return; ! 271: } ! 272: if(c==tp->stopc){ ! 273: P->state|=BLOCKED; ! 274: return; ! 275: } ! 276: if(c==tp->startc){ ! 277: P->state&=~BLOCKED; ! 278: return; ! 279: } ! 280: Ordinary: ! 281: inschar(t, c); ! 282: if(tounix && (P->state&BLOCKED)) ! 283: P->state&=~BLOCKED; ! 284: if(tounix && f->s2>t->start && (c=='\n' || (cbreak && c=='\r'))){ ! 285: Send: ! 286: sendsubstr(f->str.s, t->start, f->s2); ! 287: t->nchars-=f->s2-t->start; ! 288: t->start+=f->s2-t->start; ! 289: } ! 290: } ! 291: nback(f, c, lim) ! 292: Frame *f; ! 293: { ! 294: register n=0, s1=f->s1; ! 295: register char *s=f->str.s+s1; ! 296: static char alphanl[]= ! 297: "\n0123456789_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; ! 298: #define alphanum alphanl+1 ! 299: if(s1 <= 0) ! 300: return 0; ! 301: if(c!=CTRLW || *--s=='\n') ! 302: return 1; ! 303: /* else it's ^W. first, get to an alphanumeric (or newline) */ ! 304: while(n<s1-lim && notin(*s, alphanl)) ! 305: --s, ++n; ! 306: /* *s is alphanumeric or space; now back up to non-alphanumeric */ ! 307: while(n<s1 && !notin(*s, alphanum)) ! 308: --s, ++n; ! 309: return n; ! 310: } ! 311: notin(c, s) ! 312: register c; ! 313: register char *s; ! 314: { ! 315: c&=0xFF; ! 316: while(*s) ! 317: if(c == *s++) ! 318: return FALSE; ! 319: return TRUE; ! 320: } ! 321: inschar(t, ac) ! 322: register Type *t; ! 323: { ! 324: static char c; ! 325: static String kbdstr={ ! 326: &c, ! 327: 1, ! 328: 1 ! 329: }; ! 330: register Frame *f=t->frame; ! 331: c=ac; ! 332: instype(t, &kbdstr, f->s2); ! 333: if(!inscomplete) ! 334: scrlf(t, getto(f, f->s2)); ! 335: setsel(f, f->s2+1); ! 336: } ! 337: getto(f, end) ! 338: register Frame *f; ! 339: { ! 340: register nl, nc, i; ! 341: nl=max(NSCRL, f->nlines/5); ! 342: nc=charofpt(f, f->rect.corner); ! 343: while(nc<end) ! 344: if(f->str.s[nc++]=='\n') ! 345: nl++; ! 346: /* nl is now #lines; find how many chars from start of frame */ ! 347: for(i=nc=0; i<end; ) ! 348: if(f->str.s[i++]=='\n'){ ! 349: nc=i; ! 350: if(--nl<=0) ! 351: return nc; ! 352: } ! 353: return end; ! 354: } ! 355: advance(t) ! 356: Type *t; ! 357: { ! 358: /* should work first time unless lines are folded */ ! 359: do; while(!scrlf(t, getto(t->frame, t->frame->str.n))); ! 360: } ! 361: insertstring(p, i, s, n) /* warning: must call insure() before this! */ ! 362: String *p; ! 363: char *s; ! 364: { ! 365: String str; ! 366: str.s=s, str.n=n; ! 367: insstring(p, i, &str); ! 368: } ! 369: inserttype(t, s, n) /* warning: must call insure() before this! */ ! 370: Type *t; ! 371: char *s; ! 372: { ! 373: register Frame *f=t->frame; ! 374: String str; ! 375: str.s=s, str.n=n; ! 376: selectf(f, F_XOR); ! 377: instext(f, &str, 0); ! 378: f->s1+=n; ! 379: f->s2+=n; ! 380: t->start+=n; ! 381: selectf(f, F_XOR); ! 382: } ! 383: scrlf(t, n) ! 384: register Type *t; ! 385: register n; ! 386: { ! 387: register Frame *f=t->frame; ! 388: if(n>0){ ! 389: if(n>f->str.n) ! 390: n=f->str.n; ! 391: sendoldtext(t, n); ! 392: /* quick hack; don't worry about order of allocation */ ! 393: insure(&t->old, t->old.n+n, P); ! 394: insertstring(&t->old, t->old.n, f->str.s, n); ! 395: if(t->old.n>HIWATER) ! 396: delstring(&t->old, 0, t->old.n-LOWATER); ! 397: if(n=deltype(t, 0, n)) /* all text in frame now visible */ ! 398: P->state&=~BLOCKED; ! 399: } ! 400: setscroll(t); ! 401: return n; ! 402: } ! 403: scrlb(t, n) ! 404: register Type *t; ! 405: register n; ! 406: { ! 407: register Frame *f=t->frame; ! 408: register i; ! 409: if(n>0){ ! 410: if(n>t->old.n) ! 411: n=t->old.n; ! 412: i=t->old.n-n; ! 413: while(i>0 && t->old.s[i-1]!='\n') ! 414: i--, n++; ! 415: insure(&t->old, t->old.n+n, P); ! 416: inserttype(t, t->old.s+i, n); ! 417: delstring(&t->old, i, t->old.n); ! 418: } ! 419: setscroll(t); ! 420: } ! 421: deltype(t, s1, s2) ! 422: register Type *t; ! 423: register s1, s2; ! 424: { ! 425: register Frame *f=t->frame; ! 426: int compl; ! 427: if(s2<=t->start) ! 428: t->start-=s2-s1; ! 429: else if(s1>=t->start) ! 430: t->nchars-=s2-s1; ! 431: else if(s2>t->start){ /* deletion overlaps start */ ! 432: t->nchars-=s2-t->start; ! 433: t->start=s1; ! 434: } ! 435: selectf(f, F_XOR); ! 436: deltext(f, s1, s2); ! 437: compl=complete; ! 438: f->s1-=max(0, min(f->s1, s2)-s1); ! 439: f->s2-=max(0, min(f->s2, s2)-s1); ! 440: selectf(f, F_XOR); ! 441: return compl; ! 442: } ! 443: instype(t, s, s1) ! 444: register Type *t; ! 445: String *s; ! 446: register s1; ! 447: { ! 448: if(s->n>0){ ! 449: if(s1<t->start) ! 450: t->start+=s->n; ! 451: else if(s1>=t->start) ! 452: t->nchars+=s->n; ! 453: instext(t->frame, s, s1); ! 454: } ! 455: } ! 456: ! 457: #define CUT 0 ! 458: #define PASTE 1 ! 459: #define SNARF 2 ! 460: #define SENDIT 3 ! 461: #define SCROLL 4 ! 462: ! 463: #define UP 0 ! 464: #define DOWN 1 ! 465: ! 466: static char *editstrs[]={ ! 467: "cut", ! 468: "paste", ! 469: "snarf", ! 470: "send", ! 471: 0, ! 472: 0, ! 473: }; ! 474: static Menu editmenu={editstrs}; ! 475: ! 476: wbuttons(t) ! 477: register Type *t; ! 478: { ! 479: register Frame *f=t->frame; ! 480: static char *scrollstrs[]={ "scroll", "noscroll" }; ! 481: if(!ptinrect(mouse.xy, f->totalrect)){ /* not for us anyway */ ! 482: doubleclickOK=0; ! 483: return; ! 484: } ! 485: if(ptinrect(mouse.xy, f->scrollrect)) ! 486: scroll(t, mouse.buttons); ! 487: else if(button1()){ ! 488: if(ptinrect(mouse.xy, f->rect)) ! 489: frselect(f, mouse.xy); ! 490: }else if(button2()){ ! 491: doubleclickOK=0; ! 492: editstrs[SCROLL]=scrollstrs[t->scroll]; ! 493: switch(menuhit(&editmenu, 2)){ ! 494: case CUT: ! 495: cut(t, 1); ! 496: break; ! 497: case PASTE: ! 498: paste(t, &buf); ! 499: break; ! 500: case SNARF: ! 501: if(f->s2>f->s1) ! 502: snarf(&f->str, f->s1, f->s2); ! 503: break; ! 504: case SENDIT: ! 505: send(t); ! 506: break; ! 507: case SCROLL: ! 508: if((t->scroll^=1) && ! 509: (frameop(f, opnull, f->rect.origin, ! 510: f->str.s, f->str.n), !complete)) ! 511: advance(t); ! 512: break; ! 513: } ! 514: }else{ ! 515: doubleclickOK=0; ! 516: Urequest(RCV|KBD); ! 517: sleep(2); ! 518: Urequest(RCV|KBD|MOUSE); ! 519: } ! 520: } ! 521: snarf(p, i, j) ! 522: register String *p; ! 523: register short i, j; ! 524: { ! 525: register n = j-i; ! 526: insure(&buf, n, (struct Proc *)0); ! 527: movstring(n, p->s+i, buf.s); ! 528: buf.n = n; ! 529: } ! 530: cut(t, save) ! 531: register Type *t; ! 532: { ! 533: register n; ! 534: register Frame *f=t->frame; ! 535: if((n=f->s1) != f->s2){ ! 536: if(save) ! 537: snarf(&f->str, n, f->s2); ! 538: deltype(t, f->s1, f->s2); ! 539: f->s1=f->s2; ! 540: setsel(f, n); ! 541: P->state&=~BLOCKED; /* in case we are suspended */ ! 542: } ! 543: } ! 544: paste(t, s) ! 545: register Type *t; ! 546: String *s; ! 547: { ! 548: register Frame *f=t->frame; ! 549: if(s->n==0) ! 550: return; ! 551: cut(t, 0); ! 552: instype(t, s, f->s1); ! 553: f->s2=f->s1+s->n; ! 554: selectf(f, F_XOR); ! 555: } ! 556: send(t) ! 557: register Type *t; ! 558: { ! 559: register Frame *f=t->frame; ! 560: if(f->s1!=f->s2) ! 561: snarf(&f->str, f->s1, f->s2); ! 562: if(buf.n==0) ! 563: return; ! 564: if(t->nchars) ! 565: deltype(t, t->start, t->start+t->nchars); ! 566: if(P->ttychars.flags0&TECHO){ ! 567: instext(f, &buf, f->str.n); ! 568: if(!inscomplete) ! 569: advance(t); ! 570: } ! 571: selectf(f, F_XOR); ! 572: f->s1=f->s2=f->str.n; ! 573: sendsubstr(buf.s, 0, buf.n); ! 574: if(buf.s[buf.n-1]!='\n'){ ! 575: sendnchars(1, "\n"); ! 576: if((P->ttychars.flags0&(TRAW|TCBREAK|TECHO))==TECHO) ! 577: inschar(t, '\n'); ! 578: delim(); ! 579: } ! 580: /* else the delim's already been sent */ ! 581: t->start=f->s2; ! 582: t->nchars=0; ! 583: } ! 584: sendsubstr(s, beg, end) ! 585: register char *s; ! 586: { ! 587: register m, n; ! 588: if(beg==end){ ! 589: delim(); ! 590: return; ! 591: } ! 592: for(m=beg; m<end; m=n+1){ ! 593: /* invariant: n is the last character we are going to send */ ! 594: for(n=m; n<end && s[n]!='\n'; n++) ! 595: if(n==end-1) ! 596: break; ! 597: sendnchars(n-m+1, s+m); ! 598: if(n<end && s[n]=='\n') ! 599: delim(); ! 600: } ! 601: } ! 602: sendoldtext(t, n) ! 603: register Type *t; ! 604: { ! 605: if(t->start<n && t->nchars>0){ ! 606: if(n>t->start+t->nchars) ! 607: n=t->start+t->nchars; ! 608: sendsubstr(t->frame->str.s, t->start, n); ! 609: } ! 610: } ! 611: Texture grey = { ! 612: 0xAAAA, 0xAAAA, 0xAAAA, 0xAAAA, 0xAAAA, 0xAAAA, 0xAAAA, 0xAAAA, ! 613: 0xAAAA, 0xAAAA, 0xAAAA, 0xAAAA, 0xAAAA, 0xAAAA, 0xAAAA, 0xAAAA, ! 614: }; ! 615: Point ! 616: scrollclip(p) ! 617: Point p; ! 618: { ! 619: if(p.x<0){ ! 620: p.y-=p.x; ! 621: p.x=0; ! 622: } ! 623: if(p.y>SCROLLRANGE) ! 624: p.y=SCROLLRANGE; ! 625: return p; ! 626: } ! 627: Rectangle ! 628: scrollmark(f, p) ! 629: register Frame *f; ! 630: Point p; ! 631: { ! 632: Rectangle r; ! 633: p=scrollclip(p); ! 634: r=f->scrollrect; ! 635: r.origin.y=clixtopix(f, p.x); ! 636: r.corner.y=clixtopix(f, p.y); ! 637: return r; ! 638: } ! 639: clixtopix(f, y) ! 640: register Frame *f; ! 641: { ! 642: return f->scrollrect.origin.y+muldiv(f->nlines*newlnsz, y, SCROLLRANGE); ! 643: } ! 644: pixtoclix(f, y) ! 645: register Frame *f; ! 646: { ! 647: return muldiv(y-f->rect.origin.y, SCROLLRANGE, f->nlines*newlnsz); ! 648: } ! 649: drawscrollbar(f) ! 650: register Frame *f; ! 651: { ! 652: Rectangle r; ! 653: register Bitmap *b; /* offscreen to avoid flicker */ ! 654: r=inset(f->scrollrect, -1); ! 655: b=balloc(r); ! 656: if(b==0) ! 657: b=(Bitmap *)D; ! 658: Urectf(b, r, F_OR); ! 659: lrectf(b, scrollmark(f, f->scroll), F_XOR); ! 660: Ubitblt(b, r, D, r.origin, F_STORE); ! 661: if(b!=(Bitmap *)D) ! 662: bfree(b); ! 663: } ! 664: setscroll(t) ! 665: register Type *t; ! 666: { ! 667: register Frame *f=t->frame; ! 668: Point new; ! 669: register x, y; ! 670: x=f->rect.origin.y+1; /* a little margin at the top */ ! 671: y=f->rect.corner.y-1; /* and bottom */ ! 672: if(t->old.n+f->str.n>0) ! 673: x+=muldiv(f->nlines*newlnsz, t->old.n, t->old.n+f->str.n); ! 674: if(f->cpl[f->nlines-1]>0){ ! 675: int n; ! 676: n=charofpt(f, Pt(XMAX, YMAX)); ! 677: y-=muldiv(f->nlines*newlnsz, f->str.n-n, t->old.n+f->str.n); ! 678: } ! 679: if(x>y-(f->rect.corner.y-f->rect.origin.y)/30) ! 680: x=y-(f->rect.corner.y-f->rect.origin.y)/30; ! 681: if(y<x+(f->rect.corner.y-f->rect.origin.y)/30) ! 682: y=x+(f->rect.corner.y-f->rect.origin.y)/30; ! 683: new.x=pixtoclix(f, x); ! 684: new.y=pixtoclix(f, y); ! 685: if(abs(f->scroll.x-new.x)>20 || abs(f->scroll.y-new.y)>20){ ! 686: f->scroll=new; ! 687: drawscrollbar(f); ! 688: } ! 689: } ! 690: Point ! 691: checkmouse(f, mousep, p) ! 692: Frame *f; ! 693: Point mousep, p; ! 694: { ! 695: if(!ptinrect(mousep, f->scrollrect)){ ! 696: extern Rectangle Null; ! 697: return Null.origin; ! 698: } ! 699: return p; ! 700: } ! 701: Point ! 702: but1func(f, p) ! 703: register Frame *f; ! 704: Point p; ! 705: { ! 706: register delta=muldiv(p.y-f->rect.origin.y, f->scroll.y-f->scroll.x, f->nlines*newlnsz); ! 707: return checkmouse(f, p, sub(f->scroll, Pt(delta, delta))); ! 708: } ! 709: Point ! 710: but2func(f, p) ! 711: register Frame *f; ! 712: Point p; ! 713: { ! 714: Point scroll; ! 715: register size=(f->scroll.y-f->scroll.x)/2; ! 716: scroll.x=pixtoclix(f, p.y)-size; ! 717: scroll.y=pixtoclix(f, p.y)+size; ! 718: return checkmouse(f, p, scroll); ! 719: } ! 720: Point ! 721: but3func(f, p) ! 722: register Frame *f; ! 723: Point p; ! 724: { ! 725: register delta=muldiv(p.y-f->rect.origin.y, f->scroll.y-f->scroll.x, f->nlines*newlnsz); ! 726: return checkmouse(f, p, add(f->scroll, Pt(delta, delta))); ! 727: } ! 728: typedef Point (*ptrfpoint)(); ! 729: ptrfpoint butfunc[]={ ! 730: 0, ! 731: but1func, ! 732: but2func, ! 733: but3func, ! 734: }; ! 735: Point ! 736: guide(m, p) ! 737: Point m, p; ! 738: { ! 739: if(abs(m.x-p.x)<3) ! 740: m.x=p.x; ! 741: return m; ! 742: } ! 743: scrollbar(f, but) ! 744: register Frame *f; ! 745: { ! 746: ptrfpoint fp; ! 747: Point pt; ! 748: fp=butfunc[but]; ! 749: pt=mouse.xy; ! 750: while(button(but)){ ! 751: ltexture(D, scrollmark(f, (*fp)(f, pt)), &grey, F_XOR); ! 752: do nap(3); while(eqpt(mouse.xy, pt) && button(but)); ! 753: ltexture(D, scrollmark(f, (*fp)(f, pt)), &grey, F_XOR); ! 754: cursset(pt=guide(mouse.xy, pt)); ! 755: } ! 756: if(ptinrect(pt, f->scrollrect)){ ! 757: f->scroll=(*fp)(f, pt); ! 758: if(f->scroll.x<0){ ! 759: f->scroll.y-=f->scroll.x; ! 760: f->scroll.x=0; ! 761: } ! 762: if(f->scroll.x>SCROLLRANGE){ ! 763: f->scroll.y-=f->scroll.x-SCROLLRANGE; ! 764: f->scroll.x=SCROLLRANGE; ! 765: } ! 766: return 1; ! 767: } ! 768: return 0; ! 769: } ! 770: scroll(t, but) ! 771: register Type *t; ! 772: { ! 773: register Frame *f=t->frame; ! 774: Point old, new; ! 775: register y, b; ! 776: old=f->scroll; ! 777: if(scrollbar(f, b=whichbutton())){ ! 778: new=f->scroll; ! 779: f->scroll=old; /* ugh */ ! 780: y=mouse.xy.y; ! 781: if(b==2){ ! 782: y=muldiv(f->str.n+t->old.n, new.x, SCROLLRANGE); ! 783: if(y>=t->old.n){ ! 784: y-=t->old.n; ! 785: do; while(y<f->str.n && f->str.s[y++]!='\n'); ! 786: scrlf(t, y); ! 787: }else ! 788: scrlb(t, t->old.n-y); ! 789: }else if(new.x>=old.x) ! 790: scrlf(t, charofpt(f, Pt(f->rect.origin.x, y))); ! 791: else ! 792: scrlb(t, oldlinepos(t, (y-f->scrollrect.origin.y)/newlnsz)); ! 793: } ! 794: } ! 795: oldlinepos(t, n) ! 796: register Type *t; ! 797: register n; ! 798: { ! 799: register i=t->old.n; ! 800: while(n>0 && i>0) ! 801: if(t->old.s[--i]=='\n') ! 802: --n; ! 803: return t->old.n-i; ! 804: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.