diff --git a/Cargo.lock b/Cargo.lock index c3717904..8082e30d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -199,9 +199,9 @@ checksum = "fb58b6451e8c2a812ad979ed1d83378caa5e927eef2622017a45f251457c2c9d" [[package]] name = "core-foundation-sys" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea221b5284a47e40033bf9b66f35f984ec0ea2931eb03505246cd27a963f981b" +checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" [[package]] name = "crossbeam-channel" @@ -425,9 +425,9 @@ dependencies = [ [[package]] name = "hotwatch" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d61ee702e77f237b41761361a82e5c4bf6277dbb4bc8b6b7d745cb249cc82b31" +checksum = "39301670a6f5798b75f36a1b149a379a50df5aa7c71be50f4b41ec6eab445cb8" dependencies = [ "log", "notify", @@ -853,9 +853,9 @@ checksum = "36d62894f5590e88d99d0d82918742ba8e5bff1985af15d4906b6a65f635adb2" [[package]] name = "ppv-lite86" -version = "0.2.10" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" +checksum = "c3ca011bd0129ff4ae15cd04c4eef202cadf6c51c21e47aba319b4e0501db741" [[package]] name = "proc-macro-error" @@ -883,9 +883,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.29" +version = "1.0.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9f5105d4fdaab20335ca9565e106a5d9b82b6219b5ba735731124ac6711d23d" +checksum = "edc3358ebc67bc8b7fa0c007f945b0b18226f78437d61bec735a9eb96b61ee70" dependencies = [ "unicode-xid", ] @@ -1113,18 +1113,18 @@ dependencies = [ [[package]] name = "sharded-slab" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "740223c51853f3145fe7c90360d2d4232f2b62e3449489c207eccde818979982" +checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31" dependencies = [ "lazy_static", ] [[package]] name = "slab" -version = "0.4.4" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c307a32c1c5c437f38c7fd45d753050587732ba8628319fbdf12a7e289ccc590" +checksum = "9def91fd1e018fe007022791f865d0ccc9b3a0d5001e01aabb8b40e46000afb5" [[package]] name = "smallvec" diff --git a/README.md b/README.md index c5836483..9e761ffc 100644 --- a/README.md +++ b/README.md @@ -306,9 +306,13 @@ used [is available here](komorebi.sample.with.lib.ahk). - [x] Mouse drag to swap window container position - [x] Mouse drag to resize window container - [x] Configurable workspace and container gaps -- [x] BSP tree layout +- [x] BSP tree layout (`bsp`) - [x] Flip BSP tree layout horizontally or vertically -- [x] Equal-width, max-height column layout +- [x] Equal-width, max-height column layout (`columns`) +- [x] Equal-height, max-width row layout (`rows`) +- [x] Main half-height window with vertical stack layout (`horizontal-stack`) +- [x] Main half-width window with horizontal stack layout (`vertical-stack`) +- [x] 2x Main window (half and quarter-width) with horizontal stack layout (`ultrawide-vertical-stack`) - [x] Floating rules based on exe name, window title and class - [x] Workspace rules based on exe name and window class - [x] Additional manage rules based on exe name and window class diff --git a/komorebi-core/src/layout.rs b/komorebi-core/src/layout.rs index b975033d..a718606f 100644 --- a/komorebi-core/src/layout.rs +++ b/komorebi-core/src/layout.rs @@ -16,6 +16,9 @@ pub enum Layout { BSP, Columns, Rows, + VerticalStack, + HorizontalStack, + UltrawideVerticalStack, } #[derive(Clone, Copy, Debug, Serialize, Deserialize, Display, EnumString, ArgEnum)] @@ -131,7 +134,11 @@ impl Layout { } #[must_use] - #[allow(clippy::cast_possible_truncation, clippy::cast_possible_wrap)] + #[allow( + clippy::cast_possible_truncation, + clippy::cast_possible_wrap, + clippy::too_many_lines + )] pub fn calculate( &self, area: &Rect, @@ -185,6 +192,176 @@ impl Layout { layouts } + Layout::VerticalStack => { + let mut layouts: Vec = vec![]; + layouts.resize(len, Rect::default()); + + let primary_right = match len { + 1 => area.right, + _ => area.right / 2, + }; + + let mut main_left = area.left; + let mut stack_left = area.left + primary_right; + + match layout_flip { + Some(Flip::Horizontal | Flip::HorizontalAndVertical) if len > 1 => { + main_left = main_left + area.right - primary_right; + stack_left = area.left; + } + _ => {} + } + + let mut iter = layouts.iter_mut(); + { + if let Some(first) = iter.next() { + first.left = main_left; + first.top = area.top; + first.right = primary_right; + first.bottom = area.bottom; + } + } + + let bottom = area.bottom / (len - 1) as i32; + let mut top = 0; + + for next in iter { + next.left = stack_left; + next.top = area.top + top; + next.right = area.right - primary_right; + next.bottom = bottom; + + top += bottom; + } + + layouts + } + Layout::HorizontalStack => { + let mut layouts: Vec = vec![]; + layouts.resize(len, Rect::default()); + + let bottom = match len { + 1 => area.bottom, + _ => area.bottom / 2, + }; + + let mut main_top = area.top; + let mut stack_top = area.top + bottom; + + match layout_flip { + Some(Flip::Vertical | Flip::HorizontalAndVertical) if len > 1 => { + main_top = main_top + area.bottom - bottom; + stack_top = area.top; + } + _ => {} + } + + let mut iter = layouts.iter_mut(); + { + if let Some(first) = iter.next() { + first.left = area.left; + first.top = main_top; + first.right = area.right; + first.bottom = bottom; + } + } + + let right = area.right / (len - 1) as i32; + let mut left = 0; + + for next in iter { + next.left = area.left + left; + next.top = stack_top; + next.right = right; + next.bottom = area.bottom - bottom; + + left += right; + } + + layouts + } + Layout::UltrawideVerticalStack => { + let mut layouts: Vec = vec![]; + layouts.resize(len, Rect::default()); + + 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(Flip::Horizontal | Flip::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(Flip::Horizontal | Flip::HorizontalAndVertical) if len > 1 => { + secondary = area.left + primary_right + secondary_right; + stack = area.left; + } + _ => {} + } + + (primary, secondary, stack) + } + }; + + let mut iter = layouts.iter_mut(); + + { + if let Some(first) = iter.next() { + first.left = primary_left; + first.top = area.top; + first.right = primary_right; + first.bottom = area.bottom; + } + } + + { + if let Some(second) = iter.next() { + second.left = secondary_left; + second.top = area.top; + second.right = secondary_right; + second.bottom = area.bottom; + } + } + + if len > 2 { + let height = area.bottom / (len - 2) as i32; + let mut y = 0; + + for next in iter { + next.left = stack_left; + next.top = area.top + y; + next.right = secondary_right; + next.bottom = height; + y += height; + } + } + layouts + } }; dimensions diff --git a/komorebi-core/src/operation_direction.rs b/komorebi-core/src/operation_direction.rs index c4f3826b..f380dfa8 100644 --- a/komorebi-core/src/operation_direction.rs +++ b/komorebi-core/src/operation_direction.rs @@ -60,22 +60,36 @@ impl OperationDirection { Self::Up => match layout { Layout::BSP => len > 2 && idx != 0 && idx != 1, Layout::Columns => false, - Layout::Rows => idx != 0, + Layout::Rows | Layout::HorizontalStack => idx != 0, + Layout::VerticalStack => idx != 0 && idx != 1, + Layout::UltrawideVerticalStack => idx > 2, }, Self::Down => match layout { Layout::BSP => len > 2 && idx != len - 1 && idx % 2 != 0, Layout::Columns => false, Layout::Rows => idx != len - 1, + Layout::VerticalStack => idx != 0 && idx != len - 1, + Layout::HorizontalStack => idx == 0, + Layout::UltrawideVerticalStack => idx > 1 && idx != len - 1, }, Self::Left => match layout { Layout::BSP => len > 1 && idx != 0, - Layout::Columns => idx != 0, + Layout::Columns | Layout::VerticalStack => idx != 0, Layout::Rows => false, + Layout::HorizontalStack => idx != 0 && idx != 1, + Layout::UltrawideVerticalStack => len > 1 && idx != 1, }, Self::Right => match layout { Layout::BSP => len > 1 && idx % 2 == 0 && idx != len - 1, Layout::Columns => idx != len - 1, Layout::Rows => false, + Layout::VerticalStack => idx == 0, + Layout::HorizontalStack => idx != 0 && idx != len - 1, + Layout::UltrawideVerticalStack => match len { + 0 | 1 => false, + 2 => idx != 0, + _ => idx < 2, + }, }, } } @@ -92,11 +106,16 @@ impl OperationDirection { } } Layout::Columns => unreachable!(), - Layout::Rows => idx - 1, + Layout::Rows | Layout::VerticalStack | Layout::UltrawideVerticalStack => idx - 1, + Layout::HorizontalStack => 0, }, Self::Down => match layout { - Layout::BSP | Layout::Rows => idx + 1, + Layout::BSP + | Layout::Rows + | Layout::VerticalStack + | Layout::UltrawideVerticalStack => idx + 1, Layout::Columns => unreachable!(), + Layout::HorizontalStack => 1, }, Self::Left => match layout { Layout::BSP => { @@ -106,12 +125,24 @@ impl OperationDirection { idx - 1 } } - Layout::Columns => idx - 1, + Layout::Columns | Layout::HorizontalStack => idx - 1, Layout::Rows => unreachable!(), + Layout::VerticalStack => 0, + Layout::UltrawideVerticalStack => match idx { + 0 => 1, + 1 => unreachable!(), + _ => 0, + }, }, Self::Right => match layout { - Layout::BSP | Layout::Columns => idx + 1, + Layout::BSP | Layout::Columns | Layout::HorizontalStack => idx + 1, Layout::Rows => unreachable!(), + Layout::VerticalStack => 1, + Layout::UltrawideVerticalStack => match idx { + 1 => 0, + 0 => 2, + _ => unreachable!(), + }, }, } }