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