ref: 02ac617541ca1a7bf82b1615fb5a58235469b5d3
dir: /appl/acme/wind.b/
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, TRUE); 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, fonts : int) : string { s := sprint("%11d %11d %11d %11d %11d ", w.id, w.tag.file.buf.nc, w.body.file.buf.nc, w.isdir, w.dirty); if(fonts) return sprint("%s%11d %q %11d ", s, w.body.frame.r.dx(), w.body.reffont.f.name, w.body.frame.maxtab); return s; } 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; } }