rat_theme4/
palette.rs

1//!
2//! [Palette] is the color palette for salsa-themes.
3//!
4//! It has graduations for white, black, gray, red, orange,
5//! yellow, limegreen, green, bluegreen, cyan, blue, deepblue,
6//! purple, magenta and a redpink.
7//! And it has a primary and a secondary highlight color.
8//! And it has graduations for light/dark text.
9//!
10//! There is an algorithm that chooses the text-color for a
11//! given background.
12//!
13//! And there is a semantic layer, that can give names to
14//! specific colors. It's these names/aliases that are primarily
15//! used when composing everything into a theme.
16//!
17//! This way salsa-theme can have one dark theme that works
18//! with multiple palettes.
19//!
20
21#[cfg(feature = "serde")]
22use crate::LoadPaletteErr;
23use ratatui_core::style::{Color, Style};
24#[cfg(feature = "serde")]
25use serde::de::{Error, MapAccess, SeqAccess, Unexpected, Visitor};
26#[cfg(feature = "serde")]
27use serde::ser::SerializeStruct;
28#[cfg(feature = "serde")]
29use serde::{Deserialize, Deserializer, Serialize, Serializer};
30#[cfg(feature = "serde")]
31use std::array;
32use std::borrow::Cow;
33use std::fmt::{Display, Formatter};
34use std::mem;
35use std::str::FromStr;
36
37/// Refers to a color in the Palette.
38/// This is used for color-aliases.
39#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
40pub struct ColorIdx(pub Colors, pub usize);
41
42/// Names/Indexes into the color-table of the palette.
43#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
44pub enum Colors {
45    /// Colors for light text.
46    TextLight = 0,
47    /// Colors for dark text.
48    TextDark,
49    /// Primary highlight color.
50    Primary,
51    /// Secondary highlight color.
52    Secondary,
53    White,
54    Black,
55    Gray,
56    Red,
57    Orange,
58    Yellow,
59    LimeGreen,
60    Green,
61    BlueGreen,
62    Cyan,
63    Blue,
64    DeepBlue,
65    Purple,
66    Magenta,
67    RedPink,
68    /// Undefined color.
69    ///
70    /// Maps to Color::Reset when queried as a color.
71    /// When used to define a style fg or bg it sets them to [Option::None].
72    #[default]
73    None,
74}
75
76impl Display for ColorIdx {
77    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
78        write!(f, "{}:{}", self.0, self.1)
79    }
80}
81
82#[derive(Debug)]
83pub struct ColorIdxError;
84
85impl Display for ColorIdxError {
86    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
87        write!(f, "{:?}", self)
88    }
89}
90
91impl std::error::Error for ColorIdxError {}
92
93impl FromStr for ColorIdx {
94    type Err = ColorIdxError;
95
96    fn from_str(s: &str) -> Result<Self, Self::Err> {
97        let mut ss = s.split(':');
98        let Some(name) = ss.next() else {
99            return Err(ColorIdxError);
100        };
101        let Ok(c) = Colors::from_str(name) else {
102            return Err(ColorIdxError);
103        };
104        let Some(idx) = ss.next() else {
105            return Err(ColorIdxError);
106        };
107        let Ok(idx) = idx.parse::<usize>() else {
108            return Err(ColorIdxError);
109        };
110        Ok(ColorIdx(c, idx))
111    }
112}
113
114#[cfg(feature = "serde")]
115impl Serialize for ColorIdx {
116    fn serialize<S>(&self, ser: S) -> Result<S::Ok, S::Error>
117    where
118        S: Serializer,
119    {
120        ser.serialize_str(&self.to_string())
121    }
122}
123
124#[cfg(feature = "serde")]
125struct ColorIdxVisitor;
126
127#[cfg(feature = "serde")]
128impl<'de> Visitor<'de> for ColorIdxVisitor {
129    type Value = ColorIdx;
130
131    fn expecting(&self, f: &mut Formatter) -> std::fmt::Result {
132        write!(f, "ColorIdx")
133    }
134
135    fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
136    where
137        E: serde::de::Error,
138    {
139        v.parse::<ColorIdx>()
140            .map_err(|_| serde::de::Error::invalid_value(Unexpected::Str(v), &self))
141    }
142}
143
144#[cfg(feature = "serde")]
145impl<'de> Deserialize<'de> for ColorIdx {
146    fn deserialize<D>(des: D) -> Result<Self, D::Error>
147    where
148        D: Deserializer<'de>,
149    {
150        des.deserialize_str(ColorIdxVisitor)
151    }
152}
153
154impl Display for Colors {
155    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
156        write!(f, "{}", self.str())
157    }
158}
159
160impl FromStr for Colors {
161    type Err = ();
162
163    fn from_str(s: &str) -> Result<Self, Self::Err> {
164        match s {
165            "text-light" => Ok(Colors::TextLight),
166            "text-dark" => Ok(Colors::TextDark),
167            "primary" => Ok(Colors::Primary),
168            "secondary" => Ok(Colors::Secondary),
169            "white" => Ok(Colors::White),
170            "black" => Ok(Colors::Black),
171            "gray" => Ok(Colors::Gray),
172            "red" => Ok(Colors::Red),
173            "orange" => Ok(Colors::Orange),
174            "yellow" => Ok(Colors::Yellow),
175            "lime-green" => Ok(Colors::LimeGreen),
176            "green" => Ok(Colors::Green),
177            "blue-green" => Ok(Colors::BlueGreen),
178            "cyan" => Ok(Colors::Cyan),
179            "blue" => Ok(Colors::Blue),
180            "deep-blue" => Ok(Colors::DeepBlue),
181            "purple" => Ok(Colors::Purple),
182            "magenta" => Ok(Colors::Magenta),
183            "red-pink" => Ok(Colors::RedPink),
184            "none" => Ok(Colors::None),
185            _ => Err(()),
186        }
187    }
188}
189
190impl Colors {
191    pub const LEN: usize = 19;
192
193    pub fn array() -> &'static [Colors] {
194        use Colors::*;
195        // don't include None!
196        &[
197            TextLight, TextDark, Primary, Secondary, White, Black, Gray, Red, Orange, Yellow,
198            LimeGreen, Green, BlueGreen, Cyan, Blue, DeepBlue, Purple, Magenta, RedPink,
199        ]
200    }
201
202    pub const fn str(self) -> &'static str {
203        match self {
204            Colors::TextLight => "text-light",
205            Colors::TextDark => "text-dark",
206            Colors::Primary => "primary",
207            Colors::Secondary => "secondary",
208            Colors::White => "white",
209            Colors::Black => "black",
210            Colors::Gray => "gray",
211            Colors::Red => "red",
212            Colors::Orange => "orange",
213            Colors::Yellow => "yellow",
214            Colors::LimeGreen => "lime-green",
215            Colors::Green => "green",
216            Colors::BlueGreen => "blue-green",
217            Colors::Cyan => "cyan",
218            Colors::Blue => "blue",
219            Colors::DeepBlue => "deep-blue",
220            Colors::Purple => "purple",
221            Colors::Magenta => "magenta",
222            Colors::RedPink => "red-pink",
223            Colors::None => "none",
224        }
225    }
226}
227
228/// Color palette.
229///
230/// This provides the palette used for a theme.
231#[derive(Debug, Default, Clone, PartialEq, Eq)]
232pub struct Palette {
233    /// Name of the theme.
234    pub theme_name: Cow<'static, str>,
235    /// Which theme should be created.
236    ///
237    /// Known themes:
238    /// * Dark
239    /// * Light
240    /// * Shell
241    ///
242    /// There are 3 more special cased themes for fallback/testing
243    /// purposes.
244    ///
245    /// * Core - Fallback theme if something fails.
246    /// * Blackout - Testing theme that blacks everything.
247    /// * Fallback - Testing theme that relies on each widget's own defaults.
248    ///
249    pub theme: Cow<'static, str>,
250    /// Name of the color palette.
251    pub name: Cow<'static, str>,
252    /// Doc string.
253    pub doc: Cow<'static, str>,
254    /// Generator function.
255    /// Determines how the palette is stored.
256    /// Currently:
257    /// * `light-dark:N`
258    ///   stores `color[0]` and `color[3]` and interpolates between them.
259    ///   `color[4]..=color[7]` are generated by scaling the rgb values
260    ///   down to N.
261    /// * `color-1`
262    ///   stores one color and fills the array with the one color.
263    /// * `color-2`
264    ///   stores two colors. fills `0..=3` with the first color
265    ///   and `4..=7` with the second color.
266    /// * `color-4`
267    ///   stores 4 colors. fills `0..=3` with the colors and
268    ///   also `4..=7`
269    /// * `color-4-dark:N`
270    ///   stores 4 colors and fills `4..=7` with the darker versions
271    ///   of the first 4.
272    /// * `color-8`
273    ///   stores all 8 colors.
274    pub generator: Cow<'static, str>,
275    /// Color palette. Use [Colors] for indexing.
276    pub color: [[Color; 8]; Colors::LEN],
277    /// **Sorted** list of aliases.
278    /// Must be pre-sorted for binary-search.
279    pub aliased: Cow<'static, [(Cow<'static, str>, ColorIdx)]>,
280}
281
282#[cfg(feature = "serde")]
283impl Serialize for Palette {
284    fn serialize<S>(&self, ser: S) -> Result<S::Ok, S::Error>
285    where
286        S: Serializer,
287    {
288        let mut pal = ser.serialize_struct("Palette", 25)?;
289        pal.serialize_field("theme_name", &self.theme_name)?;
290        pal.serialize_field("theme", &self.theme)?;
291        pal.serialize_field("name", &self.name)?;
292        pal.serialize_field("doc", &self.doc)?;
293        pal.serialize_field("generator", &self.generator)?;
294        if self.generator.starts_with("light-dark") {
295            for cc in Colors::array() {
296                pal.serialize_field(
297                    cc.str(),
298                    &(self.color[*cc as usize][0], self.color[*cc as usize][3]),
299                )?;
300            }
301        } else if self.generator.starts_with("color-1") {
302            for cc in Colors::array() {
303                pal.serialize_field(cc.str(), &self.color[*cc as usize][0])?;
304            }
305        } else if self.generator.starts_with("color-2") {
306            for cc in Colors::array() {
307                pal.serialize_field(
308                    cc.str(),
309                    &(self.color[*cc as usize][0], self.color[*cc as usize][4]),
310                )?;
311            }
312        } else if self.generator.starts_with("color-4") {
313            for cc in Colors::array() {
314                pal.serialize_field(
315                    cc.str(),
316                    &(
317                        self.color[*cc as usize][0],
318                        self.color[*cc as usize][1],
319                        self.color[*cc as usize][2],
320                        self.color[*cc as usize][3],
321                    ),
322                )?;
323            }
324        } else if self.generator.starts_with("color-4-dark") {
325            for cc in Colors::array() {
326                pal.serialize_field(
327                    cc.str(),
328                    &(
329                        self.color[*cc as usize][0],
330                        self.color[*cc as usize][1],
331                        self.color[*cc as usize][2],
332                        self.color[*cc as usize][3],
333                    ),
334                )?;
335            }
336        } else if self.generator.starts_with("color-8") {
337            for cc in Colors::array() {
338                pal.serialize_field(
339                    cc.str(),
340                    &(
341                        self.color[*cc as usize][0],
342                        self.color[*cc as usize][1],
343                        self.color[*cc as usize][2],
344                        self.color[*cc as usize][3],
345                        self.color[*cc as usize][4],
346                        self.color[*cc as usize][5],
347                        self.color[*cc as usize][6],
348                        self.color[*cc as usize][7],
349                    ),
350                )?;
351            }
352        } else {
353            use serde::ser::Error;
354            return Err(S::Error::custom(LoadPaletteErr(format!(
355                "Invalid generator format {:?}",
356                self.generator
357            ))));
358        }
359        pal.serialize_field("aliased", &self.aliased)?;
360        pal.end()
361    }
362}
363
364#[cfg(feature = "serde")]
365struct PaletteVisitor;
366
367#[cfg(feature = "serde")]
368impl<'de> Visitor<'de> for PaletteVisitor {
369    type Value = Palette;
370
371    fn expecting(&self, f: &mut Formatter) -> std::fmt::Result {
372        write!(f, "struct Palette")
373    }
374
375    fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
376    where
377        A: SeqAccess<'de>,
378    {
379        let mut pal = Palette::default();
380        pal.theme_name = seq
381            .next_element::<Cow<'static, str>>()?
382            .ok_or(A::Error::invalid_length(0, &"Palette.theme_name"))?;
383        pal.theme = seq
384            .next_element::<Cow<'static, str>>()?
385            .ok_or(A::Error::invalid_length(0, &"Palette.theme"))?;
386        pal.name = seq
387            .next_element::<Cow<'static, str>>()?
388            .ok_or(A::Error::invalid_length(0, &"Palette.name"))?;
389        pal.doc = seq
390            .next_element::<Cow<'static, str>>()?
391            .ok_or(A::Error::invalid_length(0, &"Palette.doc"))?;
392        pal.generator = seq
393            .next_element::<Cow<'static, str>>()?
394            .ok_or(A::Error::invalid_length(0, &"Palette.generator"))?;
395        if pal.generator.starts_with("light-dark") {
396            let mut dark = 63;
397            if let Some(s) = pal.generator.split(':').nth(1) {
398                dark = s.trim().parse::<u8>().unwrap_or(63);
399            }
400
401            for cn in Colors::array() {
402                let (c0, c3) = seq
403                    .next_element::<(Color, Color)>()?
404                    .ok_or(A::Error::invalid_length(0, &"Palette.color"))?;
405
406                if *cn == Colors::TextLight || *cn == Colors::TextDark {
407                    pal.color[*cn as usize] =
408                        Palette::interpolatec2(c0, c3, Color::default(), Color::default())
409                } else {
410                    pal.color[*cn as usize] = Palette::interpolatec(c0, c3, dark);
411                }
412            }
413        } else if pal.generator.starts_with("color-1") {
414            for cn in Colors::array() {
415                let c0 = seq
416                    .next_element::<Color>()?
417                    .ok_or(A::Error::invalid_length(0, &"Palette.color"))?;
418                pal.color[*cn as usize] = array::from_fn(|_| c0);
419            }
420        } else if pal.generator.starts_with("color-2") {
421            for cn in Colors::array() {
422                let (c0, c1) = seq
423                    .next_element::<(Color, Color)>()?
424                    .ok_or(A::Error::invalid_length(0, &"Palette.color"))?;
425                pal.color[*cn as usize][0] = c0;
426                pal.color[*cn as usize][1] = c0;
427                pal.color[*cn as usize][2] = c0;
428                pal.color[*cn as usize][3] = c0;
429                pal.color[*cn as usize][4] = c1;
430                pal.color[*cn as usize][5] = c1;
431                pal.color[*cn as usize][6] = c1;
432                pal.color[*cn as usize][7] = c1;
433            }
434        } else if pal.generator.starts_with("color-4") {
435            for cn in Colors::array() {
436                let (c0, c1, c2, c3) = seq
437                    .next_element::<(Color, Color, Color, Color)>()?
438                    .ok_or(A::Error::invalid_length(0, &"Palette.color"))?;
439                pal.color[*cn as usize][0] = c0;
440                pal.color[*cn as usize][1] = c1;
441                pal.color[*cn as usize][2] = c2;
442                pal.color[*cn as usize][3] = c3;
443                pal.color[*cn as usize][4] = c0;
444                pal.color[*cn as usize][5] = c1;
445                pal.color[*cn as usize][6] = c2;
446                pal.color[*cn as usize][7] = c3;
447            }
448        } else if pal.generator.starts_with("color-4-dark") {
449            let mut dark = 63;
450            if let Some(s) = pal.generator.split(':').nth(1) {
451                dark = s.trim().parse::<u8>().unwrap_or(63);
452            }
453
454            for cn in Colors::array() {
455                let (c0, c1, c2, c3) = seq
456                    .next_element::<(Color, Color, Color, Color)>()?
457                    .ok_or(A::Error::invalid_length(0, &"Palette.color"))?;
458                pal.color[*cn as usize][0] = c0;
459                pal.color[*cn as usize][1] = c1;
460                pal.color[*cn as usize][2] = c2;
461                pal.color[*cn as usize][3] = c3;
462                pal.color[*cn as usize][4] = Palette::scale_color_to(c0, dark);
463                pal.color[*cn as usize][5] = Palette::scale_color_to(c1, dark);
464                pal.color[*cn as usize][6] = Palette::scale_color_to(c2, dark);
465                pal.color[*cn as usize][7] = Palette::scale_color_to(c3, dark);
466            }
467        } else if pal.generator.starts_with("color-8") {
468            for cn in Colors::array() {
469                let (c0, c1, c2, c3, c4, c5, c6, c7) = seq
470                    .next_element::<(Color, Color, Color, Color, Color, Color, Color, Color)>()?
471                    .ok_or(A::Error::invalid_length(0, &"Palette.color"))?;
472                pal.color[*cn as usize][0] = c0;
473                pal.color[*cn as usize][1] = c1;
474                pal.color[*cn as usize][2] = c2;
475                pal.color[*cn as usize][3] = c3;
476                pal.color[*cn as usize][4] = c4;
477                pal.color[*cn as usize][5] = c5;
478                pal.color[*cn as usize][6] = c6;
479                pal.color[*cn as usize][7] = c7;
480            }
481        } else {
482            return Err(A::Error::invalid_type(
483                Unexpected::Str(&pal.generator),
484                &"expected 'light-dark:N'",
485            ));
486        }
487        pal.aliased = seq
488            .next_element::<Cow<'static, [(Cow<'static, str>, ColorIdx)]>>()?
489            .ok_or(A::Error::invalid_length(0, &"Palette.aliased"))?;
490
491        Ok(pal)
492    }
493
494    fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
495    where
496        A: MapAccess<'de>,
497    {
498        let mut pal = Palette::default();
499        while let Some(key) = map.next_key::<&str>()? {
500            match key {
501                "theme_name" => pal.theme_name = map.next_value::<Cow<'static, str>>()?,
502                "theme" => pal.theme = map.next_value::<Cow<'static, str>>()?,
503                "name" => pal.name = map.next_value::<Cow<'static, str>>()?,
504                "doc" => pal.doc = map.next_value::<Cow<'static, str>>()?,
505                "generator" => {
506                    pal.generator = map.next_value::<Cow<'static, str>>()?;
507                }
508                "aliased" => {
509                    pal.aliased =
510                        map.next_value::<Cow<'static, [(Cow<'static, str>, ColorIdx)]>>()?
511                }
512                c_str => {
513                    let cn =
514                        Colors::from_str(c_str).map_err(|_| A::Error::unknown_field(c_str, &[]))?;
515                    if pal.generator.starts_with("light-dark") {
516                        let mut dark = 63;
517                        if let Some(s) = pal.generator.split(':').nth(1) {
518                            dark = s.trim().parse::<u8>().unwrap_or(63);
519                        }
520                        let (c0, c3) = map.next_value::<(Color, Color)>()?;
521                        if cn == Colors::TextLight || cn == Colors::TextDark {
522                            pal.color[cn as usize] =
523                                Palette::interpolatec2(c0, c3, Color::default(), Color::default())
524                        } else {
525                            pal.color[cn as usize] = Palette::interpolatec(c0, c3, dark);
526                        }
527                    } else if pal.generator.starts_with("color-1") {
528                        let c0 = map.next_value::<Color>()?;
529                        pal.color[cn as usize] = array::from_fn(|_| c0);
530                    } else if pal.generator.starts_with("color-2") {
531                        let (c0, c1) = map.next_value::<(Color, Color)>()?;
532                        pal.color[cn as usize][0] = c0;
533                        pal.color[cn as usize][1] = c0;
534                        pal.color[cn as usize][2] = c0;
535                        pal.color[cn as usize][3] = c0;
536                        pal.color[cn as usize][4] = c1;
537                        pal.color[cn as usize][5] = c1;
538                        pal.color[cn as usize][6] = c1;
539                        pal.color[cn as usize][7] = c1;
540                    } else if pal.generator.starts_with("color-4") {
541                        let (c0, c1, c2, c3) = map.next_value::<(Color, Color, Color, Color)>()?;
542                        pal.color[cn as usize][0] = c0;
543                        pal.color[cn as usize][1] = c1;
544                        pal.color[cn as usize][2] = c2;
545                        pal.color[cn as usize][3] = c3;
546                        pal.color[cn as usize][4] = c0;
547                        pal.color[cn as usize][5] = c1;
548                        pal.color[cn as usize][6] = c2;
549                        pal.color[cn as usize][7] = c3;
550                    } else if pal.generator.starts_with("color-4-dark") {
551                        let mut dark = 63;
552                        if let Some(s) = pal.generator.split(':').nth(1) {
553                            dark = s.trim().parse::<u8>().unwrap_or(63);
554                        }
555                        let (c0, c1, c2, c3) = map.next_value::<(Color, Color, Color, Color)>()?;
556                        pal.color[cn as usize][0] = c0;
557                        pal.color[cn as usize][1] = c1;
558                        pal.color[cn as usize][2] = c2;
559                        pal.color[cn as usize][3] = c3;
560                        pal.color[cn as usize][4] = Palette::scale_color_to(c0, dark);
561                        pal.color[cn as usize][5] = Palette::scale_color_to(c1, dark);
562                        pal.color[cn as usize][6] = Palette::scale_color_to(c2, dark);
563                        pal.color[cn as usize][7] = Palette::scale_color_to(c3, dark);
564                    } else if pal.generator.starts_with("color-8") {
565                        let (c0, c1, c2, c3, c4, c5, c6, c7) = map.next_value::<(
566                            Color,
567                            Color,
568                            Color,
569                            Color,
570                            Color,
571                            Color,
572                            Color,
573                            Color,
574                        )>()?;
575                        pal.color[cn as usize][0] = c0;
576                        pal.color[cn as usize][1] = c1;
577                        pal.color[cn as usize][2] = c2;
578                        pal.color[cn as usize][3] = c3;
579                        pal.color[cn as usize][4] = c4;
580                        pal.color[cn as usize][5] = c5;
581                        pal.color[cn as usize][6] = c6;
582                        pal.color[cn as usize][7] = c7;
583                    } else {
584                        return Err(A::Error::invalid_type(
585                            Unexpected::Str(&pal.generator),
586                            &"expected 'light-dark:N'",
587                        ));
588                    }
589                }
590            }
591        }
592
593        Ok(pal)
594    }
595}
596
597#[cfg(feature = "serde")]
598impl<'de> Deserialize<'de> for Palette {
599    fn deserialize<D>(des: D) -> Result<Self, D::Error>
600    where
601        D: Deserializer<'de>,
602    {
603        use Colors::*;
604        const FIELDS: &'static [&'static str] = &[
605            "theme_name",
606            "theme",
607            "name",
608            "doc",
609            "generator",
610            TextLight.str(),
611            TextDark.str(),
612            Primary.str(),
613            Secondary.str(),
614            White.str(),
615            Black.str(),
616            Gray.str(),
617            Red.str(),
618            Orange.str(),
619            Yellow.str(),
620            LimeGreen.str(),
621            Green.str(),
622            BlueGreen.str(),
623            Cyan.str(),
624            Blue.str(),
625            DeepBlue.str(),
626            Purple.str(),
627            Magenta.str(),
628            RedPink.str(),
629            "aliased",
630        ];
631        let mut pal = des.deserialize_struct("Palette", FIELDS, PaletteVisitor)?;
632
633        // need this sorted.
634        if !pal.aliased.is_sorted() {
635            let mut aliased = pal.aliased.into_owned();
636            aliased.sort();
637            pal.aliased = Cow::Owned(aliased);
638        }
639
640        Ok(pal)
641    }
642}
643
644/// Contrast rating for the text-color that should be used.
645#[derive(Debug)]
646pub(crate) enum Rating {
647    /// Use light/white text for the given background.
648    Light,
649    /// Use dark/black text for the given background.
650    Dark,
651}
652
653/// Create a color alias. Useful when creating a static Palette.
654pub const fn define_alias(
655    alias: &'static str,
656    color: Colors,
657    n: usize,
658) -> (Cow<'static, str>, ColorIdx) {
659    (Cow::Borrowed(alias), ColorIdx(color, n))
660}
661
662/// Create a color alias. This function is useful when
663/// modifying a Palette at runtime.
664pub fn define_rt_alias(
665    alias: impl Into<String>,
666    color: Colors,
667    n: usize,
668) -> (Cow<'static, str>, ColorIdx) {
669    let alias = alias.into();
670    (Cow::Owned(alias), ColorIdx(color, n))
671}
672
673impl Palette {
674    /// Create a style from the given white shade.
675    /// n is 0..=7 with 4..=7 as darker variants of the first 3.
676    pub fn white(&self, n: usize) -> Style {
677        self.style(Colors::White, n)
678    }
679
680    /// Create a style from the given black shade.
681    /// n is 0..=7 with 4..=7 as darker variants of the first 3.
682    pub fn black(&self, n: usize) -> Style {
683        self.style(Colors::Black, n)
684    }
685
686    /// Create a style from the given gray shade.
687    /// n is 0..=7 with 4..=7 as darker variants of the first 3.
688    pub fn gray(&self, n: usize) -> Style {
689        self.style(Colors::Gray, n)
690    }
691
692    /// Create a style from the given red shade.
693    /// n is 0..=7 with 4..=7 as darker variants of the first 3.
694    pub fn red(&self, n: usize) -> Style {
695        self.style(Colors::Red, n)
696    }
697
698    /// Create a style from the given orange shade.
699    /// n is 0..=7 with 4..=7 as darker variants of the first 3.
700    pub fn orange(&self, n: usize) -> Style {
701        self.style(Colors::Orange, n)
702    }
703
704    /// Create a style from the given yellow shade.
705    /// n is 0..=7 with 4..=7 as darker variants of the first 3.
706    pub fn yellow(&self, n: usize) -> Style {
707        self.style(Colors::Yellow, n)
708    }
709
710    /// Create a style from the given limegreen shade.
711    /// n is 0..=7 with 4..=7 as darker variants of the first 3.
712    pub fn limegreen(&self, n: usize) -> Style {
713        self.style(Colors::LimeGreen, n)
714    }
715
716    /// Create a style from the given green shade.
717    /// n is 0..=7 with 4..=7 as darker variants of the first 3.
718    pub fn green(&self, n: usize) -> Style {
719        self.style(Colors::Green, n)
720    }
721
722    /// Create a style from the given bluegreen shade.
723    /// n is 0..=7 with 4..=7 as darker variants of the first 3.
724    pub fn bluegreen(&self, n: usize) -> Style {
725        self.style(Colors::BlueGreen, n)
726    }
727
728    /// Create a style from the given cyan shade.
729    /// n is 0..=7 with 4..=7 as darker variants of the first 3.
730    pub fn cyan(&self, n: usize) -> Style {
731        self.style(Colors::Cyan, n)
732    }
733
734    /// Create a style from the given blue shade.
735    /// n is 0..=7 with 4..=7 as darker variants of the first 3.
736    pub fn blue(&self, n: usize) -> Style {
737        self.style(Colors::Blue, n)
738    }
739
740    /// Create a style from the given deepblue shade.
741    /// n is 0..=7 with 4..=7 as darker variants of the first 3.
742    pub fn deepblue(&self, n: usize) -> Style {
743        self.style(Colors::DeepBlue, n)
744    }
745
746    /// Create a style from the given purple shade.
747    /// n is 0..=7 with 4..=7 as darker variants of the first 3.
748    pub fn purple(&self, n: usize) -> Style {
749        self.style(Colors::Purple, n)
750    }
751
752    /// Create a style from the given magenta shade.
753    /// n is 0..=7 with 4..=7 as darker variants of the first 3.
754    pub fn magenta(&self, n: usize) -> Style {
755        self.style(Colors::Magenta, n)
756    }
757
758    /// Create a style from the given redpink shade.
759    /// n is 0..=7 with 4..=7 as darker variants of the first 3.
760    pub fn redpink(&self, n: usize) -> Style {
761        self.style(Colors::RedPink, n)
762    }
763
764    /// Create a style from the given primary shade.
765    /// n is 0..=7 with 4..=7 as darker variants of the first 3.
766    pub fn primary(&self, n: usize) -> Style {
767        self.style(Colors::Primary, n)
768    }
769
770    /// Create a style from the given secondary shade.
771    /// n is 0..=7 with 4..=7 as darker variants of the first 3.
772    pub fn secondary(&self, n: usize) -> Style {
773        self.style(Colors::Secondary, n)
774    }
775}
776
777impl Palette {
778    /// The Color for the id + index n.
779    pub fn color(&self, id: Colors, n: usize) -> Color {
780        if id == Colors::None {
781            Color::Reset
782        } else {
783            self.color[id as usize][n]
784        }
785    }
786
787    /// Create a style with the given background color.
788    /// The foreground is chosen from the text-colors for a
789    /// normal contrast.
790    pub fn style(&self, id: Colors, n: usize) -> Style {
791        let color = self.color(id, n);
792        self.normal_contrast(color)
793    }
794
795    /// Create a style with the given background color.
796    /// The foreground is chosen from the text-colors for
797    /// high contrast.
798    pub fn high_style(&self, id: Colors, n: usize) -> Style {
799        let color = self.color(id, n);
800        self.high_contrast(color)
801    }
802
803    /// Create a style with the given bg and fg chosen from all variants of a color.
804    /// This creates a colored-text style with the fg chosen for good contrast.
805    pub fn normal_bg_style(&self, fg: Colors, bg: Colors, m: usize) -> Style {
806        let colors_fg = &self.color[fg as usize];
807        let color_bg = self.color(bg, m);
808        self.normal_contrast_color(color_bg, colors_fg)
809    }
810
811    /// Create a style with the given bg and fg chosen from all variants of a color.
812    /// /// This creates a colored-text style with the fg chosen for high contrast.
813    pub fn high_bg_style(&self, fg: Colors, bg: Colors, m: usize) -> Style {
814        let colors_fg = &self.color[fg as usize];
815        let color_bg = self.color(bg, m);
816        self.high_contrast_color(color_bg, colors_fg)
817    }
818
819    /// Create a style with the given fg/bg.
820    pub fn fg_bg_style(&self, fg: Colors, n: usize, bg: Colors, m: usize) -> Style {
821        let color = self.color(fg, n);
822        let color_bg = self.color(bg, m);
823        let mut style = Style::new();
824        if color != Color::Reset {
825            style = style.fg(color);
826        }
827        if color_bg != Color::Reset {
828            style = style.bg(color_bg);
829        }
830        style
831    }
832
833    /// Create a style with only fg set.
834    pub fn fg_style(&self, id: Colors, n: usize) -> Style {
835        let color = self.color(id, n);
836        let mut style = Style::new();
837        if color != Color::Reset {
838            style = style.fg(color);
839        }
840        style
841    }
842
843    /// Create a style with only bg set.
844    pub fn bg_style(&self, id: Colors, n: usize) -> Style {
845        let color = self.color(id, n);
846        let mut style = Style::new();
847        if color != Color::Reset {
848            style = style.bg(color);
849        }
850        style
851    }
852
853    /// Add an alias.
854    pub fn add_aliased(&mut self, id: &str, color_idx: ColorIdx) {
855        if matches!(self.aliased, Cow::Borrowed(_)) {
856            self.aliased = Cow::Owned(mem::take(&mut self.aliased).into_owned());
857        }
858        match &mut self.aliased {
859            Cow::Borrowed(_) => {
860                unreachable!()
861            }
862            Cow::Owned(aliased) => match aliased.binary_search_by_key(&id, |v| v.0.as_ref()) {
863                Ok(n) => aliased[n] = (Cow::Owned(id.to_string()), color_idx),
864                Err(n) => aliased.insert(n, (Cow::Owned(id.to_string()), color_idx)),
865            },
866        }
867    }
868
869    /// Try to find an alias.
870    pub fn try_aliased(&self, id: &str) -> Option<ColorIdx> {
871        match self.aliased.binary_search_by_key(&id, |v| v.0.as_ref()) {
872            Ok(n) => Some(self.aliased[n].1),
873            Err(_) => None,
874        }
875    }
876
877    /// Get the ColorIdx of an aliased color.
878    ///
879    /// __Panic__
880    ///
881    /// With debug_assertions this panics if the alias is not found.
882    /// Otherwise, it returns a default.
883    pub fn aliased(&self, id: &str) -> ColorIdx {
884        match self.try_aliased(id) {
885            Some(c) => c,
886            None => {
887                if cfg!(debug_assertions) {
888                    panic!("unknown aliased color {:?} in palette {:?}", id, self.name);
889                } else {
890                    ColorIdx::default()
891                }
892            }
893        }
894    }
895
896    /// Get an aliased color.
897    pub fn color_alias(&self, id: &str) -> Color {
898        match self.try_aliased(id) {
899            Some(ColorIdx { 0: c, 1: idx }) => {
900                if c != Colors::None {
901                    self.color[c as usize][idx]
902                } else {
903                    Color::default()
904                }
905            }
906            None => {
907                if cfg!(debug_assertions) {
908                    panic!("unknown aliased color {:?} in palette {:?}", id, self.name);
909                } else {
910                    Color::default()
911                }
912            }
913        }
914    }
915
916    /// Get a Style for a color-alias.
917    /// Uses the color as bg() and finds the matching text-color
918    /// for normal contrast.
919    pub fn style_alias(&self, bg: &str) -> Style {
920        let color = self.color_alias(bg);
921        self.normal_contrast(color)
922    }
923
924    /// Get a Style for a color-alias.
925    /// Uses the color as bg() and finds the matching text-color
926    /// for high contrast.
927    pub fn high_style_alias(&self, bg: &str) -> Style {
928        let color = self.color_alias(bg);
929        self.high_contrast(color)
930    }
931
932    /// Get a Style for a color-alias.
933    /// Uses explicit aliases for fg() and bg()
934    pub fn fg_bg_style_alias(&self, fg: &str, bg: &str) -> Style {
935        let color = self.color_alias(fg);
936        let color_bg = self.color_alias(bg);
937        let mut style = Style::new();
938        if color != Color::Reset {
939            style = style.fg(color);
940        }
941        if color_bg != Color::Reset {
942            style = style.bg(color_bg);
943        }
944        style
945    }
946
947    /// Get a Style for a color-alias.
948    /// This creates a style with only the fg() color set.
949    pub fn fg_style_alias(&self, fg: &str) -> Style {
950        let color = self.color_alias(fg);
951        let mut style = Style::new();
952        if color != Color::Reset {
953            style = style.fg(color);
954        }
955        style
956    }
957
958    /// Get a Style for a color-alias.
959    /// This creates a style with only the bg() color set.
960    pub fn bg_style_alias(&self, bg: &str) -> Style {
961        let color = self.color_alias(bg);
962        let mut style = Style::new();
963        if color != Color::Reset {
964            style = style.bg(color);
965        }
966        style
967    }
968}
969
970impl Palette {
971    /// Create a style with the given background color.
972    /// Uses `white[3]` or `black[0]` for the foreground,
973    /// based on `rate_text_color`.
974    pub fn high_contrast(&self, color: Color) -> Style {
975        match Self::rate_text_color(color) {
976            None => Style::new(),
977            Some(Rating::Light) => Style::new().bg(color).fg(self.color(Colors::TextLight, 3)),
978            Some(Rating::Dark) => Style::new().bg(color).fg(self.color(Colors::TextDark, 3)),
979        }
980    }
981
982    /// Create a style with the given background color.
983    /// Uses text_light or text_dark for the foreground,
984    /// based on `rate_text_color`.
985    pub fn normal_contrast(&self, color: Color) -> Style {
986        match Self::rate_text_color(color) {
987            None => Style::new(),
988            Some(Rating::Light) => Style::new().bg(color).fg(self.color(Colors::TextLight, 0)),
989            Some(Rating::Dark) => Style::new().bg(color).fg(self.color(Colors::TextDark, 0)),
990        }
991    }
992
993    /// Pick a color from the choice with a good contrast to the
994    /// given background.
995    pub fn normal_contrast_color(&self, bg: Color, text: &[Color]) -> Style {
996        if bg == Color::Reset {
997            return Style::new();
998        }
999        let mut color0 = text[0];
1000        let mut color1 = text[0];
1001        let mut contrast1 = Self::contrast_bt_srgb(color1, bg);
1002
1003        for text_color in text {
1004            let test = Self::contrast_bt_srgb(*text_color, bg);
1005            if test > contrast1 {
1006                color0 = color1;
1007                color1 = *text_color;
1008                contrast1 = test;
1009            }
1010        }
1011
1012        Style::new().bg(bg).fg(color0)
1013    }
1014
1015    /// Pick a color from the choice with the best contrast to the
1016    /// given background.
1017    pub fn high_contrast_color(&self, bg: Color, text: &[Color]) -> Style {
1018        if bg == Color::Reset {
1019            return Style::new();
1020        }
1021        let mut color0 = text[0];
1022        let mut color1 = text[0];
1023        let mut contrast1 = Self::contrast_bt_srgb(color1, bg);
1024
1025        for text_color in text {
1026            let test = Self::contrast_bt_srgb(*text_color, bg);
1027            if test > contrast1 {
1028                color0 = color1;
1029                color1 = *text_color;
1030                contrast1 = test;
1031            }
1032        }
1033        // don't use the second brightest.
1034        _ = color0;
1035
1036        Style::new().bg(bg).fg(color1)
1037    }
1038
1039    // /// Gives the luminance according to Rec.ITU-R BT.601-7.
1040    // const fn luminance_itu(color: Color) -> f32 {
1041    //     let (r, g, b) = Self::color2rgb(color);
1042    //     0.2989f32 * (r as f32) / 255f32
1043    //         + 0.5870f32 * (g as f32) / 255f32
1044    //         + 0.1140f32 * (b as f32) / 255f32
1045    // }
1046    //
1047    // /// Gives the luminance according to Rec.ITU-R BT.601-7.
1048    // fn luminance_itu_srgb(color: Color) -> f32 {
1049    //     let (r, g, b) = Self::color2rgb(color);
1050    //     0.2989f32 * (r as f32) / 255f32
1051    //         + 0.5870f32 * (g as f32) / 255f32
1052    //         + 0.1140f32 * (b as f32) / 255f32
1053    // }
1054    //
1055    // /// Contrast between two colors.
1056    // fn contrast_itu_srgb(color: Color, color2: Color) -> f32 {
1057    //     let lum1 = Self::luminance_itu_srgb(color);
1058    //     let lum2 = Self::luminance_itu_srgb(color2);
1059    //     (lum1 + 0.05f32) / (lum2 + 0.05f32)
1060    // }
1061
1062    /// Gives the luminance according to BT.709.
1063    pub(crate) const fn luminance_bt(color: Color) -> f32 {
1064        let (r, g, b) = Self::color_to_rgb(color);
1065        0.2126f32 * ((r as f32) / 255f32)
1066            + 0.7152f32 * ((g as f32) / 255f32)
1067            + 0.0722f32 * ((b as f32) / 255f32)
1068    }
1069
1070    /// Gives the luminance according to BT.709.
1071    pub(crate) fn luminance_bt_srgb(color: Color) -> f32 {
1072        let (r, g, b) = Self::color_to_rgb(color);
1073        0.2126f32 * ((r as f32) / 255f32).powf(2.2f32)
1074            + 0.7152f32 * ((g as f32) / 255f32).powf(2.2f32)
1075            + 0.0722f32 * ((b as f32) / 255f32).powf(2.2f32)
1076    }
1077
1078    /// Contrast between two colors.
1079    pub(crate) fn contrast_bt_srgb(color: Color, color2: Color) -> f32 {
1080        let lum1 = Self::luminance_bt_srgb(color);
1081        let lum2 = Self::luminance_bt_srgb(color2);
1082        (lum1 - lum2).abs()
1083        // Don't use this prescribed method.
1084        // The abs diff comes out better.
1085        // (lum1 + 0.05f32) / (lum2 + 0.05f32)
1086    }
1087
1088    /// This gives back a [Rating] for the given background.
1089    ///
1090    /// This converts RGB to grayscale and takes the grayscale value
1091    /// of VGA cyan as threshold, which is about 105 out of 255.
1092    /// This point is a bit arbitrary, just based on what I
1093    /// perceive as acceptable. But it produces a good reading
1094    /// contrast in my experience.
1095    ///
1096    /// For the named colors it takes the VGA equivalent as a base.
1097    /// For indexed colors it splits the range in half as an estimate.
1098    pub(crate) fn rate_text_color(color: Color) -> Option<Rating> {
1099        match color {
1100            Color::Reset => None,
1101            Color::Black => Some(Rating::Light),       //0
1102            Color::Red => Some(Rating::Light),         //1
1103            Color::Green => Some(Rating::Light),       //2
1104            Color::Yellow => Some(Rating::Light),      //3
1105            Color::Blue => Some(Rating::Light),        //4
1106            Color::Magenta => Some(Rating::Light),     //5
1107            Color::Cyan => Some(Rating::Light),        //6
1108            Color::Gray => Some(Rating::Dark),         //7
1109            Color::DarkGray => Some(Rating::Light),    //8
1110            Color::LightRed => Some(Rating::Dark),     //9
1111            Color::LightGreen => Some(Rating::Dark),   //10
1112            Color::LightYellow => Some(Rating::Dark),  //11
1113            Color::LightBlue => Some(Rating::Light),   //12
1114            Color::LightMagenta => Some(Rating::Dark), //13
1115            Color::LightCyan => Some(Rating::Dark),    //14
1116            Color::White => Some(Rating::Dark),        //15
1117            c => {
1118                let lum = Self::luminance_bt(c);
1119                if lum >= 0.4117f32 {
1120                    Some(Rating::Dark)
1121                } else {
1122                    Some(Rating::Light)
1123                }
1124            }
1125        }
1126    }
1127
1128    /// Converts the given color to an equivalent grayscale.
1129    pub const fn grayscale(color: Color) -> Color {
1130        let lum = Self::luminance_bt(color);
1131        let gray = lum * 255f32;
1132        Color::Rgb(gray as u8, gray as u8, gray as u8)
1133    }
1134
1135    /// Color from u32
1136    pub const fn color_from_u32(c: u32) -> Color {
1137        let r0 = (c >> 16) as u8;
1138        let g0 = (c >> 8) as u8;
1139        let b0 = c as u8;
1140        Color::Rgb(r0, g0, b0)
1141    }
1142
1143    /// Color to u32
1144    pub const fn color_to_u32(color: Color) -> u32 {
1145        let (r, g, b) = Self::color_to_rgb(color);
1146        ((r as u32) << 16) + ((g as u32) << 8) + (b as u32)
1147    }
1148
1149    /// Calculates a linear interpolation for the two colors
1150    /// and fills the first 4 colors with it.
1151    /// The next 4 colors are scaled down versions using dark_scale_to.
1152    pub const fn interpolatec(c0: Color, c3: Color, dark_scale_to: u8) -> [Color; 8] {
1153        Self::interpolate(
1154            Self::color_to_u32(c0),
1155            Self::color_to_u32(c3),
1156            dark_scale_to,
1157        )
1158    }
1159
1160    /// Calculates a linear interpolation for the two colors
1161    /// and fills the first 4 colors with it.
1162    /// The next 4 colors are scaled down versions using dark_scale_to.
1163    pub const fn interpolate(c0: u32, c3: u32, dark_scale_to: u8) -> [Color; 8] {
1164        // dark
1165        let mut c4 = Self::color_to_rgb(Self::color_from_u32(c0));
1166        c4.0 = Self::scale_to(c4.0, dark_scale_to);
1167        c4.1 = Self::scale_to(c4.1, dark_scale_to);
1168        c4.2 = Self::scale_to(c4.2, dark_scale_to);
1169        let c4 = ((c4.0 as u32) << 16) + ((c4.1 as u32) << 8) + (c4.2 as u32);
1170
1171        let mut c7 = Self::color_to_rgb(Self::color_from_u32(c3));
1172        c7.0 = Self::scale_to(c7.0, dark_scale_to);
1173        c7.1 = Self::scale_to(c7.1, dark_scale_to);
1174        c7.2 = Self::scale_to(c7.2, dark_scale_to);
1175        let c7 = ((c7.0 as u32) << 16) + ((c7.1 as u32) << 8) + (c7.2 as u32);
1176
1177        Self::interpolate2(c0, c3, c4, c7)
1178    }
1179
1180    /// Calculates a linear interpolation for the two colors
1181    /// and fills the first 4 colors with it.
1182    /// The next 4 colors are scaled down versions using dark_scale_to.
1183    pub const fn interpolatec2(c0: Color, c3: Color, c4: Color, c7: Color) -> [Color; 8] {
1184        Self::interpolate2(
1185            Self::color_to_u32(c0),
1186            Self::color_to_u32(c3),
1187            Self::color_to_u32(c4),
1188            Self::color_to_u32(c7),
1189        )
1190    }
1191
1192    /// Calculates a linear interpolation for the two colors
1193    /// and fills the first 4 colors with it.
1194    /// The next 4 colors are scaled down versions using dark_scale_to.
1195    pub const fn interpolate2(c0: u32, c3: u32, c4: u32, c7: u32) -> [Color; 8] {
1196        // 1/3
1197        const fn i1(a: u8, b: u8) -> u8 {
1198            if a < b {
1199                a + (b - a) / 3
1200            } else {
1201                a - (a - b) / 3
1202            }
1203        }
1204        // 2/3
1205        const fn i2(a: u8, b: u8) -> u8 {
1206            if a < b {
1207                b - (b - a) / 3
1208            } else {
1209                b + (a - b) / 3
1210            }
1211        }
1212
1213        let r0 = (c0 >> 16) as u8;
1214        let g0 = (c0 >> 8) as u8;
1215        let b0 = c0 as u8;
1216
1217        let r3 = (c3 >> 16) as u8;
1218        let g3 = (c3 >> 8) as u8;
1219        let b3 = c3 as u8;
1220
1221        let r1 = i1(r0, r3);
1222        let g1 = i1(g0, g3);
1223        let b1 = i1(b0, b3);
1224
1225        let r2 = i2(r0, r3);
1226        let g2 = i2(g0, g3);
1227        let b2 = i2(b0, b3);
1228
1229        // dark
1230        let r4 = (c4 >> 16) as u8;
1231        let g4 = (c4 >> 8) as u8;
1232        let b4 = c4 as u8;
1233
1234        let r7 = (c7 >> 16) as u8;
1235        let g7 = (c7 >> 8) as u8;
1236        let b7 = c7 as u8;
1237
1238        let r5 = i1(r4, r7);
1239        let g5 = i1(g4, g7);
1240        let b5 = i1(b4, b7);
1241
1242        let r6 = i2(r4, r7);
1243        let g6 = i2(g4, g7);
1244        let b6 = i2(b4, b7);
1245
1246        [
1247            Color::Rgb(r0, g0, b0),
1248            Color::Rgb(r1, g1, b1),
1249            Color::Rgb(r2, g2, b2),
1250            Color::Rgb(r3, g3, b3),
1251            Color::Rgb(r4, g4, b4),
1252            Color::Rgb(r5, g5, b5),
1253            Color::Rgb(r6, g6, b6),
1254            Color::Rgb(r7, g7, b7),
1255        ]
1256    }
1257
1258    /// Scale the u8 down to scale_to.
1259    pub const fn scale_to(v: u8, scale_to: u8) -> u8 {
1260        (((v as u16) * scale_to as u16) / 255u16) as u8
1261    }
1262
1263    /// Scale the given color down to scale.
1264    pub const fn scale_color_to(c: Color, scale: u8) -> Color {
1265        let (r, g, b) = Palette::color_to_rgb(c);
1266        let r = Palette::scale_to(r, scale);
1267        let g = Palette::scale_to(g, scale);
1268        let b = Palette::scale_to(b, scale);
1269        Color::Rgb(r, g, b)
1270    }
1271
1272    /// Gives back the rgb for any ratatui Color.
1273    /// Has the indexed and the named colors too.
1274    pub const fn color_to_rgb(color: Color) -> (u8, u8, u8) {
1275        match color {
1276            Color::Black => (0x00, 0x00, 0x00),
1277            Color::Red => (0xaa, 0x00, 0x00),
1278            Color::Green => (0x00, 0xaa, 0x00),
1279            Color::Yellow => (0xaa, 0x55, 0x00),
1280            Color::Blue => (0x00, 0x00, 0xaa),
1281            Color::Magenta => (0xaa, 0x00, 0xaa),
1282            Color::Cyan => (0x00, 0xaa, 0xaa),
1283            Color::Gray => (0xaa, 0xaa, 0xaa),
1284            Color::DarkGray => (0x55, 0x55, 0x55),
1285            Color::LightRed => (0xff, 0x55, 0x55),
1286            Color::LightGreen => (0x55, 0xff, 0x55),
1287            Color::LightYellow => (0xff, 0xff, 0x55),
1288            Color::LightBlue => (0x55, 0x55, 0xff),
1289            Color::LightMagenta => (0xff, 0x55, 0xff),
1290            Color::LightCyan => (0x55, 0xff, 0xff),
1291            Color::White => (0xff, 0xff, 0xff),
1292            Color::Rgb(r, g, b) => (r, g, b),
1293            Color::Indexed(i) => {
1294                const VGA256: [(u8, u8, u8); 256] = [
1295                    (0x00, 0x00, 0x00),
1296                    (0x80, 0x00, 0x00),
1297                    (0x00, 0x80, 0x00),
1298                    (0x80, 0x80, 0x00),
1299                    (0x00, 0x00, 0x80),
1300                    (0x80, 0x00, 0x80),
1301                    (0x00, 0x80, 0x80),
1302                    (0xc0, 0xc0, 0xc0),
1303                    (0x80, 0x80, 0x80),
1304                    (0xff, 0x00, 0x00),
1305                    (0x00, 0xff, 0x00),
1306                    (0xff, 0xff, 0x00),
1307                    (0x00, 0x00, 0xff),
1308                    (0xff, 0x00, 0xff),
1309                    (0x00, 0xff, 0xff),
1310                    (0xff, 0xff, 0xff),
1311                    (0x00, 0x00, 0x00),
1312                    (0x00, 0x00, 0x5f),
1313                    (0x00, 0x00, 0x87),
1314                    (0x00, 0x00, 0xaf),
1315                    (0x00, 0x00, 0xd7),
1316                    (0x00, 0x00, 0xff),
1317                    (0x00, 0x5f, 0x00),
1318                    (0x00, 0x5f, 0x5f),
1319                    (0x00, 0x5f, 0x87),
1320                    (0x00, 0x5f, 0xaf),
1321                    (0x00, 0x5f, 0xd7),
1322                    (0x00, 0x5f, 0xff),
1323                    (0x00, 0x87, 0x00),
1324                    (0x00, 0x87, 0x5f),
1325                    (0x00, 0x87, 0x87),
1326                    (0x00, 0x87, 0xaf),
1327                    (0x00, 0x87, 0xd7),
1328                    (0x00, 0x87, 0xff),
1329                    (0x00, 0xaf, 0x00),
1330                    (0x00, 0xaf, 0x5f),
1331                    (0x00, 0xaf, 0x87),
1332                    (0x00, 0xaf, 0xaf),
1333                    (0x00, 0xaf, 0xd7),
1334                    (0x00, 0xaf, 0xff),
1335                    (0x00, 0xd7, 0x00),
1336                    (0x00, 0xd7, 0x5f),
1337                    (0x00, 0xd7, 0x87),
1338                    (0x00, 0xd7, 0xaf),
1339                    (0x00, 0xd7, 0xd7),
1340                    (0x00, 0xd7, 0xff),
1341                    (0x00, 0xff, 0x00),
1342                    (0x00, 0xff, 0x5f),
1343                    (0x00, 0xff, 0x87),
1344                    (0x00, 0xff, 0xaf),
1345                    (0x00, 0xff, 0xd7),
1346                    (0x00, 0xff, 0xff),
1347                    (0x5f, 0x00, 0x00),
1348                    (0x5f, 0x00, 0x5f),
1349                    (0x5f, 0x00, 0x87),
1350                    (0x5f, 0x00, 0xaf),
1351                    (0x5f, 0x00, 0xd7),
1352                    (0x5f, 0x00, 0xff),
1353                    (0x5f, 0x5f, 0x00),
1354                    (0x5f, 0x5f, 0x5f),
1355                    (0x5f, 0x5f, 0x87),
1356                    (0x5f, 0x5f, 0xaf),
1357                    (0x5f, 0x5f, 0xd7),
1358                    (0x5f, 0x5f, 0xff),
1359                    (0x5f, 0x87, 0x00),
1360                    (0x5f, 0x87, 0x5f),
1361                    (0x5f, 0x87, 0x87),
1362                    (0x5f, 0x87, 0xaf),
1363                    (0x5f, 0x87, 0xd7),
1364                    (0x5f, 0x87, 0xff),
1365                    (0x5f, 0xaf, 0x00),
1366                    (0x5f, 0xaf, 0x5f),
1367                    (0x5f, 0xaf, 0x87),
1368                    (0x5f, 0xaf, 0xaf),
1369                    (0x5f, 0xaf, 0xd7),
1370                    (0x5f, 0xaf, 0xff),
1371                    (0x5f, 0xd7, 0x00),
1372                    (0x5f, 0xd7, 0x5f),
1373                    (0x5f, 0xd7, 0x87),
1374                    (0x5f, 0xd7, 0xaf),
1375                    (0x5f, 0xd7, 0xd7),
1376                    (0x5f, 0xd7, 0xff),
1377                    (0x5f, 0xff, 0x00),
1378                    (0x5f, 0xff, 0x5f),
1379                    (0x5f, 0xff, 0x87),
1380                    (0x5f, 0xff, 0xaf),
1381                    (0x5f, 0xff, 0xd7),
1382                    (0x5f, 0xff, 0xff),
1383                    (0x87, 0x00, 0x00),
1384                    (0x87, 0x00, 0x5f),
1385                    (0x87, 0x00, 0x87),
1386                    (0x87, 0x00, 0xaf),
1387                    (0x87, 0x00, 0xd7),
1388                    (0x87, 0x00, 0xff),
1389                    (0x87, 0x5f, 0x00),
1390                    (0x87, 0x5f, 0x5f),
1391                    (0x87, 0x5f, 0x87),
1392                    (0x87, 0x5f, 0xaf),
1393                    (0x87, 0x5f, 0xd7),
1394                    (0x87, 0x5f, 0xff),
1395                    (0x87, 0x87, 0x00),
1396                    (0x87, 0x87, 0x5f),
1397                    (0x87, 0x87, 0x87),
1398                    (0x87, 0x87, 0xaf),
1399                    (0x87, 0x87, 0xd7),
1400                    (0x87, 0x87, 0xff),
1401                    (0x87, 0xaf, 0x00),
1402                    (0x87, 0xaf, 0x5f),
1403                    (0x87, 0xaf, 0x87),
1404                    (0x87, 0xaf, 0xaf),
1405                    (0x87, 0xaf, 0xd7),
1406                    (0x87, 0xaf, 0xff),
1407                    (0x87, 0xd7, 0x00),
1408                    (0x87, 0xd7, 0x5f),
1409                    (0x87, 0xd7, 0x87),
1410                    (0x87, 0xd7, 0xaf),
1411                    (0x87, 0xd7, 0xd7),
1412                    (0x87, 0xd7, 0xff),
1413                    (0x87, 0xff, 0x00),
1414                    (0x87, 0xff, 0x5f),
1415                    (0x87, 0xff, 0x87),
1416                    (0x87, 0xff, 0xaf),
1417                    (0x87, 0xff, 0xd7),
1418                    (0x87, 0xff, 0xff),
1419                    (0xaf, 0x00, 0x00),
1420                    (0xaf, 0x00, 0x5f),
1421                    (0xaf, 0x00, 0x87),
1422                    (0xaf, 0x00, 0xaf),
1423                    (0xaf, 0x00, 0xd7),
1424                    (0xaf, 0x00, 0xff),
1425                    (0xaf, 0x5f, 0x00),
1426                    (0xaf, 0x5f, 0x5f),
1427                    (0xaf, 0x5f, 0x87),
1428                    (0xaf, 0x5f, 0xaf),
1429                    (0xaf, 0x5f, 0xd7),
1430                    (0xaf, 0x5f, 0xff),
1431                    (0xaf, 0x87, 0x00),
1432                    (0xaf, 0x87, 0x5f),
1433                    (0xaf, 0x87, 0x87),
1434                    (0xaf, 0x87, 0xaf),
1435                    (0xaf, 0x87, 0xd7),
1436                    (0xaf, 0x87, 0xff),
1437                    (0xaf, 0xaf, 0x00),
1438                    (0xaf, 0xaf, 0x5f),
1439                    (0xaf, 0xaf, 0x87),
1440                    (0xaf, 0xaf, 0xaf),
1441                    (0xaf, 0xaf, 0xd7),
1442                    (0xaf, 0xaf, 0xff),
1443                    (0xaf, 0xd7, 0x00),
1444                    (0xaf, 0xd7, 0x5f),
1445                    (0xaf, 0xd7, 0x87),
1446                    (0xaf, 0xd7, 0xaf),
1447                    (0xaf, 0xd7, 0xd7),
1448                    (0xaf, 0xd7, 0xff),
1449                    (0xaf, 0xff, 0x00),
1450                    (0xaf, 0xff, 0x5f),
1451                    (0xaf, 0xff, 0x87),
1452                    (0xaf, 0xff, 0xaf),
1453                    (0xaf, 0xff, 0xd7),
1454                    (0xaf, 0xff, 0xff),
1455                    (0xd7, 0x00, 0x00),
1456                    (0xd7, 0x00, 0x5f),
1457                    (0xd7, 0x00, 0x87),
1458                    (0xd7, 0x00, 0xaf),
1459                    (0xd7, 0x00, 0xd7),
1460                    (0xd7, 0x00, 0xff),
1461                    (0xd7, 0x5f, 0x00),
1462                    (0xd7, 0x5f, 0x5f),
1463                    (0xd7, 0x5f, 0x87),
1464                    (0xd7, 0x5f, 0xaf),
1465                    (0xd7, 0x5f, 0xd7),
1466                    (0xd7, 0x5f, 0xff),
1467                    (0xd7, 0x87, 0x00),
1468                    (0xd7, 0x87, 0x5f),
1469                    (0xd7, 0x87, 0x87),
1470                    (0xd7, 0x87, 0xaf),
1471                    (0xd7, 0x87, 0xd7),
1472                    (0xd7, 0x87, 0xff),
1473                    (0xd7, 0xaf, 0x00),
1474                    (0xd7, 0xaf, 0x5f),
1475                    (0xd7, 0xaf, 0x87),
1476                    (0xd7, 0xaf, 0xaf),
1477                    (0xd7, 0xaf, 0xd7),
1478                    (0xd7, 0xaf, 0xff),
1479                    (0xd7, 0xd7, 0x00),
1480                    (0xd7, 0xd7, 0x5f),
1481                    (0xd7, 0xd7, 0x87),
1482                    (0xd7, 0xd7, 0xaf),
1483                    (0xd7, 0xd7, 0xd7),
1484                    (0xd7, 0xd7, 0xff),
1485                    (0xd7, 0xff, 0x00),
1486                    (0xd7, 0xff, 0x5f),
1487                    (0xd7, 0xff, 0x87),
1488                    (0xd7, 0xff, 0xaf),
1489                    (0xd7, 0xff, 0xd7),
1490                    (0xd7, 0xff, 0xff),
1491                    (0xff, 0x00, 0x00),
1492                    (0xff, 0x00, 0x5f),
1493                    (0xff, 0x00, 0x87),
1494                    (0xff, 0x00, 0xaf),
1495                    (0xff, 0x00, 0xd7),
1496                    (0xff, 0x00, 0xff),
1497                    (0xff, 0x5f, 0x00),
1498                    (0xff, 0x5f, 0x5f),
1499                    (0xff, 0x5f, 0x87),
1500                    (0xff, 0x5f, 0xaf),
1501                    (0xff, 0x5f, 0xd7),
1502                    (0xff, 0x5f, 0xff),
1503                    (0xff, 0x87, 0x00),
1504                    (0xff, 0x87, 0x5f),
1505                    (0xff, 0x87, 0x87),
1506                    (0xff, 0x87, 0xaf),
1507                    (0xff, 0x87, 0xd7),
1508                    (0xff, 0x87, 0xff),
1509                    (0xff, 0xaf, 0x00),
1510                    (0xff, 0xaf, 0x5f),
1511                    (0xff, 0xaf, 0x87),
1512                    (0xff, 0xaf, 0xaf),
1513                    (0xff, 0xaf, 0xd7),
1514                    (0xff, 0xaf, 0xff),
1515                    (0xff, 0xd7, 0x00),
1516                    (0xff, 0xd7, 0x5f),
1517                    (0xff, 0xd7, 0x87),
1518                    (0xff, 0xd7, 0xaf),
1519                    (0xff, 0xd7, 0xd7),
1520                    (0xff, 0xd7, 0xff),
1521                    (0xff, 0xff, 0x00),
1522                    (0xff, 0xff, 0x5f),
1523                    (0xff, 0xff, 0x87),
1524                    (0xff, 0xff, 0xaf),
1525                    (0xff, 0xff, 0xd7),
1526                    (0xff, 0xff, 0xff),
1527                    (0x08, 0x08, 0x08),
1528                    (0x12, 0x12, 0x12),
1529                    (0x1c, 0x1c, 0x1c),
1530                    (0x26, 0x26, 0x26),
1531                    (0x30, 0x30, 0x30),
1532                    (0x3a, 0x3a, 0x3a),
1533                    (0x44, 0x44, 0x44),
1534                    (0x4e, 0x4e, 0x4e),
1535                    (0x58, 0x58, 0x58),
1536                    (0x62, 0x62, 0x62),
1537                    (0x6c, 0x6c, 0x6c),
1538                    (0x76, 0x76, 0x76),
1539                    (0x80, 0x80, 0x80),
1540                    (0x8a, 0x8a, 0x8a),
1541                    (0x94, 0x94, 0x94),
1542                    (0x9e, 0x9e, 0x9e),
1543                    (0xa8, 0xa8, 0xa8),
1544                    (0xb2, 0xb2, 0xb2),
1545                    (0xbc, 0xbc, 0xbc),
1546                    (0xc6, 0xc6, 0xc6),
1547                    (0xd0, 0xd0, 0xd0),
1548                    (0xda, 0xda, 0xda),
1549                    (0xe4, 0xe4, 0xe4),
1550                    (0xee, 0xee, 0xee),
1551                ];
1552                VGA256[i as usize]
1553            }
1554            Color::Reset => (0, 0, 0),
1555        }
1556    }
1557}