1 #include "lib9.h" 2 #include "draw.h" 3 #include "tk.h" 4 #include "canvs.h" 5 6 #define O(t, e) ((long)(&((t*)0)->e)) 7 8 /* Window Options (+ means implemented) 9 +tags 10 +width 11 +height 12 +window 13 +anchor 14 */ 15 16 static 17 TkOption windopts[] = 18 { 19 "width", OPTdist, O(TkCwind, width), nil, 20 "height", OPTdist, O(TkCwind, height), nil, 21 "anchor", OPTstab, O(TkCwind, flags), tkanchor, 22 "window", OPTwinp, O(TkCwind, sub), nil, 23 nil 24 }; 25 26 static 27 TkOption itemopts[] = 28 { 29 "tags", OPTctag, O(TkCitem, tags), nil, 30 nil 31 }; 32 33 static void 34 tkcvswindsize(TkCitem *i) 35 { 36 Tk *s; 37 int bw; 38 Point p; 39 TkGeom old; 40 TkCwind *w; 41 42 w = TKobj(TkCwind, i); 43 s = w->sub; 44 if(s == nil) 45 return; 46 47 if(w->width != s->act.width || w->height != s->act.height) { 48 old = s->act; 49 s->act.width = w->width; 50 s->act.height = w->height; 51 if(s->slave) { 52 tkpackqit(s); 53 tkrunpack(s->env->top); 54 } 55 tkdeliver(s, TkConfigure, &old); 56 } 57 p = tkcvsanchor(i->p.drawpt[0], s->act.width, s->act.height, w->flags); 58 s->act.x = p.x; 59 s->act.y = p.y; 60 61 bw = 2*s->borderwidth; 62 i->p.bb.min = p; 63 i->p.bb.max.x = p.x + s->act.width + bw; 64 i->p.bb.max.y = p.y + s->act.height + bw; 65 } 66 67 TkCitem* 68 tkcvsfindwin(Tk *tk) 69 { 70 Tk *parent, *sub; 71 TkCitem *i; 72 TkCanvas *c; 73 TkCwind *w; 74 75 sub = tkfindsub(tk); 76 if(sub == nil) 77 return nil; 78 parent = sub->parent; 79 if(parent->type != TKcanvas) 80 return nil; /* inconsistent */ 81 c = TKobj(TkCanvas, parent); 82 for(i = c->head; i != nil; i = i->next) { 83 if(i->type == TkCVwindow) { 84 w = TKobj(TkCwind, i); 85 if(w->sub == sub) 86 return i; 87 } 88 } 89 return nil; 90 } 91 92 void 93 tkcvsforgetsub(Tk *sub, Tk *tk) 94 { 95 TkCwind *w; 96 TkCitem *i; 97 98 i = tkcvsfindwin(sub); 99 if(i == nil) 100 return; 101 w = TKobj(TkCwind, i); 102 if(w->focus == tk) { 103 if(0)print("tkcsvsforget sub %p %q focus %p %q\n", sub, tkname(sub), tk, tkname(tk)); 104 w->focus = nil; 105 } 106 } 107 108 static void 109 tkcvswindgeom(Tk *sub, int x, int y, int w, int h) 110 { 111 TkCitem *i; 112 Tk *parent; 113 TkCanvas *c; 114 TkCwind *win; 115 116 USED(x); 117 USED(y); 118 parent = sub->parent; 119 win = nil; 120 c = TKobj(TkCanvas, parent); 121 for(i = c->head; i; i = i->next) { 122 if(i->type == TkCVwindow) { 123 win = TKobj(TkCwind, i); 124 if(win->sub == sub) 125 break; 126 } 127 } 128 129 tkbbmax(&c->update, &i->p.bb); 130 131 if((win->flags & Tksetwidth) == 0) 132 win->width = w; 133 if ((win->flags & Tksetheight) == 0) 134 win->height = h; 135 136 sub->req.width = w; 137 sub->req.height = h; 138 tkcvswindsize(i); 139 140 tkbbmax(&c->update, &i->p.bb); 141 tkcvsdirty(parent); 142 } 143 144 static void 145 tkcvssubdestry(Tk *sub) 146 { 147 Tk *tk; 148 TkCitem *i; 149 TkCanvas *c; 150 TkCwind *win; 151 152 tk = sub->parent; 153 if(tk == nil) 154 return; 155 156 if(0)print("tkcvssubdestry %p %q\n", sub, tkname(sub)); 157 i = tkcvsfindwin(sub); 158 if(i == nil) 159 return; 160 win = TKobj(TkCwind, i); 161 if(win->sub != sub){ 162 if(win->sub != nil) 163 print("inconsistent tkcvssubdestry %p %q\n", sub, tkname(sub)); 164 return; 165 } 166 167 c = TKobj(TkCanvas, tk); 168 tkbbmax(&c->update, &i->p.bb); 169 tkcvssetdirty(tk); 170 171 win->focus = nil; 172 win->sub = nil; 173 sub->parent = nil; 174 sub->geom = nil; 175 } 176 177 Point 178 tkcvsrelpos(Tk *sub) 179 { 180 Tk *tk; 181 TkCitem *i; 182 TkCanvas *c; 183 TkCwind *win; 184 185 tk = sub->parent; 186 if(tk == nil) 187 return ZP; 188 189 c = TKobj(TkCanvas, tk); 190 for(i = c->head; i; i = i->next) { 191 if(i->type == TkCVwindow) { 192 win = TKobj(TkCwind, i); 193 if(win->sub == sub) 194 return subpt(i->p.bb.min, c->view); 195 } 196 } 197 return ZP; 198 } 199 200 static char* 201 tkcvswindchk(Tk *tk, TkCwind *w, Tk *oldsub) 202 { 203 Tk *sub; 204 205 sub = w->sub; 206 if (sub != oldsub) { 207 w->sub = oldsub; 208 if(sub == nil) 209 return nil; 210 211 if(sub->flag & Tkwindow) 212 return TkIstop; 213 214 if(sub->master != nil || sub->parent != nil) 215 return TkWpack; 216 217 if (oldsub != nil) { 218 oldsub->parent = nil; 219 oldsub->geom = nil; 220 oldsub->destroyed = nil; 221 } 222 w->sub = sub; 223 w->focus = nil; 224 sub->parent = tk; 225 tksetbits(w->sub, Tksubsub); 226 sub->geom = tkcvswindgeom; 227 sub->destroyed = tkcvssubdestry; 228 229 if(w->width == 0) 230 w->width = sub->req.width; 231 if(w->height == 0) 232 w->height = sub->req.height; 233 } 234 235 return nil; 236 } 237 238 char* 239 tkcvswindcreat(Tk* tk, char *arg, char **val) 240 { 241 char *e; 242 TkCwind *w; 243 TkCitem *i; 244 TkCanvas *c; 245 TkOptab tko[3]; 246 247 c = TKobj(TkCanvas, tk); 248 249 i = tkcnewitem(tk, TkCVwindow, sizeof(TkCitem)+sizeof(TkCwind)); 250 if(i == nil) 251 return TkNomem; 252 253 w = TKobj(TkCwind, i); 254 w->flags = Tkcenter; 255 256 e = tkparsepts(tk->env->top, &i->p, &arg, 0); 257 if(e != nil) { 258 tkcvsfreeitem(i); 259 return e; 260 } 261 if(i->p.npoint != 1) { 262 tkcvsfreeitem(i); 263 return TkFewpt; 264 } 265 266 tko[0].ptr = w; 267 tko[0].optab = windopts; 268 tko[1].ptr = i; 269 tko[1].optab = itemopts; 270 tko[2].ptr = nil; 271 e = tkparse(tk->env->top, arg, tko, nil); 272 if(e != nil) { 273 tkcvsfreeitem(i); 274 return e; 275 } 276 e = tkcvswindchk(tk, w, nil); 277 if(e != nil) { 278 tkcvsfreeitem(i); 279 return e; 280 } 281 282 e = tkcaddtag(tk, i, 1); 283 if(e != nil) { 284 tkcvsfreeitem(i); 285 return e; 286 } 287 288 e = tkvalue(val, "%d", i->id); 289 if(e != nil) { 290 tkcvsfreeitem(i); 291 return e; 292 } 293 tkcvsappend(c, i); 294 tkcvswindsize(i); 295 296 tkbbmax(&c->update, &i->p.bb); 297 tkcvssetdirty(tk); 298 return nil; 299 } 300 301 char* 302 tkcvswindcget(TkCitem *i, char *arg, char **val) 303 { 304 TkOptab tko[3]; 305 TkCwind *w = TKobj(TkCwind, i); 306 307 tko[0].ptr = w; 308 tko[0].optab = windopts; 309 tko[1].ptr = i; 310 tko[1].optab = itemopts; 311 tko[2].ptr = nil; 312 313 return tkgencget(tko, arg, val, i->env->top); 314 } 315 316 char* 317 tkcvswindconf(Tk *tk, TkCitem *i, char *arg) 318 { 319 char *e; 320 int dx, dy; 321 TkOptab tko[3]; 322 TkCwind *w = TKobj(TkCwind, i); 323 Tk *oldsub; 324 325 tko[0].ptr = w; 326 tko[0].optab = windopts; 327 tko[1].ptr = i; 328 tko[1].optab = itemopts; 329 tko[2].ptr = nil; 330 331 dx = w->width; 332 dy = w->height; 333 w->width = -1; 334 w->height = -1; 335 336 oldsub = w->sub; 337 e = tkparse(tk->env->top, arg, tko, nil); 338 if(e == nil) { 339 e = tkcvswindchk(tk, w, oldsub); 340 if(e != nil) 341 return e; 342 if(w->width == -1) 343 w->width = dx; 344 else 345 w->flags |= Tksetwidth; 346 if(w->height == -1) 347 w->height = dy; 348 else 349 w->flags |= Tksetheight; 350 tkcvswindsize(i); 351 } else { 352 w->width = dx; 353 w->height = dy; 354 } 355 return e; 356 } 357 358 void 359 tkcvswindfree(TkCitem *i) 360 { 361 Tk *sub; 362 TkCwind *w; 363 364 w = TKobj(TkCwind, i); 365 sub = w->sub; 366 if(sub != nil) { 367 sub->parent = nil; 368 sub->geom = nil; 369 sub->destroyed = nil; 370 } 371 w->focus = nil; 372 w->sub = nil; 373 } 374 375 void 376 tkcvswinddraw(Image *img, TkCitem *i, TkEnv *pe) 377 { 378 TkCwind *w; 379 Point rel; 380 Rectangle r; 381 Tk *sub; 382 383 USED(img); /* See tkimageof */ 384 USED(pe); 385 w = TKobj(TkCwind, i); 386 sub = w->sub; 387 if(sub != nil) { 388 int dirty; 389 r = i->p.bb; 390 rel.x = r.min.x + sub->borderwidth; 391 rel.y = r.min.y + sub->borderwidth; 392 if (rectclip(&r, img->clipr)) { 393 sub->dirty = rectsubpt(r, rel); 394 sub->flag |= Tkrefresh; 395 tkdrawslaves(sub, ZP, &dirty); /* XXX - Tad: propagate err? */ 396 } 397 } 398 } 399 400 char* 401 tkcvswindcoord(TkCitem *i, char *arg, int x, int y) 402 { 403 char *e; 404 TkCpoints p; 405 /* 406 TkCwind *w; 407 int xi, yi; 408 */ 409 410 if(arg == nil) { 411 tkxlatepts(i->p.parampt, i->p.npoint, x, y); 412 tkxlatepts(i->p.drawpt, i->p.npoint, TKF2I(x), TKF2I(y)); 413 tkcvswindsize(i); 414 /* 415 w = TKobj(TkCwind, i); 416 xi = TKF2I(x); 417 yi = TKF2I(y); 418 if (w->sub != nil) { 419 w->sub->act.x += xi; 420 w->sub->act.y += yi; 421 } 422 i->p.bb = rectaddpt(i->p.bb, Pt(xi, yi)); 423 */ 424 } 425 else { 426 e = tkparsepts(i->env->top, &p, &arg, 0); 427 if(e != nil) 428 return e; 429 if(p.npoint != 1) { 430 tkfreepoint(&p); 431 return TkFewpt; 432 } 433 tkfreepoint(&i->p); 434 i->p = p; 435 tkcvswindsize(i); 436 } 437 return nil; 438 } 439