1use ratatui::style::{Color, Style};
2
3#[derive(Debug, Default, Clone)]
16pub struct Palette {
17 pub name: &'static str,
18
19 pub text_light: Color,
20 pub text_bright: Color,
21 pub text_dark: Color,
22 pub text_black: Color,
23
24 pub white: [Color; 8],
25 pub black: [Color; 8],
26 pub gray: [Color; 8],
27
28 pub red: [Color; 8],
29 pub orange: [Color; 8],
30 pub yellow: [Color; 8],
31 pub limegreen: [Color; 8],
32 pub green: [Color; 8],
33 pub bluegreen: [Color; 8],
34 pub cyan: [Color; 8],
35 pub blue: [Color; 8],
36 pub deepblue: [Color; 8],
37 pub purple: [Color; 8],
38 pub magenta: [Color; 8],
39 pub redpink: [Color; 8],
40
41 pub primary: [Color; 8],
42 pub secondary: [Color; 8],
43}
44
45#[derive(Debug)]
47pub enum TextColorRating {
48 Light,
50 Dark,
52}
53
54#[derive(Debug)]
56pub enum Contrast {
57 High,
58 Normal,
59}
60
61impl Palette {
62 pub const BRIGHT_0: usize = 0;
65 pub const BRIGHT_1: usize = 1;
68 pub const BRIGHT_2: usize = 2;
71 pub const BRIGHT_3: usize = 3;
74 pub const DARK_0: usize = 4;
77 pub const DARK_1: usize = 5;
80 pub const DARK_2: usize = 6;
83 pub const DARK_3: usize = 7;
86
87 pub fn white(&self, n: usize, contrast: Contrast) -> Style {
90 self.style(self.white[n], contrast)
91 }
92
93 pub fn black(&self, n: usize, contrast: Contrast) -> Style {
96 self.style(self.black[n], contrast)
97 }
98
99 pub fn gray(&self, n: usize, contrast: Contrast) -> Style {
102 self.style(self.gray[n], contrast)
103 }
104
105 pub fn red(&self, n: usize, contrast: Contrast) -> Style {
108 self.style(self.red[n], contrast)
109 }
110
111 pub fn orange(&self, n: usize, contrast: Contrast) -> Style {
114 self.style(self.orange[n], contrast)
115 }
116
117 pub fn yellow(&self, n: usize, contrast: Contrast) -> Style {
120 self.style(self.yellow[n], contrast)
121 }
122
123 pub fn limegreen(&self, n: usize, contrast: Contrast) -> Style {
126 self.style(self.limegreen[n], contrast)
127 }
128
129 pub fn green(&self, n: usize, contrast: Contrast) -> Style {
132 self.style(self.green[n], contrast)
133 }
134
135 pub fn bluegreen(&self, n: usize, contrast: Contrast) -> Style {
138 self.style(self.bluegreen[n], contrast)
139 }
140
141 pub fn cyan(&self, n: usize, contrast: Contrast) -> Style {
144 self.style(self.cyan[n], contrast)
145 }
146
147 pub fn blue(&self, n: usize, contrast: Contrast) -> Style {
150 self.style(self.blue[n], contrast)
151 }
152
153 pub fn deepblue(&self, n: usize, contrast: Contrast) -> Style {
156 self.style(self.deepblue[n], contrast)
157 }
158
159 pub fn purple(&self, n: usize, contrast: Contrast) -> Style {
162 self.style(self.purple[n], contrast)
163 }
164
165 pub fn magenta(&self, n: usize, contrast: Contrast) -> Style {
168 self.style(self.magenta[n], contrast)
169 }
170
171 pub fn redpink(&self, n: usize, contrast: Contrast) -> Style {
174 self.style(self.redpink[n], contrast)
175 }
176
177 pub fn primary(&self, n: usize, contrast: Contrast) -> Style {
180 self.style(self.primary[n], contrast)
181 }
182
183 pub fn secondary(&self, n: usize, contrast: Contrast) -> Style {
186 self.style(self.secondary[n], contrast)
187 }
188}
189
190impl Palette {
191 pub fn style(&self, color: Color, contrast: Contrast) -> Style {
194 match contrast {
195 Contrast::High => self.high_contrast(color),
196 Contrast::Normal => self.normal_contrast(color),
197 }
198 }
199
200 pub fn high_contrast(&self, color: Color) -> Style {
204 match Self::rate_text_color(color) {
205 None => Style::reset(),
206 Some(TextColorRating::Light) => Style::new().bg(color).fg(self.text_bright),
207 Some(TextColorRating::Dark) => Style::new().bg(color).fg(self.text_black),
208 }
209 }
210
211 pub fn normal_contrast(&self, color: Color) -> Style {
215 match Self::rate_text_color(color) {
216 None => Style::reset(),
217 Some(TextColorRating::Light) => Style::new().bg(color).fg(self.text_light),
218 Some(TextColorRating::Dark) => Style::new().bg(color).fg(self.text_dark),
219 }
220 }
221
222 pub fn normal_contrast_color(&self, bg: Color, text: &[Color]) -> Style {
225 let mut color0 = text[0];
226 let mut color1 = text[0];
227 let mut contrast1 = Self::contrast_bt_srgb(color1, bg);
228
229 for i in 0..text.len() {
230 let test = Self::contrast_bt_srgb(text[i], bg);
231 if test > contrast1 {
232 color0 = color1;
233 color1 = text[i];
234 contrast1 = test;
235 }
236 }
237
238 Style::new().bg(bg).fg(color0)
239 }
240
241 pub fn high_contrast_color(&self, bg: Color, text: &[Color]) -> Style {
244 let mut color0 = text[0];
245 let mut color1 = text[0];
246 let mut contrast1 = Self::contrast_bt_srgb(color1, bg);
247
248 for i in 0..text.len() {
249 let test = Self::contrast_bt_srgb(text[i], bg);
250 if test > contrast1 {
251 color0 = color1;
252 color1 = text[i];
253 contrast1 = test;
254 }
255 }
256 _ = color0;
258
259 Style::new().bg(bg).fg(color1)
260 }
261
262 pub(crate) const fn luminance_bt(color: Color) -> f32 {
287 let (r, g, b) = Self::color2rgb(color);
288 0.2126f32 * ((r as f32) / 255f32)
289 + 0.7152f32 * ((g as f32) / 255f32)
290 + 0.0722f32 * ((b as f32) / 255f32)
291 }
292
293 pub(crate) fn luminance_bt_srgb(color: Color) -> f32 {
295 let (r, g, b) = Self::color2rgb(color);
296 0.2126f32 * ((r as f32) / 255f32).powf(2.2f32)
297 + 0.7152f32 * ((g as f32) / 255f32).powf(2.2f32)
298 + 0.0722f32 * ((b as f32) / 255f32).powf(2.2f32)
299 }
300
301 pub(crate) fn contrast_bt_srgb(color: Color, color2: Color) -> f32 {
303 let lum1 = Self::luminance_bt_srgb(color);
304 let lum2 = Self::luminance_bt_srgb(color2);
305 (lum1 - lum2).abs()
306 }
310
311 pub fn rate_text_color(color: Color) -> Option<TextColorRating> {
322 match color {
323 Color::Reset => None,
324 Color::Black => Some(TextColorRating::Light), Color::Red => Some(TextColorRating::Light), Color::Green => Some(TextColorRating::Light), Color::Yellow => Some(TextColorRating::Light), Color::Blue => Some(TextColorRating::Light), Color::Magenta => Some(TextColorRating::Light), Color::Cyan => Some(TextColorRating::Light), Color::Gray => Some(TextColorRating::Dark), Color::DarkGray => Some(TextColorRating::Light), Color::LightRed => Some(TextColorRating::Dark), Color::LightGreen => Some(TextColorRating::Dark), Color::LightYellow => Some(TextColorRating::Dark), Color::LightBlue => Some(TextColorRating::Light), Color::LightMagenta => Some(TextColorRating::Dark), Color::LightCyan => Some(TextColorRating::Dark), Color::White => Some(TextColorRating::Dark), c => {
341 let lum = Self::luminance_bt(c);
342 if lum >= 0.4117f32 {
343 Some(TextColorRating::Dark)
344 } else {
345 Some(TextColorRating::Light)
346 }
347 }
348 }
349 }
350
351 pub const fn darken(color: Color, scale_to: u8) -> Color {
357 let (r, g, b) = Self::color2rgb(color);
358 Color::Rgb(
359 Self::scale_to(r, scale_to),
360 Self::scale_to(g, scale_to),
361 Self::scale_to(b, scale_to),
362 )
363 }
364
365 pub const fn grayscale(color: Color) -> Color {
367 let lum = Self::luminance_bt(color);
368 let gray = lum * 255f32;
369 Color::Rgb(gray as u8, gray as u8, gray as u8)
370 }
371
372 pub const fn color32(c0: u32) -> Color {
374 let r0 = (c0 >> 16) as u8;
375 let g0 = (c0 >> 8) as u8;
376 let b0 = c0 as u8;
377 Color::Rgb(r0, g0, b0)
378 }
379
380 pub const fn interpolate(c0: u32, c1: u32, dark_scale_to: u8) -> [Color; 8] {
384 const fn i1(a: u8, b: u8) -> u8 {
386 if a < b {
387 a + (b - a) / 3
388 } else {
389 a - (a - b) / 3
390 }
391 }
392 const fn i2(a: u8, b: u8) -> u8 {
394 if a < b {
395 b - (b - a) / 3
396 } else {
397 b + (a - b) / 3
398 }
399 }
400
401 let r0 = (c0 >> 16) as u8;
402 let g0 = (c0 >> 8) as u8;
403 let b0 = c0 as u8;
404
405 let r3 = (c1 >> 16) as u8;
406 let g3 = (c1 >> 8) as u8;
407 let b3 = c1 as u8;
408
409 let r1 = i1(r0, r3);
410 let g1 = i1(g0, g3);
411 let b1 = i1(b0, b3);
412
413 let r2 = i2(r0, r3);
414 let g2 = i2(g0, g3);
415 let b2 = i2(b0, b3);
416
417 let r4 = Self::scale_to(r0, dark_scale_to);
419 let g4 = Self::scale_to(g0, dark_scale_to);
420 let b4 = Self::scale_to(b0, dark_scale_to);
421
422 let r5 = Self::scale_to(r1, dark_scale_to);
423 let g5 = Self::scale_to(g1, dark_scale_to);
424 let b5 = Self::scale_to(b1, dark_scale_to);
425
426 let r6 = Self::scale_to(r2, dark_scale_to);
427 let g6 = Self::scale_to(g2, dark_scale_to);
428 let b6 = Self::scale_to(b2, dark_scale_to);
429
430 let r7 = Self::scale_to(r3, dark_scale_to);
431 let g7 = Self::scale_to(g3, dark_scale_to);
432 let b7 = Self::scale_to(b3, dark_scale_to);
433
434 [
435 Color::Rgb(r0, g0, b0),
436 Color::Rgb(r1, g1, b1),
437 Color::Rgb(r2, g2, b2),
438 Color::Rgb(r3, g3, b3),
439 Color::Rgb(r4, g4, b4),
440 Color::Rgb(r5, g5, b5),
441 Color::Rgb(r6, g6, b6),
442 Color::Rgb(r7, g7, b7),
443 ]
444 }
445
446 pub const fn scale_to(v: u8, scale_to: u8) -> u8 {
448 (((v as u16) * scale_to as u16) / 255u16) as u8
449 }
450
451 pub const fn color2rgb(color: Color) -> (u8, u8, u8) {
454 match color {
455 Color::Black => (0x00, 0x00, 0x00),
456 Color::Red => (0xaa, 0x00, 0x00),
457 Color::Green => (0x00, 0xaa, 0x00),
458 Color::Yellow => (0xaa, 0x55, 0x00),
459 Color::Blue => (0x00, 0x00, 0xaa),
460 Color::Magenta => (0xaa, 0x00, 0xaa),
461 Color::Cyan => (0x00, 0xaa, 0xaa),
462 Color::Gray => (0xaa, 0xaa, 0xaa),
463 Color::DarkGray => (0x55, 0x55, 0x55),
464 Color::LightRed => (0xff, 0x55, 0x55),
465 Color::LightGreen => (0x55, 0xff, 0x55),
466 Color::LightYellow => (0xff, 0xff, 0x55),
467 Color::LightBlue => (0x55, 0x55, 0xff),
468 Color::LightMagenta => (0xff, 0x55, 0xff),
469 Color::LightCyan => (0x55, 0xff, 0xff),
470 Color::White => (0xff, 0xff, 0xff),
471 Color::Rgb(r, g, b) => (r, g, b),
472 Color::Indexed(i) => {
473 const VGA256: [(u8, u8, u8); 256] = [
474 (0x00, 0x00, 0x00),
475 (0x80, 0x00, 0x00),
476 (0x00, 0x80, 0x00),
477 (0x80, 0x80, 0x00),
478 (0x00, 0x00, 0x80),
479 (0x80, 0x00, 0x80),
480 (0x00, 0x80, 0x80),
481 (0xc0, 0xc0, 0xc0),
482 (0x80, 0x80, 0x80),
483 (0xff, 0x00, 0x00),
484 (0x00, 0xff, 0x00),
485 (0xff, 0xff, 0x00),
486 (0x00, 0x00, 0xff),
487 (0xff, 0x00, 0xff),
488 (0x00, 0xff, 0xff),
489 (0xff, 0xff, 0xff),
490 (0x00, 0x00, 0x00),
491 (0x00, 0x00, 0x5f),
492 (0x00, 0x00, 0x87),
493 (0x00, 0x00, 0xaf),
494 (0x00, 0x00, 0xd7),
495 (0x00, 0x00, 0xff),
496 (0x00, 0x5f, 0x00),
497 (0x00, 0x5f, 0x5f),
498 (0x00, 0x5f, 0x87),
499 (0x00, 0x5f, 0xaf),
500 (0x00, 0x5f, 0xd7),
501 (0x00, 0x5f, 0xff),
502 (0x00, 0x87, 0x00),
503 (0x00, 0x87, 0x5f),
504 (0x00, 0x87, 0x87),
505 (0x00, 0x87, 0xaf),
506 (0x00, 0x87, 0xd7),
507 (0x00, 0x87, 0xff),
508 (0x00, 0xaf, 0x00),
509 (0x00, 0xaf, 0x5f),
510 (0x00, 0xaf, 0x87),
511 (0x00, 0xaf, 0xaf),
512 (0x00, 0xaf, 0xd7),
513 (0x00, 0xaf, 0xff),
514 (0x00, 0xd7, 0x00),
515 (0x00, 0xd7, 0x5f),
516 (0x00, 0xd7, 0x87),
517 (0x00, 0xd7, 0xaf),
518 (0x00, 0xd7, 0xd7),
519 (0x00, 0xd7, 0xff),
520 (0x00, 0xff, 0x00),
521 (0x00, 0xff, 0x5f),
522 (0x00, 0xff, 0x87),
523 (0x00, 0xff, 0xaf),
524 (0x00, 0xff, 0xd7),
525 (0x00, 0xff, 0xff),
526 (0x5f, 0x00, 0x00),
527 (0x5f, 0x00, 0x5f),
528 (0x5f, 0x00, 0x87),
529 (0x5f, 0x00, 0xaf),
530 (0x5f, 0x00, 0xd7),
531 (0x5f, 0x00, 0xff),
532 (0x5f, 0x5f, 0x00),
533 (0x5f, 0x5f, 0x5f),
534 (0x5f, 0x5f, 0x87),
535 (0x5f, 0x5f, 0xaf),
536 (0x5f, 0x5f, 0xd7),
537 (0x5f, 0x5f, 0xff),
538 (0x5f, 0x87, 0x00),
539 (0x5f, 0x87, 0x5f),
540 (0x5f, 0x87, 0x87),
541 (0x5f, 0x87, 0xaf),
542 (0x5f, 0x87, 0xd7),
543 (0x5f, 0x87, 0xff),
544 (0x5f, 0xaf, 0x00),
545 (0x5f, 0xaf, 0x5f),
546 (0x5f, 0xaf, 0x87),
547 (0x5f, 0xaf, 0xaf),
548 (0x5f, 0xaf, 0xd7),
549 (0x5f, 0xaf, 0xff),
550 (0x5f, 0xd7, 0x00),
551 (0x5f, 0xd7, 0x5f),
552 (0x5f, 0xd7, 0x87),
553 (0x5f, 0xd7, 0xaf),
554 (0x5f, 0xd7, 0xd7),
555 (0x5f, 0xd7, 0xff),
556 (0x5f, 0xff, 0x00),
557 (0x5f, 0xff, 0x5f),
558 (0x5f, 0xff, 0x87),
559 (0x5f, 0xff, 0xaf),
560 (0x5f, 0xff, 0xd7),
561 (0x5f, 0xff, 0xff),
562 (0x87, 0x00, 0x00),
563 (0x87, 0x00, 0x5f),
564 (0x87, 0x00, 0x87),
565 (0x87, 0x00, 0xaf),
566 (0x87, 0x00, 0xd7),
567 (0x87, 0x00, 0xff),
568 (0x87, 0x5f, 0x00),
569 (0x87, 0x5f, 0x5f),
570 (0x87, 0x5f, 0x87),
571 (0x87, 0x5f, 0xaf),
572 (0x87, 0x5f, 0xd7),
573 (0x87, 0x5f, 0xff),
574 (0x87, 0x87, 0x00),
575 (0x87, 0x87, 0x5f),
576 (0x87, 0x87, 0x87),
577 (0x87, 0x87, 0xaf),
578 (0x87, 0x87, 0xd7),
579 (0x87, 0x87, 0xff),
580 (0x87, 0xaf, 0x00),
581 (0x87, 0xaf, 0x5f),
582 (0x87, 0xaf, 0x87),
583 (0x87, 0xaf, 0xaf),
584 (0x87, 0xaf, 0xd7),
585 (0x87, 0xaf, 0xff),
586 (0x87, 0xd7, 0x00),
587 (0x87, 0xd7, 0x5f),
588 (0x87, 0xd7, 0x87),
589 (0x87, 0xd7, 0xaf),
590 (0x87, 0xd7, 0xd7),
591 (0x87, 0xd7, 0xff),
592 (0x87, 0xff, 0x00),
593 (0x87, 0xff, 0x5f),
594 (0x87, 0xff, 0x87),
595 (0x87, 0xff, 0xaf),
596 (0x87, 0xff, 0xd7),
597 (0x87, 0xff, 0xff),
598 (0xaf, 0x00, 0x00),
599 (0xaf, 0x00, 0x5f),
600 (0xaf, 0x00, 0x87),
601 (0xaf, 0x00, 0xaf),
602 (0xaf, 0x00, 0xd7),
603 (0xaf, 0x00, 0xff),
604 (0xaf, 0x5f, 0x00),
605 (0xaf, 0x5f, 0x5f),
606 (0xaf, 0x5f, 0x87),
607 (0xaf, 0x5f, 0xaf),
608 (0xaf, 0x5f, 0xd7),
609 (0xaf, 0x5f, 0xff),
610 (0xaf, 0x87, 0x00),
611 (0xaf, 0x87, 0x5f),
612 (0xaf, 0x87, 0x87),
613 (0xaf, 0x87, 0xaf),
614 (0xaf, 0x87, 0xd7),
615 (0xaf, 0x87, 0xff),
616 (0xaf, 0xaf, 0x00),
617 (0xaf, 0xaf, 0x5f),
618 (0xaf, 0xaf, 0x87),
619 (0xaf, 0xaf, 0xaf),
620 (0xaf, 0xaf, 0xd7),
621 (0xaf, 0xaf, 0xff),
622 (0xaf, 0xd7, 0x00),
623 (0xaf, 0xd7, 0x5f),
624 (0xaf, 0xd7, 0x87),
625 (0xaf, 0xd7, 0xaf),
626 (0xaf, 0xd7, 0xd7),
627 (0xaf, 0xd7, 0xff),
628 (0xaf, 0xff, 0x00),
629 (0xaf, 0xff, 0x5f),
630 (0xaf, 0xff, 0x87),
631 (0xaf, 0xff, 0xaf),
632 (0xaf, 0xff, 0xd7),
633 (0xaf, 0xff, 0xff),
634 (0xd7, 0x00, 0x00),
635 (0xd7, 0x00, 0x5f),
636 (0xd7, 0x00, 0x87),
637 (0xd7, 0x00, 0xaf),
638 (0xd7, 0x00, 0xd7),
639 (0xd7, 0x00, 0xff),
640 (0xd7, 0x5f, 0x00),
641 (0xd7, 0x5f, 0x5f),
642 (0xd7, 0x5f, 0x87),
643 (0xd7, 0x5f, 0xaf),
644 (0xd7, 0x5f, 0xd7),
645 (0xd7, 0x5f, 0xff),
646 (0xd7, 0x87, 0x00),
647 (0xd7, 0x87, 0x5f),
648 (0xd7, 0x87, 0x87),
649 (0xd7, 0x87, 0xaf),
650 (0xd7, 0x87, 0xd7),
651 (0xd7, 0x87, 0xff),
652 (0xd7, 0xaf, 0x00),
653 (0xd7, 0xaf, 0x5f),
654 (0xd7, 0xaf, 0x87),
655 (0xd7, 0xaf, 0xaf),
656 (0xd7, 0xaf, 0xd7),
657 (0xd7, 0xaf, 0xff),
658 (0xd7, 0xd7, 0x00),
659 (0xd7, 0xd7, 0x5f),
660 (0xd7, 0xd7, 0x87),
661 (0xd7, 0xd7, 0xaf),
662 (0xd7, 0xd7, 0xd7),
663 (0xd7, 0xd7, 0xff),
664 (0xd7, 0xff, 0x00),
665 (0xd7, 0xff, 0x5f),
666 (0xd7, 0xff, 0x87),
667 (0xd7, 0xff, 0xaf),
668 (0xd7, 0xff, 0xd7),
669 (0xd7, 0xff, 0xff),
670 (0xff, 0x00, 0x00),
671 (0xff, 0x00, 0x5f),
672 (0xff, 0x00, 0x87),
673 (0xff, 0x00, 0xaf),
674 (0xff, 0x00, 0xd7),
675 (0xff, 0x00, 0xff),
676 (0xff, 0x5f, 0x00),
677 (0xff, 0x5f, 0x5f),
678 (0xff, 0x5f, 0x87),
679 (0xff, 0x5f, 0xaf),
680 (0xff, 0x5f, 0xd7),
681 (0xff, 0x5f, 0xff),
682 (0xff, 0x87, 0x00),
683 (0xff, 0x87, 0x5f),
684 (0xff, 0x87, 0x87),
685 (0xff, 0x87, 0xaf),
686 (0xff, 0x87, 0xd7),
687 (0xff, 0x87, 0xff),
688 (0xff, 0xaf, 0x00),
689 (0xff, 0xaf, 0x5f),
690 (0xff, 0xaf, 0x87),
691 (0xff, 0xaf, 0xaf),
692 (0xff, 0xaf, 0xd7),
693 (0xff, 0xaf, 0xff),
694 (0xff, 0xd7, 0x00),
695 (0xff, 0xd7, 0x5f),
696 (0xff, 0xd7, 0x87),
697 (0xff, 0xd7, 0xaf),
698 (0xff, 0xd7, 0xd7),
699 (0xff, 0xd7, 0xff),
700 (0xff, 0xff, 0x00),
701 (0xff, 0xff, 0x5f),
702 (0xff, 0xff, 0x87),
703 (0xff, 0xff, 0xaf),
704 (0xff, 0xff, 0xd7),
705 (0xff, 0xff, 0xff),
706 (0x08, 0x08, 0x08),
707 (0x12, 0x12, 0x12),
708 (0x1c, 0x1c, 0x1c),
709 (0x26, 0x26, 0x26),
710 (0x30, 0x30, 0x30),
711 (0x3a, 0x3a, 0x3a),
712 (0x44, 0x44, 0x44),
713 (0x4e, 0x4e, 0x4e),
714 (0x58, 0x58, 0x58),
715 (0x62, 0x62, 0x62),
716 (0x6c, 0x6c, 0x6c),
717 (0x76, 0x76, 0x76),
718 (0x80, 0x80, 0x80),
719 (0x8a, 0x8a, 0x8a),
720 (0x94, 0x94, 0x94),
721 (0x9e, 0x9e, 0x9e),
722 (0xa8, 0xa8, 0xa8),
723 (0xb2, 0xb2, 0xb2),
724 (0xbc, 0xbc, 0xbc),
725 (0xc6, 0xc6, 0xc6),
726 (0xd0, 0xd0, 0xd0),
727 (0xda, 0xda, 0xda),
728 (0xe4, 0xe4, 0xe4),
729 (0xee, 0xee, 0xee),
730 ];
731 VGA256[i as usize]
732 }
733 Color::Reset => (0, 0, 0),
734 }
735 }
736}