Пример #1
0
Файл: cline.c Проект: 8l/inferno
void
tkcvslinesize(TkCitem *i)
{
	TkCline *l;
	int j, w, as, shape[3], arrow;

	l = TKobj(TkCline, i);
	w = TKF2I(l->width);

	i->p.bb = bbnil;
	tkpolybound(i->p.drawpt, i->p.npoint, &i->p.bb);

	l->arrowf = l->capstyle;
	l->arrowl = l->capstyle;
	if(l->arrow != 0) {
		as = w/3;
		if(as < 1)
			as = 1;
		for(j = 0; j < 3; j++) {
			shape[j] = l->shape[j];
			if(shape[j] == 0)
				shape[j] = as * cvslshape[j];
		}
		arrow = ARROW(TKF2I(shape[0]), TKF2I(shape[1]), TKF2I(shape[2]));
		if(l->arrow & TkCarrowf)
			l->arrowf = arrow;
		if(l->arrow & TkCarrowl)
			l->arrowl = arrow;
		w += shape[2];
	}

	i->p.bb = insetrect(i->p.bb, -w);
}
Пример #2
0
Файл: scale.c Проект: 8l/inferno
static char*
tkscalecoords(Tk *tk, char *arg, char **val)
{
	int p, x, y, l, value;
	TkScale *tks = TKobj(TkScale, tk);
	char *e;

	value = tks->value;
	if(arg != nil && arg[0] != '\0') {
		e = tkfracword(tk->env->top, &arg, &value, tk->env);
		if (e != nil)
			return e;
	}

	value -= tks->from;
	p = tks->pixmax - tks->pixmin;
	l = TKF2I(tks->to-tks->from);
	if (l==0)
		p /= 2;
	else
		p = TKF2I(value*p/l);
	p += tks->pixmin;
	if(tks->orient == Tkvertical) {
		x = tks->center;
		y = p;
	}
	else {
		x = p;
		y = tks->center;
	}
	return tkvalue(val, "%d %d", x, y);
}
Пример #3
0
Файл: ctext.c Проект: 8l/inferno
char*
tkcvstextcoord(TkCitem *i, char *arg, int x, int y)
{
	char *e;
	TkCpoints p;

	if(arg == nil) {
		tkxlatepts(i->p.parampt, i->p.npoint, x, y);
		tkxlatepts(i->p.drawpt, i->p.npoint, TKF2I(x), TKF2I(y));
		i->p.bb = rectaddpt(i->p.bb, Pt(TKF2I(x), TKF2I(y)));
	}
	else {
		e = tkparsepts(i->env->top, &p, &arg, 0);
		if(e != nil)
			return e;
		if(p.npoint != 1) {
			tkfreepoint(&p);
			return TkFewpt;
		}
		tkfreepoint(&i->p);
		i->p = p;
		tkcvstextsize(i);
	}
	return nil;
}
Пример #4
0
Файл: crect.c Проект: 8l/inferno
void
tkcvsrectdraw(Image *img, TkCitem *i, TkEnv *pe)
{
	int lw, rw;
	TkEnv *e;
	TkCrect *r;
	Rectangle d, rr;
	Point tr, bl;
	Image *pen;

	USED(pe);

	d.min = i->p.drawpt[0];
	d.max = i->p.drawpt[1];

	e = i->env;
	r = TKobj(TkCrect, i);

	pen = nil;
	if((e->set & (1<<TkCfill)))
		pen = tkgc(e, TkCfill);

	if(pen != nil)
		draw(img, d, pen, r->stipple, d.min);

	tr.x = d.max.x;
	tr.y = d.min.y;
	bl.x = d.min.x;
	bl.y = d.max.y;

	rw = (TKF2I(r->width) + 1)/2;
	if(rw <= 0)
		return;
	lw = (TKF2I(r->width))/2;

	pen = tkgc(e, TkCforegnd);
	if(pen != nil) {
		/* horizontal lines first */
		rr.min.x = d.min.x - lw;
		rr.max.x = d.max.x + rw;
		rr.min.y = d.min.y - lw;
		rr.max.y = d.min.y + rw;
		draw(img, rr, pen, nil, rr.min);
		rr.min.y += Dy(d);
		rr.max.y += Dy(d);
		draw(img, rr, pen, nil, rr.min);
		/* now the vertical */
		/* horizontal lines first */
		rr.min.x = d.min.x - lw;
		rr.max.x = d.min.x + rw;
		rr.min.y = d.min.y + rw;
		rr.max.y = d.max.y - lw;
		draw(img, rr, pen, nil, rr.min);
		rr.min.x += Dx(d);
		rr.max.x += Dx(d);
		draw(img, rr, pen, nil, rr.min);
	}
}
Пример #5
0
Файл: canvs.c Проект: 8l/inferno
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;
}
Пример #6
0
Файл: scale.c Проект: 8l/inferno
static char*
tkscaledrag(Tk *tk, char *arg, char **val)
{
	int x, y, v;
	char *e, buf[Tkmaxitem], f[32];
	TkScale *tks = TKobj(TkScale, tk);

	USED(val);
	if((tks->flag & Dragging) == 0)
		return nil;
	if(tks->flag & Autorepeat)
		return nil;

	e = tkfracword(tk->env->top, &arg, &x, tk->env);
	if(e != nil)
		return e;
	e = tkfracword(tk->env->top, &arg, &y, tk->env);
	if(e != nil)
		return e;

	if(tks->orient == Tkvertical)
		v = TKF2I(y) + tk->borderwidth;
	else
		v = TKF2I(x) + tk->borderwidth;

	v -= tks->pix;
	x = tks->pixmax-tks->pixmin;
	if (x!=tks->sl)
		v = tks->base + (vlong)v * (tks->to-tks->from)/(x-tks->sl);
	else
		v = tks->base;
	if(tks->res > 0) {
		int a = tks->res / 2;
		if (v < 0)
			a = -a;
		v = ((v+a)/tks->res)*tks->res;
	}

	tks->value = v;
	tkscalecheckvalue(tk);

	if(tks->command != nil && tks->jump != BoolT) {
		tkfprint(f, tks->value);
		snprint(buf, sizeof(buf), "%s %s", tks->command, f);
		e = tkexec(tk->env->top, buf, nil);
	}
	tk->dirty = tkrect(tk, 1);
	return e;
}
Пример #7
0
Файл: cline.c Проект: 8l/inferno
void
tkcvslinedraw(Image *img, TkCitem *i, TkEnv *pe)
{
	int w;
	Point *p;
	TkCline *l;
	Image *pen;

	USED(pe);

	l = TKobj(TkCline, i);

	pen = l->pen;
	if(pen == nil)
		pen = tkgc(i->env, TkCforegnd);

	w = TKF2I(l->width)/2;
	if(w < 0)
		return;

	p = i->p.drawpt;
	if(l->smooth == BoolT && i->p.npoint >= 3)
		bezspline(img, p, i->p.npoint, l->arrowf, l->arrowl, w, pen, p[0]);
	else
		poly(img, p, i->p.npoint, l->arrowf, l->arrowl, w, pen, p[0]);
}
Пример #8
0
Файл: scale.c Проект: 8l/inferno
char*
tkscale(TkTop *t, char *arg, char **ret)
{
	Tk *tk;
	char *e;
	TkName *names;
	TkScale *tks;
	TkOptab tko[3];

	tk = tknewobj(t, TKscale, sizeof(Tk)+sizeof(TkScale));
	if(tk == nil)
		return TkNomem;

	tk->flag |= Tktakefocus;
	tks = TKobj(TkScale, tk);
	tks->res = TKI2F(1);
	tks->to = TKI2F(100);
	tks->len = ScaleLen;
	tks->orient = Tkvertical;
	tks->relief = TKraised;
	tks->sl = ScaleSlider;
	tks->sv = BoolT;
	tks->bigi = 0;

	tko[0].ptr = tk;
	tko[0].optab = tkgeneric;
	tko[1].ptr = tks;
	tko[1].optab = opts;
	tko[2].ptr = nil;

	names = nil;
	e = tkparse(t, arg, tko, &names);
	if(e != nil) {
		tkfreeobj(tk);
		return e;
	}
	tksettransparent(tk, tkhasalpha(tk->env, TkCbackgnd));
	tkscalecheckvalue(tk);
	tksizescale(tk);
	if (tks->bigi == 0)
		tks->bigi = TKI2F(TKF2I(tks->to - tks->from) / 10);
	e = tkbindings(t, tk, b, nelem(b));

	if(e != nil) {
		tkfreeobj(tk);
		return e;
	}

	e = tkaddchild(t, tk, &names);
	tkfreename(names);
	if(e != nil) {
		tkfreeobj(tk);
		return e;
	}
	tk->name->link = nil;

	return tkvalue(ret, "%s", tk->name->name);
}
Пример #9
0
Файл: scrol.c Проект: 8l/inferno
static void
tkhscroll(Tk *tk, TkScroll *tks, Image *i, Point size)
{
	TkEnv *e;
	Point p[3], o;
	int bo, w, h, triangle;

	e = tk->env;

	triangle = tk->act.height - Elembw;

	bo = tk->borderwidth + Elembw;
	p[0].x = bo;
	p[0].y = size.y/2;
	p[1].x = p[0].x + triangle;
	p[1].y = p[0].y - triangle/2 + 1;
	p[2].x = p[0].x + triangle;
	p[2].y = p[0].y + triangle/2 - 2;
	drawarrow(tks, i, p, e, ActiveA1, ButtonA1);

	tks->a1 = p[2].x;
	w = p[2].x + Elembw;

	p[0].x = size.x - bo - 1;
	p[1].x = p[0].x - triangle;
	p[2].x = p[0].x - triangle;
	drawarrow(tks, i, p, e, ActiveA2, ButtonA2);

	tks->a2 = p[2].x;

	o.x = bo + triangle + 2*Elembw;
	o.y = tk->borderwidth;
	w = p[2].x - 2*Elembw - w - 2*tk->borderwidth;
	h = size.y - 2*bo;

	o.x += TKF2I(tks->top*w);
	w *= tks->bot - tks->top;
	w = TKF2I(w);

	tks->t1 = o.x - Elembw;
	tks->t2 = o.x + w + Elembw;

	drawslider(tks, i, o, w, h, e);
}
Пример #10
0
Файл: scrol.c Проект: 8l/inferno
static void
tkvscroll(Tk *tk, TkScroll *tks, Image *i, Point size)
{
	TkEnv *e;
	Point p[3], o;
	int bo, w, h, triangle;

	e = tk->env;

	triangle = tk->act.width - Elembw;

	bo = tk->borderwidth + Elembw;
	p[0].x = size.x/2;
	p[0].y = bo;
	p[1].x = p[0].x - triangle/2;
	p[1].y = p[0].y + triangle;
	p[2].x = p[0].x + triangle/2;
	p[2].y = p[0].y + triangle;
	drawarrow(tks, i, p, e, ActiveA1, ButtonA1);

	tks->a1 = p[2].y;
	h = p[2].y + Elembw;

	p[0].y = size.y - bo - 1;
	p[1].y = p[0].y - triangle;
	p[2].y = p[0].y - triangle;
	drawarrow(tks, i, p, e, ActiveA2, ButtonA2);

	tks->a2 = p[2].y;

	o.x = tk->borderwidth ;
	o.y = bo + triangle + 2*Elembw;
	w = size.x - 2*bo;
	h = p[2].y - 2*Elembw - h - 2*tk->borderwidth;

	o.y += TKF2I(tks->top*h);
	h *= tks->bot - tks->top;
	h = TKF2I(h);

	tks->t1 = o.y - Elembw;
	tks->t2 = o.y + h + Elembw;

	drawslider(tks, i, o, w, h, e);
}
Пример #11
0
Файл: canvs.c Проект: 8l/inferno
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;
}
Пример #12
0
Файл: canvs.c Проект: 8l/inferno
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;
}
Пример #13
0
Файл: canvs.c Проект: 8l/inferno
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;
}
Пример #14
0
Файл: scale.c Проект: 8l/inferno
char*
tkscaleposn(TkEnv *env, Tk *tk, char *arg, int *z)
{
	int x, y;
	TkScale *tks = TKobj(TkScale, tk);
	char *e;

	e = tkfracword(env->top, &arg, &x, env);
	if(e != nil)
		return e;
	e = tkfracword(env->top, &arg, &y, env);
	if(e != nil)
		return e;

	x = TKF2I(x) + tk->borderwidth;
	y = TKF2I(y) + tk->borderwidth;

	if(tks->orient == Tkvertical) {
		if(z != nil) {
			z[0] = x;
			z[1] = y;
		}
		x = y;
	}
	else {
		if(z != nil) {
			z[0] = y;
			z[1] = x;
		}
	}
	if(x > tks->pixmin && x < tks->pixpos)
		return trough1;
	else if(x >= tks->pixpos && x < tks->pixpos+tks->sl+2*ScaleBW)
		return slider;
	else if(x >= tks->pixpos+tks->sl+2*ScaleBW && x < tks->pixmax)
		return trough2;

	return "";
}
Пример #15
0
Файл: cwind.c Проект: 8l/inferno
char*
tkcvswindcoord(TkCitem *i, char *arg, int x, int y)
{
	char *e;
	TkCpoints p;
/*
	TkCwind *w;
	int xi, yi;
*/

	if(arg == nil) {
		tkxlatepts(i->p.parampt, i->p.npoint, x, y);
		tkxlatepts(i->p.drawpt, i->p.npoint, TKF2I(x), TKF2I(y));
		tkcvswindsize(i);
/*
		w = TKobj(TkCwind, i);
		xi = TKF2I(x);
		yi = TKF2I(y);
		if (w->sub != nil) {
			w->sub->act.x += xi;
			w->sub->act.y += yi;
		}
		i->p.bb = rectaddpt(i->p.bb, Pt(xi, yi));
*/
	}
	else {
		e = tkparsepts(i->env->top, &p, &arg, 0);
		if(e != nil)
			return e;
		if(p.npoint != 1) {
			tkfreepoint(&p);
			return TkFewpt;
		}
		tkfreepoint(&i->p);
		i->p = p;
		tkcvswindsize(i);
	}
	return nil;
}
Пример #16
0
Файл: crect.c Проект: 8l/inferno
void
tkcvsrectsize(TkCitem *i)
{
	TkCrect *r;
	int w;

	r = TKobj(TkCrect, i);
	w = TKF2I(r->width)*2;

	i->p.bb = bbnil;
	tkpolybound(i->p.drawpt, i->p.npoint, &i->p.bb);
	i->p.bb = insetrect(i->p.bb, -w);
}
Пример #17
0
Файл: scale.c Проект: 8l/inferno
static char*
tkscaleget(Tk *tk, char *arg, char **val)
{
	int x, y, value, v, l;
	char buf[Tkminitem], *e;
	TkScale *tks = TKobj(TkScale, tk);

	value = tks->value;
	if(arg[0] != '\0') {
		e = tkfracword(tk->env->top, &arg, &x, tk->env);
		if (e != nil)
			return e;
		e = tkfracword(tk->env->top, &arg, &y, tk->env);
		if (e != nil)
			return e;
		if(tks->orient == Tkvertical)
			v = TKF2I(y) + tk->borderwidth;
		else
			v = TKF2I(x) + tk->borderwidth;

		if(v < tks->pixmin)
			value = tks->from;
		else
		if(v > tks->pixmax)
			value = tks->to;
		else {
			l = tks->pixmax-tks->pixmin;
			value = 0;
			if (l!=0)
				value = v * ((tks->to-tks->from)/l);
			value += tks->from;
		}
		if(tks->res > 0)
			value = (value/tks->res)*tks->res;
	}
	tkfprint(buf, value);
	return tkvalue(val, "%s", buf);
}
Пример #18
0
Файл: canvs.c Проект: 8l/inferno
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;
}
Пример #19
0
Файл: cline.c Проект: 8l/inferno
int
tkcvslinehit(TkCitem *i, Point p)
{
	TkCline *l;
	int w, np, r;
	Point *pp;

	l = TKobj(TkCline, i);
	w =TKF2I(l->width) + 2;	/* 2 for slop */

	if (l->smooth == BoolT) {
		np = getbezsplinepts(i->p.drawpt, i->p.npoint, &pp);
		r = tklinehit(pp, np, w, p);
		free(pp);
	} else
		r = tklinehit(i->p.drawpt, i->p.npoint, w, p);
	return r;
}
Пример #20
0
Файл: canvs.c Проект: 8l/inferno
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;

}
Пример #21
0
static char*
tkentryxview(Tk *tk, char *arg, char **val)
{
	int locked;
	TkEnv *env;
	TkEntry *tke;
	char *buf, *v;
	int dx, top, bot, amount, ix, x;
	char *e;

	tke = TKobj(TkEntry, tk);
	env = tk->env;
	dx = tk->act.width - 2*xinset(tk);

	buf = mallocz(Tkmaxitem, 0);
	if(buf == nil)
		return TkNomem;

	if(*arg == '\0') {
		if (tke->textlen == 0 || tke->xlen < dx) {
			bot = TKI2F(0);
			top = TKI2F(1);
		} else {
			bot = TKI2F(tke->x0) / tke->xlen;
			top = TKI2F(tke->x0 + dx) / tke->xlen;
		}
		v = tkfprint(buf, bot);
		*v++ = ' ';
		tkfprint(v, top);
		e = tkvalue(val, "%s", buf);
		free(buf);
		return e;
	}

	arg = tkitem(buf, arg);
	if(strcmp(buf, "moveto") == 0) {
		e = tkfracword(env->top, &arg, &top, nil);
		if (e != nil) {
			free(buf);
			return e;
		}
		tke->x0 = TKF2I(top*tke->xlen);
	}
	else
	if(strcmp(buf, "scroll") == 0) {
		arg = tkitem(buf, arg);
		amount = atoi(buf);
		if(*arg == 'p')		/* Pages */
			amount *= (9*tke->xlen)/10;
		else
		if(*arg == 's') {		/* Inferno-ism, "scr", must be used in the context of button2p */
			x = amount;
			amount = x < tke->oldx ? env->wzero : (x > tke->oldx ? -env->wzero : 0);
			tke->oldx = x;
		}
		tke->x0 += amount;
	}
	else {
		e = tkentryparseindex(tk, buf, &ix);
		if(e != nil) {
			free(buf);
			return e;
		}
		locked = lockdisplay(env->top->display);
		tke->x0 = entrytextwidth(tk, ix);
		if (locked)
			unlockdisplay(env->top->display);
	}
	free(buf);

	if (tke->x0 > tke->xlen - dx)
		tke->x0 = tke->xlen - dx;
	if (tke->x0 < 0)
		tke->x0 = 0;
	recalcentry(tk);
	e = tkentrysh(tk);
	blinkreset(tk);
	tk->dirty = tkrect(tk, 1);
	return e;
}
Пример #22
0
Файл: canvs.c Проект: 8l/inferno
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;
}