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
21use ratatui::style::{Color, Style};
22use std::borrow::Cow;
23use std::fmt::{Display, Formatter};
24use std::mem;
25use std::str::FromStr;
26
27/// Refers to a color in the Palette.
28/// This is used for color-aliases.
29#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
30pub struct ColorIdx(pub Colors, pub usize);
31
32/// Names/Indexes into the color-table of the palette.
33#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
34pub enum Colors {
35    /// Colors for light text.
36    TextLight = 0,
37    /// Colors for dark text.
38    TextDark,
39    /// Primary highlight color.
40    Primary,
41    /// Secondary highlight color.
42    Secondary,
43    White,
44    Black,
45    Gray,
46    Red,
47    Orange,
48    Yellow,
49    LimeGreen,
50    Green,
51    BlueGreen,
52    Cyan,
53    Blue,
54    DeepBlue,
55    Purple,
56    Magenta,
57    RedPink,
58    /// Undefined color.
59    ///
60    /// Maps to Color::Reset when queried as a color.
61    /// When used to define a style fg or bg it sets them to [Option::None].
62    #[default]
63    None,
64}
65
66impl Display for ColorIdx {
67    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
68        write!(f, "{}:{}", self.0, self.1)
69    }
70}
71
72impl FromStr for ColorIdx {
73    type Err = ();
74
75    fn from_str(s: &str) -> Result<Self, Self::Err> {
76        let mut ss = s.split(':');
77        let Some(name) = ss.next() else {
78            return Err(());
79        };
80        let Ok(c) = Colors::from_str(name) else {
81            return Err(());
82        };
83        let Some(idx) = ss.next() else { return Err(()) };
84        let Ok(idx) = idx.parse::<usize>() else {
85            return Err(());
86        };
87        Ok(ColorIdx(c, idx))
88    }
89}
90
91impl Display for Colors {
92    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
93        let s = match self {
94            Colors::TextLight => "text-light",
95            Colors::TextDark => "text-dark",
96            Colors::Primary => "primary",
97            Colors::Secondary => "secondary",
98            Colors::White => "white",
99            Colors::Black => "black",
100            Colors::Gray => "gray",
101            Colors::Red => "red",
102            Colors::Orange => "orange",
103            Colors::Yellow => "yellow",
104            Colors::LimeGreen => "lime-green",
105            Colors::Green => "green",
106            Colors::BlueGreen => "blue-green",
107            Colors::Cyan => "cyan",
108            Colors::Blue => "blue",
109            Colors::DeepBlue => "deep-blue",
110            Colors::Purple => "purple",
111            Colors::Magenta => "magenta",
112            Colors::RedPink => "red-pink",
113            Colors::None => "none",
114        };
115        write!(f, "{}", s)
116    }
117}
118
119impl FromStr for Colors {
120    type Err = ();
121
122    fn from_str(s: &str) -> Result<Self, Self::Err> {
123        match s {
124            "text-light" => Ok(Colors::TextLight),
125            "text-dark" => Ok(Colors::TextDark),
126            "primary" => Ok(Colors::Primary),
127            "secondary" => Ok(Colors::Secondary),
128            "white" => Ok(Colors::White),
129            "black" => Ok(Colors::Black),
130            "gray" => Ok(Colors::Gray),
131            "red" => Ok(Colors::Red),
132            "orange" => Ok(Colors::Orange),
133            "yellow" => Ok(Colors::Yellow),
134            "lime-green" => Ok(Colors::LimeGreen),
135            "green" => Ok(Colors::Green),
136            "blue-green" => Ok(Colors::BlueGreen),
137            "cyan" => Ok(Colors::Cyan),
138            "blue" => Ok(Colors::Blue),
139            "deep-blue" => Ok(Colors::DeepBlue),
140            "purple" => Ok(Colors::Purple),
141            "magenta" => Ok(Colors::Magenta),
142            "red-pink" => Ok(Colors::RedPink),
143            "none" => Ok(Colors::None),
144            _ => Err(()),
145        }
146    }
147}
148
149impl Colors {
150    pub const LEN: usize = 19;
151}
152
153/// Color palette.
154///
155/// This provides the palette used for a theme.
156#[derive(Debug, Clone)]
157pub struct Palette {
158    /// Name of the color palette.
159    pub name: Cow<'static, str>,
160    /// Color palette. Use [Colors] for indexing.
161    pub color: [[Color; 8]; Colors::LEN],
162    /// **Sorted** list of aliases.
163    /// Must be pre-sorted for binary-search.
164    pub aliased: Cow<'static, [(Cow<'static, str>, ColorIdx)]>,
165}
166
167impl Default for Palette {
168    fn default() -> Self {
169        Self {
170            name: Cow::Borrowed(""),
171            color: [[Color::default(); 8]; Colors::LEN],
172            aliased: Cow::Borrowed(&[]),
173        }
174    }
175}
176
177/// Contrast rating for the text-color that should be used.
178#[derive(Debug)]
179pub(crate) enum Rating {
180    /// Use light/white text for the given background.
181    Light,
182    /// Use dark/black text for the given background.
183    Dark,
184}
185
186/// Create a color alias. Useful when creating a static Palette.
187pub const fn define_alias(
188    alias: &'static str,
189    color: Colors,
190    n: usize,
191) -> (Cow<'static, str>, ColorIdx) {
192    (Cow::Borrowed(alias), ColorIdx(color, n))
193}
194
195/// Create a color alias. This function is useful when
196/// modifying a Palette at runtime.
197pub fn define_rt_alias(
198    alias: impl Into<String>,
199    color: Colors,
200    n: usize,
201) -> (Cow<'static, str>, ColorIdx) {
202    let alias = alias.into();
203    (Cow::Owned(alias), ColorIdx(color, n))
204}
205
206impl Palette {
207    /// Create a style from the given white shade.
208    /// n is 0..=7 with 4..=7 as darker variants of the first 3.
209    pub fn white(&self, n: usize) -> Style {
210        self.style(Colors::White, n)
211    }
212
213    /// Create a style from the given black shade.
214    /// n is 0..=7 with 4..=7 as darker variants of the first 3.
215    pub fn black(&self, n: usize) -> Style {
216        self.style(Colors::Black, n)
217    }
218
219    /// Create a style from the given gray shade.
220    /// n is 0..=7 with 4..=7 as darker variants of the first 3.
221    pub fn gray(&self, n: usize) -> Style {
222        self.style(Colors::Gray, n)
223    }
224
225    /// Create a style from the given red shade.
226    /// n is 0..=7 with 4..=7 as darker variants of the first 3.
227    pub fn red(&self, n: usize) -> Style {
228        self.style(Colors::Red, n)
229    }
230
231    /// Create a style from the given orange shade.
232    /// n is 0..=7 with 4..=7 as darker variants of the first 3.
233    pub fn orange(&self, n: usize) -> Style {
234        self.style(Colors::Orange, n)
235    }
236
237    /// Create a style from the given yellow shade.
238    /// n is 0..=7 with 4..=7 as darker variants of the first 3.
239    pub fn yellow(&self, n: usize) -> Style {
240        self.style(Colors::Yellow, n)
241    }
242
243    /// Create a style from the given limegreen shade.
244    /// n is 0..=7 with 4..=7 as darker variants of the first 3.
245    pub fn limegreen(&self, n: usize) -> Style {
246        self.style(Colors::LimeGreen, n)
247    }
248
249    /// Create a style from the given green shade.
250    /// n is 0..=7 with 4..=7 as darker variants of the first 3.
251    pub fn green(&self, n: usize) -> Style {
252        self.style(Colors::Green, n)
253    }
254
255    /// Create a style from the given bluegreen shade.
256    /// n is 0..=7 with 4..=7 as darker variants of the first 3.
257    pub fn bluegreen(&self, n: usize) -> Style {
258        self.style(Colors::BlueGreen, n)
259    }
260
261    /// Create a style from the given cyan shade.
262    /// n is 0..=7 with 4..=7 as darker variants of the first 3.
263    pub fn cyan(&self, n: usize) -> Style {
264        self.style(Colors::Cyan, n)
265    }
266
267    /// Create a style from the given blue shade.
268    /// n is 0..=7 with 4..=7 as darker variants of the first 3.
269    pub fn blue(&self, n: usize) -> Style {
270        self.style(Colors::Blue, n)
271    }
272
273    /// Create a style from the given deepblue shade.
274    /// n is 0..=7 with 4..=7 as darker variants of the first 3.
275    pub fn deepblue(&self, n: usize) -> Style {
276        self.style(Colors::DeepBlue, n)
277    }
278
279    /// Create a style from the given purple shade.
280    /// n is 0..=7 with 4..=7 as darker variants of the first 3.
281    pub fn purple(&self, n: usize) -> Style {
282        self.style(Colors::Purple, n)
283    }
284
285    /// Create a style from the given magenta shade.
286    /// n is 0..=7 with 4..=7 as darker variants of the first 3.
287    pub fn magenta(&self, n: usize) -> Style {
288        self.style(Colors::Magenta, n)
289    }
290
291    /// Create a style from the given redpink shade.
292    /// n is 0..=7 with 4..=7 as darker variants of the first 3.
293    pub fn redpink(&self, n: usize) -> Style {
294        self.style(Colors::RedPink, n)
295    }
296
297    /// Create a style from the given primary shade.
298    /// n is 0..=7 with 4..=7 as darker variants of the first 3.
299    pub fn primary(&self, n: usize) -> Style {
300        self.style(Colors::Primary, n)
301    }
302
303    /// Create a style from the given secondary shade.
304    /// n is 0..=7 with 4..=7 as darker variants of the first 3.
305    pub fn secondary(&self, n: usize) -> Style {
306        self.style(Colors::Secondary, n)
307    }
308}
309
310impl Palette {
311    /// The Color for the id + index n.
312    pub fn color(&self, id: Colors, n: usize) -> Color {
313        if id == Colors::None {
314            Color::Reset
315        } else {
316            self.color[id as usize][n]
317        }
318    }
319
320    /// Create a style with the given background color.
321    /// The foreground is chosen from the text-colors for a
322    /// normal contrast.
323    pub fn style(&self, id: Colors, n: usize) -> Style {
324        let color = self.color(id, n);
325        self.normal_contrast(color)
326    }
327
328    /// Create a style with the given background color.
329    /// The foreground is chosen from the text-colors for
330    /// high contrast.
331    pub fn high_style(&self, id: Colors, n: usize) -> Style {
332        let color = self.color(id, n);
333        self.high_contrast(color)
334    }
335
336    /// Create a style with the given fg/bg.
337    pub fn fg_bg_style(&self, fg: Colors, n: usize, bg: Colors, m: usize) -> Style {
338        let color = self.color(fg, n);
339        let color_bg = self.color(bg, m);
340        let mut style = Style::new();
341        if color != Color::Reset {
342            style = style.fg(color);
343        }
344        if color_bg != Color::Reset {
345            style = style.bg(color_bg);
346        }
347        style
348    }
349
350    /// Create a style with only fg set.
351    pub fn fg_style(&self, id: Colors, n: usize) -> Style {
352        let color = self.color(id, n);
353        let mut style = Style::new();
354        if color != Color::Reset {
355            style = style.fg(color);
356        }
357        style
358    }
359
360    /// Create a style with only bg set.
361    pub fn bg_style(&self, id: Colors, n: usize) -> Style {
362        let color = self.color(id, n);
363        let mut style = Style::new();
364        if color != Color::Reset {
365            style = style.bg(color);
366        }
367        style
368    }
369
370    /// Add an alias.
371    pub fn add_aliased(&mut self, id: &str, color_idx: ColorIdx) {
372        if matches!(self.aliased, Cow::Borrowed(_)) {
373            self.aliased = Cow::Owned(mem::take(&mut self.aliased).into_owned());
374        }
375        match &mut self.aliased {
376            Cow::Borrowed(_) => {
377                unreachable!()
378            }
379            Cow::Owned(aliased) => {
380                aliased.push((Cow::Owned(id.to_string()), color_idx));
381                aliased.sort();
382            }
383        }
384    }
385
386    /// Try to find an alias.
387    pub fn try_aliased(&self, id: &str) -> Option<ColorIdx> {
388        match self.aliased.binary_search_by_key(&id, |v| v.0.as_ref()) {
389            Ok(n) => Some(self.aliased[n].1),
390            Err(_) => None,
391        }
392    }
393
394    /// Get the ColorIdx of an aliased color.
395    ///
396    /// __Panic__
397    ///
398    /// With debug_assertions this panics if the alias is not found.
399    /// Otherwise, it returns a default.
400    pub fn aliased(&self, id: &str) -> ColorIdx {
401        match self.try_aliased(id) {
402            Some(c) => c,
403            None => {
404                if cfg!(debug_assertions) {
405                    panic!("unknown aliased color {:?}", id);
406                } else {
407                    ColorIdx::default()
408                }
409            }
410        }
411    }
412
413    /// Get an aliased color.
414    pub fn color_alias(&self, id: &str) -> Color {
415        match self.try_aliased(id) {
416            Some(ColorIdx { 0: c, 1: idx }) => {
417                if c != Colors::None {
418                    self.color[c as usize][idx]
419                } else {
420                    Color::default()
421                }
422            }
423            None => {
424                if cfg!(debug_assertions) {
425                    panic!("unknown aliased color {:?}", id);
426                } else {
427                    Color::default()
428                }
429            }
430        }
431    }
432
433    /// Get a Style for a color-alias.
434    /// Uses the color as bg() and finds the matching text-color
435    /// for normal contrast.
436    pub fn style_alias(&self, bg: &str) -> Style {
437        let color = self.color_alias(bg);
438        self.normal_contrast(color)
439    }
440
441    /// Get a Style for a color-alias.
442    /// Uses the color as bg() and finds the matching text-color
443    /// for high contrast.
444    pub fn high_style_alias(&self, bg: &str) -> Style {
445        let color = self.color_alias(bg);
446        self.high_contrast(color)
447    }
448
449    /// Get a Style for a color-alias.
450    /// Uses explicit aliases for fg() and bg()
451    pub fn fg_bg_style_alias(&self, fg: &str, bg: &str) -> Style {
452        let color = self.color_alias(fg);
453        let color_bg = self.color_alias(bg);
454        let mut style = Style::new();
455        if color != Color::Reset {
456            style = style.fg(color);
457        }
458        if color_bg != Color::Reset {
459            style = style.bg(color_bg);
460        }
461        style
462    }
463
464    /// Get a Style for a color-alias.
465    /// This creates a style with only the fg() color set.
466    pub fn fg_style_alias(&self, fg: &str) -> Style {
467        let color = self.color_alias(fg);
468        let mut style = Style::new();
469        if color != Color::Reset {
470            style = style.fg(color);
471        }
472        style
473    }
474
475    /// Get a Style for a color-alias.
476    /// This creates a style with only the bg() color set.
477    pub fn bg_style_alias(&self, bg: &str) -> Style {
478        let color = self.color_alias(bg);
479        let mut style = Style::new();
480        if color != Color::Reset {
481            style = style.bg(color);
482        }
483        style
484    }
485}
486
487impl Palette {
488    /// Create a style with the given background color.
489    /// Uses `white[3]` or `black[0]` for the foreground,
490    /// based on `rate_text_color`.
491    pub fn high_contrast(&self, color: Color) -> Style {
492        match Self::rate_text_color(color) {
493            None => Style::new(),
494            Some(Rating::Light) => Style::new().bg(color).fg(self.color(Colors::TextLight, 3)),
495            Some(Rating::Dark) => Style::new().bg(color).fg(self.color(Colors::TextDark, 3)),
496        }
497    }
498
499    /// Create a style with the given background color.
500    /// Uses text_light or text_dark for the foreground,
501    /// based on `rate_text_color`.
502    pub fn normal_contrast(&self, color: Color) -> Style {
503        match Self::rate_text_color(color) {
504            None => Style::new(),
505            Some(Rating::Light) => Style::new().bg(color).fg(self.color(Colors::TextLight, 0)),
506            Some(Rating::Dark) => Style::new().bg(color).fg(self.color(Colors::TextDark, 0)),
507        }
508    }
509
510    /// Pick a color from the choice with a good contrast to the
511    /// given background.
512    pub fn normal_contrast_color(&self, bg: Color, text: &[Color]) -> Style {
513        if bg == Color::Reset {
514            return Style::new();
515        }
516        let mut color0 = text[0];
517        let mut color1 = text[0];
518        let mut contrast1 = Self::contrast_bt_srgb(color1, bg);
519
520        for text_color in text {
521            let test = Self::contrast_bt_srgb(*text_color, bg);
522            if test > contrast1 {
523                color0 = color1;
524                color1 = *text_color;
525                contrast1 = test;
526            }
527        }
528
529        Style::new().bg(bg).fg(color0)
530    }
531
532    /// Pick a color from the choice with the best contrast to the
533    /// given background.
534    pub fn high_contrast_color(&self, bg: Color, text: &[Color]) -> Style {
535        if bg == Color::Reset {
536            return Style::new();
537        }
538        let mut color0 = text[0];
539        let mut color1 = text[0];
540        let mut contrast1 = Self::contrast_bt_srgb(color1, bg);
541
542        for text_color in text {
543            let test = Self::contrast_bt_srgb(*text_color, bg);
544            if test > contrast1 {
545                color0 = color1;
546                color1 = *text_color;
547                contrast1 = test;
548            }
549        }
550        // don't use the second brightest.
551        _ = color0;
552
553        Style::new().bg(bg).fg(color1)
554    }
555
556    // /// Gives the luminance according to Rec.ITU-R BT.601-7.
557    // const fn luminance_itu(color: Color) -> f32 {
558    //     let (r, g, b) = Self::color2rgb(color);
559    //     0.2989f32 * (r as f32) / 255f32
560    //         + 0.5870f32 * (g as f32) / 255f32
561    //         + 0.1140f32 * (b as f32) / 255f32
562    // }
563    //
564    // /// Gives the luminance according to Rec.ITU-R BT.601-7.
565    // fn luminance_itu_srgb(color: Color) -> f32 {
566    //     let (r, g, b) = Self::color2rgb(color);
567    //     0.2989f32 * (r as f32) / 255f32
568    //         + 0.5870f32 * (g as f32) / 255f32
569    //         + 0.1140f32 * (b as f32) / 255f32
570    // }
571    //
572    // /// Contrast between two colors.
573    // fn contrast_itu_srgb(color: Color, color2: Color) -> f32 {
574    //     let lum1 = Self::luminance_itu_srgb(color);
575    //     let lum2 = Self::luminance_itu_srgb(color2);
576    //     (lum1 + 0.05f32) / (lum2 + 0.05f32)
577    // }
578
579    /// Gives the luminance according to BT.709.
580    pub(crate) const fn luminance_bt(color: Color) -> f32 {
581        let (r, g, b) = Self::color_to_rgb(color);
582        0.2126f32 * ((r as f32) / 255f32)
583            + 0.7152f32 * ((g as f32) / 255f32)
584            + 0.0722f32 * ((b as f32) / 255f32)
585    }
586
587    /// Gives the luminance according to BT.709.
588    pub(crate) fn luminance_bt_srgb(color: Color) -> f32 {
589        let (r, g, b) = Self::color_to_rgb(color);
590        0.2126f32 * ((r as f32) / 255f32).powf(2.2f32)
591            + 0.7152f32 * ((g as f32) / 255f32).powf(2.2f32)
592            + 0.0722f32 * ((b as f32) / 255f32).powf(2.2f32)
593    }
594
595    /// Contrast between two colors.
596    pub(crate) fn contrast_bt_srgb(color: Color, color2: Color) -> f32 {
597        let lum1 = Self::luminance_bt_srgb(color);
598        let lum2 = Self::luminance_bt_srgb(color2);
599        (lum1 - lum2).abs()
600        // Don't use this prescribed method.
601        // The abs diff comes out better.
602        // (lum1 + 0.05f32) / (lum2 + 0.05f32)
603    }
604
605    /// This gives back a [Rating] for the given background.
606    ///
607    /// This converts RGB to grayscale and takes the grayscale value
608    /// of VGA cyan as threshold, which is about 105 out of 255.
609    /// This point is a bit arbitrary, just based on what I
610    /// perceive as acceptable. But it produces a good reading
611    /// contrast in my experience.
612    ///
613    /// For the named colors it takes the VGA equivalent as a base.
614    /// For indexed colors it splits the range in half as an estimate.
615    pub(crate) fn rate_text_color(color: Color) -> Option<Rating> {
616        match color {
617            Color::Reset => None,
618            Color::Black => Some(Rating::Light),       //0
619            Color::Red => Some(Rating::Light),         //1
620            Color::Green => Some(Rating::Light),       //2
621            Color::Yellow => Some(Rating::Light),      //3
622            Color::Blue => Some(Rating::Light),        //4
623            Color::Magenta => Some(Rating::Light),     //5
624            Color::Cyan => Some(Rating::Light),        //6
625            Color::Gray => Some(Rating::Dark),         //7
626            Color::DarkGray => Some(Rating::Light),    //8
627            Color::LightRed => Some(Rating::Dark),     //9
628            Color::LightGreen => Some(Rating::Dark),   //10
629            Color::LightYellow => Some(Rating::Dark),  //11
630            Color::LightBlue => Some(Rating::Light),   //12
631            Color::LightMagenta => Some(Rating::Dark), //13
632            Color::LightCyan => Some(Rating::Dark),    //14
633            Color::White => Some(Rating::Dark),        //15
634            c => {
635                let lum = Self::luminance_bt(c);
636                if lum >= 0.4117f32 {
637                    Some(Rating::Dark)
638                } else {
639                    Some(Rating::Light)
640                }
641            }
642        }
643    }
644
645    /// Converts the given color to an equivalent grayscale.
646    pub const fn grayscale(color: Color) -> Color {
647        let lum = Self::luminance_bt(color);
648        let gray = lum * 255f32;
649        Color::Rgb(gray as u8, gray as u8, gray as u8)
650    }
651
652    /// Color from u32
653    pub const fn color_from_u32(c: u32) -> Color {
654        let r0 = (c >> 16) as u8;
655        let g0 = (c >> 8) as u8;
656        let b0 = c as u8;
657        Color::Rgb(r0, g0, b0)
658    }
659
660    /// Color to u32
661    pub const fn color_to_u32(color: Color) -> u32 {
662        let (r, g, b) = Self::color_to_rgb(color);
663        ((r as u32) << 16) + ((g as u32) << 8) + (b as u32)
664    }
665
666    /// Calculates a linear interpolation for the two colors
667    /// and fills the first 4 colors with it.
668    /// The next 4 colors are scaled down versions using dark_scale_to.
669    pub const fn interpolatec(c0: Color, c3: Color, dark_scale_to: u8) -> [Color; 8] {
670        Self::interpolate(
671            Self::color_to_u32(c0),
672            Self::color_to_u32(c3),
673            dark_scale_to,
674        )
675    }
676
677    /// Calculates a linear interpolation for the two colors
678    /// and fills the first 4 colors with it.
679    /// The next 4 colors are scaled down versions using dark_scale_to.
680    pub const fn interpolate(c0: u32, c3: u32, dark_scale_to: u8) -> [Color; 8] {
681        // dark
682        let mut c4 = Self::color_to_rgb(Self::color_from_u32(c0));
683        c4.0 = Self::scale_to(c4.0, dark_scale_to);
684        c4.1 = Self::scale_to(c4.1, dark_scale_to);
685        c4.2 = Self::scale_to(c4.2, dark_scale_to);
686        let c4 = ((c4.0 as u32) << 16) + ((c4.1 as u32) << 8) + (c4.2 as u32);
687
688        let mut c7 = Self::color_to_rgb(Self::color_from_u32(c3));
689        c7.0 = Self::scale_to(c7.0, dark_scale_to);
690        c7.1 = Self::scale_to(c7.1, dark_scale_to);
691        c7.2 = Self::scale_to(c7.2, dark_scale_to);
692        let c7 = ((c7.0 as u32) << 16) + ((c7.1 as u32) << 8) + (c7.2 as u32);
693
694        Self::interpolate2(c0, c3, c4, c7)
695    }
696
697    /// Calculates a linear interpolation for the two colors
698    /// and fills the first 4 colors with it.
699    /// The next 4 colors are scaled down versions using dark_scale_to.
700    pub const fn interpolatec2(c0: Color, c3: Color, c4: Color, c7: Color) -> [Color; 8] {
701        Self::interpolate2(
702            Self::color_to_u32(c0),
703            Self::color_to_u32(c3),
704            Self::color_to_u32(c4),
705            Self::color_to_u32(c7),
706        )
707    }
708
709    /// Calculates a linear interpolation for the two colors
710    /// and fills the first 4 colors with it.
711    /// The next 4 colors are scaled down versions using dark_scale_to.
712    pub const fn interpolate2(c0: u32, c3: u32, c4: u32, c7: u32) -> [Color; 8] {
713        // 1/3
714        const fn i1(a: u8, b: u8) -> u8 {
715            if a < b {
716                a + (b - a) / 3
717            } else {
718                a - (a - b) / 3
719            }
720        }
721        // 2/3
722        const fn i2(a: u8, b: u8) -> u8 {
723            if a < b {
724                b - (b - a) / 3
725            } else {
726                b + (a - b) / 3
727            }
728        }
729
730        let r0 = (c0 >> 16) as u8;
731        let g0 = (c0 >> 8) as u8;
732        let b0 = c0 as u8;
733
734        let r3 = (c3 >> 16) as u8;
735        let g3 = (c3 >> 8) as u8;
736        let b3 = c3 as u8;
737
738        let r1 = i1(r0, r3);
739        let g1 = i1(g0, g3);
740        let b1 = i1(b0, b3);
741
742        let r2 = i2(r0, r3);
743        let g2 = i2(g0, g3);
744        let b2 = i2(b0, b3);
745
746        // dark
747        let r4 = (c4 >> 16) as u8;
748        let g4 = (c4 >> 8) as u8;
749        let b4 = c4 as u8;
750
751        let r7 = (c7 >> 16) as u8;
752        let g7 = (c7 >> 8) as u8;
753        let b7 = c7 as u8;
754
755        let r5 = i1(r4, r7);
756        let g5 = i1(g4, g7);
757        let b5 = i1(b4, b7);
758
759        let r6 = i2(r4, r7);
760        let g6 = i2(g4, g7);
761        let b6 = i2(b4, b7);
762
763        [
764            Color::Rgb(r0, g0, b0),
765            Color::Rgb(r1, g1, b1),
766            Color::Rgb(r2, g2, b2),
767            Color::Rgb(r3, g3, b3),
768            Color::Rgb(r4, g4, b4),
769            Color::Rgb(r5, g5, b5),
770            Color::Rgb(r6, g6, b6),
771            Color::Rgb(r7, g7, b7),
772        ]
773    }
774
775    /// Scale the u8 down to scale_to.
776    pub const fn scale_to(v: u8, scale_to: u8) -> u8 {
777        (((v as u16) * scale_to as u16) / 255u16) as u8
778    }
779
780    /// Gives back the rgb for any ratatui Color.
781    /// Has the indexed and the named colors too.
782    pub const fn color_to_rgb(color: Color) -> (u8, u8, u8) {
783        match color {
784            Color::Black => (0x00, 0x00, 0x00),
785            Color::Red => (0xaa, 0x00, 0x00),
786            Color::Green => (0x00, 0xaa, 0x00),
787            Color::Yellow => (0xaa, 0x55, 0x00),
788            Color::Blue => (0x00, 0x00, 0xaa),
789            Color::Magenta => (0xaa, 0x00, 0xaa),
790            Color::Cyan => (0x00, 0xaa, 0xaa),
791            Color::Gray => (0xaa, 0xaa, 0xaa),
792            Color::DarkGray => (0x55, 0x55, 0x55),
793            Color::LightRed => (0xff, 0x55, 0x55),
794            Color::LightGreen => (0x55, 0xff, 0x55),
795            Color::LightYellow => (0xff, 0xff, 0x55),
796            Color::LightBlue => (0x55, 0x55, 0xff),
797            Color::LightMagenta => (0xff, 0x55, 0xff),
798            Color::LightCyan => (0x55, 0xff, 0xff),
799            Color::White => (0xff, 0xff, 0xff),
800            Color::Rgb(r, g, b) => (r, g, b),
801            Color::Indexed(i) => {
802                const VGA256: [(u8, u8, u8); 256] = [
803                    (0x00, 0x00, 0x00),
804                    (0x80, 0x00, 0x00),
805                    (0x00, 0x80, 0x00),
806                    (0x80, 0x80, 0x00),
807                    (0x00, 0x00, 0x80),
808                    (0x80, 0x00, 0x80),
809                    (0x00, 0x80, 0x80),
810                    (0xc0, 0xc0, 0xc0),
811                    (0x80, 0x80, 0x80),
812                    (0xff, 0x00, 0x00),
813                    (0x00, 0xff, 0x00),
814                    (0xff, 0xff, 0x00),
815                    (0x00, 0x00, 0xff),
816                    (0xff, 0x00, 0xff),
817                    (0x00, 0xff, 0xff),
818                    (0xff, 0xff, 0xff),
819                    (0x00, 0x00, 0x00),
820                    (0x00, 0x00, 0x5f),
821                    (0x00, 0x00, 0x87),
822                    (0x00, 0x00, 0xaf),
823                    (0x00, 0x00, 0xd7),
824                    (0x00, 0x00, 0xff),
825                    (0x00, 0x5f, 0x00),
826                    (0x00, 0x5f, 0x5f),
827                    (0x00, 0x5f, 0x87),
828                    (0x00, 0x5f, 0xaf),
829                    (0x00, 0x5f, 0xd7),
830                    (0x00, 0x5f, 0xff),
831                    (0x00, 0x87, 0x00),
832                    (0x00, 0x87, 0x5f),
833                    (0x00, 0x87, 0x87),
834                    (0x00, 0x87, 0xaf),
835                    (0x00, 0x87, 0xd7),
836                    (0x00, 0x87, 0xff),
837                    (0x00, 0xaf, 0x00),
838                    (0x00, 0xaf, 0x5f),
839                    (0x00, 0xaf, 0x87),
840                    (0x00, 0xaf, 0xaf),
841                    (0x00, 0xaf, 0xd7),
842                    (0x00, 0xaf, 0xff),
843                    (0x00, 0xd7, 0x00),
844                    (0x00, 0xd7, 0x5f),
845                    (0x00, 0xd7, 0x87),
846                    (0x00, 0xd7, 0xaf),
847                    (0x00, 0xd7, 0xd7),
848                    (0x00, 0xd7, 0xff),
849                    (0x00, 0xff, 0x00),
850                    (0x00, 0xff, 0x5f),
851                    (0x00, 0xff, 0x87),
852                    (0x00, 0xff, 0xaf),
853                    (0x00, 0xff, 0xd7),
854                    (0x00, 0xff, 0xff),
855                    (0x5f, 0x00, 0x00),
856                    (0x5f, 0x00, 0x5f),
857                    (0x5f, 0x00, 0x87),
858                    (0x5f, 0x00, 0xaf),
859                    (0x5f, 0x00, 0xd7),
860                    (0x5f, 0x00, 0xff),
861                    (0x5f, 0x5f, 0x00),
862                    (0x5f, 0x5f, 0x5f),
863                    (0x5f, 0x5f, 0x87),
864                    (0x5f, 0x5f, 0xaf),
865                    (0x5f, 0x5f, 0xd7),
866                    (0x5f, 0x5f, 0xff),
867                    (0x5f, 0x87, 0x00),
868                    (0x5f, 0x87, 0x5f),
869                    (0x5f, 0x87, 0x87),
870                    (0x5f, 0x87, 0xaf),
871                    (0x5f, 0x87, 0xd7),
872                    (0x5f, 0x87, 0xff),
873                    (0x5f, 0xaf, 0x00),
874                    (0x5f, 0xaf, 0x5f),
875                    (0x5f, 0xaf, 0x87),
876                    (0x5f, 0xaf, 0xaf),
877                    (0x5f, 0xaf, 0xd7),
878                    (0x5f, 0xaf, 0xff),
879                    (0x5f, 0xd7, 0x00),
880                    (0x5f, 0xd7, 0x5f),
881                    (0x5f, 0xd7, 0x87),
882                    (0x5f, 0xd7, 0xaf),
883                    (0x5f, 0xd7, 0xd7),
884                    (0x5f, 0xd7, 0xff),
885                    (0x5f, 0xff, 0x00),
886                    (0x5f, 0xff, 0x5f),
887                    (0x5f, 0xff, 0x87),
888                    (0x5f, 0xff, 0xaf),
889                    (0x5f, 0xff, 0xd7),
890                    (0x5f, 0xff, 0xff),
891                    (0x87, 0x00, 0x00),
892                    (0x87, 0x00, 0x5f),
893                    (0x87, 0x00, 0x87),
894                    (0x87, 0x00, 0xaf),
895                    (0x87, 0x00, 0xd7),
896                    (0x87, 0x00, 0xff),
897                    (0x87, 0x5f, 0x00),
898                    (0x87, 0x5f, 0x5f),
899                    (0x87, 0x5f, 0x87),
900                    (0x87, 0x5f, 0xaf),
901                    (0x87, 0x5f, 0xd7),
902                    (0x87, 0x5f, 0xff),
903                    (0x87, 0x87, 0x00),
904                    (0x87, 0x87, 0x5f),
905                    (0x87, 0x87, 0x87),
906                    (0x87, 0x87, 0xaf),
907                    (0x87, 0x87, 0xd7),
908                    (0x87, 0x87, 0xff),
909                    (0x87, 0xaf, 0x00),
910                    (0x87, 0xaf, 0x5f),
911                    (0x87, 0xaf, 0x87),
912                    (0x87, 0xaf, 0xaf),
913                    (0x87, 0xaf, 0xd7),
914                    (0x87, 0xaf, 0xff),
915                    (0x87, 0xd7, 0x00),
916                    (0x87, 0xd7, 0x5f),
917                    (0x87, 0xd7, 0x87),
918                    (0x87, 0xd7, 0xaf),
919                    (0x87, 0xd7, 0xd7),
920                    (0x87, 0xd7, 0xff),
921                    (0x87, 0xff, 0x00),
922                    (0x87, 0xff, 0x5f),
923                    (0x87, 0xff, 0x87),
924                    (0x87, 0xff, 0xaf),
925                    (0x87, 0xff, 0xd7),
926                    (0x87, 0xff, 0xff),
927                    (0xaf, 0x00, 0x00),
928                    (0xaf, 0x00, 0x5f),
929                    (0xaf, 0x00, 0x87),
930                    (0xaf, 0x00, 0xaf),
931                    (0xaf, 0x00, 0xd7),
932                    (0xaf, 0x00, 0xff),
933                    (0xaf, 0x5f, 0x00),
934                    (0xaf, 0x5f, 0x5f),
935                    (0xaf, 0x5f, 0x87),
936                    (0xaf, 0x5f, 0xaf),
937                    (0xaf, 0x5f, 0xd7),
938                    (0xaf, 0x5f, 0xff),
939                    (0xaf, 0x87, 0x00),
940                    (0xaf, 0x87, 0x5f),
941                    (0xaf, 0x87, 0x87),
942                    (0xaf, 0x87, 0xaf),
943                    (0xaf, 0x87, 0xd7),
944                    (0xaf, 0x87, 0xff),
945                    (0xaf, 0xaf, 0x00),
946                    (0xaf, 0xaf, 0x5f),
947                    (0xaf, 0xaf, 0x87),
948                    (0xaf, 0xaf, 0xaf),
949                    (0xaf, 0xaf, 0xd7),
950                    (0xaf, 0xaf, 0xff),
951                    (0xaf, 0xd7, 0x00),
952                    (0xaf, 0xd7, 0x5f),
953                    (0xaf, 0xd7, 0x87),
954                    (0xaf, 0xd7, 0xaf),
955                    (0xaf, 0xd7, 0xd7),
956                    (0xaf, 0xd7, 0xff),
957                    (0xaf, 0xff, 0x00),
958                    (0xaf, 0xff, 0x5f),
959                    (0xaf, 0xff, 0x87),
960                    (0xaf, 0xff, 0xaf),
961                    (0xaf, 0xff, 0xd7),
962                    (0xaf, 0xff, 0xff),
963                    (0xd7, 0x00, 0x00),
964                    (0xd7, 0x00, 0x5f),
965                    (0xd7, 0x00, 0x87),
966                    (0xd7, 0x00, 0xaf),
967                    (0xd7, 0x00, 0xd7),
968                    (0xd7, 0x00, 0xff),
969                    (0xd7, 0x5f, 0x00),
970                    (0xd7, 0x5f, 0x5f),
971                    (0xd7, 0x5f, 0x87),
972                    (0xd7, 0x5f, 0xaf),
973                    (0xd7, 0x5f, 0xd7),
974                    (0xd7, 0x5f, 0xff),
975                    (0xd7, 0x87, 0x00),
976                    (0xd7, 0x87, 0x5f),
977                    (0xd7, 0x87, 0x87),
978                    (0xd7, 0x87, 0xaf),
979                    (0xd7, 0x87, 0xd7),
980                    (0xd7, 0x87, 0xff),
981                    (0xd7, 0xaf, 0x00),
982                    (0xd7, 0xaf, 0x5f),
983                    (0xd7, 0xaf, 0x87),
984                    (0xd7, 0xaf, 0xaf),
985                    (0xd7, 0xaf, 0xd7),
986                    (0xd7, 0xaf, 0xff),
987                    (0xd7, 0xd7, 0x00),
988                    (0xd7, 0xd7, 0x5f),
989                    (0xd7, 0xd7, 0x87),
990                    (0xd7, 0xd7, 0xaf),
991                    (0xd7, 0xd7, 0xd7),
992                    (0xd7, 0xd7, 0xff),
993                    (0xd7, 0xff, 0x00),
994                    (0xd7, 0xff, 0x5f),
995                    (0xd7, 0xff, 0x87),
996                    (0xd7, 0xff, 0xaf),
997                    (0xd7, 0xff, 0xd7),
998                    (0xd7, 0xff, 0xff),
999                    (0xff, 0x00, 0x00),
1000                    (0xff, 0x00, 0x5f),
1001                    (0xff, 0x00, 0x87),
1002                    (0xff, 0x00, 0xaf),
1003                    (0xff, 0x00, 0xd7),
1004                    (0xff, 0x00, 0xff),
1005                    (0xff, 0x5f, 0x00),
1006                    (0xff, 0x5f, 0x5f),
1007                    (0xff, 0x5f, 0x87),
1008                    (0xff, 0x5f, 0xaf),
1009                    (0xff, 0x5f, 0xd7),
1010                    (0xff, 0x5f, 0xff),
1011                    (0xff, 0x87, 0x00),
1012                    (0xff, 0x87, 0x5f),
1013                    (0xff, 0x87, 0x87),
1014                    (0xff, 0x87, 0xaf),
1015                    (0xff, 0x87, 0xd7),
1016                    (0xff, 0x87, 0xff),
1017                    (0xff, 0xaf, 0x00),
1018                    (0xff, 0xaf, 0x5f),
1019                    (0xff, 0xaf, 0x87),
1020                    (0xff, 0xaf, 0xaf),
1021                    (0xff, 0xaf, 0xd7),
1022                    (0xff, 0xaf, 0xff),
1023                    (0xff, 0xd7, 0x00),
1024                    (0xff, 0xd7, 0x5f),
1025                    (0xff, 0xd7, 0x87),
1026                    (0xff, 0xd7, 0xaf),
1027                    (0xff, 0xd7, 0xd7),
1028                    (0xff, 0xd7, 0xff),
1029                    (0xff, 0xff, 0x00),
1030                    (0xff, 0xff, 0x5f),
1031                    (0xff, 0xff, 0x87),
1032                    (0xff, 0xff, 0xaf),
1033                    (0xff, 0xff, 0xd7),
1034                    (0xff, 0xff, 0xff),
1035                    (0x08, 0x08, 0x08),
1036                    (0x12, 0x12, 0x12),
1037                    (0x1c, 0x1c, 0x1c),
1038                    (0x26, 0x26, 0x26),
1039                    (0x30, 0x30, 0x30),
1040                    (0x3a, 0x3a, 0x3a),
1041                    (0x44, 0x44, 0x44),
1042                    (0x4e, 0x4e, 0x4e),
1043                    (0x58, 0x58, 0x58),
1044                    (0x62, 0x62, 0x62),
1045                    (0x6c, 0x6c, 0x6c),
1046                    (0x76, 0x76, 0x76),
1047                    (0x80, 0x80, 0x80),
1048                    (0x8a, 0x8a, 0x8a),
1049                    (0x94, 0x94, 0x94),
1050                    (0x9e, 0x9e, 0x9e),
1051                    (0xa8, 0xa8, 0xa8),
1052                    (0xb2, 0xb2, 0xb2),
1053                    (0xbc, 0xbc, 0xbc),
1054                    (0xc6, 0xc6, 0xc6),
1055                    (0xd0, 0xd0, 0xd0),
1056                    (0xda, 0xda, 0xda),
1057                    (0xe4, 0xe4, 0xe4),
1058                    (0xee, 0xee, 0xee),
1059                ];
1060                VGA256[i as usize]
1061            }
1062            Color::Reset => (0, 0, 0),
1063        }
1064    }
1065}