From b5c5f4e3e2a77d5ef5efcf1cc4662d14b17a64d9 Mon Sep 17 00:00:00 2001 From: Yves Biener Date: Sat, 9 Nov 2024 14:29:55 +0100 Subject: [PATCH] feat(layout): fix compile errors for newly introduced layouts --- src/layout/Framing.zig | 56 +++++++++++++++------------ src/layout/HStack.zig | 86 +++++++++++++++++++++++++++--------------- src/layout/Padding.zig | 54 +++++++++++++++----------- src/layout/VStack.zig | 86 +++++++++++++++++++++++++++--------------- src/main.zig | 16 ++++++-- 5 files changed, 186 insertions(+), 112 deletions(-) diff --git a/src/layout/Framing.zig b/src/layout/Framing.zig index 7397337..9ea7abb 100644 --- a/src/layout/Framing.zig +++ b/src/layout/Framing.zig @@ -12,7 +12,7 @@ pub fn Layout(comptime Event: type) type { if (!isTaggedUnion(Event)) { @compileError("Provided user event `Event` for `Layout(comptime Event: type)` is not of type `union(enum)`."); } - const Element = union { + const Element = union(enum) { layout: @import("../layout.zig").Layout(Event), widget: @import("../widget.zig").Widget(Event), }; @@ -34,11 +34,18 @@ pub fn Layout(comptime Event: type) type { pub fn deinit(this: *@This()) void { this.contents.deinit(); - this.element.deinit(); this.events.deinit(); + switch ((&this.element).*) { + .layout => |*layout| { + layout.deinit(); + }, + .widget => |*widget| { + widget.deinit(); + }, + } } - pub fn handle(this: *@This(), event: Event) !*Event { + pub fn handle(this: *@This(), event: Event) !*Events { this.events.clearRetainingCapacity(); // order is important switch (event) { @@ -46,47 +53,48 @@ pub fn Layout(comptime Event: type) type { this.size = size; // adjust size according to the containing elements const sub_event = event; - switch (this.element) { - .layout => |layout| { - this.events.appendSlice(layout.handle(sub_event).items); + switch ((&this.element).*) { + .layout => |*layout| { + const events = try layout.handle(sub_event); + try this.events.appendSlice(events.items); }, - .widget => |widget| { + .widget => |*widget| { if (widget.handle(sub_event)) |e| { - this.events.append(e); + try this.events.append(e); } }, } }, else => { - for (this.elements.items) |element| { - switch (element) { - .layout => |layout| { - this.events.appendSlice(layout.handle(event).items); - }, - .widget => |widget| { - if (widget.handle(event)) |e| { - this.events.append(e); - } - }, - } + switch ((&this.element).*) { + .layout => |*layout| { + const events = try layout.handle(event); + try this.events.appendSlice(events.items); + }, + .widget => |*widget| { + if (widget.handle(event)) |e| { + try this.events.append(e); + } + }, } }, } + return &this.events; } pub fn content(this: *@This()) !*Contents { this.contents.clearRetainingCapacity(); - // TODO: frame contents - switch (this.element) { - .layout => |layout| { + // TODO: padding contents accordingly + switch ((&this.element).*) { + .layout => |*layout| { const layout_content = try layout.content(); try this.contents.appendSlice(layout_content.items); }, - .widget => |widget| { + .widget => |*widget| { try this.contents.appendSlice(try widget.content()); }, } - return &this.c; + return &this.contents; } }; } diff --git a/src/layout/HStack.zig b/src/layout/HStack.zig index 6fdfc26..87aeea6 100644 --- a/src/layout/HStack.zig +++ b/src/layout/HStack.zig @@ -12,9 +12,11 @@ pub fn Layout(comptime Event: type) type { if (!isTaggedUnion(Event)) { @compileError("Provided user event `Event` for `Layout(comptime Event: type)` is not of type `union(enum)`."); } - const Element = union { - layout: @import("../layout.zig").Layout(Event), - widget: @import("../widget.zig").Widget(Event), + const Widget = @import("../widget.zig").Widget(Event); + const Lay = @import("../layout.zig").Layout(Event); + const Element = union(enum) { + layout: Lay, + widget: Widget, }; const Elements = std.ArrayList(Element); const Events = std.ArrayList(Event); @@ -26,11 +28,30 @@ pub fn Layout(comptime Event: type) type { elements: Elements = undefined, events: Events = undefined, - // TODO: optional verdic argument for `Element`? - pub fn init(allocator: std.mem.Allocator) @This() { + pub fn init(allocator: std.mem.Allocator, children: anytype) @This() { + const ArgsType = @TypeOf(children); + const args_type_info = @typeInfo(ArgsType); + if (args_type_info != .Struct) { + @compileError("expected tuple or struct argument, found " ++ @typeName(ArgsType)); + } + const fields_info = args_type_info.Struct.fields; + var elements = Elements.initCapacity(allocator, fields_info.len) catch @panic("OOM"); + inline for (comptime fields_info) |field| { + const child = @field(children, field.name); + const ChildType = @TypeOf(child); + if (ChildType == Widget) { + elements.append(.{ .widget = child }) catch {}; + continue; + } + if (ChildType == Lay) { + elements.append(.{ .layout = child }) catch {}; + continue; + } + @compileError("child: " ++ field.name ++ " is not of type " ++ @typeName(Lay) ++ " or " ++ @typeName(Widget) ++ " but " ++ @typeName(ChildType)); + } return .{ .contents = Contents.init(allocator), - .elements = Elements.init(allocator), + .elements = elements, .events = Events.init(allocator), }; } @@ -38,72 +59,75 @@ pub fn Layout(comptime Event: type) type { pub fn deinit(this: *@This()) void { this.events.deinit(); this.contents.deinit(); - if (this.elements.items) |element| { - switch (element) { - .layout => |l| { - l.deinit(); + for (this.elements.items) |*element| { + switch (element.*) { + .layout => |*layout| { + layout.deinit(); }, - .widget => |w| { - w.deinit(); + .widget => |*widget| { + widget.deinit(); }, } } this.elements.deinit(); } - pub fn handle(this: *@This(), event: Event) !*Event { + pub fn handle(this: *@This(), event: Event) !*Events { this.events.clearRetainingCapacity(); // order is important switch (event) { .resize => |size| { this.size = size; // adjust size according to the containing elements - for (this.elements.items) |element| { + for (this.elements.items) |*element| { const sub_event = event; - switch (element) { - .layout => |l| { - this.events.appendSlice(l.handle(sub_event).items); + switch (element.*) { + .layout => |*layout| { + const events = try layout.handle(sub_event); + try this.events.appendSlice(events.items); }, - .widget => |w| { - if (w.handle(sub_event)) |e| { - this.events.append(e); + .widget => |*widget| { + if (widget.handle(sub_event)) |e| { + try this.events.append(e); } }, } } }, else => { - for (this.elements.items) |element| { - switch (element) { - .layout => |layout| { - this.events.appendSlice(layout.handle(event).items); + for (this.elements.items) |*element| { + switch (element.*) { + .layout => |*layout| { + const events = try layout.handle(event); + try this.events.appendSlice(events.items); }, - .widget => |widget| { + .widget => |*widget| { if (widget.handle(event)) |e| { - this.events.append(e); + try this.events.append(e); } }, } } }, } + return &this.events; } pub fn content(this: *@This()) !*Contents { this.contents.clearRetainingCapacity(); // TODO: concat contents accordingly to create a vertical stack - for (this.elements.items) |element| { - switch (element) { - .layout => |layout| { + for (this.elements.items) |*element| { + switch (element.*) { + .layout => |*layout| { const layout_content = try layout.content(); try this.contents.appendSlice(layout_content.items); }, - .widget => |widget| { + .widget => |*widget| { try this.contents.appendSlice(try widget.content()); }, } } - return &this.c; + return &this.contents; } }; } diff --git a/src/layout/Padding.zig b/src/layout/Padding.zig index c8aec73..ea32fa3 100644 --- a/src/layout/Padding.zig +++ b/src/layout/Padding.zig @@ -12,7 +12,7 @@ pub fn Layout(comptime Event: type) type { if (!isTaggedUnion(Event)) { @compileError("Provided user event `Event` for `Layout(comptime Event: type)` is not of type `union(enum)`."); } - const Element = union { + const Element = union(enum) { layout: @import("../layout.zig").Layout(Event), widget: @import("../widget.zig").Widget(Event), }; @@ -34,11 +34,18 @@ pub fn Layout(comptime Event: type) type { pub fn deinit(this: *@This()) void { this.contents.deinit(); - this.element.deinit(); this.events.deinit(); + switch ((&this.element).*) { + .layout => |*layout| { + layout.deinit(); + }, + .widget => |*widget| { + widget.deinit(); + }, + } } - pub fn handle(this: *@This(), event: Event) !*Event { + pub fn handle(this: *@This(), event: Event) !*Events { this.events.clearRetainingCapacity(); // order is important switch (event) { @@ -46,47 +53,48 @@ pub fn Layout(comptime Event: type) type { this.size = size; // adjust size according to the containing elements const sub_event = event; - switch (this.element) { - .layout => |layout| { - this.events.appendSlice(layout.handle(sub_event).items); + switch ((&this.element).*) { + .layout => |*layout| { + const events = try layout.handle(sub_event); + try this.events.appendSlice(events.items); }, - .widget => |widget| { + .widget => |*widget| { if (widget.handle(sub_event)) |e| { - this.events.append(e); + try this.events.append(e); } }, } }, else => { - for (this.elements.items) |element| { - switch (element) { - .layout => |layout| { - this.events.appendSlice(layout.handle(event).items); - }, - .widget => |widget| { - if (widget.handle(event)) |e| { - this.events.append(e); - } - }, - } + switch ((&this.element).*) { + .layout => |*layout| { + const events = try layout.handle(event); + try this.events.appendSlice(events.items); + }, + .widget => |*widget| { + if (widget.handle(event)) |e| { + try this.events.append(e); + } + }, } }, } + return &this.events; } pub fn content(this: *@This()) !*Contents { this.contents.clearRetainingCapacity(); // TODO: padding contents accordingly - switch (this.element) { - .layout => |layout| { + switch ((&this.element).*) { + .layout => |*layout| { const layout_content = try layout.content(); try this.contents.appendSlice(layout_content.items); }, - .widget => |widget| { + .widget => |*widget| { try this.contents.appendSlice(try widget.content()); }, } - return &this.c; + return &this.contents; } }; } diff --git a/src/layout/VStack.zig b/src/layout/VStack.zig index 25f481c..135dfb4 100644 --- a/src/layout/VStack.zig +++ b/src/layout/VStack.zig @@ -12,9 +12,11 @@ pub fn Layout(comptime Event: type) type { if (!isTaggedUnion(Event)) { @compileError("Provided user event `Event` for `Layout(comptime Event: type)` is not of type `union(enum)`."); } - const Element = union { - layout: @import("../layout.zig").Layout(Event), - widget: @import("../widget.zig").Widget(Event), + const Widget = @import("../widget.zig").Widget(Event); + const Lay = @import("../layout.zig").Layout(Event); + const Element = union(enum) { + layout: Lay, + widget: Widget, }; const Elements = std.ArrayList(Element); const Events = std.ArrayList(Event); @@ -26,11 +28,30 @@ pub fn Layout(comptime Event: type) type { elements: Elements = undefined, events: Events = undefined, - // TODO: optional verdic argument for `Element`? - pub fn init(allocator: std.mem.Allocator) @This() { + pub fn init(allocator: std.mem.Allocator, children: anytype) @This() { + const ArgsType = @TypeOf(children); + const args_type_info = @typeInfo(ArgsType); + if (args_type_info != .Struct) { + @compileError("expected tuple or struct argument, found " ++ @typeName(ArgsType)); + } + const fields_info = args_type_info.Struct.fields; + var elements = Elements.initCapacity(allocator, fields_info.len) catch @panic("OOM"); + inline for (comptime fields_info) |field| { + const child = @field(children, field.name); + const ChildType = @TypeOf(child); + if (ChildType == Widget) { + elements.append(.{ .widget = child }) catch {}; + continue; + } + if (ChildType == Lay) { + elements.append(.{ .layout = child }) catch {}; + continue; + } + @compileError("child: " ++ field.name ++ " is not of type " ++ @typeName(Lay) ++ " or " ++ @typeName(Widget) ++ " but " ++ @typeName(ChildType)); + } return .{ .contents = Contents.init(allocator), - .elements = Elements.init(allocator), + .elements = elements, .events = Events.init(allocator), }; } @@ -38,72 +59,75 @@ pub fn Layout(comptime Event: type) type { pub fn deinit(this: *@This()) void { this.events.deinit(); this.contents.deinit(); - if (this.elements.items) |element| { - switch (element) { - .layout => |l| { - l.deinit(); + for (this.elements.items) |*element| { + switch (element.*) { + .layout => |*layout| { + layout.deinit(); }, - .widget => |w| { - w.deinit(); + .widget => |*widget| { + widget.deinit(); }, } } this.elements.deinit(); } - pub fn handle(this: *@This(), event: Event) !*Event { + pub fn handle(this: *@This(), event: Event) !*Events { this.events.clearRetainingCapacity(); // order is important switch (event) { .resize => |size| { this.size = size; // adjust size according to the containing elements - for (this.elements.items) |element| { + for (this.elements.items) |*element| { const sub_event = event; - switch (element) { - .layout => |l| { - this.events.appendSlice(l.handle(sub_event).items); + switch (element.*) { + .layout => |*layout| { + const events = try layout.handle(sub_event); + try this.events.appendSlice(events.items); }, - .widget => |w| { - if (w.handle(sub_event)) |e| { - this.events.append(e); + .widget => |*widget| { + if (widget.handle(sub_event)) |e| { + try this.events.append(e); } }, } } }, else => { - for (this.elements.items) |element| { - switch (element) { - .layout => |layout| { - this.events.appendSlice(layout.handle(event).items); + for (this.elements.items) |*element| { + switch (element.*) { + .layout => |*layout| { + const events = try layout.handle(event); + try this.events.appendSlice(events.items); }, - .widget => |widget| { + .widget => |*widget| { if (widget.handle(event)) |e| { - this.events.append(e); + try this.events.append(e); } }, } } }, } + return &this.events; } pub fn content(this: *@This()) !*Contents { this.contents.clearRetainingCapacity(); // TODO: concat contents accordingly to create a vertical stack - for (this.elements.items) |element| { - switch (element) { - .layout => |layout| { + for (this.elements.items) |*element| { + switch (element.*) { + .layout => |*layout| { const layout_content = try layout.content(); try this.contents.appendSlice(layout_content.items); }, - .widget => |widget| { + .widget => |*widget| { try this.contents.appendSlice(try widget.content()); }, } } - return &this.c; + return &this.contents; } }; } diff --git a/src/main.zig b/src/main.zig index d3ba4db..71197b3 100644 --- a/src/main.zig +++ b/src/main.zig @@ -31,11 +31,21 @@ pub fn main() !void { const file = try std.fs.cwd().openFile("./src/main.zig", .{}); var rawText = App.Widget.RawText.init(allocator, file); - const widget = App.Widget.createFrom(&rawText); - var layout = App.Layout.Pane.init(allocator, widget); - defer layout.deinit(); // deinitializes the contained widget file.close(); + var framing = App.Layout.Framing.init(allocator, .{ + .widget = App.Widget.createFrom(&rawText), + }); + var vstack = App.Layout.VStack.init(allocator, .{ + App.Layout.createFrom(&framing), + }); + var hstack = App.Layout.HStack.init(allocator, .{ + App.Layout.createFrom(&vstack), + }); + + var layout = App.Layout.createFrom(&hstack); + defer layout.deinit(); + try app.start(); defer app.stop() catch unreachable;