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