137da2899SCharles.Forsyth #include "lib9.h"
237da2899SCharles.Forsyth #include "draw.h"
337da2899SCharles.Forsyth #include "tk.h"
437da2899SCharles.Forsyth #include "label.h"
537da2899SCharles.Forsyth
637da2899SCharles.Forsyth #define O(t, e) ((long)(&((t*)0)->e))
737da2899SCharles.Forsyth
837da2899SCharles.Forsyth /* Widget Commands (+ means implemented)
937da2899SCharles.Forsyth +cget
1037da2899SCharles.Forsyth +configure
1137da2899SCharles.Forsyth +invoke
1237da2899SCharles.Forsyth +select
1337da2899SCharles.Forsyth +deselect
1437da2899SCharles.Forsyth +toggle
1537da2899SCharles.Forsyth */
1637da2899SCharles.Forsyth
1737da2899SCharles.Forsyth enum {
1837da2899SCharles.Forsyth /* other constants */
1937da2899SCharles.Forsyth InvokePause = 200, /* delay showing button in down state when invoked */
2037da2899SCharles.Forsyth };
2137da2899SCharles.Forsyth
2237da2899SCharles.Forsyth TkOption tkbutopts[] =
2337da2899SCharles.Forsyth {
2437da2899SCharles.Forsyth "text", OPTtext, O(TkLabel, text), nil,
2537da2899SCharles.Forsyth "label", OPTtext, O(TkLabel, text), nil,
2637da2899SCharles.Forsyth "underline", OPTdist, O(TkLabel, ul), nil,
2737da2899SCharles.Forsyth "justify", OPTstab, O(TkLabel, justify), tkjustify,
2837da2899SCharles.Forsyth "anchor", OPTflag, O(TkLabel, anchor), tkanchor,
2937da2899SCharles.Forsyth "command", OPTtext, O(TkLabel, command), nil,
3037da2899SCharles.Forsyth "bitmap", OPTbmap, O(TkLabel, bitmap), nil,
3137da2899SCharles.Forsyth "image", OPTimag, O(TkLabel, img), nil,
3237da2899SCharles.Forsyth nil
3337da2899SCharles.Forsyth };
3437da2899SCharles.Forsyth
3537da2899SCharles.Forsyth TkOption tkcbopts[] =
3637da2899SCharles.Forsyth {
3737da2899SCharles.Forsyth "variable", OPTtext, O(TkLabel, variable), nil,
3837da2899SCharles.Forsyth "indicatoron", OPTstab, O(TkLabel, indicator), tkbool,
3937da2899SCharles.Forsyth "onvalue", OPTtext, O(TkLabel, value), nil,
4037da2899SCharles.Forsyth "offvalue", OPTtext, O(TkLabel, offvalue), nil,
4137da2899SCharles.Forsyth nil,
4237da2899SCharles.Forsyth };
4337da2899SCharles.Forsyth
4437da2899SCharles.Forsyth TkOption tkradopts[] =
4537da2899SCharles.Forsyth {
4637da2899SCharles.Forsyth "variable", OPTtext, O(TkLabel, variable), nil,
4737da2899SCharles.Forsyth "value", OPTtext, O(TkLabel, value), nil,
4837da2899SCharles.Forsyth "indicatoron", OPTstab, O(TkLabel, indicator), tkbool,
4937da2899SCharles.Forsyth nil,
5037da2899SCharles.Forsyth };
5137da2899SCharles.Forsyth
5237da2899SCharles.Forsyth static
5337da2899SCharles.Forsyth TkEbind bb[] =
5437da2899SCharles.Forsyth {
5537da2899SCharles.Forsyth {TkEnter, "%W configure -state active"},
5637da2899SCharles.Forsyth {TkLeave, "%W configure -state normal"},
5737da2899SCharles.Forsyth {TkButton1P, "%W tkButton1P"},
5837da2899SCharles.Forsyth {TkButton1R, "%W tkButton1R %x %y"},
5937da2899SCharles.Forsyth {TkMotion|TkButton1P, "" },
6037da2899SCharles.Forsyth {TkKey, "%W tkButtonKey 0x%K"},
6137da2899SCharles.Forsyth };
6237da2899SCharles.Forsyth
6337da2899SCharles.Forsyth static
6437da2899SCharles.Forsyth TkEbind cb[] =
6537da2899SCharles.Forsyth {
6637da2899SCharles.Forsyth {TkEnter, "%W configure -state active"},
6737da2899SCharles.Forsyth {TkLeave, "%W configure -state normal"},
6837da2899SCharles.Forsyth {TkButton1P, "%W invoke"},
6937da2899SCharles.Forsyth {TkMotion|TkButton1P, "" },
7037da2899SCharles.Forsyth {TkKey, "%W tkButtonKey 0x%K"},
7137da2899SCharles.Forsyth };
7237da2899SCharles.Forsyth
7337da2899SCharles.Forsyth
7437da2899SCharles.Forsyth static char tkselbut[] = "selectedButton";
7537da2899SCharles.Forsyth
7637da2899SCharles.Forsyth static char* newbutton(TkTop*, int, char*, char**);
7737da2899SCharles.Forsyth static int istransparent(Tk*);
7837da2899SCharles.Forsyth static void tkvarchanged(Tk*, char*, char*);
7937da2899SCharles.Forsyth
8037da2899SCharles.Forsyth char*
tkbutton(TkTop * t,char * arg,char ** ret)8137da2899SCharles.Forsyth tkbutton(TkTop *t, char *arg, char **ret)
8237da2899SCharles.Forsyth {
8337da2899SCharles.Forsyth return newbutton(t, TKbutton, arg, ret);
8437da2899SCharles.Forsyth }
8537da2899SCharles.Forsyth
8637da2899SCharles.Forsyth char*
tkcheckbutton(TkTop * t,char * arg,char ** ret)8737da2899SCharles.Forsyth tkcheckbutton(TkTop *t, char *arg, char **ret)
8837da2899SCharles.Forsyth {
8937da2899SCharles.Forsyth return newbutton(t, TKcheckbutton, arg, ret);
9037da2899SCharles.Forsyth }
9137da2899SCharles.Forsyth
9237da2899SCharles.Forsyth char*
tkradiobutton(TkTop * t,char * arg,char ** ret)9337da2899SCharles.Forsyth tkradiobutton(TkTop *t, char *arg, char **ret)
9437da2899SCharles.Forsyth {
9537da2899SCharles.Forsyth return newbutton(t, TKradiobutton, arg, ret);
9637da2899SCharles.Forsyth }
9737da2899SCharles.Forsyth
9837da2899SCharles.Forsyth static char*
newbutton(TkTop * t,int btype,char * arg,char ** ret)9937da2899SCharles.Forsyth newbutton(TkTop *t, int btype, char *arg, char **ret)
10037da2899SCharles.Forsyth {
10137da2899SCharles.Forsyth Tk *tk;
10237da2899SCharles.Forsyth char *e;
10337da2899SCharles.Forsyth TkLabel *tkl;
10437da2899SCharles.Forsyth TkName *names;
10537da2899SCharles.Forsyth TkOptab tko[4];
10637da2899SCharles.Forsyth TkVar *v;
10737da2899SCharles.Forsyth
10837da2899SCharles.Forsyth tk = tkmkbutton(t, btype);
10937da2899SCharles.Forsyth if(tk == nil)
11037da2899SCharles.Forsyth return TkNomem;
11137da2899SCharles.Forsyth
11237da2899SCharles.Forsyth tkl = TKobj(TkLabel, tk);
11337da2899SCharles.Forsyth
11437da2899SCharles.Forsyth tko[0].ptr = tk;
11537da2899SCharles.Forsyth tko[0].optab = tkgeneric;
11637da2899SCharles.Forsyth tko[1].ptr = tkl;
11737da2899SCharles.Forsyth tko[1].optab = tkbutopts;
11837da2899SCharles.Forsyth switch(btype){
11937da2899SCharles.Forsyth case TKcheckbutton:
12037da2899SCharles.Forsyth tko[2].ptr = tkl;
12137da2899SCharles.Forsyth tko[2].optab = tkcbopts;
12237da2899SCharles.Forsyth break;
12337da2899SCharles.Forsyth case TKradiobutton:
12437da2899SCharles.Forsyth tko[2].ptr = tkl;
12537da2899SCharles.Forsyth tko[2].optab = tkradopts;
12637da2899SCharles.Forsyth break;
12737da2899SCharles.Forsyth default:
12837da2899SCharles.Forsyth tk->relief = TKraised;
1290b978350Sforsyth tk->borderwidth = 1;
13037da2899SCharles.Forsyth tko[2].ptr = nil;
13137da2899SCharles.Forsyth break;
13237da2899SCharles.Forsyth }
13337da2899SCharles.Forsyth tko[3].ptr = nil;
13437da2899SCharles.Forsyth
13537da2899SCharles.Forsyth names = nil;
13637da2899SCharles.Forsyth e = tkparse(t, arg, tko, &names);
13737da2899SCharles.Forsyth if(e != nil) {
13837da2899SCharles.Forsyth tkfreeobj(tk);
13937da2899SCharles.Forsyth return e;
14037da2899SCharles.Forsyth }
14137da2899SCharles.Forsyth
14237da2899SCharles.Forsyth tksettransparent(tk, istransparent(tk));
14337da2899SCharles.Forsyth tksizebutton(tk);
14437da2899SCharles.Forsyth
14537da2899SCharles.Forsyth e = tkaddchild(t, tk, &names);
14637da2899SCharles.Forsyth tkfreename(names);
14737da2899SCharles.Forsyth if(e != nil) {
14837da2899SCharles.Forsyth tkfreeobj(tk);
14937da2899SCharles.Forsyth return e;
15037da2899SCharles.Forsyth }
15137da2899SCharles.Forsyth tk->name->link = nil;
15237da2899SCharles.Forsyth
15337da2899SCharles.Forsyth if (btype == TKradiobutton &&
15437da2899SCharles.Forsyth tkl->variable != nil &&
15537da2899SCharles.Forsyth strcmp(tkl->variable, tkselbut) == 0 &&
15637da2899SCharles.Forsyth tkl->value == nil &&
15737da2899SCharles.Forsyth tk->name != nil)
15837da2899SCharles.Forsyth tkl->value = strdup(tk->name->name);
15937da2899SCharles.Forsyth
16037da2899SCharles.Forsyth if (tkl->variable != nil) {
16137da2899SCharles.Forsyth v = tkmkvar(t, tkl->variable, 0);
16237da2899SCharles.Forsyth if (v == nil){
16337da2899SCharles.Forsyth if(btype == TKcheckbutton){
16437da2899SCharles.Forsyth e = tksetvar(t, tkl->variable, tkl->offvalue ? tkl->offvalue : "0");
16537da2899SCharles.Forsyth if (e != nil)
16637da2899SCharles.Forsyth goto err;
16737da2899SCharles.Forsyth }
16837da2899SCharles.Forsyth } else if(v->type != TkVstring){
16937da2899SCharles.Forsyth e = TkNotvt;
17037da2899SCharles.Forsyth goto err;
17137da2899SCharles.Forsyth } else
17237da2899SCharles.Forsyth tkvarchanged(tk, tkl->variable, v->value);
17337da2899SCharles.Forsyth }
17437da2899SCharles.Forsyth
17537da2899SCharles.Forsyth return tkvalue(ret, "%s", tk->name->name);
17637da2899SCharles.Forsyth
17737da2899SCharles.Forsyth err:
17837da2899SCharles.Forsyth tkfreeobj(tk);
17937da2899SCharles.Forsyth return e;
18037da2899SCharles.Forsyth }
18137da2899SCharles.Forsyth
18237da2899SCharles.Forsyth Tk*
tkmkbutton(TkTop * t,int btype)18337da2899SCharles.Forsyth tkmkbutton(TkTop *t, int btype)
18437da2899SCharles.Forsyth {
18537da2899SCharles.Forsyth Tk *tk;
18637da2899SCharles.Forsyth TkLabel *tkl;
18737da2899SCharles.Forsyth char *e;
18837da2899SCharles.Forsyth
18937da2899SCharles.Forsyth tk = tknewobj(t, btype, sizeof(Tk)+sizeof(TkLabel));
19037da2899SCharles.Forsyth if (tk == nil)
19137da2899SCharles.Forsyth return nil;
19237da2899SCharles.Forsyth
19337da2899SCharles.Forsyth e = nil;
19437da2899SCharles.Forsyth tk->relief = TKraised;
19537da2899SCharles.Forsyth tk->borderwidth = 0;
19637da2899SCharles.Forsyth tk->highlightwidth = 1;
19737da2899SCharles.Forsyth tk->flag |= Tktakefocus;
19837da2899SCharles.Forsyth tkl = TKobj(TkLabel, tk);
19937da2899SCharles.Forsyth tkl->ul = -1;
20037da2899SCharles.Forsyth tkl->justify = Tkleft;
20137da2899SCharles.Forsyth
20237da2899SCharles.Forsyth switch (btype) {
20337da2899SCharles.Forsyth case TKbutton:
20437da2899SCharles.Forsyth e = tkbindings(t, tk, bb, nelem(bb));
20537da2899SCharles.Forsyth break;
20637da2899SCharles.Forsyth case TKcheckbutton:
207f94b359dSforsyth e = tkbindings(t, tk, cb, nelem(cb));
208f94b359dSforsyth break;
20937da2899SCharles.Forsyth case TKradiobutton:
210f94b359dSforsyth tkl->variable = strdup(tkselbut);
21137da2899SCharles.Forsyth e = tkbindings(t, tk, cb, nelem(cb));
21237da2899SCharles.Forsyth break;
21337da2899SCharles.Forsyth }
21437da2899SCharles.Forsyth
21537da2899SCharles.Forsyth if (e != nil) {
21637da2899SCharles.Forsyth print("tkmkbutton internal error: %s\n", e);
21737da2899SCharles.Forsyth tkfreeobj(tk);
21837da2899SCharles.Forsyth return nil;
21937da2899SCharles.Forsyth }
22037da2899SCharles.Forsyth return tk;
22137da2899SCharles.Forsyth }
22237da2899SCharles.Forsyth
2230b978350Sforsyth /*
2240b978350Sforsyth * draw TKbutton, TKcheckbutton, TKradiobutton
2250b978350Sforsyth */
2260b978350Sforsyth char*
tkdrawbutton(Tk * tk,Point orig)2270b978350Sforsyth tkdrawbutton(Tk *tk, Point orig)
22837da2899SCharles.Forsyth {
2290b978350Sforsyth TkEnv *e;
2300b978350Sforsyth TkLabel *tkl;
2310b978350Sforsyth Rectangle r, s, mainr, focusr;
2320b978350Sforsyth int dx, dy, h;
2330b978350Sforsyth Point p, u, v, pp[4];
2340b978350Sforsyth Image *i, *dst, *cd, *cl, *ct, *img;
2350b978350Sforsyth int relief, bgnd, fgnd;
2360b978350Sforsyth
2370b978350Sforsyth e = tk->env;
2380b978350Sforsyth
2390b978350Sforsyth dst = tkimageof(tk);
2400b978350Sforsyth if(dst == nil)
2410b978350Sforsyth return nil;
2420b978350Sforsyth
2430b978350Sforsyth v.x = tk->act.width + 2*tk->borderwidth;
2440b978350Sforsyth v.y = tk->act.height + 2*tk->borderwidth;
2450b978350Sforsyth
2460b978350Sforsyth r.min = ZP;
2470b978350Sforsyth r.max = v;
2480b978350Sforsyth focusr = insetrect(r, tk->borderwidth);
2490b978350Sforsyth mainr = insetrect(focusr, tk->highlightwidth);
2500b978350Sforsyth relief = tk->relief;
2510b978350Sforsyth
2520b978350Sforsyth tkl = TKobj(TkLabel, tk);
2530b978350Sforsyth
2540b978350Sforsyth fgnd = TkCforegnd;
2550b978350Sforsyth bgnd = TkCbackgnd;
2560b978350Sforsyth if (tk->flag & Tkdisabled)
2570b978350Sforsyth fgnd = TkCdisablefgnd;
2580b978350Sforsyth else if ((tk->type == TKcheckbutton || tk->type == TKradiobutton) && tkl->indicator == BoolF && tkl->check)
2590b978350Sforsyth bgnd = TkCselect;
2600b978350Sforsyth else if (tk->flag & Tkactive) {
2610b978350Sforsyth fgnd = TkCactivefgnd;
2620b978350Sforsyth bgnd = TkCactivebgnd;
26337da2899SCharles.Forsyth }
26437da2899SCharles.Forsyth
2650b978350Sforsyth i = tkitmp(e, r.max, bgnd);
2660b978350Sforsyth if(i == nil)
2670b978350Sforsyth return nil;
2680b978350Sforsyth
2690b978350Sforsyth if(tk->flag & Tkactive)
2700b978350Sforsyth draw(i, r, tkgc(e, bgnd), nil, ZP);
2710b978350Sforsyth
2720b978350Sforsyth p = mainr.min;
2730b978350Sforsyth h = tkl->h - 2 * tk->highlightwidth;
2740b978350Sforsyth
2750b978350Sforsyth dx = tk->act.width - tkl->w - tk->ipad.x;
2760b978350Sforsyth dy = tk->act.height - tkl->h - tk->ipad.y;
2770b978350Sforsyth if((tkl->anchor & (Tknorth|Tksouth)) == 0)
2780b978350Sforsyth p.y += dy/2;
2790b978350Sforsyth else if(tkl->anchor & Tksouth)
2800b978350Sforsyth p.y += dy;
2810b978350Sforsyth
2820b978350Sforsyth if((tkl->anchor & (Tkeast|Tkwest)) == 0)
2830b978350Sforsyth p.x += dx/2;
2840b978350Sforsyth else if(tkl->anchor & Tkeast)
2850b978350Sforsyth p.x += dx;
2860b978350Sforsyth
2870b978350Sforsyth switch(tk->type) {
2880b978350Sforsyth case TKcheckbutton:
2890b978350Sforsyth if(tkl->indicator == BoolF) {
2900b978350Sforsyth relief = tkl->check? TKsunken: TKraised;
2910b978350Sforsyth break;
2920b978350Sforsyth }
2930b978350Sforsyth u.x = p.x + ButtonBorder;
2940b978350Sforsyth u.y = p.y + ButtonBorder + (h - CheckSpace) / 2;
2950b978350Sforsyth
2960b978350Sforsyth cl = tkgc(e, bgnd+TkLightshade);
2970b978350Sforsyth cd = tkgc(e, bgnd+TkDarkshade);
2980b978350Sforsyth tkbevel(i, u, CheckButton, CheckButton, CheckButtonBW, cd, cl);
2990b978350Sforsyth if(tkl->check) {
3000b978350Sforsyth u.x += CheckButtonBW+1;
3010b978350Sforsyth u.y += CheckButtonBW+1;
3020b978350Sforsyth pp[0] = u;
3030b978350Sforsyth pp[0].y += CheckButton/2-1;
3040b978350Sforsyth pp[1] = pp[0];
3050b978350Sforsyth pp[1].x += 2;
3060b978350Sforsyth pp[1].y += 2;
3070b978350Sforsyth pp[2] = u;
3080b978350Sforsyth pp[2].x += CheckButton/4;
3090b978350Sforsyth pp[2].y += CheckButton-2;
3100b978350Sforsyth pp[3] = u;
3110b978350Sforsyth pp[3].x += CheckButton-2;
3120b978350Sforsyth pp[3].y++;
3130b978350Sforsyth bezspline(i, pp, 4, Enddisc, Enddisc, 1, tkgc(e, TkCforegnd), ZP);
3140b978350Sforsyth }
3150b978350Sforsyth break;
3160b978350Sforsyth case TKradiobutton:
3170b978350Sforsyth if(tkl->indicator == BoolF) {
3180b978350Sforsyth relief = tkl->check? TKsunken: TKraised;
3190b978350Sforsyth break;
3200b978350Sforsyth }
3210b978350Sforsyth u.x = p.x + ButtonBorder;
3220b978350Sforsyth u.y = p.y + ButtonBorder + (h - CheckSpace) / 2;
3230b978350Sforsyth v = Pt(u.x+CheckButton/2,u.y+CheckButton/2);
3240b978350Sforsyth ellipse(i, v, CheckButton/2, CheckButton/2, CheckButtonBW-1, tkgc(e, bgnd+TkDarkshade), ZP);
3250b978350Sforsyth if(tkl->check)
3260b978350Sforsyth fillellipse(i, v, CheckButton/2-2, CheckButton/2-2, tkgc(e, TkCforegnd), ZP); /* could be TkCselect */
3270b978350Sforsyth break;
3280b978350Sforsyth case TKbutton:
3290b978350Sforsyth if ((tk->flag & (Tkactivated|Tkactive)) == (Tkactivated|Tkactive))
3300b978350Sforsyth relief = TKsunken;
3310b978350Sforsyth break;
3320b978350Sforsyth }
3330b978350Sforsyth
3340b978350Sforsyth p.x += tk->ipad.x/2;
3350b978350Sforsyth p.y += tk->ipad.y/2;
3360b978350Sforsyth u = ZP;
3370b978350Sforsyth if(tk->type == TKbutton && relief == TKsunken) {
3380b978350Sforsyth u.x++;
3390b978350Sforsyth u.y++;
3400b978350Sforsyth }
3410b978350Sforsyth if((tk->type == TKcheckbutton || tk->type == TKradiobutton) && tkl->indicator != BoolF)
3420b978350Sforsyth u.x += CheckSpace;
3430b978350Sforsyth
3440b978350Sforsyth img = nil;
3450b978350Sforsyth if (tkl->img != nil && tkl->img->img != nil)
3460b978350Sforsyth img = tkl->img->img;
3470b978350Sforsyth else if (tkl->bitmap != nil)
3480b978350Sforsyth img = tkl->bitmap;
3490b978350Sforsyth if (img != nil) {
3500b978350Sforsyth s.min.x = p.x + Bitpadx;
3510b978350Sforsyth s.min.y = p.y + Bitpady;
3520b978350Sforsyth s.max.x = s.min.x + Dx(img->r);
3530b978350Sforsyth s.max.y = s.min.y + Dy(img->r);
3540b978350Sforsyth s = rectaddpt(s, u);
3550b978350Sforsyth if(tkchanhastype(img->chan, CGrey))
3560b978350Sforsyth draw(i, s, tkgc(e, fgnd), img, ZP);
3570b978350Sforsyth else
3580b978350Sforsyth draw(i, s, img, nil, ZP);
3590b978350Sforsyth } else if(tkl->text != nil) {
3600b978350Sforsyth u.x += Textpadx;
3610b978350Sforsyth u.y += Textpady;
3620b978350Sforsyth ct = tkgc(e, fgnd);
3630b978350Sforsyth
3640b978350Sforsyth p.y += (h - tkl->textheight) / 2;
36586018cd3Sforsyth tkdrawstring(tk, i, addpt(u, p), tkl->text, tkl->ul, ct, tkl->justify);
3660b978350Sforsyth }
3670b978350Sforsyth
3680b978350Sforsyth // if(tkhaskeyfocus(tk))
3690b978350Sforsyth // tkbox(i, focusr, tk->highlightwidth, tkgc(e, TkChighlightfgnd));
3700b978350Sforsyth tkdrawrelief(i, tk, ZP, bgnd, relief);
3710b978350Sforsyth
3720b978350Sforsyth p.x = tk->act.x + orig.x;
3730b978350Sforsyth p.y = tk->act.y + orig.y;
3740b978350Sforsyth r = rectaddpt(r, p);
3750b978350Sforsyth draw(dst, r, i, nil, ZP);
3760b978350Sforsyth
3770b978350Sforsyth return nil;
3780b978350Sforsyth }
3790b978350Sforsyth
3800b978350Sforsyth void
tksizebutton(Tk * tk)3810b978350Sforsyth tksizebutton(Tk *tk)
3820b978350Sforsyth {
3830b978350Sforsyth int w, h;
3840b978350Sforsyth TkLabel *tkl;
3850b978350Sforsyth
3860b978350Sforsyth tkl = TKobj(TkLabel, tk);
3870b978350Sforsyth if(tkl->anchor == 0)
3880b978350Sforsyth tkl->anchor = Tkcenter;
3890b978350Sforsyth
3900b978350Sforsyth tksizelabel(tk); /* text, bitmap or image, and highlight */
3910b978350Sforsyth w = tkl->w;
3920b978350Sforsyth h = tkl->h;
3930b978350Sforsyth
3940b978350Sforsyth if((tk->type == TKcheckbutton || tk->type == TKradiobutton) && tkl->indicator != BoolF) {
3950b978350Sforsyth w += CheckSpace;
3960b978350Sforsyth if(h < CheckSpace)
3970b978350Sforsyth h = CheckSpace;
3980b978350Sforsyth }
3990b978350Sforsyth tkl->w = w;
4000b978350Sforsyth tkl->h = h;
4010b978350Sforsyth if((tk->flag & Tksetwidth) == 0)
4020b978350Sforsyth tk->req.width = w;
4030b978350Sforsyth if((tk->flag & Tksetheight) == 0)
4040b978350Sforsyth tk->req.height = h;
4050b978350Sforsyth }
4060b978350Sforsyth
40737da2899SCharles.Forsyth int
tkbuttonmargin(Tk * tk)40837da2899SCharles.Forsyth tkbuttonmargin(Tk *tk)
40937da2899SCharles.Forsyth {
41037da2899SCharles.Forsyth TkLabel *tkl;
41137da2899SCharles.Forsyth tkl = TKobj(TkLabel, tk);
41237da2899SCharles.Forsyth
41337da2899SCharles.Forsyth switch (tk->type) {
41437da2899SCharles.Forsyth case TKbutton:
41537da2899SCharles.Forsyth if (tkl->img != nil || tkl->bitmap != nil)
41637da2899SCharles.Forsyth return 0;
41737da2899SCharles.Forsyth return Textpadx+tk->highlightwidth;
41837da2899SCharles.Forsyth case TKcheckbutton:
41937da2899SCharles.Forsyth case TKradiobutton:
42037da2899SCharles.Forsyth return CheckButton + 2*CheckButtonBW + 2*ButtonBorder;
42137da2899SCharles.Forsyth }
4220b978350Sforsyth return tklabelmargin(tk);
4230b978350Sforsyth }
4240b978350Sforsyth
4250b978350Sforsyth void
tkfreebutton(Tk * tk)4260b978350Sforsyth tkfreebutton(Tk *tk)
4270b978350Sforsyth {
4280b978350Sforsyth tkfreelabel(tk);
42937da2899SCharles.Forsyth }
43037da2899SCharles.Forsyth
43137da2899SCharles.Forsyth static char*
tkbuttoncget(Tk * tk,char * arg,char ** val)43237da2899SCharles.Forsyth tkbuttoncget(Tk *tk, char *arg, char **val)
43337da2899SCharles.Forsyth {
43437da2899SCharles.Forsyth TkOptab tko[4];
43537da2899SCharles.Forsyth TkLabel *tkl = TKobj(TkLabel, tk);
43637da2899SCharles.Forsyth
43737da2899SCharles.Forsyth tko[0].ptr = tk;
43837da2899SCharles.Forsyth tko[0].optab = tkgeneric;
43937da2899SCharles.Forsyth tko[1].ptr = tkl;
44037da2899SCharles.Forsyth tko[1].optab = tkbutopts;
44137da2899SCharles.Forsyth switch(tk->type){
44237da2899SCharles.Forsyth case TKcheckbutton:
44337da2899SCharles.Forsyth tko[2].ptr = tkl;
44437da2899SCharles.Forsyth tko[2].optab = tkcbopts;
44537da2899SCharles.Forsyth break;
44637da2899SCharles.Forsyth case TKradiobutton:
44737da2899SCharles.Forsyth tko[2].ptr = tkl;
44837da2899SCharles.Forsyth tko[2].optab = tkradopts;
44937da2899SCharles.Forsyth break;
45037da2899SCharles.Forsyth default:
45137da2899SCharles.Forsyth tko[2].ptr = nil;
45237da2899SCharles.Forsyth break;
45337da2899SCharles.Forsyth }
45437da2899SCharles.Forsyth tko[3].ptr = nil;
45537da2899SCharles.Forsyth return tkgencget(tko, arg, val, tk->env->top);
45637da2899SCharles.Forsyth }
45737da2899SCharles.Forsyth
45837da2899SCharles.Forsyth static char*
tkbuttonconf(Tk * tk,char * arg,char ** val)45937da2899SCharles.Forsyth tkbuttonconf(Tk *tk, char *arg, char **val)
46037da2899SCharles.Forsyth {
46137da2899SCharles.Forsyth char *e;
46237da2899SCharles.Forsyth TkGeom g;
46337da2899SCharles.Forsyth int bd;
46437da2899SCharles.Forsyth TkOptab tko[4];
46537da2899SCharles.Forsyth TkVar *v;
46637da2899SCharles.Forsyth TkLabel *tkl = TKobj(TkLabel, tk);
46737da2899SCharles.Forsyth
46837da2899SCharles.Forsyth tko[0].ptr = tk;
46937da2899SCharles.Forsyth tko[0].optab = tkgeneric;
47037da2899SCharles.Forsyth tko[1].ptr = tkl;
47137da2899SCharles.Forsyth tko[1].optab = tkbutopts;
47237da2899SCharles.Forsyth switch(tk->type){
47337da2899SCharles.Forsyth case TKcheckbutton:
47437da2899SCharles.Forsyth tko[2].ptr = tkl;
47537da2899SCharles.Forsyth tko[2].optab = tkcbopts;
47637da2899SCharles.Forsyth break;
47737da2899SCharles.Forsyth case TKradiobutton:
47837da2899SCharles.Forsyth tko[2].ptr = tkl;
47937da2899SCharles.Forsyth tko[2].optab = tkradopts;
48037da2899SCharles.Forsyth break;
48137da2899SCharles.Forsyth default:
48237da2899SCharles.Forsyth tko[2].ptr = nil;
48337da2899SCharles.Forsyth break;
48437da2899SCharles.Forsyth }
48537da2899SCharles.Forsyth tko[3].ptr = nil;
48637da2899SCharles.Forsyth
48737da2899SCharles.Forsyth if(*arg == '\0')
48837da2899SCharles.Forsyth return tkconflist(tko, val);
48937da2899SCharles.Forsyth
49037da2899SCharles.Forsyth g = tk->req;
49137da2899SCharles.Forsyth bd = tk->borderwidth;
49237da2899SCharles.Forsyth e = tkparse(tk->env->top, arg, tko, nil);
49337da2899SCharles.Forsyth tksizebutton(tk);
49437da2899SCharles.Forsyth tkgeomchg(tk, &g, bd);
49537da2899SCharles.Forsyth
49637da2899SCharles.Forsyth tk->dirty = tkrect(tk, 1);
49737da2899SCharles.Forsyth tksettransparent(tk, istransparent(tk));
49837da2899SCharles.Forsyth /*
49937da2899SCharles.Forsyth * XXX what happens if we're now disabled, but we were in
50037da2899SCharles.Forsyth * active state before?
50137da2899SCharles.Forsyth */
50237da2899SCharles.Forsyth if (tkl->variable != nil) {
50337da2899SCharles.Forsyth v = tkmkvar(tk->env->top, tkl->variable, 0);
50437da2899SCharles.Forsyth if (v != nil) {
50537da2899SCharles.Forsyth if (v->type != TkVstring) {
50637da2899SCharles.Forsyth e = TkNotvt;
50737da2899SCharles.Forsyth free(tkl->variable);
50837da2899SCharles.Forsyth tkl->variable = nil;
50937da2899SCharles.Forsyth }
51037da2899SCharles.Forsyth else
51137da2899SCharles.Forsyth tkvarchanged(tk, tkl->variable, v->value);
51237da2899SCharles.Forsyth }
51337da2899SCharles.Forsyth }
51437da2899SCharles.Forsyth return e;
51537da2899SCharles.Forsyth }
51637da2899SCharles.Forsyth
51737da2899SCharles.Forsyth static int
istransparent(Tk * tk)51837da2899SCharles.Forsyth istransparent(Tk *tk)
51937da2899SCharles.Forsyth {
52037da2899SCharles.Forsyth TkEnv *e = tk->env;
52137da2899SCharles.Forsyth return (tkhasalpha(e, TkCbackgnd) || tkhasalpha(e, TkCselectbgnd) || tkhasalpha(e, TkCactivebgnd));
52237da2899SCharles.Forsyth }
52337da2899SCharles.Forsyth
52437da2899SCharles.Forsyth static void
tkvarchanged(Tk * tk,char * var,char * val)52537da2899SCharles.Forsyth tkvarchanged(Tk *tk, char *var, char *val)
52637da2899SCharles.Forsyth {
52737da2899SCharles.Forsyth TkLabel *tkl;
52837da2899SCharles.Forsyth char *sval;
52937da2899SCharles.Forsyth
53037da2899SCharles.Forsyth tkl = TKobj(TkLabel, tk);
53137da2899SCharles.Forsyth if (tkl->variable != nil && strcmp(tkl->variable, var) == 0) {
53237da2899SCharles.Forsyth sval = tkl->value;
53337da2899SCharles.Forsyth if (sval == nil)
53437da2899SCharles.Forsyth sval = tk->type == TKcheckbutton ? "1" : "";
53537da2899SCharles.Forsyth tkl->check = (strcmp(val, sval) == 0);
53637da2899SCharles.Forsyth tk->dirty = tkrect(tk, 1);
53737da2899SCharles.Forsyth tkdirty(tk);
53837da2899SCharles.Forsyth }
53937da2899SCharles.Forsyth }
54037da2899SCharles.Forsyth
54137da2899SCharles.Forsyth static char*
tkbutton1p(Tk * tk,char * arg,char ** val)54237da2899SCharles.Forsyth tkbutton1p(Tk *tk, char *arg, char **val)
54337da2899SCharles.Forsyth {
54437da2899SCharles.Forsyth USED(arg);
54537da2899SCharles.Forsyth USED(val);
54637da2899SCharles.Forsyth if(tk->flag & Tkdisabled)
54737da2899SCharles.Forsyth return nil;
54837da2899SCharles.Forsyth tk->flag |= Tkactivated;
54937da2899SCharles.Forsyth tk->dirty = tkrect(tk, 1);
55037da2899SCharles.Forsyth tkdirty(tk);
55137da2899SCharles.Forsyth return nil;
55237da2899SCharles.Forsyth }
55337da2899SCharles.Forsyth
55437da2899SCharles.Forsyth static char*
tkbutton1r(Tk * tk,char * arg,char ** val)55537da2899SCharles.Forsyth tkbutton1r(Tk *tk, char *arg, char **val)
55637da2899SCharles.Forsyth {
55737da2899SCharles.Forsyth char *e;
55837da2899SCharles.Forsyth Point p;
55937da2899SCharles.Forsyth Rectangle hitr;
56037da2899SCharles.Forsyth
56137da2899SCharles.Forsyth USED(arg);
56237da2899SCharles.Forsyth
56337da2899SCharles.Forsyth if(tk->flag & Tkdisabled)
56437da2899SCharles.Forsyth return nil;
56537da2899SCharles.Forsyth e = tkxyparse(tk, &arg, &p);
56637da2899SCharles.Forsyth if (e == nil) {
56737da2899SCharles.Forsyth hitr.min = ZP;
56837da2899SCharles.Forsyth hitr.max.x = tk->act.width + tk->borderwidth*2;
56937da2899SCharles.Forsyth hitr.max.y = tk->act.height + tk->borderwidth*2;
57037da2899SCharles.Forsyth if(ptinrect(p, hitr) && (tk->flag & Tkactivated))
57137da2899SCharles.Forsyth e = tkbuttoninvoke(tk, nil, val);
57237da2899SCharles.Forsyth }
57337da2899SCharles.Forsyth tk->flag &= ~Tkactivated;
57437da2899SCharles.Forsyth tk->dirty = tkrect(tk, 1);
57537da2899SCharles.Forsyth tkdirty(tk);
57637da2899SCharles.Forsyth return e;
57737da2899SCharles.Forsyth }
57837da2899SCharles.Forsyth
57937da2899SCharles.Forsyth static char*
tkbuttonkey(Tk * tk,char * arg,char ** val)58037da2899SCharles.Forsyth tkbuttonkey(Tk *tk, char *arg, char **val)
58137da2899SCharles.Forsyth {
58237da2899SCharles.Forsyth int key;
58337da2899SCharles.Forsyth
58437da2899SCharles.Forsyth if(tk->flag & Tkdisabled)
58537da2899SCharles.Forsyth return nil;
58637da2899SCharles.Forsyth
587*48c2bcd8Sforsyth key = strtol(arg, nil, 0);
58837da2899SCharles.Forsyth if (key == '\n' || key ==' ')
58937da2899SCharles.Forsyth return tkbuttoninvoke(tk, nil, val);
59037da2899SCharles.Forsyth return nil;
59137da2899SCharles.Forsyth }
59237da2899SCharles.Forsyth
59337da2899SCharles.Forsyth static char*
tkbuttontoggle(Tk * tk,char * arg,char ** val)59437da2899SCharles.Forsyth tkbuttontoggle(Tk *tk, char *arg, char **val)
59537da2899SCharles.Forsyth {
59637da2899SCharles.Forsyth char *e;
59737da2899SCharles.Forsyth TkLabel *tkl = TKobj(TkLabel, tk);
59837da2899SCharles.Forsyth char *v;
59937da2899SCharles.Forsyth
60037da2899SCharles.Forsyth USED(arg);
60137da2899SCharles.Forsyth USED(val);
60237da2899SCharles.Forsyth if(tk->flag & Tkdisabled)
60337da2899SCharles.Forsyth return nil;
60437da2899SCharles.Forsyth tkl->check = !tkl->check;
60537da2899SCharles.Forsyth if (tkl->check)
60637da2899SCharles.Forsyth v = tkl->value ? tkl->value : "1";
60737da2899SCharles.Forsyth else
60837da2899SCharles.Forsyth v = tkl->offvalue ? tkl->offvalue : "0";
60937da2899SCharles.Forsyth e = tksetvar(tk->env->top, tkl->variable, v);
61037da2899SCharles.Forsyth tk->dirty = tkrect(tk, 0);
61137da2899SCharles.Forsyth return e;
61237da2899SCharles.Forsyth }
61337da2899SCharles.Forsyth
61437da2899SCharles.Forsyth static char*
buttoninvoke(Tk * tk,char ** val)61537da2899SCharles.Forsyth buttoninvoke(Tk *tk, char **val)
61637da2899SCharles.Forsyth {
61737da2899SCharles.Forsyth char *e = nil;
61837da2899SCharles.Forsyth TkTop *top;
61937da2899SCharles.Forsyth TkLabel *tkl = TKobj(TkLabel, tk);
62037da2899SCharles.Forsyth
62137da2899SCharles.Forsyth top = tk->env->top;
62237da2899SCharles.Forsyth if (tk->type == TKcheckbutton)
62337da2899SCharles.Forsyth e = tkbuttontoggle(tk, "", val);
62437da2899SCharles.Forsyth else if (tk->type == TKradiobutton)
62537da2899SCharles.Forsyth e = tksetvar(top, tkl->variable, tkl->value);
62637da2899SCharles.Forsyth if(e != nil)
62737da2899SCharles.Forsyth return e;
62837da2899SCharles.Forsyth if(tkl->command != nil)
62937da2899SCharles.Forsyth return tkexec(tk->env->top, tkl->command, val);
63037da2899SCharles.Forsyth return nil;
63137da2899SCharles.Forsyth }
63237da2899SCharles.Forsyth
63337da2899SCharles.Forsyth static void
cancelinvoke(Tk * tk,void * v,int cancelled)63437da2899SCharles.Forsyth cancelinvoke(Tk *tk, void *v, int cancelled)
63537da2899SCharles.Forsyth {
63637da2899SCharles.Forsyth int unset;
63737da2899SCharles.Forsyth USED(cancelled);
63837da2899SCharles.Forsyth USED(v);
63937da2899SCharles.Forsyth
64037da2899SCharles.Forsyth /* if it was active before then leave it active unless cleared since */
64137da2899SCharles.Forsyth if (v)
64237da2899SCharles.Forsyth unset = 0;
64337da2899SCharles.Forsyth else
64437da2899SCharles.Forsyth unset = Tkactive;
64537da2899SCharles.Forsyth unset &= (tk->flag & Tkactive);
64637da2899SCharles.Forsyth unset |= Tkactivated;
64737da2899SCharles.Forsyth tk->flag &= ~unset;
64837da2899SCharles.Forsyth tksettransparent(tk, istransparent(tk));
64937da2899SCharles.Forsyth tk->dirty = tkrect(tk, 1);
65037da2899SCharles.Forsyth tkdirty(tk);
65137da2899SCharles.Forsyth tkupdate(tk->env->top);
65237da2899SCharles.Forsyth }
65337da2899SCharles.Forsyth
65437da2899SCharles.Forsyth char*
tkbuttoninvoke(Tk * tk,char * arg,char ** val)65537da2899SCharles.Forsyth tkbuttoninvoke(Tk *tk, char *arg, char **val)
65637da2899SCharles.Forsyth {
65737da2899SCharles.Forsyth char *e;
65837da2899SCharles.Forsyth USED(arg);
65937da2899SCharles.Forsyth
66037da2899SCharles.Forsyth if(tk->flag & Tkdisabled)
66137da2899SCharles.Forsyth return nil;
66237da2899SCharles.Forsyth e = buttoninvoke(tk, val);
66337da2899SCharles.Forsyth if (e == nil && tk->type == TKbutton && !(tk->flag & Tkactivated)) {
66437da2899SCharles.Forsyth tkrepeat(tk, cancelinvoke, (void*)(tk->flag&Tkactive), InvokePause, 0);
66537da2899SCharles.Forsyth tk->flag |= Tkactivated | Tkactive;
66637da2899SCharles.Forsyth tksettransparent(tk, istransparent(tk));
66737da2899SCharles.Forsyth tk->dirty = tkrect(tk, 1);
66837da2899SCharles.Forsyth tkdirty(tk);
66937da2899SCharles.Forsyth tkupdate(tk->env->top);
67037da2899SCharles.Forsyth }
67137da2899SCharles.Forsyth return e;
67237da2899SCharles.Forsyth }
67337da2899SCharles.Forsyth
67437da2899SCharles.Forsyth static char*
tkbuttonselect(Tk * tk,char * arg,char ** val)67537da2899SCharles.Forsyth tkbuttonselect(Tk *tk, char *arg, char **val)
67637da2899SCharles.Forsyth {
67737da2899SCharles.Forsyth char *e, *v;
67837da2899SCharles.Forsyth TkLabel *tkl = TKobj(TkLabel, tk);
67937da2899SCharles.Forsyth
68037da2899SCharles.Forsyth USED(arg);
68137da2899SCharles.Forsyth USED(val);
68237da2899SCharles.Forsyth if (tk->type == TKradiobutton)
68337da2899SCharles.Forsyth v = tkl->value;
68437da2899SCharles.Forsyth else if (tk->type == TKcheckbutton) {
68537da2899SCharles.Forsyth v = tkl->value ? tkl->value : "1";
68637da2899SCharles.Forsyth tkl->check = 1;
68737da2899SCharles.Forsyth tk->dirty = tkrect(tk, 0);
68837da2899SCharles.Forsyth } else
68937da2899SCharles.Forsyth v = nil;
69037da2899SCharles.Forsyth e = tksetvar(tk->env->top, tkl->variable, v);
69137da2899SCharles.Forsyth if(e != nil)
69237da2899SCharles.Forsyth return e;
69337da2899SCharles.Forsyth return nil;
69437da2899SCharles.Forsyth }
69537da2899SCharles.Forsyth
69637da2899SCharles.Forsyth static char*
tkbuttondeselect(Tk * tk,char * arg,char ** val)69737da2899SCharles.Forsyth tkbuttondeselect(Tk *tk, char *arg, char **val)
69837da2899SCharles.Forsyth {
69937da2899SCharles.Forsyth char *e, *v;
70037da2899SCharles.Forsyth TkLabel *tkl = TKobj(TkLabel, tk);
70137da2899SCharles.Forsyth
70237da2899SCharles.Forsyth USED(arg);
70337da2899SCharles.Forsyth USED(val);
70437da2899SCharles.Forsyth
70537da2899SCharles.Forsyth if (tk->type == TKcheckbutton) {
70637da2899SCharles.Forsyth v = tkl->offvalue ? tkl->offvalue : "0";
70737da2899SCharles.Forsyth tkl->check = 0;
70837da2899SCharles.Forsyth tk->dirty = tkrect(tk, 0);
70937da2899SCharles.Forsyth } else
71037da2899SCharles.Forsyth v = nil;
71137da2899SCharles.Forsyth
71237da2899SCharles.Forsyth e = tksetvar(tk->env->top, tkl->variable, v);
71337da2899SCharles.Forsyth if(e != nil)
71437da2899SCharles.Forsyth return e;
71537da2899SCharles.Forsyth return nil;
71637da2899SCharles.Forsyth }
71737da2899SCharles.Forsyth
71837da2899SCharles.Forsyth static
71937da2899SCharles.Forsyth TkCmdtab tkbuttoncmd[] =
72037da2899SCharles.Forsyth {
72137da2899SCharles.Forsyth "cget", tkbuttoncget,
72237da2899SCharles.Forsyth "configure", tkbuttonconf,
72337da2899SCharles.Forsyth "invoke", tkbuttoninvoke,
72437da2899SCharles.Forsyth "tkButton1P", tkbutton1p,
72537da2899SCharles.Forsyth "tkButton1R", tkbutton1r,
72637da2899SCharles.Forsyth "tkButtonKey", tkbuttonkey,
72737da2899SCharles.Forsyth nil
72837da2899SCharles.Forsyth };
72937da2899SCharles.Forsyth
73037da2899SCharles.Forsyth static
73137da2899SCharles.Forsyth TkCmdtab tkchkbuttoncmd[] =
73237da2899SCharles.Forsyth {
73337da2899SCharles.Forsyth "cget", tkbuttoncget,
73437da2899SCharles.Forsyth "configure", tkbuttonconf,
73537da2899SCharles.Forsyth "invoke", tkbuttoninvoke,
73637da2899SCharles.Forsyth "select", tkbuttonselect,
73737da2899SCharles.Forsyth "deselect", tkbuttondeselect,
73837da2899SCharles.Forsyth "toggle", tkbuttontoggle,
73937da2899SCharles.Forsyth "tkButtonKey", tkbuttonkey,
74037da2899SCharles.Forsyth nil
74137da2899SCharles.Forsyth };
74237da2899SCharles.Forsyth
74337da2899SCharles.Forsyth static
74437da2899SCharles.Forsyth TkCmdtab tkradbuttoncmd[] =
74537da2899SCharles.Forsyth {
74637da2899SCharles.Forsyth "cget", tkbuttoncget,
74737da2899SCharles.Forsyth "configure", tkbuttonconf,
74837da2899SCharles.Forsyth "invoke", tkbuttoninvoke,
74937da2899SCharles.Forsyth "select", tkbuttonselect,
75037da2899SCharles.Forsyth "deselect", tkbuttondeselect,
75137da2899SCharles.Forsyth "tkButtonKey", tkbuttonkey,
75237da2899SCharles.Forsyth nil
75337da2899SCharles.Forsyth };
75437da2899SCharles.Forsyth
75537da2899SCharles.Forsyth TkMethod buttonmethod = {
75637da2899SCharles.Forsyth "button",
75737da2899SCharles.Forsyth tkbuttoncmd,
7580b978350Sforsyth tkfreebutton,
7590b978350Sforsyth tkdrawbutton,
76037da2899SCharles.Forsyth nil,
76137da2899SCharles.Forsyth tklabelgetimgs
76237da2899SCharles.Forsyth };
76337da2899SCharles.Forsyth
76437da2899SCharles.Forsyth TkMethod checkbuttonmethod = {
76537da2899SCharles.Forsyth "checkbutton",
76637da2899SCharles.Forsyth tkchkbuttoncmd,
7670b978350Sforsyth tkfreebutton,
7680b978350Sforsyth tkdrawbutton,
76937da2899SCharles.Forsyth nil,
77037da2899SCharles.Forsyth tklabelgetimgs,
77137da2899SCharles.Forsyth nil,
77237da2899SCharles.Forsyth nil,
77337da2899SCharles.Forsyth nil,
77437da2899SCharles.Forsyth nil,
77537da2899SCharles.Forsyth nil,
77637da2899SCharles.Forsyth nil,
77737da2899SCharles.Forsyth tkvarchanged
77837da2899SCharles.Forsyth };
77937da2899SCharles.Forsyth
78037da2899SCharles.Forsyth TkMethod radiobuttonmethod = {
78137da2899SCharles.Forsyth "radiobutton",
78237da2899SCharles.Forsyth tkradbuttoncmd,
7830b978350Sforsyth tkfreebutton,
7840b978350Sforsyth tkdrawbutton,
78537da2899SCharles.Forsyth nil,
78637da2899SCharles.Forsyth nil,
78737da2899SCharles.Forsyth nil,
78837da2899SCharles.Forsyth nil,
78937da2899SCharles.Forsyth nil,
79037da2899SCharles.Forsyth nil,
79137da2899SCharles.Forsyth nil,
79237da2899SCharles.Forsyth nil,
79337da2899SCharles.Forsyth tkvarchanged
79437da2899SCharles.Forsyth };
795