xref: /inferno-os/libtk/buton.c (revision 06155dbb53eb0585800b239acd6e45b946c6e0cf)
1 #include "lib9.h"
2 #include "draw.h"
3 #include "tk.h"
4 #include "label.h"
5 
6 #define	O(t, e)		((long)(&((t*)0)->e))
7 
8 /* Widget Commands (+ means implemented)
9 	+cget
10 	+configure
11 	+invoke
12 	+select
13 	+deselect
14 	+toggle
15  */
16 
17 enum {
18 	/* other constants */
19 	InvokePause	= 200,	/* delay showing button in down state when invoked */
20 };
21 
22 TkOption tkbutopts[] =
23 {
24 	"text",		OPTtext,	O(TkLabel, text),	nil,
25 	"label",	OPTtext,	O(TkLabel, text),	nil,
26 	"underline",	OPTdist,	O(TkLabel, ul),		nil,
27 	"justify",	OPTstab,	O(TkLabel, justify),	tkjustify,
28 	"anchor",	OPTflag,	O(TkLabel, anchor),	tkanchor,
29 	"command",	OPTtext,	O(TkLabel, command),	nil,
30 	"bitmap",	OPTbmap,	O(TkLabel, bitmap),	nil,
31 	"image",	OPTimag,	O(TkLabel, img),	nil,
32 	nil
33 };
34 
35 TkOption tkcbopts[] =
36 {
37 	"variable",	OPTtext,	O(TkLabel, variable),	nil,
38 	"indicatoron",	OPTstab,	O(TkLabel, indicator),	tkbool,
39 	"onvalue",	OPTtext,	O(TkLabel, value),	nil,
40 	"offvalue",	OPTtext,	O(TkLabel, offvalue), nil,
41 	nil,
42 };
43 
44 TkOption tkradopts[] =
45 {
46 	"variable",	OPTtext,	O(TkLabel, variable),	nil,
47 	"value",	OPTtext,	O(TkLabel, value), nil,
48 	"indicatoron",	OPTstab,	O(TkLabel, indicator),	tkbool,
49 	nil,
50 };
51 
52 static
53 TkEbind bb[] =
54 {
55 	{TkEnter,	"%W configure -state active"},
56 	{TkLeave,	"%W configure -state normal"},
57 	{TkButton1P,	"%W tkButton1P"},
58 	{TkButton1R,	"%W tkButton1R %x %y"},
59 	{TkMotion|TkButton1P, 	"" },
60 	{TkKey,	"%W tkButtonKey 0x%K"},
61 };
62 
63 static
64 TkEbind cb[] =
65 {
66 	{TkEnter,		"%W configure -state active"},
67 	{TkLeave,		"%W configure -state normal"},
68 	{TkButton1P,		"%W invoke"},
69 	{TkMotion|TkButton1P, 	"" },
70 	{TkKey,	"%W tkButtonKey 0x%K"},
71 };
72 
73 
74 static char	tkselbut[] = "selectedButton";
75 
76 static char*	newbutton(TkTop*, int, char*, char**);
77 static int	istransparent(Tk*);
78 static void tkvarchanged(Tk*, char*, char*);
79 
80 char*
81 tkbutton(TkTop *t, char *arg, char **ret)
82 {
83 	return newbutton(t, TKbutton, arg, ret);
84 }
85 
86 char*
87 tkcheckbutton(TkTop *t, char *arg, char **ret)
88 {
89 	return newbutton(t, TKcheckbutton, arg, ret);
90 }
91 
92 char*
93 tkradiobutton(TkTop *t, char *arg, char **ret)
94 {
95 	return newbutton(t, TKradiobutton, arg, ret);
96 }
97 
98 static char*
99 newbutton(TkTop *t, int btype, char *arg, char **ret)
100 {
101 	Tk *tk;
102 	char *e;
103 	TkLabel *tkl;
104 	TkName *names;
105 	TkOptab tko[4];
106 	TkVar *v;
107 
108 	tk = tkmkbutton(t, btype);
109 	if(tk == nil)
110 		return TkNomem;
111 
112 	tkl = TKobj(TkLabel, tk);
113 
114 	tko[0].ptr = tk;
115 	tko[0].optab = tkgeneric;
116 	tko[1].ptr = tkl;
117 	tko[1].optab = tkbutopts;
118 	switch(btype){
119 	case TKcheckbutton:
120 		tko[2].ptr = tkl;
121 		tko[2].optab = tkcbopts;
122 		break;
123 	case TKradiobutton:
124 		tko[2].ptr = tkl;
125 		tko[2].optab = tkradopts;
126 		break;
127 	default:
128 		tk->relief = TKraised;
129 		tk->borderwidth = 1;
130 		tko[2].ptr = nil;
131 		break;
132 	}
133 	tko[3].ptr = nil;
134 
135 	names = nil;
136 	e = tkparse(t, arg, tko, &names);
137 	if(e != nil) {
138 		tkfreeobj(tk);
139 		return e;
140 	}
141 
142 	tksettransparent(tk, istransparent(tk));
143 	tksizebutton(tk);
144 
145 	e = tkaddchild(t, tk, &names);
146 	tkfreename(names);
147 	if(e != nil) {
148 		tkfreeobj(tk);
149 		return e;
150 	}
151 	tk->name->link = nil;
152 
153 	if (btype == TKradiobutton &&
154 			tkl->variable != nil &&
155 			strcmp(tkl->variable, tkselbut) == 0 &&
156 			tkl->value == nil &&
157 			tk->name != nil)
158 		tkl->value = strdup(tk->name->name);
159 
160 	if (tkl->variable != nil) {
161 		v = tkmkvar(t, tkl->variable, 0);
162 		if (v == nil){
163 			if(btype == TKcheckbutton){
164 				e = tksetvar(t, tkl->variable, tkl->offvalue ? tkl->offvalue : "0");
165 				if (e != nil)
166 					goto err;
167 			}
168 		} else if(v->type != TkVstring){
169 			e = TkNotvt;
170 			goto err;
171 		} else
172 			tkvarchanged(tk, tkl->variable, v->value);
173 	}
174 
175 	return tkvalue(ret, "%s", tk->name->name);
176 
177 err:
178 	tkfreeobj(tk);
179 	return e;
180 }
181 
182 Tk*
183 tkmkbutton(TkTop *t, int btype)
184 {
185 	Tk *tk;
186 	TkLabel *tkl;
187 	char *e;
188 
189 	tk = tknewobj(t, btype, sizeof(Tk)+sizeof(TkLabel));
190 	if (tk == nil)
191 		return nil;
192 
193 	e = nil;
194 	tk->relief = TKraised;
195 	tk->borderwidth = 0;
196 	tk->highlightwidth = 1;
197 	tk->flag |= Tktakefocus;
198 	tkl = TKobj(TkLabel, tk);
199 	tkl->ul = -1;
200 	tkl->justify = Tkleft;
201 
202 	switch (btype) {
203 	case TKbutton:
204 		e = tkbindings(t, tk, bb, nelem(bb));
205 		break;
206 	case TKcheckbutton:
207 		e = tkbindings(t, tk, cb, nelem(cb));
208 		break;
209 	case TKradiobutton:
210 		tkl->variable = strdup(tkselbut);
211 		e = tkbindings(t, tk, cb, nelem(cb));
212 		break;
213 	}
214 
215 	if (e != nil) {
216 		print("tkmkbutton internal error: %s\n", e);
217 		tkfreeobj(tk);
218 		return nil;
219 	}
220 	return tk;
221 }
222 
223 /*
224  * draw TKbutton, TKcheckbutton, TKradiobutton
225  */
226 char*
227 tkdrawbutton(Tk *tk, Point orig)
228 {
229  	TkEnv *e;
230 	TkLabel *tkl;
231 	Rectangle r, s, mainr, focusr;
232 	int dx, dy, h;
233 	Point p, u, v, pp[4];
234 	Image *i, *dst, *cd, *cl, *ct, *img;
235 	int relief, bgnd, fgnd;
236 
237 	e = tk->env;
238 
239 	dst = tkimageof(tk);
240 	if(dst == nil)
241 		return nil;
242 
243 	v.x = tk->act.width + 2*tk->borderwidth;
244 	v.y = tk->act.height + 2*tk->borderwidth;
245 
246 	r.min = ZP;
247 	r.max = v;
248 	focusr = insetrect(r, tk->borderwidth);
249 	mainr = insetrect(focusr, tk->highlightwidth);
250 	relief = tk->relief;
251 
252 	tkl = TKobj(TkLabel, tk);
253 
254 	fgnd = TkCforegnd;
255 	bgnd = TkCbackgnd;
256 	if (tk->flag & Tkdisabled)
257 		fgnd = TkCdisablefgnd;
258 	else if ((tk->type == TKcheckbutton || tk->type == TKradiobutton) && tkl->indicator == BoolF && tkl->check)
259 		bgnd = TkCselect;
260 	else if (tk->flag & Tkactive) {
261 		fgnd = TkCactivefgnd;
262 		bgnd = TkCactivebgnd;
263 	}
264 
265 	i = tkitmp(e, r.max, bgnd);
266 	if(i == nil)
267 		return nil;
268 
269 	if(tk->flag & Tkactive)
270 		draw(i, r, tkgc(e, bgnd), nil, ZP);
271 
272 	p = mainr.min;
273 	h = tkl->h - 2 * tk->highlightwidth;
274 
275 	dx = tk->act.width - tkl->w - tk->ipad.x;
276 	dy = tk->act.height - tkl->h - tk->ipad.y;
277 	if((tkl->anchor & (Tknorth|Tksouth)) == 0)
278 		p.y += dy/2;
279 	else if(tkl->anchor & Tksouth)
280 		p.y += dy;
281 
282 	if((tkl->anchor & (Tkeast|Tkwest)) == 0)
283 		p.x += dx/2;
284 	else if(tkl->anchor & Tkeast)
285 		p.x += dx;
286 
287 	switch(tk->type) {
288 	case TKcheckbutton:
289 		if(tkl->indicator == BoolF) {
290 			relief = tkl->check? TKsunken: TKraised;
291 			break;
292 		}
293 		u.x = p.x + ButtonBorder;
294 		u.y = p.y + ButtonBorder + (h - CheckSpace) / 2;
295 
296 		cl = tkgc(e, bgnd+TkLightshade);
297 		cd = tkgc(e, bgnd+TkDarkshade);
298 		tkbevel(i, u, CheckButton, CheckButton, CheckButtonBW, cd, cl);
299 		if(tkl->check) {
300 			u.x += CheckButtonBW+1;
301 			u.y += CheckButtonBW+1;
302 			pp[0] = u;
303 			pp[0].y += CheckButton/2-1;
304 			pp[1] = pp[0];
305 			pp[1].x += 2;
306 			pp[1].y += 2;
307 			pp[2] = u;
308 			pp[2].x += CheckButton/4;
309 			pp[2].y += CheckButton-2;
310 			pp[3] = u;
311 			pp[3].x += CheckButton-2;
312 			pp[3].y++;
313 			bezspline(i, pp, 4, Enddisc, Enddisc, 1, tkgc(e, TkCforegnd), ZP);
314 		}
315 		break;
316 	case TKradiobutton:
317 		if(tkl->indicator == BoolF) {
318 			relief = tkl->check? TKsunken: TKraised;
319 			break;
320 		}
321 		u.x = p.x + ButtonBorder;
322 		u.y = p.y + ButtonBorder + (h - CheckSpace) / 2;
323 		v = Pt(u.x+CheckButton/2,u.y+CheckButton/2);
324 		ellipse(i, v, CheckButton/2, CheckButton/2, CheckButtonBW-1, tkgc(e, bgnd+TkDarkshade), ZP);
325 		if(tkl->check)
326 			fillellipse(i, v, CheckButton/2-2, CheckButton/2-2, tkgc(e, TkCforegnd), ZP);	/* could be TkCselect */
327 		break;
328 	case TKbutton:
329 		if ((tk->flag & (Tkactivated|Tkactive)) == (Tkactivated|Tkactive))
330 			relief = TKsunken;
331 		break;
332 	}
333 
334 	p.x += tk->ipad.x/2;
335 	p.y += tk->ipad.y/2;
336 	u = ZP;
337 	if(tk->type == TKbutton && relief == TKsunken) {
338 		u.x++;
339 		u.y++;
340 	}
341 	if((tk->type == TKcheckbutton || tk->type == TKradiobutton) && tkl->indicator != BoolF)
342 		u.x += CheckSpace;
343 
344 	img = nil;
345 	if (tkl->img != nil && tkl->img->img != nil)
346 		img = tkl->img->img;
347 	else if (tkl->bitmap != nil)
348 		img = tkl->bitmap;
349 	if (img != nil) {
350 		s.min.x = p.x + Bitpadx;
351 		s.min.y = p.y + Bitpady;
352 		s.max.x = s.min.x + Dx(img->r);
353 		s.max.y = s.min.y + Dy(img->r);
354 		s = rectaddpt(s, u);
355 		if(tkchanhastype(img->chan, CGrey))
356 			draw(i, s, tkgc(e, fgnd), img, ZP);
357 		else
358 			draw(i, s, img, nil, ZP);
359 	} else if(tkl->text != nil) {
360 		u.x += Textpadx;
361 		u.y += Textpady;
362 		ct = tkgc(e, fgnd);
363 
364 		p.y += (h - tkl->textheight) / 2;
365 		tkdrawstring(tk, i, addpt(u, p), tkl->text, tkl->ul, ct, tkl->justify);
366 	}
367 
368 //	if(tkhaskeyfocus(tk))
369 //		tkbox(i, focusr, tk->highlightwidth, tkgc(e, TkChighlightfgnd));
370 	tkdrawrelief(i, tk, ZP, bgnd, relief);
371 
372 	p.x = tk->act.x + orig.x;
373 	p.y = tk->act.y + orig.y;
374 	r = rectaddpt(r, p);
375 	draw(dst, r, i, nil, ZP);
376 
377 	return nil;
378 }
379 
380 void
381 tksizebutton(Tk *tk)
382 {
383 	int w, h;
384 	TkLabel *tkl;
385 
386 	tkl = TKobj(TkLabel, tk);
387 	if(tkl->anchor == 0)
388 		tkl->anchor = Tkcenter;
389 
390 	tksizelabel(tk);	/* text, bitmap or image, and highlight */
391 	w = tkl->w;
392 	h = tkl->h;
393 
394 	if((tk->type == TKcheckbutton || tk->type == TKradiobutton) && tkl->indicator != BoolF) {
395 		w += CheckSpace;
396 		if(h < CheckSpace)
397 			h = CheckSpace;
398 	}
399 	tkl->w = w;
400 	tkl->h = h;
401 	if((tk->flag & Tksetwidth) == 0)
402 		tk->req.width = w;
403 	if((tk->flag & Tksetheight) == 0)
404 		tk->req.height = h;
405 }
406 
407 int
408 tkbuttonmargin(Tk *tk)
409 {
410 	TkLabel *tkl;
411 	tkl = TKobj(TkLabel, tk);
412 
413 	switch (tk->type) {
414 	case TKbutton:
415 		if (tkl->img != nil || tkl->bitmap != nil)
416 			return 0;
417 		return Textpadx+tk->highlightwidth;
418 	case TKcheckbutton:
419 	case TKradiobutton:
420 		return CheckButton + 2*CheckButtonBW + 2*ButtonBorder;
421 	}
422 	return tklabelmargin(tk);
423 }
424 
425 void
426 tkfreebutton(Tk *tk)
427 {
428 	tkfreelabel(tk);
429 }
430 
431 static char*
432 tkbuttoncget(Tk *tk, char *arg, char **val)
433 {
434 	TkOptab tko[4];
435 	TkLabel *tkl = TKobj(TkLabel, tk);
436 
437 	tko[0].ptr = tk;
438 	tko[0].optab = tkgeneric;
439 	tko[1].ptr = tkl;
440 	tko[1].optab = tkbutopts;
441 	switch(tk->type){
442 	case TKcheckbutton:
443 		tko[2].ptr = tkl;
444 		tko[2].optab = tkcbopts;
445 		break;
446 	case TKradiobutton:
447 		tko[2].ptr = tkl;
448 		tko[2].optab = tkradopts;
449 		break;
450 	default:
451 		tko[2].ptr = nil;
452 		break;
453 	}
454 	tko[3].ptr = nil;
455 	return tkgencget(tko, arg, val, tk->env->top);
456 }
457 
458 static char*
459 tkbuttonconf(Tk *tk, char *arg, char **val)
460 {
461 	char *e;
462 	TkGeom g;
463 	int bd;
464 	TkOptab tko[4];
465 	TkVar *v;
466 	TkLabel *tkl = TKobj(TkLabel, tk);
467 
468 	tko[0].ptr = tk;
469 	tko[0].optab = tkgeneric;
470 	tko[1].ptr = tkl;
471 	tko[1].optab = tkbutopts;
472 	switch(tk->type){
473 	case TKcheckbutton:
474 		tko[2].ptr = tkl;
475 		tko[2].optab = tkcbopts;
476 		break;
477 	case TKradiobutton:
478 		tko[2].ptr = tkl;
479 		tko[2].optab = tkradopts;
480 		break;
481 	default:
482 		tko[2].ptr = nil;
483 		break;
484 	}
485 	tko[3].ptr = nil;
486 
487 	if(*arg == '\0')
488 		return tkconflist(tko, val);
489 
490 	g = tk->req;
491 	bd = tk->borderwidth;
492 	e = tkparse(tk->env->top, arg, tko, nil);
493 	tksizebutton(tk);
494 	tkgeomchg(tk, &g, bd);
495 
496 	tk->dirty = tkrect(tk, 1);
497 	tksettransparent(tk, istransparent(tk));
498 	/*
499 	 * XXX what happens if we're now disabled, but we were in
500 	 * active state before?
501 	 */
502 	if (tkl->variable != nil) {
503 		v = tkmkvar(tk->env->top, tkl->variable, 0);
504 		if (v != nil) {
505 			if (v->type != TkVstring) {
506 				e = TkNotvt;
507 				free(tkl->variable);
508 				tkl->variable = nil;
509 			}
510 			else
511 				tkvarchanged(tk, tkl->variable, v->value);
512 		}
513 	}
514 	return e;
515 }
516 
517 static int
518 istransparent(Tk *tk)
519 {
520 	TkEnv *e = tk->env;
521 	return (tkhasalpha(e, TkCbackgnd) || tkhasalpha(e, TkCselectbgnd) || tkhasalpha(e, TkCactivebgnd));
522 }
523 
524 static void
525 tkvarchanged(Tk *tk, char *var, char *val)
526 {
527 	TkLabel *tkl;
528 	char *sval;
529 
530 	tkl = TKobj(TkLabel, tk);
531 	if (tkl->variable != nil && strcmp(tkl->variable, var) == 0) {
532 		sval = tkl->value;
533 		if (sval == nil)
534 			sval = tk->type == TKcheckbutton ? "1" : "";
535 		tkl->check = (strcmp(val, sval) == 0);
536 		tk->dirty = tkrect(tk, 1);
537 		tkdirty(tk);
538 	}
539 }
540 
541 static char*
542 tkbutton1p(Tk *tk, char *arg, char **val)
543 {
544 	USED(arg);
545 	USED(val);
546 	if(tk->flag & Tkdisabled)
547 		return nil;
548 	tk->flag |= Tkactivated;
549 	tk->dirty = tkrect(tk, 1);
550 	tkdirty(tk);
551 	return nil;
552 }
553 
554 static char*
555 tkbutton1r(Tk *tk, char *arg, char **val)
556 {
557 	char *e;
558 	Point p;
559 	Rectangle hitr;
560 
561 	USED(arg);
562 
563 	if(tk->flag & Tkdisabled)
564 		return nil;
565 	e = tkxyparse(tk, &arg, &p);
566 	if (e == nil) {
567 		hitr.min = ZP;
568 		hitr.max.x = tk->act.width + tk->borderwidth*2;
569 		hitr.max.y = tk->act.height + tk->borderwidth*2;
570 		if(ptinrect(p, hitr) && (tk->flag & Tkactivated))
571 			e = tkbuttoninvoke(tk, nil, val);
572 	}
573 	tk->flag &= ~Tkactivated;
574 	tk->dirty = tkrect(tk, 1);
575 	tkdirty(tk);
576 	return e;
577 }
578 
579 static char*
580 tkbuttonkey(Tk *tk, char *arg, char **val)
581 {
582 	int key;
583 
584 	if(tk->flag & Tkdisabled)
585 		return nil;
586 
587 	key = strtol(arg, nil, 0);
588 	if (key == '\n' || key ==' ')
589 		return tkbuttoninvoke(tk, nil, val);
590 	return nil;
591 }
592 
593 static char*
594 tkbuttontoggle(Tk *tk, char *arg, char **val)
595 {
596 	char *e;
597 	TkLabel *tkl = TKobj(TkLabel, tk);
598 	char *v;
599 
600 	USED(arg);
601 	USED(val);
602 	if(tk->flag & Tkdisabled)
603 		return nil;
604 	tkl->check = !tkl->check;
605 	if (tkl->check)
606 		v = tkl->value ? tkl->value : "1";
607 	else
608 		v = tkl->offvalue ? tkl->offvalue : "0";
609 	e = tksetvar(tk->env->top, tkl->variable, v);
610 	tk->dirty = tkrect(tk, 0);
611 	return e;
612 }
613 
614 static char*
615 buttoninvoke(Tk *tk, char **val)
616 {
617 	char *e = nil;
618 	TkTop *top;
619 	TkLabel *tkl = TKobj(TkLabel, tk);
620 
621 	top = tk->env->top;
622 	if (tk->type == TKcheckbutton)
623 		e = tkbuttontoggle(tk, "", val);
624 	else if (tk->type == TKradiobutton)
625 		e = tksetvar(top, tkl->variable, tkl->value);
626 	if(e != nil)
627 		return e;
628 	if(tkl->command != nil)
629 		return tkexec(tk->env->top, tkl->command, val);
630 	return nil;
631 }
632 
633 static void
634 cancelinvoke(Tk *tk, void *v, int cancelled)
635 {
636 	int unset;
637 	USED(cancelled);
638 	USED(v);
639 
640 	/* if it was active before then leave it active unless cleared since */
641 	if (v)
642 		unset = 0;
643 	else
644 		unset = Tkactive;
645 	unset &= (tk->flag & Tkactive);
646 	unset |= Tkactivated;
647 	tk->flag &= ~unset;
648 	tksettransparent(tk, istransparent(tk));
649 	tk->dirty = tkrect(tk, 1);
650 	tkdirty(tk);
651 	tkupdate(tk->env->top);
652 }
653 
654 char*
655 tkbuttoninvoke(Tk *tk, char *arg, char **val)
656 {
657 	char *e;
658 	USED(arg);
659 
660 	if(tk->flag & Tkdisabled)
661 		return nil;
662 	e = buttoninvoke(tk, val);
663 	if (e == nil && tk->type == TKbutton && !(tk->flag & Tkactivated)) {
664 		tkrepeat(tk, cancelinvoke, (void*)(tk->flag&Tkactive), InvokePause, 0);
665 		tk->flag |= Tkactivated | Tkactive;
666 		tksettransparent(tk, istransparent(tk));
667 		tk->dirty = tkrect(tk, 1);
668 		tkdirty(tk);
669 		tkupdate(tk->env->top);
670 	}
671 	return e;
672 }
673 
674 static char*
675 tkbuttonselect(Tk *tk, char *arg, char **val)
676 {
677 	char *e, *v;
678 	TkLabel *tkl = TKobj(TkLabel, tk);
679 
680 	USED(arg);
681 	USED(val);
682 	if (tk->type == TKradiobutton)
683 		v = tkl->value;
684 	else if (tk->type == TKcheckbutton) {
685 		v = tkl->value ? tkl->value : "1";
686 		tkl->check = 1;
687 		tk->dirty = tkrect(tk, 0);
688 	} else
689 		v = nil;
690 	e = tksetvar(tk->env->top, tkl->variable, v);
691 	if(e != nil)
692 		return e;
693 	return nil;
694 }
695 
696 static char*
697 tkbuttondeselect(Tk *tk, char *arg, char **val)
698 {
699 	char *e, *v;
700 	TkLabel *tkl = TKobj(TkLabel, tk);
701 
702 	USED(arg);
703 	USED(val);
704 
705 	if (tk->type == TKcheckbutton) {
706 		v = tkl->offvalue ? tkl->offvalue : "0";
707 		tkl->check = 0;
708 		tk->dirty = tkrect(tk, 0);
709 	} else
710 		v = nil;
711 
712 	e = tksetvar(tk->env->top, tkl->variable, v);
713 	if(e != nil)
714 		return e;
715 	return nil;
716 }
717 
718 static
719 TkCmdtab tkbuttoncmd[] =
720 {
721 	"cget",			tkbuttoncget,
722 	"configure",		tkbuttonconf,
723 	"invoke",		tkbuttoninvoke,
724 	"tkButton1P",		tkbutton1p,
725 	"tkButton1R",		tkbutton1r,
726 	"tkButtonKey",		tkbuttonkey,
727 	nil
728 };
729 
730 static
731 TkCmdtab tkchkbuttoncmd[] =
732 {
733 	"cget",			tkbuttoncget,
734 	"configure",		tkbuttonconf,
735 	"invoke",		tkbuttoninvoke,
736 	"select",		tkbuttonselect,
737 	"deselect",		tkbuttondeselect,
738 	"toggle",		tkbuttontoggle,
739 	"tkButtonKey",		tkbuttonkey,
740 	nil
741 };
742 
743 static
744 TkCmdtab tkradbuttoncmd[] =
745 {
746 	"cget",			tkbuttoncget,
747 	"configure",		tkbuttonconf,
748 	"invoke",		tkbuttoninvoke,
749 	"select",		tkbuttonselect,
750 	"deselect",		tkbuttondeselect,
751 	"tkButtonKey",		tkbuttonkey,
752 	nil
753 };
754 
755 TkMethod buttonmethod = {
756 	"button",
757 	tkbuttoncmd,
758 	tkfreebutton,
759 	tkdrawbutton,
760 	nil,
761 	tklabelgetimgs
762 };
763 
764 TkMethod checkbuttonmethod = {
765 	"checkbutton",
766 	tkchkbuttoncmd,
767 	tkfreebutton,
768 	tkdrawbutton,
769 	nil,
770 	tklabelgetimgs,
771 	nil,
772 	nil,
773 	nil,
774 	nil,
775 	nil,
776 	nil,
777 	tkvarchanged
778 };
779 
780 TkMethod radiobuttonmethod = {
781 	"radiobutton",
782 	tkradbuttoncmd,
783 	tkfreebutton,
784 	tkdrawbutton,
785 	nil,
786 	nil,
787 	nil,
788 	nil,
789 	nil,
790 	nil,
791 	nil,
792 	nil,
793 	tkvarchanged
794 };
795