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 static int 68 tkcvschkwfocus(TkCwind *w, Tk *tk) 69 { 70 if(w->focus == tk) 71 return 1; 72 for(tk = tk->slave; tk; tk = tk->next) 73 if(tkcvschkwfocus(w, tk)) 74 return 1; 75 return 0; 76 } 77 78 static void 79 tkcvswindgeom(Tk *sub, int x, int y, int w, int h) 80 { 81 TkCitem *i; 82 Tk *parent; 83 TkCanvas *c; 84 TkCwind *win; 85 86 USED(x); 87 USED(y); 88 parent = sub->parent; 89 win = nil; 90 c = TKobj(TkCanvas, parent); 91 for(i = c->head; i; i = i->next) { 92 if(i->type == TkCVwindow) { 93 win = TKobj(TkCwind, i); 94 if(win->sub == sub) 95 break; 96 } 97 } 98 99 if(win->focus != nil) { 100 if(tkcvschkwfocus(win, sub) == 0) 101 win->focus = nil; 102 } 103 104 tkbbmax(&c->update, &i->p.bb); 105 106 if((win->flags & Tksetwidth) == 0) 107 win->width = w; 108 if ((win->flags & Tksetheight) == 0) 109 win->height = h; 110 111 sub->req.width = w; 112 sub->req.height = h; 113 tkcvswindsize(i); 114 115 tkbbmax(&c->update, &i->p.bb); 116 tkcvsdirty(parent); 117 } 118 119 static void 120 tkcvssubdestry(Tk *sub) 121 { 122 Tk *tk; 123 TkCitem *i; 124 TkCanvas *c; 125 TkCwind *win; 126 127 tk = sub->parent; 128 if(tk == nil) 129 return; 130 131 c = TKobj(TkCanvas, tk); 132 for(i = c->head; i; i = i->next) { 133 if(i->type == TkCVwindow) { 134 win = TKobj(TkCwind, i); 135 if(win->sub == sub) { 136 tkbbmax(&c->update, &i->p.bb); 137 tkcvssetdirty(tk); 138 139 win->focus = nil; 140 win->sub = nil; 141 sub->parent = nil; 142 sub->geom = nil; 143 return; 144 } 145 } 146 } 147 } 148 149 Point 150 tkcvsrelpos(Tk *sub) 151 { 152 Tk *tk; 153 TkCitem *i; 154 TkCanvas *c; 155 TkCwind *win; 156 157 tk = sub->parent; 158 if(tk == nil) 159 return ZP; 160 161 c = TKobj(TkCanvas, tk); 162 for(i = c->head; i; i = i->next) { 163 if(i->type == TkCVwindow) { 164 win = TKobj(TkCwind, i); 165 if(win->sub == sub) 166 return subpt(i->p.bb.min, c->view); 167 } 168 } 169 return ZP; 170 } 171 172 static char* 173 tkcvswindchk(Tk *tk, TkCwind *w, Tk *oldsub) 174 { 175 Tk *sub; 176 177 sub = w->sub; 178 if (sub != oldsub) { 179 w->sub = oldsub; 180 if(sub == nil) 181 return nil; 182 183 if(sub->flag & Tkwindow) 184 return TkIstop; 185 186 if(sub->master != nil || sub->parent != nil) 187 return TkWpack; 188 189 if (oldsub != nil) { 190 oldsub->parent = nil; 191 oldsub->geom = nil; 192 oldsub->destroyed = nil; 193 } 194 w->sub = sub; 195 w->focus = nil; 196 sub->parent = tk; 197 tksetbits(w->sub, Tksubsub); 198 sub->geom = tkcvswindgeom; 199 sub->destroyed = tkcvssubdestry; 200 201 if(w->width == 0) 202 w->width = sub->req.width; 203 if(w->height == 0) 204 w->height = sub->req.height; 205 } 206 207 return nil; 208 } 209 210 char* 211 tkcvswindcreat(Tk* tk, char *arg, char **val) 212 { 213 char *e; 214 TkCwind *w; 215 TkCitem *i; 216 TkCanvas *c; 217 TkOptab tko[3]; 218 219 c = TKobj(TkCanvas, tk); 220 221 i = tkcnewitem(tk, TkCVwindow, sizeof(TkCitem)+sizeof(TkCwind)); 222 if(i == nil) 223 return TkNomem; 224 225 w = TKobj(TkCwind, i); 226 w->flags = Tkcenter; 227 228 e = tkparsepts(tk->env->top, &i->p, &arg, 0); 229 if(e != nil) { 230 tkcvsfreeitem(i); 231 return e; 232 } 233 if(i->p.npoint != 1) { 234 tkcvsfreeitem(i); 235 return TkFewpt; 236 } 237 238 tko[0].ptr = w; 239 tko[0].optab = windopts; 240 tko[1].ptr = i; 241 tko[1].optab = itemopts; 242 tko[2].ptr = nil; 243 e = tkparse(tk->env->top, arg, tko, nil); 244 if(e != nil) { 245 tkcvsfreeitem(i); 246 return e; 247 } 248 e = tkcvswindchk(tk, w, nil); 249 if(e != nil) { 250 tkcvsfreeitem(i); 251 return e; 252 } 253 254 e = tkcaddtag(tk, i, 1); 255 if(e != nil) { 256 tkcvsfreeitem(i); 257 return e; 258 } 259 260 e = tkvalue(val, "%d", i->id); 261 if(e != nil) { 262 tkcvsfreeitem(i); 263 return e; 264 } 265 tkcvsappend(c, i); 266 tkcvswindsize(i); 267 268 tkbbmax(&c->update, &i->p.bb); 269 tkcvssetdirty(tk); 270 return nil; 271 } 272 273 char* 274 tkcvswindcget(TkCitem *i, char *arg, char **val) 275 { 276 TkOptab tko[3]; 277 TkCwind *w = TKobj(TkCwind, i); 278 279 tko[0].ptr = w; 280 tko[0].optab = windopts; 281 tko[1].ptr = i; 282 tko[1].optab = itemopts; 283 tko[2].ptr = nil; 284 285 return tkgencget(tko, arg, val, i->env->top); 286 } 287 288 char* 289 tkcvswindconf(Tk *tk, TkCitem *i, char *arg) 290 { 291 char *e; 292 int dx, dy; 293 TkOptab tko[3]; 294 TkCwind *w = TKobj(TkCwind, i); 295 Tk *oldsub; 296 297 tko[0].ptr = w; 298 tko[0].optab = windopts; 299 tko[1].ptr = i; 300 tko[1].optab = itemopts; 301 tko[2].ptr = nil; 302 303 dx = w->width; 304 dy = w->height; 305 w->width = -1; 306 w->height = -1; 307 308 oldsub = w->sub; 309 e = tkparse(tk->env->top, arg, tko, nil); 310 if(e == nil) { 311 e = tkcvswindchk(tk, w, oldsub); 312 if(e != nil) 313 return e; 314 if(w->width == -1) 315 w->width = dx; 316 else 317 w->flags |= Tksetwidth; 318 if(w->height == -1) 319 w->height = dy; 320 else 321 w->flags |= Tksetheight; 322 tkcvswindsize(i); 323 } else { 324 w->width = dx; 325 w->height = dy; 326 } 327 return e; 328 } 329 330 void 331 tkcvswindfree(TkCitem *i) 332 { 333 Tk *sub; 334 TkCwind *w; 335 336 w = TKobj(TkCwind, i); 337 sub = w->sub; 338 if(w->focus == sub) 339 w->focus = nil; 340 if(sub != nil) { 341 sub->parent = nil; 342 sub->geom = nil; 343 sub->destroyed = nil; 344 } 345 } 346 347 void 348 tkcvswinddraw(Image *img, TkCitem *i, TkEnv *pe) 349 { 350 TkCwind *w; 351 Point rel; 352 Rectangle r; 353 Tk *sub; 354 355 USED(img); /* See tkimageof */ 356 USED(pe); 357 w = TKobj(TkCwind, i); 358 sub = w->sub; 359 if(sub != nil) { 360 int dirty; 361 r = i->p.bb; 362 rel.x = r.min.x + sub->borderwidth; 363 rel.y = r.min.y + sub->borderwidth; 364 if (rectclip(&r, img->clipr)) { 365 sub->dirty = rectsubpt(r, rel); 366 sub->flag |= Tkrefresh; 367 tkdrawslaves(sub, ZP, &dirty); /* XXX - Tad: propagate err? */ 368 } 369 } 370 } 371 372 char* 373 tkcvswindcoord(TkCitem *i, char *arg, int x, int y) 374 { 375 char *e; 376 TkCpoints p; 377 /* 378 TkCwind *w; 379 int xi, yi; 380 */ 381 382 if(arg == nil) { 383 tkxlatepts(i->p.parampt, i->p.npoint, x, y); 384 tkxlatepts(i->p.drawpt, i->p.npoint, TKF2I(x), TKF2I(y)); 385 tkcvswindsize(i); 386 /* 387 w = TKobj(TkCwind, i); 388 xi = TKF2I(x); 389 yi = TKF2I(y); 390 if (w->sub != nil) { 391 w->sub->act.x += xi; 392 w->sub->act.y += yi; 393 } 394 i->p.bb = rectaddpt(i->p.bb, Pt(xi, yi)); 395 */ 396 } 397 else { 398 e = tkparsepts(i->env->top, &p, &arg, 0); 399 if(e != nil) 400 return e; 401 if(p.npoint != 1) { 402 tkfreepoint(&p); 403 return TkFewpt; 404 } 405 tkfreepoint(&i->p); 406 i->p = p; 407 tkcvswindsize(i); 408 } 409 return nil; 410 } 411