1 #include <lib9.h> 2 #include <kernel.h> 3 #include "draw.h" 4 #include "tk.h" 5 #include "canvs.h" 6 7 char* 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* 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 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 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 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 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* 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* 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 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* 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* 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 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 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 342 if(anchor & Tksouth) 343 o.y = dp.y - h; 344 else 345 o.y = dp.y - h/2; 346 347 if(anchor & Tkwest) 348 o.x = dp.x; 349 else 350 if(anchor & Tkeast) 351 o.x = dp.x - w; 352 else 353 o.x = dp.x - w/2; 354 355 return o; 356 } 357 358 static TkCitem* 359 tkcvsmousefocus(TkCanvas *c, Point p) 360 { 361 TkCitem *i, *s; 362 int (*hit)(TkCitem*, Point); 363 364 if (c->grab != nil) 365 return c->grab; 366 s = nil; 367 for(i = c->head; i; i = i->next) 368 if(ptinrect(p, i->p.bb)) { 369 if ((hit = tkcimethod[i->type].hit) != nil && !(*hit)(i, p)) 370 continue; 371 s = i; 372 } 373 374 return s; 375 } 376 377 Tk* 378 tkcvsinwindow(Tk *tk, Point *p) 379 { 380 TkCanvas *c; 381 TkCitem *i; 382 Point q; 383 TkCwind *w; 384 385 c = TKobj(TkCanvas, tk); 386 387 q = addpt(*p, c->view); 388 i = tkcvsmousefocus(c, addpt(*p, c->view)); 389 if (i == nil || i->type != TkCVwindow) 390 return tk; 391 w = TKobj(TkCwind, i); 392 if (w->sub == nil) 393 return tk; 394 p->x = q.x - (i->p.bb.min.x + w->sub->borderwidth); 395 p->y = q.y - (i->p.bb.min.y + w->sub->borderwidth); 396 return w->sub; 397 } 398 399 static Tk* 400 tkcvsmouseinsub(TkCwind *w, TkMouse m) 401 { 402 Point g, mp; 403 int bd; 404 405 g = tkposn(w->sub); 406 bd = w->sub->borderwidth; 407 mp.x = m.x - (g.x + bd); 408 mp.y = m.y - (g.y + bd); 409 return tkinwindow(w->sub, mp, 0); 410 } 411 412 static Tk* 413 tkcvsdeliver(Tk *tk, TkCitem *i, int event, void *data) 414 { 415 Tk *ftk, *dest; 416 TkCtag *t; 417 TkCwind *w; 418 TkAction *a; 419 420 if(i->type == TkCVwindow) { 421 dest = nil; 422 w = TKobj(TkCwind, i); 423 if(w->sub == nil) 424 return nil; 425 426 if(!(event & TkKey) && (event & TkEmouse)) { 427 ftk = tkcvsmouseinsub(w, *(TkMouse*)data); 428 if(ftk != w->focus) { 429 tkdeliver(w->focus, TkLeave, data); 430 tkdeliver(ftk, TkEnter, data); 431 w->focus = ftk; 432 } 433 if(ftk != nil) 434 dest = tkdeliver(ftk, event, data); 435 } 436 else { 437 if (event & TkLeave) { 438 tkdeliver(w->focus, TkLeave, data); 439 w->focus = nil; 440 } else if (event & TkEnter) { 441 ftk = tkcvsmouseinsub(w, *(TkMouse*)data); 442 tkdeliver(ftk, TkEnter, data); 443 w->focus = ftk; 444 } else 445 dest = tkdeliver(w->sub, event, data); 446 } 447 return dest; 448 } 449 450 for(t = i->stag; t != nil; t = t->itemlist) { 451 a = t->name->prop.binds; 452 if(a != nil) 453 tksubdeliver(tk, a, event, data, 0); 454 } 455 return nil; 456 } 457 458 Tk* 459 tkcvsevent(Tk *tk, int event, void *data) 460 { 461 TkMouse m; 462 TkCitem *f; 463 Point mp, g; 464 TkCanvas *c; 465 Tk *dest; 466 467 c = TKobj(TkCanvas, tk); 468 469 if(event == TkLeave && c->mouse != nil) { 470 tkcvsdeliver(tk, c->mouse, TkLeave, data); 471 c->mouse = nil; 472 } 473 474 dest = nil; 475 if(!(event & TkKey) && (event & TkEmouse) || (event & TkEnter)) { 476 m = *(TkMouse*)data; 477 g = tkposn(tk); 478 mp.x = (m.x - g.x - tk->borderwidth) + c->view.x; 479 mp.y = (m.y - g.y - tk->borderwidth) + c->view.y; 480 f = tkcvsmousefocus(c, mp); 481 if(c->mouse != f) { 482 if(c->mouse != nil) { 483 tkcvsdeliver(tk, c->mouse, TkLeave, data); 484 c->current->obj = nil; 485 } 486 if(f != nil) { 487 c->current->obj = &c->curtag; 488 c->curtag.item = f; 489 tkcvsdeliver(tk, f, TkEnter, data); 490 } 491 c->mouse = f; 492 } 493 f = c->mouse; 494 if(f != nil && (event & TkEnter) == 0) 495 dest = tkcvsdeliver(tk, f, event, &m); 496 } 497 498 if(event & TkKey) { 499 f = c->focus; 500 if(f != nil) 501 tkcvsdeliver(tk, f, event, data); 502 } 503 if(dest == nil) 504 tksubdeliver(tk, tk->binds, event, data, 0); 505 return dest; 506 } 507