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
tkcvswindsize(TkCitem * i)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*
tkcvsfindwin(Tk * tk)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
tkcvsforgetsub(Tk * sub,Tk * tk)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
tkcvswindgeom(Tk * sub,int x,int y,int w,int h)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
tkcvssubdestry(Tk * sub)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
tkcvsrelpos(Tk * sub)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*
tkcvswindchk(Tk * tk,TkCwind * w,Tk * oldsub)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*
tkcvswindcreat(Tk * tk,char * arg,char ** val)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*
tkcvswindcget(TkCitem * i,char * arg,char ** val)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*
tkcvswindconf(Tk * tk,TkCitem * i,char * arg)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
tkcvswindfree(TkCitem * i)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
tkcvswinddraw(Image * img,TkCitem * i,TkEnv * pe)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*
tkcvswindcoord(TkCitem * i,char * arg,int x,int y)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