1 #include <lib9.h> 2 #include <kernel.h> 3 #include "draw.h" 4 #include "tk.h" 5 #include "keyboard.h" 6 7 #define O(t, e) ((long)(&((t*)0)->e)) 8 9 typedef struct TkScale TkScale; 10 struct TkScale 11 { 12 int value; 13 int bigi; 14 int digits; 15 int digwidth; 16 int from; /* Base of range */ 17 int to; /* Limit of range */ 18 int len; /* Length of groove */ 19 int res; /* Resolution */ 20 int sv; /* Show value */ 21 int sl; /* Slider length */ 22 int sw; /* Slider width div 2 */ 23 int relief; 24 int tick; 25 int orient; 26 char* command; 27 char* label; 28 int pixmin; 29 int pixmax; 30 int pixpos; 31 int center; 32 int pix; 33 int base; 34 int flag; 35 int jump; 36 }; 37 38 enum { 39 Dragging = (1<<0), 40 Autorepeat = (1<<1), 41 }; 42 43 static 44 TkOption opts[] = 45 { 46 "bigincrement", OPTnnfrac, O(TkScale, bigi), nil, 47 "digits", OPTdist, O(TkScale, digits), nil, 48 "from", OPTfrac, O(TkScale, from), nil, 49 "to", OPTfrac, O(TkScale, to), nil, 50 "length", OPTdist, O(TkScale, len), nil, 51 "resolution", OPTnnfrac, O(TkScale, res), nil, 52 "showrange", OPTignore, 0, nil, 53 "showvalue", OPTstab, O(TkScale, sv), tkbool, 54 "jump", OPTstab, O(TkScale, jump), tkbool, 55 "sliderlength", OPTdist, O(TkScale, sl), nil, 56 "sliderrelief", OPTstab, O(TkScale, relief), tkrelief, 57 "tickinterval", OPTfrac, O(TkScale, tick), nil, 58 "tick", OPTfrac, O(TkScale, tick), nil, 59 "label", OPTtext, O(TkScale, label), nil, 60 "command", OPTtext, O(TkScale, command), nil, 61 "orient", OPTstab, O(TkScale, orient), tkorient, 62 nil 63 }; 64 65 static char trough1[] = "trough1"; 66 static char trough2[] = "trough2"; 67 static char slider[] = "slider"; 68 69 static 70 TkEbind b[] = 71 { 72 {TkMotion, "%W tkScaleMotion %x %y"}, 73 {TkButton1P|TkMotion, "%W tkScaleDrag %x %y"}, 74 {TkButton1P, "%W tkScaleMotion %x %y; %W tkScaleBut1P %x %y"}, 75 {TkButton1P|TkDouble, "%W tkScaleMotion %x %y; %W tkScaleBut1P %x %y"}, 76 {TkButton1R, "%W tkScaleDrag %x %y; %W tkScaleBut1R; %W tkScaleMotion %x %y"}, 77 {TkKey, "%W tkScaleKey 0x%K"}, 78 }; 79 80 enum 81 { 82 Scalewidth = 18, 83 ScalePad = 2, 84 ScaleBW = 2, 85 ScaleSlider = 16, 86 ScaleLen = 80, 87 88 }; 89 90 static int 91 maximum(int a, int b) 92 { 93 if (a > b) 94 return a; 95 return b; 96 } 97 98 void 99 tksizescale(Tk *tk) 100 { 101 Point p; 102 char buf[32]; 103 TkScale *tks; 104 int fh, w, h, digits, digits2; 105 106 tks = TKobj(TkScale, tk); 107 108 digits = tks->digits; 109 if(digits <= 0) { 110 digits = tkfprint(buf, tks->from) - buf; 111 digits2 = tkfprint(buf, tks->to) - buf; 112 digits = maximum(digits, digits2); 113 if (tks->res > 0) { 114 digits2 = tkfprint(buf, tks->from + tks->res) - buf; 115 digits = maximum(digits, digits2); 116 digits2 = tkfprint(buf, tks->to - tks->res) - buf; 117 digits = maximum(digits, digits2); 118 } 119 } 120 121 digits *= tk->env->wzero; 122 if(tks->sv != BoolT) 123 digits = 0; 124 125 tks->digwidth = digits; 126 127 p = tkstringsize(tk, tks->label); 128 if(tks->orient == Tkvertical) { 129 h = tks->len + 2*ScaleBW + 2*ScalePad; 130 w = Scalewidth + 2*ScalePad + 2*ScaleBW; 131 if (p.x) 132 w += p.x + ScalePad; 133 if (tks->sv == BoolT) 134 w += digits + ScalePad; 135 } 136 else { 137 w = maximum(p.x, tks->len + ScaleBW + 2*ScalePad); 138 h = Scalewidth + 2*ScalePad + 2*ScaleBW; 139 fh = tk->env->font->height; 140 if(tks->label != nil) 141 h += fh + ScalePad; 142 if(tks->sv == BoolT) 143 h += fh + ScalePad; 144 } 145 w += 2*tk->highlightwidth; 146 h += 2*tk->highlightwidth; 147 if(!(tk->flag & Tksetwidth)) 148 tk->req.width = w; 149 if(!(tk->flag & Tksetheight)) 150 tk->req.height = h; 151 } 152 153 static int 154 tkscalecheckvalue(Tk *tk) 155 { 156 int v; 157 TkScale *tks = TKobj(TkScale, tk); 158 int limit = 1; 159 160 v = tks->value; 161 if (tks->res > 0) 162 v = (v / tks->res) * tks->res; 163 if (tks->to >= tks->from) { 164 if (v < tks->from) 165 v = tks->from; 166 else if (v > tks->to) 167 v = tks->to; 168 else 169 limit = 0; 170 } else { 171 if (v < tks->to) 172 v = tks->to; 173 else if (v > tks->from) 174 v = tks->from; 175 else 176 limit = 0; 177 } 178 /* 179 * it's possible for the value to end up as a non-whole 180 * multiple of resolution here, if the end points aren't 181 * themselves such a multiple. if so, tough - that's 182 * what you asked for! (it does mean that the endpoints 183 * are always accessible however, which could be a good thing). 184 */ 185 tks->value = v; 186 return limit; 187 } 188 189 char* 190 tkscale(TkTop *t, char *arg, char **ret) 191 { 192 Tk *tk; 193 char *e; 194 TkName *names; 195 TkScale *tks; 196 TkOptab tko[3]; 197 198 tk = tknewobj(t, TKscale, sizeof(Tk)+sizeof(TkScale)); 199 if(tk == nil) 200 return TkNomem; 201 202 tk->flag |= Tktakefocus; 203 tks = TKobj(TkScale, tk); 204 tks->res = TKI2F(1); 205 tks->to = TKI2F(100); 206 tks->len = ScaleLen; 207 tks->orient = Tkvertical; 208 tks->relief = TKraised; 209 tks->sl = ScaleSlider; 210 tks->sv = BoolT; 211 tks->bigi = 0; 212 213 tko[0].ptr = tk; 214 tko[0].optab = tkgeneric; 215 tko[1].ptr = tks; 216 tko[1].optab = opts; 217 tko[2].ptr = nil; 218 219 names = nil; 220 e = tkparse(t, arg, tko, &names); 221 if(e != nil) { 222 tkfreeobj(tk); 223 return e; 224 } 225 tksettransparent(tk, tkhasalpha(tk->env, TkCbackgnd)); 226 tkscalecheckvalue(tk); 227 tksizescale(tk); 228 if (tks->bigi == 0) 229 tks->bigi = TKI2F(TKF2I(tks->to - tks->from) / 10); 230 e = tkbindings(t, tk, b, nelem(b)); 231 232 if(e != nil) { 233 tkfreeobj(tk); 234 return e; 235 } 236 237 e = tkaddchild(t, tk, &names); 238 tkfreename(names); 239 if(e != nil) { 240 tkfreeobj(tk); 241 return e; 242 } 243 tk->name->link = nil; 244 245 return tkvalue(ret, "%s", tk->name->name); 246 } 247 248 static char* 249 tkscalecget(Tk *tk, char *arg, char **val) 250 { 251 TkOptab tko[3]; 252 TkScale *tks = TKobj(TkScale, tk); 253 254 tko[0].ptr = tk; 255 tko[0].optab = tkgeneric; 256 tko[1].ptr = tks; 257 tko[1].optab = opts; 258 tko[2].ptr = nil; 259 260 return tkgencget(tko, arg, val, tk->env->top); 261 } 262 263 void 264 tkfreescale(Tk *tk) 265 { 266 TkScale *tks = TKobj(TkScale, tk); 267 268 if(tks->command != nil) 269 free(tks->command); 270 if(tks->label != nil) 271 free(tks->label); 272 } 273 274 static void 275 tkscalehoriz(Tk *tk, Image *i) 276 { 277 TkEnv *e; 278 char sv[32]; 279 TkScale *tks; 280 Image *d, *l; 281 Rectangle r, r2, sr; 282 Point p, q; 283 int fh, sh, sl, v, w, h, len; 284 int fgnd; 285 286 e = tk->env; 287 tks = TKobj(TkScale, tk); 288 289 290 fh = e->font->height; 291 fgnd = TkCforegnd; 292 if (tk->flag & Tkdisabled) 293 fgnd = TkCdisablefgnd; 294 295 r = Rect(0, 0, tk->act.width, tk->act.height); 296 r = rectaddpt(r, Pt(tk->borderwidth, tk->borderwidth)); 297 r = insetrect(r, tk->highlightwidth); 298 r = insetrect(r, ScalePad); 299 300 if(tks->label != nil) { 301 string(i, r.min, tkgc(e, fgnd), ZP, e->font, tks->label); 302 r.min.y += fh + ScalePad; 303 } 304 if(tks->sv == BoolT) 305 r.min.y += fh + ScalePad; 306 307 sr = insetrect(r, ScaleBW); 308 w = Dx(sr); 309 h = Dy(sr); 310 sl = tks->sl + 2*ScaleBW; 311 312 l = tkgc(e, TkCbackgndlght); 313 d = tkgc(e, TkCbackgnddark); 314 tkbevel(i, r.min, w, h, ScaleBW, d, l); 315 316 tks->pixmin = sr.min.x; 317 tks->pixmax = sr.max.x; 318 319 sh = h - 2*ScaleBW; 320 tks->sw = sh/2; 321 322 w -= sl; 323 if (w <= 0) 324 w = 1; 325 p.x = sr.min.x; 326 p.y = sr.max.y; 327 if(tks->tick > 0){ 328 int j, t, l; 329 t = tks->tick; 330 l = tks->to-tks->from; 331 if (l < 0) 332 l = -l; 333 if (l == 0) 334 l = 1; 335 r2.min.y = p.y; 336 r2.max.y = p.y + ScaleBW + ScalePad; 337 for(j = 0; j <= l; j += t){ 338 r2.min.x = p.x+((vlong)j*w)/l+sl/2; 339 r2.max.x = r2.min.x+1; 340 draw(i, r2, tkgc(e, fgnd), nil, ZP); 341 } 342 } 343 v = tks->value-tks->from; 344 len = tks->to-tks->from; 345 if (len != 0) 346 p.x += ((vlong)v*w)/len; 347 p.y = sr.min.y; 348 q = p; 349 q.x += tks->sl/2 + 1; 350 q.y++; 351 if(tk->flag & Tkactivated) { 352 r2.min = p; 353 r2.max.x = p.x+sl; 354 r2.max.y = sr.max.y; 355 draw(i, r2, tkgc(e, TkCactivebgnd), nil, ZP); 356 } 357 switch(tks->relief) { 358 case TKsunken: 359 tkbevel(i, p, tks->sl, sh, ScaleBW, d, l); 360 tkbevel(i, q, 0, sh, 1, l, d); 361 break; 362 case TKraised: 363 tkbevel(i, p, tks->sl, sh, ScaleBW, l, d); 364 tkbevel(i, q, 0, sh, 1, d, l); 365 break; 366 } 367 tks->pixpos = p.x; 368 tks->center = p.y + sh/2 + ScaleBW; 369 370 if(tks->sv != BoolT) 371 return; 372 373 tkfprint(sv, tks->value); 374 if(tks->digits > 0 && tks->digits < strlen(sv)) 375 sv[tks->digits] = '\0'; 376 377 w = stringwidth(e->font, sv); 378 p.x = q.x; 379 p.x -= w/2; 380 p.y = r.min.y - fh - ScalePad; 381 if(p.x < tks->pixmin) 382 p.x = tks->pixmin; 383 if(p.x+w > tks->pixmax) 384 p.x = tks->pixmax - w; 385 386 string(i, p, tkgc(e, fgnd), ZP, e->font, sv); 387 } 388 389 static void 390 tkscalevert(Tk *tk, Image *i) 391 { 392 TkEnv *e; 393 TkScale *tks; 394 char sv[32]; 395 Image *d, *l; 396 Rectangle r, r2, sr; 397 Point p, q; 398 int fh, v, sw, w, h, len, sl; 399 int fgnd; 400 401 e = tk->env; 402 tks = TKobj(TkScale, tk); 403 404 fh = e->font->height; 405 fgnd = TkCforegnd; 406 if (tk->flag & Tkdisabled) 407 fgnd = TkCdisablefgnd; 408 409 r = Rect(0, 0, tk->act.width, tk->act.height); 410 r = rectaddpt(r, Pt(tk->borderwidth, tk->borderwidth)); 411 r = insetrect(r, tk->highlightwidth); 412 r = insetrect(r, ScalePad); 413 414 if (tks->sv) 415 r.min.x += tks->digwidth + ScalePad; 416 417 if(tks->label != nil) { 418 p = stringsize(e->font, tks->label); 419 r.max.x -= p.x; 420 string(i, Pt(r.max.x, r.min.y), tkgc(e, fgnd), ZP, e->font, tks->label); 421 r.max.x -= ScalePad; 422 } 423 424 sr = insetrect(r, ScaleBW); 425 h = Dy(sr); 426 w = Dx(sr); 427 sl = tks->sl + 2*ScaleBW; 428 429 l = tkgc(e, TkCbackgndlght); 430 d = tkgc(e, TkCbackgnddark); 431 tkbevel(i, r.min, w, h, ScaleBW, d, l); 432 433 tks->pixmin = sr.min.y; 434 tks->pixmax = sr.max.y; 435 436 sw = w - 2*ScaleBW; 437 tks->sw = sw/2; 438 439 h -= sl; 440 if (h <= 0) 441 h = 1; 442 p.x = sr.max.x; 443 p.y = sr.min.y; 444 if(tks->tick > 0){ 445 int j, t, l; 446 t = tks->tick; 447 l = tks->to-tks->from; 448 if (l < 0) 449 l = -l; 450 if (l == 0) 451 l = 1; 452 r2.min = p; 453 r2.max.x = p.x + ScaleBW + ScalePad; 454 for(j = 0; j <= l; j += t){ 455 r2.min.y = p.y+((vlong)j*h)/l+sl/2; 456 r2.max.y = r2.min.y+1; 457 draw(i, r2, tkgc(e, fgnd), nil, ZP); 458 } 459 } 460 461 v = tks->value-tks->from; 462 len = tks->to-tks->from; 463 if (len != 0) 464 p.y += ((vlong)v*h)/len; 465 p.x = sr.min.x; 466 q = p; 467 q.x++; 468 q.y += tks->sl/2 + 1; 469 if(tk->flag & Tkactivated) { 470 r2.min = p; 471 r2.max.x = sr.max.x; 472 r2.max.y = p.y+sl; 473 draw(i, r2, tkgc(e, TkCactivebgnd), nil, ZP); 474 } 475 switch(tks->relief) { 476 case TKsunken: 477 tkbevel(i, p, sw, tks->sl, ScaleBW, d, l); 478 tkbevel(i, q, sw, 0, 1, l, d); 479 break; 480 case TKraised: 481 tkbevel(i, p, sw, tks->sl, ScaleBW, l, d); 482 tkbevel(i, q, sw, 0, 1, d, l); 483 break; 484 } 485 tks->pixpos = p.y; 486 tks->center = p.x + sw/2 + ScaleBW; 487 488 if(tks->sv != BoolT) 489 return; 490 491 tkfprint(sv, tks->value); 492 if(tks->digits > 0 && tks->digits < strlen(sv)) 493 sv[tks->digits] = '\0'; 494 495 p.x = r.min.x - ScalePad - stringwidth(e->font, sv); 496 p.y = q.y; 497 p.y -= fh/2; 498 if (p.y < tks->pixmin) 499 p.y = tks->pixmin; 500 if (p.y + fh > tks->pixmax) 501 p.y = tks->pixmax - fh; 502 string(i, p, tkgc(e, fgnd), ZP, e->font, sv); 503 } 504 505 char* 506 tkdrawscale(Tk *tk, Point orig) 507 { 508 Point p; 509 TkEnv *env; 510 TkScale *tks; 511 Rectangle r, fr; 512 Image *i; 513 514 tks = TKobj(TkScale, tk); 515 env = tk->env; 516 517 r.min = ZP; 518 r.max.x = tk->act.width + 2*tk->borderwidth; 519 r.max.y = tk->act.height + 2*tk->borderwidth; 520 i = tkitmp(env, r.max, TkCbackgnd); 521 if(i == nil) 522 return nil; 523 524 if(tks->orient == Tkvertical) 525 tkscalevert(tk, i); 526 else 527 tkscalehoriz(tk, i); 528 529 tkdrawrelief(i, tk, ZP, TkCbackgnd, tk->relief); 530 if (tkhaskeyfocus(tk)) { 531 fr = insetrect(r, tk->borderwidth); 532 tkbox(i, fr, tk->highlightwidth, tkgc(env, TkChighlightfgnd)); 533 } 534 535 p.x = tk->act.x + orig.x; 536 p.y = tk->act.y + orig.y; 537 r = rectaddpt(r, p); 538 draw(tkimageof(tk), r, i, nil, ZP); 539 540 return nil; 541 } 542 543 /* Widget Commands (+ means implemented) 544 +cget 545 +configure 546 +coords 547 +get 548 +identify 549 +set 550 */ 551 552 static char* 553 tkscaleconf(Tk *tk, char *arg, char **val) 554 { 555 char *e; 556 TkGeom g; 557 int bd; 558 TkOptab tko[3]; 559 TkScale *tks = TKobj(TkScale, tk); 560 561 tko[0].ptr = tk; 562 tko[0].optab = tkgeneric; 563 tko[1].ptr = tks; 564 tko[1].optab = opts; 565 tko[2].ptr = nil; 566 567 if(*arg == '\0') 568 return tkconflist(tko, val); 569 570 g = tk->req; 571 bd = tk->borderwidth; 572 e = tkparse(tk->env->top, arg, tko, nil); 573 tksettransparent(tk, tkhasalpha(tk->env, TkCbackgnd)); 574 tkscalecheckvalue(tk); 575 tksizescale(tk); 576 tkgeomchg(tk, &g, bd); 577 578 tk->dirty = tkrect(tk, 1); 579 return e; 580 } 581 582 char* 583 tkscaleposn(TkEnv *env, Tk *tk, char *arg, int *z) 584 { 585 int x, y; 586 TkScale *tks = TKobj(TkScale, tk); 587 char *e; 588 589 e = tkfracword(env->top, &arg, &x, env); 590 if(e != nil) 591 return e; 592 e = tkfracword(env->top, &arg, &y, env); 593 if(e != nil) 594 return e; 595 596 x = TKF2I(x) + tk->borderwidth; 597 y = TKF2I(y) + tk->borderwidth; 598 599 if(tks->orient == Tkvertical) { 600 if(z != nil) { 601 z[0] = x; 602 z[1] = y; 603 } 604 x = y; 605 } 606 else { 607 if(z != nil) { 608 z[0] = y; 609 z[1] = x; 610 } 611 } 612 if(x > tks->pixmin && x < tks->pixpos) 613 return trough1; 614 else 615 if(x >= tks->pixpos && x < tks->pixpos+tks->sl+2*ScaleBW) 616 return slider; 617 else 618 if(x >= tks->pixpos+tks->sl+2*ScaleBW && x < tks->pixmax) 619 return trough2; 620 621 return ""; 622 } 623 624 static char* 625 tkscaleident(Tk *tk, char *arg, char **val) 626 { 627 char *v; 628 629 v = tkscaleposn(tk->env, tk, arg, nil); 630 if(v == nil) 631 return TkBadvl; 632 return tkvalue(val, "%s", v); 633 } 634 635 static char* 636 tkscalecoords(Tk *tk, char *arg, char **val) 637 { 638 int p, x, y, l, value; 639 TkScale *tks = TKobj(TkScale, tk); 640 char *e; 641 642 value = tks->value; 643 if(arg != nil && arg[0] != '\0') { 644 e = tkfracword(tk->env->top, &arg, &value, tk->env); 645 if (e != nil) 646 return e; 647 } 648 649 value -= tks->from; 650 p = tks->pixmax - tks->pixmin; 651 l = TKF2I(tks->to-tks->from); 652 if (l==0) 653 p /= 2; 654 else 655 p = TKF2I(value*p/l); 656 p += tks->pixmin; 657 if(tks->orient == Tkvertical) { 658 x = tks->center; 659 y = p; 660 } 661 else { 662 x = p; 663 y = tks->center; 664 } 665 return tkvalue(val, "%d %d", x, y); 666 } 667 668 static char* 669 tkscaleget(Tk *tk, char *arg, char **val) 670 { 671 int x, y, value, v, l; 672 char buf[Tkminitem], *e; 673 TkScale *tks = TKobj(TkScale, tk); 674 675 value = tks->value; 676 if(arg[0] != '\0') { 677 e = tkfracword(tk->env->top, &arg, &x, tk->env); 678 if (e != nil) 679 return e; 680 e = tkfracword(tk->env->top, &arg, &y, tk->env); 681 if (e != nil) 682 return e; 683 if(tks->orient == Tkvertical) 684 v = TKF2I(y) + tk->borderwidth; 685 else 686 v = TKF2I(x) + tk->borderwidth; 687 688 if(v < tks->pixmin) 689 value = tks->from; 690 else 691 if(v > tks->pixmax) 692 value = tks->to; 693 else { 694 l = tks->pixmax-tks->pixmin; 695 value = 0; 696 if (l!=0) 697 value = v * ((tks->to-tks->from)/l); 698 value += tks->from; 699 } 700 if(tks->res > 0) 701 value = (value/tks->res)*tks->res; 702 } 703 tkfprint(buf, value); 704 return tkvalue(val, "%s", buf); 705 } 706 707 static char* 708 tkscaleset(Tk *tk, char *arg, char **val) 709 { 710 TkScale *tks = TKobj(TkScale, tk); 711 char *e; 712 713 USED(val); 714 715 e = tkfracword(tk->env->top, &arg, &tks->value, tk->env); 716 if (e != nil) 717 return e; 718 tkscalecheckvalue(tk); 719 tk->dirty = tkrect(tk, 1); 720 return nil; 721 } 722 723 /* tkScaleMotion %x %y */ 724 static char* 725 tkscalemotion(Tk *tk, char *arg, char **val) 726 { 727 int o, z[2]; 728 char *v; 729 TkScale *tks = TKobj(TkScale, tk); 730 extern int tkstylus; 731 732 USED(val); 733 v = tkscaleposn(tk->env, tk, arg, z); 734 if(v == nil) 735 return TkBadvl; 736 737 o = tk->flag; 738 if(v != slider || z[0] < tks->center-tks->sw || z[0] > tks->center+tks->sw) 739 tk->flag &= ~Tkactivated; 740 else if(tkstylus == 0 || tk->env->top->ctxt->mstate.b != 0) 741 tk->flag |= Tkactivated; 742 743 if((o & Tkactivated) != (tk->flag & Tkactivated)) 744 tk->dirty = tkrect(tk, 1); 745 746 return nil; 747 } 748 749 static char* 750 tkscaledrag(Tk *tk, char *arg, char **val) 751 { 752 int x, y, v; 753 char *e, buf[Tkmaxitem], f[32]; 754 TkScale *tks = TKobj(TkScale, tk); 755 756 USED(val); 757 if((tks->flag & Dragging) == 0) 758 return nil; 759 if(tks->flag & Autorepeat) 760 return nil; 761 762 e = tkfracword(tk->env->top, &arg, &x, tk->env); 763 if(e != nil) 764 return e; 765 e = tkfracword(tk->env->top, &arg, &y, tk->env); 766 if(e != nil) 767 return e; 768 769 if(tks->orient == Tkvertical) 770 v = TKF2I(y) + tk->borderwidth; 771 else 772 v = TKF2I(x) + tk->borderwidth; 773 774 v -= tks->pix; 775 x = tks->pixmax-tks->pixmin; 776 if (x!=tks->sl) 777 v = tks->base + (vlong)v * (tks->to-tks->from)/(x-tks->sl); 778 else 779 v = tks->base; 780 if(tks->res > 0) { 781 int a = tks->res / 2; 782 if (v < 0) 783 a = -a; 784 v = ((v+a)/tks->res)*tks->res; 785 } 786 787 tks->value = v; 788 tkscalecheckvalue(tk); 789 790 if(tks->command != nil && tks->jump != BoolT) { 791 tkfprint(f, tks->value); 792 snprint(buf, sizeof(buf), "%s %s", tks->command, f); 793 e = tkexec(tk->env->top, buf, nil); 794 } 795 tk->dirty = tkrect(tk, 1); 796 return e; 797 } 798 799 static int 800 sgn(int v) 801 { 802 return v >= 0 ? 1 : -1; 803 } 804 805 static char* 806 stepscale(Tk *tk, char *pos, int *end) 807 { 808 TkScale *tks = TKobj(TkScale, tk); 809 char *e, buf[Tkmaxitem], f[32]; 810 int s; 811 812 s = sgn(tks->to - tks->from); 813 if(pos == trough1) { 814 tks->value -= s * tks->bigi; 815 } else { 816 /* trough2 */ 817 tks->value += s * tks->bigi; 818 } 819 s = !tkscalecheckvalue(tk); 820 if (end != nil) 821 *end = s; 822 e = nil; 823 if(tks->command != nil) { 824 /* XXX perhaps should only send command if value has actually changed */ 825 tkfprint(f, tks->value); 826 snprint(buf, sizeof(buf), "%s %s", tks->command, f); 827 e = tkexec(tk->env->top, buf, nil); 828 } 829 return e; 830 } 831 832 static void 833 screpeat(Tk *tk, void *v, int cancelled) 834 { 835 char *e, *pos; 836 int repeat; 837 TkScale *tks = TKobj(TkScale, tk); 838 839 pos = v; 840 if (cancelled) { 841 tks->flag &= ~Autorepeat; 842 return; 843 } 844 e = stepscale(tk, pos, &repeat); 845 if(e != nil || !repeat) { 846 tks->flag &= ~Autorepeat; 847 tkcancelrepeat(tk); 848 } 849 tk->dirty = tkrect(tk, 1); 850 tkupdate(tk->env->top); 851 } 852 853 static char* 854 tkscalebut1p(Tk *tk, char *arg, char **val) 855 { 856 int z[2]; 857 char *v, *e; 858 TkScale *tks = TKobj(TkScale, tk); 859 int repeat; 860 861 USED(val); 862 v = tkscaleposn(tk->env, tk, arg, z); 863 if(v == nil) 864 return TkBadvl; 865 866 e = nil; 867 if(v[0] == '\0' || z[0] < tks->center-tks->sw || z[0] > tks->center+tks->sw) 868 return nil; 869 if(v == slider) { 870 tks->flag |= Dragging; 871 tks->relief = TKsunken; 872 tks->pix = z[1]; 873 tks->base = tks->value; 874 tkscalecheckvalue(tk); 875 } else { 876 e = stepscale(tk, v, &repeat); 877 if (e == nil && repeat) { 878 tks->flag |= Autorepeat; 879 tkrepeat(tk, screpeat, v, TkRptpause, TkRptinterval); 880 } 881 } 882 883 tk->dirty = tkrect(tk, 1); 884 return e; 885 } 886 887 static char* 888 tkscalebut1r(Tk *tk, char *arg, char **val) 889 { 890 TkScale *tks = TKobj(TkScale, tk); 891 char *e, buf[Tkmaxitem], f[32]; 892 USED(val); 893 USED(arg); 894 if(tks->flag & Autorepeat) { 895 tkcancelrepeat(tk); 896 tks->flag &= ~Autorepeat; 897 } 898 e = nil; 899 if (tks->flag & Dragging) { 900 if (tks->command != nil && tks->jump == BoolT && (tks->flag & Dragging)) { 901 tkfprint(f, tks->value); 902 snprint(buf, sizeof(buf), "%s %s", tks->command, f); 903 e = tkexec(tk->env->top, buf, nil); 904 } 905 tks->relief = TKraised; 906 tks->flag &= ~Dragging; 907 tk->dirty = tkrect(tk, 1); 908 } 909 return e; 910 } 911 912 static char* 913 tkscalekey(Tk *tk, char *arg, char **val) 914 { 915 char *e; 916 int key; 917 char *pos = nil; 918 USED(arg); 919 USED(val); 920 921 if(tk->flag & Tkdisabled) 922 return nil; 923 924 key = atoi(arg); 925 if (key == Up || key == Left) 926 pos = trough1; 927 else if (key == Down || key == Right) 928 pos = trough2; 929 if (pos != nil) { 930 e = stepscale(tk, pos, nil); 931 tk->dirty = tkrect(tk, 1); 932 return e; 933 } 934 return nil; 935 } 936 937 TkCmdtab tkscalecmd[] = 938 { 939 "cget", tkscalecget, 940 "configure", tkscaleconf, 941 "set", tkscaleset, 942 "identify", tkscaleident, 943 "get", tkscaleget, 944 "coords", tkscalecoords, 945 "tkScaleMotion", tkscalemotion, 946 "tkScaleDrag", tkscaledrag, 947 "tkScaleBut1P", tkscalebut1p, 948 "tkScaleBut1R", tkscalebut1r, 949 "tkScaleKey", tkscalekey, 950 nil 951 }; 952 953 TkMethod scalemethod = { 954 "scale", 955 tkscalecmd, 956 tkfreescale, 957 tkdrawscale 958 }; 959