use crate::geometry::{Flip, Rect, Rotation, Split};
use std::{ops::Rem, vec};
use super::split::{dwindle, fibonacci, grid, horizontal, vertical};
pub fn divrem(a: usize, b: usize) -> (usize, usize) {
let division = a / b;
let remainder = a.rem(b);
(division, remainder)
}
pub fn remainderless_division(a: usize, b: usize) -> Vec<usize> {
let mut vec: Vec<usize> = vec![];
let (div, mut rem) = divrem(a, b);
for _ in 0..b {
let val = if rem > 0 {
rem -= 1;
div + 1
} else {
div
};
vec.push(val);
}
vec
}
pub fn flip(rects: &mut [Rect], flip: Flip, container: &Rect) {
if flip == Flip::None {
return;
}
for rect in rects.iter_mut() {
if flip.is_flipped_horizontal() {
let bottom_window_edge = rect.y + rect.h as i32;
let bottom_container_edge = container.y + container.h as i32;
rect.y = bottom_container_edge - bottom_window_edge;
}
if flip.is_flipped_vertical() {
let right_window_edge = rect.x + rect.w as i32;
let right_container_edge = container.x + container.w as i32;
rect.x = right_container_edge - right_window_edge;
}
}
}
pub fn rotate(rects: &mut [Rect], rotation: Rotation, container: &Rect) {
if rotation == Rotation::North {
return;
}
for rect in rects.iter_mut() {
rotate_single_rect(rect, rotation, container);
}
let n_rects = rects.len();
for i in 0..n_rects {
let mut wide_enough = true;
let mut high_enough = true;
for other in rects.iter() {
if other != &rects[i]
&& !other.contains((rects[i].x + rects[i].w as i32, rects[i].y + 1))
&& other.contains((rects[i].x + rects[i].w as i32 + 1, rects[i].y + 1))
{
wide_enough = false;
}
if other != &rects[i]
&& !other.contains((rects[i].x + 1, rects[i].y + rects[i].h as i32))
&& other.contains((rects[i].x + 1, rects[i].y + rects[i].w as i32 + 1))
{
high_enough = false;
}
}
if rects[i].x + rects[i].w as i32 + 1 == container.x + container.w as i32 {
wide_enough = false;
}
if rects[i].y + rects[i].h as i32 + 1 == container.y + container.h as i32 {
high_enough = false;
}
if !wide_enough && container.contains((rects[i].x + rects[i].w as i32 + 1, rects[i].y)) {
rects[i].w += 1;
}
if !high_enough && container.contains((rects[i].x, rects[i].y + rects[i].h as i32 + 1)) {
rects[i].h += 1;
}
}
}
fn rotate_single_rect(rect: &mut Rect, rotation: Rotation, container: &Rect) {
rect.x -= container.x;
rect.y -= container.y;
let next_anchor = rotation.next_anchor(rect);
match rotation {
Rotation::North => {}
Rotation::East => {
rect.x = container.h as i32 - next_anchor.1;
rect.y = next_anchor.0;
std::mem::swap(&mut rect.w, &mut rect.h);
}
Rotation::South => {
let next_anchor = rotation.next_anchor(rect);
rect.x = container.w as i32 - next_anchor.0;
rect.y = container.h as i32 - next_anchor.1;
}
Rotation::West => {
let next_anchor = rotation.next_anchor(rect);
rect.x = next_anchor.1;
rect.y = container.w as i32 - next_anchor.0;
std::mem::swap(&mut rect.w, &mut rect.h);
}
}
match rotation {
Rotation::North | Rotation::South => {}
Rotation::East | Rotation::West => {
rect.x *= container.w as i32;
rect.x /= container.h as i32;
rect.y *= container.h as i32;
rect.y /= container.w as i32;
rect.w *= container.w;
rect.w /= container.h;
rect.h *= container.h;
rect.h /= container.w;
}
}
rect.x += container.x;
rect.y += container.y;
}
pub fn split(rect: &Rect, amount: usize, axis: Option<Split>) -> Vec<Rect> {
match (amount, axis) {
(0, _) => vec![],
(_, None) => vec![*rect],
(_, Some(a)) => match a {
Split::Vertical => vertical(rect, amount),
Split::Horizontal => horizontal(rect, amount),
Split::Grid => grid(rect, amount),
Split::Fibonacci => fibonacci(rect, amount),
Split::Dwindle => dwindle(rect, amount),
},
}
}
#[cfg(test)]
mod tests {
use crate::{
geometry::calc::{divrem, flip, remainderless_division, split},
geometry::{Flip, Rect, Rotation, Split},
};
use super::rotate;
#[test]
fn divrem_100_by_3_gives_33_1() {
let result = divrem(100, 3);
assert_eq!(result, (33, 1));
}
#[test]
fn divrem_500_by_3_gives_166_2() {
let result = divrem(500, 3);
assert_eq!(result, (166, 2));
}
#[test]
fn remainderless_division_works_without_remainder() {
let result = remainderless_division(9, 3);
assert_eq!(vec![3, 3, 3], result);
}
#[test]
fn remainderless_division_works_with_remainders() {
let result = remainderless_division(5, 3);
assert_eq!(vec![2, 2, 1], result);
let result = remainderless_division(10, 3);
assert_eq!(vec![4, 3, 3], result);
let result = remainderless_division(29, 8);
assert_eq!(vec![4, 4, 4, 4, 4, 3, 3, 3], result);
}
const CONTAINER: Rect = Rect {
x: 0,
y: 0,
w: 400,
h: 200,
};
#[test]
fn split_by_zero() {
let rects = split(&CONTAINER, 0, Some(Split::Vertical));
assert_eq!(rects.len(), 0);
}
#[test]
fn split_single_window() {
let rects = split(&CONTAINER, 1, Some(Split::Vertical));
assert_eq!(rects.len(), 1);
assert!(rects[0].eq(&CONTAINER));
}
#[test]
fn flip_none() {
let container = Rect::new(0, 0, 400, 200);
let mut rects = vec![
Rect::new(0, 0, 400, 100),
Rect::new(200, 100, 200, 100),
Rect::new(0, 150, 200, 50),
Rect::new(0, 100, 200, 50),
];
flip(&mut rects, Flip::None, &container);
assert_eq!(
rects,
vec![
Rect::new(0, 0, 400, 100),
Rect::new(200, 100, 200, 100),
Rect::new(0, 150, 200, 50),
Rect::new(0, 100, 200, 50),
]
);
}
#[test]
fn flip_horizontal() {
let container = Rect::new(0, 0, 400, 200);
let mut rects = vec![
Rect::new(0, 0, 400, 100),
Rect::new(200, 100, 200, 100),
Rect::new(0, 150, 200, 50),
Rect::new(0, 100, 200, 50),
];
flip(&mut rects, Flip::Horizontal, &container);
assert_eq!(
rects,
vec![
Rect::new(0, 100, 400, 100),
Rect::new(200, 0, 200, 100),
Rect::new(0, 0, 200, 50),
Rect::new(0, 50, 200, 50),
]
);
}
#[test]
fn flip_vertical() {
let container = Rect::new(0, 0, 400, 200);
let mut rects = vec![
Rect::new(0, 0, 400, 100),
Rect::new(200, 100, 200, 100),
Rect::new(0, 150, 200, 50),
Rect::new(0, 100, 200, 50),
];
flip(&mut rects, Flip::Vertical, &container);
assert_eq!(
rects,
vec![
Rect::new(0, 0, 400, 100),
Rect::new(0, 100, 200, 100),
Rect::new(200, 150, 200, 50),
Rect::new(200, 100, 200, 50),
]
);
}
#[test]
fn flip_both() {
let container = Rect::new(0, 0, 400, 200);
let mut rects = vec![
Rect::new(0, 0, 400, 100),
Rect::new(200, 100, 200, 100),
Rect::new(0, 150, 200, 50),
Rect::new(0, 100, 200, 50),
];
flip(&mut rects, Flip::Both, &container);
assert_eq!(
rects,
vec![
Rect::new(0, 100, 400, 100),
Rect::new(0, 0, 200, 100),
Rect::new(200, 0, 200, 50),
Rect::new(200, 50, 200, 50),
]
);
}
#[test]
fn rotate_0_degrees() {
let container = Rect::new(0, 0, 400, 200);
let mut rects = vec![
Rect::new(0, 0, 400, 100),
Rect::new(200, 100, 200, 100),
Rect::new(0, 150, 200, 50),
Rect::new(0, 100, 200, 50),
];
rotate(&mut rects, Rotation::North, &container);
assert_eq!(
rects,
vec![
Rect::new(0, 0, 400, 100),
Rect::new(200, 100, 200, 100),
Rect::new(0, 150, 200, 50),
Rect::new(0, 100, 200, 50),
]
);
}
#[test]
fn rotate_90_degrees() {
let container = Rect::new(0, 0, 400, 200);
let mut rects = vec![
Rect::new(0, 0, 400, 100),
Rect::new(200, 100, 200, 100),
Rect::new(0, 150, 200, 50),
Rect::new(0, 100, 200, 50),
];
rotate(&mut rects, Rotation::East, &container);
assert_eq!(
rects,
vec![
Rect::new(200, 0, 200, 200),
Rect::new(0, 100, 200, 100),
Rect::new(0, 0, 100, 100),
Rect::new(100, 0, 100, 100),
]
);
}
#[test]
fn rotate_180_degrees() {
let container = Rect::new(0, 0, 400, 200);
let mut rects = vec![
Rect::new(0, 0, 400, 100),
Rect::new(200, 100, 200, 100),
Rect::new(0, 150, 200, 50),
Rect::new(0, 100, 200, 50),
];
rotate(&mut rects, Rotation::South, &container);
assert_eq!(
rects,
vec![
Rect::new(0, 100, 400, 100),
Rect::new(0, 0, 200, 100),
Rect::new(200, 0, 200, 50),
Rect::new(200, 50, 200, 50),
]
);
}
#[test]
fn rotate_270_degrees() {
let container = Rect::new(0, 0, 400, 200);
let mut rects = vec![
Rect::new(0, 0, 400, 100),
Rect::new(200, 100, 200, 100),
Rect::new(0, 150, 200, 50),
Rect::new(0, 100, 200, 50),
];
rotate(&mut rects, Rotation::West, &container);
assert_eq!(
rects,
vec![
Rect::new(0, 0, 200, 200),
Rect::new(200, 0, 200, 100),
Rect::new(300, 100, 100, 100),
Rect::new(200, 100, 100, 100),
]
);
}
#[test]
fn rotate_0_degrees_with_offset() {
let container = Rect::new(200, 50, 400, 200);
let mut rects = vec![
Rect::new(200, 50, 400, 100),
Rect::new(400, 150, 200, 100),
Rect::new(200, 200, 200, 50),
Rect::new(200, 150, 200, 50),
];
rotate(&mut rects, Rotation::North, &container);
assert_eq!(
rects,
vec![
Rect::new(200, 50, 400, 100),
Rect::new(400, 150, 200, 100),
Rect::new(200, 200, 200, 50),
Rect::new(200, 150, 200, 50),
]
);
}
#[test]
fn rotate_90_degrees_with_offset() {
let container = Rect::new(200, 50, 400, 200);
let mut rects = vec![
Rect::new(200, 50, 400, 100),
Rect::new(400, 150, 200, 100),
Rect::new(200, 200, 200, 50),
Rect::new(200, 150, 200, 50),
];
rotate(&mut rects, Rotation::East, &container);
assert_eq!(
rects,
vec![
Rect::new(400, 50, 200, 200),
Rect::new(200, 150, 200, 100),
Rect::new(200, 50, 100, 100),
Rect::new(300, 50, 100, 100),
]
);
}
#[test]
fn rotate_180_degrees_with_offset() {
let container = Rect::new(200, 50, 400, 200);
let mut rects = vec![
Rect::new(200, 50, 400, 100),
Rect::new(400, 150, 200, 100),
Rect::new(200, 200, 200, 50),
Rect::new(200, 150, 200, 50),
];
rotate(&mut rects, Rotation::South, &container);
assert_eq!(
rects,
vec![
Rect::new(200, 150, 400, 100),
Rect::new(200, 50, 200, 100),
Rect::new(400, 50, 200, 50),
Rect::new(400, 100, 200, 50),
]
);
}
#[test]
fn rotate_270_degrees_with_offset() {
let container = Rect::new(200, 50, 400, 200);
let mut rects = vec![
Rect::new(200, 50, 400, 100),
Rect::new(400, 150, 200, 100),
Rect::new(200, 200, 200, 50),
Rect::new(200, 150, 200, 50),
];
rotate(&mut rects, Rotation::West, &container);
assert_eq!(
rects,
vec![
Rect::new(200, 50, 200, 200),
Rect::new(400, 50, 200, 100),
Rect::new(500, 150, 100, 100),
Rect::new(400, 150, 100, 100),
]
);
}
#[test]
fn rotate_90_degrees_non_divisible() {
let container = Rect::new(0, 0, 401, 100);
let mut rects = vec![Rect::new(0, 0, 201, 100), Rect::new(201, 0, 200, 100)];
rotate(&mut rects, Rotation::East, &container);
assert_eq!(
rects,
vec![Rect::new(0, 0, 401, 50), Rect::new(0, 50, 401, 50)]
);
}
}