M3.60: gradient swatches and stops linked to global and spot swatches

Applying a gradient swatch records it as the gradient's swatch (the Swatches panel highlights
it and the Gradient panel's swatch menu marks it). A stop given a global or spot swatch (and a
tint) in paint.editGradient / a gradient paint's stops, dropped from the Swatches panel or
picked in the stop popover stays linked: editing the swatch recolours it, in art and in
gradient swatches, deleting it unlinks it. Spot stops separate on their plate, and a gradient
whose stops are all tints of one spot ink (or paper white) exports to PDF as a Separation
shading; gradients mixing models are written in one colour space (the PDF writer requires it;
mixed models used to abort the export).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
bflatastic
2026-10-05 02:29:19 +07:00
co-authored by Claude Opus 5.5
parent b2ececc7b4
commit 7227e295ea
10 changed files with 358 additions and 33 deletions
+18 -2
View File
@@ -13,10 +13,21 @@ pub fn color_json(c: &Color) -> Value {
}
}
/// Gradient stops as the `stops` param of `paint.editGradient` / a `gradient` paint.
/// Gradient stops as the `stops` param of `paint.editGradient` / a `gradient` paint (a linked
/// stop also carries its `swatch` and `tint` %).
pub fn stops_json(stops: &[GradientStop]) -> Value {
Value::Array(
stops.iter().map(|s| json!({"offset": s.offset, "color": color_json(&s.color), "opacity": s.opacity, "midpoint": s.midpoint})).collect(),
stops
.iter()
.map(|s| {
let mut v = json!({"offset": s.offset, "color": color_json(&s.color), "opacity": s.opacity, "midpoint": s.midpoint});
if let Some(n) = &s.swatch {
v["swatch"] = json!(n);
v["tint"] = json!(s.tint * 100.0);
}
v
})
.collect(),
)
}
@@ -75,6 +86,11 @@ mod tests {
let v = gradient_params(&g);
assert_eq!((v["start"].clone(), v["end"].clone(), v["aspect"].clone()), (json!([1.0, 2.0]), json!([3.0, 4.0]), json!(50.0)));
assert_eq!(v["swatch"], "Sky");
assert!(v["stops"][0].get("swatch").is_none(), "unlinked stops carry no link");
g.gradient.stops[1].swatch = Some("Ink".into());
g.gradient.stops[1].tint = 0.25;
let v = gradient_params(&g);
assert_eq!((v["stops"][1]["swatch"].clone(), v["stops"][1]["tint"].clone()), (json!("Ink"), json!(25.0)));
assert_eq!(color_json(&Color::gray(0.25)), json!({"gray": 0.25}));
}
}