From 4bb6f329114869e3dac74372c0de6cd633eb0e61 Mon Sep 17 00:00:00 2001 From: Taha-Mahmoodi <85902429+Taha-Mahmoodi@users.noreply.github.com> Date: Thu, 22 Oct 2026 18:53:20 +0430 Subject: [PATCH] Gradients: built with Gradient::new, so a new option touches one place --- crates/color/src/gradient.rs | 13 ++++++---- crates/color/src/libraries.rs | 2 +- crates/color/src/palette_io.rs | 14 +++++------ crates/color/src/swatch.rs | 6 ++--- crates/doc/src/style_libs.rs | 2 +- crates/effects/src/bake.rs | 2 +- crates/effects/src/group.rs | 4 ++-- crates/effects/src/lighting.rs | 4 ++-- crates/effects/src/revolve.rs | 2 +- crates/effects/src/tests_solids.rs | 2 +- crates/engine/src/cmd/buildcmds.rs | 2 +- crates/engine/src/cmd/create.rs | 2 +- crates/engine/src/cmd/effectcmd.rs | 2 +- crates/engine/src/cmd/fileio/affinity.rs | 2 +- crates/engine/src/cmd/gradient.rs | 2 +- crates/engine/src/tests_build.rs | 2 +- crates/engine/src/tests_eyedropper.rs | 8 +++---- crates/engine/src/tests_gradient.rs | 8 +++---- crates/eps/src/import/ai/paint.rs | 2 +- crates/eps/src/import/graphics.rs | 2 +- crates/eps/src/tests.rs | 2 +- crates/eps/src/tests_legacy_ai.rs | 30 ++++++++++++------------ crates/pdf/src/import_shading.rs | 2 +- crates/pdf/src/tests_import_color.rs | 2 +- crates/pdf/src/tests_import_fidelity.rs | 2 +- crates/render/src/tests_cmykblend.rs | 2 +- crates/render/src/tests_objectfx.rs | 8 +++---- crates/render/tests/golden.rs | 2 +- crates/render/tests/gradient_alpha.rs | 2 +- crates/render/tests/stroke_geometry.rs | 2 +- crates/svg/src/import.rs | 2 +- crates/svg/src/import/spread.rs | 2 +- crates/svg/tests/gradients.rs | 5 +--- crates/tools/src/xform/gradient.rs | 4 ++-- crates/ui-egui/src/panels/swatches.rs | 2 +- 35 files changed, 76 insertions(+), 76 deletions(-) diff --git a/crates/color/src/gradient.rs b/crates/color/src/gradient.rs index 1c2b96c6e..c0b80ecef 100644 --- a/crates/color/src/gradient.rs +++ b/crates/color/src/gradient.rs @@ -80,11 +80,15 @@ pub struct Gradient { impl Default for Gradient { /// Illustrator's default "White, Black" gradient. fn default() -> Self { - Self { kind: GradientKind::Linear, stops: vec![GradientStop::new(0.0, Color::WHITE), GradientStop::new(1.0, Color::BLACK)] } + Self::new(GradientKind::Linear, vec![GradientStop::new(0.0, Color::WHITE), GradientStop::new(1.0, Color::BLACK)]) } } impl Gradient { + /// A gradient of `kind` through `stops`, with the default options. + pub fn new(kind: GradientKind, stops: Vec) -> Self { + Self { kind, stops } + } /// Colour and opacity at `t` (honours midpoints). pub fn sample(&self, t: f32) -> (Color, f32) { self.sample_with(t, Color::lerp) @@ -172,7 +176,7 @@ impl Gradient { ); } stops.push(stop(1.0, to)); - Gradient { kind: GradientKind::Linear, stops } + Gradient::new(GradientKind::Linear, stops) } } @@ -582,9 +586,8 @@ mod tests { #[test] fn reverse_mirrors_midpoints() { let stop = |offset, hex, midpoint| GradientStop { midpoint, ..GradientStop::new(offset, Color::from_hex(hex).unwrap()) }; - let two = Gradient { kind: GradientKind::Linear, stops: vec![stop(0.0, "#ff0000", 0.2), stop(1.0, "#0000ff", 0.5)] }; - let three = - Gradient { kind: GradientKind::Linear, stops: vec![stop(0.0, "#ff0000", 0.2), stop(0.3, "#00ff00", 0.8), stop(1.0, "#0000ff", 0.5)] }; + let two = Gradient::new(GradientKind::Linear, vec![stop(0.0, "#ff0000", 0.2), stop(1.0, "#0000ff", 0.5)]); + let three = Gradient::new(GradientKind::Linear, vec![stop(0.0, "#ff0000", 0.2), stop(0.3, "#00ff00", 0.8), stop(1.0, "#0000ff", 0.5)]); for g in [two, three] { let mut r = g.clone(); r.reverse(); diff --git a/crates/color/src/libraries.rs b/crates/color/src/libraries.rs index 163038777..a28bc808d 100644 --- a/crates/color/src/libraries.rs +++ b/crates/color/src/libraries.rs @@ -171,7 +171,7 @@ fn group(name: &str, swatches: Vec) -> SwatchGroup { /// A gradient swatch through `stops` of (offset, colour, opacity). pub(crate) fn gradient(name: &str, kind: GradientKind, stops: &[(f32, Color, f32)]) -> Swatch { let stops = stops.iter().map(|&(offset, color, opacity)| GradientStop { opacity, ..GradientStop::new(offset, color) }).collect(); - Swatch { name: name.into(), paint: Paint::Gradient(Box::new(GradientPaint::new(Gradient { kind, stops }))), global: false, spot: false } + Swatch { name: name.into(), paint: Paint::Gradient(Box::new(GradientPaint::new(Gradient::new(kind, stops)))), global: false, spot: false } } /// `n` steps of OKLCH lightness from `l0` to `l1`, chroma `c(t)` and hue `h(t)` (`t` in 0..=1), diff --git a/crates/color/src/palette_io.rs b/crates/color/src/palette_io.rs index eed4d5a94..065e06eed 100644 --- a/crates/color/src/palette_io.rs +++ b/crates/color/src/palette_io.rs @@ -721,13 +721,13 @@ mod tests { } fn sample() -> SwatchLibrary { - let grad = Paint::Gradient(Box::new(GradientPaint::new(Gradient { - kind: GradientKind::Linear, - stops: vec![ + let grad = Paint::Gradient(Box::new(GradientPaint::new(Gradient::new( + GradientKind::Linear, + vec![ GradientStop { midpoint: 0.4, ..GradientStop::new(0.0, Color::cmyk(0.1, 0.2, 0.3, 0.0)) }, GradientStop { opacity: 0.5, ..GradientStop::new(1.0, Color::rgb8(255, 0, 0)) }, ], - }))); + )))); SwatchLibrary { name: "Brand */ Colours".into(), swatches: vec![ @@ -822,15 +822,15 @@ mod tests { name: "Positions".into(), swatches: vec![Swatch { name: "Ramp".into(), - paint: Paint::Gradient(Box::new(GradientPaint::new(Gradient { + paint: Paint::Gradient(Box::new(GradientPaint::new(Gradient::new( kind, - stops: vec![ + vec![ GradientStop::new(0.0, Color::BLACK), GradientStop::new(0.125, Color::rgb8(255, 0, 0)), GradientStop::new(0.12890625, Color::WHITE), GradientStop::new(1.0, Color::rgb8(0, 0, 255)), ], - }))), + )))), global: false, spot: false, }], diff --git a/crates/color/src/swatch.rs b/crates/color/src/swatch.rs index 21f9af988..12ae31220 100644 --- a/crates/color/src/swatch.rs +++ b/crates/color/src/swatch.rs @@ -123,13 +123,13 @@ fn base_swatches() -> (Vec, Vec) { .collect(); let grad = |name: &str, a: &str, b: &str, kind: GradientKind| Swatch { name: name.into(), - paint: Paint::Gradient(Box::new(crate::GradientPaint::new(Gradient { + paint: Paint::Gradient(Box::new(crate::GradientPaint::new(Gradient::new( kind, - stops: vec![ + vec![ GradientStop::new(0.0, Color::from_hex(a).unwrap_or(Color::WHITE)), GradientStop::new(1.0, Color::from_hex(b).unwrap_or(Color::BLACK)), ], - }))), + )))), global: false, spot: false, }; diff --git a/crates/doc/src/style_libs.rs b/crates/doc/src/style_libs.rs index 649a5bc1b..30aae49e1 100644 --- a/crates/doc/src/style_libs.rs +++ b/crates/doc/src/style_libs.rs @@ -189,7 +189,7 @@ fn fx(id: &str, params: Value) -> Effect { /// A gradient of `(offset, colour, opacity)` stops. fn gradient(kind: GradientKind, stops: &[(f32, &str, f32)]) -> Gradient { - Gradient { kind, stops: stops.iter().map(|&(offset, c, opacity)| GradientStop { opacity, ..GradientStop::new(offset, hex(c)) }).collect() } + Gradient::new(kind, stops.iter().map(|&(offset, c, opacity)| GradientStop { opacity, ..GradientStop::new(offset, hex(c)) }).collect()) } /// A linear gradient fitted to each object's box at `angle` degrees (90: upwards). diff --git a/crates/effects/src/bake.rs b/crates/effects/src/bake.rs index 47381cbaa..dfe0a8c8f 100644 --- a/crates/effects/src/bake.rs +++ b/crates/effects/src/bake.rs @@ -1034,7 +1034,7 @@ mod tests { fn gradient_copies(id: u64) -> Node { use vectorcraft_color::{Gradient, GradientKind, GradientPaint, GradientStop}; let stops = vec![GradientStop::new(0.0, Color::rgb(1.0, 0.0, 0.0)), GradientStop::new(1.0, Color::rgb(0.0, 0.0, 1.0))]; - let paint = Paint::Gradient(Box::new(GradientPaint::new(Gradient { kind: GradientKind::Linear, stops }))); + let paint = Paint::Gradient(Box::new(GradientPaint::new(Gradient::new(GradientKind::Linear, stops)))); let mut n = Node::path(NodeId(id), shapes::rectangle(Rect::new(0.0, 0.0, 10.0, 10.0)), Appearance::basic(paint, Paint::None, 0.0)); n.appearance.effects.push(fx("distort.transform", json!({"moveH": 30, "copies": 2}))); n diff --git a/crates/effects/src/group.rs b/crates/effects/src/group.rs index 35ddf527b..013d02eec 100644 --- a/crates/effects/src/group.rs +++ b/crates/effects/src/group.rs @@ -589,7 +589,7 @@ mod tests { } use vectorcraft_color::{Gradient, GradientGeom, GradientKind, GradientPaint, GradientStop}; let stops = vec![GradientStop::new(0.0, Color::rgb(1.0, 0.0, 0.0)), GradientStop::new(1.0, Color::rgb(0.0, 0.0, 1.0))]; - let ramp = GradientPaint::new(Gradient { kind: GradientKind::Linear, stops }); + let ramp = GradientPaint::new(Gradient::new(GradientKind::Linear, stops)); // The type's characters fit the gradient to its layout; the square has it placed across itself. let style = vectorcraft_doc::CharStyle { size: 40.0, fill: Paint::Gradient(Box::new(ramp.clone())), ..Default::default() }; let text = vectorcraft_doc::TextObject::point(vectorcraft_geom::Point::new(5.0, 60.0), "IIII", style); @@ -615,7 +615,7 @@ mod tests { fn a_transform_on_a_group_paints_each_copy_with_its_own_gradient() { use vectorcraft_color::{Gradient, GradientGeom, GradientKind, GradientPaint, GradientStop}; let stops = vec![GradientStop::new(0.0, Color::rgb(1.0, 0.0, 0.0)), GradientStop::new(1.0, Color::rgb(0.0, 0.0, 1.0))]; - let ramp = GradientPaint::new(Gradient { kind: GradientKind::Linear, stops }); + let ramp = GradientPaint::new(Gradient::new(GradientKind::Linear, stops)); let geom = GradientGeom { start: (0.0, 5.0).into(), end: (10.0, 5.0).into(), aspect: 1.0, focal: None }; let paints = [Paint::Gradient(Box::new(ramp.clone())), Paint::Gradient(Box::new(GradientPaint { geom: Some(geom), ..ramp }))]; for (k, paint) in paints.into_iter().enumerate() { diff --git a/crates/effects/src/lighting.rs b/crates/effects/src/lighting.rs index 6f1242b6e..9a352189d 100644 --- a/crates/effects/src/lighting.rs +++ b/crates/effects/src/lighting.rs @@ -71,7 +71,7 @@ pub(crate) fn shade(c: Color, rgb: [f64; 3]) -> Color { pub(crate) fn smooth_paint(g: vectorcraft_three_d::LightGradient, color: Color) -> Paint { use vectorcraft_doc::color::{Gradient, GradientGeom, GradientKind, GradientPaint, GradientStop}; let stops = g.stops().into_iter().map(|(at, rgb)| GradientStop::new(at, shade(color, rgb))).collect(); - let mut p = GradientPaint::new(Gradient { kind: GradientKind::Linear, stops }); + let mut p = GradientPaint::new(Gradient::new(GradientKind::Linear, stops)); p.geom = Some(GradientGeom { start: g.diffuse.start, end: g.diffuse.end, aspect: 1.0, focal: None }); Paint::Gradient(Box::new(p)) } @@ -334,7 +334,7 @@ mod tests { stop.opacity = 0.4; stop.midpoint = 0.3; let g = GradientPaint { - gradient: Gradient { kind: GradientKind::Linear, stops: vec![stop, GradientStop::new(1.0, Color::BLACK)] }, + gradient: Gradient::new(GradientKind::Linear, vec![stop, GradientStop::new(1.0, Color::BLACK)]), geom: Some(GradientGeom { start: Point::new(20.0, 30.0), end: Point::new(100.0, 30.0), aspect: 1.0, focal: None }), angle: 0.0, swatch: None, diff --git a/crates/effects/src/revolve.rs b/crates/effects/src/revolve.rs index 1f17010e3..17507f3ce 100644 --- a/crates/effects/src/revolve.rs +++ b/crates/effects/src/revolve.rs @@ -181,7 +181,7 @@ fn shading_paint(g: vectorcraft_three_d::ShadeGradient, color: impl Fn(f64) -> C use vectorcraft_doc::color::{Gradient, GradientGeom, GradientKind, GradientPaint, GradientStop}; let stops = g.brightness.into_iter().enumerate().map(|(i, s)| GradientStop { opacity: opacity(s), ..GradientStop::new(i as f32, color(s)) }).collect(); - let mut paint = GradientPaint::new(Gradient { kind: GradientKind::Linear, stops }); + let mut paint = GradientPaint::new(Gradient::new(GradientKind::Linear, stops)); paint.geom = Some(GradientGeom { start: g.start, end: g.end, aspect: 1.0, focal: None }); Paint::Gradient(Box::new(paint)) } diff --git a/crates/effects/src/tests_solids.rs b/crates/effects/src/tests_solids.rs index 61b5a7f57..9dd72d4b1 100644 --- a/crates/effects/src/tests_solids.rs +++ b/crates/effects/src/tests_solids.rs @@ -286,7 +286,7 @@ fn a_masked_surface_under_a_colored_light_stays_whole() { use vectorcraft_doc::color::{Gradient, GradientKind, GradientPaint, GradientStop}; let mut half = GradientStop::new(1.0, RED); half.opacity = 0.5; - let gradient = GradientPaint::new(Gradient { kind: GradientKind::Linear, stops: vec![GradientStop::new(0.0, RED), half] }); + let gradient = GradientPaint::new(Gradient::new(GradientKind::Linear, vec![GradientStop::new(0.0, RED), half])); for (lights, surfaces) in [(json!({"lights": [{"color": "#ff8080"}]}), 2), (json!({}), 1)] { let mut n = stroked_rect(100.0); if let Some(AppearanceItem::Fill(f)) = n.appearance.items.iter_mut().find(|i| matches!(i, AppearanceItem::Fill(_))) { diff --git a/crates/engine/src/cmd/buildcmds.rs b/crates/engine/src/cmd/buildcmds.rs index 4e0d55fe2..6d19dd24f 100644 --- a/crates/engine/src/cmd/buildcmds.rs +++ b/crates/engine/src/cmd/buildcmds.rs @@ -952,7 +952,7 @@ fn traced_shape(shape: tr::TracedShape, xf: vectorcraft_geom::Affine) -> LiveSha fn traced_gradient(g: &tr::TracedGradient, xf: vectorcraft_geom::Affine) -> Paint { use vectorcraft_color::{Gradient, GradientGeom, GradientKind, GradientPaint, GradientStop}; let stops = g.stops.iter().map(|&(at, c)| GradientStop::new(at as f32, Color::rgb8(c[0], c[1], c[2]))).collect(); - let mut paint = GradientPaint::new(Gradient { kind: GradientKind::Linear, stops }); + let mut paint = GradientPaint::new(Gradient::new(GradientKind::Linear, stops)); paint.geom = Some(GradientGeom { start: xf * g.start, end: xf * g.end, aspect: 1.0, focal: None }); Paint::Gradient(Box::new(paint)) } diff --git a/crates/engine/src/cmd/create.rs b/crates/engine/src/cmd/create.rs index a9a86195d..07a039a9a 100644 --- a/crates/engine/src/cmd/create.rs +++ b/crates/engine/src/cmd/create.rs @@ -308,7 +308,7 @@ fn flare(s: &mut Session, p: &Value) -> Result { }; let stop = |offset: f32, opacity: f32| GradientStop { opacity, ..GradientStop::new(offset, vectorcraft_color::Color::WHITE) }; let radial = |centre: Point, radius: f64, stops: Vec| { - let mut g = GradientPaint::new(Gradient { kind: GradientKind::Radial, stops }); + let mut g = GradientPaint::new(Gradient::new(GradientKind::Radial, stops)); g.geom = Some(GradientGeom { start: centre, end: centre + vectorcraft_geom::Vec2::new(radius, 0.0), aspect: 1.0, focal: None }); Paint::Gradient(Box::new(g)) }; diff --git a/crates/engine/src/cmd/effectcmd.rs b/crates/engine/src/cmd/effectcmd.rs index 01066e15e..3ad6ae9fa 100644 --- a/crates/engine/src/cmd/effectcmd.rs +++ b/crates/engine/src/cmd/effectcmd.rs @@ -1151,7 +1151,7 @@ mod tests { use vectorcraft_color::{Color, Gradient, GradientKind, GradientPaint, GradientStop, Paint}; let (mut s, id) = session_with_rect(); let stops = vec![GradientStop::new(0.0, Color::rgb(1.0, 0.0, 0.0)), GradientStop::new(1.0, Color::rgb(0.0, 0.0, 1.0))]; - let ramp = Paint::Gradient(Box::new(GradientPaint::new(Gradient { kind: GradientKind::Linear, stops }))); + let ramp = Paint::Gradient(Box::new(GradientPaint::new(Gradient::new(GradientKind::Linear, stops)))); s.edit("gradient", |d, _| { let n = d.node_mut(id).unwrap(); n.appearance.set_fill(ramp); diff --git a/crates/engine/src/cmd/fileio/affinity.rs b/crates/engine/src/cmd/fileio/affinity.rs index 726549397..8b507b986 100644 --- a/crates/engine/src/cmd/fileio/affinity.rs +++ b/crates/engine/src/cmd/fileio/affinity.rs @@ -784,7 +784,7 @@ impl Builder { } let aspect = if u.hypot() > 0.0 { (v.hypot() / u.hypot()).clamp(0.01, 100.0) } else { 1.0 }; let geom = GradientGeom { start: o, end: x, aspect: if kind == GradientKind::Radial { aspect } else { 1.0 }, focal: None }; - let mut gp = GradientPaint::new(Gradient { kind, stops }); + let mut gp = GradientPaint::new(Gradient::new(kind, stops)); gp.angle = (-(u.y)).atan2(u.x).to_degrees(); gp.geom = Some(geom); Some((Paint::Gradient(Box::new(gp)), 1.0)) diff --git a/crates/engine/src/cmd/gradient.rs b/crates/engine/src/cmd/gradient.rs index 0a85e1296..bf1132cf8 100644 --- a/crates/engine/src/cmd/gradient.rs +++ b/crates/engine/src/cmd/gradient.rs @@ -224,7 +224,7 @@ pub(crate) fn parse_gradient(g: &Value) -> Parsed { } let kind = str_param(g, "kind").map(parse_kind).transpose()?.unwrap_or_default(); let stops = g.get("stops").map(parse_stops).transpose()?.unwrap_or_else(|| Gradient::default().stops); - let mut gp = GradientPaint::new(Gradient { kind, stops }); + let mut gp = GradientPaint::new(Gradient::new(kind, stops)); gp.angle = f64_or(g, "angle", 0.0); gp.swatch = str_param(g, "swatch").map(str::to_string); let geom = GeomEdit::parse(g)?; diff --git a/crates/engine/src/tests_build.rs b/crates/engine/src/tests_build.rs index 1afa3d4e1..a80493928 100644 --- a/crates/engine/src/tests_build.rs +++ b/crates/engine/src/tests_build.rs @@ -1063,7 +1063,7 @@ fn a_gradient_face_split_by_a_closed_gap_keeps_one_gradient_across_both_halves() let mut s = session(); let r = rect(&mut s, 0.0, 0.0, 100.0, 100.0); let stops = vec![GradientStop::new(0.0, Color::rgb(1.0, 0.0, 0.0)), GradientStop::new(1.0, Color::rgb(0.0, 0.0, 1.0))]; - let gradient = Paint::Gradient(Box::new(GradientPaint::new(Gradient { kind: GradientKind::Linear, stops }))); + let gradient = Paint::Gradient(Box::new(GradientPaint::new(Gradient::new(GradientKind::Linear, stops)))); s.edit("t", |d, _| { d.node_mut(r).unwrap().appearance.set_fill(gradient); Ok(()) diff --git a/crates/engine/src/tests_eyedropper.rs b/crates/engine/src/tests_eyedropper.rs index fdb53fe4b..5fd492a40 100644 --- a/crates/engine/src/tests_eyedropper.rs +++ b/crates/engine/src/tests_eyedropper.rs @@ -407,10 +407,10 @@ fn rgb_gradient_and_mesh_colors_given_to_a_cmyk_document_separate_through_the_co assert_eq!(colors(&s)[1], blue); // New stops recolor the three points from their CMYK values. s.execute("paint.editGradient", &json!({"stops": [{"offset": 0, "color": "#ffffff"}, {"offset": 1, "color": "#ff0000"}]})).unwrap(); - let stored = vectorcraft_color::Gradient { - kind: Default::default(), - stops: vec![vectorcraft_color::GradientStop::new(0.0, managed_cmyk(Color::WHITE)), vectorcraft_color::GradientStop::new(1.0, red)], - }; + let stored = vectorcraft_color::Gradient::new( + Default::default(), + vec![vectorcraft_color::GradientStop::new(0.0, managed_cmyk(Color::WHITE)), vectorcraft_color::GradientStop::new(1.0, red)], + ); // The points mix in the model the stops share (#2829): CMYK here. assert_eq!(colors(&s), [0.0, 0.5, 1.0].map(|t| stored.sample_with(t, Color::lerp_keep_model).0), "{:?}", colors(&s)); diff --git a/crates/engine/src/tests_gradient.rs b/crates/engine/src/tests_gradient.rs index 88da019bf..1c0488feb 100644 --- a/crates/engine/src/tests_gradient.rs +++ b/crates/engine/src/tests_gradient.rs @@ -33,14 +33,14 @@ fn fill_gradient(s: &Session, id: NodeId) -> GradientPaint { /// A three-stop freeform gradient with a 0.3 midpoint, partial opacity and a placed vector. fn three_stops() -> GradientPaint { let stop = |offset, color, opacity, midpoint| GradientStop { opacity, midpoint, ..GradientStop::new(offset, color) }; - let mut g = GradientPaint::new(Gradient { - kind: GradientKind::Freeform, - stops: vec![ + let mut g = GradientPaint::new(Gradient::new( + GradientKind::Freeform, + vec![ stop(0.0, Color::rgb(1.0, 0.0, 0.0), 1.0, 0.3), stop(0.4, Color::cmyk(0.1, 0.2, 0.3, 0.4), 0.5, 0.5), stop(1.0, Color::gray(0.25), 0.75, 0.5), ], - }); + )); g.geom = Some(GradientGeom { start: Point::new(10.0, 20.0), end: Point::new(110.0, 70.0), aspect: 0.5, focal: None }); g.angle = g.geom.unwrap().angle_deg(); g diff --git a/crates/eps/src/import/ai/paint.rs b/crates/eps/src/import/ai/paint.rs index 438a52bdb..14c626026 100644 --- a/crates/eps/src/import/ai/paint.rs +++ b/crates/eps/src/import/ai/paint.rs @@ -127,7 +127,7 @@ impl GradientDef { let name = vals.iter().find_map(|v| if let V::Str(_) = v { v.text() } else { None })?; let nums: Vec = vals.iter().filter_map(V::num).collect(); let kind = if nums.first().copied() == Some(1.0) { GradientKind::Radial } else { GradientKind::Linear }; - Some(Self { name, gradient: Gradient { kind, stops: vec![] } }) + Some(Self { name, gradient: Gradient::new(kind, vec![]) }) } /// A stop (`Bs`). diff --git a/crates/eps/src/import/graphics.rs b/crates/eps/src/import/graphics.rs index 0ffc89f2f..613ed3afd 100644 --- a/crates/eps/src/import/graphics.rs +++ b/crates/eps/src/import/graphics.rs @@ -1144,7 +1144,7 @@ impl Interp<'_> { } else { (GradientKind::Linear, GradientGeom { start: m * Point::new(c(0), c(1)), end: m * Point::new(c(2), c(3)), aspect: 1.0, focal: None }) }; - let mut g = GradientPaint::new(Gradient { kind: gk, stops }); + let mut g = GradientPaint::new(Gradient::new(gk, stops)); g.geom = Some(geom); Ok(Some(g)) } diff --git a/crates/eps/src/tests.rs b/crates/eps/src/tests.rs index 4cab46284..65fd9e81d 100644 --- a/crates/eps/src/tests.rs +++ b/crates/eps/src/tests.rs @@ -150,7 +150,7 @@ fn gradient_doc(kind: GradientKind) -> Document { GradientStop::new(0.4, Color::rgb(1.0, 1.0, 0.0)), GradientStop::new(1.0, Color::rgb(0.0, 0.0, 1.0)), ]; - let paint = Paint::Gradient(Box::new(GradientPaint::new(Gradient { kind, stops }))); + let paint = Paint::Gradient(Box::new(GradientPaint::new(Gradient::new(kind, stops)))); doc_with(|d| vec![path(d, shapes::rectangle(Rect::new(20.0, 20.0, 180.0, 120.0)), paint, Paint::None, 0.0)]) } diff --git a/crates/eps/src/tests_legacy_ai.rs b/crates/eps/src/tests_legacy_ai.rs index 048daf834..3a16e6e7e 100644 --- a/crates/eps/src/tests_legacy_ai.rs +++ b/crates/eps/src/tests_legacy_ai.rs @@ -48,10 +48,10 @@ fn sample() -> Document { let clipped = shape(&mut doc, shapes::rectangle(Rect::new(150.0, 10.0, 190.0, 50.0)), Paint::solid(Color::gray(0.25)), Paint::None); let window = Node::new(doc.alloc_id(), NodeKind::Group { children: vec![Arc::new(clip), Arc::new(clipped)], clip: true }); doc.insert(Some(back), usize::MAX, window).unwrap(); - let g = Gradient { - kind: GradientKind::Linear, - stops: vec![GradientStop::new(0.0, Color::rgb(1.0, 1.0, 1.0)), GradientStop::new(1.0, Color::rgb(0.0, 0.0, 0.0))], - }; + let g = Gradient::new( + GradientKind::Linear, + vec![GradientStop::new(0.0, Color::rgb(1.0, 1.0, 1.0)), GradientStop::new(1.0, Color::rgb(0.0, 0.0, 0.0))], + ); let shaded = shape(&mut doc, shapes::rectangle(Rect::new(10.0, 60.0, 50.0, 90.0)), Paint::Gradient(Box::new(GradientPaint::new(g))), Paint::None); doc.insert(Some(back), usize::MAX, shaded).unwrap(); let ellipse = shape(&mut doc, shapes::ellipse(Rect::new(100.0, 60.0, 160.0, 90.0)), red(), Paint::None); @@ -407,10 +407,10 @@ fn empty_images_get_the_size_note_and_undecodable_ones_the_decode_note() { #[test] fn a_gradient_fill_and_its_stroke_are_one_object() { let mut doc = Document::new(100.0, 100.0); - let g = Gradient { - kind: GradientKind::Radial, - stops: vec![GradientStop::new(0.0, Color::rgb(1.0, 1.0, 1.0)), GradientStop::new(1.0, Color::cmyk(0.0, 0.0, 0.0, 1.0))], - }; + let g = Gradient::new( + GradientKind::Radial, + vec![GradientStop::new(0.0, Color::rgb(1.0, 1.0, 1.0)), GradientStop::new(1.0, Color::cmyk(0.0, 0.0, 0.0, 1.0))], + ); let mut paint = GradientPaint::new(g); paint.geom = Some(vectorcraft_color::GradientGeom { start: vectorcraft_geom::Point::new(30.0, 30.0), @@ -435,7 +435,7 @@ fn a_gradient_fill_and_its_stroke_are_one_object() { /// to the object). fn white_to_navy(kind: GradientKind, geom: Option) -> Paint { let navy = Color::rgb(27.0 / 255.0, 42.0 / 255.0, 107.0 / 255.0); - let g = Gradient { kind, stops: vec![GradientStop::new(0.0, Color::rgb(1.0, 1.0, 1.0)), GradientStop::new(1.0, navy)] }; + let g = Gradient::new(kind, vec![GradientStop::new(0.0, Color::rgb(1.0, 1.0, 1.0)), GradientStop::new(1.0, navy)]); Paint::Gradient(Box::new(GradientPaint { geom, ..GradientPaint::new(g) })) } @@ -576,7 +576,7 @@ fn radial_gradient_stops_are_listed_from_the_first() { let mut doc = Document::new(200.0, 100.0); let layer = doc.layers[0].id; for (kind, x) in [(GradientKind::Radial, 10.0), (GradientKind::Linear, 110.0)] { - let paint = Paint::Gradient(Box::new(GradientPaint::new(Gradient { kind, stops: stops.clone() }))); + let paint = Paint::Gradient(Box::new(GradientPaint::new(Gradient::new(kind, stops.clone())))); let n = shape(&mut doc, shapes::rectangle(Rect::new(x, 10.0, x + 80.0, 90.0)), paint, Paint::None); doc.insert(Some(layer), usize::MAX, n).unwrap(); } @@ -715,7 +715,7 @@ fn spots_and_gradient(spots: &[&str], gradient: &str) -> Document { } let mut first = GradientStop::new(0.0, Color::cmyk(0.0, 0.5, 1.0, 0.0)); first.swatch = Some(spots[0].into()); - let g = Gradient { kind: GradientKind::Linear, stops: vec![first, GradientStop::new(1.0, Color::cmyk(0.0, 0.0, 0.0, 0.0))] }; + let g = Gradient::new(GradientKind::Linear, vec![first, GradientStop::new(1.0, Color::cmyk(0.0, 0.0, 0.0, 0.0))]); let mut paint = GradientPaint::new(g); paint.swatch = Some(gradient.into()); let n = shape(&mut doc, shapes::rectangle(Rect::new(10.0, 50.0, 50.0, 90.0)), Paint::Gradient(Box::new(paint)), Paint::None); @@ -782,10 +782,10 @@ fn spot_gradient_and_title_names_are_written_in_windows_1252() { fn names_outside_windows_1252_are_replaced_and_kept_apart() { // 赤 and 青 (spot colors), 渐变 and グラ (gradients), 日本 (the title). let mut doc = spots_and_gradient(&["\u{8d64}", "\u{9752}"], "\u{6e10}\u{53d8}"); - let g = Gradient { - kind: GradientKind::Linear, - stops: vec![GradientStop::new(0.0, Color::cmyk(1.0, 0.0, 0.0, 0.0)), GradientStop::new(1.0, Color::cmyk(0.0, 0.0, 0.0, 0.0))], - }; + let g = Gradient::new( + GradientKind::Linear, + vec![GradientStop::new(0.0, Color::cmyk(1.0, 0.0, 0.0, 0.0)), GradientStop::new(1.0, Color::cmyk(0.0, 0.0, 0.0, 0.0))], + ); let mut paint = GradientPaint::new(g); paint.swatch = Some("\u{30b0}\u{30e9}".into()); let n = shape(&mut doc, shapes::rectangle(Rect::new(60.0, 50.0, 100.0, 90.0)), Paint::Gradient(Box::new(paint)), Paint::None); diff --git a/crates/pdf/src/import_shading.rs b/crates/pdf/src/import_shading.rs index a4954a57a..85423148f 100644 --- a/crates/pdf/src/import_shading.rs +++ b/crates/pdf/src/import_shading.rs @@ -85,7 +85,7 @@ pub(crate) fn shading_gradient(sp: &ShadingPattern, colors: &mut Colors<'_>, ink let stops = ts.iter().map(|&t| stop_at(t, (r0 + (r1 - r0) * t) / r1)).collect(); (GradientKind::Radial, geom, stops) }; - let mut g = GradientPaint::new(Gradient { kind, stops }); + let mut g = GradientPaint::new(Gradient::new(kind, stops)); g.geom = Some(geom); Some((g, *extend)) } diff --git a/crates/pdf/src/tests_import_color.rs b/crates/pdf/src/tests_import_color.rs index 3a561d723..8b98f7703 100644 --- a/crates/pdf/src/tests_import_color.rs +++ b/crates/pdf/src/tests_import_color.rs @@ -105,7 +105,7 @@ fn gray_imports_as_gray_and_rgb_documents_stay_rgb() { fn shading_stops_keep_cmyk_and_spot_tints() { let mut d = Document::new_with_mode(100.0, 50.0, ColorMode::Cmyk); d.swatches.push(spot("Ink A", Color::cmyk(0.0, 0.5, 1.0, 0.0))); - let grad = |stops: Vec| Paint::Gradient(Box::new(GradientPaint::new(Gradient { kind: GradientKind::Linear, stops }))); + let grad = |stops: Vec| Paint::Gradient(Box::new(GradientPaint::new(Gradient::new(GradientKind::Linear, stops)))); add(&mut d, grad(vec![GradientStop::new(0.0, Color::cmyk(1.0, 0.0, 0.0, 0.0)), GradientStop::new(1.0, Color::cmyk(0.0, 0.0, 1.0, 0.2))])); let ink = d.global_color("Ink A").unwrap(); let linked = |offset: f32, tint: f32| GradientStop { swatch: Some("Ink A".into()), tint, ..GradientStop::new(offset, ink.tinted(tint)) }; diff --git a/crates/pdf/src/tests_import_fidelity.rs b/crates/pdf/src/tests_import_fidelity.rs index 248f8c78a..d6be03b39 100644 --- a/crates/pdf/src/tests_import_fidelity.rs +++ b/crates/pdf/src/tests_import_fidelity.rs @@ -431,7 +431,7 @@ fn gradient_stop_opacity_round_trips() { let mut d = Document::new(100.0, 100.0); let mut stops = vec![GradientStop::new(0.0, Color::rgb(1.0, 0.0, 0.0)), GradientStop::new(1.0, Color::rgb(0.0, 0.0, 1.0))]; stops[1].opacity = 0.2; - let g = GradientPaint::new(Gradient { kind: GradientKind::Linear, stops }); + let g = GradientPaint::new(Gradient::new(GradientKind::Linear, stops)); let n = Node::path( NodeId(0), shapes::rectangle(Rect::new(10.0, 10.0, 90.0, 90.0)), diff --git a/crates/render/src/tests_cmykblend.rs b/crates/render/src/tests_cmykblend.rs index 9d3f1d933..17afce50b 100644 --- a/crates/render/src/tests_cmykblend.rs +++ b/crates/render/src/tests_cmykblend.rs @@ -154,7 +154,7 @@ fn busy_page() -> Document { shadowed.appearance.effects.push(vectorcraft_doc::Effect { id: "stylize.dropShadow".into(), params: shadow, visible: true }); add(&mut d, shadowed); let stops = vec![GradientStop::new(0.0, CYAN), GradientStop { opacity: 0.3, ..GradientStop::new(1.0, MAGENTA) }]; - let ramp = Paint::Gradient(Box::new(GradientPaint::new(Gradient { kind: GradientKind::Linear, stops }))); + let ramp = Paint::Gradient(Box::new(GradientPaint::new(Gradient::new(GradientKind::Linear, stops)))); let n = Node::path(d.alloc_id(), shapes::rectangle(Rect::new(20.0, 90.0, 120.0, 130.0)), Appearance::basic(ramp, Paint::None, 0.0)); add(&mut d, n); let mut over = rect(&mut d, Rect::new(100.0, 80.0, 160.0, 120.0), Color::cmyk(0.0, 0.0, 1.0, 0.0)); diff --git a/crates/render/src/tests_objectfx.rs b/crates/render/src/tests_objectfx.rs index 24d941d26..95ecb085e 100644 --- a/crates/render/src/tests_objectfx.rs +++ b/crates/render/src/tests_objectfx.rs @@ -370,7 +370,7 @@ fn type_drawn_through_its_outlines_keeps_its_stroke_weight_when_scaled() { #[test] fn type_drawn_through_its_outlines_keeps_its_gradients_in_place() { let stops = vec![GradientStop::new(0.0, Color::rgb(1.0, 0.0, 0.0)), GradientStop::new(1.0, Color::rgb(0.0, 0.0, 1.0))]; - let mut g = GradientPaint::new(Gradient { kind: GradientKind::Linear, stops }); + let mut g = GradientPaint::new(Gradient::new(GradientKind::Linear, stops)); g.angle = 90.0; let ramp = Paint::Gradient(Box::new(g)); // On the characters, the gradient fits the layout box in text space and turns with the type. @@ -387,7 +387,7 @@ fn type_drawn_through_its_outlines_keeps_its_gradients_in_place() { /// that runs left to right (0°) or bottom to top (90°). fn gradient_text_doc(angle: f64) -> Document { let stops = vec![GradientStop::new(0.0, Color::rgb(1.0, 0.0, 0.0)), GradientStop::new(1.0, Color::rgb(0.0, 0.0, 1.0))]; - let mut g = GradientPaint::new(Gradient { kind: GradientKind::Linear, stops }); + let mut g = GradientPaint::new(Gradient::new(GradientKind::Linear, stops)); g.angle = angle; styled_text_doc(CharStyle { size: 40.0, fill: Paint::Gradient(Box::new(g)), ..Default::default() }, Affine::IDENTITY) } @@ -443,7 +443,7 @@ fn a_transform_effect_that_scales_type_out_of_proportion_scales_its_radial_and_d let mut changed = vec![]; // A radial gradient turns into an ellipse, and a linear one at 45° turns its isolines. for (kind, angle) in [(GradientKind::Radial, 0.0), (GradientKind::Linear, 45.0)] { - let mut g = GradientPaint::new(Gradient { kind, stops: stops.clone() }); + let mut g = GradientPaint::new(Gradient::new(kind, stops.clone())); g.angle = angle; let d = styled_text_doc(CharStyle { size: 40.0, fill: Paint::Gradient(Box::new(g)), ..Default::default() }, Affine::IDENTITY); let id = d.layers[0].children().unwrap()[0].id; @@ -761,7 +761,7 @@ fn a_strokes_own_glow_paints_around_that_stroke_only() { fn a_path_with_its_own_transform_paints_each_copy_with_its_own_gradient() { use vectorcraft_color::GradientGeom; let stops = vec![GradientStop::new(0.0, Color::rgb(1.0, 0.0, 0.0)), GradientStop::new(1.0, Color::rgb(0.0, 0.0, 1.0))]; - let ramp = GradientPaint::new(Gradient { kind: GradientKind::Linear, stops }); + let ramp = GradientPaint::new(Gradient::new(GradientKind::Linear, stops)); let geom = GradientGeom { start: Point::new(0.0, 50.0), end: Point::new(20.0, 50.0), aspect: 1.0, focal: None }; // Fitted to the box on each render, and placed on the object. for paint in [ramp.clone(), GradientPaint { geom: Some(geom), ..ramp }] { diff --git a/crates/render/tests/golden.rs b/crates/render/tests/golden.rs index 20955f178..f889b1721 100644 --- a/crates/render/tests/golden.rs +++ b/crates/render/tests/golden.rs @@ -21,7 +21,7 @@ fn stops(a: Color, b: Color) -> Vec { } fn gradient(kind: GradientKind, a: Color, b: Color, angle: f64) -> Paint { - let mut gp = GradientPaint::new(Gradient { kind, stops: stops(a, b) }); + let mut gp = GradientPaint::new(Gradient::new(kind, stops(a, b))); gp.angle = angle; Paint::Gradient(Box::new(gp)) } diff --git a/crates/render/tests/gradient_alpha.rs b/crates/render/tests/gradient_alpha.rs index 15cf21247..92e515917 100644 --- a/crates/render/tests/gradient_alpha.rs +++ b/crates/render/tests/gradient_alpha.rs @@ -51,7 +51,7 @@ fn transparent_stops_blend_colour_and_opacity_apart() { (GradientKind::Linear, GradientGeom { start: Point::new(0.0, 50.0), end: Point::new(100.0, 50.0), aspect: 1.0, focal: None }), (GradientKind::Radial, GradientGeom { start: Point::new(50.0, 50.0), end: Point::new(100.0, 50.0), aspect: 1.0, focal: None }), ] { - let gradient = Gradient { kind, stops: stops.clone() }; + let gradient = Gradient::new(kind, stops.clone()); assert_follows_model(&render_view(&filled(&gradient, geom), 100, 100), &gradient, &geom); } } diff --git a/crates/render/tests/stroke_geometry.rs b/crates/render/tests/stroke_geometry.rs index b05b0d828..b53ed21c3 100644 --- a/crates/render/tests/stroke_geometry.rs +++ b/crates/render/tests/stroke_geometry.rs @@ -157,7 +157,7 @@ fn line_and_head_take_the_opacity_once() { #[test] fn a_gradient_runs_on_into_the_head() { let stops = vec![GradientStop::new(0.0, Color::rgb(1.0, 0.0, 0.0)), GradientStop::new(1.0, Color::rgb(0.0, 0.0, 1.0))]; - let paint = Paint::Gradient(Box::new(GradientPaint::new(Gradient { kind: GradientKind::Linear, stops }))); + let paint = Paint::Gradient(Box::new(GradientPaint::new(Gradient::new(GradientKind::Linear, stops)))); let d = arrow_doc(Arrowhead::Square, ArrowAlign::Tip, 1.0, |s| s.paint = paint); let h = head_of(&d); let img = render(&d); diff --git a/crates/svg/src/import.rs b/crates/svg/src/import.rs index bbcf919a2..b98d30724 100644 --- a/crates/svg/src/import.rs +++ b/crates/svg/src/import.rs @@ -1322,7 +1322,7 @@ impl Importer { } } Paint::Gradient(Box::new(GradientPaint { - gradient: Gradient { kind, stops }, + gradient: Gradient::new(kind, stops), geom: Some(geom), angle: geom.angle_deg(), swatch: None, diff --git a/crates/svg/src/import/spread.rs b/crates/svg/src/import/spread.rs index fa4f70159..1c6c1f3ec 100644 --- a/crates/svg/src/import/spread.rs +++ b/crates/svg/src/import/spread.rs @@ -80,7 +80,7 @@ fn whole_period(stops: &[GradientStop]) -> Vec { /// A period mirrored: the stops in reverse, each midpoint measured from the other side. fn mirror(period: &[GradientStop]) -> Vec { - let mut g = Gradient { kind: GradientKind::Linear, stops: period.to_vec() }; + let mut g = Gradient::new(GradientKind::Linear, period.to_vec()); g.reverse(); g.stops } diff --git a/crates/svg/tests/gradients.rs b/crates/svg/tests/gradients.rs index aba55acc7..9009316cd 100644 --- a/crates/svg/tests/gradients.rs +++ b/crates/svg/tests/gradients.rs @@ -9,10 +9,7 @@ use vectorcraft_geom::{Point, Rect, shapes}; use vectorcraft_svg::{ExportOptions, export, import}; fn black_to_white() -> GradientPaint { - GradientPaint::new(Gradient { - kind: GradientKind::Linear, - stops: vec![GradientStop::new(0.0, Color::BLACK), GradientStop::new(1.0, Color::WHITE)], - }) + GradientPaint::new(Gradient::new(GradientKind::Linear, vec![GradientStop::new(0.0, Color::BLACK), GradientStop::new(1.0, Color::WHITE)])) } fn doc_with(nodes: impl FnOnce(&mut Document) -> Vec) -> Document { diff --git a/crates/tools/src/xform/gradient.rs b/crates/tools/src/xform/gradient.rs index 2802582b0..cdc733bec 100644 --- a/crates/tools/src/xform/gradient.rs +++ b/crates/tools/src/xform/gradient.rs @@ -97,7 +97,7 @@ impl Annotator { } /// An annotator showing `stops` on `geom` (the state a drag started from). fn with(geom: GradientGeom, stops: &[GradientStop]) -> Self { - Self { geom, gradient: Gradient { kind: GradientKind::Linear, stops: stops.to_vec() } } + Self { geom, gradient: Gradient::new(GradientKind::Linear, stops.to_vec()) } } fn radial(&self) -> bool { self.gradient.kind == GradientKind::Radial @@ -604,7 +604,7 @@ mod tests { /// The test rectangle (100..200) with a horizontal gradient of `stops` from (100,150) to (200,150). fn graded(stops: Vec) -> (Document, Selection) { let (mut d, id) = doc_with_rect(); - let mut g = GradientPaint::new(Gradient { kind: GradientKind::Linear, stops }); + let mut g = GradientPaint::new(Gradient::new(GradientKind::Linear, stops)); g.geom = Some(GradientGeom { start: Point::new(100.0, 150.0), end: Point::new(200.0, 150.0), aspect: 1.0, focal: None }); d.node_mut(id).unwrap().appearance.set_fill(Paint::Gradient(Box::new(g))); let mut s = Selection::default(); diff --git a/crates/ui-egui/src/panels/swatches.rs b/crates/ui-egui/src/panels/swatches.rs index 75861ff5c..659e2c5d0 100644 --- a/crates/ui-egui/src/panels/swatches.rs +++ b/crates/ui-egui/src/panels/swatches.rs @@ -1763,7 +1763,7 @@ mod tests { let grad = |c: &str| { let stops = vec![vectorcraft_color::GradientStop::new(0.0, Color::from_hex(c).unwrap()), vectorcraft_color::GradientStop::new(1.0, Color::WHITE)]; - Paint::Gradient(Box::new(vectorcraft_color::GradientPaint::new(vectorcraft_color::Gradient { kind: GradientKind::Radial, stops }))) + Paint::Gradient(Box::new(vectorcraft_color::GradientPaint::new(vectorcraft_color::Gradient::new(GradientKind::Radial, stops)))) }; let drop_on = |app: &mut VectorcraftApp, name: &str, paint: Paint, m: Modifiers, time: f64| { let at = tile_center(&ctx, name);