1 #include <u.h> 2 #include <libc.h> 3 #include <draw.h> 4 #include <memdraw.h> 5 #include <thread.h> 6 #include <cursor.h> 7 #include <mouse.h> 8 #include <keyboard.h> 9 #include <frame.h> 10 #include <plumb.h> 11 #include <html.h> 12 #include "dat.h" 13 #include "fns.h" 14 15 Image *tagcols[NCOL]; 16 Image *textcols[NCOL]; 17 18 19 void 20 textinit(Text *t, Image *b, Rectangle r, Font *f, Image *cols[NCOL]) 21 { 22 t->all = r; 23 t->scrollr = r; 24 t->scrollr.max.x = r.min.x+Scrollsize; 25 t->lastsr = ZR; 26 r.min.x += Scrollsize+Scrollgap; 27 t->rs.nr = 0; 28 memmove(t->Frame.cols, cols, sizeof t->Frame.cols); 29 textredraw(t, r, f, b); 30 } 31 32 void 33 textredraw(Text *t, Rectangle r, Font *f, Image *b) 34 { 35 Rectangle r1; 36 37 frinit(t, r, f, b, t->Frame.cols); 38 r1 = t->r; 39 r1.min.x -= Scrollsize+Scrollgap; /* back fill to scroll bar */ 40 draw(t->b, r1, t->cols[BACK], nil, ZP); 41 t->maxtab = Maxtab*stringwidth(f, "0"); 42 textfill(t); 43 textsetselect(t, t->q0, t->q1); 44 } 45 46 int 47 textresize(Text *t, Image *b, Rectangle r) 48 { 49 if(Dy(r) > 0) 50 r.max.y -= Dy(r)%t->font->height; 51 else 52 r.max.y = r.min.y; 53 54 t->all = r; 55 t->scrollr = r; 56 t->scrollr.max.x = r.min.x+Scrollsize; 57 t->lastsr = ZR; 58 r.min.x += Scrollsize+Scrollgap; 59 frclear(t, 0); 60 textredraw(t, r, t->font, b); 61 if(t->what == Textarea) 62 textscrdraw(t); 63 return r.max.y; 64 } 65 66 void 67 textclose(Text *t) 68 { 69 closerunestr(&t->rs); 70 frclear(t, 1); 71 } 72 73 void 74 textinsert(Text *t, uint q0, Rune *r, uint n) 75 { 76 if(n == 0) 77 return; 78 79 t->rs.r = runerealloc(t->rs.r, t->rs.nr+n); 80 runemove(t->rs.r+q0+n, t->rs.r+q0, t->rs.nr-q0); 81 runemove(t->rs.r+q0, r, n); 82 t->rs.nr += n; 83 if(q0 < t->q1) 84 t->q1 += n; 85 if(q0 < t->q0) 86 t->q0 += n; 87 if(q0 < t->org) 88 t->org += n; 89 else if(q0 <= t->org+t->nchars) 90 frinsert(t, r, r+n, q0-t->org); 91 } 92 93 void 94 textfill(Text *t) 95 { 96 Rune *rp; 97 int i, n, m, nl; 98 99 if(t->lastlinefull) 100 return; 101 rp = runemalloc(BUFSIZE*8); 102 do{ 103 n = t->rs.nr-(t->org+t->nchars); 104 if(n == 0) 105 break; 106 if(n > 2000) /* educated guess at reasonable amount */ 107 n = 2000; 108 runemove(rp, t->rs.r+(t->org+t->nchars), n); 109 /* 110 * it's expensive to frinsert more than we need, so 111 * count newlines. 112 */ 113 nl = t->maxlines-t->nlines; 114 m = 0; 115 for(i=0; i<n; ){ 116 if(rp[i++] == '\n'){ 117 m++; 118 if(m >= nl) 119 break; 120 } 121 } 122 frinsert(t, rp, rp+i, t->nchars); 123 }while(t->lastlinefull == FALSE); 124 free(rp); 125 } 126 127 void 128 textdelete(Text *t, uint q0, uint q1) 129 { 130 uint n, p0, p1; 131 132 n = q1-q0; 133 if(n == 0) 134 return; 135 136 runemove(t->rs.r+q0, t->rs.r+q1, t->rs.nr-q1); 137 t->rs.nr -= n; 138 if(q0 < t->q0) 139 t->q0 -= min(n, t->q0-q0); 140 if(q0 < t->q1) 141 t->q1 -= min(n, t->q1-q0); 142 if(q1 <= t->org) 143 t->org -= n; 144 else if(q0 < t->org+t->nchars){ 145 p1 = q1 - t->org; 146 if(p1 > t->nchars) 147 p1 = t->nchars; 148 if(q0 < t->org){ 149 t->org = q0; 150 p0 = 0; 151 }else 152 p0 = q0 - t->org; 153 frdelete(t, p0, p1); 154 textfill(t); 155 } 156 t->rs.r[t->rs.nr] = L'\0'; 157 } 158 159 int 160 textbswidth(Text *t, Rune c) 161 { 162 uint q, eq; 163 Rune r; 164 int skipping; 165 166 /* there is known to be at least one character to erase */ 167 if(c == 0x08) /* ^H: erase character */ 168 return 1; 169 q = t->q0; 170 skipping = TRUE; 171 while(q > 0){ 172 r = t->rs.r[q-1]; 173 if(r == '\n'){ /* eat at most one more character */ 174 if(q == t->q0) /* eat the newline */ 175 --q; 176 break; 177 } 178 if(c == 0x17){ 179 eq = isalnum(r); 180 if(eq && skipping) /* found one; stop skipping */ 181 skipping = FALSE; 182 else if(!eq && !skipping) 183 break; 184 } 185 --q; 186 } 187 return t->q0-q; 188 } 189 190 void 191 texttype(Text *t, Rune r) 192 { 193 uint q0, q1; 194 int nb, n; 195 int nr; 196 Rune *rp; 197 198 if(t->what!=Textarea && r=='\n'){ 199 if(t->what==Urltag) 200 get(t, t, XXX, XXX, nil, 0); 201 return; 202 } 203 if(t->what==Tag && (r==Kscrollonedown || r==Kscrolloneup)) 204 return; 205 206 nr = 1; 207 rp = &r; 208 switch(r){ 209 case Kleft: 210 if(t->q0 > 0) 211 textshow(t, t->q0-1, t->q0-1, TRUE); 212 return; 213 case Kright: 214 if(t->q1 < t->rs.nr) 215 textshow(t, t->q1+1, t->q1+1, TRUE); 216 return; 217 case Kdown: 218 n = t->maxlines/3; 219 goto case_Down; 220 case Kscrollonedown: 221 n = mousescrollsize(t->maxlines); 222 if(n <= 0) 223 n = 1; 224 goto case_Down; 225 case Kpgdown: 226 n = 2*t->maxlines/3; 227 case_Down: 228 q0 = t->org+frcharofpt(t, Pt(t->r.min.x, t->r.min.y+n*t->font->height)); 229 textsetorigin(t, q0, TRUE); 230 return; 231 case Kup: 232 n = t->maxlines/3; 233 goto case_Up; 234 case Kscrolloneup: 235 n = mousescrollsize(t->maxlines); 236 goto case_Up; 237 case Kpgup: 238 n = 2*t->maxlines/3; 239 case_Up: 240 q0 = textbacknl(t, t->org, n); 241 textsetorigin(t, q0, TRUE); 242 return; 243 case Khome: 244 textshow(t, 0, 0, FALSE); 245 return; 246 case Kend: 247 textshow(t, t->rs.nr, t->rs.nr, FALSE); 248 return; 249 case 0x01: /* ^A: beginning of line */ 250 /* go to where ^U would erase, if not already at BOL */ 251 nb = 0; 252 if(t->q0>0 && t->rs.r[t->q0-1]!='\n') 253 nb = textbswidth(t, 0x15); 254 textshow(t, t->q0-nb, t->q0-nb, TRUE); 255 return; 256 case 0x05: /* ^E: end of line */ 257 q0 = t->q0; 258 while(q0<t->rs.nr && t->rs.r[q0]!='\n') 259 q0++; 260 textshow(t, q0, q0, TRUE); 261 return; 262 } 263 if(t->q1 > t->q0) 264 cut(t, t, TRUE, TRUE, nil, 0); 265 266 textshow(t, t->q0, t->q0, TRUE); 267 switch(r){ 268 case 0x08: /* ^H: erase character */ 269 case 0x15: /* ^U: erase line */ 270 case 0x17: /* ^W: erase word */ 271 if(t->q0 == 0) /* nothing to erase */ 272 return; 273 nb = textbswidth(t, r); 274 q1 = t->q0; 275 q0 = q1-nb; 276 /* if selection is at beginning of window, avoid deleting invisible text */ 277 if(q0 < t->org){ 278 q0 = t->org; 279 nb = q1-q0; 280 } 281 if(nb > 0){ 282 textdelete(t, q0, q0+nb); 283 textsetselect(t, q0, q0); 284 } 285 return; 286 } 287 /* otherwise ordinary character; just insert */ 288 textinsert(t, t->q0, &r, 1); 289 if(rp != &r) 290 free(rp); 291 textsetselect(t, t->q0+nr, t->q0+nr); 292 if(t->what == Textarea) 293 textscrdraw(t); 294 } 295 296 static Text *clicktext; 297 static uint clickmsec; 298 static Text *selecttext; 299 static uint selectq; 300 301 /* 302 * called from frame library 303 */ 304 void 305 framescroll(Frame *f, int dl) 306 { 307 if(f != &selecttext->Frame) 308 error("frameselect not right frame"); 309 textframescroll(selecttext, dl); 310 } 311 312 void 313 textframescroll(Text *t, int dl) 314 { 315 uint q0; 316 317 if(dl == 0){ 318 scrsleep(100); 319 return; 320 } 321 if(dl < 0){ 322 q0 = textbacknl(t, t->org, -dl); 323 if(selectq > t->org+t->p0) 324 textsetselect(t, t->org+t->p0, selectq); 325 else 326 textsetselect(t, selectq, t->org+t->p0); 327 }else{ 328 if(t->org+t->nchars == t->rs.nr) 329 return; 330 q0 = t->org+frcharofpt(t, Pt(t->r.min.x, t->r.min.y+dl*t->font->height)); 331 if(selectq > t->org+t->p1) 332 textsetselect(t, t->org+t->p1, selectq); 333 else 334 textsetselect(t, selectq, t->org+t->p1); 335 } 336 textsetorigin(t, q0, TRUE); 337 } 338 339 void 340 textselect(Text *t) 341 { 342 uint q0, q1; 343 int b, x, y; 344 int state; 345 346 selecttext = t; 347 /* 348 * To have double-clicking and chording, we double-click 349 * immediately if it might make sense. 350 */ 351 b = mouse->buttons; 352 q0 = t->q0; 353 q1 = t->q1; 354 selectq = t->org+frcharofpt(t, mouse->xy); 355 if(clicktext==t && mouse->msec-clickmsec<500) 356 if(q0==q1 && selectq==q0){ 357 textdoubleclick(t, &q0, &q1); 358 textsetselect(t, q0, q1); 359 flushimage(display, 1); 360 x = mouse->xy.x; 361 y = mouse->xy.y; 362 /* stay here until something interesting happens */ 363 do 364 readmouse(mousectl); 365 while(mouse->buttons==b && abs(mouse->xy.x-x)<3 && abs(mouse->xy.y-y)<3); 366 mouse->xy.x = x; /* in case we're calling frselect */ 367 mouse->xy.y = y; 368 q0 = t->q0; /* may have changed */ 369 q1 = t->q1; 370 selectq = q0; 371 } 372 if(mouse->buttons == b){ 373 t->Frame.scroll = framescroll; 374 frselect(t, mousectl); 375 /* horrible botch: while asleep, may have lost selection altogether */ 376 if(selectq > t->rs.nr) 377 selectq = t->org + t->p0; 378 t->Frame.scroll = nil; 379 if(selectq < t->org) 380 q0 = selectq; 381 else 382 q0 = t->org + t->p0; 383 if(selectq > t->org+t->nchars) 384 q1 = selectq; 385 else 386 q1 = t->org+t->p1; 387 } 388 if(q0 == q1){ 389 if(q0==t->q0 && clicktext==t && mouse->msec-clickmsec<500){ 390 textdoubleclick(t, &q0, &q1); 391 clicktext = nil; 392 }else{ 393 clicktext = t; 394 clickmsec = mouse->msec; 395 } 396 }else 397 clicktext = nil; 398 textsetselect(t, q0, q1); 399 flushimage(display, 1); 400 state = 0; /* undo when possible; +1 for cut, -1 for paste */ 401 while(mouse->buttons){ 402 mouse->msec = 0; 403 b = mouse->buttons; 404 if((b&1) && (b&6)){ 405 if(b & 2){ 406 if(state==-1 && t->what==Textarea){ 407 textsetselect(t, q0, t->q0); 408 state = 0; 409 }else if(state != 1){ 410 cut(t, t, TRUE, TRUE, nil, 0); 411 state = 1; 412 } 413 }else{ 414 if(state==1 && t->what==Textarea){ 415 textsetselect(t, q0, t->q1); 416 state = 0; 417 }else if(state != -1){ 418 paste(t, t, TRUE, FALSE, nil, 0); 419 state = -1; 420 } 421 } 422 textscrdraw(t); 423 } 424 flushimage(display, 1); 425 while(mouse->buttons == b) 426 readmouse(mousectl); 427 clicktext = nil; 428 } 429 } 430 431 void 432 textshow(Text *t, uint q0, uint q1, int doselect) 433 { 434 int qe; 435 int nl; 436 uint q; 437 438 if(t->what != Textarea){ 439 if(doselect) 440 textsetselect(t, q0, q1); 441 return; 442 } 443 if(doselect) 444 textsetselect(t, q0, q1); 445 qe = t->org+t->nchars; 446 if(t->org<=q0 && (q0<qe || (q0==qe && qe==t->rs.nr))) 447 textscrdraw(t); 448 else{ 449 nl = t->maxlines/4; 450 q = textbacknl(t, q0, nl); 451 /* avoid going backwards if trying to go forwards - long lines! */ 452 if(!(q0>t->org && q<t->org)) 453 textsetorigin(t, q, TRUE); 454 while(q0 > t->org+t->nchars) 455 textsetorigin(t, t->org+1, FALSE); 456 } 457 } 458 459 static 460 int 461 region(int a, int b) 462 { 463 if(a < b) 464 return -1; 465 if(a == b) 466 return 0; 467 return 1; 468 } 469 470 void 471 selrestore(Frame *f, Point pt0, uint p0, uint p1) 472 { 473 if(p1<=f->p0 || p0>=f->p1){ 474 /* no overlap */ 475 frdrawsel0(f, pt0, p0, p1, f->cols[BACK], f->cols[TEXT]); 476 return; 477 } 478 if(p0>=f->p0 && p1<=f->p1){ 479 /* entirely inside */ 480 frdrawsel0(f, pt0, p0, p1, f->cols[HIGH], f->cols[HTEXT]); 481 return; 482 } 483 484 /* they now are known to overlap */ 485 486 /* before selection */ 487 if(p0 < f->p0){ 488 frdrawsel0(f, pt0, p0, f->p0, f->cols[BACK], f->cols[TEXT]); 489 p0 = f->p0; 490 pt0 = frptofchar(f, p0); 491 } 492 /* after selection */ 493 if(p1 > f->p1){ 494 frdrawsel0(f, frptofchar(f, f->p1), f->p1, p1, f->cols[BACK], f->cols[TEXT]); 495 p1 = f->p1; 496 } 497 /* inside selection */ 498 frdrawsel0(f, pt0, p0, p1, f->cols[HIGH], f->cols[HTEXT]); 499 } 500 501 void 502 textsetselect(Text *t, uint q0, uint q1) 503 { 504 int p0, p1; 505 506 /* t->p0 and t->p1 are always right; t->q0 and t->q1 may be off */ 507 t->q0 = q0; 508 t->q1 = q1; 509 /* compute desired p0,p1 from q0,q1 */ 510 p0 = q0-t->org; 511 p1 = q1-t->org; 512 if(p0 < 0) 513 p0 = 0; 514 if(p1 < 0) 515 p1 = 0; 516 if(p0 > t->nchars) 517 p0 = t->nchars; 518 if(p1 > t->nchars) 519 p1 = t->nchars; 520 if(p0==t->p0 && p1==t->p1) 521 return; 522 /* screen disagrees with desired selection */ 523 if(t->p1<=p0 || p1<=t->p0 || p0==p1 || t->p1==t->p0){ 524 /* no overlap or too easy to bother trying */ 525 frdrawsel(t, frptofchar(t, t->p0), t->p0, t->p1, 0); 526 frdrawsel(t, frptofchar(t, p0), p0, p1, 1); 527 goto Return; 528 } 529 /* overlap; avoid unnecessary painting */ 530 if(p0 < t->p0){ 531 /* extend selection backwards */ 532 frdrawsel(t, frptofchar(t, p0), p0, t->p0, 1); 533 }else if(p0 > t->p0){ 534 /* trim first part of selection */ 535 frdrawsel(t, frptofchar(t, t->p0), t->p0, p0, 0); 536 } 537 if(p1 > t->p1){ 538 /* extend selection forwards */ 539 frdrawsel(t, frptofchar(t, t->p1), t->p1, p1, 1); 540 }else if(p1 < t->p1){ 541 /* trim last part of selection */ 542 frdrawsel(t, frptofchar(t, p1), p1, t->p1, 0); 543 } 544 545 Return: 546 t->p0 = p0; 547 t->p1 = p1; 548 } 549 550 551 /* 552 * Release the button in less than DELAY ms and it's considered a null selection 553 * if the mouse hardly moved, regardless of whether it crossed a char boundary. 554 */ 555 enum { 556 DELAY = 2, 557 MINMOVE = 4, 558 }; 559 560 uint 561 xselect(Frame *f, Mousectl *mc, Image *col, uint *p1p) /* when called, button is down */ 562 { 563 uint p0, p1, q, tmp; 564 ulong msec; 565 Point mp, pt0, pt1, qt; 566 int reg, b; 567 568 mp = mc->xy; 569 b = mc->buttons; 570 msec = mc->msec; 571 572 /* remove tick */ 573 if(f->p0 == f->p1) 574 frtick(f, frptofchar(f, f->p0), 0); 575 p0 = p1 = frcharofpt(f, mp); 576 pt0 = frptofchar(f, p0); 577 pt1 = frptofchar(f, p1); 578 reg = 0; 579 frtick(f, pt0, 1); 580 do{ 581 q = frcharofpt(f, mc->xy); 582 if(p1 != q){ 583 if(p0 == p1) 584 frtick(f, pt0, 0); 585 if(reg != region(q, p0)){ /* crossed starting point; reset */ 586 if(reg > 0) 587 selrestore(f, pt0, p0, p1); 588 else if(reg < 0) 589 selrestore(f, pt1, p1, p0); 590 p1 = p0; 591 pt1 = pt0; 592 reg = region(q, p0); 593 if(reg == 0) 594 frdrawsel0(f, pt0, p0, p1, col, display->white); 595 } 596 qt = frptofchar(f, q); 597 if(reg > 0){ 598 if(q > p1) 599 frdrawsel0(f, pt1, p1, q, col, display->white); 600 601 else if(q < p1) 602 selrestore(f, qt, q, p1); 603 }else if(reg < 0){ 604 if(q > p1) 605 selrestore(f, pt1, p1, q); 606 else 607 frdrawsel0(f, qt, q, p1, col, display->white); 608 } 609 p1 = q; 610 pt1 = qt; 611 } 612 if(p0 == p1) 613 frtick(f, pt0, 1); 614 flushimage(f->display, 1); 615 readmouse(mc); 616 }while(mc->buttons == b); 617 if(mc->msec-msec < DELAY && p0!=p1 618 && abs(mp.x-mc->xy.x)<MINMOVE 619 && abs(mp.y-mc->xy.y)<MINMOVE) { 620 if(reg > 0) 621 selrestore(f, pt0, p0, p1); 622 else if(reg < 0) 623 selrestore(f, pt1, p1, p0); 624 p1 = p0; 625 } 626 if(p1 < p0){ 627 tmp = p0; 628 p0 = p1; 629 p1 = tmp; 630 } 631 pt0 = frptofchar(f, p0); 632 if(p0 == p1) 633 frtick(f, pt0, 0); 634 selrestore(f, pt0, p0, p1); 635 /* restore tick */ 636 if(f->p0 == f->p1) 637 frtick(f, frptofchar(f, f->p0), 1); 638 flushimage(f->display, 1); 639 *p1p = p1; 640 return p0; 641 } 642 643 int 644 textselect23(Text *t, uint *q0, uint *q1, Image *high, int mask) 645 { 646 uint p0, p1; 647 int buts; 648 649 p0 = xselect(t, mousectl, high, &p1); 650 buts = mousectl->buttons; 651 if((buts & mask) == 0){ 652 *q0 = p0+t->org; 653 *q1 = p1+t->org; 654 } 655 656 while(mousectl->buttons) 657 readmouse(mousectl); 658 return buts; 659 } 660 661 int 662 textselect2(Text *t, uint *q0, uint *q1, Text **tp) 663 { 664 int buts; 665 666 *tp = nil; 667 buts = textselect23(t, q0, q1, but2col, 4); 668 if(buts & 4) 669 return 0; 670 if(buts & 1){ /* pick up argument */ 671 *tp = argtext; 672 return 1; 673 } 674 return 1; 675 } 676 677 int 678 textselect3(Text *t, uint *q0, uint *q1) 679 { 680 int h; 681 682 h = (textselect23(t, q0, q1, but3col, 1|2) == 0); 683 return h; 684 } 685 686 static Rune left1[] = { L'{', L'[', L'(', L'<', L'«', 0 }; 687 static Rune right1[] = { L'}', L']', L')', L'>', L'»', 0 }; 688 static Rune left2[] = { L'\n', 0 }; 689 static Rune left3[] = { L'\'', L'"', L'`', 0 }; 690 691 static 692 Rune *left[] = { 693 left1, 694 left2, 695 left3, 696 nil 697 }; 698 static 699 Rune *right[] = { 700 right1, 701 left2, 702 left3, 703 nil 704 }; 705 706 void 707 textdoubleclick(Text *t, uint *q0, uint *q1) 708 { 709 int c, i; 710 Rune *r, *l, *p; 711 uint q; 712 713 if(t->rs.nr == 0) 714 return; 715 716 for(i=0; left[i]!=nil; i++){ 717 q = *q0; 718 l = left[i]; 719 r = right[i]; 720 /* try matching character to left, looking right */ 721 if(q == 0) 722 c = '\n'; 723 else 724 c = t->rs.r[q-1]; 725 p = runestrchr(l, c); 726 if(p != nil){ 727 if(textclickmatch(t, c, t->rs.r[p-l], 1, &q)) 728 *q1 = q-(c!='\n'); 729 return; 730 } 731 /* try matching character to right, looking left */ 732 if(q == t->rs.nr) 733 c = '\n'; 734 else 735 c = t->rs.r[q]; 736 p = runestrchr(r, c); 737 if(p != nil){ 738 if(textclickmatch(t, c, l[p-r], -1, &q)){ 739 *q1 = *q0+(*q0<t->rs.nr && c=='\n'); 740 *q0 = q; 741 if(c!='\n' || q!=0 || t->rs.r[0]=='\n') 742 (*q0)++; 743 } 744 return; 745 } 746 } 747 /* try filling out word to right */ 748 while(*q1<t->rs.nr && isalnum(t->rs.r[*q1])) 749 (*q1)++; 750 /* try filling out word to left */ 751 while(*q0>0 && isalnum(t->rs.r[*q0-1])) 752 (*q0)--; 753 } 754 755 int 756 textclickmatch(Text *t, int cl, int cr, int dir, uint *q) 757 { 758 Rune c; 759 int nest; 760 761 nest = 1; 762 for(;;){ 763 if(dir > 0){ 764 if(*q == t->rs.nr) 765 break; 766 c = t->rs.r[*q]; 767 (*q)++; 768 }else{ 769 if(*q == 0) 770 break; 771 (*q)--; 772 c = t->rs.r[*q]; 773 } 774 if(c == cr){ 775 if(--nest==0) 776 return 1; 777 }else if(c == cl) 778 nest++; 779 } 780 return cl=='\n' && nest==1; 781 } 782 783 uint 784 textbacknl(Text *t, uint p, uint n) 785 { 786 int i, j; 787 788 /* look for start of this line if n==0 */ 789 if(n==0 && p>0 && t->rs.r[p-1]!='\n') 790 n = 1; 791 i = n; 792 while(i-->0 && p>0){ 793 --p; /* it's at a newline now; back over it */ 794 if(p == 0) 795 break; 796 /* at 128 chars, call it a line anyway */ 797 for(j=128; --j>0 && p>0; p--) 798 if(t->rs.r[p-1]=='\n') 799 break; 800 } 801 return p; 802 } 803 804 void 805 textsetorigin(Text *t, uint org, int exact) 806 { 807 int i, a, fixup; 808 Rune *r; 809 uint n; 810 811 if(org>0 && !exact){ 812 /* org is an estimate of the char posn; find a newline */ 813 /* don't try harder than 256 chars */ 814 for(i=0; i<256 && org<t->rs.nr; i++){ 815 if(t->rs.r[org] == '\n'){ 816 org++; 817 break; 818 } 819 org++; 820 } 821 } 822 a = org-t->org; 823 fixup = 0; 824 if(a>=0 && a<t->nchars){ 825 frdelete(t, 0, a); 826 fixup = 1; /* frdelete can leave end of last line in wrong selection mode; it doesn't know what follows */ 827 }else if(a<0 && -a<t->nchars){ 828 n = t->org - org; 829 r = runemalloc(n); 830 runemove(r, t->rs.r+org, n); 831 frinsert(t, r, r+n, 0); 832 free(r); 833 }else 834 frdelete(t, 0, t->nchars); 835 t->org = org; 836 textfill(t); 837 textscrdraw(t); 838 textsetselect(t, t->q0, t->q1); 839 if(fixup && t->p1 > t->p0) 840 frdrawsel(t, frptofchar(t, t->p1-1), t->p1-1, t->p1, 1); 841 } 842 843 void 844 textset(Text *t, Rune*r, int n) 845 { 846 textdelete(t, 0, t->rs.nr); 847 textinsert(t, 0, r, n); 848 textsetselect(t, t->q0, t->q1); 849 } 850 851 void 852 textmouse(Text *t, Point xy, int but) 853 { 854 Text *argt; 855 uint q0, q1; 856 857 if(ptinrect(xy, t->scrollr)){ 858 if(t->what == Columntag) 859 rowdragcol(&row, t->col, but); 860 else if(t->what == Tag) 861 coldragwin(t->col, t->w, but); 862 else if(t->what == Textarea) 863 textscroll(t, but); 864 if(t->col) 865 activecol = t->col; 866 return; 867 } 868 if(but == 1){ 869 selpage = nil; 870 textselect(t); 871 argtext = t; 872 seltext = t; 873 }else if(but == 2){ 874 if(textselect2(t, &q0, &q1, &argt)) 875 execute(t, q0, q1, argt); 876 }else if(but == 3){ 877 if(textselect3(t, &q0, &q1)) 878 look3(t, q0, q1); 879 } 880 } 881