summaryrefslogtreecommitdiff
path: root/appl/acme/col.b
diff options
context:
space:
mode:
Diffstat (limited to 'appl/acme/col.b')
-rw-r--r--appl/acme/col.b610
1 files changed, 610 insertions, 0 deletions
diff --git a/appl/acme/col.b b/appl/acme/col.b
new file mode 100644
index 00000000..c696fc5d
--- /dev/null
+++ b/appl/acme/col.b
@@ -0,0 +1,610 @@
+implement Columnm;
+
+include "common.m";
+
+sys : Sys;
+utils : Utils;
+drawm : Draw;
+acme : Acme;
+graph : Graph;
+gui : Gui;
+dat : Dat;
+textm : Textm;
+rowm : Rowm;
+filem : Filem;
+windowm : Windowm;
+
+FALSE, TRUE, XXX : import Dat;
+Border : import Dat;
+mouse, colbutton : import dat;
+Point, Rect, Image : import drawm;
+draw : import graph;
+min, max, abs, error, clearmouse : import utils;
+black, white, mainwin : import gui;
+Text : import textm;
+Row : import rowm;
+Window : import windowm;
+File : import filem;
+Columntag : import Textm;
+BACK : import Framem;
+tagcols, textcols : import acme;
+
+init(mods : ref Dat->Mods)
+{
+ sys = mods.sys;
+ dat = mods.dat;
+ utils = mods.utils;
+ drawm = mods.draw;
+ acme = mods.acme;
+ graph = mods.graph;
+ gui = mods.gui;
+ textm = mods.textm;
+ rowm = mods.rowm;
+ filem = mods.filem;
+ windowm = mods.windowm;
+}
+
+Column.init(c : self ref Column, r : Rect)
+{
+ r1 : Rect;
+ t : ref Text;
+ dummy : ref File = nil;
+
+ draw(mainwin, r, white, nil, (0, 0));
+ c.r = r;
+ c.row = nil;
+ c.w = nil;
+ c.nw = 0;
+ c.tag = textm->newtext();
+ t = c.tag;
+ t.w = nil;
+ t.col = c;
+ r1 = r;
+ r1.max.y = r1.min.y + (graph->font).height;
+ t.init(dummy.addtext(t), r1, dat->reffont, tagcols);
+ t.what = Columntag;
+ r1.min.y = r1.max.y;
+ r1.max.y += Border;
+ draw(mainwin, r1, black, nil, (0, 0));
+ t.insert(0, "New Cut Paste Snarf Sort Zerox Delcol ", 38, TRUE, 0);
+ t.setselect(t.file.buf.nc, t.file.buf.nc);
+ draw(mainwin, t.scrollr, colbutton, nil, colbutton.r.min);
+ c.safe = TRUE;
+}
+
+Column.add(c : self ref Column, w : ref Window, clone : ref Window, y : int) : ref Window
+{
+ r, r1 : Rect;
+ v : ref Window;
+ i, t : int;
+
+ v = nil;
+ r = c.r;
+ r.min.y = c.tag.frame.r.max.y+Border;
+ if(y<r.min.y && c.nw>0){ # steal half of last window by default
+ v = c.w[c.nw-1];
+ y = v.body.frame.r.min.y+v.body.frame.r.dy()/2;
+ }
+ # look for window we'll land on
+ for(i=0; i<c.nw; i++){
+ v = c.w[i];
+ if(y < v.r.max.y)
+ break;
+ }
+ if(c.nw > 0){
+ if(i < c.nw)
+ i++; # new window will go after v
+ #
+ # if v's too small, grow it first.
+ #
+
+ if(!c.safe || v.body.frame.maxlines<=3){
+ c.grow(v, 1, 1);
+ y = v.body.frame.r.min.y+v.body.frame.r.dy()/2;
+ }
+ r = v.r;
+ if(i == c.nw)
+ t = c.r.max.y;
+ else
+ t = c.w[i].r.min.y-Border;
+ r.max.y = t;
+ draw(mainwin, r, textcols[BACK], nil, (0, 0));
+ r1 = r;
+ y = min(y, t-(v.tag.frame.font.height+v.body.frame.font.height+Border+1));
+ r1.max.y = min(y, v.body.frame.r.min.y+v.body.frame.nlines*v.body.frame.font.height);
+ r1.min.y = v.reshape(r1, FALSE);
+ r1.max.y = r1.min.y+Border;
+ draw(mainwin, r1, black, nil, (0, 0));
+ r.min.y = r1.max.y;
+ }
+ if(w == nil){
+ w = ref Window;
+ draw(mainwin, r, textcols[BACK], nil, (0, 0));
+ w.col = c;
+ w.init(clone, r);
+ }else{
+ w.col = c;
+ w.reshape(r, FALSE);
+ }
+ w.tag.col = c;
+ w.tag.row = c.row;
+ w.body.col = c;
+ w.body.row = c.row;
+ ocw := c.w;
+ c.w = array[c.nw+1] of ref Window;
+ c.w[0:] = ocw[0:i];
+ c.w[i+1:] = ocw[i:c.nw];
+ ocw = nil;
+ c.nw++;
+ c.w[i] = w;
+ utils->savemouse(w);
+ # near but not on the button
+ graph->cursorset(w.tag.scrollr.max.add(Point(3, 3)));
+ dat->barttext = w.body;
+ c.safe = TRUE;
+ return w;
+}
+
+Column.close(c : self ref Column, w : ref Window, dofree : int)
+{
+ r : Rect;
+ i : int;
+
+ # w is locked
+ if(!c.safe)
+ c.grow(w, 1, 1);
+ for(i=0; i<c.nw; i++)
+ if(c.w[i] == w)
+ break;
+ if (i == c.nw)
+ error("can't find window");
+ r = w.r;
+ w.tag.col = nil;
+ w.body.col = nil;
+ w.col = nil;
+ utils->restoremouse(w);
+ if(dofree){
+ w.delete();
+ w.close();
+ }
+ ocw := c.w;
+ c.w = array[c.nw-1] of ref Window;
+ c.w[0:] = ocw[0:i];
+ c.w[i:] = ocw[i+1:c.nw];
+ ocw = nil;
+ c.nw--;
+ if(c.nw == 0){
+ draw(mainwin, r, white, nil, (0, 0));
+ return;
+ }
+ if(i == c.nw){ # extend last window down
+ w = c.w[i-1];
+ r.min.y = w.r.min.y;
+ r.max.y = c.r.max.y;
+ }else{ # extend next window up
+ w = c.w[i];
+ r.max.y = w.r.max.y;
+ }
+ draw(mainwin, r, textcols[BACK], nil, (0, 0));
+ if(c.safe)
+ w.reshape(r, FALSE);
+}
+
+Column.closeall(c : self ref Column)
+{
+ i : int;
+ w : ref Window;
+
+ if(c == dat->activecol)
+ dat->activecol = nil;
+ c.tag.close();
+ for(i=0; i<c.nw; i++){
+ w = c.w[i];
+ w.close();
+ }
+ c.nw = 0;
+ c.w = nil;
+ c = nil;
+ clearmouse();
+}
+
+Column.mousebut(c : self ref Column)
+{
+ graph->cursorset(c.tag.scrollr.min.add(c.tag.scrollr.max).div(2));
+}
+
+Column.reshape(c : self ref Column, r : Rect)
+{
+ i : int;
+ r1, r2 : Rect;
+ w : ref Window;
+
+ clearmouse();
+ r1 = r;
+ r1.max.y = r1.min.y + c.tag.frame.font.height;
+ c.tag.reshape(r1);
+ draw(mainwin, c.tag.scrollr, colbutton, nil, colbutton.r.min);
+ r1.min.y = r1.max.y;
+ r1.max.y += Border;
+ draw(mainwin, r1, black, nil, (0, 0));
+ r1.max.y = r.max.y;
+ for(i=0; i<c.nw; i++){
+ w = c.w[i];
+ w.maxlines = 0;
+ if(i == c.nw-1)
+ r1.max.y = r.max.y;
+ else
+ r1.max.y = r1.min.y+(w.r.dy()+Border)*r.dy()/c.r.dy();
+ r2 = r1;
+ r2.max.y = r2.min.y+Border;
+ draw(mainwin, r2, black, nil, (0, 0));
+ r1.min.y = r2.max.y;
+ r1.min.y = w.reshape(r1, FALSE);
+ }
+ c.r = r;
+}
+
+colcmp(a : ref Window, b : ref Window) : int
+{
+ r1, r2 : string;
+
+ r1 = a.body.file.name;
+ r2 = b.body.file.name;
+ if (r1 < r2)
+ return -1;
+ if (r1 > r2)
+ return 1;
+ return 0;
+}
+
+qsort(a : array of ref Window, n : int)
+{
+ i, j : int;
+ t : ref Window;
+
+ while(n > 1) {
+ i = n>>1;
+ t = a[0]; a[0] = a[i]; a[i] = t;
+ i = 0;
+ j = n;
+ for(;;) {
+ do
+ i++;
+ while(i < n && colcmp(a[i], a[0]) < 0);
+ do
+ j--;
+ while(j > 0 && colcmp(a[j], a[0]) > 0);
+ if(j < i)
+ break;
+ t = a[i]; a[i] = a[j]; a[j] = t;
+ }
+ t = a[0]; a[0] = a[j]; a[j] = t;
+ n = n-j-1;
+ if(j >= n) {
+ qsort(a, j);
+ a = a[j+1:];
+ } else {
+ qsort(a[j+1:], n);
+ n = j;
+ }
+ }
+}
+
+Column.sort(c : self ref Column)
+{
+ i, y : int;
+ r, r1 : Rect;
+ rp : array of Rect;
+ w : ref Window;
+ wp : array of ref Window;
+
+ if(c.nw == 0)
+ return;
+ clearmouse();
+ rp = array[c.nw] of Rect;
+ wp = array[c.nw] of ref Window;
+ wp[0:] = c.w[0:c.nw];
+ qsort(wp, c.nw);
+ for(i=0; i<c.nw; i++)
+ rp[i] = wp[i].r;
+ r = c.r;
+ r.min.y = c.tag.frame.r.max.y;
+ draw(mainwin, r, textcols[BACK], nil, (0, 0));
+ y = r.min.y;
+ for(i=0; i<c.nw; i++){
+ w = wp[i];
+ r.min.y = y;
+ if(i == c.nw-1)
+ r.max.y = c.r.max.y;
+ else
+ r.max.y = r.min.y+w.r.dy()+Border;
+ r1 = r;
+ r1.max.y = r1.min.y+Border;
+ draw(mainwin, r1, black, nil, (0, 0));
+ r.min.y = r1.max.y;
+ y = w.reshape(r, FALSE);
+ }
+ rp = nil;
+ c.w = wp;
+}
+
+Column.grow(c : self ref Column, w : ref Window, but : int, mv : int)
+{
+ r, cr : Rect;
+ i, j, k, l, y1, y2, tot, nnl, onl, dnl, h : int;
+ nl, ny : array of int;
+ v : ref Window;
+
+ for(i=0; i<c.nw; i++)
+ if(c.w[i] == w)
+ break;
+ if (i == c.nw)
+ error("can't find window");
+
+ cr = c.r;
+ if(but < 0){ # make sure window fills its own space properly
+ r = w.r;
+ if(i == c.nw-1)
+ r.max.y = cr.max.y;
+ else
+ r.max.y = c.w[i+1].r.min.y;
+ w.reshape(r, FALSE);
+ return;
+ }
+ cr.min.y = c.w[0].r.min.y;
+ if(but == 3){ # full size
+ if(i != 0){
+ v = c.w[0];
+ c.w[0] = w;
+ c.w[i] = v;
+ }
+ draw(mainwin, cr, textcols[BACK], nil, (0, 0));
+ w.reshape(cr, FALSE);
+ for(i=1; i<c.nw; i++)
+ c.w[i].body.frame.maxlines = 0;
+ c.safe = FALSE;
+ return;
+ }
+ # store old #lines for each window
+ onl = w.body.frame.maxlines;
+ nl = array[c.nw] of int;
+ ny = array[c.nw] of int;
+ tot = 0;
+ for(j=0; j<c.nw; j++){
+ l = c.w[j].body.frame.maxlines;
+ nl[j] = l;
+ tot += l;
+ }
+ # approximate new #lines for this window
+ if(but == 2){ # as big as can be
+ for (j = 0; j < c.nw; j++)
+ nl[j] = 0;
+ nl[i] = tot;
+ }
+ else {
+ nnl = min(onl + max(min(5, w.maxlines), onl/2), tot);
+ if(nnl < w.maxlines)
+ nnl = (w.maxlines+nnl)/2;
+ if(nnl == 0)
+ nnl = 2;
+ dnl = nnl - onl;
+ # compute new #lines for each window
+ for(k=1; k<c.nw; k++){
+ # prune from later window
+ j = i+k;
+ if(j<c.nw && nl[j]){
+ l = min(dnl, max(1, nl[j]/2));
+ nl[j] -= l;
+ nl[i] += l;
+ dnl -= l;
+ }
+ # prune from earlier window
+ j = i-k;
+ if(j>=0 && nl[j]){
+ l = min(dnl, max(1, nl[j]/2));
+ nl[j] -= l;
+ nl[i] += l;
+ dnl -= l;
+ }
+ }
+ }
+ # pack everyone above
+ y1 = cr.min.y;
+ for(j=0; j<i; j++){
+ v = c.w[j];
+ r = v.r;
+ r.min.y = y1;
+ r.max.y = y1+v.tag.all.dy();
+ if(nl[j])
+ r.max.y += 1 + nl[j]*v.body.frame.font.height;
+ if(!c.safe || !v.r.eq(r)){
+ draw(mainwin, r, textcols[BACK], nil, (0, 0));
+ v.reshape(r, c.safe);
+ }
+ r.min.y = v.r.max.y;
+ r.max.y += Border;
+ draw(mainwin, r, black, nil, (0, 0));
+ y1 = r.max.y;
+ }
+ # scan to see new size of everyone below
+ y2 = c.r.max.y;
+ for(j=c.nw-1; j>i; j--){
+ v = c.w[j];
+ r = v.r;
+ r.min.y = y2-v.tag.all.dy();
+ if(nl[j])
+ r.min.y -= 1 + nl[j]*v.body.frame.font.height;
+ r.min.y -= Border;
+ ny[j] = r.min.y;
+ y2 = r.min.y;
+ }
+ # compute new size of window
+ r = w.r;
+ r.min.y = y1;
+ r.max.y = r.min.y+w.tag.all.dy();
+ h = w.body.frame.font.height;
+ if(y2-r.max.y >= 1+h+Border){
+ r.max.y += 1;
+ r.max.y += h*((y2-r.max.y)/h);
+ }
+ # draw window
+ if(!c.safe || !w.r.eq(r)){
+ draw(mainwin, r, textcols[BACK], nil, (0, 0));
+ w.reshape(r, c.safe);
+ }
+ if(i < c.nw-1){
+ r.min.y = r.max.y;
+ r.max.y += Border;
+ draw(mainwin, r, black, nil, (0, 0));
+ for(j=i+1; j<c.nw; j++)
+ ny[j] -= (y2-r.max.y);
+ }
+ # pack everyone below
+ y1 = r.max.y;
+ for(j=i+1; j<c.nw; j++){
+ v = c.w[j];
+ r = v.r;
+ r.min.y = y1;
+ r.max.y = y1+v.tag.all.dy();
+ if(nl[j])
+ r.max.y += 1 + nl[j]*v.body.frame.font.height;
+ if(!c.safe || !v.r.eq(r)){
+ draw(mainwin, r, textcols[BACK], nil, (0, 0));
+ v.reshape(r, c.safe);
+ }
+ if(j < c.nw-1){ # no border on last window
+ r.min.y = v.r.max.y;
+ r.max.y += Border;
+ draw(mainwin, r, black, nil, (0, 0));
+ }
+ y1 = r.max.y;
+ }
+ r = w.r;
+ r.min.y = y1;
+ r.max.y = c.r.max.y;
+ draw(mainwin, r, textcols[BACK], nil, (0, 0));
+ nl = nil;
+ ny = nil;
+ c.safe = TRUE;
+ if (mv)
+ w.mousebut();
+}
+
+Column.dragwin(c : self ref Column, w : ref Window, but : int)
+{
+ r : Rect;
+ i, b : int;
+ p, op : Point;
+ v : ref Window;
+ nc : ref Column;
+
+ clearmouse();
+ graph->cursorswitch(dat->boxcursor);
+ b = mouse.buttons;
+ op = mouse.xy;
+ while(mouse.buttons == b)
+ acme->frgetmouse();
+ graph->cursorswitch(dat->arrowcursor);
+ if(mouse.buttons){
+ while(mouse.buttons)
+ acme->frgetmouse();
+ return;
+ }
+
+ for(i=0; i<c.nw; i++)
+ if(c.w[i] == w)
+ break;
+ if (i == c.nw)
+ error("can't find window");
+
+ p = mouse.xy;
+ if(abs(p.x-op.x)<5 && abs(p.y-op.y)<5){
+ c.grow(w, but, 1);
+ w.mousebut();
+ return;
+ }
+ # is it a flick to the right?
+ if(abs(p.y-op.y)<10 && p.x>op.x+30 && c.row.whichcol(p) == c)
+ p.x += w.r.dx(); # yes: toss to next column
+ nc = c.row.whichcol(p);
+ if(nc!=nil && nc!=c){
+ c.close(w, FALSE);
+ nc.add(w, nil, p.y);
+ w.mousebut();
+ return;
+ }
+ if(i==0 && c.nw==1)
+ return; # can't do it
+ if((i>0 && p.y<c.w[i-1].r.min.y) || (i<c.nw-1 && p.y>w.r.max.y)
+ || (i==0 && p.y>w.r.max.y)){
+ # shuffle
+ c.close(w, FALSE);
+ c.add(w, nil, p.y);
+ w.mousebut();
+ return;
+ }
+ if(i == 0)
+ return;
+ v = c.w[i-1];
+ if(p.y < v.tag.all.max.y)
+ p.y = v.tag.all.max.y;
+ if(p.y > w.r.max.y-w.tag.all.dy()-Border)
+ p.y = w.r.max.y-w.tag.all.dy()-Border;
+ r = v.r;
+ r.max.y = p.y;
+ if(r.max.y > v.body.frame.r.min.y){
+ r.max.y -= (r.max.y-v.body.frame.r.min.y)%v.body.frame.font.height;
+ if(v.body.frame.r.min.y == v.body.frame.r.max.y)
+ r.max.y++;
+ }
+ if(!r.eq(v.r)){
+ draw(mainwin, r, textcols[BACK], nil, (0, 0));
+ v.reshape(r, c.safe);
+ }
+ r.min.y = v.r.max.y;
+ r.max.y = r.min.y+Border;
+ draw(mainwin, r, black, nil, (0, 0));
+ r.min.y = r.max.y;
+ if(i == c.nw-1)
+ r.max.y = c.r.max.y;
+ else
+ r.max.y = c.w[i+1].r.min.y-Border;
+ # r.max.y = w.r.max.y;
+ if(!r.eq(w.r)){
+ draw(mainwin, r, textcols[BACK], nil, (0, 0));
+ w.reshape(r, c.safe);
+ }
+ c.safe = TRUE;
+ w.mousebut();
+}
+
+Column.which(c : self ref Column, p : Point) : ref Text
+{
+ i : int;
+ w : ref Window;
+
+ if(!p.in(c.r))
+ return nil;
+ if(p.in(c.tag.all))
+ return c.tag;
+ for(i=0; i<c.nw; i++){
+ w = c.w[i];
+ if(p.in(w.r)){
+ if(p.in(w.tag.all))
+ return w.tag;
+ return w.body;
+ }
+ }
+ return nil;
+}
+
+Column.clean(c : self ref Column, exiting : int) : int
+{
+ clean : int;
+ i : int;
+
+ clean = TRUE;
+ for(i=0; i<c.nw; i++)
+ clean &= c.w[i].clean(TRUE, exiting);
+ return clean;
+}