1use ratatui::style::{Color, Style};
22#[cfg(feature = "serde")]
23use serde::de::{Error, MapAccess, SeqAccess, Unexpected, Visitor};
24#[cfg(feature = "serde")]
25use serde::ser::SerializeStruct;
26#[cfg(feature = "serde")]
27use serde::{Deserialize, Deserializer, Serialize, Serializer};
28use std::borrow::Cow;
29use std::fmt::{Display, Formatter};
30use std::mem;
31use std::str::FromStr;
32
33#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
36pub struct ColorIdx(pub Colors, pub usize);
37
38#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
40pub enum Colors {
41 TextLight = 0,
43 TextDark,
45 Primary,
47 Secondary,
49 White,
50 Black,
51 Gray,
52 Red,
53 Orange,
54 Yellow,
55 LimeGreen,
56 Green,
57 BlueGreen,
58 Cyan,
59 Blue,
60 DeepBlue,
61 Purple,
62 Magenta,
63 RedPink,
64 #[default]
69 None,
70}
71
72impl Display for ColorIdx {
73 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
74 write!(f, "{}:{}", self.0, self.1)
75 }
76}
77
78#[derive(Debug)]
79pub struct ColorIdxError;
80
81impl Display for ColorIdxError {
82 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
83 write!(f, "{:?}", self)
84 }
85}
86
87impl std::error::Error for ColorIdxError {}
88
89impl FromStr for ColorIdx {
90 type Err = ColorIdxError;
91
92 fn from_str(s: &str) -> Result<Self, Self::Err> {
93 let mut ss = s.split(':');
94 let Some(name) = ss.next() else {
95 return Err(ColorIdxError);
96 };
97 let Ok(c) = Colors::from_str(name) else {
98 return Err(ColorIdxError);
99 };
100 let Some(idx) = ss.next() else {
101 return Err(ColorIdxError);
102 };
103 let Ok(idx) = idx.parse::<usize>() else {
104 return Err(ColorIdxError);
105 };
106 Ok(ColorIdx(c, idx))
107 }
108}
109
110#[cfg(feature = "serde")]
111impl Serialize for ColorIdx {
112 fn serialize<S>(&self, ser: S) -> Result<S::Ok, S::Error>
113 where
114 S: Serializer,
115 {
116 ser.serialize_str(&self.to_string())
117 }
118}
119
120#[cfg(feature = "serde")]
121struct ColorIdxVisitor;
122
123#[cfg(feature = "serde")]
124impl<'de> Visitor<'de> for ColorIdxVisitor {
125 type Value = ColorIdx;
126
127 fn expecting(&self, f: &mut Formatter) -> std::fmt::Result {
128 write!(f, "ColorIdx")
129 }
130
131 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
132 where
133 E: serde::de::Error,
134 {
135 v.parse::<ColorIdx>()
136 .map_err(|_| serde::de::Error::invalid_value(Unexpected::Str(v), &self))
137 }
138}
139
140#[cfg(feature = "serde")]
141impl<'de> Deserialize<'de> for ColorIdx {
142 fn deserialize<D>(des: D) -> Result<Self, D::Error>
143 where
144 D: Deserializer<'de>,
145 {
146 des.deserialize_str(ColorIdxVisitor)
147 }
148}
149
150impl Display for Colors {
151 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
152 write!(f, "{}", self.str())
153 }
154}
155
156impl FromStr for Colors {
157 type Err = ();
158
159 fn from_str(s: &str) -> Result<Self, Self::Err> {
160 match s {
161 "text-light" => Ok(Colors::TextLight),
162 "text-dark" => Ok(Colors::TextDark),
163 "primary" => Ok(Colors::Primary),
164 "secondary" => Ok(Colors::Secondary),
165 "white" => Ok(Colors::White),
166 "black" => Ok(Colors::Black),
167 "gray" => Ok(Colors::Gray),
168 "red" => Ok(Colors::Red),
169 "orange" => Ok(Colors::Orange),
170 "yellow" => Ok(Colors::Yellow),
171 "lime-green" => Ok(Colors::LimeGreen),
172 "green" => Ok(Colors::Green),
173 "blue-green" => Ok(Colors::BlueGreen),
174 "cyan" => Ok(Colors::Cyan),
175 "blue" => Ok(Colors::Blue),
176 "deep-blue" => Ok(Colors::DeepBlue),
177 "purple" => Ok(Colors::Purple),
178 "magenta" => Ok(Colors::Magenta),
179 "red-pink" => Ok(Colors::RedPink),
180 "none" => Ok(Colors::None),
181 _ => Err(()),
182 }
183 }
184}
185
186impl Colors {
187 pub const LEN: usize = 19;
188
189 pub fn array() -> &'static [Colors] {
190 use Colors::*;
191 &[
193 TextLight, TextDark, Primary, Secondary, White, Black, Gray, Red, Orange, Yellow,
194 LimeGreen, Green, BlueGreen, Cyan, Blue, DeepBlue, Purple, Magenta, RedPink,
195 ]
196 }
197
198 pub const fn str(self) -> &'static str {
199 match self {
200 Colors::TextLight => "text-light",
201 Colors::TextDark => "text-dark",
202 Colors::Primary => "primary",
203 Colors::Secondary => "secondary",
204 Colors::White => "white",
205 Colors::Black => "black",
206 Colors::Gray => "gray",
207 Colors::Red => "red",
208 Colors::Orange => "orange",
209 Colors::Yellow => "yellow",
210 Colors::LimeGreen => "lime-green",
211 Colors::Green => "green",
212 Colors::BlueGreen => "blue-green",
213 Colors::Cyan => "cyan",
214 Colors::Blue => "blue",
215 Colors::DeepBlue => "deep-blue",
216 Colors::Purple => "purple",
217 Colors::Magenta => "magenta",
218 Colors::RedPink => "red-pink",
219 Colors::None => "none",
220 }
221 }
222}
223
224#[derive(Debug, Clone, PartialEq, Eq)]
228pub struct Palette {
229 pub theme_name: Cow<'static, str>,
231 pub theme: Cow<'static, str>,
242 pub name: Cow<'static, str>,
244 pub doc: Cow<'static, str>,
246 pub generator: Cow<'static, str>,
260 pub color: [[Color; 8]; Colors::LEN],
262 pub aliased: Cow<'static, [(Cow<'static, str>, ColorIdx)]>,
265}
266
267#[cfg(feature = "serde")]
268impl Serialize for Palette {
269 fn serialize<S>(&self, ser: S) -> Result<S::Ok, S::Error>
270 where
271 S: Serializer,
272 {
273 let mut pal = ser.serialize_struct("Palette", 25)?;
274 pal.serialize_field("theme_name", &self.theme_name)?;
275 pal.serialize_field("theme", &self.theme)?;
276 pal.serialize_field("name", &self.name)?;
277 pal.serialize_field("doc", &self.doc)?;
278 pal.serialize_field("generator", &self.generator)?;
279 if self.generator.starts_with("light-dark") {
280 for cc in Colors::array() {
281 pal.serialize_field(
282 cc.str(),
283 &(self.color[*cc as usize][0], self.color[*cc as usize][3]),
284 )?;
285 }
286 }
287 pal.serialize_field("aliased", &self.aliased)?;
288 pal.end()
289 }
290}
291
292#[cfg(feature = "serde")]
293struct PaletteVisitor;
294
295#[cfg(feature = "serde")]
296impl<'de> Visitor<'de> for PaletteVisitor {
297 type Value = Palette;
298
299 fn expecting(&self, f: &mut Formatter) -> std::fmt::Result {
300 write!(f, "struct Palette")
301 }
302
303 fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
304 where
305 A: SeqAccess<'de>,
306 {
307 let mut pal = Palette::default();
308 pal.theme_name = seq
309 .next_element::<Cow<'static, str>>()?
310 .ok_or(A::Error::invalid_length(0, &"Palette.theme_name"))?;
311 pal.theme = seq
312 .next_element::<Cow<'static, str>>()?
313 .ok_or(A::Error::invalid_length(0, &"Palette.theme"))?;
314 pal.name = seq
315 .next_element::<Cow<'static, str>>()?
316 .ok_or(A::Error::invalid_length(0, &"Palette.name"))?;
317 pal.doc = seq
318 .next_element::<Cow<'static, str>>()?
319 .ok_or(A::Error::invalid_length(0, &"Palette.doc"))?;
320 pal.generator = seq
321 .next_element::<Cow<'static, str>>()?
322 .ok_or(A::Error::invalid_length(0, &"Palette.generator"))?;
323 if pal.generator.starts_with("light-dark") {
324 let mut dark = 63;
325 if let Some(s) = pal.generator.split(':').nth(1) {
326 dark = s.trim().parse::<u8>().unwrap_or(63);
327 }
328
329 for cn in Colors::array() {
330 let (c0, c3) = seq
331 .next_element::<(Color, Color)>()?
332 .ok_or(A::Error::invalid_length(0, &"Palette.color"))?;
333
334 if *cn == Colors::TextLight || *cn == Colors::TextDark {
335 pal.color[*cn as usize] =
336 Palette::interpolatec2(c0, c3, Color::default(), Color::default())
337 } else {
338 pal.color[*cn as usize] = Palette::interpolatec(c0, c3, dark);
339 }
340 }
341 } else {
342 return Err(A::Error::invalid_type(
343 Unexpected::Str(&pal.generator),
344 &"expected 'light-dark:N'",
345 ));
346 }
347 pal.aliased = seq
348 .next_element::<Cow<'static, [(Cow<'static, str>, ColorIdx)]>>()?
349 .ok_or(A::Error::invalid_length(0, &"Palette.aliased"))?;
350
351 Ok(pal)
352 }
353
354 fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
355 where
356 A: MapAccess<'de>,
357 {
358 let mut pal = Palette::default();
359 while let Some(key) = map.next_key::<&str>()? {
360 match key {
361 "theme_name" => pal.theme_name = map.next_value::<Cow<'static, str>>()?,
362 "theme" => pal.theme = map.next_value::<Cow<'static, str>>()?,
363 "name" => pal.name = map.next_value::<Cow<'static, str>>()?,
364 "doc" => pal.doc = map.next_value::<Cow<'static, str>>()?,
365 "generator" => {
366 pal.generator = map.next_value::<Cow<'static, str>>()?;
367 }
368 "aliased" => {
369 pal.aliased =
370 map.next_value::<Cow<'static, [(Cow<'static, str>, ColorIdx)]>>()?
371 }
372 c_str => {
373 let cn =
374 Colors::from_str(c_str).map_err(|_| A::Error::unknown_field(c_str, &[]))?;
375 if pal.generator.starts_with("light-dark") {
376 let mut dark = 63;
377 if let Some(s) = pal.generator.split(':').nth(1) {
378 dark = s.trim().parse::<u8>().unwrap_or(63);
379 }
380 let (c0, c3) = map.next_value::<(Color, Color)>()?;
381 if cn == Colors::TextLight || cn == Colors::TextDark {
382 pal.color[cn as usize] =
383 Palette::interpolatec2(c0, c3, Color::default(), Color::default())
384 } else {
385 pal.color[cn as usize] = Palette::interpolatec(c0, c3, dark);
386 }
387 } else {
388 return Err(A::Error::invalid_type(
389 Unexpected::Str(&pal.generator),
390 &"expected 'light-dark:N'",
391 ));
392 }
393 }
394 }
395 }
396
397 Ok(pal)
398 }
399}
400
401#[cfg(feature = "serde")]
402impl<'de> Deserialize<'de> for Palette {
403 fn deserialize<D>(des: D) -> Result<Self, D::Error>
404 where
405 D: Deserializer<'de>,
406 {
407 use Colors::*;
408 const FIELDS: &'static [&'static str] = &[
409 "theme_name",
410 "theme",
411 "name",
412 "doc",
413 "generator",
414 TextLight.str(),
415 TextDark.str(),
416 Primary.str(),
417 Secondary.str(),
418 White.str(),
419 Black.str(),
420 Gray.str(),
421 Red.str(),
422 Orange.str(),
423 Yellow.str(),
424 LimeGreen.str(),
425 Green.str(),
426 BlueGreen.str(),
427 Cyan.str(),
428 Blue.str(),
429 DeepBlue.str(),
430 Purple.str(),
431 Magenta.str(),
432 RedPink.str(),
433 "aliased",
434 ];
435 des.deserialize_struct("Palette", FIELDS, PaletteVisitor)
436 }
437}
438
439impl Default for Palette {
440 fn default() -> Self {
441 Self {
442 theme_name: Default::default(),
443 theme: Default::default(),
444 name: Default::default(),
445 doc: Default::default(),
446 generator: Default::default(),
447 color: Default::default(),
448 aliased: Default::default(),
449 }
450 }
451}
452
453#[derive(Debug)]
455pub(crate) enum Rating {
456 Light,
458 Dark,
460}
461
462pub const fn define_alias(
464 alias: &'static str,
465 color: Colors,
466 n: usize,
467) -> (Cow<'static, str>, ColorIdx) {
468 (Cow::Borrowed(alias), ColorIdx(color, n))
469}
470
471pub fn define_rt_alias(
474 alias: impl Into<String>,
475 color: Colors,
476 n: usize,
477) -> (Cow<'static, str>, ColorIdx) {
478 let alias = alias.into();
479 (Cow::Owned(alias), ColorIdx(color, n))
480}
481
482impl Palette {
483 pub fn white(&self, n: usize) -> Style {
486 self.style(Colors::White, n)
487 }
488
489 pub fn black(&self, n: usize) -> Style {
492 self.style(Colors::Black, n)
493 }
494
495 pub fn gray(&self, n: usize) -> Style {
498 self.style(Colors::Gray, n)
499 }
500
501 pub fn red(&self, n: usize) -> Style {
504 self.style(Colors::Red, n)
505 }
506
507 pub fn orange(&self, n: usize) -> Style {
510 self.style(Colors::Orange, n)
511 }
512
513 pub fn yellow(&self, n: usize) -> Style {
516 self.style(Colors::Yellow, n)
517 }
518
519 pub fn limegreen(&self, n: usize) -> Style {
522 self.style(Colors::LimeGreen, n)
523 }
524
525 pub fn green(&self, n: usize) -> Style {
528 self.style(Colors::Green, n)
529 }
530
531 pub fn bluegreen(&self, n: usize) -> Style {
534 self.style(Colors::BlueGreen, n)
535 }
536
537 pub fn cyan(&self, n: usize) -> Style {
540 self.style(Colors::Cyan, n)
541 }
542
543 pub fn blue(&self, n: usize) -> Style {
546 self.style(Colors::Blue, n)
547 }
548
549 pub fn deepblue(&self, n: usize) -> Style {
552 self.style(Colors::DeepBlue, n)
553 }
554
555 pub fn purple(&self, n: usize) -> Style {
558 self.style(Colors::Purple, n)
559 }
560
561 pub fn magenta(&self, n: usize) -> Style {
564 self.style(Colors::Magenta, n)
565 }
566
567 pub fn redpink(&self, n: usize) -> Style {
570 self.style(Colors::RedPink, n)
571 }
572
573 pub fn primary(&self, n: usize) -> Style {
576 self.style(Colors::Primary, n)
577 }
578
579 pub fn secondary(&self, n: usize) -> Style {
582 self.style(Colors::Secondary, n)
583 }
584}
585
586impl Palette {
587 pub fn color(&self, id: Colors, n: usize) -> Color {
589 if id == Colors::None {
590 Color::Reset
591 } else {
592 self.color[id as usize][n]
593 }
594 }
595
596 pub fn style(&self, id: Colors, n: usize) -> Style {
600 let color = self.color(id, n);
601 self.normal_contrast(color)
602 }
603
604 pub fn high_style(&self, id: Colors, n: usize) -> Style {
608 let color = self.color(id, n);
609 self.high_contrast(color)
610 }
611
612 pub fn fg_bg_style(&self, fg: Colors, n: usize, bg: Colors, m: usize) -> Style {
614 let color = self.color(fg, n);
615 let color_bg = self.color(bg, m);
616 let mut style = Style::new();
617 if color != Color::Reset {
618 style = style.fg(color);
619 }
620 if color_bg != Color::Reset {
621 style = style.bg(color_bg);
622 }
623 style
624 }
625
626 pub fn fg_style(&self, id: Colors, n: usize) -> Style {
628 let color = self.color(id, n);
629 let mut style = Style::new();
630 if color != Color::Reset {
631 style = style.fg(color);
632 }
633 style
634 }
635
636 pub fn bg_style(&self, id: Colors, n: usize) -> Style {
638 let color = self.color(id, n);
639 let mut style = Style::new();
640 if color != Color::Reset {
641 style = style.bg(color);
642 }
643 style
644 }
645
646 pub fn add_aliased(&mut self, id: &str, color_idx: ColorIdx) {
648 if matches!(self.aliased, Cow::Borrowed(_)) {
649 self.aliased = Cow::Owned(mem::take(&mut self.aliased).into_owned());
650 }
651 match &mut self.aliased {
652 Cow::Borrowed(_) => {
653 unreachable!()
654 }
655 Cow::Owned(aliased) => {
656 aliased.push((Cow::Owned(id.to_string()), color_idx));
657 aliased.sort();
658 }
659 }
660 }
661
662 pub fn try_aliased(&self, id: &str) -> Option<ColorIdx> {
664 match self.aliased.binary_search_by_key(&id, |v| v.0.as_ref()) {
665 Ok(n) => Some(self.aliased[n].1),
666 Err(_) => None,
667 }
668 }
669
670 pub fn aliased(&self, id: &str) -> ColorIdx {
677 match self.try_aliased(id) {
678 Some(c) => c,
679 None => {
680 if cfg!(debug_assertions) {
681 panic!("unknown aliased color {:?} in palette {:?}", id, self.name);
682 } else {
683 ColorIdx::default()
684 }
685 }
686 }
687 }
688
689 pub fn color_alias(&self, id: &str) -> Color {
691 match self.try_aliased(id) {
692 Some(ColorIdx { 0: c, 1: idx }) => {
693 if c != Colors::None {
694 self.color[c as usize][idx]
695 } else {
696 Color::default()
697 }
698 }
699 None => {
700 if cfg!(debug_assertions) {
701 panic!("unknown aliased color {:?} in palette {:?}", id, self.name);
702 } else {
703 Color::default()
704 }
705 }
706 }
707 }
708
709 pub fn style_alias(&self, bg: &str) -> Style {
713 let color = self.color_alias(bg);
714 self.normal_contrast(color)
715 }
716
717 pub fn high_style_alias(&self, bg: &str) -> Style {
721 let color = self.color_alias(bg);
722 self.high_contrast(color)
723 }
724
725 pub fn fg_bg_style_alias(&self, fg: &str, bg: &str) -> Style {
728 let color = self.color_alias(fg);
729 let color_bg = self.color_alias(bg);
730 let mut style = Style::new();
731 if color != Color::Reset {
732 style = style.fg(color);
733 }
734 if color_bg != Color::Reset {
735 style = style.bg(color_bg);
736 }
737 style
738 }
739
740 pub fn fg_style_alias(&self, fg: &str) -> Style {
743 let color = self.color_alias(fg);
744 let mut style = Style::new();
745 if color != Color::Reset {
746 style = style.fg(color);
747 }
748 style
749 }
750
751 pub fn bg_style_alias(&self, bg: &str) -> Style {
754 let color = self.color_alias(bg);
755 let mut style = Style::new();
756 if color != Color::Reset {
757 style = style.bg(color);
758 }
759 style
760 }
761}
762
763impl Palette {
764 pub fn high_contrast(&self, color: Color) -> Style {
768 match Self::rate_text_color(color) {
769 None => Style::new(),
770 Some(Rating::Light) => Style::new().bg(color).fg(self.color(Colors::TextLight, 3)),
771 Some(Rating::Dark) => Style::new().bg(color).fg(self.color(Colors::TextDark, 3)),
772 }
773 }
774
775 pub fn normal_contrast(&self, color: Color) -> Style {
779 match Self::rate_text_color(color) {
780 None => Style::new(),
781 Some(Rating::Light) => Style::new().bg(color).fg(self.color(Colors::TextLight, 0)),
782 Some(Rating::Dark) => Style::new().bg(color).fg(self.color(Colors::TextDark, 0)),
783 }
784 }
785
786 pub fn normal_contrast_color(&self, bg: Color, text: &[Color]) -> Style {
789 if bg == Color::Reset {
790 return Style::new();
791 }
792 let mut color0 = text[0];
793 let mut color1 = text[0];
794 let mut contrast1 = Self::contrast_bt_srgb(color1, bg);
795
796 for text_color in text {
797 let test = Self::contrast_bt_srgb(*text_color, bg);
798 if test > contrast1 {
799 color0 = color1;
800 color1 = *text_color;
801 contrast1 = test;
802 }
803 }
804
805 Style::new().bg(bg).fg(color0)
806 }
807
808 pub fn high_contrast_color(&self, bg: Color, text: &[Color]) -> Style {
811 if bg == Color::Reset {
812 return Style::new();
813 }
814 let mut color0 = text[0];
815 let mut color1 = text[0];
816 let mut contrast1 = Self::contrast_bt_srgb(color1, bg);
817
818 for text_color in text {
819 let test = Self::contrast_bt_srgb(*text_color, bg);
820 if test > contrast1 {
821 color0 = color1;
822 color1 = *text_color;
823 contrast1 = test;
824 }
825 }
826 _ = color0;
828
829 Style::new().bg(bg).fg(color1)
830 }
831
832 pub(crate) const fn luminance_bt(color: Color) -> f32 {
857 let (r, g, b) = Self::color_to_rgb(color);
858 0.2126f32 * ((r as f32) / 255f32)
859 + 0.7152f32 * ((g as f32) / 255f32)
860 + 0.0722f32 * ((b as f32) / 255f32)
861 }
862
863 pub(crate) fn luminance_bt_srgb(color: Color) -> f32 {
865 let (r, g, b) = Self::color_to_rgb(color);
866 0.2126f32 * ((r as f32) / 255f32).powf(2.2f32)
867 + 0.7152f32 * ((g as f32) / 255f32).powf(2.2f32)
868 + 0.0722f32 * ((b as f32) / 255f32).powf(2.2f32)
869 }
870
871 pub(crate) fn contrast_bt_srgb(color: Color, color2: Color) -> f32 {
873 let lum1 = Self::luminance_bt_srgb(color);
874 let lum2 = Self::luminance_bt_srgb(color2);
875 (lum1 - lum2).abs()
876 }
880
881 pub(crate) fn rate_text_color(color: Color) -> Option<Rating> {
892 match color {
893 Color::Reset => None,
894 Color::Black => Some(Rating::Light), Color::Red => Some(Rating::Light), Color::Green => Some(Rating::Light), Color::Yellow => Some(Rating::Light), Color::Blue => Some(Rating::Light), Color::Magenta => Some(Rating::Light), Color::Cyan => Some(Rating::Light), Color::Gray => Some(Rating::Dark), Color::DarkGray => Some(Rating::Light), Color::LightRed => Some(Rating::Dark), Color::LightGreen => Some(Rating::Dark), Color::LightYellow => Some(Rating::Dark), Color::LightBlue => Some(Rating::Light), Color::LightMagenta => Some(Rating::Dark), Color::LightCyan => Some(Rating::Dark), Color::White => Some(Rating::Dark), c => {
911 let lum = Self::luminance_bt(c);
912 if lum >= 0.4117f32 {
913 Some(Rating::Dark)
914 } else {
915 Some(Rating::Light)
916 }
917 }
918 }
919 }
920
921 pub const fn grayscale(color: Color) -> Color {
923 let lum = Self::luminance_bt(color);
924 let gray = lum * 255f32;
925 Color::Rgb(gray as u8, gray as u8, gray as u8)
926 }
927
928 pub const fn color_from_u32(c: u32) -> Color {
930 let r0 = (c >> 16) as u8;
931 let g0 = (c >> 8) as u8;
932 let b0 = c as u8;
933 Color::Rgb(r0, g0, b0)
934 }
935
936 pub const fn color_to_u32(color: Color) -> u32 {
938 let (r, g, b) = Self::color_to_rgb(color);
939 ((r as u32) << 16) + ((g as u32) << 8) + (b as u32)
940 }
941
942 pub const fn interpolatec(c0: Color, c3: Color, dark_scale_to: u8) -> [Color; 8] {
946 Self::interpolate(
947 Self::color_to_u32(c0),
948 Self::color_to_u32(c3),
949 dark_scale_to,
950 )
951 }
952
953 pub const fn interpolate(c0: u32, c3: u32, dark_scale_to: u8) -> [Color; 8] {
957 let mut c4 = Self::color_to_rgb(Self::color_from_u32(c0));
959 c4.0 = Self::scale_to(c4.0, dark_scale_to);
960 c4.1 = Self::scale_to(c4.1, dark_scale_to);
961 c4.2 = Self::scale_to(c4.2, dark_scale_to);
962 let c4 = ((c4.0 as u32) << 16) + ((c4.1 as u32) << 8) + (c4.2 as u32);
963
964 let mut c7 = Self::color_to_rgb(Self::color_from_u32(c3));
965 c7.0 = Self::scale_to(c7.0, dark_scale_to);
966 c7.1 = Self::scale_to(c7.1, dark_scale_to);
967 c7.2 = Self::scale_to(c7.2, dark_scale_to);
968 let c7 = ((c7.0 as u32) << 16) + ((c7.1 as u32) << 8) + (c7.2 as u32);
969
970 Self::interpolate2(c0, c3, c4, c7)
971 }
972
973 pub const fn interpolatec2(c0: Color, c3: Color, c4: Color, c7: Color) -> [Color; 8] {
977 Self::interpolate2(
978 Self::color_to_u32(c0),
979 Self::color_to_u32(c3),
980 Self::color_to_u32(c4),
981 Self::color_to_u32(c7),
982 )
983 }
984
985 pub const fn interpolate2(c0: u32, c3: u32, c4: u32, c7: u32) -> [Color; 8] {
989 const fn i1(a: u8, b: u8) -> u8 {
991 if a < b {
992 a + (b - a) / 3
993 } else {
994 a - (a - b) / 3
995 }
996 }
997 const fn i2(a: u8, b: u8) -> u8 {
999 if a < b {
1000 b - (b - a) / 3
1001 } else {
1002 b + (a - b) / 3
1003 }
1004 }
1005
1006 let r0 = (c0 >> 16) as u8;
1007 let g0 = (c0 >> 8) as u8;
1008 let b0 = c0 as u8;
1009
1010 let r3 = (c3 >> 16) as u8;
1011 let g3 = (c3 >> 8) as u8;
1012 let b3 = c3 as u8;
1013
1014 let r1 = i1(r0, r3);
1015 let g1 = i1(g0, g3);
1016 let b1 = i1(b0, b3);
1017
1018 let r2 = i2(r0, r3);
1019 let g2 = i2(g0, g3);
1020 let b2 = i2(b0, b3);
1021
1022 let r4 = (c4 >> 16) as u8;
1024 let g4 = (c4 >> 8) as u8;
1025 let b4 = c4 as u8;
1026
1027 let r7 = (c7 >> 16) as u8;
1028 let g7 = (c7 >> 8) as u8;
1029 let b7 = c7 as u8;
1030
1031 let r5 = i1(r4, r7);
1032 let g5 = i1(g4, g7);
1033 let b5 = i1(b4, b7);
1034
1035 let r6 = i2(r4, r7);
1036 let g6 = i2(g4, g7);
1037 let b6 = i2(b4, b7);
1038
1039 [
1040 Color::Rgb(r0, g0, b0),
1041 Color::Rgb(r1, g1, b1),
1042 Color::Rgb(r2, g2, b2),
1043 Color::Rgb(r3, g3, b3),
1044 Color::Rgb(r4, g4, b4),
1045 Color::Rgb(r5, g5, b5),
1046 Color::Rgb(r6, g6, b6),
1047 Color::Rgb(r7, g7, b7),
1048 ]
1049 }
1050
1051 pub const fn scale_to(v: u8, scale_to: u8) -> u8 {
1053 (((v as u16) * scale_to as u16) / 255u16) as u8
1054 }
1055
1056 pub const fn color_to_rgb(color: Color) -> (u8, u8, u8) {
1059 match color {
1060 Color::Black => (0x00, 0x00, 0x00),
1061 Color::Red => (0xaa, 0x00, 0x00),
1062 Color::Green => (0x00, 0xaa, 0x00),
1063 Color::Yellow => (0xaa, 0x55, 0x00),
1064 Color::Blue => (0x00, 0x00, 0xaa),
1065 Color::Magenta => (0xaa, 0x00, 0xaa),
1066 Color::Cyan => (0x00, 0xaa, 0xaa),
1067 Color::Gray => (0xaa, 0xaa, 0xaa),
1068 Color::DarkGray => (0x55, 0x55, 0x55),
1069 Color::LightRed => (0xff, 0x55, 0x55),
1070 Color::LightGreen => (0x55, 0xff, 0x55),
1071 Color::LightYellow => (0xff, 0xff, 0x55),
1072 Color::LightBlue => (0x55, 0x55, 0xff),
1073 Color::LightMagenta => (0xff, 0x55, 0xff),
1074 Color::LightCyan => (0x55, 0xff, 0xff),
1075 Color::White => (0xff, 0xff, 0xff),
1076 Color::Rgb(r, g, b) => (r, g, b),
1077 Color::Indexed(i) => {
1078 const VGA256: [(u8, u8, u8); 256] = [
1079 (0x00, 0x00, 0x00),
1080 (0x80, 0x00, 0x00),
1081 (0x00, 0x80, 0x00),
1082 (0x80, 0x80, 0x00),
1083 (0x00, 0x00, 0x80),
1084 (0x80, 0x00, 0x80),
1085 (0x00, 0x80, 0x80),
1086 (0xc0, 0xc0, 0xc0),
1087 (0x80, 0x80, 0x80),
1088 (0xff, 0x00, 0x00),
1089 (0x00, 0xff, 0x00),
1090 (0xff, 0xff, 0x00),
1091 (0x00, 0x00, 0xff),
1092 (0xff, 0x00, 0xff),
1093 (0x00, 0xff, 0xff),
1094 (0xff, 0xff, 0xff),
1095 (0x00, 0x00, 0x00),
1096 (0x00, 0x00, 0x5f),
1097 (0x00, 0x00, 0x87),
1098 (0x00, 0x00, 0xaf),
1099 (0x00, 0x00, 0xd7),
1100 (0x00, 0x00, 0xff),
1101 (0x00, 0x5f, 0x00),
1102 (0x00, 0x5f, 0x5f),
1103 (0x00, 0x5f, 0x87),
1104 (0x00, 0x5f, 0xaf),
1105 (0x00, 0x5f, 0xd7),
1106 (0x00, 0x5f, 0xff),
1107 (0x00, 0x87, 0x00),
1108 (0x00, 0x87, 0x5f),
1109 (0x00, 0x87, 0x87),
1110 (0x00, 0x87, 0xaf),
1111 (0x00, 0x87, 0xd7),
1112 (0x00, 0x87, 0xff),
1113 (0x00, 0xaf, 0x00),
1114 (0x00, 0xaf, 0x5f),
1115 (0x00, 0xaf, 0x87),
1116 (0x00, 0xaf, 0xaf),
1117 (0x00, 0xaf, 0xd7),
1118 (0x00, 0xaf, 0xff),
1119 (0x00, 0xd7, 0x00),
1120 (0x00, 0xd7, 0x5f),
1121 (0x00, 0xd7, 0x87),
1122 (0x00, 0xd7, 0xaf),
1123 (0x00, 0xd7, 0xd7),
1124 (0x00, 0xd7, 0xff),
1125 (0x00, 0xff, 0x00),
1126 (0x00, 0xff, 0x5f),
1127 (0x00, 0xff, 0x87),
1128 (0x00, 0xff, 0xaf),
1129 (0x00, 0xff, 0xd7),
1130 (0x00, 0xff, 0xff),
1131 (0x5f, 0x00, 0x00),
1132 (0x5f, 0x00, 0x5f),
1133 (0x5f, 0x00, 0x87),
1134 (0x5f, 0x00, 0xaf),
1135 (0x5f, 0x00, 0xd7),
1136 (0x5f, 0x00, 0xff),
1137 (0x5f, 0x5f, 0x00),
1138 (0x5f, 0x5f, 0x5f),
1139 (0x5f, 0x5f, 0x87),
1140 (0x5f, 0x5f, 0xaf),
1141 (0x5f, 0x5f, 0xd7),
1142 (0x5f, 0x5f, 0xff),
1143 (0x5f, 0x87, 0x00),
1144 (0x5f, 0x87, 0x5f),
1145 (0x5f, 0x87, 0x87),
1146 (0x5f, 0x87, 0xaf),
1147 (0x5f, 0x87, 0xd7),
1148 (0x5f, 0x87, 0xff),
1149 (0x5f, 0xaf, 0x00),
1150 (0x5f, 0xaf, 0x5f),
1151 (0x5f, 0xaf, 0x87),
1152 (0x5f, 0xaf, 0xaf),
1153 (0x5f, 0xaf, 0xd7),
1154 (0x5f, 0xaf, 0xff),
1155 (0x5f, 0xd7, 0x00),
1156 (0x5f, 0xd7, 0x5f),
1157 (0x5f, 0xd7, 0x87),
1158 (0x5f, 0xd7, 0xaf),
1159 (0x5f, 0xd7, 0xd7),
1160 (0x5f, 0xd7, 0xff),
1161 (0x5f, 0xff, 0x00),
1162 (0x5f, 0xff, 0x5f),
1163 (0x5f, 0xff, 0x87),
1164 (0x5f, 0xff, 0xaf),
1165 (0x5f, 0xff, 0xd7),
1166 (0x5f, 0xff, 0xff),
1167 (0x87, 0x00, 0x00),
1168 (0x87, 0x00, 0x5f),
1169 (0x87, 0x00, 0x87),
1170 (0x87, 0x00, 0xaf),
1171 (0x87, 0x00, 0xd7),
1172 (0x87, 0x00, 0xff),
1173 (0x87, 0x5f, 0x00),
1174 (0x87, 0x5f, 0x5f),
1175 (0x87, 0x5f, 0x87),
1176 (0x87, 0x5f, 0xaf),
1177 (0x87, 0x5f, 0xd7),
1178 (0x87, 0x5f, 0xff),
1179 (0x87, 0x87, 0x00),
1180 (0x87, 0x87, 0x5f),
1181 (0x87, 0x87, 0x87),
1182 (0x87, 0x87, 0xaf),
1183 (0x87, 0x87, 0xd7),
1184 (0x87, 0x87, 0xff),
1185 (0x87, 0xaf, 0x00),
1186 (0x87, 0xaf, 0x5f),
1187 (0x87, 0xaf, 0x87),
1188 (0x87, 0xaf, 0xaf),
1189 (0x87, 0xaf, 0xd7),
1190 (0x87, 0xaf, 0xff),
1191 (0x87, 0xd7, 0x00),
1192 (0x87, 0xd7, 0x5f),
1193 (0x87, 0xd7, 0x87),
1194 (0x87, 0xd7, 0xaf),
1195 (0x87, 0xd7, 0xd7),
1196 (0x87, 0xd7, 0xff),
1197 (0x87, 0xff, 0x00),
1198 (0x87, 0xff, 0x5f),
1199 (0x87, 0xff, 0x87),
1200 (0x87, 0xff, 0xaf),
1201 (0x87, 0xff, 0xd7),
1202 (0x87, 0xff, 0xff),
1203 (0xaf, 0x00, 0x00),
1204 (0xaf, 0x00, 0x5f),
1205 (0xaf, 0x00, 0x87),
1206 (0xaf, 0x00, 0xaf),
1207 (0xaf, 0x00, 0xd7),
1208 (0xaf, 0x00, 0xff),
1209 (0xaf, 0x5f, 0x00),
1210 (0xaf, 0x5f, 0x5f),
1211 (0xaf, 0x5f, 0x87),
1212 (0xaf, 0x5f, 0xaf),
1213 (0xaf, 0x5f, 0xd7),
1214 (0xaf, 0x5f, 0xff),
1215 (0xaf, 0x87, 0x00),
1216 (0xaf, 0x87, 0x5f),
1217 (0xaf, 0x87, 0x87),
1218 (0xaf, 0x87, 0xaf),
1219 (0xaf, 0x87, 0xd7),
1220 (0xaf, 0x87, 0xff),
1221 (0xaf, 0xaf, 0x00),
1222 (0xaf, 0xaf, 0x5f),
1223 (0xaf, 0xaf, 0x87),
1224 (0xaf, 0xaf, 0xaf),
1225 (0xaf, 0xaf, 0xd7),
1226 (0xaf, 0xaf, 0xff),
1227 (0xaf, 0xd7, 0x00),
1228 (0xaf, 0xd7, 0x5f),
1229 (0xaf, 0xd7, 0x87),
1230 (0xaf, 0xd7, 0xaf),
1231 (0xaf, 0xd7, 0xd7),
1232 (0xaf, 0xd7, 0xff),
1233 (0xaf, 0xff, 0x00),
1234 (0xaf, 0xff, 0x5f),
1235 (0xaf, 0xff, 0x87),
1236 (0xaf, 0xff, 0xaf),
1237 (0xaf, 0xff, 0xd7),
1238 (0xaf, 0xff, 0xff),
1239 (0xd7, 0x00, 0x00),
1240 (0xd7, 0x00, 0x5f),
1241 (0xd7, 0x00, 0x87),
1242 (0xd7, 0x00, 0xaf),
1243 (0xd7, 0x00, 0xd7),
1244 (0xd7, 0x00, 0xff),
1245 (0xd7, 0x5f, 0x00),
1246 (0xd7, 0x5f, 0x5f),
1247 (0xd7, 0x5f, 0x87),
1248 (0xd7, 0x5f, 0xaf),
1249 (0xd7, 0x5f, 0xd7),
1250 (0xd7, 0x5f, 0xff),
1251 (0xd7, 0x87, 0x00),
1252 (0xd7, 0x87, 0x5f),
1253 (0xd7, 0x87, 0x87),
1254 (0xd7, 0x87, 0xaf),
1255 (0xd7, 0x87, 0xd7),
1256 (0xd7, 0x87, 0xff),
1257 (0xd7, 0xaf, 0x00),
1258 (0xd7, 0xaf, 0x5f),
1259 (0xd7, 0xaf, 0x87),
1260 (0xd7, 0xaf, 0xaf),
1261 (0xd7, 0xaf, 0xd7),
1262 (0xd7, 0xaf, 0xff),
1263 (0xd7, 0xd7, 0x00),
1264 (0xd7, 0xd7, 0x5f),
1265 (0xd7, 0xd7, 0x87),
1266 (0xd7, 0xd7, 0xaf),
1267 (0xd7, 0xd7, 0xd7),
1268 (0xd7, 0xd7, 0xff),
1269 (0xd7, 0xff, 0x00),
1270 (0xd7, 0xff, 0x5f),
1271 (0xd7, 0xff, 0x87),
1272 (0xd7, 0xff, 0xaf),
1273 (0xd7, 0xff, 0xd7),
1274 (0xd7, 0xff, 0xff),
1275 (0xff, 0x00, 0x00),
1276 (0xff, 0x00, 0x5f),
1277 (0xff, 0x00, 0x87),
1278 (0xff, 0x00, 0xaf),
1279 (0xff, 0x00, 0xd7),
1280 (0xff, 0x00, 0xff),
1281 (0xff, 0x5f, 0x00),
1282 (0xff, 0x5f, 0x5f),
1283 (0xff, 0x5f, 0x87),
1284 (0xff, 0x5f, 0xaf),
1285 (0xff, 0x5f, 0xd7),
1286 (0xff, 0x5f, 0xff),
1287 (0xff, 0x87, 0x00),
1288 (0xff, 0x87, 0x5f),
1289 (0xff, 0x87, 0x87),
1290 (0xff, 0x87, 0xaf),
1291 (0xff, 0x87, 0xd7),
1292 (0xff, 0x87, 0xff),
1293 (0xff, 0xaf, 0x00),
1294 (0xff, 0xaf, 0x5f),
1295 (0xff, 0xaf, 0x87),
1296 (0xff, 0xaf, 0xaf),
1297 (0xff, 0xaf, 0xd7),
1298 (0xff, 0xaf, 0xff),
1299 (0xff, 0xd7, 0x00),
1300 (0xff, 0xd7, 0x5f),
1301 (0xff, 0xd7, 0x87),
1302 (0xff, 0xd7, 0xaf),
1303 (0xff, 0xd7, 0xd7),
1304 (0xff, 0xd7, 0xff),
1305 (0xff, 0xff, 0x00),
1306 (0xff, 0xff, 0x5f),
1307 (0xff, 0xff, 0x87),
1308 (0xff, 0xff, 0xaf),
1309 (0xff, 0xff, 0xd7),
1310 (0xff, 0xff, 0xff),
1311 (0x08, 0x08, 0x08),
1312 (0x12, 0x12, 0x12),
1313 (0x1c, 0x1c, 0x1c),
1314 (0x26, 0x26, 0x26),
1315 (0x30, 0x30, 0x30),
1316 (0x3a, 0x3a, 0x3a),
1317 (0x44, 0x44, 0x44),
1318 (0x4e, 0x4e, 0x4e),
1319 (0x58, 0x58, 0x58),
1320 (0x62, 0x62, 0x62),
1321 (0x6c, 0x6c, 0x6c),
1322 (0x76, 0x76, 0x76),
1323 (0x80, 0x80, 0x80),
1324 (0x8a, 0x8a, 0x8a),
1325 (0x94, 0x94, 0x94),
1326 (0x9e, 0x9e, 0x9e),
1327 (0xa8, 0xa8, 0xa8),
1328 (0xb2, 0xb2, 0xb2),
1329 (0xbc, 0xbc, 0xbc),
1330 (0xc6, 0xc6, 0xc6),
1331 (0xd0, 0xd0, 0xd0),
1332 (0xda, 0xda, 0xda),
1333 (0xe4, 0xe4, 0xe4),
1334 (0xee, 0xee, 0xee),
1335 ];
1336 VGA256[i as usize]
1337 }
1338 Color::Reset => (0, 0, 0),
1339 }
1340 }
1341}