123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366 |
- #include <u.h>
- #include <libc.h>
- #include <draw.h>
- #include <thread.h>
- #include <mouse.h>
- #include <keyboard.h>
- #include <control.h>
- typedef struct Menu0 Menu0; /* Menu is taken by mouse.h */
- struct Menu0
- {
- Control;
- CImage *image;
- CImage *bordercolor;
- CImage *textcolor;
- CImage *selectcolor;
- CImage *selecttextcolor;
- CFont *font;
- char **line;
- int nline;
- int border;
- int align;
- Image *window;
- int visible; /* state of menu */
- int selection; /* currently selected line; -1 == none */
- int prevsel; /* previous selection */
- int lastbut; /* previous state of mouse button */
- };
- enum{
- EAdd,
- EAlign,
- EBorder,
- EBordercolor,
- EFocus,
- EFont,
- EFormat,
- EHide,
- EImage,
- ERect,
- EReveal,
- ESelectcolor,
- ESelecttextcolor,
- EShow,
- ESize,
- ETextcolor,
- EWindow,
- };
- static char *cmds[] = {
- [EAdd] = "add",
- [EAlign] = "align",
- [EBorder] = "border",
- [EBordercolor] = "bordercolor",
- [EFocus] = "focus",
- [EFont] = "font",
- [EFormat] = "format",
- [EHide] = "hide",
- [EImage] = "image",
- [ERect] = "rect",
- [EReveal] = "reveal",
- [ESelectcolor] = "selectcolor",
- [ESelecttextcolor] = "selecttextcolor",
- [EShow] = "show",
- [ESize] = "size",
- [ETextcolor] = "textcolor",
- [EWindow] = "window",
- nil
- };
- static void menushow(Menu0*);
- static void menuhide(Menu0*);
- static void
- menufree(Control *c)
- {
- Menu0 *m;
- m = (Menu0*)c;
- _putctlfont(m->font);
- _putctlimage(m->image);
- _putctlimage(m->textcolor);
- _putctlimage(m->bordercolor);
- _putctlimage(m->selectcolor);
- _putctlimage(m->selecttextcolor);
- }
- static void
- menushow(Menu0 *m)
- {
- Rectangle r, clipr;
- int i, dx, dy, w;
- Font *f;
- Point p, q;
- Image *im, *c;
- if(m->hidden || m->window == nil)
- return;
- m->visible = 1;
- f = m->font->font;
- draw(m->window, m->rect, m->image->image, nil, m->image->image->r.min);
- if(m->border > 0)
- border(m->window, m->rect, m->border, m->bordercolor->image, ZP);
- /* text goes here */
- dx = 0;
- for(i=0; i<m->nline; i++){
- w = stringwidth(f, m->line[i]);
- if(dx < w)
- dx = w;
- }
- dy = m->nline*f->height;
- clipr = insetrect(m->rect, m->border);
- p = _ctlalignpoint(clipr, dx, dy, m->align);
- im = m->textcolor->image;
- // if(m->pressed)
- // im = m->pressedtextcolor->image;
- for(i=0; i<m->nline; i++){
- r.min = p;
- r.max.x = p.x+dx;
- r.max.y = p.y+f->height;
- c = im;
- if(i == m->selection){
- draw(m->window, r, m->selectcolor->image, nil, ZP);
- c = m->selecttextcolor->image;
- }
- q = _ctlalignpoint(r, stringwidth(f, m->line[i]), f->height, m->align%3);
- _string(m->window, q, c,
- ZP, f, m->line[i], nil, strlen(m->line[i]),
- clipr, nil, ZP, SoverD);
- p.y += f->height;
- }
- // if(m->pressed)
- // draw(m->screen, m->rect, m->lighm->image, m->mask->image, m->mask->image->r.min);
- flushimage(display, 1);
- }
- static Point
- menusize(Menu0 *m)
- {
- int x, y;
- int i;
- Point p;
- Font *f;
- x = 0;
- y = 0;
- f = m->font->font;
- for(i=0; i<m->nline; i++){
- p = stringsize(f, m->line[i]);
- if(p.x > x)
- x = p.x;
- y += f->height;
- }
- return Pt(x+2*m->border, y+2*m->border);
- }
- static void
- menuhide(Menu0 *m)
- {
- freeimage(m->window);
- m->window = nil;
- m->rect.max.y = m->rect.min.y; /* go to zero size */
- m->lastbut = 0;
- m->visible = 0;
- if(m->selection >= 0)
- m->prevsel = m->selection;
- m->selection = -1;
- _ctlfocus(m, 0);
- }
- static void
- menutrack(Control *c, Mouse *ms)
- {
- Rectangle r;
- int s;
- Menu0 *m;
- m = (Menu0*)c;
- if(m->window == nil)
- return;
- if(m->lastbut && ms->buttons==0){ /* menu was released */
- chanprint(m->event, "%q: value %d", m->name, m->selection);
- menuhide(m);
- return;
- }
- m->lastbut = ms->buttons;
- r = insetrect(m->rect, m->border);
- if(!ptinrect(ms->xy, r))
- s = -1;
- else{
- s = (ms->xy.y - r.min.y)/m->font->font->height;
- if(s < 0 || s >= m->nline)
- s = -1;
- }
- if(m->visible== 0 || s!=m->selection){
- m->selection = s;
- menushow(m);
- }
- }
- static void
- menuctl(Control *c, CParse *cp)
- {
- int up, cmd, h;
- Rectangle r;
- Menu0 *m;
- Point diag;
- m = (Menu0*)c;
- cmd = _ctllookup(cp->args[0], cmds, nelem(cmds));
- switch(cmd){
- default:
- ctlerror("%q: unrecognized message '%s'", m->name, cp->str);
- break;
- case EAdd:
- _ctlargcount(m, cp, 2);
- m->line = ctlrealloc(m->line, (m->nline+1)*sizeof(char*));
- m->line[m->nline++] = ctlstrdup(cp->args[1]);
- menushow(m);
- break;
- case EAlign:
- _ctlargcount(m, cp, 2);
- m->align = _ctlalignment(cp->args[1]);
- menushow(m);
- break;
- case EBorder:
- _ctlargcount(m, cp, 2);
- m->border = cp->iargs[1];
- menushow(m);
- break;
- case EBordercolor:
- _ctlargcount(m, cp, 2);
- _setctlimage(m, &m->bordercolor, cp->args[1]);
- menushow(m);
- break;
- case EFocus:
- _ctlargcount(m, cp, 2);
- if(atoi(cp->args[1]) == 0)
- menuhide(m);
- break;
- case EFont:
- _ctlargcount(m, cp, 2);
- _setctlfont(m, &m->font, cp->args[1]);
- break;
- case EFormat:
- _ctlargcount(m, cp, 2);
- m->format = ctlstrdup(cp->args[1]);
- break;
- case EHide:
- _ctlargcount(m, cp, 1);
- m->hidden = 1;
- break;
- case EImage:
- _ctlargcount(m, cp, 2);
- _setctlimage(m, &m->image, cp->args[1]);
- menushow(m);
- break;
- case ERect:
- _ctlargcount(m, cp, 5);
- r.min.x = cp->iargs[1];
- r.min.y = cp->iargs[2];
- r.max.x = cp->iargs[3];
- r.max.y = cp->iargs[4];
- if(Dx(r)<0 || Dy(r)<0)
- ctlerror("%q: bad rectangle: %s", m->name, cp->str);
- m->rect = r;
- menushow(m);
- break;
- case EReveal:
- _ctlargcount(m, cp, 1);
- m->hidden = 0;
- menushow(m);
- break;
- case ESelectcolor:
- _ctlargcount(m, cp, 2);
- _setctlimage(m, &m->selectcolor, cp->args[1]);
- menushow(m);
- break;
- case ESelecttextcolor:
- _ctlargcount(m, cp, 2);
- _setctlimage(m, &m->selecttextcolor, cp->args[1]);
- menushow(m);
- break;
- case EShow:
- _ctlargcount(m, cp, 1);
- menushow(m);
- break;
- case ESize:
- if (cp->nargs == 3)
- r.max = Pt(0x7fffffff, 0x7fffffff);
- else{
- _ctlargcount(m, cp, 5);
- r.max.x = cp->iargs[3];
- r.max.y = cp->iargs[4];
- }
- r.min.x = cp->iargs[1];
- r.min.y = cp->iargs[2];
- 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)
- ctlerror("%q: bad sizes: %s", m->name, cp->str);
- m->size.min = r.min;
- m->size.max = r.max;
- break;
- case ETextcolor:
- _ctlargcount(m, cp, 2);
- _setctlimage(m, &m->textcolor, cp->args[1]);
- menushow(m);
- break;
- case EWindow:
- /* no args == toggle; otherwise 0 or 1 for state of window */
- if(cp->nargs >= 2)
- up = cp->iargs[1];
- else
- up = (m->window == nil);
- if(!up){ /* take window down */
- if(m->window)
- menuhide(m);
- break;
- }
- if(m->window != nil)
- break;
- diag = menusize(m);
- m->rect.max.x = m->rect.min.x + diag.x;
- m->rect.max.y = m->rect.min.y + diag.y;
- m->window = allocwindow(_screen, m->rect, Refbackup, DWhite);
- if(m->window == nil)
- m->window = m->screen;
- up = m->prevsel;
- if(up<0 || up>=m->nline)
- up = 0;
- m->selection = up;
- menushow(m);
- h = m->font->font->height;
- moveto(m->controlset->mousectl,
- Pt(m->rect.min.x+Dx(m->rect)/2, m->rect.min.y+up*h+h/2));
- // _ctlfocus(m, 1);
- break;
- }
- }
- Control*
- createmenu(Controlset *cs, char *name)
- {
- Menu0 *m;
- m = (Menu0*)_createctl(cs, "menu", sizeof(Menu0), name);
- m->font = _getctlfont("font");
- m->image = _getctlimage("white");
- m->textcolor = _getctlimage("black");
- m->selectcolor = _getctlimage("yellow");
- m->selecttextcolor = _getctlimage("black");
- m->bordercolor = _getctlimage("black");
- m->format = ctlstrdup("%q: value %d");
- m->border = 0;
- m->align = Aupperleft;
- m->visible = 0;
- m->window = nil;
- m->lastbut = 0;
- m->selection = -1;
- m->mouse = menutrack;
- m->ctl = menuctl;
- m->exit = menufree;
- return (Control *)m;
- }
|