737 lines · 18.8 KB · C
RawDownload
#include <u.h>#include <libc.h>#include <thread.h>#include <draw.h>#include <mouse.h>#include <keyboard.h>#include <control.h>#include "group.h" static int debug = 0;static int debugm = 0;static int debugr = 0; enum{	EAdd,	EBorder,	EBordercolor,	EFocus,	EHide,	EImage,	ERect,	ERemove,	EReveal,	ESeparation,	EShow,	ESize,}; static char *cmds[] = {	[EAdd] =			"add",	[EBorder] =		"border",	[EBordercolor] =	"bordercolor",	[EFocus] = 		"focus",	[EHide] =			"hide",	[EImage] =		"image",	[ERect] =			"rect",	[ERemove] =		"remove",	[EReveal] =		"reveal",	[ESeparation] =		"separation",	[EShow] =			"show",	[ESize] =			"size",}; static void		boxboxresize(Group*, Rectangle);static void		columnresize(Group*, Rectangle);static void		groupctl(Control *c, CParse *cp);static void		groupfree(Control*);static void		groupmouse(Control *, Mouse *);static void		groupsize(Control *c);static void		removegroup(Group*, int);static void		rowresize(Group*, Rectangle);static void		stackresize(Group*, Rectangle); static voidgroupinit(Group *g){	g->bordercolor = _getctlimage("black");	g->image = _getctlimage("white");	g->border = 0;	g->mansize = 0;	g->separation = 0;	g->selected = -1;	g->lastkid = -1;	g->kids = nil;	g->separators = nil;	g->nkids = 0;	g->nseparators = 0;	g->ctl = groupctl;	g->mouse = groupmouse;	g->exit = groupfree;} static voidgroupctl(Control *c, CParse *cp){	int cmd, i, n;		Rectangle r;	Group *g; 	g = (Group*)c;	cmd = _ctllookup(cp->args[0], cmds, nelem(cmds));	switch(cmd){	case EAdd:		for (i = 1; i < cp->nargs; i++){			c = controlcalled(cp->args[i]);			if (c == nil)				ctlerror("%q: no such control: %s", g->name, cp->args[i]);			_ctladdgroup(g, c);		}		if (g->setsize)			g->setsize((Control*)g);		break;	case EBorder:		_ctlargcount(g, cp, 2);		if(cp->iargs[1] < 0)			ctlerror("%q: bad border: %c", g->name, cp->str);		g->border = cp->iargs[1];		break;	case EBordercolor:		_ctlargcount(g, cp, 2);		_setctlimage(g, &g->bordercolor, cp->args[1]);		break;	case EFocus:		/* ignore focus change */		break;	case EHide:		_ctlargcount(g, cp, 1);		for (i = 0; i < g->nkids; i++)			if (g->kids[i]->ctl)				_ctlprint(g->kids[i], "hide");		g->hidden = 1;		break;	case EImage:		_ctlargcount(g, cp, 2);		_setctlimage(g, &g->image, cp->args[1]);		break;	case ERect:		_ctlargcount(g, cp, 5);		r.min.x = cp->iargs[1];		r.min.y = cp->iargs[2];		r.max.x = cp->iargs[3];		r.max.y = cp->iargs[4];		if(Dx(r)<=0 || Dy(r)<=0)			ctlerror("%q: bad rectangle: %s", g->name, cp->str);		g->rect = r;		r = insetrect(r, g->border);		if (g->nkids == 0)			return;		switch(g->type){		case Ctlboxbox:			boxboxresize(g, r);			break;		case Ctlcolumn:			columnresize(g, r);			break;		case Ctlrow:			rowresize(g, r);			break;		case Ctlstack:			stackresize(g, r);			break;		}		break;	case ERemove:		_ctlargcount(g, cp, 2);		for (n = 0; n < g->nkids; n++)			if (strcmp(cp->args[1], g->kids[n]->name) == 0)				break;		if (n == g->nkids)			ctlerror("%s: remove nonexistent control: %q", g->name, cp->args[1]);		removegroup(g, n);		if (g->setsize)			g->setsize((Control*)g);		break;	case EReveal:		g->hidden = 0;		if (debugr) fprint(2, "reveal %s\n", g->name);		if (g->type == Ctlstack){			if (cp->nargs == 2){				if (cp->iargs[1] < 0 || cp->iargs[1] >= g->nkids)					ctlerror("%s: control out of range: %q", g->name, cp->str);				g->selected = cp->iargs[1];			}else				_ctlargcount(g, cp, 1);			for (i = 0; i < g->nkids; i++)				if (g->kids[i]->ctl){					if (g->selected == i){						if (debugr) fprint(2, "reveal %s: reveal kid %s\n", g->name, g->kids[i]->name);						_ctlprint(g->kids[i], "reveal");					}else{						if (debugr) fprint(2, "reveal %s: hide kid %s\n", g->name, g->kids[i]->name);						_ctlprint(g->kids[i], "hide");					}				}			break;		}		_ctlargcount(g, cp, 1);		if (debug) fprint(2, "reveal %s: border %R/%d\n", g->name, g->rect, g->border);		border(g->screen, g->rect, g->border, g->bordercolor->image, g->bordercolor->image->r.min);		r = insetrect(g->rect, g->border);		if (debug) fprint(2, "reveal %s: draw %R\n", g->name, r);		draw(g->screen, r, g->image->image, nil, g->image->image->r.min);		for (i = 0; i < g->nkids; i++)			if (g->kids[i]->ctl)				_ctlprint(g->kids[i], "reveal");		break;	case EShow:		_ctlargcount(g, cp, 1);		if (g->hidden)			break;		// pass it on to the kiddies		if (debug) fprint(2, "show %s: border %R/%d\n", g->name, g->rect, g->border);		border(g->screen, g->rect, g->border, g->bordercolor->image, g->bordercolor->image->r.min);		r = insetrect(g->rect, g->border);		if (debug) fprint(2, "show %s: draw %R\n", g->name, r);		draw(g->screen, r, g->image->image, nil, g->image->image->r.min);		for (i = 0; i < g->nkids; i++)			if (g->kids[i]->ctl){				if (debug) fprint(2, "show %s: kid %s: %q\n", g->name, g->kids[i]->name, cp->str);				_ctlprint(g->kids[i], "show");			}		flushimage(display, 1);		break;	case ESize:		r.max = Pt(_Ctlmaxsize, _Ctlmaxsize);		if (g->type == Ctlboxbox)			_ctlargcount(g, cp, 5);		switch(cp->nargs){		default:			ctlerror("%s: args of %q", g->name, cp->str);		case 1:			/* recursively set size */			g->mansize = 0;			if (g->setsize)				g->setsize((Control*)g);			break;		case 5:			_ctlargcount(g, cp, 5);			r.max.x = cp->iargs[3];			r.max.y = cp->iargs[4];			/* fall through */		case 3:			r.min.x = cp->iargs[1];			r.min.y = cp->iargs[2];			if(r.min.x<=0 || r.min.y<=0 || r.max.x<=0 || r.max.y<=0 || r.max.x < r.min.x || r.max.y < r.min.y)			ctlerror("%q: bad sizes: %s", g->name, cp->str);			g->size = r;			g->mansize = 1;			break;		}		break;	case ESeparation:		if (g->type != Ctlstack){			_ctlargcount(g, cp, 2);			if(cp->iargs[1] < 0)				ctlerror("%q: illegal value: %c", g->name, cp->str);			g->separation = cp->iargs[1];			break;		}		// fall through for Ctlstack	default:		ctlerror("%q: unrecognized message '%s'", g->name, cp->str);		break;	}} static voidgroupfree(Control *c){	Group *g; 	g = (Group*)c;	_putctlimage(g->bordercolor);	free(g->kids);} static voidgroupmouse(Control *c, Mouse *m){	Group *g;	int i, lastkid; 	g = (Group*)c;	if (g->type == Ctlstack){		i = g->selected;		if (i >= 0 && g->kids[i]->mouse &&                        ( ( ((m->buttons == 0) || (g->lastbut == 0)) &&                           ptinrect(m->xy, g->kids[i]->rect) ) ||                         ( ((m->buttons != 0) || (g->lastbut != 0)) &&		         (g->lastkid == i) ) ) ) {			if (debugm) fprint(2, "groupmouse %s mouse kid %s i=%d lastkid=%d buttons=%d lastbut=%d inrect=%d\n",						g->name, g->kids[i]->name, i, g->lastkid, m->buttons, g->lastbut,						ptinrect(m->xy, g->kids[i]->rect) ? 1 : 0);			(g->kids[i]->mouse)(g->kids[i], m);			g->lastkid = i;			g->lastbut = m->buttons;		} else {			if (debugm) fprint(2, "groupmouse %s skip kid %s i=%d lastkid=%d buttons=%d lastbut=%d inrect=%d\n",						g->name, g->kids[i]->name, i, g->lastkid, m->buttons, g->lastbut,						ptinrect(m->xy, g->kids[i]->rect) ? 1 : 0);		}		return;	} 	lastkid = -1;	for(i=0; i<g->nkids; i++) {		if(g->kids[i]->mouse &&                      ( ( ((m->buttons == 0) || (g->lastbut == 0)) &&                           ptinrect(m->xy, g->kids[i]->rect) ) ||                        ( ((m->buttons != 0) || (g->lastbut != 0)) &&		         (g->lastkid == i) ) ) ) {			if (debugm) fprint(2, "groupmouse %s mouse kid %s i=%d lastkid=%d buttons=%d lastbut=%d inrect=%d\n",						g->name, g->kids[i]->name, i, g->lastkid, m->buttons, g->lastbut,						ptinrect(m->xy, g->kids[i]->rect) ? 1 : 0);			(g->kids[i]->mouse)(g->kids[i], m);			lastkid = i;		} else {			if (debugm) fprint(2, "groupmouse %s skip kid %s i=%d lastkid=%d buttons=%d lastbut=%d inrect=%d\n",						g->name, g->kids[i]->name, i, g->lastkid, m->buttons, g->lastbut,						ptinrect(m->xy, g->kids[i]->rect) ? 1 : 0);		}	}	g->lastkid = lastkid;	g->lastbut = m->buttons; #ifdef notdef	if(m->buttons == 0){		/* buttons now up */		g->lastbut = 0;		return;	}	if(g->lastbut == 0 && m->buttons != 0){		/* button went down, start tracking border */		switch(g->stacking){		default:			return;		case Vertical:			p = Pt(m->xy.x, middle_of_border.y);			p0 = Pt(g->r.min.x, m->xy.y);			p1 = Pt(g->r.max.x, m->xy.y);			break;		case Horizontal:			p = Pt(middle_of_border.x, m->xy.y);			p0 = Pt(m->xy.x, g->r.min.y);			p1 = Pt(m->xy.x, g->r.max.y);			break;		}	//	setcursor();		oi = nil;	} else if (g->lastbut != 0 && s->m.buttons != 0){		/* button is down, keep tracking border */		if(!eqpt(s->m.xy, p)){			p = onscreen(s->m.xy);			r = canonrect(Rpt(p0, p));			if(Dx(r)>5 && Dy(r)>5){				i = allocwindow(wscreen, r, Refnone, 0xEEEEEEFF); /* grey */				freeimage(oi);				if(i == nil)					goto Rescue;				oi = i;				border(i, r, Selborder, red, ZP);				flushimage(display, 1);			}		}	} else if (g->lastbut != 0 && s->m.buttons == 0){		/* button went up, resize kiddies */	}	g->lastbut = s->m.buttons;#endif} static voidactivategroup(Control *c, int act){	int i;	Group *g; 	g = (Group*)c;	for (i = 0; i < g->nkids; i++)		if (act)			activate(g->kids[i]);		else			deactivate(g->kids[i]);} Control *createrow(Controlset *cs, char *name){	Control *c;	c = _createctl(cs, "row", sizeof(Group), name);	groupinit((Group*)c);	c->setsize = groupsize;	c->activate = activategroup;	return c;} Control *createcolumn(Controlset *cs, char *name){	Control *c;	c = _createctl(cs, "column", sizeof(Group), name);	groupinit((Group*)c);	c->setsize = groupsize;	c->activate = activategroup;	return c;} Control *createboxbox(Controlset *cs, char *name){	Control *c;	c = _createctl(cs, "boxbox", sizeof(Group), name);	groupinit((Group*)c);	c->activate = activategroup;	return c;} Control *createstack(Controlset *cs, char *name){	Control *c;	c = _createctl(cs, "stack", sizeof(Group), name);	groupinit((Group*)c);	c->setsize = groupsize;	return c;} void_ctladdgroup(Control *c, Control *q){	Group *g = (Group*)c; 	g->kids = ctlrealloc(g->kids, sizeof(Group*)*(g->nkids+1));	g->kids[g->nkids++] = q;} static voidremovegroup(Group *g, int n){	int i; 	if (g->selected == n)		g->selected = -1;	else if (g->selected > n)		g->selected--; 	for (i = n+1; i < g->nkids; i++)		g->kids[i-1] = g->kids[i];	g->nkids--;} static voidgroupsize(Control *c){	Rectangle r;	int i;	Control *q;	Group *g; 	g = (Group*)c;	assert(g->type == Ctlcolumn || g->type == Ctlrow || g->type == Ctlstack);	if (g->mansize) return;	r = Rect(1, 1, 1, 1);	if (debug) fprint(2, "groupsize %q\n", g->name);	for (i = 0; i < g->nkids; i++){		q = g->kids[i];		if (q->setsize)			q->setsize(q);		if (q->size.min.x == 0 || q->size.min.y == 0 || q->size.max.x == 0 || q->size.max.y == 0)			ctlerror("%q: bad size %R", q->name, q->size);		if (debug) fprint(2, "groupsize %q: [%d %q]: %R\n", g->name, i, q->name, q->size);		switch(g->type){		case Ctlrow:			if (i)				r.min.x += q->size.min.x + g->border;			else				r.min.x = q->size.min.x;			if (i)				r.max.x += q->size.max.x + g->border;			else				r.max.x = q->size.max.x;			if (r.min.y < q->size.min.y) r.min.y = q->size.min.y;			if (r.max.y < q->size.max.y) r.max.y = q->size.max.y;			break;		case Ctlcolumn:			if (r.min.x < q->size.min.x) r.min.x = q->size.min.x;			if (r.max.x < q->size.max.x) r.max.x = q->size.max.x;			if (i)				r.min.y += q->size.min.y + g->border;			else				r.min.y = q->size.min.y;			if (i)				r.max.y += q->size.max.y + g->border;			else				r.max.y = q->size.max.y;			break;		case Ctlstack:			if (r.min.x < q->size.min.x) r.min.x = q->size.min.x;			if (r.max.x < q->size.max.x) r.max.x = q->size.max.x;			if (r.min.y < q->size.min.y) r.min.y = q->size.min.y;			if (r.max.y < q->size.max.y) r.max.y = q->size.max.y;			break;		}	}	g->size = rectaddpt(r, Pt(g->border, g->border));	if (debug) fprint(2, "groupsize %q: %R\n", g->name, g->size);} static voidboxboxresize(Group *g, Rectangle r){	int rows, cols, ht, wid, i, hpad, wpad;	Rectangle rr; 	if(debug) fprint(2, "boxboxresize %q %R (%d×%d) min/max %R separation %d\n", g->name, r, Dx(r), Dy(r), g->size, g->separation);	ht = 0;	for(i=0; i<g->nkids; i++){		if (g->kids[i]->size.min.y > ht)			ht = g->kids[i]->size.min.y;

Lines 1–500 of 737.