1 #include "lib9.h" 2 #include "draw.h" 3 #include "tk.h" 4 5 #define O(t, e) ((long)(&((t*)0)->e)) 6 7 /* Layout constants */ 8 enum { 9 Triangle = 10, /* Height of scroll bar triangle */ 10 Elembw = 2, /* border around elements (triangles etc.) */ 11 }; 12 13 typedef struct TkScroll TkScroll; 14 struct TkScroll 15 { 16 int activer; 17 int orient; /* Horitontal or Vertical */ 18 int dragpix; /* Scroll delta in button drag */ 19 int dragtop; 20 int dragbot; 21 int jump; /* Jump scroll enable */ 22 int flag; /* Display flags */ 23 int top; /* Top fraction */ 24 int bot; /* Bottom fraction */ 25 int a1; /* Pixel top/left arrow1 */ 26 int t1; /* Pixel top/left trough */ 27 int t2; /* Pixel top/left lower trough */ 28 int a2; /* Pixel top/left arrow2 */ 29 char* cmd; 30 }; 31 32 enum { 33 ActiveA1 = (1<<0), /* Scrollbar control */ 34 ActiveA2 = (1<<1), 35 ActiveB1 = (1<<2), 36 ButtonA1 = (1<<3), 37 ButtonA2 = (1<<4), 38 ButtonB1 = (1<<5), 39 Autorepeat = (1<<6) 40 }; 41 42 static 43 TkOption opts[] = 44 { 45 "activerelief", OPTstab, O(TkScroll, activer), tkrelief, 46 "command", OPTtext, O(TkScroll, cmd), nil, 47 "jump", OPTstab, O(TkScroll, jump), tkbool, 48 "orient", OPTstab, O(TkScroll, orient), tkorient, 49 nil 50 }; 51 52 static 53 TkEbind b[] = 54 { 55 {TkLeave, "%W activate {}"}, 56 {TkEnter, "%W activate [%W identify %x %y]"}, 57 {TkMotion, "%W activate [%W identify %x %y]"}, 58 {TkButton1P|TkMotion, "%W tkScrollDrag %x %y"}, 59 {TkButton1P, "%W tkScrolBut1P %x %y"}, 60 {TkButton1P|TkDouble, "%W tkScrolBut1P %x %y"}, 61 {TkButton1R, "%W tkScrolBut1R; %W activate [%W identify %x %y]"}, 62 {TkButton2P, "%W tkScrolBut2P [%W fraction %x %y]"}, 63 }; 64 65 static char* 66 tkinitscroll(Tk *tk) 67 { 68 int gap; 69 TkScroll *tks; 70 71 tks = TKobj(TkScroll, tk); 72 73 gap = 2*tk->borderwidth; 74 if(tks->orient == Tkvertical) { 75 if(tk->req.width == 0) 76 tk->req.width = Triangle + gap; 77 if(tk->req.height == 0) 78 tk->req.height = 2*Triangle + gap + 6*Elembw; 79 } 80 else { 81 if(tk->req.width == 0) 82 tk->req.width = 2*Triangle + gap + 6*Elembw; 83 if(tk->req.height == 0) 84 tk->req.height = Triangle + gap; 85 } 86 87 88 return tkbindings(tk->env->top, tk, b, nelem(b)); 89 } 90 91 char* 92 tkscrollbar(TkTop *t, char *arg, char **ret) 93 { 94 Tk *tk; 95 char *e; 96 TkName *names; 97 TkScroll *tks; 98 TkOptab tko[3]; 99 100 tk = tknewobj(t, TKscrollbar, sizeof(Tk)+sizeof(TkScroll)); 101 if(tk == nil) 102 return TkNomem; 103 104 tks = TKobj(TkScroll, tk); 105 106 tk->relief = TKsunken; 107 tk->borderwidth = 2; 108 tks->activer = TKraised; 109 tks->orient = Tkvertical; 110 111 tko[0].ptr = tk; 112 tko[0].optab = tkgeneric; 113 tko[1].ptr = tks; 114 tko[1].optab = opts; 115 tko[2].ptr = nil; 116 117 names = nil; 118 e = tkparse(t, arg, tko, &names); 119 if(e != nil) { 120 tkfreeobj(tk); 121 return e; 122 } 123 tksettransparent(tk, tkhasalpha(tk->env, TkCbackgnd)); 124 125 e = tkinitscroll(tk); 126 if(e != nil) { 127 tkfreeobj(tk); 128 return e; 129 } 130 131 e = tkaddchild(t, tk, &names); 132 tkfreename(names); 133 if(e != nil) { 134 tkfreeobj(tk); 135 return e; 136 } 137 tk->name->link = nil; 138 139 return tkvalue(ret, "%s", tk->name->name); 140 } 141 142 static char* 143 tkscrollcget(Tk *tk, char *arg, char **val) 144 { 145 TkOptab tko[3]; 146 TkScroll *tks = TKobj(TkScroll, tk); 147 148 tko[0].ptr = tk; 149 tko[0].optab = tkgeneric; 150 tko[1].ptr = tks; 151 tko[1].optab = opts; 152 tko[2].ptr = nil; 153 154 return tkgencget(tko, arg, val, tk->env->top); 155 } 156 157 void 158 tkfreescrlb(Tk *tk) 159 { 160 TkScroll *tks = TKobj(TkScroll, tk); 161 162 if(tks->cmd != nil) 163 free(tks->cmd); 164 } 165 166 static void 167 tkvscroll(Tk *tk, TkScroll *tks, Image *i, Point size) 168 { 169 TkEnv *e; 170 Rectangle r; 171 Point p[3], o; 172 Image *d, *l, *t; 173 int bo, w, h, triangle, bgnd; 174 175 e = tk->env; 176 177 triangle = tk->act.width - Elembw; 178 179 bo = tk->borderwidth + Elembw; 180 p[0].x = size.x/2; 181 p[0].y = bo; 182 p[1].x = p[0].x - triangle/2; 183 p[1].y = p[0].y + triangle; 184 p[2].x = p[0].x + triangle/2; 185 p[2].y = p[0].y + triangle; 186 187 bgnd = TkCbackgnd; 188 if(tks->flag & (ActiveA1|ButtonA1)) { 189 bgnd = TkCactivebgnd; 190 fillpoly(i, p, 3, ~0, tkgc(e, bgnd), p[0]); 191 } 192 193 l = tkgc(e, bgnd+TkLightshade); 194 d = tkgc(e, bgnd+TkDarkshade); 195 if(tks->flag & ButtonA1) { 196 t = d; 197 d = l; 198 l = t; 199 } 200 line(i, p[1], p[2], 0, 0, 1, d, p[1]); 201 line(i, p[2], p[0], 0, 0, 1, d, p[2]); 202 line(i, p[0], p[1], 0, 0, 1, l, p[0]); 203 204 tks->a1 = p[2].y; 205 h = p[2].y + Elembw; 206 207 p[0].y = size.y - bo - 1; 208 p[1].y = p[0].y - triangle; 209 p[2].y = p[0].y - triangle; 210 211 bgnd = TkCbackgnd; 212 if(tks->flag & (ActiveA2|ButtonA2)) { 213 bgnd = TkCactivebgnd; 214 fillpoly(i, p, 3, ~0, tkgc(e, bgnd), p[0]); 215 } 216 217 l = tkgc(e, bgnd+TkLightshade); 218 d = tkgc(e, bgnd+TkDarkshade); 219 if(tks->flag & ButtonA2) { 220 t = d; 221 d = l; 222 l = t; 223 } 224 line(i, p[1], p[2], 0, 0, 1, l, p[1]); 225 line(i, p[2], p[0], 0, 0, 1, d, p[2]); 226 line(i, p[0], p[1], 0, 0, 1, l, p[0]); 227 228 tks->a2 = p[2].y; 229 230 o.x = tk->borderwidth ; 231 o.y = bo + triangle + 2*Elembw; 232 w = size.x - 2*bo; 233 h = p[2].y - 2*Elembw - h - 2*tk->borderwidth; 234 235 o.y += TKF2I(tks->top*h); 236 h *= tks->bot - tks->top; 237 h = TKF2I(h); 238 239 bgnd = TkCbackgnd; 240 if(tks->flag & (ActiveB1|ButtonB1)) { 241 r.min = o; 242 r.max.x = o.x + w + 2*2; 243 r.max.y = o.y + h + 2*2; 244 bgnd = TkCactivebgnd; 245 draw(i, r, tkgc(e, bgnd), nil, ZP); 246 } 247 248 tks->t1 = o.y - Elembw; 249 tks->t2 = o.y + h + Elembw; 250 l = tkgc(e, bgnd+TkLightshade); 251 d = tkgc(e, bgnd+TkDarkshade); 252 if(tks->flag & ButtonB1) 253 tkbevel(i, o, w, h, 2, d, l); 254 else 255 tkbevel(i, o, w, h, 2, l, d); 256 } 257 258 static void 259 tkhscroll(Tk *tk, TkScroll *tks, Image *i, Point size) 260 { 261 TkEnv *e; 262 Rectangle r; 263 Point p[3], o; 264 Image *d, *l, *t; 265 int bo, w, h, triangle, bgnd; 266 267 e = tk->env; 268 269 triangle = tk->act.height - Elembw; 270 271 bo = tk->borderwidth + Elembw; 272 p[0].x = bo; 273 p[0].y = size.y/2; 274 p[1].x = p[0].x + triangle; 275 p[1].y = p[0].y - triangle/2 + 1; 276 p[2].x = p[0].x + triangle; 277 p[2].y = p[0].y + triangle/2 - 2; 278 279 bgnd = TkCbackgnd; 280 if(tks->flag & (ActiveA1|ButtonA1)) { 281 bgnd = TkCactivebgnd; 282 fillpoly(i, p, 3, ~0, tkgc(e, bgnd), p[0]); 283 } 284 285 l = tkgc(e, bgnd+TkLightshade); 286 d = tkgc(e, bgnd+TkDarkshade); 287 288 if(tks->flag & ButtonA1) { 289 t = d; 290 d = l; 291 l = t; 292 } 293 line(i, p[1], p[2], 0, 0, 1, d, p[1]); 294 line(i, p[2], p[0], 0, 0, 1, d, p[2]); 295 line(i, p[0], p[1], 0, 0, 1, l, p[0]); 296 297 tks->a1 = p[2].x; 298 w = p[2].x + Elembw; 299 300 p[0].x = size.x - bo - 1; 301 p[1].x = p[0].x - triangle; 302 p[2].x = p[0].x - triangle; 303 304 bgnd = TkCbackgnd; 305 if(tks->flag & (ActiveA2|ButtonA2)) { 306 bgnd = TkCactivebgnd; 307 fillpoly(i, p, 3, ~0, tkgc(e, bgnd), p[0]); 308 } 309 310 l = tkgc(e, bgnd+TkLightshade); 311 d = tkgc(e, bgnd+TkDarkshade); 312 if(tks->flag & ButtonA2) { 313 t = d; 314 d = l; 315 l = t; 316 } 317 line(i, p[1], p[2], 0, 0, 1, l, p[1]); 318 line(i, p[2], p[0], 0, 0, 1, d, p[2]); 319 line(i, p[0], p[1], 0, 0, 1, l, p[0]); 320 321 tks->a2 = p[2].x; 322 323 o.x = bo + triangle + 2*Elembw; 324 o.y = tk->borderwidth; 325 w = p[2].x - 2*Elembw - w - 2*tk->borderwidth; 326 h = size.y - 2*bo; 327 328 o.x += TKF2I(tks->top*w); 329 w *= tks->bot - tks->top; 330 w = TKF2I(w); 331 332 bgnd = TkCbackgnd; 333 if(tks->flag & (ActiveB1|ButtonB1)) { 334 r.min = o; 335 r.max.x = o.x + w + 2*2; 336 r.max.y = o.y + h + 2*2; 337 bgnd = TkCactivebgnd; 338 draw(i, r, tkgc(e, bgnd), nil, ZP); 339 } 340 341 tks->t1 = o.x - Elembw; 342 tks->t2 = o.x + w + Elembw; 343 l = tkgc(e, bgnd+TkLightshade); 344 d = tkgc(e, bgnd+TkDarkshade); 345 if(tks->flag & ButtonB1) 346 tkbevel(i, o, w, h, 2, d, l); 347 else 348 tkbevel(i, o, w, h, 2, l, d); 349 } 350 351 char* 352 tkdrawscrlb(Tk *tk, Point orig) 353 { 354 Point p; 355 TkEnv *e; 356 Rectangle r; 357 Image *i, *dst; 358 TkScroll *tks = TKobj(TkScroll, tk); 359 360 e = tk->env; 361 362 dst = tkimageof(tk); 363 if(dst == nil) 364 return nil; 365 366 r.min = ZP; 367 r.max.x = tk->act.width + 2*tk->borderwidth; 368 r.max.y = tk->act.height + 2*tk->borderwidth; 369 370 i = tkitmp(e, r.max, TkCbackgnd); 371 if(i == nil) 372 return nil; 373 374 if(tks->orient == Tkvertical) 375 tkvscroll(tk, tks, i, r.max); 376 else 377 tkhscroll(tk, tks, i, r.max); 378 379 tkdrawrelief(i, tk, ZP, TkCbackgnd, tk->relief); 380 381 p.x = tk->act.x + orig.x; 382 p.y = tk->act.y + orig.y; 383 r = rectaddpt(r, p); 384 draw(dst, r, i, nil, ZP); 385 386 return nil; 387 } 388 389 /* Widget Commands (+ means implemented) 390 +activate 391 +cget 392 +configure 393 +delta 394 +fraction 395 +get 396 +identify 397 +set 398 */ 399 400 static char* 401 tkscrollconf(Tk *tk, char *arg, char **val) 402 { 403 char *e; 404 TkGeom g; 405 int bd; 406 TkOptab tko[3]; 407 TkScroll *tks = TKobj(TkScroll, tk); 408 409 tko[0].ptr = tk; 410 tko[0].optab = tkgeneric; 411 tko[1].ptr = tks; 412 tko[1].optab = opts; 413 tko[2].ptr = nil; 414 415 if(*arg == '\0') 416 return tkconflist(tko, val); 417 418 g = tk->req; 419 bd = tk->borderwidth; 420 e = tkparse(tk->env->top, arg, tko, nil); 421 tksettransparent(tk, tkhasalpha(tk->env, TkCbackgnd)); 422 tkgeomchg(tk, &g, bd); 423 424 tk->dirty = tkrect(tk, 1); 425 return e; 426 } 427 428 static char* 429 tkscrollactivate(Tk *tk, char *arg, char **val) 430 { 431 int s, gotarg; 432 char buf[Tkmaxitem]; 433 TkScroll *tks = TKobj(TkScroll, tk); 434 435 USED(val); 436 tkword(tk->env->top, arg, buf, buf+sizeof(buf), &gotarg); 437 s = tks->flag; 438 if (!gotarg) { 439 char *a; 440 if (s & ActiveA1) 441 a = "arrow1"; 442 else if (s & ActiveA2) 443 a = "arrow2"; 444 else if (s & ActiveB1) 445 a = "slider"; 446 else 447 a = ""; 448 return tkvalue(val, a); 449 } 450 tks->flag &= ~(ActiveA1 | ActiveA2 | ActiveB1); 451 if(strcmp(buf, "arrow1") == 0) 452 tks->flag |= ActiveA1; 453 else 454 if(strcmp(buf, "arrow2") == 0) 455 tks->flag |= ActiveA2; 456 else 457 if(strcmp(buf, "slider") == 0) 458 tks->flag |= ActiveB1; 459 460 if(s ^ tks->flag) 461 tk->dirty = tkrect(tk, 1); 462 return nil; 463 } 464 465 static char* 466 tkscrollset(Tk *tk, char *arg, char **val) 467 { 468 TkTop *t; 469 char *e; 470 TkScroll *tks = TKobj(TkScroll, tk); 471 472 USED(val); 473 t = tk->env->top; 474 e = tkfracword(t, &arg, &tks->top, nil); 475 if (e != nil) 476 return e; 477 e = tkfracword(t, &arg, &tks->bot, nil); 478 if (e != nil) 479 return e; 480 if(tks->top < 0) 481 tks->top = 0; 482 if(tks->top > TKI2F(1)) 483 tks->top = TKI2F(1); 484 if(tks->bot < 0) 485 tks->bot = 0; 486 if(tks->bot > TKI2F(1)) 487 tks->bot = TKI2F(1); 488 489 tk->dirty = tkrect(tk, 1); 490 return nil; 491 } 492 493 static char* 494 tkscrolldelta(Tk *tk, char *arg, char **val) 495 { 496 int l, delta; 497 char buf[Tkmaxitem]; 498 TkScroll *tks = TKobj(TkScroll, tk); 499 500 arg = tkitem(buf, arg); 501 if(tks->orient == Tkvertical) 502 tkitem(buf, arg); 503 if(*arg == '\0' || *buf == '\0') 504 return TkBadvl; 505 506 l = tks->a2-tks->a1-4*Elembw; 507 delta = TKI2F(1); 508 if(l != 0) 509 delta = TKI2F(atoi(buf)) / l; 510 tkfprint(buf, delta); 511 512 return tkvalue(val, "%s", buf); 513 } 514 515 static char* 516 tkscrollget(Tk *tk, char *arg, char **val) 517 { 518 char *v, buf[Tkmaxitem]; 519 TkScroll *tks = TKobj(TkScroll, tk); 520 521 USED(arg); 522 v = tkfprint(buf, tks->top); 523 *v++ = ' '; 524 tkfprint(v, tks->bot); 525 526 return tkvalue(val, "%s", buf); 527 } 528 529 static char* 530 tkscrollidentify(Tk *tk, char *arg, char **val) 531 { 532 int gotarg; 533 TkTop *t; 534 char *v, buf[Tkmaxitem]; 535 Point p; 536 TkScroll *tks = TKobj(TkScroll, tk); 537 538 t = tk->env->top; 539 arg = tkword(t, arg, buf, buf+sizeof(buf), &gotarg); 540 if (!gotarg) 541 return TkBadvl; 542 p.x = atoi(buf); 543 tkword(t, arg, buf, buf+sizeof(buf), &gotarg); 544 if (!gotarg) 545 return TkBadvl; 546 p.y = atoi(buf); 547 if (!ptinrect(p, tkrect(tk, 0))) 548 return nil; 549 if (tks->orient == Tkvertical) 550 p.x = p.y; 551 p.x += tk->borderwidth; 552 553 v = ""; 554 if(p.x <= tks->a1) 555 v = "arrow1"; 556 if(p.x > tks->a1 && p.x <= tks->t1) 557 v = "trough1"; 558 if(p.x > tks->t1 && p.x < tks->t2) 559 v = "slider"; 560 if(p.x >= tks->t2 && p.x < tks->a2) 561 v = "trough2"; 562 if(p.x >= tks->a2) 563 v = "arrow2"; 564 return tkvalue(val, "%s", v); 565 } 566 567 static char* 568 tkscrollfraction(Tk *tk, char *arg, char **val) 569 { 570 int len, frac, pos; 571 char buf[Tkmaxitem]; 572 TkScroll *tks = TKobj(TkScroll, tk); 573 574 arg = tkitem(buf, arg); 575 if(tks->orient == Tkvertical) 576 tkitem(buf, arg); 577 if(*arg == '\0' || *buf == '\0') 578 return TkBadvl; 579 580 pos = atoi(buf); 581 if(pos < tks->a1) 582 pos = tks->a1; 583 if(pos > tks->a2) 584 pos = tks->a2; 585 len = tks->a2 - tks->a1 - 4*Elembw; 586 frac = TKI2F(1); 587 if(len != 0) 588 frac = TKI2F(pos-tks->a1)/len; 589 tkfprint(buf, frac); 590 return tkvalue(val, "%s", buf); 591 } 592 593 static char* 594 tkScrolBut1R(Tk *tk, char *arg, char **val) 595 { 596 TkScroll *tks = TKobj(TkScroll, tk); 597 598 USED(val); 599 USED(arg); 600 tkcancelrepeat(tk); 601 tks->flag &= ~(ActiveA1|ActiveA2|ActiveB1|ButtonA1|ButtonA2|ButtonB1|Autorepeat); 602 tk->dirty = tkrect(tk, 1); 603 return nil; 604 } 605 606 /* tkScrolBut2P fraction */ 607 static char* 608 tkScrolBut2P(Tk *tk, char *arg, char **val) 609 { 610 TkTop *t; 611 char *e, buf[Tkmaxitem], fracbuf[Tkmaxitem]; 612 TkScroll *tks = TKobj(TkScroll, tk); 613 614 615 USED(val); 616 t = tk->env->top; 617 618 if(arg[0] == '\0') 619 return TkBadvl; 620 621 tkword(t, arg, fracbuf, fracbuf+sizeof(fracbuf), nil); 622 623 e = nil; 624 if(tks->cmd != nil) { 625 snprint(buf, sizeof(buf), "%s moveto %s", tks->cmd, fracbuf); 626 e = tkexec(t, buf, nil); 627 } 628 return e; 629 } 630 631 static void 632 sbrepeat(Tk *tk, void *v, int cancelled) 633 { 634 char *e, buf[Tkmaxitem]; 635 TkScroll *tks = TKobj(TkScroll, tk); 636 char *fmt = (char *)v; 637 638 if (cancelled) { 639 tks->flag &= ~Autorepeat; 640 return; 641 } 642 643 if(tks->cmd != nil && fmt != nil) { 644 snprint(buf, sizeof(buf), fmt, tks->cmd); 645 e = tkexec(tk->env->top, buf, nil); 646 if (e != nil) { 647 tks->flag &= ~Autorepeat; 648 tkcancelrepeat(tk); 649 } else 650 tkupdate(tk->env->top); 651 } 652 } 653 654 /* tkScrolBut1P %x %y */ 655 static char* 656 tkScrolBut1P(Tk *tk, char *arg, char **val) 657 { 658 int pix; 659 TkTop *t; 660 char *e, *fmt, buf[Tkmaxitem]; 661 TkScroll *tks = TKobj(TkScroll, tk); 662 663 USED(val); 664 t = tk->env->top; 665 666 if (tks->flag & Autorepeat) 667 return nil; 668 arg = tkword(t, arg, buf, buf+sizeof(buf), nil); 669 if(tks->orient == Tkvertical) 670 tkword(t, arg, buf, buf+sizeof(buf), nil); 671 if(buf[0] == '\0') 672 return TkBadvl; 673 674 pix = atoi(buf); 675 676 tks->dragpix = pix; 677 tks->dragtop = tks->top; 678 tks->dragbot = tks->bot; 679 680 pix += tk->borderwidth; 681 682 fmt = nil; 683 e = nil; 684 if(pix <= tks->a1) { 685 fmt = "%s scroll -1 unit"; 686 tks->flag |= ButtonA1; 687 } 688 if(pix > tks->a1 && pix <= tks->t1) 689 fmt = "%s scroll -1 page"; 690 if(pix > tks->t1 && pix < tks->t2) 691 tks->flag |= ButtonB1; 692 if(pix >= tks->t2 && pix < tks->a2) 693 fmt = "%s scroll 1 page"; 694 if(pix >= tks->a2) { 695 fmt = "%s scroll 1 unit"; 696 tks->flag |= ButtonA2; 697 } 698 if(tks->cmd != nil && fmt != nil) { 699 snprint(buf, sizeof(buf), fmt, tks->cmd); 700 e = tkexec(t, buf, nil); 701 tks->flag |= Autorepeat; 702 tkrepeat(tk, sbrepeat, fmt, TkRptpause, TkRptinterval); 703 } 704 tk->dirty = tkrect(tk, 1); 705 return e; 706 } 707 708 /* tkScrolDrag %x %y */ 709 static char* 710 tkScrollDrag(Tk *tk, char *arg, char **val) 711 { 712 TkTop *t; 713 int pix, delta; 714 char frac[32], buf[Tkmaxitem]; 715 TkScroll *tks = TKobj(TkScroll, tk); 716 717 USED(val); 718 t = tk->env->top; 719 720 if (tks->flag & Autorepeat) 721 return nil; 722 if((tks->flag & ButtonB1) == 0) 723 return nil; 724 725 arg = tkword(t, arg, buf, buf+sizeof(buf), nil); 726 if(tks->orient == Tkvertical) 727 tkword(t, arg, buf, buf+sizeof(buf), nil); 728 if(buf[0] == '\0') 729 return TkBadvl; 730 731 pix = atoi(buf); 732 733 delta = TKI2F(pix-tks->dragpix); 734 if ( tks->a2 == tks->a1 ) 735 return TkBadvl; 736 delta = delta/(tks->a2-tks->a1-4*Elembw); 737 if(tks->jump == BoolT) { 738 if(tks->dragtop+delta >= 0 && 739 tks->dragbot+delta <= TKI2F(1)) { 740 tks->top = tks->dragtop+delta; 741 tks->bot = tks->dragbot+delta; 742 } 743 return nil; 744 } 745 if(tks->cmd != nil) { 746 delta += tks->dragtop; 747 if(delta < 0) 748 delta = 0; 749 if(delta > TKI2F(1)) 750 delta = TKI2F(1); 751 tkfprint(frac, delta); 752 snprint(buf, sizeof(buf), "%s moveto %s", tks->cmd, frac); 753 return tkexec(t, buf, nil); 754 } 755 return nil; 756 } 757 758 TkCmdtab tkscrlbcmd[] = 759 { 760 "activate", tkscrollactivate, 761 "cget", tkscrollcget, 762 "configure", tkscrollconf, 763 "delta", tkscrolldelta, 764 "fraction", tkscrollfraction, 765 "get", tkscrollget, 766 "identify", tkscrollidentify, 767 "set", tkscrollset, 768 "tkScrollDrag", tkScrollDrag, 769 "tkScrolBut1P", tkScrolBut1P, 770 "tkScrolBut1R", tkScrolBut1R, 771 "tkScrolBut2P", tkScrolBut2P, 772 nil 773 }; 774 775 TkMethod scrollbarmethod = { 776 "scrollbar", 777 tkscrlbcmd, 778 tkfreescrlb, 779 tkdrawscrlb 780 }; 781