implement Pimpl;
include "mods.m";
mods, debug, win, tree: import dat;
Cpointer, cols, panelback, maxpt, cookclick, drawtag, TEXT : import gui;
Ptag, Pedit, Pdead, intag, Predraw, Panel: import wpanel;
panelctl, panelkbd, panelmouse, tagmouse, Tree: import wtree;
Icache: adt {
data: array of byte;
sum: int;
i: ref Image;
alloc: fn(d: array of byte): ref Icache;
close: fn(ic: self ref Icache);
};
Pimage: adt {
ic: ref Icache;
off: Point; # x/y offset for page
};
panels: array of ref Pimage;
images: array of ref Icache;
init(d: Livedat): string
{
prefixes = list of {"image:", "page:"};
dat = d;
initmods();
panels = array[0] of ref Pimage;
images = array[0] of ref Icache;
return nil;
}
samedata(d1, d2: array of byte): int
{
if (len d1 != len d2)
return 0;
for (i := 0; i < len d1; i++)
if (d1[i] != d2[i])
return 0;
return 1;
}
Icache.alloc(d: array of byte): ref Icache
{
dpy := win.display;
sum := 0;
for (i := 0; i < len d; i++)
sum += int d[i];
for (i = 0; i < len images ; i++)
if ((ic := images[i]) != nil)
if (sum == ic.sum && samedata(ic.data, d))
return ic;
# not found in cache. install a new entry
fname := sprint("/tmp/owinimg.%d", sys->pctl(0,nil));
fd := create(fname, ORDWR|ORCLOSE, 8r644);
if (fd == nil)
return nil;
if (write(fd, d, len d) != len d)
return nil;
sys->seek(fd, big 0, 0);
img := dpy.readimage(fd);
if (img == nil)
return nil;
ic = ref Icache(d, sum, img);
for (i = 0; i < len images; i++)
if (images[i] == nil){
images[i] = ic;
return ic;
}
nimages := array[len images + 1] of ref Icache;
nimages[0:] = images;
nimages[len images] = ic;
images = nimages;
return ic;
}
Icache.close(ic: self ref Icache)
{
if (ic != nil){
for (i := 0; i < len images; i++)
if (images[i] == ic)
images[i] = nil;
}
# Pimages referencing ic will keep their refs valid
}
pimpl(p: ref Panel): ref Pimage
{
if (p.implid < 0 || p.implid > len panels || panels[p.implid] == nil)
panic("image: bug: no impl");
return panels[p.implid];
}
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 Pimage;
npanels[0:] = panels;
panels = npanels;
}
p.implid = i;
panels[i] = ref Pimage(nil, Point(0,0));
p.minsz = Point(48, 48);
p.flags |= Pedit;
if (len p.name > 6 && p.name[0:6] == "image:")
p.wants = Point(0, 0);
else
p.wants = Point(1, 1);
}
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);
}
pupdate(p: ref Panel, d: array of byte)
{
pi := pimpl(p);
if (pi == nil)
return;
if (pi.ic != nil && samedata(pi.ic.data, d))
return;
ic := pi.ic;
pi.ic =Icache.alloc(d);
if (pi.ic == nil){
pi.ic = ic;
return;
}
oldr := Rect((0,0), (48,48));
if (ic != nil && ic.i != nil)
oldr = ic.i.r;
ic.close();
pi.off = Point(0,0);
if (!p.wants.x){
p.minsz.x = pi.ic.i.r.dx();
p.minsz.y = pi.ic.i.r.dy();
}
p.flags |= Predraw;
}
pevent(nil: ref Panel, nil: string)
{
# no ins/del events
}
pdraw(p: ref Panel)
{
pi := pimpl(p);
if (pi == nil)
return;
back := panelback(p);
ic := pi.ic;
win.image.draw(p.rect, back, nil, (0,0));
if (ic != nil) {
pt := Point(0,0);
if (p.wants.x)
pt = pi.off;
pt = ic.i.r.min.add(pt);
if (p.wants.x)
win.image.draw(p.rect, back, nil, (0,0));
win.image.draw(p.rect, ic.i, nil, pt);
}
if (p.flags&Ptag)
drawtag(p);
}
ijump(p: ref Panel, pt: Point)
{
pi := pimpl(p);
if (pi == nil)
return;
if (pt.x < 0)
pt.x = 0;
if (pt.y < 0)
pt.y = 0;
dy := p.rect.dy();
diy:= pi.ic.i.r.dy();
dx := p.rect.dx();
dix:= pi.ic.i.r.dx();
pi.off.y = pt.y * diy / dy;
pi.off.x = pt.x * dix / dx;
if (pi.off.y < 0)
pi.off.y = 0;
if (diy <= dy)
pi.off.y = 0;
else if (pi.off.y > diy - dy)
pi.off.y = diy - dy ;
if (pi.off.x < 0)
pi.off.x = 0;
if (dix <= dx)
pi.off.x = 0;
else if (pi.off.x > dix - dx)
pi.off.x = dix - dx;
}
pmouse(p: ref Panel, m: ref Cpointer, mc: chan of ref Cpointer)
{
if ((p.flags&Ptag) && intag(p, m.xy)){
tagmouse(tree, p, m, mc);
return;
}
case m.buttons {
4 =>
m = <-mc;
if (p.flags&Pdead)
return;
if (m.buttons == 0)
p.fsctl(sprint("look %s\n", p.name), 1);
else {
while(m.buttons & 4){
if (p.flags&Pdead)
return;
xy := m.xy.sub(p.rect.min);
ijump(p, xy);
pdraw(p);
m = <-mc;
}
while(m.buttons != 0)
m = <-mc;
}
2 =>
if (cookclick(m, mc))
p.fsctl(sprint("exec %s\n", p.name), 1);
}
}
pkbd(p: ref Panel, r: int)
{
panelkbd(nil, p, r);
}
psync(nil: ref Panel)
{
# can't edit, no need to sync
}
|