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 
     2 #include 
     3 #include 
     4 #include 
     5 #include 
     6 #include 
     7 #include 
     8 #include 
     9 #include 
    10 #include 
    11 #include 
    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(ynw>0){        /* steal half of last window by default */
    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; inw; 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.all) <= minht){
    82                         if(++j > 10){
    83                                 buggered = 1;        /* too many windows in column */
    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->body.fr.font->height+Border+1));
   117                 r1.max.y = min(y, v->body.fr.r.min.y+v->body.fr.nlines*v->body.fr.font->height);
   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; inw; 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; inw; 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.max), 2));
   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; inw; 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->height){
   258                                 r1.max.y += (Dy(w->r)-Border-font->height)*new/old + Border + font->height;
   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; inw == 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; inw; 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; inw; 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; inw; 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 properly */
   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; inw; 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; jnw; 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), tot);
   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; knw; k++){
   389                 /* prune from later window */
   390                 j = i+k;
   391                 if(jnw && 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; jw[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; jnw; j++)
   447                         ny[j] -= (y2-r.max.y);
   448         }
   449         /* pack everyone below */
   450         y1 = r.max.y;
   451         for(j=i+1; jnw; 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; inw; 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 size */
   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.yw[i-1]->r.min.y) || (inw-1 && p.y>w->r.max.y)
   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->height;
   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; inw; i++){
   566                 w = c->w[i];
   567                 if(ptinrect(p, w->r)){
   568                         if(ptinrect(p, w->tagtop) || ptinrect(p, w->tag.all))
   569                                 return &w->tag;
   570                         /* exclude partial line at bottom */
   571                         if(p.x >= w->body.scrollr.max.x && p.y >= w->body.fr.r.max.y)
   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; inw; i++)
   586                 clean &= winclean(c->w[i], TRUE);
   587         return clean;
   588 }