shithub: pain

ref: 0cd1f6455c02fe0c2ade3e630debb315f054b253
dir: /bindings.c/

View raw version
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <event.h>

#include "dat.h"
#include "fns.h"

Binding * BindingRoot = nil;

typedef struct DefaultBinding
{
	int type;
	int code;
	char * command;
	void (*func)(int);
} DefaultBinding;

// made with
// grep '^Binding[a-zA-Z][a-zA-Z]*' bindings.c | sed 's/^(.*)$/static void \1;/g'
static void BindingQuit(int);
static void BindingStroke(int e);
static void BindingZoomIn(int);
static void BindingZoomOut(int);
static void BindingMoveCanvas(int e);
static void BindingMoveLayer(int e);
static void BindingClearLayer(int e);
static void BindingSwitchMode(int);
static void BindingResetCanvas(int);
static void BindingResetCurrentLayer(int);

static void
BindingQuit(int)
{
	quitloop();
}

static void
BindingStroke(int e)
{
	if (e == BEleave)
	{
		if (CurrentLayer != nil)
			CurrentLayer->changed = 1;
		return;
	}

	stroke();
}

static void
BindingZoomIn(int)
{
	zoom(ZoomSensitivity);
}

static void
BindingZoomOut(int)
{
	zoom(-ZoomSensitivity);
}

static void
BindingMoveCanvas(int e)
{
	static Point MoveMark = {0};
	static int movetask = -1;
	if (e == BEenter)
		MoveMark = MousePosition;
	else if (e == BEleave) {
		CanvasAt = addpt(CanvasAt, subpt(MousePosition, MoveMark));
		CanvasMoved = DrawAllLayers = 1;
	}
}

static void
BindingMoveLayer(int e)
{
	static Point MoveMark = {0};
	static int movetask = -1;
	if (e == BEenter)
		MoveMark = MousePosition;
	else if (e == BEleave && CurrentLayer != nil) {
		CurrentLayer->offset = addpt(CurrentLayer->offset, 
			subpt(MoveMark, MousePosition));
		CurrentLayer->changed = 1;
		clearview();
	}
}

static void
BindingClearLayer(int)
{
	if (CurrentLayer != nil && newlayerimage(CurrentLayer))
		sysfatal("newlayerimage: %r");
	clearview();
}

static void
BindingSwitchMode(int)
{
	static int mode = 0;
	Binding * bm, * br;
	char * s;

	removebindings(BMouse, 2);
	removebindings(BKeyboard, 'r');
	if ((bm = addbinding(BMouse, 2)) == nil)
		sysfatal("addbinding: %r");
	if ((br = addbinding(BKeyboard, 'r')) == nil)
		sysfatal("addbinding: %r");
	s = "";
	switch(mode)
	{
		case 0:
			bm->func = BindingMoveLayer;
			br->func = BindingResetCurrentLayer;
			s = "layer";
			mode = 1;
			break;
		case 1:
			bm->func = BindingMoveCanvas;
			br->func = BindingResetCanvas;
			s = "canvas";
			mode = 0;
			break;
	}
	ntfprint("changed to %s mode\n", s);
}

static void
BindingResetCanvas(int)
{
	TargetZoom = 1;
	applyzoom();
	CanvasAt = Pt(0, 0);
	centercanvas();
}

static void
BindingResetCurrentLayer(int)
{
	if (CurrentLayer == nil)
		return;
	CurrentLayer->offset = Pt(0, 0);
	clearview();
}

static void
BindingNewLayer(int)
{
	newlayer();
}

static void
BindingNextLayer(int)
{
	setcurrentlayer(CurrentLayer->next);
}

static void
BindingPreviousLayer(int)
{
	setcurrentlayer(CurrentLayer->prev);
}

static void
BindingDeleteCurrentLayer(int)
{
	ntfprint("not yet implemented");
}

static void
BindingSave(int)
{
	int fd;
	char s[32];

	snprint(s, 32, "/tmp/pain.XXXXXX");
	mktemp(s);
	fd = create(s, OWRITE, 0755);
	if (fd < 0) {
		ntfprint("failed to save image to %s", s);
	}
	writeimage(fd, ViewImage, 0);
	close(fd);
	ntfprint("current canvas saved to %s", s);
}

DefaultBinding DefaultBindings[] = 
{
	{BKeyboard, 'q', nil, BindingQuit},
	{BKeyboard, 'c', nil, BindingClearLayer},
	{BKeyboard, 'm', nil, BindingSwitchMode},
	{BKeyboard, 'r', nil, BindingResetCanvas},
	{BKeyboard, 'n', nil, BindingNewLayer},
	{BKeyboard, 'd', nil, BindingDeleteCurrentLayer},
	{BKeyboard, 'o', nil, BindingPreviousLayer},
	{BKeyboard, 'p', nil, BindingNextLayer},
	{BKeyboard, 's', nil, BindingSave},
	{BMouse, 1, nil, BindingStroke},
	{BMouse, 8, nil, BindingZoomIn},
	{BMouse, 16, nil, BindingZoomOut},
	{BMouse, 2, nil, BindingMoveCanvas}
};

void
freebinding(Binding * b)
{
	if (b == nil)
		return;
	if (b->command != nil)
		free(b->command);

	free(b);
}

int
removebindings(int type, int code)
{
	int rc;
	Binding * e, * n;
	
	rc = 0;
	for (e = BindingRoot; e != nil; e = n) {
		if (e->type != type || e->code != code) {
			n = e->next;
			continue;
		}
		if (e->prev != nil)
			e->prev->next = e->next;
		if (e->next != nil)
			e->next->prev = e->prev;
		n = e->next;
		freebinding(e);
		if (e == BindingRoot)
			BindingRoot = e->next;
		rc++;
	}
	
	return rc;
}

Binding *
addbinding(int type, int code)
{
	Binding * b, * e;

	if ((b = calloc(sizeof(Binding), 1)) == nil) {
		werrstr("failed to allocate Binding");
		return nil;
	}
	b->next = b->prev = nil;
	
	b->type = type;
	b->code = code;
	b->state = BEleave;
	if (BindingRoot != nil) {
		for (e = BindingRoot; e->next != nil; e = e->next)
			;
		e->next = b;
		b->prev = e;
	} else
		BindingRoot = b;

	return b;
}

int
runbindings(int type, int code)
{
	int rc;
	int e;
	Binding * b;
	// print("handling bindings for %d %d\n", type,code);

	rc = 0;
	for (b = BindingRoot; b != nil; b = b->next) {
		if (b->type != type)
			continue;
		
		e = b->type == BKeyboard ? BEenter : BEleave;
		if (b->code != code) {
			if (b->state == BEleave || b->type == BKeyboard)
				continue;
		} else if(b->type == BMouse) {
			switch (b->state) {
				case BEenter:
					e = BEin;
					break;
				case BEin:
					e = BEin;
					break;
				case BEleave:
					e = BEenter;
					break;
				default:
					werrstr("invalid state");
					break;
			}
		}
		
		b->state = e;
		if (b->func != nil)
			b->func(e);
		if (b->command != nil)
			NOOP();	// TODO: Add shell command support
		rc++;
	}
	return rc;
}

Binding *
adduniquebinding(int type, int code)
{
	removebindings(type, code);
	return addbinding(type, code);
}

void
setdefaultbindings()
{
	int i;
	Binding * b;
	DefaultBinding * db;
	
	for (i = 0; i < ARRLEN(DefaultBindings); i++) {
		db = &DefaultBindings[i];
		if ((b = addbinding(db->type, db->code)) == nil)
			sysfatal("addbinding: %r");
	
		if (db->command != nil)
			b->command = strdup(db->command);
		if (db->func != nil)
			b->func = db->func;
	}
}