]> git.lizzy.rs Git - plan9front.git/blob - sys/src/libcontrol/entry.c
fix fuckup
[plan9front.git] / sys / src / libcontrol / entry.c
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
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
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
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
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
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
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
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
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*
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 }