use euclid::{Rect, Size2D};
use crate::{event::Event, unit::Cell, Printer, View as ViewTrait};
pub struct View<V> {
inner: V,
top_left: char,
top_right: char,
bottom_left: char,
bottom_right: char,
v_line: char,
h_line: char,
}
impl<V> View<V> {
pub fn new(view: V) -> Self {
Self {
inner: view,
top_left: '┌',
top_right: '┐',
bottom_left: '└',
bottom_right: '┘',
v_line: '│',
h_line: '─',
}
}
}
pub fn new<V>(view: V) -> View<V> {
View::new(view)
}
impl<T, M, V> ViewTrait<T, M> for View<V>
where
V: ViewTrait<T, M>,
{
fn draw(&self, printer: &Printer, focused: bool) {
let p_size = printer.size();
let top_left = (0, 0);
let bottom_left = (0, p_size.height - 1);
let gen_line = |l: char, c, r| {
let mut line = l.to_string();
for _ in 0..(p_size.width - 2) {
line.push(c);
}
line.push(r);
line
};
printer
.print(
&gen_line(self.top_left, self.h_line, self.top_right),
top_left,
)
.unwrap();
printer
.print(
&gen_line(self.bottom_left, self.h_line, self.bottom_right),
bottom_left,
)
.unwrap();
let mut buf = [0; 8];
let v_line = self.v_line.encode_utf8(&mut buf);
for y in 1..(p_size.height - 1) {
printer.print(v_line, (0, y)).unwrap();
printer.print(v_line, (p_size.width - 1, y)).unwrap();
}
let sub = printer
.to_sub_area(Rect::new(
(1, 1).into(),
(p_size.width - 2, p_size.height - 2).into(),
))
.unwrap();
self.inner.draw(&sub, focused);
}
fn width(&self) -> Size2D<u16, Cell> {
let (width, height) = self.inner.width().to_tuple();
(width.saturating_add(2), height.saturating_add(2)).into()
}
fn height(&self) -> Size2D<u16, Cell> {
let (width, height) = self.inner.height().to_tuple();
(width.saturating_add(2), height.saturating_add(2)).into()
}
fn layout(&self, constraint: Size2D<u16, Cell>) -> Size2D<u16, Cell> {
let inner = self.inner.layout(
(
constraint.width.saturating_sub(2),
constraint.height.saturating_sub(2),
)
.into(),
);
(inner.width.saturating_add(2), inner.height.saturating_add(2)).into()
}
fn event(
&mut self,
event: &Event<T>,
focused: bool,
) -> Box<dyn Iterator<Item = M>> {
self.inner.event(event, focused)
}
fn interactive(&self) -> bool {
self.inner.interactive()
}
}
pub trait ViewExt {
fn border(self) -> View<Self>
where
Self: Sized,
{
View::new(self)
}
}
impl<V> ViewExt for V {}