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