forsyth20121205-174063a80cc13 years agoHistory
1065 lines · 19.1 KB · C
RawDownload
#include "lib9.h"#include "draw.h"#include "keyboard.h"#include "tk.h"#include "listb.h" #define	O(t, e)		((long)(&((t*)0)->e)) /* Layout constants */enum {	Listpadx	= 2,	/* X padding of text in listboxes */}; typedef struct TkLentry TkLentry;typedef struct TkListbox TkListbox; struct TkLentry{	TkLentry*	link;	int		flag;	int		width;	char		text[TKSTRUCTALIGN];}; struct TkListbox{	TkLentry*	head;	TkLentry*	anchor;	TkLentry*	active;	int		yelem;		/* Y element at top of box */	int		xdelta;		/* h-scroll position */	int		nitem;	int		nwidth;	int		selmode;	int		sborderwidth;	char*		xscroll;	char*		yscroll;}; TkStab tkselmode[] ={	"single",	TKsingle,	"browse",	TKbrowse,	"multiple",	TKmultiple,	"extended",	TKextended,	nil}; staticTkOption opts[] ={	"xscrollcommand",	OPTtext,	O(TkListbox, xscroll),	nil,	"yscrollcommand",	OPTtext,	O(TkListbox, yscroll),	nil,	"selectmode",		OPTstab,	O(TkListbox, selmode),	tkselmode,	"selectborderwidth",	OPTnndist,	O(TkListbox, sborderwidth),	nil,	nil}; staticTkEbind b[] = {	{TkButton1P,		"%W tkListbButton1P %y"},	{TkButton1R,	"%W tkListbButton1R"},	{TkButton1P|TkMotion,	"%W tkListbButton1MP %y"},	{TkMotion,		""},	{TkKey,	"%W tkListbKey 0x%K"},};  static intlineheight(Tk *tk){	TkListbox *l = TKobj(TkListbox, tk);	return tk->env->font->height+2*(l->sborderwidth+tk->highlightwidth);} char*tklistbox(TkTop *t, char *arg, char **ret){	Tk *tk;	char *e;	TkName *names;	TkListbox *tkl;	TkOptab tko[3]; 	tk = tknewobj(t, TKlistbox, sizeof(Tk)+sizeof(TkListbox));	if(tk == nil)		return TkNomem; 	tkl = TKobj(TkListbox, tk);	tkl->sborderwidth = 1;	tk->relief = TKsunken;	tk->borderwidth = 1;	tk->highlightwidth = 1;	tk->flag |= Tktakefocus;	tk->req.width = 170;	tk->req.height = lineheight(tk)*10; 	tko[0].ptr = tk;	tko[0].optab = tkgeneric;	tko[1].ptr = tkl;	tko[1].optab = opts;	tko[2].ptr = nil; 	names = nil;	e = tkparse(t, arg, tko, &names);	if(e != nil) {		tkfreeobj(tk);		return e;	}	tksettransparent(tk, tkhasalpha(tk->env, TkCbackgnd)); 	e = tkbindings(t, tk, b, nelem(b));	if(e != nil) {		tkfreeobj(tk);		return e;	} 	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);} char*tklistbcget(Tk *tk, char *arg, char **val){	TkOptab tko[3];	TkListbox *tkl = TKobj(TkListbox, tk); 	tko[0].ptr = tk;	tko[0].optab = tkgeneric;	tko[1].ptr = tkl;	tko[1].optab = opts;	tko[2].ptr = nil; 	return tkgencget(tko, arg, val, tk->env->top);} voidtkfreelistb(Tk *tk){	TkLentry *e, *next;	TkListbox *l = TKobj(TkListbox, tk); 	for(e = l->head; e; e = next) {		next = e->link;		free(e);	}	if(l->xscroll != nil)		free(l->xscroll);	if(l->yscroll != nil)		free(l->yscroll);} char*tkdrawlistb(Tk *tk, Point orig){	Point p;	TkEnv *env;	TkLentry *e;	int lh, w, n, ly;	Rectangle r, a;	Image *i, *fg;	TkListbox *l = TKobj(TkListbox, tk); 	env = tk->env; 	r.min = ZP;	r.max.x = tk->act.width + 2*tk->borderwidth;	r.max.y = tk->act.height + 2*tk->borderwidth;	i = tkitmp(env, r.max, TkCbackgnd);	if(i == nil)		return nil; 	w = tk->act.width;	if (w < l->nwidth)		w = l->nwidth;	lh = lineheight(tk);	ly = tk->borderwidth;	p.x = tk->borderwidth+l->sborderwidth+tk->highlightwidth+Listpadx-l->xdelta;	p.y = tk->borderwidth+l->sborderwidth+tk->highlightwidth;	n = 0;	for(e = l->head; e && ly < r.max.y; e = e->link) {		if(n++ < l->yelem)			continue; 		a.min.x = tk->borderwidth;		a.min.y = ly;		a.max.x = a.min.x + tk->act.width;		a.max.y = a.min.y + lh;		if(e->flag & Tkactivated) {			draw(i, a, tkgc(env, TkCselectbgnd), nil, ZP);		} 		if(e->flag & Tkactivated)			fg = tkgc(env, TkCselectfgnd);		else			fg = tkgc(env, TkCforegnd);		string(i, p, fg, p, env->font, e->text);		if((e->flag & Tkactive) && tkhaskeyfocus(tk)) {			a.min.x = tk->borderwidth-l->xdelta;			a.max.x = a.min.x+w;			a = insetrect(a, l->sborderwidth);			tkbox(i, a, tk->highlightwidth, fg);		}		ly += lh;		p.y += lh;	} 	tkdrawrelief(i, tk, ZP, TkCbackgnd, tk->relief); 	p.x = tk->act.x + orig.x;	p.y = tk->act.y + orig.y;	r = rectaddpt(r, p);	draw(tkimageof(tk), r, i, nil, ZP); 	return nil;} inttklindex(Tk *tk, char *buf){	int index;	TkListbox *l;	TkLentry *e, *s; 	l = TKobj(TkListbox, tk); 	if(*buf == '@') {		while(*buf && *buf != ',')			buf++;		index = l->yelem + atoi(buf+1)/lineheight(tk);		if (index < 0)			return 0;		if (index > l->nitem)			return l->nitem;		return index;	}	if(*buf >= '0' && *buf <= '9')		return atoi(buf); 	if(strcmp(buf, "end") == 0) {		if(l->nitem == 0)			return 0;		return l->nitem-1;	} 	index = 0;	if(strcmp(buf, "active") == 0)		s = l->active;	else	if(strcmp(buf, "anchor") == 0)		s = l->anchor;	else		return -1; 	for(e = l->head; e; e = e->link) {		if(e == s)			return index;		index++;	}	return -1;} voidtklistsv(Tk *tk){	TkListbox *l;	int nl, lh, top, bot;	char val[Tkminitem], cmd[Tkmaxitem], *v, *e; 	l = TKobj(TkListbox, tk);	if(l->yscroll == nil)		return; 	top = 0;	bot = TKI2F(1); 	if(l->nitem != 0) {		lh = lineheight(tk);		nl = tk->act.height/lh;			/* Lines in the box */		top = TKI2F(l->yelem)/l->nitem;		bot = TKI2F(l->yelem+nl)/l->nitem;	} 	v = tkfprint(val, top);	*v++ = ' ';	tkfprint(v, bot);	snprint(cmd, sizeof(cmd), "%s %s", l->yscroll, val);	e = tkexec(tk->env->top, cmd, nil);	if ((e != nil) && (tk->name != nil))		print("tk: yscrollcommand \"%s\": %s\n", tk->name->name, e);} voidtklistsh(Tk *tk){	int nl, top, bot;	char val[Tkminitem], cmd[Tkmaxitem], *v, *e;	TkListbox *l = TKobj(TkListbox, tk); 	if(l->xscroll == nil)		return; 	top = 0;	bot = TKI2F(1); 	if(l->nwidth != 0) {		nl = tk->act.width;		top = TKI2F(l->xdelta)/l->nwidth;		bot = TKI2F(l->xdelta+nl)/l->nwidth;	} 	v = tkfprint(val, top);	*v++ = ' ';	tkfprint(v, bot);	snprint(cmd, sizeof(cmd), "%s %s", l->xscroll, val);	e = tkexec(tk->env->top, cmd, nil);	if ((e != nil) && (tk->name != nil))		print("tk: xscrollcommand \"%s\": %s\n", tk->name->name, e);} voidtklistbgeom(Tk *tk){	tklistsv(tk);	tklistsh(tk);} static voidlistbresize(Tk *tk){	TkLentry *e;	TkListbox *l = TKobj(TkListbox, tk); 	l->nwidth = 0;	for (e = l->head; e != nil; e = e->link) {		e->width = stringwidth(tk->env->font, e->text)+2*(Listpadx+l->sborderwidth+tk->highlightwidth);		if(e->width > l->nwidth)			l->nwidth = e->width;	}	tklistbgeom(tk);}  /* Widget Commands (+ means implemented)	+activate	 bbox	+cget	+configure	+curselection	+delete	+get	+index	+insert	+nearest	+see	+selection	+size	+xview	+yview*/ char*tklistbconf(Tk *tk, char *arg, char **val){	char *e;	TkGeom g;	int bd, sbw, hlw;	TkOptab tko[3];	Font *f;	TkListbox *tkl = TKobj(TkListbox, tk); 	sbw = tkl->sborderwidth;	hlw = tk->highlightwidth;	f = tk->env->font;	tko[0].ptr = tk;	tko[0].optab = tkgeneric;	tko[1].ptr = tkl;	tko[1].optab = opts;	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);	tksettransparent(tk, tkhasalpha(tk->env, TkCbackgnd));	tkgeomchg(tk, &g, bd); 	if (sbw != tkl->sborderwidth || f != tk->env->font || hlw != tk->highlightwidth)		listbresize(tk);	tk->dirty = tkrect(tk, 1);	return e;} static voidentryactivate(Tk *tk, int index){	TkListbox *l = TKobj(TkListbox, tk);	TkLentry *e;	int flag = Tkactive; 	if (l->selmode == TKbrowse)		flag |= Tkactivated;	for(e = l->head; e; e = e->link) {		if(index-- == 0) {			e->flag |= flag;			l->active = e;		} else			e->flag &= ~flag;	}	tk->dirty = tkrect(tk, 1);} char*tklistbactivate(Tk *tk, char *arg, char **val){	int index;	char buf[Tkmaxitem]; 	USED(val);	tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);	index = tklindex(tk, buf);	if(index == -1)		return TkBadix; 	entryactivate(tk, index);	return nil;} char*tklistbnearest(Tk *tk, char *arg, char **val){	int lh, y, index;	TkListbox *l = TKobj(TkListbox, tk); 	lh = lineheight(tk);	/* Line height */	y = atoi(arg);	index = l->yelem + y/lh;	if(index > l->nitem)		index = l->nitem;	return tkvalue(val, "%d", index);} char*tklistbindex(Tk *tk, char *arg, char **val){	int index;	char buf[Tkmaxitem];	tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);	index = tklindex(tk, buf);	if(index == -1)		return TkBadix;	return tkvalue(val, "%d", index);} char*tklistbsize(Tk *tk, char *arg, char **val){	TkListbox *l = TKobj(TkListbox, tk); 	USED(arg);	return tkvalue(val, "%d", l->nitem);} char*tklistbinsert(Tk *tk, char *arg, char **val){	int n, index;	TkListbox *l;	TkLentry *e, **el;	char *tbuf, buf[Tkmaxitem]; 	USED(val);	l = TKobj(TkListbox, tk); 	arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);	if(strcmp(buf, "end") == 0) {		el = &l->head;		if(*el != nil) {			for(e = *el; e->link; e = e->link)				;			el = &e->link;		}	}	else {		index = tklindex(tk, buf);		if(index == -1)			return TkBadix;		el = &l->head;		for(e = *el; e && index-- > 0; e = e->link)			el = &e->link;

Lines 1–500 of 1065.