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 /* Oval Options (+ means implemented)
10 +fill
11 +outline
12 +stipple
13 +tags
14 +width
15 */
16
17 typedef struct TkCoval TkCoval;
18 struct TkCoval
19 {
20 int width;
21 Image* stipple;
22 Image* pen;
23 TkCanvas* canv;
24 };
25
26 static
27 TkOption ovalopts[] =
28 {
29 "width", OPTnnfrac, O(TkCoval, width), nil, /* XXX should be nnfrac */
30 "stipple", OPTbmap, O(TkCoval, stipple), nil,
31 nil
32 };
33
34 static
35 TkOption itemopts[] =
36 {
37 "tags", OPTctag, O(TkCitem, tags), nil,
38 "fill", OPTcolr, O(TkCitem, env), IAUX(TkCfill),
39 "outline", OPTcolr, O(TkCitem, env), IAUX(TkCforegnd),
40 nil
41 };
42
43 void
tkcvsovalsize(TkCitem * i)44 tkcvsovalsize(TkCitem *i)
45 {
46 int w;
47 TkCoval *o;
48
49 o = TKobj(TkCoval, i);
50 w = TKF2I(o->width)*2;
51
52 i->p.bb = bbnil;
53 tkpolybound(i->p.drawpt, i->p.npoint, &i->p.bb);
54 i->p.bb = insetrect(i->p.bb, -w);
55 }
56
57 char*
tkcvsovalcreat(Tk * tk,char * arg,char ** val)58 tkcvsovalcreat(Tk* tk, char *arg, char **val)
59 {
60 char *e;
61 TkCoval *o;
62 TkCitem *i;
63 TkCanvas *c;
64 TkOptab tko[3];
65
66 c = TKobj(TkCanvas, tk);
67
68 i = tkcnewitem(tk, TkCVoval, sizeof(TkCitem)+sizeof(TkCoval));
69 if(i == nil)
70 return TkNomem;
71
72 o = TKobj(TkCoval, i);
73 o->width = TKI2F(1);
74 o->canv = c;
75 e = tkparsepts(tk->env->top, &i->p, &arg, 0);
76 if(e != nil) {
77 tkcvsfreeitem(i);
78 return e;
79 }
80 if(i->p.npoint != 2) {
81 tkcvsfreeitem(i);
82 return TkFewpt;
83 }
84
85 tko[0].ptr = o;
86 tko[0].optab = ovalopts;
87 tko[1].ptr = i;
88 tko[1].optab = itemopts;
89 tko[2].ptr = nil;
90 e = tkparse(tk->env->top, arg, tko, nil);
91 if(e != nil) {
92 tkcvsfreeitem(i);
93 return e;
94 }
95 e = tkcaddtag(tk, i, 1);
96 if(e != nil) {
97 tkcvsfreeitem(i);
98 return e;
99 }
100
101 tkcvsovalsize(i);
102
103 e = tkvalue(val, "%d", i->id);
104 if(e != nil) {
105 tkcvsfreeitem(i);
106 return e;
107 }
108
109 tkcvsappend(c, i);
110 tkbbmax(&c->update, &i->p.bb);
111 tkmkpen(&o->pen, i->env, o->stipple);
112 tkcvssetdirty(tk);
113 return nil;
114 }
115
116 char*
tkcvsovalcget(TkCitem * i,char * arg,char ** val)117 tkcvsovalcget(TkCitem *i, char *arg, char **val)
118 {
119 TkOptab tko[3];
120 TkCoval *o = TKobj(TkCoval, i);
121
122 tko[0].ptr = o;
123 tko[0].optab = ovalopts;
124 tko[1].ptr = i;
125 tko[1].optab = itemopts;
126 tko[2].ptr = nil;
127
128 return tkgencget(tko, arg, val, i->env->top);
129 }
130
131 char*
tkcvsovalconf(Tk * tk,TkCitem * i,char * arg)132 tkcvsovalconf(Tk *tk, TkCitem *i, char *arg)
133 {
134 char *e;
135 TkOptab tko[3];
136 TkCoval *o = TKobj(TkCoval, i);
137
138 tko[0].ptr = o;
139 tko[0].optab = ovalopts;
140 tko[1].ptr = i;
141 tko[1].optab = itemopts;
142 tko[2].ptr = nil;
143
144 e = tkparse(tk->env->top, arg, tko, nil);
145 tkcvsovalsize(i);
146 tkmkpen(&o->pen, i->env, o->stipple);
147
148 return e;
149 }
150
151 void
tkcvsovalfree(TkCitem * i)152 tkcvsovalfree(TkCitem *i)
153 {
154 TkCoval *o;
155
156 o = TKobj(TkCoval, i);
157 if(o->stipple)
158 freeimage(o->stipple);
159 if(o->pen)
160 freeimage(o->pen);
161 }
162
163 void
tkcvsovaldraw(Image * img,TkCitem * i,TkEnv * pe)164 tkcvsovaldraw(Image *img, TkCitem *i, TkEnv *pe)
165 {
166 Point c;
167 TkEnv *e;
168 Image *pen;
169 TkCoval *o;
170 Rectangle d;
171 int w, dx, dy;
172
173 USED(pe);
174
175 d.min = i->p.drawpt[0];
176 d.max = i->p.drawpt[1];
177
178 e = i->env;
179 o = TKobj(TkCoval, i);
180
181 pen = o->pen;
182 if(pen == nil && (e->set & (1<<TkCfill)))
183 pen = tkgc(e, TkCfill);
184
185 w = TKF2I(o->width)/2;
186 if(w < 0)
187 return;
188
189 d = canonrect(d);
190 dx = Dx(d)/2;
191 dy = Dy(d)/2;
192 c.x = d.min.x + dx;
193 c.y = d.min.y + dy;
194 if(pen != nil)
195 fillellipse(img, c, dx, dy, pen, c);
196 ellipse(img, c, dx, dy, w, tkgc(e, TkCforegnd), c);
197 }
198
199 char*
tkcvsovalcoord(TkCitem * i,char * arg,int x,int y)200 tkcvsovalcoord(TkCitem *i, char *arg, int x, int y)
201 {
202 char *e;
203 TkCpoints p;
204
205 if(arg == nil) {
206 tkxlatepts(i->p.parampt, i->p.npoint, x, y);
207 tkxlatepts(i->p.drawpt, i->p.npoint, TKF2I(x), TKF2I(y));
208 i->p.bb = rectaddpt(i->p.bb, Pt(TKF2I(x), TKF2I(y)));
209 }
210 else {
211 e = tkparsepts(i->env->top, &p, &arg, 0);
212 if(e != nil)
213 return e;
214 if(p.npoint != 2) {
215 tkfreepoint(&p);
216 return TkFewpt;
217 }
218 tkfreepoint(&i->p);
219 i->p = p;
220 tkcvsovalsize(i);
221 }
222 return nil;
223 }
224
225 int
tkcvsovalhit(TkCitem * i,Point p)226 tkcvsovalhit(TkCitem *i, Point p)
227 {
228 TkCoval *o;
229 int w, dx, dy;
230 Rectangle d;
231 vlong v;
232
233 o = TKobj(TkCoval, i);
234 w = TKF2I(o->width)/2;
235 d = canonrect(Rpt(i->p.drawpt[0], i->p.drawpt[1]));
236 d = insetrect(d, -(w/2 + 1));
237
238 dx = Dx(d)/2;
239 dy = Dy(d)/2;
240
241 p.x -= d.min.x + dx;
242 p.y -= d.min.y + dy;
243
244 dx *= dx;
245 dy *= dy;
246
247 /* XXX can we do this nicely without overflow and without vlongs? */
248 v = (vlong)(p.x*p.x)*dy;
249 v += (vlong)(p.y*p.y)*dx;
250 return v < (vlong)dx*dy;
251 }
252