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