xref: /inferno-os/libtk/cwind.c (revision d0e1d143ef6f03c75c008c7ec648859dd260cbab)
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