mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-20 21:26:09 +08:00
Migrate 'Sample Polylines' from a subgraph to a proto node (#4063)
This commit is contained in:
@@ -1938,141 +1938,6 @@ fn document_node_definitions() -> HashMap<DefinitionIdentifier, DocumentNodeDefi
|
||||
description: Cow::Borrowed("TODO"),
|
||||
properties: None,
|
||||
},
|
||||
DocumentNodeDefinition {
|
||||
identifier: "Sample Polyline",
|
||||
category: "Vector: Modifier",
|
||||
node_template: NodeTemplate {
|
||||
document_node: DocumentNode {
|
||||
implementation: DocumentNodeImplementation::Network(NodeNetwork {
|
||||
exports: vec![NodeInput::node(NodeId(2), 0)],
|
||||
nodes: [
|
||||
DocumentNode {
|
||||
inputs: vec![NodeInput::import(concrete!(Table<Vector>), 0)],
|
||||
implementation: DocumentNodeImplementation::ProtoNode(vector::subpath_segment_lengths::IDENTIFIER),
|
||||
call_argument: generic!(T),
|
||||
..Default::default()
|
||||
},
|
||||
DocumentNode {
|
||||
inputs: vec![
|
||||
NodeInput::import(concrete!(Table<Vector>), 0),
|
||||
NodeInput::import(concrete!(vector::misc::PointSpacingType), 1),
|
||||
NodeInput::import(concrete!(f64), 2),
|
||||
NodeInput::import(concrete!(u32), 3),
|
||||
NodeInput::import(concrete!(f64), 4),
|
||||
NodeInput::import(concrete!(f64), 5),
|
||||
NodeInput::import(concrete!(bool), 6),
|
||||
NodeInput::node(NodeId(0), 0),
|
||||
],
|
||||
implementation: DocumentNodeImplementation::ProtoNode(vector::sample_polyline::IDENTIFIER),
|
||||
call_argument: generic!(T),
|
||||
..Default::default()
|
||||
},
|
||||
DocumentNode {
|
||||
inputs: vec![NodeInput::node(NodeId(1), 0)],
|
||||
implementation: DocumentNodeImplementation::ProtoNode(memo::memo::IDENTIFIER),
|
||||
call_argument: generic!(T),
|
||||
..Default::default()
|
||||
},
|
||||
]
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
.map(|(id, node)| (NodeId(id as u64), node))
|
||||
.collect(),
|
||||
..Default::default()
|
||||
}),
|
||||
inputs: vec![
|
||||
NodeInput::value(TaggedValue::Vector(Default::default()), true),
|
||||
NodeInput::value(TaggedValue::PointSpacingType(Default::default()), false),
|
||||
NodeInput::value(TaggedValue::F64(100.), false),
|
||||
NodeInput::value(TaggedValue::U32(100), false),
|
||||
NodeInput::value(TaggedValue::F64(0.), false),
|
||||
NodeInput::value(TaggedValue::F64(0.), false),
|
||||
NodeInput::value(TaggedValue::Bool(false), false),
|
||||
],
|
||||
..Default::default()
|
||||
},
|
||||
persistent_node_metadata: DocumentNodePersistentMetadata {
|
||||
network_metadata: Some(NodeNetworkMetadata {
|
||||
persistent_metadata: NodeNetworkPersistentMetadata {
|
||||
node_metadata: [
|
||||
DocumentNodeMetadata {
|
||||
persistent_metadata: DocumentNodePersistentMetadata {
|
||||
node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(0, 7)),
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
DocumentNodeMetadata {
|
||||
persistent_metadata: DocumentNodePersistentMetadata {
|
||||
node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(7, 0)),
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
DocumentNodeMetadata {
|
||||
persistent_metadata: DocumentNodePersistentMetadata {
|
||||
node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(14, 0)),
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
]
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
.map(|(id, node)| (NodeId(id as u64), node))
|
||||
.collect(),
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
}),
|
||||
input_metadata: vec![
|
||||
("Content", "The shape to be resampled and converted into a polyline.").into(),
|
||||
("Spacing", node_properties::SAMPLE_POLYLINE_DESCRIPTION_SPACING).into(),
|
||||
InputMetadata::with_name_description_override(
|
||||
"Separation",
|
||||
node_properties::SAMPLE_POLYLINE_DESCRIPTION_SEPARATION,
|
||||
WidgetOverride::Number(NumberInputSettings {
|
||||
min: Some(0.),
|
||||
unit: Some(" px".to_string()),
|
||||
..Default::default()
|
||||
}),
|
||||
),
|
||||
InputMetadata::with_name_description_override(
|
||||
"Quantity",
|
||||
node_properties::SAMPLE_POLYLINE_DESCRIPTION_QUANTITY,
|
||||
WidgetOverride::Number(NumberInputSettings {
|
||||
min: Some(2.),
|
||||
is_integer: true,
|
||||
..Default::default()
|
||||
}),
|
||||
),
|
||||
InputMetadata::with_name_description_override(
|
||||
"Start Offset",
|
||||
node_properties::SAMPLE_POLYLINE_DESCRIPTION_START_OFFSET,
|
||||
WidgetOverride::Number(NumberInputSettings {
|
||||
min: Some(0.),
|
||||
unit: Some(" px".to_string()),
|
||||
..Default::default()
|
||||
}),
|
||||
),
|
||||
InputMetadata::with_name_description_override(
|
||||
"Stop Offset",
|
||||
node_properties::SAMPLE_POLYLINE_DESCRIPTION_STOP_OFFSET,
|
||||
WidgetOverride::Number(NumberInputSettings {
|
||||
min: Some(0.),
|
||||
unit: Some(" px".to_string()),
|
||||
..Default::default()
|
||||
}),
|
||||
),
|
||||
("Adaptive Spacing", node_properties::SAMPLE_POLYLINE_DESCRIPTION_ADAPTIVE_SPACING).into(),
|
||||
],
|
||||
output_names: vec!["Vector".to_string()],
|
||||
..Default::default()
|
||||
},
|
||||
},
|
||||
description: Cow::Borrowed("Convert vector geometry into a polyline composed of evenly spaced points."),
|
||||
properties: Some("sample_polyline_properties"),
|
||||
},
|
||||
DocumentNodeDefinition {
|
||||
identifier: "Scatter Points",
|
||||
category: "Vector: Modifier",
|
||||
|
||||
@@ -94,6 +94,9 @@ const NODE_REPLACEMENTS: &[NodeReplacement<'static>] = &[
|
||||
"graphene_core::transform::FreezeRealTimeNode",
|
||||
"graphene_core::transform_nodes::BoundlessFootprintNode",
|
||||
"graphene_core::transform_nodes::FreezeRealTimeNode",
|
||||
// `subpath_segment_lengths` was inlined into the `sample_polyline` proto; old "Sample Polyline" subnetworks pass through unchanged.
|
||||
"graphene_core::vector::SubpathSegmentLengthsNode",
|
||||
"core_types::vector::SubpathSegmentLengthsNode",
|
||||
],
|
||||
},
|
||||
NodeReplacement {
|
||||
@@ -946,10 +949,6 @@ const NODE_REPLACEMENTS: &[NodeReplacement<'static>] = &[
|
||||
node: graphene_std::vector::stroke::IDENTIFIER,
|
||||
aliases: &["graphene_core::vector::StrokeNode"],
|
||||
},
|
||||
NodeReplacement {
|
||||
node: graphene_std::vector::subpath_segment_lengths::IDENTIFIER,
|
||||
aliases: &["graphene_core::vector::SubpathSegmentLengthsNode"],
|
||||
},
|
||||
NodeReplacement {
|
||||
node: graphene_std::vector::tangent_on_path::IDENTIFIER,
|
||||
aliases: &["graphene_core::vector::TangentOnPathNode"],
|
||||
@@ -1075,6 +1074,10 @@ pub fn document_migration_upgrades(document: &mut DocumentMessageHandler, reset_
|
||||
}
|
||||
|
||||
fn migrate_node(node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId], document: &mut DocumentMessageHandler, reset_node_definitions_on_open: bool) -> Option<()> {
|
||||
// Must run before the reset block below: a node referencing a removed catalog entry would otherwise abort
|
||||
// `migrate_node` via the `?` on `resolve_document_node_type`, preventing subsequent migration blocks from running.
|
||||
migrate_removed_catalog_definitions(node_id, node, network_path, document);
|
||||
|
||||
if reset_node_definitions_on_open && let Some(reference) = document.network_interface.reference(node_id, network_path) {
|
||||
let node_definition = resolve_document_node_type(&reference)?;
|
||||
document.network_interface.replace_implementation(node_id, network_path, &mut node_definition.default_node_template());
|
||||
@@ -2026,6 +2029,32 @@ fn migrate_node(node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId],
|
||||
Some(())
|
||||
}
|
||||
|
||||
/// Migrates document nodes whose catalog definitions have been removed.
|
||||
///
|
||||
/// This is called from `migrate_node` BEFORE its standard reset/migration logic, since that logic aborts when it can't
|
||||
/// resolve the node's `reference` against the current catalog. Each block here detects a specific decommissioned
|
||||
/// definition by its old reference name, swaps it to a still-supported implementation, and preserves the user's inputs.
|
||||
/// After this runs, the node's reference resolves cleanly so the rest of `migrate_node` proceeds normally.
|
||||
fn migrate_removed_catalog_definitions(node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId], document: &mut DocumentMessageHandler) -> Option<()> {
|
||||
// Collapse the legacy "Sample Polyline" wrapper network into the standalone `sample_polyline` proto.
|
||||
// The proto now computes per-bezpath segment lengths inline, so the wrapper's separate `subpath_segment_lengths`
|
||||
// and `Memo` nodes are no longer needed. The 7 user-facing inputs are positionally identical between the
|
||||
// old wrapper and the new proto.
|
||||
if let Some(DefinitionIdentifier::Network(name)) = document.network_interface.reference(node_id, network_path)
|
||||
&& name == "Sample Polyline"
|
||||
&& node.inputs.len() == 7
|
||||
{
|
||||
let mut node_template = resolve_proto_node_type(graphene_std::vector::sample_polyline::IDENTIFIER)?.default_node_template();
|
||||
document.network_interface.replace_implementation(node_id, network_path, &mut node_template);
|
||||
let old_inputs = document.network_interface.replace_inputs(node_id, network_path, &mut node_template)?;
|
||||
for (index, input) in old_inputs.iter().take(7).enumerate() {
|
||||
document.network_interface.set_input(&InputConnector::node(*node_id, index), input.clone(), network_path);
|
||||
}
|
||||
}
|
||||
|
||||
Some(())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
Reference in New Issue
Block a user