forsyth20121205-174063a80cc13 years agoHistory
2220 lines · 41.5 KB · C
RawDownload
#include <lib9.h>#include <kernel.h>#include "draw.h"#include "tk.h"#include "canvs.h" /* Widget Commands (+ means implemented)	+addtag		except halo and start options of closest spec	+bbox	+bind	+canvasx	+canvasy	+cget	+configure	+coords	+create	+dchars	+delete	+dtag	+find	+focus	+gettags	+icursor	+index	+insert	+itemcget	+itemconfigure	+lower	+move	 postscript	+raise	+scale	 scan	+select	+type	+xview	+yview*/ staticTkStab tkbuffer[] = {	"visible",	TkCbufvisible,	"all",		TkCbufall,	"none",	TkCbufnone,	"auto",	TkCbufauto, 	/* backwards compatibility */	"1",		TkCbufall,	"yes",	TkCbufall,	"off",		TkCbufall,	"0",		TkCbufauto,	"no",		TkCbufauto,	"off",		TkCbufauto,	nil};	#define	O(t, e)		((long)(&((t*)0)->e))#define OA(t, e)	((long)(((t*)0)->e)) staticTkOption opts[] ={	"closeenough",		OPTfrac,	O(TkCanvas, close),	nil,	"confine",		OPTfrac,	O(TkCanvas, confine),	nil,	"scrollregion",		OPTfrac,	OA(TkCanvas, scrollr),	IAUX(4),	"xscrollincrement",	OPTfrac,	O(TkCanvas, xscrolli),	nil,	"yscrollincrement",	OPTfrac,	O(TkCanvas, yscrolli),	nil,	"xscrollcommand",	OPTtext,	O(TkCanvas, xscroll),	nil,	"yscrollcommand",	OPTtext,	O(TkCanvas, yscroll),	nil,	"width",		OPTnnfrac,	O(TkCanvas, width),	nil,	"height",		OPTnnfrac,	O(TkCanvas, height),	nil,	"buffer",		OPTstab,	O(TkCanvas, buffer),		tkbuffer,	"buffered",		OPTstab,	O(TkCanvas, buffer),	tkbool,	/* backwards compatibility */	"selectborderwidth",	OPTnndist, O(TkCanvas, sborderwidth), nil,	nil}; int cvslshape[] = { TKI2F(8), TKI2F(10), TKI2F(3) };Rectangle	bbnil = { 1000000, 1000000, -1000000, -1000000 };Rectangle	huger = { -1000000, -1000000, 1000000, 1000000 }; static void tkcvsgeom(Tk *tk);  static voidtkcvsf2i(Tk *tk, TkCanvas *tkc){	Rectangle r;	tk->req.width = TKF2I(tkc->width);	tk->req.height = TKF2I(tkc->height); 	r.min.x = TKF2I(tkc->scrollr[0]);	r.min.y = TKF2I(tkc->scrollr[1]);	r.max.x = TKF2I(tkc->scrollr[2]);	r.max.y = TKF2I(tkc->scrollr[3]); 	/*	 * make sure that the region is big enough to hold	 * the actually displayed area	 */	if (Dx(r) < tk->act.width)		r.max.x = r.min.x + tk->act.width;	if (Dy(r) < tk->act.height)		r.max.y = r.min.y + tk->act.height;	tkc->region = r; 	/*	 * make sure that the view origin is at a valid	 * position with respect to the scroll region.	 */	if (tkc->view.x + tk->act.width > r.max.x)		tkc->view.x = r.max.x - tk->act.width;	if (tkc->view.x < r.min.x)		tkc->view.x = r.min.x; 	if (tkc->view.y + tk->act.height > r.max.y)		tkc->view.y = r.max.y - tk->act.height;	if (tkc->view.y < r.min.y)		tkc->view.y = r.min.y; } char*tkcanvas(TkTop *t, char *arg, char **ret){	Tk *tk;	char *e;	TkCanvas *tkc;	TkName *names;	TkOptab tko[3]; 	tk = tknewobj(t, TKcanvas, sizeof(Tk)+sizeof(TkCanvas));	if(tk == nil)		return TkNomem; 	tkc = TKobj(TkCanvas, tk);	tkc->close = TKI2F(1);	tkc->xscrolli = TKI2F(1);	tkc->yscrolli = TKI2F(1);	tkc->width = TKI2F(360);	tkc->height = TKI2F(270);	tkc->actions = 0;	tkc->actlim = Tksweep;	tkc->mask = nil;	tkc->sborderwidth = 1; 	tko[0].ptr = tkc;	tko[0].optab = opts;	tko[1].ptr = tk;	tko[1].optab = tkgeneric;	tko[2].ptr = nil; 	names = nil;	e = tkparse(t, arg, tko, &names);	if(e != nil)		goto err;	if(names == nil) {		/* tkerr(t, arg); XXX */		e = TkBadwp;		goto err;	} 	tkc->current = tkmkname("current");	if(tkc->current == nil) {		e = TkNomem;		goto err;	} 	tksettransparent(tk, tkhasalpha(tk->env, TkCbackgnd));	tkcvsf2i(tk, tkc); 	e = tkaddchild(t, tk, &names);	tkfreename(names);	if(e != nil) {		tkfreename(tkc->current);		tkc->current = nil;		goto err;	}	tk->name->link = nil; 	e = tkvalue(ret, "%s", tk->name->name);	if(e == nil)	        return nil;		tkfreename(tkc->current);	return e;err:	tkfreeobj(tk);	return e;} voidtkcvsdirty(Tk *sub){	TkCanvas *c;	Tk *tk, *parent;	Rectangle r;	Point rel; 	rel = ZP;	for(tk = sub; tk;  tk = tk->master) {		rel.x += tk->borderwidth + tk->act.x;		rel.y += tk->borderwidth + tk->act.y;		if (tk->parent != nil)			break;	}	if (tk == nil)		return;	parent = tk->parent;	c = TKobj(TkCanvas, parent);	r = rectaddpt(sub->dirty, rel);	tkbbmax(&c->update, &r);	tkcvssetdirty(parent);} static voidtkcvsfocusorder(Tk *tk){	TkCanvas *tkc = TKobj(TkCanvas, tk);	TkCwind *win;	TkCitem *it;	TkWinfo *inf;	int i, n; 	n = 0;	for (it = tkc->head; it != nil; it = it->next) {		if (it->type == TkCVwindow) {			win = TKobj(TkCwind, it);			if (win->sub != nil)				n++;		}	}	if (n == 0)		return; 	inf = malloc(sizeof(*inf) * n);	if (inf == nil)		return; 	i = 0;	for (it = tkc->head; it != nil; it = it->next) {		if (it->type == TkCVwindow) {			win = TKobj(TkCwind, it);			if (win->sub != nil) {				inf[i].w = win->sub;				inf[i].r = it->p.bb;				i++;			}		}	} 	tksortfocusorder(inf, n);	for (i = 0; i < n; i++)		tkappendfocusorder(inf[i].w);} static char*tkcvscget(Tk *tk, char *arg, char **val){	TkOptab tko[3];	TkCanvas *tkc = TKobj(TkCanvas, tk); 	tko[0].ptr = tkc;	tko[0].optab = opts;	tko[1].ptr = tk;	tko[1].optab = tkgeneric;	tko[2].ptr = nil; 	return tkgencget(tko, arg, val, tk->env->top);} static char*tkcvsconf(Tk *tk, char *arg, char **val){	char *e;	int bd;	TkGeom g;	Rectangle r;	TkOptab tko[3];	TkCanvas *c = TKobj(TkCanvas, tk); 	tko[0].ptr = c;	tko[0].optab = opts;	tko[1].ptr = tk;	tko[1].optab = tkgeneric;	tko[2].ptr = nil; 	if(*arg == '\0')		return tkconflist(tko, val); 	r.min = c->view;	r.max.x = r.min.x+tk->act.width;	r.max.y = r.min.y+tk->act.height;	tkbbmax(&c->update, &r);	tkbbmax(&c->update, &c->region); 	bd = tk->borderwidth;	g = tk->req;	e = tkparse(tk->env->top, arg, tko, nil);	if(e != nil)		return e;	tksettransparent(tk, tkhasalpha(tk->env, TkCbackgnd)); 	tkcvsf2i(tk, c);		tkcvsgeom(tk);		tkgeomchg(tk, &g, bd);	tkbbmax(&c->update, &c->region);	tk->dirty = tkrect(tk, 1);	return nil;} voidtkcvsfreeitem(TkCitem *i){	int locked;	Display *d; 	d = i->env->top->display; 	locked = lockdisplay(d);	tkcimethod[i->type].free(i);	if(locked)		unlockdisplay(d); 	tkfreepoint(&i->p);	tkputenv(i->env);	free(i);} voidtkfreecanv(Tk *tk){	Display *d;	int j, locked;	TkCanvas *c;	TkName *n, *nn;	TkCtag *t, *tt;	TkCitem *i, *next; 	c = TKobj(TkCanvas, tk);	for(i = c->head; i; i = next) {		next = i->next;		tkcvsfreeitem(i);	} 	if(c->xscroll != nil)		free(c->xscroll);	if(c->yscroll != nil)		free(c->yscroll); 	for(j = 0; j < TkChash; j++) {		for(n = c->thash[j]; n; n = nn) {			nn = n->link;			for(t = n->obj; t; t = tt) {				tt = t->taglist;				free(t);			}			tkfreebind(n->prop.binds);			free(n);		}	} 	free(c->current); 	if((c->ialloc && c->image != nil) || c->mask != nil) {		if (c->ialloc && c->image != nil)			d = c->image->display;		else			d = c->mask->display;		locked = lockdisplay(d);		if (c->image != nil && c->ialloc)			freeimage(c->image);		if (c->mask != nil)			freeimage(c->mask);		if(locked)			unlockdisplay(d);	}} char*tkdrawcanv(Tk *tk, Point orig){	Image *dst;	TkCitem *i;	Display *d;	TkCanvas *c;	Rectangle r, bufr, oclipr;	int vis, alpha, buffer;	Point rel, p;	TkCimeth *imeth; 	c = TKobj(TkCanvas, tk);	d = tk->env->top->display;	dst = tkimageof(tk);	/*	 * translation from local to screen coords	 */	rel.x = orig.x + tk->act.x + tk->borderwidth;	rel.y = orig.y + tk->act.y + tk->borderwidth; 	buffer = c->buffer;	if (buffer == TkCbufauto)		buffer = TkCbufvisible;/*		buffer = (dst == TKobj(TkWin, tk->env->top->root)->image) ? TkCbufvisible : TkCbufnone; */ 	if (buffer == TkCbufnone) {		if(c->image != nil && c->ialloc)			freeimage(c->image);		c->image = dst;		c->ialloc = 0; 		r = tkrect(tk, 0);		bufr = r;		rectclip(&bufr, tk->dirty);		oclipr = dst->clipr; 		replclipr(dst, 0, rectaddpt(bufr, rel));		draw(dst, rectaddpt(bufr, rel), tkgc(tk->env, TkCbackgnd), nil, ZP); 		p = subpt(rel, c->view);		p.x = TKI2F(p.x);		p.y = TKI2F(p.y);		bufr = rectaddpt(bufr, c->view);		for(i = c->head; i; i = i->next) {			if(rectXrect(i->p.bb, bufr)) {				imeth = &tkcimethod[i->type];				imeth->coord(i, nil, p.x, p.y);				imeth->draw(dst, i, tk->env);				imeth->coord(i, nil, -p.x, -p.y);			}		}		replclipr(dst, 0, oclipr);	} else {		if (c->buffer == TkCbufall)			bufr = c->region;		else {			bufr.min = c->view;			bufr.max.x = c->view.x + tk->act.width;			bufr.max.y = c->view.y + tk->act.height;		}		alpha = (tk->env->colors[TkCbackgnd] & 0xff) != 0xff;		if(c->image == nil || eqrect(bufr, c->image->r) == 0) {			if(c->image != nil && c->ialloc)				freeimage(c->image);			c->image = allocimage(d, bufr, alpha?RGBA32:d->image->chan, 0, tk->env->colors[TkCbackgnd]);			c->ialloc = 1;			c->update = bufr;			tkcvssetdirty(tk);		/* unnecessary? */		}			if(c->image == nil)			return nil;			r = c->update;		if (rectclip(&r, c->image->r)) {			if (alpha)				drawop(c->image, c->update, nil, nil, ZP, Clear);			draw(c->image, c->update, tkgc(tk->env, TkCbackgnd), nil, c->view);			replclipr(c->image, 0, r);			for(i = c->head; i; i = i->next) {				if(rectXrect(i->p.bb, r))					tkcimethod[i->type].draw(c->image, i, tk->env);			}			replclipr(c->image, 0, c->image->r);		}		/*		 * if the visible area of the canvas image doesn't		 * fit completely within the dirty rectangle,		 * then we'll need to draw the background behind it		 */		r = tkrect(tk, 0);		bufr = rectsubpt(bufr, c->view);		vis = rectclip(&bufr, tkrect(tk, 0));			if (!vis || !rectinrect(tk->dirty, bufr))			draw(dst, rectaddpt(tk->dirty, rel), tkgc(tk->env, TkCbackgnd), nil, c->view);			if (vis && rectclip(&bufr, tk->dirty))			draw(dst, rectaddpt(bufr, rel), c->image, nil, addpt(bufr.min, c->view));	}  	/*	 * if the border is dirty too, then draw that	 */	if (!rectinrect(tk->dirty, bufr)) {		r.min = addpt(r.min, rel);		r.min.x -= tk->borderwidth;		r.min.y -= tk->borderwidth;		tkdrawrelief(dst, tk, r.min, TkCbackgnd, tk->relief);	}	c->update = bbnil;	return nil;} voidtkcvsappend(TkCanvas *c, TkCitem *i){

Lines 1–500 of 2220.