1use ratatui_core::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
39#[derive(Debug)]
41pub enum TextColorRating {
42 Light,
44 Dark,
46}
47
48#[derive(Debug)]
50pub enum Contrast {
51 High,
52 Normal,
53}
54
55impl Palette {
56 pub const BRIGHT_0: usize = 0;
59 pub const BRIGHT_1: usize = 1;
62 pub const BRIGHT_2: usize = 2;
65 pub const BRIGHT_3: usize = 3;
68 pub const DARK_0: usize = 4;
71 pub const DARK_1: usize = 5;
74 pub const DARK_2: usize = 6;
77 pub const DARK_3: usize = 7;
80
81 pub fn white(&self, n: usize, contrast: Contrast) -> Style {
84 self.style(self.white[n], contrast)
85 }
86
87 pub fn black(&self, n: usize, contrast: Contrast) -> Style {
90 self.style(self.black[n], contrast)
91 }
92
93 pub fn gray(&self, n: usize, contrast: Contrast) -> Style {
96 self.style(self.gray[n], contrast)
97 }
98
99 pub fn red(&self, n: usize, contrast: Contrast) -> Style {
102 self.style(self.red[n], contrast)
103 }
104
105 pub fn orange(&self, n: usize, contrast: Contrast) -> Style {
108 self.style(self.orange[n], contrast)
109 }
110
111 pub fn yellow(&self, n: usize, contrast: Contrast) -> Style {
114 self.style(self.yellow[n], contrast)
115 }
116
117 pub fn limegreen(&self, n: usize, contrast: Contrast) -> Style {
120 self.style(self.limegreen[n], contrast)
121 }
122
123 pub fn green(&self, n: usize, contrast: Contrast) -> Style {
126 self.style(self.green[n], contrast)
127 }
128
129 pub fn bluegreen(&self, n: usize, contrast: Contrast) -> Style {
132 self.style(self.bluegreen[n], contrast)
133 }
134
135 pub fn cyan(&self, n: usize, contrast: Contrast) -> Style {
138 self.style(self.cyan[n], contrast)
139 }
140
141 pub fn blue(&self, n: usize, contrast: Contrast) -> Style {
144 self.style(self.blue[n], contrast)
145 }
146
147 pub fn deepblue(&self, n: usize, contrast: Contrast) -> Style {
150 self.style(self.deepblue[n], contrast)
151 }
152
153 pub fn purple(&self, n: usize, contrast: Contrast) -> Style {
156 self.style(self.purple[n], contrast)
157 }
158
159 pub fn magenta(&self, n: usize, contrast: Contrast) -> Style {
162 self.style(self.magenta[n], contrast)
163 }
164
165 pub fn redpink(&self, n: usize, contrast: Contrast) -> Style {
168 self.style(self.redpink[n], contrast)
169 }
170
171 pub fn primary(&self, n: usize, contrast: Contrast) -> Style {
174 self.style(self.primary[n], contrast)
175 }
176
177 pub fn secondary(&self, n: usize, contrast: Contrast) -> Style {
180 self.style(self.secondary[n], contrast)
181 }
182}
183
184impl Palette {
185 pub fn style(&self, color: Color, contrast: Contrast) -> Style {
188 match contrast {
189 Contrast::High => self.high_contrast(color),
190 Contrast::Normal => self.normal_contrast(color),
191 }
192 }
193
194 pub fn high_contrast(&self, color: Color) -> Style {
198 match Self::rate_text_color(color) {
199 None => Style::reset(),
200 Some(TextColorRating::Light) => Style::new().bg(color).fg(self.white[3]),
201 Some(TextColorRating::Dark) => Style::new().bg(color).fg(self.black[0]),
202 }
203 }
204
205 pub fn normal_contrast(&self, color: Color) -> Style {
209 match Self::rate_text_color(color) {
210 None => Style::reset(),
211 Some(TextColorRating::Light) => Style::new().bg(color).fg(self.white[0]),
212 Some(TextColorRating::Dark) => Style::new().bg(color).fg(self.black[3]),
213 }
214 }
215
216 pub const fn rate_text_color(color: Color) -> Option<TextColorRating> {
227 match color {
228 Color::Reset => None,
229 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) => {
246 let grey = r as f32 * 0.2126f32 + g as f32 * 0.7152f32 + b as f32 * 0.0722f32;
252 if grey >= 105f32 {
253 Some(TextColorRating::Dark)
254 } else {
255 Some(TextColorRating::Light)
256 }
257 }
258 Color::Indexed(n) => match n {
259 0..=6 => Some(TextColorRating::Light),
260 7 => Some(TextColorRating::Dark),
261 8 => Some(TextColorRating::Light),
262 9..=11 => Some(TextColorRating::Dark),
263 12 => Some(TextColorRating::Light),
264 13..=15 => Some(TextColorRating::Dark),
265 v @ 16..=231 => {
266 if (v - 16) % 36 < 18 {
267 Some(TextColorRating::Light)
268 } else {
269 Some(TextColorRating::Dark)
270 }
271 }
272 v @ 232..=255 => {
273 if (v - 232) % 24 < 12 {
274 Some(TextColorRating::Light)
275 } else {
276 Some(TextColorRating::Dark)
277 }
278 }
279 },
280 }
281 }
282
283 pub const fn darken(color: Color, scale_to: u8) -> Color {
289 let (r, g, b) = Self::color2rgb(color);
290 Color::Rgb(
291 Self::scale_to(r, scale_to),
292 Self::scale_to(g, scale_to),
293 Self::scale_to(b, scale_to),
294 )
295 }
296
297 pub const fn grayscale(color: Color) -> Color {
299 let (r, g, b) = Self::color2rgb(color);
300 let gray = r as f32 * 0.3f32 + g as f32 * 0.59f32 + b as f32 * 0.11f32;
302 Color::Rgb(gray as u8, gray as u8, gray as u8)
303 }
304
305 pub const fn interpolate(c0: u32, c1: u32, dark_scale_to: u8) -> [Color; 8] {
309 const fn i1(a: u8, b: u8) -> u8 {
311 if a < b {
312 a + (b - a) / 3
313 } else {
314 a - (a - b) / 3
315 }
316 }
317 const fn i2(a: u8, b: u8) -> u8 {
319 if a < b {
320 b - (b - a) / 3
321 } else {
322 b + (a - b) / 3
323 }
324 }
325
326 let r0 = (c0 >> 16) as u8;
327 let g0 = (c0 >> 8) as u8;
328 let b0 = c0 as u8;
329
330 let r3 = (c1 >> 16) as u8;
331 let g3 = (c1 >> 8) as u8;
332 let b3 = c1 as u8;
333
334 let r1 = i1(r0, r3);
335 let g1 = i1(g0, g3);
336 let b1 = i1(b0, b3);
337
338 let r2 = i2(r0, r3);
339 let g2 = i2(g0, g3);
340 let b2 = i2(b0, b3);
341
342 let r4 = Self::scale_to(r0, dark_scale_to);
344 let g4 = Self::scale_to(g0, dark_scale_to);
345 let b4 = Self::scale_to(b0, dark_scale_to);
346
347 let r5 = Self::scale_to(r1, dark_scale_to);
348 let g5 = Self::scale_to(g1, dark_scale_to);
349 let b5 = Self::scale_to(b1, dark_scale_to);
350
351 let r6 = Self::scale_to(r2, dark_scale_to);
352 let g6 = Self::scale_to(g2, dark_scale_to);
353 let b6 = Self::scale_to(b2, dark_scale_to);
354
355 let r7 = Self::scale_to(r3, dark_scale_to);
356 let g7 = Self::scale_to(g3, dark_scale_to);
357 let b7 = Self::scale_to(b3, dark_scale_to);
358
359 [
360 Color::Rgb(r0, g0, b0),
361 Color::Rgb(r1, g1, b1),
362 Color::Rgb(r2, g2, b2),
363 Color::Rgb(r3, g3, b3),
364 Color::Rgb(r4, g4, b4),
365 Color::Rgb(r5, g5, b5),
366 Color::Rgb(r6, g6, b6),
367 Color::Rgb(r7, g7, b7),
368 ]
369 }
370
371 pub const fn scale_to(v: u8, scale_to: u8) -> u8 {
373 (((v as u16) * scale_to as u16) / 255u16) as u8
374 }
375
376 pub const fn color2rgb(color: Color) -> (u8, u8, u8) {
379 match color {
380 Color::Black => (0x00, 0x00, 0x00),
381 Color::Red => (0xaa, 0x00, 0x00),
382 Color::Green => (0x00, 0xaa, 0x00),
383 Color::Yellow => (0xaa, 0x55, 0x00),
384 Color::Blue => (0x00, 0x00, 0xaa),
385 Color::Magenta => (0xaa, 0x00, 0xaa),
386 Color::Cyan => (0x00, 0xaa, 0xaa),
387 Color::Gray => (0xaa, 0xaa, 0xaa),
388 Color::DarkGray => (0x55, 0x55, 0x55),
389 Color::LightRed => (0xff, 0x55, 0x55),
390 Color::LightGreen => (0x55, 0xff, 0x55),
391 Color::LightYellow => (0xff, 0xff, 0x55),
392 Color::LightBlue => (0x55, 0x55, 0xff),
393 Color::LightMagenta => (0xff, 0x55, 0xff),
394 Color::LightCyan => (0x55, 0xff, 0xff),
395 Color::White => (0xff, 0xff, 0xff),
396 Color::Rgb(r, g, b) => (r, g, b),
397 Color::Indexed(i) => {
398 const VGA256: [(u8, u8, u8); 256] = [
399 (0x00, 0x00, 0x00),
400 (0x80, 0x00, 0x00),
401 (0x00, 0x80, 0x00),
402 (0x80, 0x80, 0x00),
403 (0x00, 0x00, 0x80),
404 (0x80, 0x00, 0x80),
405 (0x00, 0x80, 0x80),
406 (0xc0, 0xc0, 0xc0),
407 (0x80, 0x80, 0x80),
408 (0xff, 0x00, 0x00),
409 (0x00, 0xff, 0x00),
410 (0xff, 0xff, 0x00),
411 (0x00, 0x00, 0xff),
412 (0xff, 0x00, 0xff),
413 (0x00, 0xff, 0xff),
414 (0xff, 0xff, 0xff),
415 (0x00, 0x00, 0x00),
416 (0x00, 0x00, 0x5f),
417 (0x00, 0x00, 0x87),
418 (0x00, 0x00, 0xaf),
419 (0x00, 0x00, 0xd7),
420 (0x00, 0x00, 0xff),
421 (0x00, 0x5f, 0x00),
422 (0x00, 0x5f, 0x5f),
423 (0x00, 0x5f, 0x87),
424 (0x00, 0x5f, 0xaf),
425 (0x00, 0x5f, 0xd7),
426 (0x00, 0x5f, 0xff),
427 (0x00, 0x87, 0x00),
428 (0x00, 0x87, 0x5f),
429 (0x00, 0x87, 0x87),
430 (0x00, 0x87, 0xaf),
431 (0x00, 0x87, 0xd7),
432 (0x00, 0x87, 0xff),
433 (0x00, 0xaf, 0x00),
434 (0x00, 0xaf, 0x5f),
435 (0x00, 0xaf, 0x87),
436 (0x00, 0xaf, 0xaf),
437 (0x00, 0xaf, 0xd7),
438 (0x00, 0xaf, 0xff),
439 (0x00, 0xd7, 0x00),
440 (0x00, 0xd7, 0x5f),
441 (0x00, 0xd7, 0x87),
442 (0x00, 0xd7, 0xaf),
443 (0x00, 0xd7, 0xd7),
444 (0x00, 0xd7, 0xff),
445 (0x00, 0xff, 0x00),
446 (0x00, 0xff, 0x5f),
447 (0x00, 0xff, 0x87),
448 (0x00, 0xff, 0xaf),
449 (0x00, 0xff, 0xd7),
450 (0x00, 0xff, 0xff),
451 (0x5f, 0x00, 0x00),
452 (0x5f, 0x00, 0x5f),
453 (0x5f, 0x00, 0x87),
454 (0x5f, 0x00, 0xaf),
455 (0x5f, 0x00, 0xd7),
456 (0x5f, 0x00, 0xff),
457 (0x5f, 0x5f, 0x00),
458 (0x5f, 0x5f, 0x5f),
459 (0x5f, 0x5f, 0x87),
460 (0x5f, 0x5f, 0xaf),
461 (0x5f, 0x5f, 0xd7),
462 (0x5f, 0x5f, 0xff),
463 (0x5f, 0x87, 0x00),
464 (0x5f, 0x87, 0x5f),
465 (0x5f, 0x87, 0x87),
466 (0x5f, 0x87, 0xaf),
467 (0x5f, 0x87, 0xd7),
468 (0x5f, 0x87, 0xff),
469 (0x5f, 0xaf, 0x00),
470 (0x5f, 0xaf, 0x5f),
471 (0x5f, 0xaf, 0x87),
472 (0x5f, 0xaf, 0xaf),
473 (0x5f, 0xaf, 0xd7),
474 (0x5f, 0xaf, 0xff),
475 (0x5f, 0xd7, 0x00),
476 (0x5f, 0xd7, 0x5f),
477 (0x5f, 0xd7, 0x87),
478 (0x5f, 0xd7, 0xaf),
479 (0x5f, 0xd7, 0xd7),
480 (0x5f, 0xd7, 0xff),
481 (0x5f, 0xff, 0x00),
482 (0x5f, 0xff, 0x5f),
483 (0x5f, 0xff, 0x87),
484 (0x5f, 0xff, 0xaf),
485 (0x5f, 0xff, 0xd7),
486 (0x5f, 0xff, 0xff),
487 (0x87, 0x00, 0x00),
488 (0x87, 0x00, 0x5f),
489 (0x87, 0x00, 0x87),
490 (0x87, 0x00, 0xaf),
491 (0x87, 0x00, 0xd7),
492 (0x87, 0x00, 0xff),
493 (0x87, 0x5f, 0x00),
494 (0x87, 0x5f, 0x5f),
495 (0x87, 0x5f, 0x87),
496 (0x87, 0x5f, 0xaf),
497 (0x87, 0x5f, 0xd7),
498 (0x87, 0x5f, 0xff),
499 (0x87, 0x87, 0x00),
500 (0x87, 0x87, 0x5f),
501 (0x87, 0x87, 0x87),
502 (0x87, 0x87, 0xaf),
503 (0x87, 0x87, 0xd7),
504 (0x87, 0x87, 0xff),
505 (0x87, 0xaf, 0x00),
506 (0x87, 0xaf, 0x5f),
507 (0x87, 0xaf, 0x87),
508 (0x87, 0xaf, 0xaf),
509 (0x87, 0xaf, 0xd7),
510 (0x87, 0xaf, 0xff),
511 (0x87, 0xd7, 0x00),
512 (0x87, 0xd7, 0x5f),
513 (0x87, 0xd7, 0x87),
514 (0x87, 0xd7, 0xaf),
515 (0x87, 0xd7, 0xd7),
516 (0x87, 0xd7, 0xff),
517 (0x87, 0xff, 0x00),
518 (0x87, 0xff, 0x5f),
519 (0x87, 0xff, 0x87),
520 (0x87, 0xff, 0xaf),
521 (0x87, 0xff, 0xd7),
522 (0x87, 0xff, 0xff),
523 (0xaf, 0x00, 0x00),
524 (0xaf, 0x00, 0x5f),
525 (0xaf, 0x00, 0x87),
526 (0xaf, 0x00, 0xaf),
527 (0xaf, 0x00, 0xd7),
528 (0xaf, 0x00, 0xff),
529 (0xaf, 0x5f, 0x00),
530 (0xaf, 0x5f, 0x5f),
531 (0xaf, 0x5f, 0x87),
532 (0xaf, 0x5f, 0xaf),
533 (0xaf, 0x5f, 0xd7),
534 (0xaf, 0x5f, 0xff),
535 (0xaf, 0x87, 0x00),
536 (0xaf, 0x87, 0x5f),
537 (0xaf, 0x87, 0x87),
538 (0xaf, 0x87, 0xaf),
539 (0xaf, 0x87, 0xd7),
540 (0xaf, 0x87, 0xff),
541 (0xaf, 0xaf, 0x00),
542 (0xaf, 0xaf, 0x5f),
543 (0xaf, 0xaf, 0x87),
544 (0xaf, 0xaf, 0xaf),
545 (0xaf, 0xaf, 0xd7),
546 (0xaf, 0xaf, 0xff),
547 (0xaf, 0xd7, 0x00),
548 (0xaf, 0xd7, 0x5f),
549 (0xaf, 0xd7, 0x87),
550 (0xaf, 0xd7, 0xaf),
551 (0xaf, 0xd7, 0xd7),
552 (0xaf, 0xd7, 0xff),
553 (0xaf, 0xff, 0x00),
554 (0xaf, 0xff, 0x5f),
555 (0xaf, 0xff, 0x87),
556 (0xaf, 0xff, 0xaf),
557 (0xaf, 0xff, 0xd7),
558 (0xaf, 0xff, 0xff),
559 (0xd7, 0x00, 0x00),
560 (0xd7, 0x00, 0x5f),
561 (0xd7, 0x00, 0x87),
562 (0xd7, 0x00, 0xaf),
563 (0xd7, 0x00, 0xd7),
564 (0xd7, 0x00, 0xff),
565 (0xd7, 0x5f, 0x00),
566 (0xd7, 0x5f, 0x5f),
567 (0xd7, 0x5f, 0x87),
568 (0xd7, 0x5f, 0xaf),
569 (0xd7, 0x5f, 0xd7),
570 (0xd7, 0x5f, 0xff),
571 (0xd7, 0x87, 0x00),
572 (0xd7, 0x87, 0x5f),
573 (0xd7, 0x87, 0x87),
574 (0xd7, 0x87, 0xaf),
575 (0xd7, 0x87, 0xd7),
576 (0xd7, 0x87, 0xff),
577 (0xd7, 0xaf, 0x00),
578 (0xd7, 0xaf, 0x5f),
579 (0xd7, 0xaf, 0x87),
580 (0xd7, 0xaf, 0xaf),
581 (0xd7, 0xaf, 0xd7),
582 (0xd7, 0xaf, 0xff),
583 (0xd7, 0xd7, 0x00),
584 (0xd7, 0xd7, 0x5f),
585 (0xd7, 0xd7, 0x87),
586 (0xd7, 0xd7, 0xaf),
587 (0xd7, 0xd7, 0xd7),
588 (0xd7, 0xd7, 0xff),
589 (0xd7, 0xff, 0x00),
590 (0xd7, 0xff, 0x5f),
591 (0xd7, 0xff, 0x87),
592 (0xd7, 0xff, 0xaf),
593 (0xd7, 0xff, 0xd7),
594 (0xd7, 0xff, 0xff),
595 (0xff, 0x00, 0x00),
596 (0xff, 0x00, 0x5f),
597 (0xff, 0x00, 0x87),
598 (0xff, 0x00, 0xaf),
599 (0xff, 0x00, 0xd7),
600 (0xff, 0x00, 0xff),
601 (0xff, 0x5f, 0x00),
602 (0xff, 0x5f, 0x5f),
603 (0xff, 0x5f, 0x87),
604 (0xff, 0x5f, 0xaf),
605 (0xff, 0x5f, 0xd7),
606 (0xff, 0x5f, 0xff),
607 (0xff, 0x87, 0x00),
608 (0xff, 0x87, 0x5f),
609 (0xff, 0x87, 0x87),
610 (0xff, 0x87, 0xaf),
611 (0xff, 0x87, 0xd7),
612 (0xff, 0x87, 0xff),
613 (0xff, 0xaf, 0x00),
614 (0xff, 0xaf, 0x5f),
615 (0xff, 0xaf, 0x87),
616 (0xff, 0xaf, 0xaf),
617 (0xff, 0xaf, 0xd7),
618 (0xff, 0xaf, 0xff),
619 (0xff, 0xd7, 0x00),
620 (0xff, 0xd7, 0x5f),
621 (0xff, 0xd7, 0x87),
622 (0xff, 0xd7, 0xaf),
623 (0xff, 0xd7, 0xd7),
624 (0xff, 0xd7, 0xff),
625 (0xff, 0xff, 0x00),
626 (0xff, 0xff, 0x5f),
627 (0xff, 0xff, 0x87),
628 (0xff, 0xff, 0xaf),
629 (0xff, 0xff, 0xd7),
630 (0xff, 0xff, 0xff),
631 (0x08, 0x08, 0x08),
632 (0x12, 0x12, 0x12),
633 (0x1c, 0x1c, 0x1c),
634 (0x26, 0x26, 0x26),
635 (0x30, 0x30, 0x30),
636 (0x3a, 0x3a, 0x3a),
637 (0x44, 0x44, 0x44),
638 (0x4e, 0x4e, 0x4e),
639 (0x58, 0x58, 0x58),
640 (0x62, 0x62, 0x62),
641 (0x6c, 0x6c, 0x6c),
642 (0x76, 0x76, 0x76),
643 (0x80, 0x80, 0x80),
644 (0x8a, 0x8a, 0x8a),
645 (0x94, 0x94, 0x94),
646 (0x9e, 0x9e, 0x9e),
647 (0xa8, 0xa8, 0xa8),
648 (0xb2, 0xb2, 0xb2),
649 (0xbc, 0xbc, 0xbc),
650 (0xc6, 0xc6, 0xc6),
651 (0xd0, 0xd0, 0xd0),
652 (0xda, 0xda, 0xda),
653 (0xe4, 0xe4, 0xe4),
654 (0xee, 0xee, 0xee),
655 ];
656 VGA256[i as usize]
657 }
658 Color::Reset => (0, 0, 0),
659 }
660 }
661}