1 #include <u.h>
2 #include <libc.h>
3 #include <draw.h>
4 #include <thread.h>
5 #include <mouse.h>
6 #include <keyboard.h>
7 #include <control.h>
8
9 typedef struct Slider Slider;
10
11 struct Slider
12 {
13 Control;
14 int border;
15 CImage *image;
16 CImage *textcolor;
17 CImage *bordercolor;
18 CImage *indicatorcolor;
19 int absolute;
20 int max;
21 int vis;
22 int value;
23 int clamphigh;
24 int clamplow;
25 int horizontal;
26 int lastbut;
27 };
28
29 enum{
30 EAbsolute,
31 EBorder,
32 EBordercolor,
33 EClamp,
34 EFocus,
35 EFormat,
36 EHide,
37 EImage,
38 EIndicatorcolor,
39 EMax,
40 EOrient,
41 ERect,
42 EReveal,
43 EShow,
44 ESize,
45 EValue,
46 EVis,
47 };
48
49 static char *cmds[] = {
50 [EAbsolute] = "absolute",
51 [EBorder] = "border",
52 [EBordercolor] = "bordercolor",
53 [EClamp] = "clamp",
54 [EFocus] = "focus",
55 [EFormat] = "format",
56 [EHide] = "hide",
57 [EImage] = "image",
58 [EIndicatorcolor] = "indicatorcolor",
59 [EMax] = "max",
60 [EOrient] = "orient",
61 [ERect] = "rect",
62 [EReveal] = "reveal",
63 [EShow] = "show",
64 [ESize] = "size",
65 [EValue] = "value",
66 [EVis] = "vis",
67 };
68
69 static void
sliderfree(Control * c)70 sliderfree(Control *c)
71 {
72 Slider *s;
73
74 s = (Slider*)c;
75 _putctlimage(s->image);
76 _putctlimage(s->textcolor);
77 _putctlimage(s->bordercolor);
78 _putctlimage(s->indicatorcolor);
79 }
80
81 static void
slidershow(Slider * s)82 slidershow(Slider *s)
83 {
84 Rectangle r, t;
85 int l, h, d;
86
87 if (s->hidden)
88 return;
89 r = s->rect;
90 draw(s->screen, r, s->image->image, nil, s->image->image->r.min);
91 if(s->border > 0){
92 border(s->screen, r, s->border, s->bordercolor->image, s->bordercolor->image->r.min);
93 r = insetrect(r, s->border);
94 }
95 if(s->max <= 0)
96 return;
97 if(s->horizontal)
98 d = Dx(r);
99 else
100 d = Dy(r);
101 l = muldiv(s->value, d, s->max);
102 h = muldiv(s->value+s->vis, d, s->max);
103 if(s->clamplow && s->clamphigh){
104 l = 0;
105 h = d;
106 }else if(s->clamplow){
107 h = l;
108 l = 0;
109 }else if(s->clamphigh)
110 h = d;
111 t = r;
112 if(s->horizontal){
113 r.max.x = r.min.x+h;
114 r.min.x += l;
115 }else{
116 r.max.y = r.min.y+h;
117 r.min.y += l;
118 }
119 if(rectclip(&r, t))
120 draw(s->screen, r, s->indicatorcolor->image, nil, s->indicatorcolor->image->r.min);
121 flushimage(display, 1);
122 }
123
124 static void
sliderctl(Control * c,CParse * cp)125 sliderctl(Control *c, CParse *cp)
126 {
127 int cmd, prev;
128 Rectangle r;
129 Slider *s;
130
131 s = (Slider*)c;
132 cmd = _ctllookup(cp->args[0], cmds, nelem(cmds));
133 switch(cmd){
134 default:
135 ctlerror("%q: unrecognized message '%s'", s->name, cp->str);
136 break;
137 case EAbsolute:
138 _ctlargcount(s, cp, 2);
139 s->absolute = cp->iargs[1];
140 break;
141 case EBorder:
142 _ctlargcount(s, cp, 2);
143 if(cp->iargs[1] < 0)
144 ctlerror("%q: bad border: %c", s->name, cp->str);
145 s->border = cp->iargs[1];
146 break;
147 case EBordercolor:
148 _ctlargcount(s, cp, 2);
149 _setctlimage(s, &s->bordercolor, cp->args[1]);
150 break;
151 case EClamp:
152 _ctlargcount(s, cp, 3);
153 if(strcmp(cp->args[1], "high") == 0)
154 s->clamphigh = cp->iargs[2];
155 else if(strcmp(cp->args[1], "low") == 0)
156 s->clamplow = cp->iargs[2];
157 else
158 ctlerror("%q: unrecognized clamp: %s", s->name, cp->str);
159 break;
160 case EFocus:
161 /* ignore focus change */
162 break;
163 case EFormat:
164 _ctlargcount(s, cp, 2);
165 s->format = ctlstrdup(cp->args[1]);
166 break;
167 case EHide:
168 _ctlargcount(s, cp, 1);
169 s->hidden = 1;
170 break;
171 case EImage:
172 _ctlargcount(s, cp, 2);
173 _setctlimage(s, &s->image, cp->args[1]);
174 break;
175 case EIndicatorcolor:
176 _ctlargcount(s, cp, 2);
177 _setctlimage(s, &s->indicatorcolor, cp->args[1]);
178 break;
179 case EMax:
180 _ctlargcount(s, cp, 2);
181 if(cp->iargs[1] < 0)
182 ctlerror("%q: negative max value: %s", s->name, cp->str);
183 if(s->max != cp->iargs[1]){
184 s->max = cp->iargs[1];
185 slidershow(s);
186 }
187 break;
188 case EOrient:
189 _ctlargcount(s, cp, 2);
190 prev = s->horizontal;
191 if(strncmp(cp->args[1], "hor", 3) == 0)
192 s->horizontal = 1;
193 else if(strncmp(cp->args[1], "ver", 3) == 0)
194 s->horizontal = 0;
195 else
196 ctlerror("%q: unrecognized orientation: %s", s->name, cp->str);
197 if(s->horizontal != prev)
198 slidershow(s);
199 break;
200 case ERect:
201 _ctlargcount(s, cp, 5);
202 r.min.x = cp->iargs[1];
203 r.min.y = cp->iargs[2];
204 r.max.x = cp->iargs[3];
205 r.max.y = cp->iargs[4];
206 if(Dx(r)<=0 || Dy(r)<=0)
207 ctlerror("%q: bad rectangle: %s", s->name, cp->str);
208 s->rect = r;
209 break;
210 case EReveal:
211 _ctlargcount(s, cp, 1);
212 s->hidden = 0;
213 slidershow(s);
214 break;
215 case EShow:
216 _ctlargcount(s, cp, 1);
217 slidershow(s);
218 break;
219 case ESize:
220 if (cp->nargs == 3)
221 r.max = Pt(0x7fffffff, 0x7fffffff);
222 else{
223 _ctlargcount(s, cp, 5);
224 r.max.x = cp->iargs[3];
225 r.max.y = cp->iargs[4];
226 }
227 r.min.x = cp->iargs[1];
228 r.min.y = cp->iargs[2];
229 if(r.min.x<=0 || r.min.y<=0 || r.max.x<=0 || r.max.y<=0 || r.max.x < r.min.x || r.max.y < r.min.y)
230 ctlerror("%q: bad sizes: %s", s->name, cp->str);
231 s->size.min = r.min;
232 s->size.max = r.max;
233 break;
234 case EValue:
235 _ctlargcount(s, cp, 2);
236 if(s->value != cp->iargs[1]){
237 s->value = cp->iargs[1];
238 slidershow(s);
239 }
240 break;
241 case EVis:
242 _ctlargcount(s, cp, 2);
243 if(s->vis != cp->iargs[1]){
244 s->vis = cp->iargs[1];
245 slidershow(s);
246 }
247 break;
248 }
249 }
250
251 static void
slidermouse(Control * c,Mouse * m)252 slidermouse(Control *c, Mouse *m)
253 {
254 Rectangle r;
255 int v, l, d, b;
256 Slider *s;
257
258 s =(Slider*)c;
259 if(m->buttons == 0){
260 /* buttons now up */
261 s->lastbut = 0;
262 return;
263 }
264 if(!s->absolute && s->lastbut==m->buttons && s->lastbut!=2){
265 /* clicks only on buttons 1 & 3; continuous motion on 2 (or when absolute) */
266 return;
267 }
268 if(s->lastbut!=0 && m->buttons!=s->lastbut){
269 /* buttons down have changed; wait for button up */
270 return;
271 }
272 s->lastbut = m->buttons;
273
274 r = insetrect(s->rect, s->border);
275 if(s->horizontal){
276 v = m->xy.x - r.min.x;
277 d = Dx(r);
278 }else{
279 v = m->xy.y - r.min.y;
280 d = Dy(r);
281 }
282 if(s->absolute)
283 b = 2;
284 else
285 b = m->buttons;
286 switch(b){
287 default:
288 return;
289 case 1:
290 l = s->value - muldiv(v, s->vis, d);
291 break;
292 case 2:
293 l = muldiv(v, s->max, d);
294 break;
295 case 4:
296 l = s->value + muldiv(v, s->vis, d);
297 break;
298 }
299 if(l < 0)
300 l = 0;
301 if(l > s->max)
302 l = s->max;
303 if(l != s->value){
304 s->value = l;
305 chanprint(s->event, s->format, s->name, s->value);
306 slidershow(s);
307 }
308 }
309
310 Control*
createslider(Controlset * cs,char * name)311 createslider(Controlset *cs, char *name)
312 {
313 Slider *s;
314
315 s = (Slider*)_createctl(cs, "slider", sizeof(Slider), name);
316 s->image = _getctlimage("white");
317 s->textcolor = _getctlimage("black");
318 s->bordercolor = _getctlimage("black");
319 s->indicatorcolor = _getctlimage("black");
320 s->format = ctlstrdup("%q: value %d");
321 s->border = 0;
322 s->mouse = slidermouse;
323 s->ctl = sliderctl;
324 s->exit = sliderfree;
325 return (Control*)s;
326 }
327