1 #include <lib9.h>
2 #include <kernel.h>
3 #include "draw.h"
4 #include "tk.h"
5 #include "canvs.h"
6
7 char*
tkparsepts(TkTop * t,TkCpoints * i,char ** arg,int close)8 tkparsepts(TkTop *t, TkCpoints *i, char **arg, int close)
9 {
10 char *s, *e;
11 Point *p, *d;
12 int n, npoint;
13
14 i->parampt = nil;
15 i->drawpt = nil;
16 i->bb = bbnil;
17 s = *arg;
18 npoint = 0;
19 while(*s) {
20 s = tkskip(s, " \t");
21 if(*s == '-' && (s[1] < '0' || s[1] > '9'))
22 break;
23 while(*s && *s != ' ' && *s != '\t')
24 s++;
25 npoint++;
26 }
27
28 i->parampt = mallocz(npoint*sizeof(Point), 0);
29 if(i->parampt == nil)
30 return TkNomem;
31
32 s = *arg;
33 p = i->parampt;
34 npoint = 0;
35 while(*s) {
36 e = tkfracword(t, &s, &p->x, nil);
37 if(e != nil)
38 goto Error;
39 e = tkfracword(t, &s, &p->y, nil);
40 if(e != nil)
41 goto Error;
42 npoint++;
43 s = tkskip(s, " \t");
44 if(*s == '-' && (s[1] < '0' || s[1] > '9'))
45 break;
46 p++;
47 }
48 *arg = s;
49 close = (close != 0);
50 i->drawpt = mallocz((npoint+close)*sizeof(Point), 0);
51 if(i->drawpt == nil){
52 e = TkNomem;
53 goto Error;
54 }
55
56 d = i->drawpt;
57 p = i->parampt;
58 for(n = 0; n < npoint; n++) {
59 d->x = TKF2I(p->x);
60 d->y = TKF2I(p->y);
61 if(d->x < i->bb.min.x)
62 i->bb.min.x = d->x;
63 if(d->x > i->bb.max.x)
64 i->bb.max.x = d->x;
65 if(d->y < i->bb.min.y)
66 i->bb.min.y = d->y;
67 if(d->y > i->bb.max.y)
68 i->bb.max.y = d->y;
69 d++;
70 p++;
71 }
72 if (close)
73 *d = i->drawpt[0];
74
75 i->npoint = npoint;
76 return nil;
77
78 Error:
79 tkfreepoint(i);
80 i->parampt = nil;
81 i->drawpt = nil;
82 return e;
83 }
84
85 TkCitem*
tkcnewitem(Tk * tk,int t,int n)86 tkcnewitem(Tk *tk, int t, int n)
87 {
88 TkCitem *i;
89
90 i = malloc(n);
91 if(i == nil)
92 return nil;
93 memset(i, 0, n);
94
95 i->type = t;
96 i->env = tk->env;
97 i->env->ref++;
98
99 return i;
100 }
101
102 /*
103 * expand the canvas's dirty rectangle, clipping
104 * appropriately to its boundaries.
105 */
106 void
tkcvssetdirty(Tk * tk)107 tkcvssetdirty(Tk *tk)
108 {
109 TkCanvas *c;
110 Rectangle r;
111 c = TKobj(TkCanvas, tk);
112
113 r = tkrect(tk, 0);
114 if (rectclip(&r, rectsubpt(c->update, c->view)))
115 combinerect(&tk->dirty, r);
116 }
117
118 void
tkxlatepts(Point * p,int npoints,int x,int y)119 tkxlatepts(Point *p, int npoints, int x, int y)
120 {
121 while(npoints--) {
122 p->x += x;
123 p->y += y;
124 p++;
125 }
126 }
127
128 void
tkbbmax(Rectangle * bb,Rectangle * r)129 tkbbmax(Rectangle *bb, Rectangle *r)
130 {
131 if(r->min.x < bb->min.x)
132 bb->min.x = r->min.x;
133 if(r->min.y < bb->min.y)
134 bb->min.y = r->min.y;
135 if(r->max.x > bb->max.x)
136 bb->max.x = r->max.x;
137 if(r->max.y > bb->max.y)
138 bb->max.y = r->max.y;
139 }
140
141 void
tkpolybound(Point * p,int n,Rectangle * r)142 tkpolybound(Point *p, int n, Rectangle *r)
143 {
144 while(n--) {
145 if(p->x < r->min.x)
146 r->min.x = p->x;
147 if(p->y < r->min.y)
148 r->min.y = p->y;
149 if(p->x > r->max.x)
150 r->max.x = p->x;
151 if(p->y > r->max.y)
152 r->max.y = p->y;
153 p++;
154 }
155 }
156
157 /*
158 * look up a tag for a canvas item.
159 * if n is non-nil, and the tag isn't found,
160 * then add it to the canvas's taglist.
161 * NB if there are no binds done on the
162 * canvas, these tags never get cleared out,
163 * even if nothing refers to them.
164 */
165 TkName*
tkctaglook(Tk * tk,TkName * n,char * name)166 tkctaglook(Tk* tk, TkName *n, char *name)
167 {
168 ulong h;
169 TkCanvas *c;
170 char *p, *s;
171 TkName *f, **l;
172
173 c = TKobj(TkCanvas, tk);
174
175 s = name;
176 if(s == nil)
177 s = n->name;
178
179 if(strcmp(s, "current") == 0)
180 return c->current;
181
182 h = 0;
183 for(p = s; *p; p++)
184 h += 3*h + *p;
185
186 l = &c->thash[h%TkChash];
187 for(f = *l; f; f = f->link)
188 if(strcmp(f->name, s) == 0)
189 return f;
190
191 if(n == nil)
192 return nil;
193 n->link = *l;
194 *l = n;
195 return n;
196 }
197
198 char*
tkcaddtag(Tk * tk,TkCitem * i,int new)199 tkcaddtag(Tk *tk, TkCitem *i, int new)
200 {
201 TkCtag *t;
202 TkCanvas *c;
203 char buf[16];
204 TkName *n, *f, *link;
205
206 c = TKobj(TkCanvas, tk);
207 if(new != 0) {
208 i->id = ++c->id;
209 snprint(buf, sizeof(buf), "%d", i->id);
210 n = tkmkname(buf);
211 if(n == nil)
212 return TkNomem;
213 n->link = i->tags;
214 i->tags = n;
215 }
216
217 for(n = i->tags; n; n = link) {
218 link = n->link;
219 f = tkctaglook(tk, n, nil);
220 if(n != f)
221 free(n);
222
223 for(t = i->stag; t; t = t->itemlist)
224 if(t->name == f)
225 break;
226 if(t == nil) {
227 t = malloc(sizeof(TkCtag));
228 if(t == nil) {
229 tkfreename(link);
230 return TkNomem;
231 }
232 t->name = f;
233 t->taglist = f->obj; /* add to head of items with this tag */
234 f->obj = t;
235 t->item = i;
236 t->itemlist = i->stag; /* add to head of tags for this item */
237 i->stag = t;
238 }
239 }
240 i->tags = nil;
241
242 if(new != 0) {
243 i->tags = tkmkname("all");
244 if(i->tags == nil)
245 return TkNomem; /* XXX - Tad: memory leak? */
246 return tkcaddtag(tk, i, 0);
247 }
248
249 return nil;
250 }
251
252 void
tkfreepoint(TkCpoints * p)253 tkfreepoint(TkCpoints *p)
254 {
255 free(p->drawpt);
256 free(p->parampt);
257 }
258
259 /*
260 * of all the items in ilist tagged with tag,
261 * return that tag for the first (topmost) item.
262 */
263 TkCtag*
tkclasttag(TkCitem * ilist,TkCtag * tag)264 tkclasttag(TkCitem *ilist, TkCtag* tag)
265 {
266 TkCtag *last, *t;
267
268 if (tag == nil || tag->taglist == nil)
269 return tag;
270 last = nil;
271 while(ilist) {
272 for(t = tag; t; t = t->taglist) {
273 if(t->item == ilist) {
274 last = t;
275 break;
276 }
277 }
278 ilist = ilist->next;
279 }
280 return last;
281 }
282
283 /*
284 * of all the items in ilist tagged with tag,
285 * return that tag for the first (bottommost) item.
286 */
287 TkCtag*
tkcfirsttag(TkCitem * ilist,TkCtag * tag)288 tkcfirsttag(TkCitem *ilist, TkCtag* tag)
289 {
290 TkCtag *t;
291
292 if (tag == nil || tag->taglist == nil)
293 return tag;
294 for (; ilist != nil; ilist = ilist->next)
295 for(t = tag; t; t = t->taglist)
296 if(t->item == ilist)
297 return t;
298 return nil;
299 }
300
301 void
tkmkpen(Image ** pen,TkEnv * e,Image * stipple)302 tkmkpen(Image **pen, TkEnv *e, Image *stipple)
303 {
304 int locked;
305 Display *d;
306 Image *new, *fill;
307
308 fill = tkgc(e, TkCfill);
309
310 d = e->top->display;
311 locked = lockdisplay(d);
312 if(*pen != nil) {
313 freeimage(*pen);
314 *pen = nil;
315 }
316 if(stipple == nil) {
317 if(locked)
318 unlockdisplay(d);
319 return;
320 }
321
322 if(fill == nil)
323 fill = d->black;
324 new = allocimage(d, stipple->r, RGBA32, 1, DTransparent); /* XXX RGBA32 is excessive sometimes... */
325 if (new != nil)
326 draw(new, stipple->r, fill, stipple, ZP);
327 else
328 new = fill;
329 if(locked)
330 unlockdisplay(d);
331 *pen = new;
332 }
333
334 Point
tkcvsanchor(Point dp,int w,int h,int anchor)335 tkcvsanchor(Point dp, int w, int h, int anchor)
336 {
337 Point o;
338
339 if(anchor & Tknorth)
340 o.y = dp.y;
341 else if(anchor & Tksouth)
342 o.y = dp.y - h;
343 else
344 o.y = dp.y - h/2;
345
346 if(anchor & Tkwest)
347 o.x = dp.x;
348 else if(anchor & Tkeast)
349 o.x = dp.x - w;
350 else
351 o.x = dp.x - w/2;
352
353 return o;
354 }
355
356 static TkCitem*
tkcvsmousefocus(TkCanvas * c,Point p)357 tkcvsmousefocus(TkCanvas *c, Point p)
358 {
359 TkCitem *i, *s;
360 int (*hit)(TkCitem*, Point);
361
362 if (c->grab != nil)
363 return c->grab;
364 s = nil;
365 for(i = c->head; i; i = i->next)
366 if(ptinrect(p, i->p.bb)) {
367 if ((hit = tkcimethod[i->type].hit) != nil && !(*hit)(i, p))
368 continue;
369 s = i;
370 }
371
372 return s;
373 }
374
375 Tk*
tkcvsinwindow(Tk * tk,Point * p)376 tkcvsinwindow(Tk *tk, Point *p)
377 {
378 TkCanvas *c;
379 TkCitem *i;
380 Point q;
381 TkCwind *w;
382
383 c = TKobj(TkCanvas, tk);
384
385 q = addpt(*p, c->view);
386 i = tkcvsmousefocus(c, addpt(*p, c->view));
387 if (i == nil || i->type != TkCVwindow)
388 return tk;
389 w = TKobj(TkCwind, i);
390 if (w->sub == nil)
391 return tk;
392 p->x = q.x - (i->p.bb.min.x + w->sub->borderwidth);
393 p->y = q.y - (i->p.bb.min.y + w->sub->borderwidth);
394 return w->sub;
395 }
396
397 static Tk*
tkcvsmouseinsub(TkCwind * w,TkMouse m)398 tkcvsmouseinsub(TkCwind *w, TkMouse m)
399 {
400 Point g, mp;
401 int bd;
402
403 g = tkposn(w->sub);
404 bd = w->sub->borderwidth;
405 mp.x = m.x - (g.x + bd);
406 mp.y = m.y - (g.y + bd);
407 return tkinwindow(w->sub, mp, 0);
408 }
409
410 static Tk*
tkcvsdeliver(Tk * tk,TkCitem * i,int event,void * data)411 tkcvsdeliver(Tk *tk, TkCitem *i, int event, void *data)
412 {
413 Tk *ftk, *dest;
414 TkCtag *t;
415 TkCwind *w;
416 TkAction *a;
417
418 if(i->type == TkCVwindow) {
419 dest = nil;
420 w = TKobj(TkCwind, i);
421 if(w->sub == nil)
422 return nil;
423
424 if(!(event & TkKey) && (event & TkEmouse)) {
425 ftk = tkcvsmouseinsub(w, *(TkMouse*)data);
426 if(ftk != w->focus) {
427 tkdeliver(w->focus, TkLeave, data);
428 if(0)print("focus %p %q %p %q\n", w->sub, tkname(w->sub), ftk, tkname(ftk));
429 tkdeliver(ftk, TkEnter, data);
430 w->focus = ftk;
431 }
432 if(ftk != nil)
433 dest = tkdeliver(ftk, event, data);
434 } else {
435 if(event & TkLeave) {
436 tkdeliver(w->focus, TkLeave, data);
437 w->focus = nil;
438 } else if(event & TkEnter) {
439 ftk = tkcvsmouseinsub(w, *(TkMouse*)data);
440 tkdeliver(ftk, TkEnter, data);
441 w->focus = ftk;
442 } else
443 dest = tkdeliver(w->sub, event, data);
444 }
445 return dest;
446 }
447
448 for(t = i->stag; t != nil; t = t->itemlist) {
449 a = t->name->prop.binds;
450 if(a != nil)
451 tksubdeliver(tk, a, event, data, 0);
452 }
453 return nil;
454 }
455
456 Tk*
tkcvsevent(Tk * tk,int event,void * data)457 tkcvsevent(Tk *tk, int event, void *data)
458 {
459 TkMouse m;
460 TkCitem *f;
461 Point mp, g;
462 TkCanvas *c;
463 Tk *dest;
464
465 c = TKobj(TkCanvas, tk);
466
467 if(event == TkLeave && c->mouse != nil) {
468 tkcvsdeliver(tk, c->mouse, TkLeave, data);
469 c->mouse = nil;
470 }
471
472 dest = nil;
473 if(!(event & TkKey) && (event & TkEmouse) || (event & TkEnter)) {
474 m = *(TkMouse*)data;
475 g = tkposn(tk);
476 mp.x = (m.x - g.x - tk->borderwidth) + c->view.x;
477 mp.y = (m.y - g.y - tk->borderwidth) + c->view.y;
478 f = tkcvsmousefocus(c, mp);
479 if(c->mouse != f) {
480 if(c->mouse != nil) {
481 tkcvsdeliver(tk, c->mouse, TkLeave, data);
482 c->current->obj = nil;
483 }
484 if(f != nil) {
485 c->current->obj = &c->curtag;
486 c->curtag.item = f;
487 tkcvsdeliver(tk, f, TkEnter, data);
488 }
489 c->mouse = f;
490 }
491 f = c->mouse;
492 if(f != nil && (event & TkEnter) == 0)
493 dest = tkcvsdeliver(tk, f, event, &m);
494 }
495
496 if(event & TkKey) {
497 f = c->focus;
498 if(f != nil)
499 tkcvsdeliver(tk, f, event, data);
500 }
501 if(dest == nil)
502 tksubdeliver(tk, tk->binds, event, data, 0);
503 return dest;
504 }
505
506 /*
507 * debugging
508 */
509 void
tkcvsdump(Tk * tk)510 tkcvsdump(Tk *tk)
511 {
512 TkCanvas *c;
513 TkCitem *it;
514 TkCwind *w;
515 char v1[Tkminitem], v2[Tkminitem];
516 int i;
517
518 if(tk == nil)
519 return;
520 c = TKobj(TkCanvas, tk);
521 tkfprint(v1, c->width);
522 tkfprint(v2, c->height);
523 print("%q configure -width %s -height %s", tkname(tk), v1, v2);
524 print(" # focus %#p mouse %#p grab %#p\n", c->focus, c->mouse, c->grab);
525 for(it = c->head; it != nil; it = it->next){
526 print("%q create %q", tkname(tk), tkcimethod[it->type].name);
527 for(i = 0; i < it->p.npoint; i++){
528 tkfprint(v1, it->p.parampt[i].x);
529 tkfprint(v2, it->p.parampt[i].y);
530 print(" %s %s", v1, v2);
531 }
532 if(it->type == TkCVwindow){
533 w = TKobj(TkCwind, it);
534 if(w->sub != nil)
535 print(" -window %q", tkname(w->sub));
536 print(" # item %#p id %d sub %#p focus [%#p %q]\n", it, it->id, w->sub, w->focus, tkname(w->focus));
537 }else
538 print("# item %#p id %d\n", it, it->id);
539 }
540 }
541