diff --git a/komorebi-core/src/arrangement.rs b/komorebi-core/src/arrangement.rs index 12727aaae..bfef744f7 100644 --- a/komorebi-core/src/arrangement.rs +++ b/komorebi-core/src/arrangement.rs @@ -130,85 +130,7 @@ impl Arrangement for DefaultLayout { layouts } - Self::UltrawideVerticalStack => { - let mut layouts: Vec = vec![]; - - let primary_right = match len { - 1 => area.right, - _ => area.right / 2, - }; - - let secondary_right = match len { - 1 => 0, - 2 => area.right - primary_right, - _ => (area.right - primary_right) / 2, - }; - - let (primary_left, secondary_left, stack_left) = match len { - 1 => (area.left, 0, 0), - 2 => { - let mut primary = area.left + secondary_right; - let mut secondary = area.left; - - match layout_flip { - Some(Axis::Horizontal | Axis::HorizontalAndVertical) if len > 1 => { - primary = area.left; - secondary = area.left + primary_right; - } - _ => {} - } - - (primary, secondary, 0) - } - _ => { - let primary = area.left + secondary_right; - let mut secondary = area.left; - let mut stack = area.left + primary_right + secondary_right; - - match layout_flip { - Some(Axis::Horizontal | Axis::HorizontalAndVertical) if len > 1 => { - secondary = area.left + primary_right + secondary_right; - stack = area.left; - } - _ => {} - } - - (primary, secondary, stack) - } - }; - - if len >= 1 { - layouts.push(Rect { - left: primary_left, - top: area.top, - right: primary_right, - bottom: area.bottom, - }); - - if len >= 2 { - layouts.push(Rect { - left: secondary_left, - top: area.top, - right: secondary_right, - bottom: area.bottom, - }); - - if len > 2 { - layouts.append(&mut rows( - &Rect { - left: stack_left, - top: area.top, - right: secondary_right, - bottom: area.bottom, - }, - len - 2, - )); - } - } - } - - layouts - } + Self::UltrawideVerticalStack => ultrawide(area, len, layout_flip, resize_dimensions), }; dimensions @@ -586,3 +508,190 @@ fn recursive_fibonacci( res } } + +fn calculate_ultrawide_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 => (), + 2 => { + let (primary, secondary) = result.split_at_mut(1); + let primary = &mut primary[0]; + let secondary = &mut secondary[0]; + // With two containers on screen container 0 is on the right + if let Some(resize_primary) = resize_dimensions[0] { + resize_left(primary, resize_primary.left); + resize_right(secondary, resize_primary.left); + } + + if let Some(resize_secondary) = resize_dimensions[1] { + resize_left(primary, resize_secondary.right); + resize_right(secondary, resize_secondary.right); + } + } + _ => { + let (primary, rest) = result.split_at_mut(1); + let (secondary, tertiary) = rest.split_at_mut(1); + let primary = &mut primary[0]; + let secondary = &mut secondary[0]; + // With three or more containers container 0 is in the center + if let Some(resize_primary) = resize_dimensions[0] { + resize_left(primary, resize_primary.left); + resize_right(primary, resize_primary.right); + + resize_right(secondary, resize_primary.left); + + for vertical_element in &mut *tertiary { + resize_left(vertical_element, resize_primary.right); + } + } + + // Container 1 is on the left + if let Some(resize_secondary) = resize_dimensions[1] { + resize_left(primary, resize_secondary.right); + resize_right(secondary, resize_secondary.right); + } + + // Handle stack on the right + for (i, rect) in resize_dimensions[2..].iter().enumerate() { + if let Some(rect) = rect { + resize_right(primary, rect.left); + tertiary + .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 tertiary[i - 1], rect.top); + resize_top(&mut tertiary[i], rect.top); + } + + // Containers in stack except last can be resized down displacing container + // below them + if i != tertiary.len() - 1 { + resize_bottom(&mut tertiary[i], rect.bottom); + resize_top(&mut tertiary[i + 1], rect.bottom); + } + } + } + } + }; + + result +} + +fn resize_left(rect: &mut Rect, resize: i32) { + rect.left += resize / 2; + rect.right += -resize / 2; +} + +fn resize_right(rect: &mut Rect, resize: i32) { + rect.right += resize / 2; +} + +fn resize_top(rect: &mut Rect, resize: i32) { + rect.top += resize / 2; + rect.bottom += -resize / 2; +} + +fn resize_bottom(rect: &mut Rect, resize: i32) { + rect.bottom += resize / 2; +} + +fn ultrawide( + area: &Rect, + len: usize, + layout_flip: Option, + resize_dimensions: &[Option], +) -> Vec { + let mut layouts: Vec = vec![]; + + let primary_right = match len { + 1 => area.right, + _ => area.right / 2, + }; + + let secondary_right = match len { + 1 => 0, + 2 => area.right - primary_right, + _ => (area.right - primary_right) / 2, + }; + + let (primary_left, secondary_left, stack_left) = match len { + 1 => (area.left, 0, 0), + 2 => { + let mut primary = area.left + secondary_right; + let mut secondary = area.left; + + match layout_flip { + Some(Axis::Horizontal | Axis::HorizontalAndVertical) if len > 1 => { + primary = area.left; + secondary = area.left + primary_right; + } + _ => {} + } + + (primary, secondary, 0) + } + _ => { + let primary = area.left + secondary_right; + let mut secondary = area.left; + let mut stack = area.left + primary_right + secondary_right; + + match layout_flip { + Some(Axis::Horizontal | Axis::HorizontalAndVertical) if len > 1 => { + secondary = area.left + primary_right + secondary_right; + stack = area.left; + } + _ => {} + } + + (primary, secondary, stack) + } + }; + + if len >= 1 { + layouts.push(Rect { + left: primary_left, + top: area.top, + right: primary_right, + bottom: area.bottom, + }); + + if len >= 2 { + layouts.push(Rect { + left: secondary_left, + top: area.top, + right: secondary_right, + bottom: area.bottom, + }); + + if len > 2 { + layouts.append(&mut rows( + &Rect { + left: stack_left, + top: area.top, + right: secondary_right, + bottom: area.bottom, + }, + len - 2, + )); + } + } + } + + let adjustment = calculate_ultrawide_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 +} diff --git a/komorebi-core/src/default_layout.rs b/komorebi-core/src/default_layout.rs index ce24c945c..b49bf7acc 100644 --- a/komorebi-core/src/default_layout.rs +++ b/komorebi-core/src/default_layout.rs @@ -33,7 +33,7 @@ impl DefaultLayout { sizing: Sizing, delta: i32, ) -> Option { - if !matches!(self, Self::BSP) { + if !matches!(self, Self::BSP) && !matches!(self, Self::UltrawideVerticalStack) { return None; }; diff --git a/komorebi/src/workspace.rs b/komorebi/src/workspace.rs index 28128861a..c3d81184d 100644 --- a/komorebi/src/workspace.rs +++ b/komorebi/src/workspace.rs @@ -775,6 +775,16 @@ impl Workspace { } fn enforce_resize_constraints(&mut self) { + match self.layout { + Layout::Default(DefaultLayout::BSP) => self.enforce_resize_constraints_for_bsp(), + Layout::Default(DefaultLayout::UltrawideVerticalStack) => { + self.enforce_resize_for_ultrawide(); + } + _ => self.enforce_no_resize(), + } + } + + fn enforce_resize_constraints_for_bsp(&mut self) { for (i, rect) in self.resize_dimensions_mut().iter_mut().enumerate() { if let Some(rect) = rect { // Even containers can't be resized to the bottom @@ -800,6 +810,72 @@ impl Workspace { } } + fn enforce_resize_for_ultrawide(&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(), + // Two windows can only be resized in the middle + 2 => { + // Zero is actually on the right + if let Some(mut right) = resize_dimensions[0] { + right.top = 0; + right.bottom = 0; + right.right = 0; + } + + // One is on the left + if let Some(mut left) = resize_dimensions[1] { + left.top = 0; + left.bottom = 0; + left.left = 0; + } + } + // Three or more windows means 0 is in center, 1 is at the left, 2.. are a vertical + // stack on the right + _ => { + // Central can be resized left or right + if let Some(mut right) = resize_dimensions[0] { + right.top = 0; + right.bottom = 0; + } + + // Left one can only be resized to the right + if let Some(mut left) = resize_dimensions[1] { + left.top = 0; + left.bottom = 0; + left.left = 0; + } + + // Handle stack on the right + let stack_size = resize_dimensions[2..].len(); + for (i, rect) in resize_dimensions[2..].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_no_resize(&mut self) { + for rect in self.resize_dimensions_mut().iter_mut().flatten() { + rect.left = 0; + rect.right = 0; + rect.top = 0; + rect.bottom = 0; + } + } + pub fn new_monocle_container(&mut self) -> Result<()> { let focused_idx = self.focused_container_idx(); let container = self