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