use super::core::Gradient;
use super::types::GradientDirection;
use crate::style::Color;
#[derive(Clone, Debug)]
pub struct LinearGradient {
pub gradient: Gradient,
pub direction: GradientDirection,
}
impl LinearGradient {
pub fn new(gradient: Gradient, direction: GradientDirection) -> Self {
Self {
gradient,
direction,
}
}
pub fn horizontal(from: Color, to: Color) -> Self {
Self::new(Gradient::linear(from, to), GradientDirection::ToRight)
}
pub fn vertical(from: Color, to: Color) -> Self {
Self::new(Gradient::linear(from, to), GradientDirection::ToBottom)
}
pub fn diagonal(from: Color, to: Color) -> Self {
Self::new(Gradient::linear(from, to), GradientDirection::ToBottomRight)
}
pub fn at(&self, x: usize, y: usize, width: usize, height: usize) -> Color {
if width == 0 || height == 0 {
return self.gradient.at(0.0);
}
let nx = if width > 1 {
x as f32 / (width - 1) as f32
} else {
0.5
};
let ny = if height > 1 {
y as f32 / (height - 1) as f32
} else {
0.5
};
let t = match self.direction {
GradientDirection::ToRight => nx,
GradientDirection::ToLeft => 1.0 - nx,
GradientDirection::ToBottom => ny,
GradientDirection::ToTop => 1.0 - ny,
GradientDirection::ToBottomRight => (nx + ny) / 2.0,
GradientDirection::ToTopRight => (nx + (1.0 - ny)) / 2.0,
GradientDirection::Angle(deg) => {
let rad = deg.to_radians();
let cos = rad.cos();
let sin = rad.sin();
((nx - 0.5) * cos + (ny - 0.5) * sin + 0.5).clamp(0.0, 1.0)
}
};
self.gradient.at(t)
}
pub fn colors_2d(&self, width: usize, height: usize) -> Vec<Vec<Color>> {
(0..height)
.map(|y| (0..width).map(|x| self.at(x, y, width, height)).collect())
.collect()
}
}