xref: /inferno-os/libtk/scrol.c (revision c9ccdbd573a9ae70f739fdca280e75da310a3324)
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*
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*
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*
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
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
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
193 drawslider(TkScroll *tks, Image *i, Point o, int w, int h, TkEnv *e)
194 {
195 	Image *l, *d, *t;
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
217 tkvscroll(Tk *tk, TkScroll *tks, Image *i, Point size)
218 {
219 	TkEnv *e;
220 	Point p[3], o;
221 	Image *d, *l;
222 	int bo, w, h, triangle, bgnd;
223 
224 	e = tk->env;
225 
226 	triangle = tk->act.width - Elembw;
227 
228 	bo = tk->borderwidth + Elembw;
229 	p[0].x = size.x/2;
230 	p[0].y = bo;
231 	p[1].x = p[0].x - triangle/2;
232 	p[1].y = p[0].y + triangle;
233 	p[2].x = p[0].x + triangle/2;
234 	p[2].y = p[0].y + triangle;
235 	drawarrow(tks, i, p, e, ActiveA1, ButtonA1);
236 
237 	tks->a1 = p[2].y;
238 	h = p[2].y + Elembw;
239 
240 	p[0].y = size.y - bo - 1;
241 	p[1].y = p[0].y - triangle;
242 	p[2].y = p[0].y - triangle;
243 	drawarrow(tks, i, p, e, ActiveA2, ButtonA2);
244 
245 	tks->a2 = p[2].y;
246 
247 	o.x = tk->borderwidth ;
248 	o.y = bo + triangle + 2*Elembw;
249 	w = size.x - 2*bo;
250 	h = p[2].y - 2*Elembw - h - 2*tk->borderwidth;
251 
252 	o.y += TKF2I(tks->top*h);
253 	h *= tks->bot - tks->top;
254 	h = TKF2I(h);
255 
256 	tks->t1 = o.y - Elembw;
257 	tks->t2 = o.y + h + Elembw;
258 
259 	drawslider(tks, i, o, w, h, e);
260 }
261 
262 static void
263 tkhscroll(Tk *tk, TkScroll *tks, Image *i, Point size)
264 {
265 	TkEnv *e;
266 	Point p[3], o;
267 	Image *d, *l;
268 	int bo, w, h, triangle, bgnd;
269 
270 	e = tk->env;
271 
272 	triangle = tk->act.height - Elembw;
273 
274 	bo = tk->borderwidth + Elembw;
275 	p[0].x = bo;
276 	p[0].y = size.y/2;
277 	p[1].x = p[0].x + triangle;
278 	p[1].y = p[0].y - triangle/2 + 1;
279 	p[2].x = p[0].x + triangle;
280 	p[2].y = p[0].y + triangle/2 - 2;
281 	drawarrow(tks, i, p, e, ActiveA1, ButtonA1);
282 
283 	tks->a1 = p[2].x;
284 	w = p[2].x + Elembw;
285 
286 	p[0].x = size.x - bo - 1;
287 	p[1].x = p[0].x - triangle;
288 	p[2].x = p[0].x - triangle;
289 	drawarrow(tks, i, p, e, ActiveA2, ButtonA2);
290 
291 	tks->a2 = p[2].x;
292 
293 	o.x = bo + triangle + 2*Elembw;
294 	o.y = tk->borderwidth;
295 	w = p[2].x - 2*Elembw - w - 2*tk->borderwidth;
296 	h = size.y - 2*bo;
297 
298 	o.x += TKF2I(tks->top*w);
299 	w *= tks->bot - tks->top;
300 	w = TKF2I(w);
301 
302 	tks->t1 = o.x - Elembw;
303 	tks->t2 = o.x + w + Elembw;
304 
305 	drawslider(tks, i, o, w, h, e);
306 }
307 
308 char*
309 tkdrawscrlb(Tk *tk, Point orig)
310 {
311 	Point p;
312 	TkEnv *e;
313 	Rectangle r;
314 	Image *i, *dst;
315 	TkScroll *tks = TKobj(TkScroll, tk);
316 
317 	e = tk->env;
318 
319 	dst = tkimageof(tk);
320 	if(dst == nil)
321 		return nil;
322 
323 	r.min = ZP;
324 	r.max.x = tk->act.width + 2*tk->borderwidth;
325 	r.max.y = tk->act.height + 2*tk->borderwidth;
326 
327 	i = tkitmp(e, r.max, TkCbackgnd);
328 	if(i == nil)
329 		return nil;
330 
331 	if(tks->orient == Tkvertical)
332 		tkvscroll(tk, tks, i, r.max);
333 	else
334 		tkhscroll(tk, tks, i, r.max);
335 
336 	tkdrawrelief(i, tk, ZP, TkCbackgnd, tk->relief);
337 
338 	p.x = tk->act.x + orig.x;
339 	p.y = tk->act.y + orig.y;
340 	r = rectaddpt(r, p);
341 	draw(dst, r, i, nil, ZP);
342 
343 	return nil;
344 }
345 
346 /* Widget Commands (+ means implemented)
347 	+activate
348 	+cget
349 	+configure
350 	+delta
351 	+fraction
352 	+get
353 	+identify
354 	+set
355 */
356 
357 static char*
358 tkscrollconf(Tk *tk, char *arg, char **val)
359 {
360 	char *e;
361 	TkGeom g;
362 	int bd;
363 	TkOptab tko[3];
364 	TkScroll *tks = TKobj(TkScroll, tk);
365 
366 	tko[0].ptr = tk;
367 	tko[0].optab = tkgeneric;
368 	tko[1].ptr = tks;
369 	tko[1].optab = opts;
370 	tko[2].ptr = nil;
371 
372 	if(*arg == '\0')
373 		return tkconflist(tko, val);
374 
375 	g = tk->req;
376 	bd = tk->borderwidth;
377 	e = tkparse(tk->env->top, arg, tko, nil);
378 	tksettransparent(tk, tkhasalpha(tk->env, TkCbackgnd));
379 	tkgeomchg(tk, &g, bd);
380 
381 	tk->dirty = tkrect(tk, 1);
382 	return e;
383 }
384 
385 static char*
386 tkscrollactivate(Tk *tk, char *arg, char **val)
387 {
388 	int s, gotarg;
389 	char buf[Tkmaxitem];
390 	TkScroll *tks = TKobj(TkScroll, tk);
391 
392 	USED(val);
393 	tkword(tk->env->top, arg, buf, buf+sizeof(buf), &gotarg);
394 	s = tks->flag;
395 	if (!gotarg) {
396 		char *a;
397 		if (s & ActiveA1)
398 			a = "arrow1";
399 		else if (s & ActiveA2)
400 			a = "arrow2";
401 		else if (s & ActiveB1)
402 			a = "slider";
403 		else
404 			a = "";
405 		return tkvalue(val, a);
406 	}
407 	tks->flag &= ~(ActiveA1 | ActiveA2 | ActiveB1);
408 	if(strcmp(buf, "arrow1") == 0)
409 		tks->flag |= ActiveA1;
410 	else
411 	if(strcmp(buf, "arrow2") == 0)
412 		tks->flag |= ActiveA2;
413 	else
414 	if(strcmp(buf, "slider") == 0)
415 		tks->flag |= ActiveB1;
416 
417 	if(s ^ tks->flag)
418 		tk->dirty = tkrect(tk, 1);
419 	return nil;
420 }
421 
422 static char*
423 tkscrollset(Tk *tk, char *arg, char **val)
424 {
425 	TkTop *t;
426 	char *e;
427 	TkScroll *tks = TKobj(TkScroll, tk);
428 
429 	USED(val);
430 	t = tk->env->top;
431 	e = tkfracword(t, &arg, &tks->top, nil);
432 	if (e != nil)
433 		return e;
434 	e = tkfracword(t, &arg, &tks->bot, nil);
435 	if (e != nil)
436 		return e;
437 	if(tks->top < 0)
438 		tks->top = 0;
439 	if(tks->top > TKI2F(1))
440 		tks->top = TKI2F(1);
441 	if(tks->bot < 0)
442 		tks->bot = 0;
443 	if(tks->bot > TKI2F(1))
444 		tks->bot = TKI2F(1);
445 
446 	tk->dirty = tkrect(tk, 1);
447 	return nil;
448 }
449 
450 static char*
451 tkscrolldelta(Tk *tk, char *arg, char **val)
452 {
453 	int l, delta;
454 	char buf[Tkmaxitem];
455 	TkScroll *tks = TKobj(TkScroll, tk);
456 
457 	arg = tkitem(buf, arg);
458 	if(tks->orient == Tkvertical)
459 		tkitem(buf, arg);
460 	if(*arg == '\0' || *buf == '\0')
461 		return TkBadvl;
462 
463 	l = tks->a2-tks->a1-4*Elembw;
464 	delta = TKI2F(1);
465 	if(l != 0)
466 		delta = TKI2F(atoi(buf)) / l;
467 	tkfprint(buf, delta);
468 
469 	return tkvalue(val, "%s", buf);
470 }
471 
472 static char*
473 tkscrollget(Tk *tk, char *arg, char **val)
474 {
475 	char *v, buf[Tkmaxitem];
476 	TkScroll *tks = TKobj(TkScroll, tk);
477 
478 	USED(arg);
479 	v = tkfprint(buf, tks->top);
480 	*v++ = ' ';
481 	tkfprint(v, tks->bot);
482 
483 	return tkvalue(val, "%s", buf);
484 }
485 
486 static char*
487 tkscrollidentify(Tk *tk, char *arg, char **val)
488 {
489 	int gotarg;
490 	TkTop *t;
491 	char *v, buf[Tkmaxitem];
492 	Point p;
493 	TkScroll *tks = TKobj(TkScroll, tk);
494 
495 	t = tk->env->top;
496 	arg = tkword(t, arg, buf, buf+sizeof(buf), &gotarg);
497 	if (!gotarg)
498 		return TkBadvl;
499 	p.x = atoi(buf);
500 	tkword(t, arg, buf, buf+sizeof(buf), &gotarg);
501 	if (!gotarg)
502 		return TkBadvl;
503 	p.y = atoi(buf);
504 	if (!ptinrect(p, tkrect(tk, 0)))
505 		return nil;
506 	if (tks->orient == Tkvertical)
507 		p.x = p.y;
508 	p.x += tk->borderwidth;
509 
510 	v = "";
511 	if(p.x <= tks->a1)
512 		v = "arrow1";
513 	if(p.x > tks->a1 && p.x <= tks->t1)
514 		v = "trough1";
515 	if(p.x > tks->t1 && p.x < tks->t2)
516 		v = "slider";
517 	if(p.x >= tks->t2 && p.x < tks->a2)
518 		v = "trough2";
519 	if(p.x >= tks->a2)
520 		v = "arrow2";
521 	return tkvalue(val, "%s", v);
522 }
523 
524 static char*
525 tkscrollfraction(Tk *tk, char *arg, char **val)
526 {
527 	int len, frac, pos;
528 	char buf[Tkmaxitem];
529 	TkScroll *tks = TKobj(TkScroll, tk);
530 
531 	arg = tkitem(buf, arg);
532 	if(tks->orient == Tkvertical)
533 		tkitem(buf, arg);
534 	if(*arg == '\0' || *buf == '\0')
535 		return TkBadvl;
536 
537 	pos = atoi(buf);
538 	if(pos < tks->a1)
539 		pos = tks->a1;
540 	if(pos > tks->a2)
541 		pos = tks->a2;
542 	len = tks->a2 - tks->a1 - 4*Elembw;
543 	frac = TKI2F(1);
544 	if(len != 0)
545 		frac = TKI2F(pos-tks->a1)/len;
546 	tkfprint(buf, frac);
547 	return tkvalue(val, "%s", buf);
548 }
549 
550 static char*
551 tkScrolBut1R(Tk *tk, char *arg, char **val)
552 {
553 	TkScroll *tks = TKobj(TkScroll, tk);
554 
555 	USED(val);
556 	USED(arg);
557 	tkcancelrepeat(tk);
558 	tks->flag &= ~(ActiveA1|ActiveA2|ActiveB1|ButtonA1|ButtonA2|ButtonB1|Autorepeat);
559 	tk->dirty = tkrect(tk, 1);
560 	return nil;
561 }
562 
563 /* tkScrolBut2P fraction */
564 static char*
565 tkScrolBut2P(Tk *tk, char *arg, char **val)
566 {
567 	TkTop *t;
568 	char *e, buf[Tkmaxitem], fracbuf[Tkmaxitem];
569 	TkScroll *tks = TKobj(TkScroll, tk);
570 
571 
572 	USED(val);
573 	t = tk->env->top;
574 
575 	if(arg[0] == '\0')
576 		return TkBadvl;
577 
578 	tkword(t, arg, fracbuf, fracbuf+sizeof(fracbuf), nil);
579 
580 	e = nil;
581 	if(tks->cmd != nil) {
582 		snprint(buf, sizeof(buf), "%s moveto %s", tks->cmd, fracbuf);
583 		e = tkexec(t, buf, nil);
584 	}
585 	return e;
586 }
587 
588 static void
589 sbrepeat(Tk *tk, void *v, int cancelled)
590 {
591 	char *e, buf[Tkmaxitem];
592 	TkScroll *tks = TKobj(TkScroll, tk);
593 	char *fmt = (char *)v;
594 
595 	if (cancelled) {
596 		tks->flag &= ~Autorepeat;
597 		return;
598 	}
599 
600 	if(tks->cmd != nil && fmt != nil) {
601 		snprint(buf, sizeof(buf), fmt, tks->cmd);
602 		e = tkexec(tk->env->top, buf, nil);
603 		if (e != nil) {
604 			tks->flag &= ~Autorepeat;
605 			tkcancelrepeat(tk);
606 		} else
607 			tkupdate(tk->env->top);
608 	}
609 }
610 
611 /* tkScrolBut1P %x %y */
612 static char*
613 tkScrolBut1P(Tk *tk, char *arg, char **val)
614 {
615 	int pix;
616 	TkTop *t;
617 	char *e, *fmt, buf[Tkmaxitem];
618 	TkScroll *tks = TKobj(TkScroll, tk);
619 
620 	USED(val);
621 	t = tk->env->top;
622 
623 	if (tks->flag & Autorepeat)
624 		return nil;
625 	arg = tkword(t, arg, buf, buf+sizeof(buf), nil);
626 	if(tks->orient == Tkvertical)
627 		tkword(t, arg, buf, buf+sizeof(buf), nil);
628 	if(buf[0] == '\0')
629 		return TkBadvl;
630 
631 	pix = atoi(buf);
632 
633 	tks->dragpix = pix;
634 	tks->dragtop = tks->top;
635 	tks->dragbot = tks->bot;
636 
637 	pix += tk->borderwidth;
638 
639 	fmt = nil;
640 	e = nil;
641 	if(pix <= tks->a1) {
642 		fmt = "%s scroll -1 unit";
643 		tks->flag |= ButtonA1;
644 	}
645 	if(pix > tks->a1 && pix <= tks->t1)
646 		fmt = "%s scroll -1 page";
647 	if(pix > tks->t1 && pix < tks->t2)
648 		tks->flag |= ButtonB1;
649 	if(pix >= tks->t2 && pix < tks->a2)
650 		fmt = "%s scroll 1 page";
651 	if(pix >= tks->a2) {
652 		fmt = "%s scroll 1 unit";
653 		tks->flag |= ButtonA2;
654 	}
655 	if(tks->cmd != nil && fmt != nil) {
656 		snprint(buf, sizeof(buf), fmt, tks->cmd);
657 		e = tkexec(t, buf, nil);
658 		tks->flag |= Autorepeat;
659 		tkrepeat(tk, sbrepeat, fmt, TkRptpause, TkRptinterval);
660 	}
661 	tk->dirty = tkrect(tk, 1);
662 	return e;
663 }
664 
665 /* tkScrolDrag %x %y */
666 static char*
667 tkScrollDrag(Tk *tk, char *arg, char **val)
668 {
669 	TkTop *t;
670 	int pix, delta;
671 	char frac[32], buf[Tkmaxitem];
672 	TkScroll *tks = TKobj(TkScroll, tk);
673 
674 	USED(val);
675 	t = tk->env->top;
676 
677 	if (tks->flag & Autorepeat)
678 		return nil;
679 	if((tks->flag & ButtonB1) == 0)
680 		return nil;
681 
682 	arg = tkword(t, arg, buf, buf+sizeof(buf), nil);
683 	if(tks->orient == Tkvertical)
684 		tkword(t, arg, buf, buf+sizeof(buf), nil);
685 	if(buf[0] == '\0')
686 		return TkBadvl;
687 
688 	pix = atoi(buf);
689 
690 	delta = TKI2F(pix-tks->dragpix);
691 	if ( tks->a2 == tks->a1 )
692 		return TkBadvl;
693 	delta = delta/(tks->a2-tks->a1-4*Elembw);
694 	if(tks->jump == BoolT) {
695 		if(tks->dragtop+delta >= 0 &&
696 		   tks->dragbot+delta <= TKI2F(1)) {
697 			tks->top = tks->dragtop+delta;
698 			tks->bot = tks->dragbot+delta;
699 		}
700 		return nil;
701 	}
702 	if(tks->cmd != nil) {
703 		delta += tks->dragtop;
704 		if(delta < 0)
705 			delta = 0;
706 		if(delta > TKI2F(1))
707 			delta = TKI2F(1);
708 		tkfprint(frac, delta);
709 		snprint(buf, sizeof(buf), "%s moveto %s", tks->cmd, frac);
710 		return tkexec(t, buf, nil);
711 	}
712 	return nil;
713 }
714 
715 TkCmdtab tkscrlbcmd[] =
716 {
717 	"activate",		tkscrollactivate,
718 	"cget",			tkscrollcget,
719 	"configure",		tkscrollconf,
720 	"delta",		tkscrolldelta,
721 	"fraction",		tkscrollfraction,
722 	"get",			tkscrollget,
723 	"identify",		tkscrollidentify,
724 	"set",			tkscrollset,
725 	"tkScrollDrag",		tkScrollDrag,
726 	"tkScrolBut1P",		tkScrolBut1P,
727 	"tkScrolBut1R",		tkScrolBut1R,
728 	"tkScrolBut2P",		tkScrolBut2P,
729 	nil
730 };
731 
732 TkMethod scrollbarmethod = {
733 	"scrollbar",
734 	tkscrlbcmd,
735 	tkfreescrlb,
736 	tkdrawscrlb
737 };
738