diff --git a/editor/src/messages/frontend/frontend_message.rs b/editor/src/messages/frontend/frontend_message.rs index 89165f238b..0a24077c0a 100644 --- a/editor/src/messages/frontend/frontend_message.rs +++ b/editor/src/messages/frontend/frontend_message.rs @@ -2,6 +2,7 @@ use super::utility_types::{DocumentDetails, MouseCursorIcon, OpenDocument}; use crate::messages::app_window::app_window_message_handler::AppWindowPlatform; use crate::messages::input_mapper::utility_types::misc::ActionShortcut; use crate::messages::layout::utility_types::widget_prelude::*; +use crate::messages::portfolio::document::node_graph::document_node_definitions::DefinitionIdentifier; use crate::messages::portfolio::document::node_graph::utility_types::{ BoxSelection, ContextMenuInformation, FrontendClickTargets, FrontendGraphInput, FrontendGraphOutput, FrontendNode, FrontendNodeType, NodeGraphErrorDiagnostic, Transform, }; @@ -55,7 +56,7 @@ pub enum FrontendMessage { // Send prefix: Send global, static data to the frontend that is never updated SendUIMetadata { #[serde(rename = "nodeDescriptions")] - node_descriptions: Vec<(String, String)>, + node_descriptions: Vec<(DefinitionIdentifier, String)>, #[serde(rename = "nodeTypes")] node_types: Vec, }, diff --git a/editor/src/messages/layout/layout_message_handler.rs b/editor/src/messages/layout/layout_message_handler.rs index 0f4f75a6f2..ede4049985 100644 --- a/editor/src/messages/layout/layout_message_handler.rs +++ b/editor/src/messages/layout/layout_message_handler.rs @@ -326,11 +326,7 @@ impl LayoutMessageHandler { responses.add(callback_message); } WidgetValueAction::Update => { - let Some(value) = value.as_str().map(|s| s.to_string()) else { - error!("NodeCatalog update was not of type String"); - return; - }; - let callback_message = (node_type_input.on_update.callback)(&value); + let callback_message = (node_type_input.on_update.callback)(&value.into()); responses.add(callback_message); } }, diff --git a/editor/src/messages/layout/utility_types/widgets/input_widgets.rs b/editor/src/messages/layout/utility_types/widgets/input_widgets.rs index ca5bdbe279..d65db607f7 100644 --- a/editor/src/messages/layout/utility_types/widgets/input_widgets.rs +++ b/editor/src/messages/layout/utility_types/widgets/input_widgets.rs @@ -1,5 +1,6 @@ use crate::messages::input_mapper::utility_types::misc::ActionShortcut; use crate::messages::layout::utility_types::widget_prelude::*; +use crate::messages::portfolio::document::node_graph::document_node_definitions::DefinitionIdentifier; use derivative::*; use graphene_std::Color; use graphene_std::raster::curve::Curve; @@ -331,7 +332,7 @@ pub struct NodeCatalog { // Callbacks #[serde(skip)] #[derivative(Debug = "ignore", PartialEq = "ignore")] - pub on_update: WidgetCallback, + pub on_update: WidgetCallback, #[serde(skip)] #[derivative(Debug = "ignore", PartialEq = "ignore")] diff --git a/editor/src/messages/portfolio/document/document_message_handler.rs b/editor/src/messages/portfolio/document/document_message_handler.rs index 4f527cae94..d10804943f 100644 --- a/editor/src/messages/portfolio/document/document_message_handler.rs +++ b/editor/src/messages/portfolio/document/document_message_handler.rs @@ -12,6 +12,7 @@ use crate::messages::layout::utility_types::widget_prelude::*; use crate::messages::portfolio::document::data_panel::{DataPanelMessageContext, DataPanelMessageHandler}; use crate::messages::portfolio::document::graph_operation::utility_types::TransformIn; use crate::messages::portfolio::document::node_graph::NodeGraphMessageContext; +use crate::messages::portfolio::document::node_graph::document_node_definitions::DefinitionIdentifier; use crate::messages::portfolio::document::node_graph::utility_types::FrontendGraphDataType; use crate::messages::portfolio::document::overlays::grid_overlays::{grid_overlay, overlay_options}; use crate::messages::portfolio::document::overlays::utility_types::{OverlaysType, OverlaysVisibilitySettings}; @@ -1549,7 +1550,7 @@ impl MessageHandler> for DocumentMes // Create an artboard and set its dimensions to the bounding box size and location let node_id = NodeId::new(); let node_layer_id = LayerNodeIdentifier::new_unchecked(node_id); - let new_artboard_node = document_node_definitions::resolve_document_node_type("Artboard") + let new_artboard_node = document_node_definitions::resolve_document_node_type(&DefinitionIdentifier::Network("Artboard".to_string())) .expect("Failed to create artboard node") .default_node_template(); responses.add(NodeGraphMessage::InsertNode { @@ -2134,8 +2135,7 @@ impl DocumentMessageHandler { network_interface.upstream_flow_back_from_nodes(vec![selected_id.to_node()], &[], FlowType::HorizontalFlow).find(|id| { network_interface .reference(id, &[]) - .map(|name| name.as_deref().unwrap_or_default() == "Boolean Operation") - .unwrap_or_default() + .is_some_and(|reference| reference == DefinitionIdentifier::Network("Boolean Operation".to_string())) }) }); diff --git a/editor/src/messages/portfolio/document/graph_operation/graph_operation_message_handler.rs b/editor/src/messages/portfolio/document/graph_operation/graph_operation_message_handler.rs index 67dc579b85..09d0659453 100644 --- a/editor/src/messages/portfolio/document/graph_operation/graph_operation_message_handler.rs +++ b/editor/src/messages/portfolio/document/graph_operation/graph_operation_message_handler.rs @@ -1,6 +1,7 @@ use super::transform_utils; use super::utility_types::ModifyInputsContext; use crate::messages::portfolio::document::graph_operation::utility_types::TransformIn; +use crate::messages::portfolio::document::node_graph::document_node_definitions::DefinitionIdentifier; use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier; use crate::messages::portfolio::document::utility_types::network_interface::{InputConnector, NodeNetworkInterface, OutputConnector}; use crate::messages::portfolio::document::utility_types::nodes::CollapsedLayers; @@ -382,7 +383,7 @@ fn import_usvg_node(modify_inputs: &mut ModifyInputsContext, node: &usvg::Node, modify_inputs.insert_vector(subpaths, layer, true, path.fill().is_some(), path.stroke().is_some()); - if let Some(transform_node_id) = modify_inputs.existing_node_id("Transform", true) { + if let Some(transform_node_id) = modify_inputs.existing_node_id(&DefinitionIdentifier::Network("Transform".to_string()), true) { transform_utils::update_transform(modify_inputs.network_interface, &transform_node_id, transform * usvg_transform(node.abs_transform())); } diff --git a/editor/src/messages/portfolio/document/graph_operation/utility_types.rs b/editor/src/messages/portfolio/document/graph_operation/utility_types.rs index 8ecc086249..02fd8009a4 100644 --- a/editor/src/messages/portfolio/document/graph_operation/utility_types.rs +++ b/editor/src/messages/portfolio/document/graph_operation/utility_types.rs @@ -1,5 +1,5 @@ use super::transform_utils; -use crate::messages::portfolio::document::node_graph::document_node_definitions::resolve_document_node_type; +use crate::messages::portfolio::document::node_graph::document_node_definitions::{DefinitionIdentifier, resolve_document_node_type}; use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier; use crate::messages::portfolio::document::utility_types::network_interface::{self, InputConnector, NodeNetworkInterface, OutputConnector}; use crate::messages::prelude::*; @@ -123,30 +123,36 @@ impl<'a> ModifyInputsContext<'a> { /// Creates a new layer and adds it to the document network. network_interface.move_layer_to_stack should be called after pub fn create_layer(&mut self, new_id: NodeId) -> LayerNodeIdentifier { - let new_merge_node = resolve_document_node_type("Merge").expect("Merge node").default_node_template(); + let new_merge_node = resolve_document_node_type(&DefinitionIdentifier::Network("Merge".to_string())) + .expect("Merge node") + .default_node_template(); self.network_interface.insert_node(new_id, new_merge_node, &[]); LayerNodeIdentifier::new(new_id, self.network_interface) } /// Creates an artboard as the primary export for the document network pub fn create_artboard(&mut self, new_id: NodeId, artboard: Artboard) -> LayerNodeIdentifier { - let artboard_node_template = resolve_document_node_type("Artboard").expect("Node").node_template_input_override([ - Some(NodeInput::value(TaggedValue::Artboard(Default::default()), true)), - Some(NodeInput::value(TaggedValue::Graphic(Default::default()), true)), - Some(NodeInput::value(TaggedValue::DVec2(artboard.location.into()), false)), - Some(NodeInput::value(TaggedValue::DVec2(artboard.dimensions.into()), false)), - Some(NodeInput::value(TaggedValue::Color(Table::new_from_element(artboard.background)), false)), - Some(NodeInput::value(TaggedValue::Bool(artboard.clip), false)), - ]); + let artboard_node_template = resolve_document_node_type(&DefinitionIdentifier::Network("Artboard".to_string())) + .expect("Node") + .node_template_input_override([ + Some(NodeInput::value(TaggedValue::Artboard(Default::default()), true)), + Some(NodeInput::value(TaggedValue::Graphic(Default::default()), true)), + Some(NodeInput::value(TaggedValue::DVec2(artboard.location.into()), false)), + Some(NodeInput::value(TaggedValue::DVec2(artboard.dimensions.into()), false)), + Some(NodeInput::value(TaggedValue::Color(Table::new_from_element(artboard.background)), false)), + Some(NodeInput::value(TaggedValue::Bool(artboard.clip), false)), + ]); self.network_interface.insert_node(new_id, artboard_node_template, &[]); LayerNodeIdentifier::new(new_id, self.network_interface) } pub fn insert_boolean_data(&mut self, operation: graphene_std::path_bool::BooleanOperation, layer: LayerNodeIdentifier) { - let boolean = resolve_document_node_type("Boolean Operation").expect("Boolean node does not exist").node_template_input_override([ - Some(NodeInput::value(TaggedValue::Graphic(Default::default()), true)), - Some(NodeInput::value(TaggedValue::BooleanOperation(operation), false)), - ]); + let boolean = resolve_document_node_type(&DefinitionIdentifier::Network("Boolean Operation".to_string())) + .expect("Boolean node does not exist") + .node_template_input_override([ + Some(NodeInput::value(TaggedValue::Graphic(Default::default()), true)), + Some(NodeInput::value(TaggedValue::BooleanOperation(operation), false)), + ]); let boolean_id = NodeId::new(); self.network_interface.insert_node(boolean_id, boolean, &[]); @@ -156,7 +162,7 @@ impl<'a> ModifyInputsContext<'a> { pub fn insert_vector(&mut self, subpaths: Vec>, layer: LayerNodeIdentifier, include_transform: bool, include_fill: bool, include_stroke: bool) { let vector = Table::new_from_element(Vector::from_subpaths(subpaths, true)); - let shape = resolve_document_node_type("Path") + let shape = resolve_document_node_type(&DefinitionIdentifier::Network("Path".to_string())) .expect("Path node does not exist") .node_template_input_override([Some(NodeInput::value(TaggedValue::Vector(vector), false))]); let shape_id = NodeId::new(); @@ -164,21 +170,27 @@ impl<'a> ModifyInputsContext<'a> { self.network_interface.move_node_to_chain_start(&shape_id, layer, &[]); if include_transform { - let transform = resolve_document_node_type("Transform").expect("Transform node does not exist").default_node_template(); + let transform = resolve_document_node_type(&DefinitionIdentifier::Network("Transform".to_string())) + .expect("Transform node does not exist") + .default_node_template(); let transform_id = NodeId::new(); self.network_interface.insert_node(transform_id, transform, &[]); self.network_interface.move_node_to_chain_start(&transform_id, layer, &[]); } if include_fill { - let fill = resolve_document_node_type("Fill").expect("Fill node does not exist").default_node_template(); + let fill = resolve_document_node_type(&DefinitionIdentifier::ProtoNode(graphene_std::vector_nodes::fill::IDENTIFIER)) + .expect("Fill node does not exist") + .default_node_template(); let fill_id = NodeId::new(); self.network_interface.insert_node(fill_id, fill, &[]); self.network_interface.move_node_to_chain_start(&fill_id, layer, &[]); } if include_stroke { - let stroke = resolve_document_node_type("Stroke").expect("Stroke node does not exist").default_node_template(); + let stroke = resolve_document_node_type(&DefinitionIdentifier::ProtoNode(graphene_std::vector_nodes::stroke::IDENTIFIER)) + .expect("Stroke node does not exist") + .default_node_template(); let stroke_id = NodeId::new(); self.network_interface.insert_node(stroke_id, stroke, &[]); self.network_interface.move_node_to_chain_start(&stroke_id, layer, &[]); @@ -186,21 +198,29 @@ impl<'a> ModifyInputsContext<'a> { } pub fn insert_text(&mut self, text: String, font: Font, typesetting: TypesettingConfig, layer: LayerNodeIdentifier) { - let stroke = resolve_document_node_type("Stroke").expect("Stroke node does not exist").default_node_template(); - let fill = resolve_document_node_type("Fill").expect("Fill node does not exist").default_node_template(); - let transform = resolve_document_node_type("Transform").expect("Transform node does not exist").default_node_template(); - let text = resolve_document_node_type("Text").expect("Text node does not exist").node_template_input_override([ - Some(NodeInput::scope("editor-api")), - Some(NodeInput::value(TaggedValue::String(text), false)), - Some(NodeInput::value(TaggedValue::Font(font), false)), - Some(NodeInput::value(TaggedValue::F64(typesetting.font_size), false)), - Some(NodeInput::value(TaggedValue::F64(typesetting.line_height_ratio), false)), - Some(NodeInput::value(TaggedValue::F64(typesetting.character_spacing), false)), - Some(NodeInput::value(TaggedValue::OptionalF64(typesetting.max_width), false)), - Some(NodeInput::value(TaggedValue::OptionalF64(typesetting.max_height), false)), - Some(NodeInput::value(TaggedValue::F64(typesetting.tilt), false)), - Some(NodeInput::value(TaggedValue::TextAlign(typesetting.align), false)), - ]); + let stroke = resolve_document_node_type(&DefinitionIdentifier::ProtoNode(graphene_std::vector_nodes::stroke::IDENTIFIER)) + .expect("Stroke node does not exist") + .default_node_template(); + let fill = resolve_document_node_type(&DefinitionIdentifier::ProtoNode(graphene_std::vector_nodes::fill::IDENTIFIER)) + .expect("Fill node does not exist") + .default_node_template(); + let transform = resolve_document_node_type(&DefinitionIdentifier::Network("Transform".to_string())) + .expect("Transform node does not exist") + .default_node_template(); + let text = resolve_document_node_type(&DefinitionIdentifier::Network("Text".to_string())) + .expect("Text node does not exist") + .node_template_input_override([ + Some(NodeInput::scope("editor-api")), + Some(NodeInput::value(TaggedValue::String(text), false)), + Some(NodeInput::value(TaggedValue::Font(font), false)), + Some(NodeInput::value(TaggedValue::F64(typesetting.font_size), false)), + Some(NodeInput::value(TaggedValue::F64(typesetting.line_height_ratio), false)), + Some(NodeInput::value(TaggedValue::F64(typesetting.character_spacing), false)), + Some(NodeInput::value(TaggedValue::OptionalF64(typesetting.max_width), false)), + Some(NodeInput::value(TaggedValue::OptionalF64(typesetting.max_height), false)), + Some(NodeInput::value(TaggedValue::F64(typesetting.tilt), false)), + Some(NodeInput::value(TaggedValue::TextAlign(typesetting.align), false)), + ]); let text_id = NodeId::new(); self.network_interface.insert_node(text_id, text, &[]); @@ -220,8 +240,10 @@ impl<'a> ModifyInputsContext<'a> { } pub fn insert_image_data(&mut self, image_frame: Table>, layer: LayerNodeIdentifier) { - let transform = resolve_document_node_type("Transform").expect("Transform node does not exist").default_node_template(); - let image = resolve_document_node_type("Image Value") + let transform = resolve_document_node_type(&DefinitionIdentifier::Network("Transform".to_string())) + .expect("Transform node does not exist") + .default_node_template(); + let image = resolve_document_node_type(&DefinitionIdentifier::ProtoNode(graphene_std::raster_nodes::std_nodes::image_value::IDENTIFIER)) .expect("ImageValue node does not exist") .node_template_input_override([Some(NodeInput::value(TaggedValue::None, false)), Some(NodeInput::value(TaggedValue::Raster(image_frame), false))]); @@ -248,15 +270,15 @@ impl<'a> ModifyInputsContext<'a> { /// Gets the node id of a node with a specific reference that is upstream from the layer node, and optionally creates it if it does not exist. /// The returned node is based on the selection dots in the layer. The right most dot will always insert/access the path that flows directly into the layer. /// Each dot after that represents an existing path node. If there is an existing upstream node, then it will always be returned first. - pub fn existing_node_id(&mut self, reference_name: &'static str, create_if_nonexistent: bool) -> Option { + pub fn existing_node_id(&mut self, reference: &DefinitionIdentifier, create_if_nonexistent: bool) -> Option { // Start from the layer node or export let output_layer = self.get_output_layer()?; - let existing_node_id = Self::locate_node_in_layer_chain(reference_name, output_layer, self.network_interface); + let existing_node_id = Self::locate_node_in_layer_chain(reference, output_layer, self.network_interface); // Create a new node if the node does not exist and update its inputs if create_if_nonexistent { - return existing_node_id.or_else(|| self.create_node(reference_name)); + return existing_node_id.or_else(|| self.create_node(reference)); } existing_node_id @@ -265,16 +287,13 @@ impl<'a> ModifyInputsContext<'a> { /// Gets the node id of a node with a specific reference (name) that is upstream (leftward) from the layer node, but before reaching another upstream layer stack. /// For example, if given a parent layer, this would find a requested "Transform" or "Boolean Operation" node in its chain, between the parent layer and its layer stack child contents. /// It would also travel up an entire layer that's not fed by a stack until reaching the generator node, such as a "Rectangle" or "Path" layer. - pub fn locate_node_in_layer_chain(reference_name: &str, left_of_layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option { + pub fn locate_node_in_layer_chain(reference: &DefinitionIdentifier, left_of_layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option { let upstream = network_interface.upstream_flow_back_from_nodes(vec![left_of_layer.to_node()], &[], network_interface::FlowType::HorizontalFlow); // Look at all of the upstream nodes for upstream_node in upstream { // Check if this is the node we have been searching for. - if network_interface - .reference(&upstream_node, &[]) - .is_some_and(|node_reference| *node_reference == Some(reference_name.to_string())) - { + if network_interface.reference(&upstream_node, &[]).is_some_and(|node_reference| node_reference == *reference) { if !network_interface.is_visible(&upstream_node, &[]) { continue; } @@ -293,10 +312,10 @@ impl<'a> ModifyInputsContext<'a> { } /// Create a new node inside the layer - pub fn create_node(&mut self, reference: &str) -> Option { + pub fn create_node(&mut self, reference: &DefinitionIdentifier) -> Option { let output_layer = self.get_output_layer()?; let Some(node_definition) = resolve_document_node_type(reference) else { - log::error!("Node type {reference} does not exist in ModifyInputsContext::existing_node_id"); + log::error!("Node {reference:?} does not exist in ModifyInputsContext::existing_node_id"); return None; }; @@ -305,7 +324,7 @@ impl<'a> ModifyInputsContext<'a> { if node_definition.identifier == "Path" { let layer_input_type = self.network_interface.input_type(&InputConnector::node(output_layer.to_node(), 1), &[]); if layer_input_type.compiled_nested_type() == Some(&concrete!(Table)) { - let Some(flatten_path_definition) = resolve_document_node_type("Flatten Path") else { + let Some(flatten_path_definition) = resolve_document_node_type(&DefinitionIdentifier::ProtoNode(graphene_std::vector_nodes::flatten_path::IDENTIFIER)) else { log::error!("Flatten Path does not exist in ModifyInputsContext::existing_node_id"); return None; }; @@ -325,7 +344,9 @@ impl<'a> ModifyInputsContext<'a> { let backup_color_index = 2; let backup_gradient_index = 3; - let Some(fill_node_id) = self.existing_node_id("Fill", true) else { return }; + let Some(fill_node_id) = self.existing_node_id(&DefinitionIdentifier::ProtoNode(graphene_std::vector_nodes::fill::IDENTIFIER), true) else { + return; + }; match &fill { Fill::None => { let input_connector = InputConnector::node(fill_node_id, backup_color_index); @@ -345,32 +366,42 @@ impl<'a> ModifyInputsContext<'a> { } pub fn blend_mode_set(&mut self, blend_mode: BlendMode) { - let Some(blend_node_id) = self.existing_node_id("Blending", true) else { return }; + let Some(blend_node_id) = self.existing_node_id(&DefinitionIdentifier::ProtoNode(graphene_std::blending_nodes::blending::IDENTIFIER), true) else { + return; + }; let input_connector = InputConnector::node(blend_node_id, 1); self.set_input_with_refresh(input_connector, NodeInput::value(TaggedValue::BlendMode(blend_mode), false), false); } pub fn opacity_set(&mut self, opacity: f64) { - let Some(blend_node_id) = self.existing_node_id("Blending", true) else { return }; + let Some(blend_node_id) = self.existing_node_id(&DefinitionIdentifier::ProtoNode(graphene_std::blending_nodes::blending::IDENTIFIER), true) else { + return; + }; let input_connector = InputConnector::node(blend_node_id, 2); self.set_input_with_refresh(input_connector, NodeInput::value(TaggedValue::F64(opacity * 100.), false), false); } pub fn blending_fill_set(&mut self, fill: f64) { - let Some(blend_node_id) = self.existing_node_id("Blending", true) else { return }; + let Some(blend_node_id) = self.existing_node_id(&DefinitionIdentifier::ProtoNode(graphene_std::blending_nodes::blending::IDENTIFIER), true) else { + return; + }; let input_connector = InputConnector::node(blend_node_id, 3); self.set_input_with_refresh(input_connector, NodeInput::value(TaggedValue::F64(fill * 100.), false), false); } pub fn clip_mode_toggle(&mut self, clip_mode: Option) { let clip = !clip_mode.unwrap_or(false); - let Some(clip_node_id) = self.existing_node_id("Blending", true) else { return }; + let Some(clip_node_id) = self.existing_node_id(&DefinitionIdentifier::ProtoNode(graphene_std::blending_nodes::blending::IDENTIFIER), true) else { + return; + }; let input_connector = InputConnector::node(clip_node_id, 4); self.set_input_with_refresh(input_connector, NodeInput::value(TaggedValue::Bool(clip), false), false); } pub fn stroke_set(&mut self, stroke: Stroke) { - let Some(stroke_node_id) = self.existing_node_id("Stroke", true) else { return }; + let Some(stroke_node_id) = self.existing_node_id(&DefinitionIdentifier::ProtoNode(graphene_std::vector::stroke::IDENTIFIER), true) else { + return; + }; let stroke_color = if let Some(color) = stroke.color { Table::new_from_element(color) } else { Table::new() }; @@ -399,7 +430,7 @@ impl<'a> ModifyInputsContext<'a> { pub fn transform_change_with_parent(&mut self, transform: DAffine2, transform_in: TransformIn, parent_transform: DAffine2, skip_rerender: bool) { // Get the existing upstream Transform node and its transform, if present, otherwise use the identity transform let (layer_transform, transform_node_id) = self - .existing_node_id("Transform", false) + .existing_node_id(&DefinitionIdentifier::Network("Transform".to_string()), false) .and_then(|transform_node_id| { let document_node = self.network_interface.document_network().nodes.get(&transform_node_id)?; Some((transform_utils::get_current_transform(&document_node.inputs), transform_node_id)) @@ -423,7 +454,7 @@ impl<'a> ModifyInputsContext<'a> { /// A new Transform node is created if one does not exist, unless it would be given the identity transform. pub fn transform_set(&mut self, transform: DAffine2, transform_in: TransformIn, skip_rerender: bool) { // Get the existing upstream Transform node, if present - let transform_node_id = self.existing_node_id("Transform", false); + let transform_node_id = self.existing_node_id(&DefinitionIdentifier::Network("Transform".to_string()), false); // Get a transform appropriate for the requested space let to_transform = match transform_in { @@ -448,7 +479,7 @@ impl<'a> ModifyInputsContext<'a> { } // Create the Transform node - self.existing_node_id("Transform", true) + self.existing_node_id(&DefinitionIdentifier::Network("Transform".to_string()), true) }) else { return; }; @@ -464,19 +495,23 @@ impl<'a> ModifyInputsContext<'a> { } pub fn vector_modify(&mut self, modification_type: VectorModificationType) { - let Some(path_node_id) = self.existing_node_id("Path", true) else { return }; + let Some(path_node_id) = self.existing_node_id(&DefinitionIdentifier::Network("Path".to_string()), true) else { + return; + }; self.network_interface.vector_modify(&path_node_id, modification_type); self.responses.add(PropertiesPanelMessage::Refresh); self.responses.add(NodeGraphMessage::RunDocumentGraph); } pub fn brush_modify(&mut self, strokes: Vec) { - let Some(brush_node_id) = self.existing_node_id("Brush", true) else { return }; + let Some(brush_node_id) = self.existing_node_id(&DefinitionIdentifier::Network("Brush".to_string()), true) else { + return; + }; self.set_input_with_refresh(InputConnector::node(brush_node_id, 1), NodeInput::value(TaggedValue::BrushStrokes(strokes), false), false); } pub fn resize_artboard(&mut self, location: IVec2, dimensions: IVec2) { - let Some(artboard_node_id) = self.existing_node_id("Artboard", true) else { + let Some(artboard_node_id) = self.existing_node_id(&DefinitionIdentifier::Network("Artboard".to_string()), true) else { return; }; diff --git a/editor/src/messages/portfolio/document/node_graph/document_node_definitions.rs b/editor/src/messages/portfolio/document/node_graph/document_node_definitions.rs index 61f00fc18c..fbb6e12158 100644 --- a/editor/src/messages/portfolio/document/node_graph/document_node_definitions.rs +++ b/editor/src/messages/portfolio/document/node_graph/document_node_definitions.rs @@ -26,7 +26,8 @@ use graphene_std::text::{Font, TypesettingConfig}; use graphene_std::transform::Footprint; use graphene_std::vector::Vector; use graphene_std::*; -use std::collections::{HashMap, HashSet, VecDeque}; +use serde_json::Value; +use std::collections::{HashMap, VecDeque}; pub struct NodePropertiesContext<'a> { pub persistent_data: &'a PersistentData, @@ -54,10 +55,47 @@ impl NodePropertiesContext<'_> { } } +/// The key used to access definitions for a Network node or Protonode +// For protonodes this is their ProtonodeIdentifier. +// For network nodes it is their display name by default, but could be something else +#[derive(Debug, Clone, Hash, Eq, PartialEq, serde::Serialize, serde::Deserialize, specta::Type)] +#[serde(tag = "type", content = "data")] +pub enum DefinitionIdentifier { + Network(String), + ProtoNode(ProtoNodeIdentifier), +} + +impl From for DefinitionIdentifier { + fn from(value: Value) -> Self { + match value { + Value::Object(mut map) => { + let typ = map.remove("type").unwrap().as_str().unwrap().to_owned(); + + match typ.as_ref() { + "Network" => { + let data = map.remove("data").unwrap().as_str().unwrap().to_owned(); + DefinitionIdentifier::Network(data) + } + "ProtoNode" => { + let data_val = map.remove("data").unwrap(); + let proto: ProtoNodeIdentifier = serde_json::from_value(data_val).unwrap(); + DefinitionIdentifier::ProtoNode(proto) + } + + _ => panic!("Unknown DefinitionIdentifier type: {:?}", typ), + } + } + + _ => panic!("Expected a JSON object to convert to DefinitionIdentifier"), + } + } +} + /// Acts as a description for a [DocumentNode] before it gets instantiated as one. -#[derive(Clone)] +/// TODO: Use this to prevent storing a copy of the implementation, if the document node is unchanged from the definition. +#[derive(Debug, Clone)] pub struct DocumentNodeDefinition { - /// Used by the reference field in [`DocumentNodeMetadata`] to prevent storing a copy of the implementation, if it is unchanged from the definition. + /// Used to create the DefinitionIdentifier::Network identifier pub identifier: &'static str, /// All data required to construct a [`DocumentNode`] and [`DocumentNodeMetadata`] @@ -75,14 +113,14 @@ pub struct DocumentNodeDefinition { pub properties: Option<&'static str>, } -// We use the once cell for lazy initialization to avoid the overhead of reconstructing the node list every time. -// TODO: make document nodes not require a `'static` lifetime to avoid having to split the construction into const and non-const parts. -static DOCUMENT_NODE_TYPES: once_cell::sync::Lazy> = once_cell::sync::Lazy::new(static_nodes); +// We use the once cell to use the document node definitions throughout the editor without passing a reference +// TODO: If dynamic node library is required, use a Mutex as well +static DOCUMENT_NODE_TYPES: once_cell::sync::Lazy> = once_cell::sync::Lazy::new(node_definitions); -// TODO: Dynamic node library /// Defines the "signature" or "header file"-like metadata for the document nodes, but not the implementation (which is defined in the node registry). /// The [`DocumentNode`] is the instance while these [`DocumentNodeDefinition`]s are the "classes" or "blueprints" from which the instances are built. -fn static_nodes() -> Vec { +/// Only the position can be set for protonodes within a definition. The rest of the metadata comes from the node macro in NODE_METADATA +fn node_definitions() -> HashMap { let custom = vec![ // TODO: Auto-generate this from its proto node macro DocumentNodeDefinition { @@ -224,7 +262,6 @@ fn static_nodes() -> Vec { node_metadata: [ DocumentNodeMetadata { persistent_metadata: DocumentNodePersistentMetadata { - display_name: "To Graphic".to_string(), node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(-21, -3)), ..Default::default() }, @@ -232,7 +269,6 @@ fn static_nodes() -> Vec { }, DocumentNodeMetadata { persistent_metadata: DocumentNodePersistentMetadata { - display_name: "Wrap Graphic".to_string(), node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(-21, -1)), ..Default::default() }, @@ -240,7 +276,6 @@ fn static_nodes() -> Vec { }, DocumentNodeMetadata { persistent_metadata: DocumentNodePersistentMetadata { - display_name: "Source Node ID".to_string(), node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(-14, -1)), ..Default::default() }, @@ -248,7 +283,6 @@ fn static_nodes() -> Vec { }, DocumentNodeMetadata { persistent_metadata: DocumentNodePersistentMetadata { - display_name: "Monitor".to_string(), node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(-7, -1)), ..Default::default() }, @@ -256,7 +290,6 @@ fn static_nodes() -> Vec { }, DocumentNodeMetadata { persistent_metadata: DocumentNodePersistentMetadata { - display_name: "Extend".to_string(), node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(0, -3)), ..Default::default() }, @@ -375,7 +408,6 @@ fn static_nodes() -> Vec { node_metadata: [ DocumentNodeMetadata { persistent_metadata: DocumentNodePersistentMetadata { - display_name: "Create Artboard".to_string(), node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(-21, -3)), ..Default::default() }, @@ -383,7 +415,6 @@ fn static_nodes() -> Vec { }, DocumentNodeMetadata { persistent_metadata: DocumentNodePersistentMetadata { - display_name: "Source Node ID".to_string(), node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(-14, -3)), ..Default::default() }, @@ -391,7 +422,6 @@ fn static_nodes() -> Vec { }, DocumentNodeMetadata { persistent_metadata: DocumentNodePersistentMetadata { - display_name: "Monitor".to_string(), node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(-7, -3)), ..Default::default() }, @@ -399,7 +429,6 @@ fn static_nodes() -> Vec { }, DocumentNodeMetadata { persistent_metadata: DocumentNodePersistentMetadata { - display_name: "Extend".to_string(), node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(0, -4)), ..Default::default() }, @@ -989,7 +1018,6 @@ fn static_nodes() -> Vec { node_metadata: [ DocumentNodeMetadata { persistent_metadata: DocumentNodePersistentMetadata { - display_name: "Load Resource".to_string(), node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(0, 0)), ..Default::default() }, @@ -997,7 +1025,6 @@ fn static_nodes() -> Vec { }, DocumentNodeMetadata { persistent_metadata: DocumentNodePersistentMetadata { - display_name: "Decode Image".to_string(), node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(7, 0)), ..Default::default() }, @@ -1071,7 +1098,6 @@ fn static_nodes() -> Vec { node_metadata: [ DocumentNodeMetadata { persistent_metadata: DocumentNodePersistentMetadata { - display_name: "Create Surface".to_string(), node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(0, 2)), ..Default::default() }, @@ -1079,7 +1105,6 @@ fn static_nodes() -> Vec { }, DocumentNodeMetadata { persistent_metadata: DocumentNodePersistentMetadata { - display_name: "Cache".to_string(), node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(7, 2)), ..Default::default() }, @@ -1087,7 +1112,6 @@ fn static_nodes() -> Vec { }, DocumentNodeMetadata { persistent_metadata: DocumentNodePersistentMetadata { - display_name: "Rasterize".to_string(), node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(14, 0)), ..Default::default() }, @@ -1113,7 +1137,7 @@ fn static_nodes() -> Vec { category: "Raster: Pattern", node_template: NodeTemplate { document_node: DocumentNode { - implementation: DocumentNodeImplementation::ProtoNode(raster_nodes::std_nodes::noise_pattern::IDENTIFIER), + implementation: DocumentNodeImplementation::ProtoNode(graphene_std::raster_nodes::std_nodes::noise_pattern::IDENTIFIER), inputs: vec![ NodeInput::value(TaggedValue::None, false), NodeInput::value(TaggedValue::Bool(true), false), @@ -1228,7 +1252,6 @@ fn static_nodes() -> Vec { node_metadata: [ DocumentNodeMetadata { persistent_metadata: DocumentNodePersistentMetadata { - display_name: "Extract Channel".to_string(), node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(0, 0)), ..Default::default() }, @@ -1236,7 +1259,6 @@ fn static_nodes() -> Vec { }, DocumentNodeMetadata { persistent_metadata: DocumentNodePersistentMetadata { - display_name: "Extract Channel".to_string(), node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(0, 2)), ..Default::default() }, @@ -1244,7 +1266,6 @@ fn static_nodes() -> Vec { }, DocumentNodeMetadata { persistent_metadata: DocumentNodePersistentMetadata { - display_name: "Extract Channel".to_string(), node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(0, 4)), ..Default::default() }, @@ -1252,7 +1273,6 @@ fn static_nodes() -> Vec { }, DocumentNodeMetadata { persistent_metadata: DocumentNodePersistentMetadata { - display_name: "Extract Channel".to_string(), node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(0, 6)), ..Default::default() }, @@ -1312,7 +1332,6 @@ fn static_nodes() -> Vec { node_metadata: [ DocumentNodeMetadata { persistent_metadata: DocumentNodePersistentMetadata { - display_name: "Extract XY".to_string(), node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(0, 0)), ..Default::default() }, @@ -1320,7 +1339,6 @@ fn static_nodes() -> Vec { }, DocumentNodeMetadata { persistent_metadata: DocumentNodePersistentMetadata { - display_name: "Extract XY".to_string(), node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(0, 2)), ..Default::default() }, @@ -1382,7 +1400,6 @@ fn static_nodes() -> Vec { persistent_metadata: NodeNetworkPersistentMetadata { node_metadata: [DocumentNodeMetadata { persistent_metadata: DocumentNodePersistentMetadata { - display_name: "Brush".to_string(), node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(0, 0)), ..Default::default() }, @@ -1463,7 +1480,6 @@ fn static_nodes() -> Vec { node_metadata: [ DocumentNodeMetadata { persistent_metadata: DocumentNodePersistentMetadata { - display_name: "Extract Executor".to_string(), node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(0, 0)), ..Default::default() }, @@ -1471,7 +1487,6 @@ fn static_nodes() -> Vec { }, DocumentNodeMetadata { persistent_metadata: DocumentNodePersistentMetadata { - display_name: "Upload Texture".to_string(), node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(7, 0)), ..Default::default() }, @@ -1479,7 +1494,6 @@ fn static_nodes() -> Vec { }, DocumentNodeMetadata { persistent_metadata: DocumentNodePersistentMetadata { - display_name: "Cache".to_string(), node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(14, 0)), ..Default::default() }, @@ -1592,7 +1606,6 @@ fn static_nodes() -> Vec { node_metadata: [ DocumentNodeMetadata { persistent_metadata: DocumentNodePersistentMetadata { - display_name: "Monitor".to_string(), node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(0, 0)), ..Default::default() }, @@ -1600,7 +1613,6 @@ fn static_nodes() -> Vec { }, DocumentNodeMetadata { persistent_metadata: DocumentNodePersistentMetadata { - display_name: "Path Modify".to_string(), node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(7, 0)), ..Default::default() }, @@ -1788,7 +1800,6 @@ fn static_nodes() -> Vec { node_metadata: [ DocumentNodeMetadata { persistent_metadata: DocumentNodePersistentMetadata { - display_name: "Monitor".to_string(), node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(0, 0)), ..Default::default() }, @@ -1796,15 +1807,7 @@ fn static_nodes() -> Vec { }, DocumentNodeMetadata { persistent_metadata: DocumentNodePersistentMetadata { - display_name: "Transform".to_string(), node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(7, 0)), - input_metadata: vec![ - ("Value", "TODO").into(), - ("Translation", "TODO").into(), - ("Rotation", "TODO").into(), - ("Scale", "TODO").into(), - ("Skew", "TODO").into(), - ], ..Default::default() }, ..Default::default() @@ -1891,7 +1894,6 @@ fn static_nodes() -> Vec { node_metadata: [ DocumentNodeMetadata { persistent_metadata: DocumentNodePersistentMetadata { - display_name: "Boolean Operation".to_string(), node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(0, 0)), ..Default::default() }, @@ -1899,7 +1901,6 @@ fn static_nodes() -> Vec { }, DocumentNodeMetadata { persistent_metadata: DocumentNodePersistentMetadata { - display_name: "Memoize".to_string(), node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(7, 0)), ..Default::default() }, @@ -1981,7 +1982,6 @@ fn static_nodes() -> Vec { node_metadata: [ DocumentNodeMetadata { persistent_metadata: DocumentNodePersistentMetadata { - display_name: "Subpath Segment Lengths".to_string(), node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(0, 7)), ..Default::default() }, @@ -1989,7 +1989,6 @@ fn static_nodes() -> Vec { }, DocumentNodeMetadata { persistent_metadata: DocumentNodePersistentMetadata { - display_name: "Sample Polyline".to_string(), node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(7, 0)), ..Default::default() }, @@ -1997,7 +1996,6 @@ fn static_nodes() -> Vec { }, DocumentNodeMetadata { persistent_metadata: DocumentNodePersistentMetadata { - display_name: "Memoize".to_string(), node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(14, 0)), ..Default::default() }, @@ -2104,7 +2102,6 @@ fn static_nodes() -> Vec { node_metadata: [ DocumentNodeMetadata { persistent_metadata: DocumentNodePersistentMetadata { - display_name: "Poisson-Disk Points".to_string(), node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(0, 0)), ..Default::default() }, @@ -2112,7 +2109,6 @@ fn static_nodes() -> Vec { }, DocumentNodeMetadata { persistent_metadata: DocumentNodePersistentMetadata { - display_name: "Memoize".to_string(), node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(7, 0)), ..Default::default() }, @@ -2637,102 +2633,56 @@ fn static_input_properties() -> InputProperties { map } -pub fn resolve_document_node_type(identifier: &str) -> Option<&DocumentNodeDefinition> { - DOCUMENT_NODE_TYPES.iter().find(|definition| definition.identifier == identifier) +pub fn resolve_document_node_type(identifier: &DefinitionIdentifier) -> Option<&'static DocumentNodeDefinition> { + DOCUMENT_NODE_TYPES.get(identifier) } -pub fn collect_node_types() -> Vec { - // Create a mapping from registry ID to document node identifier - let id_to_identifier_map: HashMap = DOCUMENT_NODE_TYPES - .iter() - .filter_map(|definition| { - if let DocumentNodeImplementation::ProtoNode(name) = &definition.node_template.document_node.implementation { - Some((name.clone(), definition.identifier)) - } else { - None - } - }) - .collect(); - let mut extracted_node_types = Vec::new(); - - let node_registry = registry::NODE_REGISTRY.lock().unwrap(); - let node_metadata = registry::NODE_METADATA.lock().unwrap(); - for (id, metadata) in node_metadata.iter() { - if let Some(implementations) = node_registry.get(id) { - let identifier = match id_to_identifier_map.get(id) { - Some(&id) => id, - None => continue, - }; - - // Extract category from metadata (already creates an owned String) - let category = metadata.category.unwrap_or_default(); - - // Extract input types (already creates owned Strings) - let input_types = implementations - .iter() - .flat_map(|(_, node_io)| node_io.inputs.iter().map(|ty| ty.nested_type().to_cow_string())) - .collect::>>() - .into_iter() - .collect::>>(); - - // Create a FrontendNodeType - let node_type = FrontendNodeType::with_input_types(identifier, category, input_types); - - // Store the created node_type - extracted_node_types.push(node_type); - } +pub fn implementation_name_from_identifier(identifier: &DefinitionIdentifier) -> String { + match identifier { + DefinitionIdentifier::Network(name) => name.clone(), + DefinitionIdentifier::ProtoNode(proto_node_identifier) => registry::NODE_METADATA + .lock() + .unwrap() + .get(proto_node_identifier) + .map(|metadata| metadata.display_name.to_string()) + .unwrap_or_else(|| { + let mut last_segment = proto_node_identifier.name.split("::").last().unwrap_or_default().to_string(); + last_segment = last_segment.strip_suffix("Node").unwrap_or(&last_segment).to_string(); + last_segment + }), } +} - let node_types: Vec = DOCUMENT_NODE_TYPES +pub fn collect_node_types() -> Vec { + DOCUMENT_NODE_TYPES .iter() - .filter(|definition| !definition.category.is_empty()) - .map(|definition| { + .filter(|(_, definition)| !definition.category.is_empty()) + .map(|(identifier, definition)| { let input_types = definition .node_template .document_node .inputs .iter() - .filter_map(|node_input| node_input.as_value().map(|node_value| node_value.ty().nested_type().to_cow_string())) - .collect::>>(); - - FrontendNodeType::with_input_types(definition.identifier, definition.category, input_types) - }) - .collect(); - - // Update categories in extracted_node_types from node_types - for extracted_node in &mut extracted_node_types { - if extracted_node.category.is_empty() { - // Find matching node in node_types and update category if found - if let Some(matching_node) = node_types.iter().find(|node_type| node_type.name == extracted_node.name) { - extracted_node.category = matching_node.category.clone(); + .map(|node_input| node_input.as_value().map(|node_value| node_value.ty().nested_type().to_string()).unwrap_or_default()) + .collect::>(); + let mut name = definition.node_template.persistent_node_metadata.display_name.clone(); + if name.is_empty() { + name = implementation_name_from_identifier(identifier) } - } - } - let missing_nodes: Vec = node_types - .iter() - .filter(|node| !extracted_node_types.iter().any(|extracted| extracted.name == node.name)) - .cloned() - .collect(); - - // Add the missing nodes to extracted_node_types - for node in missing_nodes { - extracted_node_types.push(node); - } - // Remove entries with empty categories - extracted_node_types.retain(|node| !node.category.is_empty()); - - extracted_node_types + FrontendNodeType { + identifier: identifier.clone(), + name, + category: definition.category.to_string(), + input_types, + } + }) + .collect() } -pub fn collect_node_descriptions() -> Vec<(String, String)> { +pub fn collect_node_descriptions() -> Vec<(DefinitionIdentifier, String)> { DOCUMENT_NODE_TYPES .iter() - .map(|definition| { - ( - definition.identifier.to_string(), - if definition.description != "TODO" { definition.description.to_string() } else { String::new() }, - ) - }) + .map(|(identifier, definition)| (identifier.clone(), if definition.description != "TODO" { definition.description.to_string() } else { String::new() })) .collect() } @@ -2806,12 +2756,6 @@ impl DocumentNodeDefinition { } populate_input_properties(&mut template, Vec::new()); - // Set the reference to the node definition - template.persistent_node_metadata.reference = Some(self.identifier.to_string()); - // If the display name is empty and it is not a merge node, then set it to the reference - if template.persistent_node_metadata.display_name.is_empty() && self.identifier != "Merge" { - template.persistent_node_metadata.display_name = self.identifier.to_string(); - } template } diff --git a/editor/src/messages/portfolio/document/node_graph/document_node_definitions/document_node_derive.rs b/editor/src/messages/portfolio/document/node_graph/document_node_definitions/document_node_derive.rs index 6d5154ca54..bcb2efecfd 100644 --- a/editor/src/messages/portfolio/document/node_graph/document_node_definitions/document_node_derive.rs +++ b/editor/src/messages/portfolio/document/node_graph/document_node_definitions/document_node_derive.rs @@ -1,72 +1,34 @@ +use std::collections::HashMap; + use super::DocumentNodeDefinition; +use crate::messages::portfolio::document::node_graph::document_node_definitions::DefinitionIdentifier; use crate::messages::portfolio::document::utility_types::network_interface::{DocumentNodePersistentMetadata, InputMetadata, NodeTemplate, WidgetOverride}; -use graph_craft::ProtoNodeIdentifier; use graph_craft::document::*; use graphene_std::registry::*; use graphene_std::*; -use std::collections::HashSet; - -/// Traverses a document node template and metadata in parallel to link the protonodes to their reference -fn traverse_node(node: &DocumentNode, node_metadata: &mut DocumentNodePersistentMetadata) { - match &node.implementation { - DocumentNodeImplementation::Network(node_network) => { - for (nested_node_id, nested_node) in node_network.nodes.iter() { - let nested_metadata = node_metadata - .network_metadata - .as_mut() - .expect("Network node must have network metadata") - .persistent_metadata - .node_metadata - .get_mut(nested_node_id) - .expect("Network metadata must have corresponding node id"); - traverse_node(nested_node, &mut nested_metadata.persistent_metadata); - } - } - DocumentNodeImplementation::ProtoNode(proto_node_identifier) => { - if let Some(metadata) = NODE_METADATA.lock().unwrap().get(proto_node_identifier) { - node_metadata.reference = Some(metadata.display_name.to_string()); - } - } - DocumentNodeImplementation::Extract => {} - } -} - -pub(super) fn post_process_nodes(mut custom: Vec) -> Vec { - // Link the protonodes with custom networks to their reference - for node in custom.iter_mut() { - traverse_node(&node.node_template.document_node, &mut node.node_template.persistent_node_metadata); - } - - // Remove struct generics - for DocumentNodeDefinition { node_template, .. } in custom.iter_mut() { - let NodeTemplate { - document_node: DocumentNode { implementation, .. }, - .. - } = node_template; - - if let DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier { name }) = implementation - && let Some((new_name, _suffix)) = name.rsplit_once("<") - { - *name = Cow::Owned(new_name.to_string()) - }; - } +pub(super) fn post_process_nodes(custom: Vec) -> HashMap { + // Create hashmap for the protonodes added by the macro + let mut definitions_map = HashMap::new(); + // First remove the custom protonodes and add them to the definitions map since they contain different metadata from the macro and must be inserted first + // So that network nodes which reference them use the correct metadata + let network_nodes = custom + .into_iter() + .filter_map(|definition| { + if let DocumentNodeImplementation::ProtoNode(proto_node_identifier) = &definition.node_template.document_node.implementation { + definitions_map.insert(DefinitionIdentifier::ProtoNode(proto_node_identifier.clone()), definition); + return None; + }; + Some(definition) + }) + .collect::>(); + // Add the rest of the protonodes from the macro let node_registry = NODE_REGISTRY.lock().unwrap(); - 'outer: for (id, metadata) in NODE_METADATA.lock().unwrap().iter() { - for node in custom.iter() { - let DocumentNodeDefinition { - node_template: NodeTemplate { - document_node: DocumentNode { implementation, .. }, - .. - }, - .. - } = node; - match implementation { - DocumentNodeImplementation::ProtoNode(name) if name == id => continue 'outer, - _ => (), - } - } - + for (id, metadata) in NODE_METADATA.lock().unwrap().iter() { + let identifier = DefinitionIdentifier::ProtoNode(id.clone()); + if definitions_map.contains_key(&identifier) { + continue; + }; let NodeMetadata { display_name, category, @@ -78,48 +40,96 @@ pub(super) fn post_process_nodes(mut custom: Vec) -> Vec let Some(implementations) = &node_registry.get(id) else { continue }; - let valid_inputs: HashSet<_> = implementations.iter().map(|(_, node_io)| node_io.call_argument.clone()).collect(); + let valid_inputs: Vec<_> = implementations.iter().map(|(_, node_io)| node_io.call_argument.clone()).collect(); let first_node_io = implementations.first().map(|(_, node_io)| node_io).unwrap_or(const { &NodeIOTypes::empty() }); let input_type = if valid_inputs.len() > 1 { &const { generic!(D) } } else { &first_node_io.call_argument }; - let output_type = &first_node_io.return_value; let inputs = preprocessor::node_inputs(fields, first_node_io); - let node = DocumentNodeDefinition { - identifier: display_name, - node_template: NodeTemplate { - document_node: DocumentNode { - inputs, - call_argument: input_type.clone(), - implementation: DocumentNodeImplementation::ProtoNode(id.clone()), - visible: true, - skip_deduplication: false, - context_features: ContextDependencies::from(context_features.as_slice()), - ..Default::default() - }, - persistent_node_metadata: DocumentNodePersistentMetadata { - // TODO: Store information for input overrides in the node macro - input_metadata: fields - .iter() - .map(|f| match f.widget_override { - RegistryWidgetOverride::None => (f.name, f.description).into(), - RegistryWidgetOverride::Hidden => InputMetadata::with_name_description_override(f.name, f.description, WidgetOverride::Hidden), - RegistryWidgetOverride::String(str) => InputMetadata::with_name_description_override(f.name, f.description, WidgetOverride::String(str.to_string())), - RegistryWidgetOverride::Custom(str) => InputMetadata::with_name_description_override(f.name, f.description, WidgetOverride::Custom(str.to_string())), - }) - .collect(), - output_names: vec![output_type.to_string()], - locked: false, - ..Default::default() + definitions_map.insert( + identifier, + DocumentNodeDefinition { + identifier: display_name, + node_template: NodeTemplate { + document_node: DocumentNode { + inputs, + call_argument: input_type.clone(), + implementation: DocumentNodeImplementation::ProtoNode(id.clone()), + visible: true, + skip_deduplication: false, + context_features: ContextDependencies::from(context_features.as_slice()), + ..Default::default() + }, + persistent_node_metadata: DocumentNodePersistentMetadata { + // TODO: Store information for input overrides in the node macro + input_metadata: fields + .iter() + .map(|f| match f.widget_override { + RegistryWidgetOverride::None => (f.name, f.description).into(), + RegistryWidgetOverride::Hidden => InputMetadata::with_name_description_override(f.name, f.description, WidgetOverride::Hidden), + RegistryWidgetOverride::String(str) => InputMetadata::with_name_description_override(f.name, f.description, WidgetOverride::String(str.to_string())), + RegistryWidgetOverride::Custom(str) => InputMetadata::with_name_description_override(f.name, f.description, WidgetOverride::Custom(str.to_string())), + }) + .collect(), + locked: false, + ..Default::default() + }, }, + category: category.unwrap_or("UNCATEGORIZED"), + description: Cow::Borrowed(description), + properties: *properties, }, - category: category.unwrap_or("UNCATEGORIZED"), - description: Cow::Borrowed(description), - properties: *properties, - }; + ); + } - custom.push(node); + // If any protonode does not have metadata then set its display name to its identifier string + for definition in definitions_map.values_mut() { + let metadata = NODE_METADATA.lock().unwrap(); + if let DocumentNodeImplementation::ProtoNode(id) = &definition.node_template.document_node.implementation { + if !metadata.contains_key(id) { + definition.node_template.persistent_node_metadata.display_name = definition.identifier.to_string(); + } + } + } + + // Add the rest of the network nodes to the map and add the metadata for their internal protonodes + for mut network_node in network_nodes { + traverse_node(&network_node.node_template.document_node, &mut network_node.node_template.persistent_node_metadata, &definitions_map); + // Set the reference to the node identifier + if let Some(nested_metadata) = network_node.node_template.persistent_node_metadata.network_metadata.as_mut() { + nested_metadata.persistent_metadata.reference = Some(network_node.identifier.to_string()); + // If it is not a merge node, then set the display name to the identifier/reference + if network_node.identifier != "Merge" { + network_node.node_template.persistent_node_metadata.display_name = network_node.identifier.to_string(); + } + } + definitions_map.insert(DefinitionIdentifier::Network(network_node.identifier.to_string()), network_node); } - custom + definitions_map +} + +/// Traverses a document node template and metadata in parallel to add metadata to the protonodes +fn traverse_node(node: &DocumentNode, node_metadata: &mut DocumentNodePersistentMetadata, definitions_map: &HashMap) { + match &node.implementation { + DocumentNodeImplementation::Network(node_network) => { + for (nested_node_id, nested_node) in node_network.nodes.iter() { + let nested_metadata = node_metadata.network_metadata.as_mut().unwrap().persistent_metadata.node_metadata.get_mut(nested_node_id).unwrap(); + traverse_node(nested_node, &mut nested_metadata.persistent_metadata, definitions_map); + } + } + DocumentNodeImplementation::ProtoNode(id) => { + // Set all the metadata except the position to the protonode information from the macro + // TODO: Use options in the template to specify what you want to default and what you want to override + // If this fails then the protonode id in the definition doesnt match what is generated by the macro + let Some(definition) = definitions_map.get(&DefinitionIdentifier::ProtoNode(id.clone())) else { + log::error!("Could not get definition for id {} when filling in protonode metadata for a custom node", id.clone()); + return; + }; + let mut new_metadata = definition.node_template.persistent_node_metadata.clone(); + new_metadata.node_type_metadata = node_metadata.node_type_metadata.clone(); + *node_metadata = new_metadata + } + DocumentNodeImplementation::Extract => {} + } } diff --git a/editor/src/messages/portfolio/document/node_graph/node_graph_message.rs b/editor/src/messages/portfolio/document/node_graph/node_graph_message.rs index 330d123efe..4ec91d9981 100644 --- a/editor/src/messages/portfolio/document/node_graph/node_graph_message.rs +++ b/editor/src/messages/portfolio/document/node_graph/node_graph_message.rs @@ -1,5 +1,6 @@ use super::utility_types::Direction; use crate::messages::input_mapper::utility_types::input_keyboard::Key; +use crate::messages::portfolio::document::node_graph::document_node_definitions::DefinitionIdentifier; use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier; use crate::messages::portfolio::document::utility_types::network_interface::{ImportOrExport, InputConnector, NodeTemplate, OutputConnector}; use crate::messages::prelude::*; @@ -27,16 +28,16 @@ pub enum NodeGraphMessage { SelectedNodesUpdated, Copy, CreateNodeInLayerNoTransaction { - node_type: String, + node_type: DefinitionIdentifier, layer: LayerNodeIdentifier, }, CreateNodeInLayerWithTransaction { - node_type: String, + node_type: DefinitionIdentifier, layer: LayerNodeIdentifier, }, CreateNodeFromContextMenu { node_id: Option, - node_type: String, + node_type: DefinitionIdentifier, xy: Option<(i32, i32)>, add_transaction: bool, }, diff --git a/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler.rs b/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler.rs index 9ccee2548a..caaf44b9a1 100644 --- a/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler.rs +++ b/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler.rs @@ -1,11 +1,11 @@ +use super::node_properties; use super::utility_types::{BoxSelection, ContextMenuInformation, DragStart, FrontendNode}; -use super::{document_node_definitions, node_properties}; use crate::consts::GRID_SIZE; use crate::messages::input_mapper::utility_types::macros::{action_shortcut, action_shortcut_manual}; use crate::messages::layout::utility_types::widget_prelude::*; use crate::messages::portfolio::document::document_message_handler::navigation_controls; use crate::messages::portfolio::document::graph_operation::utility_types::ModifyInputsContext; -use crate::messages::portfolio::document::node_graph::document_node_definitions::NodePropertiesContext; +use crate::messages::portfolio::document::node_graph::document_node_definitions::{DefinitionIdentifier, NodePropertiesContext, resolve_document_node_type}; use crate::messages::portfolio::document::node_graph::utility_types::{ContextMenuData, Direction, FrontendGraphDataType, NodeGraphErrorDiagnostic}; use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier; use crate::messages::portfolio::document::utility_types::misc::GroupFolderType; @@ -130,7 +130,10 @@ impl<'a> MessageHandler> for NodeG } NodeGraphMessage::AddPathNode => { if let Some(layer) = make_path_editable_is_allowed(network_interface) { - responses.add(NodeGraphMessage::CreateNodeInLayerWithTransaction { node_type: "Path".to_string(), layer }); + responses.add(NodeGraphMessage::CreateNodeInLayerWithTransaction { + node_type: DefinitionIdentifier::Network("Path".to_string()), + layer, + }); responses.add(EventMessage::SelectionChanged); } } @@ -249,10 +252,10 @@ impl<'a> MessageHandler> for NodeG let node_id = node_id.unwrap_or_else(NodeId::new); - let Some(document_node_type) = document_node_definitions::resolve_document_node_type(&node_type) else { + let Some(document_node_type) = resolve_document_node_type(&node_type) else { responses.add(DialogMessage::DisplayDialogError { title: "Cannot insert node".to_string(), - description: format!("The document node '{node_type}' does not exist in the document node list"), + description: format!("The document node '{node_type:?}' does not exist in the document node list"), }); return; }; @@ -614,7 +617,7 @@ impl<'a> MessageHandler> for NodeG // Use the network interface to add a default node, then set the imports, exports, paste the nodes inside, and connect them to the imports/exports let encapsulating_node_id = NodeId::new(); - let mut default_node_template = document_node_definitions::resolve_document_node_type("Default Network") + let mut default_node_template = resolve_document_node_type(&DefinitionIdentifier::Network("Default Network".to_string())) .expect("Default Network node should exist") .default_node_template(); let Some(center_of_selected_nodes) = network_interface.selected_nodes_bounding_box(breadcrumb_network_path).map(|[a, b]| (a + b) / 2.) else { @@ -1677,7 +1680,7 @@ impl<'a> MessageHandler> for NodeG input, }); responses.add(PropertiesPanelMessage::Refresh); - if !(network_interface.reference(&node_id, selection_network_path).is_none() || input_index == 0) && network_interface.connected_to_output(&node_id, selection_network_path) { + if network_interface.connected_to_output(&node_id, selection_network_path) { responses.add(NodeGraphMessage::RunDocumentGraph); } } @@ -2129,9 +2132,10 @@ impl NodeGraphMessageHandler { let node_chooser = node_chooser .on_update(move |node_type| { + let node_type = node_type.clone(); if let (true, Some(layer)) = (single_layer_selected, selected_layer) { NodeGraphMessage::CreateNodeInLayerWithTransaction { - node_type: node_type.clone(), + node_type, layer: LayerNodeIdentifier::new_unchecked(layer.to_node()), } .into() @@ -2141,7 +2145,7 @@ impl NodeGraphMessageHandler { messages: Box::new([ NodeGraphMessage::CreateNodeFromContextMenu { node_id: Some(node_id), - node_type: node_type.clone(), + node_type, xy: None, add_transaction: true, } @@ -2572,8 +2576,9 @@ impl NodeGraphMessageHandler { .node_metadata(&node_id, breadcrumb_network_path) .is_some_and(|node_metadata| node_metadata.persistent_metadata.is_layer()), can_be_layer: network_interface.is_eligible_to_be_layer(&node_id, breadcrumb_network_path), - reference: network_interface.reference(&node_id, breadcrumb_network_path).cloned().unwrap_or_default(), + reference: network_interface.reference(&node_id, breadcrumb_network_path), display_name: network_interface.display_name(&node_id, breadcrumb_network_path), + implementation_name: network_interface.implementation_name(&node_id, breadcrumb_network_path), primary_input, exposed_inputs, primary_output, diff --git a/editor/src/messages/portfolio/document/node_graph/node_properties.rs b/editor/src/messages/portfolio/document/node_graph/node_properties.rs index 7786cfb32a..b34acd9560 100644 --- a/editor/src/messages/portfolio/document/node_graph/node_properties.rs +++ b/editor/src/messages/portfolio/document/node_graph/node_properties.rs @@ -3,6 +3,7 @@ use super::document_node_definitions::{NODE_OVERRIDES, NodePropertiesContext}; use super::utility_types::FrontendGraphDataType; use crate::messages::layout::utility_types::widget_prelude::*; +use crate::messages::portfolio::document::node_graph::document_node_definitions::resolve_document_node_type; use crate::messages::portfolio::document::utility_types::network_interface::InputConnector; use crate::messages::prelude::*; use choice::enum_choice; @@ -1606,10 +1607,8 @@ pub(crate) fn generate_node_properties(node_id: NodeId, context: &mut NodeProper if let Some(properties_override) = context .network_interface .reference(&node_id, context.selection_network_path) - .cloned() - .unwrap_or_default() .as_ref() - .and_then(|reference| super::document_node_definitions::resolve_document_node_type(reference)) + .and_then(|identifier| resolve_document_node_type(identifier)) .and_then(|definition| definition.properties) .and_then(|properties| NODE_OVERRIDES.get(properties)) { @@ -1674,23 +1673,17 @@ pub(crate) fn generate_node_properties(node_id: NodeId, context: &mut NodeProper if layout.is_empty() { layout = node_no_properties(node_id, context); } - let name = context + let name = context.network_interface.implementation_name(&node_id, context.selection_network_path); + + let description = context .network_interface .reference(&node_id, context.selection_network_path) - .cloned() - .unwrap_or_default() // If there is an error getting the reference, default to empty string - .or_else(|| { - // If there is no reference, try to get the proto node name - context.network_interface.implementation(&node_id, context.selection_network_path).and_then(|implementation|{ - if let DocumentNodeImplementation::ProtoNode(protonode) = implementation { - Some(protonode.name.clone().into_owned()) - } else { - None - } - }) - }) - .unwrap_or("Custom Node".to_string()); - let description = context.network_interface.description(&node_id, context.selection_network_path); + .as_ref() + .and_then(|identifier| resolve_document_node_type(identifier)) + .map(|definition| definition.description.to_string()) + .filter(|string| string != "TODO") + .unwrap_or_default(); + let visible = context.network_interface.is_visible(&node_id, context.selection_network_path); let pinned = context.network_interface.is_pinned(&node_id, context.selection_network_path); LayoutGroup::Section { diff --git a/editor/src/messages/portfolio/document/node_graph/utility_types.rs b/editor/src/messages/portfolio/document/node_graph/utility_types.rs index 5b202ef483..768cf51818 100644 --- a/editor/src/messages/portfolio/document/node_graph/utility_types.rs +++ b/editor/src/messages/portfolio/document/node_graph/utility_types.rs @@ -2,7 +2,8 @@ use glam::{DVec2, IVec2}; use graph_craft::document::NodeId; use graph_craft::document::value::TaggedValue; use graphene_std::Type; -use std::borrow::Cow; + +use crate::messages::portfolio::document::node_graph::document_node_definitions::DefinitionIdentifier; #[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Hash, serde::Serialize, serde::Deserialize, specta::Type)] pub enum FrontendGraphDataType { @@ -79,9 +80,11 @@ pub struct FrontendNode { pub is_layer: bool, #[serde(rename = "canBeLayer")] pub can_be_layer: bool, - pub reference: Option, + pub reference: Option, #[serde(rename = "displayName")] pub display_name: String, + #[serde(rename = "implementationName")] + pub implementation_name: String, #[serde(rename = "primaryInput")] pub primary_input: Option, #[serde(rename = "exposedInputs")] @@ -102,29 +105,13 @@ pub struct FrontendNode { #[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize, specta::Type)] pub struct FrontendNodeType { - pub name: Cow<'static, str>, - pub category: Cow<'static, str>, + pub identifier: DefinitionIdentifier, + pub name: String, + pub category: String, #[serde(rename = "inputTypes")] - pub input_types: Option>>, + pub input_types: Vec, } -impl FrontendNodeType { - pub fn new(name: impl Into>, category: impl Into>) -> Self { - Self { - name: name.into(), - category: category.into(), - input_types: None, - } - } - - pub fn with_input_types(name: impl Into>, category: impl Into>, input_types: Vec>) -> Self { - Self { - name: name.into(), - category: category.into(), - input_types: Some(input_types), - } - } -} #[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize, specta::Type)] pub struct DragStart { pub start_x: f64, diff --git a/editor/src/messages/portfolio/document/utility_types/document_metadata.rs b/editor/src/messages/portfolio/document/utility_types/document_metadata.rs index 7ba8eaa7ae..da27d64e17 100644 --- a/editor/src/messages/portfolio/document/utility_types/document_metadata.rs +++ b/editor/src/messages/portfolio/document/utility_types/document_metadata.rs @@ -1,6 +1,7 @@ use super::network_interface::NodeNetworkInterface; use crate::messages::portfolio::document::graph_operation::transform_utils; use crate::messages::portfolio::document::graph_operation::utility_types::ModifyInputsContext; +use crate::messages::portfolio::document::node_graph::document_node_definitions::DefinitionIdentifier; use crate::messages::portfolio::document::utility_types::network_interface::FlowType; use crate::messages::tool::common_functionality::graph_modification_utils; use glam::{DAffine2, DVec2}; @@ -91,7 +92,8 @@ impl DocumentMetadata { let mut use_local = true; let graph_layer = graph_modification_utils::NodeGraphLayer::new(layer, network_interface); - if let Some(path_node) = graph_layer.upstream_visible_node_id_from_name_in_layer("Path") + let identifier = DefinitionIdentifier::Network("Path".to_string()); + if let Some(path_node) = graph_layer.upstream_visible_node_id_from_name_in_layer(&identifier) && let Some(&source) = self.first_element_source_ids.get(&layer.to_node()) && !network_interface .upstream_flow_back_from_nodes(vec![path_node], &[], FlowType::HorizontalFlow) @@ -114,7 +116,7 @@ impl DocumentMetadata { let local_transform = self.local_transforms.get(&layer.to_node()).copied(); let transform = local_transform.unwrap_or_else(|| { - let transform_node_id = ModifyInputsContext::locate_node_in_layer_chain("Transform", layer, network_interface); + let transform_node_id = ModifyInputsContext::locate_node_in_layer_chain(&DefinitionIdentifier::Network("Transform".to_string()), layer, network_interface); let transform_node = transform_node_id.and_then(|id| network_interface.document_node(&id, &[])); transform_node.map(|node| transform_utils::get_current_transform(node.inputs.as_slice())).unwrap_or_default() }); diff --git a/editor/src/messages/portfolio/document/utility_types/network_interface.rs b/editor/src/messages/portfolio/document/utility_types/network_interface.rs index daebdbfc0c..894271a2b6 100644 --- a/editor/src/messages/portfolio/document/utility_types/network_interface.rs +++ b/editor/src/messages/portfolio/document/utility_types/network_interface.rs @@ -7,7 +7,7 @@ use super::misc::PTZ; use super::nodes::SelectedNodes; use crate::consts::{EXPORTS_TO_RIGHT_EDGE_PIXEL_GAP, EXPORTS_TO_TOP_EDGE_PIXEL_GAP, GRID_SIZE, IMPORTS_TO_LEFT_EDGE_PIXEL_GAP, IMPORTS_TO_TOP_EDGE_PIXEL_GAP}; use crate::messages::portfolio::document::graph_operation::utility_types::ModifyInputsContext; -use crate::messages::portfolio::document::node_graph::document_node_definitions::{DocumentNodeDefinition, resolve_document_node_type}; +use crate::messages::portfolio::document::node_graph::document_node_definitions::{DefinitionIdentifier, implementation_name_from_identifier, resolve_document_node_type}; use crate::messages::portfolio::document::node_graph::utility_types::{Direction, FrontendClickTargets, FrontendGraphDataType, FrontendGraphInput, FrontendGraphOutput}; use crate::messages::portfolio::document::utility_types::network_interface::resolved_types::ResolvedDocumentNodeTypes; use crate::messages::portfolio::document::utility_types::wires::{GraphWireStyle, WirePath, WirePathUpdate, build_vector_wire}; @@ -469,12 +469,6 @@ impl NodeNetworkInterface { node_template } - /// Try and get the [`DocumentNodeDefinition`] for a node - pub fn get_node_definition(&self, node_id: &NodeId, network_path: &[NodeId]) -> Option<&DocumentNodeDefinition> { - let metadata = self.node_metadata(node_id, network_path)?; - resolve_document_node_type(metadata.persistent_metadata.reference.as_ref()?) - } - pub fn input_from_connector(&self, input_connector: &InputConnector, network_path: &[NodeId]) -> Option<&NodeInput> { let Some(network) = self.nested_network(network_path) else { log::error!("Could not get network in input_from_connector"); @@ -915,12 +909,30 @@ impl NodeNetworkInterface { } } - pub fn reference(&self, node_id: &NodeId, network_path: &[NodeId]) -> Option<&Option> { - let Some(node_metadata) = self.node_metadata(node_id, network_path) else { - log::error!("Could not get reference for node: {node_id:?}"); + pub fn reference(&self, node_id: &NodeId, network_path: &[NodeId]) -> Option { + let Some(document_node) = self.document_node(node_id, network_path) else { + log::error!("Could not get document_node for node in reference: {node_id:?}"); return None; }; - Some(&node_metadata.persistent_metadata.reference) + match &document_node.implementation { + DocumentNodeImplementation::Network(_) => { + let Some(node_metadata) = self.node_metadata(node_id, network_path) else { + log::error!("Could not get reference for node in reference: {node_id:?}"); + return None; + }; + node_metadata + .persistent_metadata + .network_metadata + .as_ref() + .expect("Network metadata must exist for network node in reference") + .persistent_metadata + .reference + .clone() + .map(DefinitionIdentifier::Network) + } + DocumentNodeImplementation::ProtoNode(protonode_id) => Some(DefinitionIdentifier::ProtoNode(protonode_id.clone())), + _ => None, + } } pub fn implementation(&self, node_id: &NodeId, network_path: &[NodeId]) -> Option<&DocumentNodeImplementation> { @@ -981,11 +993,6 @@ impl NodeNetworkInterface { pub fn display_name(&self, node_id: &NodeId, network_path: &[NodeId]) -> String { let is_layer = self.is_layer(node_id, network_path); - let Some(reference) = self.reference(node_id, network_path) else { - log::error!("Could not get reference in untitled_layer_label"); - return "".to_string(); - }; - let display_name = if let Some(node_metadata) = self.node_metadata(node_id, network_path) { node_metadata.persistent_metadata.display_name.clone() } else { @@ -997,18 +1004,20 @@ impl NodeNetworkInterface { if is_layer { "Untitled Layer".to_string() } else { - reference.clone().unwrap_or("Untitled Node".to_string()) + // TODO: Replace with DisplayName::Italics(name) + self.implementation_name(node_id, network_path) } } else { + // TODO: Replace with DisplayName::Normal(name) display_name } } - /// Returns the description of the node, or an empty string if it is not set. - pub fn description(&self, node_id: &NodeId, network_path: &[NodeId]) -> String { - self.get_node_definition(node_id, network_path) - .map(|node_definition| node_definition.description.to_string()) - .unwrap_or_default() + /// The uneditable name in the properties panel which represents the function name of the node implementation + pub fn implementation_name(&self, node_id: &NodeId, network_path: &[NodeId]) -> String { + self.reference(&node_id, network_path) + .map(|identifier| implementation_name_from_identifier(&identifier)) + .unwrap_or("Custom Node".to_string()) } pub fn is_locked(&self, node_id: &NodeId, network_path: &[NodeId]) -> bool { @@ -1120,7 +1129,7 @@ impl NodeNetworkInterface { pub fn is_artboard(&self, node_id: &NodeId, network_path: &[NodeId]) -> bool { self.reference(node_id, network_path) - .is_some_and(|reference| *reference == Some("Artboard".to_string()) && self.connected_to_output(node_id, &[])) + .is_some_and(|reference| reference == DefinitionIdentifier::Network("Artboard".to_string()) && self.connected_to_output(node_id, &[])) } pub fn all_artboards(&self) -> HashSet { @@ -1129,12 +1138,13 @@ impl NodeNetworkInterface { .node_metadata .iter() .filter_map(|(node_id, node_metadata)| { - if node_metadata - .persistent_metadata - .reference - .as_ref() - .is_some_and(|reference| reference == "Artboard" && self.connected_to_output(node_id, &[]) && self.is_layer(node_id, &[])) - { + if node_metadata.persistent_metadata.network_metadata.as_ref().is_some_and(|network_metadata| { + network_metadata + .persistent_metadata + .reference + .as_ref() + .is_some_and(|reference| reference == "Artboard" && self.connected_to_output(node_id, &[]) && self.is_layer(node_id, &[])) + }) { Some(LayerNodeIdentifier::new(*node_id, self)) } else { None @@ -1391,7 +1401,6 @@ impl NodeNetworkInterface { node.skip_deduplication = old_node.skip_deduplication; node.original_location = old_node.original_location; node_metadata.persistent_metadata.display_name = old_node.alias; - node_metadata.persistent_metadata.reference = if old_node.name.is_empty() { None } else { Some(old_node.name) }; node_metadata.persistent_metadata.locked = old_node.locked; node_metadata.persistent_metadata.node_type_metadata = if old_node.is_layer { NodeTypePersistentMetadata::Layer(LayerPersistentMetadata { @@ -3087,7 +3096,7 @@ impl NodeNetworkInterface { pub fn compute_modified_vector(&self, layer: LayerNodeIdentifier) -> Option { let graph_layer = graph_modification_utils::NodeGraphLayer::new(layer, self); - if let Some(path_node) = graph_layer.upstream_visible_node_id_from_name_in_layer("Path") + if let Some(path_node) = graph_layer.upstream_visible_node_id_from_name_in_layer(&DefinitionIdentifier::Network("Path".to_string())) && let Some(vector) = self.document_metadata.vector_modify.get(&path_node) { let mut modified = vector.clone(); @@ -3240,14 +3249,6 @@ impl NodeNetworkInterface { } } - pub fn set_reference(&mut self, node_id: &NodeId, network_path: &[NodeId], reference: Option) { - let Some(node_metadata) = self.node_metadata_mut(node_id, network_path) else { - log::error!("Could not get node_metadata in set_reference"); - return; - }; - node_metadata.persistent_metadata.reference = reference; - } - pub fn set_transform(&mut self, transform: DAffine2, network_path: &[NodeId]) { let Some(network_metadata) = self.network_metadata_mut(network_path) else { log::error!("Could not get nested network in set_transform"); @@ -3318,7 +3319,9 @@ impl NodeNetworkInterface { encapsulating_node_metadata.persistent_metadata.output_names.insert(insert_index as usize, output_name.to_string()); } // Clear the reference to the nodes definition - encapsulating_node_metadata.persistent_metadata.reference = None; + if let Some(network_metadata) = encapsulating_node_metadata.persistent_metadata.network_metadata.as_mut() { + network_metadata.persistent_metadata.reference = None + } }; // Update the export ports and outward wires for the current network @@ -3387,7 +3390,9 @@ impl NodeNetworkInterface { } // Clear the reference to the nodes definition - node_metadata.persistent_metadata.reference = None; + if let Some(network_metadata) = node_metadata.persistent_metadata.network_metadata.as_mut() { + network_metadata.persistent_metadata.reference = None + } // Update the metadata for the encapsulating node self.unload_node_click_targets(&node_id, &encapsulating_network_path); @@ -3443,7 +3448,7 @@ impl NodeNetworkInterface { return; }; encapsulating_node_metadata.persistent_metadata.output_names.remove(export_index); - encapsulating_node_metadata.persistent_metadata.reference = None; + encapsulating_node_metadata.persistent_metadata.network_metadata.as_mut().unwrap().persistent_metadata.reference = None; // Update the metadata for the encapsulating node self.unload_outward_wires(&encapsulating_network_path); @@ -3517,7 +3522,7 @@ impl NodeNetworkInterface { return; }; encapsulating_node_metadata.persistent_metadata.input_metadata.remove(import_index); - encapsulating_node_metadata.persistent_metadata.reference = None; + encapsulating_node_metadata.persistent_metadata.network_metadata.as_mut().unwrap().persistent_metadata.reference = None; // Update the metadata for the encapsulating node self.unload_outward_wires(encapsulating_network_path); @@ -3563,7 +3568,7 @@ impl NodeNetworkInterface { let name = encapsulating_node_metadata.persistent_metadata.output_names.remove(start_index); encapsulating_node_metadata.persistent_metadata.output_names.insert(end_index, name); - encapsulating_node_metadata.persistent_metadata.reference = None; + encapsulating_node_metadata.persistent_metadata.network_metadata.as_mut().unwrap().persistent_metadata.reference = None; // Update the metadata for the encapsulating network self.unload_outward_wires(&encapsulating_network_path); @@ -3655,7 +3660,7 @@ impl NodeNetworkInterface { let properties_row = encapsulating_node_metadata.persistent_metadata.input_metadata.remove(start_index); encapsulating_node_metadata.persistent_metadata.input_metadata.insert(end_index, properties_row); - encapsulating_node_metadata.persistent_metadata.reference = None; + encapsulating_node_metadata.persistent_metadata.network_metadata.as_mut().unwrap().persistent_metadata.reference = None; // Update the metadata for the outer network self.unload_outward_wires(&encapsulating_network_path); @@ -3761,28 +3766,17 @@ impl NodeNetworkInterface { let number_of_inputs = node.inputs.len(); let Some(metadata) = self.node_metadata_mut(node_id, network_path) else { return }; for added_input_index in metadata.persistent_metadata.input_metadata.len()..number_of_inputs { - let reference = metadata.persistent_metadata.reference.as_ref(); - let definition = reference.and_then(|reference| resolve_document_node_type(reference)); - let input_metadata = definition + let input_metadata = self + .reference(node_id, network_path) + .as_ref() + .and_then(resolve_document_node_type) .and_then(|definition| definition.node_template.persistent_node_metadata.input_metadata.get(added_input_index)) .cloned(); + let Some(metadata) = self.node_metadata_mut(node_id, network_path) else { return }; metadata.persistent_metadata.input_metadata.push(input_metadata.unwrap_or_default()); } } - /// Used to ensure the display name is the reference name in case it is empty. - pub fn validate_display_name_metadata(&mut self, node_id: &NodeId, network_path: &[NodeId]) { - let Some(metadata) = self.node_metadata_mut(node_id, network_path) else { return }; - if metadata.persistent_metadata.display_name.is_empty() - && let Some(reference) = metadata.persistent_metadata.reference.clone() - { - // Keep the name for merge nodes as empty - if reference != "Merge" { - metadata.persistent_metadata.display_name = reference; - } - } - } - // When opening an old document to ensure the output names match the number of exports pub fn validate_output_names(&mut self, node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId]) { if let DocumentNodeImplementation::Network(network) = &node.implementation { @@ -3795,13 +3789,17 @@ impl NodeNetworkInterface { } } - /// Keep metadata in sync with the new implementation if this is used by anything other than the upgrade scripts - pub fn replace_reference_name(&mut self, node_id: &NodeId, network_path: &[NodeId], reference_name: String) { - let Some(node_metadata) = self.node_metadata_mut(node_id, network_path) else { - log::error!("Could not get node metadata in replace_reference_name"); + /// Keep metadata in sync with the new implementation if this is used by anything other than the upgrade scripts. + /// Only works with network nodes. Protonodes use their ID as the reference + pub fn set_reference(&mut self, node_id: &NodeId, network_path: &[NodeId], reference_name: Option) { + let Some(node_metadata) = self + .node_metadata_mut(node_id, network_path) + .and_then(|node_metadata| node_metadata.persistent_metadata.network_metadata.as_mut()) + else { + log::error!("Could not get network metadata in replace_reference_name"); return; }; - node_metadata.persistent_metadata.reference = Some(reference_name); + node_metadata.persistent_metadata.reference = reference_name; } /// Keep metadata in sync with the new implementation if this is used by anything other than the upgrade scripts @@ -4420,7 +4418,10 @@ impl NodeNetworkInterface { node_metadata.persistent_metadata.display_name.clone_from(&display_name); // Keep the alias in sync with the `ToArtboard` name input - if node_metadata.persistent_metadata.reference.as_ref().is_some_and(|reference| reference == "Artboard") { + if self + .reference(&node_id, network_path) + .is_some_and(|reference| reference == DefinitionIdentifier::Network("Artboard".to_string())) + { let Some(nested_network) = self.network_mut(network_path) else { return; }; @@ -5405,7 +5406,9 @@ impl NodeNetworkInterface { // If a non artboard layer is attempted to be connected to the exports, and there is already an artboard connected, then connect the layer to the artboard. if let Some(first_layer) = LayerNodeIdentifier::ROOT_PARENT.children(&self.document_metadata).next() && parent == LayerNodeIdentifier::ROOT_PARENT - && self.reference(&layer.to_node(), network_path).is_none_or(|reference| *reference != Some("Artboard".to_string())) + && self + .reference(&layer.to_node(), network_path) + .is_none_or(|reference| reference != DefinitionIdentifier::Network("Artboard".to_string())) && self.is_artboard(&first_layer.to_node(), network_path) { parent = first_layer; @@ -5997,6 +6000,12 @@ impl NodeNetworkMetadata { #[derive(Debug, Clone, Default, PartialEq, serde::Serialize, serde::Deserialize)] pub struct NodeNetworkPersistentMetadata { + /// The identifier for the node definition created for custom network nodes in [`DocumentNodeDefinition`]. + /// It is only used to associate network nodes with their definition. Protonodes use their ProtonodeIdentifier. + /// The reference is removed once the node is modified, since the node now stores its own implementation and inputs. + /// TODO: Used during serialization/deserialization to prevent storing implementation or inputs (and possible other fields) if they are the same as the definition. + /// TODO: Implement node versioning so that references to old nodes can be updated to the new node definition. + pub reference: Option, /// Node metadata must exist for every document node in the network #[serde(serialize_with = "graphene_std::vector::serialize_hashmap", deserialize_with = "graphene_std::vector::deserialize_hashmap")] pub node_metadata: HashMap, @@ -6242,12 +6251,8 @@ struct InputTransientMetadata { /// Persistent metadata for each node in the network, which must be included when creating, serializing, and deserializing saving a node. #[derive(Default, Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] pub struct DocumentNodePersistentMetadata { - /// The name of the node definition, as originally set by [`DocumentNodeDefinition`], used to display in the UI and to display the appropriate properties if no display name is set. - // TODO: Used during serialization/deserialization to prevent storing implementation or inputs (and possible other fields) if they are the same as the definition. - // TODO: The reference is removed once the node is modified, since the node now stores its own implementation and inputs. - // TODO: Implement node versioning so that references to old nodes can be updated to the new node definition. - pub reference: Option, - /// A name chosen by the user for this instance of the node. Empty indicates no given name, in which case the reference name is displayed to the user in italics. + /// A name chosen by the user for this instance of the node. Empty indicates no given name, in which case the implementation name is displayed to the user in italics. + /// This is empty for all newly created nodes, except protonodes with #[skip_impl] #[serde(default)] pub display_name: String, /// Stores metadata to override the properties in the properties panel for each input. These can either be generated automatically based on the type, or with a custom function. @@ -6486,7 +6491,9 @@ mod network_interface_tests { async fn copy_isolated_node() { let mut editor = EditorTestUtils::create(); editor.new_document().await; - let rectangle = editor.create_node_by_name("Rectangle").await; + let rectangle = editor + .create_node_by_name(DefinitionIdentifier::ProtoNode(graphene_std::vector::generator_nodes::rectangle::IDENTIFIER)) + .await; editor.handle_message(NodeGraphMessage::SelectedNodesSet { nodes: vec![rectangle] }).await; let frontend_messages = editor.handle_message(NodeGraphMessage::Copy).await; let serialized_nodes = frontend_messages diff --git a/editor/src/messages/portfolio/document/utility_types/network_interface/deserialization.rs b/editor/src/messages/portfolio/document/utility_types/network_interface/deserialization.rs index c1099a0f17..bf5a00abe8 100644 --- a/editor/src/messages/portfolio/document/utility_types/network_interface/deserialization.rs +++ b/editor/src/messages/portfolio/document/utility_types/network_interface/deserialization.rs @@ -23,7 +23,6 @@ impl From for DocumentNodePersistentMe fn from(old: DocumentNodePersistentMetadataInputNames) -> Self { DocumentNodePersistentMetadata { input_metadata: Vec::new(), - reference: old.reference, display_name: old.display_name, output_names: old.output_names, locked: old.locked, @@ -75,7 +74,6 @@ impl From for DocumentNodePersisten }) } DocumentNodePersistentMetadata { - reference: old.reference, display_name: old.display_name, input_metadata: Vec::new(), output_names: old.output_names, @@ -107,7 +105,38 @@ pub struct DocumentNodePersistentMetadataHasPrimaryOutput { impl From for DocumentNodePersistentMetadata { fn from(old: DocumentNodePersistentMetadataHasPrimaryOutput) -> Self { DocumentNodePersistentMetadata { - reference: old.reference, + display_name: old.display_name, + input_metadata: old.input_metadata, + output_names: old.output_names, + locked: old.locked, + pinned: old.pinned, + node_type_metadata: old.node_type_metadata, + network_metadata: old.network_metadata, + } + } +} + +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] +struct DocumentNodePersistentMetadataStringReference { + pub reference: Option, + #[serde(default)] + pub display_name: String, + pub input_metadata: Vec, + pub output_names: Vec, + #[serde(default)] + pub locked: bool, + #[serde(default)] + pub pinned: bool, + pub node_type_metadata: NodeTypePersistentMetadata, + pub network_metadata: Option, +} + +impl From for DocumentNodePersistentMetadata { + fn from(mut old: DocumentNodePersistentMetadataStringReference) -> Self { + if let Some(metadata) = old.network_metadata.as_mut() { + metadata.persistent_metadata.reference = old.reference; + } + DocumentNodePersistentMetadata { display_name: old.display_name, input_metadata: old.input_metadata, output_names: old.output_names, @@ -126,15 +155,18 @@ where use serde::Deserialize; let value = Value::deserialize(deserializer)?; - if let Ok(document) = serde_json::from_value::(value.clone()) { - return Ok(document.into()); - }; if let Ok(document) = serde_json::from_value::(value.clone()) { return Ok(document); }; + if let Ok(document) = serde_json::from_value::(value.clone()) { + return Ok(document.into()); + }; if let Ok(document) = serde_json::from_value::(value.clone()) { return Ok(document.into()); }; + if let Ok(document) = serde_json::from_value::(value.clone()) { + return Ok(document.into()); + }; match serde_json::from_value::(value.clone()) { Ok(document) => Ok(document.into()), Err(e) => Err(serde::de::Error::custom(e)), diff --git a/editor/src/messages/portfolio/document/utility_types/transformation.rs b/editor/src/messages/portfolio/document/utility_types/transformation.rs index 63e1b8baa8..9d3e41f40e 100644 --- a/editor/src/messages/portfolio/document/utility_types/transformation.rs +++ b/editor/src/messages/portfolio/document/utility_types/transformation.rs @@ -2,6 +2,7 @@ use super::network_interface::NodeNetworkInterface; use crate::consts::{ROTATE_INCREMENT, SCALE_INCREMENT}; use crate::messages::portfolio::document::graph_operation::transform_utils; use crate::messages::portfolio::document::graph_operation::utility_types::{ModifyInputsContext, TransformIn}; +use crate::messages::portfolio::document::node_graph::document_node_definitions::DefinitionIdentifier; use crate::messages::portfolio::document::utility_types::document_metadata::{DocumentMetadata, LayerNodeIdentifier}; use crate::messages::prelude::*; use crate::messages::tool::common_functionality::shape_editor::ShapeState; @@ -53,7 +54,7 @@ impl OriginalTransforms { /// Gets the transform from the most downstream transform node fn get_layer_transform(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option { - let transform_node_id = ModifyInputsContext::locate_node_in_layer_chain("Transform", layer, network_interface)?; + let transform_node_id = ModifyInputsContext::locate_node_in_layer_chain(&DefinitionIdentifier::Network("Transform".to_string()), layer, network_interface)?; let document_node = network_interface.document_network().nodes.get(&transform_node_id)?; Some(transform_utils::get_current_transform(&document_node.inputs)) diff --git a/editor/src/messages/portfolio/document_migration.rs b/editor/src/messages/portfolio/document_migration.rs index 3ffe8a943e..6f1bf96dc4 100644 --- a/editor/src/messages/portfolio/document_migration.rs +++ b/editor/src/messages/portfolio/document_migration.rs @@ -1,7 +1,7 @@ // TODO: Eventually remove this document upgrade code // This file contains lots of hacky code for upgrading old documents to the new format -use crate::messages::portfolio::document::node_graph::document_node_definitions::resolve_document_node_type; +use crate::messages::portfolio::document::node_graph::document_node_definitions::{DefinitionIdentifier, resolve_document_node_type}; use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier; use crate::messages::portfolio::document::utility_types::network_interface::{InputConnector, NodeTemplate, OutputConnector}; use crate::messages::prelude::DocumentMessageHandler; @@ -9,11 +9,8 @@ use glam::{DVec2, IVec2}; use graph_craft::document::DocumentNode; use graph_craft::document::{DocumentNodeImplementation, NodeInput, value::TaggedValue}; use graphene_std::ProtoNodeIdentifier; -use graphene_std::subpath::Subpath; -use graphene_std::table::Table; use graphene_std::text::{TextAlign, TypesettingConfig}; use graphene_std::uuid::NodeId; -use graphene_std::vector::Vector; use graphene_std::vector::style::{PaintOrder, StrokeAlign}; use std::collections::HashMap; use std::f64::consts::PI; @@ -1023,8 +1020,8 @@ 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<()> { - if reset_node_definitions_on_open && let Some(Some(reference)) = document.network_interface.reference(node_id, network_path) { - let node_definition = resolve_document_node_type(reference)?; + 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()); } @@ -1034,13 +1031,12 @@ fn migrate_node(node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId], } // Only nodes that have not been modified and still refer to a definition can be updated - let reference = document.network_interface.reference(node_id, network_path).cloned().flatten()?; - let reference = &reference; + let reference = &document.network_interface.reference(node_id, network_path)?; let inputs_count = node.inputs.len(); // Upgrade Stroke node to reorder parameters and add "Align" and "Paint Order" (#2644) - if reference == "Stroke" && inputs_count == 8 { + if reference == &DefinitionIdentifier::ProtoNode(graphene_std::vector::solidify_stroke::IDENTIFIER) && inputs_count == 8 { let mut node_template = resolve_document_node_type(reference)?.default_node_template(); let old_inputs = document.network_interface.replace_inputs(node_id, network_path, &mut node_template)?; @@ -1059,86 +1055,9 @@ fn migrate_node(node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId], document.network_interface.set_input(&InputConnector::node(*node_id, 9), old_inputs[4].clone(), network_path); } - // Rename the old "Splines from Points" node to "Spline" and upgrade it to the new "Spline" node - if reference == "Splines from Points" { - document.network_interface.set_reference(node_id, network_path, Some("Spline".to_string())); - } - - // Upgrade the old "Spline" node to the new "Spline" node - if reference == "Spline" { - // Retrieve the proto node identifier and verify it is the old "Spline" node, otherwise skip it if this is the new "Spline" node - let identifier = document - .network_interface - .implementation(node_id, network_path) - .and_then(|implementation| implementation.get_proto_node()); - if identifier.map(|identifier| &identifier.name) != Some(&"graphene_core::vector::generator_nodes::SplineNode".into()) { - return None; - } - - // Obtain the document node for the given node ID, extract the vector points, and create a Vector path from the list of points - let node = document.network_interface.document_node(node_id, network_path)?; - let Some(TaggedValue::VecDVec2(points)) = node.inputs.get(1).and_then(|tagged_value| tagged_value.as_value()) else { - log::error!("The old Spline node's input at index 1 is not a TaggedValue::VecDVec2"); - return None; - }; - let vector = Vector::from_subpath(Subpath::from_anchors_linear(points.to_vec(), false)); - - // Retrieve the output connectors linked to the "Spline" node's output connector - let Some(spline_outputs) = document.network_interface.outward_wires(network_path)?.get(&OutputConnector::node(*node_id, 0)).cloned() else { - log::error!("Vec of InputConnector Spline node is connected to its output connector 0."); - return None; - }; - - // Get the node's current position in the graph - let Some(node_position) = document.network_interface.position(node_id, network_path) else { - log::error!("Could not get position of spline node."); - return None; - }; - - // Get the "Path" node definition and fill it in with the Vector path and default vector modification - let Some(path_node_type) = resolve_document_node_type("Path") else { - log::error!("Path node does not exist."); - return None; - }; - let path_node = path_node_type.node_template_input_override([ - Some(NodeInput::value(TaggedValue::Vector(Table::new_from_element(vector)), true)), - Some(NodeInput::value(TaggedValue::VectorModification(Default::default()), false)), - ]); - - // Get the "Spline" node definition and wire it up with the "Path" node as input - let Some(spline_node_type) = resolve_document_node_type("Spline") else { - log::error!("Spline node does not exist."); - return None; - }; - let spline_node = spline_node_type.node_template_input_override([Some(NodeInput::node(NodeId(1), 0))]); - - // Create a new node group with the "Path" and "Spline" nodes and generate new node IDs for them - let nodes = vec![(NodeId(1), path_node), (NodeId(0), spline_node)]; - let new_ids = nodes.iter().map(|(id, _)| (*id, NodeId::new())).collect::>(); - let new_spline_id = *new_ids.get(&NodeId(0))?; - let new_path_id = *new_ids.get(&NodeId(1))?; - - // Remove the old "Spline" node from the document - document.network_interface.delete_nodes(vec![*node_id], false, network_path); - - // Insert the new "Path" and "Spline" nodes into the network interface with generated IDs - document.network_interface.insert_node_group(nodes.clone(), new_ids, network_path); - - // Reposition the new "Spline" node to match the original "Spline" node's position - document.network_interface.shift_node(&new_spline_id, node_position, network_path); - - // Reposition the new "Path" node with an offset relative to the original "Spline" node's position - document.network_interface.shift_node(&new_path_id, node_position + IVec2::new(-7, 0), network_path); - - // Redirect each output connection from the old node to the new "Spline" node's output connector - for input_connector in spline_outputs { - document.network_interface.set_input(&input_connector, NodeInput::node(new_spline_id, 0), network_path); - } - } - // Upgrade Text node to include line height and character spacing, which were previously hardcoded to 1, from https://github.com/GraphiteEditor/Graphite/pull/2016 - if reference == "Text" && inputs_count != 11 { - let mut template = resolve_document_node_type(reference)?.default_node_template(); + if reference == &DefinitionIdentifier::Network("Text".to_string()) && inputs_count != 11 { + let mut template: NodeTemplate = resolve_document_node_type(&reference)?.default_node_template(); document.network_interface.replace_implementation(node_id, network_path, &mut template); let old_inputs = document.network_interface.replace_inputs(node_id, network_path, &mut template)?; @@ -1212,8 +1131,12 @@ fn migrate_node(node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId], } // Upgrade Sine, Cosine, and Tangent nodes to include a boolean input for whether the output should be in radians, which was previously the only option but is now not the default - if (reference == "Sine" || reference == "Cosine" || reference == "Tangent") && inputs_count == 1 { - let mut node_template = resolve_document_node_type(reference)?.default_node_template(); + if (reference == &DefinitionIdentifier::ProtoNode(graphene_std::math_nodes::sine::IDENTIFIER) + || reference == &DefinitionIdentifier::ProtoNode(graphene_std::math_nodes::cosine::IDENTIFIER) + || reference == &DefinitionIdentifier::ProtoNode(graphene_std::math_nodes::tangent::IDENTIFIER)) + && inputs_count == 1 + { + let mut node_template = resolve_document_node_type(&reference)?.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)?; @@ -1225,8 +1148,8 @@ fn migrate_node(node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId], } // Upgrade the 'Tangent on Path' node to include a boolean input for whether the output should be in radians, which was previously the only option but is now not the default - if (reference == "Tangent on Path") && inputs_count == 4 { - let mut node_template = resolve_document_node_type(reference)?.default_node_template(); + if reference == &DefinitionIdentifier::ProtoNode(graphene_std::vector::tangent_on_path::IDENTIFIER) && inputs_count == 4 { + let mut node_template = resolve_document_node_type(&reference)?.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)?; @@ -1241,8 +1164,8 @@ fn migrate_node(node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId], } // Upgrade the Modulo node to include a boolean input for whether the output should be always positive, which was previously not an option - if reference == "Modulo" && inputs_count == 2 { - let mut node_template = resolve_document_node_type(reference)?.default_node_template(); + if reference == &DefinitionIdentifier::ProtoNode(graphene_std::math_nodes::modulo::IDENTIFIER) && inputs_count == 2 { + let mut node_template = resolve_document_node_type(&reference)?.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)?; @@ -1255,8 +1178,8 @@ fn migrate_node(node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId], } // Upgrade the Mirror node to add the `keep_original` boolean input - if reference == "Mirror" && inputs_count == 3 { - let mut node_template = resolve_document_node_type(reference)?.default_node_template(); + if reference == &DefinitionIdentifier::ProtoNode(graphene_std::vector::mirror::IDENTIFIER) && inputs_count == 3 { + let mut node_template = resolve_document_node_type(&reference)?.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)?; @@ -1270,8 +1193,8 @@ fn migrate_node(node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId], } // Upgrade the Mirror node to add the `reference_point` input and change `offset` from `DVec2` to `f64` - if reference == "Mirror" && inputs_count == 4 { - let mut node_template = resolve_document_node_type(reference)?.default_node_template(); + if reference == &DefinitionIdentifier::ProtoNode(graphene_std::vector::mirror::IDENTIFIER) && inputs_count == 4 { + let mut node_template = resolve_document_node_type(&reference)?.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)?; @@ -1293,24 +1216,23 @@ fn migrate_node(node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId], } // Upgrade artboard name being passed as hidden value input to "Create Artboard" - if reference == "Artboard" && reset_node_definitions_on_open { + if reference == &DefinitionIdentifier::Network("Artboard".to_string()) && reset_node_definitions_on_open { let label = document.network_interface.display_name(node_id, network_path); document .network_interface .set_input(&InputConnector::node(NodeId(0), 1), NodeInput::value(TaggedValue::String(label), false), &[*node_id]); } - if reference == "Image" && inputs_count == 1 { - let mut node_template = resolve_document_node_type(reference)?.default_node_template(); + if reference == &DefinitionIdentifier::ProtoNode(graphene_std::raster_nodes::std_nodes::image_value::IDENTIFIER) && inputs_count == 1 { + let mut node_template = resolve_document_node_type(&reference)?.default_node_template(); document.network_interface.replace_implementation(node_id, network_path, &mut node_template); // Insert a new empty input for the image document.network_interface.add_import(TaggedValue::None, false, 0, "Empty", "", &[*node_id]); - document.network_interface.set_reference(node_id, network_path, Some("Image".to_string())); } - if reference == "Noise Pattern" && inputs_count == 15 { - let mut node_template = resolve_document_node_type(reference)?.default_node_template(); + if reference == &DefinitionIdentifier::ProtoNode(graphene_std::raster_nodes::std_nodes::noise_pattern::IDENTIFIER) && inputs_count == 15 { + let mut node_template = resolve_document_node_type(&reference)?.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)?; @@ -1323,8 +1245,8 @@ fn migrate_node(node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId], } } - if reference == "Instance on Points" && inputs_count == 2 { - let mut node_template = resolve_document_node_type(reference)?.default_node_template(); + if reference == &DefinitionIdentifier::ProtoNode(graphene_std::vector::instance_on_points::IDENTIFIER) && inputs_count == 2 { + let mut node_template = resolve_document_node_type(&reference)?.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)?; @@ -1333,8 +1255,8 @@ fn migrate_node(node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId], document.network_interface.set_input(&InputConnector::node(*node_id, 1), old_inputs[1].clone(), network_path); } - if reference == "Morph" && inputs_count == 4 { - let mut node_template = resolve_document_node_type(reference)?.default_node_template(); + if reference == &DefinitionIdentifier::ProtoNode(graphene_std::vector::instance_on_points::IDENTIFIER) && inputs_count == 4 { + let mut node_template = resolve_document_node_type(&reference)?.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)?; @@ -1345,8 +1267,8 @@ fn migrate_node(node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId], // We have removed the last input, so we don't add index 3 } - if reference == "Brush" && inputs_count == 4 { - let mut node_template = resolve_document_node_type(reference)?.default_node_template(); + if reference == &DefinitionIdentifier::ProtoNode(graphene_std::brush::brush::brush::IDENTIFIER) && inputs_count == 4 { + let mut node_template = resolve_document_node_type(&reference)?.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)?; @@ -1357,51 +1279,8 @@ fn migrate_node(node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId], document.network_interface.set_input(&InputConnector::node(*node_id, 2), old_inputs[3].clone(), network_path); } - if reference == "Flatten Vector Elements" { - let mut node_template = resolve_document_node_type(reference)?.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)?; - - document.network_interface.set_input(&InputConnector::node(*node_id, 0), old_inputs[0].clone(), network_path); - - document.network_interface.replace_reference_name(node_id, network_path, "Flatten Path".to_string()); - } - - if reference == "Remove Handles" { - let mut node_template = resolve_document_node_type(reference)?.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)?; - - document.network_interface.set_input(&InputConnector::node(*node_id, 0), old_inputs[0].clone(), network_path); - document - .network_interface - .set_input(&InputConnector::node(*node_id, 1), NodeInput::value(TaggedValue::F64(0.), false), network_path); - document - .network_interface - .set_input(&InputConnector::node(*node_id, 2), NodeInput::value(TaggedValue::Bool(false), false), network_path); - - document.network_interface.replace_reference_name(node_id, network_path, "Auto-Tangents".to_string()); - } - - if reference == "Generate Handles" { - let mut node_template = resolve_document_node_type("Auto-Tangents")?.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)?; - - document.network_interface.set_input(&InputConnector::node(*node_id, 0), old_inputs[0].clone(), network_path); - document.network_interface.set_input(&InputConnector::node(*node_id, 1), old_inputs[1].clone(), network_path); - document - .network_interface - .set_input(&InputConnector::node(*node_id, 2), NodeInput::value(TaggedValue::Bool(true), false), network_path); - - document.network_interface.replace_reference_name(node_id, network_path, "Auto-Tangents".to_string()); - } - - if reference == "Merge by Distance" && inputs_count == 2 { - let mut node_template = resolve_document_node_type(reference)?.default_node_template(); + if reference == &DefinitionIdentifier::ProtoNode(graphene_std::vector::merge_by_distance::IDENTIFIER) && inputs_count == 2 { + let mut node_template = resolve_document_node_type(&reference)?.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)?; @@ -1415,8 +1294,8 @@ fn migrate_node(node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId], ); } - if reference == "Spatial Merge by Distance" { - let mut node_template = resolve_document_node_type("Merge by Distance")?.default_node_template(); + if reference == &DefinitionIdentifier::ProtoNode(graphene_std::vector::merge_by_distance::IDENTIFIER) { + let mut node_template = resolve_document_node_type(&DefinitionIdentifier::ProtoNode(graphene_std::vector::merge_by_distance::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)?; @@ -1428,12 +1307,10 @@ fn migrate_node(node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId], NodeInput::value(TaggedValue::MergeByDistanceAlgorithm(graphene_std::vector::misc::MergeByDistanceAlgorithm::Spatial), false), network_path, ); - - document.network_interface.replace_reference_name(node_id, network_path, "Merge by Distance".to_string()); } - if reference == "Sample Points" && inputs_count == 5 { - let mut node_template = resolve_document_node_type("Sample Polyline")?.default_node_template(); + if reference == &DefinitionIdentifier::ProtoNode(graphene_std::vector::sample_polyline::IDENTIFIER) && inputs_count == 5 { + let mut node_template = resolve_document_node_type(&DefinitionIdentifier::ProtoNode(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)?; @@ -1448,11 +1325,11 @@ fn migrate_node(node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId], document.network_interface.set_input(&InputConnector::node(*node_id, 5), old_inputs[3].clone(), network_path); document.network_interface.set_input(&InputConnector::node(*node_id, 6), old_inputs[4].clone(), network_path); - document.network_interface.replace_reference_name(node_id, network_path, "Sample Polyline".to_string()); + document.network_interface.set_reference(node_id, network_path, Some("Sample Polyline".to_string())); } // Make the "Quantity" parameter a u32 instead of f64 - if reference == "Sample Polyline" { + if reference == &DefinitionIdentifier::ProtoNode(graphene_std::vector::sample_polyline::IDENTIFIER) { // Get the inputs, obtain the quantity value, and put the inputs back let quantity_value = document .network_interface @@ -1467,8 +1344,8 @@ fn migrate_node(node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId], } // Make the "Grid" node, if its input of index 3 is a DVec2 for "angles" instead of a u32 for the "columns" input that now succeeds "angles", move the angle to index 5 (after "columns" and "rows") - if reference == "Grid" && inputs_count == 6 { - let node_definition = resolve_document_node_type(reference)?; + if reference == &DefinitionIdentifier::ProtoNode(graphene_std::vector::generator_nodes::grid::IDENTIFIER) && inputs_count == 6 { + let node_definition = resolve_document_node_type(&reference)?; let mut new_node_template = node_definition.default_node_template(); let mut current_node_template = document.network_interface.create_node_template(node_id, network_path)?; @@ -1497,8 +1374,8 @@ fn migrate_node(node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId], } // Add the "Depth" parameter to the "Instance Index" node - if reference == "Instance Index" && inputs_count == 0 { - let mut node_template = resolve_document_node_type(reference)?.default_node_template(); + if reference == &DefinitionIdentifier::ProtoNode(graphene_std::vector::instance_index::IDENTIFIER) && inputs_count == 0 { + let mut node_template = resolve_document_node_type(&reference)?.default_node_template(); document.network_interface.replace_implementation(node_id, network_path, &mut node_template); document.network_interface.set_display_name(node_id, "Instance Index".to_string(), network_path); @@ -1510,8 +1387,8 @@ fn migrate_node(node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId], } // Migrate the Transform node to use degrees instead of radians - if reference == "Transform" && node.inputs.get(6).is_none() { - let mut node_template = resolve_document_node_type("Transform")?.default_node_template(); + if reference == &DefinitionIdentifier::Network("Transform".to_string()) && node.inputs.get(6).is_none() { + let mut node_template = resolve_document_node_type(&DefinitionIdentifier::Network("Transform".to_string()))?.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)?; @@ -1547,7 +1424,7 @@ fn migrate_node(node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId], } NodeInput::Node { .. } => { // Construct a new Multiply node for converting from degrees to radians - let Some(multiply_node) = resolve_document_node_type("Multiply") else { + let Some(multiply_node) = resolve_document_node_type(&DefinitionIdentifier::ProtoNode(graphene_std::math_nodes::multiply::IDENTIFIER)) else { log::error!("Could not get multiply node from definition when upgrading transform"); return None; }; @@ -1587,7 +1464,7 @@ fn migrate_node(node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId], // The old version would zip the source and target table rows, interpoleating each pair together. // The migrated version will instead deeply flatten both merged tables and morph sequentially between all source vectors and all target vector elements. // This migration assumes most usages didn't involve multiple parallel vector elements, and instead morphed from a single source to a single target vector element. - if reference == "Morph" && inputs_count == 3 { + if reference == &DefinitionIdentifier::ProtoNode(graphene_std::vector::morph::IDENTIFIER) && inputs_count == 3 { // Old signature: // async fn morph(_: impl Ctx, source: Table, #[expose] target: Table, #[default(0.5)] time: Fraction) -> Table { ... } // @@ -1598,7 +1475,7 @@ fn migrate_node(node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId], let old_inputs = document.network_interface.replace_inputs(node_id, network_path, &mut node_template)?; // Create a new Merge node - let Some(merge_node_type) = resolve_document_node_type("Merge") else { + let Some(merge_node_type) = resolve_document_node_type(&DefinitionIdentifier::Network("Merge".to_string())) else { log::error!("Could not get merge node from definition when upgrading morph"); return None; }; @@ -1631,7 +1508,7 @@ fn migrate_node(node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId], // Add context features to nodes that don't have them (fine-grained context caching migration) if node.context_features == graphene_std::ContextDependencies::default() - && let Some(reference) = document.network_interface.reference(node_id, network_path).cloned().flatten() + && let Some(reference) = document.network_interface.reference(node_id, network_path).clone() && let Some(node_definition) = resolve_document_node_type(&reference) { let context_features = node_definition.node_template.document_node.context_features; diff --git a/editor/src/messages/portfolio/portfolio_message_handler.rs b/editor/src/messages/portfolio/portfolio_message_handler.rs index 9826462330..9aab292f47 100644 --- a/editor/src/messages/portfolio/portfolio_message_handler.rs +++ b/editor/src/messages/portfolio/portfolio_message_handler.rs @@ -12,8 +12,7 @@ use crate::messages::input_mapper::utility_types::macros::{action_shortcut, acti use crate::messages::layout::utility_types::widget_prelude::*; use crate::messages::portfolio::document::DocumentMessageContext; use crate::messages::portfolio::document::graph_operation::utility_types::TransformIn; -use crate::messages::portfolio::document::node_graph::document_node_definitions; -use crate::messages::portfolio::document::node_graph::document_node_definitions::resolve_document_node_type; +use crate::messages::portfolio::document::node_graph::document_node_definitions::{self, DefinitionIdentifier, resolve_document_node_type}; use crate::messages::portfolio::document::utility_types::clipboards::{Clipboard, CopyBufferEntry, INTERNAL_CLIPBOARD_COUNT}; use crate::messages::portfolio::document::utility_types::network_interface::OutputConnector; use crate::messages::portfolio::document::utility_types::nodes::SelectedNodes; @@ -498,7 +497,6 @@ impl MessageHandler> for Portfolio // Ensure each node has the metadata for its inputs for (node_id, node, path) in document.network_interface.document_network().clone().recursive_nodes() { document.network_interface.validate_input_metadata(node_id, node, &path); - document.network_interface.validate_display_name_metadata(node_id, &path); document.network_interface.validate_output_names(node_id, node, &path); } @@ -640,7 +638,7 @@ impl MessageHandler> for Portfolio let mut layers = Vec::new(); for (_, new_vector, transform) in data { - let Some(node_type) = resolve_document_node_type("Path") else { + let Some(node_type) = resolve_document_node_type(&DefinitionIdentifier::Network("Path".to_string())) else { error!("Path node does not exist"); continue; }; diff --git a/editor/src/messages/tool/common_functionality/gizmos/shape_gizmos/point_radius_handle.rs b/editor/src/messages/tool/common_functionality/gizmos/shape_gizmos/point_radius_handle.rs index 55c131dce1..d72414f48a 100644 --- a/editor/src/messages/tool/common_functionality/gizmos/shape_gizmos/point_radius_handle.rs +++ b/editor/src/messages/tool/common_functionality/gizmos/shape_gizmos/point_radius_handle.rs @@ -2,6 +2,7 @@ use crate::consts::GIZMO_HIDE_THRESHOLD; use crate::consts::{COLOR_OVERLAY_RED, POINT_RADIUS_HANDLE_SNAP_THRESHOLD}; use crate::messages::frontend::utility_types::MouseCursorIcon; use crate::messages::message::Message; +use crate::messages::portfolio::document::node_graph::document_node_definitions::DefinitionIdentifier; use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier; use crate::messages::portfolio::document::{overlays::utility_types::OverlayContext, utility_types::network_interface::InputConnector}; use crate::messages::prelude::FrontendMessage; @@ -331,7 +332,8 @@ impl PointRadiusHandle { fn calculate_snap_radii(document: &DocumentMessageHandler, layer: LayerNodeIdentifier, radius_index: usize) -> Vec { let mut snap_radii = Vec::new(); - let Some(node_inputs) = NodeGraphLayer::new(layer, &document.network_interface).find_node_inputs("Star") else { + let Some(node_inputs) = NodeGraphLayer::new(layer, &document.network_interface).find_node_inputs(&DefinitionIdentifier::ProtoNode(graphene_std::vector::generator_nodes::star::IDENTIFIER)) + else { return snap_radii; }; @@ -449,7 +451,8 @@ impl PointRadiusHandle { } fn check_if_radius_flipped(&mut self, original_radius: f64, new_radius: f64, document: &DocumentMessageHandler, layer: LayerNodeIdentifier, radius_index: usize) { - let Some(node_inputs) = NodeGraphLayer::new(layer, &document.network_interface).find_node_inputs("Star") else { + let Some(node_inputs) = NodeGraphLayer::new(layer, &document.network_interface).find_node_inputs(&DefinitionIdentifier::ProtoNode(graphene_std::vector::generator_nodes::star::IDENTIFIER)) + else { return; }; diff --git a/editor/src/messages/tool/common_functionality/graph_modification_utils.rs b/editor/src/messages/tool/common_functionality/graph_modification_utils.rs index c0d1081501..c7d234e0ce 100644 --- a/editor/src/messages/tool/common_functionality/graph_modification_utils.rs +++ b/editor/src/messages/tool/common_functionality/graph_modification_utils.rs @@ -1,5 +1,5 @@ use crate::messages::portfolio::document::graph_operation::utility_types::TransformIn; -use crate::messages::portfolio::document::node_graph::document_node_definitions; +use crate::messages::portfolio::document::node_graph::document_node_definitions::{self, DefinitionIdentifier}; use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier; use crate::messages::portfolio::document::utility_types::network_interface::{FlowType, InputConnector, NodeNetworkInterface, NodeTemplate}; use crate::messages::prelude::*; @@ -24,9 +24,13 @@ pub fn find_spline(document: &DocumentMessageHandler, layer: LayerNodeIdentifier document .network_interface .upstream_flow_back_from_nodes([layer.to_node()].to_vec(), &[], FlowType::HorizontalFlow) - .map(|node_id| (document.network_interface.reference(&node_id, &[]).unwrap(), node_id)) - .take_while(|(reference, _)| reference.as_ref().is_some_and(|node_ref| node_ref != "Path")) - .find(|(reference, _)| reference.as_ref().is_some_and(|node_ref| node_ref == "Spline")) + .map(|node_id| (document.network_interface.reference(&node_id, &[]), node_id)) + .take_while(|(reference, _)| reference.as_ref().is_some_and(|node_ref| node_ref != &DefinitionIdentifier::Network("Path".to_string()))) + .find(|(reference, _)| { + reference + .as_ref() + .is_some_and(|node_ref| *node_ref == DefinitionIdentifier::ProtoNode(graphene_std::vector::spline::IDENTIFIER)) + }) .map(|node| node.1) } @@ -73,7 +77,7 @@ pub fn merge_layers(document: &DocumentMessageHandler, first_layer: LayerNodeIde // Merge the inputs of the two layers let merge_node_id = NodeId::new(); - let merge_node = document_node_definitions::resolve_document_node_type("Merge") + let merge_node = document_node_definitions::resolve_document_node_type(&DefinitionIdentifier::Network("Merge".to_string())) .expect("Failed to create merge node") .default_node_template(); responses.add(NodeGraphMessage::InsertNode { @@ -99,7 +103,7 @@ pub fn merge_layers(document: &DocumentMessageHandler, first_layer: LayerNodeIde // Add a Flatten Path node after the merge let flatten_node_id = NodeId::new(); - let flatten_node = document_node_definitions::resolve_document_node_type("Flatten Path") + let flatten_node = document_node_definitions::resolve_document_node_type(&DefinitionIdentifier::ProtoNode(graphene_std::vector::flatten_path::IDENTIFIER)) .expect("Failed to create flatten node") .default_node_template(); responses.add(NodeGraphMessage::InsertNode { @@ -113,7 +117,7 @@ pub fn merge_layers(document: &DocumentMessageHandler, first_layer: LayerNodeIde // Add a path node after the flatten node let path_node_id = NodeId::new(); - let path_node = document_node_definitions::resolve_document_node_type("Path") + let path_node = document_node_definitions::resolve_document_node_type(&DefinitionIdentifier::Network("Path".to_string())) .expect("Failed to create path node") .default_node_template(); responses.add(NodeGraphMessage::InsertNode { @@ -128,7 +132,7 @@ pub fn merge_layers(document: &DocumentMessageHandler, first_layer: LayerNodeIde // Add a Spline node after the Path node if both the layers we are merging is spline. if current_and_other_layer_is_spline { let spline_node_id = NodeId::new(); - let spline_node = document_node_definitions::resolve_document_node_type("Spline") + let spline_node = document_node_definitions::resolve_document_node_type(&DefinitionIdentifier::ProtoNode(graphene_std::vector::spline::IDENTIFIER)) .expect("Failed to create Spline node") .default_node_template(); responses.add(NodeGraphMessage::InsertNode { @@ -143,7 +147,7 @@ pub fn merge_layers(document: &DocumentMessageHandler, first_layer: LayerNodeIde // Add a transform node to ensure correct tooling modifications let transform_node_id = NodeId::new(); - let transform_node = document_node_definitions::resolve_document_node_type("Transform") + let transform_node = document_node_definitions::resolve_document_node_type(&DefinitionIdentifier::Network("Transform".to_string())) .expect("Failed to create transform node") .default_node_template(); responses.add(NodeGraphMessage::InsertNode { @@ -251,7 +255,7 @@ pub fn new_custom(id: NodeId, nodes: Vec<(NodeId, NodeTemplate)>, parent: LayerN pub fn get_origin(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option { use graphene_std::transform_nodes::transform::*; - if let TaggedValue::DVec2(origin) = NodeGraphLayer::new(layer, network_interface).find_input("Transform", TranslationInput::INDEX)? { + if let TaggedValue::DVec2(origin) = NodeGraphLayer::new(layer, network_interface).find_input(&DefinitionIdentifier::Network("Transform".to_string()), TranslationInput::INDEX)? { Some(*origin) } else { None @@ -273,7 +277,7 @@ pub fn get_viewport_center(layer: LayerNodeIdentifier, network_interface: &NodeN pub fn get_gradient(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option { let fill_index = 1; - let inputs = NodeGraphLayer::new(layer, network_interface).find_node_inputs("Fill")?; + let inputs = NodeGraphLayer::new(layer, network_interface).find_node_inputs(&DefinitionIdentifier::ProtoNode(graphene_std::vector::fill::IDENTIFIER))?; let TaggedValue::Fill(Fill::Gradient(gradient)) = inputs.get(fill_index)?.as_value()? else { return None; }; @@ -284,7 +288,7 @@ pub fn get_gradient(layer: LayerNodeIdentifier, network_interface: &NodeNetworkI pub fn get_fill_color(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option { let fill_index = 1; - let inputs = NodeGraphLayer::new(layer, network_interface).find_node_inputs("Fill")?; + let inputs = NodeGraphLayer::new(layer, network_interface).find_node_inputs(&DefinitionIdentifier::ProtoNode(graphene_std::vector::generator_nodes::star::IDENTIFIER))?; let TaggedValue::Fill(Fill::Solid(color)) = inputs.get(fill_index)?.as_value()? else { return None; }; @@ -293,7 +297,7 @@ pub fn get_fill_color(layer: LayerNodeIdentifier, network_interface: &NodeNetwor /// Get the current blend mode of a layer from the closest "Blending" node. pub fn get_blend_mode(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option { - let inputs = NodeGraphLayer::new(layer, network_interface).find_node_inputs("Blending")?; + let inputs = NodeGraphLayer::new(layer, network_interface).find_node_inputs(&DefinitionIdentifier::ProtoNode(graphene_std::blending_nodes::blending::IDENTIFIER))?; let TaggedValue::BlendMode(blend_mode) = inputs.get(1)?.as_value()? else { return None; }; @@ -309,7 +313,7 @@ pub fn get_blend_mode(layer: LayerNodeIdentifier, network_interface: &NodeNetwor /// /// With those limitations in mind, the intention of this function is to show just the value already present in an upstream Opacity node so that value can be directly edited. pub fn get_opacity(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option { - let inputs = NodeGraphLayer::new(layer, network_interface).find_node_inputs("Blending")?; + let inputs = NodeGraphLayer::new(layer, network_interface).find_node_inputs(&DefinitionIdentifier::ProtoNode(graphene_std::blending_nodes::blending::IDENTIFIER))?; let TaggedValue::F64(opacity) = inputs.get(2)?.as_value()? else { return None; }; @@ -317,7 +321,7 @@ pub fn get_opacity(layer: LayerNodeIdentifier, network_interface: &NodeNetworkIn } pub fn get_clip_mode(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option { - let inputs = NodeGraphLayer::new(layer, network_interface).find_node_inputs("Blending")?; + let inputs = NodeGraphLayer::new(layer, network_interface).find_node_inputs(&DefinitionIdentifier::ProtoNode(graphene_std::blending_nodes::blending::IDENTIFIER))?; let TaggedValue::Bool(clip) = inputs.get(4)?.as_value()? else { return None; }; @@ -325,7 +329,7 @@ pub fn get_clip_mode(layer: LayerNodeIdentifier, network_interface: &NodeNetwork } pub fn get_fill(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option { - let inputs = NodeGraphLayer::new(layer, network_interface).find_node_inputs("Blending")?; + let inputs = NodeGraphLayer::new(layer, network_interface).find_node_inputs(&DefinitionIdentifier::ProtoNode(graphene_std::blending_nodes::blending::IDENTIFIER))?; let TaggedValue::F64(fill) = inputs.get(3)?.as_value()? else { return None; }; @@ -333,52 +337,52 @@ pub fn get_fill(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInter } pub fn get_fill_id(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option { - NodeGraphLayer::new(layer, network_interface).upstream_node_id_from_name("Fill") + NodeGraphLayer::new(layer, network_interface).upstream_node_id_from_name(&DefinitionIdentifier::ProtoNode(graphene_std::vector_nodes::fill::IDENTIFIER)) } pub fn get_circle_id(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option { - NodeGraphLayer::new(layer, network_interface).upstream_node_id_from_name("Circle") + NodeGraphLayer::new(layer, network_interface).upstream_node_id_from_name(&DefinitionIdentifier::ProtoNode(graphene_std::vector_nodes::circle::IDENTIFIER)) } pub fn get_ellipse_id(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option { - NodeGraphLayer::new(layer, network_interface).upstream_node_id_from_name("Ellipse") + NodeGraphLayer::new(layer, network_interface).upstream_node_id_from_name(&DefinitionIdentifier::ProtoNode(graphene_std::vector_nodes::ellipse::IDENTIFIER)) } pub fn get_line_id(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option { - NodeGraphLayer::new(layer, network_interface).upstream_node_id_from_name("Line") + NodeGraphLayer::new(layer, network_interface).upstream_node_id_from_name(&DefinitionIdentifier::ProtoNode(graphene_std::vector_nodes::line::IDENTIFIER)) } pub fn get_polygon_id(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option { - NodeGraphLayer::new(layer, network_interface).upstream_node_id_from_name("Regular Polygon") + NodeGraphLayer::new(layer, network_interface).upstream_node_id_from_name(&DefinitionIdentifier::ProtoNode(graphene_std::vector_nodes::regular_polygon::IDENTIFIER)) } pub fn get_rectangle_id(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option { - NodeGraphLayer::new(layer, network_interface).upstream_node_id_from_name("Rectangle") + NodeGraphLayer::new(layer, network_interface).upstream_node_id_from_name(&DefinitionIdentifier::ProtoNode(graphene_std::vector_nodes::rectangle::IDENTIFIER)) } pub fn get_star_id(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option { - NodeGraphLayer::new(layer, network_interface).upstream_node_id_from_name("Star") + NodeGraphLayer::new(layer, network_interface).upstream_node_id_from_name(&DefinitionIdentifier::ProtoNode(graphene_std::vector_nodes::star::IDENTIFIER)) } pub fn get_arc_id(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option { - NodeGraphLayer::new(layer, network_interface).upstream_node_id_from_name("Arc") + NodeGraphLayer::new(layer, network_interface).upstream_node_id_from_name(&DefinitionIdentifier::ProtoNode(graphene_std::vector_nodes::arc::IDENTIFIER)) } pub fn get_spiral_id(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option { - NodeGraphLayer::new(layer, network_interface).upstream_node_id_from_name("Spiral") + NodeGraphLayer::new(layer, network_interface).upstream_node_id_from_name(&DefinitionIdentifier::ProtoNode(graphene_std::vector_nodes::spiral::IDENTIFIER)) } pub fn get_text_id(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option { - NodeGraphLayer::new(layer, network_interface).upstream_node_id_from_name("Text") + NodeGraphLayer::new(layer, network_interface).upstream_node_id_from_name(&DefinitionIdentifier::Network("Text".to_string())) } pub fn get_grid_id(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option { - NodeGraphLayer::new(layer, network_interface).upstream_node_id_from_name("Grid") + NodeGraphLayer::new(layer, network_interface).upstream_node_id_from_name(&DefinitionIdentifier::ProtoNode(graphene_std::vector_nodes::fill::IDENTIFIER)) } /// Gets properties from the Text node pub fn get_text(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option<(&String, &Font, TypesettingConfig, bool)> { - let inputs = NodeGraphLayer::new(layer, network_interface).find_node_inputs("Text")?; + let inputs = NodeGraphLayer::new(layer, network_interface).find_node_inputs(&DefinitionIdentifier::Network("Text".to_string()))?; let Some(TaggedValue::String(text)) = &inputs[1].as_value() else { return None }; let Some(TaggedValue::Font(font)) = &inputs[2].as_value() else { return None }; @@ -405,7 +409,7 @@ pub fn get_text(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInter pub fn get_stroke_width(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface) -> Option { let weight_node_input_index = graphene_std::vector::stroke::WeightInput::INDEX; - if let TaggedValue::F64(width) = NodeGraphLayer::new(layer, network_interface).find_input("Stroke", weight_node_input_index)? { + if let TaggedValue::F64(width) = NodeGraphLayer::new(layer, network_interface).find_input(&DefinitionIdentifier::ProtoNode(graphene_std::vector::stroke::IDENTIFIER), weight_node_input_index)? { Some(*width) } else { None @@ -413,8 +417,8 @@ pub fn get_stroke_width(layer: LayerNodeIdentifier, network_interface: &NodeNetw } /// Checks if a specified layer uses an upstream node matching the given name. -pub fn is_layer_fed_by_node_of_name(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface, node_name: &str) -> bool { - NodeGraphLayer::new(layer, network_interface).find_node_inputs(node_name).is_some() +pub fn is_layer_fed_by_node_of_name(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface, identifier: &DefinitionIdentifier) -> bool { + NodeGraphLayer::new(layer, network_interface).find_node_inputs(identifier).is_some() } /// An immutable reference to a layer within the document node graph for easy access. @@ -439,19 +443,19 @@ impl<'a> NodeGraphLayer<'a> { } /// Node id of a node if it exists in the layer's primary flow - pub fn upstream_node_id_from_name(&self, node_name: &str) -> Option { + pub fn upstream_node_id_from_name(&self, identifier: &DefinitionIdentifier) -> Option { self.horizontal_layer_flow() - .find(|node_id| self.network_interface.reference(node_id, &[]).is_some_and(|reference| *reference == Some(node_name.to_string()))) + .find(|node_id| self.network_interface.reference(node_id, &[]).is_some_and(|reference| reference == *identifier)) } /// Node id of a visible node if it exists in the layer's primary flow until another layer - pub fn upstream_visible_node_id_from_name_in_layer(&self, node_name: &str) -> Option { + pub fn upstream_visible_node_id_from_name_in_layer(&self, identifier: &DefinitionIdentifier) -> Option { // `.skip(1)` is used to skip self self.horizontal_layer_flow() .skip(1) .take_while(|node_id| !self.network_interface.is_layer(node_id, &[])) .filter(|node_id| self.network_interface.is_visible(node_id, &[])) - .find(|node_id| self.network_interface.reference(node_id, &[]).is_some_and(|reference| *reference == Some(node_name.to_string()))) + .find(|node_id| self.network_interface.reference(node_id, &[]).is_some_and(|reference| reference == *identifier)) } /// Node id of a protonode if it exists in the layer's primary flow @@ -467,19 +471,19 @@ impl<'a> NodeGraphLayer<'a> { } /// Find all of the inputs of a specific node within the layer's primary flow, up until the next layer is reached. - pub fn find_node_inputs(&self, node_name: &str) -> Option<&'a Vec> { + pub fn find_node_inputs(&self, identifier: &DefinitionIdentifier) -> Option<&'a Vec> { // `.skip(1)` is used to skip self self.horizontal_layer_flow() .skip(1) .take_while(|node_id| !self.network_interface.is_layer(node_id, &[])) - .find(|node_id| self.network_interface.reference(node_id, &[]).is_some_and(|reference| *reference == Some(node_name.to_string()))) + .find(|node_id| self.network_interface.reference(node_id, &[]).is_some_and(|reference| reference == *identifier)) .and_then(|node_id| self.network_interface.document_network().nodes.get(&node_id).map(|node| &node.inputs)) } /// Find a specific input of a node within the layer's primary flow - pub fn find_input(&self, node_name: &str, index: usize) -> Option<&'a TaggedValue> { + pub fn find_input(&self, identifier: &DefinitionIdentifier, index: usize) -> Option<&'a TaggedValue> { // TODO: Find a better way to accept a node input rather than using its index (which is quite unclear and fragile) - self.find_node_inputs(node_name)?.get(index)?.as_value() + self.find_node_inputs(identifier)?.get(index)?.as_value() } /// Check if a layer is a raster layer diff --git a/editor/src/messages/tool/common_functionality/shapes/arc_shape.rs b/editor/src/messages/tool/common_functionality/shapes/arc_shape.rs index a40ea4160e..ea7a10bdbe 100644 --- a/editor/src/messages/tool/common_functionality/shapes/arc_shape.rs +++ b/editor/src/messages/tool/common_functionality/shapes/arc_shape.rs @@ -1,7 +1,7 @@ use super::shape_utility::ShapeToolModifierKey; use super::*; use crate::messages::portfolio::document::graph_operation::utility_types::TransformIn; -use crate::messages::portfolio::document::node_graph::document_node_definitions::resolve_document_node_type; +use crate::messages::portfolio::document::node_graph::document_node_definitions::{DefinitionIdentifier, resolve_document_node_type}; use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier; use crate::messages::portfolio::document::utility_types::network_interface::{InputConnector, NodeTemplate}; use crate::messages::tool::common_functionality::gizmos::shape_gizmos::circle_arc_radius_handle::{RadiusHandle, RadiusHandleState}; @@ -133,7 +133,7 @@ pub struct Arc; impl Arc { pub fn create_node(arc_type: ArcType) -> NodeTemplate { - let node_type = resolve_document_node_type("Arc").expect("Ellipse node does not exist"); + let node_type = resolve_document_node_type(&DefinitionIdentifier::ProtoNode(graphene_std::vector::generator_nodes::arc::IDENTIFIER)).expect("Ellipse node does not exist"); node_type.node_template_input_override([ None, Some(NodeInput::value(TaggedValue::F64(0.5), false)), diff --git a/editor/src/messages/tool/common_functionality/shapes/circle_shape.rs b/editor/src/messages/tool/common_functionality/shapes/circle_shape.rs index fa59535b57..c163d2bd5f 100644 --- a/editor/src/messages/tool/common_functionality/shapes/circle_shape.rs +++ b/editor/src/messages/tool/common_functionality/shapes/circle_shape.rs @@ -1,5 +1,5 @@ use crate::messages::portfolio::document::graph_operation::utility_types::TransformIn; -use crate::messages::portfolio::document::node_graph::document_node_definitions::resolve_document_node_type; +use crate::messages::portfolio::document::node_graph::document_node_definitions::{DefinitionIdentifier, resolve_document_node_type}; use crate::messages::portfolio::document::overlays::utility_types::OverlayContext; use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier; use crate::messages::portfolio::document::utility_types::network_interface::{InputConnector, NodeTemplate}; @@ -82,7 +82,7 @@ pub struct Circle; impl Circle { pub fn create_node() -> NodeTemplate { - let node_type = resolve_document_node_type("Circle").expect("Circle can't be found"); + let node_type = resolve_document_node_type(&DefinitionIdentifier::ProtoNode(graphene_std::vector::generator_nodes::circle::IDENTIFIER)).expect("Circle can't be found"); node_type.node_template_input_override([None, Some(NodeInput::value(TaggedValue::F64(0.), false))]) } diff --git a/editor/src/messages/tool/common_functionality/shapes/ellipse_shape.rs b/editor/src/messages/tool/common_functionality/shapes/ellipse_shape.rs index e235072a0e..bb073d28c3 100644 --- a/editor/src/messages/tool/common_functionality/shapes/ellipse_shape.rs +++ b/editor/src/messages/tool/common_functionality/shapes/ellipse_shape.rs @@ -1,7 +1,7 @@ use super::shape_utility::ShapeToolModifierKey; use super::*; use crate::messages::portfolio::document::graph_operation::utility_types::TransformIn; -use crate::messages::portfolio::document::node_graph::document_node_definitions::resolve_document_node_type; +use crate::messages::portfolio::document::node_graph::document_node_definitions::{DefinitionIdentifier, resolve_document_node_type}; use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier; use crate::messages::portfolio::document::utility_types::network_interface::{InputConnector, NodeTemplate}; use crate::messages::tool::common_functionality::graph_modification_utils; @@ -16,7 +16,7 @@ pub struct Ellipse; impl Ellipse { pub fn create_node() -> NodeTemplate { - let node_type = resolve_document_node_type("Ellipse").expect("Ellipse node can't be found"); + let node_type = resolve_document_node_type(&DefinitionIdentifier::ProtoNode(graphene_std::vector::generator_nodes::ellipse::IDENTIFIER)).expect("Ellipse node can't be found"); node_type.node_template_input_override([None, Some(NodeInput::value(TaggedValue::F64(0.5), false)), Some(NodeInput::value(TaggedValue::F64(0.5), false))]) } diff --git a/editor/src/messages/tool/common_functionality/shapes/grid_shape.rs b/editor/src/messages/tool/common_functionality/shapes/grid_shape.rs index 1ab97ca7dd..e1c519dca8 100644 --- a/editor/src/messages/tool/common_functionality/shapes/grid_shape.rs +++ b/editor/src/messages/tool/common_functionality/shapes/grid_shape.rs @@ -1,7 +1,7 @@ use super::shape_utility::ShapeToolModifierKey; use super::*; use crate::messages::portfolio::document::graph_operation::utility_types::TransformIn; -use crate::messages::portfolio::document::node_graph::document_node_definitions::resolve_document_node_type; +use crate::messages::portfolio::document::node_graph::document_node_definitions::{DefinitionIdentifier, resolve_document_node_type}; use crate::messages::portfolio::document::overlays::utility_types::OverlayContext; use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier; use crate::messages::portfolio::document::utility_types::network_interface::{InputConnector, NodeTemplate}; @@ -86,7 +86,7 @@ pub struct Grid; impl Grid { pub fn create_node(grid_type: GridType) -> NodeTemplate { - let node_type = resolve_document_node_type("Grid").expect("Grid can't be found"); + let node_type = resolve_document_node_type(&DefinitionIdentifier::ProtoNode(graphene_std::vector::generator_nodes::grid::IDENTIFIER)).expect("Grid can't be found"); node_type.node_template_input_override([ None, Some(NodeInput::value(TaggedValue::GridType(grid_type), false)), diff --git a/editor/src/messages/tool/common_functionality/shapes/line_shape.rs b/editor/src/messages/tool/common_functionality/shapes/line_shape.rs index 16b64a2315..b10d0fd50e 100644 --- a/editor/src/messages/tool/common_functionality/shapes/line_shape.rs +++ b/editor/src/messages/tool/common_functionality/shapes/line_shape.rs @@ -1,6 +1,6 @@ use super::shape_utility::ShapeToolModifierKey; use crate::consts::{BOUNDS_SELECT_THRESHOLD, LINE_ROTATE_SNAP_ANGLE}; -use crate::messages::portfolio::document::node_graph::document_node_definitions::resolve_document_node_type; +use crate::messages::portfolio::document::node_graph::document_node_definitions::{DefinitionIdentifier, resolve_document_node_type}; use crate::messages::portfolio::document::overlays::utility_types::OverlayContext; use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier; use crate::messages::portfolio::document::utility_types::network_interface::{InputConnector, NodeTemplate}; @@ -37,7 +37,8 @@ pub struct Line; impl Line { pub fn create_node(document: &DocumentMessageHandler, drag_start: DVec2) -> NodeTemplate { - let node_type = resolve_document_node_type("Line").expect("Line node can't be found"); + let identifier = DefinitionIdentifier::ProtoNode(graphene_std::vector::generator_nodes::star::IDENTIFIER); + let node_type = resolve_document_node_type(&identifier).expect("Line node can't be found"); node_type.node_template_input_override([ None, Some(NodeInput::value(TaggedValue::DVec2(document.metadata().document_to_viewport.transform_point2(drag_start)), false)), @@ -88,7 +89,8 @@ impl Line { .selected_nodes() .selected_visible_and_unlocked_layers(&document.network_interface) .filter_map(|layer| { - let node_inputs = NodeGraphLayer::new(layer, &document.network_interface).find_node_inputs("Line")?; + let node_inputs = + NodeGraphLayer::new(layer, &document.network_interface).find_node_inputs(&DefinitionIdentifier::ProtoNode(graphene_std::vector::generator_nodes::line::IDENTIFIER))?; let (Some(&TaggedValue::DVec2(start)), Some(&TaggedValue::DVec2(end))) = (node_inputs[1].as_value(), node_inputs[2].as_value()) else { return None; @@ -171,7 +173,7 @@ fn generate_line(tool_data: &mut ShapeToolData, snap_data: SnapData, lock_angle: } pub fn clicked_on_line_endpoints(layer: LayerNodeIdentifier, document: &DocumentMessageHandler, input: &InputPreprocessorMessageHandler, shape_tool_data: &mut ShapeToolData) -> bool { - let Some(node_inputs) = NodeGraphLayer::new(layer, &document.network_interface).find_node_inputs("Line") else { + let Some(node_inputs) = NodeGraphLayer::new(layer, &document.network_interface).find_node_inputs(&DefinitionIdentifier::ProtoNode(graphene_std::vector::generator_nodes::line::IDENTIFIER)) else { return false; }; @@ -216,7 +218,7 @@ mod test_line_tool { .selected_nodes() .selected_visible_and_unlocked_layers(network_interface) .filter_map(|layer| { - let node_inputs = NodeGraphLayer::new(layer, network_interface).find_node_inputs("Line")?; + let node_inputs = NodeGraphLayer::new(layer, network_interface).find_node_inputs(&DefinitionIdentifier::ProtoNode(graphene_std::vector::generator_nodes::line::IDENTIFIER))?; let (Some(&TaggedValue::DVec2(start)), Some(&TaggedValue::DVec2(end))) = (node_inputs[1].as_value(), node_inputs[2].as_value()) else { return None; }; diff --git a/editor/src/messages/tool/common_functionality/shapes/polygon_shape.rs b/editor/src/messages/tool/common_functionality/shapes/polygon_shape.rs index 0abce50c4e..9456ff1de3 100644 --- a/editor/src/messages/tool/common_functionality/shapes/polygon_shape.rs +++ b/editor/src/messages/tool/common_functionality/shapes/polygon_shape.rs @@ -1,7 +1,7 @@ use super::shape_utility::{ShapeToolModifierKey, update_radius_sign}; use super::*; use crate::messages::portfolio::document::graph_operation::utility_types::TransformIn; -use crate::messages::portfolio::document::node_graph::document_node_definitions::resolve_document_node_type; +use crate::messages::portfolio::document::node_graph::document_node_definitions::{DefinitionIdentifier, resolve_document_node_type}; use crate::messages::portfolio::document::overlays::utility_types::OverlayContext; use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier; use crate::messages::portfolio::document::utility_types::network_interface::{InputConnector, NodeTemplate}; @@ -109,7 +109,8 @@ pub struct Polygon; impl Polygon { pub fn create_node(vertices: u32) -> NodeTemplate { - let node_type = resolve_document_node_type("Regular Polygon").expect("Regular Polygon can't be found"); + let identifier = DefinitionIdentifier::ProtoNode(graphene_std::vector::generator_nodes::line::IDENTIFIER); + let node_type = resolve_document_node_type(&identifier).expect("Regular Polygon can't be found"); node_type.node_template_input_override([None, Some(NodeInput::value(TaggedValue::U32(vertices), false)), Some(NodeInput::value(TaggedValue::F64(0.5), false))]) } @@ -167,8 +168,8 @@ impl Polygon { }; let Some(node_inputs) = NodeGraphLayer::new(layer, &document.network_interface) - .find_node_inputs("Regular Polygon") - .or(NodeGraphLayer::new(layer, &document.network_interface).find_node_inputs("Star")) + .find_node_inputs(&DefinitionIdentifier::ProtoNode(graphene_std::vector::generator_nodes::regular_polygon::IDENTIFIER)) + .or(NodeGraphLayer::new(layer, &document.network_interface).find_node_inputs(&DefinitionIdentifier::ProtoNode(graphene_std::vector::generator_nodes::star::IDENTIFIER))) else { return; }; diff --git a/editor/src/messages/tool/common_functionality/shapes/rectangle_shape.rs b/editor/src/messages/tool/common_functionality/shapes/rectangle_shape.rs index 16f95d151f..6e212b7be9 100644 --- a/editor/src/messages/tool/common_functionality/shapes/rectangle_shape.rs +++ b/editor/src/messages/tool/common_functionality/shapes/rectangle_shape.rs @@ -1,7 +1,7 @@ use super::shape_utility::ShapeToolModifierKey; use super::*; use crate::messages::portfolio::document::graph_operation::utility_types::TransformIn; -use crate::messages::portfolio::document::node_graph::document_node_definitions::resolve_document_node_type; +use crate::messages::portfolio::document::node_graph::document_node_definitions::{DefinitionIdentifier, resolve_document_node_type}; use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier; use crate::messages::portfolio::document::utility_types::network_interface::{InputConnector, NodeTemplate}; use crate::messages::tool::common_functionality::graph_modification_utils; @@ -16,7 +16,7 @@ pub struct Rectangle; impl Rectangle { pub fn create_node() -> NodeTemplate { - let node_type = resolve_document_node_type("Rectangle").expect("Rectangle node can't be found"); + let node_type = resolve_document_node_type(&DefinitionIdentifier::ProtoNode(graphene_std::vector::generator_nodes::rectangle::IDENTIFIER)).expect("Rectangle node can't be found"); node_type.node_template_input_override([None, Some(NodeInput::value(TaggedValue::F64(1.), false)), Some(NodeInput::value(TaggedValue::F64(1.), false))]) } diff --git a/editor/src/messages/tool/common_functionality/shapes/shape_utility.rs b/editor/src/messages/tool/common_functionality/shapes/shape_utility.rs index a94847c514..9b36b7082c 100644 --- a/editor/src/messages/tool/common_functionality/shapes/shape_utility.rs +++ b/editor/src/messages/tool/common_functionality/shapes/shape_utility.rs @@ -2,6 +2,7 @@ use super::ShapeToolData; use crate::consts::{ARC_SWEEP_GIZMO_RADIUS, ARC_SWEEP_GIZMO_TEXT_HEIGHT}; use crate::messages::frontend::utility_types::MouseCursorIcon; use crate::messages::message::Message; +use crate::messages::portfolio::document::node_graph::document_node_definitions::DefinitionIdentifier; use crate::messages::portfolio::document::overlays::utility_types::OverlayContext; use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier; use crate::messages::portfolio::document::utility_types::network_interface::InputConnector; @@ -152,8 +153,15 @@ pub fn update_radius_sign(end: DVec2, start: DVec2, layer: LayerNodeIdentifier, let sign_num = if end[1] > start[1] { 1. } else { -1. }; let new_layer = NodeGraphLayer::new(layer, &document.network_interface); - if new_layer.find_input("Regular Polygon", 1).unwrap_or(&TaggedValue::U32(0)).to_u32() % 2 == 1 { - let Some(polygon_node_id) = new_layer.upstream_node_id_from_name("Regular Polygon") else { return }; + if new_layer + .find_input(&DefinitionIdentifier::ProtoNode(graphene_std::vector::generator_nodes::regular_polygon::IDENTIFIER), 1) + .unwrap_or(&TaggedValue::U32(0)) + .to_u32() + % 2 == 1 + { + let Some(polygon_node_id) = new_layer.upstream_node_id_from_name(&DefinitionIdentifier::ProtoNode(graphene_std::vector_nodes::regular_polygon::IDENTIFIER)) else { + return; + }; responses.add(NodeGraphMessage::SetInput { input_connector: InputConnector::node(polygon_node_id, 2), @@ -162,8 +170,15 @@ pub fn update_radius_sign(end: DVec2, start: DVec2, layer: LayerNodeIdentifier, return; } - if new_layer.find_input("Star", 1).unwrap_or(&TaggedValue::U32(0)).to_u32() % 2 == 1 { - let Some(star_node_id) = new_layer.upstream_node_id_from_name("Star") else { return }; + if new_layer + .find_input(&DefinitionIdentifier::ProtoNode(graphene_std::vector::generator_nodes::star::IDENTIFIER), 1) + .unwrap_or(&TaggedValue::U32(0)) + .to_u32() + % 2 == 1 + { + let Some(star_node_id) = new_layer.upstream_node_id_from_name(&DefinitionIdentifier::ProtoNode(graphene_std::vector_nodes::star::IDENTIFIER)) else { + return; + }; responses.add(NodeGraphMessage::SetInput { input_connector: InputConnector::node(star_node_id, 2), @@ -232,7 +247,7 @@ pub fn anchor_overlays(document: &DocumentMessageHandler, overlay_context: &mut /// Extract the node input values of Star. /// Returns an option of (sides, radius1, radius2). pub fn extract_star_parameters(layer: Option, document: &DocumentMessageHandler) -> Option<(u32, f64, f64)> { - let node_inputs = NodeGraphLayer::new(layer?, &document.network_interface).find_node_inputs("Star")?; + let node_inputs = NodeGraphLayer::new(layer?, &document.network_interface).find_node_inputs(&DefinitionIdentifier::ProtoNode(graphene_std::vector::generator_nodes::star::IDENTIFIER))?; let (Some(&TaggedValue::U32(sides)), Some(&TaggedValue::F64(radius_1)), Some(&TaggedValue::F64(radius_2))) = (node_inputs.get(1)?.as_value(), node_inputs.get(2)?.as_value(), node_inputs.get(3)?.as_value()) @@ -246,7 +261,8 @@ pub fn extract_star_parameters(layer: Option, document: &Do /// Extract the node input values of Polygon. /// Returns an option of (sides, radius). pub fn extract_polygon_parameters(layer: Option, document: &DocumentMessageHandler) -> Option<(u32, f64)> { - let node_inputs = NodeGraphLayer::new(layer?, &document.network_interface).find_node_inputs("Regular Polygon")?; + let node_inputs = + NodeGraphLayer::new(layer?, &document.network_interface).find_node_inputs(&DefinitionIdentifier::ProtoNode(graphene_std::vector::generator_nodes::regular_polygon::IDENTIFIER))?; let (Some(&TaggedValue::U32(n)), Some(&TaggedValue::F64(radius))) = (node_inputs.get(1)?.as_value(), node_inputs.get(2)?.as_value()) else { return None; @@ -258,7 +274,7 @@ pub fn extract_polygon_parameters(layer: Option, document: /// Extract the node input values of an arc. /// Returns an option of (radius, start angle, sweep angle, arc type). pub fn extract_arc_parameters(layer: Option, document: &DocumentMessageHandler) -> Option<(f64, f64, f64, ArcType)> { - let node_inputs = NodeGraphLayer::new(layer?, &document.network_interface).find_node_inputs("Arc")?; + let node_inputs = NodeGraphLayer::new(layer?, &document.network_interface).find_node_inputs(&DefinitionIdentifier::ProtoNode(graphene_std::vector::generator_nodes::arc::IDENTIFIER))?; let (Some(&TaggedValue::F64(radius)), Some(&TaggedValue::F64(start_angle)), Some(&TaggedValue::F64(sweep_angle)), Some(&TaggedValue::ArcType(arc_type))) = ( node_inputs.get(1)?.as_value(), @@ -298,7 +314,7 @@ pub fn arc_end_points_ignore_layer(radius: f64, start_angle: f64, sweep_angle: f /// Extract the node input values of Circle. /// Returns an option of (radius). pub fn extract_circle_radius(layer: LayerNodeIdentifier, document: &DocumentMessageHandler) -> Option { - let node_inputs = NodeGraphLayer::new(layer, &document.network_interface).find_node_inputs("Circle")?; + let node_inputs = NodeGraphLayer::new(layer, &document.network_interface).find_node_inputs(&DefinitionIdentifier::ProtoNode(graphene_std::vector::generator_nodes::circle::IDENTIFIER))?; let Some(&TaggedValue::F64(radius)) = node_inputs.get(1)?.as_value() else { return None; @@ -494,7 +510,7 @@ pub fn calculate_arc_text_transform(angle: f64, offset_angle: f64, center: DVec2 pub fn extract_grid_parameters(layer: LayerNodeIdentifier, document: &DocumentMessageHandler) -> Option<(GridType, DVec2, u32, u32, DVec2)> { use graphene_std::vector::generator_nodes::grid::*; - let node_inputs = NodeGraphLayer::new(layer, &document.network_interface).find_node_inputs("Grid")?; + let node_inputs = NodeGraphLayer::new(layer, &document.network_interface).find_node_inputs(&DefinitionIdentifier::ProtoNode(graphene_std::vector::generator_nodes::grid::IDENTIFIER))?; let (Some(&TaggedValue::GridType(grid_type)), Some(&TaggedValue::DVec2(spacing)), Some(&TaggedValue::U32(columns)), Some(&TaggedValue::U32(rows)), Some(&TaggedValue::DVec2(angles))) = ( node_inputs.get(GridTypeInput::INDEX)?.as_value(), diff --git a/editor/src/messages/tool/common_functionality/shapes/spiral_shape.rs b/editor/src/messages/tool/common_functionality/shapes/spiral_shape.rs index caf0346beb..9db94ca57f 100644 --- a/editor/src/messages/tool/common_functionality/shapes/spiral_shape.rs +++ b/editor/src/messages/tool/common_functionality/shapes/spiral_shape.rs @@ -1,6 +1,6 @@ use super::*; use crate::messages::portfolio::document::graph_operation::utility_types::TransformIn; -use crate::messages::portfolio::document::node_graph::document_node_definitions::resolve_document_node_type; +use crate::messages::portfolio::document::node_graph::document_node_definitions::{DefinitionIdentifier, resolve_document_node_type}; use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier; use crate::messages::portfolio::document::utility_types::network_interface::{InputConnector, NodeTemplate}; use crate::messages::tool::common_functionality::graph_modification_utils::{self, NodeGraphLayer}; @@ -24,7 +24,8 @@ impl Spiral { SpiralType::Logarithmic => 0.1, }; - let node_type = resolve_document_node_type("Spiral").expect("Spiral node can't be found"); + let identifier = DefinitionIdentifier::ProtoNode(graphene_std::vector::generator_nodes::spiral::IDENTIFIER); + let node_type = resolve_document_node_type(&identifier).expect("Spiral node can't be found"); node_type.node_template_input_override([ None, Some(NodeInput::value(TaggedValue::SpiralType(spiral_type), false)), @@ -62,7 +63,8 @@ impl Spiral { return; }; - let Some(node_inputs) = NodeGraphLayer::new(layer, &document.network_interface).find_node_inputs("Spiral") else { + let Some(node_inputs) = NodeGraphLayer::new(layer, &document.network_interface).find_node_inputs(&DefinitionIdentifier::ProtoNode(graphene_std::vector::generator_nodes::spiral::IDENTIFIER)) + else { return; }; @@ -93,7 +95,8 @@ impl Spiral { pub fn update_turns(decrease: bool, layer: LayerNodeIdentifier, document: &DocumentMessageHandler, responses: &mut VecDeque) { use graphene_std::vector::generator_nodes::spiral::*; - let Some(node_inputs) = NodeGraphLayer::new(layer, &document.network_interface).find_node_inputs("Spiral") else { + let Some(node_inputs) = NodeGraphLayer::new(layer, &document.network_interface).find_node_inputs(&DefinitionIdentifier::ProtoNode(graphene_std::vector::generator_nodes::spiral::IDENTIFIER)) + else { return; }; diff --git a/editor/src/messages/tool/common_functionality/shapes/star_shape.rs b/editor/src/messages/tool/common_functionality/shapes/star_shape.rs index 874f464e9b..acdde2c286 100644 --- a/editor/src/messages/tool/common_functionality/shapes/star_shape.rs +++ b/editor/src/messages/tool/common_functionality/shapes/star_shape.rs @@ -1,7 +1,7 @@ use super::shape_utility::{ShapeToolModifierKey, update_radius_sign}; use super::*; use crate::messages::portfolio::document::graph_operation::utility_types::TransformIn; -use crate::messages::portfolio::document::node_graph::document_node_definitions::resolve_document_node_type; +use crate::messages::portfolio::document::node_graph::document_node_definitions::{DefinitionIdentifier, resolve_document_node_type}; use crate::messages::portfolio::document::overlays::utility_types::OverlayContext; use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier; use crate::messages::portfolio::document::utility_types::network_interface::{InputConnector, NodeTemplate}; @@ -109,7 +109,8 @@ pub struct Star; impl Star { pub fn create_node(vertices: u32) -> NodeTemplate { - let node_type = resolve_document_node_type("Star").expect("Star node can't be found"); + let identifier = DefinitionIdentifier::ProtoNode(graphene_std::vector::generator_nodes::star::IDENTIFIER); + let node_type = resolve_document_node_type(&identifier).expect("Star node can't be found"); node_type.node_template_input_override([ None, Some(NodeInput::value(TaggedValue::U32(vertices), false)), diff --git a/editor/src/messages/tool/common_functionality/utility_functions.rs b/editor/src/messages/tool/common_functionality/utility_functions.rs index 3c457aa605..0b8fbc9d07 100644 --- a/editor/src/messages/tool/common_functionality/utility_functions.rs +++ b/editor/src/messages/tool/common_functionality/utility_functions.rs @@ -1,6 +1,7 @@ use super::snapping::{SnapCandidatePoint, SnapData, SnapManager}; use super::transformation_cage::{BoundingBoxManager, SizeSnapData}; use crate::consts::ROTATE_INCREMENT; +use crate::messages::portfolio::document::node_graph::document_node_definitions::DefinitionIdentifier; use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier; use crate::messages::portfolio::document::utility_types::network_interface::{NodeNetworkInterface, OutputConnector}; use crate::messages::portfolio::document::utility_types::transformation::Selected; @@ -588,7 +589,7 @@ pub fn make_path_editable_is_allowed(network_interface: &mut NodeNetworkInterfac // Must not already have an existing Path node, in the right-most part of the layer chain, which has an empty set of modifications // (otherwise users could repeatedly keep running this command and stacking up empty Path nodes) - if let Some(TaggedValue::VectorModification(modifications)) = NodeGraphLayer::new(first_layer, network_interface).find_input("Path", 1) + if let Some(TaggedValue::VectorModification(modifications)) = NodeGraphLayer::new(first_layer, network_interface).find_input(&DefinitionIdentifier::Network("Path".to_string()), 1) && modifications.as_ref() == &VectorModification::default() { return None; diff --git a/editor/src/messages/tool/tool_messages/brush_tool.rs b/editor/src/messages/tool/tool_messages/brush_tool.rs index 17da7b23a1..47a56a358b 100644 --- a/editor/src/messages/tool/tool_messages/brush_tool.rs +++ b/editor/src/messages/tool/tool_messages/brush_tool.rs @@ -1,7 +1,7 @@ use super::tool_prelude::*; use crate::consts::DEFAULT_BRUSH_SIZE; use crate::messages::portfolio::document::graph_operation::transform_utils::get_current_transform; -use crate::messages::portfolio::document::node_graph::document_node_definitions::resolve_document_node_type; +use crate::messages::portfolio::document::node_graph::document_node_definitions::{DefinitionIdentifier, resolve_document_node_type}; use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier; use crate::messages::portfolio::document::utility_types::network_interface::FlowType; use crate::messages::tool::common_functionality::color_selector::{ToolColorOptions, ToolColorType}; @@ -316,7 +316,7 @@ impl BrushToolData { continue; }; - if *reference == Some("Brush".to_string()) && node_id != layer.to_node() { + if reference == DefinitionIdentifier::Network("Brush".to_string()) && node_id != layer.to_node() { let points_input = node.inputs.get(1)?; let Some(TaggedValue::BrushStrokes(strokes)) = points_input.as_value() else { continue }; self.strokes.clone_from(strokes); @@ -324,7 +324,7 @@ impl BrushToolData { return Some(layer); } - if *reference == Some("Transform".to_string()) { + if reference == DefinitionIdentifier::Network("Transform".to_string()) { self.transform = get_current_transform(&node.inputs) * self.transform; } } @@ -475,8 +475,9 @@ impl Fsm for BrushToolFsmState { fn new_brush_layer(document: &DocumentMessageHandler, responses: &mut VecDeque) -> LayerNodeIdentifier { responses.add(DocumentMessage::DeselectAllLayers); - let brush_node = resolve_document_node_type("Brush").expect("Brush node does not exist").default_node_template(); - + let brush_node = resolve_document_node_type(&DefinitionIdentifier::Network("Brush".to_string())) + .expect("Brush node does not exist") + .default_node_template(); let id = NodeId::new(); responses.add(GraphOperationMessage::NewCustomLayer { id, diff --git a/editor/src/messages/tool/tool_messages/freehand_tool.rs b/editor/src/messages/tool/tool_messages/freehand_tool.rs index a74635f391..1d6d96886c 100644 --- a/editor/src/messages/tool/tool_messages/freehand_tool.rs +++ b/editor/src/messages/tool/tool_messages/freehand_tool.rs @@ -1,6 +1,6 @@ use super::tool_prelude::*; use crate::consts::DEFAULT_STROKE_WIDTH; -use crate::messages::portfolio::document::node_graph::document_node_definitions::resolve_document_node_type; +use crate::messages::portfolio::document::node_graph::document_node_definitions::{DefinitionIdentifier, resolve_document_node_type}; use crate::messages::portfolio::document::overlays::utility_functions::path_endpoint_overlays; use crate::messages::portfolio::document::overlays::utility_types::OverlayContext; use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier; @@ -286,7 +286,7 @@ impl Fsm for FreehandToolFsmState { let parent = document.new_layer_bounding_artboard(input, viewport); - let node_type = resolve_document_node_type("Path").expect("Path node does not exist"); + let node_type = resolve_document_node_type(&DefinitionIdentifier::Network("Path".to_string())).expect("Path node does not exist"); let node = node_type.default_node_template(); let nodes = vec![(NodeId(0), node)]; @@ -403,7 +403,7 @@ mod test_freehand { .filter_map(|layer| { let graph_layer = NodeGraphLayer::new(layer, &document.network_interface); // Only get layers with path nodes - let _ = graph_layer.upstream_visible_node_id_from_name_in_layer("Path")?; + let _ = graph_layer.upstream_visible_node_id_from_name_in_layer(&DefinitionIdentifier::Network("Path".to_string()))?; let vector = document.network_interface.compute_modified_vector(layer)?; let transform = document.metadata().transform_to_viewport(layer); diff --git a/editor/src/messages/tool/tool_messages/path_tool.rs b/editor/src/messages/tool/tool_messages/path_tool.rs index be300ebe5c..24dcb562b9 100644 --- a/editor/src/messages/tool/tool_messages/path_tool.rs +++ b/editor/src/messages/tool/tool_messages/path_tool.rs @@ -6,7 +6,7 @@ use crate::consts::{ }; use crate::messages::input_mapper::utility_types::macros::action_shortcut_manual; use crate::messages::portfolio::document::graph_operation::utility_types::TransformIn; -use crate::messages::portfolio::document::node_graph::document_node_definitions::resolve_document_node_type; +use crate::messages::portfolio::document::node_graph::document_node_definitions::{DefinitionIdentifier, resolve_document_node_type}; use crate::messages::portfolio::document::overlays::utility_functions::{path_overlays, selected_segments}; use crate::messages::portfolio::document::overlays::utility_types::{DrawHandles, OverlayContext}; use crate::messages::portfolio::document::utility_types::clipboards::Clipboard; @@ -2759,7 +2759,7 @@ impl Fsm for PathToolFsmState { let layer = if shape_editor.selected_shape_state.contains_key(&layer) { layer } else { - let Some(node_type) = resolve_document_node_type("Path") else { + let Some(node_type) = resolve_document_node_type(&DefinitionIdentifier::Network("Path".to_string())) else { error!("Could not resolve node type for Path"); continue; }; diff --git a/editor/src/messages/tool/tool_messages/pen_tool.rs b/editor/src/messages/tool/tool_messages/pen_tool.rs index 8cb1bfeecb..fa06f3d6de 100644 --- a/editor/src/messages/tool/tool_messages/pen_tool.rs +++ b/editor/src/messages/tool/tool_messages/pen_tool.rs @@ -1,7 +1,7 @@ use super::tool_prelude::*; use crate::consts::{COLOR_OVERLAY_BLUE, DEFAULT_STROKE_WIDTH, HIDE_HANDLE_DISTANCE, LINE_ROTATE_SNAP_ANGLE, SEGMENT_OVERLAY_SIZE}; use crate::messages::input_mapper::utility_types::input_mouse::MouseKeys; -use crate::messages::portfolio::document::node_graph::document_node_definitions::resolve_document_node_type; +use crate::messages::portfolio::document::node_graph::document_node_definitions::{DefinitionIdentifier, resolve_document_node_type}; use crate::messages::portfolio::document::overlays::utility_functions::path_overlays; use crate::messages::portfolio::document::overlays::utility_types::{DrawHandles, OverlayContext}; use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier; @@ -1293,7 +1293,7 @@ impl PenToolData { } // New path layer - let node_type = resolve_document_node_type("Path").expect("Path node does not exist"); + let node_type = resolve_document_node_type(&DefinitionIdentifier::Network("Path".to_string())).expect("Path node does not exist"); let nodes = vec![(NodeId(0), node_type.default_node_template())]; let parent = document.new_layer_bounding_artboard(input, viewport); diff --git a/editor/src/messages/tool/tool_messages/select_tool.rs b/editor/src/messages/tool/tool_messages/select_tool.rs index 3a19f4a399..f0c2458ea3 100644 --- a/editor/src/messages/tool/tool_messages/select_tool.rs +++ b/editor/src/messages/tool/tool_messages/select_tool.rs @@ -4,6 +4,7 @@ use super::tool_prelude::*; use crate::consts::*; use crate::messages::input_mapper::utility_types::input_mouse::ViewportPosition; use crate::messages::portfolio::document::graph_operation::utility_types::TransformIn; +use crate::messages::portfolio::document::node_graph::document_node_definitions::DefinitionIdentifier; use crate::messages::portfolio::document::overlays::utility_types::OverlayContext; use crate::messages::portfolio::document::utility_types::document_metadata::{DocumentMetadata, LayerNodeIdentifier}; use crate::messages::portfolio::document::utility_types::misc::{AlignAggregate, AlignAxis, FlipAxis, GroupFolderType}; @@ -623,7 +624,7 @@ impl Fsm for SelectToolFsmState { let layer_to_viewport = document.metadata().transform_to_viewport(layer); overlay_context.outline(document.metadata().layer_with_free_points_outline(layer), layer_to_viewport, None); - if is_layer_fed_by_node_of_name(layer, &document.network_interface, "Text") { + if is_layer_fed_by_node_of_name(layer, &document.network_interface, &DefinitionIdentifier::Network("Text".to_string())) { let transformed_quad = layer_to_viewport * text_bounding_box(layer, document, font_cache); overlay_context.dashed_quad(transformed_quad, None, None, Some(7.), Some(5.), None); } @@ -1577,7 +1578,7 @@ impl Fsm for SelectToolFsmState { if let Some(layer) = selected_layers.next() { // Check that only one layer is selected - if selected_layers.next().is_none() && is_layer_fed_by_node_of_name(layer, &document.network_interface, "Text") { + if selected_layers.next().is_none() && is_layer_fed_by_node_of_name(layer, &document.network_interface, &DefinitionIdentifier::Network("Text".to_string())) { responses.add_front(ToolMessage::ActivateTool { tool_type: ToolType::Text }); responses.add(TextToolMessage::EditSelected); } @@ -1931,7 +1932,7 @@ fn edit_layer_shallowest_manipulation(document: &DocumentMessageHandler, layer: /// Called when a double click on a layer in deep select mode. /// If the layer is text, the text tool is selected. fn edit_layer_deepest_manipulation(layer: LayerNodeIdentifier, network_interface: &NodeNetworkInterface, responses: &mut VecDeque) { - if is_layer_fed_by_node_of_name(layer, network_interface, "Text") { + if is_layer_fed_by_node_of_name(layer, network_interface, &DefinitionIdentifier::Network("Text".to_string())) { responses.add_front(ToolMessage::ActivateTool { tool_type: ToolType::Text }); responses.add(TextToolMessage::EditSelected); } diff --git a/editor/src/messages/tool/tool_messages/spline_tool.rs b/editor/src/messages/tool/tool_messages/spline_tool.rs index 55c8352abb..8d829155be 100644 --- a/editor/src/messages/tool/tool_messages/spline_tool.rs +++ b/editor/src/messages/tool/tool_messages/spline_tool.rs @@ -1,7 +1,7 @@ use super::tool_prelude::*; use crate::consts::{DEFAULT_STROKE_WIDTH, DRAG_THRESHOLD, PATH_JOIN_THRESHOLD, SNAP_POINT_TOLERANCE}; use crate::messages::input_mapper::utility_types::input_mouse::MouseKeys; -use crate::messages::portfolio::document::node_graph::document_node_definitions::resolve_document_node_type; +use crate::messages::portfolio::document::node_graph::document_node_definitions::{DefinitionIdentifier, resolve_document_node_type}; use crate::messages::portfolio::document::overlays::utility_functions::path_endpoint_overlays; use crate::messages::portfolio::document::overlays::utility_types::OverlayContext; use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier; @@ -389,9 +389,9 @@ impl Fsm for SplineToolFsmState { let parent = document.new_layer_bounding_artboard(input, viewport); - let path_node_type = resolve_document_node_type("Path").expect("Path node does not exist"); + let path_node_type = resolve_document_node_type(&DefinitionIdentifier::Network("Path".to_string())).expect("Path node does not exist"); let path_node = path_node_type.default_node_template(); - let spline_node_type = resolve_document_node_type("Spline").expect("Spline node does not exist"); + let spline_node_type = resolve_document_node_type(&DefinitionIdentifier::ProtoNode(graphene_std::vector::spline::IDENTIFIER)).expect("Spline node does not exist"); let spline_node = spline_node_type.node_template_input_override([Some(NodeInput::node(NodeId(1), 0))]); let nodes = vec![(NodeId(1), path_node), (NodeId(0), spline_node)]; diff --git a/editor/src/messages/tool/tool_messages/text_tool.rs b/editor/src/messages/tool/tool_messages/text_tool.rs index 3bdbc479d0..bc301deb6e 100644 --- a/editor/src/messages/tool/tool_messages/text_tool.rs +++ b/editor/src/messages/tool/tool_messages/text_tool.rs @@ -3,6 +3,7 @@ use super::tool_prelude::*; use crate::consts::{COLOR_OVERLAY_BLUE, COLOR_OVERLAY_RED, DRAG_THRESHOLD}; use crate::messages::portfolio::document::graph_operation::utility_types::TransformIn; +use crate::messages::portfolio::document::node_graph::document_node_definitions::DefinitionIdentifier; use crate::messages::portfolio::document::overlays::utility_types::OverlayContext; use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier; use crate::messages::portfolio::document::utility_types::network_interface::InputConnector; @@ -446,7 +447,7 @@ impl TextToolData { document .metadata() .all_layers() - .filter(|&layer| is_layer_fed_by_node_of_name(layer, &document.network_interface, "Text")) + .filter(|&layer| is_layer_fed_by_node_of_name(layer, &document.network_interface, &DefinitionIdentifier::Network("Text".to_string()))) .find(|&layer| { let transformed_quad = document.metadata().transform_to_viewport(layer) * text_bounding_box(layer, document, font_cache); let mouse = DVec2::new(input.mouse.position.x, input.mouse.position.y); @@ -475,7 +476,7 @@ fn can_edit_selected(document: &DocumentMessageHandler) -> Option = VecDeque::new(); - let transform_node_id = ModifyInputsContext::locate_node_in_layer_chain("Transform", layer, network_interface)?; + let transform_node_id = ModifyInputsContext::locate_node_in_layer_chain(&DefinitionIdentifier::Network("Transform".to_string()), layer, network_interface)?; let document_node = network_interface.document_network().nodes.get(&transform_node_id)?; Some(transform_utils::get_current_transform(&document_node.inputs)) } diff --git a/editor/src/test_utils.rs b/editor/src/test_utils.rs index d7a69d3025..8bf39d3c0a 100644 --- a/editor/src/test_utils.rs +++ b/editor/src/test_utils.rs @@ -2,6 +2,7 @@ use crate::application::Editor; use crate::application::set_uuid_seed; use crate::messages::input_mapper::utility_types::input_keyboard::ModifierKeys; use crate::messages::input_mapper::utility_types::input_mouse::{EditorMouseState, MouseKeys, ScrollDelta, ViewportPosition}; +use crate::messages::portfolio::document::node_graph::document_node_definitions::DefinitionIdentifier; use crate::messages::portfolio::utility_types::Platform; use crate::messages::prelude::*; use crate::messages::tool::tool_messages::tool_prelude::Key; @@ -307,11 +308,11 @@ impl EditorTestUtils { .await; } - pub async fn create_node_by_name(&mut self, name: impl Into) -> NodeId { + pub async fn create_node_by_name(&mut self, node_type: DefinitionIdentifier) -> NodeId { let node_id = NodeId::new(); self.handle_message(NodeGraphMessage::CreateNodeFromContextMenu { node_id: Some(node_id), - node_type: name.into(), + node_type, xy: None, add_transaction: true, }) diff --git a/frontend/src/components/floating-menus/NodeCatalog.svelte b/frontend/src/components/floating-menus/NodeCatalog.svelte index fae48136c5..8659d7e123 100644 --- a/frontend/src/components/floating-menus/NodeCatalog.svelte +++ b/frontend/src/components/floating-menus/NodeCatalog.svelte @@ -1,7 +1,7 @@