1 #include <lib9.h> 2 #include <kernel.h> 3 #include "draw.h" 4 #include "tk.h" 5 #include "canvs.h" 6 7 /* Widget Commands (+ means implemented) 8 +addtag 9 except halo and start options of closest spec 10 +bbox 11 +bind 12 +canvasx 13 +canvasy 14 +cget 15 +configure 16 +coords 17 +create 18 +dchars 19 +delete 20 +dtag 21 +find 22 +focus 23 +gettags 24 +icursor 25 +index 26 +insert 27 +itemcget 28 +itemconfigure 29 +lower 30 +move 31 postscript 32 +raise 33 +scale 34 scan 35 +select 36 +type 37 +xview 38 +yview 39 */ 40 41 static 42 TkStab tkbuffer[] = { 43 "visible", TkCbufvisible, 44 "all", TkCbufall, 45 "none", TkCbufnone, 46 "auto", TkCbufauto, 47 48 /* backwards compatibility */ 49 "1", TkCbufall, 50 "yes", TkCbufall, 51 "off", TkCbufall, 52 "0", TkCbufauto, 53 "no", TkCbufauto, 54 "off", TkCbufauto, 55 nil 56 }; 57 58 #define O(t, e) ((long)(&((t*)0)->e)) 59 #define OA(t, e) ((long)(((t*)0)->e)) 60 61 static 62 TkOption opts[] = 63 { 64 "closeenough", OPTfrac, O(TkCanvas, close), nil, 65 "confine", OPTfrac, O(TkCanvas, confine), nil, 66 "scrollregion", OPTfrac, OA(TkCanvas, scrollr), IAUX(4), 67 "xscrollincrement", OPTfrac, O(TkCanvas, xscrolli), nil, 68 "yscrollincrement", OPTfrac, O(TkCanvas, yscrolli), nil, 69 "xscrollcommand", OPTtext, O(TkCanvas, xscroll), nil, 70 "yscrollcommand", OPTtext, O(TkCanvas, yscroll), nil, 71 "width", OPTnnfrac, O(TkCanvas, width), nil, 72 "height", OPTnnfrac, O(TkCanvas, height), nil, 73 "buffer", OPTstab, O(TkCanvas, buffer), tkbuffer, 74 "buffered", OPTstab, O(TkCanvas, buffer), tkbool, /* backwards compatibility */ 75 "selectborderwidth", OPTnndist, O(TkCanvas, sborderwidth), nil, 76 nil 77 }; 78 79 int cvslshape[] = { TKI2F(8), TKI2F(10), TKI2F(3) }; 80 Rectangle bbnil = { 1000000, 1000000, -1000000, -1000000 }; 81 Rectangle huger = { -1000000, -1000000, 1000000, 1000000 }; 82 83 static void tkcvsgeom(Tk *tk); 84 85 86 static void 87 tkcvsf2i(Tk *tk, TkCanvas *tkc) 88 { 89 Rectangle r; 90 tk->req.width = TKF2I(tkc->width); 91 tk->req.height = TKF2I(tkc->height); 92 93 r.min.x = TKF2I(tkc->scrollr[0]); 94 r.min.y = TKF2I(tkc->scrollr[1]); 95 r.max.x = TKF2I(tkc->scrollr[2]); 96 r.max.y = TKF2I(tkc->scrollr[3]); 97 98 /* 99 * make sure that the region is big enough to hold 100 * the actually displayed area 101 */ 102 if (Dx(r) < tk->act.width) 103 r.max.x = r.min.x + tk->act.width; 104 if (Dy(r) < tk->act.height) 105 r.max.y = r.min.y + tk->act.height; 106 tkc->region = r; 107 108 /* 109 * make sure that the view origin is at a valid 110 * position with respect to the scroll region. 111 */ 112 if (tkc->view.x + tk->act.width > r.max.x) 113 tkc->view.x = r.max.x - tk->act.width; 114 if (tkc->view.x < r.min.x) 115 tkc->view.x = r.min.x; 116 117 if (tkc->view.y + tk->act.height > r.max.y) 118 tkc->view.y = r.max.y - tk->act.height; 119 if (tkc->view.y < r.min.y) 120 tkc->view.y = r.min.y; 121 122 } 123 124 char* 125 tkcanvas(TkTop *t, char *arg, char **ret) 126 { 127 Tk *tk; 128 char *e; 129 TkCanvas *tkc; 130 TkName *names; 131 TkOptab tko[3]; 132 133 tk = tknewobj(t, TKcanvas, sizeof(Tk)+sizeof(TkCanvas)); 134 if(tk == nil) 135 return TkNomem; 136 137 tkc = TKobj(TkCanvas, tk); 138 tkc->close = TKI2F(1); 139 tkc->xscrolli = TKI2F(1); 140 tkc->yscrolli = TKI2F(1); 141 tkc->width = TKI2F(360); 142 tkc->height = TKI2F(270); 143 tkc->actions = 0; 144 tkc->actlim = Tksweep; 145 tkc->mask = nil; 146 tkc->sborderwidth = 1; 147 148 tko[0].ptr = tkc; 149 tko[0].optab = opts; 150 tko[1].ptr = tk; 151 tko[1].optab = tkgeneric; 152 tko[2].ptr = nil; 153 154 names = nil; 155 e = tkparse(t, arg, tko, &names); 156 if(e != nil) 157 goto err; 158 if(names == nil) { 159 /* tkerr(t, arg); XXX */ 160 e = TkBadwp; 161 goto err; 162 } 163 164 tkc->current = tkmkname("current"); 165 if(tkc->current == nil) { 166 e = TkNomem; 167 goto err; 168 } 169 170 tksettransparent(tk, tkhasalpha(tk->env, TkCbackgnd)); 171 tkcvsf2i(tk, tkc); 172 173 e = tkaddchild(t, tk, &names); 174 tkfreename(names); 175 if(e != nil) { 176 tkfreename(tkc->current); 177 tkc->current = nil; 178 goto err; 179 } 180 tk->name->link = nil; 181 182 e = tkvalue(ret, "%s", tk->name->name); 183 if(e == nil) 184 return nil; 185 186 tkfreename(tkc->current); 187 return e; 188 err: 189 tkfreeobj(tk); 190 return e; 191 } 192 193 void 194 tkcvsdirty(Tk *sub) 195 { 196 TkCanvas *c; 197 Tk *tk, *parent; 198 Rectangle r; 199 Point rel; 200 201 rel = ZP; 202 for(tk = sub; tk; tk = tk->master) { 203 rel.x += tk->borderwidth + tk->act.x; 204 rel.y += tk->borderwidth + tk->act.y; 205 if (tk->parent != nil) 206 break; 207 } 208 if (tk == nil) 209 return; 210 parent = tk->parent; 211 c = TKobj(TkCanvas, parent); 212 r = rectaddpt(sub->dirty, rel); 213 tkbbmax(&c->update, &r); 214 tkcvssetdirty(parent); 215 } 216 217 static void 218 tkcvsfocusorder(Tk *tk) 219 { 220 TkCanvas *tkc = TKobj(TkCanvas, tk); 221 TkCwind *win; 222 TkCitem *it; 223 TkWinfo *inf; 224 int i, n; 225 226 n = 0; 227 for (it = tkc->head; it != nil; it = it->next) { 228 if (it->type == TkCVwindow) { 229 win = TKobj(TkCwind, it); 230 if (win->sub != nil) 231 n++; 232 } 233 } 234 if (n == 0) 235 return; 236 237 inf = malloc(sizeof(*inf) * n); 238 if (inf == nil) 239 return; 240 241 i = 0; 242 for (it = tkc->head; it != nil; it = it->next) { 243 if (it->type == TkCVwindow) { 244 win = TKobj(TkCwind, it); 245 if (win->sub != nil) { 246 inf[i].w = win->sub; 247 inf[i].r = it->p.bb; 248 i++; 249 } 250 } 251 } 252 253 tksortfocusorder(inf, n); 254 for (i = 0; i < n; i++) 255 tkappendfocusorder(inf[i].w); 256 } 257 258 static char* 259 tkcvscget(Tk *tk, char *arg, char **val) 260 { 261 TkOptab tko[3]; 262 TkCanvas *tkc = TKobj(TkCanvas, tk); 263 264 tko[0].ptr = tkc; 265 tko[0].optab = opts; 266 tko[1].ptr = tk; 267 tko[1].optab = tkgeneric; 268 tko[2].ptr = nil; 269 270 return tkgencget(tko, arg, val, tk->env->top); 271 } 272 273 static char* 274 tkcvsconf(Tk *tk, char *arg, char **val) 275 { 276 char *e; 277 int bd; 278 TkGeom g; 279 Rectangle r; 280 TkOptab tko[3]; 281 TkCanvas *c = TKobj(TkCanvas, tk); 282 283 tko[0].ptr = c; 284 tko[0].optab = opts; 285 tko[1].ptr = tk; 286 tko[1].optab = tkgeneric; 287 tko[2].ptr = nil; 288 289 if(*arg == '\0') 290 return tkconflist(tko, val); 291 292 r.min = c->view; 293 r.max.x = r.min.x+tk->act.width; 294 r.max.y = r.min.y+tk->act.height; 295 tkbbmax(&c->update, &r); 296 tkbbmax(&c->update, &c->region); 297 298 bd = tk->borderwidth; 299 g = tk->req; 300 e = tkparse(tk->env->top, arg, tko, nil); 301 if(e != nil) 302 return e; 303 tksettransparent(tk, tkhasalpha(tk->env, TkCbackgnd)); 304 305 tkcvsf2i(tk, c); 306 307 tkcvsgeom(tk); 308 tkgeomchg(tk, &g, bd); 309 tkbbmax(&c->update, &c->region); 310 tk->dirty = tkrect(tk, 1); 311 return nil; 312 } 313 314 void 315 tkcvsfreeitem(TkCitem *i) 316 { 317 int locked; 318 Display *d; 319 320 d = i->env->top->display; 321 322 locked = lockdisplay(d); 323 tkcimethod[i->type].free(i); 324 if(locked) 325 unlockdisplay(d); 326 327 tkfreepoint(&i->p); 328 tkputenv(i->env); 329 free(i); 330 } 331 332 void 333 tkfreecanv(Tk *tk) 334 { 335 Display *d; 336 int j, locked; 337 TkCanvas *c; 338 TkName *n, *nn; 339 TkCtag *t, *tt; 340 TkCitem *i, *next; 341 342 c = TKobj(TkCanvas, tk); 343 for(i = c->head; i; i = next) { 344 next = i->next; 345 tkcvsfreeitem(i); 346 } 347 348 if(c->xscroll != nil) 349 free(c->xscroll); 350 if(c->yscroll != nil) 351 free(c->yscroll); 352 353 for(j = 0; j < TkChash; j++) { 354 for(n = c->thash[j]; n; n = nn) { 355 nn = n->link; 356 for(t = n->obj; t; t = tt) { 357 tt = t->taglist; 358 free(t); 359 } 360 tkfreebind(n->prop.binds); 361 free(n); 362 } 363 } 364 365 free(c->current); 366 367 if((c->ialloc && c->image != nil) || c->mask != nil) { 368 if (c->ialloc && c->image != nil) 369 d = c->image->display; 370 else 371 d = c->mask->display; 372 locked = lockdisplay(d); 373 if (c->image != nil && c->ialloc) 374 freeimage(c->image); 375 if (c->mask != nil) 376 freeimage(c->mask); 377 if(locked) 378 unlockdisplay(d); 379 } 380 } 381 382 enum {Bufnone = 99}; 383 384 char* 385 tkdrawcanv(Tk *tk, Point orig) 386 { 387 Image *dst; 388 TkCitem *i; 389 Display *d; 390 TkCanvas *c; 391 Rectangle r, bufr, oclipr; 392 int vis, alpha, buffer; 393 Point rel, p; 394 TkCimeth *imeth; 395 396 c = TKobj(TkCanvas, tk); 397 d = tk->env->top->display; 398 dst = tkimageof(tk); 399 /* 400 * translation from local to screen coords 401 */ 402 rel.x = orig.x + tk->act.x + tk->borderwidth; 403 rel.y = orig.y + tk->act.y + tk->borderwidth; 404 405 buffer = c->buffer; 406 if (buffer == TkCbufauto) 407 buffer = TkCbufvisible; 408 /* buffer = (dst == TKobj(TkWin, tk->env->top->root)->image) ? TkCbufvisible : TkCbufnone; */ 409 410 if (buffer == TkCbufnone) { 411 if(c->image != nil && c->ialloc) 412 freeimage(c->image); 413 c->image = dst; 414 c->ialloc = 0; 415 416 r = tkrect(tk, 0); 417 bufr = r; 418 rectclip(&bufr, tk->dirty); 419 oclipr = dst->clipr; 420 421 replclipr(dst, 0, rectaddpt(bufr, rel)); 422 draw(dst, rectaddpt(bufr, rel), tkgc(tk->env, TkCbackgnd), nil, ZP); 423 424 p = subpt(rel, c->view); 425 p.x = TKI2F(p.x); 426 p.y = TKI2F(p.y); 427 bufr = rectaddpt(bufr, c->view); 428 for(i = c->head; i; i = i->next) { 429 if(rectXrect(i->p.bb, bufr)) { 430 imeth = &tkcimethod[i->type]; 431 imeth->coord(i, nil, p.x, p.y); 432 imeth->draw(dst, i, tk->env); 433 imeth->coord(i, nil, -p.x, -p.y); 434 } 435 } 436 replclipr(dst, 0, oclipr); 437 } else { 438 if (c->buffer == TkCbufall) 439 bufr = c->region; 440 else { 441 bufr.min = c->view; 442 bufr.max.x = c->view.x + tk->act.width; 443 bufr.max.y = c->view.y + tk->act.height; 444 } 445 alpha = (tk->env->colors[TkCbackgnd] & 0xff) != 0xff; 446 if(c->image == nil || eqrect(bufr, c->image->r) == 0) { 447 if(c->image != nil && c->ialloc) 448 freeimage(c->image); 449 c->image = allocimage(d, bufr, alpha?RGBA32:d->image->chan, 0, tk->env->colors[TkCbackgnd]); 450 c->ialloc = 1; 451 c->update = bufr; 452 tkcvssetdirty(tk); /* unnecessary? */ 453 } 454 455 if(c->image == nil) 456 return nil; 457 458 r = c->update; 459 if (rectclip(&r, c->image->r)) { 460 if (alpha) 461 drawop(c->image, c->update, nil, nil, ZP, Clear); 462 draw(c->image, c->update, tkgc(tk->env, TkCbackgnd), nil, c->view); 463 replclipr(c->image, 0, r); 464 for(i = c->head; i; i = i->next) { 465 if(rectXrect(i->p.bb, r)) 466 tkcimethod[i->type].draw(c->image, i, tk->env); 467 } 468 replclipr(c->image, 0, c->image->r); 469 } 470 /* 471 * if the visible area of the canvas image doesn't 472 * fit completely within the dirty rectangle, 473 * then we'll need to draw the background behind it 474 */ 475 r = tkrect(tk, 0); 476 bufr = rectsubpt(bufr, c->view); 477 vis = rectclip(&bufr, tkrect(tk, 0)); 478 479 if (!vis || !rectinrect(tk->dirty, bufr)) 480 draw(dst, rectaddpt(tk->dirty, rel), tkgc(tk->env, TkCbackgnd), nil, c->view); 481 482 if (vis && rectclip(&bufr, tk->dirty)) 483 draw(dst, rectaddpt(bufr, rel), c->image, nil, addpt(bufr.min, c->view)); 484 } 485 486 487 /* 488 * if the border is dirty too, then draw that 489 */ 490 if (!rectinrect(tk->dirty, bufr)) { 491 r.min = addpt(r.min, rel); 492 r.min.x -= tk->borderwidth; 493 r.min.y -= tk->borderwidth; 494 tkdrawrelief(dst, tk, r.min, TkCbackgnd, tk->relief); 495 } 496 c->update = bbnil; 497 return nil; 498 } 499 500 void 501 tkcvsappend(TkCanvas *c, TkCitem *i) 502 { 503 if(c->head == nil) 504 c->head = i; 505 else 506 c->tail->next = i; 507 c->tail = i; 508 } 509 510 void 511 tkcvssv(Tk *tk) 512 { 513 TkCanvas *c; 514 int top, bot, height; 515 char val[Tkminitem], cmd[Tkmaxitem], *v, *e; 516 517 c = TKobj(TkCanvas, tk); 518 if(c->yscroll == nil) 519 return; 520 521 top = 0; 522 bot = TKI2F(1); 523 524 height = Dy(c->region); 525 if(height != 0) { 526 top = TKI2F(c->view.y)/height; 527 bot = TKI2F(c->view.y+tk->act.height)/height; 528 } 529 530 v = tkfprint(val, top); 531 *v++ = ' '; 532 tkfprint(v, bot); 533 snprint(cmd, sizeof(cmd), "%s %s", c->yscroll, val); 534 e = tkexec(tk->env->top, cmd, nil); 535 if ((e != nil) && (tk->name != nil)) 536 print("tk: yscrollcommand \"%s\": %s\n", tk->name->name, e); 537 } 538 539 void 540 tkcvssh(Tk *tk) 541 { 542 int top, bot, width; 543 TkCanvas *c = TKobj(TkCanvas, tk); 544 char val[Tkminitem], cmd[Tkmaxitem], *v, *e; 545 546 if(c->xscroll == nil) 547 return; 548 549 top = 0; 550 bot = TKI2F(1); 551 552 width = Dx(c->region); 553 if(width != 0) { 554 top = TKI2F(c->view.x)/width; 555 bot = TKI2F(c->view.x+tk->act.width)/width; 556 } 557 558 v = tkfprint(val, top); 559 *v++ = ' '; 560 tkfprint(v, bot); 561 snprint(cmd, sizeof(cmd), "%s %s", c->xscroll, val); 562 e = tkexec(tk->env->top, cmd, nil); 563 if ((e != nil) && (tk->name != nil)) 564 print("tk: xscrollcommand \"%s\": %s\n", tk->name->name, e); 565 } 566 567 static void 568 tkcvsgeom(Tk *tk) 569 { 570 TkCanvas *c; 571 c = TKobj(TkCanvas, tk); 572 573 tkcvsf2i(tk, c); 574 tk->dirty = tkrect(tk, 1); 575 c->update = c->region; 576 577 tkcvssv(tk); 578 tkcvssh(tk); 579 } 580 581 char* 582 tkcvstags(Tk *tk, char *arg, char **val, int af) 583 { 584 TkTop *o; 585 int x, y; 586 TkName *f; 587 TkCtag *t, *tt; 588 char *fmt; 589 TkCpoints p; 590 TkCanvas *c; 591 TkCitem *i, *b; 592 int d, dist, dx, dy; 593 char tag[Tkmaxitem], buf[Tkmaxitem]; 594 char *e; 595 596 USED(val); 597 598 c = TKobj(TkCanvas, tk); 599 600 o = tk->env->top; 601 if(af == TkCadd) { 602 arg = tkword(o, arg, tag, tag+sizeof(tag), nil); 603 if(tag[0] == '\0' || (tag[0] >= '0' && tag[0] <= '9')) 604 return TkBadtg; 605 } 606 607 fmt = "%d"; 608 arg = tkword(o, arg, buf, buf+sizeof(buf), nil); 609 if(strcmp(buf, "above") == 0) { 610 tkword(o, arg, buf, buf+sizeof(buf), nil); 611 f = tkctaglook(tk, nil, buf); 612 if(f == nil) 613 return TkBadtg; 614 615 t = tkclasttag(c->head, f->obj); 616 if(t == nil) 617 return TkBadtg; 618 619 for(i = t->item->next; i; i = i->next) { 620 if(af == TkCadd) { 621 i->tags = tkmkname(tag); 622 if(i->tags == nil) 623 return TkNomem; 624 tkcaddtag(tk, i, 0); 625 } 626 else { 627 e = tkvalue(val, fmt, i->id); 628 if(e != nil) 629 return e; 630 fmt = " %d"; 631 } 632 } 633 return nil; 634 } 635 636 if(strcmp(buf, "all") == 0) { 637 for(i = c->head; i; i = i->next) { 638 if(af == TkCadd) { 639 i->tags = tkmkname(tag); 640 if(i->tags == nil) 641 return TkNomem; 642 tkcaddtag(tk, i, 0); 643 } 644 else { 645 e = tkvalue(val, fmt, i->id); 646 if(e != nil) 647 return e; 648 fmt = " %d"; 649 } 650 } 651 return nil; 652 } 653 654 if(strcmp(buf, "below") == 0) { 655 tkword(o, arg, buf, buf+sizeof(buf), nil); 656 f = tkctaglook(tk, nil, buf); 657 if(f == nil) 658 return TkBadtg; 659 tt = f->obj; 660 for(b = c->head; b; b = b->next) { 661 for(t = tt; t; t = t->itemlist) 662 if(t->item == b) 663 goto found; 664 } 665 found: 666 for(i = c->head; i != b; i = i->next) { 667 if(af == TkCadd) { 668 i->tags = tkmkname(tag); 669 if(i->tags == nil) 670 return TkNomem; 671 tkcaddtag(tk, i, 0); 672 } 673 else { 674 e = tkvalue(val, fmt, i->id); 675 if(e != nil) 676 return e; 677 fmt = " %d"; 678 } 679 } 680 return nil; 681 } 682 683 if(strcmp(buf, "closest") == 0) { 684 e = tkfracword(o, &arg, &x, nil); 685 if (e == nil) 686 e = tkfracword(o, &arg, &y, nil); 687 if (e != nil) 688 return e; 689 if(*arg != '\0') 690 return "!not implemented"; 691 692 x = TKF2I(x); 693 y = TKF2I(y); 694 i = nil; 695 dist = 0; 696 for(b = c->head; b != nil; b = b->next) { 697 dx = x - (b->p.bb.min.x + Dx(b->p.bb)/2); 698 dy = y - (b->p.bb.min.y + Dy(b->p.bb)/2); 699 d = dx*dx + dy*dy; 700 if(d < dist || dist == 0) { 701 i = b; 702 dist = d; 703 } 704 } 705 if(i == nil) 706 return nil; 707 708 if(af == TkCadd) { 709 i->tags = tkmkname(tag); 710 if(i->tags == nil) 711 e = TkNomem; 712 else 713 tkcaddtag(tk, i, 0); 714 } 715 else 716 e = tkvalue(val, fmt, i->id); 717 return e; 718 } 719 720 if(strcmp(buf, "withtag") == 0) { 721 tkword(o, arg, buf, buf+sizeof(buf), nil); 722 f = tkctaglook(tk, nil, buf); 723 if(f == nil) 724 return TkBadtg; 725 for(t = f->obj; t; t = t->taglist) { 726 i = t->item; 727 if(af == TkCadd) { 728 i->tags = tkmkname(tag); 729 if(i->tags == nil) 730 return TkNomem; 731 tkcaddtag(tk, i, 0); 732 } 733 else { 734 e = tkvalue(val, fmt, i->id); 735 if(e != nil) 736 return e; 737 fmt = " %d"; 738 } 739 } 740 return nil; 741 } 742 743 if(strcmp(buf, "enclosed") == 0) { 744 e = tkparsepts(o, &p, &arg, 0); 745 if(e != nil) 746 goto done; 747 if(p.npoint != 2) { 748 e = TkFewpt; 749 goto done; 750 } 751 for(i = c->head; i; i = i->next) { 752 if(rectinrect(i->p.bb, p.bb)) { 753 if(af == TkCadd) { 754 i->tags = tkmkname(tag); 755 if(i->tags == nil) { 756 e = TkNomem; 757 goto done; 758 } 759 tkcaddtag(tk, i, 0); 760 } 761 else { 762 e = tkvalue(val, fmt, i->id); 763 if(e != nil) 764 goto done; 765 fmt = " %d"; 766 } 767 } 768 } 769 goto done; 770 } 771 772 if(strcmp(buf, "overlapping") == 0) { 773 e = tkparsepts(o, &p, &arg, 0); 774 if(e != nil) 775 goto done; 776 if(p.npoint != 2) { 777 e = TkFewpt; 778 goto done; 779 } 780 for(i = c->head; i; i = i->next) { 781 if(rectXrect(i->p.bb, p.bb)) { 782 if(af == TkCadd) { 783 i->tags = tkmkname(tag); 784 if(i->tags == nil) { 785 e = TkNomem; 786 goto done; 787 } 788 tkcaddtag(tk, i, 0); 789 } 790 else { 791 e = tkvalue(val, "%d ", i->id); 792 if(e != nil) 793 goto done; 794 } 795 } 796 } 797 goto done; 798 } 799 800 return TkBadcm; 801 802 done: /* both no error and error do the same thing */ 803 tkfreepoint(&p); 804 return e; 805 } 806 807 static char* 808 tkcvsaddtag(Tk *tk, char *arg, char **val) 809 { 810 return tkcvstags(tk, arg, val, TkCadd); 811 } 812 813 static char* 814 tkcvsfind(Tk *tk, char *arg, char **val) 815 { 816 return tkcvstags(tk, arg, val, TkCfind); 817 } 818 819 static void 820 tksweepcanv(Tk *tk) 821 { 822 int j, k; 823 TkCtag *t, *tt; 824 TkName **np, *n, *nn; 825 TkCitem *i; 826 TkCanvas *c; 827 TkAction *a; 828 829 c = TKobj(TkCanvas, tk); 830 831 for(j = 0; j < TkChash; j++) 832 for(n = c->thash[j]; n != nil; n = n->link) 833 n->ref = 0; 834 835 for(i = c->head; i != nil; i = i->next) 836 for(t = i->stag; t != nil; t = t->itemlist) 837 t->name->ref = 1; 838 839 k = 0; 840 for(j = 0; j < TkChash; j++) { 841 np = &c->thash[j]; 842 for(n = *np; n != nil; n = nn) { 843 nn = n->link; 844 if(n->ref == 0) { 845 for(t = n->obj; t != nil; t = tt) { 846 tt = t->taglist; 847 free(t); 848 } 849 tkfreebind(n->prop.binds); 850 free(n); 851 *np = nn; 852 } else { 853 np = &n->link; 854 for(a = n->prop.binds; a != nil; a = a->link) 855 k++; 856 } 857 } 858 } 859 860 c->actions = k; 861 k = 3 * k / 2; 862 if (k < Tksweep) 863 c->actlim = Tksweep; 864 else 865 c->actlim = k; 866 } 867 868 /* 869 * extension to tcl/tk: 870 * grab set tag 871 * grab release tag 872 * grab ifunset tag 873 */ 874 static char* 875 tkcvsgrab(Tk *tk, char *arg, char **val) 876 { 877 TkCtag *t; 878 TkName *f; 879 TkCanvas *c; 880 char buf[Tkmaxitem]; 881 882 c = TKobj(TkCanvas, tk); 883 arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil); 884 if (strcmp(buf, "status") == 0) { 885 if (c->grab != nil) 886 return tkvalue(val, "%d", c->grab->id); 887 } 888 else if (strcmp(buf, "release") == 0) { 889 c->grab = nil; 890 } 891 else if (strcmp(buf, "set") == 0 || strcmp(buf, "ifunset") == 0) { 892 if (buf[0] == 'i' && c->grab != nil) 893 return nil; 894 tkword(tk->env->top, arg, buf, buf + sizeof(buf), nil); 895 896 f = tkctaglook(tk, nil, buf); 897 if(f == nil || f->obj == nil) 898 return TkBadtg; 899 900 c = TKobj(TkCanvas, tk); 901 t = tkcfirsttag(c->head, f->obj); 902 if(t == nil) 903 return TkBadtg; 904 c->grab = t->item; 905 } 906 else 907 return TkBadvl; 908 return nil; 909 } 910 911 static char* 912 tkcvsbind(Tk *tk, char *arg, char **val) 913 { 914 Rune r; 915 TkCtag *t; 916 TkName *f; 917 TkAction *a; 918 TkCanvas *c; 919 int event, mode; 920 char *cmd, buf[Tkmaxitem]; 921 char *e; 922 923 c = TKobj(TkCanvas, tk); 924 if (c->actions >= c->actlim) 925 tksweepcanv(tk); 926 arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil); 927 928 f = tkctaglook(tk, nil, buf); 929 if(f == nil) { 930 f = tkctaglook(tk, tkmkname(buf), buf); 931 if(f == nil) 932 return TkNomem; 933 } 934 935 arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil); 936 if(buf[0] == '<') { 937 event = tkseqparse(buf+1); 938 if(event == -1) 939 return TkBadsq; 940 } 941 else { 942 chartorune(&r, buf); 943 event = TkKey | r; 944 } 945 if(event == 0) 946 return TkBadsq; 947 948 arg = tkskip(arg, " \t"); 949 if(*arg == '\0') { 950 for(t = f->obj; t; t = t->taglist) { 951 for(a = t->name->prop.binds; a; a = a->link) 952 if(event == a->event) 953 return tkvalue(val, "%s", a->arg); 954 for(a = t->name->prop.binds; a; a = a->link) 955 if(event & a->event) 956 return tkvalue(val, "%s", a->arg); 957 } 958 return nil; 959 } 960 961 mode = TkArepl; 962 if(*arg == '+') { 963 mode = TkAadd; 964 arg++; 965 } 966 else if(*arg == '-'){ 967 mode = TkAsub; 968 arg++; 969 } 970 971 tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil); 972 cmd = strdup(buf); 973 if(cmd == nil) 974 return TkNomem; 975 e = tkaction(&f->prop.binds, event, TkDynamic, cmd, mode); 976 if(e == nil) 977 c->actions++; 978 return e; 979 } 980 981 static char* 982 tkcvscreate(Tk *tk, char *arg, char **val) 983 { 984 TkCimeth *m; 985 char buf[Tkmaxitem]; 986 987 arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil); 988 for(m = tkcimethod; m->name; m++) 989 if(strcmp(buf, m->name) == 0) 990 return m->create(tk, arg, val); 991 992 return TkBadit; 993 } 994 995 static char* 996 tkcvsbbox(Tk *tk, char *arg, char **val) 997 { 998 TkName *f; 999 TkCtag *t; 1000 Rectangle bb; 1001 char buf[Tkmaxitem]; 1002 1003 bb = bbnil; 1004 for(;;) { 1005 arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil); 1006 if(buf[0] == '\0') 1007 break; 1008 f = tkctaglook(tk, nil, buf); 1009 if(f == nil) 1010 return TkBadtg; 1011 for(t = f->obj; t; t = t->taglist) 1012 tkbbmax(&bb, &t->item->p.bb); 1013 } 1014 return tkvalue(val, "%d %d %d %d", bb.min.x, bb.min.y, bb.max.x, bb.max.y); 1015 } 1016 1017 static char* 1018 tkcvscanvx(Tk *tk, char *arg, char **val) 1019 { 1020 int x, s; 1021 TkCanvas *c; 1022 Point p; 1023 char buf[Tkmaxitem]; 1024 1025 c = TKobj(TkCanvas, tk); 1026 arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil); 1027 if(buf[0] == '\0') 1028 return TkBadvl; 1029 1030 p = tkposn(tk); 1031 x = atoi(buf) + c->view.x - (p.x + tk->borderwidth); 1032 1033 if(*arg) { 1034 tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil); 1035 s = atoi(buf); 1036 if (s) { 1037 if (x>=0) 1038 x = ((x+s/2)/s)*s; 1039 else 1040 x = ((x-s/2)/s)*s; 1041 } 1042 } 1043 return tkvalue(val, "%d", x); 1044 } 1045 1046 static char* 1047 tkcvscanvy(Tk *tk, char *arg, char **val) 1048 { 1049 int y, s; 1050 TkCanvas *c; 1051 Point p; 1052 char buf[Tkmaxitem]; 1053 1054 c = TKobj(TkCanvas, tk); 1055 arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil); 1056 if(buf[0] == '\0') 1057 return TkBadvl; 1058 1059 p = tkposn(tk); 1060 y = atoi(buf) + c->view.y - (p.y + tk->borderwidth); 1061 1062 if(*arg) { 1063 tkitem(buf, arg); 1064 s = atoi(buf); 1065 if (s) { 1066 if (y>=0) 1067 y = ((y+s/2)/s)*s; 1068 else 1069 y = ((y-s/2)/s)*s; 1070 } 1071 } 1072 return tkvalue(val, "%d", y); 1073 } 1074 1075 static char * 1076 tkcvsscreenx(Tk *tk, char *arg, char **val) 1077 { 1078 int x; 1079 TkCanvas *c; 1080 Point p; 1081 char buf[Tkmaxitem]; 1082 1083 c = TKobj(TkCanvas, tk); 1084 tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil); 1085 if(buf[0] == '\0') 1086 return TkBadvl; 1087 p = tkposn(tk); 1088 x = atoi(buf) - c->view.x + (p.x + tk->borderwidth); 1089 return tkvalue(val, "%d", x); 1090 } 1091 1092 static char * 1093 tkcvsscreeny(Tk *tk, char *arg, char **val) 1094 { 1095 int y; 1096 TkCanvas *c; 1097 Point p; 1098 char buf[Tkmaxitem]; 1099 1100 c = TKobj(TkCanvas, tk); 1101 tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil); 1102 if(buf[0] == '\0') 1103 return TkBadvl; 1104 p = tkposn(tk); 1105 y = atoi(buf) - c->view.y + (p.y + tk->borderwidth); 1106 return tkvalue(val, "%d", y); 1107 } 1108 1109 static char* 1110 tkcvscoords(Tk *tk, char *arg, char **val) 1111 { 1112 int i; 1113 Point *p; 1114 TkCtag *t; 1115 TkName *f; 1116 TkCanvas *c; 1117 TkCitem *item; 1118 char *fmt, *e, *v, buf[Tkmaxitem]; 1119 1120 arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil); 1121 if(buf[0] == '\0') 1122 return TkBadvl; 1123 1124 f = tkctaglook(tk, nil, buf); 1125 if(f == nil || f->obj == nil) 1126 return TkBadtg; 1127 1128 c = TKobj(TkCanvas, tk); 1129 1130 t = tkcfirsttag(c->head, f->obj); 1131 if(t == nil) 1132 return TkBadtg; 1133 1134 item = t->item; 1135 1136 if(*arg == '\0') { 1137 fmt = "%s"; 1138 p = item->p.parampt; 1139 for(i = 0; i < item->p.npoint; i++) { 1140 v = tkfprint(buf, p->x); 1141 *v++ = ' '; 1142 tkfprint(v, p->y); 1143 e = tkvalue(val, fmt, buf); 1144 if(e != nil) 1145 return e; 1146 fmt = " %s"; 1147 p++; 1148 } 1149 return nil; 1150 } 1151 1152 tkbbmax(&c->update, &item->p.bb); 1153 e = tkcimethod[item->type].coord(item, arg, 0, 0); 1154 tkbbmax(&c->update, &item->p.bb); 1155 tkcvssetdirty(tk); 1156 return e; 1157 } 1158 1159 static char* 1160 tkcvsscale(Tk *tk, char *arg, char **val) 1161 { 1162 TkName *f; 1163 TkCtag *t; 1164 TkCanvas *c; 1165 TkCpoints pts; 1166 TkCitem *item; 1167 int j; 1168 char *e, buf[Tkmaxitem]; 1169 Point *p, *d, origin, scalef; 1170 1171 USED(val); 1172 1173 c = TKobj(TkCanvas, tk); 1174 1175 arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil); 1176 f = tkctaglook(tk, nil, buf); 1177 if(f == nil || f->obj == nil) 1178 return TkBadtg; 1179 1180 e = tkparsepts(tk->env->top, &pts, &arg, 0); 1181 if(e != nil) 1182 return e; 1183 if(pts.npoint != 2) { 1184 tkfreepoint(&pts); 1185 return TkFewpt; 1186 } 1187 origin = pts.parampt[0]; 1188 scalef = pts.parampt[1]; 1189 tkfreepoint(&pts); 1190 for(t = f->obj; t; t = t->taglist) { 1191 item = t->item; 1192 p = item->p.parampt; 1193 d = item->p.drawpt; 1194 for(j = 0; j < item->p.npoint; j++) { 1195 p->x -= origin.x; 1196 p->y -= origin.y; 1197 p->x = TKF2I(p->x*scalef.x); 1198 p->y = TKF2I(p->y*scalef.y); 1199 p->x += origin.x; 1200 p->y += origin.y; 1201 d->x = TKF2I(p->x); 1202 d->y = TKF2I(p->y); 1203 d++; 1204 p++; 1205 } 1206 tkbbmax(&c->update, &item->p.bb); 1207 e = tkcimethod[item->type].coord(item, nil, 0, 0); 1208 tkbbmax(&c->update, &item->p.bb); 1209 if(e != nil) 1210 return e; 1211 1212 tkcvssetdirty(tk); 1213 } 1214 return nil; 1215 } 1216 1217 static char* 1218 tkcvsdtag(Tk *tk, char *arg, char **val) 1219 { 1220 TkName *f, *dt; 1221 char buf[Tkmaxitem]; 1222 TkCtag **l, *t, *it, *tf; 1223 1224 USED(val); 1225 1226 arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil); 1227 f = tkctaglook(tk, nil, buf); 1228 if(f == nil || f->obj == nil) 1229 return TkBadtg; 1230 1231 /* 1232 XXX this code doesn't appear to work properly. 1233 fix it later. for the moment, it's just a somewhat more 1234 efficient substitute for the later code, so just use that 1235 instead. 1236 1237 if(*arg == '\0') { 1238 for(t = f->obj; t; t = tf) { 1239 l = &t->item->stag; 1240 for(it = *l; it; it = it->itemlist) { 1241 if(it->item == t->item) { 1242 *l = it->itemlist; 1243 break; 1244 } 1245 l = &it->itemlist; 1246 } 1247 1248 tf = t->taglist; 1249 free(t); 1250 } 1251 f->obj = nil; 1252 return nil; 1253 } 1254 */ 1255 if (*arg == '\0') 1256 dt = f; 1257 else { 1258 tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil); 1259 dt = tkctaglook(tk, nil, buf); 1260 if(dt == nil || dt->obj == nil) 1261 return TkBadtg; 1262 } 1263 1264 for(t = f->obj; t; t = t->taglist) { 1265 l = (TkCtag **)&dt->obj; 1266 for(it = dt->obj; it; it = it->taglist) { 1267 if(t->item == it->item) { 1268 *l = it->taglist; 1269 l = &t->item->stag; 1270 for(tf = *l; tf; tf = tf->itemlist) { 1271 if(tf == it) { 1272 *l = tf->itemlist; 1273 break; 1274 } 1275 l = &tf->itemlist; 1276 } 1277 free(it); 1278 break; 1279 } 1280 l = &it->taglist; 1281 } 1282 } 1283 return nil; 1284 } 1285 1286 static char* 1287 tkcvsdchars(Tk *tk, char *arg, char **val) 1288 { 1289 TkCtag *t; 1290 TkName *f; 1291 char *e, buf[Tkmaxitem]; 1292 1293 USED(val); 1294 1295 arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil); 1296 f = tkctaglook(tk, nil, buf); 1297 if(f == nil || f->obj == nil) 1298 return TkBadtg; 1299 1300 for(t = f->obj; t; t = t->taglist) { 1301 if(t->item->type == TkCVtext) { 1302 e = tkcvstextdchar(tk, t->item, arg); 1303 if(e != nil) 1304 return e; 1305 } 1306 } 1307 1308 return nil; 1309 } 1310 1311 static char* 1312 tkcvsindex(Tk *tk, char *arg, char **val) 1313 { 1314 TkCtag *t; 1315 TkName *f; 1316 char *e, buf[Tkmaxitem]; 1317 1318 USED(val); 1319 1320 arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil); 1321 f = tkctaglook(tk, nil, buf); 1322 if(f == nil || f->obj == nil) 1323 return TkBadtg; 1324 1325 for(t = f->obj; t; t = t->taglist) { 1326 if(t->item->type == TkCVtext) { 1327 e = tkcvstextindex(tk, t->item, arg, val); 1328 if(e != nil) 1329 return e; 1330 return nil; 1331 } 1332 } 1333 return nil; 1334 } 1335 1336 static char* 1337 tkcvsicursor(Tk *tk, char *arg, char **val) 1338 { 1339 TkCtag *t; 1340 TkName *f; 1341 char *e, buf[Tkmaxitem]; 1342 1343 USED(val); 1344 1345 arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil); 1346 f = tkctaglook(tk, nil, buf); 1347 if(f == nil || f->obj == nil) 1348 return TkBadtg; 1349 1350 for(t = f->obj; t; t = t->taglist) { 1351 if(t->item->type == TkCVtext) { 1352 e = tkcvstexticursor(tk, t->item, arg); 1353 if(e != nil) 1354 return e; 1355 return nil; 1356 } 1357 } 1358 return nil; 1359 } 1360 1361 static char* 1362 tkcvsinsert(Tk *tk, char *arg, char **val) 1363 { 1364 TkCtag *t; 1365 TkName *f; 1366 char *e, buf[Tkmaxitem]; 1367 1368 USED(val); 1369 1370 arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil); 1371 f = tkctaglook(tk, nil, buf); 1372 if(f == nil || f->obj == nil) 1373 return TkBadtg; 1374 1375 for(t = f->obj; t; t = t->taglist) { 1376 if(t->item->type == TkCVtext) { 1377 e = tkcvstextinsert(tk, t->item, arg); 1378 if(e != nil) 1379 return e; 1380 } 1381 } 1382 1383 return nil; 1384 } 1385 1386 static char* 1387 tkcvsselect(Tk *tk, char *arg, char **val) 1388 { 1389 int op; 1390 TkCtag *t; 1391 TkName *f; 1392 TkCanvas *c; 1393 char buf[Tkmaxitem]; 1394 1395 c = TKobj(TkCanvas, tk); 1396 1397 arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil); 1398 if(strcmp(buf, "clear") == 0) { 1399 tkcvstextclr(tk); 1400 return nil; 1401 } 1402 if(strcmp(buf, "item") == 0) { 1403 if(c->selection) 1404 return tkvalue(val, "%d", c->selection->id); 1405 return nil; 1406 } 1407 1408 if(strcmp(buf, "to") == 0) 1409 op = TkCselto; 1410 else 1411 if(strcmp(buf, "from") == 0) 1412 op = TkCselfrom; 1413 else 1414 if(strcmp(buf, "adjust") == 0) 1415 op = TkCseladjust; 1416 else 1417 return TkBadcm; 1418 1419 arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil); 1420 f = tkctaglook(tk, nil, buf); 1421 if(f == nil) 1422 return TkBadtg; 1423 1424 t = tkcfirsttag(c->head, f->obj); 1425 if(t == nil) 1426 return TkBadtg; 1427 1428 return tkcvstextselect(tk, t->item, arg, op); 1429 } 1430 1431 static char* 1432 tkcvsitemcget(Tk *tk, char *arg, char **val) 1433 { 1434 TkName *f; 1435 TkCtag *t; 1436 TkCitem *i; 1437 char buf[Tkmaxitem]; 1438 1439 arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil); 1440 f = tkctaglook(tk, nil, buf); 1441 if(f == nil || f->obj == nil) 1442 return TkBadtg; 1443 1444 for(i = TKobj(TkCanvas, tk)->head; i; i = i->next) { 1445 for(t = f->obj; t; t = t->taglist) 1446 if(i == t->item) 1447 return tkcimethod[i->type].cget(i, arg, val); 1448 } 1449 return nil; 1450 } 1451 1452 static char* 1453 tkcvsitemconf(Tk *tk, char *arg, char **val) 1454 { 1455 char *e; 1456 TkName *f; 1457 TkCtag *t; 1458 TkCitem *i; 1459 TkCanvas *c; 1460 char buf[Tkmaxitem]; 1461 1462 USED(val); 1463 arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil); 1464 f = tkctaglook(tk, nil, buf); 1465 if(f == nil || f->obj == nil) 1466 return TkBadtg; 1467 1468 c = TKobj(TkCanvas, tk); 1469 for(t = f->obj; t; t = t->taglist) { 1470 for(i = c->head; i; i = i->next) { 1471 if(i == t->item) { 1472 tkbbmax(&c->update, &i->p.bb); 1473 e = tkcimethod[i->type].conf(tk, i, arg); 1474 tkbbmax(&c->update, &i->p.bb); 1475 tkcvssetdirty(tk); 1476 if(e != nil) 1477 return e; 1478 } 1479 } 1480 } 1481 return nil; 1482 } 1483 1484 static void 1485 tkcvsfreename(TkCanvas *c, TkName *n) 1486 { 1487 ulong h; 1488 char *p, *s; 1489 TkName *f, **l; 1490 1491 /* just free implicit ones for now */ 1492 if(n == nil) 1493 return; 1494 s = n->name; 1495 if(s == nil || (s[0] < '0' || s[0] > '9')) 1496 return; 1497 h = 0; 1498 for(p = s; *p; p++) 1499 h += 3*h + *p; 1500 l = &c->thash[h%TkChash]; 1501 for(f = *l; f; l = &f->link, f = *l) 1502 if(f == n){ 1503 *l = f->link; 1504 tkfreebind(f->prop.binds); 1505 free(f); 1506 return; 1507 } 1508 } 1509 1510 static char* 1511 tkcvsdelete(Tk *tk, char *arg, char **val) 1512 { 1513 TkName *f; 1514 TkCanvas *c; 1515 char buf[Tkmaxitem]; 1516 TkCitem *item, *prev, *i; 1517 TkCtag *t, *inext, **l, *dit, *it; 1518 1519 USED(val); 1520 1521 c = TKobj(TkCanvas, tk); 1522 for(;;) { 1523 arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil); 1524 if(buf[0] == '\0') 1525 break; 1526 f = tkctaglook(tk, nil, buf); 1527 if(f == nil || f->obj == nil) 1528 return nil; 1529 while(f->obj) { 1530 t = f->obj; 1531 item = t->item; 1532 for(it = item->stag; it; it = inext) { 1533 inext = it->itemlist; 1534 l = (TkCtag **)&it->name->obj; 1535 for(dit = *l; dit; dit = dit->taglist) { 1536 if(dit->item == item) { 1537 *l = dit->taglist; 1538 if(dit != t){ 1539 tkcvsfreename(c, dit->name); 1540 free(dit); 1541 } 1542 break; 1543 } 1544 l = &dit->taglist; 1545 } 1546 } 1547 tkbbmax(&c->update, &item->p.bb); 1548 tkcvssetdirty(tk); 1549 prev = nil; 1550 for(i = c->head; i; i = i->next) { 1551 if(i == item) 1552 break; 1553 prev = i; 1554 } 1555 if(prev == nil) 1556 c->head = i->next; 1557 else 1558 prev->next = i->next; 1559 if(c->tail == item) 1560 c->tail = prev; 1561 if(c->focus == item) 1562 c->focus = nil; 1563 if(c->mouse == item) 1564 c->mouse = nil; 1565 if(c->selection == item) 1566 c->selection = nil; 1567 if(c->curtag.item == item) 1568 c->current->obj = nil; 1569 if (c->grab == item) 1570 c->grab = nil; 1571 1572 tkcvsfreeitem(item); 1573 free(t); 1574 } 1575 } 1576 return nil; 1577 } 1578 1579 static char* 1580 tkcvsfocus(Tk *tk, char *arg, char **val) 1581 { 1582 TkName *f; 1583 TkCtag *t; 1584 TkCanvas *c; 1585 TkCitem *i, *focus; 1586 char buf[Tkmaxitem]; 1587 1588 c = TKobj(TkCanvas, tk); 1589 1590 if(*arg == '\0') { 1591 if(c->focus == nil) 1592 return nil; 1593 return tkvalue(val, "%d", c->focus->id); 1594 } 1595 1596 tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil); 1597 if(buf[0] == '\0') 1598 return TkBadvl; 1599 f = tkctaglook(tk, nil, buf); 1600 if(f == nil || f->obj == nil) 1601 return nil; 1602 1603 focus = c->focus; 1604 if(focus != nil && focus->type == TkCVtext) 1605 tkcvstextfocus(tk, focus, 0); 1606 1607 for(i = c->head; i; i = i->next) { 1608 if(i->type == TkCVtext || i->type == TkCVwindow) { 1609 for(t = f->obj; t; t = t->taglist) 1610 if(t->item == i) 1611 focus = i; 1612 } 1613 } 1614 1615 if(focus != nil && focus->type == TkCVtext) 1616 tkcvstextfocus(tk, focus, 1); 1617 1618 c->focus = focus; 1619 return nil; 1620 } 1621 1622 static char* 1623 tkcvsgettags(Tk *tk, char *arg, char **val) 1624 { 1625 TkCtag *t; 1626 TkName *f; 1627 TkCanvas *c; 1628 char *fmt, *e, buf[Tkmaxitem]; 1629 1630 tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil); 1631 if(buf[0] == '\0') 1632 return TkBadvl; 1633 1634 f = tkctaglook(tk, nil, buf); 1635 if(f == nil) 1636 return TkBadtg; 1637 1638 c = TKobj(TkCanvas, tk); 1639 t = tkclasttag(c->head, f->obj); 1640 if(t == nil) 1641 return TkBadtg; 1642 fmt = "%s"; 1643 t = t->item->stag; 1644 while(t) { 1645 /* XXX when might t->name be legally nil? */ 1646 if (t->name != nil) { 1647 if (strcmp(t->name->name, "all")) { 1648 e = tkvalue(val, fmt, t->name->name); 1649 if(e != nil) 1650 return e; 1651 fmt = " %s"; 1652 } 1653 } 1654 t = t->itemlist; 1655 } 1656 return nil; 1657 } 1658 1659 static char* 1660 tkcvslower(Tk *tk, char *arg, char **val) 1661 { 1662 TkCtag *t; 1663 TkCanvas *c; 1664 TkName *f, *b; 1665 char buf[Tkmaxitem]; 1666 TkCitem *it, **l, **below, *items, **itemtail, *prev, *iprev; 1667 1668 USED(val); 1669 c = TKobj(TkCanvas, tk); 1670 1671 arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil); 1672 f = tkctaglook(tk, nil, buf); 1673 if(f == nil || f->obj == nil) 1674 return nil; 1675 1676 below = &c->head; 1677 tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil); 1678 if(buf[0] != '\0') { 1679 b = tkctaglook(tk, nil, buf); 1680 if(b == nil || f->obj == nil) 1681 return TkBadtg; 1682 for(it = c->head; it; it = it->next) { 1683 for(t = b->obj; t; t = t->taglist) 1684 if(t->item == it) 1685 goto found; 1686 below = &it->next; 1687 } 1688 found:; 1689 } 1690 l = &c->head; 1691 prev = iprev = nil; 1692 itemtail = &items;; 1693 for (it = *l; it != nil; it = *l) { 1694 for (t = f->obj; t; t = t->taglist) { 1695 if(t->item == it) { 1696 if (it == *below || below == &it->next) 1697 below = l; 1698 if (it == c->tail) 1699 c->tail = prev; 1700 *l = it->next; 1701 *itemtail = it; 1702 iprev = it; 1703 itemtail = &it->next; 1704 tkbbmax(&c->update, &it->p.bb); 1705 goto next; 1706 } 1707 } 1708 prev = it; 1709 l = &it->next; 1710 next:; 1711 } 1712 if (prev == nil) 1713 c->tail = iprev; 1714 *itemtail = *below; 1715 *below = items; 1716 tkcvssetdirty(tk); 1717 return nil; 1718 } 1719 1720 static char* 1721 tkcvsmove(Tk *tk, char *arg, char **val) 1722 { 1723 TkCtag *t; 1724 int fx, fy; 1725 TkTop *top; 1726 TkCpoints *p; 1727 TkName *tag; 1728 Rectangle *u; 1729 TkCitem *item; 1730 char *e; 1731 char buf[Tkmaxitem]; 1732 1733 USED(val); 1734 top = tk->env->top; 1735 arg = tkword(top, arg, buf, buf+sizeof(buf), nil); 1736 tag = tkctaglook(tk, nil, buf); 1737 if(tag == nil) 1738 return nil; 1739 1740 e = tkfracword(top, &arg, &fx, nil); 1741 if (e != nil) 1742 return e; 1743 e = tkfracword(top, &arg, &fy, nil); 1744 if(e != nil) 1745 return e; 1746 1747 u = &TKobj(TkCanvas, tk)->update; 1748 for(t = tag->obj; t; t = t->taglist) { 1749 item = t->item; 1750 p = &item->p; 1751 tkbbmax(u, &p->bb); 1752 tkcimethod[item->type].coord(item, nil, fx, fy); 1753 tkbbmax(u, &p->bb); 1754 } 1755 tkcvssetdirty(tk); 1756 return nil; 1757 } 1758 1759 static char* 1760 tkcvsraise(Tk *tk, char *arg, char **val) 1761 { 1762 TkCtag *t; 1763 TkCanvas *c; 1764 TkName *f, *a; 1765 char buf[Tkmaxitem]; 1766 TkCitem *prev, *it, *above, *items, *itemtail, *next; 1767 1768 USED(val); 1769 c = TKobj(TkCanvas, tk); 1770 1771 arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil); 1772 f = tkctaglook(tk, nil, buf); 1773 if(f == nil) 1774 return nil; 1775 1776 above = c->tail; 1777 tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil); 1778 if(buf[0] != '\0') { 1779 a = tkctaglook(tk, nil, buf); 1780 if(a == nil) 1781 return TkBadtg; 1782 /* 1783 * find topmost item in the display list matching the "above" tag 1784 */ 1785 for(it = c->head; it != nil; it = it->next) { 1786 for(t = a->obj; t; t = t->taglist) 1787 if(t->item == it) 1788 above = it; 1789 } 1790 } 1791 prev = nil; 1792 items = itemtail = nil; 1793 for (it = c->head; it != nil; it = next) { 1794 next = it->next; 1795 for (t = f->obj; t; t = t->taglist) { 1796 if(t->item == it) { 1797 if (it == above) 1798 above = next; 1799 if (prev) 1800 prev->next = next; 1801 else 1802 c->head = next; 1803 if (itemtail) 1804 itemtail->next = it; 1805 else 1806 items = it; 1807 itemtail = it; 1808 tkbbmax(&c->update, &it->p.bb); 1809 goto next; 1810 } 1811 } 1812 prev = it; 1813 next:; 1814 } 1815 if (items != nil) { 1816 if (above) { 1817 itemtail->next = above->next; 1818 if (above->next == nil) 1819 c->tail = itemtail; 1820 above->next = items; 1821 } else { 1822 if (prev) 1823 prev->next = items; 1824 else 1825 c->head = items; 1826 c->tail = itemtail; 1827 itemtail->next = nil; 1828 } 1829 } 1830 1831 tkcvssetdirty(tk); 1832 return nil; 1833 } 1834 1835 static char* 1836 tkcvstype(Tk *tk, char *arg, char **val) 1837 { 1838 TkCtag *t; 1839 TkName *f; 1840 TkCanvas *c; 1841 char buf[Tkmaxitem]; 1842 1843 tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil); 1844 if(buf[0] == '\0') 1845 return TkBadvl; 1846 1847 f = tkctaglook(tk, nil, buf); 1848 if(f == nil || f->obj == nil) 1849 return nil; 1850 1851 c = TKobj(TkCanvas, tk); 1852 1853 t = tkcfirsttag(c->head, f->obj); 1854 if(t == nil) 1855 return nil; 1856 1857 return tkvalue(val, "%s", tkcimethod[t->item->type].name); 1858 } 1859 1860 static char* 1861 tkcvsview(Tk *tk, char *arg, char **val, int nl, int *posn, int min, int max, int inc) 1862 { 1863 TkTop *t; 1864 int top, bot, diff, amount; 1865 char *e; 1866 char buf[Tkmaxitem], *v; 1867 1868 diff = max-min; 1869 if(*arg == '\0') { 1870 if ( diff == 0 ) 1871 top = bot = 0; 1872 else { 1873 top = TKI2F(*posn-min)/diff; 1874 bot = TKI2F(*posn+nl-min)/diff; 1875 } 1876 v = tkfprint(buf, top); 1877 *v++ = ' '; 1878 tkfprint(v, bot); 1879 return tkvalue(val, "%s", buf); 1880 } 1881 1882 t = tk->env->top; 1883 arg = tkword(t, arg, buf, buf+sizeof(buf), nil); 1884 if(strcmp(buf, "moveto") == 0) { 1885 e = tkfrac(&arg, &top, nil); 1886 if (e != nil) 1887 return e; 1888 *posn = min + TKF2I((top+1)*diff); 1889 } 1890 else 1891 if(strcmp(buf, "scroll") == 0) { 1892 arg = tkword(t, arg, buf, buf+sizeof(buf), nil); 1893 amount = atoi(buf); 1894 tkword(t, arg, buf, buf+sizeof(buf), nil); 1895 if(buf[0] == 'p') /* Pages */ 1896 amount = amount * nl * 9 /10; 1897 else if (inc > 0) 1898 amount *= inc; 1899 else 1900 amount = amount * nl / 10; 1901 *posn += amount; 1902 } 1903 else 1904 return TkBadcm; 1905 1906 bot = max - nl; 1907 if(*posn > bot) 1908 *posn = bot; 1909 if(*posn < min) 1910 *posn = min; 1911 1912 tk->dirty = tkrect(tk, 0); 1913 return nil; 1914 } 1915 1916 static char* 1917 tkcvsyview(Tk *tk, char *arg, char **val) 1918 { 1919 int si; 1920 char *e; 1921 TkCanvas *c = TKobj(TkCanvas, tk); 1922 1923 si = TKF2I(c->yscrolli); 1924 e = tkcvsview(tk, arg, val, tk->act.height, &c->view.y, c->region.min.y, c->region.max.y, si); 1925 tkcvssv(tk); 1926 return e; 1927 } 1928 1929 static char* 1930 tkcvsxview(Tk *tk, char *arg, char **val) 1931 { 1932 int si; 1933 char *e; 1934 TkCanvas *c = TKobj(TkCanvas, tk); 1935 1936 si = TKF2I(c->xscrolli); 1937 e = tkcvsview(tk, arg, val, tk->act.width, &c->view.x, c->region.min.x, c->region.max.x, si); 1938 tkcvssh(tk); 1939 return e; 1940 } 1941 1942 /* 1943 * return in posn the new view origin such that (preferably) smin and smax 1944 * lie between cmin and cmax (cmin is the current view origin, and cmax the 1945 * other end of the visible area). 1946 * adjust posn (the view origin) so that (preferably) both smin and smax lie 1947 * inside cmin to cmax. if both smin and smax cannot fit, then 1948 * at least make sure that spref (smin<=spref<=smax) is visible. 1949 * return 0 if no adjustment is required (the interval is already visible). 1950 * 1951 * attempt to make an adjustment as small as possible that 1952 * fits these criteria. 1953 */ 1954 static int 1955 tkadjustvis(int *posn, int c0, int c1, int s0, int s1, int spref) 1956 { 1957 int d, v; 1958 1959 d = c1 - c0; /* visible width */ 1960 1961 /* 1962 * if requested range fits inside visible range, 1963 * no adjustment is necessary 1964 */ 1965 if (c0 <= s0 && s1 <= c1) 1966 return 0; 1967 1968 /* 1969 * if requested range fits, make it fully visible 1970 */ 1971 if (s1 - s0 < d) { 1972 if (s0 < c0) 1973 v = s0; 1974 else 1975 v = s1 - d; 1976 } else { 1977 /* 1978 * choose upper or lower end of requested range, 1979 * depending on which end of requested area is already 1980 * visible (if any). 1981 */ 1982 if (c0 <= s1 && s1 < c1) { /* overlapping left of visible */ 1983 v = s1 - d; 1984 if (v > spref) 1985 v = spref; 1986 } 1987 else 1988 if (c0 <= s0 && s0 < c1) { /* overlapping right of visible */ 1989 v = s0; 1990 if (v + d <= spref) 1991 v = spref - d; 1992 } 1993 else 1994 if (s1 < c0) { /* left of visible */ 1995 v = spref; 1996 if (v + d > s1) 1997 v = s1 - d; 1998 } 1999 else { /* right of visible */ 2000 v = spref - d; 2001 if (v < s0) 2002 v = s0; 2003 } 2004 } 2005 *posn = v; 2006 return 1; 2007 } 2008 2009 static void 2010 tkcvsseerect(Tk *tk, Rectangle r, Point p) 2011 { 2012 TkCanvas *c; 2013 int scrollh, scrollv; 2014 2015 c = TKobj(TkCanvas, tk); 2016 2017 scrollh = tkadjustvis(&c->view.x, c->view.x, c->view.x + tk->act.width, 2018 r.min.x, r.max.x, p.x); 2019 scrollv = tkadjustvis(&c->view.y, c->view.y, c->view.y + tk->act.height, 2020 r.min.y, r.max.y, p.y); 2021 if (scrollh) 2022 tkcvssh(tk); 2023 if (scrollv) 2024 tkcvssv(tk); 2025 if (scrollh || scrollv) 2026 tk->dirty = tkrect(tk, 0); 2027 } 2028 2029 static char* 2030 tkcvssee(Tk *tk, char *arg, char **val) 2031 { 2032 Rectangle r; 2033 int n, coords[4]; 2034 char *e; 2035 2036 USED(val); 2037 n = 0; 2038 while (n < 4) { 2039 if (*arg == '\0') 2040 break; 2041 e = tkfracword(tk->env->top, &arg, &coords[n++], nil); 2042 if (e != nil) 2043 return e; 2044 } 2045 2046 if (n != 2 && n != 4) 2047 return TkFewpt; 2048 2049 r.min.x = TKF2I(coords[0]); 2050 r.min.y = TKF2I(coords[1]); 2051 if (n == 4) { 2052 r.max.x = TKF2I(coords[2]); 2053 r.max.y = TKF2I(coords[3]); 2054 } else 2055 r.max = r.min; 2056 r = canonrect(r); 2057 /* 2058 * XXX should intersect r with scrollregion here, as you shouldn't 2059 * be able to display things outside the scroll region. (??) 2060 */ 2061 2062 tkcvsseerect(tk, r, r.min); 2063 return nil; 2064 } 2065 2066 static void 2067 tkcvsseesub(Tk *tk, Rectangle *rr, Point *pp) 2068 { 2069 Rectangle r; 2070 Point p; 2071 TkCanvas *c; 2072 c = TKobj(TkCanvas, tk); 2073 2074 r = rectaddpt(*rr, c->view); 2075 p = addpt(*pp, c->view); 2076 2077 tkcvsseerect(tk, r, p); 2078 2079 *rr = rectsubpt(r, c->view); 2080 *pp = subpt(p, c->view); 2081 } 2082 2083 static void 2084 tkcvsgetimgs(Tk* tk, Image **image, Image **mask) 2085 { 2086 TkCanvas *c; 2087 c = TKobj(TkCanvas, tk); 2088 2089 *image = c->image; 2090 *mask = c->mask; /* XXX this is wrong - the mask image has nothing to do with the main image */ 2091 } 2092 2093 TkCimeth tkcimethod[] = 2094 { 2095 "line", tkcvslinecreat, 2096 tkcvslinedraw, 2097 tkcvslinefree, 2098 tkcvslinecoord, 2099 tkcvslinecget, 2100 tkcvslineconf, 2101 tkcvslinehit, 2102 2103 "text", tkcvstextcreat, 2104 tkcvstextdraw, 2105 tkcvstextfree, 2106 tkcvstextcoord, 2107 tkcvstextcget, 2108 tkcvstextconf, 2109 nil, 2110 2111 "rectangle", tkcvsrectcreat, 2112 tkcvsrectdraw, 2113 tkcvsrectfree, 2114 tkcvsrectcoord, 2115 tkcvsrectcget, 2116 tkcvsrectconf, 2117 nil, 2118 2119 "oval", tkcvsovalcreat, 2120 tkcvsovaldraw, 2121 tkcvsovalfree, 2122 tkcvsovalcoord, 2123 tkcvsovalcget, 2124 tkcvsovalconf, 2125 tkcvsovalhit, 2126 2127 "bitmap", tkcvsbitcreat, 2128 tkcvsbitdraw, 2129 tkcvsbitfree, 2130 tkcvsbitcoord, 2131 tkcvsbitcget, 2132 tkcvsbitconf, 2133 nil, 2134 2135 "polygon", tkcvspolycreat, 2136 tkcvspolydraw, 2137 tkcvspolyfree, 2138 tkcvspolycoord, 2139 tkcvspolycget, 2140 tkcvspolyconf, 2141 tkcvspolyhit, 2142 2143 "window", tkcvswindcreat, 2144 tkcvswinddraw, 2145 tkcvswindfree, 2146 tkcvswindcoord, 2147 tkcvswindcget, 2148 tkcvswindconf, 2149 nil, 2150 2151 "image", tkcvsimgcreat, 2152 tkcvsimgdraw, 2153 tkcvsimgfree, 2154 tkcvsimgcoord, 2155 tkcvsimgcget, 2156 tkcvsimgconf, 2157 nil, 2158 2159 "arc", tkcvsarccreat, 2160 tkcvsarcdraw, 2161 tkcvsarcfree, 2162 tkcvsarccoord, 2163 tkcvsarccget, 2164 tkcvsarcconf, 2165 nil, 2166 nil 2167 }; 2168 2169 static 2170 TkCmdtab tkcanvcmd[] = 2171 { 2172 "addtag", tkcvsaddtag, 2173 "bbox", tkcvsbbox, 2174 "bind", tkcvsbind, 2175 "cget", tkcvscget, 2176 "configure", tkcvsconf, 2177 "create", tkcvscreate, 2178 "canvasx", tkcvscanvx, 2179 "canvasy", tkcvscanvy, 2180 "coords", tkcvscoords, 2181 "dchars", tkcvsdchars, 2182 "delete", tkcvsdelete, 2183 "dtag", tkcvsdtag, 2184 "find", tkcvsfind, 2185 "focus", tkcvsfocus, 2186 "gettags", tkcvsgettags, 2187 "grab", tkcvsgrab, 2188 "icursor", tkcvsicursor, 2189 "insert", tkcvsinsert, 2190 "index", tkcvsindex, 2191 "itemcget", tkcvsitemcget, 2192 "itemconfigure", tkcvsitemconf, 2193 "lower", tkcvslower, 2194 "move", tkcvsmove, 2195 "raise", tkcvsraise, 2196 "screenx", tkcvsscreenx, 2197 "screeny", tkcvsscreeny, 2198 "see", tkcvssee, 2199 "select", tkcvsselect, 2200 "scale", tkcvsscale, 2201 "type", tkcvstype, 2202 "yview", tkcvsyview, 2203 "xview", tkcvsxview, 2204 nil 2205 }; 2206 2207 TkMethod canvasmethod = { 2208 "canvas", 2209 tkcanvcmd, 2210 tkfreecanv, 2211 tkdrawcanv, 2212 tkcvsgeom, 2213 tkcvsgetimgs, 2214 tkcvsfocusorder, 2215 tkcvsdirty, 2216 tkcvsrelpos, 2217 tkcvsevent, 2218 tkcvsseesub, 2219 tkcvsinwindow 2220 }; 2221