1use ratatui::style::{Color, Style};
2
3#[derive(Debug, Default, Clone)]
17pub struct Palette {
18 pub white: [Color; 8],
19 pub black: [Color; 8],
20 pub gray: [Color; 8],
21
22 pub red: [Color; 8],
23 pub orange: [Color; 8],
24 pub yellow: [Color; 8],
25 pub limegreen: [Color; 8],
26 pub green: [Color; 8],
27 pub bluegreen: [Color; 8],
28 pub cyan: [Color; 8],
29 pub blue: [Color; 8],
30 pub deepblue: [Color; 8],
31 pub purple: [Color; 8],
32 pub magenta: [Color; 8],
33 pub redpink: [Color; 8],
34
35 pub primary: [Color; 8],
36 pub secondary: [Color; 8],
37}
38
39pub enum TextColorRating {
41 Light,
43 Dark,
45}
46
47pub enum Contrast {
49 High,
50 Normal,
51}
52
53impl Palette {
54 pub const BRIGHT_0: usize = 0;
57 pub const BRIGHT_1: usize = 1;
60 pub const BRIGHT_2: usize = 2;
63 pub const BRIGHT_3: usize = 3;
66 pub const DARK_0: usize = 4;
69 pub const DARK_1: usize = 5;
72 pub const DARK_2: usize = 6;
75 pub const DARK_3: usize = 7;
78
79 pub fn white(&self, n: usize, contrast: Contrast) -> Style {
82 self.style(self.white[n], contrast)
83 }
84
85 pub fn black(&self, n: usize, contrast: Contrast) -> Style {
88 self.style(self.black[n], contrast)
89 }
90
91 pub fn gray(&self, n: usize, contrast: Contrast) -> Style {
94 self.style(self.gray[n], contrast)
95 }
96
97 pub fn red(&self, n: usize, contrast: Contrast) -> Style {
100 self.style(self.red[n], contrast)
101 }
102
103 pub fn orange(&self, n: usize, contrast: Contrast) -> Style {
106 self.style(self.orange[n], contrast)
107 }
108
109 pub fn yellow(&self, n: usize, contrast: Contrast) -> Style {
112 self.style(self.yellow[n], contrast)
113 }
114
115 pub fn limegreen(&self, n: usize, contrast: Contrast) -> Style {
118 self.style(self.limegreen[n], contrast)
119 }
120
121 pub fn green(&self, n: usize, contrast: Contrast) -> Style {
124 self.style(self.green[n], contrast)
125 }
126
127 pub fn bluegreen(&self, n: usize, contrast: Contrast) -> Style {
130 self.style(self.bluegreen[n], contrast)
131 }
132
133 pub fn cyan(&self, n: usize, contrast: Contrast) -> Style {
136 self.style(self.cyan[n], contrast)
137 }
138
139 pub fn blue(&self, n: usize, contrast: Contrast) -> Style {
142 self.style(self.blue[n], contrast)
143 }
144
145 pub fn deepblue(&self, n: usize, contrast: Contrast) -> Style {
148 self.style(self.deepblue[n], contrast)
149 }
150
151 pub fn purple(&self, n: usize, contrast: Contrast) -> Style {
154 self.style(self.purple[n], contrast)
155 }
156
157 pub fn magenta(&self, n: usize, contrast: Contrast) -> Style {
160 self.style(self.magenta[n], contrast)
161 }
162
163 pub fn redpink(&self, n: usize, contrast: Contrast) -> Style {
166 self.style(self.redpink[n], contrast)
167 }
168
169 pub fn primary(&self, n: usize, contrast: Contrast) -> Style {
172 self.style(self.primary[n], contrast)
173 }
174
175 pub fn secondary(&self, n: usize, contrast: Contrast) -> Style {
178 self.style(self.secondary[n], contrast)
179 }
180}
181
182impl Palette {
183 pub fn style(&self, color: Color, contrast: Contrast) -> Style {
186 match contrast {
187 Contrast::High => self.high_contrast(color),
188 Contrast::Normal => self.normal_contrast(color),
189 }
190 }
191
192 pub fn high_contrast(&self, color: Color) -> Style {
196 match Self::rate_text_color(color) {
197 None => Style::reset(),
198 Some(TextColorRating::Light) => Style::new().bg(color).fg(self.white[3]),
199 Some(TextColorRating::Dark) => Style::new().bg(color).fg(self.black[0]),
200 }
201 }
202
203 pub fn normal_contrast(&self, color: Color) -> Style {
207 match Self::rate_text_color(color) {
208 None => Style::reset(),
209 Some(TextColorRating::Light) => Style::new().bg(color).fg(self.white[0]),
210 Some(TextColorRating::Dark) => Style::new().bg(color).fg(self.black[3]),
211 }
212 }
213
214 pub const fn rate_text_color(color: Color) -> Option<TextColorRating> {
225 match color {
226 Color::Reset => None,
227 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), Color::Rgb(r, g, b) => {
244 let grey = r as f32 * 0.3f32 + g as f32 * 0.59f32 + b as f32 * 0.11f32;
246 if grey >= 105f32 {
247 Some(TextColorRating::Dark)
248 } else {
249 Some(TextColorRating::Light)
250 }
251 }
252 Color::Indexed(n) => match n {
253 0..=6 => Some(TextColorRating::Light),
254 7 => Some(TextColorRating::Dark),
255 8 => Some(TextColorRating::Light),
256 9..=11 => Some(TextColorRating::Dark),
257 12 => Some(TextColorRating::Light),
258 13..=15 => Some(TextColorRating::Dark),
259 v @ 16..=231 => {
260 if (v - 16) % 36 < 18 {
261 Some(TextColorRating::Light)
262 } else {
263 Some(TextColorRating::Dark)
264 }
265 }
266 v @ 232..=255 => {
267 if (v - 232) % 24 < 12 {
268 Some(TextColorRating::Light)
269 } else {
270 Some(TextColorRating::Dark)
271 }
272 }
273 },
274 }
275 }
276
277 pub const fn darken(color: Color, scale_to: u8) -> Color {
283 let (r, g, b) = Self::color2rgb(color);
284 Color::Rgb(
285 Self::scale_to(r, scale_to),
286 Self::scale_to(g, scale_to),
287 Self::scale_to(b, scale_to),
288 )
289 }
290
291 pub const fn grayscale(color: Color) -> Color {
293 let (r, g, b) = Self::color2rgb(color);
294 let gray = r as f32 * 0.3f32 + g as f32 * 0.59f32 + b as f32 * 0.11f32;
296 Color::Rgb(gray as u8, gray as u8, gray as u8)
297 }
298
299 pub const fn interpolate(c0: u32, c1: u32, dark_scale_to: u8) -> [Color; 8] {
303 const fn i1(a: u8, b: u8) -> u8 {
305 if a < b {
306 a + (b - a) / 3
307 } else {
308 a - (a - b) / 3
309 }
310 }
311 const fn i2(a: u8, b: u8) -> u8 {
313 if a < b {
314 b - (b - a) / 3
315 } else {
316 b + (a - b) / 3
317 }
318 }
319
320 let r0 = (c0 >> 16) as u8;
321 let g0 = (c0 >> 8) as u8;
322 let b0 = c0 as u8;
323
324 let r3 = (c1 >> 16) as u8;
325 let g3 = (c1 >> 8) as u8;
326 let b3 = c1 as u8;
327
328 let r1 = i1(r0, r3);
329 let g1 = i1(g0, g3);
330 let b1 = i1(b0, b3);
331
332 let r2 = i2(r0, r3);
333 let g2 = i2(g0, g3);
334 let b2 = i2(b0, b3);
335
336 let r4 = Self::scale_to(r0, dark_scale_to);
338 let g4 = Self::scale_to(g0, dark_scale_to);
339 let b4 = Self::scale_to(b0, dark_scale_to);
340
341 let r5 = Self::scale_to(r1, dark_scale_to);
342 let g5 = Self::scale_to(g1, dark_scale_to);
343 let b5 = Self::scale_to(b1, dark_scale_to);
344
345 let r6 = Self::scale_to(r2, dark_scale_to);
346 let g6 = Self::scale_to(g2, dark_scale_to);
347 let b6 = Self::scale_to(b2, dark_scale_to);
348
349 let r7 = Self::scale_to(r3, dark_scale_to);
350 let g7 = Self::scale_to(g3, dark_scale_to);
351 let b7 = Self::scale_to(b3, dark_scale_to);
352
353 [
354 Color::Rgb(r0, g0, b0),
355 Color::Rgb(r1, g1, b1),
356 Color::Rgb(r2, g2, b2),
357 Color::Rgb(r3, g3, b3),
358 Color::Rgb(r4, g4, b4),
359 Color::Rgb(r5, g5, b5),
360 Color::Rgb(r6, g6, b6),
361 Color::Rgb(r7, g7, b7),
362 ]
363 }
364
365 pub const fn scale_to(v: u8, scale_to: u8) -> u8 {
367 (((v as u16) * scale_to as u16) / 255u16) as u8
368 }
369
370 pub const fn color2rgb(color: Color) -> (u8, u8, u8) {
373 match color {
374 Color::Black => (0x00, 0x00, 0x00),
375 Color::Red => (0xaa, 0x00, 0x00),
376 Color::Green => (0x00, 0xaa, 0x00),
377 Color::Yellow => (0xaa, 0x55, 0x00),
378 Color::Blue => (0x00, 0x00, 0xaa),
379 Color::Magenta => (0xaa, 0x00, 0xaa),
380 Color::Cyan => (0x00, 0xaa, 0xaa),
381 Color::Gray => (0xaa, 0xaa, 0xaa),
382 Color::DarkGray => (0x55, 0x55, 0x55),
383 Color::LightRed => (0xff, 0x55, 0x55),
384 Color::LightGreen => (0x55, 0xff, 0x55),
385 Color::LightYellow => (0xff, 0xff, 0x55),
386 Color::LightBlue => (0x55, 0x55, 0xff),
387 Color::LightMagenta => (0xff, 0x55, 0xff),
388 Color::LightCyan => (0x55, 0xff, 0xff),
389 Color::White => (0xff, 0xff, 0xff),
390 Color::Rgb(r, g, b) => (r, g, b),
391 Color::Indexed(i) => {
392 const VGA256: [(u8, u8, u8); 256] = [
393 (0x00, 0x00, 0x00),
394 (0x80, 0x00, 0x00),
395 (0x00, 0x80, 0x00),
396 (0x80, 0x80, 0x00),
397 (0x00, 0x00, 0x80),
398 (0x80, 0x00, 0x80),
399 (0x00, 0x80, 0x80),
400 (0xc0, 0xc0, 0xc0),
401 (0x80, 0x80, 0x80),
402 (0xff, 0x00, 0x00),
403 (0x00, 0xff, 0x00),
404 (0xff, 0xff, 0x00),
405 (0x00, 0x00, 0xff),
406 (0xff, 0x00, 0xff),
407 (0x00, 0xff, 0xff),
408 (0xff, 0xff, 0xff),
409 (0x00, 0x00, 0x00),
410 (0x00, 0x00, 0x5f),
411 (0x00, 0x00, 0x87),
412 (0x00, 0x00, 0xaf),
413 (0x00, 0x00, 0xd7),
414 (0x00, 0x00, 0xff),
415 (0x00, 0x5f, 0x00),
416 (0x00, 0x5f, 0x5f),
417 (0x00, 0x5f, 0x87),
418 (0x00, 0x5f, 0xaf),
419 (0x00, 0x5f, 0xd7),
420 (0x00, 0x5f, 0xff),
421 (0x00, 0x87, 0x00),
422 (0x00, 0x87, 0x5f),
423 (0x00, 0x87, 0x87),
424 (0x00, 0x87, 0xaf),
425 (0x00, 0x87, 0xd7),
426 (0x00, 0x87, 0xff),
427 (0x00, 0xaf, 0x00),
428 (0x00, 0xaf, 0x5f),
429 (0x00, 0xaf, 0x87),
430 (0x00, 0xaf, 0xaf),
431 (0x00, 0xaf, 0xd7),
432 (0x00, 0xaf, 0xff),
433 (0x00, 0xd7, 0x00),
434 (0x00, 0xd7, 0x5f),
435 (0x00, 0xd7, 0x87),
436 (0x00, 0xd7, 0xaf),
437 (0x00, 0xd7, 0xd7),
438 (0x00, 0xd7, 0xff),
439 (0x00, 0xff, 0x00),
440 (0x00, 0xff, 0x5f),
441 (0x00, 0xff, 0x87),
442 (0x00, 0xff, 0xaf),
443 (0x00, 0xff, 0xd7),
444 (0x00, 0xff, 0xff),
445 (0x5f, 0x00, 0x00),
446 (0x5f, 0x00, 0x5f),
447 (0x5f, 0x00, 0x87),
448 (0x5f, 0x00, 0xaf),
449 (0x5f, 0x00, 0xd7),
450 (0x5f, 0x00, 0xff),
451 (0x5f, 0x5f, 0x00),
452 (0x5f, 0x5f, 0x5f),
453 (0x5f, 0x5f, 0x87),
454 (0x5f, 0x5f, 0xaf),
455 (0x5f, 0x5f, 0xd7),
456 (0x5f, 0x5f, 0xff),
457 (0x5f, 0x87, 0x00),
458 (0x5f, 0x87, 0x5f),
459 (0x5f, 0x87, 0x87),
460 (0x5f, 0x87, 0xaf),
461 (0x5f, 0x87, 0xd7),
462 (0x5f, 0x87, 0xff),
463 (0x5f, 0xaf, 0x00),
464 (0x5f, 0xaf, 0x5f),
465 (0x5f, 0xaf, 0x87),
466 (0x5f, 0xaf, 0xaf),
467 (0x5f, 0xaf, 0xd7),
468 (0x5f, 0xaf, 0xff),
469 (0x5f, 0xd7, 0x00),
470 (0x5f, 0xd7, 0x5f),
471 (0x5f, 0xd7, 0x87),
472 (0x5f, 0xd7, 0xaf),
473 (0x5f, 0xd7, 0xd7),
474 (0x5f, 0xd7, 0xff),
475 (0x5f, 0xff, 0x00),
476 (0x5f, 0xff, 0x5f),
477 (0x5f, 0xff, 0x87),
478 (0x5f, 0xff, 0xaf),
479 (0x5f, 0xff, 0xd7),
480 (0x5f, 0xff, 0xff),
481 (0x87, 0x00, 0x00),
482 (0x87, 0x00, 0x5f),
483 (0x87, 0x00, 0x87),
484 (0x87, 0x00, 0xaf),
485 (0x87, 0x00, 0xd7),
486 (0x87, 0x00, 0xff),
487 (0x87, 0x5f, 0x00),
488 (0x87, 0x5f, 0x5f),
489 (0x87, 0x5f, 0x87),
490 (0x87, 0x5f, 0xaf),
491 (0x87, 0x5f, 0xd7),
492 (0x87, 0x5f, 0xff),
493 (0x87, 0x87, 0x00),
494 (0x87, 0x87, 0x5f),
495 (0x87, 0x87, 0x87),
496 (0x87, 0x87, 0xaf),
497 (0x87, 0x87, 0xd7),
498 (0x87, 0x87, 0xff),
499 (0x87, 0xaf, 0x00),
500 (0x87, 0xaf, 0x5f),
501 (0x87, 0xaf, 0x87),
502 (0x87, 0xaf, 0xaf),
503 (0x87, 0xaf, 0xd7),
504 (0x87, 0xaf, 0xff),
505 (0x87, 0xd7, 0x00),
506 (0x87, 0xd7, 0x5f),
507 (0x87, 0xd7, 0x87),
508 (0x87, 0xd7, 0xaf),
509 (0x87, 0xd7, 0xd7),
510 (0x87, 0xd7, 0xff),
511 (0x87, 0xff, 0x00),
512 (0x87, 0xff, 0x5f),
513 (0x87, 0xff, 0x87),
514 (0x87, 0xff, 0xaf),
515 (0x87, 0xff, 0xd7),
516 (0x87, 0xff, 0xff),
517 (0xaf, 0x00, 0x00),
518 (0xaf, 0x00, 0x5f),
519 (0xaf, 0x00, 0x87),
520 (0xaf, 0x00, 0xaf),
521 (0xaf, 0x00, 0xd7),
522 (0xaf, 0x00, 0xff),
523 (0xaf, 0x5f, 0x00),
524 (0xaf, 0x5f, 0x5f),
525 (0xaf, 0x5f, 0x87),
526 (0xaf, 0x5f, 0xaf),
527 (0xaf, 0x5f, 0xd7),
528 (0xaf, 0x5f, 0xff),
529 (0xaf, 0x87, 0x00),
530 (0xaf, 0x87, 0x5f),
531 (0xaf, 0x87, 0x87),
532 (0xaf, 0x87, 0xaf),
533 (0xaf, 0x87, 0xd7),
534 (0xaf, 0x87, 0xff),
535 (0xaf, 0xaf, 0x00),
536 (0xaf, 0xaf, 0x5f),
537 (0xaf, 0xaf, 0x87),
538 (0xaf, 0xaf, 0xaf),
539 (0xaf, 0xaf, 0xd7),
540 (0xaf, 0xaf, 0xff),
541 (0xaf, 0xd7, 0x00),
542 (0xaf, 0xd7, 0x5f),
543 (0xaf, 0xd7, 0x87),
544 (0xaf, 0xd7, 0xaf),
545 (0xaf, 0xd7, 0xd7),
546 (0xaf, 0xd7, 0xff),
547 (0xaf, 0xff, 0x00),
548 (0xaf, 0xff, 0x5f),
549 (0xaf, 0xff, 0x87),
550 (0xaf, 0xff, 0xaf),
551 (0xaf, 0xff, 0xd7),
552 (0xaf, 0xff, 0xff),
553 (0xd7, 0x00, 0x00),
554 (0xd7, 0x00, 0x5f),
555 (0xd7, 0x00, 0x87),
556 (0xd7, 0x00, 0xaf),
557 (0xd7, 0x00, 0xd7),
558 (0xd7, 0x00, 0xff),
559 (0xd7, 0x5f, 0x00),
560 (0xd7, 0x5f, 0x5f),
561 (0xd7, 0x5f, 0x87),
562 (0xd7, 0x5f, 0xaf),
563 (0xd7, 0x5f, 0xd7),
564 (0xd7, 0x5f, 0xff),
565 (0xd7, 0x87, 0x00),
566 (0xd7, 0x87, 0x5f),
567 (0xd7, 0x87, 0x87),
568 (0xd7, 0x87, 0xaf),
569 (0xd7, 0x87, 0xd7),
570 (0xd7, 0x87, 0xff),
571 (0xd7, 0xaf, 0x00),
572 (0xd7, 0xaf, 0x5f),
573 (0xd7, 0xaf, 0x87),
574 (0xd7, 0xaf, 0xaf),
575 (0xd7, 0xaf, 0xd7),
576 (0xd7, 0xaf, 0xff),
577 (0xd7, 0xd7, 0x00),
578 (0xd7, 0xd7, 0x5f),
579 (0xd7, 0xd7, 0x87),
580 (0xd7, 0xd7, 0xaf),
581 (0xd7, 0xd7, 0xd7),
582 (0xd7, 0xd7, 0xff),
583 (0xd7, 0xff, 0x00),
584 (0xd7, 0xff, 0x5f),
585 (0xd7, 0xff, 0x87),
586 (0xd7, 0xff, 0xaf),
587 (0xd7, 0xff, 0xd7),
588 (0xd7, 0xff, 0xff),
589 (0xff, 0x00, 0x00),
590 (0xff, 0x00, 0x5f),
591 (0xff, 0x00, 0x87),
592 (0xff, 0x00, 0xaf),
593 (0xff, 0x00, 0xd7),
594 (0xff, 0x00, 0xff),
595 (0xff, 0x5f, 0x00),
596 (0xff, 0x5f, 0x5f),
597 (0xff, 0x5f, 0x87),
598 (0xff, 0x5f, 0xaf),
599 (0xff, 0x5f, 0xd7),
600 (0xff, 0x5f, 0xff),
601 (0xff, 0x87, 0x00),
602 (0xff, 0x87, 0x5f),
603 (0xff, 0x87, 0x87),
604 (0xff, 0x87, 0xaf),
605 (0xff, 0x87, 0xd7),
606 (0xff, 0x87, 0xff),
607 (0xff, 0xaf, 0x00),
608 (0xff, 0xaf, 0x5f),
609 (0xff, 0xaf, 0x87),
610 (0xff, 0xaf, 0xaf),
611 (0xff, 0xaf, 0xd7),
612 (0xff, 0xaf, 0xff),
613 (0xff, 0xd7, 0x00),
614 (0xff, 0xd7, 0x5f),
615 (0xff, 0xd7, 0x87),
616 (0xff, 0xd7, 0xaf),
617 (0xff, 0xd7, 0xd7),
618 (0xff, 0xd7, 0xff),
619 (0xff, 0xff, 0x00),
620 (0xff, 0xff, 0x5f),
621 (0xff, 0xff, 0x87),
622 (0xff, 0xff, 0xaf),
623 (0xff, 0xff, 0xd7),
624 (0xff, 0xff, 0xff),
625 (0x08, 0x08, 0x08),
626 (0x12, 0x12, 0x12),
627 (0x1c, 0x1c, 0x1c),
628 (0x26, 0x26, 0x26),
629 (0x30, 0x30, 0x30),
630 (0x3a, 0x3a, 0x3a),
631 (0x44, 0x44, 0x44),
632 (0x4e, 0x4e, 0x4e),
633 (0x58, 0x58, 0x58),
634 (0x62, 0x62, 0x62),
635 (0x6c, 0x6c, 0x6c),
636 (0x76, 0x76, 0x76),
637 (0x80, 0x80, 0x80),
638 (0x8a, 0x8a, 0x8a),
639 (0x94, 0x94, 0x94),
640 (0x9e, 0x9e, 0x9e),
641 (0xa8, 0xa8, 0xa8),
642 (0xb2, 0xb2, 0xb2),
643 (0xbc, 0xbc, 0xbc),
644 (0xc6, 0xc6, 0xc6),
645 (0xd0, 0xd0, 0xd0),
646 (0xda, 0xda, 0xda),
647 (0xe4, 0xe4, 0xe4),
648 (0xee, 0xee, 0xee),
649 ];
650 VGA256[i as usize]
651 }
652 Color::Reset => (0, 0, 0),
653 }
654 }
655}