use crate::attr::Attr;
use crate::cell::Cell;
use std::error::Error;
use unicode_width::UnicodeWidthChar;
pub type Result<T> = std::result::Result<T, Box<dyn Error>>;
pub trait Canvas {
fn size(&self) -> Result<(usize, usize)>;
fn clear(&mut self) -> Result<()>;
fn put_cell(&mut self, row: usize, col: usize, cell: Cell) -> Result<usize>;
fn put_char_with_attr(
&mut self,
row: usize,
col: usize,
ch: char,
attr: Attr,
) -> Result<usize> {
self.put_cell(row, col, Cell { ch, attr })
}
fn print_with_attr(
&mut self,
row: usize,
col: usize,
content: &str,
attr: Attr,
) -> Result<usize> {
let mut cell = Cell {
attr,
..Cell::default()
};
let mut width = 0;
for ch in content.chars() {
cell.ch = ch;
width += self.put_cell(row, col + width, cell)?;
}
Ok(width)
}
fn print(&mut self, row: usize, col: usize, content: &str) -> Result<usize> {
self.print_with_attr(row, col, content, Attr::default())
}
fn set_cursor(&mut self, row: usize, col: usize) -> Result<()>;
fn show_cursor(&mut self, show: bool) -> Result<()>;
}
pub struct BoundedCanvas<'a> {
canvas: &'a mut Canvas,
top: usize,
left: usize,
width: usize,
height: usize,
}
impl<'a> BoundedCanvas<'a> {
pub fn new(
top: usize,
left: usize,
width: usize,
height: usize,
canvas: &'a mut Canvas,
) -> Self {
Self {
canvas,
top,
left,
width,
height,
}
}
}
impl<'a> Canvas for BoundedCanvas<'a> {
fn size(&self) -> Result<(usize, usize)> {
Ok((self.width, self.height))
}
fn clear(&mut self) -> Result<()> {
for row in self.top..(self.top + self.height) {
for col in self.left..(self.left + self.width) {
let _ = self.canvas.put_cell(row, col, Cell::empty());
}
}
Ok(())
}
fn put_cell(&mut self, row: usize, col: usize, cell: Cell) -> Result<usize> {
if row >= self.height || col >= self.width {
Ok(cell.ch.width().unwrap_or(2))
} else {
self.canvas.put_cell(row + self.top, col + self.left, cell)
}
}
fn set_cursor(&mut self, row: usize, col: usize) -> Result<()> {
if row >= self.height || col >= self.width {
Ok(())
} else {
self.canvas.set_cursor(row + self.top, col + self.left)
}
}
fn show_cursor(&mut self, show: bool) -> Result<()> {
self.canvas.show_cursor(show)
}
}