Skip to main content

netrunner_core/
presentation.rs

1//! Shared, UI-agnostic presentation helpers.
2//!
3//! The cyberpunk colour palette and the mapping from [`ConnectionQuality`](crate::types::ConnectionQuality) to a
4//! colour are the same across the Ratatui TUI and the GPUI desktop app. Rather
5//! than duplicate the RGB values in every front-end, we define them **once**
6//! here and expose the [`quality_color_fn!`](crate::quality_color_fn) macro so each front-end can
7//! generate a mapping function for *its own* colour type without depending on
8//! any UI crate.
9
10/// Canonical cyberpunk palette as `(r, g, b)` triples.
11///
12/// Front-ends convert these into their native colour type.
13pub mod palette {
14    /// Neon green — excellent.
15    pub const GREEN: (u8, u8, u8) = (0x00, 0xff, 0x80);
16    /// Cyan — good.
17    pub const CYAN: (u8, u8, u8) = (0x00, 0xff, 0xff);
18    /// Yellow — average.
19    pub const YELLOW: (u8, u8, u8) = (0xff, 0xdc, 0x00);
20    /// Orange — poor.
21    pub const ORANGE: (u8, u8, u8) = (0xff, 0x8c, 0x00);
22    /// Red — very poor.
23    pub const RED: (u8, u8, u8) = (0xff, 0x3c, 0x3c);
24    /// Dim grey — failed / no data.
25    pub const DIM: (u8, u8, u8) = (0x50, 0x50, 0x64);
26}
27
28/// Return the canonical `(r, g, b)` colour for a [`ConnectionQuality`](crate::types::ConnectionQuality).
29///
30/// This is the single source of truth used by [`quality_color_fn!`](crate::quality_color_fn).
31pub const fn quality_rgb(quality: crate::types::ConnectionQuality) -> (u8, u8, u8) {
32    use crate::types::ConnectionQuality::*;
33    match quality {
34        Excellent => palette::GREEN,
35        Good => palette::CYAN,
36        Average => palette::YELLOW,
37        Poor => palette::ORANGE,
38        VeryPoor => palette::RED,
39        Failed => palette::DIM,
40    }
41}
42
43/// Generate a function mapping [`ConnectionQuality`](crate::types::ConnectionQuality) to a front-end colour type.
44///
45/// The colour is built from the canonical palette in [`quality_rgb`], so the
46/// TUI and GUI stay perfectly in sync. Pass any constructor callable as
47/// `ctor(r, g, b)`.
48///
49/// # Examples
50///
51/// Ratatui (enum-variant constructor):
52///
53/// ```ignore
54/// use ratatui::style::Color;
55/// netrunner_core::quality_color_fn!(
56///     /// Colour for a connection quality in the TUI.
57///     pub fn quality_color -> Color { Color::Rgb }
58/// );
59/// ```
60///
61/// GPUI (via a small helper):
62///
63/// ```ignore
64/// fn rgb8(r: u8, g: u8, b: u8) -> gpui::Rgba {
65///     gpui::rgb(((r as u32) << 16) | ((g as u32) << 8) | b as u32)
66/// }
67/// netrunner_core::quality_color_fn!(pub fn quality_color -> gpui::Rgba { rgb8 });
68/// ```
69#[macro_export]
70macro_rules! quality_color_fn {
71    (
72        $(#[$meta:meta])*
73        $vis:vis fn $name:ident -> $Color:ty { $ctor:expr }
74    ) => {
75        $(#[$meta])*
76        $vis fn $name(quality: $crate::types::ConnectionQuality) -> $Color {
77            let (r, g, b) = $crate::presentation::quality_rgb(quality);
78            let ctor = $ctor;
79            ctor(r, g, b)
80        }
81    };
82}
83
84#[cfg(test)]
85mod tests {
86    use crate::types::ConnectionQuality;
87
88    #[test]
89    fn quality_rgb_is_stable() {
90        assert_eq!(
91            super::quality_rgb(ConnectionQuality::Excellent),
92            super::palette::GREEN
93        );
94        assert_eq!(
95            super::quality_rgb(ConnectionQuality::Good),
96            super::palette::CYAN
97        );
98        assert_eq!(
99            super::quality_rgb(ConnectionQuality::Failed),
100            super::palette::DIM
101        );
102    }
103
104    // Prove the macro expands and produces the canonical colour for an
105    // arbitrary target type (here a plain tuple constructor).
106    crate::quality_color_fn!(fn tuple_color -> (u8, u8, u8) { |r, g, b| (r, g, b) });
107
108    #[test]
109    fn macro_uses_canonical_palette() {
110        assert_eq!(
111            tuple_color(ConnectionQuality::Average),
112            super::palette::YELLOW
113        );
114        assert_eq!(tuple_color(ConnectionQuality::Poor), super::palette::ORANGE);
115        assert_eq!(
116            tuple_color(ConnectionQuality::VeryPoor),
117            super::palette::RED
118        );
119    }
120}