termit-ui 0.0.1

Terminal UI with GUI-like layouts
Documentation
use crate::geometry::*;

pub trait Placement {
    fn place(&self, window: Window) -> Window;
}

#[derive(Default, Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct Place;

impl Placement for Place {
    fn place(&self, window: Window) -> Window {
        window
    }
}

pub trait AnchorPlaced<A> {
    fn anchor_left(self, anchor: u16) -> A;
    fn left_size(self, size: u16) -> A;
    fn anchor_right(self, anchor: u16) -> A;
    fn right_size(self, size: u16) -> A;
    fn anchor_top(self, anchor: u16) -> A;
    fn top_size(self, size: u16) -> A;
    fn anchor_bottom(self, anchor: u16) -> A;
    fn bottom_size(self, size: u16) -> A;
    fn fill(self) -> A;
}

impl Place {
    pub fn anchor_left(self, anchor: u16) -> AnchorPlacement {
        AnchorPlacement::default().anchor_left(anchor)
    }
    pub fn left_size(self, size: u16) -> AnchorPlacement {
        AnchorPlacement::default().left_size(size)
    }
    pub fn anchor_right(self, anchor: u16) -> AnchorPlacement {
        AnchorPlacement::default().anchor_right(anchor)
    }
    pub fn right_size(self, size: u16) -> AnchorPlacement {
        AnchorPlacement::default().right_size(size)
    }
    pub fn anchor_top(self, anchor: u16) -> AnchorPlacement {
        AnchorPlacement::default().anchor_top(anchor)
    }
    pub fn top_size(self, size: u16) -> AnchorPlacement {
        AnchorPlacement::default().top_size(size)
    }
    pub fn anchor_bottom(self, anchor: u16) -> AnchorPlacement {
        AnchorPlacement::default().anchor_bottom(anchor)
    }
    pub fn bottom_size(self, size: u16) -> AnchorPlacement {
        AnchorPlacement::default().bottom_size(size)
    }
    pub fn fill(self) -> AnchorPlacement {
        AnchorPlacement::default()
    }
}

#[derive(Default, Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct AnchorPlacement {
    left: Edge<X>,
    top: Edge<Y>,
    right: Edge<X>,
    bottom: Edge<Y>,
}

impl AnchorPlacement {
    pub fn anchor_left(mut self, anchor: u16) -> Self {
        self.left = Edge::Anchor(x(anchor));
        self
    }
    pub fn left_size(mut self, size: u16) -> Self {
        self.left = Edge::Size(x(size));
        self
    }
    pub fn anchor_right(mut self, anchor: u16) -> Self {
        self.right = Edge::Anchor(x(anchor));
        self
    }
    pub fn right_size(mut self, size: u16) -> Self {
        self.right = Edge::Size(x(size));
        self
    }
    pub fn anchor_top(mut self, anchor: u16) -> Self {
        self.top = Edge::Anchor(y(anchor));
        self
    }
    pub fn top_size(mut self, size: u16) -> Self {
        self.top = Edge::Size(y(size));
        self
    }
    pub fn anchor_bottom(mut self, anchor: u16) -> Self {
        self.bottom = Edge::Anchor(y(anchor));
        self
    }
    pub fn bottom_size(mut self, size: u16) -> Self {
        self.bottom = Edge::Size(y(size));
        self
    }
    pub fn fill(self) -> AnchorPlacement {
        AnchorPlacement::default()
    }
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
enum Edge<T> {
    Anchor(T),
    Size(T),
}

impl<T> Default for Edge<T>
where
    T: Default,
{
    fn default() -> Self {
        Edge::Anchor(Default::default())
    }
}

impl Placement for AnchorPlacement {
    fn place(&self, w: Window) -> Window {
        let s = w.size;

        let x = match (self.left, self.right) {
            (Edge::Size(l), Edge::Size(r)) => (s.x / 2 - l, l + r),
            (Edge::Size(l), Edge::Anchor(r)) => (s.x - l - r, l),
            (Edge::Anchor(l), Edge::Size(r)) => (l, r),
            (Edge::Anchor(l), Edge::Anchor(r)) => (l, s.x - l - r),
        };
        let y = match (self.top, self.bottom) {
            (Edge::Size(l), Edge::Size(r)) => (s.y / 2 - l, l + r),
            (Edge::Size(l), Edge::Anchor(r)) => (s.y - l - r, l),
            (Edge::Anchor(l), Edge::Size(r)) => (l, r),
            (Edge::Anchor(l), Edge::Anchor(r)) => (l, s.y - l - r),
        };

        let placement = window(point(x.0, y.0), point(x.1, y.1));

        w.crop(&placement)
    }
}

#[test]
fn test_anchor_placement() {
    let sut = AnchorPlacement::default().anchor_top(0).bottom_size(1);
    let w = sut.place(window(point(x(0), y(0)), point(x(5), y(5))));
    assert_eq!(w, window(point(x(0), y(0)), point(x(5), y(1))));

    let sut = AnchorPlacement::default().top_size(1).anchor_bottom(0);
    let w = sut.place(window(point(x(0), y(0)), point(x(5), y(5))));
    assert_eq!(w, window(point(x(0), y(4)), point(x(5), y(1))));

    let sut = AnchorPlacement::default().anchor_top(1).anchor_bottom(1);
    let w = sut.place(window(point(x(2), y(2)), point(x(5), y(5))));
    assert_eq!(w, window(point(x(2), y(3)), point(x(5), y(3))));
}