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