1use embedded_graphics::prelude::*;
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq)]
7pub struct LineStyle<C: PixelColor> {
8 pub color: C,
10 pub width: u32,
12 pub pattern: LinePattern,
14 pub cap: LineCap,
16 pub join: LineJoin,
18}
19
20#[derive(Debug, Clone, Copy, PartialEq, Eq)]
22pub enum LinePattern {
23 Solid,
25 Dashed,
27 Dotted,
29 DashDot,
31 Custom,
33}
34
35#[derive(Debug, Clone, Copy, PartialEq, Eq)]
37pub enum LineCap {
38 Butt,
40 Round,
42 Square,
44}
45
46#[derive(Debug, Clone, Copy, PartialEq, Eq)]
48pub enum LineJoin {
49 Miter,
51 Round,
53 Bevel,
55}
56
57impl<C: PixelColor> LineStyle<C> {
58 pub const fn solid(color: C) -> Self {
60 Self {
61 color,
62 width: 1,
63 pattern: LinePattern::Solid,
64 cap: LineCap::Butt,
65 join: LineJoin::Miter,
66 }
67 }
68
69 pub const fn dashed(color: C) -> Self {
71 Self {
72 color,
73 width: 1,
74 pattern: LinePattern::Dashed,
75 cap: LineCap::Butt,
76 join: LineJoin::Miter,
77 }
78 }
79
80 pub const fn dotted(color: C) -> Self {
82 Self {
83 color,
84 width: 1,
85 pattern: LinePattern::Dotted,
86 cap: LineCap::Round,
87 join: LineJoin::Round,
88 }
89 }
90
91 pub const fn width(mut self, width: u32) -> Self {
93 self.width = width;
94 self
95 }
96
97 pub const fn color(mut self, color: C) -> Self {
99 self.color = color;
100 self
101 }
102
103 pub const fn pattern(mut self, pattern: LinePattern) -> Self {
105 self.pattern = pattern;
106 self
107 }
108
109 pub const fn cap(mut self, cap: LineCap) -> Self {
111 self.cap = cap;
112 self
113 }
114
115 pub const fn join(mut self, join: LineJoin) -> Self {
117 self.join = join;
118 self
119 }
120}
121
122impl<C: PixelColor> Default for LineStyle<C>
123where
124 C: From<embedded_graphics::pixelcolor::Rgb565>,
125{
126 fn default() -> Self {
127 Self::solid(embedded_graphics::pixelcolor::Rgb565::WHITE.into())
128 }
129}
130
131#[derive(Debug, Clone, Copy, PartialEq, Eq)]
133pub struct BorderStyle<C: PixelColor> {
134 pub line: LineStyle<C>,
136 pub radius: u32,
138 pub visible: bool,
140}
141
142impl<C: PixelColor> BorderStyle<C> {
143 pub const fn new(line: LineStyle<C>) -> Self {
145 Self {
146 line,
147 radius: 0,
148 visible: true,
149 }
150 }
151
152 pub const fn rounded(line: LineStyle<C>, radius: u32) -> Self {
154 Self {
155 line,
156 radius,
157 visible: true,
158 }
159 }
160
161 pub const fn radius(mut self, radius: u32) -> Self {
163 self.radius = radius;
164 self
165 }
166
167 pub const fn visible(mut self, visible: bool) -> Self {
169 self.visible = visible;
170 self
171 }
172}
173
174impl<C: PixelColor> Default for BorderStyle<C>
175where
176 C: From<embedded_graphics::pixelcolor::Rgb565>,
177{
178 fn default() -> Self {
179 Self::new(LineStyle::default())
180 }
181}
182
183#[derive(Debug, Clone, Copy, PartialEq, Eq)]
185pub struct StrokeStyle<C: PixelColor> {
186 pub color: C,
188 pub width: u32,
190}
191
192impl<C: PixelColor> StrokeStyle<C> {
193 pub const fn new(color: C, width: u32) -> Self {
195 Self { color, width }
196 }
197}
198
199impl<C: PixelColor> From<LineStyle<C>> for StrokeStyle<C> {
200 fn from(line_style: LineStyle<C>) -> Self {
201 Self {
202 color: line_style.color,
203 width: line_style.width,
204 }
205 }
206}
207
208use super::gradient::{LinearGradient, PatternFill, RadialGradient, MAX_GRADIENT_STOPS};
209
210#[derive(Debug, Clone)]
212pub struct FillStyle<C: PixelColor> {
213 pub pattern: FillPattern<C>,
215}
216
217#[derive(Debug, Clone)]
219pub enum FillPattern<C: PixelColor> {
220 Solid(C),
222 LinearGradient(LinearGradient<C, MAX_GRADIENT_STOPS>),
224 RadialGradient(RadialGradient<C, MAX_GRADIENT_STOPS>),
226 Pattern(PatternFill<C>),
228}
229
230impl<C: PixelColor> FillStyle<C> {
231 pub const fn solid(color: C) -> Self {
233 Self {
234 pattern: FillPattern::Solid(color),
235 }
236 }
237
238 pub fn linear_gradient(gradient: LinearGradient<C, MAX_GRADIENT_STOPS>) -> Self {
240 Self {
241 pattern: FillPattern::LinearGradient(gradient),
242 }
243 }
244
245 pub fn radial_gradient(gradient: RadialGradient<C, MAX_GRADIENT_STOPS>) -> Self {
247 Self {
248 pattern: FillPattern::RadialGradient(gradient),
249 }
250 }
251
252 pub const fn pattern(pattern: PatternFill<C>) -> Self {
254 Self {
255 pattern: FillPattern::Pattern(pattern),
256 }
257 }
258
259 pub fn solid_color(&self) -> Option<C> {
261 match &self.pattern {
262 FillPattern::Solid(color) => Some(*color),
263 _ => None,
264 }
265 }
266}
267
268impl<C: PixelColor> Default for FillStyle<C>
269where
270 C: From<embedded_graphics::pixelcolor::Rgb565>,
271{
272 fn default() -> Self {
273 Self::solid(embedded_graphics::pixelcolor::Rgb565::WHITE.into())
274 }
275}
276
277#[cfg(test)]
278mod tests {
279 use super::*;
280 use embedded_graphics::pixelcolor::Rgb565;
281
282 #[test]
283 fn test_line_style_creation() {
284 let style = LineStyle::solid(Rgb565::RED);
285 assert_eq!(style.color, Rgb565::RED);
286 assert_eq!(style.width, 1);
287 assert_eq!(style.pattern, LinePattern::Solid);
288 }
289
290 #[test]
291 fn test_line_style_builder() {
292 let style = LineStyle::solid(Rgb565::BLUE)
293 .width(3)
294 .pattern(LinePattern::Dashed)
295 .cap(LineCap::Round);
296
297 assert_eq!(style.color, Rgb565::BLUE);
298 assert_eq!(style.width, 3);
299 assert_eq!(style.pattern, LinePattern::Dashed);
300 assert_eq!(style.cap, LineCap::Round);
301 }
302
303 #[test]
304 fn test_border_style() {
305 let line = LineStyle::solid(Rgb565::BLACK);
306 let border = BorderStyle::rounded(line, 5);
307
308 assert_eq!(border.radius, 5);
309 assert!(border.visible);
310 assert_eq!(border.line.color, Rgb565::BLACK);
311 }
312
313 #[test]
314 fn test_stroke_style_from_line_style() {
315 let line_style = LineStyle::solid(Rgb565::GREEN).width(2);
316 let stroke_style: StrokeStyle<Rgb565> = line_style.into();
317
318 assert_eq!(stroke_style.color, Rgb565::GREEN);
319 assert_eq!(stroke_style.width, 2);
320 }
321
322 #[test]
323 fn test_fill_style() {
324 let fill = FillStyle::solid(Rgb565::YELLOW);
325 assert_eq!(fill.solid_color(), Some(Rgb565::YELLOW));
326 assert!(matches!(fill.pattern, FillPattern::Solid(_)));
327 }
328}