xref: /plan9/sys/src/libcontrol/entry.c (revision 42dedc50a943b5d120c8c26dac13fc4664b65146)
1 #include <u.h>
2 #include <libc.h>
3 #include <draw.h>
4 #include <thread.h>
5 #include <mouse.h>
6 #include <keyboard.h>
7 #include <control.h>
8 
9 typedef struct Entry Entry;
10 
11 struct Entry
12 {
13 	Control;
14 	int		border;
15 	CFont	*font;
16 	CImage	*image;
17 	CImage	*textcolor;
18 	CImage	*bordercolor;
19 	Rune		*text;
20 	int		ntext;
21 	int		cursor;
22 	int		align;
23 	int		hasfocus;
24 	int		lastbut;
25 };
26 
27 enum{
28 	EAlign,
29 	EBorder,
30 	EBordercolor,
31 	EData,
32 	EFocus,
33 	EFont,
34 	EFormat,
35 	EHide,
36 	EImage,
37 	ERect,
38 	EReveal,
39 	EShow,
40 	ESize,
41 	ETextcolor,
42 	EValue,
43 };
44 
45 static char *cmds[] = {
46 	[EAlign] =			"align",
47 	[EBorder] =		"border",
48 	[EBordercolor] =	"bordercolor",
49 	[EData] = 			"data",
50 	[EFocus] = 		"focus",
51 	[EFont] =			"font",
52 	[EFormat] = 		"format",
53 	[EHide] =			"hide",
54 	[EImage] =		"image",
55 	[ERect] =			"rect",
56 	[EReveal] =		"reveal",
57 	[EShow] =			"show",
58 	[ESize] =			"size",
59 	[ETextcolor] =		"textcolor",
60 	[EValue] =			"value",
61 	nil
62 };
63 
64 static void
entryfree(Control * c)65 entryfree(Control *c)
66 {
67 	Entry *e;
68 
69 	e = (Entry *)c;
70 	_putctlfont(e->font);
71 	_putctlimage(e->image);
72 	_putctlimage(e->textcolor);
73 	_putctlimage(e->bordercolor);
74 	free(e->text);
75 }
76 
77 static Point
entrypoint(Entry * e,int c)78 entrypoint(Entry *e, int c)
79 {
80 	Point p;
81 	Rectangle r;
82 
83 	r = e->rect;
84 	if(e->border > 0)
85 		r = insetrect(r, e->border);
86 	p = _ctlalignpoint(r,
87 		runestringnwidth(e->font->font, e->text, e->ntext),
88 		e->font->font->height, e->align);
89 	if(c > e->ntext)
90 		c = e->ntext;
91 	p.x += runestringnwidth(e->font->font, e->text, c);
92 	return p;
93 }
94 
95 static void
entryshow(Entry * e)96 entryshow(Entry *e)
97 {
98 	Rectangle r, dr;
99 	Point p;
100 
101 	if (e->hidden)
102 		return;
103 	r = e->rect;
104 	draw(e->screen, r, e->image->image, nil, e->image->image->r.min);
105 	if(e->border > 0){
106 		border(e->screen, r, e->border, e->bordercolor->image, e->bordercolor->image->r.min);
107 		dr = insetrect(r, e->border);
108 	}else
109 		dr = r;
110 	p = entrypoint(e, 0);
111 	_string(e->screen, p, e->textcolor->image,
112 		ZP, e->font->font, nil, e->text, e->ntext,
113 		dr, nil, ZP, SoverD);
114 	if(e->hasfocus){
115 		p = entrypoint(e, e->cursor);
116 		r.min = p;
117 		r.max.x = p.x+1;
118 		r.max.y = p.y+e->font->font->height;
119 		if(rectclip(&r, dr))
120 			draw(e->screen, r, e->textcolor->image, nil, ZP);
121 	}
122 	flushimage(display, 1);
123 }
124 
125 static void
entrysetpoint(Entry * e,Point cp)126 entrysetpoint(Entry *e, Point cp)
127 {
128 	Point p;
129 	int i;
130 
131 	if(!ptinrect(cp, insetrect(e->rect, e->border)))
132 		return;
133 	p = entrypoint(e, 0);
134 	for(i=0; i<e->ntext; i++){
135 		p.x += runestringnwidth(e->font->font, e->text+i, 1);
136 		if(p.x > cp.x)
137 			break;
138 	}
139 	e->cursor = i;
140 	entryshow(e);
141 }
142 
143 static void
entrymouse(Control * c,Mouse * m)144 entrymouse(Control *c, Mouse *m)
145 {
146 	Entry *e;
147 
148 	e = (Entry*)c;
149 	if(m->buttons==1 && e->lastbut==0)
150 		entrysetpoint(e, m->xy);
151 	e->lastbut = m->buttons;
152 }
153 
154 static void
entryctl(Control * c,CParse * cp)155 entryctl(Control *c, CParse *cp)
156 {
157 	int cmd;
158 	Rectangle r;
159 	Entry *e;
160 	Rune *rp;
161 
162 	e = (Entry*)c;
163 	cmd = _ctllookup(cp->args[0], cmds, nelem(cmds));
164 	switch(cmd){
165 	default:
166 		ctlerror("%q: unrecognized message '%s'", e->name, cp->str);
167 		break;
168 	case EAlign:
169 		_ctlargcount(e, cp, 2);
170 		e->align = _ctlalignment(cp->args[1]);
171 		break;
172 	case EBorder:
173 		_ctlargcount(e, cp, 2);
174 		if(cp->iargs[1] < 0)
175 			ctlerror("%q: bad border: %c", e->name, cp->str);
176 		e->border = cp->iargs[1];
177 		break;
178 	case EBordercolor:
179 		_ctlargcount(e, cp, 2);
180 		_setctlimage(e, &e->bordercolor, cp->args[1]);
181 		break;
182 	case EData:
183 		_ctlargcount(e, cp, 1);
184 		chanprint(e->data, "%S", e->text);
185 		break;
186 	case EFocus:
187 		_ctlargcount(e, cp, 2);
188 		e->hasfocus = cp->iargs[1];
189 		e->lastbut = 0;
190 		entryshow(e);
191 		break;
192 	case EFont:
193 		_ctlargcount(e, cp, 2);
194 		_setctlfont(e, &e->font, cp->args[1]);
195 		break;
196 	case EFormat:
197 		_ctlargcount(e, cp, 2);
198 		e->format = ctlstrdup(cp->args[1]);
199 		break;
200 	case EHide:
201 		_ctlargcount(e, cp, 1);
202 		e->hidden = 1;
203 		break;
204 	case EImage:
205 		_ctlargcount(e, cp, 2);
206 		_setctlimage(e, &e->image, cp->args[1]);
207 		break;
208 	case ERect:
209 		_ctlargcount(e, cp, 5);
210 		r.min.x = cp->iargs[1];
211 		r.min.y = cp->iargs[2];
212 		r.max.x = cp->iargs[3];
213 		r.max.y = cp->iargs[4];
214 		if(Dx(r)<=0 || Dy(r)<=0)
215 			ctlerror("%q: bad rectangle: %s", e->name, cp->str);
216 		e->rect = r;
217 		break;
218 	case EReveal:
219 		_ctlargcount(e, cp, 1);
220 		e->hidden = 0;
221 		entryshow(e);
222 		break;
223 	case EShow:
224 		_ctlargcount(e, cp, 1);
225 		entryshow(e);
226 		break;
227 	case ESize:
228 		if (cp->nargs == 3)
229 			r.max = Pt(0x7fffffff, 0x7fffffff);
230 		else{
231 			_ctlargcount(e, cp, 5);
232 			r.max.x = cp->iargs[3];
233 			r.max.y = cp->iargs[4];
234 		}
235 		r.min.x = cp->iargs[1];
236 		r.min.y = cp->iargs[2];
237 		if(r.min.x<=0 || r.min.y<=0 || r.max.x<=0 || r.max.y<=0 || r.max.x < r.min.x || r.max.y < r.min.y)
238 			ctlerror("%q: bad sizes: %s", e->name, cp->str);
239 		e->size.min = r.min;
240 		e->size.max = r.max;
241 		break;
242 	case ETextcolor:
243 		_ctlargcount(e, cp, 2);
244 		_setctlimage(e, &e->textcolor, cp->args[1]);
245 		break;
246 	case EValue:
247 		_ctlargcount(e, cp, 2);
248 		rp = _ctlrunestr(cp->args[1]);
249 		if(runestrcmp(rp, e->text) != 0){
250 			free(e->text);
251 			e->text = rp;
252 			e->ntext = runestrlen(e->text);
253 			e->cursor = e->ntext;
254 			entryshow(e);
255 		}else
256 			free(rp);
257 		break;
258 	}
259 }
260 
261 static void
entrykey(Entry * e,Rune r)262 entrykey(Entry *e, Rune r)
263 {
264 	Rune *s;
265 	int n;
266 	char *p;
267 
268 	switch(r){
269 	default:
270 		e->text = ctlrealloc(e->text, (e->ntext+1+1)*sizeof(Rune));
271 		memmove(e->text+e->cursor+1, e->text+e->cursor,
272 			(e->ntext+1-e->cursor)*sizeof(Rune));
273 		e->text[e->cursor++] = r;
274 		e->ntext++;
275 		break;
276 	case L'\n':	/* newline: return value */
277 		p = _ctlstrrune(e->text);
278 		chanprint(e->event, e->format, e->name, p);
279 		free(p);
280 		return;
281 	case L'\b':
282 		if(e->cursor > 0){
283 			memmove(e->text+e->cursor-1, e->text+e->cursor,
284 				(e->ntext+1-e->cursor)*sizeof(Rune));
285 			e->cursor--;
286 			e->ntext--;
287 		}
288 		break;
289 	case Kright:
290 		if(e->cursor < e->ntext)
291 			e->cursor++;
292 		break;
293 	case Kleft:
294 		if(e->cursor > 0)
295 			e->cursor--;
296 		break;
297 	case 0x01:	/* control A: beginning of line */
298 		e->cursor = 0;
299 		break;
300 	case 0x05:	/* control E: end of line */
301 		e->cursor = e->ntext;
302 		break;
303 	case 0x15:	/* control U: kill line */
304 		e->cursor = 0;
305 		e->ntext = 0;
306 		break;
307 	case 0x16:	/* control V: paste (append snarf buffer) */
308 		s = _ctlgetsnarf();
309 		if(s != nil){
310 			n = runestrlen(s);
311 			e->text = ctlrealloc(e->text, (e->ntext+n+1)*sizeof(Rune));
312 			memmove(e->text+e->cursor+n, e->text+e->cursor,
313 				(e->ntext+1-e->cursor)*sizeof(Rune));
314 			memmove(e->text+e->cursor, s, n*sizeof(Rune));
315 			e->cursor += n;
316 			e->ntext += n;
317 		}
318 		break;
319 	}
320 	e->text[e->ntext] = L'\0';
321 }
322 
323 static void
entrykeys(Control * c,Rune * rp)324 entrykeys(Control *c, Rune *rp)
325 {
326 	Entry *e;
327 	int i;
328 
329 	e = (Entry *)c;
330 	for(i=0; rp[i]!=L'\0'; i++)
331 		entrykey(e, rp[i]);
332 	entryshow(e);
333 }
334 
335 Control*
createentry(Controlset * cs,char * name)336 createentry(Controlset *cs, char *name)
337 {
338 	Entry *e;
339 
340 	e = (Entry*) _createctl(cs, "entry", sizeof(Entry), name);
341 	e->text = ctlmalloc(sizeof(Rune));
342 	e->ntext = 0;
343 	e->image = _getctlimage("white");
344 	e->textcolor = _getctlimage("black");
345 	e->bordercolor = _getctlimage("black");
346 	e->font = _getctlfont("font");
347 	e->format = ctlstrdup("%q: value %q");
348 	e->border = 0;
349 	e->ctl = entryctl;
350 	e->mouse = entrymouse;
351 	e->key = entrykeys;
352 	e->exit = entryfree;
353 	return (Control *)e;
354 }
355