summaryrefslogtreecommitdiff
path: root/appl/acme/wind.b
diff options
context:
space:
mode:
authorCharles.Forsyth <devnull@localhost>2006-12-22 17:07:39 +0000
committerCharles.Forsyth <devnull@localhost>2006-12-22 17:07:39 +0000
commit37da2899f40661e3e9631e497da8dc59b971cbd0 (patch)
treecbc6d4680e347d906f5fa7fca73214418741df72 /appl/acme/wind.b
parent54bc8ff236ac10b3eaa928fd6bcfc0cdb2ba46ae (diff)
20060303a
Diffstat (limited to 'appl/acme/wind.b')
-rw-r--r--appl/acme/wind.b554
1 files changed, 554 insertions, 0 deletions
diff --git a/appl/acme/wind.b b/appl/acme/wind.b
new file mode 100644
index 00000000..2b97fafa
--- /dev/null
+++ b/appl/acme/wind.b
@@ -0,0 +1,554 @@
+implement Windowm;
+
+include "common.m";
+
+sys : Sys;
+utils : Utils;
+drawm : Draw;
+graph : Graph;
+gui : Gui;
+dat : Dat;
+bufferm : Bufferm;
+textm : Textm;
+filem : Filem;
+look : Look;
+scrl : Scroll;
+acme : Acme;
+
+sprint : import sys;
+FALSE, TRUE, XXX, Astring : import Dat;
+Reffont, reffont, Lock, Ref, button, modbutton : import dat;
+Point, Rect, Image : import drawm;
+min, max, error, warning, stralloc, strfree : import utils;
+font, draw : import graph;
+black, white, mainwin : import gui;
+Buffer : import bufferm;
+Body, Text, Tag : import textm;
+File : import filem;
+Xfid : import Xfidm;
+scrdraw : import scrl;
+tagcols, textcols : import acme;
+BORD : import Framem;
+
+init(mods : ref Dat->Mods)
+{
+ sys = mods.sys;
+ dat = mods.dat;
+ utils = mods.utils;
+ drawm = mods.draw;
+ graph = mods.graph;
+ gui = mods.gui;
+ textm = mods.textm;
+ filem = mods.filem;
+ bufferm = mods.bufferm;
+ look = mods.look;
+ scrl = mods.scroll;
+ acme = mods.acme;
+}
+
+winid : int;
+nullwin : Window;
+
+Window.init(w : self ref Window, clone : ref Window, r : Rect)
+{
+ r1, br : Rect;
+ f : ref File;
+ rf : ref Reffont;
+ rp : ref Astring;
+ nc : int;
+ dummy : ref File = nil;
+
+ c := w.col;
+ *w = nullwin;
+ w.col = c;
+ w.nopen = array[Dat->QMAX] of byte;
+ for (i := 0; i < Dat->QMAX; i++)
+ w.nopen[i] = byte 0;
+ w.qlock = Lock.init();
+ w.ctllock = Lock.init();
+ w.refx = Ref.init();
+ w.tag = textm->newtext();
+ w.tag.w = w;
+ w.body = textm->newtext();
+ w.body.w = w;
+ w.id = ++winid;
+ w.refx.inc();
+ w.ctlfid = ~0;
+ w.utflastqid = -1;
+ r1 = r;
+ r1.max.y = r1.min.y + font.height;
+ reffont.r.inc();
+ f = dummy.addtext(w.tag);
+ w.tag.init(f, r1, reffont, tagcols);
+ w.tag.what = Tag;
+ # tag is a copy of the contents, not a tracked image
+ if(clone != nil){
+ w.tag.delete(0, w.tag.file.buf.nc, TRUE);
+ nc = clone.tag.file.buf.nc;
+ rp = utils->stralloc(nc);
+ clone.tag.file.buf.read(0, rp, 0, nc);
+ w.tag.insert(0, rp.s, nc, TRUE, 0);
+ utils->strfree(rp);
+ rp = nil;
+ w.tag.file.reset();
+ w.tag.setselect(nc, nc);
+ }
+ r1 = r;
+ r1.min.y += font.height + 1;
+ if(r1.max.y < r1.min.y)
+ r1.max.y = r1.min.y;
+ f = nil;
+ if(clone != nil){
+ f = clone.body.file;
+ w.body.org = clone.body.org;
+ w.isscratch = clone.isscratch;
+ rf = Reffont.get(FALSE, FALSE, FALSE, clone.body.reffont.f.name);
+ }else
+ rf = Reffont.get(FALSE, FALSE, FALSE, nil);
+ f = f.addtext(w.body);
+ w.body.what = Body;
+ w.body.init(f, r1, rf, textcols);
+ r1.min.y -= 1;
+ r1.max.y = r1.min.y+1;
+ draw(mainwin, r1, tagcols[BORD], nil, (0, 0));
+ scrdraw(w.body);
+ w.r = r;
+ w.r.max.y = w.body.frame.r.max.y;
+ br.min = w.tag.scrollr.min;
+ br.max.x = br.min.x + button.r.dx();
+ br.max.y = br.min.y + button.r.dy();
+ draw(mainwin, br, button, nil, button.r.min);
+ w.filemenu = TRUE;
+ w.maxlines = w.body.frame.maxlines;
+ if(clone != nil){
+ w.dirty = clone.dirty;
+ w.body.setselect(clone.body.q0, clone.body.q1);
+ w.settag();
+ }
+}
+
+Window.reshape(w : self ref Window, r : Rect, safe : int) : int
+{
+ r1, br : Rect;
+ y : int;
+ b : ref Image;
+
+ r1 = r;
+ r1.max.y = r1.min.y + font.height;
+ y = r1.max.y;
+ if(!safe || !w.tag.frame.r.eq(r1)){
+ y = w.tag.reshape(r1);
+ b = button;
+ if(w.body.file.mod && !w.isdir && !w.isscratch)
+ b = modbutton;
+ br.min = w.tag.scrollr.min;
+ br.max.x = br.min.x + b.r.dx();
+ br.max.y = br.min.y + b.r.dy();
+ draw(mainwin, br, b, nil, b.r.min);
+ }
+ if(!safe || !w.body.frame.r.eq(r1)){
+ if(y+1+font.height > r.max.y){ # no body
+ r1.min.y = y;
+ r1.max.y = y;
+ w.body.reshape(r1);
+ w.r = r;
+ w.r.max.y = y;
+ return y;
+ }
+ r1 = r;
+ r1.min.y = y;
+ r1.max.y = y + 1;
+ draw(mainwin, r1, tagcols[BORD], nil, (0, 0));
+ r1.min.y = y + 1;
+ r1.max.y = r.max.y;
+ y = w.body.reshape(r1);
+ w.r = r;
+ w.r.max.y = y;
+ scrdraw(w.body);
+ }
+ w.maxlines = min(w.body.frame.nlines, max(w.maxlines, w.body.frame.maxlines));
+ return w.r.max.y;
+}
+
+Window.lock1(w : self ref Window, owner : int)
+{
+ w.refx.inc();
+ w.qlock.lock();
+ w.owner = owner;
+}
+
+Window.lock(w : self ref Window, owner : int)
+{
+ i : int;
+ f : ref File;
+
+ f = w.body.file;
+ for(i=0; i<f.ntext; i++)
+ f.text[i].w.lock1(owner);
+}
+
+Window.unlock(w : self ref Window)
+{
+ f := w.body.file;
+ #
+ # subtle: loop runs backwards to avoid tripping over
+ # winclose indirectly editing f.text and freeing f
+ # on the last iteration of the loop
+ #
+ for(i:=f.ntext-1; i>=0; i--){
+ w = f.text[i].w;
+ w.owner = 0;
+ w.qlock.unlock();
+ w.close();
+ }
+}
+
+Window.mousebut(w : self ref Window)
+{
+ graph->cursorset(w.tag.scrollr.min.add(w.tag.scrollr.max).div(2));
+}
+
+Window.dirfree(w : self ref Window)
+{
+ i : int;
+ dl : ref Dat->Dirlist;
+
+ if(w.isdir){
+ for(i=0; i<w.ndl; i++){
+ dl = w.dlp[i];
+ dl.r = nil;
+ dl = nil;
+ }
+ }
+ w.dlp = nil;
+ w.ndl = 0;
+}
+
+Window.close(w : self ref Window)
+{
+ i : int;
+
+ if(w.refx.dec() == 0){
+ w.dirfree();
+ w.tag.close();
+ w.body.close();
+ if(dat->activewin == w)
+ dat->activewin = nil;
+ for(i=0; i<w.nincl; i++)
+ w.incl[i] = nil;
+ w.incl = nil;
+ w.events = nil;
+ w = nil;
+ }
+}
+
+Window.delete(w : self ref Window)
+{
+ x : ref Xfid;
+
+ x = w.eventx;
+ if(x != nil){
+ w.nevents = 0;
+ w.events = nil;
+ w.eventx = nil;
+ x.c <-= Xfidm->Xnil;
+ }
+}
+
+Window.undo(w : self ref Window, isundo : int)
+{
+ body : ref Text;
+ i : int;
+ f : ref File;
+ v : ref Window;
+
+ if(w==nil)
+ return;
+ w.utflastqid = -1;
+ body = w.body;
+ (body.q0, body.q1) = body.file.undo(isundo, body.q0, body.q1);
+ body.show(body.q0, body.q1);
+ f = body.file;
+ for(i=0; i<f.ntext; i++){
+ v = f.text[i].w;
+ v.dirty = (f.seq != v.putseq);
+ if(v != w){
+ v.body.q0 = v.body.frame.p0+v.body.org;
+ v.body.q1 = v.body.frame.p1+v.body.org;
+ }
+ }
+ w.settag();
+}
+
+Window.setname(w : self ref Window, name : string, n : int)
+{
+ t : ref Text;
+ v : ref Window;
+ i : int;
+
+ t = w.body;
+ if(t.file.name == name)
+ return;
+ w.isscratch = FALSE;
+ if(n>=6 && name[n-6:n] == "/guide")
+ w.isscratch = TRUE;
+ else if(n>=7 && name[n-7:n] == "+Errors")
+ w.isscratch = TRUE;
+ t.file.setname(name, n);
+ for(i=0; i<t.file.ntext; i++){
+ v = t.file.text[i].w;
+ v.settag();
+ v.isscratch = w.isscratch;
+ }
+}
+
+Window.typex(w : self ref Window, t : ref Text, r : int)
+{
+ i : int;
+
+ t.typex(r, w.echomode);
+ if(t.what == Body)
+ for(i=0; i<t.file.ntext; i++)
+ scrdraw(t.file.text[i]);
+ w.settag();
+}
+
+Window.cleartag(w : self ref Window)
+{
+ i, n : int;
+ r : ref Astring;
+
+ # w must be committed
+ n = w.tag.file.buf.nc;
+ r = utils->stralloc(n);
+ w.tag.file.buf.read(0, r, 0, n);
+ for(i=0; i<n; i++)
+ if(r.s[i]==' ' || r.s[i]=='\t')
+ break;
+ for(; i<n; i++)
+ if(r.s[i] == '|')
+ break;
+ if(i == n)
+ return;
+ i++;
+ w.tag.delete(i, n, TRUE);
+ utils->strfree(r);
+ r = nil;
+ w.tag.file.mod = FALSE;
+ if(w.tag.q0 > i)
+ w.tag.q0 = i;
+ if(w.tag.q1 > i)
+ w.tag.q1 = i;
+ w.tag.setselect(w.tag.q0, w.tag.q1);
+}
+
+Window.settag(w : self ref Window)
+{
+ i : int;
+ f : ref File;
+
+ f = w.body.file;
+ for(i=0; i<f.ntext; i++){
+ v := f.text[i].w;
+ if(v.col.safe || v.body.frame.maxlines>0)
+ v.settag1();
+ }
+}
+
+Window.settag1(w : self ref Window)
+{
+ ii, j, k, n, bar, dirty : int;
+ old : ref Astring;
+ new : string;
+ r : int;
+ b : ref Image;
+ q0, q1 : int;
+ br : Rect;
+
+ if(w.tag.ncache!=0 || w.tag.file.mod)
+ w.commit(w.tag); # check file name; also can now modify tag
+ old = utils->stralloc(w.tag.file.buf.nc);
+ w.tag.file.buf.read(0, old, 0, w.tag.file.buf.nc);
+ for(ii=0; ii<w.tag.file.buf.nc; ii++)
+ if(old.s[ii]==' ' || old.s[ii]=='\t')
+ break;
+ if(old.s[0:ii] != w.body.file.name){
+ w.tag.delete(0, ii, TRUE);
+ w.tag.insert(0, w.body.file.name, len w.body.file.name, TRUE, 0);
+ strfree(old);
+ old = nil;
+ old = utils->stralloc(w.tag.file.buf.nc);
+ w.tag.file.buf.read(0, old, 0, w.tag.file.buf.nc);
+ }
+ new = w.body.file.name + " Del Snarf";
+ if(w.filemenu){
+ if(w.body.file.delta.nc>0 || w.body.ncache)
+ new += " Undo";
+ if(w.body.file.epsilon.nc > 0)
+ new += " Redo";
+ dirty = w.body.file.name != nil && (w.body.ncache || w.body.file.seq!=w.putseq);
+ if(!w.isdir && dirty)
+ new += " Put";
+ }
+ if(w.isdir)
+ new += " Get";
+ l := len w.body.file.name;
+ if(l >= 2 && w.body.file.name[l-2: ] == ".b")
+ new += " Limbo";
+ new += " |";
+ r = utils->strchr(old.s, '|');
+ if(r >= 0)
+ k = r+1;
+ else{
+ k = w.tag.file.buf.nc;
+ if(w.body.file.seq == 0)
+ new += " Look ";
+ }
+ if(new != old.s[0:k]){
+ n = k;
+ if(n > len new)
+ n = len new;
+ for(j=0; j<n; j++)
+ if(old.s[j] != new[j])
+ break;
+ q0 = w.tag.q0;
+ q1 = w.tag.q1;
+ w.tag.delete(j, k, TRUE);
+ w.tag.insert(j, new[j:], len new - j, TRUE, 0);
+ # try to preserve user selection
+ r = utils->strchr(old.s, '|');
+ if(r >= 0){
+ bar = r;
+ if(q0 > bar){
+ bar = utils->strchr(new, '|')-bar;
+ w.tag.q0 = q0+bar;
+ w.tag.q1 = q1+bar;
+ }
+ }
+ }
+ strfree(old);
+ old = nil;
+ new = nil;
+ w.tag.file.mod = FALSE;
+ n = w.tag.file.buf.nc+w.tag.ncache;
+ if(w.tag.q0 > n)
+ w.tag.q0 = n;
+ if(w.tag.q1 > n)
+ w.tag.q1 = n;
+ w.tag.setselect(w.tag.q0, w.tag.q1);
+ b = button;
+ if(!w.isdir && !w.isscratch && (w.body.file.mod || w.body.ncache))
+ b = modbutton;
+ br.min = w.tag.scrollr.min;
+ br.max.x = br.min.x + b.r.dx();
+ br.max.y = br.min.y + b.r.dy();
+ draw(mainwin, br, b, nil, b.r.min);
+}
+
+Window.commit(w : self ref Window, t : ref Text)
+{
+ r : ref Astring;
+ i : int;
+ f : ref File;
+
+ t.commit(TRUE);
+ f = t.file;
+ if(f.ntext > 1)
+ for(i=0; i<f.ntext; i++)
+ f.text[i].commit(FALSE); # no-op for t
+ if(t.what == Body)
+ return;
+ r = utils->stralloc(w.tag.file.buf.nc);
+ w.tag.file.buf.read(0, r, 0, w.tag.file.buf.nc);
+ for(i=0; i<w.tag.file.buf.nc; i++)
+ if(r.s[i]==' ' || r.s[i]=='\t')
+ break;
+ if(r.s[0:i] != w.body.file.name){
+ dat->seq++;
+ w.body.file.mark();
+ w.body.file.mod = TRUE;
+ w.dirty = TRUE;
+ w.setname(r.s, i);
+ w.settag();
+ }
+ utils->strfree(r);
+ r = nil;
+}
+
+Window.addincl(w : self ref Window, r : string, n : int)
+{
+ {
+ (ok, d) := sys->stat(r);
+ if(ok < 0){
+ if(r[0] == '/')
+ raise "e";
+ (r, n) = look->dirname(w.body, r, n);
+ (ok, d) = sys->stat(r);
+ if(ok < 0)
+ raise "e";
+ }
+ if((d.mode&Sys->DMDIR) == 0){
+ warning(nil, sprint("%s: not a directory\n", r));
+ r = nil;
+ return;
+ }
+ w.nincl++;
+ owi := w.incl;
+ w.incl = array[w.nincl] of string;
+ w.incl[1:] = owi[0:w.nincl-1];
+ owi = nil;
+ w.incl[0] = r;
+ r = nil;
+ }
+ exception{
+ * =>
+ warning(nil, sprint("%s: %r\n", r));
+ r = nil;
+ }
+}
+
+Window.clean(w : self ref Window, conservative : int, exiting : int) : int # as it stands, conservative is always TRUE
+{
+ if(w.isscratch || w.isdir) # don't whine if it's a guide file, error window, etc.
+ return TRUE;
+ if((!conservative||exiting) && w.nopen[Dat->QWevent]>byte 0)
+ return TRUE;
+ if(w.dirty){
+ if(w.body.file.name != nil)
+ warning(nil, sprint("%s modified\n", w.body.file.name));
+ else{
+ if(w.body.file.buf.nc < 100) # don't whine if it's too small
+ return TRUE;
+ warning(nil, "unnamed file modified\n");
+ }
+ w.dirty = FALSE;
+ return FALSE;
+ }
+ return TRUE;
+}
+
+Window.ctlprint(w : self ref Window) : string
+{
+ return sprint("%11d %11d %11d %11d %11d ", w.id, w.tag.file.buf.nc,
+ w.body.file.buf.nc, w.isdir, w.dirty);
+}
+
+Window.event(w : self ref Window, fmt : string)
+{
+ n : int;
+ x : ref Xfid;
+
+ if(w.nopen[Dat->QWevent] == byte 0)
+ return;
+ if(w.owner == 0)
+ error("no window owner");
+ n = len fmt;
+ w.events[len w.events] = w.owner;
+ w.events += fmt;
+ w.nevents += n+1;
+ x = w.eventx;
+ if(x != nil){
+ w.eventx = nil;
+ x.c <-= Xfidm->Xnil;
+ }
+}