embedded_charts/legend/
style.rs

1//! Legend styling configuration.
2
3use embedded_graphics::prelude::*;
4
5/// Complete legend styling configuration
6#[derive(Debug, Clone)]
7pub struct LegendStyle<C: PixelColor> {
8    /// Text styling
9    pub text: TextStyle<C>,
10    /// Symbol styling
11    pub symbol: SymbolStyle<C>,
12    /// Background styling
13    pub background: BackgroundStyle<C>,
14    /// Spacing configuration
15    pub spacing: SpacingStyle,
16}
17
18/// Text styling for legend labels
19#[derive(Debug, Clone)]
20pub struct TextStyle<C: PixelColor> {
21    /// Text color
22    pub color: C,
23    /// Font size (in pixels)
24    pub font_size: u32,
25    /// Line height (in pixels)
26    pub line_height: u32,
27    /// Character width (for monospace estimation)
28    pub char_width: u32,
29    /// Maximum text width (for layout calculations)
30    pub max_text_width: u32,
31    /// Text alignment
32    pub alignment: TextAlignment,
33}
34
35/// Symbol styling for legend entries
36#[derive(Debug, Clone)]
37pub struct SymbolStyle<C: PixelColor> {
38    /// Default symbol size
39    pub size: u32,
40    /// Symbol border width
41    pub border_width: u32,
42    /// Default symbol color (used as fallback)
43    pub default_color: C,
44    /// Symbol rendering quality
45    pub quality: SymbolQuality,
46}
47
48/// Background styling for the legend
49#[derive(Debug, Clone)]
50pub struct BackgroundStyle<C: PixelColor> {
51    /// Background color (None for transparent)
52    pub color: Option<C>,
53    /// Border color (None for no border)
54    pub border_color: Option<C>,
55    /// Border width
56    pub border_width: u32,
57    /// Corner radius for rounded backgrounds
58    pub corner_radius: u32,
59    /// Background opacity (0-255, 255 = opaque)
60    pub opacity: u8,
61}
62
63/// Spacing configuration for legend layout
64#[derive(Debug, Clone)]
65pub struct SpacingStyle {
66    /// Width allocated for symbols
67    pub symbol_width: u32,
68    /// Gap between symbol and text
69    pub symbol_text_gap: u32,
70    /// Spacing between legend entries
71    pub entry_spacing: u32,
72    /// Padding around the entire legend
73    pub padding: Padding,
74    /// Margins outside the legend
75    pub margins: Margins,
76}
77
78/// Text alignment options
79#[derive(Debug, Clone, Copy, PartialEq, Eq)]
80pub enum TextAlignment {
81    /// Left-aligned text
82    Left,
83    /// Center-aligned text
84    Center,
85    /// Right-aligned text
86    Right,
87}
88
89/// Symbol rendering quality options
90#[derive(Debug, Clone, Copy, PartialEq, Eq)]
91pub enum SymbolQuality {
92    /// Fast rendering with basic shapes
93    Fast,
94    /// Standard quality with anti-aliasing where possible
95    Standard,
96    /// High quality with smooth curves (may be slower)
97    High,
98}
99
100/// Padding configuration
101#[derive(Debug, Clone, Copy, PartialEq, Eq)]
102pub struct Padding {
103    /// Top padding
104    pub top: u32,
105    /// Right padding
106    pub right: u32,
107    /// Bottom padding
108    pub bottom: u32,
109    /// Left padding
110    pub left: u32,
111}
112
113/// Margins configuration
114#[derive(Debug, Clone, Copy, PartialEq, Eq)]
115pub struct Margins {
116    /// Top margin
117    pub top: u32,
118    /// Right margin
119    pub right: u32,
120    /// Bottom margin
121    pub bottom: u32,
122    /// Left margin
123    pub left: u32,
124}
125
126impl<C: PixelColor> LegendStyle<C> {
127    /// Create a new legend style with default values
128    pub fn new() -> Self
129    where
130        C: From<embedded_graphics::pixelcolor::Rgb565>,
131    {
132        Self {
133            text: TextStyle::new(),
134            symbol: SymbolStyle::new(),
135            background: BackgroundStyle::new(),
136            spacing: SpacingStyle::new(),
137        }
138    }
139
140    /// Create a minimal style for small displays
141    pub fn minimal() -> Self
142    where
143        C: From<embedded_graphics::pixelcolor::Rgb565>,
144    {
145        Self {
146            text: TextStyle::minimal(),
147            symbol: SymbolStyle::minimal(),
148            background: BackgroundStyle::minimal(),
149            spacing: SpacingStyle::minimal(),
150        }
151    }
152
153    /// Create a professional style
154    pub fn professional() -> Self
155    where
156        C: From<embedded_graphics::pixelcolor::Rgb565>,
157    {
158        Self {
159            text: TextStyle::professional(),
160            symbol: SymbolStyle::professional(),
161            background: BackgroundStyle::professional(),
162            spacing: SpacingStyle::professional(),
163        }
164    }
165
166    /// Create a compact style for space-constrained environments
167    pub fn compact() -> Self
168    where
169        C: From<embedded_graphics::pixelcolor::Rgb565>,
170    {
171        Self {
172            text: TextStyle::compact(),
173            symbol: SymbolStyle::compact(),
174            background: BackgroundStyle::compact(),
175            spacing: SpacingStyle::compact(),
176        }
177    }
178}
179
180impl<C: PixelColor> TextStyle<C> {
181    /// Create a new text style with default values
182    pub fn new() -> Self
183    where
184        C: From<embedded_graphics::pixelcolor::Rgb565>,
185    {
186        Self {
187            color: C::from(embedded_graphics::pixelcolor::Rgb565::BLACK),
188            font_size: 12,
189            line_height: 16,
190            char_width: 6,
191            max_text_width: 120,
192            alignment: TextAlignment::Left,
193        }
194    }
195
196    /// Create a minimal text style
197    pub fn minimal() -> Self
198    where
199        C: From<embedded_graphics::pixelcolor::Rgb565>,
200    {
201        Self {
202            color: C::from(embedded_graphics::pixelcolor::Rgb565::BLACK),
203            font_size: 8,
204            line_height: 10,
205            char_width: 4,
206            max_text_width: 60,
207            alignment: TextAlignment::Left,
208        }
209    }
210
211    /// Create a professional text style
212    pub fn professional() -> Self
213    where
214        C: From<embedded_graphics::pixelcolor::Rgb565>,
215    {
216        Self {
217            color: C::from(embedded_graphics::pixelcolor::Rgb565::new(8, 16, 8)), // Dark gray
218            font_size: 14,
219            line_height: 18,
220            char_width: 7,
221            max_text_width: 150,
222            alignment: TextAlignment::Left,
223        }
224    }
225
226    /// Create a compact text style
227    pub fn compact() -> Self
228    where
229        C: From<embedded_graphics::pixelcolor::Rgb565>,
230    {
231        Self {
232            color: C::from(embedded_graphics::pixelcolor::Rgb565::BLACK),
233            font_size: 10,
234            line_height: 12,
235            char_width: 5,
236            max_text_width: 80,
237            alignment: TextAlignment::Left,
238        }
239    }
240}
241
242impl<C: PixelColor> SymbolStyle<C> {
243    /// Create a new symbol style with default values
244    pub fn new() -> Self
245    where
246        C: From<embedded_graphics::pixelcolor::Rgb565>,
247    {
248        Self {
249            size: 16,
250            border_width: 1,
251            default_color: C::from(embedded_graphics::pixelcolor::Rgb565::BLUE),
252            quality: SymbolQuality::Standard,
253        }
254    }
255
256    /// Create a minimal symbol style
257    pub fn minimal() -> Self
258    where
259        C: From<embedded_graphics::pixelcolor::Rgb565>,
260    {
261        Self {
262            size: 8,
263            border_width: 0,
264            default_color: C::from(embedded_graphics::pixelcolor::Rgb565::BLUE),
265            quality: SymbolQuality::Fast,
266        }
267    }
268
269    /// Create a professional symbol style
270    pub fn professional() -> Self
271    where
272        C: From<embedded_graphics::pixelcolor::Rgb565>,
273    {
274        Self {
275            size: 20,
276            border_width: 2,
277            default_color: C::from(embedded_graphics::pixelcolor::Rgb565::new(14, 28, 14)), // Steel blue
278            quality: SymbolQuality::High,
279        }
280    }
281
282    /// Create a compact symbol style
283    pub fn compact() -> Self
284    where
285        C: From<embedded_graphics::pixelcolor::Rgb565>,
286    {
287        Self {
288            size: 12,
289            border_width: 1,
290            default_color: C::from(embedded_graphics::pixelcolor::Rgb565::BLUE),
291            quality: SymbolQuality::Standard,
292        }
293    }
294}
295
296impl<C: PixelColor> BackgroundStyle<C> {
297    /// Create a new background style with default values
298    pub fn new() -> Self {
299        Self {
300            color: None, // Transparent by default
301            border_color: None,
302            border_width: 0,
303            corner_radius: 0,
304            opacity: 255,
305        }
306    }
307
308    /// Create a minimal background style
309    pub fn minimal() -> Self {
310        Self {
311            color: None,
312            border_color: None,
313            border_width: 0,
314            corner_radius: 0,
315            opacity: 255,
316        }
317    }
318
319    /// Create a professional background style
320    pub fn professional() -> Self
321    where
322        C: From<embedded_graphics::pixelcolor::Rgb565>,
323    {
324        Self {
325            color: Some(C::from(embedded_graphics::pixelcolor::Rgb565::new(
326                31, 63, 31,
327            ))), // Light gray
328            border_color: Some(C::from(embedded_graphics::pixelcolor::Rgb565::new(
329                16, 32, 16,
330            ))), // Gray
331            border_width: 1,
332            corner_radius: 4,
333            opacity: 240,
334        }
335    }
336
337    /// Create a compact background style
338    pub fn compact() -> Self {
339        Self {
340            color: None,
341            border_color: None,
342            border_width: 0,
343            corner_radius: 0,
344            opacity: 255,
345        }
346    }
347}
348
349impl SpacingStyle {
350    /// Create a new spacing style with default values
351    pub fn new() -> Self {
352        Self {
353            symbol_width: 20,
354            symbol_text_gap: 8,
355            entry_spacing: 4,
356            padding: Padding::all(8),
357            margins: Margins::all(4),
358        }
359    }
360
361    /// Create a minimal spacing style
362    pub fn minimal() -> Self {
363        Self {
364            symbol_width: 12,
365            symbol_text_gap: 4,
366            entry_spacing: 2,
367            padding: Padding::all(2),
368            margins: Margins::all(1),
369        }
370    }
371
372    /// Create a professional spacing style
373    pub fn professional() -> Self {
374        Self {
375            symbol_width: 24,
376            symbol_text_gap: 12,
377            entry_spacing: 8,
378            padding: Padding::all(12),
379            margins: Margins::all(8),
380        }
381    }
382
383    /// Create a compact spacing style
384    pub fn compact() -> Self {
385        Self {
386            symbol_width: 16,
387            symbol_text_gap: 6,
388            entry_spacing: 3,
389            padding: Padding::all(4),
390            margins: Margins::all(2),
391        }
392    }
393}
394
395impl Padding {
396    /// Create uniform padding
397    pub const fn all(value: u32) -> Self {
398        Self {
399            top: value,
400            right: value,
401            bottom: value,
402            left: value,
403        }
404    }
405
406    /// Create symmetric padding
407    pub const fn symmetric(horizontal: u32, vertical: u32) -> Self {
408        Self {
409            top: vertical,
410            right: horizontal,
411            bottom: vertical,
412            left: horizontal,
413        }
414    }
415
416    /// Create custom padding
417    pub const fn new(top: u32, right: u32, bottom: u32, left: u32) -> Self {
418        Self {
419            top,
420            right,
421            bottom,
422            left,
423        }
424    }
425
426    /// Get total horizontal padding
427    pub const fn horizontal(&self) -> u32 {
428        self.left + self.right
429    }
430
431    /// Get total vertical padding
432    pub const fn vertical(&self) -> u32 {
433        self.top + self.bottom
434    }
435}
436
437impl Margins {
438    /// Create uniform margins
439    pub const fn all(value: u32) -> Self {
440        Self {
441            top: value,
442            right: value,
443            bottom: value,
444            left: value,
445        }
446    }
447
448    /// Create symmetric margins
449    pub const fn symmetric(horizontal: u32, vertical: u32) -> Self {
450        Self {
451            top: vertical,
452            right: horizontal,
453            bottom: vertical,
454            left: horizontal,
455        }
456    }
457
458    /// Create custom margins
459    pub const fn new(top: u32, right: u32, bottom: u32, left: u32) -> Self {
460        Self {
461            top,
462            right,
463            bottom,
464            left,
465        }
466    }
467
468    /// Get total horizontal margins
469    pub const fn horizontal(&self) -> u32 {
470        self.left + self.right
471    }
472
473    /// Get total vertical margins
474    pub const fn vertical(&self) -> u32 {
475        self.top + self.bottom
476    }
477}
478
479// Default implementations
480impl<C: PixelColor> Default for LegendStyle<C>
481where
482    C: From<embedded_graphics::pixelcolor::Rgb565>,
483{
484    fn default() -> Self {
485        Self::new()
486    }
487}
488
489impl<C: PixelColor> Default for TextStyle<C>
490where
491    C: From<embedded_graphics::pixelcolor::Rgb565>,
492{
493    fn default() -> Self {
494        Self::new()
495    }
496}
497
498impl<C: PixelColor> Default for SymbolStyle<C>
499where
500    C: From<embedded_graphics::pixelcolor::Rgb565>,
501{
502    fn default() -> Self {
503        Self::new()
504    }
505}
506
507impl<C: PixelColor> Default for BackgroundStyle<C> {
508    fn default() -> Self {
509        Self::new()
510    }
511}
512
513impl Default for SpacingStyle {
514    fn default() -> Self {
515        Self::new()
516    }
517}
518
519impl Default for TextAlignment {
520    fn default() -> Self {
521        Self::Left
522    }
523}
524
525impl Default for SymbolQuality {
526    fn default() -> Self {
527        Self::Standard
528    }
529}
530
531impl Default for Padding {
532    fn default() -> Self {
533        Self::all(4)
534    }
535}
536
537impl Default for Margins {
538    fn default() -> Self {
539        Self::all(2)
540    }
541}