ref: da5ef81858616aa4cd9bd350b2de30a8553330a3
dir: /blie.c/
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <memdraw.h>
#include <event.h>
#include <keyboard.h>
#include <cursor.h>
#include <bio.h>
#include "blie.h"
void
usage(void)
{
fprint(2, "usage: %s [-cd] dir\n", argv0);
exits(nil);
}
int bliedebug = 0;
char Nlayers[] = "layers";
char *root = nil;
Vdata vdata = {
.layerwinwidth = 150,
.keyoffset = 10,
.keyzoom = 0.2,
};
Vstate vstate = {
.zoom = 1.0,
.offset = { 0, 0 },
};
static void
initvdata(void)
{
Point p;
p = stringsize(font, "|H");
vdata.fontheight = p.y;
vdata.gray = allocimagemix(display, DBlack, DWhite);
}
typedef struct Estate Estate;
struct Estate {
Editor *ed;
Layer *l;
};
Estate estate;
typedef struct Dstate Dstate;
struct Dstate {
Cursor *cursor;
Image *cursimg;
Image *cursorblit;
Point bloffset;
Point curoffset;
};
Dstate dstate;
typedef struct Panels Panels;
struct Panels {
Image *tools;
Image *layers;
Image *drawing;
};
Panels panels;
Screen *scr;
void
changecursor(Cursor *c, Image *i, Point off)
{
dstate.cursor = c;
dstate.cursimg = i;
dstate.curoffset = off;
}
int
loadfile(void)
{
Biobuf *b;
int fd;
char *s;
b = Bopen(Nlayers, OREAD);
if (!b) {
fd = create(Nlayers, OREAD, 0666);
close(fd);
b = Bopen(Nlayers, OREAD);
}
if (!b)
sysfatal("unable to open layers file: %r");
while (s = Brdstr(b, '\n', 1))
addlayer(s);
return 1;
}
static void
docomp(Layer *l, int id, void *aux)
{
int i;
Memimage **img = (Memimage**)aux;
Editor *ed = l->editor;
i = (id + 1)%2;
if (bliedebug)
fprint(2, "composite: %s\n", l->name);
if (ed->composite)
img[id%2] = ed->composite(l, img[i]);
else
img[id%2] = ecomposite(l, img[i]);
freememimage(img[i]);
img[i] = nil;
}
void
outputcomposite(void)
{
Memimage *img[2]; /* swapchain */
int i;
img[0] = nil;
img[1] = nil;
i = foreachlayer(docomp, img);
if (img[i%2])
writememimage(1, img[i%2]);
else
writememimage(1, img[(i+1)%2]);
}
static void
redrawdrawing(void)
{
Memimage *img[2]; /* swapchain */
int i;
img[0] = nil;
img[1] = nil;
i = (foreachlayer(docomp, img) + 1) % 2;
sampleview(panels.drawing, img[i]);
if (!(estate.ed && estate.ed->overlay))
return;
estate.ed->overlay(estate.l, panels.drawing);
}
static void
redrawtools(void)
{
if (estate.ed) {
estate.ed->drawtools(estate.l, panels.tools);
} else {
draw(panels.tools, panels.tools->r, display->white, nil, ZP);
}
}
static void
redraw(void)
{
redrawlayers(panels.layers, estate.l);
line(panels.layers, panels.layers->r.min,
Pt(panels.layers->r.min.x, panels.layers->r.max.y),
Endsquare, Endsquare, 0, display->black, ZP);
redrawdrawing();
redrawtools();
line(panels.tools,
Pt(panels.tools->r.min.x, panels.tools->r.max.y-1),
subpt(panels.tools->r.max, Pt(0, 1)),
Endsquare, Endsquare, 0, display->black, ZP);
}
static void
screeninit(void)
{
Rectangle tr;
freescreen(scr);
scr = allocscreen(screen, display->black, 0);
freeimage(panels.tools);
freeimage(panels.layers);
freeimage(panels.drawing);
if (estate.ed) {
tr = rectaddpt(estate.ed->toolrect(estate.l), screen->r.min);
tr.max.x = screen->r.max.x;
} else {
tr = screen->r;
tr.max.y = tr.min.y + 10;
}
panels.tools = allocwindow(scr, tr, 0, 0xCCCCCCFF);
tr.min.y = tr.max.y;
tr.min.x = screen->r.max.x - vdata.layerwinwidth;
tr.max = screen->r.max;
panels.layers = allocwindow(scr, tr, 0, 0xCCCCCCFF);
tr.min.x = screen->r.min.x;
tr.min.y = panels.tools->r.max.y;
tr.max.x = panels.layers->r.min.x;
tr.max.y = screen->r.max.y;
panels.drawing = allocwindow(scr, tr, 0, 0xCC00CCFF);
flushimage(display, 1);
}
void
eresized(int new)
{
if (new && getwindow(display, Refnone) < 0)
sysfatal("resize failed: %r");
screeninit();
redraw();
}
static void
activatelayer(Layer *l)
{
estate.ed = l->editor;
estate.l = l;
screeninit();
redraw();
}
static void
drawcursor(Point xy, int hide)
{
Rectangle r;
if (dstate.cursorblit) {
draw(screen, dstate.cursorblit->r, dstate.cursorblit, nil,
dstate.cursorblit->r.min);
freeimage(dstate.cursorblit);
dstate.cursorblit = nil;
}
if (hide || !dstate.cursimg)
return;
r = dstate.cursimg->r;
r = rectaddpt(r, addpt(xy, dstate.curoffset));
dstate.cursorblit = allocimage(display, r, screen->chan, 0, DWhite);
drawop(dstate.cursorblit, dstate.cursorblit->r, screen, nil, dstate.cursorblit->r.min, S);
drawop(screen, r, dstate.cursimg, nil, ZP, SoverD);
#ifdef NOP /* debug display */
drawop(screen, screen->r, dstate.cursimg, nil, ZP, SoverD);
drawop(screen, screen->r, dstate.cursorblit, nil,
addpt(Pt(-50, 0), dstate.cursorblit->r.min), S);
#endif
}
static void
handlemouse(Event ev)
{
int n;
Point xy;
Mouse *m = &ev.mouse;
xy = m->xy;
n = 0;
if (ptinrect(m->xy, panels.layers->r)) {
esetcursor(nil);
drawcursor(m->xy, 1);
if (m->buttons) {
m->xy = subpt(m->xy, panels.layers->r.min);
clicklayer(*m, activatelayer);
}
return;
}
if (estate.ed && ptinrect(m->xy, panels.tools->r)) {
esetcursor(nil);
drawcursor(m->xy, 1);
m->xy = subpt(m->xy, panels.tools->r.min);
if (estate.ed->toolinput)
n = estate.ed->toolinput(estate.l, Emouse, ev);
switch (n) {
case 1:
redrawdrawing();
break;
case 2:
redrawtools();
break;
case 3:
redraw();
break;
}
return;
}
if (estate.ed && ptinrect(m->xy, panels.drawing->r)) {
m->xy = subpt(m->xy, panels.drawing->r.min);
if (estate.ed->drawinput)
n = estate.ed->drawinput(estate.l, Emouse, ev);
switch (n) {
case 1:
redrawdrawing();
break;
case 2:
redrawtools();
break;
case 3:
redraw();
break;
}
esetcursor(dstate.cursor);
drawcursor(xy, 0);
return;
}
}
/* return 1 = handled */
static int
handledrawingkey(int kbdc)
{
switch (kbdc) {
case Kup:
vstate.offset.y += vdata.keyoffset;
goto Redraw;
case Kdown:
vstate.offset.y -= vdata.keyoffset;
goto Redraw;
case Kleft:
vstate.offset.x += vdata.keyoffset;
goto Redraw;
case Kright:
vstate.offset.x -= vdata.keyoffset;
goto Redraw;
case '.':
vstate.zoom += vdata.keyzoom;
goto Redraw;
case ',':
vstate.zoom -= vdata.keyzoom;
goto Redraw;
}
return 0;
Redraw:
redrawdrawing();
return 1;
}
static void
handlekeyboard(Event ev)
{
Mouse *m = &ev.mouse;
/* global keys */
switch (ev.kbdc) {
case 'q':
case Kdel:
exits(nil);
}
if (ptinrect(m->xy, panels.layers->r)) {
/* functionality: delete layer, add layer, change layer */
/*
l - label (prompt)
a - add new layer (prompt editor, name, label)
d - delete layer
pgup - move layer up
pgdn - move layer down
*/
return;
}
if (estate.ed && ptinrect(m->xy, panels.tools->r)) {
m->xy = subpt(m->xy, panels.tools->r.min);
if (estate.ed->toolinput)
estate.ed->toolinput(estate.l, Ekeyboard, ev);
return;
}
if (ptinrect(m->xy, panels.drawing->r)) {
if (handledrawingkey(ev.kbdc))
return;
if (estate.ed && estate.ed->drawinput) {
m->xy = subpt(m->xy, panels.drawing->r.min);
estate.ed->drawinput(estate.l, Ekeyboard, ev);
}
return;
}
}
void
main(int argc, char **argv)
{
int outputonly = 0;
Event ev;
int e;
ARGBEGIN{
case 'c':
outputonly++;
break;
case 'd':
bliedebug++;
break;
}ARGEND;
root = "";
if (argc) {
root = argv[0];
}
rfork(RFNAMEG);
if (chdir(root))
sysfatal("cannot chdir: %r");
if (memimageinit())
sysfatal("memimageinit: %r");
loadeditors();
if (!loadfile())
sysfatal("cannot load data: %r");
if (outputonly) {
outputcomposite();
exits(nil);
}
if (initdraw(nil, nil, "blie") < 0)
sysfatal("initdraw: %r");
einit(Emouse|Ekeyboard);
initvdata();
estate.ed = nil;
estate.l = nil;
screeninit();
redraw();
for (;;) {
e = event(&ev);
switch (e) {
case Emouse:
handlemouse(ev);
break;
case Ekeyboard:
handlekeyboard(ev);
break;
}
}
}