shithub: pain

ref: 434c6ce50a65ecfdfc4e537edbb2ed4f50da6312
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;
static Point MoveMark = {0};

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

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

static void
BindingStroke(int e)
{
	if (e != BEenter)
		return;

	stroke();
}

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

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

static void
movecanvas(void)
{
	CanvasAt = addpt(CanvasAt, subpt(MousePosition, MoveMark));
	CanvasMoved = DrawAllLayers = 1;
}

static void
BindingMoveCanvas(int e)
{
	static int movetask = -1;
	if (e != BEenter)
		return;
	MoveMark = MousePosition;
	removetask(movetask);
	movetask = newtask(msec() + 250, movecanvas);
}

DefaultBinding DefaultBindings[] = 
{
	{BKeyboard, 'q', nil, BindingQuit},
	{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 = nil;
		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;
	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 || b->code != code) {
			if (b->type == type && b->state != BEleave && b->func != nil)
				b->func(b->state = BEleave);				
			continue;
		}
		
		e = BEleave;
		switch (b->state) {
			case BEenter:
				e = BEin;
				break;
			case BEin:
				e = BEin;
				break;
			case BEleave:
				e = BEenter;
				break;
			default:
				werrstr("invalid state");
				break;
		}
		
		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;
	}
}