aboutsummaryrefslogtreecommitdiff
path: root/src/app/input/mouse.rs
diff options
context:
space:
mode:
authorOgulcan Celik <ogulcancelik@gmail.com>2026-05-12 00:24:13 +0300
committerOgulcan Celik <ogulcancelik@gmail.com>2026-05-12 00:24:13 +0300
commit520f4272d0f332f2a98a2a7486be1797feb86dcf (patch)
treef53830efc04e6961d7b0cd003bc453b95a714fe1 /src/app/input/mouse.rs
parent8d5dca8cfe2d580835d3392d0ebdff57f7de7298 (diff)
feat: add agent cycling and tab wheel switching
fixes #92
Diffstat (limited to 'src/app/input/mouse.rs')
-rw-r--r--src/app/input/mouse.rs109
1 files changed, 99 insertions, 10 deletions
diff --git a/src/app/input/mouse.rs b/src/app/input/mouse.rs
index 99157d0d..779af3ed 100644
--- a/src/app/input/mouse.rs
+++ b/src/app/input/mouse.rs
@@ -581,19 +581,24 @@ impl AppState {
}
}
- MouseEventKind::ScrollUp | MouseEventKind::ScrollDown if !in_sidebar => {
- if self.on_tab_bar(mouse.column, mouse.row) {
- match mouse.kind {
- MouseEventKind::ScrollUp => self.scroll_tabs_left(),
- MouseEventKind::ScrollDown => self.scroll_tabs_right(),
- _ => {}
- }
- } else if !self.scroll_selection_with_wheel(mouse) {
- self.selection = None;
- self.handle_terminal_wheel(mouse);
+ MouseEventKind::ScrollUp | MouseEventKind::ScrollDown
+ if self.on_tab_bar(mouse.column, mouse.row) =>
+ {
+ match mouse.kind {
+ MouseEventKind::ScrollUp => self.previous_tab(),
+ MouseEventKind::ScrollDown => self.next_tab(),
+ _ => {}
}
}
+ MouseEventKind::ScrollUp | MouseEventKind::ScrollDown
+ if !in_sidebar && self.scroll_selection_with_wheel(mouse) => {}
+
+ MouseEventKind::ScrollUp | MouseEventKind::ScrollDown if !in_sidebar => {
+ self.selection = None;
+ self.handle_terminal_wheel(mouse);
+ }
+
MouseEventKind::ScrollUp if in_sidebar => {
let agent_area = self.agent_panel_rect();
let over_agent_panel = agent_area != Rect::default()
@@ -1568,6 +1573,90 @@ mod tests {
}
#[test]
+ fn wheel_over_tab_bar_switches_tabs() {
+ let mut app = app_for_mouse_test();
+ let mut ws = Workspace::test_new("one");
+ ws.test_add_tab(Some("two"));
+ ws.test_add_tab(Some("three"));
+ app.state.workspaces = vec![ws];
+ app.state.active = Some(0);
+ app.state.selected = 0;
+ app.state.mode = Mode::Terminal;
+
+ crate::ui::compute_view(&mut app.state, Rect::new(0, 0, 106, 20));
+ let tab_bar = app.state.view.tab_bar_rect;
+
+ app.handle_mouse(mouse(MouseEventKind::ScrollDown, tab_bar.x + 1, tab_bar.y));
+ assert_eq!(app.state.workspaces[0].active_tab, 1);
+
+ app.handle_mouse(mouse(MouseEventKind::ScrollUp, tab_bar.x + 1, tab_bar.y));
+ assert_eq!(app.state.workspaces[0].active_tab, 0);
+
+ app.handle_mouse(mouse(MouseEventKind::ScrollUp, tab_bar.x + 1, tab_bar.y));
+ assert_eq!(app.state.workspaces[0].active_tab, 2);
+
+ app.handle_mouse(mouse(
+ MouseEventKind::ScrollDown,
+ tab_bar.x + tab_bar.width.saturating_sub(1),
+ tab_bar.y,
+ ));
+ assert_eq!(app.state.workspaces[0].active_tab, 0);
+ }
+
+ #[test]
+ fn wheel_over_overflowing_tab_bar_switches_tabs() {
+ let mut app = app_for_mouse_test();
+ let mut ws = Workspace::test_new("one");
+ ws.tabs[0].set_custom_name("very-long-one".into());
+ ws.test_add_tab(Some("very-long-two"));
+ ws.test_add_tab(Some("very-long-three"));
+ app.state.workspaces = vec![ws];
+ app.state.active = Some(0);
+ app.state.selected = 0;
+ app.state.mode = Mode::Terminal;
+
+ crate::ui::compute_view(&mut app.state, Rect::new(0, 0, 65, 20));
+ assert!(app.state.view.tab_scroll_right_hit_area.width > 0);
+ let tab_bar = app.state.view.tab_bar_rect;
+
+ app.handle_mouse(mouse(
+ MouseEventKind::ScrollDown,
+ tab_bar.x + tab_bar.width.saturating_sub(2),
+ tab_bar.y,
+ ));
+ assert_eq!(app.state.workspaces[0].active_tab, 1);
+
+ app.handle_mouse(mouse(
+ MouseEventKind::ScrollDown,
+ tab_bar.x + tab_bar.width.saturating_sub(2),
+ tab_bar.y,
+ ));
+ assert_eq!(app.state.workspaces[0].active_tab, 2);
+ }
+
+ #[test]
+ fn wheel_outside_tab_bar_does_not_switch_tabs() {
+ let mut app = app_for_mouse_test();
+ let mut ws = Workspace::test_new("one");
+ ws.test_add_tab(Some("two"));
+ app.state.workspaces = vec![ws];
+ app.state.active = Some(0);
+ app.state.selected = 0;
+ app.state.mode = Mode::Terminal;
+
+ crate::ui::compute_view(&mut app.state, Rect::new(0, 0, 106, 20));
+ let terminal = app.state.view.terminal_area;
+
+ app.handle_mouse(mouse(
+ MouseEventKind::ScrollDown,
+ terminal.x + 1,
+ terminal.y + 1,
+ ));
+
+ assert_eq!(app.state.workspaces[0].active_tab, 0);
+ }
+
+ #[test]
fn mobile_switch_button_opens_switcher_and_workspace_row_switches_workspace() {
let mut app = app_for_mouse_test();
app.state.workspaces = vec![Workspace::test_new("one"), Workspace::test_new("two")];