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}