| use crate::{rgb::Rgb, Color}; |
| |
| /// Linear color gradient between two color stops |
| #[derive(Debug, Clone, Copy, PartialEq, Eq)] |
| pub struct Gradient { |
| /// Start Color of Gradient |
| pub start: Rgb, |
| |
| /// End Color of Gradient |
| pub end: Rgb, |
| } |
| |
| impl Gradient { |
| /// Creates a new [Gradient] with two [Rgb] colors, `start` and `end` |
| #[inline] |
| pub const fn new(start: Rgb, end: Rgb) -> Self { |
| Self { start, end } |
| } |
| pub const fn from_color_rgb(start: Color, end: Color) -> Self { |
| let start_grad = match start { |
| Color::Rgb(r, g, b) => Rgb { r, g, b }, |
| _ => Rgb { r: 0, g: 0, b: 0 }, |
| }; |
| let end_grad = match end { |
| Color::Rgb(r, g, b) => Rgb { r, g, b }, |
| _ => Rgb { r: 0, g: 0, b: 0 }, |
| }; |
| |
| Self { |
| start: start_grad, |
| end: end_grad, |
| } |
| } |
| |
| /// Computes the [Rgb] color between `start` and `end` for `t` |
| pub fn at(&self, t: f32) -> Rgb { |
| self.start.lerp(self.end, t) |
| } |
| |
| /// Returns the reverse of `self` |
| #[inline] |
| pub const fn reverse(&self) -> Self { |
| Self::new(self.end, self.start) |
| } |
| |
| #[allow(dead_code)] |
| pub fn build(&self, text: &str, target: TargetGround) -> String { |
| let delta = 1.0 / text.len() as f32; |
| let mut result = text.char_indices().fold(String::new(), |mut acc, (i, c)| { |
| let temp = format!( |
| "\x1B[{}m{}", |
| self.at(i as f32 * delta).ansi_color_code(target), |
| c |
| ); |
| acc.push_str(&temp); |
| acc |
| }); |
| |
| result.push_str("\x1B[0m"); |
| result |
| } |
| } |
| |
| #[allow(dead_code)] |
| pub fn build_all_gradient_text(text: &str, foreground: Gradient, background: Gradient) -> String { |
| let delta = 1.0 / text.len() as f32; |
| let mut result = text.char_indices().fold(String::new(), |mut acc, (i, c)| { |
| let step = i as f32 * delta; |
| let temp = format!( |
| "\x1B[{};{}m{}", |
| foreground |
| .at(step) |
| .ansi_color_code(TargetGround::Foreground), |
| background |
| .at(step) |
| .ansi_color_code(TargetGround::Background), |
| c |
| ); |
| acc.push_str(&temp); |
| acc |
| }); |
| |
| result.push_str("\x1B[0m"); |
| result |
| } |
| |
| #[derive(Debug, Clone, Copy, PartialEq, Eq)] |
| pub enum TargetGround { |
| Foreground, |
| Background, |
| } |
| |
| impl TargetGround { |
| #[inline] |
| pub const fn code(&self) -> u8 { |
| match self { |
| Self::Foreground => 30, |
| Self::Background => 40, |
| } |
| } |
| } |
| |
| pub trait ANSIColorCode { |
| fn ansi_color_code(&self, target: TargetGround) -> String; |
| } |