xref: /plan9-contrib/sys/src/libcontrol/slider.c (revision 9a747e4fd48b9f4522c70c07e8f882a15030f964)
180ee5cbfSDavid du Colombier #include <u.h>
280ee5cbfSDavid du Colombier #include <libc.h>
380ee5cbfSDavid du Colombier #include <draw.h>
480ee5cbfSDavid du Colombier #include <thread.h>
580ee5cbfSDavid du Colombier #include <mouse.h>
680ee5cbfSDavid du Colombier #include <keyboard.h>
780ee5cbfSDavid du Colombier #include <control.h>
880ee5cbfSDavid du Colombier 
980ee5cbfSDavid du Colombier typedef struct Slider Slider;
1080ee5cbfSDavid du Colombier 
1180ee5cbfSDavid du Colombier struct Slider
1280ee5cbfSDavid du Colombier {
1380ee5cbfSDavid du Colombier 	Control;
1480ee5cbfSDavid du Colombier 	int		border;
1580ee5cbfSDavid du Colombier 	CImage	*image;
1680ee5cbfSDavid du Colombier 	CImage	*textcolor;
1780ee5cbfSDavid du Colombier 	CImage	*bordercolor;
1880ee5cbfSDavid du Colombier 	CImage	*indicatorcolor;
1980ee5cbfSDavid du Colombier 	int		absolute;
2080ee5cbfSDavid du Colombier 	int		max;
2180ee5cbfSDavid du Colombier 	int		vis;
2280ee5cbfSDavid du Colombier 	int		value;
2380ee5cbfSDavid du Colombier 	int		clamphigh;
2480ee5cbfSDavid du Colombier 	int		clamplow;
2580ee5cbfSDavid du Colombier 	int		horizontal;
2680ee5cbfSDavid du Colombier 	int		lastbut;
2780ee5cbfSDavid du Colombier };
2880ee5cbfSDavid du Colombier 
2980ee5cbfSDavid du Colombier enum{
3080ee5cbfSDavid du Colombier 	EAbsolute,
3180ee5cbfSDavid du Colombier 	EBorder,
3280ee5cbfSDavid du Colombier 	EBordercolor,
3380ee5cbfSDavid du Colombier 	EClamp,
3480ee5cbfSDavid du Colombier 	EFocus,
3580ee5cbfSDavid du Colombier 	EFormat,
36*9a747e4fSDavid du Colombier 	EHide,
3780ee5cbfSDavid du Colombier 	EImage,
3880ee5cbfSDavid du Colombier 	EIndicatorcolor,
3980ee5cbfSDavid du Colombier 	EMax,
4080ee5cbfSDavid du Colombier 	EOrient,
4180ee5cbfSDavid du Colombier 	ERect,
42*9a747e4fSDavid du Colombier 	EReveal,
4380ee5cbfSDavid du Colombier 	EShow,
44*9a747e4fSDavid du Colombier 	ESize,
4580ee5cbfSDavid du Colombier 	EValue,
4680ee5cbfSDavid du Colombier 	EVis,
4780ee5cbfSDavid du Colombier };
4880ee5cbfSDavid du Colombier 
4980ee5cbfSDavid du Colombier static char *cmds[] = {
5080ee5cbfSDavid du Colombier 	[EAbsolute] =		"absolute",
5180ee5cbfSDavid du Colombier 	[EBorder] =		"border",
5280ee5cbfSDavid du Colombier 	[EBordercolor] =	"bordercolor",
5380ee5cbfSDavid du Colombier 	[EClamp] =		"clamp",
5480ee5cbfSDavid du Colombier 	[EFocus] = 		"focus",
5580ee5cbfSDavid du Colombier 	[EFormat] = 		"format",
56*9a747e4fSDavid du Colombier 	[EHide] =			"hide",
5780ee5cbfSDavid du Colombier 	[EImage] =		"image",
5880ee5cbfSDavid du Colombier 	[EIndicatorcolor] =	"indicatorcolor",
5980ee5cbfSDavid du Colombier 	[EMax] =			"max",
6080ee5cbfSDavid du Colombier 	[EOrient] =		"orient",
6180ee5cbfSDavid du Colombier 	[ERect] =			"rect",
62*9a747e4fSDavid du Colombier 	[EReveal] =		"reveal",
6380ee5cbfSDavid du Colombier 	[EShow] =			"show",
64*9a747e4fSDavid du Colombier 	[ESize] =			"size",
6580ee5cbfSDavid du Colombier 	[EValue] =			"value",
6680ee5cbfSDavid du Colombier 	[EVis] =			"vis",
6780ee5cbfSDavid du Colombier };
6880ee5cbfSDavid du Colombier 
6980ee5cbfSDavid du Colombier static void
sliderfree(Control * c)70*9a747e4fSDavid du Colombier sliderfree(Control *c)
7180ee5cbfSDavid du Colombier {
7280ee5cbfSDavid du Colombier 	Slider *s;
7380ee5cbfSDavid du Colombier 
74*9a747e4fSDavid du Colombier 	s = (Slider*)c;
7580ee5cbfSDavid du Colombier 	_putctlimage(s->image);
7680ee5cbfSDavid du Colombier 	_putctlimage(s->textcolor);
7780ee5cbfSDavid du Colombier 	_putctlimage(s->bordercolor);
7880ee5cbfSDavid du Colombier 	_putctlimage(s->indicatorcolor);
7980ee5cbfSDavid du Colombier }
8080ee5cbfSDavid du Colombier 
8180ee5cbfSDavid du Colombier static void
slidershow(Slider * s)8280ee5cbfSDavid du Colombier slidershow(Slider *s)
8380ee5cbfSDavid du Colombier {
8480ee5cbfSDavid du Colombier 	Rectangle r, t;
8580ee5cbfSDavid du Colombier 	int l, h, d;
8680ee5cbfSDavid du Colombier 
87*9a747e4fSDavid du Colombier 	if (s->hidden)
88*9a747e4fSDavid du Colombier 		return;
8980ee5cbfSDavid du Colombier 	r = s->rect;
9080ee5cbfSDavid du Colombier 	draw(s->screen, r, s->image->image, nil, s->image->image->r.min);
9180ee5cbfSDavid du Colombier 	if(s->border > 0){
9280ee5cbfSDavid du Colombier 		border(s->screen, r, s->border, s->bordercolor->image, s->bordercolor->image->r.min);
9380ee5cbfSDavid du Colombier 		r = insetrect(r, s->border);
9480ee5cbfSDavid du Colombier 	}
9580ee5cbfSDavid du Colombier 	if(s->max <= 0)
9680ee5cbfSDavid du Colombier 		return;
9780ee5cbfSDavid du Colombier 	if(s->horizontal)
9880ee5cbfSDavid du Colombier 		d = Dx(r);
9980ee5cbfSDavid du Colombier 	else
10080ee5cbfSDavid du Colombier 		d = Dy(r);
10180ee5cbfSDavid du Colombier 	l = muldiv(s->value, d, s->max);
10280ee5cbfSDavid du Colombier 	h = muldiv(s->value+s->vis, d, s->max);
10380ee5cbfSDavid du Colombier 	if(s->clamplow && s->clamphigh){
10480ee5cbfSDavid du Colombier 		l = 0;
10580ee5cbfSDavid du Colombier 		h = d;
10680ee5cbfSDavid du Colombier 	}else if(s->clamplow){
10780ee5cbfSDavid du Colombier 		h = l;
10880ee5cbfSDavid du Colombier 		l = 0;
10980ee5cbfSDavid du Colombier 	}else if(s->clamphigh)
11080ee5cbfSDavid du Colombier 		h = d;
11180ee5cbfSDavid du Colombier 	t = r;
11280ee5cbfSDavid du Colombier 	if(s->horizontal){
11380ee5cbfSDavid du Colombier 		r.max.x = r.min.x+h;
11480ee5cbfSDavid du Colombier 		r.min.x += l;
11580ee5cbfSDavid du Colombier 	}else{
11680ee5cbfSDavid du Colombier 		r.max.y = r.min.y+h;
11780ee5cbfSDavid du Colombier 		r.min.y += l;
11880ee5cbfSDavid du Colombier 	}
11980ee5cbfSDavid du Colombier 	if(rectclip(&r, t))
12080ee5cbfSDavid du Colombier 		draw(s->screen, r, s->indicatorcolor->image, nil, s->indicatorcolor->image->r.min);
12180ee5cbfSDavid du Colombier 	flushimage(display, 1);
12280ee5cbfSDavid du Colombier }
12380ee5cbfSDavid du Colombier 
12480ee5cbfSDavid du Colombier static void
sliderctl(Control * c,CParse * cp)125*9a747e4fSDavid du Colombier sliderctl(Control *c, CParse *cp)
12680ee5cbfSDavid du Colombier {
12780ee5cbfSDavid du Colombier 	int cmd, prev;
12880ee5cbfSDavid du Colombier 	Rectangle r;
12980ee5cbfSDavid du Colombier 	Slider *s;
13080ee5cbfSDavid du Colombier 
13180ee5cbfSDavid du Colombier 	s = (Slider*)c;
132*9a747e4fSDavid du Colombier 	cmd = _ctllookup(cp->args[0], cmds, nelem(cmds));
13380ee5cbfSDavid du Colombier 	switch(cmd){
13480ee5cbfSDavid du Colombier 	default:
135*9a747e4fSDavid du Colombier 		ctlerror("%q: unrecognized message '%s'", s->name, cp->str);
13680ee5cbfSDavid du Colombier 		break;
13780ee5cbfSDavid du Colombier 	case EAbsolute:
138*9a747e4fSDavid du Colombier 		_ctlargcount(s, cp, 2);
139*9a747e4fSDavid du Colombier 		s->absolute = cp->iargs[1];
14080ee5cbfSDavid du Colombier 		break;
14180ee5cbfSDavid du Colombier 	case EBorder:
142*9a747e4fSDavid du Colombier 		_ctlargcount(s, cp, 2);
143*9a747e4fSDavid du Colombier 		if(cp->iargs[1] < 0)
144*9a747e4fSDavid du Colombier 			ctlerror("%q: bad border: %c", s->name, cp->str);
145*9a747e4fSDavid du Colombier 		s->border = cp->iargs[1];
14680ee5cbfSDavid du Colombier 		break;
14780ee5cbfSDavid du Colombier 	case EBordercolor:
148*9a747e4fSDavid du Colombier 		_ctlargcount(s, cp, 2);
149*9a747e4fSDavid du Colombier 		_setctlimage(s, &s->bordercolor, cp->args[1]);
15080ee5cbfSDavid du Colombier 		break;
15180ee5cbfSDavid du Colombier 	case EClamp:
152*9a747e4fSDavid du Colombier 		_ctlargcount(s, cp, 3);
153*9a747e4fSDavid du Colombier 		if(strcmp(cp->args[1], "high") == 0)
154*9a747e4fSDavid du Colombier 			s->clamphigh = cp->iargs[2];
155*9a747e4fSDavid du Colombier 		else if(strcmp(cp->args[1], "low") == 0)
156*9a747e4fSDavid du Colombier 			s->clamplow = cp->iargs[2];
15780ee5cbfSDavid du Colombier 		else
158*9a747e4fSDavid du Colombier 			ctlerror("%q: unrecognized clamp: %s", s->name, cp->str);
15980ee5cbfSDavid du Colombier 		break;
16080ee5cbfSDavid du Colombier 	case EFocus:
16180ee5cbfSDavid du Colombier 		/* ignore focus change */
16280ee5cbfSDavid du Colombier 		break;
16380ee5cbfSDavid du Colombier 	case EFormat:
164*9a747e4fSDavid du Colombier 		_ctlargcount(s, cp, 2);
165*9a747e4fSDavid du Colombier 		s->format = ctlstrdup(cp->args[1]);
166*9a747e4fSDavid du Colombier 		break;
167*9a747e4fSDavid du Colombier 	case EHide:
168*9a747e4fSDavid du Colombier 		_ctlargcount(s, cp, 1);
169*9a747e4fSDavid du Colombier 		s->hidden = 1;
17080ee5cbfSDavid du Colombier 		break;
17180ee5cbfSDavid du Colombier 	case EImage:
172*9a747e4fSDavid du Colombier 		_ctlargcount(s, cp, 2);
173*9a747e4fSDavid du Colombier 		_setctlimage(s, &s->image, cp->args[1]);
17480ee5cbfSDavid du Colombier 		break;
17580ee5cbfSDavid du Colombier 	case EIndicatorcolor:
176*9a747e4fSDavid du Colombier 		_ctlargcount(s, cp, 2);
177*9a747e4fSDavid du Colombier 		_setctlimage(s, &s->indicatorcolor, cp->args[1]);
17880ee5cbfSDavid du Colombier 		break;
17980ee5cbfSDavid du Colombier 	case EMax:
180*9a747e4fSDavid du Colombier 		_ctlargcount(s, cp, 2);
181*9a747e4fSDavid du Colombier 		if(cp->iargs[1] < 0)
182*9a747e4fSDavid du Colombier 			ctlerror("%q: negative max value: %s", s->name, cp->str);
183*9a747e4fSDavid du Colombier 		if(s->max != cp->iargs[1]){
184*9a747e4fSDavid du Colombier 			s->max = cp->iargs[1];
18580ee5cbfSDavid du Colombier 			slidershow(s);
18680ee5cbfSDavid du Colombier 		}
18780ee5cbfSDavid du Colombier 		break;
18880ee5cbfSDavid du Colombier 	case EOrient:
189*9a747e4fSDavid du Colombier 		_ctlargcount(s, cp, 2);
19080ee5cbfSDavid du Colombier 		prev = s->horizontal;
191*9a747e4fSDavid du Colombier 		if(strncmp(cp->args[1], "hor", 3) == 0)
19280ee5cbfSDavid du Colombier 			s->horizontal = 1;
193*9a747e4fSDavid du Colombier 		else if(strncmp(cp->args[1], "ver", 3) == 0)
19480ee5cbfSDavid du Colombier 			s->horizontal = 0;
19580ee5cbfSDavid du Colombier 		else
196*9a747e4fSDavid du Colombier 			ctlerror("%q: unrecognized orientation: %s", s->name, cp->str);
19780ee5cbfSDavid du Colombier 		if(s->horizontal != prev)
19880ee5cbfSDavid du Colombier 			slidershow(s);
19980ee5cbfSDavid du Colombier 		break;
20080ee5cbfSDavid du Colombier 	case ERect:
201*9a747e4fSDavid du Colombier 		_ctlargcount(s, cp, 5);
202*9a747e4fSDavid du Colombier 		r.min.x = cp->iargs[1];
203*9a747e4fSDavid du Colombier 		r.min.y = cp->iargs[2];
204*9a747e4fSDavid du Colombier 		r.max.x = cp->iargs[3];
205*9a747e4fSDavid du Colombier 		r.max.y = cp->iargs[4];
20680ee5cbfSDavid du Colombier 		if(Dx(r)<=0 || Dy(r)<=0)
207*9a747e4fSDavid du Colombier 			ctlerror("%q: bad rectangle: %s", s->name, cp->str);
20880ee5cbfSDavid du Colombier 		s->rect = r;
20980ee5cbfSDavid du Colombier 		break;
210*9a747e4fSDavid du Colombier 	case EReveal:
211*9a747e4fSDavid du Colombier 		_ctlargcount(s, cp, 1);
212*9a747e4fSDavid du Colombier 		s->hidden = 0;
21380ee5cbfSDavid du Colombier 		slidershow(s);
21480ee5cbfSDavid du Colombier 		break;
215*9a747e4fSDavid du Colombier 	case EShow:
216*9a747e4fSDavid du Colombier 		_ctlargcount(s, cp, 1);
217*9a747e4fSDavid du Colombier 		slidershow(s);
218*9a747e4fSDavid du Colombier 		break;
219*9a747e4fSDavid du Colombier 	case ESize:
220*9a747e4fSDavid du Colombier 		if (cp->nargs == 3)
221*9a747e4fSDavid du Colombier 			r.max = Pt(0x7fffffff, 0x7fffffff);
222*9a747e4fSDavid du Colombier 		else{
223*9a747e4fSDavid du Colombier 			_ctlargcount(s, cp, 5);
224*9a747e4fSDavid du Colombier 			r.max.x = cp->iargs[3];
225*9a747e4fSDavid du Colombier 			r.max.y = cp->iargs[4];
226*9a747e4fSDavid du Colombier 		}
227*9a747e4fSDavid du Colombier 		r.min.x = cp->iargs[1];
228*9a747e4fSDavid du Colombier 		r.min.y = cp->iargs[2];
229*9a747e4fSDavid du Colombier 		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*9a747e4fSDavid du Colombier 			ctlerror("%q: bad sizes: %s", s->name, cp->str);
231*9a747e4fSDavid du Colombier 		s->size.min = r.min;
232*9a747e4fSDavid du Colombier 		s->size.max = r.max;
233*9a747e4fSDavid du Colombier 		break;
23480ee5cbfSDavid du Colombier 	case EValue:
235*9a747e4fSDavid du Colombier 		_ctlargcount(s, cp, 2);
236*9a747e4fSDavid du Colombier 		if(s->value != cp->iargs[1]){
237*9a747e4fSDavid du Colombier 			s->value = cp->iargs[1];
23880ee5cbfSDavid du Colombier 			slidershow(s);
23980ee5cbfSDavid du Colombier 		}
24080ee5cbfSDavid du Colombier 		break;
24180ee5cbfSDavid du Colombier 	case EVis:
242*9a747e4fSDavid du Colombier 		_ctlargcount(s, cp, 2);
243*9a747e4fSDavid du Colombier 		if(s->vis != cp->iargs[1]){
244*9a747e4fSDavid du Colombier 			s->vis = cp->iargs[1];
24580ee5cbfSDavid du Colombier 			slidershow(s);
24680ee5cbfSDavid du Colombier 		}
24780ee5cbfSDavid du Colombier 		break;
24880ee5cbfSDavid du Colombier 	}
24980ee5cbfSDavid du Colombier }
25080ee5cbfSDavid du Colombier 
25180ee5cbfSDavid du Colombier static void
slidermouse(Control * c,Mouse * m)252*9a747e4fSDavid du Colombier slidermouse(Control *c, Mouse *m)
25380ee5cbfSDavid du Colombier {
25480ee5cbfSDavid du Colombier 	Rectangle r;
25580ee5cbfSDavid du Colombier 	int v, l, d, b;
256*9a747e4fSDavid du Colombier 	Slider *s;
25780ee5cbfSDavid du Colombier 
258*9a747e4fSDavid du Colombier 	s =(Slider*)c;
259*9a747e4fSDavid du Colombier 	if(m->buttons == 0){
26080ee5cbfSDavid du Colombier 		/* buttons now up */
26180ee5cbfSDavid du Colombier 		s->lastbut = 0;
26280ee5cbfSDavid du Colombier 		return;
26380ee5cbfSDavid du Colombier 	}
264*9a747e4fSDavid du Colombier 	if(!s->absolute && s->lastbut==m->buttons && s->lastbut!=2){
26580ee5cbfSDavid du Colombier 		/* clicks only on buttons 1 & 3; continuous motion on 2 (or when absolute) */
26680ee5cbfSDavid du Colombier 		return;
26780ee5cbfSDavid du Colombier 	}
268*9a747e4fSDavid du Colombier 	if(s->lastbut!=0 && m->buttons!=s->lastbut){
26980ee5cbfSDavid du Colombier 		/* buttons down have changed; wait for button up */
27080ee5cbfSDavid du Colombier 		return;
27180ee5cbfSDavid du Colombier 	}
272*9a747e4fSDavid du Colombier 	s->lastbut = m->buttons;
27380ee5cbfSDavid du Colombier 
27480ee5cbfSDavid du Colombier 	r = insetrect(s->rect, s->border);
27580ee5cbfSDavid du Colombier 	if(s->horizontal){
276*9a747e4fSDavid du Colombier 		v = m->xy.x - r.min.x;
27780ee5cbfSDavid du Colombier 		d = Dx(r);
27880ee5cbfSDavid du Colombier 	}else{
279*9a747e4fSDavid du Colombier 		v = m->xy.y - r.min.y;
28080ee5cbfSDavid du Colombier 		d = Dy(r);
28180ee5cbfSDavid du Colombier 	}
28280ee5cbfSDavid du Colombier 	if(s->absolute)
28380ee5cbfSDavid du Colombier 		b = 2;
28480ee5cbfSDavid du Colombier 	else
285*9a747e4fSDavid du Colombier 		b = m->buttons;
28680ee5cbfSDavid du Colombier 	switch(b){
28780ee5cbfSDavid du Colombier 	default:
28880ee5cbfSDavid du Colombier 		return;
28980ee5cbfSDavid du Colombier 	case 1:
29080ee5cbfSDavid du Colombier 		l = s->value - muldiv(v, s->vis, d);
29180ee5cbfSDavid du Colombier 		break;
29280ee5cbfSDavid du Colombier 	case 2:
29380ee5cbfSDavid du Colombier 		l = muldiv(v, s->max, d);
29480ee5cbfSDavid du Colombier 		break;
29580ee5cbfSDavid du Colombier 	case 4:
29680ee5cbfSDavid du Colombier 		l = s->value + muldiv(v, s->vis, d);
29780ee5cbfSDavid du Colombier 		break;
29880ee5cbfSDavid du Colombier 	}
29980ee5cbfSDavid du Colombier 	if(l < 0)
30080ee5cbfSDavid du Colombier 		l = 0;
30180ee5cbfSDavid du Colombier 	if(l > s->max)
30280ee5cbfSDavid du Colombier 		l = s->max;
30380ee5cbfSDavid du Colombier 	if(l != s->value){
30480ee5cbfSDavid du Colombier 		s->value = l;
305*9a747e4fSDavid du Colombier 		chanprint(s->event, s->format, s->name, s->value);
30680ee5cbfSDavid du Colombier 		slidershow(s);
30780ee5cbfSDavid du Colombier 	}
30880ee5cbfSDavid du Colombier }
309*9a747e4fSDavid du Colombier 
310*9a747e4fSDavid du Colombier Control*
createslider(Controlset * cs,char * name)311*9a747e4fSDavid du Colombier createslider(Controlset *cs, char *name)
312*9a747e4fSDavid du Colombier {
313*9a747e4fSDavid du Colombier 	Slider *s;
314*9a747e4fSDavid du Colombier 
315*9a747e4fSDavid du Colombier 	s = (Slider*)_createctl(cs, "slider", sizeof(Slider), name);
316*9a747e4fSDavid du Colombier 	s->image = _getctlimage("white");
317*9a747e4fSDavid du Colombier 	s->textcolor = _getctlimage("black");
318*9a747e4fSDavid du Colombier 	s->bordercolor = _getctlimage("black");
319*9a747e4fSDavid du Colombier 	s->indicatorcolor = _getctlimage("black");
320*9a747e4fSDavid du Colombier 	s->format = ctlstrdup("%q: value %d");
321*9a747e4fSDavid du Colombier 	s->border = 0;
322*9a747e4fSDavid du Colombier 	s->mouse = slidermouse;
323*9a747e4fSDavid du Colombier 	s->ctl = sliderctl;
324*9a747e4fSDavid du Colombier 	s->exit = sliderfree;
325*9a747e4fSDavid du Colombier 	return (Control*)s;
326*9a747e4fSDavid du Colombier }
327