Charles.Forsyth20060303a828770d19 years agoHistory
408 lines · 7.5 KB · C
RawDownload
#include "lib9.h"#include "draw.h"#include "tk.h" #define	O(t, e)		((long)(&((t*)0)->e)) typedef struct TkPanel TkPanel;struct TkPanel{	Image*	image;	Image*	matte;	Point		view;	/* vector from image origin to widget origin */	Rectangle		r;		/* drawn rectangle (in image coords) */	int		anchor;	int		hasalpha;	/* does the image include an alpha channel? */}; static TkOption tkpanelopts[] ={	"anchor",	OPTflag,	O(TkPanel, anchor),	tkanchor,	nil}; static inttkdrawnrect(Image *image, Image *matte, Rectangle *r){	*r = image->clipr;	if (matte != nil) {		if (!rectclip(r, matte->clipr))			return 0;		if (!matte->repl && !rectclip(r, matte->r))			return 0;	}	if (!image->repl && !rectclip(r, image->r))		return 0;	return 1;} char*tkpanel(TkTop *t, char *arg, char **ret){	TkOptab tko[3];	Tk *tk;	TkPanel *tkp;	TkName *names;	char *e; 	tk = tknewobj(t, TKpanel, sizeof(Tk)+sizeof(TkPanel));	if(tk == nil)		return TkNomem; 	tkp = TKobj(TkPanel, tk);	tkp->anchor = Tkcenter; 	tko[0].ptr = tk;	tko[0].optab = tkgeneric;	tko[1].ptr = tkp;	tko[1].optab = tkpanelopts;	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)); 	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);} voidtkgetpanelimage(Tk *tk, Image **i, Image **m){	TkPanel *tkp = TKobj(TkPanel, tk);	*i = tkp->image;	*m = tkp->matte;} voidtksetpanelimage(Tk *tk, Image *image, Image *matte){	TkPanel *tkp = TKobj(TkPanel, tk);	int ishuge;	TkGeom g; 	g = tk->req; 	tkp->image = image;	tkp->matte = matte; 	if (!tkdrawnrect(image, matte, &tkp->r)) {		tkp->r.min = image->r.min;		tkp->r.max = image->r.min;	} 	tkp->view = tkp->r.min;		/* XXX do we actually want to keep the old one? */	/*	 * if both image and matte are replicated, then we've got no idea what	 * the rectangle should be, so request zero size, and set origin to (0, 0).	 */	ishuge = (Dx(tkp->r) >= 10000000);	if((tk->flag & Tksetwidth) == 0){		if(ishuge)			tk->req.width = 0;		else			tk->req.width = Dx(tkp->r);	}	if(ishuge)		tkp->view.x = 0; 	ishuge = (Dy(tkp->r) >= 10000000);	if((tk->flag & Tksetheight) == 0){		if(ishuge)			tk->req.height = 0;		else			tk->req.height = Dy(tkp->r);	}	if(ishuge)		tkp->view.y = 0; 	tkp->hasalpha = tkchanhastype(image->chan, CAlpha);	tkgeomchg(tk, &g, tk->borderwidth);	tksettransparent(tk, tkp->hasalpha || tkhasalpha(tk->env, TkCbackgnd));	tk->dirty = tkrect(tk, 0);} static voidtkfreepanel(Tk *tk){	TkPanel *tkp = TKobj(TkPanel, tk);	tkdelpanelimage(tk->env->top, tkp->image);	tkdelpanelimage(tk->env->top, tkp->matte);} static Pointtkpanelview(Tk *tk){	int dx, dy;	Point view;	TkPanel *tkp = TKobj(TkPanel, tk);		dx = tk->act.width - Dx(tkp->r);	dy = tk->act.height - Dy(tkp->r); 	view = tkp->view; 	if (dx > 0) {		if((tkp->anchor & (Tkeast|Tkwest)) == 0)			view.x -= dx/2;		else		if(tkp->anchor & Tkeast)			view.x -= dx;	}	if (dy > 0) {		if((tkp->anchor & (Tknorth|Tksouth)) == 0)			view.y -= dy/2;		else		if(tkp->anchor & Tksouth)			view.y -= dy;	}	return view;} static char*tkdrawpanel(Tk *tk, Point orig){	Rectangle r, pr;	TkPanel *tkp = TKobj(TkPanel, tk);	Image *i;	int any;	Point view, p; 	i = tkimageof(tk);	if (i == nil)		return nil; 	p.x = orig.x + tk->act.x + tk->borderwidth;	p.y = orig.y + tk->act.y + tk->borderwidth; 	view = tkpanelview(tk); 	/*	 * if the image doesn't fully cover the dirty rectangle, then	 * paint some background in there	 */	r = rectsubpt(tkp->r, view);		/* convert to widget coords */	pr = tkrect(tk, 0);	any = rectclip(&r, pr);				/* clip to inside widget borders */ 	if (!any || tkp->hasalpha || !rectinrect(tk->dirty, r))		draw(i, rectaddpt(tk->dirty, p), tkgc(tk->env, TkCbackgnd), nil, ZP); 	if (any && rectclip(&r, tk->dirty))		draw(i, rectaddpt(r, p), tkp->image, tkp->matte, addpt(r.min, view)); 	if (!rectinrect(tk->dirty, pr)) {		p.x -= tk->borderwidth;		p.y -= tk->borderwidth;		tkdrawrelief(i, tk, p, TkCbackgnd, tk->relief);	}	return nil;} static char*tkpanelcget(Tk *tk, char *arg, char **val){	TkOptab tko[3];	TkPanel *tkp = TKobj(TkPanel, tk); 	tko[0].ptr = tk;	tko[0].optab = tkgeneric;	tko[1].ptr = tkp;	tko[1].optab = tkpanelopts;	tko[2].ptr = nil; 	return tkgencget(tko, arg, val, tk->env->top);} static char*tkpanelcvt(Tk *tk, char *arg, int rel, int *p){	char buf[Tkmaxitem]; 	tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);	if(buf[0] == '\0')		return TkBadvl;	*p = atoi(buf) + rel;	return nil;} /* * screen to image */static char*tkpanelpanelx(Tk *tk, char *arg, char **val){	Point p;	char *e; 	USED(val);	p = subpt(tkposn(tk), tkpanelview(tk));	e = tkpanelcvt(tk, arg, -p.x, &p.x);	if (e != nil)		return e;	return tkvalue(val, "%d", p.x);} static char*tkpanelpanely(Tk *tk, char *arg, char **val){	Point p;	char *e; 	USED(val);	p = subpt(tkposn(tk), tkpanelview(tk));	e = tkpanelcvt(tk, arg, -p.y, &p.y);	if (e != nil)		return e;	return tkvalue(val, "%d", p.y);} /* * image to screen */static char*tkpanelscreenx(Tk *tk, char *arg, char **val){	Point p;	char *e; 	USED(val);	p = subpt(tkposn(tk), tkpanelview(tk));	e = tkpanelcvt(tk, arg, p.x, &p.x);	if (e != nil)		return e;	return tkvalue(val, "%d", p.x);} static char*tkpanelscreeny(Tk *tk, char *arg, char **val){	Point p;	char *e; 	USED(val);	p = subpt(tkposn(tk), tkpanelview(tk));	e = tkpanelcvt(tk, arg, p.y, &p.y);	if (e != nil)		return e;	return tkvalue(val, "%d", p.y);} static char*tkpanelconf(Tk *tk, char *arg, char **val){	char *e;	TkGeom g;	int bd;	TkOptab tko[3];	TkPanel *tkp = TKobj(TkPanel, tk); 	tko[0].ptr = tk;	tko[0].optab = tkgeneric;	tko[1].ptr = tkp;	tko[1].optab = tkpanelopts;	tko[2].ptr = nil; 	if(*arg == '\0')		return tkconflist(tko, val); 	g = tk->req;	bd = tk->borderwidth;	e = tkparse(tk->env->top, arg, tko, nil);	tkgeomchg(tk, &g, bd);	tksettransparent(tk, tkp->hasalpha || tkhasalpha(tk->env, TkCbackgnd)); 	tk->dirty = tkrect(tk, 1); 	return e;} static char*tkpaneldirty(Tk *tk, char *arg, char **val){	char buf[Tkmaxitem];	int n, coords[4];	Rectangle r;	char *e, *p;	TkPanel *tkp = TKobj(TkPanel, tk); 	USED(val);	n = 0;	while (n < 4) {		arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);		if (buf[0] == 0)			break;		p = buf;		e = tkfrac(&p, &coords[n++], nil);		if (e != nil)			return TkBadvl;	}	if (n == 0)		r = tkp->r;	else {		 if (n != 4)			return TkBadvl;		r.min.x = TKF2I(coords[0]);		r.min.y = TKF2I(coords[1]);		r.max.x = TKF2I(coords[2]);		r.max.y = TKF2I(coords[3]);	}	if (rectclip(&r, tkp->r)) {		r = rectsubpt(r, tkpanelview(tk));		/* convert to widget coords */		if (rectclip(&r, tkrect(tk, 0)))			/* clip to visible area */			combinerect(&tk->dirty, r);	}	return nil;} static char*tkpanelorigin(Tk *tk, char *arg, char **val){	char *e;	Point view;	TkPanel *tkp = TKobj(TkPanel, tk); 	e = tkxyparse(tk, &arg, &view);	if (e != nil) {		if (e == TkOparg)			return tkvalue(val, "%d %d", tkp->view.x, tkp->view.y);		return e;	}	tkp->view = view;	tk->dirty = tkrect(tk, 0);	return nil;} staticTkCmdtab tkpanelcmd[] ={	"cget",			tkpanelcget,	"configure",		tkpanelconf,	"dirty",			tkpaneldirty,	"origin",			tkpanelorigin,	"panelx",			tkpanelpanelx,	"panely",			tkpanelpanely,	"screenx",			tkpanelscreenx,	"screeny",			tkpanelscreeny,	nil}; TkMethod panelmethod = {	"panel",	tkpanelcmd,	tkfreepanel,	tkdrawpanel};