implement Pimpl;
include "sys.m";
sys: Sys;
sprint, fprint: import sys;
include "styx.m";
include "styxservers.m";
Styxserver: import Styxservers;
include "daytime.m";
include "dat.m";
dat: Dat;
mnt, evc, Qdir, debug, appl, slash: import dat;
include "string.m";
str: String;
splitl: import str;
include "names.m";
names: Names;
dirname: import names;
include "error.m";
err: Error;
checkload, panic, stderr: import err;
include "tbl.m";
tbl: Tbl;
Table: import tbl;
include "mpanel.m";
Amax, Panel, Repl, Tappl, Trepl: import Panels;
Aclean, Afont, Asel, Amark, Ascroll, Atab: con Amax + iota;
init(d: Dat): list of string
{
dat = d;
sys = dat->sys;
err = dat->err;
str = dat->str;
names = dat->names;
return list of {"text:", "button:", "label:", "tag:", "tbl:"};
}
pinit(p: ref Panel)
{
(t, n) := splitl(p.name, ":");
if (n != nil)
n = n[1:];
else
n = "";
case t {
* =>
p.data = array of byte "";
"button" or "label" =>
p.data = array of byte n;
}
}
rinit(p: ref Panel, r: ref Repl)
{
(t, nil) := splitl(p.name, ":");
nfont := "font R";
case t {
"tbl" =>
nfont = "font R";
"label" or "button" or "tag" =>
nfont = "font B";
* =>
nfont = "font R";
}
attrs := array[] of { "clean", nfont, "sel 0 0", "mark 0", "noscroll", "tab 4"};
nattrs := array[len r.attrs + len attrs] of string;
nattrs[0:] = r.attrs;
nattrs[len r.attrs:] = attrs;
r.attrs = nattrs;
}
newdata(p: ref Panel): string
{
for (i := 0; i < len p.data; i++)
if (p.data[i] == byte 0)
return "UTF 0 not allowed";
return nil;
}
sel(p: ref Panel, r: ref Repl, args: list of string): (int, string)
{
n := int hd tl args;
n2:= int hd tl tl args;
if (n < 0 || n2 < 0)
return (0, "negative pos");
if (n > len p.data)
n = len p.data;
if (n2 > len p.data)
n2 = len p.data;
r.attrs[Asel] = sprint("sel %d %d", n, n2);
if (r.id == 0){
for (rn := 0; rn < len p.repl; rn++)
if ((pr := p.repl[rn]) != nil)
pr.attrs[Asel] = r.attrs[Asel];
return (1, nil);
} else
return (0, nil);
}
dirtyclean(p: ref Panel, r: ref Repl, args: list of string): (int, string)
{
r.attrs[Aclean] = hd args;
for (rn := 0; rn < len p.repl; rn++)
if ((pr := p.repl[rn]) != nil)
pr.attrs[Aclean] = r.attrs[Aclean];
return (1, nil);
}
font(p: ref Panel, r: ref Repl, args: list of string): (int, string)
{
fonts := array[] of { "L", "B", "S", "R", "I", "T" };
for (x := 0; x < len fonts; x++)
if (hd tl args == fonts[x])
break;
if (x == len fonts)
return (0, "not a font");
r.attrs[Afont] = "font " + fonts[x];
if (r.id == 0){
for (rn := 0; rn < len p.repl; rn++)
if ((pr := p.repl[rn]) != nil)
pr.attrs[Afont] = r.attrs[Afont];
return (1, nil);
} else
return (0, nil);
}
mark(p: ref Panel, r: ref Repl, args: list of string): (int, string)
{
n := int hd tl args;
if (n < 0)
return (0, "negative mark");
if (n > len p.data)
n = len p.data;
r.attrs[Amark] = sprint("mark %d", n);
if (r.id == 0){
for (rn := 0; rn < len p.repl; rn++)
if ((pr := p.repl[rn]) != nil)
pr.attrs[Amark] = r.attrs[Amark];
return (1, nil);
} else
return (0, nil);
}
tab(p: ref Panel, r: ref Repl, args: list of string): (int, string)
{
n := int hd tl args;
if (n < 3 || n > 10)
return (0, "tab must be in [3:10]");
r.attrs[Atab] = sprint("tab %d", n);
if (r.id == 0){
for (rn := 0; rn < len p.repl; rn++)
if ((pr := p.repl[rn]) != nil)
pr.attrs[Atab] = r.attrs[Atab];
return (1, nil);
} else
return (0, nil);
}
# Both ins and del need special update rules. They return (2, *)
# to signal fswrite to update other replicas by sending just the
# ctl data via events, and not by posting update events using the
# conventional rules.
# Also, although we store data as array of byte, positions refer
# to runes.
# BUG: converting to string and back to array of byte was fine
# for testing, but it's not reasonable. Convert offsets instead.
del(p: ref Panel, nil: ref Repl, args: list of string): (int, string)
{
pos := int hd tl args;
n := int hd tl tl args;
data := string p.data;
if (pos > len data)
pos = len data;
if (pos < 0)
return (0, "negative pos");
if (pos + n > len data)
n = len data - pos;
if (n == 0)
return (0, nil);
if (n < 0)
return (0, "negative del");
data = data[0:pos] + data[pos+n:];
p.data = array of byte data;
return (2, nil); # see comment above
}
ins(p: ref Panel, nil: ref Repl, args: list of string): (int, string)
{
pos := int hd tl args;
b := hd tl tl args;
data := string p.data;
if (pos+1 > len data)
pos = len data;
if (pos < 0)
return (0, "negative pos");
data = data[0:pos] + b + data [pos:];
p.data = array of byte data;
return (2, nil); # see comment above
}
ctl(p: ref Panels->Panel, r: ref Panels->Repl, ctl: list of string): (int, string)
{
case hd ctl {
"clean" or "dirty" =>
if (len ctl != 1)
return (0, "no arguments needed");
return dirtyclean(p, r, ctl);
"font" =>
if (len ctl != 2)
return (0, "1 argument needed");
return font(p, r, ctl);
"sel" =>
if (len ctl != 3)
return (0, "2 arguments needed");
return sel(p, r, ctl);
"mark" =>
if (len ctl != 2)
return (0, "1 argument needed");
return mark(p, r, ctl);
"ins" =>
if (len ctl != 3)
return (0, "2 arguments needed");
return ins(p, r, ctl);
"del" =>
if (len ctl != 3)
return (0, "2 arguments needed");
return del(p, r, ctl);
"tab" =>
if (len ctl != 2)
return(0, "1 argument needed");
return tab(p, r, ctl);
* =>
return (0, "not mine");
}
}
|