henesyinit from lsubb0c8bdb6 years agoHistory
342 lines · 6.9 KB · C
RawDownload
#include <u.h>#include <libc.h>#include <thread.h>#include <fcall.h>#include <draw.h>#include <mouse.h>#include <frame.h>#include <9p.h>#include "gui.h" /* We follow the conventions in graphics(2). * Rectangles do not include the max point. */ int layoutdebug; /* * Compute size and record if we want more x/y room * by looking into the inner components. * Save also current rect in orect. */static voidsize(File* f){	Panel*	p;	Panel*	np;	File**	l;	File**	w;	File*	fp;	int	some; 	p = f->aux;	p->orect = p->rect;	switch(p->type){	case Qcol:		// lay out inner parts in rows	case Qrow:		// lay out inner parts in cols		if (hastag(f))			p->size = Pt(Tagwid + Inset, Inset);		else			p->size = Pt(Inset, Inset);		p->wants = Pt(0,0);		some = 0;		w = newfilewalk(f); 		for (l = w; fp = *l; l++){			if (!ispanel(fp))				continue;			np = fp->aux;			if (np->flags&Phide)				continue;			some++;			size(fp);			// We ignore wants.[xy] != 1. See comment below.			p->wants.x |= (np->wants.x == 1);			p->wants.y |= (np->wants.y == 1);			if (p->type == Qcol){				if (some)					p->size.y += Inset;				p->size.y += np->size.y;				if (p->size.x < np->size.x)					p->size.x = np->size.x;			} else {				if (some)					p->size.x += Inset;				p->size.x += np->size.x;				if (p->size.y < np->size.y)					p->size.y = np->size.y;			}		}		endfilewalk(w);		if (!some && (p->flags&Playout))			p->wants = Pt(1,1);		addpt(p->size, Pt(Inset, Inset));		break;	default:		p->size = p->minsz;		if (p->size.x < Inset)	// ensure a min sz			p->size.x = Inset;		if (p->size.y < Inset)			p->size.y = Inset;		/* Heuristic to keep tiny text panels		 * small. If they don't want too much,		 * we assing the space and ignore their wants.		 */		if (p->wants.x)			if (p->maxsz.x && p->maxsz.x < 120){				p->wants.x = 2; // ignored later				p->size.x = p->maxsz.x;			} else				p->wants.x = 1;		if (p->wants.y)			if (p->maxsz.y && p->maxsz.y < 120){				p->wants.y = 2; // ignored later				p->size.y = p->maxsz.y;			} else				p->wants.y = 1;		break;	}} /* * Recursively layout the hierarchy to its minimum size. * Panel.rect enters with the available rectangle * for showing the file and its hierarchy. It leaves * the routine with the actual rectangle used. */static voidpack(File* f){	Rectangle r;	Point	max;	Panel*	p;	Panel* np;	File**	w;	File**	l;	File*	fp;	int	some; 	p = f->aux;	switch(p->type){	case Qcol:		// lay out inner parts in rows	case Qrow:		// lay out inner parts in cols		r = insetrect(p->rect, Inset);		if (hastag(f))			r.min.x += Tagwid;		max = r.min;		// r is always the avail rectangle.		// max is the max. point used.		some = 0;		w = newfilewalk(f);		for (l = w; fp = *l; l++){			if (!ispanel(fp))				continue;			np = fp->aux;			if (np->flags&Phide)				continue;			some++;			np->rect = r;			pack(fp);			rectclip(&np->rect, p->rect);			if (max.x < np->rect.max.x)				max.x = np->rect.max.x;			if (max.y < np->rect.max.y)				max.y = np->rect.max.y;			if (p->type == Qcol)				r.min.y = np->rect.max.y + Inset;			else				r.min.x = np->rect.max.x + Inset;		}		endfilewalk(w);		if (!some)			goto atom;		p->rect.max = addpt(max, Pt(Inset, Inset));		break; 	default:	// Atom	atom:		if (p->size.x > Dx(p->rect))			p->rect.max.x = p->rect.min.x + Dx(p->rect);		else			p->rect.max.x = p->rect.min.x + p->size.x;		if (p->size.y > Dy(p->rect))			p->rect.max.y = p->rect.min.y + Dy(p->rect);		else			p->rect.max.y = p->rect.min.y + p->size.y;		break;	}	if(1)	ldprint("pack %s: %03dx%03d %R\n", f->name,		Dx(p->rect), Dy(p->rect), p->rect);} static voidmove(File* f, Point pt){	Panel*	p;	File**	w;	File**	l;	File*	fp;	Panel*	np; 	p = f->aux;	p->rect.min.x += pt.x;	p->rect.max.x += pt.x;	p->rect.min.y += pt.y;	p->rect.max.y += pt.y;	w = newfilewalk(f);	for (l = w; fp = *l; l++){		if (!ispanel(fp))			continue;		np = fp->aux;		if (!(np->flags&Phide))			move(fp, pt);	}	endfilewalk(w);} /* * Expands inner components to use all the space * available in this one. Only those who want x/y space * are expanded. */static voidexpand(File* f){	Panel*	p;	Panel* np;	File**	w;	File**	l;	File*	fp;	int	n;	int	nwx, nwy;	Point	last;	Point	spare;	int	offset;	int	incr;	int	maxx, dx; 	p = f->aux;	if (p->type != Qrow && p->type != Qcol)		return;	/*	 * Determine space and how many want x,y room	 */	nwx = nwy = maxx = 0;	last = ZP;	w = newfilewalk(f);	for (l = w; fp = *l; l++){		if (!ispanel(fp))			continue;		np = fp->aux;		if (!(np->flags&Phide)){			dx = Dx(np->rect);			if (dx > maxx)				maxx = dx;			if (np->wants.x == 1)				nwx++;			if (np->wants.y == 1)				nwy++;			last = np->rect.max;		}	}	endfilewalk(w);	spare = subpt(p->rect.max, last);	spare = subpt(spare, Pt(Inset, Inset)); 	/*	 * Resize to consume spare space:	 */ 	/* 1. Try to make them equal sized.	 *    By now, this is only done for rows.	 *    Column processing would be equivalent.	 */	offset = 0;	if (p->type == Qrow){		w = newfilewalk(f);		for (l = w; fp = *l; l++){			if (!ispanel(fp))				continue;			np = fp->aux;			if (np->flags&Phide)				continue;			if (p->type == Qrow){				move(fp, Pt(offset, 0));				dx = maxx - Dx(np->rect);				if (np->wants.x == 1 && spare.x > 0 && dx > 0){					incr = (dx > spare.x) ? spare.x : dx;					np->rect.max.x += incr;					offset += incr;					spare.x -= incr;				}			}			ldprint("expand.1: %s wx %d wy %d %dx%d %R\n", fp->name,				np->wants.x, np->wants.y, Dx(np->rect),				Dy(np->rect), np->rect);			expand(fp);		}		endfilewalk(w);	}	/* 2. Proportional sharing of what remains	 *    and extend the other coordinate to use whatever	 *    empty space is there due to different sizes in that axys.	 */	offset = 0;	w = newfilewalk(f);	for (l = w; fp = *l; l++){		if (!ispanel(fp))			continue;		np = fp->aux;		if (np->flags&Phide)			continue;		if (p->type == Qcol){			move(fp, Pt(0, offset));			n = p->rect.max.x - Inset;			if (np->rect.max.x < n)			if (np->type == Qcol || np->type == Qrow || np->wants.x == 1)				np->rect.max.x = n;			if (np->wants.y == 1 && spare.y > 0){				incr = spare.y/nwy;				np->rect.max.y += incr;				offset += incr;			}		} else {			move(fp, Pt(offset, 0));			n = p->rect.max.y - Inset;			if (np->rect.max.y < n)			if (np->type == Qcol || np->type == Qrow || np->wants.y == 1)				np->rect.max.y = n;			if (np->wants.x == 1 && spare.x > 0){				incr = spare.x/nwx;				np->rect.max.x += incr;				offset += incr;			}		}		ldprint("expand.2: %s wx %d wy %d %dx%d %R\n", fp->name,			np->wants.x, np->wants.y, Dx(np->rect),			Dy(np->rect), np->rect);		expand(fp);	}	endfilewalk(w);} voidlayout(File* f){	Rectangle r;	Panel*	p; 	p = f->aux;	if (screen == nil)		return;	r = screen->r;	p->rect = r;	size(f);	/* BUG: if none of /devs/ui/col:n wants.x/wants.y	 * we should set wants.x/wants.y for any of them.	 * Otherwise, the screen gets ugly.	 */	pack(f);	p->rect = r;	expand(f);}