| 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 | |