1use core::marker::PhantomData;
2
3use embedded_graphics_core::{
4 geometry::{AnchorPoint, AnchorX},
5 prelude::*,
6 primitives::Rectangle,
7};
8
9#[doc = include_str!("../assets/test_image.svg")]
17#[derive(Default)]
37pub struct TestImage<C: RgbColor> {
38 color_type: PhantomData<C>,
39}
40
41impl<C: RgbColor> TestImage<C> {
42 pub const fn new() -> Self {
44 Self {
45 color_type: PhantomData,
46 }
47 }
48}
49
50const BORDER_WIDTH: u32 = 1;
51const BORDER_PADDING: u32 = 4;
52const TOP_LEFT_MARKER_SIZE: u32 = 20;
53
54impl<C: RgbColor> Drawable for TestImage<C> {
55 type Color = C;
56 type Output = ();
57
58 fn draw<D>(&self, target: &mut D) -> Result<Self::Output, D::Error>
59 where
60 D: DrawTarget<Color = Self::Color>,
61 {
62 draw_border(target, BORDER_WIDTH)?;
63
64 let color_bar_area = target
65 .bounding_box()
66 .offset(-i32::try_from(BORDER_WIDTH + BORDER_PADDING).unwrap());
67 draw_color_bars(target, &color_bar_area)?;
68
69 draw_top_left_marker(target, &color_bar_area, TOP_LEFT_MARKER_SIZE)?;
70
71 Ok(())
72 }
73}
74
75fn draw_border<D>(target: &mut D, width: u32) -> Result<(), D::Error>
77where
78 D: DrawTarget,
79 D::Color: RgbColor,
80{
81 let bounding_box = target.bounding_box();
82 let inner_box = bounding_box.offset(-i32::try_from(width).unwrap());
83
84 target.fill_contiguous(
85 &bounding_box,
86 bounding_box.points().map(|p| {
87 if inner_box.contains(p) {
88 D::Color::BLACK
89 } else {
90 D::Color::WHITE
91 }
92 }),
93 )
94}
95
96fn draw_color_bars<D>(target: &mut D, area: &Rectangle) -> Result<(), D::Error>
98where
99 D: DrawTarget,
100 D::Color: RgbColor,
101{
102 target.fill_solid(area, RgbColor::GREEN)?;
103 Character::new(G, area.center()).draw(target)?;
104
105 let rect = area.resized_width(area.size.width / 3, AnchorX::Left);
106 target.fill_solid(&rect, RgbColor::RED)?;
107 Character::new(R, rect.center()).draw(target)?;
108
109 let rect = area.resized_width(area.size.width / 3, AnchorX::Right);
110 target.fill_solid(&rect, RgbColor::BLUE)?;
111 Character::new(B, rect.center()).draw(target)?;
112
113 Ok(())
114}
115
116fn draw_top_left_marker<D>(target: &mut D, area: &Rectangle, size: u32) -> Result<(), D::Error>
118where
119 D: DrawTarget,
120 D::Color: RgbColor,
121{
122 let mut rect = area.resized(Size::new(size, 1), AnchorPoint::TopLeft);
123
124 while rect.size.width > 0 {
125 target.fill_solid(&rect, D::Color::WHITE)?;
126
127 rect.top_left.y += 1;
128 rect.size.width -= 1;
129 }
130
131 Ok(())
132}
133
134const R: &[u8] = &[
135 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ];
147
148const G: &[u8] = &[
149 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ];
161
162const B: &[u8] = &[
163 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ];
175
176struct Character<C> {
177 data: &'static [u8],
178 center: Point,
179 color_type: PhantomData<C>,
180}
181
182impl<C> Character<C> {
183 fn new(data: &'static [u8], center: Point) -> Self {
184 Self {
185 data,
186 center,
187 color_type: PhantomData,
188 }
189 }
190}
191
192impl<C: RgbColor> Drawable for Character<C> {
193 type Color = C;
194 type Output = ();
195
196 fn draw<D>(&self, target: &mut D) -> Result<(), D::Error>
197 where
198 D: DrawTarget<Color = Self::Color>,
199 {
200 let rect = Rectangle::with_center(self.center, Size::new(9, 11));
201
202 target.fill_contiguous(
203 &rect,
204 self.data.iter().map(|d| {
205 if *d == 0 {
206 RgbColor::BLACK
207 } else {
208 RgbColor::WHITE
209 }
210 }),
211 )
212 }
213}