]> git.lizzy.rs Git - plan9front.git/blob - sys/src/libcontrol/slider.c
bcm64: do not use OTP_BOOTMODE_REG to determine OSC frequency (thanks richard miller)
[plan9front.git] / sys / src / libcontrol / slider.c
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
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
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
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
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*
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 }