Skip to main content

embedded_gui/
palette.rs

1//! Semantic color roles and display modes for HUD / instrument panels.
2//!
3//! Consumers map UI elements to [`InkRole`] values and resolve them through a
4//! [`DisplayPalette`] for the active [`DisplayMode`]. This replaces ad-hoc
5//! tagging tricks (such as encoding highlight ink in a color channel LSB) with
6//! an explicit normal vs. stealth palette.
7
8use embedded_graphics_core::pixelcolor::Rgb565;
9
10/// Active display appearance mode.
11#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
12pub enum DisplayMode {
13    #[default]
14    Normal,
15    /// Low-brightness, reduced-emission palette for covert / night use.
16    Stealth,
17}
18
19/// Semantic ink roles used when drawing HUD elements.
20#[derive(Clone, Copy, Debug, PartialEq, Eq)]
21pub enum InkRole {
22    Background,
23    Primary,
24    Highlight,
25    Accent,
26    Muted,
27}
28
29/// Normal and stealth colors for each [`InkRole`].
30#[derive(Clone, Copy, Debug)]
31pub struct DisplayPalette {
32    pub mode: DisplayMode,
33    pub normal: RoleColors,
34    pub stealth: RoleColors,
35}
36
37/// Concrete RGB565 values for each ink role in one mode.
38#[derive(Clone, Copy, Debug)]
39pub struct RoleColors {
40    pub background: Rgb565,
41    pub primary: Rgb565,
42    pub highlight: Rgb565,
43    pub accent: Rgb565,
44    pub muted: Rgb565,
45}
46
47impl RoleColors {
48    pub const fn new(
49        background: Rgb565,
50        primary: Rgb565,
51        highlight: Rgb565,
52        accent: Rgb565,
53        muted: Rgb565,
54    ) -> Self {
55        Self {
56            background,
57            primary,
58            highlight,
59            accent,
60            muted,
61        }
62    }
63
64    pub const fn resolve(self, role: InkRole) -> Rgb565 {
65        match role {
66            InkRole::Background => self.background,
67            InkRole::Primary => self.primary,
68            InkRole::Highlight => self.highlight,
69            InkRole::Accent => self.accent,
70            InkRole::Muted => self.muted,
71        }
72    }
73}
74
75impl DisplayPalette {
76    pub const fn new(normal: RoleColors, stealth: RoleColors) -> Self {
77        Self {
78            mode: DisplayMode::Normal,
79            normal,
80            stealth,
81        }
82    }
83
84    pub const fn with_mode(self, mode: DisplayMode) -> Self {
85        Self { mode, ..self }
86    }
87
88    pub fn set_mode(&mut self, mode: DisplayMode) {
89        self.mode = mode;
90    }
91
92    pub fn resolve(&self, role: InkRole) -> Rgb565 {
93        match self.mode {
94            DisplayMode::Normal => self.normal.resolve(role),
95            DisplayMode::Stealth => self.stealth.resolve(role),
96        }
97    }
98}