fm/config/
gradient.rs

1use anyhow::{anyhow, Result};
2use ratatui::style::Color;
3
4use crate::config::{ColorG, MAX_GRADIENT_NORMAL};
5
6/// A gradient between 2 colors with a number of steps.
7/// Colors are calculated on the fly with the `step` method.
8/// An array can be built with `as_array` since the number of steps
9/// is known at compile time.
10/// We can't hard code the whold gradient since we don't know what
11/// colors the user want to use for start and end.
12#[derive(Debug, Clone, Copy)]
13pub struct Gradient {
14    start: ColorG,
15    end: ColorG,
16    step_ratio: f32,
17    len: usize,
18}
19
20impl Gradient {
21    pub fn new(start: ColorG, end: ColorG, len: usize) -> Self {
22        let step_ratio = 1_f32 / len as f32;
23        Self {
24            start,
25            end,
26            step_ratio,
27            len,
28        }
29    }
30
31    fn step(&self, step: usize) -> ColorG {
32        let position = self.step_ratio * step as f32;
33
34        let r = self.start.r as f32 + (self.end.r as f32 - self.start.r as f32) * position;
35        let g = self.start.g as f32 + (self.end.g as f32 - self.start.g as f32) * position;
36        let b = self.start.b as f32 + (self.end.b as f32 - self.start.b as f32) * position;
37
38        ColorG {
39            r: r.round() as u8,
40            g: g.round() as u8,
41            b: b.round() as u8,
42        }
43    }
44
45    pub fn as_array(&self) -> Result<[Color; MAX_GRADIENT_NORMAL]> {
46        self.gradient()
47            .collect::<Vec<Color>>()
48            .try_into()
49            .map_err(|_| anyhow!("Couldn't create an array for gradient"))
50    }
51
52    pub fn gradient(&self) -> impl Iterator<Item = Color> + '_ {
53        (0..self.len).map(|step| self.step(step).as_ratatui())
54    }
55}