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