diff options
| author | Charles.Forsyth <devnull@localhost> | 2006-12-22 17:07:39 +0000 |
|---|---|---|
| committer | Charles.Forsyth <devnull@localhost> | 2006-12-22 17:07:39 +0000 |
| commit | 37da2899f40661e3e9631e497da8dc59b971cbd0 (patch) | |
| tree | cbc6d4680e347d906f5fa7fca73214418741df72 /libtk/canvs.c | |
| parent | 54bc8ff236ac10b3eaa928fd6bcfc0cdb2ba46ae (diff) | |
20060303a
Diffstat (limited to 'libtk/canvs.c')
| -rw-r--r-- | libtk/canvs.c | 2220 |
1 files changed, 2220 insertions, 0 deletions
diff --git a/libtk/canvs.c b/libtk/canvs.c new file mode 100644 index 00000000..9d7cc4d1 --- /dev/null +++ b/libtk/canvs.c @@ -0,0 +1,2220 @@ +#include <lib9.h> +#include <kernel.h> +#include "draw.h" +#include "tk.h" +#include "canvs.h" + +/* Widget Commands (+ means implemented) + +addtag + except halo and start options of closest spec + +bbox + +bind + +canvasx + +canvasy + +cget + +configure + +coords + +create + +dchars + +delete + +dtag + +find + +focus + +gettags + +icursor + +index + +insert + +itemcget + +itemconfigure + +lower + +move + postscript + +raise + +scale + scan + +select + +type + +xview + +yview +*/ + +static +TkStab tkbuffer[] = { + "visible", TkCbufvisible, + "all", TkCbufall, + "none", TkCbufnone, + "auto", TkCbufauto, + + /* backwards compatibility */ + "1", TkCbufall, + "yes", TkCbufall, + "off", TkCbufall, + "0", TkCbufauto, + "no", TkCbufauto, + "off", TkCbufauto, + nil +}; + +#define O(t, e) ((long)(&((t*)0)->e)) +#define OA(t, e) ((long)(((t*)0)->e)) + +static +TkOption opts[] = +{ + "closeenough", OPTfrac, O(TkCanvas, close), nil, + "confine", OPTfrac, O(TkCanvas, confine), nil, + "scrollregion", OPTfrac, OA(TkCanvas, scrollr), IAUX(4), + "xscrollincrement", OPTfrac, O(TkCanvas, xscrolli), nil, + "yscrollincrement", OPTfrac, O(TkCanvas, yscrolli), nil, + "xscrollcommand", OPTtext, O(TkCanvas, xscroll), nil, + "yscrollcommand", OPTtext, O(TkCanvas, yscroll), nil, + "width", OPTnnfrac, O(TkCanvas, width), nil, + "height", OPTnnfrac, O(TkCanvas, height), nil, + "buffer", OPTstab, O(TkCanvas, buffer), tkbuffer, + "buffered", OPTstab, O(TkCanvas, buffer), tkbool, /* backwards compatibility */ + "selectborderwidth", OPTnndist, O(TkCanvas, sborderwidth), nil, + nil +}; + +int cvslshape[] = { TKI2F(8), TKI2F(10), TKI2F(3) }; +Rectangle bbnil = { 1000000, 1000000, -1000000, -1000000 }; +Rectangle huger = { -1000000, -1000000, 1000000, 1000000 }; + +static void tkcvsgeom(Tk *tk); + + +static void +tkcvsf2i(Tk *tk, TkCanvas *tkc) +{ + Rectangle r; + tk->req.width = TKF2I(tkc->width); + tk->req.height = TKF2I(tkc->height); + + r.min.x = TKF2I(tkc->scrollr[0]); + r.min.y = TKF2I(tkc->scrollr[1]); + r.max.x = TKF2I(tkc->scrollr[2]); + r.max.y = TKF2I(tkc->scrollr[3]); + + /* + * make sure that the region is big enough to hold + * the actually displayed area + */ + if (Dx(r) < tk->act.width) + r.max.x = r.min.x + tk->act.width; + if (Dy(r) < tk->act.height) + r.max.y = r.min.y + tk->act.height; + tkc->region = r; + + /* + * make sure that the view origin is at a valid + * position with respect to the scroll region. + */ + if (tkc->view.x + tk->act.width > r.max.x) + tkc->view.x = r.max.x - tk->act.width; + if (tkc->view.x < r.min.x) + tkc->view.x = r.min.x; + + if (tkc->view.y + tk->act.height > r.max.y) + tkc->view.y = r.max.y - tk->act.height; + if (tkc->view.y < r.min.y) + tkc->view.y = r.min.y; + +} + +char* +tkcanvas(TkTop *t, char *arg, char **ret) +{ + Tk *tk; + char *e; + TkCanvas *tkc; + TkName *names; + TkOptab tko[3]; + + tk = tknewobj(t, TKcanvas, sizeof(Tk)+sizeof(TkCanvas)); + if(tk == nil) + return TkNomem; + + tkc = TKobj(TkCanvas, tk); + tkc->close = TKI2F(1); + tkc->xscrolli = TKI2F(1); + tkc->yscrolli = TKI2F(1); + tkc->width = TKI2F(360); + tkc->height = TKI2F(270); + tkc->actions = 0; + tkc->actlim = Tksweep; + tkc->mask = nil; + tkc->sborderwidth = 1; + + tko[0].ptr = tkc; + tko[0].optab = opts; + tko[1].ptr = tk; + tko[1].optab = tkgeneric; + tko[2].ptr = nil; + + names = nil; + e = tkparse(t, arg, tko, &names); + if(e != nil) + goto err; + if(names == nil) { + /* tkerr(t, arg); XXX */ + e = TkBadwp; + goto err; + } + + tkc->current = tkmkname("current"); + if(tkc->current == nil) { + e = TkNomem; + goto err; + } + + tksettransparent(tk, tkhasalpha(tk->env, TkCbackgnd)); + tkcvsf2i(tk, tkc); + + e = tkaddchild(t, tk, &names); + tkfreename(names); + if(e != nil) { + tkfreename(tkc->current); + tkc->current = nil; + goto err; + } + tk->name->link = nil; + + e = tkvalue(ret, "%s", tk->name->name); + if(e == nil) + return nil; + + tkfreename(tkc->current); + return e; +err: + tkfreeobj(tk); + return e; +} + +void +tkcvsdirty(Tk *sub) +{ + TkCanvas *c; + Tk *tk, *parent; + Rectangle r; + Point rel; + + rel = ZP; + for(tk = sub; tk; tk = tk->master) { + rel.x += tk->borderwidth + tk->act.x; + rel.y += tk->borderwidth + tk->act.y; + if (tk->parent != nil) + break; + } + if (tk == nil) + return; + parent = tk->parent; + c = TKobj(TkCanvas, parent); + r = rectaddpt(sub->dirty, rel); + tkbbmax(&c->update, &r); + tkcvssetdirty(parent); +} + +static void +tkcvsfocusorder(Tk *tk) +{ + TkCanvas *tkc = TKobj(TkCanvas, tk); + TkCwind *win; + TkCitem *it; + TkWinfo *inf; + int i, n; + + n = 0; + for (it = tkc->head; it != nil; it = it->next) { + if (it->type == TkCVwindow) { + win = TKobj(TkCwind, it); + if (win->sub != nil) + n++; + } + } + if (n == 0) + return; + + inf = malloc(sizeof(*inf) * n); + if (inf == nil) + return; + + i = 0; + for (it = tkc->head; it != nil; it = it->next) { + if (it->type == TkCVwindow) { + win = TKobj(TkCwind, it); + if (win->sub != nil) { + inf[i].w = win->sub; + inf[i].r = it->p.bb; + i++; + } + } + } + + tksortfocusorder(inf, n); + for (i = 0; i < n; i++) + tkappendfocusorder(inf[i].w); +} + +static char* +tkcvscget(Tk *tk, char *arg, char **val) +{ + TkOptab tko[3]; + TkCanvas *tkc = TKobj(TkCanvas, tk); + + tko[0].ptr = tkc; + tko[0].optab = opts; + tko[1].ptr = tk; + tko[1].optab = tkgeneric; + tko[2].ptr = nil; + + return tkgencget(tko, arg, val, tk->env->top); +} + +static char* +tkcvsconf(Tk *tk, char *arg, char **val) +{ + char *e; + int bd; + TkGeom g; + Rectangle r; + TkOptab tko[3]; + TkCanvas *c = TKobj(TkCanvas, tk); + + tko[0].ptr = c; + tko[0].optab = opts; + tko[1].ptr = tk; + tko[1].optab = tkgeneric; + tko[2].ptr = nil; + + if(*arg == '\0') + return tkconflist(tko, val); + + r.min = c->view; + r.max.x = r.min.x+tk->act.width; + r.max.y = r.min.y+tk->act.height; + tkbbmax(&c->update, &r); + tkbbmax(&c->update, &c->region); + + bd = tk->borderwidth; + g = tk->req; + e = tkparse(tk->env->top, arg, tko, nil); + if(e != nil) + return e; + tksettransparent(tk, tkhasalpha(tk->env, TkCbackgnd)); + + tkcvsf2i(tk, c); + + tkcvsgeom(tk); + tkgeomchg(tk, &g, bd); + tkbbmax(&c->update, &c->region); + tk->dirty = tkrect(tk, 1); + return nil; +} + +void +tkcvsfreeitem(TkCitem *i) +{ + int locked; + Display *d; + + d = i->env->top->display; + + locked = lockdisplay(d); + tkcimethod[i->type].free(i); + if(locked) + unlockdisplay(d); + + tkfreepoint(&i->p); + tkputenv(i->env); + free(i); +} + +void +tkfreecanv(Tk *tk) +{ + Display *d; + int j, locked; + TkCanvas *c; + TkName *n, *nn; + TkCtag *t, *tt; + TkCitem *i, *next; + + c = TKobj(TkCanvas, tk); + for(i = c->head; i; i = next) { + next = i->next; + tkcvsfreeitem(i); + } + + if(c->xscroll != nil) + free(c->xscroll); + if(c->yscroll != nil) + free(c->yscroll); + + for(j = 0; j < TkChash; j++) { + for(n = c->thash[j]; n; n = nn) { + nn = n->link; + for(t = n->obj; t; t = tt) { + tt = t->taglist; + free(t); + } + tkfreebind(n->prop.binds); + free(n); + } + } + + free(c->current); + + if((c->ialloc && c->image != nil) || c->mask != nil) { + if (c->ialloc && c->image != nil) + d = c->image->display; + else + d = c->mask->display; + locked = lockdisplay(d); + if (c->image != nil && c->ialloc) + freeimage(c->image); + if (c->mask != nil) + freeimage(c->mask); + if(locked) + unlockdisplay(d); + } +} + +enum {Bufnone = 99}; + +char* +tkdrawcanv(Tk *tk, Point orig) +{ + Image *dst; + TkCitem *i; + Display *d; + TkCanvas *c; + Rectangle r, bufr, oclipr; + int vis, alpha, buffer; + Point rel, p; + TkCimeth *imeth; + + c = TKobj(TkCanvas, tk); + d = tk->env->top->display; + dst = tkimageof(tk); + /* + * translation from local to screen coords + */ + rel.x = orig.x + tk->act.x + tk->borderwidth; + rel.y = orig.y + tk->act.y + tk->borderwidth; + + buffer = c->buffer; + if (buffer == TkCbufauto) + buffer = TkCbufvisible; +/* buffer = (dst == TKobj(TkWin, tk->env->top->root)->image) ? TkCbufvisible : TkCbufnone; */ + + if (buffer == TkCbufnone) { + if(c->image != nil && c->ialloc) + freeimage(c->image); + c->image = dst; + c->ialloc = 0; + + r = tkrect(tk, 0); + bufr = r; + rectclip(&bufr, tk->dirty); + oclipr = dst->clipr; + + replclipr(dst, 0, rectaddpt(bufr, rel)); + draw(dst, rectaddpt(bufr, rel), tkgc(tk->env, TkCbackgnd), nil, ZP); + + p = subpt(rel, c->view); + p.x = TKI2F(p.x); + p.y = TKI2F(p.y); + bufr = rectaddpt(bufr, c->view); + for(i = c->head; i; i = i->next) { + if(rectXrect(i->p.bb, bufr)) { + imeth = &tkcimethod[i->type]; + imeth->coord(i, nil, p.x, p.y); + imeth->draw(dst, i, tk->env); + imeth->coord(i, nil, -p.x, -p.y); + } + } + replclipr(dst, 0, oclipr); + } else { + if (c->buffer == TkCbufall) + bufr = c->region; + else { + bufr.min = c->view; + bufr.max.x = c->view.x + tk->act.width; + bufr.max.y = c->view.y + tk->act.height; + } + alpha = (tk->env->colors[TkCbackgnd] & 0xff) != 0xff; + if(c->image == nil || eqrect(bufr, c->image->r) == 0) { + if(c->image != nil && c->ialloc) + freeimage(c->image); + c->image = allocimage(d, bufr, alpha?RGBA32:d->image->chan, 0, tk->env->colors[TkCbackgnd]); + c->ialloc = 1; + c->update = bufr; + tkcvssetdirty(tk); /* unnecessary? */ + } + + if(c->image == nil) + return nil; + + r = c->update; + if (rectclip(&r, c->image->r)) { + if (alpha) + drawop(c->image, c->update, nil, nil, ZP, Clear); + draw(c->image, c->update, tkgc(tk->env, TkCbackgnd), nil, c->view); + replclipr(c->image, 0, r); + for(i = c->head; i; i = i->next) { + if(rectXrect(i->p.bb, r)) + tkcimethod[i->type].draw(c->image, i, tk->env); + } + replclipr(c->image, 0, c->image->r); + } + /* + * if the visible area of the canvas image doesn't + * fit completely within the dirty rectangle, + * then we'll need to draw the background behind it + */ + r = tkrect(tk, 0); + bufr = rectsubpt(bufr, c->view); + vis = rectclip(&bufr, tkrect(tk, 0)); + + if (!vis || !rectinrect(tk->dirty, bufr)) + draw(dst, rectaddpt(tk->dirty, rel), tkgc(tk->env, TkCbackgnd), nil, c->view); + + if (vis && rectclip(&bufr, tk->dirty)) + draw(dst, rectaddpt(bufr, rel), c->image, nil, addpt(bufr.min, c->view)); + } + + + /* + * if the border is dirty too, then draw that + */ + if (!rectinrect(tk->dirty, bufr)) { + r.min = addpt(r.min, rel); + r.min.x -= tk->borderwidth; + r.min.y -= tk->borderwidth; + tkdrawrelief(dst, tk, r.min, TkCbackgnd, tk->relief); + } + c->update = bbnil; + return nil; +} + +void +tkcvsappend(TkCanvas *c, TkCitem *i) +{ + if(c->head == nil) + c->head = i; + else + c->tail->next = i; + c->tail = i; +} + +void +tkcvssv(Tk *tk) +{ + TkCanvas *c; + int top, bot, height; + char val[Tkminitem], cmd[Tkmaxitem], *v, *e; + + c = TKobj(TkCanvas, tk); + if(c->yscroll == nil) + return; + + top = 0; + bot = TKI2F(1); + + height = Dy(c->region); + if(height != 0) { + top = TKI2F(c->view.y)/height; + bot = TKI2F(c->view.y+tk->act.height)/height; + } + + v = tkfprint(val, top); + *v++ = ' '; + tkfprint(v, bot); + snprint(cmd, sizeof(cmd), "%s %s", c->yscroll, val); + e = tkexec(tk->env->top, cmd, nil); + if ((e != nil) && (tk->name != nil)) + print("tk: yscrollcommand \"%s\": %s\n", tk->name->name, e); +} + +void +tkcvssh(Tk *tk) +{ + int top, bot, width; + TkCanvas *c = TKobj(TkCanvas, tk); + char val[Tkminitem], cmd[Tkmaxitem], *v, *e; + + if(c->xscroll == nil) + return; + + top = 0; + bot = TKI2F(1); + + width = Dx(c->region); + if(width != 0) { + top = TKI2F(c->view.x)/width; + bot = TKI2F(c->view.x+tk->act.width)/width; + } + + v = tkfprint(val, top); + *v++ = ' '; + tkfprint(v, bot); + snprint(cmd, sizeof(cmd), "%s %s", c->xscroll, val); + e = tkexec(tk->env->top, cmd, nil); + if ((e != nil) && (tk->name != nil)) + print("tk: xscrollcommand \"%s\": %s\n", tk->name->name, e); +} + +static void +tkcvsgeom(Tk *tk) +{ + TkCanvas *c; + c = TKobj(TkCanvas, tk); + + tkcvsf2i(tk, c); + tk->dirty = tkrect(tk, 1); + c->update = c->region; + + tkcvssv(tk); + tkcvssh(tk); +} + +char* +tkcvstags(Tk *tk, char *arg, char **val, int af) +{ + TkTop *o; + int x, y; + TkName *f; + TkCtag *t, *tt; + char *fmt; + TkCpoints p; + TkCanvas *c; + TkCitem *i, *b; + int d, dist, dx, dy; + char tag[Tkmaxitem], buf[Tkmaxitem]; + char *e; + + USED(val); + + c = TKobj(TkCanvas, tk); + + o = tk->env->top; + if(af == TkCadd) { + arg = tkword(o, arg, tag, tag+sizeof(tag), nil); + if(tag[0] == '\0' || (tag[0] >= '0' && tag[0] <= '9')) + return TkBadtg; + } + + fmt = "%d"; + arg = tkword(o, arg, buf, buf+sizeof(buf), nil); + if(strcmp(buf, "above") == 0) { + tkword(o, arg, buf, buf+sizeof(buf), nil); + f = tkctaglook(tk, nil, buf); + if(f == nil) + return TkBadtg; + + t = tkclasttag(c->head, f->obj); + if(t == nil) + return TkBadtg; + + for(i = t->item->next; i; i = i->next) { + if(af == TkCadd) { + i->tags = tkmkname(tag); + if(i->tags == nil) + return TkNomem; + tkcaddtag(tk, i, 0); + } + else { + e = tkvalue(val, fmt, i->id); + if(e != nil) + return e; + fmt = " %d"; + } + } + return nil; + } + + if(strcmp(buf, "all") == 0) { + for(i = c->head; i; i = i->next) { + if(af == TkCadd) { + i->tags = tkmkname(tag); + if(i->tags == nil) + return TkNomem; + tkcaddtag(tk, i, 0); + } + else { + e = tkvalue(val, fmt, i->id); + if(e != nil) + return e; + fmt = " %d"; + } + } + return nil; + } + + if(strcmp(buf, "below") == 0) { + tkword(o, arg, buf, buf+sizeof(buf), nil); + f = tkctaglook(tk, nil, buf); + if(f == nil) + return TkBadtg; + tt = f->obj; + for(b = c->head; b; b = b->next) { + for(t = tt; t; t = t->itemlist) + if(t->item == b) + goto found; + } + found: + for(i = c->head; i != b; i = i->next) { + if(af == TkCadd) { + i->tags = tkmkname(tag); + if(i->tags == nil) + return TkNomem; + tkcaddtag(tk, i, 0); + } + else { + e = tkvalue(val, fmt, i->id); + if(e != nil) + return e; + fmt = " %d"; + } + } + return nil; + } + + if(strcmp(buf, "closest") == 0) { + e = tkfracword(o, &arg, &x, nil); + if (e == nil) + e = tkfracword(o, &arg, &y, nil); + if (e != nil) + return e; + if(*arg != '\0') + return "!not implemented"; + + x = TKF2I(x); + y = TKF2I(y); + i = nil; + dist = 0; + for(b = c->head; b != nil; b = b->next) { + dx = x - (b->p.bb.min.x + Dx(b->p.bb)/2); + dy = y - (b->p.bb.min.y + Dy(b->p.bb)/2); + d = dx*dx + dy*dy; + if(d < dist || dist == 0) { + i = b; + dist = d; + } + } + if(i == nil) + return nil; + + if(af == TkCadd) { + i->tags = tkmkname(tag); + if(i->tags == nil) + e = TkNomem; + else + tkcaddtag(tk, i, 0); + } + else + e = tkvalue(val, fmt, i->id); + return e; + } + + if(strcmp(buf, "withtag") == 0) { + tkword(o, arg, buf, buf+sizeof(buf), nil); + f = tkctaglook(tk, nil, buf); + if(f == nil) + return TkBadtg; + for(t = f->obj; t; t = t->taglist) { + i = t->item; + if(af == TkCadd) { + i->tags = tkmkname(tag); + if(i->tags == nil) + return TkNomem; + tkcaddtag(tk, i, 0); + } + else { + e = tkvalue(val, fmt, i->id); + if(e != nil) + return e; + fmt = " %d"; + } + } + return nil; + } + + if(strcmp(buf, "enclosed") == 0) { + e = tkparsepts(o, &p, &arg, 0); + if(e != nil) + goto done; + if(p.npoint != 2) { + e = TkFewpt; + goto done; + } + for(i = c->head; i; i = i->next) { + if(rectinrect(i->p.bb, p.bb)) { + if(af == TkCadd) { + i->tags = tkmkname(tag); + if(i->tags == nil) { + e = TkNomem; + goto done; + } + tkcaddtag(tk, i, 0); + } + else { + e = tkvalue(val, fmt, i->id); + if(e != nil) + goto done; + fmt = " %d"; + } + } + } + goto done; + } + + if(strcmp(buf, "overlapping") == 0) { + e = tkparsepts(o, &p, &arg, 0); + if(e != nil) + goto done; + if(p.npoint != 2) { + e = TkFewpt; + goto done; + } + for(i = c->head; i; i = i->next) { + if(rectXrect(i->p.bb, p.bb)) { + if(af == TkCadd) { + i->tags = tkmkname(tag); + if(i->tags == nil) { + e = TkNomem; + goto done; + } + tkcaddtag(tk, i, 0); + } + else { + e = tkvalue(val, "%d ", i->id); + if(e != nil) + goto done; + } + } + } + goto done; + } + + return TkBadcm; + +done: /* both no error and error do the same thing */ + tkfreepoint(&p); + return e; +} + +static char* +tkcvsaddtag(Tk *tk, char *arg, char **val) +{ + return tkcvstags(tk, arg, val, TkCadd); +} + +static char* +tkcvsfind(Tk *tk, char *arg, char **val) +{ + return tkcvstags(tk, arg, val, TkCfind); +} + +static void +tksweepcanv(Tk *tk) +{ + int j, k; + TkCtag *t, *tt; + TkName **np, *n, *nn; + TkCitem *i; + TkCanvas *c; + TkAction *a; + + c = TKobj(TkCanvas, tk); + + for(j = 0; j < TkChash; j++) + for(n = c->thash[j]; n != nil; n = n->link) + n->ref = 0; + + for(i = c->head; i != nil; i = i->next) + for(t = i->stag; t != nil; t = t->itemlist) + t->name->ref = 1; + + k = 0; + for(j = 0; j < TkChash; j++) { + np = &c->thash[j]; + for(n = *np; n != nil; n = nn) { + nn = n->link; + if(n->ref == 0) { + for(t = n->obj; t != nil; t = tt) { + tt = t->taglist; + free(t); + } + tkfreebind(n->prop.binds); + free(n); + *np = nn; + } else { + np = &n->link; + for(a = n->prop.binds; a != nil; a = a->link) + k++; + } + } + } + + c->actions = k; + k = 3 * k / 2; + if (k < Tksweep) + c->actlim = Tksweep; + else + c->actlim = k; +} + +/* + * extension to tcl/tk: + * grab set tag + * grab release tag + * grab ifunset tag + */ +static char* +tkcvsgrab(Tk *tk, char *arg, char **val) +{ + TkCtag *t; + TkName *f; + TkCanvas *c; + char buf[Tkmaxitem]; + + c = TKobj(TkCanvas, tk); + arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil); + if (strcmp(buf, "status") == 0) { + if (c->grab != nil) + return tkvalue(val, "%d", c->grab->id); + } + else if (strcmp(buf, "release") == 0) { + c->grab = nil; + } + else if (strcmp(buf, "set") == 0 || strcmp(buf, "ifunset") == 0) { + if (buf[0] == 'i' && c->grab != nil) + return nil; + tkword(tk->env->top, arg, buf, buf + sizeof(buf), nil); + + f = tkctaglook(tk, nil, buf); + if(f == nil || f->obj == nil) + return TkBadtg; + + c = TKobj(TkCanvas, tk); + t = tkcfirsttag(c->head, f->obj); + if(t == nil) + return TkBadtg; + c->grab = t->item; + } + else + return TkBadvl; + return nil; +} + +static char* +tkcvsbind(Tk *tk, char *arg, char **val) +{ + Rune r; + TkCtag *t; + TkName *f; + TkAction *a; + TkCanvas *c; + int event, mode; + char *cmd, buf[Tkmaxitem]; + char *e; + + c = TKobj(TkCanvas, tk); + if (c->actions >= c->actlim) + tksweepcanv(tk); + arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil); + + f = tkctaglook(tk, nil, buf); + if(f == nil) { + f = tkctaglook(tk, tkmkname(buf), buf); + if(f == nil) + return TkNomem; + } + + arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil); + if(buf[0] == '<') { + event = tkseqparse(buf+1); + if(event == -1) + return TkBadsq; + } + else { + chartorune(&r, buf); + event = TkKey | r; + } + if(event == 0) + return TkBadsq; + + arg = tkskip(arg, " \t"); + if(*arg == '\0') { + for(t = f->obj; t; t = t->taglist) { + for(a = t->name->prop.binds; a; a = a->link) + if(event == a->event) + return tkvalue(val, "%s", a->arg); + for(a = t->name->prop.binds; a; a = a->link) + if(event & a->event) + return tkvalue(val, "%s", a->arg); + } + return nil; + } + + mode = TkArepl; + if(*arg == '+') { + mode = TkAadd; + arg++; + } + else if(*arg == '-'){ + mode = TkAsub; + arg++; + } + + tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil); + cmd = strdup(buf); + if(cmd == nil) + return TkNomem; + e = tkaction(&f->prop.binds, event, TkDynamic, cmd, mode); + if(e == nil) + c->actions++; + return e; +} + +static char* +tkcvscreate(Tk *tk, char *arg, char **val) +{ + TkCimeth *m; + char buf[Tkmaxitem]; + + arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil); + for(m = tkcimethod; m->name; m++) + if(strcmp(buf, m->name) == 0) + return m->create(tk, arg, val); + + return TkBadit; +} + +static char* +tkcvsbbox(Tk *tk, char *arg, char **val) +{ + TkName *f; + TkCtag *t; + Rectangle bb; + char buf[Tkmaxitem]; + + bb = bbnil; + for(;;) { + arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil); + if(buf[0] == '\0') + break; + f = tkctaglook(tk, nil, buf); + if(f == nil) + return TkBadtg; + for(t = f->obj; t; t = t->taglist) + tkbbmax(&bb, &t->item->p.bb); + } + return tkvalue(val, "%d %d %d %d", bb.min.x, bb.min.y, bb.max.x, bb.max.y); +} + +static char* +tkcvscanvx(Tk *tk, char *arg, char **val) +{ + int x, s; + TkCanvas *c; + Point p; + char buf[Tkmaxitem]; + + c = TKobj(TkCanvas, tk); + arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil); + if(buf[0] == '\0') + return TkBadvl; + + p = tkposn(tk); + x = atoi(buf) + c->view.x - (p.x + tk->borderwidth); + + if(*arg) { + tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil); + s = atoi(buf); + if (s) { + if (x>=0) + x = ((x+s/2)/s)*s; + else + x = ((x-s/2)/s)*s; + } + } + return tkvalue(val, "%d", x); +} + +static char* +tkcvscanvy(Tk *tk, char *arg, char **val) +{ + int y, s; + TkCanvas *c; + Point p; + char buf[Tkmaxitem]; + + c = TKobj(TkCanvas, tk); + arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil); + if(buf[0] == '\0') + return TkBadvl; + + p = tkposn(tk); + y = atoi(buf) + c->view.y - (p.y + tk->borderwidth); + + if(*arg) { + tkitem(buf, arg); + s = atoi(buf); + if (s) { + if (y>=0) + y = ((y+s/2)/s)*s; + else + y = ((y-s/2)/s)*s; + } + } + return tkvalue(val, "%d", y); +} + +static char * +tkcvsscreenx(Tk *tk, char *arg, char **val) +{ + int x; + TkCanvas *c; + Point p; + char buf[Tkmaxitem]; + + c = TKobj(TkCanvas, tk); + tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil); + if(buf[0] == '\0') + return TkBadvl; + p = tkposn(tk); + x = atoi(buf) - c->view.x + (p.x + tk->borderwidth); + return tkvalue(val, "%d", x); +} + +static char * +tkcvsscreeny(Tk *tk, char *arg, char **val) +{ + int y; + TkCanvas *c; + Point p; + char buf[Tkmaxitem]; + + c = TKobj(TkCanvas, tk); + tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil); + if(buf[0] == '\0') + return TkBadvl; + p = tkposn(tk); + y = atoi(buf) - c->view.y + (p.y + tk->borderwidth); + return tkvalue(val, "%d", y); +} + +static char* +tkcvscoords(Tk *tk, char *arg, char **val) +{ + int i; + Point *p; + TkCtag *t; + TkName *f; + TkCanvas *c; + TkCitem *item; + char *fmt, *e, *v, buf[Tkmaxitem]; + + arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil); + if(buf[0] == '\0') + return TkBadvl; + + f = tkctaglook(tk, nil, buf); + if(f == nil || f->obj == nil) + return TkBadtg; + + c = TKobj(TkCanvas, tk); + + t = tkcfirsttag(c->head, f->obj); + if(t == nil) + return TkBadtg; + + item = t->item; + + if(*arg == '\0') { + fmt = "%s"; + p = item->p.parampt; + for(i = 0; i < item->p.npoint; i++) { + v = tkfprint(buf, p->x); + *v++ = ' '; + tkfprint(v, p->y); + e = tkvalue(val, fmt, buf); + if(e != nil) + return e; + fmt = " %s"; + p++; + } + return nil; + } + + tkbbmax(&c->update, &item->p.bb); + e = tkcimethod[item->type].coord(item, arg, 0, 0); + tkbbmax(&c->update, &item->p.bb); + tkcvssetdirty(tk); + return e; +} + +static char* +tkcvsscale(Tk *tk, char *arg, char **val) +{ + TkName *f; + TkCtag *t; + TkCanvas *c; + TkCpoints pts; + TkCitem *item; + int j; + char *e, buf[Tkmaxitem]; + Point *p, *d, origin, scalef; + + USED(val); + + c = TKobj(TkCanvas, tk); + + arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil); + f = tkctaglook(tk, nil, buf); + if(f == nil || f->obj == nil) + return TkBadtg; + + e = tkparsepts(tk->env->top, &pts, &arg, 0); + if(e != nil) + return e; + if(pts.npoint != 2) { + tkfreepoint(&pts); + return TkFewpt; + } + origin = pts.parampt[0]; + scalef = pts.parampt[1]; + tkfreepoint(&pts); + for(t = f->obj; t; t = t->taglist) { + item = t->item; + p = item->p.parampt; + d = item->p.drawpt; + for(j = 0; j < item->p.npoint; j++) { + p->x -= origin.x; + p->y -= origin.y; + p->x = TKF2I(p->x*scalef.x); + p->y = TKF2I(p->y*scalef.y); + p->x += origin.x; + p->y += origin.y; + d->x = TKF2I(p->x); + d->y = TKF2I(p->y); + d++; + p++; + } + tkbbmax(&c->update, &item->p.bb); + e = tkcimethod[item->type].coord(item, nil, 0, 0); + tkbbmax(&c->update, &item->p.bb); + if(e != nil) + return e; + + tkcvssetdirty(tk); + } + return nil; +} + +static char* +tkcvsdtag(Tk *tk, char *arg, char **val) +{ + TkName *f, *dt; + char buf[Tkmaxitem]; + TkCtag **l, *t, *it, *tf; + + USED(val); + + arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil); + f = tkctaglook(tk, nil, buf); + if(f == nil || f->obj == nil) + return TkBadtg; + +/* + XXX this code doesn't appear to work properly. + fix it later. for the moment, it's just a somewhat more + efficient substitute for the later code, so just use that + instead. + + if(*arg == '\0') { + for(t = f->obj; t; t = tf) { + l = &t->item->stag; + for(it = *l; it; it = it->itemlist) { + if(it->item == t->item) { + *l = it->itemlist; + break; + } + l = &it->itemlist; + } + + tf = t->taglist; + free(t); + } + f->obj = nil; + return nil; + } +*/ + if (*arg == '\0') + dt = f; + else { + tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil); + dt = tkctaglook(tk, nil, buf); + if(dt == nil || dt->obj == nil) + return TkBadtg; + } + + for(t = f->obj; t; t = t->taglist) { + l = (TkCtag **)&dt->obj; + for(it = dt->obj; it; it = it->taglist) { + if(t->item == it->item) { + *l = it->taglist; + l = &t->item->stag; + for(tf = *l; tf; tf = tf->itemlist) { + if(tf == it) { + *l = tf->itemlist; + break; + } + l = &tf->itemlist; + } + free(it); + break; + } + l = &it->taglist; + } + } + return nil; +} + +static char* +tkcvsdchars(Tk *tk, char *arg, char **val) +{ + TkCtag *t; + TkName *f; + char *e, buf[Tkmaxitem]; + + USED(val); + + arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil); + f = tkctaglook(tk, nil, buf); + if(f == nil || f->obj == nil) + return TkBadtg; + + for(t = f->obj; t; t = t->taglist) { + if(t->item->type == TkCVtext) { + e = tkcvstextdchar(tk, t->item, arg); + if(e != nil) + return e; + } + } + + return nil; +} + +static char* +tkcvsindex(Tk *tk, char *arg, char **val) +{ + TkCtag *t; + TkName *f; + char *e, buf[Tkmaxitem]; + + USED(val); + + arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil); + f = tkctaglook(tk, nil, buf); + if(f == nil || f->obj == nil) + return TkBadtg; + + for(t = f->obj; t; t = t->taglist) { + if(t->item->type == TkCVtext) { + e = tkcvstextindex(tk, t->item, arg, val); + if(e != nil) + return e; + return nil; + } + } + return nil; +} + +static char* +tkcvsicursor(Tk *tk, char *arg, char **val) +{ + TkCtag *t; + TkName *f; + char *e, buf[Tkmaxitem]; + + USED(val); + + arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil); + f = tkctaglook(tk, nil, buf); + if(f == nil || f->obj == nil) + return TkBadtg; + + for(t = f->obj; t; t = t->taglist) { + if(t->item->type == TkCVtext) { + e = tkcvstexticursor(tk, t->item, arg); + if(e != nil) + return e; + return nil; + } + } + return nil; +} + +static char* +tkcvsinsert(Tk *tk, char *arg, char **val) +{ + TkCtag *t; + TkName *f; + char *e, buf[Tkmaxitem]; + + USED(val); + + arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil); + f = tkctaglook(tk, nil, buf); + if(f == nil || f->obj == nil) + return TkBadtg; + + for(t = f->obj; t; t = t->taglist) { + if(t->item->type == TkCVtext) { + e = tkcvstextinsert(tk, t->item, arg); + if(e != nil) + return e; + } + } + + return nil; +} + +static char* +tkcvsselect(Tk *tk, char *arg, char **val) +{ + int op; + TkCtag *t; + TkName *f; + TkCanvas *c; + char buf[Tkmaxitem]; + + c = TKobj(TkCanvas, tk); + + arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil); + if(strcmp(buf, "clear") == 0) { + tkcvstextclr(tk); + return nil; + } + if(strcmp(buf, "item") == 0) { + if(c->selection) + return tkvalue(val, "%d", c->selection->id); + return nil; + } + + if(strcmp(buf, "to") == 0) + op = TkCselto; + else + if(strcmp(buf, "from") == 0) + op = TkCselfrom; + else + if(strcmp(buf, "adjust") == 0) + op = TkCseladjust; + else + return TkBadcm; + + arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil); + f = tkctaglook(tk, nil, buf); + if(f == nil) + return TkBadtg; + + t = tkcfirsttag(c->head, f->obj); + if(t == nil) + return TkBadtg; + + return tkcvstextselect(tk, t->item, arg, op); +} + +static char* +tkcvsitemcget(Tk *tk, char *arg, char **val) +{ + TkName *f; + TkCtag *t; + TkCitem *i; + char buf[Tkmaxitem]; + + arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil); + f = tkctaglook(tk, nil, buf); + if(f == nil || f->obj == nil) + return TkBadtg; + + for(i = TKobj(TkCanvas, tk)->head; i; i = i->next) { + for(t = f->obj; t; t = t->taglist) + if(i == t->item) + return tkcimethod[i->type].cget(i, arg, val); + } + return nil; +} + +static char* +tkcvsitemconf(Tk *tk, char *arg, char **val) +{ + char *e; + TkName *f; + TkCtag *t; + TkCitem *i; + TkCanvas *c; + char buf[Tkmaxitem]; + + USED(val); + arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil); + f = tkctaglook(tk, nil, buf); + if(f == nil || f->obj == nil) + return TkBadtg; + + c = TKobj(TkCanvas, tk); + for(t = f->obj; t; t = t->taglist) { + for(i = c->head; i; i = i->next) { + if(i == t->item) { + tkbbmax(&c->update, &i->p.bb); + e = tkcimethod[i->type].conf(tk, i, arg); + tkbbmax(&c->update, &i->p.bb); + tkcvssetdirty(tk); + if(e != nil) + return e; + } + } + } + return nil; +} + +static void +tkcvsfreename(TkCanvas *c, TkName *n) +{ + ulong h; + char *p, *s; + TkName *f, **l; + + /* just free implicit ones for now */ + if(n == nil) + return; + s = n->name; + if(s == nil || (s[0] < '0' || s[0] > '9')) + return; + h = 0; + for(p = s; *p; p++) + h += 3*h + *p; + l = &c->thash[h%TkChash]; + for(f = *l; f; l = &f->link, f = *l) + if(f == n){ + *l = f->link; + tkfreebind(f->prop.binds); + free(f); + return; + } +} + +static char* +tkcvsdelete(Tk *tk, char *arg, char **val) +{ + TkName *f; + TkCanvas *c; + char buf[Tkmaxitem]; + TkCitem *item, *prev, *i; + TkCtag *t, *inext, **l, *dit, *it; + + USED(val); + + c = TKobj(TkCanvas, tk); + for(;;) { + arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil); + if(buf[0] == '\0') + break; + f = tkctaglook(tk, nil, buf); + if(f == nil || f->obj == nil) + return nil; + while(f->obj) { + t = f->obj; + item = t->item; + for(it = item->stag; it; it = inext) { + inext = it->itemlist; + l = (TkCtag **)&it->name->obj; + for(dit = *l; dit; dit = dit->taglist) { + if(dit->item == item) { + *l = dit->taglist; + if(dit != t){ + tkcvsfreename(c, dit->name); + free(dit); + } + break; + } + l = &dit->taglist; + } + } + tkbbmax(&c->update, &item->p.bb); + tkcvssetdirty(tk); + prev = nil; + for(i = c->head; i; i = i->next) { + if(i == item) + break; + prev = i; + } + if(prev == nil) + c->head = i->next; + else + prev->next = i->next; + if(c->tail == item) + c->tail = prev; + if(c->focus == item) + c->focus = nil; + if(c->mouse == item) + c->mouse = nil; + if(c->selection == item) + c->selection = nil; + if(c->curtag.item == item) + c->current->obj = nil; + if (c->grab == item) + c->grab = nil; + + tkcvsfreeitem(item); + free(t); + } + } + return nil; +} + +static char* +tkcvsfocus(Tk *tk, char *arg, char **val) +{ + TkName *f; + TkCtag *t; + TkCanvas *c; + TkCitem *i, *focus; + char buf[Tkmaxitem]; + + c = TKobj(TkCanvas, tk); + + if(*arg == '\0') { + if(c->focus == nil) + return nil; + return tkvalue(val, "%d", c->focus->id); + } + + tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil); + if(buf[0] == '\0') + return TkBadvl; + f = tkctaglook(tk, nil, buf); + if(f == nil || f->obj == nil) + return nil; + + focus = c->focus; + if(focus != nil && focus->type == TkCVtext) + tkcvstextfocus(tk, focus, 0); + + for(i = c->head; i; i = i->next) { + if(i->type == TkCVtext || i->type == TkCVwindow) { + for(t = f->obj; t; t = t->taglist) + if(t->item == i) + focus = i; + } + } + + if(focus != nil && focus->type == TkCVtext) + tkcvstextfocus(tk, focus, 1); + + c->focus = focus; + return nil; +} + +static char* +tkcvsgettags(Tk *tk, char *arg, char **val) +{ + TkCtag *t; + TkName *f; + TkCanvas *c; + char *fmt, *e, buf[Tkmaxitem]; + + tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil); + if(buf[0] == '\0') + return TkBadvl; + + f = tkctaglook(tk, nil, buf); + if(f == nil) + return TkBadtg; + + c = TKobj(TkCanvas, tk); + t = tkclasttag(c->head, f->obj); + if(t == nil) + return TkBadtg; + fmt = "%s"; + t = t->item->stag; + while(t) { + /* XXX when might t->name be legally nil? */ + if (t->name != nil) { + if (strcmp(t->name->name, "all")) { + e = tkvalue(val, fmt, t->name->name); + if(e != nil) + return e; + fmt = " %s"; + } + } + t = t->itemlist; + } + return nil; +} + +static char* +tkcvslower(Tk *tk, char *arg, char **val) +{ + TkCtag *t; + TkCanvas *c; + TkName *f, *b; + char buf[Tkmaxitem]; + TkCitem *it, **l, **below, *items, **itemtail, *prev, *iprev; + + USED(val); + c = TKobj(TkCanvas, tk); + + arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil); + f = tkctaglook(tk, nil, buf); + if(f == nil || f->obj == nil) + return nil; + + below = &c->head; + tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil); + if(buf[0] != '\0') { + b = tkctaglook(tk, nil, buf); + if(b == nil || f->obj == nil) + return TkBadtg; + for(it = c->head; it; it = it->next) { + for(t = b->obj; t; t = t->taglist) + if(t->item == it) + goto found; + below = &it->next; + } + found:; + } + l = &c->head; + prev = iprev = nil; + itemtail = &items;; + for (it = *l; it != nil; it = *l) { + for (t = f->obj; t; t = t->taglist) { + if(t->item == it) { + if (it == *below || below == &it->next) + below = l; + if (it == c->tail) + c->tail = prev; + *l = it->next; + *itemtail = it; + iprev = it; + itemtail = &it->next; + tkbbmax(&c->update, &it->p.bb); + goto next; + } + } + prev = it; + l = &it->next; +next:; + } + if (prev == nil) + c->tail = iprev; + *itemtail = *below; + *below = items; + tkcvssetdirty(tk); + return nil; +} + +static char* +tkcvsmove(Tk *tk, char *arg, char **val) +{ + TkCtag *t; + int fx, fy; + TkTop *top; + TkCpoints *p; + TkName *tag; + Rectangle *u; + TkCitem *item; + char *e; + char buf[Tkmaxitem]; + + USED(val); + top = tk->env->top; + arg = tkword(top, arg, buf, buf+sizeof(buf), nil); + tag = tkctaglook(tk, nil, buf); + if(tag == nil) + return nil; + + e = tkfracword(top, &arg, &fx, nil); + if (e != nil) + return e; + e = tkfracword(top, &arg, &fy, nil); + if(e != nil) + return e; + + u = &TKobj(TkCanvas, tk)->update; + for(t = tag->obj; t; t = t->taglist) { + item = t->item; + p = &item->p; + tkbbmax(u, &p->bb); + tkcimethod[item->type].coord(item, nil, fx, fy); + tkbbmax(u, &p->bb); + } + tkcvssetdirty(tk); + return nil; +} + +static char* +tkcvsraise(Tk *tk, char *arg, char **val) +{ + TkCtag *t; + TkCanvas *c; + TkName *f, *a; + char buf[Tkmaxitem]; + TkCitem *prev, *it, *above, *items, *itemtail, *next; + + USED(val); + c = TKobj(TkCanvas, tk); + + arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil); + f = tkctaglook(tk, nil, buf); + if(f == nil) + return nil; + + above = c->tail; + tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil); + if(buf[0] != '\0') { + a = tkctaglook(tk, nil, buf); + if(a == nil) + return TkBadtg; + /* + * find topmost item in the display list matching the "above" tag + */ + for(it = c->head; it != nil; it = it->next) { + for(t = a->obj; t; t = t->taglist) + if(t->item == it) + above = it; + } + } + prev = nil; + items = itemtail = nil; + for (it = c->head; it != nil; it = next) { + next = it->next; + for (t = f->obj; t; t = t->taglist) { + if(t->item == it) { + if (it == above) + above = next; + if (prev) + prev->next = next; + else + c->head = next; + if (itemtail) + itemtail->next = it; + else + items = it; + itemtail = it; + tkbbmax(&c->update, &it->p.bb); + goto next; + } + } + prev = it; +next:; + } + if (items != nil) { + if (above) { + itemtail->next = above->next; + if (above->next == nil) + c->tail = itemtail; + above->next = items; + } else { + if (prev) + prev->next = items; + else + c->head = items; + c->tail = itemtail; + itemtail->next = nil; + } + } + + tkcvssetdirty(tk); + return nil; +} + +static char* +tkcvstype(Tk *tk, char *arg, char **val) +{ + TkCtag *t; + TkName *f; + TkCanvas *c; + char buf[Tkmaxitem]; + + tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil); + if(buf[0] == '\0') + return TkBadvl; + + f = tkctaglook(tk, nil, buf); + if(f == nil || f->obj == nil) + return nil; + + c = TKobj(TkCanvas, tk); + + t = tkcfirsttag(c->head, f->obj); + if(t == nil) + return nil; + + return tkvalue(val, "%s", tkcimethod[t->item->type].name); +} + +static char* +tkcvsview(Tk *tk, char *arg, char **val, int nl, int *posn, int min, int max, int inc) +{ + TkTop *t; + int top, bot, diff, amount; + char *e; + char buf[Tkmaxitem], *v; + + diff = max-min; + if(*arg == '\0') { + if ( diff == 0 ) + top = bot = 0; + else { + top = TKI2F(*posn-min)/diff; + bot = TKI2F(*posn+nl-min)/diff; + } + v = tkfprint(buf, top); + *v++ = ' '; + tkfprint(v, bot); + return tkvalue(val, "%s", buf); + } + + t = tk->env->top; + arg = tkword(t, arg, buf, buf+sizeof(buf), nil); + if(strcmp(buf, "moveto") == 0) { + e = tkfrac(&arg, &top, nil); + if (e != nil) + return e; + *posn = min + TKF2I((top+1)*diff); + } + else + if(strcmp(buf, "scroll") == 0) { + arg = tkword(t, arg, buf, buf+sizeof(buf), nil); + amount = atoi(buf); + tkword(t, arg, buf, buf+sizeof(buf), nil); + if(buf[0] == 'p') /* Pages */ + amount = amount * nl * 9 /10; + else if (inc > 0) + amount *= inc; + else + amount = amount * nl / 10; + *posn += amount; + } + else + return TkBadcm; + + bot = max - nl; + if(*posn > bot) + *posn = bot; + if(*posn < min) + *posn = min; + + tk->dirty = tkrect(tk, 0); + return nil; +} + +static char* +tkcvsyview(Tk *tk, char *arg, char **val) +{ + int si; + char *e; + TkCanvas *c = TKobj(TkCanvas, tk); + + si = TKF2I(c->yscrolli); + e = tkcvsview(tk, arg, val, tk->act.height, &c->view.y, c->region.min.y, c->region.max.y, si); + tkcvssv(tk); + return e; +} + +static char* +tkcvsxview(Tk *tk, char *arg, char **val) +{ + int si; + char *e; + TkCanvas *c = TKobj(TkCanvas, tk); + + si = TKF2I(c->xscrolli); + e = tkcvsview(tk, arg, val, tk->act.width, &c->view.x, c->region.min.x, c->region.max.x, si); + tkcvssh(tk); + return e; +} + +/* + * return in posn the new view origin such that (preferably) smin and smax + * lie between cmin and cmax (cmin is the current view origin, and cmax the + * other end of the visible area). + * adjust posn (the view origin) so that (preferably) both smin and smax lie + * inside cmin to cmax. if both smin and smax cannot fit, then + * at least make sure that spref (smin<=spref<=smax) is visible. + * return 0 if no adjustment is required (the interval is already visible). + * + * attempt to make an adjustment as small as possible that + * fits these criteria. + */ +static int +tkadjustvis(int *posn, int c0, int c1, int s0, int s1, int spref) +{ + int d, v; + + d = c1 - c0; /* visible width */ + + /* + * if requested range fits inside visible range, + * no adjustment is necessary + */ + if (c0 <= s0 && s1 <= c1) + return 0; + + /* + * if requested range fits, make it fully visible + */ + if (s1 - s0 < d) { + if (s0 < c0) + v = s0; + else + v = s1 - d; + } else { + /* + * choose upper or lower end of requested range, + * depending on which end of requested area is already + * visible (if any). + */ + if (c0 <= s1 && s1 < c1) { /* overlapping left of visible */ + v = s1 - d; + if (v > spref) + v = spref; + } + else + if (c0 <= s0 && s0 < c1) { /* overlapping right of visible */ + v = s0; + if (v + d <= spref) + v = spref - d; + } + else + if (s1 < c0) { /* left of visible */ + v = spref; + if (v + d > s1) + v = s1 - d; + } + else { /* right of visible */ + v = spref - d; + if (v < s0) + v = s0; + } + } + *posn = v; + return 1; +} + +static void +tkcvsseerect(Tk *tk, Rectangle r, Point p) +{ + TkCanvas *c; + int scrollh, scrollv; + + c = TKobj(TkCanvas, tk); + + scrollh = tkadjustvis(&c->view.x, c->view.x, c->view.x + tk->act.width, + r.min.x, r.max.x, p.x); + scrollv = tkadjustvis(&c->view.y, c->view.y, c->view.y + tk->act.height, + r.min.y, r.max.y, p.y); + if (scrollh) + tkcvssh(tk); + if (scrollv) + tkcvssv(tk); + if (scrollh || scrollv) + tk->dirty = tkrect(tk, 0); +} + +static char* +tkcvssee(Tk *tk, char *arg, char **val) +{ + Rectangle r; + int n, coords[4]; + char *e; + + USED(val); + n = 0; + while (n < 4) { + if (*arg == '\0') + break; + e = tkfracword(tk->env->top, &arg, &coords[n++], nil); + if (e != nil) + return e; + } + + if (n != 2 && n != 4) + return TkFewpt; + + r.min.x = TKF2I(coords[0]); + r.min.y = TKF2I(coords[1]); + if (n == 4) { + r.max.x = TKF2I(coords[2]); + r.max.y = TKF2I(coords[3]); + } else + r.max = r.min; + r = canonrect(r); + /* + * XXX should intersect r with scrollregion here, as you shouldn't + * be able to display things outside the scroll region. (??) + */ + + tkcvsseerect(tk, r, r.min); + return nil; +} + +static void +tkcvsseesub(Tk *tk, Rectangle *rr, Point *pp) +{ + Rectangle r; + Point p; + TkCanvas *c; + c = TKobj(TkCanvas, tk); + + r = rectaddpt(*rr, c->view); + p = addpt(*pp, c->view); + + tkcvsseerect(tk, r, p); + + *rr = rectsubpt(r, c->view); + *pp = subpt(p, c->view); +} + +static void +tkcvsgetimgs(Tk* tk, Image **image, Image **mask) +{ + TkCanvas *c; + c = TKobj(TkCanvas, tk); + + *image = c->image; + *mask = c->mask; /* XXX this is wrong - the mask image has nothing to do with the main image */ +} + +TkCimeth tkcimethod[] = +{ + "line", tkcvslinecreat, + tkcvslinedraw, + tkcvslinefree, + tkcvslinecoord, + tkcvslinecget, + tkcvslineconf, + tkcvslinehit, + + "text", tkcvstextcreat, + tkcvstextdraw, + tkcvstextfree, + tkcvstextcoord, + tkcvstextcget, + tkcvstextconf, + nil, + + "rectangle", tkcvsrectcreat, + tkcvsrectdraw, + tkcvsrectfree, + tkcvsrectcoord, + tkcvsrectcget, + tkcvsrectconf, + nil, + + "oval", tkcvsovalcreat, + tkcvsovaldraw, + tkcvsovalfree, + tkcvsovalcoord, + tkcvsovalcget, + tkcvsovalconf, + tkcvsovalhit, + + "bitmap", tkcvsbitcreat, + tkcvsbitdraw, + tkcvsbitfree, + tkcvsbitcoord, + tkcvsbitcget, + tkcvsbitconf, + nil, + + "polygon", tkcvspolycreat, + tkcvspolydraw, + tkcvspolyfree, + tkcvspolycoord, + tkcvspolycget, + tkcvspolyconf, + tkcvspolyhit, + + "window", tkcvswindcreat, + tkcvswinddraw, + tkcvswindfree, + tkcvswindcoord, + tkcvswindcget, + tkcvswindconf, + nil, + + "image", tkcvsimgcreat, + tkcvsimgdraw, + tkcvsimgfree, + tkcvsimgcoord, + tkcvsimgcget, + tkcvsimgconf, + nil, + + "arc", tkcvsarccreat, + tkcvsarcdraw, + tkcvsarcfree, + tkcvsarccoord, + tkcvsarccget, + tkcvsarcconf, + nil, + nil +}; + +static +TkCmdtab tkcanvcmd[] = +{ + "addtag", tkcvsaddtag, + "bbox", tkcvsbbox, + "bind", tkcvsbind, + "cget", tkcvscget, + "configure", tkcvsconf, + "create", tkcvscreate, + "canvasx", tkcvscanvx, + "canvasy", tkcvscanvy, + "coords", tkcvscoords, + "dchars", tkcvsdchars, + "delete", tkcvsdelete, + "dtag", tkcvsdtag, + "find", tkcvsfind, + "focus", tkcvsfocus, + "gettags", tkcvsgettags, + "grab", tkcvsgrab, + "icursor", tkcvsicursor, + "insert", tkcvsinsert, + "index", tkcvsindex, + "itemcget", tkcvsitemcget, + "itemconfigure", tkcvsitemconf, + "lower", tkcvslower, + "move", tkcvsmove, + "raise", tkcvsraise, + "screenx", tkcvsscreenx, + "screeny", tkcvsscreeny, + "see", tkcvssee, + "select", tkcvsselect, + "scale", tkcvsscale, + "type", tkcvstype, + "yview", tkcvsyview, + "xview", tkcvsxview, + nil +}; + +TkMethod canvasmethod = { + "canvas", + tkcanvcmd, + tkfreecanv, + tkdrawcanv, + tkcvsgeom, + tkcvsgetimgs, + tkcvsfocusorder, + tkcvsdirty, + tkcvsrelpos, + tkcvsevent, + tkcvsseesub, + tkcvsinwindow +}; |
