summaryrefslogtreecommitdiff
path: root/libtk/canvu.c
diff options
context:
space:
mode:
authorCharles.Forsyth <devnull@localhost>2006-12-22 17:07:39 +0000
committerCharles.Forsyth <devnull@localhost>2006-12-22 17:07:39 +0000
commit37da2899f40661e3e9631e497da8dc59b971cbd0 (patch)
treecbc6d4680e347d906f5fa7fca73214418741df72 /libtk/canvu.c
parent54bc8ff236ac10b3eaa928fd6bcfc0cdb2ba46ae (diff)
20060303a
Diffstat (limited to 'libtk/canvu.c')
-rw-r--r--libtk/canvu.c506
1 files changed, 506 insertions, 0 deletions
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 <lib9.h>
+#include <kernel.h>
+#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;
+}