embedded_graphics_core/drawable.rs
1//! `Drawable` trait and helpers
2use 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
67pub 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))]
142pub struct Pixel<C>(pub Point, pub C)
143where
144 C: PixelColor;
145
146impl<C> Drawable for Pixel<C>
147where
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(core::iter::once(*self))
158 }
159}
160
161#[cfg(test)]
162mod 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}