180ee5cbfSDavid du Colombier #include <u.h>
280ee5cbfSDavid du Colombier #include <libc.h>
380ee5cbfSDavid du Colombier #include <draw.h>
480ee5cbfSDavid du Colombier #include <thread.h>
580ee5cbfSDavid du Colombier #include <mouse.h>
680ee5cbfSDavid du Colombier #include <keyboard.h>
780ee5cbfSDavid du Colombier #include <control.h>
880ee5cbfSDavid du Colombier
980ee5cbfSDavid du Colombier typedef struct Button Button;
1080ee5cbfSDavid du Colombier
1180ee5cbfSDavid du Colombier struct Button
1280ee5cbfSDavid du Colombier {
1380ee5cbfSDavid du Colombier Control;
1480ee5cbfSDavid du Colombier CImage *image;
1580ee5cbfSDavid du Colombier CImage *mask;
1680ee5cbfSDavid du Colombier CImage *light;
17*6f314b92SDavid du Colombier CImage *pale;
1880ee5cbfSDavid du Colombier CImage *bordercolor;
1980ee5cbfSDavid du Colombier int pressed;
2080ee5cbfSDavid du Colombier int lastbut;
2180ee5cbfSDavid du Colombier int lastshow;
2280ee5cbfSDavid du Colombier int border;
2380ee5cbfSDavid du Colombier int align;
24*6f314b92SDavid du Colombier int off;
25*6f314b92SDavid du Colombier int prepress;
2680ee5cbfSDavid du Colombier };
2780ee5cbfSDavid du Colombier
2880ee5cbfSDavid du Colombier enum{
2980ee5cbfSDavid du Colombier EAlign,
3080ee5cbfSDavid du Colombier EBorder,
3180ee5cbfSDavid du Colombier EBordercolor,
3280ee5cbfSDavid du Colombier EFocus,
3380ee5cbfSDavid du Colombier EFormat,
349a747e4fSDavid du Colombier EHide,
3580ee5cbfSDavid du Colombier EImage,
3680ee5cbfSDavid du Colombier ELight,
3780ee5cbfSDavid du Colombier EMask,
38*6f314b92SDavid du Colombier EPale,
3980ee5cbfSDavid du Colombier ERect,
409a747e4fSDavid du Colombier EReveal,
4180ee5cbfSDavid du Colombier EShow,
429a747e4fSDavid du Colombier ESize,
4380ee5cbfSDavid du Colombier EValue,
4480ee5cbfSDavid du Colombier };
4580ee5cbfSDavid du Colombier
4680ee5cbfSDavid du Colombier static char *cmds[] = {
4780ee5cbfSDavid du Colombier [EAlign] = "align",
4880ee5cbfSDavid du Colombier [EBorder] = "border",
4980ee5cbfSDavid du Colombier [EBordercolor] = "bordercolor",
5080ee5cbfSDavid du Colombier [EFocus] = "focus",
5180ee5cbfSDavid du Colombier [EFormat] = "format",
529a747e4fSDavid du Colombier [EHide] = "hide",
5380ee5cbfSDavid du Colombier [EImage] = "image",
5480ee5cbfSDavid du Colombier [ELight] = "light",
5580ee5cbfSDavid du Colombier [EMask] = "mask",
56*6f314b92SDavid du Colombier [EPale] = "pale",
5780ee5cbfSDavid du Colombier [ERect] = "rect",
589a747e4fSDavid du Colombier [EReveal] = "reveal",
5980ee5cbfSDavid du Colombier [EShow] = "show",
609a747e4fSDavid du Colombier [ESize] = "size",
6180ee5cbfSDavid du Colombier [EValue] = "value",
6280ee5cbfSDavid du Colombier nil
6380ee5cbfSDavid du Colombier };
6480ee5cbfSDavid du Colombier
6580ee5cbfSDavid du Colombier static void
buttonfree(Control * c)669a747e4fSDavid du Colombier buttonfree(Control *c)
6780ee5cbfSDavid du Colombier {
6880ee5cbfSDavid du Colombier Button *b;
6980ee5cbfSDavid du Colombier
709a747e4fSDavid du Colombier b = (Button *)c;
7180ee5cbfSDavid du Colombier _putctlimage(b->image);
7280ee5cbfSDavid du Colombier _putctlimage(b->mask);
7380ee5cbfSDavid du Colombier _putctlimage(b->light);
74*6f314b92SDavid du Colombier _putctlimage(b->pale);
7580ee5cbfSDavid du Colombier _putctlimage(b->bordercolor);
7680ee5cbfSDavid du Colombier }
7780ee5cbfSDavid du Colombier
7880ee5cbfSDavid du Colombier static void
buttonshow(Button * b)7980ee5cbfSDavid du Colombier buttonshow(Button *b)
8080ee5cbfSDavid du Colombier {
8180ee5cbfSDavid du Colombier Rectangle r;
8280ee5cbfSDavid du Colombier
839a747e4fSDavid du Colombier if (b->hidden)
849a747e4fSDavid du Colombier return;
8580ee5cbfSDavid du Colombier r = b->rect;
8680ee5cbfSDavid du Colombier if(b->border > 0){
8780ee5cbfSDavid du Colombier border(b->screen, r, b->border, b->bordercolor->image, ZP);
8880ee5cbfSDavid du Colombier r = insetrect(b->rect, b->border);
8980ee5cbfSDavid du Colombier }
9080ee5cbfSDavid du Colombier draw(b->screen, r, b->image->image, nil, b->image->image->r.min);
91*6f314b92SDavid du Colombier if(b->off)
92*6f314b92SDavid du Colombier draw(b->screen, r, b->pale->image, b->mask->image, b->mask->image->r.min);
93*6f314b92SDavid du Colombier else if(b->pressed)
9480ee5cbfSDavid du Colombier draw(b->screen, r, b->light->image, b->mask->image, b->mask->image->r.min);
9580ee5cbfSDavid du Colombier b->lastshow = b->pressed;
9680ee5cbfSDavid du Colombier flushimage(display, 1);
9780ee5cbfSDavid du Colombier }
989a747e4fSDavid du Colombier
999a747e4fSDavid du Colombier static void
buttonmouse(Control * c,Mouse * m)1009a747e4fSDavid du Colombier buttonmouse(Control *c, Mouse *m)
1019a747e4fSDavid du Colombier {
1029a747e4fSDavid du Colombier Button *b;
1039a747e4fSDavid du Colombier
1049a747e4fSDavid du Colombier b = (Button*)c;
1059a747e4fSDavid du Colombier
106*6f314b92SDavid du Colombier if(m->buttons&7) {
107*6f314b92SDavid du Colombier if (ptinrect(m->xy,b->rect)) {
108*6f314b92SDavid du Colombier if (b->off) {
109*6f314b92SDavid du Colombier b->off = 0;
110*6f314b92SDavid du Colombier buttonshow(b);
111*6f314b92SDavid du Colombier }
112*6f314b92SDavid du Colombier } else {
113*6f314b92SDavid du Colombier if (!b->off) {
114*6f314b92SDavid du Colombier b->off = 1;
115*6f314b92SDavid du Colombier buttonshow(b);
116*6f314b92SDavid du Colombier }
117*6f314b92SDavid du Colombier }
118*6f314b92SDavid du Colombier }
1199a747e4fSDavid du Colombier if((m->buttons&7) != b->lastbut){
1209a747e4fSDavid du Colombier if(m->buttons & 7){
121*6f314b92SDavid du Colombier b->prepress = b->pressed;
1229a747e4fSDavid du Colombier if (b->pressed)
1239a747e4fSDavid du Colombier b->pressed = 0;
1249a747e4fSDavid du Colombier else
1259a747e4fSDavid du Colombier b->pressed = m->buttons & 7;
1269a747e4fSDavid du Colombier buttonshow(b);
1279a747e4fSDavid du Colombier }else /* generate event on button up */
128*6f314b92SDavid du Colombier if (ptinrect(m->xy,b->rect))
1299a747e4fSDavid du Colombier chanprint(b->event, b->format, b->name, b->pressed);
130*6f314b92SDavid du Colombier else {
131*6f314b92SDavid du Colombier b->off = 0;
132*6f314b92SDavid du Colombier b->pressed = b->prepress;
133*6f314b92SDavid du Colombier buttonshow(b);
134*6f314b92SDavid du Colombier }
1359a747e4fSDavid du Colombier }
1369a747e4fSDavid du Colombier b->lastbut = m->buttons & 7;
13780ee5cbfSDavid du Colombier }
13880ee5cbfSDavid du Colombier
13980ee5cbfSDavid du Colombier static void
buttonctl(Control * c,CParse * cp)1409a747e4fSDavid du Colombier buttonctl(Control *c, CParse *cp)
14180ee5cbfSDavid du Colombier {
14280ee5cbfSDavid du Colombier int cmd;
14380ee5cbfSDavid du Colombier Rectangle r;
14480ee5cbfSDavid du Colombier Button *b;
14580ee5cbfSDavid du Colombier
14680ee5cbfSDavid du Colombier b = (Button*)c;
1479a747e4fSDavid du Colombier cmd = _ctllookup(cp->args[0], cmds, nelem(cmds));
14880ee5cbfSDavid du Colombier switch(cmd){
14980ee5cbfSDavid du Colombier default:
1509a747e4fSDavid du Colombier ctlerror("%q: unrecognized message '%s'", b->name, cp->str);
15180ee5cbfSDavid du Colombier break;
15280ee5cbfSDavid du Colombier case EAlign:
1539a747e4fSDavid du Colombier _ctlargcount(b, cp, 2);
1549a747e4fSDavid du Colombier b->align = _ctlalignment(cp->args[1]);
15580ee5cbfSDavid du Colombier b->lastshow = -1; /* force redraw */
15680ee5cbfSDavid du Colombier break;
15780ee5cbfSDavid du Colombier case EBorder:
1589a747e4fSDavid du Colombier _ctlargcount(b, cp, 2);
1599a747e4fSDavid du Colombier b->border = cp->iargs[1];
16080ee5cbfSDavid du Colombier b->lastshow = -1; /* force redraw */
16180ee5cbfSDavid du Colombier break;
16280ee5cbfSDavid du Colombier case EBordercolor:
1639a747e4fSDavid du Colombier _ctlargcount(b, cp, 2);
1649a747e4fSDavid du Colombier _setctlimage(b, &b->bordercolor, cp->args[1]);
16580ee5cbfSDavid du Colombier b->lastshow = -1; /* force redraw */
16680ee5cbfSDavid du Colombier break;
16780ee5cbfSDavid du Colombier case EFocus:
16880ee5cbfSDavid du Colombier /* ignore focus change */
16980ee5cbfSDavid du Colombier break;
17080ee5cbfSDavid du Colombier case EFormat:
1719a747e4fSDavid du Colombier _ctlargcount(b, cp, 2);
1729a747e4fSDavid du Colombier b->format = ctlstrdup(cp->args[1]);
1739a747e4fSDavid du Colombier break;
1749a747e4fSDavid du Colombier case EHide:
1759a747e4fSDavid du Colombier _ctlargcount(b, cp, 1);
1769a747e4fSDavid du Colombier b->hidden = 1;
17780ee5cbfSDavid du Colombier break;
17880ee5cbfSDavid du Colombier case EImage:
1799a747e4fSDavid du Colombier _ctlargcount(b, cp, 2);
1809a747e4fSDavid du Colombier _setctlimage(b, &b->image, cp->args[1]);
18180ee5cbfSDavid du Colombier b->lastshow = -1; /* force redraw */
18280ee5cbfSDavid du Colombier break;
18380ee5cbfSDavid du Colombier case ELight:
1849a747e4fSDavid du Colombier _ctlargcount(b, cp, 2);
1859a747e4fSDavid du Colombier _setctlimage(b, &b->light, cp->args[1]);
18680ee5cbfSDavid du Colombier b->lastshow = -1; /* force redraw */
18780ee5cbfSDavid du Colombier break;
18880ee5cbfSDavid du Colombier case EMask:
1899a747e4fSDavid du Colombier _ctlargcount(b, cp, 2);
1909a747e4fSDavid du Colombier _setctlimage(b, &b->mask, cp->args[1]);
19180ee5cbfSDavid du Colombier b->lastshow = -1; /* force redraw */
19280ee5cbfSDavid du Colombier break;
193*6f314b92SDavid du Colombier case EPale:
194*6f314b92SDavid du Colombier _ctlargcount(b, cp, 2);
195*6f314b92SDavid du Colombier _setctlimage(b, &b->pale, cp->args[1]);
196*6f314b92SDavid du Colombier b->lastshow = -1; /* force redraw */
197*6f314b92SDavid du Colombier break;
19880ee5cbfSDavid du Colombier case ERect:
1999a747e4fSDavid du Colombier _ctlargcount(b, cp, 5);
2009a747e4fSDavid du Colombier r.min.x = cp->iargs[1];
2019a747e4fSDavid du Colombier r.min.y = cp->iargs[2];
2029a747e4fSDavid du Colombier r.max.x = cp->iargs[3];
2039a747e4fSDavid du Colombier r.max.y = cp->iargs[4];
20480ee5cbfSDavid du Colombier if(Dx(r)<0 || Dy(r)<0)
2059a747e4fSDavid du Colombier ctlerror("%q: bad rectangle: %s", b->name, cp->str);
20680ee5cbfSDavid du Colombier b->rect = r;
20780ee5cbfSDavid du Colombier b->lastshow = -1; /* force redraw */
20880ee5cbfSDavid du Colombier break;
2099a747e4fSDavid du Colombier case EReveal:
2109a747e4fSDavid du Colombier _ctlargcount(b, cp, 1);
2119a747e4fSDavid du Colombier b->hidden = 0;
21280ee5cbfSDavid du Colombier buttonshow(b);
21380ee5cbfSDavid du Colombier break;
2149a747e4fSDavid du Colombier case EShow:
2159a747e4fSDavid du Colombier _ctlargcount(b, cp, 1);
2169a747e4fSDavid du Colombier buttonshow(b);
2179a747e4fSDavid du Colombier break;
2189a747e4fSDavid du Colombier case ESize:
2199a747e4fSDavid du Colombier if (cp->nargs == 3)
2209a747e4fSDavid du Colombier r.max = Pt(0x7fffffff, 0x7fffffff);
2219a747e4fSDavid du Colombier else{
2229a747e4fSDavid du Colombier _ctlargcount(b, cp, 5);
2239a747e4fSDavid du Colombier r.max.x = cp->iargs[3];
2249a747e4fSDavid du Colombier r.max.y = cp->iargs[4];
2259a747e4fSDavid du Colombier }
2269a747e4fSDavid du Colombier r.min.x = cp->iargs[1];
2279a747e4fSDavid du Colombier r.min.y = cp->iargs[2];
2289a747e4fSDavid du Colombier 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)
2299a747e4fSDavid du Colombier ctlerror("%q: bad sizes: %s", b->name, cp->str);
2309a747e4fSDavid du Colombier b->size.min = r.min;
2319a747e4fSDavid du Colombier b->size.max = r.max;
2329a747e4fSDavid du Colombier break;
23380ee5cbfSDavid du Colombier case EValue:
2349a747e4fSDavid du Colombier _ctlargcount(b, cp, 2);
2359a747e4fSDavid du Colombier if((cp->iargs[1]!=0) != b->pressed){
23680ee5cbfSDavid du Colombier b->pressed ^= 1;
23780ee5cbfSDavid du Colombier buttonshow(b);
23880ee5cbfSDavid du Colombier }
23980ee5cbfSDavid du Colombier break;
24080ee5cbfSDavid du Colombier }
24180ee5cbfSDavid du Colombier }
2429a747e4fSDavid du Colombier
2439a747e4fSDavid du Colombier Control*
createbutton(Controlset * cs,char * name)2449a747e4fSDavid du Colombier createbutton(Controlset *cs, char *name)
2459a747e4fSDavid du Colombier {
2469a747e4fSDavid du Colombier Button *b;
2479a747e4fSDavid du Colombier b = (Button*)_createctl(cs, "button", sizeof(Button), name);
2489a747e4fSDavid du Colombier b->image = _getctlimage("white");
2499a747e4fSDavid du Colombier b->mask = _getctlimage("opaque");
2509a747e4fSDavid du Colombier b->light = _getctlimage("yellow");
251*6f314b92SDavid du Colombier b->pale = _getctlimage("paleyellow");
2529a747e4fSDavid du Colombier b->bordercolor = _getctlimage("black");
2539a747e4fSDavid du Colombier b->format = ctlstrdup("%q: value %d");
2549a747e4fSDavid du Colombier b->lastshow = -1;
2559a747e4fSDavid du Colombier b->border = 0;
2569a747e4fSDavid du Colombier b->align = Aupperleft;
2579a747e4fSDavid du Colombier b->ctl = buttonctl;
2589a747e4fSDavid du Colombier b->mouse = buttonmouse;
2599a747e4fSDavid du Colombier b->key = nil;
2609a747e4fSDavid du Colombier b->exit = buttonfree;
261*6f314b92SDavid du Colombier b->off = 0;
262*6f314b92SDavid du Colombier b->prepress = 0;
2639a747e4fSDavid du Colombier return (Control*)b;
2649a747e4fSDavid du Colombier }
265