From 465d60def86c86593eb28d9d4b39aa4a06452326 Mon Sep 17 00:00:00 2001 From: axdank Date: Thu, 24 Oct 2024 00:01:54 -0300 Subject: [PATCH] gui: add move_current_tab action --- src/Surface.zig | 6 ++++++ src/apprt/action.zig | 10 ++++++++++ src/apprt/glfw.zig | 1 + src/apprt/gtk/App.zig | 18 ++++++++++++++++++ src/apprt/gtk/Window.zig | 9 +++++++++ src/apprt/gtk/notebook.zig | 27 +++++++++++++++++++++++++++ src/input/Binding.zig | 4 ++++ 7 files changed, 75 insertions(+) diff --git a/src/Surface.zig b/src/Surface.zig index bd5073e3a..dca9c6316 100644 --- a/src/Surface.zig +++ b/src/Surface.zig @@ -3913,6 +3913,12 @@ pub fn performBindingAction(self: *Surface, action: input.Binding.Action) !bool }, ), + .move_current_tab => |position| try self.rt_app.performAction( + .{ .surface = self }, + .move_current_tab, + position, + ), + .new_split => |direction| try self.rt_app.performAction( .{ .surface = self }, .new_split, diff --git a/src/apprt/action.zig b/src/apprt/action.zig index 9fce8502f..e9c1f1005 100644 --- a/src/apprt/action.zig +++ b/src/apprt/action.zig @@ -100,6 +100,9 @@ pub const Action = union(Key) { /// Toggle the visibility of all Ghostty terminal windows. toggle_visibility, + /// Move current tab given a position + move_current_tab: isize, + /// Jump to a specific tab. Must handle the scenario that the tab /// value is invalid. goto_tab: GotoTab, @@ -190,6 +193,7 @@ pub const Action = union(Key) { toggle_window_decorations, toggle_quick_terminal, toggle_visibility, + move_current_tab, goto_tab, goto_split, resize_split, @@ -318,6 +322,12 @@ pub const GotoTab = enum(c_int) { _, }; +/// Move current tab . +pub const MoveCurrentTabDirection = enum(c_int) { + right, + left, +}; + /// The fullscreen mode to toggle to if we're moving to fullscreen. pub const Fullscreen = enum(c_int) { native, diff --git a/src/apprt/glfw.zig b/src/apprt/glfw.zig index 668dd9143..49eecab32 100644 --- a/src/apprt/glfw.zig +++ b/src/apprt/glfw.zig @@ -213,6 +213,7 @@ pub const App = struct { .toggle_quick_terminal, .toggle_visibility, .goto_tab, + .move_current_tab, .inspector, .render_inspector, .quit_timer, diff --git a/src/apprt/gtk/App.zig b/src/apprt/gtk/App.zig index 10a2bdc02..595e8e5b6 100644 --- a/src/apprt/gtk/App.zig +++ b/src/apprt/gtk/App.zig @@ -456,6 +456,7 @@ pub fn performAction( .new_tab => try self.newTab(target), .goto_tab => self.gotoTab(target, value), + .move_current_tab => self.moveCurrentTab(target, value), .new_split => try self.newSplit(target, value), .resize_split => self.resizeSplit(target, value), .equalize_splits => self.equalizeSplits(target), @@ -527,6 +528,23 @@ fn gotoTab(_: *App, target: apprt.Target, tab: apprt.action.GotoTab) void { } } +fn moveCurrentTab(_: *App, target: apprt.Target, position: isize) void { + switch (target) { + .app => {}, + .surface => |v| { + const window = v.rt_surface.container.window() orelse { + log.info( + "moveCurrentTab invalid for container={s}", + .{@tagName(v.rt_surface.container)}, + ); + return; + }; + + window.moveCurrentTab(v.rt_surface, @intCast(position)); + }, + } +} + fn newSplit( self: *App, target: apprt.Target, diff --git a/src/apprt/gtk/Window.zig b/src/apprt/gtk/Window.zig index 65041d600..8fb6cac77 100644 --- a/src/apprt/gtk/Window.zig +++ b/src/apprt/gtk/Window.zig @@ -456,6 +456,15 @@ pub fn gotoNextTab(self: *Window, surface: *Surface) void { self.focusCurrentTab(); } +/// Move the current tab for a surface. +pub fn moveCurrentTab(self: *Window, surface: *Surface, position: c_int) void { + const tab = surface.container.tab() orelse { + log.info("surface is not attached to a tab bar, cannot navigate", .{}); + return; + }; + self.notebook.moveTab(tab, position); +} + /// Go to the next tab for a surface. pub fn gotoLastTab(self: *Window) void { const max = self.notebook.nPages() -| 1; diff --git a/src/apprt/gtk/notebook.zig b/src/apprt/gtk/notebook.zig index 53cadc2d2..dce729989 100644 --- a/src/apprt/gtk/notebook.zig +++ b/src/apprt/gtk/notebook.zig @@ -183,6 +183,33 @@ pub const Notebook = union(enum) { self.gotoNthTab(next_idx); } + pub fn moveTab(self: Notebook, tab: *Tab, position: c_int) void { + switch (self) { + .gtk_notebook => |notebook| { + c.gtk_notebook_reorder_child(notebook, @ptrCast(tab.box), position); + }, + .adw_tab_view => |tab_view| { + if (comptime !adwaita.versionAtLeast(0, 0, 0)) unreachable; + const page = c.adw_tab_view_get_page(tab_view, @ptrCast(tab.box)); + + const page_idx = self.getTabPosition(tab) orelse return; + + const max = self.nPages() -| 1; + var new_position: c_int = page_idx + position; + + if (new_position < 0) { + new_position = max; + } else if (new_position > max) { + new_position = 0; + } + + if (new_position == page_idx) return; + + _ = c.adw_tab_view_reorder_page(tab_view, page, new_position); + }, + } + } + pub fn setTabLabel(self: Notebook, tab: *Tab, title: [:0]const u8) void { switch (self) { .adw_tab_view => |tab_view| { diff --git a/src/input/Binding.zig b/src/input/Binding.zig index c9e90d946..943a704c4 100644 --- a/src/input/Binding.zig +++ b/src/input/Binding.zig @@ -300,6 +300,9 @@ pub const Action = union(enum) { /// Go to the tab with the specific number, 1-indexed. goto_tab: usize, + /// Move current tab to a position + move_current_tab: isize, + /// Toggle the tab overview. /// This only works with libadwaita enabled currently. toggle_tab_overview: void, @@ -646,6 +649,7 @@ pub const Action = union(enum) { .next_tab, .last_tab, .goto_tab, + .move_current_tab, .toggle_tab_overview, .new_split, .goto_split,