embedded_graphics/primitives/styled.rs
1use crate::{
2 draw_target::DrawTarget,
3 geometry::{Dimensions, Point},
4 pixelcolor::PixelColor,
5 primitives::OffsetOutline,
6 primitives::{PrimitiveStyle, Rectangle},
7 transform::Transform,
8 Drawable,
9};
10
11/// Styled.
12#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default)]
13#[cfg_attr(feature = "defmt", derive(::defmt::Format))]
14pub struct Styled<T, S> {
15 /// Primitive.
16 pub primitive: T,
17 /// Style.
18 pub style: S,
19}
20
21impl<T, S> Styled<T, S> {
22 /// Creates a styled.
23 pub const fn new(primitive: T, style: S) -> Self {
24 Self { primitive, style }
25 }
26}
27
28impl<T: OffsetOutline, C: PixelColor> Styled<T, PrimitiveStyle<C>> {
29 /// Returns the fill area.
30 ///
31 /// The returned primitive coincides with the area that would be filled by calling [`draw`]
32 /// on this styled primitive.
33 ///
34 /// # Examples
35 ///
36 /// ```
37 /// use embedded_graphics::{
38 /// pixelcolor::Rgb888,
39 /// prelude::*,
40 /// primitives::{Circle, PrimitiveStyleBuilder},
41 /// };
42 ///
43 /// let style = PrimitiveStyleBuilder::new()
44 /// .fill_color(Rgb888::RED)
45 /// .stroke_color(Rgb888::GREEN)
46 /// .stroke_width(6)
47 /// .build();
48 ///
49 /// let center = Point::new(10, 20);
50 /// let diameter = 10;
51 ///
52 /// let circle = Circle::with_center(center, diameter).into_styled(style);
53 ///
54 /// assert_eq!(circle.fill_area(), Circle::with_center(center, diameter - style.stroke_width));
55 /// ```
56 ///
57 /// [`draw`]: crate::Drawable::draw
58 pub fn fill_area(&self) -> T {
59 self.style.fill_area(&self.primitive)
60 }
61
62 /// Returns the stroke area.
63 ///
64 /// The outer edge of the returned primitive coincides with the outer edge of the stroke that
65 /// would be drawn by calling [`draw`] on this styled primitive.
66 ///
67 /// # Examples
68 ///
69 /// This example tests if a point lies on the stroke. Because the stoke area surrounds the
70 /// stoke and fill an additional test is required to check that the point is not inside the fill
71 /// area.
72 ///
73 /// ```
74 /// use embedded_graphics::{
75 /// pixelcolor::Rgb888,
76 /// prelude::*,
77 /// primitives::{Circle, PrimitiveStyle},
78 /// };
79 ///
80 /// let style = PrimitiveStyle::with_stroke(Rgb888::RED, 6);
81 ///
82 /// let center = Point::new(10, 20);
83 /// let diameter = 10;
84 ///
85 /// let circle = Circle::with_center(center, diameter).into_styled(style);
86 ///
87 /// // A point lies on the stroke if it is inside the stroke area but not in the fill area.
88 /// let is_on_stroke = |p| circle.stroke_area().contains(p) && !circle.fill_area().contains(p);
89 ///
90 /// assert!(is_on_stroke(center + Size::new(0, diameter / 2)));
91 /// assert!(!is_on_stroke(center));
92 /// ```
93 ///
94 /// [`draw`]: crate::Drawable::draw
95 pub fn stroke_area(&self) -> T {
96 self.style.stroke_area(&self.primitive)
97 }
98}
99
100impl<T: StyledPixels<S>, S> Styled<T, S> {
101 /// Returns an iterator over the pixels in this styled primitive.
102 pub fn pixels(&self) -> T::Iter {
103 self.primitive.pixels(&self.style)
104 }
105}
106
107impl<T: StyledDimensions<S>, S> Dimensions for Styled<T, S> {
108 fn bounding_box(&self) -> Rectangle {
109 self.primitive.styled_bounding_box(&self.style)
110 }
111}
112
113impl<T: StyledDrawable<S>, S> Drawable for Styled<T, S> {
114 type Color = T::Color;
115 type Output = T::Output;
116
117 fn draw<D>(&self, target: &mut D) -> Result<Self::Output, D::Error>
118 where
119 D: DrawTarget<Color = Self::Color>,
120 {
121 self.primitive.draw_styled(&self.style, target)
122 }
123}
124
125impl<T: Transform, S: Clone> Transform for Styled<T, S> {
126 fn translate(&self, by: Point) -> Self {
127 Self {
128 primitive: self.primitive.translate(by),
129 style: self.style.clone(),
130 }
131 }
132
133 fn translate_mut(&mut self, by: Point) -> &mut Self {
134 self.primitive.translate_mut(by);
135
136 self
137 }
138}
139
140/// Styled drawable.
141pub trait StyledDrawable<S> {
142 /// Color type.
143 type Color: PixelColor;
144 /// Output type.
145 type Output;
146
147 /// Draws the primitive using the given style.
148 fn draw_styled<D>(&self, style: &S, target: &mut D) -> Result<Self::Output, D::Error>
149 where
150 D: DrawTarget<Color = Self::Color>;
151}
152
153/// Styled dimensions.
154pub trait StyledDimensions<S> {
155 /// Returns the bounding box using the given style.
156 fn styled_bounding_box(&self, style: &S) -> Rectangle;
157}
158
159/// Styled drawable.
160pub trait StyledPixels<S> {
161 /// Iterator type.
162 type Iter;
163
164 /// Returns an iterator over all pixels in this styled primitive.
165 fn pixels(&self, style: &S) -> Self::Iter;
166}