pub use denise::icon::{GRID, Icon, Ink, MAX_SHAPES, Shape, fx_along};
use denise::{Color, Rect};
use crate::canvas::Canvas;
impl Canvas<'_> {
pub fn draw_icon(&mut self, icon: &Icon, rect: Rect, fore: Color, back: Color) {
crate::painter::Painter::draw_icon(self, icon, rect, fore, back);
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::testing::TestCanvas;
const FORE: Color = Color::rgb(255, 255, 255);
const BACK: Color = Color::rgb(0, 0, 0);
static SQUARE: Icon = Icon::new(&[Shape::fore(&[(0, 0), (100, 0), (100, 100), (0, 100)])]);
static RING: Icon = Icon::new(&[
Shape::fore(&[(0, 0), (100, 0), (100, 100), (0, 100)]),
Shape::back(&[(30, 30), (70, 30), (70, 70), (30, 70)]),
]);
#[test]
fn an_icon_fills_the_rectangle_it_is_given() {
let mut c = TestCanvas::new(40, 40);
c.canvas()
.draw_icon(&SQUARE, Rect::new(8, 8, 24, 24), FORE, BACK);
assert_eq!(c.at(20, 20), FORE.to_argb8888(), "the middle is not filled");
assert_eq!(c.at(2, 2), 0, "it painted outside its rectangle");
assert_eq!(c.at(37, 37), 0, "it painted outside its rectangle");
}
#[test]
fn a_back_shape_knocks_a_hole_in_the_one_before_it() {
let mut c = TestCanvas::new(40, 40);
c.canvas()
.draw_icon(&RING, Rect::new(0, 0, 40, 40), FORE, BACK);
assert_eq!(c.at(4, 20), FORE.to_argb8888(), "the ring is missing");
assert_eq!(c.at(20, 20), BACK.to_argb8888(), "the hole was not punched");
}
#[test]
fn a_hole_before_its_shape_is_covered_by_it() {
static WRONG: Icon = Icon::new(&[
Shape::back(&[(30, 30), (70, 30), (70, 70), (30, 70)]),
Shape::fore(&[(0, 0), (100, 0), (100, 100), (0, 100)]),
]);
let mut c = TestCanvas::new(40, 40);
c.canvas()
.draw_icon(&WRONG, Rect::new(0, 0, 40, 40), FORE, BACK);
assert_eq!(
c.at(20, 20),
FORE.to_argb8888(),
"shapes are drawn in order, so this hole should have been covered"
);
}
#[test]
fn an_icon_scales_rather_than_magnifies() {
let mut small = TestCanvas::new(32, 32);
small
.canvas()
.draw_icon(&RING, Rect::new(0, 0, 16, 16), FORE, BACK);
let mut large = TestCanvas::new(32, 32);
large
.canvas()
.draw_icon(&RING, Rect::new(0, 0, 32, 32), FORE, BACK);
for (c, side) in [(&small, 16), (&large, 32)] {
let edge = side / 10;
assert_eq!(
c.at(edge, side / 2),
FORE.to_argb8888(),
"the ring is missing at {side}px"
);
assert_eq!(
c.at(side / 2, side / 2),
BACK.to_argb8888(),
"the hole is missing at {side}px"
);
}
}
#[test]
fn an_empty_rectangle_is_not_drawn() {
let mut c = TestCanvas::new(8, 8);
c.canvas()
.draw_icon(&SQUARE, Rect::new(2, 2, 0, 6), FORE, BACK);
c.canvas()
.draw_icon(&SQUARE, Rect::new(2, 2, 6, 0), FORE, BACK);
assert!(c.pixels().iter().all(|&p| p == 0), "something was drawn");
}
#[test]
fn a_degenerate_shape_is_skipped() {
static LINE: Icon = Icon::new(&[
Shape::fore(&[(0, 0), (100, 100)]),
Shape::fore(&[(0, 40), (100, 40), (100, 60), (0, 60)]),
]);
let mut c = TestCanvas::new(20, 20);
c.canvas()
.draw_icon(&LINE, Rect::new(0, 0, 20, 20), FORE, BACK);
assert_eq!(c.at(10, 10), FORE.to_argb8888(), "the valid shape was lost");
}
}