]> git.lizzy.rs Git - plan9front.git/blob - sys/src/libcontrol/menu.c
usbxhci: implement command timeouts and aborts, serialize unstall
[plan9front.git] / sys / src / libcontrol / menu.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 Menu0 Menu0;     /* Menu is taken by mouse.h */
10
11 struct Menu0
12 {
13         Control;
14         CImage  *image;
15         CImage  *bordercolor;
16         CImage  *textcolor;
17         CImage  *selectcolor;
18         CImage  *selecttextcolor;
19         CFont   *font;
20         char            **line;
21         int             nline;
22         int             border;
23         int             align;
24         Image   *window;
25         int             visible;        /* state of menu */
26         int             selection;              /* currently selected line; -1 == none */
27         int             prevsel;        /* previous selection */
28         int             lastbut;        /* previous state of mouse button */
29 };
30
31 enum{
32         EAdd,
33         EAlign,
34         EBorder,
35         EBordercolor,
36         EFocus,
37         EFont,
38         EFormat,
39         EHide,
40         EImage,
41         ERect,
42         EReveal,
43         ESelectcolor,
44         ESelecttextcolor,
45         EShow,
46         ESize,
47         ETextcolor,
48         EWindow,
49 };
50
51 static char *cmds[] = {
52         [EAdd] =                        "add",
53         [EAlign] =                      "align",
54         [EBorder] =             "border",
55         [EBordercolor] =        "bordercolor",
56         [EFocus] =              "focus",
57         [EFont] =                       "font",
58         [EFormat] =             "format",
59         [EHide] =                       "hide",
60         [EImage] =              "image",
61         [ERect] =                       "rect",
62         [EReveal] =             "reveal",
63         [ESelectcolor] =        "selectcolor",
64         [ESelecttextcolor] =    "selecttextcolor",
65         [EShow] =                       "show",
66         [ESize] =                       "size",
67         [ETextcolor] =          "textcolor",
68         [EWindow] =             "window",
69         nil
70 };
71
72 static void     menushow(Menu0*);
73 static void menuhide(Menu0*);
74
75 static void
76 menufree(Control *c)
77 {
78         Menu0 *m;
79
80         m = (Menu0*)c;
81         _putctlfont(m->font);
82         _putctlimage(m->image);
83         _putctlimage(m->textcolor);
84         _putctlimage(m->bordercolor);
85         _putctlimage(m->selectcolor);
86         _putctlimage(m->selecttextcolor);
87 }
88
89 static void
90 menushow(Menu0 *m)
91 {
92         Rectangle r, clipr;
93         int i, dx, dy, w;
94         Font *f;
95         Point p, q;
96         Image *im, *c;
97
98         if(m->hidden || m->window == nil)
99                 return;
100
101         m->visible = 1;
102         f = m->font->font;
103         draw(m->window, m->rect, m->image->image, nil, m->image->image->r.min);
104         if(m->border > 0)
105                 border(m->window, m->rect, m->border, m->bordercolor->image, ZP);
106         /* text goes here */
107         dx = 0;
108         for(i=0; i<m->nline; i++){
109                 w = stringwidth(f, m->line[i]);
110                 if(dx < w)
111                         dx = w;
112         }
113         dy = m->nline*f->height;
114         clipr = insetrect(m->rect, m->border);
115         p = _ctlalignpoint(clipr, dx, dy, m->align);
116         im = m->textcolor->image;
117 //      if(m->pressed)
118 //              im = m->pressedtextcolor->image;
119         for(i=0; i<m->nline; i++){
120                 r.min = p;
121                 r.max.x = p.x+dx;
122                 r.max.y = p.y+f->height;
123                 c = im;
124                 if(i == m->selection){
125                         draw(m->window, r, m->selectcolor->image, nil, ZP);
126                         c = m->selecttextcolor->image;
127                 }
128                 q = _ctlalignpoint(r, stringwidth(f, m->line[i]), f->height, m->align%3);
129                 _string(m->window, q, c,
130                         ZP, f, m->line[i], nil, strlen(m->line[i]),
131                         clipr, nil, ZP, SoverD);
132                 p.y += f->height;
133         }
134 //      if(m->pressed)
135 //              draw(m->screen, m->rect, m->lighm->image, m->mask->image, m->mask->image->r.min);
136         flushimage(display, 1);
137 }
138
139 static Point
140 menusize(Menu0 *m)
141 {
142         int x, y;
143         int i;
144         Point p;
145         Font *f;
146
147         x = 0;
148         y = 0;
149         f = m->font->font;
150         for(i=0; i<m->nline; i++){
151                 p = stringsize(f, m->line[i]);
152                 if(p.x > x)
153                         x = p.x;
154                 y += f->height;
155         }
156
157         return Pt(x+2*m->border, y+2*m->border);
158 }
159
160 static void
161 menuhide(Menu0 *m)
162 {
163         freeimage(m->window);
164         m->window = nil;
165         m->rect.max.y = m->rect.min.y;  /* go to zero size */
166         m->lastbut = 0;
167         m->visible = 0;
168         if(m->selection >= 0)
169                 m->prevsel = m->selection;
170         m->selection = -1;
171         _ctlfocus(m, 0);
172 }
173
174 static void
175 menutrack(Control *c, Mouse *ms)
176 {
177         Rectangle r;
178         int s;
179         Menu0 *m;
180
181         m = (Menu0*)c;
182         if(m->window == nil)
183                 return;
184         if(m->lastbut && ms->buttons==0){       /* menu was released */
185                 chanprint(m->event, "%q: value %d", m->name, m->selection);
186                 menuhide(m);
187                 return;
188         }
189         m->lastbut = ms->buttons;
190         r = insetrect(m->rect, m->border);
191         if(!ptinrect(ms->xy, r))
192                 s = -1;
193         else{
194                 s = (ms->xy.y - r.min.y)/m->font->font->height;
195                 if(s < 0 || s >= m->nline)
196                         s = -1;
197         }
198         if(m->visible== 0 || s!=m->selection){
199                 m->selection = s;
200                 menushow(m);
201         }
202 }
203
204 static void
205 menuctl(Control *c, CParse *cp)
206 {
207         int up, cmd, h;
208         Rectangle r;
209         Menu0 *m;
210         Point diag;
211
212         m = (Menu0*)c;
213         cmd = _ctllookup(cp->args[0], cmds, nelem(cmds));
214         switch(cmd){
215         default:
216                 ctlerror("%q: unrecognized message '%s'", m->name, cp->str);
217                 break;
218         case EAdd:
219                 _ctlargcount(m, cp, 2);
220                 m->line = ctlrealloc(m->line, (m->nline+1)*sizeof(char*));
221                 m->line[m->nline++] = ctlstrdup(cp->args[1]);
222                 menushow(m);
223                 break;
224         case EAlign:
225                 _ctlargcount(m, cp, 2);
226                 m->align = _ctlalignment(cp->args[1]);
227                 menushow(m);
228                 break;
229         case EBorder:
230                 _ctlargcount(m, cp, 2);
231                 m->border = cp->iargs[1];
232                 menushow(m);
233                 break;
234         case EBordercolor:
235                 _ctlargcount(m, cp, 2);
236                 _setctlimage(m, &m->bordercolor, cp->args[1]);
237                 menushow(m);
238                 break;
239         case EFocus:
240                 _ctlargcount(m, cp, 2);
241                 if(strtol(cp->args[1], 0, 0) == 0)
242                         menuhide(m);
243                 break;
244         case EFont:
245                 _ctlargcount(m, cp, 2);
246                 _setctlfont(m, &m->font, cp->args[1]);
247                 break;
248         case EFormat:
249                 _ctlargcount(m, cp, 2);
250                 m->format = ctlstrdup(cp->args[1]);
251                 break;
252         case EHide:
253                 _ctlargcount(m, cp, 1);
254                 m->hidden = 1;
255                 break;
256         case EImage:
257                 _ctlargcount(m, cp, 2);
258                 _setctlimage(m, &m->image, cp->args[1]);
259                 menushow(m);
260                 break;
261         case ERect:
262                 _ctlargcount(m, cp, 5);
263                 r.min.x = cp->iargs[1];
264                 r.min.y = cp->iargs[2];
265                 r.max.x = cp->iargs[3];
266                 r.max.y = cp->iargs[4];
267                 if(Dx(r)<0 || Dy(r)<0)
268                         ctlerror("%q: bad rectangle: %s", m->name, cp->str);
269                 m->rect = r;
270                 menushow(m);
271                 break;
272         case EReveal:
273                 _ctlargcount(m, cp, 1);
274                 m->hidden = 0;
275                 menushow(m);
276                 break;
277         case ESelectcolor:
278                 _ctlargcount(m, cp, 2);
279                 _setctlimage(m, &m->selectcolor, cp->args[1]);
280                 menushow(m);
281                 break;
282         case ESelecttextcolor:
283                 _ctlargcount(m, cp, 2);
284                 _setctlimage(m, &m->selecttextcolor, cp->args[1]);
285                 menushow(m);
286                 break;
287         case EShow:
288                 _ctlargcount(m, cp, 1);
289                 menushow(m);
290                 break;
291         case ESize:
292                 if (cp->nargs == 3)
293                         r.max = Pt(0x7fffffff, 0x7fffffff);
294                 else{
295                         _ctlargcount(m, cp, 5);
296                         r.max.x = cp->iargs[3];
297                         r.max.y = cp->iargs[4];
298                 }
299                 r.min.x = cp->iargs[1];
300                 r.min.y = cp->iargs[2];
301                 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)
302                         ctlerror("%q: bad sizes: %s", m->name, cp->str);
303                 m->size.min = r.min;
304                 m->size.max = r.max;
305                 break;
306         case ETextcolor:
307                 _ctlargcount(m, cp, 2);
308                 _setctlimage(m, &m->textcolor, cp->args[1]);
309                 menushow(m);
310                 break;
311         case EWindow:
312                 /* no args == toggle; otherwise 0 or 1 for state of window */
313                 if(cp->nargs >= 2)
314                         up = cp->iargs[1];
315                 else
316                         up = (m->window == nil);
317                 if(!up){        /* take window down */
318                         if(m->window)
319                                 menuhide(m);
320                         break;
321                 }
322                 if(m->window != nil)
323                         break;
324                 diag = menusize(m);
325                 m->rect.max.x = m->rect.min.x + diag.x;
326                 m->rect.max.y = m->rect.min.y + diag.y;
327                 m->window = allocwindow(_screen, m->rect, Refbackup, DWhite);
328                 if(m->window == nil)
329                         m->window = m->screen;
330                 up = m->prevsel;
331                 if(up<0 || up>=m->nline)
332                         up = 0;
333                 m->selection = up;
334                 menushow(m);
335                 h = m->font->font->height;
336                 moveto(m->controlset->mousectl,
337                         Pt(m->rect.min.x+Dx(m->rect)/2, m->rect.min.y+up*h+h/2));
338 //              _ctlfocus(m, 1);
339                 break;
340         }
341 }
342
343 Control*
344 createmenu(Controlset *cs, char *name)
345 {
346         Menu0 *m;
347
348         m = (Menu0*)_createctl(cs, "menu", sizeof(Menu0), name);
349         m->font = _getctlfont("font");
350         m->image = _getctlimage("white");
351         m->textcolor = _getctlimage("black");
352         m->selectcolor = _getctlimage("yellow");
353         m->selecttextcolor = _getctlimage("black");
354         m->bordercolor = _getctlimage("black");
355         m->format = ctlstrdup("%q: value %d");
356         m->border = 0;
357         m->align = Aupperleft;
358         m->visible = 0;
359         m->window = nil;
360         m->lastbut = 0;
361         m->selection = -1;
362         m->mouse = menutrack;
363         m->ctl = menuctl;
364         m->exit = menufree;
365         return (Control *)m;
366 }