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, Default, Clone, PartialEq, Eq)]
228pub struct Palette {
229 pub theme_name: Cow<'static, str>,
231 pub theme: Cow<'static, str>,
246 pub name: Cow<'static, str>,
248 pub doc: Cow<'static, str>,
250 pub generator: Cow<'static, str>,
264 pub color: [[Color; 8]; Colors::LEN],
266 pub aliased: Cow<'static, [(Cow<'static, str>, ColorIdx)]>,
269}
270
271#[cfg(feature = "serde")]
272impl Serialize for Palette {
273 fn serialize<S>(&self, ser: S) -> Result<S::Ok, S::Error>
274 where
275 S: Serializer,
276 {
277 let mut pal = ser.serialize_struct("Palette", 25)?;
278 pal.serialize_field("theme_name", &self.theme_name)?;
279 pal.serialize_field("theme", &self.theme)?;
280 pal.serialize_field("name", &self.name)?;
281 pal.serialize_field("doc", &self.doc)?;
282 pal.serialize_field("generator", &self.generator)?;
283 if self.generator.starts_with("light-dark") {
284 for cc in Colors::array() {
285 pal.serialize_field(
286 cc.str(),
287 &(self.color[*cc as usize][0], self.color[*cc as usize][3]),
288 )?;
289 }
290 }
291 pal.serialize_field("aliased", &self.aliased)?;
292 pal.end()
293 }
294}
295
296#[cfg(feature = "serde")]
297struct PaletteVisitor;
298
299#[cfg(feature = "serde")]
300impl<'de> Visitor<'de> for PaletteVisitor {
301 type Value = Palette;
302
303 fn expecting(&self, f: &mut Formatter) -> std::fmt::Result {
304 write!(f, "struct Palette")
305 }
306
307 fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
308 where
309 A: SeqAccess<'de>,
310 {
311 let mut pal = Palette::default();
312 pal.theme_name = seq
313 .next_element::<Cow<'static, str>>()?
314 .ok_or(A::Error::invalid_length(0, &"Palette.theme_name"))?;
315 pal.theme = seq
316 .next_element::<Cow<'static, str>>()?
317 .ok_or(A::Error::invalid_length(0, &"Palette.theme"))?;
318 pal.name = seq
319 .next_element::<Cow<'static, str>>()?
320 .ok_or(A::Error::invalid_length(0, &"Palette.name"))?;
321 pal.doc = seq
322 .next_element::<Cow<'static, str>>()?
323 .ok_or(A::Error::invalid_length(0, &"Palette.doc"))?;
324 pal.generator = seq
325 .next_element::<Cow<'static, str>>()?
326 .ok_or(A::Error::invalid_length(0, &"Palette.generator"))?;
327 if pal.generator.starts_with("light-dark") {
328 let mut dark = 63;
329 if let Some(s) = pal.generator.split(':').nth(1) {
330 dark = s.trim().parse::<u8>().unwrap_or(63);
331 }
332
333 for cn in Colors::array() {
334 let (c0, c3) = seq
335 .next_element::<(Color, Color)>()?
336 .ok_or(A::Error::invalid_length(0, &"Palette.color"))?;
337
338 if *cn == Colors::TextLight || *cn == Colors::TextDark {
339 pal.color[*cn as usize] =
340 Palette::interpolatec2(c0, c3, Color::default(), Color::default())
341 } else {
342 pal.color[*cn as usize] = Palette::interpolatec(c0, c3, dark);
343 }
344 }
345 } else {
346 return Err(A::Error::invalid_type(
347 Unexpected::Str(&pal.generator),
348 &"expected 'light-dark:N'",
349 ));
350 }
351 pal.aliased = seq
352 .next_element::<Cow<'static, [(Cow<'static, str>, ColorIdx)]>>()?
353 .ok_or(A::Error::invalid_length(0, &"Palette.aliased"))?;
354
355 Ok(pal)
356 }
357
358 fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
359 where
360 A: MapAccess<'de>,
361 {
362 let mut pal = Palette::default();
363 while let Some(key) = map.next_key::<&str>()? {
364 match key {
365 "theme_name" => pal.theme_name = map.next_value::<Cow<'static, str>>()?,
366 "theme" => pal.theme = map.next_value::<Cow<'static, str>>()?,
367 "name" => pal.name = map.next_value::<Cow<'static, str>>()?,
368 "doc" => pal.doc = map.next_value::<Cow<'static, str>>()?,
369 "generator" => {
370 pal.generator = map.next_value::<Cow<'static, str>>()?;
371 }
372 "aliased" => {
373 pal.aliased =
374 map.next_value::<Cow<'static, [(Cow<'static, str>, ColorIdx)]>>()?
375 }
376 c_str => {
377 let cn =
378 Colors::from_str(c_str).map_err(|_| A::Error::unknown_field(c_str, &[]))?;
379 if pal.generator.starts_with("light-dark") {
380 let mut dark = 63;
381 if let Some(s) = pal.generator.split(':').nth(1) {
382 dark = s.trim().parse::<u8>().unwrap_or(63);
383 }
384 let (c0, c3) = map.next_value::<(Color, Color)>()?;
385 if cn == Colors::TextLight || cn == Colors::TextDark {
386 pal.color[cn as usize] =
387 Palette::interpolatec2(c0, c3, Color::default(), Color::default())
388 } else {
389 pal.color[cn as usize] = Palette::interpolatec(c0, c3, dark);
390 }
391 } else {
392 return Err(A::Error::invalid_type(
393 Unexpected::Str(&pal.generator),
394 &"expected 'light-dark:N'",
395 ));
396 }
397 }
398 }
399 }
400
401 Ok(pal)
402 }
403}
404
405#[cfg(feature = "serde")]
406impl<'de> Deserialize<'de> for Palette {
407 fn deserialize<D>(des: D) -> Result<Self, D::Error>
408 where
409 D: Deserializer<'de>,
410 {
411 use Colors::*;
412 const FIELDS: &'static [&'static str] = &[
413 "theme_name",
414 "theme",
415 "name",
416 "doc",
417 "generator",
418 TextLight.str(),
419 TextDark.str(),
420 Primary.str(),
421 Secondary.str(),
422 White.str(),
423 Black.str(),
424 Gray.str(),
425 Red.str(),
426 Orange.str(),
427 Yellow.str(),
428 LimeGreen.str(),
429 Green.str(),
430 BlueGreen.str(),
431 Cyan.str(),
432 Blue.str(),
433 DeepBlue.str(),
434 Purple.str(),
435 Magenta.str(),
436 RedPink.str(),
437 "aliased",
438 ];
439 let mut pal = des.deserialize_struct("Palette", FIELDS, PaletteVisitor)?;
440
441 if !pal.aliased.is_sorted() {
443 let mut aliased = pal.aliased.into_owned();
444 aliased.sort();
445 pal.aliased = Cow::Owned(aliased);
446 }
447
448 Ok(pal)
449 }
450}
451
452#[derive(Debug)]
454pub(crate) enum Rating {
455 Light,
457 Dark,
459}
460
461pub const fn define_alias(
463 alias: &'static str,
464 color: Colors,
465 n: usize,
466) -> (Cow<'static, str>, ColorIdx) {
467 (Cow::Borrowed(alias), ColorIdx(color, n))
468}
469
470pub fn define_rt_alias(
473 alias: impl Into<String>,
474 color: Colors,
475 n: usize,
476) -> (Cow<'static, str>, ColorIdx) {
477 let alias = alias.into();
478 (Cow::Owned(alias), ColorIdx(color, n))
479}
480
481impl Palette {
482 pub fn white(&self, n: usize) -> Style {
485 self.style(Colors::White, n)
486 }
487
488 pub fn black(&self, n: usize) -> Style {
491 self.style(Colors::Black, n)
492 }
493
494 pub fn gray(&self, n: usize) -> Style {
497 self.style(Colors::Gray, n)
498 }
499
500 pub fn red(&self, n: usize) -> Style {
503 self.style(Colors::Red, n)
504 }
505
506 pub fn orange(&self, n: usize) -> Style {
509 self.style(Colors::Orange, n)
510 }
511
512 pub fn yellow(&self, n: usize) -> Style {
515 self.style(Colors::Yellow, n)
516 }
517
518 pub fn limegreen(&self, n: usize) -> Style {
521 self.style(Colors::LimeGreen, n)
522 }
523
524 pub fn green(&self, n: usize) -> Style {
527 self.style(Colors::Green, n)
528 }
529
530 pub fn bluegreen(&self, n: usize) -> Style {
533 self.style(Colors::BlueGreen, n)
534 }
535
536 pub fn cyan(&self, n: usize) -> Style {
539 self.style(Colors::Cyan, n)
540 }
541
542 pub fn blue(&self, n: usize) -> Style {
545 self.style(Colors::Blue, n)
546 }
547
548 pub fn deepblue(&self, n: usize) -> Style {
551 self.style(Colors::DeepBlue, n)
552 }
553
554 pub fn purple(&self, n: usize) -> Style {
557 self.style(Colors::Purple, n)
558 }
559
560 pub fn magenta(&self, n: usize) -> Style {
563 self.style(Colors::Magenta, n)
564 }
565
566 pub fn redpink(&self, n: usize) -> Style {
569 self.style(Colors::RedPink, n)
570 }
571
572 pub fn primary(&self, n: usize) -> Style {
575 self.style(Colors::Primary, n)
576 }
577
578 pub fn secondary(&self, n: usize) -> Style {
581 self.style(Colors::Secondary, n)
582 }
583}
584
585impl Palette {
586 pub fn color(&self, id: Colors, n: usize) -> Color {
588 if id == Colors::None {
589 Color::Reset
590 } else {
591 self.color[id as usize][n]
592 }
593 }
594
595 pub fn style(&self, id: Colors, n: usize) -> Style {
599 let color = self.color(id, n);
600 self.normal_contrast(color)
601 }
602
603 pub fn high_style(&self, id: Colors, n: usize) -> Style {
607 let color = self.color(id, n);
608 self.high_contrast(color)
609 }
610
611 pub fn fg_bg_style(&self, fg: Colors, n: usize, bg: Colors, m: usize) -> Style {
613 let color = self.color(fg, n);
614 let color_bg = self.color(bg, m);
615 let mut style = Style::new();
616 if color != Color::Reset {
617 style = style.fg(color);
618 }
619 if color_bg != Color::Reset {
620 style = style.bg(color_bg);
621 }
622 style
623 }
624
625 pub fn fg_style(&self, id: Colors, n: usize) -> Style {
627 let color = self.color(id, n);
628 let mut style = Style::new();
629 if color != Color::Reset {
630 style = style.fg(color);
631 }
632 style
633 }
634
635 pub fn bg_style(&self, id: Colors, n: usize) -> Style {
637 let color = self.color(id, n);
638 let mut style = Style::new();
639 if color != Color::Reset {
640 style = style.bg(color);
641 }
642 style
643 }
644
645 pub fn add_aliased(&mut self, id: &str, color_idx: ColorIdx) {
647 if matches!(self.aliased, Cow::Borrowed(_)) {
648 self.aliased = Cow::Owned(mem::take(&mut self.aliased).into_owned());
649 }
650 match &mut self.aliased {
651 Cow::Borrowed(_) => {
652 unreachable!()
653 }
654 Cow::Owned(aliased) => match aliased.binary_search_by_key(&id, |v| v.0.as_ref()) {
655 Ok(n) => aliased[n] = (Cow::Owned(id.to_string()), color_idx),
656 Err(n) => aliased.insert(n, (Cow::Owned(id.to_string()), color_idx)),
657 },
658 }
659 }
660
661 pub fn try_aliased(&self, id: &str) -> Option<ColorIdx> {
663 match self.aliased.binary_search_by_key(&id, |v| v.0.as_ref()) {
664 Ok(n) => Some(self.aliased[n].1),
665 Err(_) => None,
666 }
667 }
668
669 pub fn aliased(&self, id: &str) -> ColorIdx {
676 match self.try_aliased(id) {
677 Some(c) => c,
678 None => {
679 if cfg!(debug_assertions) {
680 panic!("unknown aliased color {:?} in palette {:?}", id, self.name);
681 } else {
682 ColorIdx::default()
683 }
684 }
685 }
686 }
687
688 pub fn color_alias(&self, id: &str) -> Color {
690 match self.try_aliased(id) {
691 Some(ColorIdx { 0: c, 1: idx }) => {
692 if c != Colors::None {
693 self.color[c as usize][idx]
694 } else {
695 Color::default()
696 }
697 }
698 None => {
699 if cfg!(debug_assertions) {
700 panic!("unknown aliased color {:?} in palette {:?}", id, self.name);
701 } else {
702 Color::default()
703 }
704 }
705 }
706 }
707
708 pub fn style_alias(&self, bg: &str) -> Style {
712 let color = self.color_alias(bg);
713 self.normal_contrast(color)
714 }
715
716 pub fn high_style_alias(&self, bg: &str) -> Style {
720 let color = self.color_alias(bg);
721 self.high_contrast(color)
722 }
723
724 pub fn fg_bg_style_alias(&self, fg: &str, bg: &str) -> Style {
727 let color = self.color_alias(fg);
728 let color_bg = self.color_alias(bg);
729 let mut style = Style::new();
730 if color != Color::Reset {
731 style = style.fg(color);
732 }
733 if color_bg != Color::Reset {
734 style = style.bg(color_bg);
735 }
736 style
737 }
738
739 pub fn fg_style_alias(&self, fg: &str) -> Style {
742 let color = self.color_alias(fg);
743 let mut style = Style::new();
744 if color != Color::Reset {
745 style = style.fg(color);
746 }
747 style
748 }
749
750 pub fn bg_style_alias(&self, bg: &str) -> Style {
753 let color = self.color_alias(bg);
754 let mut style = Style::new();
755 if color != Color::Reset {
756 style = style.bg(color);
757 }
758 style
759 }
760}
761
762impl Palette {
763 pub fn high_contrast(&self, color: Color) -> Style {
767 match Self::rate_text_color(color) {
768 None => Style::new(),
769 Some(Rating::Light) => Style::new().bg(color).fg(self.color(Colors::TextLight, 3)),
770 Some(Rating::Dark) => Style::new().bg(color).fg(self.color(Colors::TextDark, 3)),
771 }
772 }
773
774 pub fn normal_contrast(&self, color: Color) -> Style {
778 match Self::rate_text_color(color) {
779 None => Style::new(),
780 Some(Rating::Light) => Style::new().bg(color).fg(self.color(Colors::TextLight, 0)),
781 Some(Rating::Dark) => Style::new().bg(color).fg(self.color(Colors::TextDark, 0)),
782 }
783 }
784
785 pub fn normal_contrast_color(&self, bg: Color, text: &[Color]) -> Style {
788 if bg == Color::Reset {
789 return Style::new();
790 }
791 let mut color0 = text[0];
792 let mut color1 = text[0];
793 let mut contrast1 = Self::contrast_bt_srgb(color1, bg);
794
795 for text_color in text {
796 let test = Self::contrast_bt_srgb(*text_color, bg);
797 if test > contrast1 {
798 color0 = color1;
799 color1 = *text_color;
800 contrast1 = test;
801 }
802 }
803
804 Style::new().bg(bg).fg(color0)
805 }
806
807 pub fn high_contrast_color(&self, bg: Color, text: &[Color]) -> Style {
810 if bg == Color::Reset {
811 return Style::new();
812 }
813 let mut color0 = text[0];
814 let mut color1 = text[0];
815 let mut contrast1 = Self::contrast_bt_srgb(color1, bg);
816
817 for text_color in text {
818 let test = Self::contrast_bt_srgb(*text_color, bg);
819 if test > contrast1 {
820 color0 = color1;
821 color1 = *text_color;
822 contrast1 = test;
823 }
824 }
825 _ = color0;
827
828 Style::new().bg(bg).fg(color1)
829 }
830
831 pub(crate) const fn luminance_bt(color: Color) -> f32 {
856 let (r, g, b) = Self::color_to_rgb(color);
857 0.2126f32 * ((r as f32) / 255f32)
858 + 0.7152f32 * ((g as f32) / 255f32)
859 + 0.0722f32 * ((b as f32) / 255f32)
860 }
861
862 pub(crate) fn luminance_bt_srgb(color: Color) -> f32 {
864 let (r, g, b) = Self::color_to_rgb(color);
865 0.2126f32 * ((r as f32) / 255f32).powf(2.2f32)
866 + 0.7152f32 * ((g as f32) / 255f32).powf(2.2f32)
867 + 0.0722f32 * ((b as f32) / 255f32).powf(2.2f32)
868 }
869
870 pub(crate) fn contrast_bt_srgb(color: Color, color2: Color) -> f32 {
872 let lum1 = Self::luminance_bt_srgb(color);
873 let lum2 = Self::luminance_bt_srgb(color2);
874 (lum1 - lum2).abs()
875 }
879
880 pub(crate) fn rate_text_color(color: Color) -> Option<Rating> {
891 match color {
892 Color::Reset => None,
893 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 => {
910 let lum = Self::luminance_bt(c);
911 if lum >= 0.4117f32 {
912 Some(Rating::Dark)
913 } else {
914 Some(Rating::Light)
915 }
916 }
917 }
918 }
919
920 pub const fn grayscale(color: Color) -> Color {
922 let lum = Self::luminance_bt(color);
923 let gray = lum * 255f32;
924 Color::Rgb(gray as u8, gray as u8, gray as u8)
925 }
926
927 pub const fn color_from_u32(c: u32) -> Color {
929 let r0 = (c >> 16) as u8;
930 let g0 = (c >> 8) as u8;
931 let b0 = c as u8;
932 Color::Rgb(r0, g0, b0)
933 }
934
935 pub const fn color_to_u32(color: Color) -> u32 {
937 let (r, g, b) = Self::color_to_rgb(color);
938 ((r as u32) << 16) + ((g as u32) << 8) + (b as u32)
939 }
940
941 pub const fn interpolatec(c0: Color, c3: Color, dark_scale_to: u8) -> [Color; 8] {
945 Self::interpolate(
946 Self::color_to_u32(c0),
947 Self::color_to_u32(c3),
948 dark_scale_to,
949 )
950 }
951
952 pub const fn interpolate(c0: u32, c3: u32, dark_scale_to: u8) -> [Color; 8] {
956 let mut c4 = Self::color_to_rgb(Self::color_from_u32(c0));
958 c4.0 = Self::scale_to(c4.0, dark_scale_to);
959 c4.1 = Self::scale_to(c4.1, dark_scale_to);
960 c4.2 = Self::scale_to(c4.2, dark_scale_to);
961 let c4 = ((c4.0 as u32) << 16) + ((c4.1 as u32) << 8) + (c4.2 as u32);
962
963 let mut c7 = Self::color_to_rgb(Self::color_from_u32(c3));
964 c7.0 = Self::scale_to(c7.0, dark_scale_to);
965 c7.1 = Self::scale_to(c7.1, dark_scale_to);
966 c7.2 = Self::scale_to(c7.2, dark_scale_to);
967 let c7 = ((c7.0 as u32) << 16) + ((c7.1 as u32) << 8) + (c7.2 as u32);
968
969 Self::interpolate2(c0, c3, c4, c7)
970 }
971
972 pub const fn interpolatec2(c0: Color, c3: Color, c4: Color, c7: Color) -> [Color; 8] {
976 Self::interpolate2(
977 Self::color_to_u32(c0),
978 Self::color_to_u32(c3),
979 Self::color_to_u32(c4),
980 Self::color_to_u32(c7),
981 )
982 }
983
984 pub const fn interpolate2(c0: u32, c3: u32, c4: u32, c7: u32) -> [Color; 8] {
988 const fn i1(a: u8, b: u8) -> u8 {
990 if a < b {
991 a + (b - a) / 3
992 } else {
993 a - (a - b) / 3
994 }
995 }
996 const fn i2(a: u8, b: u8) -> u8 {
998 if a < b {
999 b - (b - a) / 3
1000 } else {
1001 b + (a - b) / 3
1002 }
1003 }
1004
1005 let r0 = (c0 >> 16) as u8;
1006 let g0 = (c0 >> 8) as u8;
1007 let b0 = c0 as u8;
1008
1009 let r3 = (c3 >> 16) as u8;
1010 let g3 = (c3 >> 8) as u8;
1011 let b3 = c3 as u8;
1012
1013 let r1 = i1(r0, r3);
1014 let g1 = i1(g0, g3);
1015 let b1 = i1(b0, b3);
1016
1017 let r2 = i2(r0, r3);
1018 let g2 = i2(g0, g3);
1019 let b2 = i2(b0, b3);
1020
1021 let r4 = (c4 >> 16) as u8;
1023 let g4 = (c4 >> 8) as u8;
1024 let b4 = c4 as u8;
1025
1026 let r7 = (c7 >> 16) as u8;
1027 let g7 = (c7 >> 8) as u8;
1028 let b7 = c7 as u8;
1029
1030 let r5 = i1(r4, r7);
1031 let g5 = i1(g4, g7);
1032 let b5 = i1(b4, b7);
1033
1034 let r6 = i2(r4, r7);
1035 let g6 = i2(g4, g7);
1036 let b6 = i2(b4, b7);
1037
1038 [
1039 Color::Rgb(r0, g0, b0),
1040 Color::Rgb(r1, g1, b1),
1041 Color::Rgb(r2, g2, b2),
1042 Color::Rgb(r3, g3, b3),
1043 Color::Rgb(r4, g4, b4),
1044 Color::Rgb(r5, g5, b5),
1045 Color::Rgb(r6, g6, b6),
1046 Color::Rgb(r7, g7, b7),
1047 ]
1048 }
1049
1050 pub const fn scale_to(v: u8, scale_to: u8) -> u8 {
1052 (((v as u16) * scale_to as u16) / 255u16) as u8
1053 }
1054
1055 pub const fn color_to_rgb(color: Color) -> (u8, u8, u8) {
1058 match color {
1059 Color::Black => (0x00, 0x00, 0x00),
1060 Color::Red => (0xaa, 0x00, 0x00),
1061 Color::Green => (0x00, 0xaa, 0x00),
1062 Color::Yellow => (0xaa, 0x55, 0x00),
1063 Color::Blue => (0x00, 0x00, 0xaa),
1064 Color::Magenta => (0xaa, 0x00, 0xaa),
1065 Color::Cyan => (0x00, 0xaa, 0xaa),
1066 Color::Gray => (0xaa, 0xaa, 0xaa),
1067 Color::DarkGray => (0x55, 0x55, 0x55),
1068 Color::LightRed => (0xff, 0x55, 0x55),
1069 Color::LightGreen => (0x55, 0xff, 0x55),
1070 Color::LightYellow => (0xff, 0xff, 0x55),
1071 Color::LightBlue => (0x55, 0x55, 0xff),
1072 Color::LightMagenta => (0xff, 0x55, 0xff),
1073 Color::LightCyan => (0x55, 0xff, 0xff),
1074 Color::White => (0xff, 0xff, 0xff),
1075 Color::Rgb(r, g, b) => (r, g, b),
1076 Color::Indexed(i) => {
1077 const VGA256: [(u8, u8, u8); 256] = [
1078 (0x00, 0x00, 0x00),
1079 (0x80, 0x00, 0x00),
1080 (0x00, 0x80, 0x00),
1081 (0x80, 0x80, 0x00),
1082 (0x00, 0x00, 0x80),
1083 (0x80, 0x00, 0x80),
1084 (0x00, 0x80, 0x80),
1085 (0xc0, 0xc0, 0xc0),
1086 (0x80, 0x80, 0x80),
1087 (0xff, 0x00, 0x00),
1088 (0x00, 0xff, 0x00),
1089 (0xff, 0xff, 0x00),
1090 (0x00, 0x00, 0xff),
1091 (0xff, 0x00, 0xff),
1092 (0x00, 0xff, 0xff),
1093 (0xff, 0xff, 0xff),
1094 (0x00, 0x00, 0x00),
1095 (0x00, 0x00, 0x5f),
1096 (0x00, 0x00, 0x87),
1097 (0x00, 0x00, 0xaf),
1098 (0x00, 0x00, 0xd7),
1099 (0x00, 0x00, 0xff),
1100 (0x00, 0x5f, 0x00),
1101 (0x00, 0x5f, 0x5f),
1102 (0x00, 0x5f, 0x87),
1103 (0x00, 0x5f, 0xaf),
1104 (0x00, 0x5f, 0xd7),
1105 (0x00, 0x5f, 0xff),
1106 (0x00, 0x87, 0x00),
1107 (0x00, 0x87, 0x5f),
1108 (0x00, 0x87, 0x87),
1109 (0x00, 0x87, 0xaf),
1110 (0x00, 0x87, 0xd7),
1111 (0x00, 0x87, 0xff),
1112 (0x00, 0xaf, 0x00),
1113 (0x00, 0xaf, 0x5f),
1114 (0x00, 0xaf, 0x87),
1115 (0x00, 0xaf, 0xaf),
1116 (0x00, 0xaf, 0xd7),
1117 (0x00, 0xaf, 0xff),
1118 (0x00, 0xd7, 0x00),
1119 (0x00, 0xd7, 0x5f),
1120 (0x00, 0xd7, 0x87),
1121 (0x00, 0xd7, 0xaf),
1122 (0x00, 0xd7, 0xd7),
1123 (0x00, 0xd7, 0xff),
1124 (0x00, 0xff, 0x00),
1125 (0x00, 0xff, 0x5f),
1126 (0x00, 0xff, 0x87),
1127 (0x00, 0xff, 0xaf),
1128 (0x00, 0xff, 0xd7),
1129 (0x00, 0xff, 0xff),
1130 (0x5f, 0x00, 0x00),
1131 (0x5f, 0x00, 0x5f),
1132 (0x5f, 0x00, 0x87),
1133 (0x5f, 0x00, 0xaf),
1134 (0x5f, 0x00, 0xd7),
1135 (0x5f, 0x00, 0xff),
1136 (0x5f, 0x5f, 0x00),
1137 (0x5f, 0x5f, 0x5f),
1138 (0x5f, 0x5f, 0x87),
1139 (0x5f, 0x5f, 0xaf),
1140 (0x5f, 0x5f, 0xd7),
1141 (0x5f, 0x5f, 0xff),
1142 (0x5f, 0x87, 0x00),
1143 (0x5f, 0x87, 0x5f),
1144 (0x5f, 0x87, 0x87),
1145 (0x5f, 0x87, 0xaf),
1146 (0x5f, 0x87, 0xd7),
1147 (0x5f, 0x87, 0xff),
1148 (0x5f, 0xaf, 0x00),
1149 (0x5f, 0xaf, 0x5f),
1150 (0x5f, 0xaf, 0x87),
1151 (0x5f, 0xaf, 0xaf),
1152 (0x5f, 0xaf, 0xd7),
1153 (0x5f, 0xaf, 0xff),
1154 (0x5f, 0xd7, 0x00),
1155 (0x5f, 0xd7, 0x5f),
1156 (0x5f, 0xd7, 0x87),
1157 (0x5f, 0xd7, 0xaf),
1158 (0x5f, 0xd7, 0xd7),
1159 (0x5f, 0xd7, 0xff),
1160 (0x5f, 0xff, 0x00),
1161 (0x5f, 0xff, 0x5f),
1162 (0x5f, 0xff, 0x87),
1163 (0x5f, 0xff, 0xaf),
1164 (0x5f, 0xff, 0xd7),
1165 (0x5f, 0xff, 0xff),
1166 (0x87, 0x00, 0x00),
1167 (0x87, 0x00, 0x5f),
1168 (0x87, 0x00, 0x87),
1169 (0x87, 0x00, 0xaf),
1170 (0x87, 0x00, 0xd7),
1171 (0x87, 0x00, 0xff),
1172 (0x87, 0x5f, 0x00),
1173 (0x87, 0x5f, 0x5f),
1174 (0x87, 0x5f, 0x87),
1175 (0x87, 0x5f, 0xaf),
1176 (0x87, 0x5f, 0xd7),
1177 (0x87, 0x5f, 0xff),
1178 (0x87, 0x87, 0x00),
1179 (0x87, 0x87, 0x5f),
1180 (0x87, 0x87, 0x87),
1181 (0x87, 0x87, 0xaf),
1182 (0x87, 0x87, 0xd7),
1183 (0x87, 0x87, 0xff),
1184 (0x87, 0xaf, 0x00),
1185 (0x87, 0xaf, 0x5f),
1186 (0x87, 0xaf, 0x87),
1187 (0x87, 0xaf, 0xaf),
1188 (0x87, 0xaf, 0xd7),
1189 (0x87, 0xaf, 0xff),
1190 (0x87, 0xd7, 0x00),
1191 (0x87, 0xd7, 0x5f),
1192 (0x87, 0xd7, 0x87),
1193 (0x87, 0xd7, 0xaf),
1194 (0x87, 0xd7, 0xd7),
1195 (0x87, 0xd7, 0xff),
1196 (0x87, 0xff, 0x00),
1197 (0x87, 0xff, 0x5f),
1198 (0x87, 0xff, 0x87),
1199 (0x87, 0xff, 0xaf),
1200 (0x87, 0xff, 0xd7),
1201 (0x87, 0xff, 0xff),
1202 (0xaf, 0x00, 0x00),
1203 (0xaf, 0x00, 0x5f),
1204 (0xaf, 0x00, 0x87),
1205 (0xaf, 0x00, 0xaf),
1206 (0xaf, 0x00, 0xd7),
1207 (0xaf, 0x00, 0xff),
1208 (0xaf, 0x5f, 0x00),
1209 (0xaf, 0x5f, 0x5f),
1210 (0xaf, 0x5f, 0x87),
1211 (0xaf, 0x5f, 0xaf),
1212 (0xaf, 0x5f, 0xd7),
1213 (0xaf, 0x5f, 0xff),
1214 (0xaf, 0x87, 0x00),
1215 (0xaf, 0x87, 0x5f),
1216 (0xaf, 0x87, 0x87),
1217 (0xaf, 0x87, 0xaf),
1218 (0xaf, 0x87, 0xd7),
1219 (0xaf, 0x87, 0xff),
1220 (0xaf, 0xaf, 0x00),
1221 (0xaf, 0xaf, 0x5f),
1222 (0xaf, 0xaf, 0x87),
1223 (0xaf, 0xaf, 0xaf),
1224 (0xaf, 0xaf, 0xd7),
1225 (0xaf, 0xaf, 0xff),
1226 (0xaf, 0xd7, 0x00),
1227 (0xaf, 0xd7, 0x5f),
1228 (0xaf, 0xd7, 0x87),
1229 (0xaf, 0xd7, 0xaf),
1230 (0xaf, 0xd7, 0xd7),
1231 (0xaf, 0xd7, 0xff),
1232 (0xaf, 0xff, 0x00),
1233 (0xaf, 0xff, 0x5f),
1234 (0xaf, 0xff, 0x87),
1235 (0xaf, 0xff, 0xaf),
1236 (0xaf, 0xff, 0xd7),
1237 (0xaf, 0xff, 0xff),
1238 (0xd7, 0x00, 0x00),
1239 (0xd7, 0x00, 0x5f),
1240 (0xd7, 0x00, 0x87),
1241 (0xd7, 0x00, 0xaf),
1242 (0xd7, 0x00, 0xd7),
1243 (0xd7, 0x00, 0xff),
1244 (0xd7, 0x5f, 0x00),
1245 (0xd7, 0x5f, 0x5f),
1246 (0xd7, 0x5f, 0x87),
1247 (0xd7, 0x5f, 0xaf),
1248 (0xd7, 0x5f, 0xd7),
1249 (0xd7, 0x5f, 0xff),
1250 (0xd7, 0x87, 0x00),
1251 (0xd7, 0x87, 0x5f),
1252 (0xd7, 0x87, 0x87),
1253 (0xd7, 0x87, 0xaf),
1254 (0xd7, 0x87, 0xd7),
1255 (0xd7, 0x87, 0xff),
1256 (0xd7, 0xaf, 0x00),
1257 (0xd7, 0xaf, 0x5f),
1258 (0xd7, 0xaf, 0x87),
1259 (0xd7, 0xaf, 0xaf),
1260 (0xd7, 0xaf, 0xd7),
1261 (0xd7, 0xaf, 0xff),
1262 (0xd7, 0xd7, 0x00),
1263 (0xd7, 0xd7, 0x5f),
1264 (0xd7, 0xd7, 0x87),
1265 (0xd7, 0xd7, 0xaf),
1266 (0xd7, 0xd7, 0xd7),
1267 (0xd7, 0xd7, 0xff),
1268 (0xd7, 0xff, 0x00),
1269 (0xd7, 0xff, 0x5f),
1270 (0xd7, 0xff, 0x87),
1271 (0xd7, 0xff, 0xaf),
1272 (0xd7, 0xff, 0xd7),
1273 (0xd7, 0xff, 0xff),
1274 (0xff, 0x00, 0x00),
1275 (0xff, 0x00, 0x5f),
1276 (0xff, 0x00, 0x87),
1277 (0xff, 0x00, 0xaf),
1278 (0xff, 0x00, 0xd7),
1279 (0xff, 0x00, 0xff),
1280 (0xff, 0x5f, 0x00),
1281 (0xff, 0x5f, 0x5f),
1282 (0xff, 0x5f, 0x87),
1283 (0xff, 0x5f, 0xaf),
1284 (0xff, 0x5f, 0xd7),
1285 (0xff, 0x5f, 0xff),
1286 (0xff, 0x87, 0x00),
1287 (0xff, 0x87, 0x5f),
1288 (0xff, 0x87, 0x87),
1289 (0xff, 0x87, 0xaf),
1290 (0xff, 0x87, 0xd7),
1291 (0xff, 0x87, 0xff),
1292 (0xff, 0xaf, 0x00),
1293 (0xff, 0xaf, 0x5f),
1294 (0xff, 0xaf, 0x87),
1295 (0xff, 0xaf, 0xaf),
1296 (0xff, 0xaf, 0xd7),
1297 (0xff, 0xaf, 0xff),
1298 (0xff, 0xd7, 0x00),
1299 (0xff, 0xd7, 0x5f),
1300 (0xff, 0xd7, 0x87),
1301 (0xff, 0xd7, 0xaf),
1302 (0xff, 0xd7, 0xd7),
1303 (0xff, 0xd7, 0xff),
1304 (0xff, 0xff, 0x00),
1305 (0xff, 0xff, 0x5f),
1306 (0xff, 0xff, 0x87),
1307 (0xff, 0xff, 0xaf),
1308 (0xff, 0xff, 0xd7),
1309 (0xff, 0xff, 0xff),
1310 (0x08, 0x08, 0x08),
1311 (0x12, 0x12, 0x12),
1312 (0x1c, 0x1c, 0x1c),
1313 (0x26, 0x26, 0x26),
1314 (0x30, 0x30, 0x30),
1315 (0x3a, 0x3a, 0x3a),
1316 (0x44, 0x44, 0x44),
1317 (0x4e, 0x4e, 0x4e),
1318 (0x58, 0x58, 0x58),
1319 (0x62, 0x62, 0x62),
1320 (0x6c, 0x6c, 0x6c),
1321 (0x76, 0x76, 0x76),
1322 (0x80, 0x80, 0x80),
1323 (0x8a, 0x8a, 0x8a),
1324 (0x94, 0x94, 0x94),
1325 (0x9e, 0x9e, 0x9e),
1326 (0xa8, 0xa8, 0xa8),
1327 (0xb2, 0xb2, 0xb2),
1328 (0xbc, 0xbc, 0xbc),
1329 (0xc6, 0xc6, 0xc6),
1330 (0xd0, 0xd0, 0xd0),
1331 (0xda, 0xda, 0xda),
1332 (0xe4, 0xe4, 0xe4),
1333 (0xee, 0xee, 0xee),
1334 ];
1335 VGA256[i as usize]
1336 }
1337 Color::Reset => (0, 0, 0),
1338 }
1339 }
1340}