1 | use crate::{ |
2 | draw_target::DrawTarget, |
3 | geometry::{Dimensions, Point}, |
4 | iterator::PixelIteratorExt, |
5 | primitives::Rectangle, |
6 | transform::Transform, |
7 | Pixel, |
8 | }; |
9 | |
10 | /// Translated draw target. |
11 | /// |
12 | /// Created by calling [`translated`] on any [`DrawTarget`]. |
13 | /// See the [`translated`] method documentation for more. |
14 | /// |
15 | /// [`translated`]: crate::draw_target::DrawTargetExt::translated |
16 | #[derive (Debug)] |
17 | #[cfg_attr (feature = "defmt" , derive(::defmt::Format))] |
18 | pub struct Translated<'a, T> |
19 | where |
20 | T: DrawTarget, |
21 | { |
22 | parent: &'a mut T, |
23 | offset: Point, |
24 | } |
25 | |
26 | impl<'a, T> Translated<'a, T> |
27 | where |
28 | T: DrawTarget, |
29 | { |
30 | pub(super) fn new(parent: &'a mut T, offset: Point) -> Self { |
31 | Self { parent, offset } |
32 | } |
33 | } |
34 | |
35 | impl<T> DrawTarget for Translated<'_, T> |
36 | where |
37 | T: DrawTarget, |
38 | { |
39 | type Color = T::Color; |
40 | type Error = T::Error; |
41 | |
42 | fn draw_iter<I>(&mut self, pixels: I) -> Result<(), Self::Error> |
43 | where |
44 | I: IntoIterator<Item = Pixel<Self::Color>>, |
45 | { |
46 | self.parent |
47 | .draw_iter(pixels.into_iter().translated(self.offset)) |
48 | } |
49 | |
50 | fn fill_contiguous<I>(&mut self, area: &Rectangle, colors: I) -> Result<(), Self::Error> |
51 | where |
52 | I: IntoIterator<Item = Self::Color>, |
53 | { |
54 | let area = area.translate(self.offset); |
55 | self.parent.fill_contiguous(&area, colors) |
56 | } |
57 | |
58 | fn fill_solid(&mut self, area: &Rectangle, color: Self::Color) -> Result<(), Self::Error> { |
59 | let area = area.translate(self.offset); |
60 | self.parent.fill_solid(&area, color) |
61 | } |
62 | |
63 | fn clear(&mut self, color: Self::Color) -> Result<(), Self::Error> { |
64 | self.parent.clear(color) |
65 | } |
66 | } |
67 | |
68 | impl<T> Dimensions for Translated<'_, T> |
69 | where |
70 | T: DrawTarget, |
71 | { |
72 | fn bounding_box(&self) -> Rectangle { |
73 | self.parent.bounding_box().translate(-self.offset) |
74 | } |
75 | } |
76 | |
77 | #[cfg (test)] |
78 | mod tests { |
79 | use crate::{ |
80 | draw_target::{DrawTarget, DrawTargetExt}, |
81 | geometry::Dimensions, |
82 | geometry::{Point, Size}, |
83 | mock_display::MockDisplay, |
84 | pixelcolor::BinaryColor, |
85 | primitives::Rectangle, |
86 | transform::Transform, |
87 | Pixel, |
88 | }; |
89 | |
90 | #[test ] |
91 | fn draw_iter() { |
92 | let mut display = MockDisplay::new(); |
93 | |
94 | let mut translated = display.translated(Point::new(2, 3)); |
95 | |
96 | let pixels = [ |
97 | Pixel(Point::new(0, 0), BinaryColor::On), |
98 | Pixel(Point::new(1, 2), BinaryColor::Off), |
99 | ]; |
100 | translated.draw_iter(pixels.iter().copied()).unwrap(); |
101 | |
102 | display.assert_pattern(&[ |
103 | " " , // |
104 | " " , // |
105 | " " , // |
106 | " # " , // |
107 | " " , // |
108 | " ." , // |
109 | ]); |
110 | } |
111 | |
112 | #[test ] |
113 | fn fill_contiguous() { |
114 | let mut display = MockDisplay::new(); |
115 | |
116 | let mut translated = display.translated(Point::new(3, 2)); |
117 | |
118 | let colors = [ |
119 | 1, 1, 1, 1, 1, // |
120 | 0, 0, 0, 0, 1, // |
121 | 0, 1, 0, 1, 1, // |
122 | 1, 0, 1, 0, 1, // |
123 | ]; |
124 | let area = Rectangle::new(Point::new(1, 2), Size::new(5, 4)); |
125 | translated |
126 | .fill_contiguous(&area, colors.iter().map(|c| BinaryColor::from(*c != 0))) |
127 | .unwrap(); |
128 | |
129 | display.assert_pattern(&[ |
130 | " " , // |
131 | " " , // |
132 | " " , // |
133 | " " , // |
134 | " #####" , // |
135 | " ....#" , // |
136 | " .#.##" , // |
137 | " #.#.#" , // |
138 | ]); |
139 | } |
140 | |
141 | #[test ] |
142 | fn fill_solid() { |
143 | let mut display = MockDisplay::new(); |
144 | |
145 | let mut translated = display.translated(Point::new(1, 3)); |
146 | |
147 | let area = Rectangle::new(Point::new(2, 1), Size::new(3, 4)); |
148 | translated.fill_solid(&area, BinaryColor::On).unwrap(); |
149 | |
150 | display.assert_pattern(&[ |
151 | " " , // |
152 | " " , // |
153 | " " , // |
154 | " " , // |
155 | " ###" , // |
156 | " ###" , // |
157 | " ###" , // |
158 | " ###" , // |
159 | ]); |
160 | } |
161 | |
162 | #[test ] |
163 | fn clear() { |
164 | let mut display = MockDisplay::new(); |
165 | let mut translated = display.translated(Point::new(1, 3)); |
166 | translated.clear(BinaryColor::On).unwrap(); |
167 | |
168 | let mut expected = MockDisplay::new(); |
169 | expected.clear(BinaryColor::On).unwrap(); |
170 | |
171 | display.assert_eq(&expected); |
172 | } |
173 | |
174 | #[test ] |
175 | fn bounding_box() { |
176 | let mut display: MockDisplay<BinaryColor> = MockDisplay::new(); |
177 | let display_bb = display.bounding_box(); |
178 | |
179 | let translated = display.translated(Point::new(1, 3)); |
180 | |
181 | assert_eq!( |
182 | display_bb.translate(-Point::new(1, 3)), |
183 | translated.bounding_box() |
184 | ); |
185 | } |
186 | } |
187 | |