forsyth20121205-174063a80cc13 years agoHistory
389 lines · 6.6 KB · C
RawDownload
#include "lib9.h"#include "draw.h"#include "tk.h"#include "textw.h" #define istring u.string#define iwin u.win#define imark u.mark#define iline u.line #define	O(t, e)		((long)(&((t*)0)->e)) static char* tktwincget(Tk*, char*, char**);static char* tktwinconfigure(Tk*, char*, char**);static char* tktwincreate(Tk*, char*, char**);static char* tktwinnames(Tk*, char*, char**);static int winowned(Tk *tk, Tk *sub); staticTkStab tkalign[] ={	"top",		Tktop,	"bottom",	Tkbottom,	"center",	Tkcenter,	"baseline",	Tkbaseline,	nil}; staticTkOption twinopts[] ={	"align",	OPTstab,	O(TkTwind, align),	tkalign,	"create",	OPTtext,	O(TkTwind, create),	nil,	"padx",		OPTnndist,	O(TkTwind, padx),	nil,	"pady",		OPTnndist,	O(TkTwind, pady),	nil,	"stretch",	OPTstab,	O(TkTwind, stretch),	tkbool,	"window",	OPTwinp,	O(TkTwind, sub),	nil,	"ascent",	OPTdist,	O(TkTwind, ascent), nil,	nil}; TkCmdtabtktwincmd[] ={	"cget",		tktwincget,	"configure",	tktwinconfigure,	"create",	tktwincreate,	"names",	tktwinnames,	nil}; inttktfindsubitem(Tk *sub, TkTindex *ix){	Tk *tk, *isub;	TkText *tkt; 	tk = sub->parent;	if(tk != nil) {		tkt = TKobj(TkText, tk);		tktstartind(tkt, ix);		do {			if(ix->item->kind == TkTwin) {				isub = ix->item->iwin->sub;				if(isub != nil && 				   isub->name != nil && 				   strcmp(isub->name->name, sub->name->name) == 0)				return 1;			}		} while(tktadjustind(tkt, TkTbyitem, ix));	}	return 0;} static voidtktwindsize(Tk *tk, TkTindex *ix){	Tk *s;	TkTitem *i;	TkTwind *w;  	i = ix->item;	/* assert(i->kind == TkTwin); */ 	w = i->iwin;	s = w->sub;	if(s == nil)		return; 	if(w->width != s->act.width || w->height != s->act.height) {		s->act.width = w->width;		s->act.height = w->height;		if(s->slave) {			tkpackqit(s);			tkrunpack(tk->env->top);		}	} 	tktfixgeom(tk, tktprevwrapline(tk, ix->line), ix->line, 0);	tktextsize(tk, 1);} voidtktxtforgetsub(Tk *sub, Tk *tk){	TkTwind *w;	TkTindex ix; 	if(!tktfindsubitem(sub, &ix))		return;	w = ix.item->iwin;	if(w->focus == tk) {if(0)print("tktxtforget sub %p %q focus %p %q\n", sub, tkname(sub), tk, tkname(tk));		w->focus = nil;	}} static voidtktwingeom(Tk *sub, int x, int y, int w, int h){	TkTindex ix;	Tk *tk;	TkTwind *win; 	USED(x);	USED(y); 	tk = sub->parent;	if(!tktfindsubitem(sub, &ix)) {		print("tktwingeom: %s not found\n", sub->name->name);		return;	} 	win = ix.item->iwin; 	win->width = w;	win->height = h; 	sub->req.width = w;	sub->req.height = h;	tktwindsize(tk, &ix);} static voidtktdestroyed(Tk *sub){	TkTindex ix;	Tk *tk; 	if(tktfindsubitem(sub, &ix)) {		ix.item->iwin->sub = nil;		ix.item->iwin->focus = nil;		if((tk = sub->parent) != nil) {			tktfixgeom(tk, tktprevwrapline(tk, ix.line), ix.line, 0);			tktextsize(tk, 1);			sub->parent = nil;		}	}} voidtktdirty(Tk *sub){	Tk *tk, *parent, *isub;	TkText *tkt;	TkTindex ix; 	parent = nil;	for(tk = sub; tk && parent == nil; tk = tk->master)		parent = tk->parent;	if(tk == nil)		return; 	tkt = TKobj(TkText, parent);	tktstartind(tkt, &ix);	do {		if(ix.item->kind == TkTwin) {			isub = ix.item->iwin->sub;			if(isub != nil) {				tktfixgeom(parent, tktprevwrapline(parent, ix.line), ix.line, 0);				if (sub->flag & Tktransparent)					parent->flag |= Tkrefresh;	/* XXX could be more efficient, by drawing the background locally? */				return;			}		}	} while(tktadjustind(tkt, TkTbyitem, &ix));	tktextsize(parent, 1);} static char*tktwinchk(Tk *tk, TkTwind *w, Tk *oldsub){	Tk *sub; 	sub = w->sub;	if (sub != oldsub) {		w->sub = oldsub;		if(sub == nil)			return nil; 		if(sub->flag & Tkwindow)			return TkIstop;			if(sub->master != nil || sub->parent != nil)			return TkWpack; 		if (oldsub != nil) {			oldsub->parent = nil;			oldsub->geom = nil;			oldsub->destroyed = nil;		}		w->sub = sub;		w->focus = nil; 		sub->parent = tk;		tksetbits(sub, Tksubsub);		sub->geom = tktwingeom;		sub->destroyed = tktdestroyed; 		w->width = sub->req.width;		w->height = sub->req.height;		w->owned = winowned(tk, sub);	} 	return nil;}  /* Text Window Command (+ means implemented)	+cget	+configure	+create	+names*/ static char*tktwincget(Tk *tk, char *arg, char **val){	char *e;	TkTindex ix;	TkOptab tko[2]; 	e = tktindparse(tk, &arg, &ix);	if(e != nil)		return e;	if(ix.item->kind != TkTwin)		return TkBadwp; 	tko[0].ptr = ix.item->iwin;	tko[0].optab = twinopts;	tko[1].ptr = nil; 	return tkgencget(tko, arg, val, tk->env->top);} static char*tktwinconfigure(Tk *tk, char *arg, char **val){	char *e;	TkTindex ix;	TkOptab tko[2];	Tk *oldsub; 	USED(val); 	e = tktindparse(tk, &arg, &ix);	if(e != nil)		return e;	if(ix.item->kind != TkTwin)		return TkBadwp; 	oldsub = ix.item->iwin->sub; 	tko[0].ptr = ix.item->iwin;	tko[0].optab = twinopts;	tko[1].ptr = nil; 	e = tkparse(tk->env->top, arg, tko, nil);	if(e != nil)		return e; 	e = tktwinchk(tk, ix.item->iwin, oldsub);	if(e != nil)		return e; 	tktwindsize(tk, &ix);	return nil;} /* * return true if tk is an ancestor of sub */static intwinowned(Tk *tk, Tk *sub){	int len;	if (tk->name == nil || sub->name == nil)		return 0;	len = strlen(tk->name->name);	if (strncmp(tk->name->name, sub->name->name, len) == 0 &&			sub->name->name[len] == '.')		return 1;	return 0;} static char*tktwincreate(Tk *tk, char *arg, char **val){	char *e;	TkTindex ix;	TkTitem *i;	TkText *tkt;	TkOptab tko[2]; 	USED(val); 	tkt = TKobj(TkText, tk); 	e = tktindparse(tk, &arg, &ix);	if(e != nil)		return e; 	e = tktnewitem(TkTwin, 0, &i);	if(e != nil)		return e; 	i->iwin = malloc(sizeof(TkTwind));	if(i->iwin == nil) {		tktfreeitems(tkt, i, 1);		return TkNomem;	} 	memset(i->iwin, 0, sizeof(TkTwind));	i->iwin->align = Tkcenter;	i->iwin->ascent = -1; 	tko[0].ptr = i->iwin;	tko[0].optab = twinopts;	tko[1].ptr = nil; 	e = tkparse(tk->env->top, arg, tko, nil);	if(e != nil) {    err1:		tktfreeitems(tkt, i, 1);		return e;	} 	e = tktwinchk(tk, i->iwin, nil);	if(e != nil)		goto err1; 	e = tktsplititem(&ix);	if(e != nil)		goto err1; 	tktiteminsert(tkt, &ix, i);	if(e != nil)		goto err1; 	tktadjustind(tkt, TkTbyitemback, &ix);	tktwindsize(tk, &ix); 	return nil;} static char*tktwinnames(Tk *tk, char *arg, char **val){	char *e, *fmt;	TkTindex ix;	TkText *tkt = TKobj(TkText, tk); 	USED(arg); 	tktstartind(tkt, &ix);	fmt = "%s";	do {		if(ix.item->kind == TkTwin &&		   ix.item->iwin->sub != nil &&                     ix.item->iwin->sub->name != nil) {			e = tkvalue(val, fmt, ix.item->iwin->sub->name->name);			if(e != nil)				return e;			fmt = " %s";		}	} while(tktadjustind(tkt, TkTbyitem, &ix));	return nil;}