ref: 82b046f36f8084a22bbb5d71edd0edd9179561eb
dir: /appl/acme/row.b/
implement Rowm; include "common.m"; sys : Sys; bufio : Bufio; utils : Utils; drawm : Draw; acme : Acme; graph : Graph; gui : Gui; dat : Dat; bufferm : Bufferm; textm : Textm; filem : Filem; windowm : Windowm; columnm : Columnm; exec : Exec; look : Look; edit : Edit; ecmd : Editcmd; ALLLOOPER, ALLTOFILE, ALLMATCHFILE, ALLFILECHECK, ALLELOGTERM, ALLEDITINIT, ALLUPDATE: import Edit; sprint : import sys; FALSE, TRUE, XXX : import Dat; Border, BUFSIZE, Astring : import Dat; Reffont, reffont, Lock, Ref : import dat; row, home, mouse : import dat; fontnames : import acme; font, draw : import graph; Point, Rect, Image : import drawm; min, max, abs, error, warning, clearmouse, stralloc, strfree : import utils; black, white, mainwin : import gui; Buffer : import bufferm; Tag, Rowtag, Text : import textm; Window : import windowm; File : import filem; Column : import columnm; Iobuf : import bufio; init(mods : ref Dat->Mods) { sys = mods.sys; bufio = mods.bufio; dat = mods.dat; utils = mods.utils; drawm = mods.draw; acme = mods.acme; graph = mods.graph; gui = mods.gui; bufferm = mods.bufferm; textm = mods.textm; filem = mods.filem; windowm = mods.windowm; columnm = mods.columnm; exec = mods.exec; look = mods.look; edit = mods.edit; ecmd = mods.editcmd; } newrow() : ref Row { r := ref Row; r.qlock = Lock.init(); r.r = ((0, 0), (0, 0)); r.tag = nil; r.col = nil; r.ncol = 0; return r; } Row.init(row : self ref Row, r : Rect) { r1 : Rect; t : ref Text; dummy : ref File = nil; draw(mainwin, r, white, nil, (0, 0)); row.r = r; row.col = nil; row.ncol = 0; r1 = r; r1.max.y = r1.min.y + font.height; row.tag = textm->newtext(); t = row.tag; t.init(dummy.addtext(t), r1, Reffont.get(FALSE, FALSE, FALSE, nil), acme->tagcols); t.what = Rowtag; t.row = row; t.w = nil; t.col = nil; r1.min.y = r1.max.y; r1.max.y += Border; draw(mainwin, r1, black, nil, (0, 0)); t.insert(0, "Newcol Kill Putall Dump Exit ", 29, TRUE, 0); t.setselect(t.file.buf.nc, t.file.buf.nc); } Row.add(row : self ref Row, c : ref Column, x : int) : ref Column { r, r1 : Rect; d : ref Column; i : int; d = nil; r = row.r; r.min.y = row.tag.frame.r.max.y+Border; if(x<r.min.x && row.ncol>0){ #steal 40% of last column by default d = row.col[row.ncol-1]; x = d.r.min.x + 3*d.r.dx()/5; } # look for column we'll land on for(i=0; i<row.ncol; i++){ d = row.col[i]; if(x < d.r.max.x) break; } if(row.ncol > 0){ if(i < row.ncol) i++; # new column will go after d r = d.r; if(r.dx() < 100) return nil; draw(mainwin, r, white, nil, (0, 0)); r1 = r; r1.max.x = min(x, r.max.x-50); if(r1.dx() < 50) r1.max.x = r1.min.x+50; d.reshape(r1); r1.min.x = r1.max.x; r1.max.x = r1.min.x+Border; draw(mainwin, r1, black, nil, (0, 0)); r.min.x = r1.max.x; } if(c == nil){ c = ref Column; c.init(r); reffont.r.inc(); }else c.reshape(r); c.row = row; c.tag.row = row; orc := row.col; row.col = array[row.ncol+1] of ref Column; row.col[0:] = orc[0:i]; row.col[i+1:] = orc[i:row.ncol]; orc = nil; row.col[i] = c; row.ncol++; clearmouse(); return c; } Row.reshape(row : self ref Row, r : Rect) { i, dx, odx : int; r1, r2 : Rect; c : ref Column; dx = r.dx(); odx = row.r.dx(); row.r = r; r1 = r; r1.max.y = r1.min.y + font.height; row.tag.reshape(r1); r1.min.y = r1.max.y; r1.max.y += Border; draw(mainwin, r1, black, nil, (0, 0)); r.min.y = r1.max.y; r1 = r; r1.max.x = r1.min.x; for(i=0; i<row.ncol; i++){ c = row.col[i]; r1.min.x = r1.max.x; if(i == row.ncol-1) r1.max.x = r.max.x; else r1.max.x = r1.min.x+c.r.dx()*dx/odx; r2 = r1; r2.max.x = r2.min.x+Border; draw(mainwin, r2, black, nil, (0, 0)); r1.min.x = r2.max.x; c.reshape(r1); } } Row.dragcol(row : self ref Row, c : ref Column) { r : Rect; i, b, x : int; p, op : Point; d : 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<row.ncol; i++) if(row.col[i] == c) break; if (i == row.ncol) error("can't find column"); if(i == 0) return; p = mouse.xy; if((abs(p.x-op.x)<5 && abs(p.y-op.y)<5)) return; if((i>0 && p.x<row.col[i-1].r.min.x) || (i<row.ncol-1 && p.x>c.r.max.x)){ # shuffle x = c.r.min.x; row.close(c, FALSE); if(row.add(c, p.x) == nil) # whoops! if(row.add(c, x) == nil) # WHOOPS! if(row.add(c, -1)==nil){ # shit! row.close(c, TRUE); return; } c.mousebut(); return; } d = row.col[i-1]; if(p.x < d.r.min.x+80+Dat->Scrollwid) p.x = d.r.min.x+80+Dat->Scrollwid; if(p.x > c.r.max.x-80-Dat->Scrollwid) p.x = c.r.max.x-80-Dat->Scrollwid; r = d.r; r.max.x = c.r.max.x; draw(mainwin, r, white, nil, (0, 0)); r.max.x = p.x; d.reshape(r); r = c.r; r.min.x = p.x; r.max.x = r.min.x; r.max.x += Border; draw(mainwin, r, black, nil, (0, 0)); r.min.x = r.max.x; r.max.x = c.r.max.x; c.reshape(r); c.mousebut(); } Row.close(row : self ref Row, c : ref Column, dofree : int) { r : Rect; i : int; for(i=0; i<row.ncol; i++) if(row.col[i] == c) break; if (i == row.ncol) error("can't find column"); r = c.r; if(dofree) c.closeall(); orc := row.col; row.col = array[row.ncol-1] of ref Column; row.col[0:] = orc[0:i]; row.col[i:] = orc[i+1:row.ncol]; orc = nil; row.ncol--; if(row.ncol == 0){ draw(mainwin, r, white, nil, (0, 0)); return; } if(i == row.ncol){ # extend last column right c = row.col[i-1]; r.min.x = c.r.min.x; r.max.x = row.r.max.x; }else{ # extend next window left c = row.col[i]; r.max.x = c.r.max.x; } draw(mainwin, r, white, nil, (0, 0)); c.reshape(r); } Row.whichcol(row : self ref Row, p : Point) : ref Column { i : int; c : ref Column; for(i=0; i<row.ncol; i++){ c = row.col[i]; if(p.in(c.r)) return c; } return nil; } Row.which(row : self ref Row, p : Point) : ref Text { c : ref Column; if(p.in(row.tag.all)) return row.tag; c = row.whichcol(p); if(c != nil) return c.which(p); return nil; } Row.typex(row : self ref Row, r : int, p : Point) : ref Text { w : ref Window; t : ref Text; clearmouse(); row.qlock.lock(); if(dat->bartflag) t = dat->barttext; else t = row.which(p); if(t!=nil && !(t.what==Tag && p.in(t.scrollr))){ w = t.w; if(w == nil) t.typex(r, 0); else{ w.lock('K'); w.typex(t, r); w.unlock(); } } row.qlock.unlock(); return t; } Row.clean(row : self ref Row, exiting : int) : int { clean : int; i : int; clean = TRUE; for(i=0; i<row.ncol; i++) clean &= row.col[i].clean(exiting); return clean; } Row.dump(row : self ref Row, file : string) { i, j, m, n, dumped : int; q0, q1 : int; b : ref Iobuf; buf, fontname, a : string; r : ref Astring; c : ref Column; w, w1 : ref Window; t : ref Text; if(row.ncol == 0) return; { if(file == nil){ if(home == nil){ warning(nil, "can't find file for dump: $home not defined\n"); raise "e"; } buf = sprint("%s/acme.dump", home); file = buf; } b = bufio->create(file, Bufio->OWRITE, 8r600); if(b == nil){ warning(nil, sprint("can't open %s: %r\n", file)); raise "e"; } r = stralloc(BUFSIZE); b.puts(acme->wdir); b.putc('\n'); b.puts(fontnames[0]); b.putc('\n'); b.puts(fontnames[1]); b.putc('\n'); for(i=0; i<row.ncol; i++){ c = row.col[i]; b.puts(sprint("%11d", 100*(c.r.min.x-row.r.min.x)/row.r.dx())); if(i == row.ncol-1) b.putc('\n'); else b.putc(' '); } for(i=0; i<row.ncol; i++){ c = row.col[i]; for(j=0; j<c.nw; j++) c.w[j].body.file.dumpid = 0; } for(i=0; i<row.ncol; i++){ c = row.col[i]; for(j=0; j<c.nw; j++){ w = c.w[j]; w.commit(w.tag); t = w.body; # windows owned by others get special treatment if(w.nopen[Dat->QWevent] > byte 0) if(w.dumpstr == nil) continue; # zeroxes of external windows are tossed if(t.file.ntext > 1) for(n=0; n<t.file.ntext; n++){ w1 = t.file.text[n].w; if(w == w1) continue; if(w1.nopen[Dat->QWevent] != byte 0) { j = c.nw; continue; } } fontname = ""; if(t.reffont.f != font) fontname = t.reffont.f.name; a = t.file.name; if(t.file.dumpid){ dumped = FALSE; b.puts(sprint("x%11d %11d %11d %11d %11d %s\n", i, t.file.dumpid, w.body.q0, w.body.q1, 100*(w.r.min.y-c.r.min.y)/c.r.dy(), fontname)); }else if(w.dumpstr != nil){ dumped = FALSE; b.puts(sprint("e%11d %11d %11d %11d %11d %s\n", i, t.file.dumpid, 0, 0, 100*(w.r.min.y-c.r.min.y)/c.r.dy(), fontname)); }else if(len a == 0){ # don't save unnamed windows continue; }else if((!w.dirty && utils->access(a)==0) || w.isdir){ dumped = FALSE; t.file.dumpid = w.id; b.puts(sprint("f%11d %11d %11d %11d %11d %s\n", i, w.id, w.body.q0, w.body.q1, 100*(w.r.min.y-c.r.min.y)/c.r.dy(), fontname)); }else{ dumped = TRUE; t.file.dumpid = w.id; b.puts(sprint("F%11d %11d %11d %11d %11d %11d %s\n", i, j, w.body.q0, w.body.q1, 100*(w.r.min.y-c.r.min.y)/c.r.dy(), w.body.file.buf.nc, fontname)); } a = nil; buf = w.ctlprint(0); b.puts(buf); m = min(BUFSIZE, w.tag.file.buf.nc); w.tag.file.buf.read(0, r, 0, m); n = 0; while(n<m && r.s[n]!='\n') n++; r.s[n++] = '\n'; b.puts(r.s[0:n]); if(dumped){ q0 = 0; q1 = t.file.buf.nc; while(q0 < q1){ n = q1 - q0; if(n > Dat->BUFSIZE) n = Dat->BUFSIZE; t.file.buf.read(q0, r, 0, n); b.puts(r.s[0:n]); q0 += n; } } if(w.dumpstr != nil){ if(w.dumpdir != nil) b.puts(sprint("%s\n%s\n", w.dumpdir, w.dumpstr)); else b.puts(sprint("\n%s\n", w.dumpstr)); } } } b.close(); b = nil; strfree(r); r = nil; } exception{ * => return; } } rdline(b : ref Iobuf, line : int) : (int, string) { l : string; l = b.gets('\n'); if(l != nil) line++; return (line, l); } Row.loadx(row : self ref Row, file : string, initing : int) { i, j, line, percent, y, nr, nfontr, n, ns, ndumped, dumpid, x : int; b, bout : ref Iobuf; fontname : string; l, buf, t : string; rune : int; r, fontr : string; c, c1, c2 : ref Column; q0, q1 : int; r1, r2 : Rect; w : ref Window; { if(file == nil){ if(home == nil){ warning(nil, "can't find file for load: $home not defined\n"); raise "e"; } buf = sprint("%s/acme.dump", home); file = buf; } b = bufio->open(file, Bufio->OREAD); if(b == nil){ warning(nil, sprint("can't open load file %s: %r\n", file)); raise "e"; } { # current directory (line, l) = rdline(b, 0); if(l == nil) raise "e"; l = l[0:len l - 1]; if(sys->chdir(l) < 0){ warning(nil, sprint("can't chdir %s\n", l)); b.close(); return; } # global fonts for(i=0; i<2; i++){ (line, l) = rdline(b, line); if(l == nil) raise "e"; l = l[0:len l -1]; if(l != nil && l != fontnames[i]) Reffont.get(i, TRUE, i==0 && initing, l); } if(initing && row.ncol==0) row.init(mainwin.clipr); (line, l) = rdline(b, line); if(l == nil) raise "e"; j = len l/12; if(j<=0 || j>10) raise "e"; for(i=0; i<j; i++){ percent = int l[12*i:12*i+11]; if(percent<0 || percent>=100) raise "e"; x = row.r.min.x+percent*row.r.dx()/100; if(i < row.ncol){ if(i == 0) continue; c1 = row.col[i-1]; c2 = row.col[i]; r1 = c1.r; r2 = c2.r; r1.max.x = x; r2.min.x = x+Border; if(r1.dx() < 50 || r2.dx() < 50) continue; draw(mainwin, (r1.min, r2.max), white, nil, (0, 0)); c1.reshape(r1); c2.reshape(r2); r2.min.x = x; r2.max.x = x+Border; draw(mainwin, r2, black, nil, (0, 0)); } if(i >= row.ncol) row.add(nil, x); } for(;;){ (line, l) = rdline(b, line); if(l == nil) break; dumpid = 0; case(l[0]){ 'e' => if(len l < 1+5*12+1) raise "e"; (line, l) = rdline(b, line); # ctl line; ignored if(l == nil) raise "e"; (line, l) = rdline(b, line); # directory if(l == nil) raise "e"; l = l[0:len l -1]; if(len l != 0) r = l; else{ if(home == nil) r = "./"; else r = home+"/"; } nr = len r; (line, l) = rdline(b, line); # command if(l == nil) raise "e"; t = l[0:len l -1]; spawn exec->run(nil, t, r, nr, TRUE, nil, nil, FALSE); # r is freed in run() continue; 'f' => if(len l < 1+5*12+1) raise "e"; fontname = l[1+5*12:len l - 1]; ndumped = -1; 'F' => if(len l < 1+6*12+1) raise "e"; fontname = l[1+6*12:len l - 1]; ndumped = int l[1+5*12:1+5*12+11]; 'x' => if(len l < 1+5*12+1) raise "e"; fontname = l[1+5*12: len l - 1]; ndumped = -1; dumpid = int l[1+1*12:1+1*12+11]; * => raise "e"; } l = l[0:len l -1]; if(len fontname != 0) { fontr = fontname; nfontr = len fontname; } else (fontr, nfontr) = (nil, 0); i = int l[1+0*12:1+0*12+11]; j = int l[1+1*12:1+1*12+11]; q0 = int l[1+2*12:1+2*12+11]; q1 = int l[1+3*12:1+3*12+11]; percent = int l[1+4*12:1+4*12+11]; if(i<0 || i>10) raise "e"; if(i > row.ncol) i = row.ncol; c = row.col[i]; y = c.r.min.y+(percent*c.r.dy())/100; if(y<c.r.min.y || y>=c.r.max.y) y = -1; if(dumpid == 0) w = c.add(nil, nil, y); else w = c.add(nil, look->lookid(dumpid, TRUE), y); if(w == nil) continue; w.dumpid = j; (line, l) = rdline(b, line); if(l == nil) raise "e"; l = l[0:len l - 1]; r = l[5*12:len l]; nr = len r; ns = -1; for(n=0; n<nr; n++){ if(r[n] == '/') ns = n; if(r[n] == ' ') break; } if(dumpid == 0) w.setname(r, n); for(; n<nr; n++) if(r[n] == '|') break; w.cleartag(); w.tag.insert(w.tag.file.buf.nc, r[n+1:len r], nr-(n+1), TRUE, 0); if(ndumped >= 0){ # simplest thing is to put it in a file and load that buf = sprint("/tmp/d%d.%.4sacme", sys->pctl(0, nil), utils->getuser()); bout = bufio->create(buf, Bufio->OWRITE, 8r600); if(bout == nil){ warning(nil, "can't create temp file: %r\n"); b.close(); return; } for(n=0; n<ndumped; n++){ rune = b.getc(); if(rune == '\n') line++; if(rune == Bufio->EOF){ bout.close(); bout = nil; raise "e"; } bout.putc(rune); } bout.close(); bout = nil; w.body.loadx(0, buf, 1); w.body.file.mod = TRUE; for(n=0; n<w.body.file.ntext; n++) w.body.file.text[n].w.dirty = TRUE; w.settag(); sys->remove(buf); buf = nil; }else if(dumpid==0 && r[ns+1]!='+' && r[ns+1]!='-') exec->get(w.body, nil, nil, FALSE, nil, 0); l = r = nil; if(fontr != nil){ exec->fontx(w.body, nil, nil, fontr, nfontr); fontr = nil; } if(q0>w.body.file.buf.nc || q1>w.body.file.buf.nc || q0>q1) q0 = q1 = 0; w.body.show(q0, q1, TRUE); w.maxlines = min(w.body.frame.nlines, max(w.maxlines, w.body.frame.maxlines)); } b.close(); } exception{ * => warning(nil, sprint("bad load file %s:%d\n", file, line)); b.close(); raise "e"; } } exception{ * => return; } } allwindows(o: int, aw: ref Dat->Allwin) { for(i:=0; i<row.ncol; i++){ c := row.col[i]; for(j:=0; j<c.nw; j++){ w := c.w[j]; case (o){ ALLLOOPER => pick k := aw{ LP => ecmd->alllooper(w, k.lp); } ALLTOFILE => pick k := aw{ FF => ecmd->alltofile(w, k.ff); } ALLMATCHFILE => pick k := aw{ FF => ecmd->allmatchfile(w, k.ff); } ALLFILECHECK => pick k := aw{ FC => ecmd->allfilecheck(w, k.fc); } ALLELOGTERM => edit->allelogterm(w); ALLEDITINIT => edit->alleditinit(w); ALLUPDATE => edit->allupdate(w); } } } }