forsyth20110330-0926ef949cd15 years agoHistory
963 lines · 18.4 KB · C
RawDownload
#include <lib9.h>#include <kernel.h>#include "draw.h"#include "tk.h"#include "keyboard.h" #define	O(t, e)		((long)(&((t*)0)->e)) typedef struct TkScale TkScale;struct TkScale{	int	value;	int	bigi;	int	digits;	int	digwidth;	int	from;		/* Base of range */	int	to;		/* Limit of range */	int	len;		/* Length of groove */	int	res;		/* Resolution */	int	sv;		/* Show value */	int	sl;		/* Slider length */	int	sw;		/* Slider width div 2 */	int	relief;	int	tick;	int	orient;	char*	command;	char*	label;	int	pixmin;	int	pixmax;	int	pixpos;	int	center;	int	pix;	int	base;	int	flag;	int	jump;}; enum {	Dragging = (1<<0),	Autorepeat = (1<<1),}; staticTkOption opts[] ={	"bigincrement",		OPTnnfrac,	O(TkScale, bigi),	nil,	"digits",		OPTdist,	O(TkScale, digits),	nil,	"from",			OPTfrac,	O(TkScale, from),	nil,	"to",			OPTfrac,	O(TkScale, to),		nil,	"length",		OPTdist,	O(TkScale, len),	nil,	"resolution",		OPTnnfrac,	O(TkScale, res),	nil,	"showrange",	OPTignore,	0,	nil,	"showvalue",		OPTstab,	O(TkScale, sv),		tkbool,	"jump",		OPTstab, O(TkScale, jump),	tkbool,	"sliderlength",		OPTdist,	O(TkScale, sl),		nil,	"sliderrelief",		OPTstab,	O(TkScale, relief),	tkrelief,	"tickinterval",		OPTfrac,	O(TkScale, tick),	nil,	"tick",		OPTfrac,	O(TkScale, tick),	nil,	"label",		OPTtext,	O(TkScale, label),	nil,	"command",		OPTtext,	O(TkScale, command),	nil,	"orient",		OPTstab,	O(TkScale, orient),	tkorient,	nil}; static char trough1[] = "trough1";static char trough2[] = "trough2";static char slider[]  = "slider"; staticTkEbind b[] = {	{TkMotion,		"%W tkScaleMotion %x %y"},	{TkButton1P|TkMotion,	"%W tkScaleDrag %x %y"},	{TkButton1P,		"%W tkScaleMotion %x %y; %W tkScaleBut1P %x %y"},	{TkButton1P|TkDouble,	"%W tkScaleMotion %x %y; %W tkScaleBut1P %x %y"},	{TkButton1R,		"%W tkScaleDrag %x %y; %W tkScaleBut1R; %W tkScaleMotion %x %y"},	{TkKey,		"%W tkScaleKey 0x%K"},}; enum{	Scalewidth	= 18,	ScalePad	= 2,	ScaleBW		= 1,	ScaleSlider	= 16,	ScaleLen	= 80, }; static intmaximum(int a, int b){	if (a > b)		return a;	return b;} voidtksizescale(Tk *tk){	Point p;	char buf[32];	TkScale *tks;	int fh, w, h, digits, digits2; 	tks = TKobj(TkScale, tk); 	digits = tks->digits;	if(digits <= 0) {		digits = tkfprint(buf, tks->from) - buf;		digits2 = tkfprint(buf, tks->to) - buf;		digits = maximum(digits, digits2);		if (tks->res > 0) {			digits2 = tkfprint(buf, tks->from + tks->res) - buf;			digits = maximum(digits, digits2);			digits2 = tkfprint(buf, tks->to - tks->res) - buf;			digits = maximum(digits, digits2);		}	} 	digits *= tk->env->wzero;	if(tks->sv != BoolT)		digits = 0; 	tks->digwidth = digits; 	p = tkstringsize(tk, tks->label);	if(tks->orient == Tkvertical) {		h = tks->len + 2*ScaleBW + 2*ScalePad;		w = Scalewidth + 2*ScalePad + 2*ScaleBW;		if (p.x)			w += p.x + ScalePad;		if (tks->sv == BoolT)			w += digits + ScalePad;	} else {		w = maximum(p.x, tks->len + ScaleBW + 2*ScalePad);		h = Scalewidth + 2*ScalePad + 2*ScaleBW;		fh = tk->env->font->height;		if(tks->label != nil)			h += fh + ScalePad;		if(tks->sv == BoolT)			h += fh + ScalePad;	}	w += 2*tk->highlightwidth;	h += 2*tk->highlightwidth;	if(!(tk->flag & Tksetwidth))		tk->req.width = w;	if(!(tk->flag & Tksetheight))		tk->req.height = h;} static inttkscalecheckvalue(Tk *tk){	int v;	TkScale *tks = TKobj(TkScale, tk);	int limit = 1; 	v = tks->value;	if (tks->res > 0)		v = (v / tks->res) * tks->res;	if (tks->to >= tks->from) {		if (v < tks->from)			v = tks->from;		else if (v > tks->to)			v = tks->to;		else			limit = 0;	} else {		if (v < tks->to)			v = tks->to;		else if (v > tks->from)			v = tks->from;		else			limit = 0;	}	/*	 *  it's possible for the value to end up as a non-whole	 * multiple of resolution here, if the end points aren't	 * themselves such a multiple. if so, tough - that's	 * what you asked for! (it does mean that the endpoints	 * are always accessible however, which could be a good thing).	 */	tks->value = v;	return limit;} char*tkscale(TkTop *t, char *arg, char **ret){	Tk *tk;	char *e;	TkName *names;	TkScale *tks;	TkOptab tko[3]; 	tk = tknewobj(t, TKscale, sizeof(Tk)+sizeof(TkScale));	if(tk == nil)		return TkNomem; 	tk->flag |= Tktakefocus;	tks = TKobj(TkScale, tk);	tks->res = TKI2F(1);	tks->to = TKI2F(100);	tks->len = ScaleLen;	tks->orient = Tkvertical;	tks->relief = TKraised;	tks->sl = ScaleSlider;	tks->sv = BoolT;	tks->bigi = 0; 	tko[0].ptr = tk;	tko[0].optab = tkgeneric;	tko[1].ptr = tks;	tko[1].optab = opts;	tko[2].ptr = nil; 	names = nil;	e = tkparse(t, arg, tko, &names);	if(e != nil) {		tkfreeobj(tk);		return e;	}	tksettransparent(tk, tkhasalpha(tk->env, TkCbackgnd));	tkscalecheckvalue(tk);	tksizescale(tk);	if (tks->bigi == 0)		tks->bigi = TKI2F(TKF2I(tks->to - tks->from) / 10);	e = tkbindings(t, tk, b, nelem(b)); 	if(e != nil) {		tkfreeobj(tk);		return e;	} 	e = tkaddchild(t, tk, &names);	tkfreename(names);	if(e != nil) {		tkfreeobj(tk);		return e;	}	tk->name->link = nil; 	return tkvalue(ret, "%s", tk->name->name);} static char*tkscalecget(Tk *tk, char *arg, char **val){	TkOptab tko[3];	TkScale *tks = TKobj(TkScale, tk); 	tko[0].ptr = tk;	tko[0].optab = tkgeneric;	tko[1].ptr = tks;	tko[1].optab = opts;	tko[2].ptr = nil; 	return tkgencget(tko, arg, val, tk->env->top);} voidtkfreescale(Tk *tk){	TkScale *tks = TKobj(TkScale, tk); 	if(tks->command != nil)		free(tks->command);	if(tks->label != nil)		free(tks->label);} static voidtkscalehoriz(Tk *tk, Image *i){	TkEnv *e;	char sv[32];	TkScale *tks;	Image *d, *l;	Rectangle r, r2, sr;	Point p, q;	int fh, sh, gh, sl, v, w, h, len;	int fgnd; 	e = tk->env;	tks = TKobj(TkScale, tk);  	fh = e->font->height;	fgnd = TkCforegnd;	if (tk->flag & Tkdisabled)		fgnd = TkCdisablefgnd; 	r = Rect(0, 0, tk->act.width, tk->act.height);	r = rectaddpt(r, Pt(tk->borderwidth, tk->borderwidth));	r = insetrect(r, tk->highlightwidth);	r = insetrect(r, ScalePad); 	if(tks->label != nil) {		string(i, r.min, tkgc(e, fgnd), ZP, e->font, tks->label);		r.min.y += fh + ScalePad;	}	if(tks->sv == BoolT)		r.min.y += fh + ScalePad; 	sr = insetrect(r, ScaleBW);	w = Dx(sr);	h = Dy(sr);	sl = tks->sl + 2*ScaleBW; 	l = tkgc(e, TkCbackgndlght);	d = tkgc(e, TkCbackgnddark);	tkbevel(i, r.min, w, h, ScaleBW, d, l); 	tks->pixmin = sr.min.x;	tks->pixmax = sr.max.x; 	sh = h - 2*ScaleBW;	tks->sw = sh/2; 	w -= sl;	if (w <= 0)		w = 1;	p.x = sr.min.x;	p.y = sr.max.y;	if(tks->tick > 0){		int j, t, l;		t = tks->tick;		l = tks->to-tks->from;		if (l < 0)			l = -l;		if (l == 0)			l = 1;		r2.min.y = p.y;		r2.max.y = p.y + ScaleBW + ScalePad;		for(j = 0; j <= l; j += t){			r2.min.x = p.x+((vlong)j*w)/l+sl/2;			r2.max.x = r2.min.x+1;			draw(i, r2, tkgc(e, fgnd), nil, ZP);		}	}	v = tks->value-tks->from;	len = tks->to-tks->from;	if (len != 0)		p.x += ((vlong)v*w)/len;	p.y = sr.min.y;	q = p;	q.x += tks->sl/2 + 1;	if(ScaleBW > 1) {		gh = sh;		q.y++;	} else		gh = sh-1;	if(tk->flag & Tkactivated) {		r2.min = p;		r2.max.x = p.x+sl;		r2.max.y = sr.max.y;		draw(i, r2, tkgc(e, TkCactivebgnd), nil, ZP);	}	switch(tks->relief) {	case TKsunken:		tkbevel(i, p, tks->sl, sh, ScaleBW, d, l);		tkbevel(i, q, 0, gh, 1, l, d);		break;	case TKraised:		tkbevel(i, p, tks->sl, sh, ScaleBW, l, d);		tkbevel(i, q, 0, gh, 1, d, l);		break;	}	tks->pixpos = p.x;	tks->center = p.y + sh/2 + ScaleBW; 	if(tks->sv != BoolT)		return; 	tkfprint(sv, tks->value);	if(tks->digits > 0 && tks->digits < strlen(sv))		sv[tks->digits] = '\0'; 	w = stringwidth(e->font, sv);	p.x = q.x;	p.x -= w/2;	p.y = r.min.y - fh - ScalePad;	if(p.x < tks->pixmin)		p.x = tks->pixmin;	if(p.x+w > tks->pixmax)		p.x = tks->pixmax - w;		string(i, p, tkgc(e, fgnd), ZP, e->font, sv);} static voidtkscalevert(Tk *tk, Image *i){	TkEnv *e;	TkScale *tks;	char sv[32];	Image *d, *l;	Rectangle r, r2, sr;	Point p, q;	int fh, v, sw, gw, w, h, len, sl;	int fgnd; 	e = tk->env;	tks = TKobj(TkScale, tk); 	fh = e->font->height;	fgnd = TkCforegnd;	if (tk->flag & Tkdisabled)		fgnd = TkCdisablefgnd; 	r = Rect(0, 0, tk->act.width, tk->act.height);	r = rectaddpt(r, Pt(tk->borderwidth, tk->borderwidth));	r = insetrect(r, tk->highlightwidth);	r = insetrect(r, ScalePad); 	if (tks->sv)		r.min.x += tks->digwidth + ScalePad; 	if(tks->label != nil) {		p =  stringsize(e->font, tks->label);		r.max.x -= p.x;		string(i, Pt(r.max.x, r.min.y), tkgc(e, fgnd), ZP, e->font, tks->label);		r.max.x -= ScalePad;	} 	sr = insetrect(r, ScaleBW);	h = Dy(sr);	w = Dx(sr);	sl = tks->sl + 2*ScaleBW; 	l = tkgc(e, TkCbackgndlght);	d = tkgc(e, TkCbackgnddark);	tkbevel(i, r.min, w, h, ScaleBW, d, l); 	tks->pixmin = sr.min.y;	tks->pixmax = sr.max.y; 	sw = w - 2*ScaleBW;	tks->sw = sw/2; 	h -= sl;	if (h <= 0)		h = 1;	p.x = sr.max.x;	p.y = sr.min.y;	if(tks->tick > 0){		int j, t, l;		t = tks->tick;		l = tks->to-tks->from;		if (l < 0)			l = -l;		if (l == 0)			l = 1;		r2.min = p;		r2.max.x = p.x + ScaleBW + ScalePad;		for(j = 0; j <= l; j += t){			r2.min.y = p.y+((vlong)j*h)/l+sl/2;			r2.max.y = r2.min.y+1;			draw(i, r2, tkgc(e, fgnd), nil, ZP);		}	} 	v = tks->value-tks->from;	len  = tks->to-tks->from;	if (len != 0)		p.y += ((vlong)v*h)/len;	p.x = sr.min.x;	q = p;	if(ScaleBW > 1) {		q.x++;		gw = sw;	} else		gw = sw-1;	q.y += tks->sl/2 + 1;	if(tk->flag & Tkactivated) {		r2.min = p;		r2.max.x = sr.max.x;		r2.max.y = p.y+sl;		draw(i, r2, tkgc(e, TkCactivebgnd), nil, ZP);	}	switch(tks->relief) {	case TKsunken:		tkbevel(i, p, sw, tks->sl, ScaleBW, d, l);		tkbevel(i, q, gw, 0, 1, l, d);		break;	case TKraised:		tkbevel(i, p, sw, tks->sl, ScaleBW, l, d);		tkbevel(i, q, gw, 0, 1, d, l);		break;	}	tks->pixpos = p.y;	tks->center = p.x + sw/2 + ScaleBW; 	if(tks->sv != BoolT)		return; 	tkfprint(sv, tks->value);	if(tks->digits > 0 && tks->digits < strlen(sv))		sv[tks->digits] = '\0';

Lines 1–500 of 963.