implement Pimpl;
include "mods.m";
mods, debug, win, tree: import dat;
Cpointer, cols, panelback, maxpt, cookclick, drawtag, TEXT,
BACK, HIGH, HBORD, BORD, HTEXT, SET, CLEAR, MBACK, MSET, MCLEAR, WS1,
WS2, WS3 : import gui;
Ptag, nth, Predraw, Panel: import wpanel;
panelctl, panelkbd, panelmouse, tagmouse, Tree: import wtree;
Pdraw: adt {
canvas: ref Image;
dcmds: string;
};
# Beware: Draw functions and colors must be kept in sync with
# ../mero/ompdraw.b, which checks out user writes for validity
# we recheck here, just in case.
Drawfunc: type ref fn(canvas: ref Image, args: list of string): Point;
Dcmd: adt {
name: string;
drawfn: Drawfunc;
};
Dcol: adt {
name: string;
img: ref Image;
};
dcols: list of Dcol;
dcmds: array of Dcmd;
panels: array of ref Pdraw;
pimpl(p: ref Panel): ref Pdraw
{
if (p.implid < 0 || p.implid > len panels || panels[p.implid] == nil)
panic("draw: bug: no impl");
return panels[p.implid];
}
initcols()
{
dpy := win.display;
icols := array[] of {
("black", Draw->Black),
("white", Draw->White),
("red", Draw->Red),
("green", Draw->Green),
("blue", Draw->Blue),
("cyan", Draw->Cyan),
("magenta", Draw->Magenta),
("yellow", Draw->Yellow),
("grey", Draw->Grey),
("paleyellow", Draw->Paleyellow),
("darkyellow", Draw->Darkyellow),
("darkgreen", Draw->Darkgreen),
("palegreen", Draw->Palegreen),
("medgreen", Draw->Medgreen),
("darkblue", Draw->Darkblue),
("palebluegreen", Draw->Palebluegreen),
("paleblue", Draw->Paleblue),
("bluegreen", Draw->Bluegreen),
("greygreen", Draw->Greygreen),
("palegreygreen", Draw->Palegreygreen),
("yellowgreen", Draw->Yellowgreen),
("medblue", Draw->Medblue),
("greyblue", Draw->Greyblue),
("palegreyblue", Draw->Palegreyblue),
("purpleblue", Draw->Purpleblue),
};
dcols = nil;
for (i := 0; i < len icols; i++)
dcols = Dcol(icols[i].t0, dpy.color(icols[i].t1))::dcols;
dcols = Dcol("back", cols[BACK]):: dcols;
dcols = Dcol("high", cols[HIGH])::dcols;
dcols = Dcol("bord", cols[BORD])::dcols;
dcols = Dcol("text", cols[TEXT])::dcols;
dcols = Dcol("htext", cols[HTEXT])::dcols;
dcols = Dcol("hbord", cols[HBORD])::dcols;
dcols = Dcol("set", cols[SET])::dcols;
dcols = Dcol("clear", cols[CLEAR])::dcols;
dcols = Dcol("mback", cols[MBACK])::dcols;
dcols = Dcol("mset", cols[MSET])::dcols;
dcols = Dcol("mclear", cols[MCLEAR])::dcols;
dcols = Dcol("ws1", cols[WS1])::dcols;
dcols = Dcol("ws2", cols[WS2])::dcols;
dcols = Dcol("ws3", cols[WS3])::dcols;
}
init(d: Livedat): string
{
prefixes = list of {"draw:"};
dat = d;
initmods();
# BUG: needs arc fillarc, bezier, fillbezier, and text (from Draw->Image)
# and probably needs move and copy.
# PIC would be a nice language to implement here.
dcmds = array[] of {
Dcmd("ellipse", dellipse), # ellipse cx cy rx ry [w col]
Dcmd("fillellipse", dfillellipse), # fillellipse cx cy rx ry [col]
Dcmd("line", dline), # line ax ay bx by [ea eb r col]
Dcmd("rect", drect), # rect ax ay bx by [col]
Dcmd("poly", dpoly), # poly x0 y0 x1 y1 ... xn yn e0 en w col
Dcmd("bezspline", dpoly), # bezspline x0 y0 x1 y1 ... xn yn e0 en w col
Dcmd("fillpoly", dfillpoly), # fillpoly x0 y0 x1 y1 ... xn yn w col
Dcmd("fillbezspline", dfillpoly) # fillbezspline x0 y0 x1 y1 ... xn yn w col
};
return nil;
}
pinit(p: ref Panel)
{
if (tree == nil)
tree = dat->tree;
for (i := 0; i < len panels; i++)
if (panels[i] == nil)
break;
if (i == len panels){
npanels := array[i+16] of ref Pdraw;
npanels[0:] = panels;
panels = npanels;
}
p.implid = i;
panels[i] = ref Pdraw(nil, "");
p.minsz = Point(48,48);
}
pterm(p: ref Panel)
{
if (p.implid != -1){
pimpl(p); # check
panels[p.implid] = nil;
p.implid = -1;
}
}
pctl(p: ref Panel, s: string)
{
panelctl(tree, p, s);
}
pevent(nil: ref Panel, nil: string)
{
# no ins/del events
}
atocol(s: string): ref Image
{
for(l := dcols; l != nil; l = tl l)
if ((hd l).name == s)
return (hd l).img;
fprint(stderr, "o/live: atocol unknown color %s\n", s);
return cols[TEXT];
}
dellipse(canvas: ref Image, args: list of string): Point
{
if (len args < 5 || len args > 7)
return Point(0,0);
pt := Point(int nth(args, 1), int nth(args, 2));
rd := Point(int nth(args, 3), int nth(args, 4));
c := cols[TEXT];
wid := 0;
if (len args >= 6)
wid = int nth(args, 5);
if (len args == 7)
c = atocol(nth(args, 6));
if (canvas != nil)
canvas.ellipse(pt, rd.x, rd.y, wid, c, (0,0));
return pt.add(rd);
}
dfillellipse(canvas: ref Image, args: list of string): Point
{
if (len args < 5 || len args > 6)
return Point(0,0);
pt := Point(int nth(args, 1), int nth(args, 2));
rd := Point(int nth(args, 3), int nth(args, 4));
c := cols[TEXT];
if (len args == 6)
c = atocol(nth(args, 5));
if (canvas != nil)
canvas.fillellipse(pt, rd.x, rd.y, c, (0,0));
return pt.add(rd);
}
dline(canvas: ref Image, args: list of string): Point
{
if (len args < 5 || len args > 9)
return Point(0,0);
min := Point(int nth(args, 1), int nth(args, 2));
max := Point(int nth(args, 3), int nth(args, 4));
ea := eb := wid := 0;
c := cols[TEXT];
if (len args >= 6)
ea = int nth(args, 5);
if (len args >= 7)
eb = int nth(args, 6);
if (len args >= 8)
wid = int nth(args, 7);
if (len args >= 9)
c = atocol(nth(args, 8));
if (canvas != nil)
canvas.line(min, max, ea, eb, wid, c, (0,0));
r := Rect(min, max);
r = r.canon();
return r.max;
}
drect(canvas: ref Image, args: list of string): Point
{
if (len args < 5 || len args > 6)
return Point(0,0);
min := Point(int nth(args, 1), int nth(args, 2));
max := Point(int nth(args, 3), int nth(args, 4));
r := Rect(min, max);
col := cols[TEXT];
if (len args == 6)
col = atocol(nth(args, 5));
if (canvas != nil)
canvas.draw(r, col, nil, (0,0));
return max;
}
dpoly(canvas: ref Image, args: list of string): Point
{
l := len args;
if (l < 5 + 3 * 2)
return Point(0,0);
np := (l -5)/2;
pts := array[np] of Point;
cmd := hd args;
args = tl args;
max := Point(0,0);
for(i := 0; i < len pts; i++){
pts[i] = Point(int hd args, int hd tl args);
args = tl tl args;
if (max.x < pts[i].x)
max.x = pts[i].x;
if (max.y < pts[i].y)
max.y = pts[i].y;
}
e0 := int hd args; args = tl args;
e1 := int hd args; args = tl args;
w := int hd args; args = tl args;
col := atocol(hd args);
if (canvas != nil)
case cmd {
"bezspline" =>
canvas.bezspline(pts, e0, e1, w, col, (0,0));
* =>
canvas.poly(pts, e0, e1, w, col, (0,0));
}
return max;
}
dfillpoly(canvas: ref Image, args: list of string): Point
{
l := len args;
if (l < 3 + 3 * 2)
return Point(0,0);
np := (l - 3)/2;
pts := array[np] of Point;
cmd := hd args;
args = tl args;
max := Point(0,0);
for(i := 0; i < len pts; i++){
pts[i] = Point(int hd args, int hd tl args);
args = tl tl args;
if (max.x < pts[i].x)
max.x = pts[i].x;
if (max.y < pts[i].y)
max.y = pts[i].y;
}
w := int hd args; args = tl args;
col := atocol(hd args);
if (canvas != nil)
case cmd {
"fillbezspline" =>
canvas.fillbezspline(pts, w, col, (0,0));
* =>
canvas.fillpoly(pts, w, col, (0,0));
}
return max;
}
drawcmds(s: string, canvas: ref Image): Point
{
max := Point(0,0);
(nil, cmds) := tokenize(s, "\n");
for(; cmds != nil; cmds = tl cmds){
(nargs, args) := tokenize(hd cmds, " \t");
if (nargs > 0){
for (i := 0; i < len dcmds; i++)
if (dcmds[i].name == hd args){
if (canvas != nil && debug['D']){
for(l := args; l != nil; l = tl l)
fprint(stderr, "'%s' ", hd l);
fprint(stderr, "\n");
}
x := dcmds[i];
p := x.drawfn(canvas, args);
max = maxpt(max, p);
break;
}
}
}
max = max.add((2,2)); # two extra pixels
max = maxpt(max, Point(10, 10)); # and ensure a min. sz
return max;
}
pupdate(p: ref Panel, d: array of byte)
{
if (dcols == nil)
initcols();
dpy := win.display;
c := win.image.chans;
pi := pimpl(p);
if (pi == nil)
return;
ncmds := string d;
if (pi.dcmds == ncmds)
return;
pi.dcmds = string d;
if (pi.canvas != nil)
pi.canvas = nil;
p.minsz = drawcmds(pi.dcmds, nil); # compute size
r := Rect((0,0), p.minsz);
cback := panelback(p.parent);
ncanvas := dpy.newimage(r, c, 0, Draw->White);
if (ncanvas == nil){
fprint(stderr, "o/live: pdraw: %r\n");
return;
}
ncanvas.draw(ncanvas.r, cback, nil, (0,0));
drawcmds(pi.dcmds, ncanvas);
pi.canvas = ncanvas;
p.flags |= Predraw;
}
pdraw(p: ref Panel)
{
if (dcols == nil)
initcols();
pi := pimpl(p);
cback := panelback(p);
if (pi != nil && pi.canvas != nil){
win.image.draw(p.rect, pi.canvas, nil, (0,0));
if (pi.canvas.r.dx() < p.rect.dx()){
r := p.rect;
r.min.x += pi.canvas.r.dx();
win.image.draw(r, cback, nil, (0,0));
}
if (pi.canvas.r.dy() < p.rect.dy()){
r := p.rect;
r.min.y += pi.canvas.r.dy();
win.image.draw(r, cback, nil, (0,0));
}
} else
win.image.draw(p.rect, cback, nil, (0,0));
if (p.flags&Ptag)
drawtag(p);
}
pmouse(p: ref Panel, m: ref Cpointer, mc: chan of ref Cpointer)
{
if (panelmouse(tree, p, m, mc))
return;
pt := m.xy.sub(p.rect.min);
b := m.buttons;
if (m.buttons != 0 && cookclick(m, mc))
p.fsctl(sprint("click %d %d %d %d\n", pt.x, pt.y, b, m.msec), 1);
}
pkbd(p: ref Panel, r: int)
{
panelkbd(nil, p, r);
}
psync(nil: ref Panel)
{
# can't edit, no need to sync
}
|