xref: /inferno-os/libtk/cline.c (revision 37da2899f40661e3e9631e497da8dc59b971cbd0)
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 /* Line Options (+ means implemented)
9 	+arrow
10 	+arrowshape
11 	+capstyle
12 	+fill
13 	 joinstyle
14 	+smooth
15 	+splinesteps
16 	+stipple
17 	+tags
18 	+width
19 */
20 
21 static
22 TkStab tklines[] =
23 {
24 	"none",		0,
25 	"first",	TkCarrowf,
26 	"last",		TkCarrowl,
27 	"both",		TkCarrowf|TkCarrowl,
28 	nil
29 };
30 
31 static
32 TkStab tkcapstyle[] =
33 {
34 	"butt",	Endsquare,
35 	"projecting",	Endsquare,
36 	"round",	Enddisc,
37 	nil
38 };
39 
40 static
41 TkOption lineopts[] =
42 {
43 	"arrow",	OPTstab,	O(TkCline, arrow),	tklines,
44 	"arrowshape",	OPTfrac,	O(TkCline, shape[0]),	IAUX(3),
45 	"width",	OPTnnfrac,	O(TkCline, width),	nil,
46 	"stipple",	OPTbmap,	O(TkCline, stipple),	nil,
47 	"smooth",	OPTstab,	O(TkCline, smooth),	tkbool,
48 	"splinesteps",	OPTdist,	O(TkCline, steps),	nil,
49 	"capstyle",	OPTstab,	O(TkCline, capstyle),	tkcapstyle,
50 	nil
51 };
52 
53 static
54 TkOption itemopts[] =
55 {
56 	"tags",		OPTctag,	O(TkCitem, tags),	nil,
57 	"fill",		OPTcolr,	O(TkCitem, env),	IAUX(TkCforegnd),
58 	nil
59 };
60 
61 void
tkcvslinesize(TkCitem * i)62 tkcvslinesize(TkCitem *i)
63 {
64 	TkCline *l;
65 	int j, w, as, shape[3], arrow;
66 
67 	l = TKobj(TkCline, i);
68 	w = TKF2I(l->width);
69 
70 	i->p.bb = bbnil;
71 	tkpolybound(i->p.drawpt, i->p.npoint, &i->p.bb);
72 
73 	l->arrowf = l->capstyle;
74 	l->arrowl = l->capstyle;
75 	if(l->arrow != 0) {
76 		as = w/3;
77 		if(as < 1)
78 			as = 1;
79 		for(j = 0; j < 3; j++) {
80 			shape[j] = l->shape[j];
81 			if(shape[j] == 0)
82 				shape[j] = as * cvslshape[j];
83 		}
84 		arrow = ARROW(TKF2I(shape[0]), TKF2I(shape[1]), TKF2I(shape[2]));
85 		if(l->arrow & TkCarrowf)
86 			l->arrowf = arrow;
87 		if(l->arrow & TkCarrowl)
88 			l->arrowl = arrow;
89 		w += shape[2];
90 	}
91 
92 	i->p.bb = insetrect(i->p.bb, -w);
93 }
94 
95 char*
tkcvslinecreat(Tk * tk,char * arg,char ** val)96 tkcvslinecreat(Tk* tk, char *arg, char **val)
97 {
98 	char *e;
99 	TkCline *l;
100 	TkCitem *i;
101 	TkCanvas *c;
102 	TkOptab tko[3];
103 
104 	c = TKobj(TkCanvas, tk);
105 
106 	i = tkcnewitem(tk, TkCVline, sizeof(TkCitem)+sizeof(TkCline));
107 	if(i == nil)
108 		return TkNomem;
109 
110 	l = TKobj(TkCline, i);
111 	l->width = TKI2F(1);
112 
113 	e = tkparsepts(tk->env->top, &i->p, &arg, 0);
114 	if(e != nil) {
115 		tkcvsfreeitem(i);
116 		return e;
117 	}
118 
119 	tko[0].ptr = l;
120 	tko[0].optab = lineopts;
121 	tko[1].ptr = i;
122 	tko[1].optab = itemopts;
123 	tko[2].ptr = nil;
124 	e = tkparse(tk->env->top, arg, tko, nil);
125 	if(e != nil) {
126 		tkcvsfreeitem(i);
127 		return e;
128 	}
129 	tkmkpen(&l->pen, i->env, l->stipple);
130 
131 	e = tkcaddtag(tk, i, 1);
132 	if(e != nil) {
133 		tkcvsfreeitem(i);
134 		return e;
135 	}
136 
137 	tkcvslinesize(i);
138 	e = tkvalue(val, "%d", i->id);
139 	if(e != nil) {
140 		tkcvsfreeitem(i);
141 		return e;
142 	}
143 	tkcvsappend(c, i);
144 
145 	tkbbmax(&c->update, &i->p.bb);
146 	tkcvssetdirty(tk);
147 	return nil;
148 }
149 
150 char*
tkcvslinecget(TkCitem * i,char * arg,char ** val)151 tkcvslinecget(TkCitem *i, char *arg, char **val)
152 {
153 	TkOptab tko[3];
154 	TkCline *l = TKobj(TkCline, i);
155 
156 	tko[0].ptr = l;
157 	tko[0].optab = lineopts;
158 	tko[1].ptr = i;
159 	tko[1].optab = itemopts;
160 	tko[2].ptr = nil;
161 
162 	return tkgencget(tko, arg, val, i->env->top);
163 }
164 
165 char*
tkcvslineconf(Tk * tk,TkCitem * i,char * arg)166 tkcvslineconf(Tk *tk, TkCitem *i, char *arg)
167 {
168 	char *e;
169 	TkOptab tko[3];
170 	TkCline *l = TKobj(TkCline, i);
171 
172 	tko[0].ptr = l;
173 	tko[0].optab = lineopts;
174 	tko[1].ptr = i;
175 	tko[1].optab = itemopts;
176 	tko[2].ptr = nil;
177 
178 	e = tkparse(tk->env->top, arg, tko, nil);
179 
180 	tkmkpen(&l->pen, i->env, l->stipple);
181 	tkcvslinesize(i);
182 
183 	return e;
184 }
185 
186 void
tkcvslinefree(TkCitem * i)187 tkcvslinefree(TkCitem *i)
188 {
189 	TkCline *l;
190 
191 	l = TKobj(TkCline, i);
192 	if(l->stipple)
193 		freeimage(l->stipple);
194 	if(l->pen)
195 		freeimage(l->pen);
196 }
197 
198 void
tkcvslinedraw(Image * img,TkCitem * i,TkEnv * pe)199 tkcvslinedraw(Image *img, TkCitem *i, TkEnv *pe)
200 {
201 	int w;
202 	Point *p;
203 	TkCline *l;
204 	Image *pen;
205 
206 	USED(pe);
207 
208 	l = TKobj(TkCline, i);
209 
210 	pen = l->pen;
211 	if(pen == nil)
212 		pen = tkgc(i->env, TkCforegnd);
213 
214 	w = TKF2I(l->width)/2;
215 	if(w < 0)
216 		return;
217 
218 	p = i->p.drawpt;
219 	if(l->smooth == BoolT && i->p.npoint >= 3)
220 		bezspline(img, p, i->p.npoint, l->arrowf, l->arrowl, w, pen, p[0]);
221 	else
222 		poly(img, p, i->p.npoint, l->arrowf, l->arrowl, w, pen, p[0]);
223 }
224 
225 char*
tkcvslinecoord(TkCitem * i,char * arg,int x,int y)226 tkcvslinecoord(TkCitem *i, char *arg, int x, int y)
227 {
228 	char *e;
229 	TkCpoints p;
230 
231 	if(arg == nil) {
232 		tkxlatepts(i->p.parampt, i->p.npoint, x, y);
233 		tkxlatepts(i->p.drawpt, i->p.npoint, TKF2I(x), TKF2I(y));
234 		i->p.bb = rectaddpt(i->p.bb, Pt(TKF2I(x), TKF2I(y)));
235 	}
236 	else {
237 		e = tkparsepts(i->env->top, &p, &arg, 0);
238 		if(e != nil)
239 			return e;
240 		if(p.npoint < 2) {
241 			tkfreepoint(&p);
242 			return TkFewpt;
243 		}
244 		tkfreepoint(&i->p);
245 		i->p = p;
246 		tkcvslinesize(i);
247 	}
248 	return nil;
249 }
250 
251 int
tkcvslinehit(TkCitem * i,Point p)252 tkcvslinehit(TkCitem *i, Point p)
253 {
254 	TkCline *l;
255 	int w, np, r;
256 	Point *pp;
257 
258 	l = TKobj(TkCline, i);
259 	w =TKF2I(l->width) + 2;	/* 2 for slop */
260 
261 	if (l->smooth == BoolT) {
262 		np = getbezsplinepts(i->p.drawpt, i->p.npoint, &pp);
263 		r = tklinehit(pp, np, w, p);
264 		free(pp);
265 	} else
266 		r = tklinehit(i->p.drawpt, i->p.npoint, w, p);
267 	return r;
268 }
269