mirror of
https://github.com/LGUG2Z/komorebi.git
synced 2026-03-27 20:01:14 +01:00
Realised that I hadn't turned on super pedantic mode for clippy in the komorebi-core and komorebic crates. This commit ensures the same clippy config across all crates and applies the lint suggestions that arose as a result of turning on the same config everywhere.
389 lines
12 KiB
Rust
389 lines
12 KiB
Rust
use std::num::NonZeroUsize;
|
|
|
|
use clap::ArgEnum;
|
|
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, ArgEnum)]
|
|
#[strum(serialize_all = "snake_case")]
|
|
pub enum Layout {
|
|
BSP,
|
|
Columns,
|
|
Rows,
|
|
}
|
|
|
|
#[derive(Clone, Copy, Debug, Serialize, Deserialize, Display, EnumString, ArgEnum)]
|
|
#[strum(serialize_all = "snake_case")]
|
|
pub enum Flip {
|
|
Horizontal,
|
|
Vertical,
|
|
HorizontalAndVertical,
|
|
}
|
|
|
|
impl Layout {
|
|
#[must_use]
|
|
#[allow(clippy::cast_precision_loss)]
|
|
pub fn resize(
|
|
&self,
|
|
unaltered: &Rect,
|
|
resize: &Option<Rect>,
|
|
edge: OperationDirection,
|
|
sizing: Sizing,
|
|
step: Option<i32>,
|
|
) -> Option<Rect> {
|
|
if !matches!(self, Self::BSP) {
|
|
return None;
|
|
};
|
|
|
|
let max_divisor = 1.005;
|
|
let mut r = resize.unwrap_or_default();
|
|
|
|
let resize_step = step.unwrap_or(50);
|
|
|
|
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_step) as f32).abs();
|
|
let max = unaltered.right as f32 / max_divisor;
|
|
if diff < max {
|
|
r.left += -resize_step;
|
|
}
|
|
}
|
|
Sizing::Decrease => {
|
|
let diff = ((r.left - -resize_step) as f32).abs();
|
|
let max = unaltered.right as f32 / max_divisor;
|
|
if diff < max {
|
|
r.left -= -resize_step;
|
|
}
|
|
}
|
|
},
|
|
OperationDirection::Up => match sizing {
|
|
Sizing::Increase => {
|
|
let diff = ((r.top + resize_step) as f32).abs();
|
|
let max = unaltered.bottom as f32 / max_divisor;
|
|
if diff < max {
|
|
r.top += -resize_step;
|
|
}
|
|
}
|
|
Sizing::Decrease => {
|
|
let diff = ((r.top - resize_step) as f32).abs();
|
|
let max = unaltered.bottom as f32 / max_divisor;
|
|
if diff < max {
|
|
r.top -= -resize_step;
|
|
}
|
|
}
|
|
},
|
|
OperationDirection::Right => match sizing {
|
|
Sizing::Increase => {
|
|
let diff = ((r.right + resize_step) as f32).abs();
|
|
let max = unaltered.right as f32 / max_divisor;
|
|
if diff < max {
|
|
r.right += resize_step;
|
|
}
|
|
}
|
|
Sizing::Decrease => {
|
|
let diff = ((r.right - resize_step) as f32).abs();
|
|
let max = unaltered.right as f32 / max_divisor;
|
|
if diff < max {
|
|
r.right -= resize_step;
|
|
}
|
|
}
|
|
},
|
|
OperationDirection::Down => match sizing {
|
|
Sizing::Increase => {
|
|
let diff = ((r.bottom + resize_step) as f32).abs();
|
|
let max = unaltered.bottom as f32 / max_divisor;
|
|
if diff < max {
|
|
r.bottom += resize_step;
|
|
}
|
|
}
|
|
Sizing::Decrease => {
|
|
let diff = ((r.bottom - resize_step) as f32).abs();
|
|
let max = unaltered.bottom as f32 / max_divisor;
|
|
if diff < max {
|
|
r.bottom -= resize_step;
|
|
}
|
|
}
|
|
},
|
|
};
|
|
|
|
if r.eq(&Rect::default()) {
|
|
None
|
|
} else {
|
|
Option::from(r)
|
|
}
|
|
}
|
|
|
|
#[must_use]
|
|
#[allow(clippy::cast_possible_truncation, clippy::cast_possible_wrap)]
|
|
pub fn calculate(
|
|
&self,
|
|
area: &Rect,
|
|
len: NonZeroUsize,
|
|
container_padding: Option<i32>,
|
|
layout_flip: Option<Flip>,
|
|
resize_dimensions: &[Option<Rect>],
|
|
) -> Vec<Rect> {
|
|
let len = usize::from(len);
|
|
let mut dimensions = match self {
|
|
Layout::BSP => recursive_fibonacci(
|
|
0,
|
|
len,
|
|
area,
|
|
layout_flip,
|
|
calculate_resize_adjustments(resize_dimensions),
|
|
),
|
|
Layout::Columns => {
|
|
let right = area.right / len as i32;
|
|
let mut left = 0;
|
|
|
|
let mut layouts: Vec<Rect> = vec![];
|
|
for _ in 0..len {
|
|
layouts.push(Rect {
|
|
left: area.left + left,
|
|
top: area.top,
|
|
right,
|
|
bottom: area.bottom,
|
|
});
|
|
|
|
left += right;
|
|
}
|
|
|
|
layouts
|
|
}
|
|
Layout::Rows => {
|
|
let bottom = area.bottom / len as i32;
|
|
let mut top = 0;
|
|
|
|
let mut layouts: Vec<Rect> = vec![];
|
|
for _ in 0..len {
|
|
layouts.push(Rect {
|
|
left: area.left,
|
|
top: area.top + top,
|
|
right: area.right,
|
|
bottom,
|
|
});
|
|
|
|
top += bottom;
|
|
}
|
|
|
|
layouts
|
|
}
|
|
};
|
|
|
|
dimensions
|
|
.iter_mut()
|
|
.for_each(|l| l.add_padding(container_padding));
|
|
|
|
dimensions
|
|
}
|
|
}
|
|
|
|
fn calculate_resize_adjustments(resize_dimensions: &[Option<Rect>]) -> Vec<Option<Rect>> {
|
|
let mut resize_adjustments = resize_dimensions.to_vec();
|
|
|
|
// This needs to be aware of layout flips
|
|
for (i, opt) in resize_dimensions.iter().enumerate() {
|
|
if let Some(resize_ref) = opt {
|
|
if i > 0 {
|
|
if resize_ref.left != 0 {
|
|
#[allow(clippy::if_not_else)]
|
|
let range = if i == 1 {
|
|
0..1
|
|
} else if i & 1 != 0 {
|
|
i - 1..i
|
|
} else {
|
|
i - 2..i
|
|
};
|
|
|
|
for n in range {
|
|
let should_adjust = n % 2 == 0;
|
|
if should_adjust {
|
|
if let Some(Some(adjacent_resize)) = resize_adjustments.get_mut(n) {
|
|
adjacent_resize.right += resize_ref.left;
|
|
} else {
|
|
resize_adjustments[n] = Option::from(Rect {
|
|
left: 0,
|
|
top: 0,
|
|
right: resize_ref.left,
|
|
bottom: 0,
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
if let Some(rr) = resize_adjustments[i].as_mut() {
|
|
rr.left = 0;
|
|
}
|
|
}
|
|
|
|
if resize_ref.top != 0 {
|
|
let range = if i == 1 {
|
|
0..1
|
|
} else if i & 1 == 0 {
|
|
i - 1..i
|
|
} else {
|
|
i - 2..i
|
|
};
|
|
|
|
for n in range {
|
|
let should_adjust = n % 2 != 0;
|
|
if should_adjust {
|
|
if let Some(Some(adjacent_resize)) = resize_adjustments.get_mut(n) {
|
|
adjacent_resize.bottom += resize_ref.top;
|
|
} else {
|
|
resize_adjustments[n] = Option::from(Rect {
|
|
left: 0,
|
|
top: 0,
|
|
right: 0,
|
|
bottom: resize_ref.top,
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
if let Some(Some(resize)) = resize_adjustments.get_mut(i) {
|
|
resize.top = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
let cleaned_resize_adjustments: Vec<_> = resize_adjustments
|
|
.iter()
|
|
.map(|adjustment| match adjustment {
|
|
None => None,
|
|
Some(rect) if rect.eq(&Rect::default()) => None,
|
|
Some(_) => *adjustment,
|
|
})
|
|
.collect();
|
|
|
|
cleaned_resize_adjustments
|
|
}
|
|
|
|
fn recursive_fibonacci(
|
|
idx: usize,
|
|
count: usize,
|
|
area: &Rect,
|
|
layout_flip: Option<Flip>,
|
|
resize_adjustments: Vec<Option<Rect>>,
|
|
) -> Vec<Rect> {
|
|
let mut a = *area;
|
|
|
|
let resized = if let Some(Some(r)) = resize_adjustments.get(idx) {
|
|
a.left += r.left;
|
|
a.top += r.top;
|
|
a.right += r.right;
|
|
a.bottom += r.bottom;
|
|
a
|
|
} else {
|
|
*area
|
|
};
|
|
|
|
let half_width = area.right / 2;
|
|
let half_height = area.bottom / 2;
|
|
let half_resized_width = resized.right / 2;
|
|
let half_resized_height = resized.bottom / 2;
|
|
|
|
let (main_x, alt_x, alt_y, main_y);
|
|
|
|
if let Some(flip) = layout_flip {
|
|
match flip {
|
|
Flip::Horizontal => {
|
|
main_x = resized.left + half_width + (half_width - half_resized_width);
|
|
alt_x = resized.left;
|
|
|
|
alt_y = resized.top + half_resized_height;
|
|
main_y = resized.top;
|
|
}
|
|
Flip::Vertical => {
|
|
main_y = resized.top + half_height + (half_height - half_resized_height);
|
|
alt_y = resized.top;
|
|
|
|
main_x = resized.left;
|
|
alt_x = resized.left + half_resized_width;
|
|
}
|
|
Flip::HorizontalAndVertical => {
|
|
main_x = resized.left + half_width + (half_width - half_resized_width);
|
|
alt_x = resized.left;
|
|
main_y = resized.top + half_height + (half_height - half_resized_height);
|
|
alt_y = resized.top;
|
|
}
|
|
}
|
|
} else {
|
|
main_x = resized.left;
|
|
alt_x = resized.left + half_resized_width;
|
|
main_y = resized.top;
|
|
alt_y = resized.top + half_resized_height;
|
|
}
|
|
|
|
#[allow(clippy::if_not_else)]
|
|
if count == 0 {
|
|
vec![]
|
|
} else if count == 1 {
|
|
vec![Rect {
|
|
left: resized.left,
|
|
top: resized.top,
|
|
right: resized.right,
|
|
bottom: resized.bottom,
|
|
}]
|
|
} else if idx % 2 != 0 {
|
|
let mut res = vec![Rect {
|
|
left: resized.left,
|
|
top: main_y,
|
|
right: resized.right,
|
|
bottom: half_resized_height,
|
|
}];
|
|
res.append(&mut recursive_fibonacci(
|
|
idx + 1,
|
|
count - 1,
|
|
&Rect {
|
|
left: area.left,
|
|
top: alt_y,
|
|
right: area.right,
|
|
bottom: area.bottom - half_resized_height,
|
|
},
|
|
layout_flip,
|
|
resize_adjustments,
|
|
));
|
|
res
|
|
} else {
|
|
let mut res = vec![Rect {
|
|
left: main_x,
|
|
top: resized.top,
|
|
right: half_resized_width,
|
|
bottom: resized.bottom,
|
|
}];
|
|
res.append(&mut recursive_fibonacci(
|
|
idx + 1,
|
|
count - 1,
|
|
&Rect {
|
|
left: alt_x,
|
|
top: area.top,
|
|
right: area.right - half_resized_width,
|
|
bottom: area.bottom,
|
|
},
|
|
layout_flip,
|
|
resize_adjustments,
|
|
));
|
|
res
|
|
}
|
|
}
|