ref: c0cbe87b357a4464a7d10ab8f38a65c77ea3b629
dir: /libtk/carcs.c/
#include "lib9.h" #include "draw.h" #include "tk.h" #include "canvs.h" #define O(t, e) ((long)(&((t*)0)->e)) typedef void (*Drawfn)(Image*, Point, int, int, Image*, int); /* Arc Options (+ means implemented) +extent +fill +outline outlinestipple +start +stipple +style (+pieslice chord +arc) +tags +width */ typedef struct TkCarc TkCarc; struct TkCarc { int width; int start; int extent; int style; Image* stipple; Image* pen; }; enum Style { Pieslice, Chord, Arc }; static TkStab tkstyle[] = { "pieslice", Pieslice, "arc", Arc, "chord", Arc, /* Can't do chords */ nil }; static TkOption arcopts[] = { "start", OPTfrac, O(TkCarc, start), nil, "extent", OPTfrac, O(TkCarc, extent), nil, "style", OPTstab, O(TkCarc, style), tkstyle, "width", OPTnnfrac, O(TkCarc, width), nil, "stipple", OPTbmap, O(TkCarc, stipple), nil, nil }; static TkOption itemopts[] = { "tags", OPTctag, O(TkCitem, tags), nil, "fill", OPTcolr, O(TkCitem, env), IAUX(TkCfill), "outline", OPTcolr, O(TkCitem, env), IAUX(TkCforegnd), nil }; void tkcvsarcsize(TkCitem *i) { int w; TkCarc *a; a = TKobj(TkCarc, i); w = TKF2I(a->width)*2; i->p.bb = bbnil; tkpolybound(i->p.drawpt, i->p.npoint, &i->p.bb); i->p.bb = insetrect(i->p.bb, -w); } char* tkcvsarccreat(Tk* tk, char *arg, char **val) { char *e; TkCarc *a; TkCitem *i; TkCanvas *c; TkOptab tko[3]; c = TKobj(TkCanvas, tk); i = tkcnewitem(tk, TkCVarc, sizeof(TkCitem)+sizeof(TkCarc)); if(i == nil) return TkNomem; a = TKobj(TkCarc, i); a->width = TKI2F(1); e = tkparsepts(tk->env->top, &i->p, &arg, 0); if(e != nil) { tkcvsfreeitem(i); return e; } if(i->p.npoint != 2) { tkcvsfreeitem(i); return TkFewpt; } tko[0].ptr = a; tko[0].optab = arcopts; tko[1].ptr = i; tko[1].optab = itemopts; tko[2].ptr = nil; e = tkparse(tk->env->top, arg, tko, nil); if(e != nil) { tkcvsfreeitem(i); return e; } e = tkcaddtag(tk, i, 1); if(e != nil) { tkcvsfreeitem(i); return e; } tkcvsarcsize(i); tkmkpen(&a->pen, i->env, a->stipple); tkcvsappend(c, i); tkbbmax(&c->update, &i->p.bb); tkcvssetdirty(tk); return tkvalue(val, "%d", i->id); } char* tkcvsarccget(TkCitem *i, char *arg, char **val) { TkOptab tko[3]; TkCarc *a = TKobj(TkCarc, i); tko[0].ptr = a; tko[0].optab = arcopts; tko[1].ptr = i; tko[1].optab = itemopts; tko[2].ptr = nil; return tkgencget(tko, arg, val, i->env->top); } char* tkcvsarcconf(Tk *tk, TkCitem *i, char *arg) { char *e; TkOptab tko[3]; TkCarc *a = TKobj(TkCarc, i); tko[0].ptr = a; tko[0].optab = arcopts; tko[1].ptr = i; tko[1].optab = itemopts; tko[2].ptr = nil; e = tkparse(tk->env->top, arg, tko, nil); tkcvsarcsize(i); tkmkpen(&a->pen, i->env, a->stipple); return e; } void tkcvsarcfree(TkCitem *i) { TkCarc *a; a = TKobj(TkCarc, i); if(a->stipple) freeimage(a->stipple); if(a->pen) freeimage(a->pen); } void tkcvsarcdraw(Image *img, TkCitem *i, TkEnv *pe) { TkEnv *e; TkCarc *a; Rectangle d; int w, dx, dy; int s, ext, s0, s1, e0, e1, l; Image *pen, *col, *tmp; Point p0, p1, c; extern void drawarc(Point,int,int,int,int,int,Image *,Image *,Image *); USED(pe); d.min = i->p.drawpt[0]; d.max = i->p.drawpt[1]; e = i->env; a = TKobj(TkCarc, i); pen = a->pen; if(pen == nil && (e->set & (1<<TkCfill))) pen = tkgc(e, TkCfill); w = TKF2I(a->width)/2; if(w < 0) return; d = canonrect(d); dx = Dx(d)/2; dy = Dy(d)/2; c.x = (d.min.x+d.max.x)/2; c.y = (d.min.y+d.max.y)/2; s = TKF2I(a->start); ext = TKF2I(a->extent); /* if(ext == 0) ext = 90; */ if(a->style != Arc && pen != nil) fillarc(img, c, dx, dy, pen, Pt(0,0), s, ext); col = tkgc(e, TkCforegnd); arc(img, c, dx, dy, w, col, Pt(0,0), s, ext); if(a->style == Pieslice){ /* * It is difficult to compute the intersection of the lines * and the ellipse using integers, so let the draw library * do it for us: use a full ellipse as the source of color * for drawing the lines. */ tmp = allocimage(img->display, d, img->chan, 0, DNofill); if(tmp == nil) return; /* copy dest to tmp so lines don't spill beyond edge of ellipse */ drawop(tmp, d, img, nil, d.min, S); fillellipse(tmp, c, dx, dy, col, Pt(0,0)); icossin(s, &s1, &s0); icossin(s+ext, &e1, &e0); if(dx > dy) l = 2*dx+1; else l = 2*dy+1; p0 = Pt(c.x+l*s1/ICOSSCALE, c.y-l*s0/ICOSSCALE); p1 = Pt(c.x+l*e1/ICOSSCALE, c.y-l*e0/ICOSSCALE); line(img, c, p0, Endsquare, Endsquare, w, tmp, c); line(img, c, p1, Endsquare, Endsquare, w, tmp, c); freeimage(tmp); } } char* tkcvsarccoord(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 != 2) { tkfreepoint(&p); return TkFewpt; } tkfreepoint(&i->p); i->p = p; tkcvsarcsize(i); } return nil; }