Skip to content

Commit

Permalink
feat(wm): ultrawide layout resizing (#545)
Browse files Browse the repository at this point in the history
* 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

* Add resize constraints for UltrawideVerticalStack layout

Add Workspace::enforce_resize_for_ultrawide method to apply resize
constraints for ultrawide vertical stack layout.

* 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

* feat(wm): Enable ultrawide layout in DefaultLayout::resize

* feat(wm): refactor ultrawide resize calculation

Add some helper function and descriptive variable names in calculate_ultrawide_adjustment
Apply clippy lints
  • Loading branch information
NotLebedev authored Oct 7, 2023
1 parent b048e7c commit e5a8146
Show file tree
Hide file tree
Showing 3 changed files with 265 additions and 80 deletions.
267 changes: 188 additions & 79 deletions komorebi-core/src/arrangement.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,85 +130,7 @@ impl Arrangement for DefaultLayout {

layouts
}
Self::UltrawideVerticalStack => {
let mut layouts: Vec<Rect> = 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
Expand Down Expand Up @@ -586,3 +508,190 @@ fn recursive_fibonacci(
res
}
}

fn calculate_ultrawide_adjustment(resize_dimensions: &[Option<Rect>]) -> Vec<Rect> {
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<Axis>,
resize_dimensions: &[Option<Rect>],
) -> Vec<Rect> {
let mut layouts: Vec<Rect> = 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
}
2 changes: 1 addition & 1 deletion komorebi-core/src/default_layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ impl DefaultLayout {
sizing: Sizing,
delta: i32,
) -> Option<Rect> {
if !matches!(self, Self::BSP) {
if !matches!(self, Self::BSP) && !matches!(self, Self::UltrawideVerticalStack) {
return None;
};

Expand Down
76 changes: 76 additions & 0 deletions komorebi/src/workspace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down

0 comments on commit e5a8146

Please sign in to comment.