From 37da2899f40661e3e9631e497da8dc59b971cbd0 Mon Sep 17 00:00:00 2001 From: "Charles.Forsyth" Date: Fri, 22 Dec 2006 17:07:39 +0000 Subject: 20060303a --- libtk/canvu.c | 506 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 506 insertions(+) create mode 100644 libtk/canvu.c (limited to 'libtk/canvu.c') diff --git a/libtk/canvu.c b/libtk/canvu.c new file mode 100644 index 00000000..3894ff20 --- /dev/null +++ b/libtk/canvu.c @@ -0,0 +1,506 @@ +#include +#include +#include "draw.h" +#include "tk.h" +#include "canvs.h" + +char* +tkparsepts(TkTop *t, TkCpoints *i, char **arg, int close) +{ + char *s, *e; + Point *p, *d; + int n, npoint; + + i->parampt = nil; + i->drawpt = nil; + i->bb = bbnil; + s = *arg; + npoint = 0; + while(*s) { + s = tkskip(s, " \t"); + if(*s == '-' && (s[1] < '0' || s[1] > '9')) + break; + while(*s && *s != ' ' && *s != '\t') + s++; + npoint++; + } + + i->parampt = mallocz(npoint*sizeof(Point), 0); + if(i->parampt == nil) + return TkNomem; + + s = *arg; + p = i->parampt; + npoint = 0; + while(*s) { + e = tkfracword(t, &s, &p->x, nil); + if(e != nil) + goto Error; + e = tkfracword(t, &s, &p->y, nil); + if(e != nil) + goto Error; + npoint++; + s = tkskip(s, " \t"); + if(*s == '-' && (s[1] < '0' || s[1] > '9')) + break; + p++; + } + *arg = s; + close = (close != 0); + i->drawpt = mallocz((npoint+close)*sizeof(Point), 0); + if(i->drawpt == nil){ + e = TkNomem; + goto Error; + } + + d = i->drawpt; + p = i->parampt; + for(n = 0; n < npoint; n++) { + d->x = TKF2I(p->x); + d->y = TKF2I(p->y); + if(d->x < i->bb.min.x) + i->bb.min.x = d->x; + if(d->x > i->bb.max.x) + i->bb.max.x = d->x; + if(d->y < i->bb.min.y) + i->bb.min.y = d->y; + if(d->y > i->bb.max.y) + i->bb.max.y = d->y; + d++; + p++; + } + if (close) + *d = i->drawpt[0]; + + i->npoint = npoint; + return nil; + +Error: + tkfreepoint(i); + i->parampt = nil; + i->drawpt = nil; + return e; +} + +TkCitem* +tkcnewitem(Tk *tk, int t, int n) +{ + TkCitem *i; + + i = malloc(n); + if(i == nil) + return nil; + memset(i, 0, n); + + i->type = t; + i->env = tk->env; + i->env->ref++; + + return i; +} + +/* + * expand the canvas's dirty rectangle, clipping + * appropriately to its boundaries. + */ +void +tkcvssetdirty(Tk *tk) +{ + TkCanvas *c; + Rectangle r; + c = TKobj(TkCanvas, tk); + + r = tkrect(tk, 0); + if (rectclip(&r, rectsubpt(c->update, c->view))) + combinerect(&tk->dirty, r); +} + +void +tkxlatepts(Point *p, int npoints, int x, int y) +{ + while(npoints--) { + p->x += x; + p->y += y; + p++; + } +} + +void +tkbbmax(Rectangle *bb, Rectangle *r) +{ + if(r->min.x < bb->min.x) + bb->min.x = r->min.x; + if(r->min.y < bb->min.y) + bb->min.y = r->min.y; + if(r->max.x > bb->max.x) + bb->max.x = r->max.x; + if(r->max.y > bb->max.y) + bb->max.y = r->max.y; +} + +void +tkpolybound(Point *p, int n, Rectangle *r) +{ + while(n--) { + if(p->x < r->min.x) + r->min.x = p->x; + if(p->y < r->min.y) + r->min.y = p->y; + if(p->x > r->max.x) + r->max.x = p->x; + if(p->y > r->max.y) + r->max.y = p->y; + p++; + } +} + +/* + * look up a tag for a canvas item. + * if n is non-nil, and the tag isn't found, + * then add it to the canvas's taglist. + * NB if there are no binds done on the + * canvas, these tags never get cleared out, + * even if nothing refers to them. + */ +TkName* +tkctaglook(Tk* tk, TkName *n, char *name) +{ + ulong h; + TkCanvas *c; + char *p, *s; + TkName *f, **l; + + c = TKobj(TkCanvas, tk); + + s = name; + if(s == nil) + s = n->name; + + if(strcmp(s, "current") == 0) + return c->current; + + h = 0; + for(p = s; *p; p++) + h += 3*h + *p; + + l = &c->thash[h%TkChash]; + for(f = *l; f; f = f->link) + if(strcmp(f->name, s) == 0) + return f; + + if(n == nil) + return nil; + n->link = *l; + *l = n; + return n; +} + +char* +tkcaddtag(Tk *tk, TkCitem *i, int new) +{ + TkCtag *t; + TkCanvas *c; + char buf[16]; + TkName *n, *f, *link; + + c = TKobj(TkCanvas, tk); + if(new != 0) { + i->id = ++c->id; + snprint(buf, sizeof(buf), "%d", i->id); + n = tkmkname(buf); + if(n == nil) + return TkNomem; + n->link = i->tags; + i->tags = n; + } + + for(n = i->tags; n; n = link) { + link = n->link; + f = tkctaglook(tk, n, nil); + if(n != f) + free(n); + + for(t = i->stag; t; t = t->itemlist) + if(t->name == f) + break; + if(t == nil) { + t = malloc(sizeof(TkCtag)); + if(t == nil) { + tkfreename(link); + return TkNomem; + } + t->name = f; + t->taglist = f->obj; /* add to head of items with this tag */ + f->obj = t; + t->item = i; + t->itemlist = i->stag; /* add to head of tags for this item */ + i->stag = t; + } + } + i->tags = nil; + + if(new != 0) { + i->tags = tkmkname("all"); + if(i->tags == nil) + return TkNomem; /* XXX - Tad: memory leak? */ + return tkcaddtag(tk, i, 0); + } + + return nil; +} + +void +tkfreepoint(TkCpoints *p) +{ + free(p->drawpt); + free(p->parampt); +} + +/* + * of all the items in ilist tagged with tag, + * return that tag for the first (topmost) item. + */ +TkCtag* +tkclasttag(TkCitem *ilist, TkCtag* tag) +{ + TkCtag *last, *t; + + if (tag == nil || tag->taglist == nil) + return tag; + last = nil; + while(ilist) { + for(t = tag; t; t = t->taglist) { + if(t->item == ilist) { + last = t; + break; + } + } + ilist = ilist->next; + } + return last; +} + +/* + * of all the items in ilist tagged with tag, + * return that tag for the first (bottommost) item. + */ +TkCtag* +tkcfirsttag(TkCitem *ilist, TkCtag* tag) +{ + TkCtag *t; + + if (tag == nil || tag->taglist == nil) + return tag; + for (; ilist != nil; ilist = ilist->next) + for(t = tag; t; t = t->taglist) + if(t->item == ilist) + return t; + return nil; +} + +void +tkmkpen(Image **pen, TkEnv *e, Image *stipple) +{ + int locked; + Display *d; + Image *new, *fill; + + fill = tkgc(e, TkCfill); + + d = e->top->display; + locked = lockdisplay(d); + if(*pen != nil) { + freeimage(*pen); + *pen = nil; + } + if(stipple == nil) { + if(locked) + unlockdisplay(d); + return; + } + + if(fill == nil) + fill = d->black; + new = allocimage(d, stipple->r, RGBA32, 1, DTransparent); /* XXX RGBA32 is excessive sometimes... */ + if (new != nil) + draw(new, stipple->r, fill, stipple, ZP); + else + new = fill; + if(locked) + unlockdisplay(d); + *pen = new; +} + +Point +tkcvsanchor(Point dp, int w, int h, int anchor) +{ + Point o; + + if(anchor & Tknorth) + o.y = dp.y; + else + if(anchor & Tksouth) + o.y = dp.y - h; + else + o.y = dp.y - h/2; + + if(anchor & Tkwest) + o.x = dp.x; + else + if(anchor & Tkeast) + o.x = dp.x - w; + else + o.x = dp.x - w/2; + + return o; +} + +static TkCitem* +tkcvsmousefocus(TkCanvas *c, Point p) +{ + TkCitem *i, *s; + int (*hit)(TkCitem*, Point); + + if (c->grab != nil) + return c->grab; + s = nil; + for(i = c->head; i; i = i->next) + if(ptinrect(p, i->p.bb)) { + if ((hit = tkcimethod[i->type].hit) != nil && !(*hit)(i, p)) + continue; + s = i; + } + + return s; +} + +Tk* +tkcvsinwindow(Tk *tk, Point *p) +{ + TkCanvas *c; + TkCitem *i; + Point q; + TkCwind *w; + + c = TKobj(TkCanvas, tk); + + q = addpt(*p, c->view); + i = tkcvsmousefocus(c, addpt(*p, c->view)); + if (i == nil || i->type != TkCVwindow) + return tk; + w = TKobj(TkCwind, i); + if (w->sub == nil) + return tk; + p->x = q.x - (i->p.bb.min.x + w->sub->borderwidth); + p->y = q.y - (i->p.bb.min.y + w->sub->borderwidth); + return w->sub; +} + +static Tk* +tkcvsmouseinsub(TkCwind *w, TkMouse m) +{ + Point g, mp; + int bd; + + g = tkposn(w->sub); + bd = w->sub->borderwidth; + mp.x = m.x - (g.x + bd); + mp.y = m.y - (g.y + bd); + return tkinwindow(w->sub, mp, 0); +} + +static Tk* +tkcvsdeliver(Tk *tk, TkCitem *i, int event, void *data) +{ + Tk *ftk, *dest; + TkCtag *t; + TkCwind *w; + TkAction *a; + + if(i->type == TkCVwindow) { + dest = nil; + w = TKobj(TkCwind, i); + if(w->sub == nil) + return nil; + + if(!(event & TkKey) && (event & TkEmouse)) { + ftk = tkcvsmouseinsub(w, *(TkMouse*)data); + if(ftk != w->focus) { + tkdeliver(w->focus, TkLeave, data); + tkdeliver(ftk, TkEnter, data); + w->focus = ftk; + } + if(ftk != nil) + dest = tkdeliver(ftk, event, data); + } + else { + if (event & TkLeave) { + tkdeliver(w->focus, TkLeave, data); + w->focus = nil; + } else if (event & TkEnter) { + ftk = tkcvsmouseinsub(w, *(TkMouse*)data); + tkdeliver(ftk, TkEnter, data); + w->focus = ftk; + } else + dest = tkdeliver(w->sub, event, data); + } + return dest; + } + + for(t = i->stag; t != nil; t = t->itemlist) { + a = t->name->prop.binds; + if(a != nil) + tksubdeliver(tk, a, event, data, 0); + } + return nil; +} + +Tk* +tkcvsevent(Tk *tk, int event, void *data) +{ + TkMouse m; + TkCitem *f; + Point mp, g; + TkCanvas *c; + Tk *dest; + + c = TKobj(TkCanvas, tk); + + if(event == TkLeave && c->mouse != nil) { + tkcvsdeliver(tk, c->mouse, TkLeave, data); + c->mouse = nil; + } + + dest = nil; + if(!(event & TkKey) && (event & TkEmouse) || (event & TkEnter)) { + m = *(TkMouse*)data; + g = tkposn(tk); + mp.x = (m.x - g.x - tk->borderwidth) + c->view.x; + mp.y = (m.y - g.y - tk->borderwidth) + c->view.y; + f = tkcvsmousefocus(c, mp); + if(c->mouse != f) { + if(c->mouse != nil) { + tkcvsdeliver(tk, c->mouse, TkLeave, data); + c->current->obj = nil; + } + if(f != nil) { + c->current->obj = &c->curtag; + c->curtag.item = f; + tkcvsdeliver(tk, f, TkEnter, data); + } + c->mouse = f; + } + f = c->mouse; + if(f != nil && (event & TkEnter) == 0) + dest = tkcvsdeliver(tk, f, event, &m); + } + + if(event & TkKey) { + f = c->focus; + if(f != nil) + tkcvsdeliver(tk, f, event, data); + } + if(dest == nil) + tksubdeliver(tk, tk->binds, event, data, 0); + return dest; +} -- cgit v1.2.3