scale.c 18 KB

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