diff --git a/examples/continuous.zig b/examples/continuous.zig index 2c737cc..49f1f55 100644 --- a/examples/continuous.zig +++ b/examples/continuous.zig @@ -231,8 +231,8 @@ pub fn main() !void { } } - container.resize(try renderer.resize()); - container.reposition(.{}); + container.resize(&app.model, try renderer.resize()); + container.reposition(&app.model, .{}); try renderer.render(@TypeOf(container), &container, App.Model, &app.model); try renderer.flush(); } diff --git a/examples/demo.zig b/examples/demo.zig index 7d7c253..b9d1ae3 100644 --- a/examples/demo.zig +++ b/examples/demo.zig @@ -182,8 +182,8 @@ pub fn main() !void { else => {}, } - container.resize(try renderer.resize()); - container.reposition(.{}); + container.resize(&app.model, try renderer.resize()); + container.reposition(&app.model, .{}); try renderer.render(@TypeOf(container), &container, App.Model, &app.model); try renderer.flush(); } diff --git a/examples/elements/alignment.zig b/examples/elements/alignment.zig index 604e477..9238cfe 100644 --- a/examples/elements/alignment.zig +++ b/examples/elements/alignment.zig @@ -86,8 +86,8 @@ pub fn main() !void { else => {}, } - container.resize(try renderer.resize()); - container.reposition(.{}); + container.resize(&app.model, try renderer.resize()); + container.reposition(&app.model, .{}); try renderer.render(@TypeOf(container), &container, App.Model, &app.model); try renderer.flush(); } diff --git a/examples/elements/button.zig b/examples/elements/button.zig index a070001..57f250b 100644 --- a/examples/elements/button.zig +++ b/examples/elements/button.zig @@ -135,8 +135,8 @@ pub fn main() !void { else => {}, } - container.resize(try renderer.resize()); - container.reposition(.{}); + container.resize(&app.model, try renderer.resize()); + container.reposition(&app.model, .{}); try renderer.render(@TypeOf(container), &container, App.Model, &app.model); try renderer.flush(); } diff --git a/examples/elements/input.zig b/examples/elements/input.zig index 61cf21b..bf76603 100644 --- a/examples/elements/input.zig +++ b/examples/elements/input.zig @@ -149,8 +149,8 @@ pub fn main() !void { else => {}, } - container.resize(try renderer.resize()); - container.reposition(.{}); + container.resize(&app.model, try renderer.resize()); + container.reposition(&app.model, .{}); try renderer.render(@TypeOf(container), &container, App.Model, &app.model); try renderer.flush(); } diff --git a/examples/elements/progress.zig b/examples/elements/progress.zig index 5d48ef9..4b63a7f 100644 --- a/examples/elements/progress.zig +++ b/examples/elements/progress.zig @@ -155,8 +155,8 @@ pub fn main() !void { } } - container.resize(try renderer.resize()); - container.reposition(.{}); + container.resize(&app.model, try renderer.resize()); + container.reposition(&app.model, .{}); try renderer.render(@TypeOf(container), &container, App.Model, &app.model); try renderer.flush(); } diff --git a/examples/elements/radio-button.zig b/examples/elements/radio-button.zig index 6b23fda..c4264c6 100644 --- a/examples/elements/radio-button.zig +++ b/examples/elements/radio-button.zig @@ -83,8 +83,8 @@ pub fn main() !void { else => {}, } - container.resize(try renderer.resize()); - container.reposition(.{}); + container.resize(&app.model, try renderer.resize()); + container.reposition(&app.model, .{}); try renderer.render(@TypeOf(container), &container, App.Model, &app.model); try renderer.flush(); } diff --git a/examples/elements/scrollable.zig b/examples/elements/scrollable.zig index 99c8d2e..821b693 100644 --- a/examples/elements/scrollable.zig +++ b/examples/elements/scrollable.zig @@ -184,8 +184,8 @@ pub fn main() !void { else => {}, } - container.resize(try renderer.resize()); - container.reposition(.{}); + container.resize(&app.model, try renderer.resize()); + container.reposition(&app.model, .{}); try renderer.render(@TypeOf(container), &container, App.Model, &app.model); try renderer.flush(); } diff --git a/examples/elements/selection.zig b/examples/elements/selection.zig index 61c5716..8d68e2f 100644 --- a/examples/elements/selection.zig +++ b/examples/elements/selection.zig @@ -83,8 +83,8 @@ pub fn main() !void { else => {}, } - container.resize(try renderer.resize()); - container.reposition(.{}); + container.resize(&app.model, try renderer.resize()); + container.reposition(&app.model, .{}); try renderer.render(@TypeOf(container), &container, App.Model, &app.model); try renderer.flush(); } diff --git a/examples/errors.zig b/examples/errors.zig index 0e67d22..e557d5c 100644 --- a/examples/errors.zig +++ b/examples/errors.zig @@ -146,8 +146,8 @@ pub fn main() !void { else => {}, } - container.resize(try renderer.resize()); - container.reposition(.{}); + container.resize(&app.model, try renderer.resize()); + container.reposition(&app.model, .{}); try renderer.render(@TypeOf(container), &container, App.Model, &app.model); try renderer.flush(); } diff --git a/examples/layouts/grid.zig b/examples/layouts/grid.zig index 225c4a7..c85383f 100644 --- a/examples/layouts/grid.zig +++ b/examples/layouts/grid.zig @@ -102,8 +102,8 @@ pub fn main() !void { else => {}, } - container.resize(try renderer.resize()); - container.reposition(.{}); + container.resize(&app.model, try renderer.resize()); + container.reposition(&app.model, .{}); try renderer.render(@TypeOf(container), &container, App.Model, &app.model); try renderer.flush(); } diff --git a/examples/layouts/horizontal.zig b/examples/layouts/horizontal.zig index 534870c..70db90c 100644 --- a/examples/layouts/horizontal.zig +++ b/examples/layouts/horizontal.zig @@ -94,8 +94,8 @@ pub fn main() !void { else => {}, } - container.resize(try renderer.resize()); - container.reposition(.{}); + container.resize(&app.model, try renderer.resize()); + container.reposition(&app.model, .{}); try renderer.render(@TypeOf(container), &container, App.Model, &app.model); try renderer.flush(); } diff --git a/examples/layouts/mixed.zig b/examples/layouts/mixed.zig index 1bad8c8..a29da15 100644 --- a/examples/layouts/mixed.zig +++ b/examples/layouts/mixed.zig @@ -110,8 +110,8 @@ pub fn main() !void { else => {}, } - container.resize(try renderer.resize()); - container.reposition(.{}); + container.resize(&app.model, try renderer.resize()); + container.reposition(&app.model, .{}); try renderer.render(@TypeOf(container), &container, App.Model, &app.model); try renderer.flush(); } diff --git a/examples/layouts/vertical.zig b/examples/layouts/vertical.zig index d1a56c6..dddc618 100644 --- a/examples/layouts/vertical.zig +++ b/examples/layouts/vertical.zig @@ -93,8 +93,8 @@ pub fn main() !void { else => {}, } - container.resize(try renderer.resize()); - container.reposition(.{}); + container.resize(&app.model, try renderer.resize()); + container.reposition(&app.model, .{}); try renderer.render(@TypeOf(container), &container, App.Model, &app.model); try renderer.flush(); } diff --git a/examples/styles/palette.zig b/examples/styles/palette.zig index 64359c0..300e5f2 100644 --- a/examples/styles/palette.zig +++ b/examples/styles/palette.zig @@ -89,8 +89,8 @@ pub fn main() !void { else => {}, } - container.resize(try renderer.resize()); - container.reposition(.{}); + container.resize(&app.model, try renderer.resize()); + container.reposition(&app.model, .{}); try renderer.render(@TypeOf(container), &container, App.Model, &app.model); try renderer.flush(); } diff --git a/examples/styles/text.zig b/examples/styles/text.zig index 7013fc4..a6c8b88 100644 --- a/examples/styles/text.zig +++ b/examples/styles/text.zig @@ -117,7 +117,7 @@ const TextStyles = struct { }; } - fn minSize(ctx: *anyopaque, size: zterm.Point) zterm.Point { + fn minSize(ctx: *anyopaque, _: *const App.Model, size: zterm.Point) zterm.Point { _ = ctx; _ = size; return .{ @@ -253,8 +253,8 @@ pub fn main() !void { } } - container.resize(try renderer.resize()); - container.reposition(.{}); + container.resize(&app.model, try renderer.resize()); + container.reposition(&app.model, .{}); try renderer.render(@TypeOf(container), &container, App.Model, &app.model); try renderer.flush(); } diff --git a/src/container.zig b/src/container.zig index c15496c..df5c6d4 100644 --- a/src/container.zig +++ b/src/container.zig @@ -654,10 +654,10 @@ pub fn Container(Model: type, Event: type) type { try this.elements.append(this.allocator, element); } - pub fn reposition(this: *@This(), origin: Point) void { + pub fn reposition(this: *@This(), model: *const Model, origin: Point) void { const layout = this.properties.layout; this.origin = origin; - this.element.reposition(origin); + this.element.reposition(model, origin); var offset = origin.add(.{ .x = Layout.getAbsolutePadding(layout.padding.left, this.size.x), @@ -669,7 +669,7 @@ pub fn Container(Model: type, Event: type) type { if (sides.top) offset.y += 1; for (this.elements.items) |*child| { - child.reposition(offset); + child.reposition(model, offset); switch (layout.direction) { .horizontal => offset.x += child.size.x + layout.gap, @@ -739,7 +739,7 @@ pub fn Container(Model: type, Event: type) type { } /// growable implicitly requires the root `Container` to have a set a size property to the size of the available terminal screen - fn grow_resize(this: *@This(), max_size: Point) void { + fn grow_resize(this: *@This(), model: *const Model, max_size: Point) void { const layout = this.properties.layout; var remainder = switch (layout.direction) { .horizontal => max_size.x -| (Layout.getAbsolutePadding(layout.padding.left, this.size.x) + Layout.getAbsolutePadding(layout.padding.right, this.size.x)), @@ -881,11 +881,11 @@ pub fn Container(Model: type, Event: type) type { } } - this.element.resize(this.size); - for (this.elements.items) |*child| child.grow_resize(child.size); + this.element.resize(model, this.size); + for (this.elements.items) |*child| child.grow_resize(model, child.size); } - pub fn resize(this: *@This(), size: Point) void { + pub fn resize(this: *@This(), model: *const Model, size: Point) void { // NOTE assume that this function is only called for the root `Container` this.size = size; const fit_size = this.fit_resize(); @@ -902,7 +902,7 @@ pub fn Container(Model: type, Event: type) type { .y = @max(size.y, fit_size.y), }, } - this.grow_resize(this.size); + this.grow_resize(model, this.size); } pub fn handle(this: *const @This(), model: *Model, event: Event) !void { diff --git a/src/element.zig b/src/element.zig index 2b5699c..a47e756 100644 --- a/src/element.zig +++ b/src/element.zig @@ -15,9 +15,9 @@ pub fn Element(Model: type, Event: type) type { vtable: *const VTable = &.{}, pub const VTable = struct { - minSize: ?*const fn (ctx: *anyopaque, size: Point) Point = null, - resize: ?*const fn (ctx: *anyopaque, size: Point) void = null, - reposition: ?*const fn (ctx: *anyopaque, origin: Point) void = null, + minSize: ?*const fn (ctx: *anyopaque, model: *const Model, size: Point) Point = null, + resize: ?*const fn (ctx: *anyopaque, model: *const Model, size: Point) void = null, + reposition: ?*const fn (ctx: *anyopaque, model: *const Model, origin: Point) void = null, handle: ?*const fn (ctx: *anyopaque, model: *Model, event: Event) anyerror!void = null, content: ?*const fn (ctx: *anyopaque, model: *const Model, cells: []Cell, size: Point) anyerror!void = null, }; @@ -35,9 +35,9 @@ pub fn Element(Model: type, Event: type) type { /// Currently only used for `Scrollable` elements, such that the /// directly nested element in the `Scrollable`'s `Container` can /// request a minimal size for its contents. - pub inline fn minSize(this: @This(), size: Point) Point { + pub inline fn minSize(this: @This(), model: *const Model, size: Point) Point { if (this.vtable.minSize) |minSize_fn| { - const min_size = minSize_fn(this.ptr, size); + const min_size = minSize_fn(this.ptr, model, size); return .{ .x = @max(size.x, min_size.x), .y = @max(size.y, min_size.y), @@ -46,15 +46,15 @@ pub fn Element(Model: type, Event: type) type { } /// Resize the corresponding `Element` with the given *size*. - pub inline fn resize(this: @This(), size: Point) void { + pub inline fn resize(this: @This(), model: *const Model, size: Point) void { if (this.vtable.resize) |resize_fn| - resize_fn(this.ptr, size); + resize_fn(this.ptr, model, size); } /// Reposition the corresponding `Element` with the given *origin*. - pub inline fn reposition(this: @This(), origin: Point) void { + pub inline fn reposition(this: @This(), model: *const Model, origin: Point) void { if (this.vtable.reposition) |reposition_fn| - reposition_fn(this.ptr, origin); + reposition_fn(this.ptr, model, origin); } /// Handle the received event. The event is one of the user provided @@ -161,13 +161,13 @@ pub fn Alignment(Model: type, Event: type) type { }; } - fn resize(ctx: *anyopaque, size: Point) void { + fn resize(ctx: *anyopaque, model: *const Model, size: Point) void { const this: *@This() = @ptrCast(@alignCast(ctx)); this.size = size; - this.container.resize(size); + this.container.resize(model, size); } - fn reposition(ctx: *anyopaque, anchor: Point) void { + fn reposition(ctx: *anyopaque, model: *const Model, anchor: Point) void { const this: *@This() = @ptrCast(@alignCast(ctx)); var origin = anchor; origin.x = switch (this.configuration.h) { @@ -180,7 +180,7 @@ pub fn Alignment(Model: type, Event: type) type { .center => origin.y + (this.size.y / 2) -| (this.container.size.y / 2), .end => this.size.y -| this.container.size.y, }; - this.container.reposition(origin); + this.container.reposition(model, origin); } fn handle(ctx: *anyopaque, model: *Model, event: Event) !void { @@ -270,13 +270,13 @@ pub fn Scrollable(Model: type, Event: type) type { }; } - fn resize(ctx: *anyopaque, size: Point) void { + fn resize(ctx: *anyopaque, model: *const Model, size: Point) void { const this: *@This() = @ptrCast(@alignCast(ctx)); const last_max_anchor_x = this.container_size.x -| this.size.x; const last_max_anchor_y = this.container_size.y -| this.size.y; // NOTE `container_size` denotes the `size` required for the container contents - var container_size = this.container.element.minSize(size); + var container_size = this.container.element.minSize(model, size); if (this.configuration.scrollbar) { this.configuration.y_axis = this.container.properties.size.dim.x > size.x or container_size.x > size.x; this.configuration.x_axis = this.container.properties.size.dim.y > size.y or container_size.y > size.y; @@ -287,7 +287,7 @@ pub fn Scrollable(Model: type, Event: type) type { // NOTE this call is at this point required as the container size // may also be defined through the `Container`'s `Properties`, which // may define a dimension (for static layouts) - this.container.resize(container_size); // notify the container about the minimal size it should have + this.container.resize(model, container_size); // notify the container about the minimal size it should have // update the calculated size of the container container_size = this.container.size; @@ -302,9 +302,9 @@ pub fn Scrollable(Model: type, Event: type) type { this.container_size = container_size; } - fn reposition(ctx: *anyopaque, _: Point) void { + fn reposition(ctx: *anyopaque, model: *const Model, _: Point) void { const this: *@This() = @ptrCast(@alignCast(ctx)); - this.container.reposition(.{}); + this.container.reposition(model, .{}); } fn handle(ctx: *anyopaque, model: *Model, event: Event) !void { @@ -1140,8 +1140,8 @@ test "scrollable vertical" { var renderer: testing.Renderer = .init(allocator, size); defer renderer.deinit(); - container.resize(size); - container.reposition(.{}); + container.resize(&.{}, size); + container.reposition(&.{}, .{}); try renderer.render(@TypeOf(container), &container, Model, &.{}); try testing.expectEqualCells(.{}, renderer.size, @import("test/element/scrollable.vertical.top.zon"), renderer.screen); @@ -1257,8 +1257,8 @@ test "scrollable vertical with scrollbar" { var renderer: testing.Renderer = .init(allocator, size); defer renderer.deinit(); - container.resize(size); - container.reposition(.{}); + container.resize(&.{}, size); + container.reposition(&.{}, .{}); try renderer.render(@TypeOf(container), &container, Model, &.{}); try testing.expectEqualCells(.{}, renderer.size, @import("test/element/scrollable.vertical.scrollbar.top.zon"), renderer.screen); @@ -1337,8 +1337,8 @@ test "scrollable horizontal" { var renderer: testing.Renderer = .init(allocator, size); defer renderer.deinit(); - container.resize(size); - container.reposition(.{}); + container.resize(&.{}, size); + container.reposition(&.{}, .{}); try renderer.render(@TypeOf(container), &container, Model, &.{}); try testing.expectEqualCells(.{}, renderer.size, @import("test/element/scrollable.horizontal.left.zon"), renderer.screen); @@ -1417,8 +1417,8 @@ test "scrollable horizontal with scrollbar" { var renderer: testing.Renderer = .init(allocator, size); defer renderer.deinit(); - container.resize(size); - container.reposition(.{}); + container.resize(&.{}, size); + container.reposition(&.{}, .{}); try renderer.render(@TypeOf(container), &container, Model, &.{}); try testing.expectEqualCells(.{}, renderer.size, @import("test/element/scrollable.horizontal.scrollbar.left.zon"), renderer.screen); @@ -1631,8 +1631,8 @@ test "input element" { var renderer: testing.Renderer = .init(allocator, size); defer renderer.deinit(); - container.resize(size); - container.reposition(.{}); + container.resize(&.{}, size); + container.reposition(&.{}, .{}); try renderer.render(@TypeOf(container), &container, Model, &.{}); // try testing.expectEqualCells(.{}, renderer.size, @import("test/element/input.without.text.zon"), renderer.screen); @@ -1697,8 +1697,8 @@ test "button" { var renderer: testing.Renderer = .init(allocator, size); defer renderer.deinit(); - container.resize(size); - container.reposition(.{}); + container.resize(&.{}, size); + container.reposition(&.{}, .{}); try renderer.render(@TypeOf(container), &container, Model, &.{}); // try testing.expectEqualCells(.{}, renderer.size, @import("test/element/button.zon"), renderer.screen); @@ -1755,8 +1755,8 @@ test "progress" { var renderer: testing.Renderer = .init(allocator, size); defer renderer.deinit(); - container.resize(size); - container.reposition(.{}); + container.resize(&.{}, size); + container.reposition(&.{}, .{}); try renderer.render(@TypeOf(container), &container, Model, &.{}); // try testing.expectEqualCells(.{}, renderer.size, @import("test/element/progress_zero.zon"), renderer.screen); @@ -1764,8 +1764,8 @@ test "progress" { try container.handle(&model, .{ .progress = 25, }); - container.resize(size); - container.reposition(.{}); + container.resize(&.{}, size); + container.reposition(&.{}, .{}); try renderer.render(@TypeOf(container), &container, Model, &.{}); // try testing.expectEqualCells(.{}, renderer.size, @import("test/element/progress_one_quarter.zon"), renderer.screen); @@ -1773,8 +1773,8 @@ test "progress" { try container.handle(&model, .{ .progress = 50, }); - container.resize(size); - container.reposition(.{}); + container.resize(&.{}, size); + container.reposition(&.{}, .{}); try renderer.render(@TypeOf(container), &container, Model, &.{}); // try testing.expectEqualCells(.{}, renderer.size, @import("test/element/progress_half.zon"), renderer.screen); @@ -1782,8 +1782,8 @@ test "progress" { try container.handle(&model, .{ .progress = 75, }); - container.resize(size); - container.reposition(.{}); + container.resize(&.{}, size); + container.reposition(&.{}, .{}); try renderer.render(@TypeOf(container), &container, Model, &.{}); // try testing.expectEqualCells(.{}, renderer.size, @import("test/element/progress_three_quarter.zon"), renderer.screen); @@ -1791,8 +1791,8 @@ test "progress" { try container.handle(&model, .{ .progress = 100, }); - container.resize(size); - container.reposition(.{}); + container.resize(&.{}, size); + container.reposition(&.{}, .{}); try renderer.render(@TypeOf(container), &container, Model, &.{}); // try testing.expectEqualCells(.{}, renderer.size, @import("test/element/progress_one_hundred.zon"), renderer.screen); } diff --git a/src/testing.zig b/src/testing.zig index 399c2f8..df656eb 100644 --- a/src/testing.zig +++ b/src/testing.zig @@ -112,9 +112,11 @@ pub fn expectContainerScreen(size: Point, comptime T: type, container: *T, compt var renderer: Renderer = .init(allocator, size); defer renderer.deinit(); - container.resize(size); - container.reposition(.{}); - try renderer.render(T, container, Model, &.{}); + const model: Model = .{}; + + container.resize(&model, size); + container.reposition(&model, .{}); + try renderer.render(T, container, Model, &model); try expectEqualCells(.{}, renderer.size, expected, renderer.screen); }