xref: /plan9/sys/src/libcontrol/textbutton.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 Textbutton Textbutton;
10 
11 struct Textbutton
12 {
13 	Control;
14 	CFont	*font;
15 	CImage	*image;
16 	CImage	*mask;
17 	CImage	*light;
18 	CImage	*bordercolor;
19 	CImage	*textcolor;
20 	CImage	*pressedtextcolor;
21 	CImage	*paletextcolor;
22 	int		pressed;
23 	int		lastbut;
24 	int		lastshow;
25 	char		**line;
26 	int		nline;
27 	int		align;
28 	int		border;
29 	int		off;
30 	int		showoff;
31 	int		prepress;
32 };
33 
34 enum{
35 	EAlign,
36 	EBorder,
37 	EBordercolor,
38 	EFocus,
39 	EFont,
40 	EFormat,
41 	EHide,
42 	EImage,
43 	ELight,
44 	EMask,
45 	EPaletextcolor,
46 	EPressedtextcolor,
47 	ERect,
48 	EReveal,
49 	EShow,
50 	ESize,
51 	EText,
52 	ETextcolor,
53 	EValue,
54 };
55 
56 static char *cmds[] = {
57 	[EAlign] =			"align",
58 	[EBorder] =		"border",
59 	[EBordercolor] = 	"bordercolor",
60 	[EFocus] = 		"focus",
61 	[EFont] =			"font",
62 	[EFormat] = 		"format",
63 	[EHide] =			"hide",
64 	[EImage] =		"image",
65 	[ELight] =			"light",
66 	[EMask] =			"mask",
67 	[EPaletextcolor] ="paletextcolor",
68 	[EPressedtextcolor] ="pressedtextcolor",
69 	[ERect] =			"rect",
70 	[EReveal] =		"reveal",
71 	[EShow] =			"show",
72 	[ESize] =			"size",
73 	[EText] =			"text",
74 	[ETextcolor] =		"textcolor",
75 	[EValue] =			"value",
76 	nil
77 };
78 
79 static void	textbuttonshow(Textbutton*);
80 
81 static void
textbuttonmouse(Control * c,Mouse * m)82 textbuttonmouse(Control *c, Mouse *m)
83 {
84 	Textbutton *t;
85 
86 	t = (Textbutton *)c;
87 	if(m->buttons&7) {
88 		if (ptinrect(m->xy,t->rect)) {
89 			if (t->off) {
90 				t->off = 0;
91 				textbuttonshow(t);
92 			}
93 		} else {
94 			if (!t->off) {
95 				t->off = 1;
96 				textbuttonshow(t);
97 			}
98 		}
99 	}
100 	if((m->buttons&7) != t->lastbut){
101 		if(m->buttons & 7){
102 			t->prepress = t->pressed;
103 			if (t->pressed)
104 				t->pressed = 0;
105 			else
106 				t->pressed = 1;
107 			textbuttonshow(t);
108 		}else{	/* generate event on button up */
109 			if (ptinrect(m->xy,t->rect))
110 				chanprint(t->event, t->format, t->name, t->pressed);
111 			else {
112 				t->off = 0;
113 				t->pressed = t->prepress;
114 				textbuttonshow(t);
115 			}
116 		}
117 	}
118 	t->lastbut = m->buttons & 7;
119 }
120 
121 static void
textbuttonfree(Control * c)122 textbuttonfree(Control *c)
123 {
124 	int i;
125 	Textbutton *t;
126 
127 	t = (Textbutton*)c;
128 	_putctlfont(t->font);
129 	_putctlimage(t->image);
130 	_putctlimage(t->light);
131 	_putctlimage(t->mask);
132 	_putctlimage(t->textcolor);
133 	_putctlimage(t->bordercolor);
134 	_putctlimage(t->paletextcolor);
135 	_putctlimage(t->pressedtextcolor);
136 	for(i=0; i<t->nline; i++)
137 		free(t->line[i]);
138 	free(t->line);
139 }
140 
141 static void
textbuttonshow(Textbutton * t)142 textbuttonshow(Textbutton *t)
143 {
144 	Rectangle r, clipr;
145 	int i, dx, dy, w;
146 	Font *f;
147 	Point p, q;
148 	Image *im;
149 
150 	if(t->hidden || (t->lastshow == t->pressed && t->showoff == t->off))
151 		return;
152 	f = t->font->font;
153 	draw(t->screen, t->rect, t->image->image, nil, t->image->image->r.min);
154 	if(t->border > 0)
155 		border(t->screen, t->rect, t->border, t->bordercolor->image, ZP);
156 	/* text goes here */
157 	dx = 0;
158 	for(i=0; i<t->nline; i++){
159 		w = stringwidth(f, t->line[i]);
160 		if(dx < w)
161 			dx = w;
162 	}
163 	dy = t->nline*f->height;
164 	clipr = insetrect(t->rect, t->border);
165 	p = _ctlalignpoint(clipr, dx, dy, t->align);
166 	im = t->textcolor->image;
167 	if(t->off)
168 		im = t->paletextcolor->image;
169 	else if(t->pressed)
170 		im = t->pressedtextcolor->image;
171 	for(i=0; i<t->nline; i++){
172 		r.min = p;
173 		r.max.x = p.x+dx;
174 		r.max.y = p.y+f->height;
175 		q = _ctlalignpoint(r, stringwidth(f, t->line[i]), f->height, t->align%3);
176 		_string(t->screen, q, im,
177 			ZP, f, t->line[i], nil, strlen(t->line[i]),
178 			clipr, nil, ZP, SoverD);
179 		p.y += f->height;
180 	}
181 	if(t->off || t->pressed)
182 		draw(t->screen, t->rect, t->light->image, t->mask->image, t->mask->image->r.min);
183 	t->lastshow = t->pressed;
184 	t->showoff = t->off;
185 	flushimage(display, 1);
186 }
187 
188 static void
textbuttonctl(Control * c,CParse * cp)189 textbuttonctl(Control *c, CParse *cp)
190 {
191 	int cmd, i;
192 	Rectangle r;
193 	Textbutton *t;
194 
195 	t = (Textbutton*)c;
196 	cmd = _ctllookup(cp->args[0], cmds, nelem(cmds));
197 	switch(cmd){
198 	default:
199 		ctlerror("%q: unrecognized message '%s'", t->name, cp->str);
200 		break;
201 	case EAlign:
202 		_ctlargcount(t, cp, 2);
203 		t->align = _ctlalignment(cp->args[1]);
204 		t->lastshow = -1;	/* force redraw */
205 		break;
206 	case EBorder:
207 		_ctlargcount(t, cp, 2);
208 		t->border = cp->iargs[1];
209 		t->lastshow = -1;	/* force redraw */
210 		break;
211 	case EBordercolor:
212 		_ctlargcount(t, cp, 2);
213 		_setctlimage(t, &t->bordercolor, cp->args[1]);
214 		t->lastshow = -1;	/* force redraw */
215 		break;
216 	case EFocus:
217 		break;
218 	case EFont:
219 		_ctlargcount(t, cp, 2);
220 		_setctlfont(t, &t->font, cp->args[1]);
221 		t->lastshow = -1;	/* force redraw */
222 		break;
223 	case EFormat:
224 		_ctlargcount(t, cp, 2);
225 		t->format = ctlstrdup(cp->args[1]);
226 		break;
227 	case EHide:
228 		_ctlargcount(t, cp, 1);
229 		t->hidden = 1;
230 		break;
231 	case EImage:
232 		_ctlargcount(t, cp, 2);
233 		_setctlimage(t, &t->image, cp->args[1]);
234 		t->lastshow = -1;	/* force redraw */
235 		break;
236 	case ELight:
237 		_ctlargcount(t, cp, 2);
238 		_setctlimage(t, &t->light, cp->args[1]);
239 		t->lastshow = -1;	/* force redraw */
240 		break;
241 	case EMask:
242 		_ctlargcount(t, cp, 2);
243 		_setctlimage(t, &t->mask, cp->args[1]);
244 		t->lastshow = -1;	/* force redraw */
245 		break;
246 	case EPaletextcolor:
247 		_ctlargcount(t, cp, 2);
248 		_setctlimage(t, &t->paletextcolor, cp->args[1]);
249 		t->lastshow = -1;	/* force redraw */
250 		break;
251 	case EPressedtextcolor:
252 		_ctlargcount(t, cp, 2);
253 		_setctlimage(t, &t->pressedtextcolor, cp->args[1]);
254 		t->lastshow = -1;	/* force redraw */
255 		break;
256 	case ERect:
257 		_ctlargcount(t, cp, 5);
258 		r.min.x = cp->iargs[1];
259 		r.min.y = cp->iargs[2];
260 		r.max.x = cp->iargs[3];
261 		r.max.y = cp->iargs[4];
262 		if(Dx(r)<=0 || Dy(r)<=0)
263 			ctlerror("%q: bad rectangle: %s", t->name, cp->str);
264 		t->rect = r;
265 		t->lastshow = -1;	/* force redraw */
266 		break;
267 	case EReveal:
268 		_ctlargcount(t, cp, 1);
269 		t->hidden = 0;
270 		t->lastshow = -1;	/* force redraw */
271 		textbuttonshow(t);
272 		break;
273 	case EShow:
274 		_ctlargcount(t, cp, 1);
275 		t->lastshow = -1;	/* force redraw */
276 		textbuttonshow(t);
277 		break;
278 	case ESize:
279 		if (cp->nargs == 3)
280 			r.max = Pt(0x7fffffff, 0x7fffffff);
281 		else{
282 			_ctlargcount(t, cp, 5);
283 			r.max.x = cp->iargs[3];
284 			r.max.y = cp->iargs[4];
285 		}
286 		r.min.x = cp->iargs[1];
287 		r.min.y = cp->iargs[2];
288 		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)
289 			ctlerror("%q: bad sizes: %s", t->name, cp->str);
290 		t->size.min = r.min;
291 		t->size.max = r.max;
292 		break;
293 	case EText:
294 		/* free existing text */
295 		for(i=0; i<t->nline; i++)
296 			free(t->line[i]);
297 		t->nline = cp->nargs-1;
298 		t->line = ctlrealloc(t->line, t->nline*sizeof(char*));
299 		for(i=0; i<t->nline; i++)
300 			t->line[i] = ctlstrdup(cp->args[i+1]);
301 		t->lastshow = -1;	/* force redraw */
302 		textbuttonshow(t);
303 		break;
304 	case ETextcolor:
305 		_ctlargcount(t, cp, 2);
306 		_setctlimage(t, &t->textcolor, cp->args[1]);
307 		t->lastshow = -1;	/* force redraw */
308 		break;
309 	case EValue:
310 		_ctlargcount(t, cp, 2);
311 		if((cp->iargs[1]!=0) != t->pressed){
312 			t->pressed ^= 1;
313 			textbuttonshow(t);
314 		}
315 		break;
316 	}
317 }
318 
319 Control*
createtextbutton(Controlset * cs,char * name)320 createtextbutton(Controlset *cs, char *name)
321 {
322 	Textbutton *t;
323 
324 	t = (Textbutton *)_createctl(cs, "textbutton", sizeof(Textbutton), name);
325 	t->line = ctlmalloc(sizeof(char*));
326 	t->nline = 0;
327 	t->image = _getctlimage("white");
328 	t->light = _getctlimage("yellow");
329 	t->mask = _getctlimage("opaque");
330 	t->bordercolor = _getctlimage("black");
331 	t->textcolor = _getctlimage("black");
332 	t->pressedtextcolor = _getctlimage("black");
333 	t->paletextcolor = _getctlimage("paleyellow");
334 	t->font = _getctlfont("font");
335 	t->format = ctlstrdup("%q: value %d");
336 	t->lastshow = -1;
337 	t->mouse = textbuttonmouse;
338 	t->ctl = textbuttonctl;
339 	t->exit = textbuttonfree;
340 	t->prepress = 0;
341 	t->off = 0;
342 	t->showoff = -1;
343 	return (Control *)t;
344 }
345