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