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