xref: /plan9/sys/src/libcontrol/button.c (revision 6f314b92956e16637888967d7478acfbd2ac8dab)
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