graphic design tool
git clone https://git.lucas.co/cce-designer.git
refactor: Visualize's Blend has no Mix; a save holding it loads as Set
Mix fell into Set's arm: Opacity fades every blend alike, so the two
were one option under two names. The merge turns a saved Mix into Set so
the row does not load as an invalid choice.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
nodes/visualize.json | 4 ++--
src/app.rs | 8 ++++++++
src/geometry.rs | 5 +++--
src/main.rs | 23 +++++++++++++++++++++++
4 files changed, 36 insertions(+), 4 deletions(-)
diff --git a/nodes/visualize.json b/nodes/visualize.json
index f8d1db8..6c05f59 100644
--- a/nodes/visualize.json
+++ b/nodes/visualize.json
@@ -52,10 +52,10 @@
},
{
"name": "Blend",
- "type": "choice:Set,Mix,Multiply,Add",
+ "type": "choice:Set,Multiply,Add",
"default": "Set",
"show_when": "Mode == Ramp",
- "description": "How the ramp colour meets the existing colour: Set and Mix replace it, Multiply tints it, Add brightens it. Opacity then fades toward the result."
+ "description": "How the ramp colour meets the existing colour: Set replaces it, Multiply tints it, Add brightens it. Opacity then fades toward the result."
},
{
"name": "Opacity",
diff --git a/src/app.rs b/src/app.rs
index 503e6b0..4c31883 100644
--- a/src/app.rs
+++ b/src/app.rs
@@ -1135,6 +1135,14 @@ pub fn merge_template_defs(root: &mut FsNode, templates: &[NodeTemplate]) {
}
}
fn merge_node(node: &mut FsNode, templates: &[NodeTemplate]) {
+ // Visualize's Mix blend was Set under another name (Opacity fades
+ // every blend alike) and is retired; a save holding it is Set, or
+ // it would load as a choice the row no longer offers.
+ if node.node_type == "visualize" {
+ if let Some(p) = node.params.iter_mut().find(|p| p.name == "Blend" && p.text().trim().eq_ignore_ascii_case("mix")) {
+ p.set_text("Set".to_string());
+ }
+ }
if let Some(t) = template_for(node, templates) {
let owns_impl = t.node_type.eq_ignore_ascii_case("node") && !t.children.is_empty();
let children_match = t.children.iter().all(|tc| {
diff --git a/src/geometry.rs b/src/geometry.rs
index f79339f..9e84663 100644
--- a/src/geometry.rs
+++ b/src/geometry.rs
@@ -3869,8 +3869,9 @@ pub(crate) fn apply_visualize(geom: &mut Detail, target: &FsNode, ocl_error: &mu
_ => c,
};
// Opacity is applied the same way for every blend, so a stack of
- // Visualize nodes fades uniformly and Mix is just Set at less than
- // full strength.
+ // Visualize nodes fades uniformly. (A Mix blend was Set by another
+ // name, this fade being all it did; it is retired, and a save
+ // holding it loads as Set.)
let out = [
old[0] + (mixed[0] - old[0]) * opacity,
old[1] + (mixed[1] - old[1]) * opacity,
diff --git a/src/main.rs b/src/main.rs
index 4c2823f..2bc4d56 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -4967,6 +4967,29 @@ mod tests {
.expect("a known kind is added");
}
+ /// Visualize's Blend has no Mix: it was Set under another name, Opacity
+ /// fading every blend alike. A save that chose it loads as Set, a
+ /// valid choice, rather than as a text the row no longer offers.
+ #[test]
+ fn visualize_mix_blend_loads_as_set() {
+ let templates_root = crate::app::load_fs_tree();
+ let templates = crate::app::flatten_node_templates(&templates_root);
+ let t = templates_root.children.iter().find(|t| t.node_type == "visualize").unwrap();
+ let blend = t.params.iter().find(|p| p.name == "Blend").unwrap();
+ assert_eq!(blend.choice_options(), vec!["Set", "Multiply", "Add"]);
+ let mut old = t.clone();
+ let p = old.params.iter_mut().find(|p| p.name == "Blend").unwrap();
+ p.set_type("choice:Set,Mix,Multiply,Add");
+ p.set_text("Mix".to_string());
+ assert!(p.invalid().is_none(), "the old row took Mix");
+ let mut root = templates_root.clone();
+ root.children = vec![old];
+ crate::app::merge_template_defs(&mut root, &templates);
+ let p = root.children[0].params.iter().find(|p| p.name == "Blend").unwrap();
+ assert_eq!(p.text(), "Set");
+ assert!(p.invalid().is_none(), "{:?}", p.invalid());
+ }
+
#[test]
fn test_loader_merges_new_template_params() {
let templates_root = crate::app::load_fs_tree();