1 #include "lib9.h" 2 #include "draw.h" 3 #include "tk.h" 4 #include "textw.h" 5 6 #define istring u.string 7 #define iwin u.win 8 #define imark u.mark 9 #define iline u.line 10 11 #define O(t, e) ((long)(&((t*)0)->e)) 12 13 static char* tktwincget(Tk*, char*, char**); 14 static char* tktwinconfigure(Tk*, char*, char**); 15 static char* tktwincreate(Tk*, char*, char**); 16 static char* tktwinnames(Tk*, char*, char**); 17 static int winowned(Tk *tk, Tk *sub); 18 19 static 20 TkStab tkalign[] = 21 { 22 "top", Tktop, 23 "bottom", Tkbottom, 24 "center", Tkcenter, 25 "baseline", Tkbaseline, 26 nil 27 }; 28 29 static 30 TkOption twinopts[] = 31 { 32 "align", OPTstab, O(TkTwind, align), tkalign, 33 "create", OPTtext, O(TkTwind, create), nil, 34 "padx", OPTnndist, O(TkTwind, padx), nil, 35 "pady", OPTnndist, O(TkTwind, pady), nil, 36 "stretch", OPTstab, O(TkTwind, stretch), tkbool, 37 "window", OPTwinp, O(TkTwind, sub), nil, 38 "ascent", OPTdist, O(TkTwind, ascent), nil, 39 nil 40 }; 41 42 TkCmdtab 43 tktwincmd[] = 44 { 45 "cget", tktwincget, 46 "configure", tktwinconfigure, 47 "create", tktwincreate, 48 "names", tktwinnames, 49 nil 50 }; 51 52 int 53 tktfindsubitem(Tk *sub, TkTindex *ix) 54 { 55 Tk *tk, *isub; 56 TkText *tkt; 57 58 tk = sub->parent; 59 if(tk != nil) { 60 tkt = TKobj(TkText, tk); 61 tktstartind(tkt, ix); 62 do { 63 if(ix->item->kind == TkTwin) { 64 isub = ix->item->iwin->sub; 65 if(isub != nil && 66 isub->name != nil && 67 strcmp(isub->name->name, sub->name->name) == 0) 68 return 1; 69 } 70 } while(tktadjustind(tkt, TkTbyitem, ix)); 71 } 72 return 0; 73 } 74 75 static void 76 tktwindsize(Tk *tk, TkTindex *ix) 77 { 78 Tk *s; 79 TkTitem *i; 80 TkTwind *w; 81 82 83 i = ix->item; 84 /* assert(i->kind == TkTwin); */ 85 86 w = i->iwin; 87 s = w->sub; 88 if(s == nil) 89 return; 90 91 if(w->width != s->act.width || w->height != s->act.height) { 92 s->act.width = w->width; 93 s->act.height = w->height; 94 if(s->slave) { 95 tkpackqit(s); 96 tkrunpack(tk->env->top); 97 } 98 } 99 100 tktfixgeom(tk, tktprevwrapline(tk, ix->line), ix->line, 0); 101 tktextsize(tk, 1); 102 } 103 104 /* 105 * check that w->focus is a window packed under tk. 106 * XXX couldn't this be done more simply by traversing 107 * directly upwards from w->focus and seeing whether 108 * it hits tk? (same applies to tkcvschkwfocus in cwind.c) 109 */ 110 static int 111 tktchkwfocus(TkTwind *w, Tk *tk) 112 { 113 if(w->focus == tk) 114 return 1; 115 for(tk = tk->slave; tk; tk = tk->next) 116 if(tktchkwfocus(w, tk)) 117 return 1; 118 return 0; 119 } 120 121 static void 122 tktwingeom(Tk *sub, int x, int y, int w, int h) 123 { 124 TkTindex ix; 125 Tk *tk; 126 TkTwind *win; 127 128 USED(x); 129 USED(y); 130 131 tk = sub->parent; 132 if(!tktfindsubitem(sub, &ix)) { 133 print("tktwingeom: %s not found\n", sub->name->name); 134 return; 135 } 136 137 win = ix.item->iwin; 138 139 if(win->focus != nil) { 140 if(tktchkwfocus(win, sub) == 0) 141 win->focus = nil; 142 } 143 144 win->width = w; 145 win->height = h; 146 147 sub->req.width = w; 148 sub->req.height = h; 149 tktwindsize(tk, &ix); 150 } 151 152 static void 153 tktdestroyed(Tk *sub) 154 { 155 TkTindex ix; 156 Tk *tk; 157 158 if(tktfindsubitem(sub, &ix)) { 159 ix.item->iwin->sub = nil; 160 ix.item->iwin->focus = nil; 161 if((tk = sub->parent) != nil) { 162 tktfixgeom(tk, tktprevwrapline(tk, ix.line), ix.line, 0); 163 tktextsize(tk, 1); 164 sub->parent = nil; 165 } 166 } 167 } 168 169 void 170 tktdirty(Tk *sub) 171 { 172 Tk *tk, *parent, *isub; 173 TkText *tkt; 174 TkTindex ix; 175 176 parent = nil; 177 for(tk = sub; tk && parent == nil; tk = tk->master) 178 parent = tk->parent; 179 if(tk == nil) 180 return; 181 182 tkt = TKobj(TkText, parent); 183 tktstartind(tkt, &ix); 184 do { 185 if(ix.item->kind == TkTwin) { 186 isub = ix.item->iwin->sub; 187 if(isub != nil) { 188 tktfixgeom(parent, tktprevwrapline(parent, ix.line), ix.line, 0); 189 if (sub->flag & Tktransparent) 190 parent->flag |= Tkrefresh; /* XXX could be more efficient, by drawing the background locally? */ 191 return; 192 } 193 } 194 } while(tktadjustind(tkt, TkTbyitem, &ix)); 195 tktextsize(parent, 1); 196 } 197 198 static char* 199 tktwinchk(Tk *tk, TkTwind *w, Tk *oldsub) 200 { 201 Tk *sub; 202 203 sub = w->sub; 204 if (sub != oldsub) { 205 w->sub = oldsub; 206 if(sub == nil) 207 return nil; 208 209 if(sub->flag & Tkwindow) 210 return TkIstop; 211 212 if(sub->master != nil || sub->parent != nil) 213 return TkWpack; 214 215 if (oldsub != nil) { 216 oldsub->parent = nil; 217 oldsub->geom = nil; 218 oldsub->destroyed = nil; 219 } 220 w->sub = sub; 221 w->focus = nil; 222 223 sub->parent = tk; 224 tksetbits(sub, Tksubsub); 225 sub->geom = tktwingeom; 226 sub->destroyed = tktdestroyed; 227 228 w->width = sub->req.width; 229 w->height = sub->req.height; 230 w->owned = winowned(tk, sub); 231 } 232 233 return nil; 234 } 235 236 237 /* Text Window Command (+ means implemented) 238 +cget 239 +configure 240 +create 241 +names 242 */ 243 244 static char* 245 tktwincget(Tk *tk, char *arg, char **val) 246 { 247 char *e; 248 TkTindex ix; 249 TkOptab tko[2]; 250 251 e = tktindparse(tk, &arg, &ix); 252 if(e != nil) 253 return e; 254 if(ix.item->kind != TkTwin) 255 return TkBadwp; 256 257 tko[0].ptr = ix.item->iwin; 258 tko[0].optab = twinopts; 259 tko[1].ptr = nil; 260 261 return tkgencget(tko, arg, val, tk->env->top); 262 } 263 264 static char* 265 tktwinconfigure(Tk *tk, char *arg, char **val) 266 { 267 char *e; 268 TkTindex ix; 269 TkOptab tko[2]; 270 Tk *oldsub; 271 272 USED(val); 273 274 e = tktindparse(tk, &arg, &ix); 275 if(e != nil) 276 return e; 277 if(ix.item->kind != TkTwin) 278 return TkBadwp; 279 280 oldsub = ix.item->iwin->sub; 281 282 tko[0].ptr = ix.item->iwin; 283 tko[0].optab = twinopts; 284 tko[1].ptr = nil; 285 286 e = tkparse(tk->env->top, arg, tko, nil); 287 if(e != nil) 288 return e; 289 290 e = tktwinchk(tk, ix.item->iwin, oldsub); 291 if(e != nil) 292 return e; 293 294 tktwindsize(tk, &ix); 295 return nil; 296 } 297 298 /* 299 * return true if tk is an ancestor of sub 300 */ 301 static int 302 winowned(Tk *tk, Tk *sub) 303 { 304 int len; 305 if (tk->name == nil || sub->name == nil) 306 return 0; 307 len = strlen(tk->name->name); 308 if (strncmp(tk->name->name, sub->name->name, len) == 0 && 309 sub->name->name[len] == '.') 310 return 1; 311 return 0; 312 } 313 314 static char* 315 tktwincreate(Tk *tk, char *arg, char **val) 316 { 317 char *e; 318 TkTindex ix; 319 TkTitem *i; 320 TkText *tkt; 321 TkOptab tko[2]; 322 323 USED(val); 324 325 tkt = TKobj(TkText, tk); 326 327 e = tktindparse(tk, &arg, &ix); 328 if(e != nil) 329 return e; 330 331 e = tktnewitem(TkTwin, 0, &i); 332 if(e != nil) 333 return e; 334 335 i->iwin = malloc(sizeof(TkTwind)); 336 if(i->iwin == nil) { 337 tktfreeitems(tkt, i, 1); 338 return TkNomem; 339 } 340 341 memset(i->iwin, 0, sizeof(TkTwind)); 342 i->iwin->align = Tkcenter; 343 i->iwin->ascent = -1; 344 345 tko[0].ptr = i->iwin; 346 tko[0].optab = twinopts; 347 tko[1].ptr = nil; 348 349 e = tkparse(tk->env->top, arg, tko, nil); 350 if(e != nil) { 351 err1: 352 tktfreeitems(tkt, i, 1); 353 return e; 354 } 355 356 e = tktwinchk(tk, i->iwin, nil); 357 if(e != nil) 358 goto err1; 359 360 e = tktsplititem(&ix); 361 if(e != nil) 362 goto err1; 363 364 tktiteminsert(tkt, &ix, i); 365 if(e != nil) 366 goto err1; 367 368 tktadjustind(tkt, TkTbyitemback, &ix); 369 tktwindsize(tk, &ix); 370 371 return nil; 372 } 373 374 static char* 375 tktwinnames(Tk *tk, char *arg, char **val) 376 { 377 char *e, *fmt; 378 TkTindex ix; 379 TkText *tkt = TKobj(TkText, tk); 380 381 USED(arg); 382 383 tktstartind(tkt, &ix); 384 fmt = "%s"; 385 do { 386 if(ix.item->kind == TkTwin && 387 ix.item->iwin->sub != nil && 388 ix.item->iwin->sub->name != nil) { 389 e = tkvalue(val, fmt, ix.item->iwin->sub->name->name); 390 if(e != nil) 391 return e; 392 fmt = " %s"; 393 } 394 } while(tktadjustind(tkt, TkTbyitem, &ix)); 395 return nil; 396 } 397