xref: /inferno-os/libtk/entry.c (revision 5849851a19380dbb62a47d9c4d868a81e42fa79b)
137da2899SCharles.Forsyth #include <lib9.h>
237da2899SCharles.Forsyth #include <kernel.h>
337da2899SCharles.Forsyth #include "draw.h"
437da2899SCharles.Forsyth #include "keyboard.h"
537da2899SCharles.Forsyth #include "tk.h"
637da2899SCharles.Forsyth 
737da2899SCharles.Forsyth /* Widget Commands (+ means implemented)
837da2899SCharles.Forsyth 	+bbox
937da2899SCharles.Forsyth 	+cget
1037da2899SCharles.Forsyth 	+configure
1137da2899SCharles.Forsyth 	+delete
1237da2899SCharles.Forsyth 	+get
1337da2899SCharles.Forsyth 	+icursor
1437da2899SCharles.Forsyth 	+index
1537da2899SCharles.Forsyth 	 scan
1637da2899SCharles.Forsyth 	+selection
1737da2899SCharles.Forsyth 	+xview
1837da2899SCharles.Forsyth 	+see
1937da2899SCharles.Forsyth */
2037da2899SCharles.Forsyth 
2137da2899SCharles.Forsyth #define	O(t, e)		((long)(&((t*)0)->e))
2237da2899SCharles.Forsyth 
2337da2899SCharles.Forsyth #define CNTL(c) ((c)&0x1f)
2437da2899SCharles.Forsyth #define DEL 0x7f
2537da2899SCharles.Forsyth 
2637da2899SCharles.Forsyth /* Layout constants */
2737da2899SCharles.Forsyth enum {
2837da2899SCharles.Forsyth 	Entrypady	= 0,
2937da2899SCharles.Forsyth 	Entrypadx	= 0,
3037da2899SCharles.Forsyth 	Inswidth = 2,
3137da2899SCharles.Forsyth 
3237da2899SCharles.Forsyth 	Ecursoron = 1<<0,
3337da2899SCharles.Forsyth 	Ecenter = 1<<1,
3437da2899SCharles.Forsyth 	Eright = 1<<2,
3537da2899SCharles.Forsyth 	Eleft = 1<<3,
3637da2899SCharles.Forsyth 	Ewordsel = 1<<4,
3737da2899SCharles.Forsyth 
3837da2899SCharles.Forsyth 	Ejustify = Ecenter|Eleft|Eright
3937da2899SCharles.Forsyth };
4037da2899SCharles.Forsyth 
4137da2899SCharles.Forsyth static TkStab tkjust[] =
4237da2899SCharles.Forsyth {
4337da2899SCharles.Forsyth 	"left",	Eleft,
4437da2899SCharles.Forsyth 	"right",	Eright,
4537da2899SCharles.Forsyth 	"center",	Ecenter,
4637da2899SCharles.Forsyth 	nil
4737da2899SCharles.Forsyth };
4837da2899SCharles.Forsyth 
4937da2899SCharles.Forsyth static
5037da2899SCharles.Forsyth TkEbind b[] =
5137da2899SCharles.Forsyth {
5237da2899SCharles.Forsyth 	{TkKey,			"%W delete sel.first sel.last; %W insert insert {%A};%W see insert"},
5337da2899SCharles.Forsyth 	{TkKey|CNTL('a'),	"%W icursor 0;%W see insert;%W selection clear"},
5437da2899SCharles.Forsyth 	{TkKey|Home,		"%W icursor 0;%W see insert;%W selection clear"},
5537da2899SCharles.Forsyth 	{TkKey|CNTL('d'),	"%W delete insert; %W see insert"},
5637da2899SCharles.Forsyth 	{TkKey|CNTL('e'),    "%W icursor end; %W see insert;%W selection clear"},
5737da2899SCharles.Forsyth 	{TkKey|End,	     "%W icursor end; %W see insert;%W selection clear"},
5837da2899SCharles.Forsyth 	{TkKey|CNTL('h'),	"%W tkEntryBS;%W see insert"},
5937da2899SCharles.Forsyth 	{TkKey|CNTL('k'),	"%W delete insert end;%W see insert"},
6037da2899SCharles.Forsyth 	{TkKey|CNTL('u'),	"%W delete 0 end;%W see insert"},
6137da2899SCharles.Forsyth 	{TkKey|CNTL('w'),	"%W delete sel.first sel.last; %W tkEntryBW;%W see insert"},
6237da2899SCharles.Forsyth 	{TkKey|DEL,		"%W tkEntryBS 1;%W see insert"},
6337da2899SCharles.Forsyth 	{TkKey|CNTL('\\'),	"%W selection clear"},
6437da2899SCharles.Forsyth 	{TkKey|CNTL('/'),	"%W selection range 0 end"},
6537da2899SCharles.Forsyth 	{TkKey|Left,	"%W icursor insert-1;%W selection clear;%W selection from insert;%W see insert"},
6637da2899SCharles.Forsyth 	{TkKey|Right,	"%W icursor insert+1;%W selection clear;%W selection from insert;%W see insert"},
6737da2899SCharles.Forsyth 	{TkButton1P,		"focus %W; %W tkEntryB1P %X"},
6837da2899SCharles.Forsyth 	{TkButton1P|TkMotion, 	"%W tkEntryB1M %X"},
6937da2899SCharles.Forsyth 	{TkButton1R,		"%W tkEntryB1R"},
7037da2899SCharles.Forsyth 	{TkButton1P|TkDouble,	"%W tkEntryB1P %X;%W selection word @%x"},
7137da2899SCharles.Forsyth 	{TkButton2P,			"%W tkEntryB2P %x"},
7237da2899SCharles.Forsyth 	{TkButton2P|TkMotion,	"%W xview scroll %x scr"},
7337da2899SCharles.Forsyth 	{TkFocusin,		"%W tkEntryFocus in"},
7437da2899SCharles.Forsyth 	{TkFocusout,		"%W tkEntryFocus out"},
7537da2899SCharles.Forsyth 	{TkKey|APP|'\t',	""},
7637da2899SCharles.Forsyth 	{TkKey|BackTab,		""},
7737da2899SCharles.Forsyth };
7837da2899SCharles.Forsyth 
7937da2899SCharles.Forsyth typedef struct TkEntry TkEntry;
8037da2899SCharles.Forsyth struct TkEntry
8137da2899SCharles.Forsyth {
8237da2899SCharles.Forsyth 	Rune*	text;
8337da2899SCharles.Forsyth 	int		textlen;
8437da2899SCharles.Forsyth 
8537da2899SCharles.Forsyth 	char*	xscroll;
8637da2899SCharles.Forsyth 	char*	show;
8737da2899SCharles.Forsyth 	int		flag;
8837da2899SCharles.Forsyth 	int		oldx;
8937da2899SCharles.Forsyth 
9037da2899SCharles.Forsyth 	int		icursor;		/* index of insertion cursor */
9137da2899SCharles.Forsyth 	int		anchor;		/* selection anchor point */
9237da2899SCharles.Forsyth 	int		sel0;			/* index of start of selection */
9337da2899SCharles.Forsyth 	int		sel1;			/* index of end of selection */
9437da2899SCharles.Forsyth 
9537da2899SCharles.Forsyth 	int		x0;			/* x-offset of visible area */
9637da2899SCharles.Forsyth 
9737da2899SCharles.Forsyth 	/* derived values */
9837da2899SCharles.Forsyth 	int		v0;			/* index of first visible character */
9937da2899SCharles.Forsyth 	int		v1;			/* index of last visible character + 1 */
10037da2899SCharles.Forsyth 	int		xlen;			/* length of text in pixels*/
10137da2899SCharles.Forsyth 	int		xv0;			/* position of first visible character */
10237da2899SCharles.Forsyth 	int		xsel0;		/* position of start of selection */
10337da2899SCharles.Forsyth 	int		xsel1;		/* position of end of selection */
10437da2899SCharles.Forsyth 	int		xicursor;		/* position of insertion cursor */
10537da2899SCharles.Forsyth };
10637da2899SCharles.Forsyth 
10737da2899SCharles.Forsyth static void blinkreset(Tk*);
10837da2899SCharles.Forsyth 
10937da2899SCharles.Forsyth static
11037da2899SCharles.Forsyth TkOption opts[] =
11137da2899SCharles.Forsyth {
11237da2899SCharles.Forsyth 	"xscrollcommand",	OPTtext,	O(TkEntry, xscroll),	nil,
11337da2899SCharles.Forsyth 	"justify",		OPTstab,	O(TkEntry, flag),	tkjust,
11437da2899SCharles.Forsyth 	"show",			OPTtext,	O(TkEntry, show),	nil,
11537da2899SCharles.Forsyth 	nil
11637da2899SCharles.Forsyth };
11737da2899SCharles.Forsyth 
11837da2899SCharles.Forsyth static int
xinset(Tk * tk)11937da2899SCharles.Forsyth xinset(Tk *tk)
12037da2899SCharles.Forsyth {
12137da2899SCharles.Forsyth 	return Entrypadx + tk->highlightwidth;
12237da2899SCharles.Forsyth }
12337da2899SCharles.Forsyth 
12437da2899SCharles.Forsyth static int
yinset(Tk * tk)12537da2899SCharles.Forsyth yinset(Tk *tk)
12637da2899SCharles.Forsyth {
12737da2899SCharles.Forsyth 	return Entrypady + tk->highlightwidth;
12837da2899SCharles.Forsyth }
12937da2899SCharles.Forsyth 
13037da2899SCharles.Forsyth static void
tksizeentry(Tk * tk)13137da2899SCharles.Forsyth tksizeentry(Tk *tk)
13237da2899SCharles.Forsyth {
13337da2899SCharles.Forsyth 	if((tk->flag & Tksetwidth) == 0)
13437da2899SCharles.Forsyth 		tk->req.width = tk->env->wzero*25 + 2*xinset(tk) + Inswidth;
13537da2899SCharles.Forsyth 	if((tk->flag & Tksetheight) == 0)
13637da2899SCharles.Forsyth 		tk->req.height = tk->env->font->height+ 2*yinset(tk);
13737da2899SCharles.Forsyth }
13837da2899SCharles.Forsyth 
13937da2899SCharles.Forsyth int
entrytextwidth(Tk * tk,int n)14037da2899SCharles.Forsyth entrytextwidth(Tk *tk, int n)
14137da2899SCharles.Forsyth {
14237da2899SCharles.Forsyth 	TkEntry *tke = TKobj(TkEntry, tk);
14337da2899SCharles.Forsyth 	Rune c;
14437da2899SCharles.Forsyth 	Font *f;
14537da2899SCharles.Forsyth 
14637da2899SCharles.Forsyth 	f = tk->env->font;
14737da2899SCharles.Forsyth 	if (tke->show != nil) {
14837da2899SCharles.Forsyth 		chartorune(&c, tke->show);
14937da2899SCharles.Forsyth 		return n * runestringnwidth(f, &c, 1);
15037da2899SCharles.Forsyth 	}
15137da2899SCharles.Forsyth 	return runestringnwidth(f, tke->text, n);
15237da2899SCharles.Forsyth }
15337da2899SCharles.Forsyth 
15437da2899SCharles.Forsyth static int
x2index(Tk * tk,int x,int * xc)15537da2899SCharles.Forsyth x2index(Tk *tk,  int x, int *xc)
15637da2899SCharles.Forsyth {
15737da2899SCharles.Forsyth 	TkEntry *tke = TKobj(TkEntry, tk);
15837da2899SCharles.Forsyth 	int t0, t1, r, q;
15937da2899SCharles.Forsyth 
16037da2899SCharles.Forsyth 	t0 = 0;
16137da2899SCharles.Forsyth 	t1 = tke->textlen;
16237da2899SCharles.Forsyth 	while (t0 <= t1) {
16337da2899SCharles.Forsyth 		r = (t0 + t1) / 2;
16437da2899SCharles.Forsyth 		q = entrytextwidth(tk, r);
16537da2899SCharles.Forsyth 		if (q == x) {
16637da2899SCharles.Forsyth 			if (xc != nil)
16737da2899SCharles.Forsyth 				*xc = q;
16837da2899SCharles.Forsyth 			return r;
16937da2899SCharles.Forsyth 		}
17037da2899SCharles.Forsyth 		if (q < x)
17137da2899SCharles.Forsyth 			t0 = r + 1;
17237da2899SCharles.Forsyth 		else
17337da2899SCharles.Forsyth 			t1 = r - 1;
17437da2899SCharles.Forsyth 	}
17537da2899SCharles.Forsyth 	if (xc != nil)
17637da2899SCharles.Forsyth 		*xc = t1 > 0 ? entrytextwidth(tk, t1) : 0;
17737da2899SCharles.Forsyth 	if (t1 < 0)
17837da2899SCharles.Forsyth 		t1 = 0;
17937da2899SCharles.Forsyth 	return t1;
18037da2899SCharles.Forsyth }
18137da2899SCharles.Forsyth 
18237da2899SCharles.Forsyth /*
18337da2899SCharles.Forsyth  * recalculate derived values
18437da2899SCharles.Forsyth  */
18537da2899SCharles.Forsyth static void
recalcentry(Tk * tk)18637da2899SCharles.Forsyth recalcentry(Tk *tk)
18737da2899SCharles.Forsyth {
18837da2899SCharles.Forsyth 	TkEntry *tke = TKobj(TkEntry, tk);
18937da2899SCharles.Forsyth 	int x, avail, locked;
19037da2899SCharles.Forsyth 
19137da2899SCharles.Forsyth 	locked = lockdisplay(tk->env->top->display);
19237da2899SCharles.Forsyth 
19337da2899SCharles.Forsyth 	tke->xlen = entrytextwidth(tk, tke->textlen) + Inswidth;
19437da2899SCharles.Forsyth 
19537da2899SCharles.Forsyth 	avail = tk->act.width - 2*xinset(tk);
19637da2899SCharles.Forsyth 	if (tke->xlen < avail) {
19737da2899SCharles.Forsyth 		switch(tke->flag & Ejustify) {
19837da2899SCharles.Forsyth 		default:
19937da2899SCharles.Forsyth 			tke->x0 = 0;
20037da2899SCharles.Forsyth 			break;
20137da2899SCharles.Forsyth 		case Eright:
20237da2899SCharles.Forsyth 			tke->x0 = -(avail - tke->xlen);
20337da2899SCharles.Forsyth 			break;
20437da2899SCharles.Forsyth 		case Ecenter:
20537da2899SCharles.Forsyth 			tke->x0 = -(avail - tke->xlen) / 2;
20637da2899SCharles.Forsyth 			break;
20737da2899SCharles.Forsyth 		}
20837da2899SCharles.Forsyth 	}
20937da2899SCharles.Forsyth 
21037da2899SCharles.Forsyth 	tke->v0 = x2index(tk, tke->x0, &tke->xv0);
21137da2899SCharles.Forsyth 	tke->v1 = x2index(tk, tk->act.width + tke->x0, &x);
21237da2899SCharles.Forsyth 	/* perhaps include partial last character */
21337da2899SCharles.Forsyth 	if (tke->v1 < tke->textlen && x < avail + tke->x0)
21437da2899SCharles.Forsyth 		tke->v1++;
21537da2899SCharles.Forsyth 	tke->xsel0 = entrytextwidth(tk, tke->sel0);
21637da2899SCharles.Forsyth 	tke->xsel1 = entrytextwidth(tk, tke->sel1);
21737da2899SCharles.Forsyth 	tke->xicursor = entrytextwidth(tk, tke->icursor);
21837da2899SCharles.Forsyth 
21937da2899SCharles.Forsyth 	if (locked)
22037da2899SCharles.Forsyth 		unlockdisplay(tk->env->top->display);
22137da2899SCharles.Forsyth }
22237da2899SCharles.Forsyth 
22337da2899SCharles.Forsyth char*
tkentry(TkTop * t,char * arg,char ** ret)22437da2899SCharles.Forsyth tkentry(TkTop *t, char *arg, char **ret)
22537da2899SCharles.Forsyth {
22637da2899SCharles.Forsyth 	Tk *tk;
22737da2899SCharles.Forsyth 	char *e;
22837da2899SCharles.Forsyth 	TkName *names;
22937da2899SCharles.Forsyth 	TkEntry *tke;
23037da2899SCharles.Forsyth 	TkOptab tko[3];
23137da2899SCharles.Forsyth 
23237da2899SCharles.Forsyth 	tk = tknewobj(t, TKentry, sizeof(Tk)+sizeof(TkEntry));
23337da2899SCharles.Forsyth 	if(tk == nil)
23437da2899SCharles.Forsyth 		return TkNomem;
23537da2899SCharles.Forsyth 
23637da2899SCharles.Forsyth 	tk->relief = TKsunken;
237*c9ccdbd5Sforsyth 	tk->borderwidth = 1;
23837da2899SCharles.Forsyth 	tk->flag |= Tktakefocus;
23937da2899SCharles.Forsyth 	tk->highlightwidth = 1;
24037da2899SCharles.Forsyth 
24137da2899SCharles.Forsyth 	tke = TKobj(TkEntry, tk);
24237da2899SCharles.Forsyth 
24337da2899SCharles.Forsyth 	tko[0].ptr = tk;
24437da2899SCharles.Forsyth 	tko[0].optab = tkgeneric;
24537da2899SCharles.Forsyth 	tko[1].ptr = tke;
24637da2899SCharles.Forsyth 	tko[1].optab = opts;
24737da2899SCharles.Forsyth 	tko[2].ptr = nil;
24837da2899SCharles.Forsyth 
24937da2899SCharles.Forsyth 	names = nil;
25037da2899SCharles.Forsyth 	e = tkparse(t, arg, tko, &names);
25137da2899SCharles.Forsyth 	if(e != nil) {
25237da2899SCharles.Forsyth 		tkfreeobj(tk);
25337da2899SCharles.Forsyth 		return e;
25437da2899SCharles.Forsyth 	}
25537da2899SCharles.Forsyth 	tksettransparent(tk, tkhasalpha(tk->env, TkCbackgnd));
25637da2899SCharles.Forsyth 	tksizeentry(tk);
25737da2899SCharles.Forsyth 	e = tkbindings(t, tk, b, nelem(b));
25837da2899SCharles.Forsyth 
25937da2899SCharles.Forsyth 	if(e != nil) {
26037da2899SCharles.Forsyth 		tkfreeobj(tk);
26137da2899SCharles.Forsyth 		return e;
26237da2899SCharles.Forsyth 	}
26337da2899SCharles.Forsyth 
26437da2899SCharles.Forsyth 	e = tkaddchild(t, tk, &names);
26537da2899SCharles.Forsyth 	tkfreename(names);
26637da2899SCharles.Forsyth 	if(e != nil) {
26737da2899SCharles.Forsyth 		tkfreeobj(tk);
26837da2899SCharles.Forsyth 		return e;
26937da2899SCharles.Forsyth 	}
27037da2899SCharles.Forsyth 	tk->name->link = nil;
27137da2899SCharles.Forsyth 	recalcentry(tk);
27237da2899SCharles.Forsyth 
27337da2899SCharles.Forsyth 	return tkvalue(ret, "%s", tk->name->name);
27437da2899SCharles.Forsyth }
27537da2899SCharles.Forsyth 
27637da2899SCharles.Forsyth static char*
tkentrycget(Tk * tk,char * arg,char ** val)27737da2899SCharles.Forsyth tkentrycget(Tk *tk, char *arg, char **val)
27837da2899SCharles.Forsyth {
27937da2899SCharles.Forsyth 	TkOptab tko[3];
28037da2899SCharles.Forsyth 	TkEntry *tke = TKobj(TkEntry, tk);
28137da2899SCharles.Forsyth 
28237da2899SCharles.Forsyth 	tko[0].ptr = tk;
28337da2899SCharles.Forsyth 	tko[0].optab = tkgeneric;
28437da2899SCharles.Forsyth 	tko[1].ptr = tke;
28537da2899SCharles.Forsyth 	tko[1].optab = opts;
28637da2899SCharles.Forsyth 	tko[2].ptr = nil;
28737da2899SCharles.Forsyth 
28837da2899SCharles.Forsyth 	return tkgencget(tko, arg, val, tk->env->top);
28937da2899SCharles.Forsyth }
29037da2899SCharles.Forsyth 
29137da2899SCharles.Forsyth void
tkfreeentry(Tk * tk)29237da2899SCharles.Forsyth tkfreeentry(Tk *tk)
29337da2899SCharles.Forsyth {
29437da2899SCharles.Forsyth 	TkEntry *tke = TKobj(TkEntry, tk);
29537da2899SCharles.Forsyth 
29637da2899SCharles.Forsyth 	free(tke->xscroll);
29737da2899SCharles.Forsyth 	free(tke->text);
29837da2899SCharles.Forsyth 	free(tke->show);
29937da2899SCharles.Forsyth }
30037da2899SCharles.Forsyth 
30137da2899SCharles.Forsyth static void
tkentrytext(Image * i,Rectangle s,Tk * tk,TkEnv * env)30237da2899SCharles.Forsyth tkentrytext(Image *i, Rectangle s, Tk *tk, TkEnv *env)
30337da2899SCharles.Forsyth {
30437da2899SCharles.Forsyth 	TkEntry *tke = TKobj(TkEntry, tk);
30537da2899SCharles.Forsyth 	Point dp;
30637da2899SCharles.Forsyth 	int s0, s1, xs0, xs1, j;
30737da2899SCharles.Forsyth 	Rectangle r;
30837da2899SCharles.Forsyth 	Rune showr, *text;
30937da2899SCharles.Forsyth 
31037da2899SCharles.Forsyth 	dp = Pt(s.min.x - (tke->x0 - tke->xv0), s.min.y);
31137da2899SCharles.Forsyth 	if (tke->show) {
31237da2899SCharles.Forsyth 		chartorune(&showr, tke->show);
31337da2899SCharles.Forsyth 		text = mallocz(sizeof(Rune) * (tke->textlen+1), 0);
31437da2899SCharles.Forsyth 		if (text == nil)
31537da2899SCharles.Forsyth 			return;
31637da2899SCharles.Forsyth 		for (j = 0; j < tke->textlen; j++)
31737da2899SCharles.Forsyth 			text[j] = showr;
31837da2899SCharles.Forsyth 	} else
31937da2899SCharles.Forsyth 		text = tke->text;
32037da2899SCharles.Forsyth 
32137da2899SCharles.Forsyth 	runestringn(i, dp, tkgc(env, TkCforegnd), dp, env->font,
32237da2899SCharles.Forsyth 				text+tke->v0, tke->v1-tke->v0);
32337da2899SCharles.Forsyth 
32437da2899SCharles.Forsyth 	if (tke->sel0 < tke->v1 && tke->sel1 > tke->v0) {
32537da2899SCharles.Forsyth 		if (tke->sel0 < tke->v0) {
32637da2899SCharles.Forsyth 			s0 = tke->v0;
32737da2899SCharles.Forsyth 			xs0 = tke->xv0 - tke->x0;
32837da2899SCharles.Forsyth 		} else {
32937da2899SCharles.Forsyth 			s0 = tke->sel0;
33037da2899SCharles.Forsyth 			xs0 = tke->xsel0 - tke->x0;
33137da2899SCharles.Forsyth 		}
33237da2899SCharles.Forsyth 
33337da2899SCharles.Forsyth 		if (tke->sel1 > tke->v1) {
33437da2899SCharles.Forsyth 			s1 = tke->v1;
33537da2899SCharles.Forsyth 			xs1 = s.max.x;
33637da2899SCharles.Forsyth 		} else {
33737da2899SCharles.Forsyth 			s1 = tke->sel1;
33837da2899SCharles.Forsyth 			xs1 = tke->xsel1 - tke->x0;
33937da2899SCharles.Forsyth 		}
34037da2899SCharles.Forsyth 
34137da2899SCharles.Forsyth 		r = rectaddpt(Rect(xs0, 0, xs1, env->font->height), s.min);
34237da2899SCharles.Forsyth 		tktextsdraw(i, r, env, 1);
34337da2899SCharles.Forsyth 		runestringn(i, r.min, tkgc(env, TkCselectfgnd), r.min, env->font,
34437da2899SCharles.Forsyth 				text+s0, s1-s0);
34537da2899SCharles.Forsyth 	}
34637da2899SCharles.Forsyth 
34737da2899SCharles.Forsyth 	if((tke->flag&Ecursoron) && tke->icursor >= tke->v0 && tke->icursor <= tke->v1) {
34837da2899SCharles.Forsyth 		r = Rect(
34937da2899SCharles.Forsyth 			tke->xicursor - tke->x0, 0,
35037da2899SCharles.Forsyth 			tke->xicursor - tke->x0 + Inswidth, env->font->height
35137da2899SCharles.Forsyth 		);
35237da2899SCharles.Forsyth 		draw(i, rectaddpt(r, s.min), tkgc(env, TkCforegnd), nil, ZP);
35337da2899SCharles.Forsyth 	}
35437da2899SCharles.Forsyth 	if (tke->show)
35537da2899SCharles.Forsyth 		free(text);
35637da2899SCharles.Forsyth }
35737da2899SCharles.Forsyth 
35837da2899SCharles.Forsyth char*
tkdrawentry(Tk * tk,Point orig)35937da2899SCharles.Forsyth tkdrawentry(Tk *tk, Point orig)
36037da2899SCharles.Forsyth {
36137da2899SCharles.Forsyth 	Point p;
36237da2899SCharles.Forsyth 	TkEnv *env;
36337da2899SCharles.Forsyth 	Rectangle r, s;
36437da2899SCharles.Forsyth 	Image *i;
36537da2899SCharles.Forsyth 	int xp, yp;
36637da2899SCharles.Forsyth 
36737da2899SCharles.Forsyth 	env = tk->env;
36837da2899SCharles.Forsyth 
36937da2899SCharles.Forsyth 	r.min = ZP;
37037da2899SCharles.Forsyth 	r.max.x = tk->act.width + 2*tk->borderwidth;
37137da2899SCharles.Forsyth 	r.max.y = tk->act.height + 2*tk->borderwidth;
37237da2899SCharles.Forsyth 	i = tkitmp(env, r.max, TkCbackgnd);
37337da2899SCharles.Forsyth 	if(i == nil)
37437da2899SCharles.Forsyth 		return nil;
37537da2899SCharles.Forsyth 
37637da2899SCharles.Forsyth 	xp = tk->borderwidth + xinset(tk);
37737da2899SCharles.Forsyth 	yp = tk->borderwidth + yinset(tk);
37837da2899SCharles.Forsyth 	s = r;
37937da2899SCharles.Forsyth 	s.min.x += xp;
38037da2899SCharles.Forsyth 	s.max.x -= xp;
38137da2899SCharles.Forsyth 	s.min.y += yp;
38237da2899SCharles.Forsyth 	s.max.y -= yp;
38337da2899SCharles.Forsyth 	tkentrytext(i, s, tk, env);
38437da2899SCharles.Forsyth 
38537da2899SCharles.Forsyth 	tkdrawrelief(i, tk, ZP, TkCbackgnd, tk->relief);
38637da2899SCharles.Forsyth 
38737da2899SCharles.Forsyth 	if (tkhaskeyfocus(tk))
38837da2899SCharles.Forsyth 		tkbox(i, insetrect(r, tk->borderwidth), tk->highlightwidth, tkgc(tk->env, TkChighlightfgnd));
38937da2899SCharles.Forsyth 
39037da2899SCharles.Forsyth 	p.x = tk->act.x + orig.x;
39137da2899SCharles.Forsyth 	p.y = tk->act.y + orig.y;
39237da2899SCharles.Forsyth 	r = rectaddpt(r, p);
39337da2899SCharles.Forsyth 	draw(tkimageof(tk), r, i, nil, ZP);
39437da2899SCharles.Forsyth 
39537da2899SCharles.Forsyth 	return nil;
39637da2899SCharles.Forsyth }
39737da2899SCharles.Forsyth 
39837da2899SCharles.Forsyth char*
tkentrysh(Tk * tk)39937da2899SCharles.Forsyth tkentrysh(Tk *tk)
40037da2899SCharles.Forsyth {
40137da2899SCharles.Forsyth 	TkEntry *tke = TKobj(TkEntry, tk);
40237da2899SCharles.Forsyth 	int dx, top, bot;
40337da2899SCharles.Forsyth 	char *val, *cmd, *v, *e;
40437da2899SCharles.Forsyth 
40537da2899SCharles.Forsyth 	if(tke->xscroll == nil)
40637da2899SCharles.Forsyth 		return nil;
40737da2899SCharles.Forsyth 
40837da2899SCharles.Forsyth 	bot = 0;
40937da2899SCharles.Forsyth 	top = Tkfpscalar;
41037da2899SCharles.Forsyth 
41137da2899SCharles.Forsyth 	if(tke->text != 0 && tke->textlen != 0) {
41237da2899SCharles.Forsyth 		dx = tk->act.width - 2*xinset(tk);
41337da2899SCharles.Forsyth 
41437da2899SCharles.Forsyth 		if (tke->xlen > dx) {
41537da2899SCharles.Forsyth 			bot = TKI2F(tke->x0) / tke->xlen;
41637da2899SCharles.Forsyth 			top = TKI2F(tke->x0 + dx) / tke->xlen;
41737da2899SCharles.Forsyth 		}
41837da2899SCharles.Forsyth 	}
41937da2899SCharles.Forsyth 
42037da2899SCharles.Forsyth 	val = mallocz(Tkminitem, 0);
42137da2899SCharles.Forsyth 	if(val == nil)
42237da2899SCharles.Forsyth 		return TkNomem;
42337da2899SCharles.Forsyth 	v = tkfprint(val, bot);
42437da2899SCharles.Forsyth 	*v++ = ' ';
42537da2899SCharles.Forsyth 	tkfprint(v, top);
42637da2899SCharles.Forsyth 	cmd = mallocz(Tkminitem, 0);
42737da2899SCharles.Forsyth 	if(cmd == nil) {
42837da2899SCharles.Forsyth 		free(val);
42937da2899SCharles.Forsyth 		return TkNomem;
43037da2899SCharles.Forsyth 	}
43137da2899SCharles.Forsyth 	sprint(cmd, "%s %s", tke->xscroll, val);
43237da2899SCharles.Forsyth 	e = tkexec(tk->env->top, cmd, nil);
43337da2899SCharles.Forsyth 	free(cmd);
43437da2899SCharles.Forsyth 	free(val);
43537da2899SCharles.Forsyth 	return e;
43637da2899SCharles.Forsyth }
43737da2899SCharles.Forsyth 
43837da2899SCharles.Forsyth void
tkentrygeom(Tk * tk)43937da2899SCharles.Forsyth tkentrygeom(Tk *tk)
44037da2899SCharles.Forsyth {
44137da2899SCharles.Forsyth 	char *e;
44237da2899SCharles.Forsyth 	e = tkentrysh(tk);
44337da2899SCharles.Forsyth 	if ((e != nil) &&	/* XXX - Tad: should propagate not print */
44437da2899SCharles.Forsyth              (tk->name != nil))
44537da2899SCharles.Forsyth 		print("tk: xscrollcommand \"%s\": %s\n", tk->name->name, e);
44637da2899SCharles.Forsyth 	recalcentry(tk);
44737da2899SCharles.Forsyth }
44837da2899SCharles.Forsyth 
44937da2899SCharles.Forsyth static char*
tkentryconf(Tk * tk,char * arg,char ** val)45037da2899SCharles.Forsyth tkentryconf(Tk *tk, char *arg, char **val)
45137da2899SCharles.Forsyth {
45237da2899SCharles.Forsyth 	char *e;
45337da2899SCharles.Forsyth 	TkGeom g;
45437da2899SCharles.Forsyth 	int bd;
45537da2899SCharles.Forsyth 	TkOptab tko[3];
45637da2899SCharles.Forsyth 	TkEntry *tke = TKobj(TkEntry, tk);
45737da2899SCharles.Forsyth 
45837da2899SCharles.Forsyth 	tko[0].ptr = tk;
45937da2899SCharles.Forsyth 	tko[0].optab = tkgeneric;
46037da2899SCharles.Forsyth 	tko[1].ptr = tke;
46137da2899SCharles.Forsyth 	tko[1].optab = opts;
46237da2899SCharles.Forsyth 	tko[2].ptr = nil;
46337da2899SCharles.Forsyth 
46437da2899SCharles.Forsyth 	if(*arg == '\0')
46537da2899SCharles.Forsyth 		return tkconflist(tko, val);
46637da2899SCharles.Forsyth 
46737da2899SCharles.Forsyth 	bd = tk->borderwidth;
46837da2899SCharles.Forsyth 	g = tk->req;
46937da2899SCharles.Forsyth 	e = tkparse(tk->env->top, arg, tko, nil);
47037da2899SCharles.Forsyth 	tksettransparent(tk, tkhasalpha(tk->env, TkCbackgnd));
47137da2899SCharles.Forsyth 	tksizeentry(tk);
47237da2899SCharles.Forsyth 	tkgeomchg(tk, &g, bd);
47337da2899SCharles.Forsyth 	recalcentry(tk);
47437da2899SCharles.Forsyth 	tk->dirty = tkrect(tk, 1);
47537da2899SCharles.Forsyth 	return e;
47637da2899SCharles.Forsyth }
47737da2899SCharles.Forsyth 
47837da2899SCharles.Forsyth static char*
tkentryparseindex(Tk * tk,char * buf,int * index)47937da2899SCharles.Forsyth tkentryparseindex(Tk *tk, char *buf, int *index)
48037da2899SCharles.Forsyth {
48137da2899SCharles.Forsyth 	TkEntry *tke = TKobj(TkEntry, tk);
48237da2899SCharles.Forsyth 	TkEnv *env;
48337da2899SCharles.Forsyth 	char *mod;
48437da2899SCharles.Forsyth 	int i, x, locked, modstart;
48537da2899SCharles.Forsyth 
48637da2899SCharles.Forsyth 	modstart = 0;
48737da2899SCharles.Forsyth 	for(mod = buf; *mod != '\0'; mod++)
48837da2899SCharles.Forsyth 		if(*mod == '-' || *mod == '+') {
48937da2899SCharles.Forsyth 			modstart = *mod;
49037da2899SCharles.Forsyth 			*mod = '\0';
49137da2899SCharles.Forsyth 			break;
49237da2899SCharles.Forsyth 		}
49337da2899SCharles.Forsyth 	if(strcmp(buf, "end") == 0)
49437da2899SCharles.Forsyth 		i = tke->textlen;
49537da2899SCharles.Forsyth 	else
49637da2899SCharles.Forsyth 	if(strcmp(buf, "anchor") == 0)
49737da2899SCharles.Forsyth 		i = tke->anchor;
49837da2899SCharles.Forsyth 	else
49937da2899SCharles.Forsyth 	if(strcmp(buf, "insert") == 0)
50037da2899SCharles.Forsyth 		i = tke->icursor;
50137da2899SCharles.Forsyth 	else
50237da2899SCharles.Forsyth 	if(strcmp(buf, "sel.first") == 0)
50337da2899SCharles.Forsyth 		i = tke->sel0;
50437da2899SCharles.Forsyth 	else
50537da2899SCharles.Forsyth 	if(strcmp(buf, "sel.last") == 0)
50637da2899SCharles.Forsyth 		i = tke->sel1;
50737da2899SCharles.Forsyth 	else
50837da2899SCharles.Forsyth 	if(buf[0] >= '0' && buf[0] <= '9')
50937da2899SCharles.Forsyth 		i = atoi(buf);
51037da2899SCharles.Forsyth 	else
51137da2899SCharles.Forsyth 	if(buf[0] == '@') {
51237da2899SCharles.Forsyth 		x = atoi(buf+1) - xinset(tk);
51337da2899SCharles.Forsyth 		if(tke->textlen == 0) {
51437da2899SCharles.Forsyth 			*index = 0;
51537da2899SCharles.Forsyth 			return nil;
51637da2899SCharles.Forsyth 		}
51737da2899SCharles.Forsyth 		env = tk->env;
51837da2899SCharles.Forsyth 		locked = lockdisplay(env->top->display);
51937da2899SCharles.Forsyth 		i = x2index(tk, x + tke->x0, nil);	/* XXX could possibly select nearest character? */
52037da2899SCharles.Forsyth 		if(locked)
52137da2899SCharles.Forsyth 			unlockdisplay(env->top->display);
52237da2899SCharles.Forsyth 	}
52337da2899SCharles.Forsyth 	else
52437da2899SCharles.Forsyth 		return TkBadix;
52537da2899SCharles.Forsyth 
52637da2899SCharles.Forsyth 	if(i < 0 || i > tke->textlen)
52737da2899SCharles.Forsyth 		return TkBadix;
52837da2899SCharles.Forsyth 	if(modstart) {
52937da2899SCharles.Forsyth 		*mod = modstart;
53037da2899SCharles.Forsyth 		i += atoi(mod);
53137da2899SCharles.Forsyth 		if(i < 0)
53237da2899SCharles.Forsyth 			i = 0;
53337da2899SCharles.Forsyth 		if(i > tke->textlen)
53437da2899SCharles.Forsyth 			i = tke->textlen;
53537da2899SCharles.Forsyth 	}
53637da2899SCharles.Forsyth 	*index = i;
53737da2899SCharles.Forsyth 	return nil;
53837da2899SCharles.Forsyth }
53937da2899SCharles.Forsyth 
54037da2899SCharles.Forsyth /*
54137da2899SCharles.Forsyth  * return bounding box of character at index, in coords relative to
54237da2899SCharles.Forsyth  * the top left position of the text.
54337da2899SCharles.Forsyth  */
54437da2899SCharles.Forsyth static Rectangle
tkentrybbox(Tk * tk,int index)54537da2899SCharles.Forsyth tkentrybbox(Tk *tk, int index)
54637da2899SCharles.Forsyth {
54737da2899SCharles.Forsyth 	TkEntry *tke;
54837da2899SCharles.Forsyth 	TkEnv *env;
54937da2899SCharles.Forsyth 	Display *d;
55037da2899SCharles.Forsyth 	int x, cw, locked;
55137da2899SCharles.Forsyth 	Rectangle r;
55237da2899SCharles.Forsyth 
55337da2899SCharles.Forsyth 	tke = TKobj(TkEntry, tk);
55437da2899SCharles.Forsyth 	env = tk->env;
55537da2899SCharles.Forsyth 
55637da2899SCharles.Forsyth 	d = env->top->display;
55737da2899SCharles.Forsyth 
55837da2899SCharles.Forsyth 	locked = lockdisplay(d);
55937da2899SCharles.Forsyth 	x = entrytextwidth(tk, index);
56037da2899SCharles.Forsyth 	if (index < tke->textlen)
56137da2899SCharles.Forsyth 		cw = entrytextwidth(tk, index+1) - x;
56237da2899SCharles.Forsyth 	else
56337da2899SCharles.Forsyth 		cw = Inswidth;
56437da2899SCharles.Forsyth 	if(locked)
56537da2899SCharles.Forsyth 		unlockdisplay(d);
56637da2899SCharles.Forsyth 
56737da2899SCharles.Forsyth 	r.min.x = x;
56837da2899SCharles.Forsyth 	r.min.y = 0;
56937da2899SCharles.Forsyth 	r.max.x = x + cw;
57037da2899SCharles.Forsyth 	r.max.y = env->font->height;
57137da2899SCharles.Forsyth 	return r;
57237da2899SCharles.Forsyth }
57337da2899SCharles.Forsyth 
57437da2899SCharles.Forsyth static void
tkentrysee(Tk * tk,int index,int jump)57537da2899SCharles.Forsyth tkentrysee(Tk *tk, int index, int jump)
57637da2899SCharles.Forsyth {
57737da2899SCharles.Forsyth 	TkEntry *tke = TKobj(TkEntry, tk);
57837da2899SCharles.Forsyth 	int dx, margin;
57937da2899SCharles.Forsyth 	Rectangle r;
58037da2899SCharles.Forsyth 
58137da2899SCharles.Forsyth 	r = tkentrybbox(tk, index);
58237da2899SCharles.Forsyth 	dx = tk->act.width - 2*xinset(tk);
58337da2899SCharles.Forsyth 	if (jump)
58437da2899SCharles.Forsyth 		margin = dx / 4;
58537da2899SCharles.Forsyth 	else
58637da2899SCharles.Forsyth 		margin = 0;
58737da2899SCharles.Forsyth 	if (r.min.x <= tke->x0 || r.max.x > tke->x0 + dx) {
58837da2899SCharles.Forsyth 		if (r.min.x <= tke->x0) {
58937da2899SCharles.Forsyth 			tke->x0 = r.min.x - margin;
59037da2899SCharles.Forsyth 			if (tke->x0 < 0)
59137da2899SCharles.Forsyth 				tke->x0 = 0;
59237da2899SCharles.Forsyth 		} else if (r.max.x >= tke->x0 + dx) {
59337da2899SCharles.Forsyth 			tke->x0 = r.max.x - dx + margin;
59437da2899SCharles.Forsyth 			if (tke->x0 > tke->xlen - dx)
59537da2899SCharles.Forsyth 				tke->x0 = tke->xlen - dx;
59637da2899SCharles.Forsyth 		}
59737da2899SCharles.Forsyth 		tk->dirty = tkrect(tk, 0);
59837da2899SCharles.Forsyth 	}
59937da2899SCharles.Forsyth 	r = rectaddpt(r, Pt(xinset(tk) - tke->x0, yinset(tk)));
60037da2899SCharles.Forsyth 	tksee(tk, r, r.min);
60137da2899SCharles.Forsyth }
60237da2899SCharles.Forsyth 
60337da2899SCharles.Forsyth static char*
tkentryseecmd(Tk * tk,char * arg,char ** val)60437da2899SCharles.Forsyth tkentryseecmd(Tk *tk, char *arg, char **val)
60537da2899SCharles.Forsyth {
60637da2899SCharles.Forsyth 	int index;
60737da2899SCharles.Forsyth 	char *e, *buf;
60837da2899SCharles.Forsyth 
60937da2899SCharles.Forsyth 	USED(val);
61037da2899SCharles.Forsyth 
61137da2899SCharles.Forsyth 	buf = mallocz(Tkmaxitem, 0);
61237da2899SCharles.Forsyth 	if(buf == nil)
61337da2899SCharles.Forsyth 		return TkNomem;
61437da2899SCharles.Forsyth 	tkword(tk->env->top, arg, buf, buf+Tkmaxitem, nil);
61537da2899SCharles.Forsyth 	e = tkentryparseindex(tk, buf, &index);
61637da2899SCharles.Forsyth 	free(buf);
61737da2899SCharles.Forsyth 	if(e != nil)
61837da2899SCharles.Forsyth 		return e;
61937da2899SCharles.Forsyth 
62037da2899SCharles.Forsyth 	tkentrysee(tk, index, 1);
62137da2899SCharles.Forsyth 	recalcentry(tk);
62237da2899SCharles.Forsyth 
62337da2899SCharles.Forsyth 	return nil;
62437da2899SCharles.Forsyth }
62537da2899SCharles.Forsyth 
62637da2899SCharles.Forsyth static char*
tkentrybboxcmd(Tk * tk,char * arg,char ** val)62737da2899SCharles.Forsyth tkentrybboxcmd(Tk *tk, char *arg, char **val)
62837da2899SCharles.Forsyth {
62937da2899SCharles.Forsyth 	TkEntry *tke = TKobj(TkEntry, tk);
63037da2899SCharles.Forsyth 	char *r, *buf;
63137da2899SCharles.Forsyth 	int index;
63237da2899SCharles.Forsyth 	Rectangle bbox;
63337da2899SCharles.Forsyth 
63437da2899SCharles.Forsyth 	buf = mallocz(Tkmaxitem, 0);
63537da2899SCharles.Forsyth 	if(buf == nil)
63637da2899SCharles.Forsyth 		return TkNomem;
63737da2899SCharles.Forsyth 	tkword(tk->env->top, arg, buf, buf+Tkmaxitem, nil);
63837da2899SCharles.Forsyth 	r = tkentryparseindex(tk, buf, &index);
63937da2899SCharles.Forsyth 	free(buf);
64037da2899SCharles.Forsyth 	if(r != nil)
64137da2899SCharles.Forsyth 		return r;
64237da2899SCharles.Forsyth 	bbox = rectaddpt(tkentrybbox(tk, index), Pt(xinset(tk) - tke->x0, yinset(tk)));
64337da2899SCharles.Forsyth 	return tkvalue(val, "%d %d %d %d", bbox.min.x, bbox.min.y, bbox.max.x, bbox.max.y);
64437da2899SCharles.Forsyth }
64537da2899SCharles.Forsyth 
64637da2899SCharles.Forsyth static char*
tkentryindex(Tk * tk,char * arg,char ** val)64737da2899SCharles.Forsyth tkentryindex(Tk *tk, char *arg, char **val)
64837da2899SCharles.Forsyth {
64937da2899SCharles.Forsyth 	int index;
65037da2899SCharles.Forsyth 	char *r, *buf;
65137da2899SCharles.Forsyth 
65237da2899SCharles.Forsyth 	buf = mallocz(Tkmaxitem, 0);
65337da2899SCharles.Forsyth 	if(buf == nil)
65437da2899SCharles.Forsyth 		return TkNomem;
65537da2899SCharles.Forsyth 	tkword(tk->env->top, arg, buf, buf+Tkmaxitem, nil);
65637da2899SCharles.Forsyth 	r = tkentryparseindex(tk, buf, &index);
65737da2899SCharles.Forsyth 	free(buf);
65837da2899SCharles.Forsyth 	if(r != nil)
65937da2899SCharles.Forsyth 		return r;
66037da2899SCharles.Forsyth 	return tkvalue(val, "%d", index);
66137da2899SCharles.Forsyth }
66237da2899SCharles.Forsyth 
66337da2899SCharles.Forsyth static char*
tkentryicursor(Tk * tk,char * arg,char ** val)66437da2899SCharles.Forsyth tkentryicursor(Tk *tk, char *arg, char **val)
66537da2899SCharles.Forsyth {
66637da2899SCharles.Forsyth 	TkEntry *tke = TKobj(TkEntry, tk);
66737da2899SCharles.Forsyth 	int index, locked;
66837da2899SCharles.Forsyth 	char *r, *buf;
66937da2899SCharles.Forsyth 
67037da2899SCharles.Forsyth 	USED(val);
67137da2899SCharles.Forsyth 	buf = mallocz(Tkmaxitem, 0);
67237da2899SCharles.Forsyth 	if(buf == nil)
67337da2899SCharles.Forsyth 		return TkNomem;
67437da2899SCharles.Forsyth 	tkword(tk->env->top, arg, buf, buf+Tkmaxitem, nil);
67537da2899SCharles.Forsyth 	r = tkentryparseindex(tk, buf, &index);
67637da2899SCharles.Forsyth 	free(buf);
67737da2899SCharles.Forsyth 	if(r != nil)
67837da2899SCharles.Forsyth 		return r;
67937da2899SCharles.Forsyth 	tke->icursor = index;
68037da2899SCharles.Forsyth 	locked = lockdisplay(tk->env->top->display);
68137da2899SCharles.Forsyth 	tke->xicursor = entrytextwidth(tk, tke->icursor);
68237da2899SCharles.Forsyth 	if (locked)
68337da2899SCharles.Forsyth 		unlockdisplay(tk->env->top->display);
68437da2899SCharles.Forsyth 
68537da2899SCharles.Forsyth 	blinkreset(tk);
68637da2899SCharles.Forsyth 	tk->dirty = tkrect(tk, 1);
68737da2899SCharles.Forsyth 	return nil;
68837da2899SCharles.Forsyth }
68937da2899SCharles.Forsyth 
69037da2899SCharles.Forsyth static int
adjustforins(int i,int n,int q)69137da2899SCharles.Forsyth adjustforins(int i, int n, int q)
69237da2899SCharles.Forsyth {
69337da2899SCharles.Forsyth 	if (i <= q)
69437da2899SCharles.Forsyth 		q += n;
69537da2899SCharles.Forsyth 	return q;
69637da2899SCharles.Forsyth }
69737da2899SCharles.Forsyth 
69837da2899SCharles.Forsyth static int
adjustfordel(int d0,int d1,int q)69937da2899SCharles.Forsyth adjustfordel(int d0, int d1, int q)
70037da2899SCharles.Forsyth {
70137da2899SCharles.Forsyth 	if (d1 <= q)
70237da2899SCharles.Forsyth 		q -= d1 - d0;
70337da2899SCharles.Forsyth 	else if (d0 <= q && q <= d1)
70437da2899SCharles.Forsyth 		q = d0;
70537da2899SCharles.Forsyth 	return q;
70637da2899SCharles.Forsyth }
70737da2899SCharles.Forsyth 
70837da2899SCharles.Forsyth static char*
tkentryget(Tk * tk,char * arg,char ** val)70937da2899SCharles.Forsyth tkentryget(Tk *tk, char *arg, char **val)
71037da2899SCharles.Forsyth {
71137da2899SCharles.Forsyth 	TkTop *top;
71237da2899SCharles.Forsyth 	TkEntry *tke;
71337da2899SCharles.Forsyth 	int first, last;
71437da2899SCharles.Forsyth 	char *e, *buf;
71537da2899SCharles.Forsyth 
71637da2899SCharles.Forsyth 	tke = TKobj(TkEntry, tk);
71737da2899SCharles.Forsyth 	if(tke->text == nil)
71837da2899SCharles.Forsyth 		return nil;
71937da2899SCharles.Forsyth 
72037da2899SCharles.Forsyth 	arg = tkskip(arg, " \t");
72137da2899SCharles.Forsyth 	if(*arg == '\0')
72237da2899SCharles.Forsyth 		return tkvalue(val, "%.*S", tke->textlen, tke->text);
72337da2899SCharles.Forsyth 
72437da2899SCharles.Forsyth 	top = tk->env->top;
72537da2899SCharles.Forsyth 	buf = mallocz(Tkmaxitem, 0);
72637da2899SCharles.Forsyth 	if(buf == nil)
72737da2899SCharles.Forsyth 		return TkNomem;
72837da2899SCharles.Forsyth 	arg = tkword(top, arg, buf, buf+Tkmaxitem, nil);
72937da2899SCharles.Forsyth 	e = tkentryparseindex(tk, buf, &first);
73037da2899SCharles.Forsyth 	if(e != nil) {
73137da2899SCharles.Forsyth 		free(buf);
73237da2899SCharles.Forsyth 		return e;
73337da2899SCharles.Forsyth 	}
73437da2899SCharles.Forsyth 	last = first+1;
73537da2899SCharles.Forsyth 	tkword(top, arg, buf, buf+Tkmaxitem, nil);
73637da2899SCharles.Forsyth 	if(buf[0] != '\0') {
73737da2899SCharles.Forsyth 		e = tkentryparseindex(tk, buf, &last);
73837da2899SCharles.Forsyth 		if(e != nil) {
73937da2899SCharles.Forsyth 			free(buf);
74037da2899SCharles.Forsyth 			return e;
74137da2899SCharles.Forsyth 		}
74237da2899SCharles.Forsyth 	}
74337da2899SCharles.Forsyth 	free(buf);
74437da2899SCharles.Forsyth 	if(last <= first || tke->textlen == 0 || first == tke->textlen)
74537da2899SCharles.Forsyth 		return tkvalue(val, "%S", L"");
74637da2899SCharles.Forsyth 	return tkvalue(val, "%.*S", last-first, tke->text+first);
74737da2899SCharles.Forsyth }
74837da2899SCharles.Forsyth 
74937da2899SCharles.Forsyth static char*
tkentryinsert(Tk * tk,char * arg,char ** val)75037da2899SCharles.Forsyth tkentryinsert(Tk *tk, char *arg, char **val)
75137da2899SCharles.Forsyth {
75237da2899SCharles.Forsyth 	TkTop *top;
75337da2899SCharles.Forsyth 	TkEntry *tke;
75437da2899SCharles.Forsyth 	int ins, i, n, locked;
75537da2899SCharles.Forsyth 	char *e, *t, *text, *buf;
75637da2899SCharles.Forsyth 	Rune *etext;
75737da2899SCharles.Forsyth 
75837da2899SCharles.Forsyth 	USED(val);
75937da2899SCharles.Forsyth 	tke = TKobj(TkEntry, tk);
76037da2899SCharles.Forsyth 
76137da2899SCharles.Forsyth 	top = tk->env->top;
76237da2899SCharles.Forsyth 	buf = mallocz(Tkmaxitem, 0);
76337da2899SCharles.Forsyth 	if(buf == nil)
76437da2899SCharles.Forsyth 		return TkNomem;
76537da2899SCharles.Forsyth 	arg = tkword(top, arg, buf, buf+Tkmaxitem, nil);
76637da2899SCharles.Forsyth 	e = tkentryparseindex(tk, buf, &ins);
76737da2899SCharles.Forsyth 	free(buf);
76837da2899SCharles.Forsyth 	if(e != nil)
76937da2899SCharles.Forsyth 		return e;
77037da2899SCharles.Forsyth 
77137da2899SCharles.Forsyth 	if(*arg == '\0')
77237da2899SCharles.Forsyth 		return nil;
77337da2899SCharles.Forsyth 
77437da2899SCharles.Forsyth 	n = strlen(arg) + 1;
77537da2899SCharles.Forsyth 	if(n < Tkmaxitem)
77637da2899SCharles.Forsyth 		n = Tkmaxitem;
77737da2899SCharles.Forsyth 	text = malloc(n);
77837da2899SCharles.Forsyth 	if(text == nil)
77937da2899SCharles.Forsyth 		return TkNomem;
78037da2899SCharles.Forsyth 
78137da2899SCharles.Forsyth 	tkword(top, arg, text, text+n, nil);
78237da2899SCharles.Forsyth 	n = utflen(text);
78337da2899SCharles.Forsyth 	etext = realloc(tke->text, (tke->textlen+n+1)*sizeof(Rune));
78437da2899SCharles.Forsyth 	if(etext == nil) {
78537da2899SCharles.Forsyth 		free(text);
78637da2899SCharles.Forsyth 		return TkNomem;
78737da2899SCharles.Forsyth 	}
78837da2899SCharles.Forsyth 	tke->text = etext;
78937da2899SCharles.Forsyth 
79037da2899SCharles.Forsyth 	memmove(tke->text+ins+n, tke->text+ins, (tke->textlen-ins)*sizeof(Rune));
79137da2899SCharles.Forsyth 	t = text;
79237da2899SCharles.Forsyth 	for(i=0; i<n; i++)
79337da2899SCharles.Forsyth 		t += chartorune(tke->text+ins+i, t);
79437da2899SCharles.Forsyth 	free(text);
79537da2899SCharles.Forsyth 
79637da2899SCharles.Forsyth 	tke->textlen += n;
79737da2899SCharles.Forsyth 
79837da2899SCharles.Forsyth 	tke->sel0 = adjustforins(ins, n, tke->sel0);
79937da2899SCharles.Forsyth 	tke->sel1 = adjustforins(ins, n, tke->sel1);
80037da2899SCharles.Forsyth 	tke->icursor = adjustforins(ins, n, tke->icursor);
80137da2899SCharles.Forsyth 	tke->anchor = adjustforins(ins, n, tke->anchor);
80237da2899SCharles.Forsyth 
80337da2899SCharles.Forsyth 	locked = lockdisplay(tk->env->top->display);
80437da2899SCharles.Forsyth 	if (ins < tke->v0)
80537da2899SCharles.Forsyth 		tke->x0 += entrytextwidth(tk, tke->v0 + n) + (tke->x0 - tke->xv0);
80637da2899SCharles.Forsyth 	if (locked)
80737da2899SCharles.Forsyth 		unlockdisplay(tk->env->top->display);
80837da2899SCharles.Forsyth 	recalcentry(tk);
80937da2899SCharles.Forsyth 
81037da2899SCharles.Forsyth 	e = tkentrysh(tk);
81137da2899SCharles.Forsyth 	blinkreset(tk);
81237da2899SCharles.Forsyth 	tk->dirty = tkrect(tk, 1);
81337da2899SCharles.Forsyth 
81437da2899SCharles.Forsyth 	return e;
81537da2899SCharles.Forsyth }
81637da2899SCharles.Forsyth 
81737da2899SCharles.Forsyth static char*
tkentrydelete(Tk * tk,char * arg,char ** val)81837da2899SCharles.Forsyth tkentrydelete(Tk *tk, char *arg, char **val)
81937da2899SCharles.Forsyth {
82037da2899SCharles.Forsyth 	TkTop *top;
82137da2899SCharles.Forsyth 	TkEntry *tke;
82237da2899SCharles.Forsyth 	int d0, d1, locked;
82337da2899SCharles.Forsyth 	char *e, *buf;
82437da2899SCharles.Forsyth 	Rune *text;
82537da2899SCharles.Forsyth 
82637da2899SCharles.Forsyth 	USED(val);
82737da2899SCharles.Forsyth 
82837da2899SCharles.Forsyth 	tke = TKobj(TkEntry, tk);
82937da2899SCharles.Forsyth 
83037da2899SCharles.Forsyth 	top = tk->env->top;
83137da2899SCharles.Forsyth 	buf = mallocz(Tkmaxitem, 0);
83237da2899SCharles.Forsyth 	if(buf == nil)
83337da2899SCharles.Forsyth 		return TkNomem;
83437da2899SCharles.Forsyth 	arg = tkword(top, arg, buf, buf+Tkmaxitem, nil);
83537da2899SCharles.Forsyth 	e = tkentryparseindex(tk, buf, &d0);
83637da2899SCharles.Forsyth 	if(e != nil) {
83737da2899SCharles.Forsyth 		free(buf);
83837da2899SCharles.Forsyth 		return e;
83937da2899SCharles.Forsyth 	}
84037da2899SCharles.Forsyth 
84137da2899SCharles.Forsyth 	d1 = d0+1;
84237da2899SCharles.Forsyth 	tkword(top, arg, buf, buf+Tkmaxitem, nil);
84337da2899SCharles.Forsyth 	if(buf[0] != '\0') {
84437da2899SCharles.Forsyth 		e = tkentryparseindex(tk, buf, &d1);
84537da2899SCharles.Forsyth 		if(e != nil) {
84637da2899SCharles.Forsyth 			free(buf);
84737da2899SCharles.Forsyth 			return e;
84837da2899SCharles.Forsyth 		}
84937da2899SCharles.Forsyth 	}
85037da2899SCharles.Forsyth 	free(buf);
85137da2899SCharles.Forsyth 	if(d1 <= d0 || tke->textlen == 0 || d0 >= tke->textlen)
85237da2899SCharles.Forsyth 		return nil;
85337da2899SCharles.Forsyth 
85437da2899SCharles.Forsyth 	memmove(tke->text+d0, tke->text+d1, (tke->textlen-d1)*sizeof(Rune));
85537da2899SCharles.Forsyth 	tke->textlen -= d1 - d0;
85637da2899SCharles.Forsyth 
85737da2899SCharles.Forsyth 	text = realloc(tke->text, (tke->textlen+1) * sizeof(Rune));
85837da2899SCharles.Forsyth 	if (text != nil)
85937da2899SCharles.Forsyth 		tke->text = text;
86037da2899SCharles.Forsyth 	tke->sel0 = adjustfordel(d0, d1, tke->sel0);
86137da2899SCharles.Forsyth 	tke->sel1 = adjustfordel(d0, d1, tke->sel1);
86237da2899SCharles.Forsyth 	tke->icursor = adjustfordel(d0, d1, tke->icursor);
86337da2899SCharles.Forsyth 	tke->anchor = adjustfordel(d0, d1, tke->anchor);
86437da2899SCharles.Forsyth 
86537da2899SCharles.Forsyth 	locked = lockdisplay(tk->env->top->display);
86637da2899SCharles.Forsyth 	if (d1 < tke->v0)
86737da2899SCharles.Forsyth 		tke->x0 = entrytextwidth(tk, tke->v0 - (d1 - d0)) + (tke->x0 - tke->xv0);
86837da2899SCharles.Forsyth 	else if (d0 < tke->v0)
86937da2899SCharles.Forsyth 		tke->x0 = entrytextwidth(tk, d0);
87037da2899SCharles.Forsyth 	if (locked)
87137da2899SCharles.Forsyth 		unlockdisplay(tk->env->top->display);
87237da2899SCharles.Forsyth 	recalcentry(tk);
87337da2899SCharles.Forsyth 
87437da2899SCharles.Forsyth 	e = tkentrysh(tk);
87537da2899SCharles.Forsyth 	blinkreset(tk);
87637da2899SCharles.Forsyth 	tk->dirty = tkrect(tk, 1);
87737da2899SCharles.Forsyth 
87837da2899SCharles.Forsyth 	return e;
87937da2899SCharles.Forsyth }
88037da2899SCharles.Forsyth 
88137da2899SCharles.Forsyth /*	Used for both backspace and DEL.  If a selection exists, delete it.
88237da2899SCharles.Forsyth  *	Otherwise delete the character to the left(right) of the insertion
88337da2899SCharles.Forsyth  *	cursor, if any.
88437da2899SCharles.Forsyth  */
88537da2899SCharles.Forsyth static char*
tkentrybs(Tk * tk,char * arg,char ** val)88637da2899SCharles.Forsyth tkentrybs(Tk *tk, char *arg, char **val)
88737da2899SCharles.Forsyth {
88837da2899SCharles.Forsyth 	TkEntry *tke = TKobj(TkEntry, tk);
88937da2899SCharles.Forsyth 	char *buf, *e;
89037da2899SCharles.Forsyth 	int ix;
89137da2899SCharles.Forsyth 
89237da2899SCharles.Forsyth 	USED(val);
89337da2899SCharles.Forsyth 	USED(arg);
89437da2899SCharles.Forsyth 
89537da2899SCharles.Forsyth 	if(tke->textlen == 0)
89637da2899SCharles.Forsyth 		return nil;
89737da2899SCharles.Forsyth 
89837da2899SCharles.Forsyth 	if(tke->sel0 < tke->sel1)
89937da2899SCharles.Forsyth 		return tkentrydelete(tk, "sel.first sel.last", nil);
90037da2899SCharles.Forsyth 
90137da2899SCharles.Forsyth 	buf = mallocz(Tkmaxitem, 0);
90237da2899SCharles.Forsyth 	if(buf == nil)
90337da2899SCharles.Forsyth 		return TkNomem;
90437da2899SCharles.Forsyth 	tkword(tk->env->top, arg, buf, buf+Tkmaxitem, nil);
90537da2899SCharles.Forsyth 	ix = -1;
90637da2899SCharles.Forsyth 	if(buf[0] != '\0') {
90737da2899SCharles.Forsyth 		e = tkentryparseindex(tk, buf, &ix);
90837da2899SCharles.Forsyth 		if(e != nil) {
90937da2899SCharles.Forsyth 			free(buf);
91037da2899SCharles.Forsyth 			return e;
91137da2899SCharles.Forsyth 		}
91237da2899SCharles.Forsyth 	}
91337da2899SCharles.Forsyth 	if(ix > -1) {			/* DEL */
91437da2899SCharles.Forsyth 		if(tke->icursor >= tke->textlen) {
91537da2899SCharles.Forsyth 			free(buf);
91637da2899SCharles.Forsyth 			return nil;
91737da2899SCharles.Forsyth 		}
91837da2899SCharles.Forsyth 	}
91937da2899SCharles.Forsyth 	else {				/* backspace */
92037da2899SCharles.Forsyth 		if(tke->icursor == 0) {
92137da2899SCharles.Forsyth 			free(buf);
92237da2899SCharles.Forsyth 			return nil;
92337da2899SCharles.Forsyth 		}
92437da2899SCharles.Forsyth 		tke->icursor--;
92537da2899SCharles.Forsyth 	}
92637da2899SCharles.Forsyth 	snprint(buf, Tkmaxitem, "%d", tke->icursor);
92737da2899SCharles.Forsyth 	e = tkentrydelete(tk, buf, nil);
92837da2899SCharles.Forsyth 	free(buf);
92937da2899SCharles.Forsyth 	return e;
93037da2899SCharles.Forsyth }
93137da2899SCharles.Forsyth 
93237da2899SCharles.Forsyth static char*
tkentrybw(Tk * tk,char * arg,char ** val)93337da2899SCharles.Forsyth tkentrybw(Tk *tk, char *arg, char **val)
93437da2899SCharles.Forsyth {
93537da2899SCharles.Forsyth 	int start;
93637da2899SCharles.Forsyth 	Rune *text;
93737da2899SCharles.Forsyth 	TkEntry *tke;
93837da2899SCharles.Forsyth 	char buf[32];
93937da2899SCharles.Forsyth 
94037da2899SCharles.Forsyth 	USED(val);
94137da2899SCharles.Forsyth 	USED(arg);
94237da2899SCharles.Forsyth 
94337da2899SCharles.Forsyth 	tke = TKobj(TkEntry, tk);
94437da2899SCharles.Forsyth 	if(tke->textlen == 0 || tke->icursor == 0)
94537da2899SCharles.Forsyth 		return nil;
94637da2899SCharles.Forsyth 
94737da2899SCharles.Forsyth 	text = tke->text;
94837da2899SCharles.Forsyth 	start = tke->icursor-1;
94937da2899SCharles.Forsyth 	while(start > 0 && !tkiswordchar(text[start]))
95037da2899SCharles.Forsyth 		--start;
95137da2899SCharles.Forsyth 	while(start > 0 && tkiswordchar(text[start-1]))
95237da2899SCharles.Forsyth 		--start;
95337da2899SCharles.Forsyth 
95437da2899SCharles.Forsyth 	snprint(buf, sizeof(buf), "%d %d", start, tke->icursor);
95537da2899SCharles.Forsyth 	return tkentrydelete(tk, buf, nil);
95637da2899SCharles.Forsyth }
95737da2899SCharles.Forsyth 
95837da2899SCharles.Forsyth char*
tkentryselect(Tk * tk,char * arg,char ** val)95937da2899SCharles.Forsyth tkentryselect(Tk *tk, char *arg, char **val)
96037da2899SCharles.Forsyth {
96137da2899SCharles.Forsyth 	TkTop *top;
96237da2899SCharles.Forsyth 	int start, from, to, locked;
96337da2899SCharles.Forsyth 	TkEntry *tke;
96437da2899SCharles.Forsyth 	char *e, *buf;
96537da2899SCharles.Forsyth 
96637da2899SCharles.Forsyth 	buf = mallocz(Tkmaxitem, 0);
96737da2899SCharles.Forsyth 	if(buf == nil)
96837da2899SCharles.Forsyth 		return TkNomem;
96937da2899SCharles.Forsyth 
97037da2899SCharles.Forsyth 	tke = TKobj(TkEntry, tk);
97137da2899SCharles.Forsyth 
97237da2899SCharles.Forsyth 	top = tk->env->top;
97337da2899SCharles.Forsyth 	arg = tkword(top, arg, buf, buf+Tkmaxitem, nil);
97437da2899SCharles.Forsyth 	if(strcmp(buf, "clear") == 0) {
97537da2899SCharles.Forsyth 		tke->sel0 = 0;
97637da2899SCharles.Forsyth 		tke->sel1 = 0;
97737da2899SCharles.Forsyth 	}
97837da2899SCharles.Forsyth 	else
97937da2899SCharles.Forsyth 	if(strcmp(buf, "from") == 0) {
98037da2899SCharles.Forsyth 		tkword(top, arg, buf, buf+Tkmaxitem, nil);
98137da2899SCharles.Forsyth 		e = tkentryparseindex(tk, buf, &tke->anchor);
98237da2899SCharles.Forsyth 		tke->flag &= ~Ewordsel;
98337da2899SCharles.Forsyth 		free(buf);
98437da2899SCharles.Forsyth 		return e;
98537da2899SCharles.Forsyth 	}
98637da2899SCharles.Forsyth 	else
98737da2899SCharles.Forsyth 	if(strcmp(buf, "to") == 0) {
98837da2899SCharles.Forsyth 		tkword(top, arg, buf, buf+Tkmaxitem, nil);
98937da2899SCharles.Forsyth 		e = tkentryparseindex(tk, buf, &to);
99037da2899SCharles.Forsyth 		if(e != nil) {
99137da2899SCharles.Forsyth 			free(buf);
99237da2899SCharles.Forsyth 			return e;
99337da2899SCharles.Forsyth 		}
99437da2899SCharles.Forsyth 
99537da2899SCharles.Forsyth 		if(to < tke->anchor) {
99637da2899SCharles.Forsyth 			if(tke->flag & Ewordsel)
99737da2899SCharles.Forsyth 				while(to > 0 && tkiswordchar(tke->text[to-1]))
99837da2899SCharles.Forsyth 					--to;
99937da2899SCharles.Forsyth 			tke->sel0 = to;
100037da2899SCharles.Forsyth 			tke->sel1 = tke->anchor;
100137da2899SCharles.Forsyth 		}
100237da2899SCharles.Forsyth 		else
100337da2899SCharles.Forsyth 		if(to >= tke->anchor) {
100437da2899SCharles.Forsyth 			if(tke->flag & Ewordsel)
100537da2899SCharles.Forsyth 				while(to < tke->textlen &&
100637da2899SCharles.Forsyth 						tkiswordchar(tke->text[to]))
100737da2899SCharles.Forsyth 					to++;
100837da2899SCharles.Forsyth 			tke->sel0 = tke->anchor;
100937da2899SCharles.Forsyth 			tke->sel1 = to;
101037da2899SCharles.Forsyth 		}
101137da2899SCharles.Forsyth 		tkentrysee(tk, to, 0);
101237da2899SCharles.Forsyth 		recalcentry(tk);
101337da2899SCharles.Forsyth 	}
101437da2899SCharles.Forsyth 	else
101537da2899SCharles.Forsyth 	if(strcmp(buf, "word") == 0) {	/* inferno invention */
101637da2899SCharles.Forsyth 		tkword(top, arg, buf, buf+Tkmaxitem, nil);
101737da2899SCharles.Forsyth 		e = tkentryparseindex(tk, buf, &start);
101837da2899SCharles.Forsyth 		if(e != nil) {
101937da2899SCharles.Forsyth 			free(buf);
102037da2899SCharles.Forsyth 			return e;
102137da2899SCharles.Forsyth 		}
102237da2899SCharles.Forsyth 		from = start;
102337da2899SCharles.Forsyth 		while(from > 0 && tkiswordchar(tke->text[from-1]))
102437da2899SCharles.Forsyth 			--from;
102537da2899SCharles.Forsyth 		to = start;
102637da2899SCharles.Forsyth 		while(to < tke->textlen && tkiswordchar(tke->text[to]))
102737da2899SCharles.Forsyth 			to++;
102837da2899SCharles.Forsyth 		tke->sel0 = from;
102937da2899SCharles.Forsyth 		tke->sel1 = to;
103037da2899SCharles.Forsyth 		tke->anchor = from;
103137da2899SCharles.Forsyth 		tke->icursor = from;
103237da2899SCharles.Forsyth 		tke->flag |= Ewordsel;
103337da2899SCharles.Forsyth 		locked = lockdisplay(tk->env->top->display);
103437da2899SCharles.Forsyth 		tke->xicursor = entrytextwidth(tk, tke->icursor);
103537da2899SCharles.Forsyth 		if (locked)
103637da2899SCharles.Forsyth 			unlockdisplay(tk->env->top->display);
103737da2899SCharles.Forsyth 	}
103837da2899SCharles.Forsyth 	else
103937da2899SCharles.Forsyth 	if(strcmp(buf, "present") == 0) {
104037da2899SCharles.Forsyth 		e = tkvalue(val, "%d", tke->sel1 > tke->sel0);
104137da2899SCharles.Forsyth 		free(buf);
104237da2899SCharles.Forsyth 		return e;
104337da2899SCharles.Forsyth 	}
104437da2899SCharles.Forsyth 	else
104537da2899SCharles.Forsyth 	if(strcmp(buf, "range") == 0) {
104637da2899SCharles.Forsyth 		arg = tkword(top, arg, buf, buf+Tkmaxitem, nil);
104737da2899SCharles.Forsyth 		e = tkentryparseindex(tk, buf, &from);
104837da2899SCharles.Forsyth 		if(e != nil) {
104937da2899SCharles.Forsyth 			free(buf);
105037da2899SCharles.Forsyth 			return e;
105137da2899SCharles.Forsyth 		}
105237da2899SCharles.Forsyth 		tkword(top, arg, buf, buf+Tkmaxitem, nil);
105337da2899SCharles.Forsyth 		e = tkentryparseindex(tk, buf, &to);
105437da2899SCharles.Forsyth 		if(e != nil) {
105537da2899SCharles.Forsyth 			free(buf);
105637da2899SCharles.Forsyth 			return e;
105737da2899SCharles.Forsyth 		}
105837da2899SCharles.Forsyth 		tke->sel0 = from;
105937da2899SCharles.Forsyth 		tke->sel1 = to;
106037da2899SCharles.Forsyth 		if(to <= from) {
106137da2899SCharles.Forsyth 			tke->sel0 = 0;
106237da2899SCharles.Forsyth 			tke->sel1 = 0;
106337da2899SCharles.Forsyth 		}
106437da2899SCharles.Forsyth 	}
106537da2899SCharles.Forsyth 	else
106637da2899SCharles.Forsyth 	if(strcmp(buf, "adjust") == 0) {
106737da2899SCharles.Forsyth 		tkword(top, arg, buf, buf+Tkmaxitem, nil);
106837da2899SCharles.Forsyth 		e = tkentryparseindex(tk, buf, &to);
106937da2899SCharles.Forsyth 		if(e != nil) {
107037da2899SCharles.Forsyth 			free(buf);
107137da2899SCharles.Forsyth 			return e;
107237da2899SCharles.Forsyth 		}
107337da2899SCharles.Forsyth 		if(tke->sel0 == 0 && tke->sel1 == 0) {
107437da2899SCharles.Forsyth 			tke->sel0 = tke->anchor;
107537da2899SCharles.Forsyth 			tke->sel1 = to;
107637da2899SCharles.Forsyth 		}
107737da2899SCharles.Forsyth 		else {
107837da2899SCharles.Forsyth 			if(abs(tke->sel0-to) < abs(tke->sel1-to)) {
107937da2899SCharles.Forsyth 				tke->sel0 = to;
108037da2899SCharles.Forsyth 				tke->anchor = tke->sel1;
108137da2899SCharles.Forsyth 			}
108237da2899SCharles.Forsyth 			else {
108337da2899SCharles.Forsyth 				tke->sel1 = to;
108437da2899SCharles.Forsyth 				tke->anchor = tke->sel0;
108537da2899SCharles.Forsyth 			}
108637da2899SCharles.Forsyth 		}
108737da2899SCharles.Forsyth 		if(tke->sel0 > tke->sel1) {
108837da2899SCharles.Forsyth 			to = tke->sel0;
108937da2899SCharles.Forsyth 			tke->sel0 = tke->sel1;
109037da2899SCharles.Forsyth 			tke->sel1 = to;
109137da2899SCharles.Forsyth 		}
109237da2899SCharles.Forsyth 	}
109337da2899SCharles.Forsyth 	else {
109437da2899SCharles.Forsyth 		free(buf);
109537da2899SCharles.Forsyth 		return TkBadcm;
109637da2899SCharles.Forsyth 	}
109737da2899SCharles.Forsyth 	locked = lockdisplay(tk->env->top->display);
109837da2899SCharles.Forsyth 	tke->xsel0 = entrytextwidth(tk, tke->sel0);
109937da2899SCharles.Forsyth 	tke->xsel1 = entrytextwidth(tk, tke->sel1);
110037da2899SCharles.Forsyth 	if (locked)
110137da2899SCharles.Forsyth 		unlockdisplay(tk->env->top->display);
110237da2899SCharles.Forsyth 	tk->dirty = tkrect(tk, 1);
110337da2899SCharles.Forsyth 	free(buf);
110437da2899SCharles.Forsyth 	return nil;
110537da2899SCharles.Forsyth }
110637da2899SCharles.Forsyth 
110737da2899SCharles.Forsyth 
110837da2899SCharles.Forsyth static char*
tkentryb2p(Tk * tk,char * arg,char ** val)110937da2899SCharles.Forsyth tkentryb2p(Tk *tk, char *arg, char **val)
111037da2899SCharles.Forsyth {
111137da2899SCharles.Forsyth 	TkEntry *tke;
111237da2899SCharles.Forsyth 	char *buf;
111337da2899SCharles.Forsyth 
111437da2899SCharles.Forsyth 	USED(val);
111537da2899SCharles.Forsyth 
111637da2899SCharles.Forsyth 	tke = TKobj(TkEntry, tk);
111737da2899SCharles.Forsyth 	buf = malloc(Tkmaxitem);
111837da2899SCharles.Forsyth 	if (buf == nil)
111937da2899SCharles.Forsyth 		return TkNomem;
112037da2899SCharles.Forsyth 
112137da2899SCharles.Forsyth 	tkword(tk->env->top, arg, buf, buf+Tkmaxitem, nil);
112237da2899SCharles.Forsyth 	tke->oldx = atoi(buf);
112337da2899SCharles.Forsyth 	return nil;
112437da2899SCharles.Forsyth }
112537da2899SCharles.Forsyth 
112637da2899SCharles.Forsyth static char*
tkentryxview(Tk * tk,char * arg,char ** val)112737da2899SCharles.Forsyth tkentryxview(Tk *tk, char *arg, char **val)
112837da2899SCharles.Forsyth {
112937da2899SCharles.Forsyth 	int locked;
113037da2899SCharles.Forsyth 	TkEnv *env;
113137da2899SCharles.Forsyth 	TkEntry *tke;
113237da2899SCharles.Forsyth 	char *buf, *v;
113337da2899SCharles.Forsyth 	int dx, top, bot, amount, ix, x;
113437da2899SCharles.Forsyth 	char *e;
113537da2899SCharles.Forsyth 
113637da2899SCharles.Forsyth 	tke = TKobj(TkEntry, tk);
113737da2899SCharles.Forsyth 	env = tk->env;
113837da2899SCharles.Forsyth 	dx = tk->act.width - 2*xinset(tk);
113937da2899SCharles.Forsyth 
114037da2899SCharles.Forsyth 	buf = mallocz(Tkmaxitem, 0);
114137da2899SCharles.Forsyth 	if(buf == nil)
114237da2899SCharles.Forsyth 		return TkNomem;
114337da2899SCharles.Forsyth 
114437da2899SCharles.Forsyth 	if(*arg == '\0') {
114537da2899SCharles.Forsyth 		if (tke->textlen == 0 || tke->xlen < dx) {
114637da2899SCharles.Forsyth 			bot = TKI2F(0);
114737da2899SCharles.Forsyth 			top = TKI2F(1);
114837da2899SCharles.Forsyth 		} else {
114937da2899SCharles.Forsyth 			bot = TKI2F(tke->x0) / tke->xlen;
115037da2899SCharles.Forsyth 			top = TKI2F(tke->x0 + dx) / tke->xlen;
115137da2899SCharles.Forsyth 		}
115237da2899SCharles.Forsyth 		v = tkfprint(buf, bot);
115337da2899SCharles.Forsyth 		*v++ = ' ';
115437da2899SCharles.Forsyth 		tkfprint(v, top);
115537da2899SCharles.Forsyth 		e = tkvalue(val, "%s", buf);
115637da2899SCharles.Forsyth 		free(buf);
115737da2899SCharles.Forsyth 		return e;
115837da2899SCharles.Forsyth 	}
115937da2899SCharles.Forsyth 
116037da2899SCharles.Forsyth 	arg = tkitem(buf, arg);
116137da2899SCharles.Forsyth 	if(strcmp(buf, "moveto") == 0) {
116237da2899SCharles.Forsyth 		e = tkfracword(env->top, &arg, &top, nil);
116337da2899SCharles.Forsyth 		if (e != nil) {
116437da2899SCharles.Forsyth 			free(buf);
116537da2899SCharles.Forsyth 			return e;
116637da2899SCharles.Forsyth 		}
116737da2899SCharles.Forsyth 		tke->x0 = TKF2I(top*tke->xlen);
116837da2899SCharles.Forsyth 	}
116937da2899SCharles.Forsyth 	else
117037da2899SCharles.Forsyth 	if(strcmp(buf, "scroll") == 0) {
117137da2899SCharles.Forsyth 		arg = tkitem(buf, arg);
117237da2899SCharles.Forsyth 		amount = atoi(buf);
117337da2899SCharles.Forsyth 		if(*arg == 'p')		/* Pages */
117437da2899SCharles.Forsyth 			amount *= (9*tke->xlen)/10;
117537da2899SCharles.Forsyth 		else
117637da2899SCharles.Forsyth 		if(*arg == 's') {		/* Inferno-ism, "scr", must be used in the context of button2p */
117737da2899SCharles.Forsyth 			x = amount;
117837da2899SCharles.Forsyth 			amount = x < tke->oldx ? env->wzero : (x > tke->oldx ? -env->wzero : 0);
117937da2899SCharles.Forsyth 			tke->oldx = x;
118037da2899SCharles.Forsyth 		}
118137da2899SCharles.Forsyth 		tke->x0 += amount;
118237da2899SCharles.Forsyth 	}
118337da2899SCharles.Forsyth 	else {
118437da2899SCharles.Forsyth 		e = tkentryparseindex(tk, buf, &ix);
118537da2899SCharles.Forsyth 		if(e != nil) {
118637da2899SCharles.Forsyth 			free(buf);
118737da2899SCharles.Forsyth 			return e;
118837da2899SCharles.Forsyth 		}
118937da2899SCharles.Forsyth 		locked = lockdisplay(env->top->display);
119037da2899SCharles.Forsyth 		tke->x0 = entrytextwidth(tk, ix);
119137da2899SCharles.Forsyth 		if (locked)
119237da2899SCharles.Forsyth 			unlockdisplay(env->top->display);
119337da2899SCharles.Forsyth 	}
119437da2899SCharles.Forsyth 	free(buf);
119537da2899SCharles.Forsyth 
119637da2899SCharles.Forsyth 	if (tke->x0 > tke->xlen - dx)
119737da2899SCharles.Forsyth 		tke->x0 = tke->xlen - dx;
119837da2899SCharles.Forsyth 	if (tke->x0 < 0)
119937da2899SCharles.Forsyth 		tke->x0 = 0;
120037da2899SCharles.Forsyth 	recalcentry(tk);
120137da2899SCharles.Forsyth 	e = tkentrysh(tk);
120237da2899SCharles.Forsyth 	blinkreset(tk);
120337da2899SCharles.Forsyth 	tk->dirty = tkrect(tk, 1);
120437da2899SCharles.Forsyth 	return e;
120537da2899SCharles.Forsyth }
120637da2899SCharles.Forsyth 
120737da2899SCharles.Forsyth static void
autoselect(Tk * tk,void * v,int cancelled)120837da2899SCharles.Forsyth autoselect(Tk *tk, void *v, int cancelled)
120937da2899SCharles.Forsyth {
121037da2899SCharles.Forsyth 	TkEntry *tke = TKobj(TkEntry, tk);
121137da2899SCharles.Forsyth 	Rectangle hitr;
121237da2899SCharles.Forsyth 	char buf[32];
121337da2899SCharles.Forsyth 	Point p;
121437da2899SCharles.Forsyth 
121537da2899SCharles.Forsyth 	USED(v);
121637da2899SCharles.Forsyth 
121737da2899SCharles.Forsyth 	if (cancelled)
121837da2899SCharles.Forsyth 		return;
121937da2899SCharles.Forsyth 
122037da2899SCharles.Forsyth 	p = tkscrn2local(tk, Pt(tke->oldx, 0));
122137da2899SCharles.Forsyth 	p.y = 0;
122237da2899SCharles.Forsyth 	if (tkvisiblerect(tk, &hitr) && ptinrect(p, hitr))
122337da2899SCharles.Forsyth 		return;
122437da2899SCharles.Forsyth 
122537da2899SCharles.Forsyth 	snprint(buf, sizeof(buf), "to @%d", p.x);
122637da2899SCharles.Forsyth 	tkentryselect(tk, buf, nil);
122737da2899SCharles.Forsyth 	tkdirty(tk);
122837da2899SCharles.Forsyth 	tkupdate(tk->env->top);
122937da2899SCharles.Forsyth }
123037da2899SCharles.Forsyth 
123137da2899SCharles.Forsyth static char*
tkentryb1p(Tk * tk,char * arg,char ** ret)123237da2899SCharles.Forsyth tkentryb1p(Tk *tk, char* arg, char **ret)
123337da2899SCharles.Forsyth {
123437da2899SCharles.Forsyth 	TkEntry *tke = TKobj(TkEntry, tk);
123537da2899SCharles.Forsyth 	Point p;
123637da2899SCharles.Forsyth 	int i, locked, x;
123737da2899SCharles.Forsyth 	char buf[32], *e;
123837da2899SCharles.Forsyth 	USED(ret);
123937da2899SCharles.Forsyth 
124037da2899SCharles.Forsyth 	x = atoi(arg);
124137da2899SCharles.Forsyth 	p = tkscrn2local(tk, Pt(x, 0));
124237da2899SCharles.Forsyth 	sprint(buf, "@%d", p.x);
124337da2899SCharles.Forsyth 	e = tkentryparseindex(tk, buf, &i);
124437da2899SCharles.Forsyth 	if (e != nil)
124537da2899SCharles.Forsyth 		return e;
124637da2899SCharles.Forsyth 	tke->sel0 = 0;
124737da2899SCharles.Forsyth 	tke->sel1 = 0;
124837da2899SCharles.Forsyth 	tke->icursor = i;
124937da2899SCharles.Forsyth 	tke->anchor = i;
125037da2899SCharles.Forsyth 	tke->flag &= ~Ewordsel;
125137da2899SCharles.Forsyth 
125237da2899SCharles.Forsyth 	locked = lockdisplay(tk->env->top->display);
125337da2899SCharles.Forsyth 	tke->xsel0 = 0;
125437da2899SCharles.Forsyth 	tke->xsel1 = 0;
125537da2899SCharles.Forsyth 	tke->xicursor = entrytextwidth(tk, tke->icursor);
125637da2899SCharles.Forsyth 	if (locked)
125737da2899SCharles.Forsyth 		unlockdisplay(tk->env->top->display);
125837da2899SCharles.Forsyth 
125937da2899SCharles.Forsyth 	tke->oldx = x;
126037da2899SCharles.Forsyth 	blinkreset(tk);
126137da2899SCharles.Forsyth 	tkrepeat(tk, autoselect, nil, TkRptpause, TkRptinterval);
126237da2899SCharles.Forsyth 	tk->dirty = tkrect(tk, 0);
126337da2899SCharles.Forsyth 	return nil;
126437da2899SCharles.Forsyth }
126537da2899SCharles.Forsyth 
126637da2899SCharles.Forsyth static char*
tkentryb1m(Tk * tk,char * arg,char ** ret)126737da2899SCharles.Forsyth tkentryb1m(Tk *tk, char* arg, char **ret)
126837da2899SCharles.Forsyth {
126937da2899SCharles.Forsyth 	TkEntry *tke = TKobj(TkEntry, tk);
127037da2899SCharles.Forsyth 	Point p;
127137da2899SCharles.Forsyth 	Rectangle hitr;
127237da2899SCharles.Forsyth 	char buf[32];
127337da2899SCharles.Forsyth 	USED(ret);
127437da2899SCharles.Forsyth 
127537da2899SCharles.Forsyth 	p.x = atoi(arg);
127637da2899SCharles.Forsyth 	tke->oldx = p.x;
127737da2899SCharles.Forsyth 	p = tkscrn2local(tk, p);
127837da2899SCharles.Forsyth 	p.y = 0;
127937da2899SCharles.Forsyth 	if (!tkvisiblerect(tk, &hitr) || !ptinrect(p, hitr))
128037da2899SCharles.Forsyth 		return nil;
128137da2899SCharles.Forsyth 	snprint(buf, sizeof(buf), "to @%d", p.x);
128237da2899SCharles.Forsyth 	tkentryselect(tk, buf, nil);
128337da2899SCharles.Forsyth 	return nil;
128437da2899SCharles.Forsyth }
128537da2899SCharles.Forsyth 
128637da2899SCharles.Forsyth static char*
tkentryb1r(Tk * tk,char * arg,char ** ret)128737da2899SCharles.Forsyth tkentryb1r(Tk *tk, char* arg, char **ret)
128837da2899SCharles.Forsyth {
128937da2899SCharles.Forsyth 	USED(tk);
129037da2899SCharles.Forsyth 	USED(arg);
129137da2899SCharles.Forsyth 	USED(ret);
129237da2899SCharles.Forsyth 	tkcancelrepeat(tk);
129337da2899SCharles.Forsyth 	return nil;
129437da2899SCharles.Forsyth }
129537da2899SCharles.Forsyth 
129637da2899SCharles.Forsyth static void
blinkreset(Tk * tk)129737da2899SCharles.Forsyth blinkreset(Tk *tk)
129837da2899SCharles.Forsyth {
129937da2899SCharles.Forsyth 	TkEntry *e = TKobj(TkEntry, tk);
130037da2899SCharles.Forsyth 	if (!tkhaskeyfocus(tk) || tk->flag&Tkdisabled)
130137da2899SCharles.Forsyth 		return;
130237da2899SCharles.Forsyth 	e->flag |= Ecursoron;
130337da2899SCharles.Forsyth 	tkblinkreset(tk);
130437da2899SCharles.Forsyth }
130537da2899SCharles.Forsyth 
130637da2899SCharles.Forsyth static void
showcaret(Tk * tk,int on)130737da2899SCharles.Forsyth showcaret(Tk *tk, int on)
130837da2899SCharles.Forsyth {
130937da2899SCharles.Forsyth 	TkEntry *e = TKobj(TkEntry, tk);
131037da2899SCharles.Forsyth 
131137da2899SCharles.Forsyth 	if (on)
131237da2899SCharles.Forsyth 		e->flag |= Ecursoron;
131337da2899SCharles.Forsyth 	else
131437da2899SCharles.Forsyth 		e->flag &= ~Ecursoron;
131537da2899SCharles.Forsyth 	tk->dirty = tkrect(tk, 0);
131637da2899SCharles.Forsyth }
131737da2899SCharles.Forsyth 
131837da2899SCharles.Forsyth char*
tkentryfocus(Tk * tk,char * arg,char ** ret)131937da2899SCharles.Forsyth tkentryfocus(Tk *tk, char* arg, char **ret)
132037da2899SCharles.Forsyth {
132137da2899SCharles.Forsyth 	int on = 0;
132237da2899SCharles.Forsyth 	USED(ret);
132337da2899SCharles.Forsyth 
132437da2899SCharles.Forsyth 	if (tk->flag&Tkdisabled)
132537da2899SCharles.Forsyth 		return nil;
132637da2899SCharles.Forsyth 
132737da2899SCharles.Forsyth 	if(strcmp(arg, " in") == 0) {
132837da2899SCharles.Forsyth 		tkblink(tk, showcaret);
132937da2899SCharles.Forsyth 		on = 1;
133037da2899SCharles.Forsyth 	}
133137da2899SCharles.Forsyth 	else
133237da2899SCharles.Forsyth 		tkblink(nil, nil);
133337da2899SCharles.Forsyth 
133437da2899SCharles.Forsyth 	showcaret(tk, on);
133537da2899SCharles.Forsyth 	return nil;
133637da2899SCharles.Forsyth }
133737da2899SCharles.Forsyth 
133837da2899SCharles.Forsyth static
133937da2899SCharles.Forsyth TkCmdtab tkentrycmd[] =
134037da2899SCharles.Forsyth {
134137da2899SCharles.Forsyth 	"cget",			tkentrycget,
134237da2899SCharles.Forsyth 	"configure",		tkentryconf,
134337da2899SCharles.Forsyth 	"delete",		tkentrydelete,
134437da2899SCharles.Forsyth 	"get",			tkentryget,
134537da2899SCharles.Forsyth 	"icursor",		tkentryicursor,
134637da2899SCharles.Forsyth 	"index",		tkentryindex,
134737da2899SCharles.Forsyth 	"insert",		tkentryinsert,
134837da2899SCharles.Forsyth 	"selection",		tkentryselect,
134937da2899SCharles.Forsyth 	"xview",		tkentryxview,
135037da2899SCharles.Forsyth 	"tkEntryBS",		tkentrybs,
135137da2899SCharles.Forsyth 	"tkEntryBW",		tkentrybw,
135237da2899SCharles.Forsyth 	"tkEntryB1P",		tkentryb1p,
135337da2899SCharles.Forsyth 	"tkEntryB1M",		tkentryb1m,
135437da2899SCharles.Forsyth 	"tkEntryB1R",		tkentryb1r,
135537da2899SCharles.Forsyth 	"tkEntryB2P",		tkentryb2p,
135637da2899SCharles.Forsyth 	"tkEntryFocus",		tkentryfocus,
135737da2899SCharles.Forsyth 	"bbox",			tkentrybboxcmd,
135837da2899SCharles.Forsyth 	"see",		tkentryseecmd,
135937da2899SCharles.Forsyth 	nil
136037da2899SCharles.Forsyth };
136137da2899SCharles.Forsyth 
136237da2899SCharles.Forsyth TkMethod entrymethod = {
136337da2899SCharles.Forsyth 	"entry",
136437da2899SCharles.Forsyth 	tkentrycmd,
136537da2899SCharles.Forsyth 	tkfreeentry,
136637da2899SCharles.Forsyth 	tkdrawentry,
136737da2899SCharles.Forsyth 	tkentrygeom
136837da2899SCharles.Forsyth };
1369