summaryrefslogtreecommitdiff
path: root/appl/wm/brutus/mod.b
diff options
context:
space:
mode:
Diffstat (limited to 'appl/wm/brutus/mod.b')
-rw-r--r--appl/wm/brutus/mod.b335
1 files changed, 335 insertions, 0 deletions
diff --git a/appl/wm/brutus/mod.b b/appl/wm/brutus/mod.b
new file mode 100644
index 00000000..02f8e20e
--- /dev/null
+++ b/appl/wm/brutus/mod.b
@@ -0,0 +1,335 @@
+implement Brutusext;
+
+# <Extension mod file>
+# For module descriptions (in book)
+
+Name: con "Brutus mod";
+
+include "sys.m";
+ sys: Sys;
+
+include "draw.m";
+ draw: Draw;
+ Context, Font: import draw;
+
+include "bufio.m";
+ bufio: Bufio;
+ Iobuf: import bufio;
+
+include "tk.m";
+ tk: Tk;
+
+include "tkclient.m";
+ tkclient: Tkclient;
+
+include "string.m";
+ S : String;
+
+include "brutus.m";
+ Size8, Index, Roman, Italic, Bold, Type, NFONT, NSIZE: import Brutus;
+
+include "brutusext.m";
+
+Mstring: adt
+{
+ s: string;
+ style: int;
+ indexed: int;
+ width: int;
+ next: cyclic ref Mstring;
+};
+
+fontname := array[NFONT] of {
+ "/fonts/lucidasans/unicode.7.font",
+ "/fonts/lucidasans/italiclatin1.7.font",
+ "/fonts/lucidasans/boldlatin1.7.font",
+ "/fonts/lucidasans/typelatin1.7.font",
+ };
+
+fontswitch := array[NFONT] of {
+ "\\fontseries{m}\\rmfamily ",
+ "\\itshape ",
+ "\\fontseries{b}\\rmfamily ",
+ "\\fontseries{mc}\\ttfamily ",
+ };
+
+fontref := array[NFONT] of ref Font;
+
+LEFTCHARS: con 45;
+LEFTPIX: con LEFTCHARS*7; # 7 is width of lucidasans/typelatin1.7 chars
+
+init(s: Sys, d: Draw, b: Bufio, t: Tk, w: Tkclient)
+{
+ sys = s;
+ draw = d;
+ bufio = b;
+ tk = t;
+ tkclient = w;
+ S = load String String->PATH;
+}
+
+create(parent: string, t: ref Tk->Toplevel, name, args: string): string
+{
+ (spec, err) := getspec(parent, args);
+ if(err != nil)
+ return err;
+ n := len spec;
+ if(n == 0)
+ return "empty spec";
+ d := t.image.display;
+ for(i:=0; i < NFONT; i++) {
+ if(i == Bold || fontref[i] != nil)
+ continue;
+ fontref[i] = Font.open(d, fontname[i]);
+ if(fontref[i] == nil)
+ return sys->sprint("can't open font %s: %r\n", fontname[i]);
+ }
+ (nil, nil, rw, nil) := measure(spec, 1);
+ lw := LEFTPIX;
+ wd := lw + rw;
+ fnt := fontref[Roman];
+ ht := n * fnt.height;
+ err = tk->cmd(t, "canvas " + name + " -width " + string wd
+ + " -height " + string ht
+ + " -font " + fontname[Type]);
+ if(len err > 0 && err[0] == '!')
+ return "problem creating canvas";
+ y := 0;
+ xl := 0;
+ xr := lw;
+ for(l := spec; l != nil; l = tl l) {
+ (lm, rm) := hd l;
+ canvmstring(t, name, lm, xl, y);
+ canvmstring(t, name, rm, xr, y);
+ y += fnt.height;
+ }
+ tk->cmd(t, "update");
+ return "";
+}
+
+canvmstring(t: ref Tk->Toplevel, canv: string, m: ref Mstring, x, y: int)
+{
+ # assume fonts all have same ascent
+ while(m != nil) {
+ pos := string x + " " + string y;
+ font := "";
+ if(m.style != Type)
+ font = " -font " + fontname[m.style];
+ e := tk->cmd(t, canv + " create text " + pos + " -anchor nw "
+ + font + " -text '" + m.s);
+ x += m.width;
+ m = m.next;
+ }
+}
+
+getspec(parent, args: string) : (list of (ref Mstring, ref Mstring), string)
+{
+ (n, argl) := sys->tokenize(args, " ");
+ if(n != 1)
+ return (nil, "usage: " + Name + " file");
+ b := bufio->open(fullname(parent, hd argl), Sys->OREAD);
+ if(b == nil)
+ return (nil, sys->sprint("can't open %s, the error was: %r", hd argl));
+ mm : list of (ref Mstring, ref Mstring) = nil;
+ for(;;) {
+ s := b.gets('\n');
+ if(s == "")
+ break;
+ (nf, fl) := sys->tokenize(s, " ");
+ if(nf == 0)
+ mm = (nil, nil) :: mm;
+ else {
+ sleft := "";
+ sright := "";
+ if(nf == 1) {
+ f := hd fl;
+ if(s[0] == '\t')
+ sright = f;
+ else
+ sleft = f;
+ }
+ else {
+ sleft = hd fl;
+ sright = hd tl fl;
+ }
+ mm = (tom(sleft, Type, Roman, 1), tom(sright, Italic, Type, 0)) :: mm;
+ }
+ }
+ ans : list of (ref Mstring, ref Mstring) = nil;
+ while(mm != nil) {
+ ans = hd mm :: ans;
+ mm = tl mm;
+ }
+ return (ans, "");
+}
+
+tom(str: string, defstyle, altstyle, doindex: int) : ref Mstring
+{
+ if(str == "")
+ return nil;
+ if(str[len str - 1] == '\n')
+ str = str[0: len str - 1];
+ if(str == "")
+ return nil;
+ style := defstyle;
+ if(str[0] == '|')
+ style = altstyle;
+ (nil, l) := sys->tokenize(str, "|");
+ dummy := ref Mstring;
+ last := dummy;
+ if(doindex && l != nil && S->prefix(" ", hd l))
+ doindex = 0; # continuation line
+ while(l != nil) {
+ s := hd l;
+ m : ref Mstring;
+ if(doindex && style == defstyle) {
+ # index 'words' in defstyle, but not past : or (
+ (sl,sr) := S->splitl(s, ":(");
+ while(sl != nil) {
+ a : string;
+ (a,sl) = S->splitl(sl, "a-zA-Z");
+ if(a != "") {
+ m = ref Mstring(a, style, 0, 0, nil);
+ last.next = m;
+ last = m;
+ }
+ if(sl != "") {
+ b : string;
+ (b,sl) = S->splitl(sl, "^a-zA-Z0-9_");
+ if(b != "") {
+ m = ref Mstring(b, style, 1, 0, nil);
+ last.next = m;
+ last = m;
+ }
+ }
+ }
+ if(sr != "") {
+ m = ref Mstring(sr, style, 0, 0, nil);
+ last.next = m;
+ last = m;
+ doindex = 0;
+ }
+ }
+ else {
+ m = ref Mstring(s, style, 0, 0, nil);
+ last.next = m;
+ last = m;
+ }
+ l = tl l;
+ if(style == defstyle)
+ style = altstyle;
+ else
+ style = defstyle;
+ }
+ return dummy.next;
+}
+
+measure(spec: list of (ref Mstring, ref Mstring), pixels: int) : (int, ref Mstring, int, ref Mstring)
+{
+ maxl := 0;
+ maxr := 0;
+ maxlm : ref Mstring = nil;
+ maxrm : ref Mstring = nil;
+ while(spec != nil) {
+ (lm, rm) := hd spec;
+ spec = tl spec;
+ (maxl, maxlm) = measuremax(lm, maxl, maxlm, pixels);
+ (maxr, maxrm) = measuremax(rm, maxr, maxrm, pixels);
+ }
+ return (maxl, maxlm, maxr, maxrm);
+}
+
+measuremax(m: ref Mstring, maxw: int, maxm: ref Mstring, pixels: int) : (int, ref Mstring)
+{
+ w := 0;
+ for(mm := m; mm != nil; mm = mm.next) {
+ if(pixels)
+ mm.width = fontref[mm.style].width(mm.s);
+ else
+ mm.width = len mm.s;
+ w += mm.width;
+ }
+ if(w > maxw) {
+ maxw = w;
+ maxm = m;
+ }
+ return (maxw, maxm);
+}
+
+cook(parent: string, nil: int, args: string): (ref Celem, string)
+{
+ (spec, err) := getspec(parent, args);
+ if(err != nil)
+ return (nil, err);
+ (nil, maxlm, nil, nil) := measure(spec, 0);
+ ans := fontce(Roman);
+ tail := specialce("\\begin{tabbing}\\hspace{3in}\\=\\kill\n");
+ tail = add(ans, nil, tail);
+ for(l := spec; l != nil; l = tl l) {
+ (lm, rm) := hd l;
+ tail = cookmstring(ans, tail, lm, 1);
+ tail = add(ans, tail, specialce("\\>"));
+ tail = cookmstring(ans, tail, rm, 0);
+ tail = add(ans, tail, specialce("\\\\\n"));
+ }
+ add(ans, tail, specialce("\\end{tabbing}"));
+ return (ans, "");
+}
+
+cookmstring(par, tail: ref Celem, m: ref Mstring, doindex: int) : ref Celem
+{
+ s := "";
+ if(m == nil)
+ return tail;
+ while(m != nil) {
+ e := fontce(m.style);
+ te := textce(m.s);
+ add(e, nil, te);
+ if(doindex && m.indexed) {
+ ie := ref Celem(Index, nil, nil, nil, nil, nil);
+ add(ie, nil, e);
+ e = ie;
+ }
+ tail = add(par, tail, e);
+ m = m.next;
+ }
+ return tail;
+}
+
+specialce(s: string) : ref Celem
+{
+ return ref Celem(Special, s, nil, nil, nil, nil);
+}
+
+textce(s: string) : ref Celem
+{
+ return ref Celem(Text, s, nil, nil, nil, nil);
+}
+
+fontce(sty: int) : ref Celem
+{
+ return ref Celem(sty*NSIZE+Size8, nil, nil, nil, nil, nil);
+}
+
+add(par, tail: ref Celem, e: ref Celem) : ref Celem
+{
+ if(tail == nil) {
+ par.contents = e;
+ e.parent = par;
+ }
+ else
+ tail.next = e;
+ e.prev = tail;
+ return e;
+}
+
+fullname(parent, file: string): string
+{
+ if(len parent==0 || (len file>0 && (file[0]=='/' || file[0]=='#')))
+ return file;
+
+ for(i:=len parent-1; i>=0; i--)
+ if(parent[i] == '/')
+ return parent[0:i+1] + file;
+ return file;
+}