xref: /plan9/sys/src/cmd/abaco/cols.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
colinit(Column * c,Rectangle r)16*7ab27030SDavid du Colombier colinit(Column *c, Rectangle r)
17*7ab27030SDavid du Colombier {
18*7ab27030SDavid du Colombier 	Rectangle r1;
19*7ab27030SDavid du Colombier 	Text *t;
20*7ab27030SDavid du Colombier 
21*7ab27030SDavid du Colombier 	draw(screen, r, display->white, nil, ZP);
22*7ab27030SDavid du Colombier 	c->r = r;
23*7ab27030SDavid du Colombier 	c->w = nil;
24*7ab27030SDavid du Colombier 	c->nw = 0;
25*7ab27030SDavid du Colombier 	t = &c->tag;
26*7ab27030SDavid du Colombier 	t->w = nil;
27*7ab27030SDavid du Colombier 	t->col = c;
28*7ab27030SDavid du Colombier 	r1 = r;
29*7ab27030SDavid du Colombier 	r1.max.y = r1.min.y + font->height;
30*7ab27030SDavid du Colombier 	textinit(t, screen, r1, font, tagcols);
31*7ab27030SDavid du Colombier 	t->what = Columntag;
32*7ab27030SDavid du Colombier 	r1.min.y = r1.max.y;
33*7ab27030SDavid du Colombier 	r1.max.y += Border;
34*7ab27030SDavid du Colombier 	draw(screen, r1, display->black, nil, ZP);
35*7ab27030SDavid du Colombier 	textinsert(t, 0, L"New Cut Paste Snarf Sort Delcol ", 32);
36*7ab27030SDavid du Colombier 	textsetselect(t, t->rs.nr, t->rs.nr);
37*7ab27030SDavid du Colombier 	draw(screen, t->scrollr, colbutton, nil, colbutton->r.min);
38*7ab27030SDavid du Colombier 	c->safe = TRUE;
39*7ab27030SDavid du Colombier }
40*7ab27030SDavid du Colombier 
41*7ab27030SDavid du Colombier Window*
coladd(Column * c,Window * w,Window * clone,int y)42*7ab27030SDavid du Colombier coladd(Column *c, Window *w, Window *clone, int y)
43*7ab27030SDavid du Colombier {
44*7ab27030SDavid du Colombier 	Rectangle r, r1;
45*7ab27030SDavid du Colombier 	Window *v;
46*7ab27030SDavid du Colombier 	int i, t;
47*7ab27030SDavid du Colombier 
48*7ab27030SDavid du Colombier 	v = nil;
49*7ab27030SDavid du Colombier 	r = c->r;
50*7ab27030SDavid du Colombier 	r.min.y = c->tag.r.max.y+Border;
51*7ab27030SDavid du Colombier 	if(y<r.min.y && c->nw>0){	/* steal half of last window by default */
52*7ab27030SDavid du Colombier 		v = c->w[c->nw-1];
53*7ab27030SDavid du Colombier 		y = v->page.all.min.y+Dy(v->page.all)/2;
54*7ab27030SDavid du Colombier 	}
55*7ab27030SDavid du Colombier 	/* look for window we'll land on */
56*7ab27030SDavid du Colombier 	for(i=0; i<c->nw; i++){
57*7ab27030SDavid du Colombier 		v = c->w[i];
58*7ab27030SDavid du Colombier 		if(y < v->r.max.y)
59*7ab27030SDavid du Colombier 			break;
60*7ab27030SDavid du Colombier 	}
61*7ab27030SDavid du Colombier 	if(c->nw > 0){
62*7ab27030SDavid du Colombier 		if(i < c->nw)
63*7ab27030SDavid du Colombier 			i++;	/* new window will go after v */
64*7ab27030SDavid du Colombier 		/*
65*7ab27030SDavid du Colombier 		 * if v's too small, grow it first.
66*7ab27030SDavid du Colombier 		 */
67*7ab27030SDavid du Colombier 		if(!c->safe || Dy(v->page.all)<=3 ){
68*7ab27030SDavid du Colombier 			colgrow(c, v, 1);
69*7ab27030SDavid du Colombier 			y = v->page.all.min.y+Dy(v->page.all)/2;
70*7ab27030SDavid du Colombier 		}
71*7ab27030SDavid du Colombier 		r = v->r;
72*7ab27030SDavid du Colombier 		if(i == c->nw)
73*7ab27030SDavid du Colombier 			t = c->r.max.y;
74*7ab27030SDavid du Colombier 		else
75*7ab27030SDavid du Colombier 			t = c->w[i]->r.min.y-Border;
76*7ab27030SDavid du Colombier 		r.max.y = t;
77*7ab27030SDavid du Colombier 		r1 = r;
78*7ab27030SDavid du Colombier 		y = min(y, t-(Dy(v->r)-Dy(v->page.all)));
79*7ab27030SDavid du Colombier 		r1.max.y = min(y, v->page.all.min.y+Dy(v->page.all));
80*7ab27030SDavid du Colombier 		r1.min.y = winresize(v, r1, FALSE);
81*7ab27030SDavid du Colombier 		r1.max.y = r1.min.y+Border;
82*7ab27030SDavid du Colombier 		draw(screen, r1, display->black, nil, ZP);
83*7ab27030SDavid du Colombier 		r.min.y = r1.max.y;
84*7ab27030SDavid du Colombier 	}
85*7ab27030SDavid du Colombier 	if(w == nil){
86*7ab27030SDavid du Colombier 		w = emalloc(sizeof(Window));
87*7ab27030SDavid du Colombier 		w->col = c;
88*7ab27030SDavid du Colombier 		wininit(w, clone, r);
89*7ab27030SDavid du Colombier 	}else{
90*7ab27030SDavid du Colombier 		w->col = c;
91*7ab27030SDavid du Colombier 		winresize(w, r, FALSE);
92*7ab27030SDavid du Colombier 	}
93*7ab27030SDavid du Colombier 	w->tag.col = c;
94*7ab27030SDavid du Colombier 	w->tag.row = c->row;
95*7ab27030SDavid du Colombier 	w->url.col = c;
96*7ab27030SDavid du Colombier 	w->url.row = c->row;
97*7ab27030SDavid du Colombier 	w->page.col = c;
98*7ab27030SDavid du Colombier 	w->page.row = c->row;
99*7ab27030SDavid du Colombier 	w->status.col = c;
100*7ab27030SDavid du Colombier 	w->status.row = c->row;
101*7ab27030SDavid du Colombier 	c->w = realloc(c->w, (c->nw+1)*sizeof(Window*));
102*7ab27030SDavid du Colombier 	memmove(c->w+i+1, c->w+i, (c->nw-i)*sizeof(Window*));
103*7ab27030SDavid du Colombier 	c->nw++;
104*7ab27030SDavid du Colombier 	c->w[i] = w;
105*7ab27030SDavid du Colombier 	savemouse(w);
106*7ab27030SDavid du Colombier 	/* near but not on the button */
107*7ab27030SDavid du Colombier 	moveto(mousectl, addpt(w->tag.scrollr.max, Pt(3, 3)));
108*7ab27030SDavid du Colombier 	c->safe = TRUE;
109*7ab27030SDavid du Colombier 	return w;
110*7ab27030SDavid du Colombier }
111*7ab27030SDavid du Colombier 
112*7ab27030SDavid du Colombier void
colclose(Column * c,Window * w,int dofree)113*7ab27030SDavid du Colombier colclose(Column *c, Window *w, int dofree)
114*7ab27030SDavid du Colombier {
115*7ab27030SDavid du Colombier 	Rectangle r;
116*7ab27030SDavid du Colombier 	int i;
117*7ab27030SDavid du Colombier 
118*7ab27030SDavid du Colombier 	/* w is locked */
119*7ab27030SDavid du Colombier 	if(!c->safe)
120*7ab27030SDavid du Colombier 		colgrow(c, w, 1);
121*7ab27030SDavid du Colombier 	for(i=0; i<c->nw; i++)
122*7ab27030SDavid du Colombier 		if(c->w[i] == w)
123*7ab27030SDavid du Colombier 			goto Found;
124*7ab27030SDavid du Colombier 	error("can't find window");
125*7ab27030SDavid du Colombier   Found:
126*7ab27030SDavid du Colombier 	r = w->r;
127*7ab27030SDavid du Colombier 	w->tag.col = nil;
128*7ab27030SDavid du Colombier 	w->url.col = nil;
129*7ab27030SDavid du Colombier 	w->page.col = nil;
130*7ab27030SDavid du Colombier 	w->col = nil;
131*7ab27030SDavid du Colombier 	restoremouse(w);
132*7ab27030SDavid du Colombier 	if(dofree)
133*7ab27030SDavid du Colombier 		winclose(w);
134*7ab27030SDavid du Colombier 	memmove(c->w+i, c->w+i+1, (c->nw-i)*sizeof(Window*));
135*7ab27030SDavid du Colombier 	c->nw--;
136*7ab27030SDavid du Colombier 	c->w = realloc(c->w, c->nw*sizeof(Window*));
137*7ab27030SDavid du Colombier 	if(c->nw == 0){
138*7ab27030SDavid du Colombier 		draw(screen, r, display->white, nil, ZP);
139*7ab27030SDavid du Colombier 		return;
140*7ab27030SDavid du Colombier 	}
141*7ab27030SDavid du Colombier 	if(i == c->nw){		/* extend last window down */
142*7ab27030SDavid du Colombier 		w = c->w[i-1];
143*7ab27030SDavid du Colombier 		r.min.y = w->r.min.y;
144*7ab27030SDavid du Colombier 		r.max.y = c->r.max.y;
145*7ab27030SDavid du Colombier 	}else{			/* extend next window up */
146*7ab27030SDavid du Colombier 		w = c->w[i];
147*7ab27030SDavid du Colombier 		r.max.y = w->r.max.y;
148*7ab27030SDavid du Colombier 	}
149*7ab27030SDavid du Colombier 	if(c->safe)
150*7ab27030SDavid du Colombier 		winresize(w, r, FALSE);
151*7ab27030SDavid du Colombier }
152*7ab27030SDavid du Colombier 
153*7ab27030SDavid du Colombier void
colcloseall(Column * c)154*7ab27030SDavid du Colombier colcloseall(Column *c)
155*7ab27030SDavid du Colombier {
156*7ab27030SDavid du Colombier 	int i;
157*7ab27030SDavid du Colombier 	Window *w;
158*7ab27030SDavid du Colombier 
159*7ab27030SDavid du Colombier 	if(c == activecol)
160*7ab27030SDavid du Colombier 		activecol = nil;
161*7ab27030SDavid du Colombier 	if(seltext && c==seltext->col)
162*7ab27030SDavid du Colombier 		seltext = nil;
163*7ab27030SDavid du Colombier 	textclose(&c->tag);
164*7ab27030SDavid du Colombier 	for(i=0; i<c->nw; i++){
165*7ab27030SDavid du Colombier 		w = c->w[i];
166*7ab27030SDavid du Colombier 		w->tag.col = nil;
167*7ab27030SDavid du Colombier 		w->url.col = nil;
168*7ab27030SDavid du Colombier 		w->page.col = nil;
169*7ab27030SDavid du Colombier 		w->col = nil;
170*7ab27030SDavid du Colombier 		winclose(w);
171*7ab27030SDavid du Colombier 	}
172*7ab27030SDavid du Colombier 	c->nw = 0;
173*7ab27030SDavid du Colombier 	free(c->w);
174*7ab27030SDavid du Colombier 	free(c);
175*7ab27030SDavid du Colombier 	clearmouse();
176*7ab27030SDavid du Colombier }
177*7ab27030SDavid du Colombier 
178*7ab27030SDavid du Colombier void
colmousebut(Column * c)179*7ab27030SDavid du Colombier colmousebut(Column *c)
180*7ab27030SDavid du Colombier {
181*7ab27030SDavid du Colombier 	moveto(mousectl, divpt(addpt(c->tag.scrollr.min, c->tag.scrollr.max), 2));
182*7ab27030SDavid du Colombier }
183*7ab27030SDavid du Colombier 
184*7ab27030SDavid du Colombier void
colresize(Column * c,Rectangle r)185*7ab27030SDavid du Colombier colresize(Column *c, Rectangle r)
186*7ab27030SDavid du Colombier {
187*7ab27030SDavid du Colombier 	int i;
188*7ab27030SDavid du Colombier 	Rectangle r1, r2;
189*7ab27030SDavid du Colombier 	Window *w;
190*7ab27030SDavid du Colombier 
191*7ab27030SDavid du Colombier 	clearmouse();
192*7ab27030SDavid du Colombier 	r1 = r;
193*7ab27030SDavid du Colombier 	r1.max.y = r1.min.y + c->tag.font->height;
194*7ab27030SDavid du Colombier 	textresize(&c->tag, screen, r1);
195*7ab27030SDavid du Colombier 	draw(screen, c->tag.scrollr, colbutton, nil, colbutton->r.min);
196*7ab27030SDavid du Colombier 	r1.min.y = r1.max.y;
197*7ab27030SDavid du Colombier 	r1.max.y += Border;
198*7ab27030SDavid du Colombier 	draw(screen, r1, display->black, nil, ZP);
199*7ab27030SDavid du Colombier 	r1.max.y = r.max.y;
200*7ab27030SDavid du Colombier 	for(i=0; i<c->nw; i++){
201*7ab27030SDavid du Colombier 		w = c->w[i];
202*7ab27030SDavid du Colombier 		if(i == c->nw-1)
203*7ab27030SDavid du Colombier 			r1.max.y = r.max.y;
204*7ab27030SDavid du Colombier 		else
205*7ab27030SDavid du Colombier 			r1.max.y = r1.min.y+(Dy(w->r)+Border)*Dy(r)/Dy(c->r);
206*7ab27030SDavid du Colombier 		r2 = r1;
207*7ab27030SDavid du Colombier 		r2.max.y = r2.min.y+Border;
208*7ab27030SDavid du Colombier 		draw(screen, r2, display->black, nil, ZP);
209*7ab27030SDavid du Colombier 		r1.min.y = r2.max.y;
210*7ab27030SDavid du Colombier 		r1.min.y = winresize(w, r1, FALSE);
211*7ab27030SDavid du Colombier 	}
212*7ab27030SDavid du Colombier 	c->r = r;
213*7ab27030SDavid du Colombier }
214*7ab27030SDavid du Colombier 
215*7ab27030SDavid du Colombier static
216*7ab27030SDavid du Colombier int
colcmp(void * a,void * b)217*7ab27030SDavid du Colombier colcmp(void *a, void *b)
218*7ab27030SDavid du Colombier {
219*7ab27030SDavid du Colombier 	Rune *r1, *r2;
220*7ab27030SDavid du Colombier 	int i, nr1, nr2;
221*7ab27030SDavid du Colombier 
222*7ab27030SDavid du Colombier 	r1 = (*(Window**)a)->page.title.r;
223*7ab27030SDavid du Colombier 	nr1 = (*(Window**)a)->page.title.nr;
224*7ab27030SDavid du Colombier 	r2 = (*(Window**)b)->page.title.r;
225*7ab27030SDavid du Colombier 	nr2 = (*(Window**)b)->page.title.nr;
226*7ab27030SDavid du Colombier 	for(i=0; i<nr1 && i<nr2; i++){
227*7ab27030SDavid du Colombier 		if(*r1 != *r2)
228*7ab27030SDavid du Colombier 			return *r1-*r2;
229*7ab27030SDavid du Colombier 		r1++;
230*7ab27030SDavid du Colombier 		r2++;
231*7ab27030SDavid du Colombier 	}
232*7ab27030SDavid du Colombier 	return nr1-nr2;
233*7ab27030SDavid du Colombier }
234*7ab27030SDavid du Colombier 
235*7ab27030SDavid du Colombier void
colsort(Column * c)236*7ab27030SDavid du Colombier colsort(Column *c)
237*7ab27030SDavid du Colombier {
238*7ab27030SDavid du Colombier 	int i, y;
239*7ab27030SDavid du Colombier 	Rectangle r, r1, *rp;
240*7ab27030SDavid du Colombier 	Window **wp, *w;
241*7ab27030SDavid du Colombier 
242*7ab27030SDavid du Colombier 	if(c->nw == 0)
243*7ab27030SDavid du Colombier 		return;
244*7ab27030SDavid du Colombier 	clearmouse();
245*7ab27030SDavid du Colombier 	rp = emalloc(c->nw*sizeof(Rectangle));
246*7ab27030SDavid du Colombier 	wp = emalloc(c->nw*sizeof(Window*));
247*7ab27030SDavid du Colombier 	memmove(wp, c->w, c->nw*sizeof(Window*));
248*7ab27030SDavid du Colombier 	qsort(wp, c->nw, sizeof(Window*), colcmp);
249*7ab27030SDavid du Colombier 	for(i=0; i<c->nw; i++)
250*7ab27030SDavid du Colombier 		rp[i] = wp[i]->r;
251*7ab27030SDavid du Colombier 	r = c->r;
252*7ab27030SDavid du Colombier 	y = c->tag.r.max.y;
253*7ab27030SDavid du Colombier 	for(i=0; i<c->nw; i++){
254*7ab27030SDavid du Colombier 		w = wp[i];
255*7ab27030SDavid du Colombier 		r.min.y = y;
256*7ab27030SDavid du Colombier 		if(i == c->nw-1)
257*7ab27030SDavid du Colombier 			r.max.y = c->r.max.y;
258*7ab27030SDavid du Colombier 		else
259*7ab27030SDavid du Colombier 			r.max.y = r.min.y+Dy(w->r)+Border;
260*7ab27030SDavid du Colombier 		r1 = r;
261*7ab27030SDavid du Colombier 		r1.max.y = r1.min.y+Border;
262*7ab27030SDavid du Colombier 		draw(screen, r1, display->black, nil, ZP);
263*7ab27030SDavid du Colombier 		r.min.y = r1.max.y;
264*7ab27030SDavid du Colombier 		y = winresize(w, r, FALSE);
265*7ab27030SDavid du Colombier 	}
266*7ab27030SDavid du Colombier 	free(rp);
267*7ab27030SDavid du Colombier 	free(c->w);
268*7ab27030SDavid du Colombier 	c->w = wp;
269*7ab27030SDavid du Colombier }
270*7ab27030SDavid du Colombier 
271*7ab27030SDavid du Colombier void
colgrow(Column * c,Window * w,int but)272*7ab27030SDavid du Colombier colgrow(Column *c, Window *w, int but)
273*7ab27030SDavid du Colombier {
274*7ab27030SDavid du Colombier 	Rectangle r, cr;
275*7ab27030SDavid du Colombier 	int i, j, k, l, y1, y2, *nl, *ny, tot, nnl, onl, dnl, h, wnl;
276*7ab27030SDavid du Colombier 	Window *v;
277*7ab27030SDavid du Colombier 
278*7ab27030SDavid du Colombier 	for(i=0; i<c->nw; i++)
279*7ab27030SDavid du Colombier 		if(c->w[i] == w)
280*7ab27030SDavid du Colombier 			goto Found;
281*7ab27030SDavid du Colombier 	error("can't find window");
282*7ab27030SDavid du Colombier 
283*7ab27030SDavid du Colombier   Found:
284*7ab27030SDavid du Colombier 	cr = c->r;
285*7ab27030SDavid du Colombier 	if(but < 0){	/* make sure window fills its own space properly */
286*7ab27030SDavid du Colombier 		r = w->r;
287*7ab27030SDavid du Colombier 		if(i==c->nw-1 || c->safe==FALSE)
288*7ab27030SDavid du Colombier 			r.max.y = cr.max.y;
289*7ab27030SDavid du Colombier 		else
290*7ab27030SDavid du Colombier 			r.max.y = c->w[i+1]->r.min.y;
291*7ab27030SDavid du Colombier 		winresize(w, r, FALSE);
292*7ab27030SDavid du Colombier 		return;
293*7ab27030SDavid du Colombier 	}
294*7ab27030SDavid du Colombier 	cr.min.y = c->w[0]->r.min.y;
295*7ab27030SDavid du Colombier 	if(but == 3){	/* full size */
296*7ab27030SDavid du Colombier 		if(i != 0){
297*7ab27030SDavid du Colombier 			v = c->w[0];
298*7ab27030SDavid du Colombier 			c->w[0] = w;
299*7ab27030SDavid du Colombier 			c->w[i] = v;
300*7ab27030SDavid du Colombier 		}
301*7ab27030SDavid du Colombier 		for(j=1; j<c->nw; j++)
302*7ab27030SDavid du Colombier 			c->w[j]->page.all = ZR;
303*7ab27030SDavid du Colombier 		winresize(w, cr, FALSE);
304*7ab27030SDavid du Colombier 		c->safe = FALSE;
305*7ab27030SDavid du Colombier 		return;
306*7ab27030SDavid du Colombier 	}
307*7ab27030SDavid du Colombier 	/* store old #lines for each window */
308*7ab27030SDavid du Colombier 	wnl = Dy(w->page.all);
309*7ab27030SDavid du Colombier 	onl = wnl;
310*7ab27030SDavid du Colombier 	nl = emalloc(c->nw * sizeof(int));
311*7ab27030SDavid du Colombier 	ny = emalloc(c->nw * sizeof(int));
312*7ab27030SDavid du Colombier 	tot = 0;
313*7ab27030SDavid du Colombier 	for(j=0; j<c->nw; j++){
314*7ab27030SDavid du Colombier 		l = Dy(c->w[j]->page.all);
315*7ab27030SDavid du Colombier 		nl[j] = l;
316*7ab27030SDavid du Colombier 		tot += l;
317*7ab27030SDavid du Colombier 	}
318*7ab27030SDavid du Colombier 	/* approximate new #lines for this window */
319*7ab27030SDavid du Colombier 	if(but == 2){	/* as big as can be */
320*7ab27030SDavid du Colombier 		memset(nl, 0, c->nw * sizeof(int));
321*7ab27030SDavid du Colombier 		goto Pack;
322*7ab27030SDavid du Colombier 	}
323*7ab27030SDavid du Colombier 	nnl = min(onl + max(min(5, wnl), onl/2), tot);
324*7ab27030SDavid du Colombier 	if(nnl < wnl)
325*7ab27030SDavid du Colombier 		nnl = (wnl+nnl)/2;
326*7ab27030SDavid du Colombier 	if(nnl == 0)
327*7ab27030SDavid du Colombier 		nnl = 2;
328*7ab27030SDavid du Colombier 	dnl = nnl - onl;
329*7ab27030SDavid du Colombier 	/* compute new #lines for each window */
330*7ab27030SDavid du Colombier 	for(k=1; k<c->nw; k++){
331*7ab27030SDavid du Colombier 		/* prune from later window */
332*7ab27030SDavid du Colombier 		j = i+k;
333*7ab27030SDavid du Colombier 		if(j<c->nw && nl[j]){
334*7ab27030SDavid du Colombier 			l = min(dnl, max(1, nl[j]/2));
335*7ab27030SDavid du Colombier 			nl[j] -= l;
336*7ab27030SDavid du Colombier 			nl[i] += l;
337*7ab27030SDavid du Colombier 			dnl -= l;
338*7ab27030SDavid du Colombier 		}
339*7ab27030SDavid du Colombier 		/* prune from earlier window */
340*7ab27030SDavid du Colombier 		j = i-k;
341*7ab27030SDavid du Colombier 		if(j>=0 && nl[j]){
342*7ab27030SDavid du Colombier 			l = min(dnl, max(1, nl[j]/2));
343*7ab27030SDavid du Colombier 			nl[j] -= l;
344*7ab27030SDavid du Colombier 			nl[i] += l;
345*7ab27030SDavid du Colombier 			dnl -= l;
346*7ab27030SDavid du Colombier 		}
347*7ab27030SDavid du Colombier 	}
348*7ab27030SDavid du Colombier     Pack:
349*7ab27030SDavid du Colombier 	/* pack everyone above */
350*7ab27030SDavid du Colombier 	y1 = cr.min.y;
351*7ab27030SDavid du Colombier 	for(j=0; j<i; j++){
352*7ab27030SDavid du Colombier 		v = c->w[j];
353*7ab27030SDavid du Colombier 		r = v->r;
354*7ab27030SDavid du Colombier 		r.min.y = y1;
355*7ab27030SDavid du Colombier 		r.max.y = y1+Dy(v->tag.all)+Border+Dy(v->url.all);
356*7ab27030SDavid du Colombier 		if(nl[j])
357*7ab27030SDavid du Colombier 			r.max.y += 1 + nl[j];
358*7ab27030SDavid du Colombier 		if(!c->safe || !eqrect(v->r, r))
359*7ab27030SDavid du Colombier 			winresize(v, r, c->safe);
360*7ab27030SDavid du Colombier 
361*7ab27030SDavid du Colombier 		r.min.y = v->r.max.y;
362*7ab27030SDavid du Colombier 		r.max.y += Border;
363*7ab27030SDavid du Colombier 		draw(screen, r, display->black, nil, ZP);
364*7ab27030SDavid du Colombier 		y1 = r.max.y;
365*7ab27030SDavid du Colombier 	}
366*7ab27030SDavid du Colombier 	/* scan to see new size of everyone below */
367*7ab27030SDavid du Colombier 	y2 = c->r.max.y;
368*7ab27030SDavid du Colombier 	for(j=c->nw-1; j>i; j--){
369*7ab27030SDavid du Colombier 		v = c->w[j];
370*7ab27030SDavid du Colombier 		r = v->r;
371*7ab27030SDavid du Colombier 		r.min.y = y2-Dy(v->tag.all)-Border-Dy(v->url.all);
372*7ab27030SDavid du Colombier 		if(nl[j])
373*7ab27030SDavid du Colombier 			r.min.y -= 1 + nl[j];
374*7ab27030SDavid du Colombier 		r.min.y -= Border;
375*7ab27030SDavid du Colombier 		ny[j] = r.min.y;
376*7ab27030SDavid du Colombier 		y2 = r.min.y;
377*7ab27030SDavid du Colombier 	}
378*7ab27030SDavid du Colombier 	/* compute new size of window */
379*7ab27030SDavid du Colombier 	r = w->r;
380*7ab27030SDavid du Colombier 	r.min.y = y1;
381*7ab27030SDavid du Colombier 	if(i == c->nw-1)
382*7ab27030SDavid du Colombier 		r.max.y = c->r.max.y;
383*7ab27030SDavid du Colombier 	else{
384*7ab27030SDavid du Colombier 		r.max.y = r.min.y+Dy(w->tag.all)+Border+Dy(w->url.all);
385*7ab27030SDavid du Colombier 		h = font->height;
386*7ab27030SDavid du Colombier 		if(y2-r.max.y >= 2*(1+h+Border)){
387*7ab27030SDavid du Colombier 			r.max.y += 1;
388*7ab27030SDavid du Colombier 			r.max.y += h*((y2-r.max.y)/h);
389*7ab27030SDavid du Colombier 		}
390*7ab27030SDavid du Colombier 	}
391*7ab27030SDavid du Colombier 	/* draw window */
392*7ab27030SDavid du Colombier 	if(!c->safe || !eqrect(w->r, r))
393*7ab27030SDavid du Colombier 		winresize(w, r, c->safe);
394*7ab27030SDavid du Colombier 
395*7ab27030SDavid du Colombier 	if(i < c->nw-1){
396*7ab27030SDavid du Colombier 		r.min.y = r.max.y;
397*7ab27030SDavid du Colombier 		r.max.y += Border;
398*7ab27030SDavid du Colombier 		draw(screen, r, display->black, nil, ZP);
399*7ab27030SDavid du Colombier 		for(j=i+1; j<c->nw; j++)
400*7ab27030SDavid du Colombier 			ny[j] -= (y2-r.max.y);
401*7ab27030SDavid du Colombier 	}
402*7ab27030SDavid du Colombier 	/* pack everyone below */
403*7ab27030SDavid du Colombier 	y1 = r.max.y;
404*7ab27030SDavid du Colombier 	for(j=i+1; j<c->nw; j++){
405*7ab27030SDavid du Colombier 		v = c->w[j];
406*7ab27030SDavid du Colombier 		r = v->r;
407*7ab27030SDavid du Colombier 		r.min.y = y1;
408*7ab27030SDavid du Colombier 		if(j == c->nw-1)
409*7ab27030SDavid du Colombier 			r.max.y = c->r.max.y;
410*7ab27030SDavid du Colombier 		else{
411*7ab27030SDavid du Colombier 			r.max.y = y1+Dy(v->tag.all)+Border+Dy(v->url.all);
412*7ab27030SDavid du Colombier 			if(nl[j])
413*7ab27030SDavid du Colombier 				r.max.y += 1 + nl[j];
414*7ab27030SDavid du Colombier 		}
415*7ab27030SDavid du Colombier 		if(!c->safe || !eqrect(v->r, r))
416*7ab27030SDavid du Colombier 			winresize(v, r, c->safe);
417*7ab27030SDavid du Colombier 		if(j < c->nw-1){	/* no border on last window */
418*7ab27030SDavid du Colombier 			r.min.y = v->r.max.y;
419*7ab27030SDavid du Colombier 			r.max.y += Border;
420*7ab27030SDavid du Colombier 			draw(screen, r, display->black, nil, ZP);
421*7ab27030SDavid du Colombier 		}
422*7ab27030SDavid du Colombier 		y1 = r.max.y;
423*7ab27030SDavid du Colombier 	}
424*7ab27030SDavid du Colombier 	free(nl);
425*7ab27030SDavid du Colombier 	free(ny);
426*7ab27030SDavid du Colombier 	c->safe = TRUE;
427*7ab27030SDavid du Colombier 	winmousebut(w);
428*7ab27030SDavid du Colombier }
429*7ab27030SDavid du Colombier 
430*7ab27030SDavid du Colombier void
coldragwin(Column * c,Window * w,int but)431*7ab27030SDavid du Colombier coldragwin(Column *c, Window *w, int but)
432*7ab27030SDavid du Colombier {
433*7ab27030SDavid du Colombier 	Rectangle r;
434*7ab27030SDavid du Colombier 	int i, b;
435*7ab27030SDavid du Colombier 	Point p, op;
436*7ab27030SDavid du Colombier 	Window *v;
437*7ab27030SDavid du Colombier 	Column *nc;
438*7ab27030SDavid du Colombier 
439*7ab27030SDavid du Colombier 	clearmouse();
440*7ab27030SDavid du Colombier 	setcursor(mousectl, &boxcursor);
441*7ab27030SDavid du Colombier 	b = mouse->buttons;
442*7ab27030SDavid du Colombier 	op = mouse->xy;
443*7ab27030SDavid du Colombier 	while(mouse->buttons == b)
444*7ab27030SDavid du Colombier 		readmouse(mousectl);
445*7ab27030SDavid du Colombier 	setcursor(mousectl, nil);
446*7ab27030SDavid du Colombier 	if(mouse->buttons){
447*7ab27030SDavid du Colombier 		while(mouse->buttons)
448*7ab27030SDavid du Colombier 			readmouse(mousectl);
449*7ab27030SDavid du Colombier 		return;
450*7ab27030SDavid du Colombier 	}
451*7ab27030SDavid du Colombier 
452*7ab27030SDavid du Colombier 	for(i=0; i<c->nw; i++)
453*7ab27030SDavid du Colombier 		if(c->w[i] == w)
454*7ab27030SDavid du Colombier 			goto Found;
455*7ab27030SDavid du Colombier 	error("can't find window");
456*7ab27030SDavid du Colombier 
457*7ab27030SDavid du Colombier   Found:
458*7ab27030SDavid du Colombier 	p = mouse->xy;
459*7ab27030SDavid du Colombier 	if(abs(p.x-op.x)<5 && abs(p.y-op.y)<5){
460*7ab27030SDavid du Colombier 		colgrow(c, w, but);
461*7ab27030SDavid du Colombier 		winmousebut(w);
462*7ab27030SDavid du Colombier 		return;
463*7ab27030SDavid du Colombier 	}
464*7ab27030SDavid du Colombier 	/* is it a flick to the right? */
465*7ab27030SDavid du Colombier 	if(abs(p.y-op.y)<10 && p.x>op.x+30 && rowwhichcol(c->row, p)==c)
466*7ab27030SDavid du Colombier 		p.x = op.x+Dx(w->r);	/* yes: toss to next column */
467*7ab27030SDavid du Colombier 	nc = rowwhichcol(c->row, p);
468*7ab27030SDavid du Colombier 	if(nc!=nil && nc!=c){
469*7ab27030SDavid du Colombier 		colclose(c, w, FALSE);
470*7ab27030SDavid du Colombier 		coladd(nc, w, nil, p.y);
471*7ab27030SDavid du Colombier 		winmousebut(w);
472*7ab27030SDavid du Colombier 		return;
473*7ab27030SDavid du Colombier 	}
474*7ab27030SDavid du Colombier 	if(i==0 && c->nw==1)
475*7ab27030SDavid du Colombier 		return;			/* can't do it */
476*7ab27030SDavid du Colombier 	if((i>0 && p.y<c->w[i-1]->r.min.y) || (i<c->nw-1 && p.y>w->r.max.y)
477*7ab27030SDavid du Colombier 	|| (i==0 && p.y>w->r.max.y)){
478*7ab27030SDavid du Colombier 		/* shuffle */
479*7ab27030SDavid du Colombier 		colclose(c, w, FALSE);
480*7ab27030SDavid du Colombier 		coladd(c, w, nil, p.y);
481*7ab27030SDavid du Colombier 		winmousebut(w);
482*7ab27030SDavid du Colombier 		return;
483*7ab27030SDavid du Colombier 	}
484*7ab27030SDavid du Colombier 	if(i == 0)
485*7ab27030SDavid du Colombier 		return;
486*7ab27030SDavid du Colombier 	v = c->w[i-1];
487*7ab27030SDavid du Colombier 	if(p.y < v->url.all.max.y)
488*7ab27030SDavid du Colombier 		p.y = v->url.all.max.y;
489*7ab27030SDavid du Colombier 	if(p.y > w->r.max.y-Dy(w->tag.all)-Border-Dy(w->url.all))
490*7ab27030SDavid du Colombier 		p.y = w->r.max.y-Dy(w->tag.all)-Border-Dy(w->url.all);
491*7ab27030SDavid du Colombier 	r = v->r;
492*7ab27030SDavid du Colombier 	r.max.y = p.y;
493*7ab27030SDavid du Colombier 	if(r.max.y > v->page.all.min.y){
494*7ab27030SDavid du Colombier 		r.max.y -= (r.max.y-v->page.all.min.y)%font->height;
495*7ab27030SDavid du Colombier 		if(v->page.all.min.y == v->page.all.max.y)
496*7ab27030SDavid du Colombier 			r.max.y++;
497*7ab27030SDavid du Colombier 	}
498*7ab27030SDavid du Colombier 	if(!eqrect(v->r, r))
499*7ab27030SDavid du Colombier 		winresize(v, r, c->safe);
500*7ab27030SDavid du Colombier 	r.min.y = v->r.max.y;
501*7ab27030SDavid du Colombier 	r.max.y = r.min.y+Border;
502*7ab27030SDavid du Colombier 	draw(screen, r, display->black, nil, ZP);
503*7ab27030SDavid du Colombier 	r.min.y = r.max.y;
504*7ab27030SDavid du Colombier 	if(i == c->nw-1)
505*7ab27030SDavid du Colombier 		r.max.y = c->r.max.y;
506*7ab27030SDavid du Colombier 	else
507*7ab27030SDavid du Colombier 		r.max.y = c->w[i+1]->r.min.y-Border;
508*7ab27030SDavid du Colombier 	if(!eqrect(w->r, r))
509*7ab27030SDavid du Colombier 		winresize(w, r, c->safe);
510*7ab27030SDavid du Colombier 	c->safe = TRUE;
511*7ab27030SDavid du Colombier     	winmousebut(w);
512*7ab27030SDavid du Colombier }
513*7ab27030SDavid du Colombier 
514*7ab27030SDavid du Colombier Text*
colwhich(Column * c,Point p,Rune r,int key)515*7ab27030SDavid du Colombier colwhich(Column *c, Point p, Rune r, int key)
516*7ab27030SDavid du Colombier {
517*7ab27030SDavid du Colombier 	Window *w;
518*7ab27030SDavid du Colombier 	Text *t;
519*7ab27030SDavid du Colombier 	int i;
520*7ab27030SDavid du Colombier 
521*7ab27030SDavid du Colombier 	if(!ptinrect(p, c->r))
522*7ab27030SDavid du Colombier 		return nil;
523*7ab27030SDavid du Colombier 	if(ptinrect(p, c->tag.all))
524*7ab27030SDavid du Colombier 		return &c->tag;
525*7ab27030SDavid du Colombier 	for(i=0; i<c->nw; i++){
526*7ab27030SDavid du Colombier 		w = c->w[i];
527*7ab27030SDavid du Colombier 		if(ptinrect(p, w->r)){
528*7ab27030SDavid du Colombier 			winlock(w, key ? 'K' : 'M');
529*7ab27030SDavid du Colombier 			if(key)
530*7ab27030SDavid du Colombier 				t = wintype(w, p, r);
531*7ab27030SDavid du Colombier 			else
532*7ab27030SDavid du Colombier 				t = winmouse(w, p, r);
533*7ab27030SDavid du Colombier 			winunlock(w);
534*7ab27030SDavid du Colombier 			return t;
535*7ab27030SDavid du Colombier 		}
536*7ab27030SDavid du Colombier 	}
537*7ab27030SDavid du Colombier 	return nil;
538*7ab27030SDavid du Colombier }
539*7ab27030SDavid du Colombier 
540*7ab27030SDavid du Colombier int
colclean(Column * c)541*7ab27030SDavid du Colombier colclean(Column *c)
542*7ab27030SDavid du Colombier {
543*7ab27030SDavid du Colombier 	int i, clean;
544*7ab27030SDavid du Colombier 
545*7ab27030SDavid du Colombier 	clean = TRUE;
546*7ab27030SDavid du Colombier 	for(i=0; i<c->nw; i++)
547*7ab27030SDavid du Colombier 		clean &= winclean(c->w[i], TRUE);
548*7ab27030SDavid du Colombier 	return clean;
549*7ab27030SDavid du Colombier }
550