Charles.Forsyth20060303a828770d19 years agoHistory
539 lines · 10.6 KB · C
RawDownload
#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;} voidtksizelabel(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;} inttklabelmargin(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);} voidtkfreelabel(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 voidtktriangle(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)

Lines 1–500 of 539.