use crate::canvas::Canvas;
use crate::color::CanvasColor;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct RowCell {
pub glyph: char,
pub color: CanvasColor,
}
pub type RowBuffer = Vec<RowCell>;
pub trait GraphicsArea {
fn nrows(&self) -> usize;
fn ncols(&self) -> usize;
fn blank_char(&self) -> char {
' '
}
fn prepare_render(&mut self) {}
fn render_row(&self, row: usize, out: &mut RowBuffer);
fn finish_render(&mut self) {}
}
impl<C: Canvas> GraphicsArea for C {
fn nrows(&self) -> usize {
self.char_height()
}
fn ncols(&self) -> usize {
self.char_width()
}
fn render_row(&self, row: usize, out: &mut RowBuffer) {
out.clear();
out.extend(
self.row_cells(row)
.map(|(glyph, color)| RowCell { glyph, color }),
);
}
}
#[cfg(test)]
mod tests {
use super::{GraphicsArea, RowBuffer};
use crate::canvas::{
AsciiCanvas, BlockCanvas, BrailleCanvas, Canvas, DensityCanvas, DotCanvas,
};
use crate::color::CanvasColor;
#[test]
fn canvas_graphics_area_render_row_matches_glyph_and_color_cells() {
let mut canvas = BrailleCanvas::new(1, 1, 0.0, 0.0, 1.0, 1.0);
canvas.pixel(0, 0, CanvasColor::BLUE);
canvas.pixel(1, 3, CanvasColor::RED);
let mut row = RowBuffer::new();
canvas.render_row(0, &mut row);
assert_eq!(row.len(), 1);
assert_eq!(row[0].glyph, '⢁');
assert_eq!(row[0].color, CanvasColor::MAGENTA);
}
#[test]
fn canvas_graphics_area_reports_dimensions() {
let canvas = BrailleCanvas::new(4, 3, 0.0, 0.0, 1.0, 1.0);
assert_eq!(canvas.ncols(), 4);
assert_eq!(canvas.nrows(), 3);
}
#[test]
fn all_canvas_types_render_rows_through_graphics_area() {
fn assert_single_cell<C: Canvas + GraphicsArea>(mut canvas: C) {
canvas.pixel(0, 0, CanvasColor::GREEN);
let mut row = RowBuffer::new();
canvas.render_row(0, &mut row);
assert_eq!(row.len(), 1);
assert_eq!(row[0].color, CanvasColor::GREEN);
}
assert_single_cell(BrailleCanvas::new(1, 1, 0.0, 0.0, 1.0, 1.0));
assert_single_cell(BlockCanvas::new(1, 1, 0.0, 0.0, 1.0, 1.0));
assert_single_cell(AsciiCanvas::new(1, 1, 0.0, 0.0, 1.0, 1.0));
assert_single_cell(DotCanvas::new(1, 1, 0.0, 0.0, 1.0, 1.0));
assert_single_cell(DensityCanvas::new(1, 1, 0.0, 0.0, 1.0, 1.0));
}
#[test]
fn render_row_reuses_buffer_by_replacing_previous_contents() {
let mut canvas = DotCanvas::new(2, 1, 0.0, 0.0, 1.0, 1.0);
canvas.pixel(0, 0, CanvasColor::YELLOW);
canvas.pixel(1, 0, CanvasColor::CYAN);
let mut row = RowBuffer::new();
row.push(super::RowCell {
glyph: 'x',
color: CanvasColor::RED,
});
canvas.render_row(0, &mut row);
assert_eq!(row.len(), 2);
assert_eq!(row[0].glyph, '\'');
assert_eq!(row[0].color, CanvasColor::YELLOW);
assert_eq!(row[1].glyph, '\'');
assert_eq!(row[1].color, CanvasColor::CYAN);
}
#[test]
fn graphics_area_default_hooks_are_noops() {
let mut canvas = BlockCanvas::new(1, 1, 0.0, 0.0, 1.0, 1.0);
assert_eq!(canvas.blank_char(), ' ');
canvas.prepare_render();
canvas.finish_render();
let mut row = RowBuffer::new();
canvas.render_row(0, &mut row);
assert_eq!(row.len(), 1);
}
}