Introduction
Introduction Statistics Contact Development Disclaimer Help
tcols.c - plan9port - [fork] Plan 9 from user space
git clone git://src.adamsgaard.dk/plan9port
Log
Files
Refs
README
LICENSE
---
tcols.c (12516B)
---
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 <libsec.h>
12 #include "dat.h"
13 #include "fns.h"
14
15 static Rune Lheader[] = {
16 'N', 'e', 'w', ' ',
17 'C', 'u', 't', ' ',
18 'P', 'a', 's', 't', 'e', ' ',
19 'S', 'n', 'a', 'r', 'f', ' ',
20 'S', 'o', 'r', 't', ' ',
21 'Z', 'e', 'r', 'o', 'x', ' ',
22 'D', 'e', 'l', 'c', 'o', 'l', ' ',
23 0
24 };
25
26 void
27 colinit(Column *c, Rectangle r)
28 {
29 Rectangle r1;
30 Text *t;
31
32 draw(screen, r, display->white, nil, ZP);
33 c->r = r;
34 c->w = nil;
35 c->nw = 0;
36 t = &c->tag;
37 t->w = nil;
38 t->col = c;
39 r1 = r;
40 r1.max.y = r1.min.y + font->height;
41 textinit(t, fileaddtext(nil, t), r1, &reffont, tagcols);
42 t->what = Columntag;
43 r1.min.y = r1.max.y;
44 r1.max.y += Border;
45 draw(screen, r1, display->black, nil, ZP);
46 textinsert(t, 0, Lheader, 38, TRUE);
47 textsetselect(t, t->file->b.nc, t->file->b.nc);
48 draw(screen, t->scrollr, colbutton, nil, colbutton->r.min);
49 c->safe = TRUE;
50 }
51
52 Window*
53 coladd(Column *c, Window *w, Window *clone, int y)
54 {
55 Rectangle r, r1;
56 Window *v;
57 int i, j, minht, ymax, buggered;
58
59 v = nil;
60 r = c->r;
61 r.min.y = c->tag.fr.r.max.y+Border;
62 if(y<r.min.y && c->nw>0){ /* steal half of last window by…
63 v = c->w[c->nw-1];
64 y = v->body.fr.r.min.y+Dy(v->body.fr.r)/2;
65 }
66 /* look for window we'll land on */
67 for(i=0; i<c->nw; i++){
68 v = c->w[i];
69 if(y < v->r.max.y)
70 break;
71 }
72 buggered = 0;
73 if(c->nw > 0){
74 if(i < c->nw)
75 i++; /* new window will go after v */
76 /*
77 * if landing window (v) is too small, grow it first.
78 */
79 minht = v->tag.fr.font->height+Border+1;
80 j = 0;
81 while(!c->safe || v->body.fr.maxlines<=3 || Dy(v->body.a…
82 if(++j > 10){
83 buggered = 1; /* too many windows…
84 break;
85 }
86 colgrow(c, v, 1);
87 }
88
89 /*
90 * figure out where to split v to make room for w
91 */
92
93 /* new window stops where next window begins */
94 if(i < c->nw)
95 ymax = c->w[i]->r.min.y-Border;
96 else
97 ymax = c->r.max.y;
98
99 /* new window must start after v's tag ends */
100 y = max(y, v->tagtop.max.y+Border);
101
102 /* new window must start early enough to end before ymax…
103 y = min(y, ymax - minht);
104
105 /* if y is too small, too many windows in column */
106 if(y < v->tagtop.max.y+Border)
107 buggered = 1;
108
109 /*
110 * resize & redraw v
111 */
112 r = v->r;
113 r.max.y = ymax;
114 draw(screen, r, textcols[BACK], nil, ZP);
115 r1 = r;
116 y = min(y, ymax-(v->tag.fr.font->height*v->taglines+v->b…
117 r1.max.y = min(y, v->body.fr.r.min.y+v->body.fr.nlines*v…
118 r1.min.y = winresize(v, r1, FALSE, FALSE);
119 r1.max.y = r1.min.y+Border;
120 draw(screen, r1, display->black, nil, ZP);
121
122 /*
123 * leave r with w's coordinates
124 */
125 r.min.y = r1.max.y;
126 }
127 if(w == nil){
128 w = emalloc(sizeof(Window));
129 w->col = c;
130 draw(screen, r, textcols[BACK], nil, ZP);
131 wininit(w, clone, r);
132 }else{
133 w->col = c;
134 winresize(w, r, FALSE, TRUE);
135 }
136 w->tag.col = c;
137 w->tag.row = c->row;
138 w->body.col = c;
139 w->body.row = c->row;
140 c->w = realloc(c->w, (c->nw+1)*sizeof(Window*));
141 memmove(c->w+i+1, c->w+i, (c->nw-i)*sizeof(Window*));
142 c->nw++;
143 c->w[i] = w;
144 c->safe = TRUE;
145
146 /* if there were too many windows, redraw the whole column */
147 if(buggered)
148 colresize(c, c->r);
149
150 savemouse(w);
151 /* near the button, but in the body */
152 moveto(mousectl, addpt(w->tag.scrollr.max, Pt(3, 3)));
153 barttext = &w->body;
154 return w;
155 }
156
157 void
158 colclose(Column *c, Window *w, int dofree)
159 {
160 Rectangle r;
161 int i, didmouse, up;
162
163 /* w is locked */
164 if(!c->safe)
165 colgrow(c, w, 1);
166 for(i=0; i<c->nw; i++)
167 if(c->w[i] == w)
168 goto Found;
169 error("can't find window");
170 Found:
171 r = w->r;
172 w->tag.col = nil;
173 w->body.col = nil;
174 w->col = nil;
175 didmouse = restoremouse(w);
176 if(dofree){
177 windelete(w);
178 winclose(w);
179 }
180 c->nw--;
181 memmove(c->w+i, c->w+i+1, (c->nw-i)*sizeof(Window*));
182 c->w = realloc(c->w, c->nw*sizeof(Window*));
183 if(c->nw == 0){
184 draw(screen, r, display->white, nil, ZP);
185 return;
186 }
187 up = 0;
188 if(i == c->nw){ /* extend last window down */
189 w = c->w[i-1];
190 r.min.y = w->r.min.y;
191 r.max.y = c->r.max.y;
192 }else{ /* extend next window up */
193 up = 1;
194 w = c->w[i];
195 r.max.y = w->r.max.y;
196 }
197 draw(screen, r, textcols[BACK], nil, ZP);
198 if(c->safe) {
199 if(!didmouse && up)
200 w->showdel = TRUE;
201 winresize(w, r, FALSE, TRUE);
202 if(!didmouse && up)
203 movetodel(w);
204 }
205 }
206
207 void
208 colcloseall(Column *c)
209 {
210 int i;
211 Window *w;
212
213 if(c == activecol)
214 activecol = nil;
215 textclose(&c->tag);
216 for(i=0; i<c->nw; i++){
217 w = c->w[i];
218 winclose(w);
219 }
220 c->nw = 0;
221 free(c->w);
222 free(c);
223 clearmouse();
224 }
225
226 void
227 colmousebut(Column *c)
228 {
229 moveto(mousectl, divpt(addpt(c->tag.scrollr.min, c->tag.scrollr.…
230 }
231
232 void
233 colresize(Column *c, Rectangle r)
234 {
235 int i, old, new;
236 Rectangle r1, r2;
237 Window *w;
238
239 clearmouse();
240 r1 = r;
241 r1.max.y = r1.min.y + c->tag.fr.font->height;
242 textresize(&c->tag, r1, TRUE);
243 draw(screen, c->tag.scrollr, colbutton, nil, colbutton->r.min);
244 r1.min.y = r1.max.y;
245 r1.max.y += Border;
246 draw(screen, r1, display->black, nil, ZP);
247 r1.max.y = r.max.y;
248 new = Dy(r) - c->nw*(Border + font->height);
249 old = Dy(c->r) - c->nw*(Border + font->height);
250 for(i=0; i<c->nw; i++){
251 w = c->w[i];
252 w->maxlines = 0;
253 if(i == c->nw-1)
254 r1.max.y = r.max.y;
255 else{
256 r1.max.y = r1.min.y;
257 if(new > 0 && old > 0 && Dy(w->r) > Border+font-…
258 r1.max.y += (Dy(w->r)-Border-font->heigh…
259 }
260 }
261 r1.max.y = max(r1.max.y, r1.min.y + Border+font->height);
262 r2 = r1;
263 r2.max.y = r2.min.y+Border;
264 draw(screen, r2, display->black, nil, ZP);
265 r1.min.y = r2.max.y;
266 r1.min.y = winresize(w, r1, FALSE, i==c->nw-1);
267 }
268 c->r = r;
269 }
270
271 static
272 int
273 colcmp(const void *a, const void *b)
274 {
275 Rune *r1, *r2;
276 int i, nr1, nr2;
277
278 r1 = (*(Window**)a)->body.file->name;
279 nr1 = (*(Window**)a)->body.file->nname;
280 r2 = (*(Window**)b)->body.file->name;
281 nr2 = (*(Window**)b)->body.file->nname;
282 for(i=0; i<nr1 && i<nr2; i++){
283 if(*r1 != *r2)
284 return *r1-*r2;
285 r1++;
286 r2++;
287 }
288 return nr1-nr2;
289 }
290
291 void
292 colsort(Column *c)
293 {
294 int i, y;
295 Rectangle r, r1, *rp;
296 Window **wp, *w;
297
298 if(c->nw == 0)
299 return;
300 clearmouse();
301 rp = emalloc(c->nw*sizeof(Rectangle));
302 wp = emalloc(c->nw*sizeof(Window*));
303 memmove(wp, c->w, c->nw*sizeof(Window*));
304 qsort(wp, c->nw, sizeof(Window*), colcmp);
305 for(i=0; i<c->nw; i++)
306 rp[i] = wp[i]->r;
307 r = c->r;
308 r.min.y = c->tag.fr.r.max.y;
309 draw(screen, r, textcols[BACK], nil, ZP);
310 y = r.min.y;
311 for(i=0; i<c->nw; i++){
312 w = wp[i];
313 r.min.y = y;
314 if(i == c->nw-1)
315 r.max.y = c->r.max.y;
316 else
317 r.max.y = r.min.y+Dy(w->r)+Border;
318 r1 = r;
319 r1.max.y = r1.min.y+Border;
320 draw(screen, r1, display->black, nil, ZP);
321 r.min.y = r1.max.y;
322 y = winresize(w, r, FALSE, i==c->nw-1);
323 }
324 free(rp);
325 free(c->w);
326 c->w = wp;
327 }
328
329 void
330 colgrow(Column *c, Window *w, int but)
331 {
332 Rectangle r, cr;
333 int i, j, k, l, y1, y2, *nl, *ny, tot, nnl, onl, dnl, h;
334 Window *v;
335
336 for(i=0; i<c->nw; i++)
337 if(c->w[i] == w)
338 goto Found;
339 error("can't find window");
340
341 Found:
342 cr = c->r;
343 if(but < 0){ /* make sure window fills its own space prop…
344 r = w->r;
345 if(i==c->nw-1 || c->safe==FALSE)
346 r.max.y = cr.max.y;
347 else
348 r.max.y = c->w[i+1]->r.min.y - Border;
349 winresize(w, r, FALSE, TRUE);
350 return;
351 }
352 cr.min.y = c->w[0]->r.min.y;
353 if(but == 3){ /* full size */
354 if(i != 0){
355 v = c->w[0];
356 c->w[0] = w;
357 c->w[i] = v;
358 }
359 draw(screen, cr, textcols[BACK], nil, ZP);
360 winresize(w, cr, FALSE, TRUE);
361 for(i=1; i<c->nw; i++)
362 c->w[i]->body.fr.maxlines = 0;
363 c->safe = FALSE;
364 return;
365 }
366 /* store old #lines for each window */
367 onl = w->body.fr.maxlines;
368 nl = emalloc(c->nw * sizeof(int));
369 ny = emalloc(c->nw * sizeof(int));
370 tot = 0;
371 for(j=0; j<c->nw; j++){
372 l = c->w[j]->taglines-1 + c->w[j]->body.fr.maxlines;
373 nl[j] = l;
374 tot += l;
375 }
376 /* approximate new #lines for this window */
377 if(but == 2){ /* as big as can be */
378 memset(nl, 0, c->nw * sizeof(int));
379 goto Pack;
380 }
381 nnl = min(onl + max(min(5, w->taglines-1+w->maxlines), onl/2), t…
382 if(nnl < w->taglines-1+w->maxlines)
383 nnl = (w->taglines-1+w->maxlines + nnl)/2;
384 if(nnl == 0)
385 nnl = 2;
386 dnl = nnl - onl;
387 /* compute new #lines for each window */
388 for(k=1; k<c->nw; k++){
389 /* prune from later window */
390 j = i+k;
391 if(j<c->nw && nl[j]){
392 l = min(dnl, max(1, nl[j]/2));
393 nl[j] -= l;
394 nl[i] += l;
395 dnl -= l;
396 }
397 /* prune from earlier window */
398 j = i-k;
399 if(j>=0 && nl[j]){
400 l = min(dnl, max(1, nl[j]/2));
401 nl[j] -= l;
402 nl[i] += l;
403 dnl -= l;
404 }
405 }
406 Pack:
407 /* pack everyone above */
408 y1 = cr.min.y;
409 for(j=0; j<i; j++){
410 v = c->w[j];
411 r = v->r;
412 r.min.y = y1;
413 r.max.y = y1+Dy(v->tagtop);
414 if(nl[j])
415 r.max.y += 1 + nl[j]*v->body.fr.font->height;
416 r.min.y = winresize(v, r, c->safe, FALSE);
417 r.max.y += Border;
418 draw(screen, r, display->black, nil, ZP);
419 y1 = r.max.y;
420 }
421 /* scan to see new size of everyone below */
422 y2 = c->r.max.y;
423 for(j=c->nw-1; j>i; j--){
424 v = c->w[j];
425 r = v->r;
426 r.min.y = y2-Dy(v->tagtop);
427 if(nl[j])
428 r.min.y -= 1 + nl[j]*v->body.fr.font->height;
429 r.min.y -= Border;
430 ny[j] = r.min.y;
431 y2 = r.min.y;
432 }
433 /* compute new size of window */
434 r = w->r;
435 r.min.y = y1;
436 r.max.y = y2;
437 h = w->body.fr.font->height;
438 if(Dy(r) < Dy(w->tagtop)+1+h+Border)
439 r.max.y = r.min.y + Dy(w->tagtop)+1+h+Border;
440 /* draw window */
441 r.max.y = winresize(w, r, c->safe, TRUE);
442 if(i < c->nw-1){
443 r.min.y = r.max.y;
444 r.max.y += Border;
445 draw(screen, r, display->black, nil, ZP);
446 for(j=i+1; j<c->nw; j++)
447 ny[j] -= (y2-r.max.y);
448 }
449 /* pack everyone below */
450 y1 = r.max.y;
451 for(j=i+1; j<c->nw; j++){
452 v = c->w[j];
453 r = v->r;
454 r.min.y = y1;
455 r.max.y = y1+Dy(v->tagtop);
456 if(nl[j])
457 r.max.y += 1 + nl[j]*v->body.fr.font->height;
458 y1 = winresize(v, r, c->safe, j==c->nw-1);
459 if(j < c->nw-1){ /* no border on last window */
460 r.min.y = y1;
461 r.max.y += Border;
462 draw(screen, r, display->black, nil, ZP);
463 y1 = r.max.y;
464 }
465 }
466 free(nl);
467 free(ny);
468 c->safe = TRUE;
469 winmousebut(w);
470 }
471
472 void
473 coldragwin(Column *c, Window *w, int but)
474 {
475 Rectangle r;
476 int i, b;
477 Point p, op;
478 Window *v;
479 Column *nc;
480
481 clearmouse();
482 setcursor2(mousectl, &boxcursor, &boxcursor2);
483 b = mouse->buttons;
484 op = mouse->xy;
485 while(mouse->buttons == b)
486 readmouse(mousectl);
487 setcursor(mousectl, nil);
488 if(mouse->buttons){
489 while(mouse->buttons)
490 readmouse(mousectl);
491 return;
492 }
493
494 for(i=0; i<c->nw; i++)
495 if(c->w[i] == w)
496 goto Found;
497 error("can't find window");
498
499 Found:
500 if(w->tagexpand) /* force recomputation of window tag siz…
501 w->taglines = 1;
502 p = mouse->xy;
503 if(abs(p.x-op.x)<5 && abs(p.y-op.y)<5){
504 colgrow(c, w, but);
505 winmousebut(w);
506 return;
507 }
508 /* is it a flick to the right? */
509 if(abs(p.y-op.y)<10 && p.x>op.x+30 && rowwhichcol(c->row, p)==c)
510 p.x = op.x+Dx(w->r); /* yes: toss to next column …
511 nc = rowwhichcol(c->row, p);
512 if(nc!=nil && nc!=c){
513 colclose(c, w, FALSE);
514 coladd(nc, w, nil, p.y);
515 winmousebut(w);
516 return;
517 }
518 if(i==0 && c->nw==1)
519 return; /* can't do it */
520 if((i>0 && p.y<c->w[i-1]->r.min.y) || (i<c->nw-1 && p.y>w->r.max…
521 || (i==0 && p.y>w->r.max.y)){
522 /* shuffle */
523 colclose(c, w, FALSE);
524 coladd(c, w, nil, p.y);
525 winmousebut(w);
526 return;
527 }
528 if(i == 0)
529 return;
530 v = c->w[i-1];
531 if(p.y < v->tagtop.max.y)
532 p.y = v->tagtop.max.y;
533 if(p.y > w->r.max.y-Dy(w->tagtop)-Border)
534 p.y = w->r.max.y-Dy(w->tagtop)-Border;
535 r = v->r;
536 r.max.y = p.y;
537 if(r.max.y > v->body.fr.r.min.y){
538 r.max.y -= (r.max.y-v->body.fr.r.min.y)%v->body.fr.font-…
539 if(v->body.fr.r.min.y == v->body.fr.r.max.y)
540 r.max.y++;
541 }
542 r.min.y = winresize(v, r, c->safe, FALSE);
543 r.max.y = r.min.y+Border;
544 draw(screen, r, display->black, nil, ZP);
545 r.min.y = r.max.y;
546 if(i == c->nw-1)
547 r.max.y = c->r.max.y;
548 else
549 r.max.y = c->w[i+1]->r.min.y-Border;
550 winresize(w, r, c->safe, TRUE);
551 c->safe = TRUE;
552 winmousebut(w);
553 }
554
555 Text*
556 colwhich(Column *c, Point p)
557 {
558 int i;
559 Window *w;
560
561 if(!ptinrect(p, c->r))
562 return nil;
563 if(ptinrect(p, c->tag.all))
564 return &c->tag;
565 for(i=0; i<c->nw; i++){
566 w = c->w[i];
567 if(ptinrect(p, w->r)){
568 if(ptinrect(p, w->tagtop) || ptinrect(p, w->tag.…
569 return &w->tag;
570 /* exclude partial line at bottom */
571 if(p.x >= w->body.scrollr.max.x && p.y >= w->bod…
572 return nil;
573 return &w->body;
574 }
575 }
576 return nil;
577 }
578
579 int
580 colclean(Column *c)
581 {
582 int i, clean;
583
584 clean = TRUE;
585 for(i=0; i<c->nw; i++)
586 clean &= winclean(c->w[i], TRUE);
587 return clean;
588 }
You are viewing proxied material from mx1.adamsgaard.dk. The copyright of proxied material belongs to its original authors. Any comments or complaints in relation to proxied material should be directed to the original authors of the content concerned. Please see the disclaimer for more details.