From 1fb3a8828a460816d59bbb0da1e4bc271a854395 Mon Sep 17 00:00:00 2001 From: CJ van den Berg Date: Mon, 3 Nov 2025 20:47:18 +0100 Subject: [PATCH 1/2] fix: be more precise about tracking active state in scrollbar_v widget --- src/tui/scrollbar_v.zig | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/tui/scrollbar_v.zig b/src/tui/scrollbar_v.zig index 8f0911a..306521e 100644 --- a/src/tui/scrollbar_v.zig +++ b/src/tui/scrollbar_v.zig @@ -68,17 +68,17 @@ pub fn receive(self: *Self, _: tp.pid_ref, m: tp.message) error{Exit}!bool { self.active = true; self.move_to(y, ypx); return true; - } else if (try m.match(.{ "B", input.event.release, tp.more })) { + } else if (try m.match(.{ "B", input.event.release, @intFromEnum(input.mouse.BUTTON1), tp.more })) { self.active = false; return true; } else if (try m.match(.{ "D", input.event.press, @intFromEnum(input.mouse.BUTTON1), tp.any, tp.any, tp.extract(&y), tp.any, tp.extract(&ypx) })) { self.active = true; self.move_to(y, ypx); return true; - } else if (try m.match(.{ "B", input.event.release, tp.more })) { + } else if (try m.match(.{ "B", input.event.release, @intFromEnum(input.mouse.BUTTON1), tp.more })) { self.active = false; return true; - } else if (try m.match(.{ "D", input.event.release, tp.more })) { + } else if (try m.match(.{ "D", input.event.release, @intFromEnum(input.mouse.BUTTON1), tp.more })) { self.active = false; return true; } else if (try m.match(.{ "H", tp.extract(&self.hover) })) { From fa6ea11d57e151a99bbb0ef05c66f5d9793b48c0 Mon Sep 17 00:00:00 2001 From: CJ van den Berg Date: Mon, 3 Nov 2025 20:48:08 +0100 Subject: [PATCH 2/2] fix: only reset mouse drag context when the dragging button is released closes #320 --- src/tui/status/tabs.zig | 2 +- src/tui/tui.zig | 24 +++++++++++++++++++++--- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/src/tui/status/tabs.zig b/src/tui/status/tabs.zig index ab15adc..32729dd 100644 --- a/src/tui/status/tabs.zig +++ b/src/tui/status/tabs.zig @@ -206,7 +206,7 @@ pub const TabBar = struct { if (self.tabs[dragging].widget.dynamic_cast(Tab.ButtonType)) |btn| btn.hover = false; self.update(); for (self.widget_list.widgets.items) |*widgetstate| if (widgetstate.widget.dynamic_cast(Tab.ButtonType)) |btn| if (btn.drag_pos) |_| - tui.set_drag_source(&widgetstate.widget); + tui.update_drag_source(&widgetstate.widget); tui.refresh_hover(); } } diff --git a/src/tui/tui.zig b/src/tui/tui.zig index ac38613..95959e4 100644 --- a/src/tui/tui.zig +++ b/src/tui/tui.zig @@ -10,6 +10,7 @@ const builtin = @import("builtin"); const file_link = @import("file_link"); pub const renderer = @import("renderer"); +const input = @import("input"); const command = @import("command"); const EventHandler = @import("EventHandler"); const keybind = @import("keybind"); @@ -57,6 +58,7 @@ last_hover_y: c_int = -1, commands: Commands = undefined, logger: log.Logger, drag_source: ?*Widget = null, +drag_button: ?input.MouseType = null, dark_theme: Widget.Theme, dark_parsed_theme: ?std.json.Parsed(Widget.Theme), light_theme: Widget.Theme, @@ -587,7 +589,9 @@ fn dispatch_mouse(ctx: *anyopaque, y: c_int, x: c_int, cbor_msg: []const u8) voi self.unrendered_input_events_count += 1; const send_func = if (self.drag_source) |_| &send_mouse_drag else &send_mouse; send_func(self, y, x, from, m) catch |e| self.logger.err("dispatch mouse", e); - self.drag_source = null; + var btn: input.MouseType = 0; + _ = m.match(.{ tp.string, tp.any, tp.extract(&btn), tp.more }) catch false; + self.maybe_reset_drag_source_internal(btn); } fn dispatch_mouse_drag(ctx: *anyopaque, y: c_int, x: c_int, cbor_msg: []const u8) void { @@ -596,7 +600,9 @@ fn dispatch_mouse_drag(ctx: *anyopaque, y: c_int, x: c_int, cbor_msg: []const u8 const m: tp.message = .{ .buf = cbor_msg }; const from = tp.self_pid(); self.unrendered_input_events_count += 1; - if (self.drag_source == null) self.drag_source = self.find_coord_widget(@intCast(y), @intCast(x)); + var btn: input.MouseType = undefined; + if (m.match(.{ tp.string, tp.any, tp.extract(&btn), tp.more }) catch false) + if (self.drag_source == null) self.set_drag_source(self.find_coord_widget(@intCast(y), @intCast(x)), btn); self.send_mouse_drag(y, x, from, m) catch |e| self.logger.err("dispatch mouse", e); } @@ -1439,14 +1445,26 @@ pub fn get_keybind_mode() ?Mode { return self.input_mode_ orelse self.delayed_init_input_mode; } -pub fn set_drag_source(drag_source: *Widget) void { +pub fn update_drag_source(drag_source: *Widget) void { const self = current(); self.drag_source = drag_source; } +fn set_drag_source(self: *Self, drag_source: ?*Widget, btn: input.MouseType) void { + self.drag_source = drag_source; + self.drag_button = btn; +} + pub fn reset_drag_context() void { const self = current(); self.drag_source = null; + self.drag_button = 0; +} + +fn maybe_reset_drag_source_internal(self: *Self, btn: input.MouseType) void { + if (self.drag_button != btn) return; + self.drag_source = null; + self.drag_button = 0; } pub fn need_render() void {