use clap::ValueEnum; use schemars::JsonSchema; use serde::Deserialize; use serde::Serialize; use strum::Display; use strum::EnumString; use crate::OperationDirection; use crate::Rect; use crate::Sizing; #[derive( Clone, Copy, Debug, Serialize, Deserialize, Display, EnumString, ValueEnum, JsonSchema, )] #[strum(serialize_all = "snake_case")] pub enum DefaultLayout { BSP, Columns, Rows, VerticalStack, HorizontalStack, UltrawideVerticalStack, Grid, // NOTE: If any new layout is added, please make sure to register the same in `DefaultLayout::cycle` } impl DefaultLayout { #[must_use] #[allow(clippy::cast_precision_loss, clippy::only_used_in_recursion)] pub fn resize( &self, unaltered: &Rect, resize: &Option, edge: OperationDirection, sizing: Sizing, delta: i32, ) -> Option { if !matches!(self, Self::BSP) && !matches!(self, Self::UltrawideVerticalStack) { return None; }; let max_divisor = 1.005; let mut r = resize.unwrap_or_default(); let resize_delta = delta; match edge { OperationDirection::Left => match sizing { Sizing::Increase => { // Some final checks to make sure the user can't infinitely resize to // the point of pushing other windows out of bounds // Note: These checks cannot take into account the changes made to the // edges of adjacent windows at operation time, so it is still possible // to push windows out of bounds by maxing out an Increase Left on a // Window with index 1, and then maxing out a Decrease Right on a Window // with index 0. I don't think it's worth trying to defensively program // against this; if people end up in this situation they are better off // just hitting the retile command let diff = ((r.left + -resize_delta) as f32).abs(); let max = unaltered.right as f32 / max_divisor; if diff < max { r.left += -resize_delta; } } Sizing::Decrease => { let diff = ((r.left - -resize_delta) as f32).abs(); let max = unaltered.right as f32 / max_divisor; if diff < max { r.left -= -resize_delta; } } }, OperationDirection::Up => match sizing { Sizing::Increase => { let diff = ((r.top + resize_delta) as f32).abs(); let max = unaltered.bottom as f32 / max_divisor; if diff < max { r.top += -resize_delta; } } Sizing::Decrease => { let diff = ((r.top - resize_delta) as f32).abs(); let max = unaltered.bottom as f32 / max_divisor; if diff < max { r.top -= -resize_delta; } } }, OperationDirection::Right => match sizing { Sizing::Increase => { let diff = ((r.right + resize_delta) as f32).abs(); let max = unaltered.right as f32 / max_divisor; if diff < max { r.right += resize_delta; } } Sizing::Decrease => { let diff = ((r.right - resize_delta) as f32).abs(); let max = unaltered.right as f32 / max_divisor; if diff < max { r.right -= resize_delta; } } }, OperationDirection::Down => match sizing { Sizing::Increase => { let diff = ((r.bottom + resize_delta) as f32).abs(); let max = unaltered.bottom as f32 / max_divisor; if diff < max { r.bottom += resize_delta; } } Sizing::Decrease => { let diff = ((r.bottom - resize_delta) as f32).abs(); let max = unaltered.bottom as f32 / max_divisor; if diff < max { r.bottom -= resize_delta; } } }, }; if r.eq(&Rect::default()) { None } else { Option::from(r) } } #[must_use] pub const fn cycle_next(self) -> Self { match self { Self::BSP => Self::Columns, Self::Columns => Self::Rows, Self::Rows => Self::VerticalStack, Self::VerticalStack => Self::HorizontalStack, Self::HorizontalStack => Self::UltrawideVerticalStack, Self::UltrawideVerticalStack => Self::Grid, Self::Grid => Self::BSP, } } #[must_use] pub const fn cycle_previous(self) -> Self { match self { Self::BSP => Self::UltrawideVerticalStack, Self::UltrawideVerticalStack => Self::HorizontalStack, Self::HorizontalStack => Self::VerticalStack, Self::VerticalStack => Self::Rows, Self::Rows => Self::Columns, Self::Columns => Self::Grid, Self::Grid => Self::BSP, } } }