Add basic support for radial gradients (#639)

* Add SVG string generator for radial gradients

* Add the UI for the linear vs radial radio inputs

* Initial radial gradient support for gradient tool

* Enabled click and drag support for radial gradients

* Refactor code for gradient in properties panel

* Added gradient type to gradient struct

* Finish refactor to use gradient_type instead of fill

* Fix lint issue

* Combine LinearGradient and RadialGradient in Fill enum

* Add label to properties panel and fix bug

Co-authored-by: Robert Nadal <Robnadal44@gmail.com>
Co-authored-by: Oliver Davies <oliver@psyfer.io>
This commit is contained in:
Hannah Li
2022-05-23 17:00:53 -07:00
committed by Keavon Chambers
co-authored by Robert Nadal Oliver Davies
parent ef53577b20
commit dd002355fa
3 changed files with 201 additions and 107 deletions
+38 -11
View File
@@ -36,6 +36,18 @@ impl Default for ViewMode {
}
}
#[derive(PartialEq, Clone, Copy, Debug, Hash, Serialize, Deserialize)]
pub enum GradientType {
Linear,
Radial,
}
impl Default for GradientType {
fn default() -> Self {
GradientType::Linear
}
}
/// A gradient fill.
///
/// Contains the start and end points, along with the colors at varying points along the length.
@@ -47,16 +59,19 @@ pub struct Gradient {
pub transform: DAffine2,
pub positions: Vec<(f64, Option<Color>)>,
uuid: u64,
pub gradient_type: GradientType,
}
impl Gradient {
/// Constructs a new gradient with the colors at 0 and 1 specified.
pub fn new(start: DVec2, start_color: Color, end: DVec2, end_color: Color, transform: DAffine2, uuid: u64) -> Self {
pub fn new(start: DVec2, start_color: Color, end: DVec2, end_color: Color, transform: DAffine2, uuid: u64, gradient_type: GradientType) -> Self {
Gradient {
start,
end,
positions: vec![(0., Some(start_color)), (1., Some(end_color))],
transform,
uuid,
gradient_type,
}
}
@@ -86,23 +101,35 @@ impl Gradient {
.map(|(i, entry)| entry.to_string() + if i == 5 { "" } else { "," })
.collect::<String>();
let _ = write!(
svg_defs,
r#"<linearGradient id="{}" x1="{}" x2="{}" y1="{}" y2="{}" gradientTransform="matrix({})">{}</linearGradient>"#,
self.uuid, start.x, end.x, start.y, end.y, transform, positions
);
match self.gradient_type {
GradientType::Linear => {
let _ = write!(
svg_defs,
r#"<linearGradient id="{}" x1="{}" x2="{}" y1="{}" y2="{}" gradientTransform="matrix({})">{}</linearGradient>"#,
self.uuid, start.x, end.x, start.y, end.y, transform, positions
);
}
GradientType::Radial => {
let radius = (f64::powi(start.x - end.x, 2) + f64::powi(start.y - end.y, 2)).sqrt();
let _ = write!(
svg_defs,
r#"<radialGradient id="{}" cx="{}" cy="{}" r="{}" gradientTransform="matrix({})">{}</radialGradient>"#,
self.uuid, start.x, start.y, radius, transform, positions
);
}
}
}
}
/// Describes the fill of a layer.
///
/// Can be None, a solid [Color], a linear [Gradient], or potentially some sort of image or pattern in the future
/// Can be None, a solid [Color], a linear [Gradient], a radial [Gradient] or potentially some sort of image or pattern in the future
#[repr(C)]
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum Fill {
None,
Solid(Color),
LinearGradient(Gradient),
Gradient(Gradient),
}
impl Default for Fill {
@@ -117,13 +144,13 @@ impl Fill {
Self::Solid(color)
}
/// Evaluate the color at some point on the fill. Doesn't currently work for LinearGradient.
/// Evaluate the color at some point on the fill. Doesn't currently work for Gradient.
pub fn color(&self) -> Color {
match self {
Self::None => Color::BLACK,
Self::Solid(color) => *color,
// TODO: Should correctly sample the gradient
Self::LinearGradient(Gradient { positions, .. }) => positions[0].1.unwrap_or(Color::BLACK),
Self::Gradient(Gradient { positions, .. }) => positions[0].1.unwrap_or(Color::BLACK),
}
}
@@ -132,7 +159,7 @@ impl Fill {
match self {
Self::None => r#" fill="none""#.to_string(),
Self::Solid(color) => format!(r##" fill="#{}"{}"##, color.rgb_hex(), format_opacity("fill", color.a())),
Self::LinearGradient(gradient) => {
Self::Gradient(gradient) => {
gradient.render_defs(svg_defs, multiplied_transform, bounds, transformed_bounds);
format!(r##" fill="url('#{}')""##, gradient.uuid)
}