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*
tklabel(TkTop * t,char * arg,char ** ret)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*
tklabelcget(Tk * tk,char * arg,char ** val)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*
tklabelconf(Tk * tk,char * arg,char ** val)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
tksizelabel(Tk * tk)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
tklabelmargin(Tk * tk)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
tkfreelabel(Tk * tk)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
tktriangle(Point u,Image * i,TkEnv * e)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*
tkdrawlabel(Tk * tk,Point orig)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
tklabelgetimgs(Tk * tk,Image ** image,Image ** mask)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