ref: 13590f759547f4ef544b251f2966b4ed2d82038c
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; int numlayers = 0; 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; numlayers++; } 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, sr; data = (void**)aux; img = data[0]; active = data[1]; p = img->r.min; p.y += numlayers * layerheight; p.y -= n * layerheight; r.min = r.max = p; r.max.x += vdata.layerwinwidth; r.max.y += layerheight; sr.min = Pt(r.min.x, r.max.y); sr.max = r.max; if (l == active) { draw(img, r, vdata.gray, nil, ZP); } string(img, addpt(p, Pt(2, 2)), display->black, ZP, font, l->label); if (l == active && l->editor && l->editor->drawlwin) { r.min.y += vdata.fontheight; l->editor->drawlwin(l, img, r); } line(img, sr.min, sr.max, Endsquare, Endsquare, 0, display->black, ZP); } void redrawlayers(Image *img, Layer *active) { void *data[2]; data[0] = img; data[1] = active; layerheight = vdata.fontheight + 20; 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; Image *img; Event *ev; Layer *active; Redrawwin *ret; Rectangle r; a = (void**)aux; factivate = a[0]; w = a[1]; img = a[2]; ev = a[3]; active = a[4]; ret = a[5]; USED(img); if (n != *w) return; if (l != active) { factivate(l); return; } r.min = r.max = ZP; r.max.x = vdata.layerwinwidth; r.min.y += numlayers * layerheight; r.min.y -= n * layerheight; r.max.y = r.min.y + layerheight; r.min.y += vdata.fontheight; if (l->editor && l->editor->lwininput) { if (ptinrect(ev->mouse.xy, r)) { ev->mouse.xy.x -= r.min.x; ev->mouse.xy.y -= r.min.y; *ret |= l->editor->lwininput(l, Emouse, *ev); } } } Redrawwin clicklayer(Event ev, Layer *active, Image *img, void (*f)(Layer*)) { void *aux[6]; int d; Redrawwin result; aux[0] = f; aux[1] = &d; aux[2] = img; aux[3] = &ev; aux[4] = active; aux[5] = &result; result = Rnil; d = numlayers - ev.mouse.xy.y / layerheight; foreachlayer(checkclick, aux); return result; }