1 #include "lib9.h" 2 #include "draw.h" 3 #include "tk.h" 4 #include "canvs.h" 5 6 #define O(t, e) ((long)(&((t*)0)->e)) 7 typedef void (*Drawfn)(Image*, Point, int, int, Image*, int); 8 9 /* Arc Options (+ means implemented) 10 +extent 11 +fill 12 +outline 13 outlinestipple 14 +start 15 +stipple 16 +style (+pieslice chord +arc) 17 +tags 18 +width 19 */ 20 21 typedef struct TkCarc TkCarc; 22 struct TkCarc 23 { 24 int width; 25 int start; 26 int extent; 27 int style; 28 Image* stipple; 29 Image* pen; 30 }; 31 32 enum Style 33 { 34 Pieslice, 35 Chord, 36 Arc 37 }; 38 39 static 40 TkStab tkstyle[] = 41 { 42 "pieslice", Pieslice, 43 "arc", Arc, 44 "chord", Arc, /* Can't do chords */ 45 nil 46 }; 47 48 static 49 TkOption arcopts[] = 50 { 51 "start", OPTfrac, O(TkCarc, start), nil, 52 "extent", OPTfrac, O(TkCarc, extent), nil, 53 "style", OPTstab, O(TkCarc, style), tkstyle, 54 "width", OPTnnfrac, O(TkCarc, width), nil, 55 "stipple", OPTbmap, O(TkCarc, stipple), nil, 56 nil 57 }; 58 59 static 60 TkOption itemopts[] = 61 { 62 "tags", OPTctag, O(TkCitem, tags), nil, 63 "fill", OPTcolr, O(TkCitem, env), IAUX(TkCfill), 64 "outline", OPTcolr, O(TkCitem, env), IAUX(TkCforegnd), 65 nil 66 }; 67 68 void 69 tkcvsarcsize(TkCitem *i) 70 { 71 int w; 72 TkCarc *a; 73 74 a = TKobj(TkCarc, i); 75 w = TKF2I(a->width)*2; 76 77 i->p.bb = bbnil; 78 tkpolybound(i->p.drawpt, i->p.npoint, &i->p.bb); 79 i->p.bb = insetrect(i->p.bb, -w); 80 } 81 82 char* 83 tkcvsarccreat(Tk* tk, char *arg, char **val) 84 { 85 char *e; 86 TkCarc *a; 87 TkCitem *i; 88 TkCanvas *c; 89 TkOptab tko[3]; 90 91 c = TKobj(TkCanvas, tk); 92 93 i = tkcnewitem(tk, TkCVarc, sizeof(TkCitem)+sizeof(TkCarc)); 94 if(i == nil) 95 return TkNomem; 96 97 a = TKobj(TkCarc, i); 98 a->width = TKI2F(1); 99 100 e = tkparsepts(tk->env->top, &i->p, &arg, 0); 101 if(e != nil) { 102 tkcvsfreeitem(i); 103 return e; 104 } 105 if(i->p.npoint != 2) { 106 tkcvsfreeitem(i); 107 return TkFewpt; 108 } 109 110 tko[0].ptr = a; 111 tko[0].optab = arcopts; 112 tko[1].ptr = i; 113 tko[1].optab = itemopts; 114 tko[2].ptr = nil; 115 e = tkparse(tk->env->top, arg, tko, nil); 116 if(e != nil) { 117 tkcvsfreeitem(i); 118 return e; 119 } 120 121 e = tkcaddtag(tk, i, 1); 122 if(e != nil) { 123 tkcvsfreeitem(i); 124 return e; 125 } 126 127 tkcvsarcsize(i); 128 tkmkpen(&a->pen, i->env, a->stipple); 129 130 tkcvsappend(c, i); 131 132 tkbbmax(&c->update, &i->p.bb); 133 tkcvssetdirty(tk); 134 return tkvalue(val, "%d", i->id); 135 } 136 137 char* 138 tkcvsarccget(TkCitem *i, char *arg, char **val) 139 { 140 TkOptab tko[3]; 141 TkCarc *a = TKobj(TkCarc, i); 142 143 tko[0].ptr = a; 144 tko[0].optab = arcopts; 145 tko[1].ptr = i; 146 tko[1].optab = itemopts; 147 tko[2].ptr = nil; 148 149 return tkgencget(tko, arg, val, i->env->top); 150 } 151 152 char* 153 tkcvsarcconf(Tk *tk, TkCitem *i, char *arg) 154 { 155 char *e; 156 TkOptab tko[3]; 157 TkCarc *a = TKobj(TkCarc, i); 158 159 tko[0].ptr = a; 160 tko[0].optab = arcopts; 161 tko[1].ptr = i; 162 tko[1].optab = itemopts; 163 tko[2].ptr = nil; 164 165 e = tkparse(tk->env->top, arg, tko, nil); 166 tkcvsarcsize(i); 167 tkmkpen(&a->pen, i->env, a->stipple); 168 169 return e; 170 } 171 172 173 void 174 tkcvsarcfree(TkCitem *i) 175 { 176 TkCarc *a; 177 178 a = TKobj(TkCarc, i); 179 if(a->stipple) 180 freeimage(a->stipple); 181 if(a->pen) 182 freeimage(a->pen); 183 } 184 185 void 186 tkcvsarcdraw(Image *img, TkCitem *i, TkEnv *pe) 187 { 188 TkEnv *e; 189 TkCarc *a; 190 Rectangle d; 191 int w, dx, dy; 192 int s, ext, s0, s1, e0, e1, l; 193 Image *pen, *col, *tmp; 194 Point p0, p1, c; 195 extern void drawarc(Point,int,int,int,int,int,Image *,Image *,Image *); 196 197 USED(pe); 198 199 d.min = i->p.drawpt[0]; 200 d.max = i->p.drawpt[1]; 201 202 e = i->env; 203 a = TKobj(TkCarc, i); 204 205 pen = a->pen; 206 if(pen == nil && (e->set & (1<<TkCfill))) 207 pen = tkgc(e, TkCfill); 208 209 w = TKF2I(a->width)/2; 210 if(w < 0) 211 return; 212 213 d = canonrect(d); 214 dx = Dx(d)/2; 215 dy = Dy(d)/2; 216 c.x = (d.min.x+d.max.x)/2; 217 c.y = (d.min.y+d.max.y)/2; 218 s = TKF2I(a->start); 219 ext = TKF2I(a->extent); 220 /* 221 if(ext == 0) 222 ext = 90; 223 */ 224 225 if(a->style != Arc && pen != nil) 226 fillarc(img, c, dx, dy, pen, Pt(0,0), s, ext); 227 col = tkgc(e, TkCforegnd); 228 arc(img, c, dx, dy, w, col, Pt(0,0), s, ext); 229 if(a->style == Pieslice){ 230 /* 231 * It is difficult to compute the intersection of the lines 232 * and the ellipse using integers, so let the draw library 233 * do it for us: use a full ellipse as the source of color 234 * for drawing the lines. 235 */ 236 tmp = allocimage(img->display, d, img->chan, 0, DNofill); 237 if(tmp == nil) 238 return; 239 /* copy dest to tmp so lines don't spill beyond edge of ellipse */ 240 drawop(tmp, d, img, nil, d.min, S); 241 fillellipse(tmp, c, dx, dy, col, Pt(0,0)); 242 icossin(s, &s1, &s0); 243 icossin(s+ext, &e1, &e0); 244 if(dx > dy) 245 l = 2*dx+1; 246 else 247 l = 2*dy+1; 248 p0 = Pt(c.x+l*s1/ICOSSCALE, c.y-l*s0/ICOSSCALE); 249 p1 = Pt(c.x+l*e1/ICOSSCALE, c.y-l*e0/ICOSSCALE); 250 line(img, c, p0, Endsquare, Endsquare, w, tmp, c); 251 line(img, c, p1, Endsquare, Endsquare, w, tmp, c); 252 freeimage(tmp); 253 } 254 } 255 256 char* 257 tkcvsarccoord(TkCitem *i, char *arg, int x, int y) 258 { 259 char *e; 260 TkCpoints p; 261 262 if(arg == nil) { 263 tkxlatepts(i->p.parampt, i->p.npoint, x, y); 264 tkxlatepts(i->p.drawpt, i->p.npoint, TKF2I(x), TKF2I(y)); 265 i->p.bb = rectaddpt(i->p.bb, Pt(TKF2I(x), TKF2I(y))); 266 } 267 else { 268 e = tkparsepts(i->env->top, &p, &arg, 0); 269 if(e != nil) 270 return e; 271 if(p.npoint != 2) { 272 tkfreepoint(&p); 273 return TkFewpt; 274 } 275 tkfreepoint(&i->p); 276 i->p = p; 277 tkcvsarcsize(i); 278 } 279 return nil; 280 } 281