shithub: blie

ref: 13590f759547f4ef544b251f2966b4ed2d82038c
dir: /efilter.c/

View raw version
#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,
};