From ad32e46bc9fd6d1d9b7a3615979a3b80877c9300 Mon Sep 17 00:00:00 2001 From: Yves Biener Date: Wed, 5 Nov 2025 22:08:35 +0100 Subject: [PATCH] feat(element/scrollable): mouse support for scrollbar interaction Fix an issue with the scrollbar contents to work proper with statically defined `Container` sizes through its `Properties` sizing option. --- src/element.zig | 32 +++++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/src/element.zig b/src/element.zig index 8c3a765..2b5699c 100644 --- a/src/element.zig +++ b/src/element.zig @@ -284,6 +284,12 @@ pub fn Scrollable(Model: type, Event: type) type { container_size.x -= if (this.configuration.x_axis) 1 else 0; container_size.y -= if (this.configuration.y_axis) 1 else 0; } + // 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 + // update the calculated size of the container + container_size = this.container.size; const new_max_anchor_x = container_size.x -| size.x; const new_max_anchor_y = container_size.y -| size.y; @@ -293,7 +299,6 @@ pub fn Scrollable(Model: type, Event: type) type { 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.size = size; - this.container.resize(container_size); // notify the container about the minimal size it should have this.container_size = container_size; } @@ -342,20 +347,37 @@ pub fn Scrollable(Model: type, Event: type) type { } }, .mouse => |mouse| switch (mouse.button) { - Mouse.Button.wheel_up => if (this.container_size.y > this.size.y) { + .wheel_up => if (this.container_size.y > this.size.y) { this.anchor.y -|= 1; }, - Mouse.Button.wheel_down => if (this.container_size.y > this.size.y) { + .wheel_down => if (this.container_size.y > this.size.y) { const max_anchor_y = this.container_size.y -| this.size.y; this.anchor.y = @min(this.anchor.y + 1, max_anchor_y); }, - Mouse.Button.wheel_left => if (this.container_size.x > this.size.x) { + .wheel_left => if (this.container_size.x > this.size.x) { this.anchor.x -|= 1; }, - Mouse.Button.wheel_right => if (this.container_size.x > this.size.x) { + .wheel_right => if (this.container_size.x > this.size.x) { const max_anchor_x = this.container_size.x -| this.size.x; this.anchor.x = @min(this.anchor.x + 1, max_anchor_x); }, + .left => { + // horizontal (-) scrollbar click + if (this.configuration.y_axis and mouse.y == this.size.y - 1) { + const ratio = @as(f32, @floatFromInt(mouse.x)) / @as(f32, @floatFromInt(this.size.x)); + const value: u16 = @intFromFloat(ratio * @as(f32, @floatFromInt(this.container_size.x))); + const max_anchor_x = this.container_size.x -| this.size.x; + this.anchor.x = @min(value, max_anchor_x); + } + + // vertical (|) scrollbar click + if (this.configuration.x_axis and mouse.x == this.size.x - 1) { + const ratio = @as(f32, @floatFromInt(mouse.y)) / @as(f32, @floatFromInt(this.size.y)); + const value: u16 = @intFromFloat(ratio * @as(f32, @floatFromInt(this.container_size.y))); + const max_anchor_y = this.container_size.y -| this.size.y; + this.anchor.y = @min(value, max_anchor_y); + } + }, else => try this.container.handle(model, .{ .mouse = .{ .x = mouse.x + this.anchor.x,