Charles.Forsyth20060303a828770d19 years agoHistory
609 lines · 11.0 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 = 2;		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;	if (btype == TKradiobutton)		tkl->variable = strdup(tkselbut); 	switch (btype) {	case TKbutton:		e = tkbindings(t, tk, bb, nelem(bb));		break;	case TKcheckbutton:	case TKradiobutton:		e = tkbindings(t, tk, cb, nelem(cb));		break;	} 	if (e != nil) {		print("tkmkbutton internal error: %s\n", e);		tkfreeobj(tk);		return nil;	}	return tk;} void tksizebutton(Tk *tk){	tksizelabel(tk);} /* shame that this is separated from the sizing and rendering code in label.c */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 0;} 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?	 */	if (tkl->variable != nil) {		v = tkmkvar(tk->env->top, tkl->variable, 0);		if (v != nil) {			if (v->type != TkVstring) {				e = TkNotvt;				free(tkl->variable);				tkl->variable = nil;			}			else				tkvarchanged(tk, tkl->variable, v->value);		}	}	return e;} static intistransparent(Tk *tk){	TkEnv *e = tk->env;	return (tkhasalpha(e, TkCbackgnd) || tkhasalpha(e, TkCselectbgnd) || tkhasalpha(e, TkCactivebgnd));} static voidtkvarchanged(Tk *tk, char *var, char *val){	TkLabel *tkl;	char *sval; 	tkl = TKobj(TkLabel, tk);	if (tkl->variable != nil && strcmp(tkl->variable, var) == 0) {		sval = tkl->value;		if (sval == nil)			sval = tk->type == TKcheckbutton ? "1" : "";		tkl->check = (strcmp(val, sval) == 0);		tk->dirty = tkrect(tk, 1);		tkdirty(tk);	}} static char*tkbutton1p(Tk *tk, char *arg, char **val){	USED(arg);	USED(val);	if(tk->flag & Tkdisabled)		return nil;	tk->flag |= Tkactivated;	tk->dirty = tkrect(tk, 1);	tkdirty(tk);	return nil;} static char*tkbutton1r(Tk *tk, char *arg, char **val){	char *e;	Point p;	Rectangle hitr; 	USED(arg); 	if(tk->flag & Tkdisabled)		return nil;	e = tkxyparse(tk, &arg, &p);	if (e == nil) {		hitr.min = ZP;		hitr.max.x = tk->act.width + tk->borderwidth*2;		hitr.max.y = tk->act.height + tk->borderwidth*2;		if(ptinrect(p, hitr) && (tk->flag & Tkactivated))			e = tkbuttoninvoke(tk, nil, val);	}	tk->flag &= ~Tkactivated;	tk->dirty = tkrect(tk, 1);	tkdirty(tk);	return e;} static char*tkbuttonkey(Tk *tk, char *arg, char **val){	int key; 	if(tk->flag & Tkdisabled)		return nil; 	key = atoi(arg);	if (key == '\n' || key ==' ')		return tkbuttoninvoke(tk, nil, val);	return nil;} static char*tkbuttontoggle(Tk *tk, char *arg, char **val){	char *e;	TkLabel *tkl = TKobj(TkLabel, tk);	char *v; 	USED(arg);	USED(val);	if(tk->flag & Tkdisabled)		return nil;	tkl->check = !tkl->check;	if (tkl->check)		v = tkl->value ? tkl->value : "1";	else		v = tkl->offvalue ? tkl->offvalue : "0";	e = tksetvar(tk->env->top, tkl->variable, v);	tk->dirty = tkrect(tk, 0);	return e;} static char*buttoninvoke(Tk *tk, char **val){	char *e = nil;	TkTop *top;	TkLabel *tkl = TKobj(TkLabel, tk); 	top = tk->env->top;	if (tk->type == TKcheckbutton)		e = tkbuttontoggle(tk, "", val);	else if (tk->type == TKradiobutton)		e = tksetvar(top, tkl->variable, tkl->value);	if(e != nil)		return e;	if(tkl->command != nil)		return tkexec(tk->env->top, tkl->command, val);	return nil;} static voidcancelinvoke(Tk *tk, void *v, int cancelled){	int unset;	USED(cancelled);	USED(v); 	/* if it was active before then leave it active unless cleared since */	if (v)		unset = 0;	else		unset = Tkactive;	unset &= (tk->flag & Tkactive);	unset |= Tkactivated;	tk->flag &= ~unset;	tksettransparent(tk, istransparent(tk));	tk->dirty = tkrect(tk, 1);	tkdirty(tk);	tkupdate(tk->env->top);} char*tkbuttoninvoke(Tk *tk, char *arg, char **val){	char *e;	USED(arg); 	if(tk->flag & Tkdisabled)		return nil;	e = buttoninvoke(tk, val);	if (e == nil && tk->type == TKbutton && !(tk->flag & Tkactivated)) {		tkrepeat(tk, cancelinvoke, (void*)(tk->flag&Tkactive), InvokePause, 0);		tk->flag |= Tkactivated | Tkactive;		tksettransparent(tk, istransparent(tk));		tk->dirty = tkrect(tk, 1);		tkdirty(tk);		tkupdate(tk->env->top);	}	return e;} static char*tkbuttonselect(Tk *tk, char *arg, char **val){	char *e, *v;	TkLabel *tkl = TKobj(TkLabel, tk); 	USED(arg);	USED(val);	if (tk->type == TKradiobutton)		v = tkl->value;	else if (tk->type == TKcheckbutton) {		v = tkl->value ? tkl->value : "1";

Lines 1–500 of 609.