From a283c34dbbad44dfddfa4b5eafa6d8e3b47b7c14 Mon Sep 17 00:00:00 2001 From: Winter <102400503+exoess@users.noreply.github.com> Date: Tue, 9 Jul 2024 21:52:48 -0700 Subject: [PATCH] Add move-column-{left/right}-or-to-monitor-{left/right} (#528) * feature added, move-column-left-or-monitor-left and move-column-right-or-monitor-right * fixed stupid mistake * yalter's fixes * fixed names * fixed a stupid mistake --------- Co-authored-by: Ivan Molodetskikh --- niri-config/src/lib.rs | 6 +++++ niri-ipc/src/lib.rs | 4 ++++ src/input/mod.rs | 34 +++++++++++++++++++++++++++ src/layout/mod.rs | 52 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 96 insertions(+) diff --git a/niri-config/src/lib.rs b/niri-config/src/lib.rs index 114027f..d2343ff 100644 --- a/niri-config/src/lib.rs +++ b/niri-config/src/lib.rs @@ -995,6 +995,8 @@ pub enum Action { MoveColumnRight, MoveColumnToFirst, MoveColumnToLast, + MoveColumnLeftOrToMonitorLeft, + MoveColumnRightOrToMonitorRight, MoveWindowDown, MoveWindowUp, MoveWindowDownOrToWorkspaceDown, @@ -1075,6 +1077,10 @@ impl From for Action { niri_ipc::Action::MoveColumnRight => Self::MoveColumnRight, niri_ipc::Action::MoveColumnToFirst => Self::MoveColumnToFirst, niri_ipc::Action::MoveColumnToLast => Self::MoveColumnToLast, + niri_ipc::Action::MoveColumnLeftOrToMonitorLeft => Self::MoveColumnLeftOrToMonitorLeft, + niri_ipc::Action::MoveColumnRightOrToMonitorRight => { + Self::MoveColumnRightOrToMonitorRight + } niri_ipc::Action::MoveWindowDown => Self::MoveWindowDown, niri_ipc::Action::MoveWindowUp => Self::MoveWindowUp, niri_ipc::Action::MoveWindowDownOrToWorkspaceDown => { diff --git a/niri-ipc/src/lib.rs b/niri-ipc/src/lib.rs index 931898b..16817df 100644 --- a/niri-ipc/src/lib.rs +++ b/niri-ipc/src/lib.rs @@ -152,6 +152,10 @@ pub enum Action { MoveColumnToFirst, /// Move the focused column to the end of the workspace. MoveColumnToLast, + /// Move the focused column to the left or to the monitor to the left. + MoveColumnLeftOrToMonitorLeft, + /// Move the focused column to the right or to the monitor to the right. + MoveColumnRightOrToMonitorRight, /// Move the focused window down in a column. MoveWindowDown, /// Move the focused window up in a column. diff --git a/src/input/mod.rs b/src/input/mod.rs index d96de0c..148129c 100644 --- a/src/input/mod.rs +++ b/src/input/mod.rs @@ -571,6 +571,40 @@ impl State { // FIXME: granular self.niri.queue_redraw_all(); } + Action::MoveColumnLeftOrToMonitorLeft => { + if let Some(output) = self.niri.output_left() { + if self.niri.layout.move_column_left_or_to_output(&output) + && !self.maybe_warp_cursor_to_focus_centered() + { + self.move_cursor_to_output(&output); + } else { + self.maybe_warp_cursor_to_focus(); + } + } else { + self.niri.layout.move_left(); + self.maybe_warp_cursor_to_focus(); + } + + // FIXME: granular + self.niri.queue_redraw_all(); + } + Action::MoveColumnRightOrToMonitorRight => { + if let Some(output) = self.niri.output_right() { + if self.niri.layout.move_column_right_or_to_output(&output) + && !self.maybe_warp_cursor_to_focus_centered() + { + self.move_cursor_to_output(&output); + } else { + self.maybe_warp_cursor_to_focus(); + } + } else { + self.niri.layout.move_right(); + self.maybe_warp_cursor_to_focus(); + } + + // FIXME: granular + self.niri.queue_redraw_all(); + } Action::MoveWindowDown => { self.niri.layout.move_down(); self.maybe_warp_cursor_to_focus(); diff --git a/src/layout/mod.rs b/src/layout/mod.rs index fadde1f..21e9066 100644 --- a/src/layout/mod.rs +++ b/src/layout/mod.rs @@ -1196,6 +1196,36 @@ impl Layout { monitor.move_column_to_last(); } + pub fn move_column_left_or_to_output(&mut self, output: &Output) -> bool { + if let Some(monitor) = self.active_monitor() { + let workspace = monitor.active_workspace(); + let curr_idx = workspace.active_column_idx; + + if !workspace.columns.is_empty() && curr_idx != 0 { + monitor.move_left(); + return false; + } + } + + self.move_column_to_output(output); + true + } + + pub fn move_column_right_or_to_output(&mut self, output: &Output) -> bool { + if let Some(monitor) = self.active_monitor() { + let workspace = monitor.active_workspace(); + let curr_idx = workspace.active_column_idx; + + if !workspace.columns.is_empty() && curr_idx != workspace.columns.len() - 1 { + monitor.move_right(); + return false; + } + } + + self.move_column_to_output(output); + true + } + pub fn move_down(&mut self) { let Some(monitor) = self.active_monitor() else { return; @@ -2797,6 +2827,8 @@ mod tests { MoveColumnRight, MoveColumnToFirst, MoveColumnToLast, + MoveColumnLeftOrToMonitorLeft(#[proptest(strategy = "1..=2u8")] u8), + MoveColumnRightOrToMonitorRight(#[proptest(strategy = "1..=2u8")] u8), MoveWindowDown, MoveWindowUp, MoveWindowDownOrToWorkspaceDown, @@ -3154,6 +3186,22 @@ mod tests { Op::MoveColumnRight => layout.move_right(), Op::MoveColumnToFirst => layout.move_column_to_first(), Op::MoveColumnToLast => layout.move_column_to_last(), + Op::MoveColumnLeftOrToMonitorLeft(id) => { + let name = format!("output{id}"); + let Some(output) = layout.outputs().find(|o| o.name() == name).cloned() else { + return; + }; + + layout.move_column_left_or_to_output(&output); + } + Op::MoveColumnRightOrToMonitorRight(id) => { + let name = format!("output{id}"); + let Some(output) = layout.outputs().find(|o| o.name() == name).cloned() else { + return; + }; + + layout.move_column_right_or_to_output(&output); + } Op::MoveWindowDown => layout.move_down(), Op::MoveWindowUp => layout.move_up(), Op::MoveWindowDownOrToWorkspaceDown => layout.move_down_or_to_workspace_down(), @@ -3384,6 +3432,8 @@ mod tests { Op::FocusWindowOrWorkspaceDown, Op::MoveColumnLeft, Op::MoveColumnRight, + Op::MoveColumnLeftOrToMonitorLeft(0), + Op::MoveColumnRightOrToMonitorRight(1), Op::ConsumeWindowIntoColumn, Op::ExpelWindowFromColumn, Op::CenterColumn, @@ -3563,6 +3613,8 @@ mod tests { Op::FocusWindowOrWorkspaceDown, Op::MoveColumnLeft, Op::MoveColumnRight, + Op::MoveColumnLeftOrToMonitorLeft(0), + Op::MoveColumnRightOrToMonitorRight(1), Op::ConsumeWindowIntoColumn, Op::ExpelWindowFromColumn, Op::CenterColumn,