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 void 105 tktxtforgetsub(Tk *sub, Tk *tk) 106 { 107 TkTwind *w; 108 TkTindex ix; 109 110 if(!tktfindsubitem(sub, &ix)) 111 return; 112 w = ix.item->iwin; 113 if(w->focus == tk) { 114 if(0)print("tktxtforget sub %p %q focus %p %q\n", sub, tkname(sub), tk, tkname(tk)); 115 w->focus = nil; 116 } 117 } 118 119 static void 120 tktwingeom(Tk *sub, int x, int y, int w, int h) 121 { 122 TkTindex ix; 123 Tk *tk; 124 TkTwind *win; 125 126 USED(x); 127 USED(y); 128 129 tk = sub->parent; 130 if(!tktfindsubitem(sub, &ix)) { 131 print("tktwingeom: %s not found\n", sub->name->name); 132 return; 133 } 134 135 win = ix.item->iwin; 136 137 win->width = w; 138 win->height = h; 139 140 sub->req.width = w; 141 sub->req.height = h; 142 tktwindsize(tk, &ix); 143 } 144 145 static void 146 tktdestroyed(Tk *sub) 147 { 148 TkTindex ix; 149 Tk *tk; 150 151 if(tktfindsubitem(sub, &ix)) { 152 ix.item->iwin->sub = nil; 153 ix.item->iwin->focus = nil; 154 if((tk = sub->parent) != nil) { 155 tktfixgeom(tk, tktprevwrapline(tk, ix.line), ix.line, 0); 156 tktextsize(tk, 1); 157 sub->parent = nil; 158 } 159 } 160 } 161 162 void 163 tktdirty(Tk *sub) 164 { 165 Tk *tk, *parent, *isub; 166 TkText *tkt; 167 TkTindex ix; 168 169 parent = nil; 170 for(tk = sub; tk && parent == nil; tk = tk->master) 171 parent = tk->parent; 172 if(tk == nil) 173 return; 174 175 tkt = TKobj(TkText, parent); 176 tktstartind(tkt, &ix); 177 do { 178 if(ix.item->kind == TkTwin) { 179 isub = ix.item->iwin->sub; 180 if(isub != nil) { 181 tktfixgeom(parent, tktprevwrapline(parent, ix.line), ix.line, 0); 182 if (sub->flag & Tktransparent) 183 parent->flag |= Tkrefresh; /* XXX could be more efficient, by drawing the background locally? */ 184 return; 185 } 186 } 187 } while(tktadjustind(tkt, TkTbyitem, &ix)); 188 tktextsize(parent, 1); 189 } 190 191 static char* 192 tktwinchk(Tk *tk, TkTwind *w, Tk *oldsub) 193 { 194 Tk *sub; 195 196 sub = w->sub; 197 if (sub != oldsub) { 198 w->sub = oldsub; 199 if(sub == nil) 200 return nil; 201 202 if(sub->flag & Tkwindow) 203 return TkIstop; 204 205 if(sub->master != nil || sub->parent != nil) 206 return TkWpack; 207 208 if (oldsub != nil) { 209 oldsub->parent = nil; 210 oldsub->geom = nil; 211 oldsub->destroyed = nil; 212 } 213 w->sub = sub; 214 w->focus = nil; 215 216 sub->parent = tk; 217 tksetbits(sub, Tksubsub); 218 sub->geom = tktwingeom; 219 sub->destroyed = tktdestroyed; 220 221 w->width = sub->req.width; 222 w->height = sub->req.height; 223 w->owned = winowned(tk, sub); 224 } 225 226 return nil; 227 } 228 229 230 /* Text Window Command (+ means implemented) 231 +cget 232 +configure 233 +create 234 +names 235 */ 236 237 static char* 238 tktwincget(Tk *tk, char *arg, char **val) 239 { 240 char *e; 241 TkTindex ix; 242 TkOptab tko[2]; 243 244 e = tktindparse(tk, &arg, &ix); 245 if(e != nil) 246 return e; 247 if(ix.item->kind != TkTwin) 248 return TkBadwp; 249 250 tko[0].ptr = ix.item->iwin; 251 tko[0].optab = twinopts; 252 tko[1].ptr = nil; 253 254 return tkgencget(tko, arg, val, tk->env->top); 255 } 256 257 static char* 258 tktwinconfigure(Tk *tk, char *arg, char **val) 259 { 260 char *e; 261 TkTindex ix; 262 TkOptab tko[2]; 263 Tk *oldsub; 264 265 USED(val); 266 267 e = tktindparse(tk, &arg, &ix); 268 if(e != nil) 269 return e; 270 if(ix.item->kind != TkTwin) 271 return TkBadwp; 272 273 oldsub = ix.item->iwin->sub; 274 275 tko[0].ptr = ix.item->iwin; 276 tko[0].optab = twinopts; 277 tko[1].ptr = nil; 278 279 e = tkparse(tk->env->top, arg, tko, nil); 280 if(e != nil) 281 return e; 282 283 e = tktwinchk(tk, ix.item->iwin, oldsub); 284 if(e != nil) 285 return e; 286 287 tktwindsize(tk, &ix); 288 return nil; 289 } 290 291 /* 292 * return true if tk is an ancestor of sub 293 */ 294 static int 295 winowned(Tk *tk, Tk *sub) 296 { 297 int len; 298 if (tk->name == nil || sub->name == nil) 299 return 0; 300 len = strlen(tk->name->name); 301 if (strncmp(tk->name->name, sub->name->name, len) == 0 && 302 sub->name->name[len] == '.') 303 return 1; 304 return 0; 305 } 306 307 static char* 308 tktwincreate(Tk *tk, char *arg, char **val) 309 { 310 char *e; 311 TkTindex ix; 312 TkTitem *i; 313 TkText *tkt; 314 TkOptab tko[2]; 315 316 USED(val); 317 318 tkt = TKobj(TkText, tk); 319 320 e = tktindparse(tk, &arg, &ix); 321 if(e != nil) 322 return e; 323 324 e = tktnewitem(TkTwin, 0, &i); 325 if(e != nil) 326 return e; 327 328 i->iwin = malloc(sizeof(TkTwind)); 329 if(i->iwin == nil) { 330 tktfreeitems(tkt, i, 1); 331 return TkNomem; 332 } 333 334 memset(i->iwin, 0, sizeof(TkTwind)); 335 i->iwin->align = Tkcenter; 336 i->iwin->ascent = -1; 337 338 tko[0].ptr = i->iwin; 339 tko[0].optab = twinopts; 340 tko[1].ptr = nil; 341 342 e = tkparse(tk->env->top, arg, tko, nil); 343 if(e != nil) { 344 err1: 345 tktfreeitems(tkt, i, 1); 346 return e; 347 } 348 349 e = tktwinchk(tk, i->iwin, nil); 350 if(e != nil) 351 goto err1; 352 353 e = tktsplititem(&ix); 354 if(e != nil) 355 goto err1; 356 357 tktiteminsert(tkt, &ix, i); 358 if(e != nil) 359 goto err1; 360 361 tktadjustind(tkt, TkTbyitemback, &ix); 362 tktwindsize(tk, &ix); 363 364 return nil; 365 } 366 367 static char* 368 tktwinnames(Tk *tk, char *arg, char **val) 369 { 370 char *e, *fmt; 371 TkTindex ix; 372 TkText *tkt = TKobj(TkText, tk); 373 374 USED(arg); 375 376 tktstartind(tkt, &ix); 377 fmt = "%s"; 378 do { 379 if(ix.item->kind == TkTwin && 380 ix.item->iwin->sub != nil && 381 ix.item->iwin->sub->name != nil) { 382 e = tkvalue(val, fmt, ix.item->iwin->sub->name->name); 383 if(e != nil) 384 return e; 385 fmt = " %s"; 386 } 387 } while(tktadjustind(tkt, TkTbyitem, &ix)); 388 return nil; 389 } 390