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 8 typedef struct TkCpoly TkCpoly; 9 struct TkCpoly 10 { 11 int width; 12 Image* stipple; 13 Image* pen; 14 TkCanvas* canv; 15 int smooth; 16 int steps; 17 int winding; 18 }; 19 20 static 21 TkStab tkwinding[] = 22 { 23 "nonzero", ~0, 24 "odd", 1, 25 nil 26 }; 27 28 /* Polygon Options (+ means implemented) 29 +fill 30 +smooth 31 +splinesteps 32 +stipple 33 +tags 34 +width 35 +outline 36 */ 37 static 38 TkOption polyopts[] = 39 { 40 "width", OPTnnfrac, O(TkCpoly, width), nil, 41 "stipple", OPTbmap, O(TkCpoly, stipple), nil, 42 "smooth", OPTstab, O(TkCpoly, smooth), tkbool, 43 "splinesteps", OPTdist, O(TkCpoly, steps), nil, 44 "winding", OPTstab, O(TkCpoly, winding), tkwinding, 45 nil 46 }; 47 48 static 49 TkOption itemopts[] = 50 { 51 "tags", OPTctag, O(TkCitem, tags), nil, 52 "fill", OPTcolr, O(TkCitem, env), IAUX(TkCfill), 53 "outline", OPTcolr, O(TkCitem, env), IAUX(TkCforegnd), 54 nil 55 }; 56 57 void 58 tkcvspolysize(TkCitem *i) 59 { 60 int w; 61 TkCpoly *p; 62 63 p = TKobj(TkCpoly, i); 64 w = TKF2I(p->width); 65 66 i->p.bb = bbnil; 67 tkpolybound(i->p.drawpt, i->p.npoint, &i->p.bb); 68 i->p.bb = insetrect(i->p.bb, -w); 69 } 70 71 char* 72 tkcvspolycreat(Tk* tk, char *arg, char **val) 73 { 74 char *e; 75 TkCpoly *p; 76 TkCitem *i; 77 TkCanvas *c; 78 TkOptab tko[3]; 79 80 c = TKobj(TkCanvas, tk); 81 82 i = tkcnewitem(tk, TkCVpoly, sizeof(TkCitem)+sizeof(TkCpoly)); 83 if(i == nil) 84 return TkNomem; 85 86 p = TKobj(TkCpoly, i); 87 p->width = TKI2F(1); 88 p->winding = ~0; 89 90 e = tkparsepts(tk->env->top, &i->p, &arg, 1); 91 if(e == nil && i->p.npoint < 3) 92 e = TkBadvl; 93 if(e != nil) { 94 tkcvsfreeitem(i); 95 return e; 96 } 97 98 tko[0].ptr = p; 99 tko[0].optab = polyopts; 100 tko[1].ptr = i; 101 tko[1].optab = itemopts; 102 tko[2].ptr = nil; 103 e = tkparse(tk->env->top, arg, tko, nil); 104 if(e != nil) { 105 tkcvsfreeitem(i); 106 return e; 107 } 108 p->canv = c; 109 110 e = tkcaddtag(tk, i, 1); 111 if(e != nil) { 112 tkcvsfreeitem(i); 113 return e; 114 } 115 116 tkcvspolysize(i); 117 tkmkpen(&p->pen, i->env, p->stipple); 118 119 e = tkvalue(val, "%d", i->id); 120 if(e != nil) { 121 tkcvsfreeitem(i); 122 return e; 123 } 124 125 tkcvsappend(c, i); 126 tkbbmax(&c->update, &i->p.bb); 127 tkcvssetdirty(tk); 128 return nil; 129 } 130 131 char* 132 tkcvspolycget(TkCitem *i, char *arg, char **val) 133 { 134 TkOptab tko[3]; 135 TkCpoly *p = TKobj(TkCpoly, i); 136 137 tko[0].ptr = p; 138 tko[0].optab = polyopts; 139 tko[1].ptr = i; 140 tko[1].optab = itemopts; 141 tko[2].ptr = nil; 142 143 return tkgencget(tko, arg, val, i->env->top); 144 } 145 146 char* 147 tkcvspolyconf(Tk *tk, TkCitem *i, char *arg) 148 { 149 char *e; 150 TkOptab tko[3]; 151 TkCpoly *p = TKobj(TkCpoly, i); 152 153 tko[0].ptr = p; 154 tko[0].optab = polyopts; 155 tko[1].ptr = i; 156 tko[1].optab = itemopts; 157 tko[2].ptr = nil; 158 159 e = tkparse(tk->env->top, arg, tko, nil); 160 161 tkcvspolysize(i); 162 tkmkpen(&p->pen, i->env, p->stipple); 163 164 return e; 165 } 166 167 void 168 tkcvspolyfree(TkCitem *i) 169 { 170 TkCpoly *p; 171 172 p = TKobj(TkCpoly, i); 173 if(p->stipple) 174 freeimage(p->stipple); 175 if(p->pen) 176 freeimage(p->pen); 177 } 178 179 void 180 tkcvspolydraw(Image *img, TkCitem *i, TkEnv *pe) 181 { 182 int w; 183 TkEnv *e; 184 TkCpoly *p; 185 Image *pen; 186 Point *pts; 187 188 USED(pe); 189 190 p = TKobj(TkCpoly, i); 191 192 e = i->env; 193 194 pen = p->pen; 195 if(pen == nil && (e->set & (1<<TkCfill))) 196 pen = tkgc(e, TkCfill); 197 198 pts = i->p.drawpt; 199 if(i->p.npoint > 0 && pen != nil) { 200 if (p->smooth == BoolT) 201 fillbezspline(img, pts, i->p.npoint+1, p->winding, pen, pts[0]); 202 else 203 fillpoly(img, pts, i->p.npoint+1, p->winding, pen, pts[0]); 204 } 205 206 w = TKF2I(p->width) - 1; 207 if(w >= 0 && (e->set & (1<<TkCforegnd))) { 208 pen = tkgc(i->env, TkCforegnd); 209 if (p->smooth == BoolT) 210 bezspline(img, pts, i->p.npoint+1, Enddisc, Enddisc, w, pen, pts[0]); 211 else 212 poly(img, pts, i->p.npoint+1, Enddisc, Enddisc, w, pen, pts[0]); 213 } 214 } 215 216 char* 217 tkcvspolycoord(TkCitem *i, char *arg, int x, int y) 218 { 219 char *e; 220 TkCpoints p; 221 222 if(arg == nil) { 223 tkxlatepts(i->p.parampt, i->p.npoint, x, y); 224 tkxlatepts(i->p.drawpt, i->p.npoint, TKF2I(x), TKF2I(y)); 225 i->p.drawpt[i->p.npoint] = i->p.drawpt[0]; 226 i->p.bb = rectaddpt(i->p.bb, Pt(TKF2I(x), TKF2I(y))); 227 } 228 else { 229 e = tkparsepts(i->env->top, &p, &arg, 1); 230 if(e != nil) 231 return e; 232 if(p.npoint < 2) { 233 tkfreepoint(&p); 234 return TkFewpt; 235 } 236 tkfreepoint(&i->p); 237 i->p = p; 238 tkcvspolysize(i); 239 } 240 return nil; 241 } 242 243 int 244 tkcvspolyhit(TkCitem *item, Point p) 245 { 246 Point *poly; 247 int r, np, fill, w; 248 TkCpoly *l; 249 TkEnv *e; 250 251 l = TKobj(TkCpoly, item); 252 w = TKF2I(l->width) + 2; /* include some slop */ 253 e = item->env; 254 fill = e->set & (1<<TkCfill); 255 if (l->smooth == BoolT) { 256 /* this works but it's slow if used intensively... */ 257 np = getbezsplinepts(item->p.drawpt, item->p.npoint + 1, &poly); 258 if (fill) 259 r = tkinsidepoly(poly, np, l->winding, p); 260 else 261 r = tklinehit(poly, np, w, p); 262 free(poly); 263 } else { 264 if (fill) 265 r = tkinsidepoly(item->p.drawpt, item->p.npoint, l->winding, p); 266 else 267 r = tklinehit(item->p.drawpt, item->p.npoint + 1, w, p); 268 } 269 return r; 270 } 271