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
use crate::{
draw_target::DrawTarget,
geometry::{Dimensions, Point},
pixelcolor::PixelColor,
primitives::OffsetOutline,
primitives::{PrimitiveStyle, Rectangle},
transform::Transform,
Drawable,
};
/// Styled.
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default)]
#[cfg_attr(feature = "defmt", derive(::defmt::Format))]
pub struct Styled<T, S> {
/// Primitive.
pub primitive: T,
/// Style.
pub style: S,
}
impl<T, S> Styled<T, S> {
/// Creates a styled.
pub const fn new(primitive: T, style: S) -> Self {
Self { primitive, style }
}
}
impl<T: OffsetOutline, C: PixelColor> Styled<T, PrimitiveStyle<C>> {
/// Returns the fill area.
///
/// The returned primitive coincides with the area that would be filled by calling [`draw`]
/// on this styled primitive.
///
/// # Examples
///
/// ```
/// use embedded_graphics::{
/// pixelcolor::Rgb888,
/// prelude::*,
/// primitives::{Circle, PrimitiveStyleBuilder},
/// };
///
/// let style = PrimitiveStyleBuilder::new()
/// .fill_color(Rgb888::RED)
/// .stroke_color(Rgb888::GREEN)
/// .stroke_width(6)
/// .build();
///
/// let center = Point::new(10, 20);
/// let diameter = 10;
///
/// let circle = Circle::with_center(center, diameter).into_styled(style);
///
/// assert_eq!(circle.fill_area(), Circle::with_center(center, diameter - style.stroke_width));
/// ```
///
/// [`draw`]: crate::Drawable::draw
pub fn fill_area(&self) -> T {
self.style.fill_area(&self.primitive)
}
/// Returns the stroke area.
///
/// The outer edge of the returned primitive coincides with the outer edge of the stroke that
/// would be drawn by calling [`draw`] on this styled primitive.
///
/// # Examples
///
/// This example tests if a point lies on the stroke. Because the stoke area surrounds the
/// stoke and fill an additional test is required to check that the point is not inside the fill
/// area.
///
/// ```
/// use embedded_graphics::{
/// pixelcolor::Rgb888,
/// prelude::*,
/// primitives::{Circle, PrimitiveStyle},
/// };
///
/// let style = PrimitiveStyle::with_stroke(Rgb888::RED, 6);
///
/// let center = Point::new(10, 20);
/// let diameter = 10;
///
/// let circle = Circle::with_center(center, diameter).into_styled(style);
///
/// // A point lies on the stroke if it is inside the stroke area but not in the fill area.
/// let is_on_stroke = |p| circle.stroke_area().contains(p) && !circle.fill_area().contains(p);
///
/// assert!(is_on_stroke(center + Size::new(0, diameter / 2)));
/// assert!(!is_on_stroke(center));
/// ```
///
/// [`draw`]: crate::Drawable::draw
pub fn stroke_area(&self) -> T {
self.style.stroke_area(&self.primitive)
}
}
impl<T: StyledPixels<S>, S> Styled<T, S> {
/// Returns an iterator over the pixels in this styled primitive.
pub fn pixels(&self) -> T::Iter {
self.primitive.pixels(&self.style)
}
}
impl<T: StyledDimensions<S>, S> Dimensions for Styled<T, S> {
fn bounding_box(&self) -> Rectangle {
self.primitive.styled_bounding_box(&self.style)
}
}
impl<T: StyledDrawable<S>, S> Drawable for Styled<T, S> {
type Color = T::Color;
type Output = T::Output;
fn draw<D>(&self, target: &mut D) -> Result<Self::Output, D::Error>
where
D: DrawTarget<Color = Self::Color>,
{
self.primitive.draw_styled(&self.style, target)
}
}
impl<T: Transform, S: Clone> Transform for Styled<T, S> {
fn translate(&self, by: Point) -> Self {
Self {
primitive: self.primitive.translate(by),
style: self.style.clone(),
}
}
fn translate_mut(&mut self, by: Point) -> &mut Self {
self.primitive.translate_mut(by);
self
}
}
/// Styled drawable.
pub trait StyledDrawable<S> {
/// Color type.
type Color: PixelColor;
/// Output type.
type Output;
/// Draws the primitive using the given style.
fn draw_styled<D>(&self, style: &S, target: &mut D) -> Result<Self::Output, D::Error>
where
D: DrawTarget<Color = Self::Color>;
}
/// Styled dimensions.
pub trait StyledDimensions<S> {
/// Returns the bounding box using the given style.
fn styled_bounding_box(&self, style: &S) -> Rectangle;
}
/// Styled drawable.
pub trait StyledPixels<S> {
/// Iterator type.
type Iter;
/// Returns an iterator over all pixels in this styled primitive.
fn pixels(&self, style: &S) -> Self::Iter;
}