summaryrefslogtreecommitdiff
path: root/libtk
diff options
context:
space:
mode:
authorforsyth <forsyth@vitanuova.com>2010-03-25 09:26:15 +0000
committerforsyth <forsyth@vitanuova.com>2010-03-25 09:26:15 +0000
commit0b97835064f7a6adffa5529a9676920f6c1ad3bf (patch)
tree861903e6a033f5382390a4e87d6d4d2a572e8026 /libtk
parentc9ccdbd573a9ae70f739fdca280e75da310a3324 (diff)
20100325-0926
Diffstat (limited to 'libtk')
-rw-r--r--libtk/buton.c209
-rw-r--r--libtk/label.c200
-rw-r--r--libtk/label.h5
-rw-r--r--libtk/menus.c4
-rw-r--r--libtk/mkfile1
-rw-r--r--libtk/scrol.c8
-rw-r--r--libtk/utils.c4
-rw-r--r--libtk/varbl.c91
8 files changed, 322 insertions, 200 deletions
diff --git a/libtk/buton.c b/libtk/buton.c
index 2f8a20f4..5cbd1d6e 100644
--- a/libtk/buton.c
+++ b/libtk/buton.c
@@ -126,7 +126,7 @@ newbutton(TkTop *t, int btype, char *arg, char **ret)
break;
default:
tk->relief = TKraised;
- tk->borderwidth = 2;
+ tk->borderwidth = 1;
tko[2].ptr = nil;
break;
}
@@ -219,12 +219,193 @@ tkmkbutton(TkTop *t, int btype)
return tk;
}
-void tksizebutton(Tk *tk)
+/*
+ * draw TKbutton, TKcheckbutton, TKradiobutton
+ */
+char*
+tkdrawbutton(Tk *tk, Point orig)
{
- tksizelabel(tk);
+ TkEnv *e;
+ TkLabel *tkl;
+ Rectangle r, s, mainr, focusr;
+ int dx, dy, h;
+ Point p, u, v, pp[4];
+ Image *i, *dst, *cd, *cl, *ct, *img;
+ char *o;
+ int relief, bgnd, fgnd;
+
+ e = tk->env;
+
+ dst = tkimageof(tk);
+ if(dst == nil)
+ return nil;
+
+ v.x = tk->act.width + 2*tk->borderwidth;
+ v.y = tk->act.height + 2*tk->borderwidth;
+
+ r.min = ZP;
+ r.max = v;
+ focusr = insetrect(r, tk->borderwidth);
+ mainr = insetrect(focusr, tk->highlightwidth);
+ relief = tk->relief;
+
+ tkl = TKobj(TkLabel, tk);
+
+ fgnd = TkCforegnd;
+ bgnd = TkCbackgnd;
+ if (tk->flag & Tkdisabled)
+ fgnd = TkCdisablefgnd;
+ else if ((tk->type == TKcheckbutton || tk->type == TKradiobutton) && tkl->indicator == BoolF && tkl->check)
+ bgnd = TkCselect;
+ else if (tk->flag & Tkactive) {
+ fgnd = TkCactivefgnd;
+ bgnd = TkCactivebgnd;
+ }
+
+ i = tkitmp(e, r.max, bgnd);
+ if(i == nil)
+ return nil;
+
+ if(tk->flag & Tkactive)
+ draw(i, r, tkgc(e, bgnd), nil, ZP);
+
+ p = mainr.min;
+ h = tkl->h - 2 * tk->highlightwidth;
+
+ dx = tk->act.width - tkl->w - tk->ipad.x;
+ dy = tk->act.height - tkl->h - tk->ipad.y;
+ if((tkl->anchor & (Tknorth|Tksouth)) == 0)
+ p.y += dy/2;
+ else if(tkl->anchor & Tksouth)
+ p.y += dy;
+
+ if((tkl->anchor & (Tkeast|Tkwest)) == 0)
+ p.x += dx/2;
+ else if(tkl->anchor & Tkeast)
+ p.x += dx;
+
+ switch(tk->type) {
+ case TKcheckbutton:
+ if(tkl->indicator == BoolF) {
+ relief = tkl->check? TKsunken: TKraised;
+ break;
+ }
+ u.x = p.x + ButtonBorder;
+ u.y = p.y + ButtonBorder + (h - CheckSpace) / 2;
+
+ cl = tkgc(e, bgnd+TkLightshade);
+ cd = tkgc(e, bgnd+TkDarkshade);
+ tkbevel(i, u, CheckButton, CheckButton, CheckButtonBW, cd, cl);
+ if(tkl->check) {
+ u.x += CheckButtonBW+1;
+ u.y += CheckButtonBW+1;
+ pp[0] = u;
+ pp[0].y += CheckButton/2-1;
+ pp[1] = pp[0];
+ pp[1].x += 2;
+ pp[1].y += 2;
+ pp[2] = u;
+ pp[2].x += CheckButton/4;
+ pp[2].y += CheckButton-2;
+ pp[3] = u;
+ pp[3].x += CheckButton-2;
+ pp[3].y++;
+ bezspline(i, pp, 4, Enddisc, Enddisc, 1, tkgc(e, TkCforegnd), ZP);
+ }
+ break;
+ case TKradiobutton:
+ if(tkl->indicator == BoolF) {
+ relief = tkl->check? TKsunken: TKraised;
+ break;
+ }
+ u.x = p.x + ButtonBorder;
+ u.y = p.y + ButtonBorder + (h - CheckSpace) / 2;
+ v = Pt(u.x+CheckButton/2,u.y+CheckButton/2);
+ ellipse(i, v, CheckButton/2, CheckButton/2, CheckButtonBW-1, tkgc(e, bgnd+TkDarkshade), ZP);
+ if(tkl->check)
+ fillellipse(i, v, CheckButton/2-2, CheckButton/2-2, tkgc(e, TkCforegnd), ZP); /* could be TkCselect */
+ break;
+ case TKbutton:
+ if ((tk->flag & (Tkactivated|Tkactive)) == (Tkactivated|Tkactive))
+ relief = TKsunken;
+ break;
+ }
+
+ p.x += tk->ipad.x/2;
+ p.y += tk->ipad.y/2;
+ u = ZP;
+ if(tk->type == TKbutton && relief == TKsunken) {
+ u.x++;
+ u.y++;
+ }
+ if((tk->type == TKcheckbutton || tk->type == TKradiobutton) && tkl->indicator != BoolF)
+ u.x += CheckSpace;
+
+ img = nil;
+ if (tkl->img != nil && tkl->img->img != nil)
+ img = tkl->img->img;
+ else if (tkl->bitmap != nil)
+ img = tkl->bitmap;
+ if (img != nil) {
+ s.min.x = p.x + Bitpadx;
+ s.min.y = p.y + Bitpady;
+ s.max.x = s.min.x + Dx(img->r);
+ s.max.y = s.min.y + Dy(img->r);
+ s = rectaddpt(s, u);
+ if(tkchanhastype(img->chan, CGrey))
+ draw(i, s, tkgc(e, fgnd), img, ZP);
+ else
+ draw(i, s, img, nil, ZP);
+ } else if(tkl->text != nil) {
+ u.x += Textpadx;
+ u.y += Textpady;
+ ct = tkgc(e, fgnd);
+
+ p.y += (h - tkl->textheight) / 2;
+ o = tkdrawstring(tk, i, addpt(u, p), tkl->text, tkl->ul, ct, tkl->justify);
+ if(o != nil)
+ return o;
+ }
+
+// if(tkhaskeyfocus(tk))
+// tkbox(i, focusr, tk->highlightwidth, tkgc(e, TkChighlightfgnd));
+ tkdrawrelief(i, tk, ZP, bgnd, relief);
+
+ p.x = tk->act.x + orig.x;
+ p.y = tk->act.y + orig.y;
+ r = rectaddpt(r, p);
+ draw(dst, r, i, nil, ZP);
+
+ return nil;
+}
+
+void
+tksizebutton(Tk *tk)
+{
+ int w, h;
+ TkLabel *tkl;
+
+ tkl = TKobj(TkLabel, tk);
+ if(tkl->anchor == 0)
+ tkl->anchor = Tkcenter;
+
+ tksizelabel(tk); /* text, bitmap or image, and highlight */
+ w = tkl->w;
+ h = tkl->h;
+
+ if((tk->type == TKcheckbutton || tk->type == TKradiobutton) && tkl->indicator != BoolF) {
+ w += CheckSpace;
+ if(h < CheckSpace)
+ h = CheckSpace;
+ }
+ tkl->w = w;
+ tkl->h = h;
+ if((tk->flag & Tksetwidth) == 0)
+ tk->req.width = w;
+ if((tk->flag & Tksetheight) == 0)
+ tk->req.height = h;
}
-/* shame that this is separated from the sizing and rendering code in label.c */
int
tkbuttonmargin(Tk *tk)
{
@@ -240,7 +421,13 @@ tkbuttonmargin(Tk *tk)
case TKradiobutton:
return CheckButton + 2*CheckButtonBW + 2*ButtonBorder;
}
- return 0;
+ return tklabelmargin(tk);
+}
+
+void
+tkfreebutton(Tk *tk)
+{
+ tkfreelabel(tk);
}
static char*
@@ -570,8 +757,8 @@ TkCmdtab tkradbuttoncmd[] =
TkMethod buttonmethod = {
"button",
tkbuttoncmd,
- tkfreelabel,
- tkdrawlabel,
+ tkfreebutton,
+ tkdrawbutton,
nil,
tklabelgetimgs
};
@@ -579,8 +766,8 @@ TkMethod buttonmethod = {
TkMethod checkbuttonmethod = {
"checkbutton",
tkchkbuttoncmd,
- tkfreelabel,
- tkdrawlabel,
+ tkfreebutton,
+ tkdrawbutton,
nil,
tklabelgetimgs,
nil,
@@ -595,8 +782,8 @@ TkMethod checkbuttonmethod = {
TkMethod radiobuttonmethod = {
"radiobutton",
tkradbuttoncmd,
- tkfreelabel,
- tkdrawlabel,
+ tkfreebutton,
+ tkdrawbutton,
nil,
nil,
nil,
diff --git a/libtk/label.c b/libtk/label.c
index 63355266..fe1ca2ff 100644
--- a/libtk/label.c
+++ b/libtk/label.c
@@ -6,11 +6,6 @@
#define O(t, e) ((long)(&((t*)0)->e))
-/* Layout constants */
-enum {
- CheckSpace = CheckButton + 2*CheckButtonBW + 2*ButtonBorder,
-};
-
TkOption tklabelopts[] =
{
"text", OPTtext, O(TkLabel, text), nil,
@@ -140,11 +135,7 @@ tksizelabel(Tk *tk)
tkl->textheight = p.y;
}
- if((tk->type == TKcheckbutton || tk->type == TKradiobutton) && tkl->indicator != BoolF) {
- w += CheckSpace;
- if(h < CheckSpace)
- h = CheckSpace;
- } else if(tk->type == TKcascade) {
+ if(tk->type == TKcascade) {
w += CheckButton + 2*CheckButtonBW;
if(h < CheckButton)
h = CheckButton;
@@ -165,9 +156,12 @@ tklabelmargin(Tk *tk)
TkLabel *tkl;
Image *img;
- if (tk->type == TKseparator)
+ switch(tk->type){
+ case TKseparator:
return 0;
- if (tk->type == TKlabel || tk->type == TKcascade) {
+
+ case TKlabel:
+ case TKcascade:
tkl = TKobj(TkLabel, tk);
img = nil;
if (tkl->img != nil)
@@ -177,8 +171,11 @@ tklabelmargin(Tk *tk)
if (img != nil)
return Bitpadx;
return Textpadx;
+
+ default:
+ fprint(2, "label margin: type %d\n", tk->type);
+ return 0;
}
- return tkbuttonmargin(tk);
}
void
@@ -218,7 +215,6 @@ tkfreelabel(Tk *tk)
static void
tktriangle(Point u, Image *i, TkEnv *e)
{
- int j;
Point p[3];
u.y++;
@@ -232,7 +228,7 @@ tktriangle(Point u, Image *i, TkEnv *e)
}
/*
- * draw TKlabel, TKcheckbutton, TKradiobutton
+ * draw TKlabel, TKseparator, and TKcascade (cascade should really be a button)
*/
char*
tkdrawlabel(Tk *tk, Point orig)
@@ -241,8 +237,8 @@ tkdrawlabel(Tk *tk, Point orig)
TkLabel *tkl;
Rectangle r, s, mainr, focusr;
int dx, dy, h;
- Point p, u, v, *pp;
- Image *i, *dst, *cd, *cl, *ct, *img;
+ Point p, u, v;
+ Image *i, *dst, *ct, *img;
char *o;
int relief, bgnd, fgnd;
@@ -256,8 +252,7 @@ tkdrawlabel(Tk *tk, Point orig)
v.y = tk->act.height + 2*tk->borderwidth;
r.min = ZP;
- r.max.x = v.x;
- r.max.y = v.y;
+ r.max = v;
focusr = insetrect(r, tk->borderwidth);
mainr = insetrect(focusr, tk->highlightwidth);
relief = tk->relief;
@@ -268,8 +263,6 @@ tkdrawlabel(Tk *tk, Point orig)
bgnd = TkCbackgnd;
if (tk->flag & Tkdisabled)
fgnd = TkCdisablefgnd;
- else if ((tk->type == TKcheckbutton || tk->type == TKradiobutton) && tkl->indicator == BoolF && tkl->check)
- bgnd = TkCselect;
else if (tk->flag & Tkactive) {
fgnd = TkCactivefgnd;
bgnd = TkCactivebgnd;
@@ -297,95 +290,28 @@ tkdrawlabel(Tk *tk, Point orig)
else if(tkl->anchor & Tkeast)
p.x += dx;
- switch(tk->type) {
- case TKcheckbutton:
- if (tkl->indicator == BoolF) {
- relief = tkl->check?TKsunken:TKraised;
- break;
- }
- u.x = p.x + ButtonBorder;
- u.y = p.y + ButtonBorder + (h - CheckSpace) / 2;
-
- cl = tkgc(e, bgnd+TkLightshade);
- cd = tkgc(e, bgnd+TkDarkshade);
- if(tkl->check) {
- tkbevel(i, u, CheckButton, CheckButton, CheckButtonBW, cd, cl);
- u.x += CheckButtonBW;
- u.y += CheckButtonBW;
- s.min = u;
- s.max.x = u.x + CheckButton;
- s.max.y = u.y + CheckButton;
- draw(i, s, tkgc(e, TkCselect), nil, ZP);
- }
- else
- tkbevel(i, u, CheckButton, CheckButton, CheckButtonBW, cl, cd);
- break;
- case TKradiobutton:
- if (tkl->indicator == BoolF) {
- relief = tkl->check?TKsunken:TKraised;
- break;
- }
- u.x = p.x + ButtonBorder;
- u.y = p.y + ButtonBorder + (h - CheckSpace) / 2;
- pp = mallocz(4*sizeof(Point), 0);
- if(pp == nil)
- return TkNomem;
- pp[0].x = u.x + CheckButton/2;
- pp[0].y = u.y;
- pp[1].x = u.x + CheckButton;
- pp[1].y = u.y + CheckButton/2;
- pp[2].x = pp[0].x;
- pp[2].y = u.y + CheckButton;
- pp[3].x = u.x;
- pp[3].y = pp[1].y;
- cl = tkgc(e, bgnd+TkLightshade);
- cd = tkgc(e, bgnd+TkDarkshade);
- if(tkl->check)
- fillpoly(i, pp, 4, ~0, tkgc(e, TkCselect), pp[0]);
- else {
- ct = cl;
- cl = cd;
- cd = ct;
- }
- line(i, pp[0], pp[1], 0, Enddisc, CheckButtonBW/2, cd, pp[0]);
- line(i, pp[1], pp[2], 0, Enddisc, CheckButtonBW/2, cl, pp[1]);
- line(i, pp[2], pp[3], 0, Enddisc, CheckButtonBW/2, cl, pp[2]);
- line(i, pp[3], pp[0], 0, Enddisc, CheckButtonBW/2, cd, pp[3]);
- free(pp);
- break;
- case TKcascade:
- u.x = mainr.max.x - CheckButton - CheckButtonBW;
+ if(tk->type == TKcascade) {
+ u.x = mainr.max.x - CheckButton - CheckButtonBW; /* TO DO: CheckButton etc is really the triangle/arrow */
u.y = p.y + ButtonBorder + (h-CheckSpace)/2;
tktriangle(u, i, e);
- break;
- case TKbutton:
- if ((tk->flag & (Tkactivated|Tkactive)) == (Tkactivated|Tkactive))
- relief = TKsunken;
- break;
}
p.x += tk->ipad.x/2;
p.y += tk->ipad.y/2;
u = ZP;
- if(tk->type == TKbutton && relief == TKsunken) {
- u.x++;
- u.y++;
- }
- if((tk->type == TKcheckbutton || tk->type == TKradiobutton) && tkl->indicator != BoolF)
- u.x += CheckSpace;
img = nil;
- if (tkl->img != nil && tkl->img->img != nil)
+ if(tkl->img != nil && tkl->img->img != nil)
img = tkl->img->img;
else if (tkl->bitmap != nil)
img = tkl->bitmap;
- if (img != nil) {
+ if(img != nil) {
s.min.x = p.x + Bitpadx;
s.min.y = p.y + Bitpady;
s.max.x = s.min.x + Dx(img->r);
s.max.y = s.min.y + Dy(img->r);
s = rectaddpt(s, u);
- if (tkchanhastype(img->chan, CGrey))
+ if(tkchanhastype(img->chan, CGrey))
draw(i, s, tkgc(e, fgnd), img, ZP);
else
draw(i, s, img, nil, ZP);
@@ -400,7 +326,7 @@ tkdrawlabel(Tk *tk, Point orig)
return o;
}
- if (tkhaskeyfocus(tk))
+ if(tkhaskeyfocus(tk))
tkbox(i, focusr, tk->highlightwidth, tkgc(e, TkChighlightfgnd));
tkdrawrelief(i, tk, ZP, bgnd, relief);
@@ -412,92 +338,6 @@ tkdrawlabel(Tk *tk, Point orig)
return nil;
}
-char*
-tksetvar(TkTop *top, char *c, char *newval)
-{
- TkVar *v;
- TkWin *tkw;
- Tk *f, *m;
- void (*vc)(Tk*, char*, char*);
-
- if (c == nil || c[0] == '\0')
- return nil;
-
- v = tkmkvar(top, c, TkVstring);
- if(v == nil)
- return TkNomem;
- if(v->type != TkVstring)
- return TkNotvt;
-
- if(newval == nil)
- newval = "";
-
- if(v->value != nil) {
- if (strcmp(v->value, newval) == 0)
- return nil;
- free(v->value);
- }
-
- v->value = strdup(newval);
- if(v->value == nil)
- return TkNomem;
-
- for(f = top->root; f; f = f->siblings) {
- if(f->type == TKmenu) {
- tkw = TKobj(TkWin, f);
- for(m = tkw->slave; m; m = m->next)
- if ((vc = tkmethod[m->type]->varchanged) != nil)
- (*vc)(m, c, newval);
- } else
- if ((vc = tkmethod[f->type]->varchanged) != nil)
- (*vc)(f, c, newval);
- }
-
- return nil;
-}
-
-char*
-tkvariable(TkTop *t, char *arg, char **ret)
-{
- TkVar *v;
- char *fmt, *e, *buf, *ebuf, *val;
- int l;
-
- l = strlen(arg) + 2;
- buf = malloc(l);
- if(buf == nil)
- return TkNomem;
- ebuf = buf+l;
-
- arg = tkword(t, arg, buf, ebuf, nil);
- arg = tkskip(arg, " \t");
- if (*arg == '\0') {
- if(strcmp(buf, "lasterror") == 0) {
- free(buf);
- if(t->err == nil)
- return nil;
- fmt = "%s: %s";
- if(strlen(t->errcmd) == sizeof(t->errcmd)-1)
- fmt = "%s...: %s";
- e = tkvalue(ret, fmt, t->errcmd, t->err);
- t->err = nil;
- return e;
- }
- v = tkmkvar(t, buf, 0);
- free(buf);
- if(v == nil || v->value == nil)
- return nil;
- if(v->type != TkVstring)
- return TkNotvt;
- return tkvalue(ret, "%s", v->value);
- }
- val = buf+strlen(buf)+1;
- tkword(t, arg, val, ebuf, nil);
- e = tksetvar(t, buf, val);
- free(buf);
- return e;
-}
-
void
tklabelgetimgs(Tk *tk, Image **image, Image **mask)
{
diff --git a/libtk/label.h b/libtk/label.h
index 6541a10b..7824ecec 100644
--- a/libtk/label.h
+++ b/libtk/label.h
@@ -45,8 +45,9 @@ enum {
Bitpadx = 0, /* Bitmap padding in labels */
Bitpady = 0,
CheckButton = 10,
- CheckButtonBW = 2,
+ CheckButtonBW = 1,
ButtonBorder = 4,
+ CheckSpace = CheckButton + 2*CheckButtonBW + 2*ButtonBorder,
};
extern TkOption tkbutopts[];
@@ -63,8 +64,10 @@ extern char* tksetvar(TkTop*, char*, char*);
/* buton.c */
extern Tk* tkmkbutton(TkTop*, int);
extern void tksizebutton(Tk*);
+extern char* tkdrawbutton(Tk*, Point);
extern char* tkbuttoninvoke(Tk*, char*, char**);
extern char* tkradioinvoke(Tk*, char*, char**);
+extern void tkfreebutton(Tk*);
/* support for menus */
extern int tklabelmargin(Tk*);
diff --git a/libtk/menus.c b/libtk/menus.c
index 4d4d55d4..ea02cef8 100644
--- a/libtk/menus.c
+++ b/libtk/menus.c
@@ -155,7 +155,7 @@ tksizemenubutton(Tk *tk)
TkLabel *tkl = TKobj(TkLabel, tk);
tksizelabel(tk);
- if (tk->type != TKchoicebutton)
+ if(tk->type != TKchoicebutton)
return;
w = tk->req.width;
h = tk->req.height;
@@ -789,7 +789,7 @@ layout(Tk *menu)
/* determine padding for item text alignment */
for (tk = tkw->slave; tk != nil; tk = tk->next) {
- m = tklabelmargin(tk);
+ m = tkbuttonmargin(tk); /* TO DO: relies on buttonmargin defaulting to labelmargin */
tk->act.x = m; /* temp store */
if (m > maxmargin)
maxmargin = m;
diff --git a/libtk/mkfile b/libtk/mkfile
index f52a0148..84dc2feb 100644
--- a/libtk/mkfile
+++ b/libtk/mkfile
@@ -10,6 +10,7 @@ OFILES=\
panel.$O\
parse.$O\
utils.$O\
+ varbl.$O\
windw.$O\
xdata.$O\
diff --git a/libtk/scrol.c b/libtk/scrol.c
index cae26907..0e94e461 100644
--- a/libtk/scrol.c
+++ b/libtk/scrol.c
@@ -192,7 +192,7 @@ drawarrow(TkScroll *tks, Image *i, Point p[3], TkEnv *e, int activef, int button
static void
drawslider(TkScroll *tks, Image *i, Point o, int w, int h, TkEnv *e)
{
- Image *l, *d, *t;
+ Image *l, *d;
Rectangle r;
int bgnd;
@@ -218,8 +218,7 @@ tkvscroll(Tk *tk, TkScroll *tks, Image *i, Point size)
{
TkEnv *e;
Point p[3], o;
- Image *d, *l;
- int bo, w, h, triangle, bgnd;
+ int bo, w, h, triangle;
e = tk->env;
@@ -264,8 +263,7 @@ tkhscroll(Tk *tk, TkScroll *tks, Image *i, Point size)
{
TkEnv *e;
Point p[3], o;
- Image *d, *l;
- int bo, w, h, triangle, bgnd;
+ int bo, w, h, triangle;
e = tk->env;
diff --git a/libtk/utils.c b/libtk/utils.c
index 00dd9d90..b783a73d 100644
--- a/libtk/utils.c
+++ b/libtk/utils.c
@@ -1541,7 +1541,8 @@ tkrect(Tk *tk, int withborder)
{
Rectangle r;
int bd;
- bd = withborder ? tk->borderwidth : 0;
+
+ bd = withborder? tk->borderwidth: 0;
r.min.x = -bd;
r.min.y = -bd;
r.max.x = tk->act.width + bd;
@@ -1910,6 +1911,7 @@ tklinehit(Point *a, int np, int w, Point p)
{
Point *b;
int z, nx, ny, nrm;
+
while(np-- > 1) {
b = a+1;
nx = a->y - b->y;
diff --git a/libtk/varbl.c b/libtk/varbl.c
new file mode 100644
index 00000000..9f5346ff
--- /dev/null
+++ b/libtk/varbl.c
@@ -0,0 +1,91 @@
+#include <lib9.h>
+#include <kernel.h>
+#include "draw.h"
+#include "tk.h"
+#include "label.h"
+
+char*
+tksetvar(TkTop *top, char *c, char *newval)
+{
+ TkVar *v;
+ TkWin *tkw;
+ Tk *f, *m;
+ void (*vc)(Tk*, char*, char*);
+
+ if (c == nil || c[0] == '\0')
+ return nil;
+
+ v = tkmkvar(top, c, TkVstring);
+ if(v == nil)
+ return TkNomem;
+ if(v->type != TkVstring)
+ return TkNotvt;
+
+ if(newval == nil)
+ newval = "";
+
+ if(v->value != nil) {
+ if (strcmp(v->value, newval) == 0)
+ return nil;
+ free(v->value);
+ }
+
+ v->value = strdup(newval);
+ if(v->value == nil)
+ return TkNomem;
+
+ for(f = top->root; f; f = f->siblings) {
+ if(f->type == TKmenu) {
+ tkw = TKobj(TkWin, f);
+ for(m = tkw->slave; m; m = m->next)
+ if ((vc = tkmethod[m->type]->varchanged) != nil)
+ (*vc)(m, c, newval);
+ } else
+ if ((vc = tkmethod[f->type]->varchanged) != nil)
+ (*vc)(f, c, newval);
+ }
+
+ return nil;
+}
+
+char*
+tkvariable(TkTop *t, char *arg, char **ret)
+{
+ TkVar *v;
+ char *fmt, *e, *buf, *ebuf, *val;
+ int l;
+
+ l = strlen(arg) + 2;
+ buf = malloc(l);
+ if(buf == nil)
+ return TkNomem;
+ ebuf = buf+l;
+
+ arg = tkword(t, arg, buf, ebuf, nil);
+ arg = tkskip(arg, " \t");
+ if (*arg == '\0') {
+ if(strcmp(buf, "lasterror") == 0) {
+ free(buf);
+ if(t->err == nil)
+ return nil;
+ fmt = "%s: %s";
+ if(strlen(t->errcmd) == sizeof(t->errcmd)-1)
+ fmt = "%s...: %s";
+ e = tkvalue(ret, fmt, t->errcmd, t->err);
+ t->err = nil;
+ return e;
+ }
+ v = tkmkvar(t, buf, 0);
+ free(buf);
+ if(v == nil || v->value == nil)
+ return nil;
+ if(v->type != TkVstring)
+ return TkNotvt;
+ return tkvalue(ret, "%s", v->value);
+ }
+ val = buf+strlen(buf)+1;
+ tkword(t, arg, val, ebuf, nil);
+ e = tksetvar(t, buf, val);
+ free(buf);
+ return e;
+}