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