ref: 72ea71f4d629f81f7c5eb34d31cf4b873162d06b
dir: /efilter.c/
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <draw.h>
#include <memdraw.h>
#include <event.h>
#include <plumb.h>
#include "blie.h"
#include "db.h"
#define DEBUG
static int consfd = -1;
static void
clog(char *fmt, ...)
{
#ifdef DEBUG
va_list args;
if (consfd < 0) {
consfd = open("#c/cons", OWRITE|OCEXEC);
if (consfd < 0)
return;
}
fprint(consfd, "blie-efilter: ");
va_start(args, fmt);
vfprint(consfd, fmt, args);
va_end(args);
fprint(consfd, "\n");
#endif
}
/* TODO: add params as entries, use putenv(2) */
/* stored in database */
typedef struct Data Data;
struct Data {
char *script;
ulong mtime;
Db *db;
};
static int lwinoffset = 10;
static Point toolcell;
static void
finitialize()
{
if (headless)
return;
toolcell = Pt(15, vdata.fontheight);
}
static void
finit(Layer *l)
{
Data *d;
char *s;
if (l->data)
return;
clog("init layer: %s", l->name);
l->data = mallocz(sizeof(Data), 1);
d = l->data;
d->script = smprint("l/%s/script", l->name);
s = smprint("l/%s/params", l->name);
d->db = opendb(s);
free(s);
}
static Rectangle
ftoolrect(Layer*)
{
return Rect(0, 0, 1, 1);
}
static void
fdrawtools(Layer*, Image*)
{
}
static int
fsavedata(Layer *l)
{
Data *d;
int r = 0;
d = (Data*)l->data;
r |= writedb(d->db, nil);
return r;
}
static Redrawwin
ftoolinput(Layer*, int, Event)
{
return Rnil;
}
static void
setenvs(Data *d)
{
Dpack *dv;
Dtuple *dt;
dv = getdpack(d->db, "params");
for (dt = dv->tuple; dt; dt = dt->next) {
clog("$%s = %s", dt->key, dt->value);
putenv(dt->key, dt->value);
}
}
static Memimage*
readfiltered(Memimage *i, Data *d)
{
Memimage *result;
int in[2];
int out[2];
int errfd;
Dir *dir;
if (pipe(in) < 0)
sysfatal("%r");
if (pipe(out) < 0)
sysfatal("%r");
dir = dirfstat(in[0]);
if (!dir)
sysfatal("%r");
dir->length = i->width * Dy(i->r) * sizeof(ulong) + 12*5;
if (!dirfwstat(in[0], dir))
sysfatal("%r");
free(dir);
switch (rfork(RFFDG|RFREND|RFPROC|RFENVG|RFNAMEG)) {
case -1:
sysfatal("fork: %r");
case 0:
/* child process */
setenvs(d);
errfd = open("#c/cons", OWRITE|OCEXEC);
if (errfd >= 0) {
dup(errfd, 2);
}
dup(in[1], 0);
dup(out[1], 1);
close(in[0]);
close(out[0]);
execl(d->script, d->script, nil);
sysfatal("%r");
default:
close(in[1]);
close(out[1]);
}
writememimage(in[0], i);
result = readmemimage(out[0]);
if (!result)
sysfatal("%r");
close(in[0]);
close(out[0]);
return result;
}
static Memimage*
fcomposite(Layer *l, Memimage *img)
{
Data *d;
d = (Data*)l->data;
if (!img || !d)
return nil;
return readfiltered(img, d);
}
static void
drcells(Image *i, Point p, char *s, int hl)
{
Rectangle r;
r.min = p;
r.max = addpt(p, toolcell);
draw(i, r, display->white, nil, ZP);
border(i, r, 1, vdata.gray, ZP);
if (hl) {
r = insetrect(r, 2);
draw(i, r, vdata.gray, nil, ZP);
}
string(i, addpt(p, Pt(2, 2)), display->black, ZP, font, s);
}
static void
fdrawlwin(Layer*, Image *i, Rectangle r)
{
Point p;
p = r.min;
p.x += lwinoffset;
drcells(i, p, "E", 0);
p.x += toolcell.x;
drcells(i, p, "P", 0);
p.x += toolcell.x;
drcells(i, p, "A", 0);
p.x += toolcell.x;
drcells(i, p, "D", 0);
}
static int
editparams(Data *d, Mouse m)
{
Ask *asks;
Dpack *dv;
Dtuple *dt;
int num, i, n;
if (!d || !d->db)
return 0;
dv = getdpack(d->db, "params");
if (!dv)
return 0;
num = 0;
for (dt = dv->tuple; dt; dt = dt->next)
num++;
asks = mallocz((num+1) * sizeof(Ask), 1);
i = 0;
for (dt = dv->tuple; dt; dt = dt->next) {
n = strlen(dt->value);
if (n < 511)
n = 511;
n++;
asks[i].label = dt->key;
asks[i].value = mallocz(n, 1);
snprint(asks[i].value, n, "%s", dt->value);
asks[i].nval = n;
i++;
}
m.xy = vstate.mousepos;
if (!ask(asks, m)) {
for (i = 0; i < num; i++)
free(asks[i].value);
free(asks);
return 0;
}
for (i = 0; i < num; i++) {
setdval(dv, asks[i].label, asks[i].value);
free(asks[i].value);
}
free(asks);
return 1;
}
static int
editscr(Data *d, Mouse m)
{
int fd;
char wd[256];
if (m.buttons & 1) /* left click: dirty */
return 1;
if (! (m.buttons & 4)) /* right click: edit */
return 0;
if (!d || !d->script)
return 0;
fd = plumbopen("send", OWRITE);
if (fd < 0)
return 0;
getwd(wd, sizeof wd);
plumbsendtext(fd, "blie", "edit", wd, d->script);
close(fd);
return 1;
}
static int
addparam(Data *d, Mouse m, int del)
{
Dpack *dv;
char buf[512];
char *s;
if (!d || !d->db)
return 0;
dv = getdpack(d->db, "params");
if (!dv) {
clog("no params found");
return 0;
}
m.xy = vstate.mousepos;
buf[0] = 0;
if (!eenter("name", buf, sizeof buf, &m))
return 0;
if (del) {
deldtuple(dv, buf);
return 1;
}
s = strdup(buf);
buf[0] = 0;
if (!eenter("value", buf, sizeof buf, &m)) {
free(s);
return 0;
}
setdval(dv, s, buf);
free(s);
return 1;
}
static Redrawwin
flwininput(Layer *l, int, Event ev)
{
Data *d;
d = (Data*)l->data;
ev.mouse.xy.x -= lwinoffset;
if (ev.mouse.xy.y / toolcell.y != 0)
return Rnil;
switch (ev.mouse.xy.x / toolcell.x) {
case 0: /* edit script (plumb) */
if (editscr(d, ev.mouse))
goto Out;
break;
case 1: /* edit params */
if (editparams(d, ev.mouse))
goto Out;
break;
case 2: /* add param */
if (addparam(d, ev.mouse, 0))
goto Out;
break;
case 3: /* delete param */
if (addparam(d, ev.mouse, 1))
goto Out;
break;
}
return Rnil;
Out:
dirtylayer(l);
setdrawingdirty(Dcontent);
return Rdrawing;
}
Editor efilter = {
.name = "filter",
.init = finitialize,
.initlayer = finit,
.raw = nil,
.mask = nil,
.composite = fcomposite,
.overlay = nil,
.toolrect = ftoolrect,
.drawtools = fdrawtools,
.drawlwin = fdrawlwin,
.savedata = fsavedata,
.savetools = nil,
.drawinput = nil,
.toolinput = ftoolinput,
.lwininput = flwininput,
};