Some checks failed
Zig Project Action / Lint, Spell-check and test zig project (push) Failing after 4m26s
107 lines
4.9 KiB
Zig
107 lines
4.9 KiB
Zig
//! Dynamic dispatch for layout implementations. Each `Layout` has to implement
|
|
//! the `Layout.Interface`.
|
|
//!
|
|
//! Create a `Layout` using `createFrom(object: anytype)` and use them through
|
|
//! the defined `Layout.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
|
|
//! `Element`s (union of `Layout` or `Widget`) when deallocated. This means
|
|
//! that `deinit()` will also deallocate every used `Element` too.
|
|
//!
|
|
//! When `Layout.render` is called the provided `Renderer` type is expected
|
|
//! which handles how contents are rendered for a given layout.
|
|
const std = @import("std");
|
|
const isTaggedUnion = @import("event.zig").isTaggedUnion;
|
|
|
|
pub fn Layout(comptime Event: type, comptime Renderer: type) type {
|
|
if (!isTaggedUnion(Event)) {
|
|
@compileError("Provided user event `Event` for `Layout(comptime Event: type)` is not of type `union(enum)`.");
|
|
}
|
|
const Events = std.ArrayList(Event);
|
|
const Type = struct {
|
|
const LayoutType = @This();
|
|
const Element = union(enum) {
|
|
layout: LayoutType,
|
|
widget: @import("widget.zig").Widget(Event, Renderer),
|
|
};
|
|
pub const Interface = @import("interface").Interface(.{
|
|
.handle = fn (anytype, Event) anyerror!*Events,
|
|
.render = fn (anytype, *Renderer) anyerror!void,
|
|
.deinit = fn (anytype) void,
|
|
}, .{});
|
|
|
|
const VTable = struct {
|
|
handle: *const fn (this: *LayoutType, event: Event) anyerror!*Events,
|
|
render: *const fn (this: *LayoutType, renderer: *Renderer) anyerror!void,
|
|
deinit: *const fn (this: *LayoutType) void,
|
|
};
|
|
|
|
object: *anyopaque = undefined,
|
|
vtable: *const VTable = undefined,
|
|
|
|
// Handle the provided `Event` for this `Layout`.
|
|
pub fn handle(this: *LayoutType, event: Event) !*Events {
|
|
return try this.vtable.handle(this, event);
|
|
}
|
|
|
|
// Render this `Layout` completely. This will render contained sub-elements too.
|
|
pub fn render(this: *LayoutType, renderer: *Renderer) !void {
|
|
return try this.vtable.render(this, renderer);
|
|
}
|
|
|
|
pub fn deinit(this: *LayoutType) void {
|
|
this.vtable.deinit(this);
|
|
}
|
|
|
|
pub fn createFrom(object: anytype) LayoutType {
|
|
return LayoutType{
|
|
.object = @ptrCast(@alignCast(object)),
|
|
.vtable = &.{
|
|
.handle = struct {
|
|
// Handle the provided `Event` for this `Layout`.
|
|
fn handle(this: *LayoutType, event: Event) !*Events {
|
|
const layout: @TypeOf(object) = @ptrCast(@alignCast(this.object));
|
|
return try layout.handle(event);
|
|
}
|
|
}.handle,
|
|
.render = struct {
|
|
// Render the contents of this `Layout`.
|
|
fn render(this: *LayoutType, renderer: *Renderer) !void {
|
|
const layout: @TypeOf(object) = @ptrCast(@alignCast(this.object));
|
|
try layout.render(renderer);
|
|
}
|
|
}.render,
|
|
.deinit = struct {
|
|
fn deinit(this: *LayoutType) void {
|
|
const layout: @TypeOf(object) = @ptrCast(@alignCast(this.object));
|
|
layout.deinit();
|
|
}
|
|
}.deinit,
|
|
},
|
|
};
|
|
}
|
|
|
|
// import and export of `Layout` implementations
|
|
pub const HContainer = @import("layout/HContainer.zig").Layout(Event, Element, Renderer);
|
|
pub const HStack = @import("layout/HStack.zig").Layout(Event, Element, Renderer);
|
|
pub const VContainer = @import("layout/VContainer.zig").Layout(Event, Element, Renderer);
|
|
pub const VStack = @import("layout/VStack.zig").Layout(Event, Element, Renderer);
|
|
pub const Padding = @import("layout/Padding.zig").Layout(Event, Element, Renderer);
|
|
pub const Margin = @import("layout/Margin.zig").Layout(Event, Element, Renderer);
|
|
pub const Framing = @import("layout/Framing.zig").Layout(Event, Element, Renderer);
|
|
pub const Tab = @import("layout/Tab.zig").Layout(Event, Element, Renderer);
|
|
};
|
|
// test layout implementation satisfies the interface
|
|
comptime Type.Interface.satisfiedBy(Type);
|
|
comptime Type.Interface.satisfiedBy(Type.HContainer);
|
|
comptime Type.Interface.satisfiedBy(Type.HStack);
|
|
comptime Type.Interface.satisfiedBy(Type.VContainer);
|
|
comptime Type.Interface.satisfiedBy(Type.VStack);
|
|
comptime Type.Interface.satisfiedBy(Type.Padding);
|
|
comptime Type.Interface.satisfiedBy(Type.Margin);
|
|
comptime Type.Interface.satisfiedBy(Type.Framing);
|
|
comptime Type.Interface.satisfiedBy(Type.Tab);
|
|
return Type;
|
|
}
|