xref: /inferno-os/libtk/label.c (revision 06155dbb53eb0585800b239acd6e45b946c6e0cf)
1 #include <lib9.h>
2 #include <kernel.h>
3 #include "draw.h"
4 #include "tk.h"
5 #include "label.h"
6 
7 #define	O(t, e)		((long)(&((t*)0)->e))
8 
9 TkOption tklabelopts[] =
10 {
11 	"text",		OPTtext,	O(TkLabel, text),	nil,
12 	"label",	OPTtext,	O(TkLabel, text),	nil,
13 	"underline",	OPTdist,	O(TkLabel, ul),		nil,
14 	"justify",	OPTflag,	O(TkLabel, justify),	tkjustify,
15 	"anchor",	OPTflag,	O(TkLabel, anchor),	tkanchor,
16 	"bitmap",	OPTbmap,	O(TkLabel, bitmap),	nil,
17 	"image",	OPTimag,	O(TkLabel, img),	nil,
18 	nil
19 };
20 
21 char*
22 tklabel(TkTop *t, char *arg, char **ret)
23 {
24 	Tk *tk;
25 	char *e;
26 	TkLabel *tkl;
27 	TkName *names;
28 	TkOptab tko[3];
29 
30 	tk = tknewobj(t, TKlabel, sizeof(Tk)+sizeof(TkLabel));
31 	if(tk == nil)
32 		return TkNomem;
33 
34 	tkl = TKobj(TkLabel, tk);
35 	tkl->ul = -1;
36 	tkl->justify = Tkleft;
37 
38 	tko[0].ptr = tk;
39 	tko[0].optab = tkgeneric;
40 	tko[1].ptr = tkl;
41 	tko[1].optab = tklabelopts;
42 	tko[2].ptr = nil;
43 
44 	names = nil;
45 	e = tkparse(t, arg, tko, &names);
46 	if(e != nil) {
47 		tkfreeobj(tk);
48 		return e;
49 	}
50 
51 	tksizelabel(tk);
52 	tksettransparent(tk, tkhasalpha(tk->env, TkCbackgnd));
53 
54 	e = tkaddchild(t, tk, &names);
55 	tkfreename(names);
56 	if(e != nil) {
57 		tkfreeobj(tk);
58 		return e;
59 	}
60 	tk->name->link = nil;
61 
62 	return tkvalue(ret, "%s", tk->name->name);
63 }
64 
65 static char*
66 tklabelcget(Tk *tk, char *arg, char **val)
67 {
68 	TkOptab tko[3];
69 	TkLabel *tkl = TKobj(TkLabel, tk);
70 
71 	tko[0].ptr = tk;
72 	tko[0].optab = tkgeneric;
73 	tko[1].ptr = tkl;
74 	tko[1].optab = tklabelopts;
75 	tko[2].ptr = nil;
76 
77 	return tkgencget(tko, arg, val, tk->env->top);
78 }
79 
80 static char*
81 tklabelconf(Tk *tk, char *arg, char **val)
82 {
83 	char *e;
84 	TkGeom g;
85 	int bd;
86 	TkOptab tko[3];
87 	TkLabel *tkl = TKobj(TkLabel, tk);
88 
89 	tko[0].ptr = tk;
90 	tko[0].optab = tkgeneric;
91 	tko[1].ptr = tkl;
92 	tko[1].optab = tklabelopts;
93 	tko[2].ptr = nil;
94 
95 	if(*arg == '\0')
96 		return tkconflist(tko, val);
97 
98 	g = tk->req;
99 	bd = tk->borderwidth;
100 	e = tkparse(tk->env->top, arg, tko, nil);
101 	tksizelabel(tk);
102 	tksettransparent(tk, tkhasalpha(tk->env, TkCbackgnd));
103 	tkgeomchg(tk, &g, bd);
104 
105 	tk->dirty = tkrect(tk, 1);
106 	return e;
107 }
108 
109 void
110 tksizelabel(Tk *tk)
111 {
112 	Point p;
113 	int w, h;
114 	TkLabel *tkl;
115 
116 	tkl = TKobj(TkLabel, tk);
117 	if(tkl->anchor == 0)
118 		tkl->anchor = Tkcenter;
119 
120 	w = 0;
121 	h = 0;
122 	tkl->textheight = 0;
123 	if(tkl->img != nil) {
124 		w = tkl->img->w + 2*Bitpadx;
125 		h = tkl->img->h + 2*Bitpady;
126 	} else if(tkl->bitmap != nil) {
127 		w = Dx(tkl->bitmap->r) + 2*Bitpadx;
128 		h = Dy(tkl->bitmap->r) + 2*Bitpady;
129 	} else if(tkl->text != nil) {
130 		p = tkstringsize(tk, tkl->text);
131 		w = p.x + 2*Textpadx;
132 		h = p.y + 2*Textpady;
133 		if(tkl->ul != -1 && tkl->ul > strlen(tkl->text))
134 			tkl->ul = strlen(tkl->text);	/* underline all */
135 		tkl->textheight = p.y;
136 	}
137 
138 	if(tk->type == TKcascade) {
139 		w += CheckButton + 2*CheckButtonBW;
140 		if(h < CheckButton)
141 			h = CheckButton;
142 	}
143 	w += 2*tk->highlightwidth;
144 	h += 2*tk->highlightwidth;
145 	tkl->w = w;
146 	tkl->h = h;
147 	if((tk->flag & Tksetwidth) == 0)
148 		tk->req.width = w;
149 	if((tk->flag & Tksetheight) == 0)
150 		tk->req.height = h;
151 }
152 
153 int
154 tklabelmargin(Tk *tk)
155 {
156 	TkLabel *tkl;
157 	Image *img;
158 
159 	switch(tk->type){
160 	case TKseparator:
161 		return 0;
162 
163 	case TKlabel:
164 	case TKcascade:
165 		tkl = TKobj(TkLabel, tk);
166 		img = nil;
167 		if (tkl->img != nil)
168 			img = tkl->img->img;
169 		else if (tkl->bitmap != nil)
170 			img = tkl->bitmap;
171 		if (img != nil)
172 			return Bitpadx;
173 		return Textpadx;
174 
175 	default:
176 		fprint(2, "label margin: type %d\n", tk->type);
177 		return 0;
178 	}
179 }
180 
181 void
182 tkfreelabel(Tk *tk)
183 {
184 	Image *i;
185 	int locked;
186 	Display *d;
187 	TkLabel *tkl;
188 
189 	tkl = TKobj(TkLabel, tk);
190 
191 	if(tkl->text != nil)
192 		free(tkl->text);
193 	if(tkl->command != nil)
194 		free(tkl->command);
195 	if(tkl->value != nil)
196 		free(tkl->value);
197 	if(tkl->variable != nil) {
198 		tkfreevar(tk->env->top, tkl->variable, tk->flag & Tkswept);
199 		free(tkl->variable);
200 	}
201 	if(tkl->img != nil)
202 		tkimgput(tkl->img);
203 	i = tkl->bitmap;
204 	if(i != nil) {
205 		d = i->display;
206 		locked = lockdisplay(d);
207 		freeimage(i);
208 		if(locked)
209 			unlockdisplay(d);
210 	}
211 	if(tkl->menu != nil)
212 		free(tkl->menu);
213 }
214 
215 static void
216 tktriangle(Point u, Image *i, TkEnv *e)
217 {
218 	Point p[3];
219 
220 	u.y++;
221 	p[0].x = u.x + CheckButton;
222 	p[0].y = u.y + CheckButton/2;
223 	p[1].x = u.x;
224 	p[1].y = u.y + CheckButton;
225 	p[2].x = u.x;
226 	p[2].y = u.y;
227 	fillpoly(i, p, 3, ~0, tkgc(e, TkCforegnd), p[0]);
228 }
229 
230 /*
231  * draw TKlabel, TKseparator, and TKcascade (cascade should really be a button)
232  */
233 char*
234 tkdrawlabel(Tk *tk, Point orig)
235 {
236  	TkEnv *e;
237 	TkLabel *tkl;
238 	Rectangle r, s, mainr, focusr;
239 	int dx, dy, h;
240 	Point p, u, v;
241 	Image *i, *dst, *ct, *img;
242 	int relief, bgnd, fgnd;
243 
244 	e = tk->env;
245 
246 	dst = tkimageof(tk);
247 	if(dst == nil)
248 		return nil;
249 
250 	v.x = tk->act.width + 2*tk->borderwidth;
251 	v.y = tk->act.height + 2*tk->borderwidth;
252 
253 	r.min = ZP;
254 	r.max = v;
255 	focusr = insetrect(r, tk->borderwidth);
256 	mainr = insetrect(focusr, tk->highlightwidth);
257 	relief = tk->relief;
258 
259 	tkl = TKobj(TkLabel, tk);
260 
261 	fgnd = TkCforegnd;
262 	bgnd = TkCbackgnd;
263 	if (tk->flag & Tkdisabled)
264 		fgnd = TkCdisablefgnd;
265 	else if (tk->flag & Tkactive) {
266 		fgnd = TkCactivefgnd;
267 		bgnd = TkCactivebgnd;
268 	}
269 
270 	i = tkitmp(e, r.max, bgnd);
271 	if(i == nil)
272 		return nil;
273 
274 	if(tk->flag & Tkactive)
275 		draw(i, r, tkgc(e, bgnd), nil, ZP);
276 
277 	p = mainr.min;
278 	h = tkl->h - 2 * tk->highlightwidth;
279 
280 	dx = tk->act.width - tkl->w - tk->ipad.x;
281 	dy = tk->act.height - tkl->h - tk->ipad.y;
282 	if((tkl->anchor & (Tknorth|Tksouth)) == 0)
283 		p.y += dy/2;
284 	else if(tkl->anchor & Tksouth)
285 		p.y += dy;
286 
287 	if((tkl->anchor & (Tkeast|Tkwest)) == 0)
288 		p.x += dx/2;
289 	else if(tkl->anchor & Tkeast)
290 		p.x += dx;
291 
292 	if(tk->type == TKcascade) {
293 		u.x = mainr.max.x - CheckButton - CheckButtonBW;	/* TO DO: CheckButton etc is really the triangle/arrow */
294 		u.y = p.y + ButtonBorder + (h-CheckSpace)/2;
295 		tktriangle(u, i, e);
296 	}
297 
298 	p.x += tk->ipad.x/2;
299 	p.y += tk->ipad.y/2;
300 	u = ZP;
301 
302 	img = nil;
303 	if(tkl->img != nil && tkl->img->img != nil)
304 		img = tkl->img->img;
305 	else if (tkl->bitmap != nil)
306 		img = tkl->bitmap;
307 	if(img != nil) {
308 		s.min.x = p.x + Bitpadx;
309 		s.min.y = p.y + Bitpady;
310 		s.max.x = s.min.x + Dx(img->r);
311 		s.max.y = s.min.y + Dy(img->r);
312 		s = rectaddpt(s, u);
313 		if(tkchanhastype(img->chan, CGrey))
314 			draw(i, s, tkgc(e, fgnd), img, ZP);
315 		else
316 			draw(i, s, img, nil, ZP);
317 	} else if(tkl->text != nil) {
318 		u.x += Textpadx;
319 		u.y += Textpady;
320 		ct = tkgc(e, fgnd);
321 
322 		p.y += (h - tkl->textheight) / 2;
323 		tkdrawstring(tk, i, addpt(u, p), tkl->text, tkl->ul, ct, tkl->justify);
324 	}
325 
326 	if(tkhaskeyfocus(tk))
327 		tkbox(i, focusr, tk->highlightwidth, tkgc(e, TkChighlightfgnd));
328 	tkdrawrelief(i, tk, ZP, bgnd, relief);
329 
330 	p.x = tk->act.x + orig.x;
331 	p.y = tk->act.y + orig.y;
332 	r = rectaddpt(r, p);
333 	draw(dst, r, i, nil, ZP);
334 
335 	return nil;
336 }
337 
338 void
339 tklabelgetimgs(Tk *tk, Image **image, Image **mask)
340 {
341 	TkLabel *tkl;
342 
343 	tkl = TKobj(TkLabel, tk);
344 	*mask = nil;
345 	if (tkl->img != nil)
346 		*image = tkl->img->img;
347 	else
348 		*image = tkl->bitmap;
349 }
350 
351 static
352 TkCmdtab tklabelcmd[] =
353 {
354 	"cget",			tklabelcget,
355 	"configure",		tklabelconf,
356 	nil
357 };
358 
359 TkMethod labelmethod = {
360 	"label",
361 	tklabelcmd,
362 	tkfreelabel,
363 	tkdrawlabel,
364 	nil,
365 	tklabelgetimgs
366 };
367