xref: /inferno-os/libtk/coval.c (revision 7781741266783e4df3b35d42a55e8e504838898b)
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