xref: /plan9/sys/src/libcontrol/button.c (revision 6f314b92956e16637888967d7478acfbd2ac8dab)
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 Button Button;
10 
11 struct Button
12 {
13 	Control;
14 	CImage	*image;
15 	CImage	*mask;
16 	CImage	*light;
17 	CImage	*pale;
18 	CImage	*bordercolor;
19 	int		pressed;
20 	int		lastbut;
21 	int		lastshow;
22 	int		border;
23 	int		align;
24 	int		off;
25 	int		prepress;
26 };
27 
28 enum{
29 	EAlign,
30 	EBorder,
31 	EBordercolor,
32 	EFocus,
33 	EFormat,
34 	EHide,
35 	EImage,
36 	ELight,
37 	EMask,
38 	EPale,
39 	ERect,
40 	EReveal,
41 	EShow,
42 	ESize,
43 	EValue,
44 };
45 
46 static char *cmds[] = {
47 	[EAlign] = 		"align",
48 	[EBorder] = 	"border",
49 	[EBordercolor] = "bordercolor",
50 	[EFocus] = 	"focus",
51 	[EFormat] = 	"format",
52 	[EHide] =		"hide",
53 	[EImage] =	"image",
54 	[ELight] =		"light",
55 	[EMask] =		"mask",
56 	[EPale] =		"pale",
57 	[ERect] =		"rect",
58 	[EReveal] =	"reveal",
59 	[EShow] =		"show",
60 	[ESize] =		"size",
61 	[EValue] =		"value",
62 	nil
63 };
64 
65 static void
buttonfree(Control * c)66 buttonfree(Control *c)
67 {
68 	Button *b;
69 
70 	b = (Button *)c;
71 	_putctlimage(b->image);
72 	_putctlimage(b->mask);
73 	_putctlimage(b->light);
74 	_putctlimage(b->pale);
75 	_putctlimage(b->bordercolor);
76 }
77 
78 static void
buttonshow(Button * b)79 buttonshow(Button *b)
80 {
81 	Rectangle r;
82 
83 	if (b->hidden)
84 		return;
85 	r = b->rect;
86 	if(b->border > 0){
87 		border(b->screen, r, b->border, b->bordercolor->image, ZP);
88 		r = insetrect(b->rect, b->border);
89 	}
90 	draw(b->screen, r, b->image->image, nil, b->image->image->r.min);
91 	if(b->off)
92 		draw(b->screen, r, b->pale->image, b->mask->image, b->mask->image->r.min);
93 	else if(b->pressed)
94 		draw(b->screen, r, b->light->image, b->mask->image, b->mask->image->r.min);
95 	b->lastshow = b->pressed;
96 	flushimage(display, 1);
97 }
98 
99 static void
buttonmouse(Control * c,Mouse * m)100 buttonmouse(Control *c, Mouse *m)
101 {
102 	Button *b;
103 
104 	b = (Button*)c;
105 
106 	if(m->buttons&7) {
107 		if (ptinrect(m->xy,b->rect)) {
108 			if (b->off) {
109 				b->off = 0;
110 				buttonshow(b);
111 			}
112 		} else {
113 			if (!b->off) {
114 				b->off = 1;
115 				buttonshow(b);
116 			}
117 		}
118 	}
119 	if((m->buttons&7) != b->lastbut){
120 		if(m->buttons & 7){
121 			b->prepress = b->pressed;
122 			if (b->pressed)
123 				b->pressed = 0;
124 			else
125 				b->pressed = m->buttons & 7;
126 			buttonshow(b);
127 		}else	/* generate event on button up */
128 			if (ptinrect(m->xy,b->rect))
129 				chanprint(b->event, b->format, b->name, b->pressed);
130 			else {
131 				b->off = 0;
132 				b->pressed = b->prepress;
133 				buttonshow(b);
134 			}
135 	}
136 	b->lastbut = m->buttons & 7;
137 }
138 
139 static void
buttonctl(Control * c,CParse * cp)140 buttonctl(Control *c, CParse *cp)
141 {
142 	int cmd;
143 	Rectangle r;
144 	Button *b;
145 
146 	b = (Button*)c;
147 	cmd = _ctllookup(cp->args[0], cmds, nelem(cmds));
148 	switch(cmd){
149 	default:
150 		ctlerror("%q: unrecognized message '%s'", b->name, cp->str);
151 		break;
152 	case EAlign:
153 		_ctlargcount(b, cp, 2);
154 		b->align = _ctlalignment(cp->args[1]);
155 		b->lastshow = -1;	/* force redraw */
156 		break;
157 	case EBorder:
158 		_ctlargcount(b, cp, 2);
159 		b->border = cp->iargs[1];
160 		b->lastshow = -1;	/* force redraw */
161 		break;
162 	case EBordercolor:
163 		_ctlargcount(b, cp, 2);
164 		_setctlimage(b, &b->bordercolor, cp->args[1]);
165 		b->lastshow = -1;	/* force redraw */
166 		break;
167 	case EFocus:
168 		/* ignore focus change */
169 		break;
170 	case EFormat:
171 		_ctlargcount(b, cp, 2);
172 		b->format = ctlstrdup(cp->args[1]);
173 		break;
174 	case EHide:
175 		_ctlargcount(b, cp, 1);
176 		b->hidden = 1;
177 		break;
178 	case EImage:
179 		_ctlargcount(b, cp, 2);
180 		_setctlimage(b, &b->image, cp->args[1]);
181 		b->lastshow = -1;	/* force redraw */
182 		break;
183 	case ELight:
184 		_ctlargcount(b, cp, 2);
185 		_setctlimage(b, &b->light, cp->args[1]);
186 		b->lastshow = -1;	/* force redraw */
187 		break;
188 	case EMask:
189 		_ctlargcount(b, cp, 2);
190 		_setctlimage(b, &b->mask, cp->args[1]);
191 		b->lastshow = -1;	/* force redraw */
192 		break;
193 	case EPale:
194 		_ctlargcount(b, cp, 2);
195 		_setctlimage(b, &b->pale, cp->args[1]);
196 		b->lastshow = -1;	/* force redraw */
197 		break;
198 	case ERect:
199 		_ctlargcount(b, cp, 5);
200 		r.min.x = cp->iargs[1];
201 		r.min.y = cp->iargs[2];
202 		r.max.x = cp->iargs[3];
203 		r.max.y = cp->iargs[4];
204 		if(Dx(r)<0 || Dy(r)<0)
205 			ctlerror("%q: bad rectangle: %s", b->name, cp->str);
206 		b->rect = r;
207 		b->lastshow = -1;	/* force redraw */
208 		break;
209 	case EReveal:
210 		_ctlargcount(b, cp, 1);
211 		b->hidden = 0;
212 		buttonshow(b);
213 		break;
214 	case EShow:
215 		_ctlargcount(b, cp, 1);
216 		buttonshow(b);
217 		break;
218 	case ESize:
219 		if (cp->nargs == 3)
220 			r.max = Pt(0x7fffffff, 0x7fffffff);
221 		else{
222 			_ctlargcount(b, cp, 5);
223 			r.max.x = cp->iargs[3];
224 			r.max.y = cp->iargs[4];
225 		}
226 		r.min.x = cp->iargs[1];
227 		r.min.y = cp->iargs[2];
228 		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)
229 			ctlerror("%q: bad sizes: %s", b->name, cp->str);
230 		b->size.min = r.min;
231 		b->size.max = r.max;
232 		break;
233 	case EValue:
234 		_ctlargcount(b, cp, 2);
235 		if((cp->iargs[1]!=0) != b->pressed){
236 			b->pressed ^= 1;
237 			buttonshow(b);
238 		}
239 		break;
240 	}
241 }
242 
243 Control*
createbutton(Controlset * cs,char * name)244 createbutton(Controlset *cs, char *name)
245 {
246 	Button *b;
247 	b = (Button*)_createctl(cs, "button", sizeof(Button), name);
248 	b->image = _getctlimage("white");
249 	b->mask = _getctlimage("opaque");
250 	b->light = _getctlimage("yellow");
251 	b->pale = _getctlimage("paleyellow");
252 	b->bordercolor = _getctlimage("black");
253 	b->format = ctlstrdup("%q: value %d");
254 	b->lastshow = -1;
255 	b->border = 0;
256 	b->align = Aupperleft;
257 	b->ctl = buttonctl;
258 	b->mouse = buttonmouse;
259 	b->key = nil;
260 	b->exit = buttonfree;
261 	b->off = 0;
262 	b->prepress = 0;
263 	return (Control*)b;
264 }
265