xref: /inferno-os/libtk/cpoly.c (revision d0e1d143ef6f03c75c008c7ec648859dd260cbab)
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