diff options
| author | Charles.Forsyth <devnull@localhost> | 2006-12-22 17:07:39 +0000 |
|---|---|---|
| committer | Charles.Forsyth <devnull@localhost> | 2006-12-22 17:07:39 +0000 |
| commit | 37da2899f40661e3e9631e497da8dc59b971cbd0 (patch) | |
| tree | cbc6d4680e347d906f5fa7fca73214418741df72 /libtk/label.c | |
| parent | 54bc8ff236ac10b3eaa928fd6bcfc0cdb2ba46ae (diff) | |
20060303a
Diffstat (limited to 'libtk/label.c')
| -rw-r--r-- | libtk/label.c | 539 |
1 files changed, 539 insertions, 0 deletions
diff --git a/libtk/label.c b/libtk/label.c new file mode 100644 index 00000000..79d6344a --- /dev/null +++ b/libtk/label.c @@ -0,0 +1,539 @@ +#include <lib9.h> +#include <kernel.h> +#include "draw.h" +#include "tk.h" +#include "label.h" + +#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, + "label", OPTtext, O(TkLabel, text), nil, + "underline", OPTdist, O(TkLabel, ul), nil, + "justify", OPTflag, O(TkLabel, justify), tkjustify, + "anchor", OPTflag, O(TkLabel, anchor), tkanchor, + "bitmap", OPTbmap, O(TkLabel, bitmap), nil, + "image", OPTimag, O(TkLabel, img), nil, + nil +}; + +char* +tklabel(TkTop *t, char *arg, char **ret) +{ + Tk *tk; + char *e; + TkLabel *tkl; + TkName *names; + TkOptab tko[3]; + + tk = tknewobj(t, TKlabel, sizeof(Tk)+sizeof(TkLabel)); + if(tk == nil) + return TkNomem; + + tkl = TKobj(TkLabel, tk); + tkl->ul = -1; + tkl->justify = Tkleft; + + tko[0].ptr = tk; + tko[0].optab = tkgeneric; + tko[1].ptr = tkl; + tko[1].optab = tklabelopts; + tko[2].ptr = nil; + + names = nil; + e = tkparse(t, arg, tko, &names); + if(e != nil) { + tkfreeobj(tk); + return e; + } + + tksizelabel(tk); + tksettransparent(tk, tkhasalpha(tk->env, TkCbackgnd)); + + e = tkaddchild(t, tk, &names); + tkfreename(names); + if(e != nil) { + tkfreeobj(tk); + return e; + } + tk->name->link = nil; + + return tkvalue(ret, "%s", tk->name->name); +} + +static char* +tklabelcget(Tk *tk, char *arg, char **val) +{ + TkOptab tko[3]; + TkLabel *tkl = TKobj(TkLabel, tk); + + tko[0].ptr = tk; + tko[0].optab = tkgeneric; + tko[1].ptr = tkl; + tko[1].optab = tklabelopts; + tko[2].ptr = nil; + + return tkgencget(tko, arg, val, tk->env->top); +} + +static char* +tklabelconf(Tk *tk, char *arg, char **val) +{ + char *e; + TkGeom g; + int bd; + TkOptab tko[3]; + TkLabel *tkl = TKobj(TkLabel, tk); + + tko[0].ptr = tk; + tko[0].optab = tkgeneric; + tko[1].ptr = tkl; + tko[1].optab = tklabelopts; + tko[2].ptr = nil; + + if(*arg == '\0') + return tkconflist(tko, val); + + g = tk->req; + bd = tk->borderwidth; + e = tkparse(tk->env->top, arg, tko, nil); + tksizelabel(tk); + tksettransparent(tk, tkhasalpha(tk->env, TkCbackgnd)); + tkgeomchg(tk, &g, bd); + + tk->dirty = tkrect(tk, 1); + return e; +} + +void +tksizelabel(Tk *tk) +{ + Point p; + int w, h; + TkLabel *tkl; + + tkl = TKobj(TkLabel, tk); + if(tkl->anchor == 0) + tkl->anchor = Tkcenter; + + w = 0; + h = 0; + tkl->textheight = 0; + if(tkl->img != nil) { + w = tkl->img->w + 2*Bitpadx; + h = tkl->img->h + 2*Bitpady; + } + else + if(tkl->bitmap != nil) { + w = Dx(tkl->bitmap->r) + 2*Bitpadx; + h = Dy(tkl->bitmap->r) + 2*Bitpady; + } + else + if(tkl->text != nil) { + p = tkstringsize(tk, tkl->text); + w = p.x + 2*Textpadx; + h = p.y + 2*Textpady; + if(tkl->ul != -1 && tkl->ul > strlen(tkl->text)) + tkl->ul = -1; + 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) { + w += CheckButton + 2*CheckButtonBW; + if(h < CheckButton) + h = CheckButton; + } + w += 2*tk->highlightwidth; + h += 2*tk->highlightwidth; + tkl->w = w; + tkl->h = h; + if((tk->flag & Tksetwidth) == 0) + tk->req.width = w; + if((tk->flag & Tksetheight) == 0) + tk->req.height = h; +} + +int +tklabelmargin(Tk *tk) +{ + TkLabel *tkl; + Image *img; + + if (tk->type == TKseparator) + return 0; + if (tk->type == TKlabel || tk->type == TKcascade) { + tkl = TKobj(TkLabel, tk); + img = nil; + if (tkl->img != nil) + img = tkl->img->img; + else if (tkl->bitmap != nil) + img = tkl->bitmap; + if (img != nil) + return Bitpadx; + return Textpadx; + } + return tkbuttonmargin(tk); +} + +void +tkfreelabel(Tk *tk) +{ + Image *i; + int locked; + Display *d; + TkLabel *tkl; + + tkl = TKobj(TkLabel, tk); + + if(tkl->text != nil) + free(tkl->text); + if(tkl->command != nil) + free(tkl->command); + if(tkl->value != nil) + free(tkl->value); + if(tkl->variable != nil) { + tkfreevar(tk->env->top, tkl->variable, tk->flag & Tkswept); + free(tkl->variable); + } + if(tkl->img != nil) + tkimgput(tkl->img); + i = tkl->bitmap; + if(i != nil) { + d = i->display; + locked = lockdisplay(d); + freeimage(i); + if(locked) + unlockdisplay(d); + } + if(tkl->menu != nil) + free(tkl->menu); +} + +static void +tktriangle(Point u, Image *i, TkEnv *e) +{ + int j; + Point p[3]; + + u.y++; + p[0].x = u.x + CheckButton; + p[0].y = u.y + CheckButton/2; + p[1].x = u.x; + p[1].y = u.y + CheckButton; + p[2].x = u.x; + p[2].y = u.y; + fillpoly(i, p, 3, ~0, tkgc(e, TkCbackgnddark), p[0]); + for(j = 0; j < 3; j++) + p[j].y -= 2; + + fillpoly(i, p, 3, ~0, tkgc(e, TkCbackgndlght), p[0]); +} + +/* + * draw TKlabel, TKcheckbutton, TKradiobutton + */ +char* +tkdrawlabel(Tk *tk, Point orig) +{ + TkEnv *e; + TkLabel *tkl; + Rectangle r, s, mainr, focusr; + int dx, dy, h; + Point p, u, v, *pp; + 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.x = v.x; + r.max.y = v.y; + 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); + 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; + 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) + 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; +} + +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) +{ + TkLabel *tkl; + + tkl = TKobj(TkLabel, tk); + *mask = nil; + if (tkl->img != nil) + *image = tkl->img->img; + else + *image = tkl->bitmap; +} + +static +TkCmdtab tklabelcmd[] = +{ + "cget", tklabelcget, + "configure", tklabelconf, + nil +}; + +TkMethod labelmethod = { + "label", + tklabelcmd, + tkfreelabel, + tkdrawlabel, + nil, + tklabelgetimgs +}; |
