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