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() {