xref: /plan9-contrib/sys/src/cmd/abaco/tabs.c (revision 7ab27030036b6c877a6f81728daeda263d1ca3cf)
1*7ab27030SDavid du Colombier #include <u.h>
2*7ab27030SDavid du Colombier #include <libc.h>
3*7ab27030SDavid du Colombier #include <draw.h>
4*7ab27030SDavid du Colombier #include <memdraw.h>
5*7ab27030SDavid du Colombier #include <thread.h>
6*7ab27030SDavid du Colombier #include <cursor.h>
7*7ab27030SDavid du Colombier #include <mouse.h>
8*7ab27030SDavid du Colombier #include <keyboard.h>
9*7ab27030SDavid du Colombier #include <frame.h>
10*7ab27030SDavid du Colombier #include <plumb.h>
11*7ab27030SDavid du Colombier #include <html.h>
12*7ab27030SDavid du Colombier #include "dat.h"
13*7ab27030SDavid du Colombier #include "fns.h"
14*7ab27030SDavid du Colombier 
15*7ab27030SDavid du Colombier void
drawtable(Box * b,Page * p,Image * im)16*7ab27030SDavid du Colombier drawtable(Box *b, Page *p, Image *im)
17*7ab27030SDavid du Colombier {
18*7ab27030SDavid du Colombier 	Rectangle r, cr;
19*7ab27030SDavid du Colombier 	Tablecell *c;
20*7ab27030SDavid du Colombier 	Table *t;
21*7ab27030SDavid du Colombier 
22*7ab27030SDavid du Colombier 	t = ((Itable *)b->i)->table;
23*7ab27030SDavid du Colombier 	r = rectsubpt(b->r, p->pos);
24*7ab27030SDavid du Colombier 	draw(im, r, getcolor(t->background.color), nil, ZP);
25*7ab27030SDavid du Colombier 	if(t->border)
26*7ab27030SDavid du Colombier 		border(im, r, t->border, display->black, ZP);
27*7ab27030SDavid du Colombier 	for(c=t->cells; c!=nil; c=c->next){
28*7ab27030SDavid du Colombier 		cr = rectsubpt(c->lay->r, p->pos);
29*7ab27030SDavid du Colombier 		if(c->background.color != t->background.color)
30*7ab27030SDavid du Colombier 			draw(im, cr, getcolor(c->background.color), nil, ZP);
31*7ab27030SDavid du Colombier 		if(t->border)
32*7ab27030SDavid du Colombier 			border(im, cr, t->border, display->black, ZP);
33*7ab27030SDavid du Colombier 		laydraw(p, im,  c->lay);
34*7ab27030SDavid du Colombier 	}
35*7ab27030SDavid du Colombier }
36*7ab27030SDavid du Colombier 
37*7ab27030SDavid du Colombier enum
38*7ab27030SDavid du Colombier {
39*7ab27030SDavid du Colombier 	Tablemax = 2000,
40*7ab27030SDavid du Colombier 	Ttoplevel = 1<<0,
41*7ab27030SDavid du Colombier 
42*7ab27030SDavid du Colombier };
43*7ab27030SDavid du Colombier 
44*7ab27030SDavid du Colombier static
45*7ab27030SDavid du Colombier void
settable(Table * t)46*7ab27030SDavid du Colombier settable(Table *t)
47*7ab27030SDavid du Colombier {
48*7ab27030SDavid du Colombier 	Tablecell *c;
49*7ab27030SDavid du Colombier 	Lay *lay;
50*7ab27030SDavid du Colombier 
51*7ab27030SDavid du Colombier 	for(c=t->cells; c!=nil; c=c->next){
52*7ab27030SDavid du Colombier 		lay = layitems(c->content, Rect(0,0,0,0), FALSE);
53*7ab27030SDavid du Colombier 		c->minw = Dx(lay->r);
54*7ab27030SDavid du Colombier 		layfree(lay);
55*7ab27030SDavid du Colombier 		if(dimenkind(c->wspec) == Dnone){
56*7ab27030SDavid du Colombier 			lay = layitems(c->content, Rect(0,0,Tablemax,0), FALSE);
57*7ab27030SDavid du Colombier 			c->maxw = Dx(lay->r);
58*7ab27030SDavid du Colombier 			layfree(lay);
59*7ab27030SDavid du Colombier 		}
60*7ab27030SDavid du Colombier 	}
61*7ab27030SDavid du Colombier }
62*7ab27030SDavid du Colombier 
63*7ab27030SDavid du Colombier void
settables(Page * p)64*7ab27030SDavid du Colombier settables(Page *p)
65*7ab27030SDavid du Colombier {
66*7ab27030SDavid du Colombier 	Table *t;
67*7ab27030SDavid du Colombier 	Item *i;
68*7ab27030SDavid du Colombier 
69*7ab27030SDavid du Colombier 	if(p->doc==nil)
70*7ab27030SDavid du Colombier 		return;
71*7ab27030SDavid du Colombier 	for(i=p->items; i!=nil; i=i->next)
72*7ab27030SDavid du Colombier 		if(i->tag == Itabletag)
73*7ab27030SDavid du Colombier 			((Itable *)i)->table->flags |= Ttoplevel;
74*7ab27030SDavid du Colombier 
75*7ab27030SDavid du Colombier 	for(t=p->doc->tables; t!=nil; t=t->next)
76*7ab27030SDavid du Colombier 		settable(t);
77*7ab27030SDavid du Colombier }
78*7ab27030SDavid du Colombier 
79*7ab27030SDavid du Colombier static
80*7ab27030SDavid du Colombier int
cellwidth(Table * t,Tablecell * c,int sep)81*7ab27030SDavid du Colombier cellwidth(Table *t, Tablecell *c, int sep)
82*7ab27030SDavid du Colombier {
83*7ab27030SDavid du Colombier 	int w, i, n;
84*7ab27030SDavid du Colombier 
85*7ab27030SDavid du Colombier 	n = c->colspan;
86*7ab27030SDavid du Colombier 	if(n == 1)
87*7ab27030SDavid du Colombier 		return t->cols[c->col].width;
88*7ab27030SDavid du Colombier 	if(n == 0)
89*7ab27030SDavid du Colombier 		n = t->ncol - c->col;
90*7ab27030SDavid du Colombier 
91*7ab27030SDavid du Colombier 	w = t->cellspacing*(n-1) + n*sep;
92*7ab27030SDavid du Colombier 	for(i=c->col; i<c->col+n; i++)
93*7ab27030SDavid du Colombier 		w += t->cols[i].width;
94*7ab27030SDavid du Colombier 
95*7ab27030SDavid du Colombier 	return w;
96*7ab27030SDavid du Colombier }
97*7ab27030SDavid du Colombier 
98*7ab27030SDavid du Colombier static
99*7ab27030SDavid du Colombier int
cellheight(Table * t,Tablecell * c,int sep)100*7ab27030SDavid du Colombier cellheight(Table *t, Tablecell *c, int sep)
101*7ab27030SDavid du Colombier {
102*7ab27030SDavid du Colombier 	int h, i, n;
103*7ab27030SDavid du Colombier 
104*7ab27030SDavid du Colombier 	n = c->rowspan;
105*7ab27030SDavid du Colombier 	if(n == 1)
106*7ab27030SDavid du Colombier 		return t->rows[c->row].height;
107*7ab27030SDavid du Colombier 	if(n == 0)
108*7ab27030SDavid du Colombier 		n = t->nrow - c->row;
109*7ab27030SDavid du Colombier 
110*7ab27030SDavid du Colombier 	h = t->cellspacing*(n-1) + n*sep;
111*7ab27030SDavid du Colombier 	for(i=c->row; i<c->row+n; i++)
112*7ab27030SDavid du Colombier 		h += t->rows[i].height;
113*7ab27030SDavid du Colombier 
114*7ab27030SDavid du Colombier 	return h;
115*7ab27030SDavid du Colombier }
116*7ab27030SDavid du Colombier 
117*7ab27030SDavid du Colombier static
118*7ab27030SDavid du Colombier int
getwidth(int * w,int n)119*7ab27030SDavid du Colombier getwidth(int *w, int n)
120*7ab27030SDavid du Colombier {
121*7ab27030SDavid du Colombier 	int i, tot;
122*7ab27030SDavid du Colombier 
123*7ab27030SDavid du Colombier 	tot = 0;
124*7ab27030SDavid du Colombier 	for(i=0; i<n; i++)
125*7ab27030SDavid du Colombier 		tot += w[i];
126*7ab27030SDavid du Colombier 
127*7ab27030SDavid du Colombier 	return tot;
128*7ab27030SDavid du Colombier }
129*7ab27030SDavid du Colombier 
130*7ab27030SDavid du Colombier static
131*7ab27030SDavid du Colombier void
fixcols(Table * t,int * width,int sep,int domax)132*7ab27030SDavid du Colombier fixcols(Table *t, int *width, int sep, int domax)
133*7ab27030SDavid du Colombier {
134*7ab27030SDavid du Colombier 	Tablecell *c;
135*7ab27030SDavid du Colombier 	int w, aw, i, d, n, rem;
136*7ab27030SDavid du Colombier 
137*7ab27030SDavid du Colombier 
138*7ab27030SDavid du Colombier 	for(c=t->cells; c!=nil; c=c->next){
139*7ab27030SDavid du Colombier 		if(c->colspan == 1)
140*7ab27030SDavid du Colombier 			continue;
141*7ab27030SDavid du Colombier 
142*7ab27030SDavid du Colombier 		n = c->colspan;
143*7ab27030SDavid du Colombier 		if(n == 0)
144*7ab27030SDavid du Colombier 			n = t->ncol - c->col;
145*7ab27030SDavid du Colombier 
146*7ab27030SDavid du Colombier 		w = domax ? c->maxw : c->minw;
147*7ab27030SDavid du Colombier 		w -= t->cellspacing*(n-1) + n*sep;
148*7ab27030SDavid du Colombier 
149*7ab27030SDavid du Colombier 		aw = 0;
150*7ab27030SDavid du Colombier 		for(i=c->col; i<c->col+n; i++)
151*7ab27030SDavid du Colombier 			aw += width[i];
152*7ab27030SDavid du Colombier 
153*7ab27030SDavid du Colombier 		rem = w-aw;
154*7ab27030SDavid du Colombier 		if(rem <= 0)
155*7ab27030SDavid du Colombier 			continue;
156*7ab27030SDavid du Colombier 
157*7ab27030SDavid du Colombier 		for(i=c->col; i<c->col+n; i++){
158*7ab27030SDavid du Colombier 			if(aw > 0){
159*7ab27030SDavid du Colombier 				d = width[i]*100/aw;
160*7ab27030SDavid du Colombier 				d = d*rem/100;
161*7ab27030SDavid du Colombier 			}else
162*7ab27030SDavid du Colombier 				d = rem/n;
163*7ab27030SDavid du Colombier 			width[i] += d;
164*7ab27030SDavid du Colombier 		}
165*7ab27030SDavid du Colombier 	}
166*7ab27030SDavid du Colombier }
167*7ab27030SDavid du Colombier 
168*7ab27030SDavid du Colombier static
169*7ab27030SDavid du Colombier int
tablewidth(Table * t,int tw,int sep)170*7ab27030SDavid du Colombier tablewidth(Table *t, int tw, int sep)
171*7ab27030SDavid du Colombier {
172*7ab27030SDavid du Colombier 	Tablecell *c;
173*7ab27030SDavid du Colombier 	int i, w, tmin, tmax, d;
174*7ab27030SDavid du Colombier 	int *maxw, *minw;
175*7ab27030SDavid du Colombier 	int totw;
176*7ab27030SDavid du Colombier 
177*7ab27030SDavid du Colombier 	maxw = emalloc(sizeof(int)*t->ncol);
178*7ab27030SDavid du Colombier 	minw = emalloc(sizeof(int)*t->ncol);
179*7ab27030SDavid du Colombier 	for(c=t->cells; c!=nil; c=c->next){
180*7ab27030SDavid du Colombier 		if(dimenkind(c->wspec) != Dnone){
181*7ab27030SDavid du Colombier 			d = c->minw;
182*7ab27030SDavid du Colombier 			c->minw = c->maxw = max(dimwidth(c->wspec, tw), c->minw);
183*7ab27030SDavid du Colombier 			c->minw = d;
184*7ab27030SDavid du Colombier 		}
185*7ab27030SDavid du Colombier 		if(c->colspan != 1)
186*7ab27030SDavid du Colombier 			continue;
187*7ab27030SDavid du Colombier 		maxw[c->col] = max(maxw[c->col], c->maxw);
188*7ab27030SDavid du Colombier 		minw[c->col] = max(minw[c->col], c->minw);
189*7ab27030SDavid du Colombier 	}
190*7ab27030SDavid du Colombier 	totw = 0;
191*7ab27030SDavid du Colombier 	fixcols(t, maxw, sep, TRUE);
192*7ab27030SDavid du Colombier 	tmax = getwidth(maxw, t->ncol);
193*7ab27030SDavid du Colombier 	if(tmax <= tw){
194*7ab27030SDavid du Colombier 		d = 0;
195*7ab27030SDavid du Colombier 		if(tw>tmax && dimenkind(t->width)!=Dnone && t->availw!=Tablemax)
196*7ab27030SDavid du Colombier 			d = (tw-tmax)/t->ncol;
197*7ab27030SDavid du Colombier 		for(i=0; i<t->ncol; i++){
198*7ab27030SDavid du Colombier 			t->cols[i].width = maxw[i] + d;
199*7ab27030SDavid du Colombier 			totw += t->cols[i].width;
200*7ab27030SDavid du Colombier 		}
201*7ab27030SDavid du Colombier 	}else{
202*7ab27030SDavid du Colombier 		fixcols(t, minw, sep, FALSE);
203*7ab27030SDavid du Colombier 		tmin = getwidth(minw, t->ncol);
204*7ab27030SDavid du Colombier 		w = tw - tmin;
205*7ab27030SDavid du Colombier 		d = tmax - tmin;
206*7ab27030SDavid du Colombier 		for(i=0; i<t->ncol; i++){
207*7ab27030SDavid du Colombier 			if(w<=0 || d<=0)
208*7ab27030SDavid du Colombier 				t->cols[i].width = minw[i];
209*7ab27030SDavid du Colombier 			else
210*7ab27030SDavid du Colombier 				t->cols[i].width = minw[i] + (maxw[i] - minw[i])*w/d;
211*7ab27030SDavid du Colombier 			totw += t->cols[i].width;
212*7ab27030SDavid du Colombier 		}
213*7ab27030SDavid du Colombier 	}
214*7ab27030SDavid du Colombier 	free(minw);
215*7ab27030SDavid du Colombier 	free(maxw);
216*7ab27030SDavid du Colombier 
217*7ab27030SDavid du Colombier 	return totw;
218*7ab27030SDavid du Colombier }
219*7ab27030SDavid du Colombier 
220*7ab27030SDavid du Colombier static
221*7ab27030SDavid du Colombier void
fixrows(Table * t,int sep)222*7ab27030SDavid du Colombier fixrows(Table *t, int sep)
223*7ab27030SDavid du Colombier {
224*7ab27030SDavid du Colombier 	Tablecell *c;
225*7ab27030SDavid du Colombier 	Lay *lay;
226*7ab27030SDavid du Colombier 	int h, ah, i, d, n, rem;
227*7ab27030SDavid du Colombier 
228*7ab27030SDavid du Colombier 	for(c=t->cells; c!=nil; c=c->next){
229*7ab27030SDavid du Colombier 		if(c->rowspan == 1)
230*7ab27030SDavid du Colombier 			continue;
231*7ab27030SDavid du Colombier 		n = c->rowspan;
232*7ab27030SDavid du Colombier 		if(n==0 || c->row+n>t->nrow)
233*7ab27030SDavid du Colombier 			n = t->nrow - c->row;
234*7ab27030SDavid du Colombier 
235*7ab27030SDavid du Colombier 		lay = layitems(c->content, Rect(0,0,cellwidth(t, c, sep),0), FALSE);
236*7ab27030SDavid du Colombier 		h = max(Dy(lay->r), c->hspec);
237*7ab27030SDavid du Colombier 		layfree(lay);
238*7ab27030SDavid du Colombier 		h -= t->cellspacing*(n-1) + n*sep;
239*7ab27030SDavid du Colombier 		ah = 0;
240*7ab27030SDavid du Colombier 		for(i=c->row; i<c->row+n; i++)
241*7ab27030SDavid du Colombier 			ah += t->rows[i].height;
242*7ab27030SDavid du Colombier 
243*7ab27030SDavid du Colombier 		rem = h-ah;
244*7ab27030SDavid du Colombier 		if(rem <= 0)
245*7ab27030SDavid du Colombier 			continue;
246*7ab27030SDavid du Colombier 
247*7ab27030SDavid du Colombier 		for(i=c->row; i<c->row+n; i++){
248*7ab27030SDavid du Colombier 			if(ah > 0){
249*7ab27030SDavid du Colombier 				d = t->rows[i].height*100/ah;
250*7ab27030SDavid du Colombier 				d = d*rem/100;
251*7ab27030SDavid du Colombier 			}else
252*7ab27030SDavid du Colombier 				d = rem/n;
253*7ab27030SDavid du Colombier 
254*7ab27030SDavid du Colombier 			t->rows[i].height += d;
255*7ab27030SDavid du Colombier 		}
256*7ab27030SDavid du Colombier 	}
257*7ab27030SDavid du Colombier }
258*7ab27030SDavid du Colombier 
259*7ab27030SDavid du Colombier static
260*7ab27030SDavid du Colombier int
tableheight(Table * t,int sep)261*7ab27030SDavid du Colombier tableheight(Table *t, int sep)
262*7ab27030SDavid du Colombier {
263*7ab27030SDavid du Colombier 	Tablecell *c;
264*7ab27030SDavid du Colombier 	Lay *lay;
265*7ab27030SDavid du Colombier 	int i, h, toth;
266*7ab27030SDavid du Colombier 
267*7ab27030SDavid du Colombier 	for(i=0; i<t->nrow; i++){
268*7ab27030SDavid du Colombier 		h = 0;
269*7ab27030SDavid du Colombier 		for(c=t->rows[i].cells; c!=nil; c=c->nextinrow){
270*7ab27030SDavid du Colombier 			if(c->rowspan != 1)
271*7ab27030SDavid du Colombier 				continue;
272*7ab27030SDavid du Colombier 			lay = layitems(c->content, Rect(0, 0, cellwidth(t, c, sep), 0), FALSE);
273*7ab27030SDavid du Colombier 			h = max(h, max(Dy(lay->r), c->hspec));
274*7ab27030SDavid du Colombier 			layfree(lay);
275*7ab27030SDavid du Colombier 		}
276*7ab27030SDavid du Colombier 		t->rows[i].height = h;
277*7ab27030SDavid du Colombier 	}
278*7ab27030SDavid du Colombier 	fixrows(t, sep);
279*7ab27030SDavid du Colombier 	toth = 0;
280*7ab27030SDavid du Colombier 	for(i=0; i<t->nrow; i++)
281*7ab27030SDavid du Colombier 		toth += t->rows[i].height;
282*7ab27030SDavid du Colombier 
283*7ab27030SDavid du Colombier 	return toth;
284*7ab27030SDavid du Colombier }
285*7ab27030SDavid du Colombier 
286*7ab27030SDavid du Colombier void
tablesize(Table * t,int availw)287*7ab27030SDavid du Colombier tablesize(Table *t, int availw)
288*7ab27030SDavid du Colombier {
289*7ab27030SDavid du Colombier 	int w, sep, hsep, vsep;
290*7ab27030SDavid du Colombier 
291*7ab27030SDavid du Colombier 	t->availw = availw;
292*7ab27030SDavid du Colombier 	sep = 2*(t->border+t->cellpadding);
293*7ab27030SDavid du Colombier 	hsep = t->cellspacing*(t->ncol+1) + 2*t->border + t->ncol*sep;
294*7ab27030SDavid du Colombier 	vsep = t->cellspacing*(t->nrow+1) + 2*t->border + t->nrow*sep;
295*7ab27030SDavid du Colombier 	w = dimwidth(t->width, availw);
296*7ab27030SDavid du Colombier 	w -= hsep;
297*7ab27030SDavid du Colombier 	w = w>0 ? w : 0;
298*7ab27030SDavid du Colombier 	t->totw = tablewidth(t, w, sep);
299*7ab27030SDavid du Colombier 	t->totw += hsep;
300*7ab27030SDavid du Colombier 	t->toth = tableheight(t, sep);
301*7ab27030SDavid du Colombier 	t->toth += vsep;
302*7ab27030SDavid du Colombier }
303*7ab27030SDavid du Colombier 
304*7ab27030SDavid du Colombier void
laytable(Itable * it,Rectangle r)305*7ab27030SDavid du Colombier laytable(Itable *it, Rectangle r)
306*7ab27030SDavid du Colombier {
307*7ab27030SDavid du Colombier 	Rectangle cr;
308*7ab27030SDavid du Colombier 	Tablecell *c;
309*7ab27030SDavid du Colombier 	Table *t;
310*7ab27030SDavid du Colombier 	int x, y, h, w;
311*7ab27030SDavid du Colombier 	int sep, i;
312*7ab27030SDavid du Colombier 
313*7ab27030SDavid du Colombier 	t = it->table;
314*7ab27030SDavid du Colombier 
315*7ab27030SDavid du Colombier 	sep = (t->cellpadding+t->border) * 2;
316*7ab27030SDavid du Colombier 	r = insetrect(r, t->cellspacing+t->border);
317*7ab27030SDavid du Colombier 	for(c=t->cells; c!=nil; c=c->next){
318*7ab27030SDavid du Colombier 		w = cellwidth(t, c, sep);
319*7ab27030SDavid du Colombier 		h = cellheight(t, c, sep);
320*7ab27030SDavid du Colombier 		x = r.min.x;
321*7ab27030SDavid du Colombier 		if(c->col > 0)
322*7ab27030SDavid du Colombier 			for(i=0; i<c->col; i++)
323*7ab27030SDavid du Colombier 				x += t->cols[i].width + sep + t->cellspacing;
324*7ab27030SDavid du Colombier 		y = r.min.y;
325*7ab27030SDavid du Colombier 		if(c->row > 0)
326*7ab27030SDavid du Colombier 			for(i=0;i <c->row; i++)
327*7ab27030SDavid du Colombier 				y += t->rows[i].height + sep + t->cellspacing;
328*7ab27030SDavid du Colombier 		cr = Rect(x, y, x+w+sep, y+h+sep);
329*7ab27030SDavid du Colombier 		c->lay = layitems(c->content, insetrect(cr, sep/2), TRUE);
330*7ab27030SDavid du Colombier 		c->lay->r = cr;
331*7ab27030SDavid du Colombier 	}
332*7ab27030SDavid du Colombier }
333