xref: /inferno-os/libtk/carcs.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 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