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(atoi(cp->args[1]) == 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 } 367