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