termit-ui 0.0.1

Terminal UI with GUI-like layouts
Documentation
use crate::geometry::*;
use crate::graphics::*;
use crate::widget::Painter;
use std::io;
use std::ops::Range;

#[derive(Debug)]
pub struct Screen {
    size: Point,
    points: Vec<Option<Spot>>,
}

impl Screen {
    pub fn new(size: Point) -> Self {
        let mut scr = Screen {
            size: Point::default(),
            points: vec![],
        };
        scr.resize(size).unwrap();
        scr
    }
    pub fn get_size(&self) -> Point {
        self.size
    }
    pub fn resize(&mut self, newsize: Point) -> io::Result<()> {
        let mut newpoints = Vec::with_capacity(newsize.area() as usize);

        for i in 0..newsize.area() {
            if let Some(point) = newsize.point_at_idx(i) {
                if let Some(idx) = self.size.idx_at_point(point) {
                    newpoints.push(self.points[idx as usize].take());
                } else {
                    newpoints.push(None);
                }
            } else {
                newpoints.push(None);
            }
        }

        self.points = newpoints;
        self.size = newsize;

        Ok(())
    }

    pub fn draw(&mut self, drawing: Drawing) {
        trace!("Screen drawing {:?}", drawing);

        for (pos, spot) in drawing.spots() {
            if let Some(i) = self.size.idx_at_point(pos + drawing.scope.position) {
                self.points[i as usize] = Some(spot);
            }
        }
    }
}

impl Painter for Screen {
    fn get_area(&self) -> Window {
        window(Point::default(), self.size)
    }
    fn paint(&mut self, mut drawing: Drawing) -> io::Result<()> {
        drawing.scope = &self.get_area() & &drawing.scope;
        self.draw(drawing);
        Ok(())
    }
}

#[derive(Debug)]
pub struct ScreenDrawings<'a> {
    screen: &'a Screen,
    counter: Range<usize>,
    drawing: Option<Drawing>,
}

impl<'a> ScreenDrawings<'a> {
    fn new(screen: &'a Screen) -> Self {
        ScreenDrawings {
            screen,
            counter: (0..screen.points.len()),
            drawing: None,
        }
    }
}

impl<'a> Iterator for ScreenDrawings<'a> {
    type Item = Drawing;
    fn next(&mut self) -> Option<Self::Item> {
        while let Some(idx) = self.counter.next() {
            if let Some(ref spot) = self.screen.points[idx] {
                if let Some(mut d) = self.drawing.take() {
                    if spot.style == d.style {
                        self.drawing = Some(d.append(&spot.symbol));
                    } else {
                        put(self, idx, spot);
                        return Some(d);
                    }
                } else {
                    put(self, idx, spot);
                }
            } else if self.drawing.is_some() {
                return self.drawing.take();
            }
        }
        self.drawing.take()
    }
}
fn put(it: &mut ScreenDrawings, idx: usize, spot: &Spot) {
    it.screen
        .size
        .point_at_idx(idx as u32)
        .map(|pos| it.drawing = Some(spot.as_drawing().with_pos(pos)));
}

impl<'a> IntoIterator for &'a Screen {
    type Item = Drawing;
    type IntoIter = ScreenDrawings<'a>;
    fn into_iter(self) -> Self::IntoIter {
        ScreenDrawings::new(self)
    }
}

#[test]
fn test_screen_drawing() {
    let mut sut = Screen::new(point(x(4), y(3)));

    assert_eq!(sut.size.area(), 12);

    sut.draw("a".as_drawing().left(1).top(1));

    println!("{:?}", sut.points);

    assert_eq!(
        sut.points[5],
        Some(Spot {
            symbol: "a".to_owned(),
            ..Default::default()
        })
    );
}

#[test]
fn test_screen_last_point() {
    let mut sut = Screen::new(point(x(4), y(3)));

    sut.draw("a".as_drawing().left(3).top(2));

    println!("{:?}", sut.points);

    assert_eq!(
        sut.points[11],
        Some(Spot {
            symbol: "a".to_owned(),
            ..Default::default()
        })
    );
}

#[test]
fn test_screen_resize() {
    let mut sut = Screen::new(point(x(1), y(1)));

    sut.draw("a".as_drawing().left(0).top(0));

    sut.resize(point(x(2), y(2))).unwrap();

    println!("{:?}", sut.points);

    assert_eq!(
        sut.points[0],
        Some(Spot {
            symbol: "a".to_owned(),
            ..Default::default()
        })
    );
}

#[test]
fn test_screen_iterator() {
    let sut = Screen {
        points: vec![Some(Spot {
            symbol: "x".to_owned(),
            style: Style::default(),
        })],
        size: point(x(3), y(1)),
    };

    let mut sut = sut.into_iter();

    println!("{:?}", sut);

    let result = sut.next();

    println!("{:?}", sut);

    assert_eq!(result, Some("x".as_drawing()));
}