From 8ebab702aceabab25f662659ff8a86ba5e97e15d Mon Sep 17 00:00:00 2001 From: Yves Biener Date: Wed, 5 Nov 2025 18:33:16 +0100 Subject: [PATCH] fix(element/scrollable): reduce the number of `minSize` calls and correctly resize scrollable `Container` --- src/container.zig | 2 +- src/element.zig | 27 +++++++++++++-------------- 2 files changed, 14 insertions(+), 15 deletions(-) diff --git a/src/container.zig b/src/container.zig index 1a37f8d..c15496c 100644 --- a/src/container.zig +++ b/src/container.zig @@ -891,7 +891,7 @@ pub fn Container(Model: type, Event: type) type { const fit_size = this.fit_resize(); // if (fit_size.y > size.y or fit_size.x > size.x) @panic("error: cannot render in available space"); switch (this.properties.size.grow) { - .both => this.size = Point.max(size, fit_size), + .both => this.size = .max(size, fit_size), .fixed => {}, .horizontal => this.size = .{ .x = @max(size.x, fit_size.x), diff --git a/src/element.zig b/src/element.zig index 0ac37fa..8c3a765 100644 --- a/src/element.zig +++ b/src/element.zig @@ -275,26 +275,26 @@ pub fn Scrollable(Model: type, Event: type) type { const last_max_anchor_x = this.container_size.x -| this.size.x; const last_max_anchor_y = this.container_size.y -| this.size.y; - this.size = size; + // NOTE `container_size` denotes the `size` required for the container contents + var container_size = this.container.element.minSize(size); if (this.configuration.scrollbar) { - this.configuration.y_axis = this.container.properties.size.dim.x > this.size.x or this.container.size.x > this.size.x; - this.configuration.x_axis = this.container.properties.size.dim.y > this.size.y or this.container.size.y > this.size.y; + 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; + // correct size dimensions due to space needed for the axis (if any) + container_size.x -= if (this.configuration.x_axis) 1 else 0; + container_size.y -= if (this.configuration.y_axis) 1 else 0; + } - const min_size = this.container.element.minSize(size); - this.container.resize(.{ - .x = min_size.x - if (this.configuration.x_axis) @as(u16, 1) else @as(u16, 0), - .y = min_size.y - if (this.configuration.y_axis) @as(u16, 1) else @as(u16, 0), - }); - } else this.container.resize(this.container.element.minSize(size)); // notify the container about the minimal size it should have (can be larger) - - const new_max_anchor_x = this.container.size.x -| size.x; - const new_max_anchor_y = this.container.size.y -| size.y; + const new_max_anchor_x = container_size.x -| size.x; + const new_max_anchor_y = container_size.y -| size.y; // correct anchor if necessary if (new_max_anchor_x < last_max_anchor_x and this.anchor.x > new_max_anchor_x) this.anchor.x = new_max_anchor_x; if (new_max_anchor_y < last_max_anchor_y and this.anchor.y > new_max_anchor_y) this.anchor.y = new_max_anchor_y; - this.container_size = this.container.size; + this.size = size; + this.container.resize(container_size); // notify the container about the minimal size it should have + this.container_size = container_size; } fn reposition(ctx: *anyopaque, _: Point) void { @@ -305,7 +305,6 @@ pub fn Scrollable(Model: type, Event: type) type { fn handle(ctx: *anyopaque, model: *Model, event: Event) !void { const this: *@This() = @ptrCast(@alignCast(ctx)); switch (event) { - .init => this.container.resize(this.container.element.minSize(this.size)), // TODO what about multiple scrollable `Element` usages? mouse // can differ between them (due to the event being only send to // the `Container` / `Element` one under the cursor!)