forsyth20121205-174063a80cc13 years agoHistory
794 lines · 15.2 KB · C
RawDownload
#include "lib9.h"#include "draw.h"#include "tk.h"#include "label.h" #define	O(t, e)		((long)(&((t*)0)->e)) /* Widget Commands (+ means implemented)	+cget	+configure	+invoke	+select	+deselect	+toggle */ enum {	/* other constants */	InvokePause	= 200,	/* delay showing button in down state when invoked */}; TkOption tkbutopts[] ={	"text",		OPTtext,	O(TkLabel, text),	nil,	"label",	OPTtext,	O(TkLabel, text),	nil,	"underline",	OPTdist,	O(TkLabel, ul),		nil,	"justify",	OPTstab,	O(TkLabel, justify),	tkjustify,	"anchor",	OPTflag,	O(TkLabel, anchor),	tkanchor,	"command",	OPTtext,	O(TkLabel, command),	nil,	"bitmap",	OPTbmap,	O(TkLabel, bitmap),	nil,	"image",	OPTimag,	O(TkLabel, img),	nil,	nil}; TkOption tkcbopts[] ={	"variable",	OPTtext,	O(TkLabel, variable),	nil,	"indicatoron",	OPTstab,	O(TkLabel, indicator),	tkbool,	"onvalue",	OPTtext,	O(TkLabel, value),	nil,	"offvalue",	OPTtext,	O(TkLabel, offvalue), nil,	nil,}; TkOption tkradopts[] ={	"variable",	OPTtext,	O(TkLabel, variable),	nil,	"value",	OPTtext,	O(TkLabel, value), nil,	"indicatoron",	OPTstab,	O(TkLabel, indicator),	tkbool,	nil,}; staticTkEbind bb[] ={	{TkEnter,	"%W configure -state active"},	{TkLeave,	"%W configure -state normal"},	{TkButton1P,	"%W tkButton1P"},	{TkButton1R,	"%W tkButton1R %x %y"},	{TkMotion|TkButton1P, 	"" },	{TkKey,	"%W tkButtonKey 0x%K"},}; staticTkEbind cb[] = {	{TkEnter,		"%W configure -state active"},	{TkLeave,		"%W configure -state normal"},	{TkButton1P,		"%W invoke"},	{TkMotion|TkButton1P, 	"" },	{TkKey,	"%W tkButtonKey 0x%K"},};  static char	tkselbut[] = "selectedButton"; static char*	newbutton(TkTop*, int, char*, char**);static int	istransparent(Tk*);static void tkvarchanged(Tk*, char*, char*); char*tkbutton(TkTop *t, char *arg, char **ret){	return newbutton(t, TKbutton, arg, ret);} char*tkcheckbutton(TkTop *t, char *arg, char **ret){	return newbutton(t, TKcheckbutton, arg, ret);} char*tkradiobutton(TkTop *t, char *arg, char **ret){	return newbutton(t, TKradiobutton, arg, ret);} static char*newbutton(TkTop *t, int btype, char *arg, char **ret){	Tk *tk;	char *e;	TkLabel *tkl;	TkName *names;	TkOptab tko[4];	TkVar *v; 	tk = tkmkbutton(t, btype);	if(tk == nil)		return TkNomem; 	tkl = TKobj(TkLabel, tk); 	tko[0].ptr = tk;	tko[0].optab = tkgeneric;	tko[1].ptr = tkl;	tko[1].optab = tkbutopts;	switch(btype){	case TKcheckbutton:		tko[2].ptr = tkl;		tko[2].optab = tkcbopts;		break;	case TKradiobutton:		tko[2].ptr = tkl;		tko[2].optab = tkradopts;		break;	default:		tk->relief = TKraised;		tk->borderwidth = 1;		tko[2].ptr = nil;		break;	}	tko[3].ptr = nil; 	names = nil;	e = tkparse(t, arg, tko, &names);	if(e != nil) {		tkfreeobj(tk);		return e;	} 	tksettransparent(tk, istransparent(tk));	tksizebutton(tk); 	e = tkaddchild(t, tk, &names);	tkfreename(names);	if(e != nil) {		tkfreeobj(tk);		return e;	}	tk->name->link = nil; 	if (btype == TKradiobutton &&			tkl->variable != nil &&			strcmp(tkl->variable, tkselbut) == 0 &&			tkl->value == nil &&			tk->name != nil)		tkl->value = strdup(tk->name->name); 	if (tkl->variable != nil) {		v = tkmkvar(t, tkl->variable, 0);		if (v == nil){			if(btype == TKcheckbutton){				e = tksetvar(t, tkl->variable, tkl->offvalue ? tkl->offvalue : "0");				if (e != nil)					goto err;			}		} else if(v->type != TkVstring){			e = TkNotvt;			goto err;		} else			tkvarchanged(tk, tkl->variable, v->value);	} 	return tkvalue(ret, "%s", tk->name->name); err:	tkfreeobj(tk);	return e;} Tk*tkmkbutton(TkTop *t, int btype){	Tk *tk;	TkLabel *tkl;	char *e; 	tk = tknewobj(t, btype, sizeof(Tk)+sizeof(TkLabel));	if (tk == nil)		return nil; 	e = nil;	tk->relief = TKraised;	tk->borderwidth = 0;	tk->highlightwidth = 1;	tk->flag |= Tktakefocus;	tkl = TKobj(TkLabel, tk);	tkl->ul = -1;	tkl->justify = Tkleft; 	switch (btype) {	case TKbutton:		e = tkbindings(t, tk, bb, nelem(bb));		break;	case TKcheckbutton:		e = tkbindings(t, tk, cb, nelem(cb));		break;	case TKradiobutton:		tkl->variable = strdup(tkselbut);		e = tkbindings(t, tk, cb, nelem(cb));		break;	} 	if (e != nil) {		print("tkmkbutton internal error: %s\n", e);		tkfreeobj(tk);		return nil;	}	return tk;} /* * draw TKbutton, TKcheckbutton, TKradiobutton */char*tkdrawbutton(Tk *tk, Point orig){ 	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;	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;		tkdrawstring(tk, i, addpt(u, p), tkl->text, tkl->ul, ct, tkl->justify);	} //	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;} voidtksizebutton(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;} inttkbuttonmargin(Tk *tk){	TkLabel *tkl;	tkl = TKobj(TkLabel, tk); 	switch (tk->type) {	case TKbutton:		if (tkl->img != nil || tkl->bitmap != nil)			return 0;		return Textpadx+tk->highlightwidth;	case TKcheckbutton:	case TKradiobutton:		return CheckButton + 2*CheckButtonBW + 2*ButtonBorder;	}	return tklabelmargin(tk);} voidtkfreebutton(Tk *tk){	tkfreelabel(tk);} static char*tkbuttoncget(Tk *tk, char *arg, char **val){	TkOptab tko[4];	TkLabel *tkl = TKobj(TkLabel, tk); 	tko[0].ptr = tk;	tko[0].optab = tkgeneric;	tko[1].ptr = tkl;	tko[1].optab = tkbutopts;	switch(tk->type){	case TKcheckbutton:		tko[2].ptr = tkl;		tko[2].optab = tkcbopts;		break;	case TKradiobutton:		tko[2].ptr = tkl;		tko[2].optab = tkradopts;		break;	default:		tko[2].ptr = nil;		break;	}	tko[3].ptr = nil;	return tkgencget(tko, arg, val, tk->env->top);} static char*tkbuttonconf(Tk *tk, char *arg, char **val){	char *e;	TkGeom g;	int bd;	TkOptab tko[4];	TkVar *v;	TkLabel *tkl = TKobj(TkLabel, tk); 	tko[0].ptr = tk;	tko[0].optab = tkgeneric;	tko[1].ptr = tkl;	tko[1].optab = tkbutopts;	switch(tk->type){	case TKcheckbutton:		tko[2].ptr = tkl;		tko[2].optab = tkcbopts;		break;	case TKradiobutton:		tko[2].ptr = tkl;		tko[2].optab = tkradopts;		break;	default:		tko[2].ptr = nil;		break;	}	tko[3].ptr = nil; 	if(*arg == '\0')		return tkconflist(tko, val); 	g = tk->req;	bd = tk->borderwidth;	e = tkparse(tk->env->top, arg, tko, nil);	tksizebutton(tk);	tkgeomchg(tk, &g, bd); 	tk->dirty = tkrect(tk, 1);	tksettransparent(tk, istransparent(tk));	/*	 * XXX what happens if we're now disabled, but we were in	 * active state before?

Lines 1–500 of 794.