//! Dynamic dispatch for layout implementations. //! Each layout should at last implement these functions: //! - handle(this: *@This(), event: Event) anyerror!*std.ArrayList(Event) {} //! - content(this: *@This()) anyerror!*std.ArrayList(u8) {} //! - deinit(this: *@This()) void {} //! //! Create a `Layout` using `createFrom(object: anytype)` and use them through //! the defined interface. The layout will take care of calling the correct //! implementation of the corresponding underlying type. //! //! Each `Layout` is responsible for clearing the allocated memory of the used //! widgets when deallocated. This means that `deinit()` will also deallocate //! every used widget too. const std = @import("std"); const lib_event = @import("event.zig"); pub fn Layout(comptime Event: type) type { if (!lib_event.isTaggedUnion(Event)) { @compileError("Provided user event `Event` for `Layout(comptime Event: type)` is not of type `union(enum)`."); } return struct { const LayoutType = @This(); const Ptr = usize; const VTable = struct { handle: *const fn (this: *LayoutType, event: Event) anyerror!*std.ArrayList(Event), content: *const fn (this: *LayoutType) anyerror!*std.ArrayList(u8), deinit: *const fn (this: *LayoutType) void, }; object: Ptr = undefined, vtable: *const VTable = undefined, // Handle the provided `Event` for this `Widget`. pub fn handle(this: *LayoutType, event: Event) !*std.ArrayList(Event) { return try this.vtable.handle(this, event); } // Return the entire content of this `Widget`. pub fn content(this: *LayoutType) !*std.ArrayList(u8) { return try this.vtable.content(this); } pub fn deinit(this: *LayoutType) void { this.vtable.deinit(this); this.* = undefined; } pub fn createFrom(object: anytype) LayoutType { return LayoutType{ .object = @intFromPtr(object), .vtable = &.{ .handle = struct { // Handle the provided `Event` for this `Widget`. fn handle(this: *LayoutType, event: Event) !*std.ArrayList(Event) { const layout: @TypeOf(object) = @ptrFromInt(this.object); return try layout.handle(event); } }.handle, .content = struct { // Return the entire content of this `Widget`. fn content(this: *LayoutType) !*std.ArrayList(u8) { const layout: @TypeOf(object) = @ptrFromInt(this.object); return try layout.content(); } }.content, .deinit = struct { fn deinit(this: *LayoutType) void { const layout: @TypeOf(object) = @ptrFromInt(this.object); layout.deinit(); } }.deinit, }, }; } // import and export of `Layout` implementations pub const Pane = @import("layout/Pane.zig").Layout(Event); }; }