xref: /inferno-os/libtk/ctext.c (revision 37da2899f40661e3e9631e497da8dc59b971cbd0)
1*37da2899SCharles.Forsyth #include <lib9.h>
2*37da2899SCharles.Forsyth #include <kernel.h>
3*37da2899SCharles.Forsyth #include "draw.h"
4*37da2899SCharles.Forsyth #include "tk.h"
5*37da2899SCharles.Forsyth #include "canvs.h"
6*37da2899SCharles.Forsyth 
7*37da2899SCharles.Forsyth #define	O(t, e)		((long)(&((t*)0)->e))
8*37da2899SCharles.Forsyth 
9*37da2899SCharles.Forsyth /* Text Options (+ means implemented)
10*37da2899SCharles.Forsyth 	+anchor
11*37da2899SCharles.Forsyth 	+fill
12*37da2899SCharles.Forsyth 	+font
13*37da2899SCharles.Forsyth 	+justify
14*37da2899SCharles.Forsyth 	+stipple
15*37da2899SCharles.Forsyth 	+tags
16*37da2899SCharles.Forsyth 	+text
17*37da2899SCharles.Forsyth 	+width
18*37da2899SCharles.Forsyth */
19*37da2899SCharles.Forsyth 
20*37da2899SCharles.Forsyth /* Layout constants */
21*37da2899SCharles.Forsyth enum {
22*37da2899SCharles.Forsyth 	Cvsicursor	= 1,	/* Extra height of insertion cursor in canvas */
23*37da2899SCharles.Forsyth };
24*37da2899SCharles.Forsyth 
25*37da2899SCharles.Forsyth typedef struct TkCtext TkCtext;
26*37da2899SCharles.Forsyth struct TkCtext
27*37da2899SCharles.Forsyth {
28*37da2899SCharles.Forsyth 	int	anchor;
29*37da2899SCharles.Forsyth 	Point	anchorp;
30*37da2899SCharles.Forsyth 	int	justify;
31*37da2899SCharles.Forsyth 	int	icursor;
32*37da2899SCharles.Forsyth 	int	focus;
33*37da2899SCharles.Forsyth 	int	pixwidth;
34*37da2899SCharles.Forsyth 	int	pixheight;
35*37da2899SCharles.Forsyth 	int	sell;
36*37da2899SCharles.Forsyth 	int	self;
37*37da2899SCharles.Forsyth 	int	selfrom;
38*37da2899SCharles.Forsyth 	int	sbw;
39*37da2899SCharles.Forsyth 	int	width;
40*37da2899SCharles.Forsyth 	int	nlines;
41*37da2899SCharles.Forsyth 	Image*	stipple;
42*37da2899SCharles.Forsyth 	Image*	pen;
43*37da2899SCharles.Forsyth 	char*	text;
44*37da2899SCharles.Forsyth 	int	tlen;
45*37da2899SCharles.Forsyth 	TkEnv	*env;
46*37da2899SCharles.Forsyth };
47*37da2899SCharles.Forsyth 
48*37da2899SCharles.Forsyth static
49*37da2899SCharles.Forsyth TkOption textopts[] =
50*37da2899SCharles.Forsyth {
51*37da2899SCharles.Forsyth 	"anchor",	OPTstab,	O(TkCtext, anchor),	tkanchor,
52*37da2899SCharles.Forsyth 	"justify",	OPTstab,	O(TkCtext, justify),	tktabjust,
53*37da2899SCharles.Forsyth 	"width",	OPTdist,	O(TkCtext, width),	IAUX(O(TkCtext, env)),
54*37da2899SCharles.Forsyth 	"stipple",	OPTbmap,	O(TkCtext, stipple),	nil,
55*37da2899SCharles.Forsyth 	"text",		OPTtext,	O(TkCtext, text),	nil,
56*37da2899SCharles.Forsyth 	nil
57*37da2899SCharles.Forsyth };
58*37da2899SCharles.Forsyth 
59*37da2899SCharles.Forsyth static
60*37da2899SCharles.Forsyth TkOption itemopts[] =
61*37da2899SCharles.Forsyth {
62*37da2899SCharles.Forsyth 	"tags",		OPTctag,	O(TkCitem, tags),	nil,
63*37da2899SCharles.Forsyth 	"font",		OPTfont,	O(TkCitem, env),	nil,
64*37da2899SCharles.Forsyth 	"fill",		OPTcolr,	O(TkCitem, env),	IAUX(TkCfill),
65*37da2899SCharles.Forsyth 	nil
66*37da2899SCharles.Forsyth };
67*37da2899SCharles.Forsyth 
68*37da2899SCharles.Forsyth static char*
tkcvstextgetl(TkCtext * t,Font * font,char * start,int * len)69*37da2899SCharles.Forsyth tkcvstextgetl(TkCtext *t, Font *font, char *start, int *len)
70*37da2899SCharles.Forsyth {
71*37da2899SCharles.Forsyth 	int w, n;
72*37da2899SCharles.Forsyth 	char *lspc, *posn;
73*37da2899SCharles.Forsyth 
74*37da2899SCharles.Forsyth 	w = t->width;
75*37da2899SCharles.Forsyth 	if(w <= 0)
76*37da2899SCharles.Forsyth 		w = 1000000;
77*37da2899SCharles.Forsyth 
78*37da2899SCharles.Forsyth 	n = 0;
79*37da2899SCharles.Forsyth 	lspc = nil;
80*37da2899SCharles.Forsyth 	posn = start;
81*37da2899SCharles.Forsyth 	while(*posn && *posn != '\n') {
82*37da2899SCharles.Forsyth 		if(*posn == ' ')
83*37da2899SCharles.Forsyth 			lspc = posn;
84*37da2899SCharles.Forsyth 		n += stringnwidth(font, posn, 1);
85*37da2899SCharles.Forsyth 		if(n >= w && posn != start) {
86*37da2899SCharles.Forsyth 			if(lspc != nil)
87*37da2899SCharles.Forsyth 				posn = lspc;
88*37da2899SCharles.Forsyth 			*len = posn - start;
89*37da2899SCharles.Forsyth 			if(lspc != nil)
90*37da2899SCharles.Forsyth 				posn++;
91*37da2899SCharles.Forsyth 			return posn;
92*37da2899SCharles.Forsyth 		}
93*37da2899SCharles.Forsyth 		posn++;
94*37da2899SCharles.Forsyth 	}
95*37da2899SCharles.Forsyth 	*len = posn - start;
96*37da2899SCharles.Forsyth 	if(*posn == '\n')
97*37da2899SCharles.Forsyth 		posn++;
98*37da2899SCharles.Forsyth 	return posn;
99*37da2899SCharles.Forsyth }
100*37da2899SCharles.Forsyth 
101*37da2899SCharles.Forsyth void
tkcvstextsize(TkCitem * i)102*37da2899SCharles.Forsyth tkcvstextsize(TkCitem *i)
103*37da2899SCharles.Forsyth {
104*37da2899SCharles.Forsyth 	Point o;
105*37da2899SCharles.Forsyth 	Font *font;
106*37da2899SCharles.Forsyth 	TkCtext *t;
107*37da2899SCharles.Forsyth 	Display *d;
108*37da2899SCharles.Forsyth 	char *next, *p;
109*37da2899SCharles.Forsyth 	int len, pixw, locked;
110*37da2899SCharles.Forsyth 
111*37da2899SCharles.Forsyth 	t = TKobj(TkCtext, i);
112*37da2899SCharles.Forsyth 
113*37da2899SCharles.Forsyth 	font = i->env->font;
114*37da2899SCharles.Forsyth 	d = i->env->top->display;
115*37da2899SCharles.Forsyth 	t->pixwidth = 0;
116*37da2899SCharles.Forsyth 	t->pixheight = 0;
117*37da2899SCharles.Forsyth 
118*37da2899SCharles.Forsyth 	p = t->text;
119*37da2899SCharles.Forsyth 	if(p != nil) {
120*37da2899SCharles.Forsyth 		locked = lockdisplay(d);
121*37da2899SCharles.Forsyth 		while(*p) {
122*37da2899SCharles.Forsyth 			next = tkcvstextgetl(t, font, p, &len);
123*37da2899SCharles.Forsyth 			pixw = stringnwidth(font, p, len);
124*37da2899SCharles.Forsyth 			if(pixw > t->pixwidth)
125*37da2899SCharles.Forsyth 				t->pixwidth = pixw;
126*37da2899SCharles.Forsyth 			t->pixheight += font->height;
127*37da2899SCharles.Forsyth 			p = next;
128*37da2899SCharles.Forsyth 		}
129*37da2899SCharles.Forsyth 		if(locked)
130*37da2899SCharles.Forsyth 			unlockdisplay(d);
131*37da2899SCharles.Forsyth 	}
132*37da2899SCharles.Forsyth 
133*37da2899SCharles.Forsyth 	o = tkcvsanchor(i->p.drawpt[0], t->pixwidth, t->pixheight, t->anchor);
134*37da2899SCharles.Forsyth 
135*37da2899SCharles.Forsyth 	i->p.bb.min.x = o.x;
136*37da2899SCharles.Forsyth 	i->p.bb.min.y = o.y - Cvsicursor;
137*37da2899SCharles.Forsyth 	i->p.bb.max.x = o.x + t->pixwidth;
138*37da2899SCharles.Forsyth 	i->p.bb.max.y = o.y + t->pixheight + Cvsicursor;
139*37da2899SCharles.Forsyth 	i->p.bb = insetrect(i->p.bb, -2*t->sbw);
140*37da2899SCharles.Forsyth 	t->anchorp = subpt(o, i->p.drawpt[0]);
141*37da2899SCharles.Forsyth }
142*37da2899SCharles.Forsyth 
143*37da2899SCharles.Forsyth char*
tkcvstextcreat(Tk * tk,char * arg,char ** val)144*37da2899SCharles.Forsyth tkcvstextcreat(Tk* tk, char *arg, char **val)
145*37da2899SCharles.Forsyth {
146*37da2899SCharles.Forsyth 	char *e;
147*37da2899SCharles.Forsyth 	TkCtext *t;
148*37da2899SCharles.Forsyth 	TkCitem *i;
149*37da2899SCharles.Forsyth 	TkCanvas *c;
150*37da2899SCharles.Forsyth 	TkOptab tko[3];
151*37da2899SCharles.Forsyth 
152*37da2899SCharles.Forsyth 	c = TKobj(TkCanvas, tk);
153*37da2899SCharles.Forsyth 
154*37da2899SCharles.Forsyth 	i = tkcnewitem(tk, TkCVtext, sizeof(TkCitem)+sizeof(TkCtext));
155*37da2899SCharles.Forsyth 	if(i == nil)
156*37da2899SCharles.Forsyth 		return TkNomem;
157*37da2899SCharles.Forsyth 
158*37da2899SCharles.Forsyth 	t = TKobj(TkCtext, i);
159*37da2899SCharles.Forsyth 	t->justify = Tkleft;
160*37da2899SCharles.Forsyth 	t->anchor = Tkcenter;
161*37da2899SCharles.Forsyth 	t->sell = -1;
162*37da2899SCharles.Forsyth 	t->self = -1;
163*37da2899SCharles.Forsyth 	t->icursor = -1;
164*37da2899SCharles.Forsyth 	t->sbw = c->sborderwidth;
165*37da2899SCharles.Forsyth 	t->env = tk->env;
166*37da2899SCharles.Forsyth 
167*37da2899SCharles.Forsyth 	e = tkparsepts(tk->env->top, &i->p, &arg, 0);
168*37da2899SCharles.Forsyth 	if(e != nil) {
169*37da2899SCharles.Forsyth 		tkcvsfreeitem(i);
170*37da2899SCharles.Forsyth 		return e;
171*37da2899SCharles.Forsyth 	}
172*37da2899SCharles.Forsyth 	if(i->p.npoint != 1) {
173*37da2899SCharles.Forsyth 		tkcvsfreeitem(i);
174*37da2899SCharles.Forsyth 		return TkFewpt;
175*37da2899SCharles.Forsyth 	}
176*37da2899SCharles.Forsyth 
177*37da2899SCharles.Forsyth 	tko[0].ptr = t;
178*37da2899SCharles.Forsyth 	tko[0].optab = textopts;
179*37da2899SCharles.Forsyth 	tko[1].ptr = i;
180*37da2899SCharles.Forsyth 	tko[1].optab = itemopts;
181*37da2899SCharles.Forsyth 	tko[2].ptr = nil;
182*37da2899SCharles.Forsyth 	e = tkparse(tk->env->top, arg, tko, nil);
183*37da2899SCharles.Forsyth 	if(e != nil) {
184*37da2899SCharles.Forsyth 		tkcvsfreeitem(i);
185*37da2899SCharles.Forsyth 		return e;
186*37da2899SCharles.Forsyth 	}
187*37da2899SCharles.Forsyth 
188*37da2899SCharles.Forsyth 	e = tkcaddtag(tk, i, 1);
189*37da2899SCharles.Forsyth 	if(e != nil) {
190*37da2899SCharles.Forsyth 		tkcvsfreeitem(i);
191*37da2899SCharles.Forsyth 		return e;
192*37da2899SCharles.Forsyth 	}
193*37da2899SCharles.Forsyth 
194*37da2899SCharles.Forsyth 	t->tlen = 0;
195*37da2899SCharles.Forsyth 	if(t->text != nil)
196*37da2899SCharles.Forsyth 		t->tlen = strlen(t->text);
197*37da2899SCharles.Forsyth 
198*37da2899SCharles.Forsyth 	tkmkpen(&t->pen, i->env, t->stipple);
199*37da2899SCharles.Forsyth 	tkcvstextsize(i);
200*37da2899SCharles.Forsyth 	e = tkvalue(val, "%d", i->id);
201*37da2899SCharles.Forsyth 	if(e != nil) {
202*37da2899SCharles.Forsyth 		tkcvsfreeitem(i);
203*37da2899SCharles.Forsyth 		return e;
204*37da2899SCharles.Forsyth 	}
205*37da2899SCharles.Forsyth 
206*37da2899SCharles.Forsyth 	tkcvsappend(c, i);
207*37da2899SCharles.Forsyth 
208*37da2899SCharles.Forsyth 	tkbbmax(&c->update, &i->p.bb);
209*37da2899SCharles.Forsyth 	tkcvssetdirty(tk);
210*37da2899SCharles.Forsyth 	return nil;
211*37da2899SCharles.Forsyth }
212*37da2899SCharles.Forsyth 
213*37da2899SCharles.Forsyth char*
tkcvstextcget(TkCitem * i,char * arg,char ** val)214*37da2899SCharles.Forsyth tkcvstextcget(TkCitem *i, char *arg, char **val)
215*37da2899SCharles.Forsyth {
216*37da2899SCharles.Forsyth 	TkOptab tko[3];
217*37da2899SCharles.Forsyth 	TkCtext *t = TKobj(TkCtext, i);
218*37da2899SCharles.Forsyth 
219*37da2899SCharles.Forsyth 	tko[0].ptr = t;
220*37da2899SCharles.Forsyth 	tko[0].optab = textopts;
221*37da2899SCharles.Forsyth 	tko[1].ptr = i;
222*37da2899SCharles.Forsyth 	tko[1].optab = itemopts;
223*37da2899SCharles.Forsyth 	tko[2].ptr = nil;
224*37da2899SCharles.Forsyth 
225*37da2899SCharles.Forsyth 	return tkgencget(tko, arg, val, i->env->top);
226*37da2899SCharles.Forsyth }
227*37da2899SCharles.Forsyth 
228*37da2899SCharles.Forsyth char*
tkcvstextconf(Tk * tk,TkCitem * i,char * arg)229*37da2899SCharles.Forsyth tkcvstextconf(Tk *tk, TkCitem *i, char *arg)
230*37da2899SCharles.Forsyth {
231*37da2899SCharles.Forsyth 	char *e;
232*37da2899SCharles.Forsyth 	TkOptab tko[3];
233*37da2899SCharles.Forsyth 	TkCtext *t = TKobj(TkCtext, i);
234*37da2899SCharles.Forsyth 
235*37da2899SCharles.Forsyth 	tko[0].ptr = t;
236*37da2899SCharles.Forsyth 	tko[0].optab = textopts;
237*37da2899SCharles.Forsyth 	tko[1].ptr = i;
238*37da2899SCharles.Forsyth 	tko[1].optab = itemopts;
239*37da2899SCharles.Forsyth 	tko[2].ptr = nil;
240*37da2899SCharles.Forsyth 
241*37da2899SCharles.Forsyth 	e = tkparse(tk->env->top, arg, tko, nil);
242*37da2899SCharles.Forsyth 
243*37da2899SCharles.Forsyth 	t->tlen = 0;
244*37da2899SCharles.Forsyth 	if(t->text != nil)
245*37da2899SCharles.Forsyth 		t->tlen = strlen(t->text);
246*37da2899SCharles.Forsyth 
247*37da2899SCharles.Forsyth 	tkmkpen(&t->pen, i->env, t->stipple);
248*37da2899SCharles.Forsyth 	tkcvstextsize(i);
249*37da2899SCharles.Forsyth 
250*37da2899SCharles.Forsyth 	return e;
251*37da2899SCharles.Forsyth }
252*37da2899SCharles.Forsyth 
253*37da2899SCharles.Forsyth void
tkcvstextfree(TkCitem * i)254*37da2899SCharles.Forsyth tkcvstextfree(TkCitem *i)
255*37da2899SCharles.Forsyth {
256*37da2899SCharles.Forsyth 	TkCtext *t;
257*37da2899SCharles.Forsyth 
258*37da2899SCharles.Forsyth 	t = TKobj(TkCtext, i);
259*37da2899SCharles.Forsyth 	if(t->stipple != nil)
260*37da2899SCharles.Forsyth 		freeimage(t->stipple);
261*37da2899SCharles.Forsyth 	if(t->pen != nil)
262*37da2899SCharles.Forsyth 		freeimage(t->pen);
263*37da2899SCharles.Forsyth 	if(t->text != nil)
264*37da2899SCharles.Forsyth 		free(t->text);
265*37da2899SCharles.Forsyth }
266*37da2899SCharles.Forsyth 
267*37da2899SCharles.Forsyth void
tkcvstextdraw(Image * img,TkCitem * i,TkEnv * pe)268*37da2899SCharles.Forsyth tkcvstextdraw(Image *img, TkCitem *i, TkEnv *pe)
269*37da2899SCharles.Forsyth {
270*37da2899SCharles.Forsyth 	TkEnv *e;
271*37da2899SCharles.Forsyth 	TkCtext *t;
272*37da2899SCharles.Forsyth 	Point o, dp;
273*37da2899SCharles.Forsyth 	Rectangle r;
274*37da2899SCharles.Forsyth 	char *p, *next;
275*37da2899SCharles.Forsyth 	Image *pen;
276*37da2899SCharles.Forsyth 	int len, lw, end, start;
277*37da2899SCharles.Forsyth 
278*37da2899SCharles.Forsyth 	t = TKobj(TkCtext, i);
279*37da2899SCharles.Forsyth 
280*37da2899SCharles.Forsyth 	e = i->env;
281*37da2899SCharles.Forsyth 	pen = t->pen;
282*37da2899SCharles.Forsyth 	if(pen == nil) {
283*37da2899SCharles.Forsyth 		if (e->set & (1<<TkCfill))
284*37da2899SCharles.Forsyth 			pen = tkgc(e, TkCfill);
285*37da2899SCharles.Forsyth 		else
286*37da2899SCharles.Forsyth 			pen = img->display->black;
287*37da2899SCharles.Forsyth 	}
288*37da2899SCharles.Forsyth 
289*37da2899SCharles.Forsyth 
290*37da2899SCharles.Forsyth 	o = addpt(t->anchorp, i->p.drawpt[0]);
291*37da2899SCharles.Forsyth 	p = t->text;
292*37da2899SCharles.Forsyth 	while(p && *p) {
293*37da2899SCharles.Forsyth 		next = tkcvstextgetl(t, e->font, p, &len);
294*37da2899SCharles.Forsyth 		dp = o;
295*37da2899SCharles.Forsyth 		if(t->justify != Tkleft) {
296*37da2899SCharles.Forsyth 			lw = stringnwidth(e->font, p, len);
297*37da2899SCharles.Forsyth 			if(t->justify == Tkcenter)
298*37da2899SCharles.Forsyth 				dp.x += (t->pixwidth - lw)/2;
299*37da2899SCharles.Forsyth 			else
300*37da2899SCharles.Forsyth 			if(t->justify == Tkright)
301*37da2899SCharles.Forsyth 				dp.x += t->pixwidth - lw;
302*37da2899SCharles.Forsyth 		}
303*37da2899SCharles.Forsyth 		lw = p - t->text;
304*37da2899SCharles.Forsyth 		if(t->self != -1 && lw+len > t->self) {
305*37da2899SCharles.Forsyth 			if(t->sell >= t->self) {
306*37da2899SCharles.Forsyth 				start = t->self - lw;
307*37da2899SCharles.Forsyth 				end = t->sell - lw;
308*37da2899SCharles.Forsyth 			}
309*37da2899SCharles.Forsyth 			else {
310*37da2899SCharles.Forsyth 				start = t->sell - lw;
311*37da2899SCharles.Forsyth 				end = t->self - lw;
312*37da2899SCharles.Forsyth 			}
313*37da2899SCharles.Forsyth 			if(start < 0)
314*37da2899SCharles.Forsyth 				r.min.x = o.x;
315*37da2899SCharles.Forsyth 			else
316*37da2899SCharles.Forsyth 				r.min.x = dp.x + stringnwidth(e->font, p, start);
317*37da2899SCharles.Forsyth 			r.min.y = dp.y;
318*37da2899SCharles.Forsyth 			if(end > len)
319*37da2899SCharles.Forsyth 				r.max.x = o.x + t->pixwidth;
320*37da2899SCharles.Forsyth 			else
321*37da2899SCharles.Forsyth 				r.max.x = dp.x + stringnwidth(e->font, p, end);
322*37da2899SCharles.Forsyth 			r.max.y = dp.y + e->font->height;
323*37da2899SCharles.Forsyth 			tktextsdraw(img, r, pe, t->sbw);
324*37da2899SCharles.Forsyth 			r.max.y = dp.y;
325*37da2899SCharles.Forsyth 			if(start > 0)
326*37da2899SCharles.Forsyth 				stringn(img, dp, pen, dp, e->font, p, start);
327*37da2899SCharles.Forsyth 			if(end > start)
328*37da2899SCharles.Forsyth 				stringn(img, r.min, tkgc(pe, TkCselectfgnd), r.min, e->font, p+start, end-start);
329*37da2899SCharles.Forsyth 			if(len > end)
330*37da2899SCharles.Forsyth 				stringn(img, r.max, pen, r.max, e->font, p+end, len-end);
331*37da2899SCharles.Forsyth 		}
332*37da2899SCharles.Forsyth 		else
333*37da2899SCharles.Forsyth 			stringn(img, dp, pen, dp, e->font, p, len);
334*37da2899SCharles.Forsyth 		if(t->focus) {
335*37da2899SCharles.Forsyth 			lw = p - t->text;
336*37da2899SCharles.Forsyth 			if(t->icursor >= lw && t->icursor <= lw+len) {
337*37da2899SCharles.Forsyth 				lw = t->icursor - lw;
338*37da2899SCharles.Forsyth 				if(lw > 0)
339*37da2899SCharles.Forsyth 					lw = stringnwidth(e->font, p, lw);
340*37da2899SCharles.Forsyth 				r.min.x = dp.x + lw;
341*37da2899SCharles.Forsyth 				r.min.y = dp.y - 1;
342*37da2899SCharles.Forsyth 				r.max.x = r.min.x + 2;
343*37da2899SCharles.Forsyth 				r.max.y = r.min.y + e->font->height + 1;
344*37da2899SCharles.Forsyth 				draw(img, r, pen, nil, ZP);
345*37da2899SCharles.Forsyth 			}
346*37da2899SCharles.Forsyth 		}
347*37da2899SCharles.Forsyth 		o.y += e->font->height;
348*37da2899SCharles.Forsyth 		p = next;
349*37da2899SCharles.Forsyth 	}
350*37da2899SCharles.Forsyth }
351*37da2899SCharles.Forsyth 
352*37da2899SCharles.Forsyth char*
tkcvstextcoord(TkCitem * i,char * arg,int x,int y)353*37da2899SCharles.Forsyth tkcvstextcoord(TkCitem *i, char *arg, int x, int y)
354*37da2899SCharles.Forsyth {
355*37da2899SCharles.Forsyth 	char *e;
356*37da2899SCharles.Forsyth 	TkCpoints p;
357*37da2899SCharles.Forsyth 
358*37da2899SCharles.Forsyth 	if(arg == nil) {
359*37da2899SCharles.Forsyth 		tkxlatepts(i->p.parampt, i->p.npoint, x, y);
360*37da2899SCharles.Forsyth 		tkxlatepts(i->p.drawpt, i->p.npoint, TKF2I(x), TKF2I(y));
361*37da2899SCharles.Forsyth 		i->p.bb = rectaddpt(i->p.bb, Pt(TKF2I(x), TKF2I(y)));
362*37da2899SCharles.Forsyth 	}
363*37da2899SCharles.Forsyth 	else {
364*37da2899SCharles.Forsyth 		e = tkparsepts(i->env->top, &p, &arg, 0);
365*37da2899SCharles.Forsyth 		if(e != nil)
366*37da2899SCharles.Forsyth 			return e;
367*37da2899SCharles.Forsyth 		if(p.npoint != 1) {
368*37da2899SCharles.Forsyth 			tkfreepoint(&p);
369*37da2899SCharles.Forsyth 			return TkFewpt;
370*37da2899SCharles.Forsyth 		}
371*37da2899SCharles.Forsyth 		tkfreepoint(&i->p);
372*37da2899SCharles.Forsyth 		i->p = p;
373*37da2899SCharles.Forsyth 		tkcvstextsize(i);
374*37da2899SCharles.Forsyth 	}
375*37da2899SCharles.Forsyth 	return nil;
376*37da2899SCharles.Forsyth }
377*37da2899SCharles.Forsyth 
378*37da2899SCharles.Forsyth int
tkcvstextsrch(TkCitem * i,int x,int y)379*37da2899SCharles.Forsyth tkcvstextsrch(TkCitem *i, int x, int y)
380*37da2899SCharles.Forsyth {
381*37da2899SCharles.Forsyth 	TkCtext *t;
382*37da2899SCharles.Forsyth 	Font *font;
383*37da2899SCharles.Forsyth 	Display *d;
384*37da2899SCharles.Forsyth 	char *p, *next;
385*37da2899SCharles.Forsyth 	int n, len, locked;
386*37da2899SCharles.Forsyth 
387*37da2899SCharles.Forsyth 	t = TKobj(TkCtext, i);
388*37da2899SCharles.Forsyth 
389*37da2899SCharles.Forsyth 	n = 0;
390*37da2899SCharles.Forsyth 	font = i->env->font;
391*37da2899SCharles.Forsyth 	d = i->env->top->display;
392*37da2899SCharles.Forsyth 	p = t->text;
393*37da2899SCharles.Forsyth 	if(p == nil)
394*37da2899SCharles.Forsyth 		return 0;
395*37da2899SCharles.Forsyth 	while(*p) {
396*37da2899SCharles.Forsyth 		next = tkcvstextgetl(t, font, p, &len);
397*37da2899SCharles.Forsyth 		if(y <= font->height) {
398*37da2899SCharles.Forsyth 			locked = lockdisplay(d);
399*37da2899SCharles.Forsyth 			for(n = 0; n < len && x > stringnwidth(font, p, n+1); n++)
400*37da2899SCharles.Forsyth 				;
401*37da2899SCharles.Forsyth 			if(locked)
402*37da2899SCharles.Forsyth 				unlockdisplay(d);
403*37da2899SCharles.Forsyth 			break;
404*37da2899SCharles.Forsyth 		}
405*37da2899SCharles.Forsyth 		y -= font->height;
406*37da2899SCharles.Forsyth 		p = next;
407*37da2899SCharles.Forsyth 	}
408*37da2899SCharles.Forsyth 	return p - t->text + n;
409*37da2899SCharles.Forsyth }
410*37da2899SCharles.Forsyth 
411*37da2899SCharles.Forsyth static char*
tkcvsparseindex(TkCitem * i,char * buf,int * index)412*37da2899SCharles.Forsyth tkcvsparseindex(TkCitem *i, char *buf, int *index)
413*37da2899SCharles.Forsyth {
414*37da2899SCharles.Forsyth 	Point o;
415*37da2899SCharles.Forsyth 	char *p;
416*37da2899SCharles.Forsyth 	int x, y;
417*37da2899SCharles.Forsyth 	TkCtext *t;
418*37da2899SCharles.Forsyth 
419*37da2899SCharles.Forsyth 	t = TKobj(TkCtext, i);
420*37da2899SCharles.Forsyth 
421*37da2899SCharles.Forsyth 	if(strcmp(buf, "end") == 0) {
422*37da2899SCharles.Forsyth 		*index = t->tlen;
423*37da2899SCharles.Forsyth 		return nil;
424*37da2899SCharles.Forsyth 	}
425*37da2899SCharles.Forsyth 	if(strcmp(buf, "sel.first") == 0) {
426*37da2899SCharles.Forsyth 		if(t->self < 0)
427*37da2899SCharles.Forsyth 			return TkBadix;
428*37da2899SCharles.Forsyth 		*index = t->self;
429*37da2899SCharles.Forsyth 		return nil;
430*37da2899SCharles.Forsyth 	}
431*37da2899SCharles.Forsyth 	if(strcmp(buf, "sel.last") == 0) {
432*37da2899SCharles.Forsyth 		if(t->sell < 0)
433*37da2899SCharles.Forsyth 			return TkBadix;
434*37da2899SCharles.Forsyth 		*index = t->sell;
435*37da2899SCharles.Forsyth 		return nil;
436*37da2899SCharles.Forsyth 	}
437*37da2899SCharles.Forsyth 	if(strcmp(buf, "insert") == 0) {
438*37da2899SCharles.Forsyth 		*index = t->icursor;
439*37da2899SCharles.Forsyth 		return nil;
440*37da2899SCharles.Forsyth 	}
441*37da2899SCharles.Forsyth 	if(buf[0] == '@') {
442*37da2899SCharles.Forsyth 		x = atoi(buf+1);
443*37da2899SCharles.Forsyth 		p = strchr(buf, ',');
444*37da2899SCharles.Forsyth 		if(p == nil)
445*37da2899SCharles.Forsyth 			return TkBadix;
446*37da2899SCharles.Forsyth 		y = atoi(p+1);
447*37da2899SCharles.Forsyth 		o = i->p.drawpt[0];
448*37da2899SCharles.Forsyth 		*index = tkcvstextsrch(i, (x-t->anchorp.x)-o.x, (y-t->anchorp.y)-o.y);
449*37da2899SCharles.Forsyth 		return nil;
450*37da2899SCharles.Forsyth 	}
451*37da2899SCharles.Forsyth 
452*37da2899SCharles.Forsyth 	if(buf[0] < '0' || buf[0] > '9')
453*37da2899SCharles.Forsyth 		return TkBadix;
454*37da2899SCharles.Forsyth 	x = atoi(buf);
455*37da2899SCharles.Forsyth 	if(x < 0)
456*37da2899SCharles.Forsyth 		x = 0;
457*37da2899SCharles.Forsyth 	if(x > t->tlen)
458*37da2899SCharles.Forsyth 		x = t->tlen;
459*37da2899SCharles.Forsyth 	*index = x;
460*37da2899SCharles.Forsyth 	return nil;
461*37da2899SCharles.Forsyth }
462*37da2899SCharles.Forsyth 
463*37da2899SCharles.Forsyth char*
tkcvstextdchar(Tk * tk,TkCitem * i,char * arg)464*37da2899SCharles.Forsyth tkcvstextdchar(Tk *tk, TkCitem *i, char *arg)
465*37da2899SCharles.Forsyth {
466*37da2899SCharles.Forsyth 	TkTop *top;
467*37da2899SCharles.Forsyth 	TkCtext *t;
468*37da2899SCharles.Forsyth 	int first, last;
469*37da2899SCharles.Forsyth 	char *e, buf[Tkmaxitem];
470*37da2899SCharles.Forsyth 
471*37da2899SCharles.Forsyth 	t = TKobj(TkCtext, i);
472*37da2899SCharles.Forsyth 
473*37da2899SCharles.Forsyth 	top = tk->env->top;
474*37da2899SCharles.Forsyth 	arg = tkword(top, arg, buf, buf+sizeof(buf), nil);
475*37da2899SCharles.Forsyth 	e = tkcvsparseindex(i, buf, &first);
476*37da2899SCharles.Forsyth 	if(e != nil)
477*37da2899SCharles.Forsyth 		return e;
478*37da2899SCharles.Forsyth 
479*37da2899SCharles.Forsyth 	last = first+1;
480*37da2899SCharles.Forsyth 	if(*arg != '\0') {
481*37da2899SCharles.Forsyth 		tkword(top, arg, buf, buf+sizeof(buf), nil);
482*37da2899SCharles.Forsyth 		e = tkcvsparseindex(i, buf, &last);
483*37da2899SCharles.Forsyth 		if(e != nil)
484*37da2899SCharles.Forsyth 			return e;
485*37da2899SCharles.Forsyth 	}
486*37da2899SCharles.Forsyth 	if(last <= first || t->tlen == 0)
487*37da2899SCharles.Forsyth 		return nil;
488*37da2899SCharles.Forsyth 
489*37da2899SCharles.Forsyth 	tkbbmax(&TKobj(TkCanvas, tk)->update, &i->p.bb);
490*37da2899SCharles.Forsyth 
491*37da2899SCharles.Forsyth 	memmove(t->text+first, t->text+last, t->tlen-last+1);
492*37da2899SCharles.Forsyth 	t->tlen -= last-first;
493*37da2899SCharles.Forsyth 
494*37da2899SCharles.Forsyth 	tkcvstextsize(i);
495*37da2899SCharles.Forsyth 	tkbbmax(&TKobj(TkCanvas, tk)->update, &i->p.bb);
496*37da2899SCharles.Forsyth 
497*37da2899SCharles.Forsyth 	tkcvssetdirty(tk);
498*37da2899SCharles.Forsyth 	return nil;
499*37da2899SCharles.Forsyth }
500*37da2899SCharles.Forsyth 
501*37da2899SCharles.Forsyth char*
tkcvstextinsert(Tk * tk,TkCitem * i,char * arg)502*37da2899SCharles.Forsyth tkcvstextinsert(Tk *tk, TkCitem *i, char *arg)
503*37da2899SCharles.Forsyth {
504*37da2899SCharles.Forsyth 	TkTop *top;
505*37da2899SCharles.Forsyth 	TkCtext *t;
506*37da2899SCharles.Forsyth 	int first, n;
507*37da2899SCharles.Forsyth 	char *e, *text, buf[Tkmaxitem];
508*37da2899SCharles.Forsyth 
509*37da2899SCharles.Forsyth 	t = TKobj(TkCtext, i);
510*37da2899SCharles.Forsyth 
511*37da2899SCharles.Forsyth 	top = tk->env->top;
512*37da2899SCharles.Forsyth 	arg = tkword(top, arg, buf, buf+sizeof(buf), nil);
513*37da2899SCharles.Forsyth 	e = tkcvsparseindex(i, buf, &first);
514*37da2899SCharles.Forsyth 	if(e != nil)
515*37da2899SCharles.Forsyth 		return e;
516*37da2899SCharles.Forsyth 
517*37da2899SCharles.Forsyth 	if(*arg == '\0')
518*37da2899SCharles.Forsyth 		return nil;
519*37da2899SCharles.Forsyth 
520*37da2899SCharles.Forsyth 	text = malloc(Tkcvstextins);
521*37da2899SCharles.Forsyth 	if(text == nil)
522*37da2899SCharles.Forsyth 		return TkNomem;
523*37da2899SCharles.Forsyth 
524*37da2899SCharles.Forsyth 	tkword(top, arg, text, text+Tkcvstextins, nil);
525*37da2899SCharles.Forsyth 	n = strlen(text);
526*37da2899SCharles.Forsyth 	t->text = realloc(t->text, t->tlen+n+1);
527*37da2899SCharles.Forsyth 	if(t->text == nil) {
528*37da2899SCharles.Forsyth 		free(text);
529*37da2899SCharles.Forsyth 		return TkNomem;
530*37da2899SCharles.Forsyth 	}
531*37da2899SCharles.Forsyth 	if(t->tlen == 0)
532*37da2899SCharles.Forsyth 		t->text[0] = '\0';
533*37da2899SCharles.Forsyth 
534*37da2899SCharles.Forsyth 	tkbbmax(&TKobj(TkCanvas, tk)->update, &i->p.bb);
535*37da2899SCharles.Forsyth 
536*37da2899SCharles.Forsyth 	memmove(t->text+first+n, t->text+first, t->tlen-first+1);
537*37da2899SCharles.Forsyth 	memmove(t->text+first, text, n);
538*37da2899SCharles.Forsyth 	t->tlen += n;
539*37da2899SCharles.Forsyth 	free(text);
540*37da2899SCharles.Forsyth 
541*37da2899SCharles.Forsyth 	tkcvstextsize(i);
542*37da2899SCharles.Forsyth 	tkbbmax(&TKobj(TkCanvas, tk)->update, &i->p.bb);
543*37da2899SCharles.Forsyth 
544*37da2899SCharles.Forsyth 	tkcvssetdirty(tk);
545*37da2899SCharles.Forsyth 	return nil;
546*37da2899SCharles.Forsyth }
547*37da2899SCharles.Forsyth 
548*37da2899SCharles.Forsyth char*
tkcvstextindex(Tk * tk,TkCitem * i,char * arg,char ** val)549*37da2899SCharles.Forsyth tkcvstextindex(Tk *tk, TkCitem *i, char *arg, char **val)
550*37da2899SCharles.Forsyth {
551*37da2899SCharles.Forsyth 	int first;
552*37da2899SCharles.Forsyth 	char *e, buf[Tkmaxitem];
553*37da2899SCharles.Forsyth 
554*37da2899SCharles.Forsyth 	tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
555*37da2899SCharles.Forsyth 	e = tkcvsparseindex(i, buf, &first);
556*37da2899SCharles.Forsyth 	if(e != nil)
557*37da2899SCharles.Forsyth 		return e;
558*37da2899SCharles.Forsyth 
559*37da2899SCharles.Forsyth 	return tkvalue(val, "%d", first);
560*37da2899SCharles.Forsyth }
561*37da2899SCharles.Forsyth 
562*37da2899SCharles.Forsyth char*
tkcvstexticursor(Tk * tk,TkCitem * i,char * arg)563*37da2899SCharles.Forsyth tkcvstexticursor(Tk *tk, TkCitem *i, char *arg)
564*37da2899SCharles.Forsyth {
565*37da2899SCharles.Forsyth 	int first;
566*37da2899SCharles.Forsyth 	TkCanvas *c;
567*37da2899SCharles.Forsyth 	char *e, buf[Tkmaxitem];
568*37da2899SCharles.Forsyth 
569*37da2899SCharles.Forsyth 	tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
570*37da2899SCharles.Forsyth 	e = tkcvsparseindex(i, buf, &first);
571*37da2899SCharles.Forsyth 	if(e != nil)
572*37da2899SCharles.Forsyth 		return e;
573*37da2899SCharles.Forsyth 
574*37da2899SCharles.Forsyth 	TKobj(TkCtext, i)->icursor = first;
575*37da2899SCharles.Forsyth 
576*37da2899SCharles.Forsyth 	c = TKobj(TkCanvas, tk);
577*37da2899SCharles.Forsyth 	if(c->focus == i) {
578*37da2899SCharles.Forsyth 		tkbbmax(&c->update, &i->p.bb);
579*37da2899SCharles.Forsyth 		tkcvssetdirty(tk);
580*37da2899SCharles.Forsyth 	}
581*37da2899SCharles.Forsyth 	return nil;
582*37da2899SCharles.Forsyth }
583*37da2899SCharles.Forsyth 
584*37da2899SCharles.Forsyth void
tkcvstextfocus(Tk * tk,TkCitem * i,int x)585*37da2899SCharles.Forsyth tkcvstextfocus(Tk *tk, TkCitem *i, int x)
586*37da2899SCharles.Forsyth {
587*37da2899SCharles.Forsyth 	TkCtext *t;
588*37da2899SCharles.Forsyth 	TkCanvas *c;
589*37da2899SCharles.Forsyth 
590*37da2899SCharles.Forsyth 	if(i == nil)
591*37da2899SCharles.Forsyth 		return;
592*37da2899SCharles.Forsyth 
593*37da2899SCharles.Forsyth 	t = TKobj(TkCtext, i);
594*37da2899SCharles.Forsyth 	c = TKobj(TkCanvas, tk);
595*37da2899SCharles.Forsyth 
596*37da2899SCharles.Forsyth 	if(t->focus != x) {
597*37da2899SCharles.Forsyth 		t->focus = x;
598*37da2899SCharles.Forsyth 		tkbbmax(&c->update, &i->p.bb);
599*37da2899SCharles.Forsyth 		tkcvssetdirty(tk);
600*37da2899SCharles.Forsyth 	}
601*37da2899SCharles.Forsyth }
602*37da2899SCharles.Forsyth 
603*37da2899SCharles.Forsyth void
tkcvstextclr(Tk * tk)604*37da2899SCharles.Forsyth tkcvstextclr(Tk *tk)
605*37da2899SCharles.Forsyth {
606*37da2899SCharles.Forsyth 	TkCtext *t;
607*37da2899SCharles.Forsyth 	TkCanvas *c;
608*37da2899SCharles.Forsyth 	TkCitem *item;
609*37da2899SCharles.Forsyth 
610*37da2899SCharles.Forsyth 	c = TKobj(TkCanvas, tk);
611*37da2899SCharles.Forsyth 	item = c->selection;
612*37da2899SCharles.Forsyth 	if(item == nil)
613*37da2899SCharles.Forsyth 		return;
614*37da2899SCharles.Forsyth 
615*37da2899SCharles.Forsyth 	c->selection = nil;
616*37da2899SCharles.Forsyth 	t = TKobj(TkCtext, item);
617*37da2899SCharles.Forsyth 	t->sell = -1;
618*37da2899SCharles.Forsyth 	t->self = -1;
619*37da2899SCharles.Forsyth 	tkbbmax(&c->update, &item->p.bb);
620*37da2899SCharles.Forsyth 	tkcvssetdirty(tk);
621*37da2899SCharles.Forsyth }
622*37da2899SCharles.Forsyth 
623*37da2899SCharles.Forsyth char*
tkcvstextselect(Tk * tk,TkCitem * i,char * arg,int op)624*37da2899SCharles.Forsyth tkcvstextselect(Tk *tk, TkCitem *i, char *arg, int op)
625*37da2899SCharles.Forsyth {
626*37da2899SCharles.Forsyth 	int indx;
627*37da2899SCharles.Forsyth 	TkCtext *t;
628*37da2899SCharles.Forsyth 	TkCanvas *c;
629*37da2899SCharles.Forsyth 	char *e, buf[Tkmaxitem];
630*37da2899SCharles.Forsyth 
631*37da2899SCharles.Forsyth 	tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
632*37da2899SCharles.Forsyth 	e = tkcvsparseindex(i, buf, &indx);
633*37da2899SCharles.Forsyth 	if(e != nil)
634*37da2899SCharles.Forsyth 		return e;
635*37da2899SCharles.Forsyth 
636*37da2899SCharles.Forsyth 	c = TKobj(TkCanvas, tk);
637*37da2899SCharles.Forsyth 	t = TKobj(TkCtext, i);
638*37da2899SCharles.Forsyth 	switch(op) {
639*37da2899SCharles.Forsyth 	case TkCselfrom:
640*37da2899SCharles.Forsyth 		t->selfrom = indx;
641*37da2899SCharles.Forsyth 		return nil;
642*37da2899SCharles.Forsyth 	case TkCseladjust:
643*37da2899SCharles.Forsyth 		if(c->selection == i) {
644*37da2899SCharles.Forsyth 			if(abs(t->self-indx) < abs(t->sell-indx)) {
645*37da2899SCharles.Forsyth 				t->self = indx;
646*37da2899SCharles.Forsyth 				t->selfrom = t->sell;
647*37da2899SCharles.Forsyth 			}
648*37da2899SCharles.Forsyth 			else {
649*37da2899SCharles.Forsyth 				t->sell = indx;
650*37da2899SCharles.Forsyth 				t->selfrom = t->self;
651*37da2899SCharles.Forsyth 			}
652*37da2899SCharles.Forsyth 		}
653*37da2899SCharles.Forsyth 		/* No break */
654*37da2899SCharles.Forsyth 	case TkCselto:
655*37da2899SCharles.Forsyth 		if(c->selection != i)
656*37da2899SCharles.Forsyth 			tkcvstextclr(tk);
657*37da2899SCharles.Forsyth 		c->selection = i;
658*37da2899SCharles.Forsyth 		t->self = t->selfrom;
659*37da2899SCharles.Forsyth 		t->sell = indx;
660*37da2899SCharles.Forsyth 		break;
661*37da2899SCharles.Forsyth 	}
662*37da2899SCharles.Forsyth 	t->sbw = c->sborderwidth;
663*37da2899SCharles.Forsyth 	tkbbmax(&TKobj(TkCanvas, tk)->update, &i->p.bb);
664*37da2899SCharles.Forsyth 	tkcvssetdirty(tk);
665*37da2899SCharles.Forsyth 	return nil;
666*37da2899SCharles.Forsyth }
667