From 51e45c4b22afc60567e255ccf7c9278f5f76465a Mon Sep 17 00:00:00 2001 From: NotLebedev Date: Fri, 22 Sep 2023 14:27:32 +0300 Subject: [PATCH 1/5] Allow different resize constraints for layouts Change Workspace::enforce_resize_constraints to enforce constraints differently for different layouts Add enforce_no_resize method for all but bsp layout resize_dimensions --- komorebi/src/workspace.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/komorebi/src/workspace.rs b/komorebi/src/workspace.rs index 28128861a..9fe9e5cd2 100644 --- a/komorebi/src/workspace.rs +++ b/komorebi/src/workspace.rs @@ -775,6 +775,13 @@ impl Workspace { } fn enforce_resize_constraints(&mut self) { + match self.layout { + Layout::Default(DefaultLayout::BSP) => self.enforce_resize_constraints_for_bsp(), + _ => 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 +807,17 @@ impl Workspace { } } + fn enforce_no_resize(&mut self) { + for rect in self.resize_dimensions_mut().iter_mut() { + if let Some(rect) = rect { + 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 From 9daddebb3315913e66840ea591d9197982d44ea1 Mon Sep 17 00:00:00 2001 From: NotLebedev Date: Fri, 22 Sep 2023 16:41:03 +0300 Subject: [PATCH 2/5] Add resize constraints for UltrawideVerticalStack layout Add Workspace::enforce_resize_for_ultrawide method to apply resize constraints for ultrawide vertical stack layout. --- komorebi/src/workspace.rs | 60 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/komorebi/src/workspace.rs b/komorebi/src/workspace.rs index 9fe9e5cd2..72a94c4af 100644 --- a/komorebi/src/workspace.rs +++ b/komorebi/src/workspace.rs @@ -777,6 +777,9 @@ 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(), } } @@ -807,6 +810,63 @@ impl Workspace { } } + fn enforce_resize_for_ultrawide(&mut self) { + let mut 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() { if let Some(rect) = rect { From 0dd00eb4817a6875a35cef787d0e956abe46c079 Mon Sep 17 00:00:00 2001 From: NotLebedev Date: Fri, 22 Sep 2023 16:46:17 +0300 Subject: [PATCH 3/5] feat(wm): Use resize_dimensions in calculate for ultrawide layout Add function calculate_ultrawide_adjustment to calculate adjustments for individual containers in ultrawide vertical stack layout Refactor ultrawide layout generation in separate function and use calculated adjustments --- komorebi-core/src/arrangement.rs | 252 +++++++++++++++++++++---------- 1 file changed, 173 insertions(+), 79 deletions(-) diff --git a/komorebi-core/src/arrangement.rs b/komorebi-core/src/arrangement.rs index 12727aaae..68f8abe94 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,175 @@ 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 => { + // With two containers on screen container 0 is on the right + if let Some(resize_primary) = resize_dimensions[0] { + result[0].left += resize_primary.left / 2; + result[0].right += -resize_primary.left / 2; + result[1].right += resize_primary.left / 2; + } + + if let Some(resize_secondary) = resize_dimensions[1] { + result[0].left += resize_secondary.right / 2; + result[0].right += -resize_secondary.right / 2; + result[1].right += resize_secondary.right / 2; + } + } + _ => { + // With three or more containers container 0 is in the center + if let Some(resize_primary) = resize_dimensions[0] { + result[0].left += resize_primary.left / 2; + result[0].right += -resize_primary.left / 2; + result[0].right += resize_primary.right / 2; + + result[1].right += resize_primary.left / 2; + + result[2..] + .iter_mut() + .for_each(|vertical_element| { + vertical_element.left += resize_primary.right / 2; + vertical_element.right += -resize_primary.right / 2; + }); + } + + // Container 1 is on the left + if let Some(resize_secondary) = resize_dimensions[1] { + result[0].left += resize_secondary.right / 2; + result[0].right += -resize_secondary.right / 2; + result[1].right += resize_secondary.right / 2; + } + + // Handle stack on the right + for (i, rect) in resize_dimensions[2..].iter().enumerate() { + if let Some(rect) = rect { + result[0].right += rect.left / 2; + result[2..] + .iter_mut() + .for_each(|vertical_element| { + vertical_element.left += rect.left / 2; + vertical_element.right += -rect.left / 2; + }); + + + // Containers in stack except first can be resized up displacing container + // above them + if i != 0 { + result[2..][i - 1].bottom += rect.top / 2; + result[2..][i].top += rect.top / 2; + result[2..][i].bottom += -rect.top / 2; + } + + // Containers in stack except last can be resized down displacing container + // below them + if i != result[2..].len() - 1 { + result[2..][i].bottom += rect.bottom / 2; + result[2..][i + 1].top += rect.bottom / 2; + result[2..][i + 1].bottom += -rect.bottom / 2; + } + } + } + } + }; + + result +} + +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 +} From 2f9c9088b9e84fb06c5afc35239507815996b1d8 Mon Sep 17 00:00:00 2001 From: NotLebedev Date: Fri, 22 Sep 2023 16:47:11 +0300 Subject: [PATCH 4/5] feat(wm): Enable ultrawide layout in DefaultLayout::resize --- komorebi-core/src/default_layout.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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; }; From 9bf7d0f7ca2d31e311c83d9cbd393b09ee88b54b Mon Sep 17 00:00:00 2001 From: NotLebedev Date: Sun, 24 Sep 2023 23:06:46 +0300 Subject: [PATCH 5/5] feat(wm): refactor ultrawide resize calculation Add some helper function and descriptive variable names in calculate_ultrawide_adjustment Apply clippy lints --- komorebi-core/src/arrangement.rs | 93 ++++++++++++++++++-------------- komorebi/src/workspace.rs | 16 +++--- 2 files changed, 61 insertions(+), 48 deletions(-) diff --git a/komorebi-core/src/arrangement.rs b/komorebi-core/src/arrangement.rs index 68f8abe94..bfef744f7 100644 --- a/komorebi-core/src/arrangement.rs +++ b/komorebi-core/src/arrangement.rs @@ -516,69 +516,63 @@ fn calculate_ultrawide_adjustment(resize_dimensions: &[Option]) -> Vec (), 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] { - result[0].left += resize_primary.left / 2; - result[0].right += -resize_primary.left / 2; - result[1].right += resize_primary.left / 2; + resize_left(primary, resize_primary.left); + resize_right(secondary, resize_primary.left); } if let Some(resize_secondary) = resize_dimensions[1] { - result[0].left += resize_secondary.right / 2; - result[0].right += -resize_secondary.right / 2; - result[1].right += resize_secondary.right / 2; + 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] { - result[0].left += resize_primary.left / 2; - result[0].right += -resize_primary.left / 2; - result[0].right += resize_primary.right / 2; + resize_left(primary, resize_primary.left); + resize_right(primary, resize_primary.right); - result[1].right += resize_primary.left / 2; + resize_right(secondary, resize_primary.left); - result[2..] - .iter_mut() - .for_each(|vertical_element| { - vertical_element.left += resize_primary.right / 2; - vertical_element.right += -resize_primary.right / 2; - }); + 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] { - result[0].left += resize_secondary.right / 2; - result[0].right += -resize_secondary.right / 2; - result[1].right += resize_secondary.right / 2; + 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 { - result[0].right += rect.left / 2; - result[2..] + resize_right(primary, rect.left); + tertiary .iter_mut() - .for_each(|vertical_element| { - vertical_element.left += rect.left / 2; - vertical_element.right += -rect.left / 2; - }); - + .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 { - result[2..][i - 1].bottom += rect.top / 2; - result[2..][i].top += rect.top / 2; - result[2..][i].bottom += -rect.top / 2; + 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 != result[2..].len() - 1 { - result[2..][i].bottom += rect.bottom / 2; - result[2..][i + 1].top += rect.bottom / 2; - result[2..][i + 1].bottom += -rect.bottom / 2; + if i != tertiary.len() - 1 { + resize_bottom(&mut tertiary[i], rect.bottom); + resize_top(&mut tertiary[i + 1], rect.bottom); } } } @@ -588,6 +582,24 @@ fn calculate_ultrawide_adjustment(resize_dimensions: &[Option]) -> Vec self.enforce_resize_constraints_for_bsp(), Layout::Default(DefaultLayout::UltrawideVerticalStack) => { - self.enforce_resize_for_ultrawide() + self.enforce_resize_for_ultrawide(); } _ => self.enforce_no_resize(), } @@ -811,7 +811,7 @@ impl Workspace { } fn enforce_resize_for_ultrawide(&mut self) { - let mut resize_dimensions = self.resize_dimensions_mut(); + 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(), @@ -868,13 +868,11 @@ impl Workspace { } fn enforce_no_resize(&mut self) { - for rect in self.resize_dimensions_mut().iter_mut() { - if let Some(rect) = rect { - rect.left = 0; - rect.right = 0; - rect.top = 0; - rect.bottom = 0; - } + for rect in self.resize_dimensions_mut().iter_mut().flatten() { + rect.left = 0; + rect.right = 0; + rect.top = 0; + rect.bottom = 0; } }