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