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