ref: a3477b9d29227db6e78cede76fdd9d6b83f5ea76
dir: /layer.c/
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <memdraw.h>
#include <event.h>
#include <bio.h>
#include "blie.h"
char Ebadfmt[] = "bad file format: ";
typedef struct List List;
struct List {
Layer *layer;
List *next;
};
List *firstlayer = nil;
static Drawop
str2op(char *s)
{
#define OP(n) if (!strcmp(s, "n")) { return n; }
OP(Clear);
OP(SinD);
OP(DinS);
OP(SoutD);
OP(DoutS);
OP(S);
OP(SoverD);
OP(SatopD);
OP(SxorD);
OP(D);
OP(DoverS);
OP(DatopS);
OP(DxorS);
#undef OP
return SoverD;
}
static char*
op2str(Drawop op)
{
#define OP(n) if (op == n) { return "n"; }
OP(Clear);
OP(SinD);
OP(DinS);
OP(SoutD);
OP(DoutS);
OP(S);
OP(SoverD);
OP(SatopD);
OP(SxorD);
OP(D);
OP(DoverS);
OP(DatopS);
OP(DxorS);
#undef OP
return "SoverD";
}
static void
_renum(Layer *l, int id, int, void*)
{
l->num = id;
}
static void
renumlayers(void)
{
foreachlayer(_renum, nil);
}
static void
addlayerl(Layer *l)
{
List *f;
if (!firstlayer) {
firstlayer = mallocz(sizeof(List), 1);
firstlayer->layer = l;
l->num = 0;
return;
}
for (f = firstlayer; f->next; f = f->next)
continue;
f->next = mallocz(sizeof(List), 1);
f->next->layer = l;
l->num = f->layer->num + 1;
}
void
addlayer(char *name)
{
Biobuf *b;
char *file;
char *ed, *lbl, *op;
Layer *l;
if (!name || !name[0])
return;
file = smprint("l/%s/meta", name);
b = Bopen(file, OREAD);
free(file);
if (!b)
sysfatal("error opening file %s/meta: %r", name);
ed = Brdstr(b, '\n', 1);
if (!ed)
sysfatal("%s%s/meta: missing editor", Ebadfmt, name);
lbl = Brdstr(b, '\n', 1);
if (!lbl)
sysfatal("%s%s/meta: missing label", Ebadfmt, name);
op = Brdstr(b, '\n', 1);
if (!op)
sysfatal("%s%s/meta: missing drawop", Ebadfmt, name);
l = mallocz(sizeof(Layer), 1);
l->name = strdup(name);
l->label = strdup(lbl);
l->editor = geteditor(ed);
l->op = str2op(op);
if (!l->editor)
sysfatal("editor %s not found for %s", ed, name);
addlayerl(l);
free(lbl);
free(ed);
free(op);
Bterm(b);
}
void
movelayer(Layer *layer, int dir)
{
List *parent;
List *l;
if (firstlayer->layer == layer) {
if (dir == DOWN) {
l = firstlayer->next;
firstlayer->next = l ? l->next : nil;
l->next = firstlayer;
firstlayer = l;
return;
}
if (dir == UP)
return; /* NOP */
}
/* find parent */
for (l = firstlayer; l && l->next->layer != layer; l = l->next)
continue;
if (!l)
return; /* not found */
parent = l;
if (dir == DOWN)
goto Movedown;
if (dir != UP)
sysfatal("code error: direction != UP|DOWN");
/* movelayer(layer, UP) == movelayer(parent, DOWN) */
movelayer(parent->layer, DOWN);
return;
Movedown:
l = parent->next;
if (!l)
return; /* NOP: last element */
parent->next = l->next;
l->next = l->next ? l->next->next : nil;
parent->next->next = l;
// TODO: verify!
l->layer->num--;
if (l->next)
l->next->layer->num++;
}
void
dirtylayer(Layer *layer)
{
if (layer->composited)
freememimage(layer->composited);
layer->composited = nil;
}
void
savelayermeta(Layer *layer)
{
Biobuf *b;
char *file;
file = smprint("l/%s/meta", layer->name);
b = Bopen(file, OWRITE|OTRUNC);
free(file);
if (!b)
sysfatal("error opening file %s.meta for write: %r", layer->name);
Bprint(b, "%s\n%s\n", layer->editor->name, layer->label);
Bterm(b);
}
int
foreachlayer(void (*f)(Layer*, int, int, void*), void* aux)
{
List *l;
int i;
i = 0;
for (l = firstlayer; l; l = l->next, i++) {
f(l->layer, i, !l->next, aux);
}
return i;
}
int layerheight;
static void
redrawlayer(Layer *l, int n, int, void *aux)
{
void **data;
Image *img;
Layer *active;
Point p;
Rectangle r;
data = (void**)aux;
img = data[0];
active = data[1];
p = img->r.min;
p.y += n * layerheight;
if (l == active) {
r.min = r.max = p;
r.max.x += vdata.layerwinwidth;
r.max.y += layerheight;
draw(img, r, vdata.gray, nil, ZP);
}
string(img, addpt(p, Pt(2, 2)), display->black, ZP, font, l->label);
}
void
redrawlayers(Image *img, Layer *active)
{
void *data[2];
data[0] = img;
data[1] = active;
layerheight = vdata.fontheight + 10;
draw(img, img->r, display->white, nil, ZP);
foreachlayer(redrawlayer, data);
line(img, img->r.min, Pt(img->r.min.x, img->r.max.y),
Endsquare, Endsquare, 0, display->black, ZP);
}
static void
checkclick(Layer *l, int n, int, void *aux)
{
void **a;
void (*factivate)(Layer*);
int *w;
a = (void**)aux;
factivate = a[0];
w = a[1];
if (n == *w)
factivate(l);
}
void
clicklayer(Mouse m, void (*f)(Layer*))
{
void *aux[2];
int d;
aux[0] = f;
aux[1] = &d;
d = m.xy.y / layerheight;
foreachlayer(checkclick, aux);
}