Charles.Forsyth20060303a828770d19 years agoHistory
1552 lines · 32.0 KB · C
RawDownload
#include "lib9.h"#include "draw.h"#include "tk.h" /* * XXX TODO * - grid rowcget|columncget * - grid columnconfigure/rowconfigure accepts a list of indexes? */ #define	O(t, e)		((long)(&((t*)0)->e)) typedef struct TkGridparam TkGridparam;typedef struct TkBeamparam TkBeamparam; struct TkGridparam{	Point	span;	Tk*	in;	Point	pad;	Point ipad;	char	*row;	char *col;	int	sticky;}; struct TkBeamparam{	int	minsize;	int	maxsize;	int	weight;	int	pad;	char	*name;	int	equalise;}; staticTkOption opts[] ={	"padx",		OPTnndist,	O(TkGridparam, pad.x),	nil,	"pady",		OPTnndist,	O(TkGridparam, pad.y),	nil,	"ipadx",	OPTnndist,	O(TkGridparam, ipad.x),	nil,	"ipady",	OPTnndist,	O(TkGridparam, ipad.y),	nil,	"in",		OPTwinp,		O(TkGridparam, in),		nil,	"row",	OPTtext,		O(TkGridparam, row), nil,	"column",	OPTtext,		O(TkGridparam, col), nil,	"rowspan",	OPTnndist,	O(TkGridparam, span.y), nil,	"columnspan",	OPTnndist,	O(TkGridparam, span.x), nil,	"sticky",	OPTsticky,		O(TkGridparam, sticky), nil,	nil}; staticTkOption beamopts[] ={	"minsize",		OPTnndist,	O(TkBeamparam, minsize),	nil,	"maxsize",	OPTnndist,	O(TkBeamparam, maxsize),	nil,	"weight",		OPTnndist,	O(TkBeamparam, weight),	nil,	"pad",		OPTnndist,	O(TkBeamparam, pad),		nil,	"name",		OPTtext,		O(TkBeamparam, name),		nil,	"equalise",	OPTstab,		O(TkBeamparam, equalise),	tkbool,	nil}; voidprintgrid(TkGrid *grid){	int x, y;	Point dim; 	dim = grid->dim;	print("grid %P\n", grid->dim);	print("  row heights: ");	for(y = 0; y < dim.y; y++)		print("%d[%d,%d,w%d,p%d]%s ",			grid->rows[y].act,			grid->rows[y].minsize,			grid->rows[y].maxsize < 0x7fffffff ? grid->rows[y].maxsize : -1,			grid->rows[y].weight,			grid->rows[y].pad,			grid->rows[y].name ? grid->rows[y].name : "");	print("\n");	print("  col widths: ");	for(x = 0; x < dim.x; x++)		print("%d[%d,%d,w%d,p%d]%s ",			grid->cols[x].act,			grid->cols[x].minsize,			grid->cols[x].maxsize < 0x7fffffff ? grid->cols[x].maxsize : -1,			grid->cols[x].weight,			grid->cols[x].pad,			grid->cols[x].name ? grid->cols[x].name : "");	print("\n");	for(y = 0; y < dim.y; y++){		print("  row %d: ", y);		for(x = 0; x < dim.x; x++){			print("%p;", grid->cells[y][x].tk);			print("%s%P\t", grid->cells[y][x].tk?grid->cells[y][x].tk->name->name:"(nil)",				grid->cells[y][x].span);		}		print("\n");	}} static voidtkgridsetopt(TkGridparam *p, Tk *tk){	if(p->pad.x != -1)		tk->pad.x = p->pad.x*2;	if(p->pad.y != -1)		tk->pad.y = p->pad.y*2;	if(p->ipad.x != -1)		tk->ipad.x = p->ipad.x*2;	if(p->ipad.y != -1)		tk->ipad.y = p->ipad.y*2;	if(p->sticky != -1)		tk->flag = (tk->flag & ~(Tkanchor|Tkfill)) | (p->sticky & (Tkanchor|Tkfill));} static voidinitbeam(TkGridbeam *beam, int n){	int i;	memset(beam, 0, n * sizeof(TkGridbeam));	for(i = 0; i < n; i++)		beam[i].maxsize = 0x7fffffff;} static char*ensuregridsize(TkGrid *grid, Point dim){	TkGridcell **cells, *cellrow;	TkGridbeam *cols, *rows;	Point olddim;	int i;	olddim = grid->dim;	if(dim.x < olddim.x)		dim.x = olddim.x;	if(dim.y < olddim.y)		dim.y = olddim.y;	if(dim.y > olddim.y){		cells = realloc(grid->cells, sizeof(TkGridcell*)*dim.y);		if(cells == nil)			return TkNomem;		grid->cells = cells;		for(i = olddim.y; i < dim.y; i++){			cells[i] = malloc(sizeof(TkGridcell)*dim.x);			if(cells[i] == nil){				for(i--; i >= olddim.y; i--)					free(cells[i]);				return TkNomem;			}		}		rows = realloc(grid->rows, sizeof(TkGridbeam)*dim.y);		if(rows == nil)			return TkNomem;		grid->rows = rows;		initbeam(rows + olddim.y, dim.y - olddim.y);		grid->dim.y = dim.y;	} 	if(dim.x > olddim.x){		/*		 * any newly allocated rows will have the correct number of		 * columns, so we don't need to reallocate them		 */		cells = grid->cells;		for(i = 0; i < olddim.y; i++){			cellrow = realloc(cells[i], sizeof(TkGridcell) * dim.x);			if(cellrow == nil)				return TkNomem;	/* leak some earlier rows, but not permanently */			memset(cellrow + olddim.x, 0, (dim.x-olddim.x)*sizeof(TkGridcell));			cells[i] = cellrow;		}		cols = realloc(grid->cols, sizeof(TkGridbeam)*dim.x);		if(cols == nil)			return TkNomem;		initbeam(cols + olddim.x, dim.x - olddim.x);		grid->cols = cols;		grid->dim.x = dim.x;	}	return nil;} static TkGridbeam*delbeams(TkGridbeam *beam, int nb, int x0, int x1){	int i;	TkGridbeam *b;	for(i = x0; i < x1; i++)		free(beam[i].name);	memmove(&beam[x0], &beam[x1], sizeof(TkGridbeam) * (nb-x1));	b = realloc(beam, sizeof(TkGridbeam) * (nb-(x1-x0)));	return b ? b : beam;} static voiddelrows(TkGrid *grid, int y0, int y1){	TkGridcell **cells;	memmove(grid->cells+y0, grid->cells+y1, sizeof(TkGridcell*) * (grid->dim.y-y1));	grid->dim.y -= (y1 - y0);	cells = realloc(grid->cells, sizeof(TkGridcell*) * grid->dim.y);	if(cells != nil || grid->dim.y == 0)		grid->cells = cells;		/* can realloc to a smaller size ever fail? */} static voiddelcols(TkGrid *grid, int x0, int x1){	TkGridcell **cells, *row;	int y, ndx;	Point dim;	dim = grid->dim;	ndx = dim.x - (x1 - x0);	cells = grid->cells;	for(y = 0; y < dim.y; y++){		row = cells[y];		memmove(row+x0, row+x1, sizeof(TkGridcell) * (dim.x - x1));		row = realloc(row, sizeof(TkGridcell) * ndx);		if(row != nil || ndx == 0)			cells[y] = row;	}	grid->dim.x = ndx;} /* * insert items into rows/cols; the beam has already been expanded appropriately. */voidinsbeams(TkGridbeam *beam, int nb, int x, int n){	memmove(&beam[x+n], &beam[x], sizeof(TkGridbeam)*(nb-x-n));	initbeam(beam+x, n);} static char*insrows(TkGrid *grid, int y0, int n){	Point olddim;	char *e;	TkGridcell **cells, *tmp;	int y; 	olddim = grid->dim;	if(y0 > olddim.y){		n = y0 + n - olddim.y;		y0 = olddim.y;	} 	e = ensuregridsize(grid, Pt(olddim.x, olddim.y + n));	if(e != nil)		return e;	/*	 * we know the extra rows will have been filled	 * with blank, properly allocated rows, so just swap 'em with the	 * ones that need moving.	 */	cells = grid->cells;	for(y = olddim.y - 1; y >= y0; y--){		tmp = cells[y + n];		cells[y + n] = cells[y];		cells[y] = tmp;	}	insbeams(grid->rows, grid->dim.y, y0, n);	return nil;} static char*inscols(TkGrid *grid, int x0, int n){	TkGridcell **cells;	Point olddim;	int y;	char *e; 	olddim = grid->dim;	if(x0 > olddim.x){		n = x0 + n - olddim.x;		x0 = olddim.x;	} 	e = ensuregridsize(grid, Pt(olddim.x + n, olddim.y));	if(e != nil)		return e; 	cells = grid->cells;	for(y = 0; y < olddim.y; y++){		memmove(cells[y] + x0 + n, cells[y] + x0, sizeof(TkGridcell) * (olddim.x - x0));		memset(cells[y] + x0, 0, sizeof(TkGridcell) * n);	}	insbeams(grid->cols, grid->dim.x, x0, n);	return nil;} static intmaximum(int a, int b){	if(a > b)		return a;	return b;} /* * return the width of cols/rows between x0 and x1 in the beam, * excluding the padding at either end, but including padding in the middle. */static intbeamsize(TkGridbeam *cols, int x0, int x1){	int tot, fpad, x; 	if(x0 >= x1)		return 0; 	tot = cols[x0].act;	fpad = cols[x0].pad;	for(x = x0 + 1; x < x1; x++){		tot += cols[x].act + maximum(cols[x].pad, fpad);		fpad = cols[x].pad;	}	return tot;} /* * return starting position of cell index on beam, relative * to top-left of grid */static intbeamcellpos(TkGridbeam *beam, int blen, int index){	int x;	if(blen == 0 || index >= blen || index < 0)		return 0;	x = beam[0].pad + beamsize(beam, 0, index);	if(index > 0)		x += maximum(beam[index-1].pad, beam[index].pad);	return x;} static Rectanglecellbbox(TkGrid *grid, Point pos){	Point dim;	Rectangle r; 	dim = grid->dim;	if(pos.x > dim.x)		pos.x = dim.x;	if(pos.y > dim.y)		pos.y = dim.y; 	r.min.x = beamcellpos(grid->cols, dim.x, pos.x);	r.min.y = beamcellpos(grid->rows, dim.y, pos.y);	if(pos.x == dim.x)		r.max.x = r.min.x;	else		r.max.x = r.min.x + grid->cols[pos.x].act;	if(pos.y == dim.y)		r.max.y = r.min.y;	else		r.max.y = r.min.y + grid->rows[pos.y].act;	return rectaddpt(r, grid->origin);} /* * return true ifthere are any spanning cells covering row _index_ */static intgridrowhasspan(TkGrid *grid, int index){	int i, d;	Point dim;	TkGridcell *cell; 	dim = grid->dim;	if(index > 0 && index < dim.y){		for(i = 0; i < dim.x; i++){			cell = &grid->cells[index][i];			if(cell->tk != nil){				d = cell->span.x;				if(d == 0)					return 1;				i += d - 1;			}		}	}	return 0;} /* * return true ifthere are any spanning cells covering column _index_ */static intgridcolhasspan(TkGrid *grid, int index){	int i, d;	Point dim;	TkGridcell *cell; 	dim = grid->dim;	if(index > 0 && index < dim.x){		for(i = 0; i < dim.y; i++){			cell = &grid->cells[i][index];			if(cell->tk != nil){				d = cell->span.y;				if(d == 0)					return 1;				i += d - 1;			}		}	}	return 0;} /* * find cell that's spanning the grid position p */static intfindspan(TkGrid *grid, Point p, Point *cp){	Point dim;	TkGridcell **cells;	Tk *tk; 	dim = grid->dim;	cells = grid->cells; 	if(p.x < 0 || p.y < 0 || p.x >= dim.x || p.y >= dim.y)		return 0; 	if(cells[p.y][p.x].tk == nil)		return 0; 	if(cells[p.y][p.x].span.x == 0){		tk = cells[p.y][p.x].tk;		for(; p.y >= 0; p.y--)			if(cells[p.y][p.x].tk != tk)				break;		p.y++;		for(; p.x >= 0; p.x--)			if(cells[p.y][p.x].tk != tk)				break;		p.x++;	}	*cp = p;	return 1;} static intparsegridindex(TkGridbeam *beam, int blen, char *s){	int n, i;	char *e; 	if(s[0] == '\0')		return -1; 	n = strtol(s, &e, 10);	if(*e == '\0')		return n; 	if(strcmp(s, "end") == 0)		return blen; 	for(i = 0; i < blen; i++)		if(beam[i].name != nil && strcmp(beam[i].name, s) == 0)			return i;	return -1;} static char*tkgridconfigure(TkTop *t, TkGridparam *p, TkName *names){	TkGrid *grid;	TkGridcell **cells;	TkName *n;	Tk *tkf, *tkp;	Point dim, pos, q, span, startpos;	int maxcol, c, i, j, x;	char *e; 	if(names == nil)		return nil; 	if(p->span.x < 1 || p->span.y < 1)		return TkBadvl; 	tkf = nil; 	maxcol = 0;	for(n = names; n; n = n->link){		c = n->name[0];		if((c=='-' || c=='^' || c=='x') && n->name[1] == '\0'){			maxcol++;			continue;		}		tkp = tklook(t, n->name, 0);		if(tkp == nil){			tkerr(t, n->name);			return TkBadwp;		}		if(tkp->flag & Tkwindow)

Lines 1–500 of 1552.