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
tkcvspolysize(TkCitem * i)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*
tkcvspolycreat(Tk * tk,char * arg,char ** val)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*
tkcvspolycget(TkCitem * i,char * arg,char ** val)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*
tkcvspolyconf(Tk * tk,TkCitem * i,char * arg)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
tkcvspolyfree(TkCitem * i)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
tkcvspolydraw(Image * img,TkCitem * i,TkEnv * pe)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*
tkcvspolycoord(TkCitem * i,char * arg,int x,int y)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
tkcvspolyhit(TkCitem * item,Point p)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