embedded_graphics/draw_target/
translated.rs

1use 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))]
18pub struct Translated<'a, T>
19where
20    T: DrawTarget,
21{
22    parent: &'a mut T,
23    offset: Point,
24}
25
26impl<'a, T> Translated<'a, T>
27where
28    T: DrawTarget,
29{
30    pub(super) fn new(parent: &'a mut T, offset: Point) -> Self {
31        Self { parent, offset }
32    }
33}
34
35impl<T> DrawTarget for Translated<'_, T>
36where
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
68impl<T> Dimensions for Translated<'_, T>
69where
70    T: DrawTarget,
71{
72    fn bounding_box(&self) -> Rectangle {
73        self.parent.bounding_box().translate(-self.offset)
74    }
75}
76
77#[cfg(test)]
78mod 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}