diff --git a/src/Element.zig b/src/Element.zig index f7430b1..808e37c 100644 --- a/src/Element.zig +++ b/src/Element.zig @@ -19,26 +19,26 @@ pub const Interface = struct { destroy: *const fn (?*anyopaque) void, minimum_size: *const fn (?*anyopaque, RenderResources) [2]f32, render: *const fn (?*anyopaque, *seizer.Canvas, RenderResources, [2]f32, [2]f32) void, - get_actions: *const fn (?*anyopaque, *std.ArrayList(Action), RenderResources, [2]f32, [2]f32) Error!void, + event: *const fn (?*anyopaque, Event) ?Command, }; pub const RenderResources = struct { - hovered: ?Element.Command, + hovered: bool, deck: DeckSprites, font: seizer.Canvas.Font, }; -pub const Action = struct { - center: [2]f32, - command: Command, +pub const Event = union(enum) { + up, + right, + down, + left, + activate, }; pub const Command = union(enum) { + none, goto_reference: protocol.Reference, - callback: struct { - pointer: ?*anyopaque, - function: *const fn (?*anyopaque) void, - }, }; const DeckSprites = assets.DeckSprites; diff --git a/src/Element/HBox.zig b/src/Element/HBox.zig index 0770aee..0405d22 100644 --- a/src/Element/HBox.zig +++ b/src/Element/HBox.zig @@ -1,5 +1,6 @@ allocator: std.mem.Allocator, children: std.ArrayListUnmanaged(Element), +hovered: usize, pub fn create(allocator: std.mem.Allocator) !*@This() { const this = try allocator.create(@This()); @@ -7,6 +8,7 @@ pub fn create(allocator: std.mem.Allocator) !*@This() { this.* = .{ .allocator = allocator, .children = .{}, + .hovered = 0, }; return this; } @@ -22,7 +24,7 @@ pub fn element(this: *@This()) Element { .destroy = &element_destroy, .minimum_size = &element_minimum_size, .render = &element_render, - .get_actions = &element_get_actions, + .event = &element_event, }, }; } @@ -76,50 +78,45 @@ pub fn element_render(pointer: ?*anyopaque, canvas: *seizer.Canvas, render_resou const space_around = empty_space / @as(f32, @floatFromInt(num_spaces)); var x: f32 = min[0] + @max(space_around, 0); - for (this.children.items) |child| { + for (this.children.items, 0..) |child, child_index| { const child_size = child.interface.minimum_size(child.pointer, render_resources); const child_min = [2]f32{ x, min[1] }; const child_max = [2]f32{ x + child_size[0], max[1] }; - child.interface.render(child.pointer, canvas, render_resources, child_min, child_max); + var child_render_resources = render_resources; + child_render_resources.hovered = render_resources.hovered and child_index == this.hovered; + child.interface.render(child.pointer, canvas, child_render_resources, child_min, child_max); x += child_size[0] + space_around; } } -pub fn element_get_actions(pointer: ?*anyopaque, actions: *std.ArrayList(Element.Action), render_resources: Element.RenderResources, min: [2]f32, max: [2]f32) Element.Error!void { +pub fn element_activate(pointer: ?*anyopaque) ?Element.Command { const this: *@This() = @ptrCast(@alignCast(pointer)); - if (this.children.items.len == 0) return; + if (this.hovered >= this.children.items.len) return null; + const hovered = this.children.items[this.hovered]; + return hovered.interface.activate(hovered.pointer); +} - const parent_size = [2]f32{ - max[0] - min[0], - max[1] - min[1], +pub fn element_event(pointer: ?*anyopaque, event: Element.Event) ?Element.Command { + const this: *@This() = @ptrCast(@alignCast(pointer)); + + if (this.hovered < this.children.items.len) { + const hovered = this.children.items[this.hovered]; + if (hovered.interface.event(hovered.pointer, event)) |cmd| { + return cmd; + } + } + + const new_hovered: usize = switch (event) { + .right => if (this.hovered < this.children.items.len - 1) this.hovered + 1 else return null, + .left => if (this.hovered > 0) this.hovered - 1 else return null, + else => return null, }; - - var filled_space: f32 = 0; - for (this.children.items) |child| { - const child_size = child.interface.minimum_size(child.pointer, render_resources); - - filled_space += child_size[0]; - } - - const empty_space = parent_size[0] - filled_space; - - const space_around = empty_space / @as(f32, @floatFromInt((this.children.items.len + 1))); - - var x: f32 = min[0] + space_around; - for (this.children.items) |child| { - const child_size = child.interface.minimum_size(child.pointer, render_resources); - - const child_min = [2]f32{ x, min[1] }; - const child_max = [2]f32{ x + child_size[0], max[1] }; - - try child.interface.get_actions(child.pointer, actions, render_resources, child_min, child_max); - - x += child_size[0] + space_around; - } + this.hovered = new_hovered; + return Element.Command.none; } const Element = @import("../Element.zig"); diff --git a/src/Element/Link.zig b/src/Element/Link.zig index 5e62361..e6922c0 100644 --- a/src/Element/Link.zig +++ b/src/Element/Link.zig @@ -21,7 +21,7 @@ pub fn element(this: *@This()) Element { .destroy = &element_destroy, .minimum_size = &element_minimum_size, .render = &element_render, - .get_actions = &element_get_actions, + .event = &element_event, }, }; } @@ -44,7 +44,7 @@ pub fn element_render(pointer: ?*anyopaque, canvas: *seizer.Canvas, render_resou this.child.interface.render(this.child.pointer, canvas, render_resources, min, max); // render selection indicator on top if this link is selected - if (render_resources.hovered != null and std.meta.eql(render_resources.hovered.?, Element.Command{ .goto_reference = this.reference })) { + if (render_resources.hovered) { canvas.rect( .{ min[0], min[1] }, .{ max[0] - min[0], max[1] - min[1] }, @@ -53,18 +53,13 @@ pub fn element_render(pointer: ?*anyopaque, canvas: *seizer.Canvas, render_resou } } -pub fn element_get_actions(pointer: ?*anyopaque, actions: *std.ArrayList(Element.Action), render_resources: Element.RenderResources, min: [2]f32, max: [2]f32) Element.Error!void { +pub fn element_event(pointer: ?*anyopaque, event: Element.Event) ?Element.Command { const this: *@This() = @ptrCast(@alignCast(pointer)); - _ = render_resources; - - try actions.append(.{ - .center = [2]f32{ - (min[0] + max[0]) / 2, - (min[1] + max[1]) / 2, - }, - .command = .{ .goto_reference = this.reference }, - }); + switch (event) { + .activate => return Element.Command{ .goto_reference = this.reference }, + else => return null, + } } const Element = @import("../Element.zig"); diff --git a/src/Element/Page.zig b/src/Element/Page.zig index 3522608..2d992cb 100644 --- a/src/Element/Page.zig +++ b/src/Element/Page.zig @@ -1,5 +1,6 @@ allocator: std.mem.Allocator, children: std.ArrayListUnmanaged(Child), +hovered: usize, pub const Child = struct { /// Where is the child attached on the parent? Imagine it as a pin going through @@ -25,6 +26,7 @@ pub fn create(allocator: std.mem.Allocator) !*@This() { this.* = .{ .allocator = allocator, .children = .{}, + .hovered = 0, }; return this; } @@ -44,7 +46,7 @@ pub fn element(this: *@This()) Element { .destroy = &element_destroy, .minimum_size = &element_minimum_size, .render = &element_render, - .get_actions = &element_get_actions, + .event = &element_event, }, }; } @@ -82,7 +84,7 @@ pub fn element_render(pointer: ?*anyopaque, canvas: *seizer.Canvas, render_resou max[1] - min[1], }; - for (this.children.items) |child| { + for (this.children.items, 0..) |child, child_index| { const pos_in_parent = [2]f32{ child.anchor_in_parent[0] * parent_size[0], child.anchor_in_parent[1] * parent_size[1], @@ -104,41 +106,69 @@ pub fn element_render(pointer: ?*anyopaque, canvas: *seizer.Canvas, render_resou @min(max[1], pos_in_parent[1] + (child_size[1] - pos_in_child[1])), }; - child.element.interface.render(child.element.pointer, canvas, render_resources, child_min, child_max); + var child_render_resources = render_resources; + child_render_resources.hovered = render_resources.hovered and child_index == this.hovered; + + child.element.interface.render(child.element.pointer, canvas, child_render_resources, child_min, child_max); } } -pub fn element_get_actions(pointer: ?*anyopaque, actions: *std.ArrayList(Element.Action), render_resources: Element.RenderResources, min: [2]f32, max: [2]f32) Element.Error!void { +pub fn element_event(pointer: ?*anyopaque, event: Element.Event) ?Element.Command { const this: *@This() = @ptrCast(@alignCast(pointer)); - const parent_size = [2]f32{ - max[0] - min[0], - max[1] - min[1], + if (this.hovered < this.children.items.len) { + const hovered = this.children.items[this.hovered].element; + if (hovered.interface.event(hovered.pointer, event)) |cmd| { + return cmd; + } + } + + const direction: [2]f32 = switch (event) { + .up => .{ 0, -1 }, + .right => .{ 1, 0 }, + .down => .{ 0, 1 }, + .left => .{ -1, 0 }, + else => return null, }; - for (this.children.items) |child| { - const pos_in_parent = [2]f32{ - child.anchor_in_parent[0] * parent_size[0], - child.anchor_in_parent[1] * parent_size[1], - }; + const current_center: [2]f32 = if (this.hovered < this.children.items.len) this.children.items[this.hovered].anchor_in_parent else .{ 0.5, 0.5 }; - const child_size = child.element.interface.minimum_size(child.element.pointer, render_resources); + var new_distance: ?f32 = null; + var new_hovered: ?usize = null; + for (this.children.items, 0..) |child, child_index| { + if (child_index == this.hovered) { + continue; + } + if (distanceToAction(current_center, direction, child.anchor_in_parent)) |distance| { + if (new_distance == null or (new_distance != null and distance < new_distance.?)) { + new_hovered = child_index; + new_distance = distance; + } + } + } - const pos_in_child = [2]f32{ - child.anchor_in_child[0] * child_size[0], - child.anchor_in_child[1] * child_size[1], - }; + if (new_hovered) |h| { + this.hovered = h; + return Element.Command.none; + } + return null; +} - const child_min = [2]f32{ - pos_in_parent[0] - pos_in_child[0], - pos_in_parent[1] - pos_in_child[1], - }; - const child_max = [2]f32{ - pos_in_parent[0] + (child_size[0] - pos_in_child[0]), - pos_in_parent[1] + (child_size[1] - pos_in_child[1]), - }; +fn distanceToAction(origin: [2]f32, direction: [2]f32, other_pos: [2]f32) ?f32 { + const off_axis_dir = [2]f32{ direction[1], -direction[0] }; + const offset = [2]f32{ + other_pos[0] - origin[0], + other_pos[1] - origin[1], + }; - try child.element.interface.get_actions(child.element.pointer, actions, render_resources, child_min, child_max); + // use dot product to check how in line with each direction the point of interest is + const in_axis_distance = offset[0] * direction[0] + offset[1] * direction[1]; + const off_axis_distance = offset[0] * off_axis_dir[0] + offset[1] * off_axis_dir[1]; + + if (in_axis_distance > 0) { + return in_axis_distance + off_axis_distance * off_axis_distance; + } else { + return null; } } diff --git a/src/Element/Text.zig b/src/Element/Text.zig index 5323c3b..3663f47 100644 --- a/src/Element/Text.zig +++ b/src/Element/Text.zig @@ -22,7 +22,7 @@ pub fn element(this: *@This()) Element { .destroy = &element_destroy, .minimum_size = &element_minimum_size, .render = &element_render, - .get_actions = &element_get_actions, + .event = &element_event, }, }; } @@ -46,12 +46,11 @@ pub fn element_render(pointer: ?*anyopaque, canvas: *seizer.Canvas, render_resou _ = canvas.writeText(min, this.text, .{}); } -pub fn element_get_actions(pointer: ?*anyopaque, actions: *std.ArrayList(Element.Action), render_resources: Element.RenderResources, min: [2]f32, max: [2]f32) Element.Error!void { - _ = pointer; - _ = actions; - _ = render_resources; - _ = min; - _ = max; +pub fn element_event(pointer: ?*anyopaque, event: Element.Event) ?Element.Command { + const this: *@This() = @ptrCast(@alignCast(pointer)); + _ = this; + _ = event; + return null; } const Element = @import("../Element.zig"); diff --git a/src/Element/View.zig b/src/Element/View.zig index 26d900e..ac96afb 100644 --- a/src/Element/View.zig +++ b/src/Element/View.zig @@ -1,30 +1,27 @@ allocator: std.mem.Allocator, reference: protocol.Reference, + +handler_pointer: ?*anyopaque, response: ?protocol.Response, -link_actions_in_view: std.AutoHashMapUnmanaged(*LinkProxy, void) = .{}, - const View = @This(); -const LinkProxy = struct { - view: *View, - reference: protocol.Reference, - - fn callback(pointer: ?*anyopaque) void { - const this: *@This() = @ptrCast(@alignCast(pointer)); - - this.view.setReference(this.reference); - } -}; - pub fn create(allocator: std.mem.Allocator, reference: protocol.Reference) !*@This() { const this = try allocator.create(@This()); errdefer allocator.destroy(this); + var handler_pointer: ?*anyopaque = null; + switch (reference) { + .handler => |interface| if (interface.create) |handler_create| { + handler_pointer = try handler_create(allocator); + }, + } + this.* = .{ .allocator = allocator, .reference = reference, .response = null, + .handler_pointer = handler_pointer, }; return this; } @@ -35,13 +32,18 @@ pub fn setReference(this: *@This(), reference: protocol.Reference) void { this.response = null; } + switch (this.reference) { + .handler => |interface| if (interface.deinit) |deinit| deinit(this.handler_pointer), + } + this.handler_pointer = null; + this.reference = reference; - var action_proxies_iter = this.link_actions_in_view.keyIterator(); - while (action_proxies_iter.next()) |link_proxy| { - this.allocator.destroy(link_proxy.*); + switch (this.reference) { + .handler => |interface| if (interface.create) |handler_create| { + this.handler_pointer = handler_create(this.allocator) catch unreachable; + }, } - this.link_actions_in_view.clearRetainingCapacity(); } pub fn element(this: *@This()) Element { @@ -51,7 +53,7 @@ pub fn element(this: *@This()) Element { .destroy = &element_destroy, .minimum_size = &element_minimum_size, .render = &element_render, - .get_actions = &element_get_actions, + .event = &element_event, }, }; } @@ -67,14 +69,8 @@ pub fn element_destroy(pointer: ?*anyopaque) void { response.arena.deinit(); } - var action_proxies_iter = this.link_actions_in_view.keyIterator(); - while (action_proxies_iter.next()) |link_proxy| { - this.allocator.destroy(link_proxy.*); - } - this.link_actions_in_view.deinit(this.allocator); - switch (this.reference) { - .handler => |handler| if (handler.interface.deinit) |deinit| deinit(handler.pointer), + .handler => |interface| if (interface.deinit) |deinit| deinit(this.handler_pointer), } this.allocator.destroy(this); @@ -95,7 +91,7 @@ pub fn element_render(pointer: ?*anyopaque, canvas: *seizer.Canvas, render_resou const this: *@This() = @ptrCast(@alignCast(pointer)); if (this.response == null) { - this.response = this.reference.handler.interface.handle(this.reference.handler.pointer, .{ + this.response = this.reference.handler.handle(this.handler_pointer, .{ .allocator = this.allocator, }) catch response_error: { std.log.warn("Could not get response", .{}); @@ -104,70 +100,29 @@ pub fn element_render(pointer: ?*anyopaque, canvas: *seizer.Canvas, render_resou } if (this.response) |response| { - var child_render_resources = render_resources; - - if (render_resources.hovered) |hovered| { - switch (hovered) { - .callback => |cb| { - if (this.link_actions_in_view.getKey(@ptrCast(@alignCast(cb.pointer)))) |link_proxy| { - child_render_resources.hovered = .{ .goto_reference = link_proxy.reference }; - } - }, - else => {}, - } - } - switch (response.body) { - .element => |root| root.interface.render(root.pointer, canvas, child_render_resources, min, max), + .element => |root| root.interface.render(root.pointer, canvas, render_resources, min, max), } } else { _ = canvas.writeText(min, LOADING_TEXT, .{}); } } -pub fn element_get_actions(pointer: ?*anyopaque, actions: *std.ArrayList(Element.Action), render_resources: Element.RenderResources, min: [2]f32, max: [2]f32) Element.Error!void { +pub fn element_event(pointer: ?*anyopaque, event: Element.Event) ?Element.Command { const this: *@This() = @ptrCast(@alignCast(pointer)); - // clean up previous link actions - var action_proxies_iter = this.link_actions_in_view.keyIterator(); - while (action_proxies_iter.next()) |link_proxy| { - this.allocator.destroy(link_proxy.*); - } - this.link_actions_in_view.clearRetainingCapacity(); - - var children_actions = std.ArrayList(Element.Action).init(this.allocator); - defer children_actions.deinit(); - if (this.response) |response| { switch (response.body) { - .element => |root| { - try root.interface.get_actions(root.pointer, &children_actions, render_resources, min, max); + .element => |root| if (root.interface.event(root.pointer, event)) |cmd| switch (cmd) { + .none => return Element.Command.none, + .goto_reference => |ref| { + this.setReference(ref); + }, }, } } - for (children_actions.items) |child_action| { - switch (child_action.command) { - .goto_reference => |ref| { - const link_proxy_action = try this.allocator.create(LinkProxy); - try this.link_actions_in_view.put(this.allocator, link_proxy_action, {}); - link_proxy_action.* = .{ - .view = this, - .reference = ref, - }; - try actions.append(.{ - .center = child_action.center, - .command = .{ - .callback = .{ - .pointer = link_proxy_action, - .function = &LinkProxy.callback, - }, - }, - }); - }, - .callback => try actions.append(child_action), - } - } + return null; } const Element = @import("../Element.zig"); diff --git a/src/LocalUI.zig b/src/LocalUI.zig index db6c22e..4b63b97 100644 --- a/src/LocalUI.zig +++ b/src/LocalUI.zig @@ -1,9 +1,7 @@ -pub const main_menu = Handler{ - .pointer = null, - .interface = &.{ - .handle = &main_menu_handler, - .deinit = null, - }, +pub const main_menu = &Handler.Interface{ + .create = null, + .handle = &main_menu_handler, + .deinit = null, }; fn main_menu_handler(_: ?*anyopaque, request: Request) Handler.Error!Response { @@ -26,12 +24,10 @@ fn main_menu_handler(_: ?*anyopaque, request: Request) Handler.Error!Response { return Response{ .arena = arena, .body = .{ .element = page.element() } }; } -pub const join_multiplayer_game = Handler{ - .pointer = null, - .interface = &.{ - .handle = &join_multiplayer_game_handler, - .deinit = null, - }, +pub const join_multiplayer_game = &Handler.Interface{ + .create = null, + .handle = &join_multiplayer_game_handler, + .deinit = null, }; fn join_multiplayer_game_handler(_: ?*anyopaque, request: Request) Handler.Error!Response { @@ -46,12 +42,10 @@ fn join_multiplayer_game_handler(_: ?*anyopaque, request: Request) Handler.Error return Response{ .arena = arena, .body = .{ .element = page.element() } }; } -pub const host_multiplayer_game = Handler{ - .pointer = null, - .interface = &.{ - .handle = &host_multiplayer_game_handler, - .deinit = null, - }, +pub const host_multiplayer_game = &Handler.Interface{ + .create = null, + .handle = &host_multiplayer_game_handler, + .deinit = null, }; fn host_multiplayer_game_handler(_: ?*anyopaque, request: Request) Handler.Error!Response { diff --git a/src/c.zig b/src/c.zig new file mode 100644 index 0000000..2942881 --- /dev/null +++ b/src/c.zig @@ -0,0 +1,4 @@ +pub usingnamespace @cImport({ + @cInclude("enet/enet.h"); + @cInclude("mdns.h"); +}); diff --git a/src/main.zig b/src/main.zig index 03d4a1a..217581b 100644 --- a/src/main.zig +++ b/src/main.zig @@ -187,12 +187,6 @@ pub fn main() !void { const main_view = try Element.View.create(gpa.allocator(), .{ .handler = LocalUI.main_menu }); defer main_view.element().interface.destroy(main_view.element().pointer); - var actions = std.ArrayList(Element.Action).init(gpa.allocator()); - defer actions.deinit(); - - // TODO: Restore hovered_action when undoing - var hovered_action: ?Element.Action = null; - if (seizer.backend.glfw.c.glfwJoystickIsGamepad(seizer.backend.glfw.c.GLFW_JOYSTICK_1) != 0) { std.log.info("detected gamepad = \"{?s}\" {?s}", .{ seizer.backend.glfw.c.glfwGetGamepadName(seizer.backend.glfw.c.GLFW_JOYSTICK_1), seizer.backend.glfw.c.glfwGetJoystickGUID(seizer.backend.glfw.c.GLFW_JOYSTICK_1) }); } else if (seizer.backend.glfw.c.glfwJoystickPresent(seizer.backend.glfw.c.GLFW_JOYSTICK_1) != 0) { @@ -276,58 +270,49 @@ pub fn main() !void { prev_controller_input_state = controller_input_state; } - if (hovered_action) |hovered| { - if (input_state.action) { - switch (hovered.command) { - .goto_reference => { - std.debug.panic("Got `.goto_reference` action at top-level; expected `main_view` to proxy them all into LinkProxy callbacks.", .{}); - }, - .callback => |cb| { - cb.function(cb.pointer); - }, - } - } - } else if (actions.items.len > 0) { - hovered_action = actions.items[0]; - } + if (input_state.up) _ = main_view.element().interface.event(main_view.element().pointer, .up); + if (input_state.right) _ = main_view.element().interface.event(main_view.element().pointer, .right); + if (input_state.down) _ = main_view.element().interface.event(main_view.element().pointer, .down); + if (input_state.left) _ = main_view.element().interface.event(main_view.element().pointer, .left); + if (input_state.action) _ = main_view.element().interface.event(main_view.element().pointer, .activate); - if (hovered_action) |hovered| { - var direction = [2]f32{ 0, 0 }; - if (input_state.left) { - direction[0] -= 1; - } - if (input_state.right) { - direction[0] += 1; - } - if (input_state.up) { - direction[1] -= 1; - } - if (input_state.down) { - direction[1] += 1; - } + // if (hovered_action) |hovered| { + // var direction = [2]f32{ 0, 0 }; + // if (input_state.left) { + // direction[0] -= 1; + // } + // if (input_state.right) { + // direction[0] += 1; + // } + // if (input_state.up) { + // direction[1] -= 1; + // } + // if (input_state.down) { + // direction[1] += 1; + // } - var new_distance: ?f32 = null; - var new_action = hovered; - for (actions.items) |action| { - if (std.meta.eql(action.command, hovered.command)) { - continue; - } - if (distanceToAction(hovered.center, direction, action.center)) |distance| { - if (new_distance == null or (new_distance != null and distance < new_distance.?)) { - new_action = Element.Action{ - .center = .{ - if (input_state.left or input_state.right) action.center[0] else hovered.center[0], - if (input_state.up or input_state.down) action.center[1] else hovered.center[1], - }, - .command = action.command, - }; - new_distance = distance; - } - } - } + // var new_distance: ?f32 = null; + // var new_action = hovered; + // for (actions.items) |action| { + // if (std.meta.eql(action.command, hovered.command)) { + // continue; + // } + // if (distanceToAction(hovered.center, direction, action.center)) |distance| { + // if (new_distance == null or (new_distance != null and distance < new_distance.?)) { + // new_action = Element.Action{ + // .center = .{ + // if (input_state.left or input_state.right) action.center[0] else hovered.center[0], + // if (input_state.up or input_state.down) action.center[1] else hovered.center[1], + // }, + // .command = action.command, + // }; + // new_distance = distance; + // } + // } + // } - hovered_action = new_action; - } + // hovered_action = new_action; + // } gl.clearColor(0.7, 0.5, 0.5, 1.0); gl.clear(gl.COLOR_BUFFER_BIT); @@ -373,7 +358,7 @@ pub fn main() !void { main_view.element().pointer, &canvas, .{ - .hovered = if (hovered_action) |ha| ha.command else null, + .hovered = true, .deck = deck_sprites, .font = canvas.font, }, @@ -384,27 +369,9 @@ pub fn main() !void { }, ); - _ = canvas.printText(.{ 0, 0 }, "#actions = {}", .{actions.items.len}, .{}); - canvas.end(); seizer.backend.glfw.c.glfwSwapBuffers(window); - - actions.clearRetainingCapacity(); - try main_view.element().interface.get_actions( - main_view.element().pointer, - &actions, - .{ - .hovered = if (hovered_action) |ha| ha.command else null, - .deck = deck_sprites, - .font = canvas.font, - }, - .{ 0, 0 }, - .{ - @floatFromInt(window_size[0]), - @floatFromInt(window_size[1]), - }, - ); } } diff --git a/src/protocol.zig b/src/protocol.zig index 31cf8e5..ad0f2ac 100644 --- a/src/protocol.zig +++ b/src/protocol.zig @@ -5,13 +5,14 @@ pub const Handler = struct { pub const Error = error{OutOfMemory}; pub const Fn = *const fn (Request) Error!Response; pub const Interface = struct { + create: ?*const fn (std.mem.Allocator) Error!?*anyopaque, handle: *const fn (?*anyopaque, Request) Error!Response, deinit: ?*const fn (?*anyopaque) void, }; }; pub const Reference = union(enum) { - handler: Handler, + handler: *const Handler.Interface, }; pub const Request = struct {