From 383533e2d9a0cf1e893516311acd2cf4ce2f2dcc Mon Sep 17 00:00:00 2001 From: LGUG2Z Date: Sun, 28 Apr 2024 12:17:51 -0700 Subject: [PATCH] feat(wm): add right-main-vertical-stack layout This commit adds a new RightMainVerticalStack layout, adapting code from the similarly named LeftWM layout. It turns out that the horizontal axis flip on the VerticalStack does not play well with resize offsets. It was ultimately easier to implement this layout and the logic for resizing both VerticalStack and RightMainVerticalStack independently than to make resize offsets and horizontal axis flips work together. I still have no idea why resize offsets and horizontal axis flips aren't working properly together. Horizontal axis flips have been disabled for both the VerticalStack and RightMainVerticalStack layouts. re #789 --- komorebi-core/src/arrangement.rs | 163 ++++++++++++++++++++++++++-- komorebi-core/src/default_layout.rs | 15 ++- komorebi-core/src/direction.rs | 19 +++- komorebi/src/workspace.rs | 72 ++++++++++++ 4 files changed, 252 insertions(+), 17 deletions(-) diff --git a/komorebi-core/src/arrangement.rs b/komorebi-core/src/arrangement.rs index 3403df13..2cb8608a 100644 --- a/komorebi-core/src/arrangement.rs +++ b/komorebi-core/src/arrangement.rs @@ -54,16 +54,8 @@ impl Arrangement for DefaultLayout { _ => area.right / 2, }; - let mut main_left = area.left; - let mut stack_left = area.left + primary_right; - - match layout_flip { - Some(Axis::Horizontal | Axis::HorizontalAndVertical) if len > 1 => { - main_left = main_left + area.right - primary_right; - stack_left = area.left; - } - _ => {} - } + let main_left = area.left; + let stack_left = area.left + primary_right; if len >= 1 { layouts.push(Rect { @@ -86,6 +78,65 @@ impl Arrangement for DefaultLayout { } } + let adjustment = calculate_vertical_stack_adjustment(resize_dimensions); + layouts + .iter_mut() + .zip(adjustment.iter()) + .for_each(|(layout, adjustment)| { + layout.top += adjustment.top; + layout.bottom += adjustment.bottom; + layout.left += adjustment.left; + layout.right += adjustment.right; + }); + + layouts + } + Self::RightMainVerticalStack => { + // Shamelessly borrowed from LeftWM: https://github.com/leftwm/leftwm/commit/f673851745295ae7584a102535566f559d96a941 + let mut layouts: Vec = vec![]; + + let primary_width = match len { + 1 => area.right, + _ => area.right / 2, + }; + + let primary_left = match len { + 1 => 0, + _ => area.right - primary_width, + }; + + if len >= 1 { + layouts.push(Rect { + left: area.left + primary_left, + top: area.top, + right: primary_width, + bottom: area.bottom, + }); + + if len > 1 { + layouts.append(&mut rows( + &Rect { + left: area.left, + top: area.top, + right: primary_left, + bottom: area.bottom, + }, + len - 1, + )); + } + } + + let adjustment = calculate_right_vertical_stack_adjustment(resize_dimensions); + layouts + .iter_mut() + .zip(adjustment.iter()) + .for_each(|(layout, adjustment)| { + layout.top += adjustment.top; + layout.bottom += adjustment.bottom; + layout.left += adjustment.left; + layout.right += adjustment.right; + }); + layouts } Self::HorizontalStack => { @@ -562,6 +613,98 @@ fn recursive_fibonacci( } } +fn calculate_vertical_stack_adjustment(resize_dimensions: &[Option]) -> Vec { + let len = resize_dimensions.len(); + let mut result = vec![Rect::default(); len]; + match len { + // One container can't be resized + 0 | 1 => (), + _ => { + let (master, stack) = result.split_at_mut(1); + let primary = &mut master[0]; + + if let Some(resize) = resize_dimensions[0] { + resize_right(primary, resize.right); + for s in &mut *stack { + resize_left(s, resize.right); + } + } + + // Handle stack on the right + for (i, rect) in resize_dimensions[1..].iter().enumerate() { + if let Some(rect) = rect { + resize_right(primary, rect.left); + stack + .iter_mut() + .for_each(|vertical_element| resize_left(vertical_element, rect.left)); + + // Containers in stack except first can be resized up displacing container + // above them + if i != 0 { + resize_bottom(&mut stack[i - 1], rect.top); + resize_top(&mut stack[i], rect.top); + } + + // Containers in stack except last can be resized down displacing container + // below them + if i != stack.len() - 1 { + resize_bottom(&mut stack[i], rect.bottom); + resize_top(&mut stack[i + 1], rect.bottom); + } + } + } + } + }; + + result +} + +fn calculate_right_vertical_stack_adjustment(resize_dimensions: &[Option]) -> Vec { + let len = resize_dimensions.len(); + let mut result = vec![Rect::default(); len]; + match len { + // One container can't be resized + 0 | 1 => (), + _ => { + let (master, stack) = result.split_at_mut(1); + let primary = &mut master[0]; + + if let Some(resize) = resize_dimensions[0] { + resize_left(primary, resize.left); + for s in &mut *stack { + resize_right(s, resize.left); + } + } + + // Handle stack on the left + for (i, rect) in resize_dimensions[1..].iter().enumerate() { + if let Some(rect) = rect { + resize_left(primary, rect.right); + stack + .iter_mut() + .for_each(|vertical_element| resize_right(vertical_element, rect.right)); + + // Containers in stack except first can be resized up displacing container + // above them + if i != 0 { + resize_bottom(&mut stack[i - 1], rect.top); + resize_top(&mut stack[i], rect.top); + } + + // Containers in stack except last can be resized down displacing container + // below them + if i != stack.len() - 1 { + resize_bottom(&mut stack[i], rect.bottom); + resize_top(&mut stack[i + 1], rect.bottom); + } + } + } + } + }; + + result +} + fn calculate_ultrawide_adjustment(resize_dimensions: &[Option]) -> Vec { let len = resize_dimensions.len(); let mut result = vec![Rect::default(); len]; diff --git a/komorebi-core/src/default_layout.rs b/komorebi-core/src/default_layout.rs index c804cf6e..54d15c67 100644 --- a/komorebi-core/src/default_layout.rs +++ b/komorebi-core/src/default_layout.rs @@ -30,6 +30,7 @@ pub enum DefaultLayout { HorizontalStack, UltrawideVerticalStack, Grid, + RightMainVerticalStack, // NOTE: If any new layout is added, please make sure to register the same in `DefaultLayout::cycle` } @@ -44,7 +45,13 @@ impl DefaultLayout { sizing: Sizing, delta: i32, ) -> Option { - if !matches!(self, Self::BSP) && !matches!(self, Self::UltrawideVerticalStack) { + if !matches!( + self, + Self::BSP + | Self::UltrawideVerticalStack + | Self::VerticalStack + | Self::RightMainVerticalStack + ) { return None; }; @@ -146,7 +153,8 @@ impl DefaultLayout { Self::VerticalStack => Self::HorizontalStack, Self::HorizontalStack => Self::UltrawideVerticalStack, Self::UltrawideVerticalStack => Self::Grid, - Self::Grid => Self::BSP, + Self::Grid => Self::RightMainVerticalStack, + Self::RightMainVerticalStack => Self::BSP, } } @@ -159,7 +167,8 @@ impl DefaultLayout { Self::VerticalStack => Self::Rows, Self::Rows => Self::Columns, Self::Columns => Self::Grid, - Self::Grid => Self::BSP, + Self::Grid => Self::RightMainVerticalStack, + Self::RightMainVerticalStack => Self::BSP, } } } diff --git a/komorebi-core/src/direction.rs b/komorebi-core/src/direction.rs index 950e5de2..de8c625e 100644 --- a/komorebi-core/src/direction.rs +++ b/komorebi-core/src/direction.rs @@ -95,7 +95,7 @@ impl Direction for DefaultLayout { Self::BSP => count > 2 && idx != 0 && idx != 1, Self::Columns => false, Self::Rows | Self::HorizontalStack => idx != 0, - Self::VerticalStack => idx != 0 && idx != 1, + Self::VerticalStack | Self::RightMainVerticalStack => idx != 0 && idx != 1, Self::UltrawideVerticalStack => idx > 2, Self::Grid => !is_grid_edge(op_direction, idx, count), }, @@ -103,7 +103,7 @@ impl Direction for DefaultLayout { Self::BSP => count > 2 && idx != count - 1 && idx % 2 != 0, Self::Columns => false, Self::Rows => idx != count - 1, - Self::VerticalStack => idx != 0 && idx != count - 1, + Self::VerticalStack | Self::RightMainVerticalStack => idx != 0 && idx != count - 1, Self::HorizontalStack => idx == 0, Self::UltrawideVerticalStack => idx > 1 && idx != count - 1, Self::Grid => !is_grid_edge(op_direction, idx, count), @@ -111,6 +111,7 @@ impl Direction for DefaultLayout { OperationDirection::Left => match self { Self::BSP => count > 1 && idx != 0, Self::Columns | Self::VerticalStack => idx != 0, + Self::RightMainVerticalStack => idx == 0, Self::Rows => false, Self::HorizontalStack => idx != 0 && idx != 1, Self::UltrawideVerticalStack => count > 1 && idx != 1, @@ -121,6 +122,7 @@ impl Direction for DefaultLayout { Self::Columns => idx != count - 1, Self::Rows => false, Self::VerticalStack => idx == 0, + Self::RightMainVerticalStack => idx != 0, Self::HorizontalStack => idx != 0 && idx != count - 1, Self::UltrawideVerticalStack => match count { 0 | 1 => false, @@ -147,7 +149,10 @@ impl Direction for DefaultLayout { } } Self::Columns => unreachable!(), - Self::Rows | Self::VerticalStack | Self::UltrawideVerticalStack => idx - 1, + Self::Rows + | Self::VerticalStack + | Self::UltrawideVerticalStack + | Self::RightMainVerticalStack => idx - 1, Self::HorizontalStack => 0, Self::Grid => grid_neighbor(op_direction, idx, count), } @@ -160,7 +165,11 @@ impl Direction for DefaultLayout { count: Option, ) -> usize { match self { - Self::BSP | Self::Rows | Self::VerticalStack | Self::UltrawideVerticalStack => idx + 1, + Self::BSP + | Self::Rows + | Self::VerticalStack + | Self::UltrawideVerticalStack + | Self::RightMainVerticalStack => idx + 1, Self::Columns => unreachable!(), Self::HorizontalStack => 1, Self::Grid => grid_neighbor(op_direction, idx, count), @@ -184,6 +193,7 @@ impl Direction for DefaultLayout { Self::Columns | Self::HorizontalStack => idx - 1, Self::Rows => unreachable!(), Self::VerticalStack => 0, + Self::RightMainVerticalStack => 1, Self::UltrawideVerticalStack => match idx { 0 => 1, 1 => unreachable!(), @@ -203,6 +213,7 @@ impl Direction for DefaultLayout { Self::BSP | Self::Columns | Self::HorizontalStack => idx + 1, Self::Rows => unreachable!(), Self::VerticalStack => 1, + Self::RightMainVerticalStack => 0, Self::UltrawideVerticalStack => match idx { 1 => 0, 0 => 2, diff --git a/komorebi/src/workspace.rs b/komorebi/src/workspace.rs index d0c4972f..6dea8247 100644 --- a/komorebi/src/workspace.rs +++ b/komorebi/src/workspace.rs @@ -894,6 +894,12 @@ impl Workspace { fn enforce_resize_constraints(&mut self) { match self.layout { Layout::Default(DefaultLayout::BSP) => self.enforce_resize_constraints_for_bsp(), + Layout::Default(DefaultLayout::VerticalStack) => { + self.enforce_resize_for_vertical_stack() + } + Layout::Default(DefaultLayout::RightMainVerticalStack) => { + self.enforce_resize_for_right_vertical_stack() + } Layout::Default(DefaultLayout::UltrawideVerticalStack) => { self.enforce_resize_for_ultrawide(); } @@ -927,6 +933,72 @@ impl Workspace { } } + fn enforce_resize_for_vertical_stack(&mut self) { + let resize_dimensions = self.resize_dimensions_mut(); + match resize_dimensions.len() { + // Single window can not be resized at all + 0 | 1 => self.enforce_no_resize(), + _ => { + // Zero is actually on the left + if let Some(mut left) = resize_dimensions[0] { + left.top = 0; + left.bottom = 0; + left.left = 0; + } + + // Handle stack on the right + let stack_size = resize_dimensions[1..].len(); + for (i, rect) in resize_dimensions[1..].iter_mut().enumerate() { + if let Some(rect) = rect { + // No containers can resize to the right + rect.right = 0; + + // First container in stack cant resize up + if i == 0 { + rect.top = 0; + } else if i == stack_size - 1 { + // Last cant be resized to the bottom + rect.bottom = 0; + } + } + } + } + } + } + + fn enforce_resize_for_right_vertical_stack(&mut self) { + let resize_dimensions = self.resize_dimensions_mut(); + match resize_dimensions.len() { + // Single window can not be resized at all + 0 | 1 => self.enforce_no_resize(), + _ => { + // Zero is actually on the right + if let Some(mut left) = resize_dimensions[1] { + left.top = 0; + left.bottom = 0; + left.right = 0; + } + + // Handle stack on the right + let stack_size = resize_dimensions[1..].len(); + for (i, rect) in resize_dimensions[1..].iter_mut().enumerate() { + if let Some(rect) = rect { + // No containers can resize to the left + rect.left = 0; + + // First container in stack cant resize up + if i == 0 { + rect.top = 0; + } else if i == stack_size - 1 { + // Last cant be resized to the bottom + rect.bottom = 0; + } + } + } + } + } + } + fn enforce_resize_for_ultrawide(&mut self) { let resize_dimensions = self.resize_dimensions_mut(); match resize_dimensions.len() {