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
tkcvsarcsize(TkCitem * i)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*
tkcvsarccreat(Tk * tk,char * arg,char ** val)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*
tkcvsarccget(TkCitem * i,char * arg,char ** val)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*
tkcvsarcconf(Tk * tk,TkCitem * i,char * arg)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
tkcvsarcfree(TkCitem * i)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
tkcvsarcdraw(Image * img,TkCitem * i,TkEnv * pe)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*
tkcvsarccoord(TkCitem * i,char * arg,int x,int y)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