xref: /inferno-os/libtk/scale.c (revision 48c2bcd8842a77d6fca4a18505e622e9a9d3d38b)
137da2899SCharles.Forsyth #include <lib9.h>
237da2899SCharles.Forsyth #include <kernel.h>
337da2899SCharles.Forsyth #include "draw.h"
437da2899SCharles.Forsyth #include "tk.h"
537da2899SCharles.Forsyth #include "keyboard.h"
637da2899SCharles.Forsyth 
737da2899SCharles.Forsyth #define	O(t, e)		((long)(&((t*)0)->e))
837da2899SCharles.Forsyth 
937da2899SCharles.Forsyth typedef struct TkScale TkScale;
1037da2899SCharles.Forsyth struct TkScale
1137da2899SCharles.Forsyth {
1237da2899SCharles.Forsyth 	int	value;
1337da2899SCharles.Forsyth 	int	bigi;
1437da2899SCharles.Forsyth 	int	digits;
1537da2899SCharles.Forsyth 	int	digwidth;
1637da2899SCharles.Forsyth 	int	from;		/* Base of range */
1737da2899SCharles.Forsyth 	int	to;		/* Limit of range */
1837da2899SCharles.Forsyth 	int	len;		/* Length of groove */
1937da2899SCharles.Forsyth 	int	res;		/* Resolution */
2037da2899SCharles.Forsyth 	int	sv;		/* Show value */
2137da2899SCharles.Forsyth 	int	sl;		/* Slider length */
2237da2899SCharles.Forsyth 	int	sw;		/* Slider width div 2 */
2337da2899SCharles.Forsyth 	int	relief;
2437da2899SCharles.Forsyth 	int	tick;
2537da2899SCharles.Forsyth 	int	orient;
2637da2899SCharles.Forsyth 	char*	command;
2737da2899SCharles.Forsyth 	char*	label;
2837da2899SCharles.Forsyth 	int	pixmin;
2937da2899SCharles.Forsyth 	int	pixmax;
3037da2899SCharles.Forsyth 	int	pixpos;
3137da2899SCharles.Forsyth 	int	center;
3237da2899SCharles.Forsyth 	int	pix;
3337da2899SCharles.Forsyth 	int	base;
3437da2899SCharles.Forsyth 	int	flag;
3537da2899SCharles.Forsyth 	int	jump;
3637da2899SCharles.Forsyth };
3737da2899SCharles.Forsyth 
3837da2899SCharles.Forsyth enum {
3937da2899SCharles.Forsyth 	Dragging = (1<<0),
4037da2899SCharles.Forsyth 	Autorepeat = (1<<1),
4137da2899SCharles.Forsyth };
4237da2899SCharles.Forsyth 
4337da2899SCharles.Forsyth static
4437da2899SCharles.Forsyth TkOption opts[] =
4537da2899SCharles.Forsyth {
4637da2899SCharles.Forsyth 	"bigincrement",		OPTnnfrac,	O(TkScale, bigi),	nil,
4737da2899SCharles.Forsyth 	"digits",		OPTdist,	O(TkScale, digits),	nil,
4837da2899SCharles.Forsyth 	"from",			OPTfrac,	O(TkScale, from),	nil,
4937da2899SCharles.Forsyth 	"to",			OPTfrac,	O(TkScale, to),		nil,
5037da2899SCharles.Forsyth 	"length",		OPTdist,	O(TkScale, len),	nil,
5137da2899SCharles.Forsyth 	"resolution",		OPTnnfrac,	O(TkScale, res),	nil,
5237da2899SCharles.Forsyth 	"showrange",	OPTignore,	0,	nil,
5337da2899SCharles.Forsyth 	"showvalue",		OPTstab,	O(TkScale, sv),		tkbool,
5437da2899SCharles.Forsyth 	"jump",		OPTstab, O(TkScale, jump),	tkbool,
5537da2899SCharles.Forsyth 	"sliderlength",		OPTdist,	O(TkScale, sl),		nil,
5637da2899SCharles.Forsyth 	"sliderrelief",		OPTstab,	O(TkScale, relief),	tkrelief,
5737da2899SCharles.Forsyth 	"tickinterval",		OPTfrac,	O(TkScale, tick),	nil,
5837da2899SCharles.Forsyth 	"tick",		OPTfrac,	O(TkScale, tick),	nil,
5937da2899SCharles.Forsyth 	"label",		OPTtext,	O(TkScale, label),	nil,
6037da2899SCharles.Forsyth 	"command",		OPTtext,	O(TkScale, command),	nil,
6137da2899SCharles.Forsyth 	"orient",		OPTstab,	O(TkScale, orient),	tkorient,
6237da2899SCharles.Forsyth 	nil
6337da2899SCharles.Forsyth };
6437da2899SCharles.Forsyth 
6537da2899SCharles.Forsyth static char trough1[] = "trough1";
6637da2899SCharles.Forsyth static char trough2[] = "trough2";
6737da2899SCharles.Forsyth static char slider[]  = "slider";
6837da2899SCharles.Forsyth 
6937da2899SCharles.Forsyth static
7037da2899SCharles.Forsyth TkEbind b[] =
7137da2899SCharles.Forsyth {
7237da2899SCharles.Forsyth 	{TkMotion,		"%W tkScaleMotion %x %y"},
7337da2899SCharles.Forsyth 	{TkButton1P|TkMotion,	"%W tkScaleDrag %x %y"},
7437da2899SCharles.Forsyth 	{TkButton1P,		"%W tkScaleMotion %x %y; %W tkScaleBut1P %x %y"},
7537da2899SCharles.Forsyth 	{TkButton1P|TkDouble,	"%W tkScaleMotion %x %y; %W tkScaleBut1P %x %y"},
7637da2899SCharles.Forsyth 	{TkButton1R,		"%W tkScaleDrag %x %y; %W tkScaleBut1R; %W tkScaleMotion %x %y"},
7737da2899SCharles.Forsyth 	{TkKey,		"%W tkScaleKey 0x%K"},
7837da2899SCharles.Forsyth };
7937da2899SCharles.Forsyth 
8037da2899SCharles.Forsyth enum
8137da2899SCharles.Forsyth {
8237da2899SCharles.Forsyth 	Scalewidth	= 18,
8337da2899SCharles.Forsyth 	ScalePad	= 2,
84c9ccdbd5Sforsyth 	ScaleBW		= 1,
8537da2899SCharles.Forsyth 	ScaleSlider	= 16,
8637da2899SCharles.Forsyth 	ScaleLen	= 80,
8737da2899SCharles.Forsyth 
8837da2899SCharles.Forsyth };
8937da2899SCharles.Forsyth 
9037da2899SCharles.Forsyth static int
maximum(int a,int b)9137da2899SCharles.Forsyth maximum(int a, int b)
9237da2899SCharles.Forsyth {
9337da2899SCharles.Forsyth 	if (a > b)
9437da2899SCharles.Forsyth 		return a;
9537da2899SCharles.Forsyth 	return b;
9637da2899SCharles.Forsyth }
9737da2899SCharles.Forsyth 
9837da2899SCharles.Forsyth void
tksizescale(Tk * tk)9937da2899SCharles.Forsyth tksizescale(Tk *tk)
10037da2899SCharles.Forsyth {
10137da2899SCharles.Forsyth 	Point p;
10237da2899SCharles.Forsyth 	char buf[32];
10337da2899SCharles.Forsyth 	TkScale *tks;
10437da2899SCharles.Forsyth 	int fh, w, h, digits, digits2;
10537da2899SCharles.Forsyth 
10637da2899SCharles.Forsyth 	tks = TKobj(TkScale, tk);
10737da2899SCharles.Forsyth 
10837da2899SCharles.Forsyth 	digits = tks->digits;
10937da2899SCharles.Forsyth 	if(digits <= 0) {
11037da2899SCharles.Forsyth 		digits = tkfprint(buf, tks->from) - buf;
11137da2899SCharles.Forsyth 		digits2 = tkfprint(buf, tks->to) - buf;
11237da2899SCharles.Forsyth 		digits = maximum(digits, digits2);
11337da2899SCharles.Forsyth 		if (tks->res > 0) {
11437da2899SCharles.Forsyth 			digits2 = tkfprint(buf, tks->from + tks->res) - buf;
11537da2899SCharles.Forsyth 			digits = maximum(digits, digits2);
11637da2899SCharles.Forsyth 			digits2 = tkfprint(buf, tks->to - tks->res) - buf;
11737da2899SCharles.Forsyth 			digits = maximum(digits, digits2);
11837da2899SCharles.Forsyth 		}
11937da2899SCharles.Forsyth 	}
12037da2899SCharles.Forsyth 
12137da2899SCharles.Forsyth 	digits *= tk->env->wzero;
12237da2899SCharles.Forsyth 	if(tks->sv != BoolT)
12337da2899SCharles.Forsyth 		digits = 0;
12437da2899SCharles.Forsyth 
12537da2899SCharles.Forsyth 	tks->digwidth = digits;
12637da2899SCharles.Forsyth 
12737da2899SCharles.Forsyth 	p = tkstringsize(tk, tks->label);
12837da2899SCharles.Forsyth 	if(tks->orient == Tkvertical) {
12937da2899SCharles.Forsyth 		h = tks->len + 2*ScaleBW + 2*ScalePad;
13037da2899SCharles.Forsyth 		w = Scalewidth + 2*ScalePad + 2*ScaleBW;
13137da2899SCharles.Forsyth 		if (p.x)
13237da2899SCharles.Forsyth 			w += p.x + ScalePad;
13337da2899SCharles.Forsyth 		if (tks->sv == BoolT)
13437da2899SCharles.Forsyth 			w += digits + ScalePad;
135c9ccdbd5Sforsyth 	} else {
13637da2899SCharles.Forsyth 		w = maximum(p.x, tks->len + ScaleBW + 2*ScalePad);
13737da2899SCharles.Forsyth 		h = Scalewidth + 2*ScalePad + 2*ScaleBW;
13837da2899SCharles.Forsyth 		fh = tk->env->font->height;
13937da2899SCharles.Forsyth 		if(tks->label != nil)
14037da2899SCharles.Forsyth 			h += fh + ScalePad;
14137da2899SCharles.Forsyth 		if(tks->sv == BoolT)
14237da2899SCharles.Forsyth 			h += fh + ScalePad;
14337da2899SCharles.Forsyth 	}
14437da2899SCharles.Forsyth 	w += 2*tk->highlightwidth;
14537da2899SCharles.Forsyth 	h += 2*tk->highlightwidth;
14637da2899SCharles.Forsyth 	if(!(tk->flag & Tksetwidth))
14737da2899SCharles.Forsyth 		tk->req.width = w;
14837da2899SCharles.Forsyth 	if(!(tk->flag & Tksetheight))
14937da2899SCharles.Forsyth 		tk->req.height = h;
15037da2899SCharles.Forsyth }
15137da2899SCharles.Forsyth 
15237da2899SCharles.Forsyth static int
tkscalecheckvalue(Tk * tk)15337da2899SCharles.Forsyth tkscalecheckvalue(Tk *tk)
15437da2899SCharles.Forsyth {
15537da2899SCharles.Forsyth 	int v;
15637da2899SCharles.Forsyth 	TkScale *tks = TKobj(TkScale, tk);
15737da2899SCharles.Forsyth 	int limit = 1;
15837da2899SCharles.Forsyth 
15937da2899SCharles.Forsyth 	v = tks->value;
16037da2899SCharles.Forsyth 	if (tks->res > 0)
16137da2899SCharles.Forsyth 		v = (v / tks->res) * tks->res;
16237da2899SCharles.Forsyth 	if (tks->to >= tks->from) {
16337da2899SCharles.Forsyth 		if (v < tks->from)
16437da2899SCharles.Forsyth 			v = tks->from;
16537da2899SCharles.Forsyth 		else if (v > tks->to)
16637da2899SCharles.Forsyth 			v = tks->to;
16737da2899SCharles.Forsyth 		else
16837da2899SCharles.Forsyth 			limit = 0;
16937da2899SCharles.Forsyth 	} else {
17037da2899SCharles.Forsyth 		if (v < tks->to)
17137da2899SCharles.Forsyth 			v = tks->to;
17237da2899SCharles.Forsyth 		else if (v > tks->from)
17337da2899SCharles.Forsyth 			v = tks->from;
17437da2899SCharles.Forsyth 		else
17537da2899SCharles.Forsyth 			limit = 0;
17637da2899SCharles.Forsyth 	}
17737da2899SCharles.Forsyth 	/*
17837da2899SCharles.Forsyth 	 *  it's possible for the value to end up as a non-whole
17937da2899SCharles.Forsyth 	 * multiple of resolution here, if the end points aren't
18037da2899SCharles.Forsyth 	 * themselves such a multiple. if so, tough - that's
18137da2899SCharles.Forsyth 	 * what you asked for! (it does mean that the endpoints
18237da2899SCharles.Forsyth 	 * are always accessible however, which could be a good thing).
18337da2899SCharles.Forsyth 	 */
18437da2899SCharles.Forsyth 	tks->value = v;
18537da2899SCharles.Forsyth 	return limit;
18637da2899SCharles.Forsyth }
18737da2899SCharles.Forsyth 
18837da2899SCharles.Forsyth char*
tkscale(TkTop * t,char * arg,char ** ret)18937da2899SCharles.Forsyth tkscale(TkTop *t, char *arg, char **ret)
19037da2899SCharles.Forsyth {
19137da2899SCharles.Forsyth 	Tk *tk;
19237da2899SCharles.Forsyth 	char *e;
19337da2899SCharles.Forsyth 	TkName *names;
19437da2899SCharles.Forsyth 	TkScale *tks;
19537da2899SCharles.Forsyth 	TkOptab tko[3];
19637da2899SCharles.Forsyth 
19737da2899SCharles.Forsyth 	tk = tknewobj(t, TKscale, sizeof(Tk)+sizeof(TkScale));
19837da2899SCharles.Forsyth 	if(tk == nil)
19937da2899SCharles.Forsyth 		return TkNomem;
20037da2899SCharles.Forsyth 
20137da2899SCharles.Forsyth 	tk->flag |= Tktakefocus;
20237da2899SCharles.Forsyth 	tks = TKobj(TkScale, tk);
20337da2899SCharles.Forsyth 	tks->res = TKI2F(1);
20437da2899SCharles.Forsyth 	tks->to = TKI2F(100);
20537da2899SCharles.Forsyth 	tks->len = ScaleLen;
20637da2899SCharles.Forsyth 	tks->orient = Tkvertical;
20737da2899SCharles.Forsyth 	tks->relief = TKraised;
20837da2899SCharles.Forsyth 	tks->sl = ScaleSlider;
20937da2899SCharles.Forsyth 	tks->sv = BoolT;
21037da2899SCharles.Forsyth 	tks->bigi = 0;
21137da2899SCharles.Forsyth 
21237da2899SCharles.Forsyth 	tko[0].ptr = tk;
21337da2899SCharles.Forsyth 	tko[0].optab = tkgeneric;
21437da2899SCharles.Forsyth 	tko[1].ptr = tks;
21537da2899SCharles.Forsyth 	tko[1].optab = opts;
21637da2899SCharles.Forsyth 	tko[2].ptr = nil;
21737da2899SCharles.Forsyth 
21837da2899SCharles.Forsyth 	names = nil;
21937da2899SCharles.Forsyth 	e = tkparse(t, arg, tko, &names);
22037da2899SCharles.Forsyth 	if(e != nil) {
22137da2899SCharles.Forsyth 		tkfreeobj(tk);
22237da2899SCharles.Forsyth 		return e;
22337da2899SCharles.Forsyth 	}
22437da2899SCharles.Forsyth 	tksettransparent(tk, tkhasalpha(tk->env, TkCbackgnd));
22537da2899SCharles.Forsyth 	tkscalecheckvalue(tk);
22637da2899SCharles.Forsyth 	tksizescale(tk);
22737da2899SCharles.Forsyth 	if (tks->bigi == 0)
22837da2899SCharles.Forsyth 		tks->bigi = TKI2F(TKF2I(tks->to - tks->from) / 10);
22937da2899SCharles.Forsyth 	e = tkbindings(t, tk, b, nelem(b));
23037da2899SCharles.Forsyth 
23137da2899SCharles.Forsyth 	if(e != nil) {
23237da2899SCharles.Forsyth 		tkfreeobj(tk);
23337da2899SCharles.Forsyth 		return e;
23437da2899SCharles.Forsyth 	}
23537da2899SCharles.Forsyth 
23637da2899SCharles.Forsyth 	e = tkaddchild(t, tk, &names);
23737da2899SCharles.Forsyth 	tkfreename(names);
23837da2899SCharles.Forsyth 	if(e != nil) {
23937da2899SCharles.Forsyth 		tkfreeobj(tk);
24037da2899SCharles.Forsyth 		return e;
24137da2899SCharles.Forsyth 	}
24237da2899SCharles.Forsyth 	tk->name->link = nil;
24337da2899SCharles.Forsyth 
24437da2899SCharles.Forsyth 	return tkvalue(ret, "%s", tk->name->name);
24537da2899SCharles.Forsyth }
24637da2899SCharles.Forsyth 
24737da2899SCharles.Forsyth static char*
tkscalecget(Tk * tk,char * arg,char ** val)24837da2899SCharles.Forsyth tkscalecget(Tk *tk, char *arg, char **val)
24937da2899SCharles.Forsyth {
25037da2899SCharles.Forsyth 	TkOptab tko[3];
25137da2899SCharles.Forsyth 	TkScale *tks = TKobj(TkScale, tk);
25237da2899SCharles.Forsyth 
25337da2899SCharles.Forsyth 	tko[0].ptr = tk;
25437da2899SCharles.Forsyth 	tko[0].optab = tkgeneric;
25537da2899SCharles.Forsyth 	tko[1].ptr = tks;
25637da2899SCharles.Forsyth 	tko[1].optab = opts;
25737da2899SCharles.Forsyth 	tko[2].ptr = nil;
25837da2899SCharles.Forsyth 
25937da2899SCharles.Forsyth 	return tkgencget(tko, arg, val, tk->env->top);
26037da2899SCharles.Forsyth }
26137da2899SCharles.Forsyth 
26237da2899SCharles.Forsyth void
tkfreescale(Tk * tk)26337da2899SCharles.Forsyth tkfreescale(Tk *tk)
26437da2899SCharles.Forsyth {
26537da2899SCharles.Forsyth 	TkScale *tks = TKobj(TkScale, tk);
26637da2899SCharles.Forsyth 
26737da2899SCharles.Forsyth 	if(tks->command != nil)
26837da2899SCharles.Forsyth 		free(tks->command);
26937da2899SCharles.Forsyth 	if(tks->label != nil)
27037da2899SCharles.Forsyth 		free(tks->label);
27137da2899SCharles.Forsyth }
27237da2899SCharles.Forsyth 
27337da2899SCharles.Forsyth static void
tkscalehoriz(Tk * tk,Image * i)27437da2899SCharles.Forsyth tkscalehoriz(Tk *tk, Image *i)
27537da2899SCharles.Forsyth {
27637da2899SCharles.Forsyth 	TkEnv *e;
27737da2899SCharles.Forsyth 	char sv[32];
27837da2899SCharles.Forsyth 	TkScale *tks;
27937da2899SCharles.Forsyth 	Image *d, *l;
28037da2899SCharles.Forsyth 	Rectangle r, r2, sr;
28137da2899SCharles.Forsyth 	Point p, q;
282c9ccdbd5Sforsyth 	int fh, sh, gh, sl, v, w, h, len;
28337da2899SCharles.Forsyth 	int fgnd;
28437da2899SCharles.Forsyth 
28537da2899SCharles.Forsyth 	e = tk->env;
28637da2899SCharles.Forsyth 	tks = TKobj(TkScale, tk);
28737da2899SCharles.Forsyth 
28837da2899SCharles.Forsyth 
28937da2899SCharles.Forsyth 	fh = e->font->height;
29037da2899SCharles.Forsyth 	fgnd = TkCforegnd;
29137da2899SCharles.Forsyth 	if (tk->flag & Tkdisabled)
29237da2899SCharles.Forsyth 		fgnd = TkCdisablefgnd;
29337da2899SCharles.Forsyth 
29437da2899SCharles.Forsyth 	r = Rect(0, 0, tk->act.width, tk->act.height);
29537da2899SCharles.Forsyth 	r = rectaddpt(r, Pt(tk->borderwidth, tk->borderwidth));
29637da2899SCharles.Forsyth 	r = insetrect(r, tk->highlightwidth);
29737da2899SCharles.Forsyth 	r = insetrect(r, ScalePad);
29837da2899SCharles.Forsyth 
29937da2899SCharles.Forsyth 	if(tks->label != nil) {
30037da2899SCharles.Forsyth 		string(i, r.min, tkgc(e, fgnd), ZP, e->font, tks->label);
30137da2899SCharles.Forsyth 		r.min.y += fh + ScalePad;
30237da2899SCharles.Forsyth 	}
30337da2899SCharles.Forsyth 	if(tks->sv == BoolT)
30437da2899SCharles.Forsyth 		r.min.y += fh + ScalePad;
30537da2899SCharles.Forsyth 
30637da2899SCharles.Forsyth 	sr = insetrect(r, ScaleBW);
30737da2899SCharles.Forsyth 	w = Dx(sr);
30837da2899SCharles.Forsyth 	h = Dy(sr);
30937da2899SCharles.Forsyth 	sl = tks->sl + 2*ScaleBW;
31037da2899SCharles.Forsyth 
31137da2899SCharles.Forsyth 	l = tkgc(e, TkCbackgndlght);
31237da2899SCharles.Forsyth 	d = tkgc(e, TkCbackgnddark);
31337da2899SCharles.Forsyth 	tkbevel(i, r.min, w, h, ScaleBW, d, l);
31437da2899SCharles.Forsyth 
31537da2899SCharles.Forsyth 	tks->pixmin = sr.min.x;
31637da2899SCharles.Forsyth 	tks->pixmax = sr.max.x;
31737da2899SCharles.Forsyth 
31837da2899SCharles.Forsyth 	sh = h - 2*ScaleBW;
31937da2899SCharles.Forsyth 	tks->sw = sh/2;
32037da2899SCharles.Forsyth 
32137da2899SCharles.Forsyth 	w -= sl;
32237da2899SCharles.Forsyth 	if (w <= 0)
32337da2899SCharles.Forsyth 		w = 1;
32437da2899SCharles.Forsyth 	p.x = sr.min.x;
32537da2899SCharles.Forsyth 	p.y = sr.max.y;
32637da2899SCharles.Forsyth 	if(tks->tick > 0){
32737da2899SCharles.Forsyth 		int j, t, l;
32837da2899SCharles.Forsyth 		t = tks->tick;
32937da2899SCharles.Forsyth 		l = tks->to-tks->from;
33037da2899SCharles.Forsyth 		if (l < 0)
33137da2899SCharles.Forsyth 			l = -l;
33237da2899SCharles.Forsyth 		if (l == 0)
33337da2899SCharles.Forsyth 			l = 1;
33437da2899SCharles.Forsyth 		r2.min.y = p.y;
33537da2899SCharles.Forsyth 		r2.max.y = p.y + ScaleBW + ScalePad;
33637da2899SCharles.Forsyth 		for(j = 0; j <= l; j += t){
33737da2899SCharles.Forsyth 			r2.min.x = p.x+((vlong)j*w)/l+sl/2;
33837da2899SCharles.Forsyth 			r2.max.x = r2.min.x+1;
33937da2899SCharles.Forsyth 			draw(i, r2, tkgc(e, fgnd), nil, ZP);
34037da2899SCharles.Forsyth 		}
34137da2899SCharles.Forsyth 	}
34237da2899SCharles.Forsyth 	v = tks->value-tks->from;
34337da2899SCharles.Forsyth 	len = tks->to-tks->from;
34437da2899SCharles.Forsyth 	if (len != 0)
34537da2899SCharles.Forsyth 		p.x += ((vlong)v*w)/len;
34637da2899SCharles.Forsyth 	p.y = sr.min.y;
34737da2899SCharles.Forsyth 	q = p;
34837da2899SCharles.Forsyth 	q.x += tks->sl/2 + 1;
349c9ccdbd5Sforsyth 	if(ScaleBW > 1) {
350c9ccdbd5Sforsyth 		gh = sh;
35137da2899SCharles.Forsyth 		q.y++;
352c9ccdbd5Sforsyth 	} else
353c9ccdbd5Sforsyth 		gh = sh-1;
35437da2899SCharles.Forsyth 	if(tk->flag & Tkactivated) {
35537da2899SCharles.Forsyth 		r2.min = p;
35637da2899SCharles.Forsyth 		r2.max.x = p.x+sl;
35737da2899SCharles.Forsyth 		r2.max.y = sr.max.y;
35837da2899SCharles.Forsyth 		draw(i, r2, tkgc(e, TkCactivebgnd), nil, ZP);
35937da2899SCharles.Forsyth 	}
36037da2899SCharles.Forsyth 	switch(tks->relief) {
36137da2899SCharles.Forsyth 	case TKsunken:
36237da2899SCharles.Forsyth 		tkbevel(i, p, tks->sl, sh, ScaleBW, d, l);
363c9ccdbd5Sforsyth 		tkbevel(i, q, 0, gh, 1, l, d);
36437da2899SCharles.Forsyth 		break;
36537da2899SCharles.Forsyth 	case TKraised:
36637da2899SCharles.Forsyth 		tkbevel(i, p, tks->sl, sh, ScaleBW, l, d);
367c9ccdbd5Sforsyth 		tkbevel(i, q, 0, gh, 1, d, l);
36837da2899SCharles.Forsyth 		break;
36937da2899SCharles.Forsyth 	}
37037da2899SCharles.Forsyth 	tks->pixpos = p.x;
37137da2899SCharles.Forsyth 	tks->center = p.y + sh/2 + ScaleBW;
37237da2899SCharles.Forsyth 
37337da2899SCharles.Forsyth 	if(tks->sv != BoolT)
37437da2899SCharles.Forsyth 		return;
37537da2899SCharles.Forsyth 
37637da2899SCharles.Forsyth 	tkfprint(sv, tks->value);
37737da2899SCharles.Forsyth 	if(tks->digits > 0 && tks->digits < strlen(sv))
37837da2899SCharles.Forsyth 		sv[tks->digits] = '\0';
37937da2899SCharles.Forsyth 
38037da2899SCharles.Forsyth 	w = stringwidth(e->font, sv);
38137da2899SCharles.Forsyth 	p.x = q.x;
38237da2899SCharles.Forsyth 	p.x -= w/2;
38337da2899SCharles.Forsyth 	p.y = r.min.y - fh - ScalePad;
38437da2899SCharles.Forsyth 	if(p.x < tks->pixmin)
38537da2899SCharles.Forsyth 		p.x = tks->pixmin;
38637da2899SCharles.Forsyth 	if(p.x+w > tks->pixmax)
38737da2899SCharles.Forsyth 		p.x = tks->pixmax - w;
38837da2899SCharles.Forsyth 
38937da2899SCharles.Forsyth 	string(i, p, tkgc(e, fgnd), ZP, e->font, sv);
39037da2899SCharles.Forsyth }
39137da2899SCharles.Forsyth 
39237da2899SCharles.Forsyth static void
tkscalevert(Tk * tk,Image * i)39337da2899SCharles.Forsyth tkscalevert(Tk *tk, Image *i)
39437da2899SCharles.Forsyth {
39537da2899SCharles.Forsyth 	TkEnv *e;
39637da2899SCharles.Forsyth 	TkScale *tks;
39737da2899SCharles.Forsyth 	char sv[32];
39837da2899SCharles.Forsyth 	Image *d, *l;
39937da2899SCharles.Forsyth 	Rectangle r, r2, sr;
40037da2899SCharles.Forsyth 	Point p, q;
401c9ccdbd5Sforsyth 	int fh, v, sw, gw, w, h, len, sl;
40237da2899SCharles.Forsyth 	int fgnd;
40337da2899SCharles.Forsyth 
40437da2899SCharles.Forsyth 	e = tk->env;
40537da2899SCharles.Forsyth 	tks = TKobj(TkScale, tk);
40637da2899SCharles.Forsyth 
40737da2899SCharles.Forsyth 	fh = e->font->height;
40837da2899SCharles.Forsyth 	fgnd = TkCforegnd;
40937da2899SCharles.Forsyth 	if (tk->flag & Tkdisabled)
41037da2899SCharles.Forsyth 		fgnd = TkCdisablefgnd;
41137da2899SCharles.Forsyth 
41237da2899SCharles.Forsyth 	r = Rect(0, 0, tk->act.width, tk->act.height);
41337da2899SCharles.Forsyth 	r = rectaddpt(r, Pt(tk->borderwidth, tk->borderwidth));
41437da2899SCharles.Forsyth 	r = insetrect(r, tk->highlightwidth);
41537da2899SCharles.Forsyth 	r = insetrect(r, ScalePad);
41637da2899SCharles.Forsyth 
41737da2899SCharles.Forsyth 	if (tks->sv)
41837da2899SCharles.Forsyth 		r.min.x += tks->digwidth + ScalePad;
41937da2899SCharles.Forsyth 
42037da2899SCharles.Forsyth 	if(tks->label != nil) {
42137da2899SCharles.Forsyth 		p =  stringsize(e->font, tks->label);
42237da2899SCharles.Forsyth 		r.max.x -= p.x;
42337da2899SCharles.Forsyth 		string(i, Pt(r.max.x, r.min.y), tkgc(e, fgnd), ZP, e->font, tks->label);
42437da2899SCharles.Forsyth 		r.max.x -= ScalePad;
42537da2899SCharles.Forsyth 	}
42637da2899SCharles.Forsyth 
42737da2899SCharles.Forsyth 	sr = insetrect(r, ScaleBW);
42837da2899SCharles.Forsyth 	h = Dy(sr);
42937da2899SCharles.Forsyth 	w = Dx(sr);
43037da2899SCharles.Forsyth 	sl = tks->sl + 2*ScaleBW;
43137da2899SCharles.Forsyth 
43237da2899SCharles.Forsyth 	l = tkgc(e, TkCbackgndlght);
43337da2899SCharles.Forsyth 	d = tkgc(e, TkCbackgnddark);
43437da2899SCharles.Forsyth 	tkbevel(i, r.min, w, h, ScaleBW, d, l);
43537da2899SCharles.Forsyth 
43637da2899SCharles.Forsyth 	tks->pixmin = sr.min.y;
43737da2899SCharles.Forsyth 	tks->pixmax = sr.max.y;
43837da2899SCharles.Forsyth 
43937da2899SCharles.Forsyth 	sw = w - 2*ScaleBW;
44037da2899SCharles.Forsyth 	tks->sw = sw/2;
44137da2899SCharles.Forsyth 
44237da2899SCharles.Forsyth 	h -= sl;
44337da2899SCharles.Forsyth 	if (h <= 0)
44437da2899SCharles.Forsyth 		h = 1;
44537da2899SCharles.Forsyth 	p.x = sr.max.x;
44637da2899SCharles.Forsyth 	p.y = sr.min.y;
44737da2899SCharles.Forsyth 	if(tks->tick > 0){
44837da2899SCharles.Forsyth 		int j, t, l;
44937da2899SCharles.Forsyth 		t = tks->tick;
45037da2899SCharles.Forsyth 		l = tks->to-tks->from;
45137da2899SCharles.Forsyth 		if (l < 0)
45237da2899SCharles.Forsyth 			l = -l;
45337da2899SCharles.Forsyth 		if (l == 0)
45437da2899SCharles.Forsyth 			l = 1;
45537da2899SCharles.Forsyth 		r2.min = p;
45637da2899SCharles.Forsyth 		r2.max.x = p.x + ScaleBW + ScalePad;
45737da2899SCharles.Forsyth 		for(j = 0; j <= l; j += t){
45837da2899SCharles.Forsyth 			r2.min.y = p.y+((vlong)j*h)/l+sl/2;
45937da2899SCharles.Forsyth 			r2.max.y = r2.min.y+1;
46037da2899SCharles.Forsyth 			draw(i, r2, tkgc(e, fgnd), nil, ZP);
46137da2899SCharles.Forsyth 		}
46237da2899SCharles.Forsyth 	}
46337da2899SCharles.Forsyth 
46437da2899SCharles.Forsyth 	v = tks->value-tks->from;
46537da2899SCharles.Forsyth 	len  = tks->to-tks->from;
46637da2899SCharles.Forsyth 	if (len != 0)
46737da2899SCharles.Forsyth 		p.y += ((vlong)v*h)/len;
46837da2899SCharles.Forsyth 	p.x = sr.min.x;
46937da2899SCharles.Forsyth 	q = p;
470c9ccdbd5Sforsyth 	if(ScaleBW > 1) {
47137da2899SCharles.Forsyth 		q.x++;
472c9ccdbd5Sforsyth 		gw = sw;
473c9ccdbd5Sforsyth 	} else
474c9ccdbd5Sforsyth 		gw = sw-1;
47537da2899SCharles.Forsyth 	q.y += tks->sl/2 + 1;
47637da2899SCharles.Forsyth 	if(tk->flag & Tkactivated) {
47737da2899SCharles.Forsyth 		r2.min = p;
47837da2899SCharles.Forsyth 		r2.max.x = sr.max.x;
47937da2899SCharles.Forsyth 		r2.max.y = p.y+sl;
48037da2899SCharles.Forsyth 		draw(i, r2, tkgc(e, TkCactivebgnd), nil, ZP);
48137da2899SCharles.Forsyth 	}
48237da2899SCharles.Forsyth 	switch(tks->relief) {
48337da2899SCharles.Forsyth 	case TKsunken:
48437da2899SCharles.Forsyth 		tkbevel(i, p, sw, tks->sl, ScaleBW, d, l);
4851b078c23Sforsyth 		tkbevel(i, q, gw, 0, 1, l, d);
48637da2899SCharles.Forsyth 		break;
48737da2899SCharles.Forsyth 	case TKraised:
48837da2899SCharles.Forsyth 		tkbevel(i, p, sw, tks->sl, ScaleBW, l, d);
4891b078c23Sforsyth 		tkbevel(i, q, gw, 0, 1, d, l);
49037da2899SCharles.Forsyth 		break;
49137da2899SCharles.Forsyth 	}
49237da2899SCharles.Forsyth 	tks->pixpos = p.y;
49337da2899SCharles.Forsyth 	tks->center = p.x + sw/2 + ScaleBW;
49437da2899SCharles.Forsyth 
49537da2899SCharles.Forsyth 	if(tks->sv != BoolT)
49637da2899SCharles.Forsyth 		return;
49737da2899SCharles.Forsyth 
49837da2899SCharles.Forsyth 	tkfprint(sv, tks->value);
49937da2899SCharles.Forsyth 	if(tks->digits > 0 && tks->digits < strlen(sv))
50037da2899SCharles.Forsyth 		sv[tks->digits] = '\0';
50137da2899SCharles.Forsyth 
50237da2899SCharles.Forsyth 	p.x = r.min.x - ScalePad - stringwidth(e->font, sv);
50337da2899SCharles.Forsyth 	p.y = q.y;
50437da2899SCharles.Forsyth 	p.y -= fh/2;
50537da2899SCharles.Forsyth 	if (p.y < tks->pixmin)
50637da2899SCharles.Forsyth 		p.y = tks->pixmin;
50737da2899SCharles.Forsyth 	if (p.y + fh > tks->pixmax)
50837da2899SCharles.Forsyth 		p.y = tks->pixmax - fh;
50937da2899SCharles.Forsyth 	string(i, p, tkgc(e, fgnd), ZP, e->font, sv);
51037da2899SCharles.Forsyth }
51137da2899SCharles.Forsyth 
51237da2899SCharles.Forsyth char*
tkdrawscale(Tk * tk,Point orig)51337da2899SCharles.Forsyth tkdrawscale(Tk *tk, Point orig)
51437da2899SCharles.Forsyth {
51537da2899SCharles.Forsyth 	Point p;
51637da2899SCharles.Forsyth 	TkEnv *env;
51737da2899SCharles.Forsyth 	TkScale *tks;
51837da2899SCharles.Forsyth 	Rectangle r, fr;
51937da2899SCharles.Forsyth 	Image *i;
52037da2899SCharles.Forsyth 
52137da2899SCharles.Forsyth 	tks = TKobj(TkScale, tk);
52237da2899SCharles.Forsyth 	env = tk->env;
52337da2899SCharles.Forsyth 
52437da2899SCharles.Forsyth 	r.min = ZP;
52537da2899SCharles.Forsyth 	r.max.x = tk->act.width + 2*tk->borderwidth;
52637da2899SCharles.Forsyth 	r.max.y = tk->act.height + 2*tk->borderwidth;
52737da2899SCharles.Forsyth 	i = tkitmp(env, r.max, TkCbackgnd);
52837da2899SCharles.Forsyth 	if(i == nil)
52937da2899SCharles.Forsyth 		return nil;
53037da2899SCharles.Forsyth 
53137da2899SCharles.Forsyth 	if(tks->orient == Tkvertical)
53237da2899SCharles.Forsyth 		tkscalevert(tk, i);
53337da2899SCharles.Forsyth 	else
53437da2899SCharles.Forsyth 		tkscalehoriz(tk, i);
53537da2899SCharles.Forsyth 
53637da2899SCharles.Forsyth 	tkdrawrelief(i, tk, ZP, TkCbackgnd, tk->relief);
53737da2899SCharles.Forsyth 	if (tkhaskeyfocus(tk)) {
53837da2899SCharles.Forsyth 		fr = insetrect(r, tk->borderwidth);
53937da2899SCharles.Forsyth 		tkbox(i, fr, tk->highlightwidth, tkgc(env, TkChighlightfgnd));
54037da2899SCharles.Forsyth 	}
54137da2899SCharles.Forsyth 
54237da2899SCharles.Forsyth 	p.x = tk->act.x + orig.x;
54337da2899SCharles.Forsyth 	p.y = tk->act.y + orig.y;
54437da2899SCharles.Forsyth 	r = rectaddpt(r, p);
54537da2899SCharles.Forsyth 	draw(tkimageof(tk), r, i, nil, ZP);
54637da2899SCharles.Forsyth 
54737da2899SCharles.Forsyth 	return nil;
54837da2899SCharles.Forsyth }
54937da2899SCharles.Forsyth 
55037da2899SCharles.Forsyth /* Widget Commands (+ means implemented)
55137da2899SCharles.Forsyth 	+cget
55237da2899SCharles.Forsyth 	+configure
55337da2899SCharles.Forsyth 	+coords
55437da2899SCharles.Forsyth 	+get
55537da2899SCharles.Forsyth 	+identify
55637da2899SCharles.Forsyth 	+set
55737da2899SCharles.Forsyth */
55837da2899SCharles.Forsyth 
55937da2899SCharles.Forsyth static char*
tkscaleconf(Tk * tk,char * arg,char ** val)56037da2899SCharles.Forsyth tkscaleconf(Tk *tk, char *arg, char **val)
56137da2899SCharles.Forsyth {
56237da2899SCharles.Forsyth 	char *e;
56337da2899SCharles.Forsyth 	TkGeom g;
56437da2899SCharles.Forsyth 	int bd;
56537da2899SCharles.Forsyth 	TkOptab tko[3];
56637da2899SCharles.Forsyth 	TkScale *tks = TKobj(TkScale, tk);
56737da2899SCharles.Forsyth 
56837da2899SCharles.Forsyth 	tko[0].ptr = tk;
56937da2899SCharles.Forsyth 	tko[0].optab = tkgeneric;
57037da2899SCharles.Forsyth 	tko[1].ptr = tks;
57137da2899SCharles.Forsyth 	tko[1].optab = opts;
57237da2899SCharles.Forsyth 	tko[2].ptr = nil;
57337da2899SCharles.Forsyth 
57437da2899SCharles.Forsyth 	if(*arg == '\0')
57537da2899SCharles.Forsyth 		return tkconflist(tko, val);
57637da2899SCharles.Forsyth 
57737da2899SCharles.Forsyth 	g = tk->req;
57837da2899SCharles.Forsyth 	bd = tk->borderwidth;
57937da2899SCharles.Forsyth 	e = tkparse(tk->env->top, arg, tko, nil);
58037da2899SCharles.Forsyth 	tksettransparent(tk, tkhasalpha(tk->env, TkCbackgnd));
58137da2899SCharles.Forsyth 	tkscalecheckvalue(tk);
58237da2899SCharles.Forsyth 	tksizescale(tk);
58337da2899SCharles.Forsyth 	tkgeomchg(tk, &g, bd);
58437da2899SCharles.Forsyth 
58537da2899SCharles.Forsyth 	tk->dirty = tkrect(tk, 1);
58637da2899SCharles.Forsyth 	return e;
58737da2899SCharles.Forsyth }
58837da2899SCharles.Forsyth 
58937da2899SCharles.Forsyth char*
tkscaleposn(TkEnv * env,Tk * tk,char * arg,int * z)59037da2899SCharles.Forsyth tkscaleposn(TkEnv *env, Tk *tk, char *arg, int *z)
59137da2899SCharles.Forsyth {
59237da2899SCharles.Forsyth 	int x, y;
59337da2899SCharles.Forsyth 	TkScale *tks = TKobj(TkScale, tk);
59437da2899SCharles.Forsyth 	char *e;
59537da2899SCharles.Forsyth 
59637da2899SCharles.Forsyth 	e = tkfracword(env->top, &arg, &x, env);
59737da2899SCharles.Forsyth 	if(e != nil)
59837da2899SCharles.Forsyth 		return e;
59937da2899SCharles.Forsyth 	e = tkfracword(env->top, &arg, &y, env);
60037da2899SCharles.Forsyth 	if(e != nil)
60137da2899SCharles.Forsyth 		return e;
60237da2899SCharles.Forsyth 
60337da2899SCharles.Forsyth 	x = TKF2I(x) + tk->borderwidth;
60437da2899SCharles.Forsyth 	y = TKF2I(y) + tk->borderwidth;
60537da2899SCharles.Forsyth 
60637da2899SCharles.Forsyth 	if(tks->orient == Tkvertical) {
60737da2899SCharles.Forsyth 		if(z != nil) {
60837da2899SCharles.Forsyth 			z[0] = x;
60937da2899SCharles.Forsyth 			z[1] = y;
61037da2899SCharles.Forsyth 		}
61137da2899SCharles.Forsyth 		x = y;
61237da2899SCharles.Forsyth 	}
61337da2899SCharles.Forsyth 	else {
61437da2899SCharles.Forsyth 		if(z != nil) {
61537da2899SCharles.Forsyth 			z[0] = y;
61637da2899SCharles.Forsyth 			z[1] = x;
61737da2899SCharles.Forsyth 		}
61837da2899SCharles.Forsyth 	}
61937da2899SCharles.Forsyth 	if(x > tks->pixmin && x < tks->pixpos)
62037da2899SCharles.Forsyth 		return trough1;
621c9ccdbd5Sforsyth 	else if(x >= tks->pixpos && x < tks->pixpos+tks->sl+2*ScaleBW)
62237da2899SCharles.Forsyth 		return slider;
623c9ccdbd5Sforsyth 	else if(x >= tks->pixpos+tks->sl+2*ScaleBW && x < tks->pixmax)
62437da2899SCharles.Forsyth 		return trough2;
62537da2899SCharles.Forsyth 
62637da2899SCharles.Forsyth 	return "";
62737da2899SCharles.Forsyth }
62837da2899SCharles.Forsyth 
62937da2899SCharles.Forsyth static char*
tkscaleident(Tk * tk,char * arg,char ** val)63037da2899SCharles.Forsyth tkscaleident(Tk *tk, char *arg, char **val)
63137da2899SCharles.Forsyth {
63237da2899SCharles.Forsyth 	char *v;
63337da2899SCharles.Forsyth 
63437da2899SCharles.Forsyth 	v = tkscaleposn(tk->env, tk, arg, nil);
63537da2899SCharles.Forsyth 	if(v == nil)
63637da2899SCharles.Forsyth 		return TkBadvl;
63737da2899SCharles.Forsyth 	return tkvalue(val, "%s", v);
63837da2899SCharles.Forsyth }
63937da2899SCharles.Forsyth 
64037da2899SCharles.Forsyth static char*
tkscalecoords(Tk * tk,char * arg,char ** val)64137da2899SCharles.Forsyth tkscalecoords(Tk *tk, char *arg, char **val)
64237da2899SCharles.Forsyth {
64337da2899SCharles.Forsyth 	int p, x, y, l, value;
64437da2899SCharles.Forsyth 	TkScale *tks = TKobj(TkScale, tk);
64537da2899SCharles.Forsyth 	char *e;
64637da2899SCharles.Forsyth 
64737da2899SCharles.Forsyth 	value = tks->value;
64837da2899SCharles.Forsyth 	if(arg != nil && arg[0] != '\0') {
64937da2899SCharles.Forsyth 		e = tkfracword(tk->env->top, &arg, &value, tk->env);
65037da2899SCharles.Forsyth 		if (e != nil)
65137da2899SCharles.Forsyth 			return e;
65237da2899SCharles.Forsyth 	}
65337da2899SCharles.Forsyth 
65437da2899SCharles.Forsyth 	value -= tks->from;
65537da2899SCharles.Forsyth 	p = tks->pixmax - tks->pixmin;
65637da2899SCharles.Forsyth 	l = TKF2I(tks->to-tks->from);
65737da2899SCharles.Forsyth 	if (l==0)
65837da2899SCharles.Forsyth 		p /= 2;
65937da2899SCharles.Forsyth 	else
66037da2899SCharles.Forsyth 		p = TKF2I(value*p/l);
66137da2899SCharles.Forsyth 	p += tks->pixmin;
66237da2899SCharles.Forsyth 	if(tks->orient == Tkvertical) {
66337da2899SCharles.Forsyth 		x = tks->center;
66437da2899SCharles.Forsyth 		y = p;
66537da2899SCharles.Forsyth 	}
66637da2899SCharles.Forsyth 	else {
66737da2899SCharles.Forsyth 		x = p;
66837da2899SCharles.Forsyth 		y = tks->center;
66937da2899SCharles.Forsyth 	}
67037da2899SCharles.Forsyth 	return tkvalue(val, "%d %d", x, y);
67137da2899SCharles.Forsyth }
67237da2899SCharles.Forsyth 
67337da2899SCharles.Forsyth static char*
tkscaleget(Tk * tk,char * arg,char ** val)67437da2899SCharles.Forsyth tkscaleget(Tk *tk, char *arg, char **val)
67537da2899SCharles.Forsyth {
67637da2899SCharles.Forsyth 	int x, y, value, v, l;
67737da2899SCharles.Forsyth 	char buf[Tkminitem], *e;
67837da2899SCharles.Forsyth 	TkScale *tks = TKobj(TkScale, tk);
67937da2899SCharles.Forsyth 
68037da2899SCharles.Forsyth 	value = tks->value;
68137da2899SCharles.Forsyth 	if(arg[0] != '\0') {
68237da2899SCharles.Forsyth 		e = tkfracword(tk->env->top, &arg, &x, tk->env);
68337da2899SCharles.Forsyth 		if (e != nil)
68437da2899SCharles.Forsyth 			return e;
68537da2899SCharles.Forsyth 		e = tkfracword(tk->env->top, &arg, &y, tk->env);
68637da2899SCharles.Forsyth 		if (e != nil)
68737da2899SCharles.Forsyth 			return e;
68837da2899SCharles.Forsyth 		if(tks->orient == Tkvertical)
68937da2899SCharles.Forsyth 			v = TKF2I(y) + tk->borderwidth;
69037da2899SCharles.Forsyth 		else
69137da2899SCharles.Forsyth 			v = TKF2I(x) + tk->borderwidth;
69237da2899SCharles.Forsyth 
69337da2899SCharles.Forsyth 		if(v < tks->pixmin)
69437da2899SCharles.Forsyth 			value = tks->from;
69537da2899SCharles.Forsyth 		else
69637da2899SCharles.Forsyth 		if(v > tks->pixmax)
69737da2899SCharles.Forsyth 			value = tks->to;
69837da2899SCharles.Forsyth 		else {
69937da2899SCharles.Forsyth 			l = tks->pixmax-tks->pixmin;
70037da2899SCharles.Forsyth 			value = 0;
70137da2899SCharles.Forsyth 			if (l!=0)
70237da2899SCharles.Forsyth 				value = v * ((tks->to-tks->from)/l);
70337da2899SCharles.Forsyth 			value += tks->from;
70437da2899SCharles.Forsyth 		}
70537da2899SCharles.Forsyth 		if(tks->res > 0)
70637da2899SCharles.Forsyth 			value = (value/tks->res)*tks->res;
70737da2899SCharles.Forsyth 	}
70837da2899SCharles.Forsyth 	tkfprint(buf, value);
70937da2899SCharles.Forsyth 	return tkvalue(val, "%s", buf);
71037da2899SCharles.Forsyth }
71137da2899SCharles.Forsyth 
71237da2899SCharles.Forsyth static char*
tkscaleset(Tk * tk,char * arg,char ** val)71337da2899SCharles.Forsyth tkscaleset(Tk *tk, char *arg, char **val)
71437da2899SCharles.Forsyth {
71537da2899SCharles.Forsyth 	TkScale *tks = TKobj(TkScale, tk);
71637da2899SCharles.Forsyth 	char *e;
71737da2899SCharles.Forsyth 
71837da2899SCharles.Forsyth 	USED(val);
71937da2899SCharles.Forsyth 
72037da2899SCharles.Forsyth 	e = tkfracword(tk->env->top, &arg, &tks->value, tk->env);
72137da2899SCharles.Forsyth 	if (e != nil)
72237da2899SCharles.Forsyth 		return e;
72337da2899SCharles.Forsyth 	tkscalecheckvalue(tk);
72437da2899SCharles.Forsyth 	tk->dirty = tkrect(tk, 1);
72537da2899SCharles.Forsyth 	return nil;
72637da2899SCharles.Forsyth }
72737da2899SCharles.Forsyth 
72837da2899SCharles.Forsyth /* tkScaleMotion %x %y */
72937da2899SCharles.Forsyth static char*
tkscalemotion(Tk * tk,char * arg,char ** val)73037da2899SCharles.Forsyth tkscalemotion(Tk *tk, char *arg, char **val)
73137da2899SCharles.Forsyth {
73237da2899SCharles.Forsyth 	int o, z[2];
73337da2899SCharles.Forsyth 	char *v;
73437da2899SCharles.Forsyth 	TkScale *tks = TKobj(TkScale, tk);
73537da2899SCharles.Forsyth 	extern int tkstylus;
73637da2899SCharles.Forsyth 
73737da2899SCharles.Forsyth 	USED(val);
73837da2899SCharles.Forsyth 	v = tkscaleposn(tk->env, tk, arg, z);
73937da2899SCharles.Forsyth 	if(v == nil)
74037da2899SCharles.Forsyth 		return TkBadvl;
74137da2899SCharles.Forsyth 
74237da2899SCharles.Forsyth 	o = tk->flag;
74337da2899SCharles.Forsyth 	if(v != slider || z[0] < tks->center-tks->sw || z[0] > tks->center+tks->sw)
74437da2899SCharles.Forsyth 		tk->flag &= ~Tkactivated;
74537da2899SCharles.Forsyth 	else if(tkstylus == 0 || tk->env->top->ctxt->mstate.b != 0)
74637da2899SCharles.Forsyth 		tk->flag |= Tkactivated;
74737da2899SCharles.Forsyth 
74837da2899SCharles.Forsyth 	if((o & Tkactivated) != (tk->flag & Tkactivated))
74937da2899SCharles.Forsyth 		tk->dirty = tkrect(tk, 1);
75037da2899SCharles.Forsyth 
75137da2899SCharles.Forsyth 	return nil;
75237da2899SCharles.Forsyth }
75337da2899SCharles.Forsyth 
75437da2899SCharles.Forsyth static char*
tkscaledrag(Tk * tk,char * arg,char ** val)75537da2899SCharles.Forsyth tkscaledrag(Tk *tk, char *arg, char **val)
75637da2899SCharles.Forsyth {
75737da2899SCharles.Forsyth 	int x, y, v;
75837da2899SCharles.Forsyth 	char *e, buf[Tkmaxitem], f[32];
75937da2899SCharles.Forsyth 	TkScale *tks = TKobj(TkScale, tk);
76037da2899SCharles.Forsyth 
76137da2899SCharles.Forsyth 	USED(val);
76237da2899SCharles.Forsyth 	if((tks->flag & Dragging) == 0)
76337da2899SCharles.Forsyth 		return nil;
76437da2899SCharles.Forsyth 	if(tks->flag & Autorepeat)
76537da2899SCharles.Forsyth 		return nil;
76637da2899SCharles.Forsyth 
76737da2899SCharles.Forsyth 	e = tkfracword(tk->env->top, &arg, &x, tk->env);
76837da2899SCharles.Forsyth 	if(e != nil)
76937da2899SCharles.Forsyth 		return e;
77037da2899SCharles.Forsyth 	e = tkfracword(tk->env->top, &arg, &y, tk->env);
77137da2899SCharles.Forsyth 	if(e != nil)
77237da2899SCharles.Forsyth 		return e;
77337da2899SCharles.Forsyth 
77437da2899SCharles.Forsyth 	if(tks->orient == Tkvertical)
77537da2899SCharles.Forsyth 		v = TKF2I(y) + tk->borderwidth;
77637da2899SCharles.Forsyth 	else
77737da2899SCharles.Forsyth 		v = TKF2I(x) + tk->borderwidth;
77837da2899SCharles.Forsyth 
77937da2899SCharles.Forsyth 	v -= tks->pix;
78037da2899SCharles.Forsyth 	x = tks->pixmax-tks->pixmin;
78137da2899SCharles.Forsyth 	if (x!=tks->sl)
78237da2899SCharles.Forsyth 		v = tks->base + (vlong)v * (tks->to-tks->from)/(x-tks->sl);
78337da2899SCharles.Forsyth 	else
78437da2899SCharles.Forsyth 		v = tks->base;
78537da2899SCharles.Forsyth 	if(tks->res > 0) {
78637da2899SCharles.Forsyth 		int a = tks->res / 2;
78737da2899SCharles.Forsyth 		if (v < 0)
78837da2899SCharles.Forsyth 			a = -a;
78937da2899SCharles.Forsyth 		v = ((v+a)/tks->res)*tks->res;
79037da2899SCharles.Forsyth 	}
79137da2899SCharles.Forsyth 
79237da2899SCharles.Forsyth 	tks->value = v;
79337da2899SCharles.Forsyth 	tkscalecheckvalue(tk);
79437da2899SCharles.Forsyth 
79537da2899SCharles.Forsyth 	if(tks->command != nil && tks->jump != BoolT) {
79637da2899SCharles.Forsyth 		tkfprint(f, tks->value);
79737da2899SCharles.Forsyth 		snprint(buf, sizeof(buf), "%s %s", tks->command, f);
79837da2899SCharles.Forsyth 		e = tkexec(tk->env->top, buf, nil);
79937da2899SCharles.Forsyth 	}
80037da2899SCharles.Forsyth 	tk->dirty = tkrect(tk, 1);
80137da2899SCharles.Forsyth 	return e;
80237da2899SCharles.Forsyth }
80337da2899SCharles.Forsyth 
80437da2899SCharles.Forsyth static int
sgn(int v)80537da2899SCharles.Forsyth sgn(int v)
80637da2899SCharles.Forsyth {
80737da2899SCharles.Forsyth 	return v >= 0 ? 1 : -1;
80837da2899SCharles.Forsyth }
80937da2899SCharles.Forsyth 
81037da2899SCharles.Forsyth static char*
stepscale(Tk * tk,char * pos,int * end)81137da2899SCharles.Forsyth stepscale(Tk *tk, char *pos, int *end)
81237da2899SCharles.Forsyth {
81337da2899SCharles.Forsyth 	TkScale *tks = TKobj(TkScale, tk);
81437da2899SCharles.Forsyth 	char *e, buf[Tkmaxitem], f[32];
81537da2899SCharles.Forsyth 	int s;
81637da2899SCharles.Forsyth 
81737da2899SCharles.Forsyth 	s = sgn(tks->to - tks->from);
81837da2899SCharles.Forsyth 	if(pos == trough1) {
81937da2899SCharles.Forsyth 		tks->value -= s * tks->bigi;
82037da2899SCharles.Forsyth 	} else {
82137da2899SCharles.Forsyth 		/* trough2 */
82237da2899SCharles.Forsyth 		tks->value += s * tks->bigi;
82337da2899SCharles.Forsyth 	}
82437da2899SCharles.Forsyth 	s = !tkscalecheckvalue(tk);
82537da2899SCharles.Forsyth 	if (end != nil)
82637da2899SCharles.Forsyth 		*end = s;
82737da2899SCharles.Forsyth 	e = nil;
82837da2899SCharles.Forsyth 	if(tks->command != nil) {
82937da2899SCharles.Forsyth 		/* XXX perhaps should only send command if value has actually changed */
83037da2899SCharles.Forsyth 		tkfprint(f, tks->value);
83137da2899SCharles.Forsyth 		snprint(buf, sizeof(buf), "%s %s", tks->command, f);
83237da2899SCharles.Forsyth 		e = tkexec(tk->env->top, buf, nil);
83337da2899SCharles.Forsyth 	}
83437da2899SCharles.Forsyth 	return e;
83537da2899SCharles.Forsyth }
83637da2899SCharles.Forsyth 
83737da2899SCharles.Forsyth static void
screpeat(Tk * tk,void * v,int cancelled)83837da2899SCharles.Forsyth screpeat(Tk *tk, void *v, int cancelled)
83937da2899SCharles.Forsyth {
84037da2899SCharles.Forsyth 	char *e, *pos;
84137da2899SCharles.Forsyth 	int repeat;
84237da2899SCharles.Forsyth 	TkScale *tks = TKobj(TkScale, tk);
84337da2899SCharles.Forsyth 
84437da2899SCharles.Forsyth 	pos = v;
84537da2899SCharles.Forsyth 	if (cancelled) {
84637da2899SCharles.Forsyth 		tks->flag &= ~Autorepeat;
84737da2899SCharles.Forsyth 		return;
84837da2899SCharles.Forsyth 	}
84937da2899SCharles.Forsyth 	e = stepscale(tk, pos, &repeat);
85037da2899SCharles.Forsyth 	if(e != nil || !repeat) {
85137da2899SCharles.Forsyth 		tks->flag &= ~Autorepeat;
85237da2899SCharles.Forsyth 		tkcancelrepeat(tk);
85337da2899SCharles.Forsyth 	}
85437da2899SCharles.Forsyth 	tk->dirty = tkrect(tk, 1);
85537da2899SCharles.Forsyth 	tkupdate(tk->env->top);
85637da2899SCharles.Forsyth }
85737da2899SCharles.Forsyth 
85837da2899SCharles.Forsyth static char*
tkscalebut1p(Tk * tk,char * arg,char ** val)85937da2899SCharles.Forsyth tkscalebut1p(Tk *tk, char *arg, char **val)
86037da2899SCharles.Forsyth {
86137da2899SCharles.Forsyth 	int z[2];
86237da2899SCharles.Forsyth 	char *v, *e;
86337da2899SCharles.Forsyth 	TkScale *tks = TKobj(TkScale, tk);
86437da2899SCharles.Forsyth 	int repeat;
86537da2899SCharles.Forsyth 
86637da2899SCharles.Forsyth 	USED(val);
86737da2899SCharles.Forsyth 	v = tkscaleposn(tk->env, tk, arg, z);
86837da2899SCharles.Forsyth 	if(v == nil)
86937da2899SCharles.Forsyth 		return TkBadvl;
87037da2899SCharles.Forsyth 
87137da2899SCharles.Forsyth 	e = nil;
87237da2899SCharles.Forsyth 	if(v[0] == '\0' || z[0] < tks->center-tks->sw || z[0] > tks->center+tks->sw)
87337da2899SCharles.Forsyth 		return nil;
87437da2899SCharles.Forsyth 	if(v == slider) {
87537da2899SCharles.Forsyth 		tks->flag |= Dragging;
87637da2899SCharles.Forsyth 		tks->relief = TKsunken;
87737da2899SCharles.Forsyth 		tks->pix = z[1];
87837da2899SCharles.Forsyth 		tks->base = tks->value;
87937da2899SCharles.Forsyth 		tkscalecheckvalue(tk);
88037da2899SCharles.Forsyth 	} else  {
88137da2899SCharles.Forsyth 		e = stepscale(tk, v, &repeat);
88237da2899SCharles.Forsyth 		if (e == nil && repeat) {
88337da2899SCharles.Forsyth 			tks->flag |= Autorepeat;
88437da2899SCharles.Forsyth 			tkrepeat(tk, screpeat, v, TkRptpause, TkRptinterval);
88537da2899SCharles.Forsyth 		}
88637da2899SCharles.Forsyth 	}
88737da2899SCharles.Forsyth 
88837da2899SCharles.Forsyth 	tk->dirty = tkrect(tk, 1);
88937da2899SCharles.Forsyth 	return e;
89037da2899SCharles.Forsyth }
89137da2899SCharles.Forsyth 
89237da2899SCharles.Forsyth static char*
tkscalebut1r(Tk * tk,char * arg,char ** val)89337da2899SCharles.Forsyth tkscalebut1r(Tk *tk, char *arg, char **val)
89437da2899SCharles.Forsyth {
89537da2899SCharles.Forsyth 	TkScale *tks = TKobj(TkScale, tk);
89637da2899SCharles.Forsyth 	char *e, buf[Tkmaxitem], f[32];
89737da2899SCharles.Forsyth 	USED(val);
89837da2899SCharles.Forsyth 	USED(arg);
89937da2899SCharles.Forsyth 	if(tks->flag & Autorepeat) {
90037da2899SCharles.Forsyth 		tkcancelrepeat(tk);
90137da2899SCharles.Forsyth 		tks->flag &= ~Autorepeat;
90237da2899SCharles.Forsyth 	}
90337da2899SCharles.Forsyth 	e = nil;
90437da2899SCharles.Forsyth 	if (tks->flag & Dragging) {
90537da2899SCharles.Forsyth 		if (tks->command != nil && tks->jump == BoolT && (tks->flag & Dragging)) {
90637da2899SCharles.Forsyth 			tkfprint(f, tks->value);
90737da2899SCharles.Forsyth 			snprint(buf, sizeof(buf), "%s %s", tks->command, f);
90837da2899SCharles.Forsyth 			e = tkexec(tk->env->top, buf, nil);
90937da2899SCharles.Forsyth 		}
91037da2899SCharles.Forsyth 		tks->relief = TKraised;
91137da2899SCharles.Forsyth 		tks->flag &= ~Dragging;
91237da2899SCharles.Forsyth 		tk->dirty = tkrect(tk, 1);
91337da2899SCharles.Forsyth 	}
91437da2899SCharles.Forsyth 	return e;
91537da2899SCharles.Forsyth }
91637da2899SCharles.Forsyth 
91737da2899SCharles.Forsyth static char*
tkscalekey(Tk * tk,char * arg,char ** val)91837da2899SCharles.Forsyth tkscalekey(Tk *tk, char *arg, char **val)
91937da2899SCharles.Forsyth {
92037da2899SCharles.Forsyth 	char *e;
92137da2899SCharles.Forsyth 	int key;
92237da2899SCharles.Forsyth 	char *pos = nil;
92337da2899SCharles.Forsyth 	USED(arg);
92437da2899SCharles.Forsyth 	USED(val);
92537da2899SCharles.Forsyth 
92637da2899SCharles.Forsyth 	if(tk->flag & Tkdisabled)
92737da2899SCharles.Forsyth 		return nil;
92837da2899SCharles.Forsyth 
929*48c2bcd8Sforsyth 	key = strtol(arg, nil, 0);
93037da2899SCharles.Forsyth 	if (key == Up || key == Left)
93137da2899SCharles.Forsyth 		pos = trough1;
93237da2899SCharles.Forsyth 	else if (key == Down || key == Right)
93337da2899SCharles.Forsyth 		pos = trough2;
93437da2899SCharles.Forsyth 	if (pos != nil) {
93537da2899SCharles.Forsyth 		e = stepscale(tk, pos, nil);
93637da2899SCharles.Forsyth 		tk->dirty = tkrect(tk, 1);
93737da2899SCharles.Forsyth 		return e;
93837da2899SCharles.Forsyth 	}
93937da2899SCharles.Forsyth 	return nil;
94037da2899SCharles.Forsyth }
94137da2899SCharles.Forsyth 
94237da2899SCharles.Forsyth TkCmdtab tkscalecmd[] =
94337da2899SCharles.Forsyth {
94437da2899SCharles.Forsyth 	"cget",			tkscalecget,
94537da2899SCharles.Forsyth 	"configure",		tkscaleconf,
94637da2899SCharles.Forsyth 	"set",			tkscaleset,
94737da2899SCharles.Forsyth 	"identify",		tkscaleident,
94837da2899SCharles.Forsyth 	"get",			tkscaleget,
94937da2899SCharles.Forsyth 	"coords",		tkscalecoords,
95037da2899SCharles.Forsyth 	"tkScaleMotion",	tkscalemotion,
95137da2899SCharles.Forsyth 	"tkScaleDrag",		tkscaledrag,
95237da2899SCharles.Forsyth 	"tkScaleBut1P",		tkscalebut1p,
95337da2899SCharles.Forsyth 	"tkScaleBut1R",		tkscalebut1r,
95437da2899SCharles.Forsyth 	"tkScaleKey",		tkscalekey,
95537da2899SCharles.Forsyth 	nil
95637da2899SCharles.Forsyth };
95737da2899SCharles.Forsyth 
95837da2899SCharles.Forsyth TkMethod scalemethod = {
95937da2899SCharles.Forsyth 	"scale",
96037da2899SCharles.Forsyth 	tkscalecmd,
96137da2899SCharles.Forsyth 	tkfreescale,
96237da2899SCharles.Forsyth 	tkdrawscale
96337da2899SCharles.Forsyth };
964