xref: /inferno-os/libtk/listb.c (revision 48c2bcd8842a77d6fca4a18505e622e9a9d3d38b)
137da2899SCharles.Forsyth #include "lib9.h"
237da2899SCharles.Forsyth #include "draw.h"
337da2899SCharles.Forsyth #include "keyboard.h"
437da2899SCharles.Forsyth #include "tk.h"
537da2899SCharles.Forsyth #include "listb.h"
637da2899SCharles.Forsyth 
737da2899SCharles.Forsyth #define	O(t, e)		((long)(&((t*)0)->e))
837da2899SCharles.Forsyth 
937da2899SCharles.Forsyth /* Layout constants */
1037da2899SCharles.Forsyth enum {
1137da2899SCharles.Forsyth 	Listpadx	= 2,	/* X padding of text in listboxes */
1237da2899SCharles.Forsyth };
1337da2899SCharles.Forsyth 
1437da2899SCharles.Forsyth typedef struct TkLentry TkLentry;
1537da2899SCharles.Forsyth typedef struct TkListbox TkListbox;
1637da2899SCharles.Forsyth 
1737da2899SCharles.Forsyth struct TkLentry
1837da2899SCharles.Forsyth {
1937da2899SCharles.Forsyth 	TkLentry*	link;
2037da2899SCharles.Forsyth 	int		flag;
2137da2899SCharles.Forsyth 	int		width;
2237da2899SCharles.Forsyth 	char		text[TKSTRUCTALIGN];
2337da2899SCharles.Forsyth };
2437da2899SCharles.Forsyth 
2537da2899SCharles.Forsyth struct TkListbox
2637da2899SCharles.Forsyth {
2737da2899SCharles.Forsyth 	TkLentry*	head;
2837da2899SCharles.Forsyth 	TkLentry*	anchor;
2937da2899SCharles.Forsyth 	TkLentry*	active;
3037da2899SCharles.Forsyth 	int		yelem;		/* Y element at top of box */
3137da2899SCharles.Forsyth 	int		xdelta;		/* h-scroll position */
3237da2899SCharles.Forsyth 	int		nitem;
3337da2899SCharles.Forsyth 	int		nwidth;
3437da2899SCharles.Forsyth 	int		selmode;
3537da2899SCharles.Forsyth 	int		sborderwidth;
3637da2899SCharles.Forsyth 	char*		xscroll;
3737da2899SCharles.Forsyth 	char*		yscroll;
3837da2899SCharles.Forsyth };
3937da2899SCharles.Forsyth 
4037da2899SCharles.Forsyth TkStab tkselmode[] =
4137da2899SCharles.Forsyth {
4237da2899SCharles.Forsyth 	"single",	TKsingle,
4337da2899SCharles.Forsyth 	"browse",	TKbrowse,
4437da2899SCharles.Forsyth 	"multiple",	TKmultiple,
4537da2899SCharles.Forsyth 	"extended",	TKextended,
4637da2899SCharles.Forsyth 	nil
4737da2899SCharles.Forsyth };
4837da2899SCharles.Forsyth 
4937da2899SCharles.Forsyth static
5037da2899SCharles.Forsyth TkOption opts[] =
5137da2899SCharles.Forsyth {
5237da2899SCharles.Forsyth 	"xscrollcommand",	OPTtext,	O(TkListbox, xscroll),	nil,
5337da2899SCharles.Forsyth 	"yscrollcommand",	OPTtext,	O(TkListbox, yscroll),	nil,
5437da2899SCharles.Forsyth 	"selectmode",		OPTstab,	O(TkListbox, selmode),	tkselmode,
5537da2899SCharles.Forsyth 	"selectborderwidth",	OPTnndist,	O(TkListbox, sborderwidth),	nil,
5637da2899SCharles.Forsyth 	nil
5737da2899SCharles.Forsyth };
5837da2899SCharles.Forsyth 
5937da2899SCharles.Forsyth static
6037da2899SCharles.Forsyth TkEbind b[] =
6137da2899SCharles.Forsyth {
6237da2899SCharles.Forsyth 	{TkButton1P,		"%W tkListbButton1P %y"},
6337da2899SCharles.Forsyth 	{TkButton1R,	"%W tkListbButton1R"},
6437da2899SCharles.Forsyth 	{TkButton1P|TkMotion,	"%W tkListbButton1MP %y"},
6537da2899SCharles.Forsyth 	{TkMotion,		""},
6637da2899SCharles.Forsyth 	{TkKey,	"%W tkListbKey 0x%K"},
6737da2899SCharles.Forsyth };
6837da2899SCharles.Forsyth 
6937da2899SCharles.Forsyth 
7037da2899SCharles.Forsyth static int
lineheight(Tk * tk)7137da2899SCharles.Forsyth lineheight(Tk *tk)
7237da2899SCharles.Forsyth {
7337da2899SCharles.Forsyth 	TkListbox *l = TKobj(TkListbox, tk);
7437da2899SCharles.Forsyth 	return tk->env->font->height+2*(l->sborderwidth+tk->highlightwidth);
7537da2899SCharles.Forsyth }
7637da2899SCharles.Forsyth 
7737da2899SCharles.Forsyth char*
tklistbox(TkTop * t,char * arg,char ** ret)7837da2899SCharles.Forsyth tklistbox(TkTop *t, char *arg, char **ret)
7937da2899SCharles.Forsyth {
8037da2899SCharles.Forsyth 	Tk *tk;
8137da2899SCharles.Forsyth 	char *e;
8237da2899SCharles.Forsyth 	TkName *names;
8337da2899SCharles.Forsyth 	TkListbox *tkl;
8437da2899SCharles.Forsyth 	TkOptab tko[3];
8537da2899SCharles.Forsyth 
8637da2899SCharles.Forsyth 	tk = tknewobj(t, TKlistbox, sizeof(Tk)+sizeof(TkListbox));
8737da2899SCharles.Forsyth 	if(tk == nil)
8837da2899SCharles.Forsyth 		return TkNomem;
8937da2899SCharles.Forsyth 
9037da2899SCharles.Forsyth 	tkl = TKobj(TkListbox, tk);
9137da2899SCharles.Forsyth 	tkl->sborderwidth = 1;
9237da2899SCharles.Forsyth 	tk->relief = TKsunken;
93c9ccdbd5Sforsyth 	tk->borderwidth = 1;
9437da2899SCharles.Forsyth 	tk->highlightwidth = 1;
9537da2899SCharles.Forsyth 	tk->flag |= Tktakefocus;
9637da2899SCharles.Forsyth 	tk->req.width = 170;
9737da2899SCharles.Forsyth 	tk->req.height = lineheight(tk)*10;
9837da2899SCharles.Forsyth 
9937da2899SCharles.Forsyth 	tko[0].ptr = tk;
10037da2899SCharles.Forsyth 	tko[0].optab = tkgeneric;
10137da2899SCharles.Forsyth 	tko[1].ptr = tkl;
10237da2899SCharles.Forsyth 	tko[1].optab = opts;
10337da2899SCharles.Forsyth 	tko[2].ptr = nil;
10437da2899SCharles.Forsyth 
10537da2899SCharles.Forsyth 	names = nil;
10637da2899SCharles.Forsyth 	e = tkparse(t, arg, tko, &names);
10737da2899SCharles.Forsyth 	if(e != nil) {
10837da2899SCharles.Forsyth 		tkfreeobj(tk);
10937da2899SCharles.Forsyth 		return e;
11037da2899SCharles.Forsyth 	}
11137da2899SCharles.Forsyth 	tksettransparent(tk, tkhasalpha(tk->env, TkCbackgnd));
11237da2899SCharles.Forsyth 
11337da2899SCharles.Forsyth 	e = tkbindings(t, tk, b, nelem(b));
11437da2899SCharles.Forsyth 	if(e != nil) {
11537da2899SCharles.Forsyth 		tkfreeobj(tk);
11637da2899SCharles.Forsyth 		return e;
11737da2899SCharles.Forsyth 	}
11837da2899SCharles.Forsyth 
11937da2899SCharles.Forsyth 	e = tkaddchild(t, tk, &names);
12037da2899SCharles.Forsyth 	tkfreename(names);
12137da2899SCharles.Forsyth 	if(e != nil) {
12237da2899SCharles.Forsyth 		tkfreeobj(tk);
12337da2899SCharles.Forsyth 		return e;
12437da2899SCharles.Forsyth 	}
12537da2899SCharles.Forsyth 	tk->name->link = nil;
12637da2899SCharles.Forsyth 
12737da2899SCharles.Forsyth 	return tkvalue(ret, "%s", tk->name->name);
12837da2899SCharles.Forsyth }
12937da2899SCharles.Forsyth 
13037da2899SCharles.Forsyth char*
tklistbcget(Tk * tk,char * arg,char ** val)13137da2899SCharles.Forsyth tklistbcget(Tk *tk, char *arg, char **val)
13237da2899SCharles.Forsyth {
13337da2899SCharles.Forsyth 	TkOptab tko[3];
13437da2899SCharles.Forsyth 	TkListbox *tkl = TKobj(TkListbox, tk);
13537da2899SCharles.Forsyth 
13637da2899SCharles.Forsyth 	tko[0].ptr = tk;
13737da2899SCharles.Forsyth 	tko[0].optab = tkgeneric;
13837da2899SCharles.Forsyth 	tko[1].ptr = tkl;
13937da2899SCharles.Forsyth 	tko[1].optab = opts;
14037da2899SCharles.Forsyth 	tko[2].ptr = nil;
14137da2899SCharles.Forsyth 
14237da2899SCharles.Forsyth 	return tkgencget(tko, arg, val, tk->env->top);
14337da2899SCharles.Forsyth }
14437da2899SCharles.Forsyth 
14537da2899SCharles.Forsyth void
tkfreelistb(Tk * tk)14637da2899SCharles.Forsyth tkfreelistb(Tk *tk)
14737da2899SCharles.Forsyth {
14837da2899SCharles.Forsyth 	TkLentry *e, *next;
14937da2899SCharles.Forsyth 	TkListbox *l = TKobj(TkListbox, tk);
15037da2899SCharles.Forsyth 
15137da2899SCharles.Forsyth 	for(e = l->head; e; e = next) {
15237da2899SCharles.Forsyth 		next = e->link;
15337da2899SCharles.Forsyth 		free(e);
15437da2899SCharles.Forsyth 	}
15537da2899SCharles.Forsyth 	if(l->xscroll != nil)
15637da2899SCharles.Forsyth 		free(l->xscroll);
15737da2899SCharles.Forsyth 	if(l->yscroll != nil)
15837da2899SCharles.Forsyth 		free(l->yscroll);
15937da2899SCharles.Forsyth }
16037da2899SCharles.Forsyth 
16137da2899SCharles.Forsyth char*
tkdrawlistb(Tk * tk,Point orig)16237da2899SCharles.Forsyth tkdrawlistb(Tk *tk, Point orig)
16337da2899SCharles.Forsyth {
16437da2899SCharles.Forsyth 	Point p;
16537da2899SCharles.Forsyth 	TkEnv *env;
16637da2899SCharles.Forsyth 	TkLentry *e;
16737da2899SCharles.Forsyth 	int lh, w, n, ly;
16837da2899SCharles.Forsyth 	Rectangle r, a;
16937da2899SCharles.Forsyth 	Image *i, *fg;
17037da2899SCharles.Forsyth 	TkListbox *l = TKobj(TkListbox, tk);
17137da2899SCharles.Forsyth 
17237da2899SCharles.Forsyth 	env = tk->env;
17337da2899SCharles.Forsyth 
17437da2899SCharles.Forsyth 	r.min = ZP;
17537da2899SCharles.Forsyth 	r.max.x = tk->act.width + 2*tk->borderwidth;
17637da2899SCharles.Forsyth 	r.max.y = tk->act.height + 2*tk->borderwidth;
17737da2899SCharles.Forsyth 	i = tkitmp(env, r.max, TkCbackgnd);
17837da2899SCharles.Forsyth 	if(i == nil)
17937da2899SCharles.Forsyth 		return nil;
18037da2899SCharles.Forsyth 
18137da2899SCharles.Forsyth 	w = tk->act.width;
18237da2899SCharles.Forsyth 	if (w < l->nwidth)
18337da2899SCharles.Forsyth 		w = l->nwidth;
18437da2899SCharles.Forsyth 	lh = lineheight(tk);
18537da2899SCharles.Forsyth 	ly = tk->borderwidth;
18637da2899SCharles.Forsyth 	p.x = tk->borderwidth+l->sborderwidth+tk->highlightwidth+Listpadx-l->xdelta;
18737da2899SCharles.Forsyth 	p.y = tk->borderwidth+l->sborderwidth+tk->highlightwidth;
18837da2899SCharles.Forsyth 	n = 0;
18937da2899SCharles.Forsyth 	for(e = l->head; e && ly < r.max.y; e = e->link) {
19037da2899SCharles.Forsyth 		if(n++ < l->yelem)
19137da2899SCharles.Forsyth 			continue;
19237da2899SCharles.Forsyth 
19337da2899SCharles.Forsyth 		a.min.x = tk->borderwidth;
19437da2899SCharles.Forsyth 		a.min.y = ly;
19537da2899SCharles.Forsyth 		a.max.x = a.min.x + tk->act.width;
19637da2899SCharles.Forsyth 		a.max.y = a.min.y + lh;
19737da2899SCharles.Forsyth 		if(e->flag & Tkactivated) {
19837da2899SCharles.Forsyth 			draw(i, a, tkgc(env, TkCselectbgnd), nil, ZP);
19937da2899SCharles.Forsyth 		}
20037da2899SCharles.Forsyth 
20137da2899SCharles.Forsyth 		if(e->flag & Tkactivated)
20237da2899SCharles.Forsyth 			fg = tkgc(env, TkCselectfgnd);
20337da2899SCharles.Forsyth 		else
20437da2899SCharles.Forsyth 			fg = tkgc(env, TkCforegnd);
20537da2899SCharles.Forsyth 		string(i, p, fg, p, env->font, e->text);
20637da2899SCharles.Forsyth 		if((e->flag & Tkactive) && tkhaskeyfocus(tk)) {
20737da2899SCharles.Forsyth 			a.min.x = tk->borderwidth-l->xdelta;
20837da2899SCharles.Forsyth 			a.max.x = a.min.x+w;
20937da2899SCharles.Forsyth 			a = insetrect(a, l->sborderwidth);
21037da2899SCharles.Forsyth 			tkbox(i, a, tk->highlightwidth, fg);
21137da2899SCharles.Forsyth 		}
21237da2899SCharles.Forsyth 		ly += lh;
21337da2899SCharles.Forsyth 		p.y += lh;
21437da2899SCharles.Forsyth 	}
21537da2899SCharles.Forsyth 
21637da2899SCharles.Forsyth 	tkdrawrelief(i, tk, ZP, TkCbackgnd, tk->relief);
21737da2899SCharles.Forsyth 
21837da2899SCharles.Forsyth 	p.x = tk->act.x + orig.x;
21937da2899SCharles.Forsyth 	p.y = tk->act.y + orig.y;
22037da2899SCharles.Forsyth 	r = rectaddpt(r, p);
22137da2899SCharles.Forsyth 	draw(tkimageof(tk), r, i, nil, ZP);
22237da2899SCharles.Forsyth 
22337da2899SCharles.Forsyth 	return nil;
22437da2899SCharles.Forsyth }
22537da2899SCharles.Forsyth 
22637da2899SCharles.Forsyth int
tklindex(Tk * tk,char * buf)22737da2899SCharles.Forsyth tklindex(Tk *tk, char *buf)
22837da2899SCharles.Forsyth {
22937da2899SCharles.Forsyth 	int index;
23037da2899SCharles.Forsyth 	TkListbox *l;
23137da2899SCharles.Forsyth 	TkLentry *e, *s;
23237da2899SCharles.Forsyth 
23337da2899SCharles.Forsyth 	l = TKobj(TkListbox, tk);
23437da2899SCharles.Forsyth 
23537da2899SCharles.Forsyth 	if(*buf == '@') {
23637da2899SCharles.Forsyth 		while(*buf && *buf != ',')
23737da2899SCharles.Forsyth 			buf++;
23837da2899SCharles.Forsyth 		index = l->yelem + atoi(buf+1)/lineheight(tk);
23937da2899SCharles.Forsyth 		if (index < 0)
24037da2899SCharles.Forsyth 			return 0;
24137da2899SCharles.Forsyth 		if (index > l->nitem)
24237da2899SCharles.Forsyth 			return l->nitem;
24337da2899SCharles.Forsyth 		return index;
24437da2899SCharles.Forsyth 	}
24537da2899SCharles.Forsyth 	if(*buf >= '0' && *buf <= '9')
24637da2899SCharles.Forsyth 		return atoi(buf);
24737da2899SCharles.Forsyth 
24837da2899SCharles.Forsyth 	if(strcmp(buf, "end") == 0) {
24937da2899SCharles.Forsyth 		if(l->nitem == 0)
25037da2899SCharles.Forsyth 			return 0;
25137da2899SCharles.Forsyth 		return l->nitem-1;
25237da2899SCharles.Forsyth 	}
25337da2899SCharles.Forsyth 
25437da2899SCharles.Forsyth 	index = 0;
25537da2899SCharles.Forsyth 	if(strcmp(buf, "active") == 0)
25637da2899SCharles.Forsyth 		s = l->active;
25737da2899SCharles.Forsyth 	else
25837da2899SCharles.Forsyth 	if(strcmp(buf, "anchor") == 0)
25937da2899SCharles.Forsyth 		s = l->anchor;
26037da2899SCharles.Forsyth 	else
26137da2899SCharles.Forsyth 		return -1;
26237da2899SCharles.Forsyth 
26337da2899SCharles.Forsyth 	for(e = l->head; e; e = e->link) {
26437da2899SCharles.Forsyth 		if(e == s)
26537da2899SCharles.Forsyth 			return index;
26637da2899SCharles.Forsyth 		index++;
26737da2899SCharles.Forsyth 	}
26837da2899SCharles.Forsyth 	return -1;
26937da2899SCharles.Forsyth }
27037da2899SCharles.Forsyth 
27137da2899SCharles.Forsyth void
tklistsv(Tk * tk)27237da2899SCharles.Forsyth tklistsv(Tk *tk)
27337da2899SCharles.Forsyth {
27437da2899SCharles.Forsyth 	TkListbox *l;
27537da2899SCharles.Forsyth 	int nl, lh, top, bot;
27637da2899SCharles.Forsyth 	char val[Tkminitem], cmd[Tkmaxitem], *v, *e;
27737da2899SCharles.Forsyth 
27837da2899SCharles.Forsyth 	l = TKobj(TkListbox, tk);
27937da2899SCharles.Forsyth 	if(l->yscroll == nil)
28037da2899SCharles.Forsyth 		return;
28137da2899SCharles.Forsyth 
28237da2899SCharles.Forsyth 	top = 0;
28337da2899SCharles.Forsyth 	bot = TKI2F(1);
28437da2899SCharles.Forsyth 
28537da2899SCharles.Forsyth 	if(l->nitem != 0) {
28637da2899SCharles.Forsyth 		lh = lineheight(tk);
28737da2899SCharles.Forsyth 		nl = tk->act.height/lh;			/* Lines in the box */
28837da2899SCharles.Forsyth 		top = TKI2F(l->yelem)/l->nitem;
28937da2899SCharles.Forsyth 		bot = TKI2F(l->yelem+nl)/l->nitem;
29037da2899SCharles.Forsyth 	}
29137da2899SCharles.Forsyth 
29237da2899SCharles.Forsyth 	v = tkfprint(val, top);
29337da2899SCharles.Forsyth 	*v++ = ' ';
29437da2899SCharles.Forsyth 	tkfprint(v, bot);
29537da2899SCharles.Forsyth 	snprint(cmd, sizeof(cmd), "%s %s", l->yscroll, val);
29637da2899SCharles.Forsyth 	e = tkexec(tk->env->top, cmd, nil);
29737da2899SCharles.Forsyth 	if ((e != nil) && (tk->name != nil))
29837da2899SCharles.Forsyth 		print("tk: yscrollcommand \"%s\": %s\n", tk->name->name, e);
29937da2899SCharles.Forsyth }
30037da2899SCharles.Forsyth 
30137da2899SCharles.Forsyth void
tklistsh(Tk * tk)30237da2899SCharles.Forsyth tklistsh(Tk *tk)
30337da2899SCharles.Forsyth {
30437da2899SCharles.Forsyth 	int nl, top, bot;
30537da2899SCharles.Forsyth 	char val[Tkminitem], cmd[Tkmaxitem], *v, *e;
30637da2899SCharles.Forsyth 	TkListbox *l = TKobj(TkListbox, tk);
30737da2899SCharles.Forsyth 
30837da2899SCharles.Forsyth 	if(l->xscroll == nil)
30937da2899SCharles.Forsyth 		return;
31037da2899SCharles.Forsyth 
31137da2899SCharles.Forsyth 	top = 0;
31237da2899SCharles.Forsyth 	bot = TKI2F(1);
31337da2899SCharles.Forsyth 
31437da2899SCharles.Forsyth 	if(l->nwidth != 0) {
31537da2899SCharles.Forsyth 		nl = tk->act.width;
31637da2899SCharles.Forsyth 		top = TKI2F(l->xdelta)/l->nwidth;
31737da2899SCharles.Forsyth 		bot = TKI2F(l->xdelta+nl)/l->nwidth;
31837da2899SCharles.Forsyth 	}
31937da2899SCharles.Forsyth 
32037da2899SCharles.Forsyth 	v = tkfprint(val, top);
32137da2899SCharles.Forsyth 	*v++ = ' ';
32237da2899SCharles.Forsyth 	tkfprint(v, bot);
32337da2899SCharles.Forsyth 	snprint(cmd, sizeof(cmd), "%s %s", l->xscroll, val);
32437da2899SCharles.Forsyth 	e = tkexec(tk->env->top, cmd, nil);
32537da2899SCharles.Forsyth 	if ((e != nil) && (tk->name != nil))
32637da2899SCharles.Forsyth 		print("tk: xscrollcommand \"%s\": %s\n", tk->name->name, e);
32737da2899SCharles.Forsyth }
32837da2899SCharles.Forsyth 
32937da2899SCharles.Forsyth void
tklistbgeom(Tk * tk)33037da2899SCharles.Forsyth tklistbgeom(Tk *tk)
33137da2899SCharles.Forsyth {
33237da2899SCharles.Forsyth 	tklistsv(tk);
33337da2899SCharles.Forsyth 	tklistsh(tk);
33437da2899SCharles.Forsyth }
33537da2899SCharles.Forsyth 
33637da2899SCharles.Forsyth static void
listbresize(Tk * tk)33737da2899SCharles.Forsyth listbresize(Tk *tk)
33837da2899SCharles.Forsyth {
33937da2899SCharles.Forsyth 	TkLentry *e;
34037da2899SCharles.Forsyth 	TkListbox *l = TKobj(TkListbox, tk);
34137da2899SCharles.Forsyth 
34237da2899SCharles.Forsyth 	l->nwidth = 0;
34337da2899SCharles.Forsyth 	for (e = l->head; e != nil; e = e->link) {
34437da2899SCharles.Forsyth 		e->width = stringwidth(tk->env->font, e->text)+2*(Listpadx+l->sborderwidth+tk->highlightwidth);
34537da2899SCharles.Forsyth 		if(e->width > l->nwidth)
34637da2899SCharles.Forsyth 			l->nwidth = e->width;
34737da2899SCharles.Forsyth 	}
34837da2899SCharles.Forsyth 	tklistbgeom(tk);
34937da2899SCharles.Forsyth }
35037da2899SCharles.Forsyth 
35137da2899SCharles.Forsyth 
35237da2899SCharles.Forsyth /* Widget Commands (+ means implemented)
35337da2899SCharles.Forsyth 	+activate
35437da2899SCharles.Forsyth 	 bbox
35537da2899SCharles.Forsyth 	+cget
35637da2899SCharles.Forsyth 	+configure
35737da2899SCharles.Forsyth 	+curselection
35837da2899SCharles.Forsyth 	+delete
35937da2899SCharles.Forsyth 	+get
36037da2899SCharles.Forsyth 	+index
36137da2899SCharles.Forsyth 	+insert
36237da2899SCharles.Forsyth 	+nearest
36337da2899SCharles.Forsyth 	+see
36437da2899SCharles.Forsyth 	+selection
36537da2899SCharles.Forsyth 	+size
36637da2899SCharles.Forsyth 	+xview
36737da2899SCharles.Forsyth 	+yview
36837da2899SCharles.Forsyth */
36937da2899SCharles.Forsyth 
37037da2899SCharles.Forsyth char*
tklistbconf(Tk * tk,char * arg,char ** val)37137da2899SCharles.Forsyth tklistbconf(Tk *tk, char *arg, char **val)
37237da2899SCharles.Forsyth {
37337da2899SCharles.Forsyth 	char *e;
37437da2899SCharles.Forsyth 	TkGeom g;
37537da2899SCharles.Forsyth 	int bd, sbw, hlw;
37637da2899SCharles.Forsyth 	TkOptab tko[3];
37737da2899SCharles.Forsyth 	Font *f;
37837da2899SCharles.Forsyth 	TkListbox *tkl = TKobj(TkListbox, tk);
37937da2899SCharles.Forsyth 
38037da2899SCharles.Forsyth 	sbw = tkl->sborderwidth;
38137da2899SCharles.Forsyth 	hlw = tk->highlightwidth;
38237da2899SCharles.Forsyth 	f = tk->env->font;
38337da2899SCharles.Forsyth 	tko[0].ptr = tk;
38437da2899SCharles.Forsyth 	tko[0].optab = tkgeneric;
38537da2899SCharles.Forsyth 	tko[1].ptr = tkl;
38637da2899SCharles.Forsyth 	tko[1].optab = opts;
38737da2899SCharles.Forsyth 	tko[2].ptr = nil;
38837da2899SCharles.Forsyth 
38937da2899SCharles.Forsyth 	if(*arg == '\0')
39037da2899SCharles.Forsyth 		return tkconflist(tko, val);
39137da2899SCharles.Forsyth 
39237da2899SCharles.Forsyth 	g = tk->req;
39337da2899SCharles.Forsyth 	bd = tk->borderwidth;
39437da2899SCharles.Forsyth 	e = tkparse(tk->env->top, arg, tko, nil);
39537da2899SCharles.Forsyth 	tksettransparent(tk, tkhasalpha(tk->env, TkCbackgnd));
39637da2899SCharles.Forsyth 	tkgeomchg(tk, &g, bd);
39737da2899SCharles.Forsyth 
39837da2899SCharles.Forsyth 	if (sbw != tkl->sborderwidth || f != tk->env->font || hlw != tk->highlightwidth)
39937da2899SCharles.Forsyth 		listbresize(tk);
40037da2899SCharles.Forsyth 	tk->dirty = tkrect(tk, 1);
40137da2899SCharles.Forsyth 	return e;
40237da2899SCharles.Forsyth }
40337da2899SCharles.Forsyth 
40437da2899SCharles.Forsyth static void
entryactivate(Tk * tk,int index)40537da2899SCharles.Forsyth entryactivate(Tk *tk, int index)
40637da2899SCharles.Forsyth {
40737da2899SCharles.Forsyth 	TkListbox *l = TKobj(TkListbox, tk);
40837da2899SCharles.Forsyth 	TkLentry *e;
40937da2899SCharles.Forsyth 	int flag = Tkactive;
41037da2899SCharles.Forsyth 
41137da2899SCharles.Forsyth 	if (l->selmode == TKbrowse)
41237da2899SCharles.Forsyth 		flag |= Tkactivated;
41337da2899SCharles.Forsyth 	for(e = l->head; e; e = e->link) {
41437da2899SCharles.Forsyth 		if(index-- == 0) {
41537da2899SCharles.Forsyth 			e->flag |= flag;
41637da2899SCharles.Forsyth 			l->active = e;
41737da2899SCharles.Forsyth 		} else
41837da2899SCharles.Forsyth 			e->flag &= ~flag;
41937da2899SCharles.Forsyth 	}
42037da2899SCharles.Forsyth 	tk->dirty = tkrect(tk, 1);
42137da2899SCharles.Forsyth }
42237da2899SCharles.Forsyth 
42337da2899SCharles.Forsyth char*
tklistbactivate(Tk * tk,char * arg,char ** val)42437da2899SCharles.Forsyth tklistbactivate(Tk *tk, char *arg, char **val)
42537da2899SCharles.Forsyth {
42637da2899SCharles.Forsyth 	int index;
42737da2899SCharles.Forsyth 	char buf[Tkmaxitem];
42837da2899SCharles.Forsyth 
42937da2899SCharles.Forsyth 	USED(val);
43037da2899SCharles.Forsyth 	tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
43137da2899SCharles.Forsyth 	index = tklindex(tk, buf);
43237da2899SCharles.Forsyth 	if(index == -1)
43337da2899SCharles.Forsyth 		return TkBadix;
43437da2899SCharles.Forsyth 
43537da2899SCharles.Forsyth 	entryactivate(tk, index);
43637da2899SCharles.Forsyth 	return nil;
43737da2899SCharles.Forsyth }
43837da2899SCharles.Forsyth 
43937da2899SCharles.Forsyth char*
tklistbnearest(Tk * tk,char * arg,char ** val)44037da2899SCharles.Forsyth tklistbnearest(Tk *tk, char *arg, char **val)
44137da2899SCharles.Forsyth {
44237da2899SCharles.Forsyth 	int lh, y, index;
44337da2899SCharles.Forsyth 	TkListbox *l = TKobj(TkListbox, tk);
44437da2899SCharles.Forsyth 
44537da2899SCharles.Forsyth 	lh = lineheight(tk);	/* Line height */
44637da2899SCharles.Forsyth 	y = atoi(arg);
44737da2899SCharles.Forsyth 	index = l->yelem + y/lh;
44837da2899SCharles.Forsyth 	if(index > l->nitem)
44937da2899SCharles.Forsyth 		index = l->nitem;
45037da2899SCharles.Forsyth 	return tkvalue(val, "%d", index);
45137da2899SCharles.Forsyth }
45237da2899SCharles.Forsyth 
45337da2899SCharles.Forsyth char*
tklistbindex(Tk * tk,char * arg,char ** val)45437da2899SCharles.Forsyth tklistbindex(Tk *tk, char *arg, char **val)
45537da2899SCharles.Forsyth {
45637da2899SCharles.Forsyth 	int index;
45737da2899SCharles.Forsyth 	char buf[Tkmaxitem];
45837da2899SCharles.Forsyth 	tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
45937da2899SCharles.Forsyth 	index = tklindex(tk, buf);
46037da2899SCharles.Forsyth 	if(index == -1)
46137da2899SCharles.Forsyth 		return TkBadix;
46237da2899SCharles.Forsyth 	return tkvalue(val, "%d", index);
46337da2899SCharles.Forsyth }
46437da2899SCharles.Forsyth 
46537da2899SCharles.Forsyth char*
tklistbsize(Tk * tk,char * arg,char ** val)46637da2899SCharles.Forsyth tklistbsize(Tk *tk, char *arg, char **val)
46737da2899SCharles.Forsyth {
46837da2899SCharles.Forsyth 	TkListbox *l = TKobj(TkListbox, tk);
46937da2899SCharles.Forsyth 
47037da2899SCharles.Forsyth 	USED(arg);
47137da2899SCharles.Forsyth 	return tkvalue(val, "%d", l->nitem);
47237da2899SCharles.Forsyth }
47337da2899SCharles.Forsyth 
47437da2899SCharles.Forsyth char*
tklistbinsert(Tk * tk,char * arg,char ** val)47537da2899SCharles.Forsyth tklistbinsert(Tk *tk, char *arg, char **val)
47637da2899SCharles.Forsyth {
47737da2899SCharles.Forsyth 	int n, index;
47837da2899SCharles.Forsyth 	TkListbox *l;
47937da2899SCharles.Forsyth 	TkLentry *e, **el;
48037da2899SCharles.Forsyth 	char *tbuf, buf[Tkmaxitem];
48137da2899SCharles.Forsyth 
48237da2899SCharles.Forsyth 	USED(val);
48337da2899SCharles.Forsyth 	l = TKobj(TkListbox, tk);
48437da2899SCharles.Forsyth 
48537da2899SCharles.Forsyth 	arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
48637da2899SCharles.Forsyth 	if(strcmp(buf, "end") == 0) {
48737da2899SCharles.Forsyth 		el = &l->head;
48837da2899SCharles.Forsyth 		if(*el != nil) {
48937da2899SCharles.Forsyth 			for(e = *el; e->link; e = e->link)
49037da2899SCharles.Forsyth 				;
49137da2899SCharles.Forsyth 			el = &e->link;
49237da2899SCharles.Forsyth 		}
49337da2899SCharles.Forsyth 	}
49437da2899SCharles.Forsyth 	else {
49537da2899SCharles.Forsyth 		index = tklindex(tk, buf);
49637da2899SCharles.Forsyth 		if(index == -1)
49737da2899SCharles.Forsyth 			return TkBadix;
49837da2899SCharles.Forsyth 		el = &l->head;
49937da2899SCharles.Forsyth 		for(e = *el; e && index-- > 0; e = e->link)
50037da2899SCharles.Forsyth 			el = &e->link;
50137da2899SCharles.Forsyth 	}
50237da2899SCharles.Forsyth 
50337da2899SCharles.Forsyth 	n = strlen(arg);
50437da2899SCharles.Forsyth 	if(n > Tkmaxitem) {
50537da2899SCharles.Forsyth 		n = (n*3)/2;
50637da2899SCharles.Forsyth 		tbuf = malloc(n);
50737da2899SCharles.Forsyth 		if(tbuf == nil)
50837da2899SCharles.Forsyth 			return TkNomem;
50937da2899SCharles.Forsyth 	}
51037da2899SCharles.Forsyth 	else {
51137da2899SCharles.Forsyth 		tbuf = buf;
51237da2899SCharles.Forsyth 		n = sizeof(buf);
51337da2899SCharles.Forsyth 	}
51437da2899SCharles.Forsyth 
51537da2899SCharles.Forsyth 	while(*arg) {
51637da2899SCharles.Forsyth 		arg = tkword(tk->env->top, arg, tbuf, &tbuf[n], nil);
51737da2899SCharles.Forsyth 		e = malloc(sizeof(TkLentry)+strlen(tbuf)+1);
51837da2899SCharles.Forsyth 		if(e == nil)
51937da2899SCharles.Forsyth 			return TkNomem;
52037da2899SCharles.Forsyth 
52137da2899SCharles.Forsyth 		e->flag = 0;
52237da2899SCharles.Forsyth 		strcpy(e->text, tbuf);
52337da2899SCharles.Forsyth 		e->link = *el;
52437da2899SCharles.Forsyth 		*el = e;
52537da2899SCharles.Forsyth 		el = &e->link;
52637da2899SCharles.Forsyth 		e->width = stringwidth(tk->env->font, e->text)+2*(Listpadx+l->sborderwidth+tk->highlightwidth);
52737da2899SCharles.Forsyth 		if(e->width > l->nwidth)
52837da2899SCharles.Forsyth 			l->nwidth = e->width;
52937da2899SCharles.Forsyth 		l->nitem++;
53037da2899SCharles.Forsyth 	}
53137da2899SCharles.Forsyth 
53237da2899SCharles.Forsyth 	if(tbuf != buf)
53337da2899SCharles.Forsyth 		free(tbuf);
53437da2899SCharles.Forsyth 
53537da2899SCharles.Forsyth 	tklistbgeom(tk);
53637da2899SCharles.Forsyth 	tk->dirty = tkrect(tk, 1);
53737da2899SCharles.Forsyth 	return nil;
53837da2899SCharles.Forsyth }
53937da2899SCharles.Forsyth 
54037da2899SCharles.Forsyth int
tklistbrange(Tk * tk,char * arg,int * s,int * e)54137da2899SCharles.Forsyth tklistbrange(Tk *tk, char *arg, int *s, int *e)
54237da2899SCharles.Forsyth {
54337da2899SCharles.Forsyth 	char buf[Tkmaxitem];
54437da2899SCharles.Forsyth 
54537da2899SCharles.Forsyth 	arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
54637da2899SCharles.Forsyth 	*s = tklindex(tk, buf);
54737da2899SCharles.Forsyth 	if(*s == -1)
54837da2899SCharles.Forsyth 		return -1;
54937da2899SCharles.Forsyth 	*e = *s;
55037da2899SCharles.Forsyth 	if(*arg == '\0')
55137da2899SCharles.Forsyth 		return 0;
55237da2899SCharles.Forsyth 
55337da2899SCharles.Forsyth 	tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
55437da2899SCharles.Forsyth 	*e = tklindex(tk, buf);
55537da2899SCharles.Forsyth 	if(*e == -1)
55637da2899SCharles.Forsyth 		return -1;
55737da2899SCharles.Forsyth 	return 0;
55837da2899SCharles.Forsyth }
55937da2899SCharles.Forsyth 
56037da2899SCharles.Forsyth char*
tklistbselection(Tk * tk,char * arg,char ** val)56137da2899SCharles.Forsyth tklistbselection(Tk *tk, char *arg, char **val)
56237da2899SCharles.Forsyth {
56337da2899SCharles.Forsyth 	TkTop *t;
56437da2899SCharles.Forsyth 	TkLentry *f;
56537da2899SCharles.Forsyth 	TkListbox *l;
56637da2899SCharles.Forsyth 	int s, e, indx;
56737da2899SCharles.Forsyth 	char buf[Tkmaxitem];
56837da2899SCharles.Forsyth 
56937da2899SCharles.Forsyth 	l = TKobj(TkListbox, tk);
57037da2899SCharles.Forsyth 
57137da2899SCharles.Forsyth 	t = tk->env->top;
57237da2899SCharles.Forsyth 	arg = tkword(t, arg, buf, buf+sizeof(buf), nil);
57337da2899SCharles.Forsyth 	if(strcmp(buf, "includes") == 0) {
57437da2899SCharles.Forsyth 		tkword(t, arg, buf, buf+sizeof(buf), nil);
57537da2899SCharles.Forsyth 		indx = tklindex(tk, buf);
57637da2899SCharles.Forsyth 		if(indx == -1)
57737da2899SCharles.Forsyth 			return TkBadix;
57837da2899SCharles.Forsyth 		for(f = l->head; f && indx > 0; f = f->link)
57937da2899SCharles.Forsyth 			indx--;
58037da2899SCharles.Forsyth 		s = 0;
58137da2899SCharles.Forsyth 		if(f && (f->flag&Tkactivated))
58237da2899SCharles.Forsyth 			s = 1;
58337da2899SCharles.Forsyth 		return tkvalue(val, "%d", s);
58437da2899SCharles.Forsyth 	}
58537da2899SCharles.Forsyth 
58637da2899SCharles.Forsyth 	if(strcmp(buf, "anchor") == 0) {
58737da2899SCharles.Forsyth 		tkword(t, arg, buf, buf+sizeof(buf), nil);
58837da2899SCharles.Forsyth 		indx = tklindex(tk, buf);
58937da2899SCharles.Forsyth 		if(indx == -1)
59037da2899SCharles.Forsyth 			return TkBadix;
59137da2899SCharles.Forsyth 		for(f = l->head; f && indx > 0; f = f->link)
59237da2899SCharles.Forsyth 			indx--;
59337da2899SCharles.Forsyth 		if(f != nil)
59437da2899SCharles.Forsyth 			l->anchor = f;
59537da2899SCharles.Forsyth 		return nil;
59637da2899SCharles.Forsyth 	}
59737da2899SCharles.Forsyth 	indx = 0;
59837da2899SCharles.Forsyth 	if(strcmp(buf, "clear") == 0) {
59937da2899SCharles.Forsyth 		if(tklistbrange(tk, arg, &s, &e) != 0)
60037da2899SCharles.Forsyth 			return TkBadix;
60137da2899SCharles.Forsyth 		for(f = l->head; f; f = f->link) {
60237da2899SCharles.Forsyth 			if(indx <= e && indx++ >= s)
60337da2899SCharles.Forsyth 				f->flag &= ~Tkactivated;
60437da2899SCharles.Forsyth 		}
60537da2899SCharles.Forsyth 		tk->dirty = tkrect(tk, 1);
60637da2899SCharles.Forsyth 		return nil;
60737da2899SCharles.Forsyth 	}
60837da2899SCharles.Forsyth 	if(strcmp(buf, "set") == 0) {
60937da2899SCharles.Forsyth 		if(tklistbrange(tk, arg, &s, &e) != 0)
61037da2899SCharles.Forsyth 			return TkBadix;
61137da2899SCharles.Forsyth 		for(f = l->head; f; f = f->link) {
61237da2899SCharles.Forsyth 			if(indx <= e && indx++ >= s)
61337da2899SCharles.Forsyth 				f->flag |= Tkactivated;
61437da2899SCharles.Forsyth 		}
61537da2899SCharles.Forsyth 		tk->dirty = tkrect(tk, 1);
61637da2899SCharles.Forsyth 		return nil;
61737da2899SCharles.Forsyth 	}
61837da2899SCharles.Forsyth 	return TkBadcm;
61937da2899SCharles.Forsyth }
62037da2899SCharles.Forsyth 
62137da2899SCharles.Forsyth char*
tklistbdelete(Tk * tk,char * arg,char ** val)62237da2899SCharles.Forsyth tklistbdelete(Tk *tk, char *arg, char **val)
62337da2899SCharles.Forsyth {
62437da2899SCharles.Forsyth 	TkLentry *e, **el;
62537da2899SCharles.Forsyth 	int start, end, indx, bh;
62637da2899SCharles.Forsyth 	TkListbox *l = TKobj(TkListbox, tk);
62737da2899SCharles.Forsyth 
62837da2899SCharles.Forsyth 	USED(val);
62937da2899SCharles.Forsyth 	if(tklistbrange(tk, arg, &start, &end) != 0)
63037da2899SCharles.Forsyth 		return TkBadix;
63137da2899SCharles.Forsyth 
63237da2899SCharles.Forsyth 	indx = 0;
63337da2899SCharles.Forsyth 	el = &l->head;
63437da2899SCharles.Forsyth 	for(e = l->head; e && indx < start; e = e->link) {
63537da2899SCharles.Forsyth 		indx++;
63637da2899SCharles.Forsyth 		el = &e->link;
63737da2899SCharles.Forsyth 	}
63837da2899SCharles.Forsyth 	while(e != nil && indx <= end) {
63937da2899SCharles.Forsyth 		*el = e->link;
64037da2899SCharles.Forsyth 		if(e->width == l->nwidth)
64137da2899SCharles.Forsyth 			l->nwidth = 0;
64237da2899SCharles.Forsyth 		if (e == l->anchor)
64337da2899SCharles.Forsyth 			l->anchor = nil;
64437da2899SCharles.Forsyth 		if (e == l->active)
64537da2899SCharles.Forsyth 			l->active = nil;
64637da2899SCharles.Forsyth 		free(e);
64737da2899SCharles.Forsyth 		e = *el;
64837da2899SCharles.Forsyth 		indx++;
64937da2899SCharles.Forsyth 		l->nitem--;
65037da2899SCharles.Forsyth 	}
65137da2899SCharles.Forsyth 	if(l->nwidth == 0) {
65237da2899SCharles.Forsyth 		for(e = l->head; e; e = e->link)
65337da2899SCharles.Forsyth 			if(e->width > l->nwidth)
65437da2899SCharles.Forsyth 				l->nwidth = e->width;
65537da2899SCharles.Forsyth 	}
65637da2899SCharles.Forsyth 	bh = tk->act.height/lineheight(tk);	/* Box height */
65737da2899SCharles.Forsyth 	if(l->yelem + bh > l->nitem)
65837da2899SCharles.Forsyth 		l->yelem = l->nitem - bh;
65937da2899SCharles.Forsyth 	if(l->yelem < 0)
66037da2899SCharles.Forsyth 		l->yelem = 0;
66137da2899SCharles.Forsyth 
66237da2899SCharles.Forsyth 	tklistbgeom(tk);
66337da2899SCharles.Forsyth 	tk->dirty = tkrect(tk, 1);
66437da2899SCharles.Forsyth 	return nil;
66537da2899SCharles.Forsyth }
66637da2899SCharles.Forsyth 
66737da2899SCharles.Forsyth char*
tklistbget(Tk * tk,char * arg,char ** val)66837da2899SCharles.Forsyth tklistbget(Tk *tk, char *arg, char **val)
66937da2899SCharles.Forsyth {
67037da2899SCharles.Forsyth 	TkLentry *e;
67137da2899SCharles.Forsyth 	char *r, *fmt;
67237da2899SCharles.Forsyth 	int start, end, indx;
67337da2899SCharles.Forsyth 	TkListbox *l = TKobj(TkListbox, tk);
67437da2899SCharles.Forsyth 
67537da2899SCharles.Forsyth 	if(tklistbrange(tk, arg, &start, &end) != 0)
67637da2899SCharles.Forsyth 		return TkBadix;
67737da2899SCharles.Forsyth 
67837da2899SCharles.Forsyth 	indx = 0;
67937da2899SCharles.Forsyth 	for(e = l->head; e && indx < start; e = e->link)
68037da2899SCharles.Forsyth 		indx++;
68137da2899SCharles.Forsyth 	fmt = "%s";
68237da2899SCharles.Forsyth 	while(e != nil && indx <= end) {
68337da2899SCharles.Forsyth 		r = tkvalue(val, fmt, e->text);
68437da2899SCharles.Forsyth 		if(r != nil)
68537da2899SCharles.Forsyth 			return r;
68637da2899SCharles.Forsyth 		indx++;
68737da2899SCharles.Forsyth 		fmt = " %s";
68837da2899SCharles.Forsyth 		e = e->link;
68937da2899SCharles.Forsyth 	}
69037da2899SCharles.Forsyth 	return nil;
69137da2899SCharles.Forsyth }
69237da2899SCharles.Forsyth 
69337da2899SCharles.Forsyth char*
tklistbcursel(Tk * tk,char * arg,char ** val)69437da2899SCharles.Forsyth tklistbcursel(Tk *tk, char *arg, char **val)
69537da2899SCharles.Forsyth {
69637da2899SCharles.Forsyth 	int indx;
69737da2899SCharles.Forsyth 	TkLentry *e;
69837da2899SCharles.Forsyth 	char *r, *fmt;
69937da2899SCharles.Forsyth 	TkListbox *l = TKobj(TkListbox, tk);
70037da2899SCharles.Forsyth 
70137da2899SCharles.Forsyth 	USED(arg);
70237da2899SCharles.Forsyth 	indx = 0;
70337da2899SCharles.Forsyth 	fmt = "%d";
70437da2899SCharles.Forsyth 	for(e = l->head; e; e = e->link) {
70537da2899SCharles.Forsyth 		if(e->flag & Tkactivated) {
70637da2899SCharles.Forsyth 			r = tkvalue(val, fmt, indx);
70737da2899SCharles.Forsyth 			if(r != nil)
70837da2899SCharles.Forsyth 				return r;
70937da2899SCharles.Forsyth 			fmt = " %d";
71037da2899SCharles.Forsyth 		}
71137da2899SCharles.Forsyth 		indx++;
71237da2899SCharles.Forsyth 	}
71337da2899SCharles.Forsyth 	return nil;
71437da2899SCharles.Forsyth }
71537da2899SCharles.Forsyth 
71637da2899SCharles.Forsyth static char*
tklistbview(Tk * tk,char * arg,char ** val,int nl,int * posn,int max)71737da2899SCharles.Forsyth tklistbview(Tk *tk, char *arg, char **val, int nl, int *posn, int max)
71837da2899SCharles.Forsyth {
71937da2899SCharles.Forsyth 	int top, bot, amount;
72037da2899SCharles.Forsyth 	char buf[Tkmaxitem];
72137da2899SCharles.Forsyth 	char *v, *e;
72237da2899SCharles.Forsyth 
72337da2899SCharles.Forsyth 	top = 0;
72437da2899SCharles.Forsyth 	if(*arg == '\0') {
72537da2899SCharles.Forsyth 		if ( max <= nl || max == 0 ) {	/* Double test redundant at
72637da2899SCharles.Forsyth 						 * this time, but want to
72737da2899SCharles.Forsyth 						 * protect against future
72837da2899SCharles.Forsyth 						 * calls. -- DBK */
72937da2899SCharles.Forsyth 			top = 0;
73037da2899SCharles.Forsyth 			bot = TKI2F(1);
73137da2899SCharles.Forsyth 		}
73237da2899SCharles.Forsyth 		else {
73337da2899SCharles.Forsyth 			top = TKI2F(*posn)/max;
73437da2899SCharles.Forsyth 			bot = TKI2F(*posn+nl)/max;
73537da2899SCharles.Forsyth 		}
73637da2899SCharles.Forsyth 		v = tkfprint(buf, top);
73737da2899SCharles.Forsyth 		*v++ = ' ';
73837da2899SCharles.Forsyth 		tkfprint(v, bot);
73937da2899SCharles.Forsyth 		return tkvalue(val, "%s", buf);
74037da2899SCharles.Forsyth 	}
74137da2899SCharles.Forsyth 
74237da2899SCharles.Forsyth 	arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
74337da2899SCharles.Forsyth 	if(strcmp(buf, "moveto") == 0) {
74437da2899SCharles.Forsyth 		e = tkfracword(tk->env->top, &arg, &top, nil);
74537da2899SCharles.Forsyth 		if (e != nil)
74637da2899SCharles.Forsyth 			return e;
74737da2899SCharles.Forsyth 		*posn = TKF2I((top+1)*max);
74837da2899SCharles.Forsyth 	}
74937da2899SCharles.Forsyth 	else
75037da2899SCharles.Forsyth 	if(strcmp(buf, "scroll") == 0) {
75137da2899SCharles.Forsyth 		arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
75237da2899SCharles.Forsyth 		amount = atoi(buf);
75337da2899SCharles.Forsyth 		tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
75437da2899SCharles.Forsyth 		if(buf[0] == 'p')		/* Pages */
75537da2899SCharles.Forsyth 			amount *= nl;
75637da2899SCharles.Forsyth 		*posn += amount;
75737da2899SCharles.Forsyth 	}
75837da2899SCharles.Forsyth 	else {
75937da2899SCharles.Forsyth 		top = tklindex(tk, buf);
76037da2899SCharles.Forsyth 		if(top == -1)
76137da2899SCharles.Forsyth 			return TkBadix;
76237da2899SCharles.Forsyth 		*posn = top;
76337da2899SCharles.Forsyth 	}
76437da2899SCharles.Forsyth 
76537da2899SCharles.Forsyth 	bot = max - nl;
76637da2899SCharles.Forsyth 	if(*posn > bot)
76737da2899SCharles.Forsyth 		*posn = bot;
76837da2899SCharles.Forsyth 	if(*posn < 0)
76937da2899SCharles.Forsyth 		*posn = 0;
77037da2899SCharles.Forsyth 
77137da2899SCharles.Forsyth 	tk->dirty = tkrect(tk, 1);
77237da2899SCharles.Forsyth 	return nil;
77337da2899SCharles.Forsyth }
77437da2899SCharles.Forsyth 
77537da2899SCharles.Forsyth static int
entrysee(Tk * tk,int index)77637da2899SCharles.Forsyth entrysee(Tk *tk, int index)
77737da2899SCharles.Forsyth {
77837da2899SCharles.Forsyth 	TkListbox *l = TKobj(TkListbox, tk);
77937da2899SCharles.Forsyth 	int bh;
78037da2899SCharles.Forsyth 
78137da2899SCharles.Forsyth 	/* Box height in lines */
78237da2899SCharles.Forsyth 	bh = tk->act.height/lineheight(tk);
78337da2899SCharles.Forsyth 	if (bh > l->nitem)
78437da2899SCharles.Forsyth 		bh = l->nitem;
78537da2899SCharles.Forsyth 	if (index >= l->nitem)
78637da2899SCharles.Forsyth 		index = l->nitem -1;
78737da2899SCharles.Forsyth 	if (index < 0)
78837da2899SCharles.Forsyth 		index = 0;
78937da2899SCharles.Forsyth 
79037da2899SCharles.Forsyth 	/* If the item is already visible, do nothing */
79137da2899SCharles.Forsyth 	if (l->nitem == 0 || index >= l->yelem && index < l->yelem+bh)
79237da2899SCharles.Forsyth 		return index;
79337da2899SCharles.Forsyth 
79437da2899SCharles.Forsyth 	if (index < l->yelem)
79537da2899SCharles.Forsyth 		l->yelem = index;
79637da2899SCharles.Forsyth 	else
79737da2899SCharles.Forsyth 		l->yelem = index - (bh-1);
79837da2899SCharles.Forsyth 
79937da2899SCharles.Forsyth 	tklistsv(tk);
80037da2899SCharles.Forsyth 	tk->dirty = tkrect(tk, 1);
80137da2899SCharles.Forsyth 	return index;
80237da2899SCharles.Forsyth }
80337da2899SCharles.Forsyth 
80437da2899SCharles.Forsyth char*
tklistbsee(Tk * tk,char * arg,char ** val)80537da2899SCharles.Forsyth tklistbsee(Tk *tk, char *arg, char **val)
80637da2899SCharles.Forsyth {
80737da2899SCharles.Forsyth 	int index;
80837da2899SCharles.Forsyth 	char buf[Tkmaxitem];
80937da2899SCharles.Forsyth 
81037da2899SCharles.Forsyth 	USED(val);
81137da2899SCharles.Forsyth 	tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
81237da2899SCharles.Forsyth 	index = tklindex(tk, buf);
81337da2899SCharles.Forsyth 	if(index == -1)
81437da2899SCharles.Forsyth 		return TkBadix;
81537da2899SCharles.Forsyth 
81637da2899SCharles.Forsyth 	entrysee(tk, index);
81737da2899SCharles.Forsyth 	return nil;
81837da2899SCharles.Forsyth }
81937da2899SCharles.Forsyth 
82037da2899SCharles.Forsyth char*
tklistbyview(Tk * tk,char * arg,char ** val)82137da2899SCharles.Forsyth tklistbyview(Tk *tk, char *arg, char **val)
82237da2899SCharles.Forsyth {
82337da2899SCharles.Forsyth 	int bh;
82437da2899SCharles.Forsyth 	char *e;
82537da2899SCharles.Forsyth 	TkListbox *l = TKobj(TkListbox, tk);
82637da2899SCharles.Forsyth 
82737da2899SCharles.Forsyth 	bh = tk->act.height/lineheight(tk);	/* Box height */
82837da2899SCharles.Forsyth 	e = tklistbview(tk, arg, val, bh, &l->yelem, l->nitem);
82937da2899SCharles.Forsyth 	tklistsv(tk);
83037da2899SCharles.Forsyth 	return e;
83137da2899SCharles.Forsyth }
83237da2899SCharles.Forsyth 
83337da2899SCharles.Forsyth char*
tklistbxview(Tk * tk,char * arg,char ** val)83437da2899SCharles.Forsyth tklistbxview(Tk *tk, char *arg, char **val)
83537da2899SCharles.Forsyth {
83637da2899SCharles.Forsyth 	char *e;
83737da2899SCharles.Forsyth 	TkListbox *l = TKobj(TkListbox, tk);
83837da2899SCharles.Forsyth 
83937da2899SCharles.Forsyth 	e = tklistbview(tk, arg, val, tk->act.width, &l->xdelta, l->nwidth);
84037da2899SCharles.Forsyth 	tklistsh(tk);
84137da2899SCharles.Forsyth 	return e;
84237da2899SCharles.Forsyth }
84337da2899SCharles.Forsyth 
84437da2899SCharles.Forsyth static TkLentry*
entryset(TkListbox * l,int indx,int toggle)84537da2899SCharles.Forsyth entryset(TkListbox *l, int indx, int toggle)
84637da2899SCharles.Forsyth {
84737da2899SCharles.Forsyth 	TkLentry *e, *anchor;
84837da2899SCharles.Forsyth 
84937da2899SCharles.Forsyth 	anchor = nil;
85037da2899SCharles.Forsyth 	for(e = l->head; e; e = e->link) {
85137da2899SCharles.Forsyth 		if (indx-- == 0) {
85237da2899SCharles.Forsyth 			anchor = e;
85337da2899SCharles.Forsyth 			if (toggle) {
85437da2899SCharles.Forsyth 				e->flag ^= Tkactivated;
85537da2899SCharles.Forsyth 				break;
85637da2899SCharles.Forsyth 			} else
85737da2899SCharles.Forsyth 				e->flag |= Tkactivated;
85837da2899SCharles.Forsyth 			continue;
85937da2899SCharles.Forsyth 		}
86037da2899SCharles.Forsyth 		if (!toggle)
86137da2899SCharles.Forsyth 			e->flag &= ~Tkactivated;
86237da2899SCharles.Forsyth 	}
86337da2899SCharles.Forsyth 	return anchor;
86437da2899SCharles.Forsyth }
86537da2899SCharles.Forsyth 
86637da2899SCharles.Forsyth static void
selectto(TkListbox * l,int indx)86737da2899SCharles.Forsyth selectto(TkListbox *l, int indx)
86837da2899SCharles.Forsyth {
86937da2899SCharles.Forsyth 	TkLentry *e;
87037da2899SCharles.Forsyth 	int inrange;
87137da2899SCharles.Forsyth 
87237da2899SCharles.Forsyth 	if (l->anchor == nil)
87337da2899SCharles.Forsyth 		return;
87437da2899SCharles.Forsyth 	inrange = 0;
87537da2899SCharles.Forsyth 	for(e = l->head; e; e = e->link) {
87637da2899SCharles.Forsyth 		if(indx == 0)
87737da2899SCharles.Forsyth 			inrange = !inrange;
87837da2899SCharles.Forsyth 		if(e == l->anchor)
87937da2899SCharles.Forsyth 			inrange = !inrange;
88037da2899SCharles.Forsyth 		if(inrange || e == l->anchor || indx == 0)
88137da2899SCharles.Forsyth 			e->flag |= Tkactivated;
88237da2899SCharles.Forsyth 		else
88337da2899SCharles.Forsyth 			e->flag &= ~Tkactivated;
88437da2899SCharles.Forsyth 		indx--;
88537da2899SCharles.Forsyth 	}
88637da2899SCharles.Forsyth }
88737da2899SCharles.Forsyth 
88837da2899SCharles.Forsyth static char*
dragto(Tk * tk,int y)88937da2899SCharles.Forsyth dragto(Tk *tk, int y)
89037da2899SCharles.Forsyth {
89137da2899SCharles.Forsyth 	int indx;
89237da2899SCharles.Forsyth 	TkLentry *e;
89337da2899SCharles.Forsyth 	TkListbox *l = TKobj(TkListbox, tk);
89437da2899SCharles.Forsyth 
89537da2899SCharles.Forsyth 	indx = y/lineheight(tk);
89637da2899SCharles.Forsyth 	if (y < 0)
89737da2899SCharles.Forsyth 		indx--;	/* int division rounds towards 0 */
89837da2899SCharles.Forsyth 	if (y < tk->act.height && indx >= l->nitem)
89937da2899SCharles.Forsyth 		return nil;
90037da2899SCharles.Forsyth 	indx = entrysee(tk, l->yelem+indx);
90137da2899SCharles.Forsyth 	entryactivate(tk, indx);
90237da2899SCharles.Forsyth 
90337da2899SCharles.Forsyth 	if(l->selmode == TKsingle || l->selmode == TKmultiple)
90437da2899SCharles.Forsyth 		return nil;
90537da2899SCharles.Forsyth 
90637da2899SCharles.Forsyth 	if(l->selmode == TKbrowse) {
90737da2899SCharles.Forsyth 		for(e = l->head; e; e = e->link) {
90837da2899SCharles.Forsyth 			if(indx-- == 0) {
90937da2899SCharles.Forsyth 				if (e == l->anchor)
91037da2899SCharles.Forsyth 					return nil;
91137da2899SCharles.Forsyth 				l->anchor = e;
91237da2899SCharles.Forsyth 				e->flag |= Tkactivated;
91337da2899SCharles.Forsyth 			} else
91437da2899SCharles.Forsyth 				e->flag &= ~Tkactivated;
91537da2899SCharles.Forsyth 		}
91637da2899SCharles.Forsyth 		return nil;
91737da2899SCharles.Forsyth 	}
91837da2899SCharles.Forsyth 	/* extended selection mode */
91937da2899SCharles.Forsyth 	selectto(l, indx);
92037da2899SCharles.Forsyth 	tk->dirty = tkrect(tk, 1);
92137da2899SCharles.Forsyth 	return nil;
92237da2899SCharles.Forsyth }
92337da2899SCharles.Forsyth 
92437da2899SCharles.Forsyth static void
autoselect(Tk * tk,void * v,int cancelled)92537da2899SCharles.Forsyth autoselect(Tk *tk, void *v, int cancelled)
92637da2899SCharles.Forsyth {
92737da2899SCharles.Forsyth 	Point pt;
92837da2899SCharles.Forsyth 	int y, eh, ne;
92937da2899SCharles.Forsyth 
93037da2899SCharles.Forsyth 	USED(v);
93137da2899SCharles.Forsyth 	if (cancelled)
93237da2899SCharles.Forsyth 		return;
93337da2899SCharles.Forsyth 
93437da2899SCharles.Forsyth 	pt = tkposn(tk);
93537da2899SCharles.Forsyth 	pt.y += tk->borderwidth;
93637da2899SCharles.Forsyth 	y = tk->env->top->ctxt->mstate.y;
93737da2899SCharles.Forsyth 	y -= pt.y;
93837da2899SCharles.Forsyth 	eh = lineheight(tk);
93937da2899SCharles.Forsyth 	ne = tk->act.height/eh;
94037da2899SCharles.Forsyth 	if (y >= 0 && y < eh*ne)
94137da2899SCharles.Forsyth 		return;
94237da2899SCharles.Forsyth 	dragto(tk, y);
94337da2899SCharles.Forsyth 	tkdirty(tk);
94437da2899SCharles.Forsyth 	tkupdate(tk->env->top);
94537da2899SCharles.Forsyth }
94637da2899SCharles.Forsyth 
94737da2899SCharles.Forsyth static char*
tklistbbutton1p(Tk * tk,char * arg,char ** val)94837da2899SCharles.Forsyth tklistbbutton1p(Tk *tk, char *arg, char **val)
94937da2899SCharles.Forsyth {
95037da2899SCharles.Forsyth 	TkListbox *l = TKobj(TkListbox, tk);
95137da2899SCharles.Forsyth 	int y, indx;
95237da2899SCharles.Forsyth 
95337da2899SCharles.Forsyth 	USED(val);
95437da2899SCharles.Forsyth 
95537da2899SCharles.Forsyth 	y = atoi(arg);
95637da2899SCharles.Forsyth 	indx = y/lineheight(tk);
95737da2899SCharles.Forsyth 	indx += l->yelem;
95837da2899SCharles.Forsyth 	if (indx < l->nitem) {
95937da2899SCharles.Forsyth 		l->anchor = entryset(l, indx, l->selmode == TKmultiple);
96037da2899SCharles.Forsyth 		entryactivate(tk, indx);
96137da2899SCharles.Forsyth 		entrysee(tk, indx);
96237da2899SCharles.Forsyth 	}
96337da2899SCharles.Forsyth 	tkrepeat(tk, autoselect, nil, TkRptpause, TkRptinterval);
96437da2899SCharles.Forsyth 	return nil;
96537da2899SCharles.Forsyth }
96637da2899SCharles.Forsyth 
96737da2899SCharles.Forsyth char *
tklistbbutton1r(Tk * tk,char * arg,char ** val)96837da2899SCharles.Forsyth tklistbbutton1r(Tk *tk, char *arg, char **val)
96937da2899SCharles.Forsyth {
97037da2899SCharles.Forsyth 	USED(arg);
97137da2899SCharles.Forsyth 	USED(val);
97237da2899SCharles.Forsyth 	tkcancelrepeat(tk);
97337da2899SCharles.Forsyth 	return nil;
97437da2899SCharles.Forsyth }
97537da2899SCharles.Forsyth 
97637da2899SCharles.Forsyth char*
tklistbbutton1m(Tk * tk,char * arg,char ** val)97737da2899SCharles.Forsyth tklistbbutton1m(Tk *tk, char *arg, char **val)
97837da2899SCharles.Forsyth {
97937da2899SCharles.Forsyth 	int y, eh, ne;
98037da2899SCharles.Forsyth 	USED(val);
98137da2899SCharles.Forsyth 
98237da2899SCharles.Forsyth 	eh = lineheight(tk);
98337da2899SCharles.Forsyth 	ne = tk->act.height/eh;
98437da2899SCharles.Forsyth 	y = atoi(arg);
98537da2899SCharles.Forsyth 	/* If outside the box, let autoselect handle it */
98637da2899SCharles.Forsyth 	if (y < 0 || y >= ne * eh)
98737da2899SCharles.Forsyth 		return nil;
98837da2899SCharles.Forsyth 	return dragto(tk, y);
98937da2899SCharles.Forsyth }
99037da2899SCharles.Forsyth 
99137da2899SCharles.Forsyth char*
tklistbkey(Tk * tk,char * arg,char ** val)99237da2899SCharles.Forsyth tklistbkey(Tk *tk, char *arg, char **val)
99337da2899SCharles.Forsyth {
99437da2899SCharles.Forsyth 	TkListbox *l = TKobj(TkListbox, tk);
99537da2899SCharles.Forsyth 	TkLentry *e;
99637da2899SCharles.Forsyth 	int key, active;
99737da2899SCharles.Forsyth 	USED(val);
99837da2899SCharles.Forsyth 
99937da2899SCharles.Forsyth 	if(tk->flag & Tkdisabled)
100037da2899SCharles.Forsyth 		return nil;
100137da2899SCharles.Forsyth 
1002*48c2bcd8Sforsyth 	key = strtol(arg, nil, 0);
100337da2899SCharles.Forsyth 	active = 0;
100437da2899SCharles.Forsyth 	for (e = l->head; e != nil; e = e->link) {
100537da2899SCharles.Forsyth 		if (e->flag & Tkactive)
100637da2899SCharles.Forsyth 			break;
100737da2899SCharles.Forsyth 		active++;
100837da2899SCharles.Forsyth 	}
100937da2899SCharles.Forsyth 
101037da2899SCharles.Forsyth 	if (key == '\n' || key == ' ') {
101137da2899SCharles.Forsyth 		l->anchor = entryset(l, active, l->selmode == TKmultiple);
101237da2899SCharles.Forsyth 		tk->dirty = tkrect(tk, 0);
101337da2899SCharles.Forsyth 		return nil;
101437da2899SCharles.Forsyth 	}
101537da2899SCharles.Forsyth 	if (key == Up)
101637da2899SCharles.Forsyth 		active--;
101737da2899SCharles.Forsyth 	else if (key == Down)
101837da2899SCharles.Forsyth 		active++;
101937da2899SCharles.Forsyth 	else
102037da2899SCharles.Forsyth 		return nil;
102137da2899SCharles.Forsyth 
102237da2899SCharles.Forsyth 	if (active < 0)
102337da2899SCharles.Forsyth 		active = 0;
102437da2899SCharles.Forsyth 	if (active >= l->nitem)
102537da2899SCharles.Forsyth 		active = l->nitem-1;
102637da2899SCharles.Forsyth 	entryactivate(tk, active);
102737da2899SCharles.Forsyth 	if (l->selmode == TKextended) {
102837da2899SCharles.Forsyth 		selectto(l, active);
102937da2899SCharles.Forsyth 		tk->dirty = tkrect(tk, 0);
103037da2899SCharles.Forsyth 	}
103137da2899SCharles.Forsyth 	entrysee(tk, active);
103237da2899SCharles.Forsyth 	return nil;
103337da2899SCharles.Forsyth }
103437da2899SCharles.Forsyth 
103537da2899SCharles.Forsyth static
103637da2899SCharles.Forsyth TkCmdtab tklistcmd[] =
103737da2899SCharles.Forsyth {
103837da2899SCharles.Forsyth 	"activate",		tklistbactivate,
103937da2899SCharles.Forsyth 	"cget",			tklistbcget,
104037da2899SCharles.Forsyth 	"configure",		tklistbconf,
104137da2899SCharles.Forsyth 	"curselection",		tklistbcursel,
104237da2899SCharles.Forsyth 	"delete",		tklistbdelete,
104337da2899SCharles.Forsyth 	"get",			tklistbget,
104437da2899SCharles.Forsyth 	"index",		tklistbindex,
104537da2899SCharles.Forsyth 	"insert",		tklistbinsert,
104637da2899SCharles.Forsyth 	"nearest",		tklistbnearest,
104737da2899SCharles.Forsyth 	"selection",		tklistbselection,
104837da2899SCharles.Forsyth 	"see",			tklistbsee,
104937da2899SCharles.Forsyth 	"size",			tklistbsize,
105037da2899SCharles.Forsyth 	"xview",		tklistbxview,
105137da2899SCharles.Forsyth 	"yview",		tklistbyview,
105237da2899SCharles.Forsyth 	"tkListbButton1P",	tklistbbutton1p,
105337da2899SCharles.Forsyth 	"tkListbButton1R",	tklistbbutton1r,
105437da2899SCharles.Forsyth 	"tkListbButton1MP",	tklistbbutton1m,
105537da2899SCharles.Forsyth 	"tkListbKey",	tklistbkey,
105637da2899SCharles.Forsyth 	nil
105737da2899SCharles.Forsyth };
105837da2899SCharles.Forsyth 
105937da2899SCharles.Forsyth TkMethod listboxmethod = {
106037da2899SCharles.Forsyth 	"listbox",
106137da2899SCharles.Forsyth 	tklistcmd,
106237da2899SCharles.Forsyth 	tkfreelistb,
106337da2899SCharles.Forsyth 	tkdrawlistb,
106437da2899SCharles.Forsyth 	tklistbgeom
106537da2899SCharles.Forsyth };
1066