use std::vec;
use crate::{
core::renderer::{draw_onto, FrameBuffer},
node::Node,
style::{color, GeneralBorderPattern, GeneralStyle, NoStyle, TString},
};
#[derive(Debug)]
pub struct Canvas {
pub buffer: FrameBuffer,
}
impl Canvas {
pub fn new(node: &dyn Node) -> Self {
Canvas {
buffer: FrameBuffer::from_node_measure(vec![], node),
}
.fill_style(color::AsBackground(color::Black))
}
pub fn new_template(node: &dyn Node) -> Self {
Canvas {
buffer: FrameBuffer::from_node_measure(
vec![TString::from_str(&n_char(' ', 600), NoStyle); 600],
node,
),
}
}
pub fn new_with_style(node: &dyn Node, color: impl Into<GeneralStyle>) -> Self {
Self::new(node).fill_style(color)
}
pub fn new_and_fill(node: &dyn Node, c: char, style: impl Into<GeneralStyle>) -> Self {
Self::new(node).fill(c, style)
}
pub fn finish(&self) -> FrameBuffer {
self.buffer.clone()
}
pub fn fill(mut self, c: char, style: impl Into<GeneralStyle>) -> Self {
let width = self.buffer.right - self.buffer.left;
let height = self.buffer.bottom - self.buffer.top;
self.buffer.data =
vec![TString::from_str(&n_char(c, width as usize), style); height as usize];
self
}
pub fn fill_style(self, color: impl Into<GeneralStyle>) -> Self {
self.fill(' ', color)
}
pub fn draw_buffer(mut self, buffer: Canvas) -> Self {
draw_onto(&mut self.buffer, vec![buffer.buffer]);
self
}
pub fn draw_buffers(mut self, buffers: Vec<Canvas>) -> Self {
let mut buffers_ = vec![];
for buffer in buffers {
buffers_.push(buffer.buffer);
}
draw_onto(&mut self.buffer, buffers_);
self
}
pub fn draw_rect(
mut self,
pos: (i32, i32),
size: (i32, i32),
c: char,
style: impl Into<GeneralStyle>,
) -> Self {
let (x, y) = pos;
let (w, h) = size;
if w == 0 || h == 0 {
return self;
}
let style: GeneralStyle = style.into();
let data = vec![
TString::from_str(
vec![c; w as usize].into_iter().collect::<String>().as_str(),
style
);
h as usize
];
let result = FrameBuffer::new(
data,
self.buffer.left + x,
self.buffer.top + y,
self.buffer.left + x + w,
self.buffer.top + y + h,
);
draw_onto(&mut self.buffer, vec![result]);
self
}
pub fn draw_text(mut self, text: &str, style: impl Into<GeneralStyle>, x: i32, y: i32) -> Self {
let text = text.to_string();
let style: GeneralStyle = style.into();
let ttext: Vec<_> = text
.split('\n')
.map(|line| TString::from_str(line, style.clone()))
.collect();
let result = FrameBuffer::new(
ttext,
self.buffer.left + x,
self.buffer.top + y,
self.buffer.left + x + text.len() as i32,
self.buffer.top + y + 1,
);
draw_onto(&mut self.buffer, vec![result]);
self
}
pub fn draw_border(
self,
width: i32,
height: i32,
border_pattern: impl Into<GeneralBorderPattern>,
border_style: impl Into<GeneralStyle>,
) -> Self {
let style = border_style.into();
let pattern = border_pattern.into();
self.draw_rect((0, 0), (1, 1), pattern.top_right, style.clone())
.draw_rect((width - 1, 0), (1, 1), pattern.top_left, style.clone())
.draw_rect((0, height - 1), (1, 1), pattern.bottom_right, style.clone())
.draw_rect(
(width - 1, height - 1),
(1, 1),
pattern.bottom_left,
style.clone(),
)
.draw_rect((1, 0), (width - 2, 1), pattern.top, style.clone())
.draw_rect(
(1, height - 1),
(width - 2, 1),
pattern.bottom,
style.clone(),
)
.draw_rect((0, 1), (1, height - 2), pattern.left, style.clone())
.draw_rect(
(width - 1, 1),
(1, height - 2),
pattern.right,
style.clone(),
)
}
}
fn n_char(c: char, n: usize) -> String {
let mut result = String::new();
for _ in 0..n {
result.push(c);
}
result
}