Subversion Repositories planix.SVN

Rev

Details | Last modification | View Log | RSS feed

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