embedded_graphics/draw_target/
cropped.rs1use crate::{
2 draw_target::{DrawTarget, DrawTargetExt, Translated},
3 geometry::{OriginDimensions, Size},
4 primitives::Rectangle,
5 Pixel,
6};
7
8#[derive(Debug)]
15pub struct Cropped<'a, T>
16where
17 T: DrawTarget,
18{
19 parent: Translated<'a, T>,
20 size: Size,
21}
22
23impl<'a, T> Cropped<'a, T>
24where
25 T: DrawTarget,
26{
27 pub(super) fn new(parent: &'a mut T, area: &Rectangle) -> Self {
28 let area = area.intersection(&parent.bounding_box());
29
30 Self {
31 parent: parent.translated(area.top_left),
32 size: area.size,
33 }
34 }
35}
36
37impl<T> DrawTarget for Cropped<'_, T>
38where
39 T: DrawTarget,
40{
41 type Color = T::Color;
42 type Error = T::Error;
43
44 fn draw_iter<I>(&mut self, pixels: I) -> Result<(), Self::Error>
45 where
46 I: IntoIterator<Item = Pixel<Self::Color>>,
47 {
48 self.parent.draw_iter(pixels)
49 }
50
51 fn fill_contiguous<I>(&mut self, area: &Rectangle, colors: I) -> Result<(), Self::Error>
52 where
53 I: IntoIterator<Item = Self::Color>,
54 {
55 self.parent.fill_contiguous(area, colors)
56 }
57
58 fn fill_solid(&mut self, area: &Rectangle, color: Self::Color) -> Result<(), Self::Error> {
59 self.parent.fill_solid(area, color)
60 }
61}
62
63impl<T> OriginDimensions for Cropped<'_, T>
64where
65 T: DrawTarget,
66{
67 fn size(&self) -> Size {
68 self.size
69 }
70}
71
72#[cfg(test)]
73mod tests {
74 use crate::{
75 draw_target::{DrawTarget, DrawTargetExt},
76 geometry::Dimensions,
77 geometry::{Point, Size},
78 mock_display::MockDisplay,
79 pixelcolor::BinaryColor,
80 primitives::{Primitive, PrimitiveStyle, Rectangle},
81 Drawable, Pixel,
82 };
83
84 #[test]
85 fn draw_iter() {
86 let mut display = MockDisplay::new();
87
88 let area = Rectangle::new(Point::new(2, 3), Size::new(10, 10));
89 let mut cropped = display.cropped(&area);
90
91 let pixels = [
92 Pixel(Point::new(0, 0), BinaryColor::On),
93 Pixel(Point::new(1, 2), BinaryColor::Off),
94 ];
95 cropped.draw_iter(pixels.iter().copied()).unwrap();
96
97 display.assert_pattern(&[
98 " ", " ", " ", " # ", " ", " .", ]);
105 }
106
107 #[test]
108 fn fill_contiguous() {
109 let mut display = MockDisplay::new();
110
111 let area = Rectangle::new(Point::new(3, 2), Size::new(10, 10));
112 let mut cropped = display.cropped(&area);
113
114 let colors = [
115 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, ];
120 let area = Rectangle::new(Point::new(1, 2), Size::new(5, 4));
121 cropped
122 .fill_contiguous(&area, colors.iter().map(|c| BinaryColor::from(*c != 0)))
123 .unwrap();
124
125 display.assert_pattern(&[
126 " ", " ", " ", " ", " #####", " ....#", " .#.##", " #.#.#", ]);
135 }
136
137 #[test]
138 fn fill_solid() {
139 let mut display = MockDisplay::new();
140
141 let area = Rectangle::new(Point::new(1, 3), Size::new(10, 10));
142 let mut cropped = display.cropped(&area);
143
144 let area = Rectangle::new(Point::new(2, 1), Size::new(3, 4));
145 cropped.fill_solid(&area, BinaryColor::On).unwrap();
146
147 display.assert_pattern(&[
148 " ", " ", " ", " ", " ###", " ###", " ###", " ###", ]);
157 }
158
159 #[test]
160 fn clear() {
161 let mut display = MockDisplay::new();
162
163 let area = Rectangle::new(Point::new(1, 3), Size::new(3, 4));
164 let mut cropped = display.cropped(&area);
165 cropped.clear(BinaryColor::On).unwrap();
166
167 let mut expected = MockDisplay::new();
168 area.into_styled(PrimitiveStyle::with_fill(BinaryColor::On))
169 .draw(&mut expected)
170 .unwrap();
171
172 display.assert_eq(&expected);
173 }
174
175 #[test]
176 fn bounding_box() {
177 let mut display: MockDisplay<BinaryColor> = MockDisplay::new();
178
179 let size = Size::new(3, 4);
180 let area = Rectangle::new(Point::new(1, 3), size);
181 let cropped = display.cropped(&area);
182
183 assert_eq!(cropped.bounding_box(), Rectangle::new(Point::zero(), size));
184 }
185
186 #[test]
187 fn bounding_box_is_clipped() {
188 let mut display: MockDisplay<BinaryColor> = MockDisplay::new();
189 let display_bb = display.bounding_box();
190
191 let top_left = Point::new(10, 20);
192 let size = Size::new(1000, 1000);
193 let area = Rectangle::new(top_left, size);
194 let cropped = display.cropped(&area);
195
196 let expected_size = display_bb.size - Size::new(top_left.x as u32, top_left.y as u32);
197
198 assert_eq!(
199 cropped.bounding_box(),
200 Rectangle::new(Point::zero(), expected_size),
201 );
202 }
203}