use std::cmp;
use serde::{Deserialize, Serialize};
use crate::geometry::{Flip, Reserve, Rotation, Size, Split};
use super::defaults::{
center_main, center_main_balanced, center_main_fluid, dwindle, even_horizontal, even_vertical,
fibonacci, grid, main_and_deck, main_and_horizontal_stack, main_and_vert_stack, monocle,
right_main_and_vert_stack,
};
const DEFAULT_MAIN_SIZE_CHANGE_PIXEL: i32 = 50;
const DEFAULT_MAIN_SIZE_CHANGE_PERCENTAGE: i32 = 5;
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Layouts {
pub layouts: Vec<Layout>,
}
impl Eq for Layouts {}
impl Layouts {
pub fn get(&self, name: &str) -> Option<&Layout> {
self.layouts.iter().find(|&l| l.name.as_str() == name)
}
pub fn get_mut<'a>(&'a mut self, name: &str) -> Option<&'a mut Layout> {
self.layouts.iter_mut().find(|l| l.name.as_str() == name)
}
pub fn names(&self) -> Vec<String> {
self.layouts.iter().map(|x| x.name.clone()).collect()
}
pub fn len(&self) -> usize {
self.layouts.len()
}
pub fn is_empty(&self) -> bool {
self.layouts.is_empty()
}
pub fn get_index(&self, name: &str) -> Option<usize> {
self.layouts.iter().position(|l| l.name.as_str() == name)
}
}
impl Default for Layouts {
fn default() -> Self {
Self {
layouts: vec![
even_horizontal(),
even_vertical(),
monocle(),
grid(),
main_and_vert_stack(),
main_and_horizontal_stack(),
right_main_and_vert_stack(),
fibonacci(),
dwindle(),
main_and_deck(),
center_main(),
center_main_balanced(),
center_main_fluid(),
],
}
}
}
type LayoutName = String;
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
#[serde(default)]
pub struct Layout {
pub name: LayoutName,
pub flip: Flip,
pub rotate: Rotation,
pub reserve: Reserve,
pub columns: Columns,
}
impl Layout {
pub fn is_monocle(&self) -> bool {
self.columns.main.is_none()
&& self.columns.second_stack.is_none()
&& self.columns.stack.split.is_none()
}
pub fn is_main_and_deck(&self) -> bool {
match &self.columns.main {
Some(main) => {
self.columns.second_stack.is_none()
&& main.split.is_none()
&& self.columns.stack.split.is_none()
}
None => false,
}
}
pub fn main_size(&self) -> Option<Size> {
self.columns.main.as_ref().map(|m| m.size)
}
pub fn main_window_count(&self) -> Option<usize> {
self.columns.main.as_ref().map(|m| m.count)
}
pub fn set_main_size(&mut self, size: Size) {
if let Some(main) = self.columns.main.as_mut() {
main.size = size;
}
}
pub fn increase_main_size(&mut self, upper_bound: i32) {
if let Some(main) = self.columns.main.as_mut() {
match main.size {
Size::Pixel(_) => {
self.change_main_size(DEFAULT_MAIN_SIZE_CHANGE_PIXEL, upper_bound);
}
Size::Ratio(_) => {
self.change_main_size(DEFAULT_MAIN_SIZE_CHANGE_PERCENTAGE, upper_bound);
}
};
};
}
pub fn decrease_main_size(&mut self) {
if let Some(main) = self.columns.main.as_mut() {
match main.size {
Size::Pixel(_) => self.change_main_size(-DEFAULT_MAIN_SIZE_CHANGE_PIXEL, i32::MAX),
Size::Ratio(_) => {
self.change_main_size(-DEFAULT_MAIN_SIZE_CHANGE_PERCENTAGE, i32::MAX);
}
};
};
}
pub fn change_main_size(&mut self, delta: i32, upper_bound: i32) {
if let Some(main) = self.columns.main.as_mut() {
main.size = match main.size {
Size::Pixel(px) => Size::Pixel(cmp::max(0, cmp::min(upper_bound, px + delta))),
Size::Ratio(ratio) => {
Size::Ratio(f32::max(0.0, f32::min(1.0, ratio + (delta as f32 * 0.01))))
}
}
}
}
pub fn set_main_window_count(&mut self, count: usize) {
if let Some(main) = self.columns.main.as_mut() {
main.count = cmp::max(0, count);
}
}
pub fn increase_main_window_count(&mut self) {
if let Some(main) = self.columns.main.as_mut() {
main.count = main.count.saturating_add(1);
}
}
pub fn decrease_main_window_count(&mut self) {
if let Some(main) = self.columns.main.as_mut() {
main.count = main.count.saturating_sub(1);
}
}
pub fn rotate(&mut self, clockwise: bool) {
self.rotate = if clockwise {
self.rotate.clockwise()
} else {
self.rotate.counter_clockwise()
}
}
pub fn check(&self) {
if self.columns.second_stack.is_some() && self.columns.main.is_none() {
}
}
pub fn update_defaults(custom: &Vec<Layout>) -> Vec<Layout> {
let mut layouts = Layouts::default().layouts;
for custom_layout in custom {
layouts.push(custom_layout.clone());
}
layouts
}
}
impl Default for Layout {
fn default() -> Self {
Self {
name: String::from("Default"),
flip: Flip::None,
rotate: Rotation::North,
reserve: Reserve::None,
columns: Columns::default(),
}
}
}
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
#[serde(default)]
pub struct Columns {
pub flip: Flip,
pub rotate: Rotation,
pub main: Option<Main>,
pub stack: Stack,
pub second_stack: Option<SecondStack>,
}
impl Default for Columns {
fn default() -> Self {
Self {
flip: Flip::default(),
rotate: Rotation::default(),
main: Some(Main::default()),
stack: Stack::default(),
second_stack: None,
}
}
}
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
#[serde(default)]
pub struct Main {
pub count: usize,
pub size: Size,
pub flip: Flip,
pub rotate: Rotation,
pub split: Option<Split>,
}
impl Default for Main {
fn default() -> Self {
Self {
count: 1,
size: Size::Ratio(0.5),
flip: Flip::default(),
rotate: Rotation::default(),
split: Some(Split::Vertical),
}
}
}
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
#[serde(default)]
pub struct Stack {
pub flip: Flip,
pub rotate: Rotation,
pub split: Option<Split>,
}
impl Default for Stack {
fn default() -> Self {
Self {
flip: Flip::default(),
rotate: Rotation::default(),
split: Some(Split::Horizontal),
}
}
}
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
#[serde(default)]
pub struct SecondStack {
pub flip: Flip,
pub rotate: Rotation,
pub split: Split,
}
impl Default for SecondStack {
fn default() -> Self {
Self {
flip: Flip::default(),
rotate: Rotation::default(),
split: Split::Horizontal,
}
}
}
#[cfg(test)]
mod tests {
use crate::{
geometry::Size,
layouts::{
layout::{DEFAULT_MAIN_SIZE_CHANGE_PERCENTAGE, DEFAULT_MAIN_SIZE_CHANGE_PIXEL},
Layouts,
},
Layout,
};
#[test]
fn monocle_layout_is_monocle() {
let layouts = Layouts::default();
let layout = layouts.get("Monocle").unwrap();
assert!(layout.is_monocle());
}
#[test]
fn main_and_deck_layout_is_main_and_deck() {
let layouts = Layouts::default();
let layout = layouts.get("MainAndDeck").unwrap();
assert!(layout.is_main_and_deck());
}
#[test]
fn set_main_size_works() {
let mut layout = Layout::default();
layout.set_main_size(Size::Ratio(0.5));
assert_eq!(Some(Size::Ratio(0.5)), layout.main_size());
}
#[test]
fn increase_main_size_percentage_works() {
let mut layout = Layout::default();
layout.set_main_size(Size::Ratio(0.5));
layout.increase_main_size(500);
assert_eq!(
Some(Size::Ratio(
0.5 + (DEFAULT_MAIN_SIZE_CHANGE_PERCENTAGE as f32 * 0.01)
)),
layout.main_size()
);
}
#[test]
fn decrease_main_size_percentage_works() {
let mut layout = Layout::default();
layout.set_main_size(Size::Ratio(0.5));
layout.decrease_main_size();
assert_eq!(
Some(Size::Ratio(
0.5 - (DEFAULT_MAIN_SIZE_CHANGE_PERCENTAGE as f32 * 0.01)
)),
layout.main_size()
);
}
#[test]
fn increase_main_size_pixel_works() {
let mut layout = Layout::default();
layout.set_main_size(Size::Pixel(200));
layout.increase_main_size(500);
assert_eq!(
Some(Size::Pixel(200 + DEFAULT_MAIN_SIZE_CHANGE_PIXEL)),
layout.main_size()
);
}
#[test]
fn decrease_main_size_pixel_works() {
let mut layout = Layout::default();
layout.set_main_size(Size::Pixel(200));
layout.decrease_main_size();
assert_eq!(
Some(Size::Pixel(200 - DEFAULT_MAIN_SIZE_CHANGE_PIXEL)),
layout.main_size()
);
}
#[test]
fn change_main_size_percentage_negative_works() {
let mut layout = Layout::default();
layout.set_main_size(Size::Ratio(0.5));
layout.change_main_size(-5, 500);
assert_eq!(Some(Size::Ratio(0.45)), layout.main_size());
}
#[test]
fn change_main_size_percentage_positive_works() {
let mut layout = Layout::default();
layout.set_main_size(Size::Ratio(0.5));
layout.change_main_size(5, 500);
assert_eq!(Some(Size::Ratio(0.55)), layout.main_size());
}
#[test]
fn change_main_size_pixel_negative_works() {
let mut layout = Layout::default();
layout.set_main_size(Size::Pixel(200));
layout.change_main_size(-5, 500);
assert_eq!(Some(Size::Pixel(195)), layout.main_size());
}
#[test]
fn change_main_size_pixel_positive_works() {
let mut layout = Layout::default();
layout.set_main_size(Size::Pixel(200));
layout.change_main_size(5, 500);
assert_eq!(Some(Size::Pixel(205)), layout.main_size());
}
#[test]
fn decrease_main_size_does_not_go_below_zero() {
let mut layout = Layout::default();
layout.set_main_size(Size::Pixel(200));
layout.change_main_size(-200, 500);
assert_eq!(Some(Size::Pixel(0)), layout.main_size());
layout.change_main_size(-200, 500);
assert_eq!(Some(Size::Pixel(0)), layout.main_size());
}
#[test]
fn decrease_main_size_does_not_go_above_upper_bound() {
let mut layout = Layout::default();
layout.set_main_size(Size::Pixel(200));
layout.change_main_size(200, 500);
assert_eq!(Some(Size::Pixel(400)), layout.main_size());
layout.change_main_size(200, 500);
assert_eq!(Some(Size::Pixel(500)), layout.main_size());
}
#[test]
fn set_main_window_count_works() {
let mut layout = Layout::default();
layout.set_main_window_count(5);
assert_eq!(Some(5), layout.main_window_count());
}
#[test]
fn increase_main_window_count_works() {
let mut layout = Layout::default();
layout.set_main_window_count(5);
layout.increase_main_window_count();
assert_eq!(Some(6), layout.main_window_count());
}
#[test]
fn decrease_main_window_count_works() {
let mut layout = Layout::default();
layout.set_main_window_count(5);
layout.decrease_main_window_count();
assert_eq!(Some(4), layout.main_window_count());
}
#[test]
fn main_window_count_does_not_go_below_zero() {
let mut layout = Layout::default();
layout.set_main_window_count(1);
layout.decrease_main_window_count();
assert_eq!(Some(0), layout.main_window_count());
layout.decrease_main_window_count();
assert_eq!(Some(0), layout.main_window_count());
}
}