| 1 | use crate::{rgb::Rgb, Color}; |
| 2 | |
| 3 | /// Linear color gradient between two color stops |
| 4 | #[derive (Debug, Clone, Copy, PartialEq, Eq)] |
| 5 | pub struct Gradient { |
| 6 | /// Start Color of Gradient |
| 7 | pub start: Rgb, |
| 8 | |
| 9 | /// End Color of Gradient |
| 10 | pub end: Rgb, |
| 11 | } |
| 12 | |
| 13 | impl Gradient { |
| 14 | /// Creates a new [Gradient] with two [Rgb] colors, `start` and `end` |
| 15 | #[inline ] |
| 16 | pub const fn new(start: Rgb, end: Rgb) -> Self { |
| 17 | Self { start, end } |
| 18 | } |
| 19 | pub const fn from_color_rgb(start: Color, end: Color) -> Self { |
| 20 | let start_grad = match start { |
| 21 | Color::Rgb(r, g, b) => Rgb { r, g, b }, |
| 22 | _ => Rgb { r: 0, g: 0, b: 0 }, |
| 23 | }; |
| 24 | let end_grad = match end { |
| 25 | Color::Rgb(r, g, b) => Rgb { r, g, b }, |
| 26 | _ => Rgb { r: 0, g: 0, b: 0 }, |
| 27 | }; |
| 28 | |
| 29 | Self { |
| 30 | start: start_grad, |
| 31 | end: end_grad, |
| 32 | } |
| 33 | } |
| 34 | |
| 35 | /// Computes the [Rgb] color between `start` and `end` for `t` |
| 36 | pub fn at(&self, t: f32) -> Rgb { |
| 37 | self.start.lerp(self.end, t) |
| 38 | } |
| 39 | |
| 40 | /// Returns the reverse of `self` |
| 41 | #[inline ] |
| 42 | pub const fn reverse(&self) -> Self { |
| 43 | Self::new(self.end, self.start) |
| 44 | } |
| 45 | |
| 46 | #[allow (dead_code)] |
| 47 | pub fn build(&self, text: &str, target: TargetGround) -> String { |
| 48 | let delta = 1.0 / text.len() as f32; |
| 49 | let mut result = text.char_indices().fold(String::new(), |mut acc, (i, c)| { |
| 50 | let temp = format!( |
| 51 | " \x1B[ {}m {}" , |
| 52 | self.at(i as f32 * delta).ansi_color_code(target), |
| 53 | c |
| 54 | ); |
| 55 | acc.push_str(&temp); |
| 56 | acc |
| 57 | }); |
| 58 | |
| 59 | result.push_str(" \x1B[0m" ); |
| 60 | result |
| 61 | } |
| 62 | } |
| 63 | |
| 64 | #[allow (dead_code)] |
| 65 | pub fn build_all_gradient_text(text: &str, foreground: Gradient, background: Gradient) -> String { |
| 66 | let delta: f32 = 1.0 / text.len() as f32; |
| 67 | let mut result: String = text.char_indices().fold(init:String::new(), |mut acc: String, (i: usize, c: char)| { |
| 68 | let step: f32 = i as f32 * delta; |
| 69 | let temp: String = format!( |
| 70 | " \x1B[ {}; {}m {}" , |
| 71 | foreground |
| 72 | .at(step) |
| 73 | .ansi_color_code(TargetGround::Foreground), |
| 74 | background |
| 75 | .at(step) |
| 76 | .ansi_color_code(TargetGround::Background), |
| 77 | c |
| 78 | ); |
| 79 | acc.push_str(&temp); |
| 80 | acc |
| 81 | }); |
| 82 | |
| 83 | result.push_str(string:" \x1B[0m" ); |
| 84 | result |
| 85 | } |
| 86 | |
| 87 | #[derive (Debug, Clone, Copy, PartialEq, Eq)] |
| 88 | pub enum TargetGround { |
| 89 | Foreground, |
| 90 | Background, |
| 91 | } |
| 92 | |
| 93 | impl TargetGround { |
| 94 | #[inline ] |
| 95 | pub const fn code(&self) -> u8 { |
| 96 | match self { |
| 97 | Self::Foreground => 30, |
| 98 | Self::Background => 40, |
| 99 | } |
| 100 | } |
| 101 | } |
| 102 | |
| 103 | pub trait ANSIColorCode { |
| 104 | fn ansi_color_code(&self, target: TargetGround) -> String; |
| 105 | } |
| 106 | |