diff --git a/komorebi-core/src/default_layout.rs b/komorebi-core/src/default_layout.rs index b49bf7ac..635bc1c4 100644 --- a/komorebi-core/src/default_layout.rs +++ b/komorebi-core/src/default_layout.rs @@ -20,6 +20,7 @@ pub enum DefaultLayout { VerticalStack, HorizontalStack, UltrawideVerticalStack, + // NOTE: If any new layout is added, please make sure to register the same in `DefaultLayout::cycle` } impl DefaultLayout { @@ -125,4 +126,28 @@ impl DefaultLayout { Option::from(r) } } + + #[must_use] + pub const fn cycle_next(self) -> Self { + match self { + Self::BSP => Self::Columns, + Self::Columns => Self::Rows, + Self::Rows => Self::VerticalStack, + Self::VerticalStack => Self::HorizontalStack, + Self::HorizontalStack => Self::UltrawideVerticalStack, + Self::UltrawideVerticalStack => Self::BSP, + } + } + + #[must_use] + pub const fn cycle_previous(self) -> Self { + match self { + Self::BSP => Self::UltrawideVerticalStack, + Self::UltrawideVerticalStack => Self::HorizontalStack, + Self::HorizontalStack => Self::VerticalStack, + Self::VerticalStack => Self::Rows, + Self::Rows => Self::Columns, + Self::Columns => Self::BSP, + } + } } diff --git a/komorebi-core/src/lib.rs b/komorebi-core/src/lib.rs index a06a73b3..ef59e9b7 100644 --- a/komorebi-core/src/lib.rs +++ b/komorebi-core/src/lib.rs @@ -77,6 +77,7 @@ pub enum SocketMessage { AdjustContainerPadding(Sizing, i32), AdjustWorkspacePadding(Sizing, i32), ChangeLayout(DefaultLayout), + CycleLayout(CycleDirection), ChangeLayoutCustom(PathBuf), FlipLayout(Axis), // Monitor and Workspace Commands diff --git a/komorebi/src/process_command.rs b/komorebi/src/process_command.rs index 1a0539b1..7588650d 100644 --- a/komorebi/src/process_command.rs +++ b/komorebi/src/process_command.rs @@ -448,6 +448,7 @@ impl WindowManager { SocketMessage::Retile => self.retile_all(false)?, SocketMessage::FlipLayout(layout_flip) => self.flip_layout(layout_flip)?, SocketMessage::ChangeLayout(layout) => self.change_workspace_layout_default(layout)?, + SocketMessage::CycleLayout(direction) => self.cycle_layout(direction)?, SocketMessage::ChangeLayoutCustom(ref path) => { self.change_workspace_custom_layout(path.clone())?; } @@ -1254,6 +1255,7 @@ impl WindowManager { match message { SocketMessage::ChangeLayout(_) + | SocketMessage::CycleLayout(_) | SocketMessage::ChangeLayoutCustom(_) | SocketMessage::FlipLayout(_) | SocketMessage::ManageFocusedWindow diff --git a/komorebi/src/window_manager.rs b/komorebi/src/window_manager.rs index 87af1eb8..25cac399 100644 --- a/komorebi/src/window_manager.rs +++ b/komorebi/src/window_manager.rs @@ -1705,6 +1705,29 @@ impl WindowManager { self.update_focused_workspace(self.mouse_follows_focus) } + #[tracing::instrument(skip(self))] + pub fn cycle_layout(&mut self, direction: CycleDirection) -> Result<()> { + tracing::info!("cycling layout"); + + let workspace = self.focused_workspace_mut()?; + let current_layout = workspace.layout(); + + match current_layout { + Layout::Default(current) => { + let new_layout = match direction { + CycleDirection::Previous => current.cycle_previous(), + CycleDirection::Next => current.cycle_next(), + }; + + tracing::info!("next layout: {new_layout}"); + workspace.set_layout(Layout::Default(new_layout)); + } + Layout::Custom(_) => {} + } + + self.update_focused_workspace(self.mouse_follows_focus) + } + #[tracing::instrument(skip(self))] pub fn change_workspace_custom_layout(&mut self, path: PathBuf) -> Result<()> { tracing::info!("changing layout"); diff --git a/komorebic.lib.ahk b/komorebic.lib.ahk index febeea99..e1e279b4 100644 --- a/komorebic.lib.ahk +++ b/komorebic.lib.ahk @@ -196,6 +196,10 @@ ChangeLayout(default_layout) { RunWait("komorebic.exe change-layout " default_layout, , "Hide") } +CycleLayout(operation_direction) { + RunWait("komorebic.exe cycle-layout " operation_direction, , "Hide") +} + LoadCustomLayout(path) { RunWait("komorebic.exe load-custom-layout " path, , "Hide") } diff --git a/komorebic/src/main.rs b/komorebic/src/main.rs index f2c4ed12..b0516f80 100644 --- a/komorebic/src/main.rs +++ b/komorebic/src/main.rs @@ -125,6 +125,7 @@ gen_enum_subcommand_args! { CycleStack: CycleDirection, FlipLayout: Axis, ChangeLayout: DefaultLayout, + CycleLayout: CycleDirection, WatchConfiguration: BooleanState, MouseFollowsFocus: BooleanState, Query: StateQuery, @@ -865,6 +866,9 @@ enum SubCommand { /// Set the layout on the focused workspace #[clap(arg_required_else_help = true)] ChangeLayout(ChangeLayout), + /// Cycle between available layouts + #[clap(arg_required_else_help = true)] + CycleLayout(CycleLayout), /// Load a custom layout from file for the focused workspace #[clap(arg_required_else_help = true)] LoadCustomLayout(LoadCustomLayout), @@ -1678,6 +1682,9 @@ Stop-Process -Name:whkd -ErrorAction SilentlyContinue SubCommand::ChangeLayout(arg) => { send_message(&SocketMessage::ChangeLayout(arg.default_layout).as_bytes()?)?; } + SubCommand::CycleLayout(arg) => { + send_message(&SocketMessage::CycleLayout(arg.cycle_direction).as_bytes()?)?; + } SubCommand::LoadCustomLayout(arg) => { send_message( &SocketMessage::ChangeLayoutCustom(resolve_windows_path(&arg.path)?).as_bytes()?,