diff options
author | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
---|---|---|
committer | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
commit | e5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch) | |
tree | d8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/libcontrol/menu.c |
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/libcontrol/menu.c')
-rwxr-xr-x | sys/src/libcontrol/menu.c | 366 |
1 files changed, 366 insertions, 0 deletions
diff --git a/sys/src/libcontrol/menu.c b/sys/src/libcontrol/menu.c new file mode 100755 index 000000000..56b915a4c --- /dev/null +++ b/sys/src/libcontrol/menu.c @@ -0,0 +1,366 @@ +#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; +} |