Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: reorder tabs via left mouse drag #6527

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs/config/lua/keyassignment/MoveTabRelative.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ Move the current tab relative to its peers. The argument specifies an
offset. eg: `-1` moves the tab to the left of the current tab, while `1` moves
the tab to the right.

It is also possible to reorder tabs via left mouse drag on the tab bar entry.

```lua
local act = wezterm.action

Expand Down
61 changes: 53 additions & 8 deletions wezterm-gui/src/termwindow/mouseevent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use ::window::{
use config::keyassignment::{KeyAssignment, MouseEventTrigger, SpawnTabDomain};
use config::MouseEventAltScreen;
use mux::pane::{Pane, WithPaneLines};
use mux::tab::SplitDirection;
use mux::tab::{SplitDirection, TabId};
use mux::Mux;
use mux_lua::MuxPane;
use std::convert::TryInto;
Expand Down Expand Up @@ -332,6 +332,45 @@ impl super::TermWindow {
self.dragging.replace((item, start_event));
}

fn find_tab_item_by_idx(&mut self, target_tab_idx: TabId) -> Option<&UIItem> {
self.ui_items.iter().find(|item| match item.item_type {
UIItemType::TabBar(TabBarItem::Tab { tab_idx, .. }) => tab_idx == target_tab_idx,
_ => false,
})
}

fn drag_reorder_tab(
&mut self,
mut item: UIItem,
tab_idx: TabId,
start_event: MouseEvent,
event: MouseEvent,
) {
let current_x = event.coords.x;
let drag_right = current_x.saturating_sub(start_event.coords.x) > 0;
let delta = if drag_right { 1 } else { -1 };

let next_tab_idx = tab_idx.saturating_add_signed(delta);
if let Some(next_tab) = self.find_tab_item_by_idx(next_tab_idx) {
let next_tab_midpoint = next_tab.x.saturating_add(next_tab.width / 2) as isize;
let over_threshold = (drag_right && current_x > next_tab_midpoint)
|| (!drag_right && current_x < next_tab_midpoint);
if over_threshold {
if let Ok(_) = self.move_tab_relative(delta) {
if let Some(tab) = self.find_tab_item_by_idx(next_tab_idx) {
// Ensure we have updated tab index
item = tab.clone();
}
}
}
}

// We are only interested in the moment to moment direction of dragging; not
// the overall (from first click that initiated drag), so we always replace
// the start_event.
self.dragging.replace((item, event));
}

fn drag_ui_item(
&mut self,
item: UIItem,
Expand All @@ -348,6 +387,9 @@ impl super::TermWindow {
UIItemType::ScrollThumb => {
self.drag_scroll_thumb(item, start_event, event, context);
}
UIItemType::TabBar(TabBarItem::Tab { tab_idx, .. }) => {
self.drag_reorder_tab(item, tab_idx, start_event, event);
}
_ => {
log::error!("drag not implemented for {:?}", item);
}
Expand All @@ -364,8 +406,8 @@ impl super::TermWindow {
) {
self.last_ui_item.replace(item.clone());
match item.item_type {
UIItemType::TabBar(item) => {
self.mouse_event_tab_bar(item, event, context);
UIItemType::TabBar(tab_bar_item) => {
self.mouse_event_tab_bar(item, tab_bar_item, event, context);
}
UIItemType::AboveScrollThumb => {
self.mouse_event_above_scroll_thumb(item, pane, event, context);
Expand Down Expand Up @@ -455,14 +497,17 @@ impl super::TermWindow {

pub fn mouse_event_tab_bar(
&mut self,
item: TabBarItem,
item: UIItem,
tab_bar_item: TabBarItem,
event: MouseEvent,
context: &dyn WindowOps,
) {
match event.kind {
WMEK::Press(MousePress::Left) => match item {
WMEK::Press(MousePress::Left) => match tab_bar_item {
TabBarItem::Tab { tab_idx, .. } => {
self.activate_tab(tab_idx as isize).ok();
// For reordering tabs
self.dragging = Some((item, event));
}
TabBarItem::NewTabButton { .. } => {
self.do_new_tab_button_click(MousePress::Left);
Expand Down Expand Up @@ -510,7 +555,7 @@ impl super::TermWindow {
}
}
},
WMEK::Press(MousePress::Middle) => match item {
WMEK::Press(MousePress::Middle) => match tab_bar_item {
TabBarItem::Tab { tab_idx, .. } => {
self.close_specific_tab(tab_idx, true);
}
Expand All @@ -522,7 +567,7 @@ impl super::TermWindow {
| TabBarItem::RightStatus
| TabBarItem::WindowButton(_) => {}
},
WMEK::Press(MousePress::Right) => match item {
WMEK::Press(MousePress::Right) => match tab_bar_item {
TabBarItem::Tab { .. } => {
self.show_tab_navigator();
}
Expand All @@ -534,7 +579,7 @@ impl super::TermWindow {
| TabBarItem::RightStatus
| TabBarItem::WindowButton(_) => {}
},
WMEK::Move => match item {
WMEK::Move => match tab_bar_item {
TabBarItem::None | TabBarItem::LeftStatus | TabBarItem::RightStatus => {
context.set_window_drag_position(event.screen_coords);
}
Expand Down