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