245 lines
6.2 KiB
Zig
245 lines
6.2 KiB
Zig
backingAllocator: std.mem.Allocator,
|
|
arena: std.heap.ArenaAllocator,
|
|
inputEvents: std.AutoHashMapUnmanaged(NodeHandle, std.ArrayListUnmanaged(Listener)),
|
|
pressEvents: std.AutoHashMapUnmanaged(NodeHandle, std.ArrayListUnmanaged(PressedListener)),
|
|
|
|
const std = @import("std");
|
|
const papyrus = @import("papyrus.zig");
|
|
|
|
const NodeHandle = papyrus.NodeHandle;
|
|
const Context = papyrus.Context;
|
|
|
|
const RingQueueU = core.RingQueueU;
|
|
|
|
const core = @import("core");
|
|
const assertf = core.assertf;
|
|
|
|
pub const Key = enum(i32) {
|
|
Unknown = -1,
|
|
Space = 32,
|
|
Apostrophe = 39,
|
|
Comma = 44,
|
|
Period = 45,
|
|
Slash = 47,
|
|
@"0" = 48,
|
|
@"1" = 49,
|
|
@"2" = 50,
|
|
@"3" = 51,
|
|
@"4" = 52,
|
|
@"5" = 53,
|
|
@"6" = 54,
|
|
@"7" = 55,
|
|
@"8" = 56,
|
|
@"9" = 57,
|
|
Semicolon = 59,
|
|
Equal = 61,
|
|
A = 65,
|
|
B = 66,
|
|
C = 67,
|
|
D = 68,
|
|
E = 69,
|
|
F = 70,
|
|
G = 71,
|
|
H = 72,
|
|
I = 73,
|
|
J = 74,
|
|
K = 75,
|
|
L = 76,
|
|
M = 77,
|
|
N = 78,
|
|
O = 79,
|
|
P = 80,
|
|
Q = 81,
|
|
R = 82,
|
|
S = 83,
|
|
T = 84,
|
|
U = 85,
|
|
V = 86,
|
|
W = 87,
|
|
X = 88,
|
|
Y = 89,
|
|
Z = 90,
|
|
LeftBrackSq = 91,
|
|
BackSlash = 92,
|
|
RightBrackSq = 93,
|
|
Mouse1 = 10001,
|
|
Mouse2 = 10002,
|
|
Mouse3 = 10003,
|
|
Mouse4 = 10004,
|
|
Mouse5 = 10005,
|
|
_,
|
|
};
|
|
|
|
pub const Type = enum {
|
|
mouseOver,
|
|
mouseOff,
|
|
};
|
|
|
|
pub const PressedType = enum {
|
|
onPressed,
|
|
onReleased,
|
|
};
|
|
|
|
pub const HandlerError = error{
|
|
UnknownError,
|
|
EventPanic,
|
|
EventDropped,
|
|
EventIgnored,
|
|
};
|
|
|
|
pub const SingleFn = *const fn (NodeHandle, ?*anyopaque) HandlerError!void;
|
|
pub const PressedFn = *const fn (NodeHandle, PressedType, ?*anyopaque) HandlerError!void;
|
|
|
|
const Listener = struct {
|
|
node: NodeHandle,
|
|
event: Type,
|
|
context: ?*anyopaque,
|
|
eventFn: SingleFn,
|
|
innate: bool,
|
|
};
|
|
|
|
const PressedListener = struct {
|
|
node: NodeHandle,
|
|
keycode: Key,
|
|
event: PressedType,
|
|
context: ?*anyopaque,
|
|
eventFn: PressedFn,
|
|
innate: bool,
|
|
};
|
|
|
|
pub fn installMouseOverEventAdvanced(
|
|
self: *@This(),
|
|
node: NodeHandle,
|
|
event: Type,
|
|
context: ?*anyopaque,
|
|
eventFn: SingleFn,
|
|
innate: bool,
|
|
) !void {
|
|
const allocator = self.arena.allocator();
|
|
|
|
const listener: Listener = .{
|
|
.node = node,
|
|
.event = event,
|
|
.context = context,
|
|
.eventFn = eventFn,
|
|
.innate = innate,
|
|
};
|
|
|
|
if (self.inputEvents.getPtr(node)) |listenerList| {
|
|
try listenerList.append(allocator, listener);
|
|
} else {
|
|
var newListenerList: std.ArrayListUnmanaged(Listener) = .{};
|
|
try newListenerList.append(allocator, listener);
|
|
try self.inputEvents.put(allocator, node, newListenerList);
|
|
}
|
|
}
|
|
|
|
pub fn installMouseOverEvent(
|
|
self: *@This(),
|
|
node: NodeHandle,
|
|
event: Type,
|
|
context: ?*anyopaque,
|
|
eventFn: SingleFn,
|
|
) !void {
|
|
try installMouseOverEventAdvanced(self, node, event, context, eventFn, false);
|
|
}
|
|
|
|
pub fn pushMouseOverEvent(self: *@This(), node: NodeHandle, event: Type) HandlerError!void {
|
|
if (self.inputEvents.get(node)) |listeners| {
|
|
for (listeners.items) |listener| {
|
|
if (listener.event == event) {
|
|
try listener.eventFn(node, listener.context);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn pushPressedEvent(self: *@This(), node: NodeHandle, event: PressedType, keycode: Key) !void {
|
|
if (self.pressEvents.get(node)) |listeners| {
|
|
for (listeners.items) |listener| {
|
|
if (listener.event == event and keycode == listener.keycode) {
|
|
try listener.eventFn(node, event, listener.context);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn installOnPressedEventAdvanced(self: *@This(), node: NodeHandle, event: PressedType, keycode: Key, context: ?*anyopaque, eventFn: PressedFn, innate: bool) !void {
|
|
const listener: PressedListener = .{
|
|
.node = node,
|
|
.event = event,
|
|
.keycode = keycode,
|
|
.context = context,
|
|
.eventFn = eventFn,
|
|
.innate = innate,
|
|
};
|
|
|
|
const allocator = self.arena.allocator();
|
|
|
|
if (self.pressEvents.getPtr(node)) |listenerList| {
|
|
try listenerList.append(allocator, listener);
|
|
} else {
|
|
var newListenerList: std.ArrayListUnmanaged(PressedListener) = .{};
|
|
try newListenerList.append(allocator, listener);
|
|
try self.pressEvents.put(allocator, node, newListenerList);
|
|
}
|
|
}
|
|
|
|
pub fn installOnPressedEvent(self: *@This(), node: NodeHandle, event: PressedType, keycode: Key, context: ?*anyopaque, eventFn: PressedFn) !void {
|
|
try installOnPressedEventAdvanced(self, node, event, keycode, context, eventFn, false);
|
|
}
|
|
|
|
pub fn init(allocator: std.mem.Allocator) @This() {
|
|
return .{
|
|
.backingAllocator = allocator,
|
|
.arena = std.heap.ArenaAllocator.init(allocator),
|
|
.inputEvents = .{},
|
|
.pressEvents = .{},
|
|
};
|
|
}
|
|
|
|
pub fn deinit(self: *@This()) void {
|
|
self.arena.deinit();
|
|
}
|
|
|
|
pub fn uninstallAllEvents(self: *@This(), node: NodeHandle) !void {
|
|
try self.uninstallPressEvents(node);
|
|
try self.uninstallBasicEvents(node);
|
|
}
|
|
|
|
pub fn uninstallPressEvents(self: *@This(), node: NodeHandle) !void {
|
|
if (self.pressEvents.contains(node)) {
|
|
const allocator = self.arena.allocator();
|
|
var newList = std.ArrayListUnmanaged(PressedListener){};
|
|
var items = self.pressEvents.get(node).?;
|
|
for (items.items) |i| {
|
|
if (i.innate) {
|
|
try newList.append(allocator, i);
|
|
}
|
|
}
|
|
try self.pressEvents.put(allocator, node, newList);
|
|
items.deinit(allocator);
|
|
}
|
|
}
|
|
|
|
pub fn uninstallBasicEvents(self: *@This(), node: NodeHandle) !void {
|
|
if (self.inputEvents.contains(node)) {
|
|
const allocator = self.arena.allocator();
|
|
var newList = std.ArrayListUnmanaged(Listener){};
|
|
var items = self.inputEvents.get(node).?;
|
|
for (items.items) |i| {
|
|
if (i.innate) {
|
|
try newList.append(allocator, i);
|
|
}
|
|
}
|
|
try self.inputEvents.put(allocator, node, newList);
|
|
items.deinit(allocator);
|
|
}
|
|
}
|
|
|
|
// a more extreme version of uninstallAllEvents that purges even builtin events
|
|
pub fn uninstallAllEvents_OnDestroy(self: *@This(), node: NodeHandle) void {
|
|
_ = self.inputEvents.remove(node);
|
|
_ = self.pressEvents.remove(node);
|
|
}
|