use crate::process::DrawProcess;
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Frame {
grid: Grid,
}
impl Frame {
pub fn new(x_min: usize, y_min: usize, x_max: usize, y_max: usize) -> Frame {
Frame {
grid: Grid {
start_x: x_min,
start_y: y_min,
end_x: x_max,
end_y: y_max,
},
}
}
pub fn next_frame(&self) -> Grid {
self.grid.clone()
}
pub fn resize(&mut self, x_min: usize, y_min: usize, x_max: usize, y_max: usize) {
self.grid = Grid {
start_x: x_min,
start_y: y_min,
end_x: x_max,
end_y: y_max,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum Alignment {
Minus,
Plus,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
enum Maximum {
None,
X(usize, Alignment),
Y(usize, Alignment),
}
impl Default for Maximum {
fn default() -> Self {
Maximum::None
}
}
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Debug, Clone, PartialEq, Eq, Default, Hash)]
pub struct SplitStrategy {
min_size_x: Option<usize>,
min_size_y: Option<usize>,
max_size: Maximum,
}
impl SplitStrategy {
pub fn new() -> SplitStrategy {
SplitStrategy {
min_size_x: None,
min_size_y: None,
max_size: Maximum::None,
}
}
pub fn max_x(mut self, v: usize, a: Alignment) -> Self {
if matches!(self.max_size, Maximum::None) {
self.max_size = Maximum::X(v, a);
self
} else {
panic!("A maximum already exists!")
}
}
pub fn max_y(mut self, v: usize, a: Alignment) -> Self {
if matches!(self.max_size, Maximum::None) {
self.max_size = Maximum::Y(v, a);
self
} else {
panic!("A maximum already exists!")
}
}
pub fn min_x(mut self, v: usize) -> Self {
self.min_size_x = Some(v);
self
}
pub fn min_y(mut self, v: usize) -> Self {
self.min_size_y = Some(v);
self
}
#[doc(hidden)]
fn apply(&self, grid: &mut Grid) -> Option<Grid> {
if grid.start_x == grid.end_x || grid.start_y == grid.end_y {
return None;
}
if let Some(val) = self.min_size_y {
if grid.end_y <= grid.start_y + val {
return None;
}
}
if let Some(val) = self.min_size_x {
if grid.end_x <= grid.start_x + val {
return None;
}
}
match &self.max_size {
Maximum::None => {
let return_value = Some(Grid::new(grid.start_x, grid.start_y, grid.end_x, grid.end_y));
grid.start_x = grid.end_x;
grid.start_y = grid.end_y;
return_value
}
Maximum::X(size, alignment) => {
let size = *size;
let size = size.min(grid.end_x - grid.start_x);
if matches!(alignment, Alignment::Minus) {
let return_value = Some(Grid::new(grid.start_x, grid.start_y, grid.start_x + size, grid.end_y));
grid.start_x += size;
return_value
} else {
let return_value = Some(Grid::new(grid.end_x - size, grid.start_y, grid.end_x, grid.end_y));
grid.end_x -= size;
return_value
}
}
Maximum::Y(size, alignment) => {
let size = *size;
let size = size.min(grid.end_y - grid.start_y);
if matches!(alignment, Alignment::Minus) {
let return_value = Some(Grid::new(grid.start_x, grid.start_y, grid.end_x, grid.start_y + size));
grid.start_y += size;
return_value
} else {
let return_value = Some(Grid::new(grid.start_x, grid.end_y - size, grid.end_x, grid.end_y));
grid.end_y -= size;
return_value
}
}
}
}
}
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Grid {
pub start_x: usize,
pub start_y: usize,
pub end_x: usize,
pub end_y: usize,
}
impl Grid {
fn new(start_x: usize, start_y: usize, end_x: usize, end_y: usize) -> Grid {
Grid {
start_x,
start_y,
end_x,
end_y,
}
}
pub fn split(&mut self, strategy: &SplitStrategy) -> Option<Grid> {
strategy.apply(self)
}
pub fn extend(&mut self, grid: Grid) -> Result<(), Grid> {
if self.start_x == grid.start_x && self.end_x == grid.end_x {
if self.end_y == grid.start_y {
self.end_y = grid.end_y;
return Ok(())
}
if self.start_y == grid.end_y {
self.start_y = grid.start_y;
return Ok(())
}
}
if self.start_y == grid.start_y && self.end_y == grid.end_y {
if self.end_x == grid.start_x {
self.end_x = grid.end_x;
return Ok(())
}
if self.start_x == grid.end_x {
self.start_x = grid.start_x;
return Ok(())
}
}
Err(grid)
}
pub fn into_process(self, strategy: DividerStrategy) -> DrawProcess {
DrawProcess::new(self, strategy)
}
}
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum DividerStrategy {
Beginning,
End,
Halfway,
Pos(usize),
}