1 | //! `Drawable` trait and helpers |
2 | use crate::{draw_target::DrawTarget, geometry::Point, pixelcolor::PixelColor}; |
3 | |
4 | /// Marks an object as "drawable". Must be implemented for all graphics objects |
5 | /// |
6 | /// The `Drawable` trait describes how a particular graphical object is drawn. A `Drawable` object |
7 | /// can define its `draw` method as a collection of graphical primitives or as an iterator |
8 | /// over pixels being rendered with [`DrawTarget`]'s [`draw_iter`] method. |
9 | /// |
10 | /// ```rust |
11 | /// use embedded_graphics::{ |
12 | /// mono_font::{ascii::FONT_6X9, MonoTextStyle}, |
13 | /// pixelcolor::{BinaryColor, PixelColor, Rgb888}, |
14 | /// prelude::*, |
15 | /// primitives::{Rectangle, PrimitiveStyle}, |
16 | /// text::Text, |
17 | /// }; |
18 | /// |
19 | /// struct Button<'a, C: PixelColor> { |
20 | /// top_left: Point, |
21 | /// size: Size, |
22 | /// bg_color: C, |
23 | /// fg_color: C, |
24 | /// text: &'a str, |
25 | /// } |
26 | /// |
27 | /// impl<C> Drawable for Button<'_, C> |
28 | /// where |
29 | /// C: PixelColor + From<BinaryColor>, |
30 | /// { |
31 | /// type Color = C; |
32 | /// type Output = (); |
33 | /// |
34 | /// fn draw<D>(&self, target: &mut D) -> Result<Self::Output, D::Error> |
35 | /// where |
36 | /// D: DrawTarget<Color = C>, |
37 | /// { |
38 | /// Rectangle::new(self.top_left, self.size) |
39 | /// .into_styled(PrimitiveStyle::with_fill(self.bg_color)) |
40 | /// .draw(target)?; |
41 | /// |
42 | /// let style = MonoTextStyle::new(&FONT_6X9, self.fg_color); |
43 | /// |
44 | /// Text::new(self.text, Point::new(6, 13), style).draw(target)?; |
45 | /// |
46 | /// Ok(()) |
47 | /// } |
48 | /// } |
49 | /// |
50 | /// let mut button = Button { |
51 | /// top_left: Point::zero(), |
52 | /// size: Size::new(60, 20), |
53 | /// bg_color: Rgb888::RED, |
54 | /// fg_color: Rgb888::BLUE, |
55 | /// text: "Click me!" , |
56 | /// }; |
57 | /// |
58 | /// # use embedded_graphics::mock_display::MockDisplay; |
59 | /// # let mut display = MockDisplay::default(); |
60 | /// # display.set_allow_overdraw(true); |
61 | /// button.draw(&mut display)?; |
62 | /// # Ok::<(), core::convert::Infallible>(()) |
63 | /// ``` |
64 | /// |
65 | /// [`DrawTarget`]: crate::draw_target::DrawTarget |
66 | /// [`draw_iter`]: crate::draw_target::DrawTarget::draw_iter |
67 | pub trait Drawable { |
68 | /// The pixel color type. |
69 | type Color: PixelColor; |
70 | |
71 | /// The return type of the `draw` method. |
72 | /// |
73 | /// The `Output` type can be used to return results and values produced from the drawing of the |
74 | /// current item. For example, rendering two differently styled text items next to each other |
75 | /// can make use of a returned value, allowing the next text to be positioned after the first: |
76 | /// |
77 | /// ``` |
78 | /// use embedded_graphics::{ |
79 | /// mono_font::{ |
80 | /// ascii::{FONT_10X20, FONT_6X10}, |
81 | /// MonoTextStyle, |
82 | /// }, |
83 | /// pixelcolor::BinaryColor, |
84 | /// prelude::*, |
85 | /// text::Text, |
86 | /// }; |
87 | /// |
88 | /// # let mut display = embedded_graphics::mock_display::MockDisplay::new(); |
89 | /// # display.set_allow_out_of_bounds_drawing(true); |
90 | /// let label_style = MonoTextStyle::new(&FONT_6X10, BinaryColor::On); |
91 | /// let value_style = MonoTextStyle::new(&FONT_10X20, BinaryColor::On); |
92 | /// |
93 | /// let next_point = Text::new("Label " , Point::new(10, 20), label_style) |
94 | /// .draw(&mut display)?; |
95 | /// |
96 | /// Text::new("1234" , next_point, value_style).draw(&mut display)?; |
97 | /// # Ok::<(), core::convert::Infallible>(()) |
98 | /// ``` |
99 | /// |
100 | /// Use `()` if no value should be returned. |
101 | type Output; |
102 | |
103 | /// Draw the graphics object using the supplied DrawTarget. |
104 | fn draw<D>(&self, target: &mut D) -> Result<Self::Output, D::Error> |
105 | where |
106 | D: DrawTarget<Color = Self::Color>; |
107 | } |
108 | |
109 | /// A single pixel. |
110 | /// |
111 | /// `Pixel` objects are used to specify the position and color of drawn pixels. |
112 | /// |
113 | /// # Examples |
114 | /// |
115 | /// The [`Drawable`] trait is implemented for `Pixel` which allows single pixels |
116 | /// to be drawn to a [`DrawTarget`]: |
117 | /// ``` |
118 | /// use embedded_graphics::{pixelcolor::BinaryColor, prelude::*}; |
119 | /// # use embedded_graphics::mock_display::MockDisplay; |
120 | /// # let mut display = MockDisplay::new(); |
121 | /// |
122 | /// Pixel(Point::new(1, 2), BinaryColor::On).draw(&mut display)?; |
123 | /// # Ok::<(), core::convert::Infallible>(()) |
124 | /// ``` |
125 | /// |
126 | /// Iterators with `Pixel` items can also be drawn: |
127 | /// |
128 | /// ``` |
129 | /// use embedded_graphics::{pixelcolor::BinaryColor, prelude::*}; |
130 | /// # use embedded_graphics::mock_display::MockDisplay; |
131 | /// # let mut display = MockDisplay::new(); |
132 | /// |
133 | /// (0..32) |
134 | /// .map(|i| Pixel(Point::new(i, i * 2), BinaryColor::On)) |
135 | /// .draw(&mut display)?; |
136 | /// # Ok::<(), core::convert::Infallible>(()) |
137 | /// ``` |
138 | /// |
139 | /// [`DrawTarget`]: crate::draw_target::DrawTarget |
140 | #[derive (Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default)] |
141 | #[cfg_attr (feature = "defmt" , derive(::defmt::Format))] |
142 | pub struct Pixel<C>(pub Point, pub C) |
143 | where |
144 | C: PixelColor; |
145 | |
146 | impl<C> Drawable for Pixel<C> |
147 | where |
148 | C: PixelColor, |
149 | { |
150 | type Color = C; |
151 | type Output = (); |
152 | |
153 | fn draw<D>(&self, target: &mut D) -> Result<Self::Output, D::Error> |
154 | where |
155 | D: DrawTarget<Color = C>, |
156 | { |
157 | target.draw_iter(pixels:core::iter::once(*self)) |
158 | } |
159 | } |
160 | |
161 | #[cfg (test)] |
162 | mod tests { |
163 | // NOTE: `crate` cannot be used here due to circular dependency resolution behavior. |
164 | use embedded_graphics::{ |
165 | geometry::Point, mock_display::MockDisplay, pixelcolor::BinaryColor, Drawable, Pixel, |
166 | }; |
167 | |
168 | #[test ] |
169 | fn draw_pixel() { |
170 | let mut display = MockDisplay::new(); |
171 | Pixel(Point::new(0, 0), BinaryColor::On) |
172 | .draw(&mut display) |
173 | .unwrap(); |
174 | Pixel(Point::new(2, 1), BinaryColor::On) |
175 | .draw(&mut display) |
176 | .unwrap(); |
177 | Pixel(Point::new(1, 2), BinaryColor::On) |
178 | .draw(&mut display) |
179 | .unwrap(); |
180 | |
181 | display.assert_pattern(&[ |
182 | "# " , // |
183 | " #" , // |
184 | " # " , // |
185 | ]); |
186 | } |
187 | } |
188 | |