diff --git a/editor/src/messages/portfolio/document/document_message_handler.rs b/editor/src/messages/portfolio/document/document_message_handler.rs index 48828ee878..0002268c69 100644 --- a/editor/src/messages/portfolio/document/document_message_handler.rs +++ b/editor/src/messages/portfolio/document/document_message_handler.rs @@ -70,7 +70,7 @@ pub struct OldDocumentMessageHandler { /// Sets whether or not the rulers should be drawn along the top and left edges of the viewport area. pub rulers_visible: bool, /// Sets whether or not the node graph is drawn (as an overlay) on top of the viewport area, or otherwise if it's hidden. - pub graph_view_overlay_open: bool, + pub graph_ui_open: bool, /// The current user choices for snapping behavior, including whether snapping is enabled at all. pub snapping_state: SnappingState, } @@ -299,6 +299,7 @@ impl MessageHandler> for DocumentMessag } DocumentMessage::ClearLayersPanel => { // Send an empty layer list + // TODO: Dont create a new document message handler just to get the default data buffer for an empty layer structure let data_buffer: RawBuffer = Self::default().serialize_root(); responses.add(FrontendMessage::UpdateDocumentLayerStructure { data_buffer }); @@ -1326,7 +1327,7 @@ impl DocumentMessageHandler { view_mode: old_message_handler.view_mode, overlays_visible: old_message_handler.overlays_visible, rulers_visible: old_message_handler.rulers_visible, - graph_view_overlay_open: old_message_handler.graph_view_overlay_open, + graph_view_overlay_open: old_message_handler.graph_ui_open, snapping_state: old_message_handler.snapping_state, ..Default::default() }; @@ -1979,7 +1980,7 @@ impl DocumentMessageHandler { /// Create a network interface with a single export fn default_document_network_interface() -> NodeNetworkInterface { let mut network_interface = NodeNetworkInterface::default(); - network_interface.add_export(TaggedValue::ArtboardGroup(graphene_core::ArtboardGroup::EMPTY), -1, "".to_string(), &[]); network_interface.insert_network_metadata(NodeNetworkPersistentMetadata::default(), &[]); + network_interface.add_export(TaggedValue::ArtboardGroup(graphene_core::ArtboardGroup::EMPTY), -1, "".to_string(), &[]); network_interface } 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 93139bab30..271ed7cbc4 100644 --- a/editor/src/messages/portfolio/document/utility_types/network_interface.rs +++ b/editor/src/messages/portfolio/document/utility_types/network_interface.rs @@ -7,8 +7,9 @@ use crate::messages::tool::common_functionality::graph_modification_utils; use bezier_rs::Subpath; use graph_craft::document::{value::TaggedValue, DocumentNode, DocumentNodeImplementation, NodeId, NodeInput, NodeNetwork, OldDocumentNodeImplementation, OldNodeNetwork}; -use graph_craft::document::{InputConnector, OutputConnector, Previewing, RootNode, PTZ}; +use graph_craft::document::{InputConnector, LayerOwner, NetworkEdgeDistance, OutputConnector, Ports, Previewing, RootNode, TransientMetadata, PTZ}; use graph_craft::{concrete, Type}; +use graphene_std::memo::MemoHashGuard; use graphene_std::renderer::{ClickTarget, Quad}; use graphene_std::vector::{PointId, VectorData, VectorModificationType}; use interpreted_executor::{dynamic_executor::ResolvedDocumentNodeTypes, node_registry::NODE_REGISTRY}; @@ -24,6 +25,8 @@ pub struct NodeNetworkInterface { /// The node graph that generates this document's artwork. It recursively stores its sub-graphs, so this root graph is the whole snapshot of the document content. /// A public mutable reference should never be created. It should only be mutated through custom setters which perform the necessary side effects to keep network_metadata in sync network: NodeNetwork, + /// Stores all editor information for the document network as inputs to nodes. The node graph overlay nodes are added to this network. + metadata_network: NodeNetwork, // TODO: Remove and store in node network with IDs based on Self::metadata_node_id /// Stores all editor information for a NodeNetwork. Should automatically kept in sync by the setter methods when changes to the document network are made. network_metadata: NodeNetworkMetadata, @@ -39,8 +42,9 @@ pub struct NodeNetworkInterface { transaction_status: TransactionStatus, } +//TODO: This could probably be merged into tagged values // Enum to represent all metadata in the network, which can be used uniquely identify any stored value -#[derive(Hash)] +#[derive(Copy, Clone, Hash, Debug)] pub enum MetadataType { // Network persistent metadata Previewing, @@ -48,11 +52,11 @@ pub enum MetadataType { SelectionUndoHistory, SelectionRedoHistory, // Network transient metadata - SelectedNodes, StackDependents, AllNodesBoundingBox, OutwardWires, ImportExportPorts, + RoundedNetworkEdgeDistance, // Node persistent metadata Reference, DisplayName, @@ -69,7 +73,7 @@ pub enum MetadataType { IsLayer, } -#[derive(Hash)] +#[derive(Copy, Clone, Hash, Debug)] pub enum NavigationMetadataType { PTZ, NodeGraphToViewport, @@ -80,6 +84,7 @@ impl Clone for NodeNetworkInterface { fn clone(&self) -> Self { Self { network: self.network.clone(), + metadata_network: self.metadata_network.clone(), network_metadata: self.network_metadata.clone(), document_metadata: Default::default(), resolved_types: Default::default(), @@ -90,7 +95,7 @@ impl Clone for NodeNetworkInterface { impl PartialEq for NodeNetworkInterface { fn eq(&self, other: &Self) -> bool { - self.network == other.network && self.network_metadata == other.network_metadata + self.network == other.network && self.metadata_network == other.metadata_network } } @@ -101,6 +106,10 @@ impl NodeNetworkInterface { self.network.nested_network(network_path) } + pub fn metadata_network(&self, network_path: &[NodeId]) -> Option<&NodeNetwork> { + self.metadata_network.nested_network(network_path) + } + /// The network metadata should always exist for the current network pub fn network_metadata(&self, network_path: &[NodeId]) -> Option<&NodeNetworkMetadata> { self.network_metadata.nested_metadata(network_path) @@ -504,7 +513,7 @@ impl NodeNetworkInterface { fn metadata_value(&self, metadata: MetadataType, node_path: &[NodeId]) -> Option<&TaggedValue> { let node_id = Self::metadata_node_id(metadata, node_path); - let network = self.network(&[]).unwrap(); + let network = self.metadata_network(&[]).unwrap(); let Some(node) = network.nodes.get(&node_id) else { log::error!("Could not get node {node_id} in value_from_node_id"); return None; @@ -512,6 +521,21 @@ impl NodeNetworkInterface { node.inputs.first().expect("Metadata node should always have primary input to store data").as_value() } + /// Returns the MemoHashGuard, which much be dereferenced with .deref_mut() to access the mutable value + fn metadata_value_mut(&mut self, metadata: MetadataType, node_path: &[NodeId]) -> Option> { + let network = self.metadata_network_mut(&[]).unwrap(); + let metadata_node_id = Self::metadata_node_id(metadata, node_path); + let Some(metadata_node) = network.nodes.get_mut(&metadata_node_id) else { + log::error!("Could not get metadata {metadata:?} for node path {node_path:?} with id {metadata_node_id} in metadata_value_mut"); + return None; + }; + let Some(metadata_input) = metadata_node.inputs.get_mut(0) else { + log::error!("Could not get metadata input in metadata_value_mut"); + return None; + }; + metadata_input.as_value_mut() + } + /// Get the [`Type`] for any InputConnector pub fn input_type(&self, input_connector: &InputConnector, network_path: &[NodeId]) -> Type { // TODO: If the input_connector is a NodeInput::Value, return the type of the tagged value @@ -735,14 +759,13 @@ impl NodeNetworkInterface { pub fn frontend_imports(&mut self, network_path: &[NodeId]) -> Option> { self.import_export_ports(network_path).cloned().map(|import_export_ports| { import_export_ports - .output_ports - .iter() + .output_ports() .filter_map(|(import_index, click_target)| { // Get import name from parent node metadata input, which must match the number of imports. // Empty string means to use type, or "Import + index" if type can't be determined let import_name = self .encapsulating_node_metadata(network_path) - .and_then(|encapsulating_metadata| encapsulating_metadata.persistent_metadata.input_names.get(*import_index).cloned()) + .and_then(|encapsulating_metadata| encapsulating_metadata.persistent_metadata.input_names.get(import_index).cloned()) .unwrap_or_default(); let mut import_metadata = None; @@ -751,14 +774,14 @@ impl NodeNetworkInterface { let mut encapsulating_path = network_path.to_vec(); let encapsulating_node_id = encapsulating_path.pop().unwrap(); - let input_type = self.input_type(&InputConnector::node(encapsulating_node_id, *import_index), &encapsulating_path); + let input_type = self.input_type(&InputConnector::node(encapsulating_node_id, import_index), &encapsulating_path); let data_type = FrontendGraphDataType::with_type(&input_type); let import_name = if import_name.is_empty() { input_type.clone().nested_type().to_string() } else { import_name }; let connected_to = self .outward_wires(network_path) - .and_then(|outward_wires| outward_wires.get(&OutputConnector::Import(*import_index))) + .and_then(|outward_wires| outward_wires.get(&OutputConnector::Import(import_index))) .cloned() .unwrap_or_else(|| { log::error!("Could not get OutputConnector::Import({import_index}) in outward wires"); @@ -785,15 +808,14 @@ impl NodeNetworkInterface { pub fn frontend_exports(&mut self, network_path: &[NodeId]) -> Option> { self.import_export_ports(network_path).cloned().map(|import_export_ports| { import_export_ports - .input_ports - .iter() + .input_ports() .filter_map(|(export_index, click_target)| { let Some(network) = self.network(network_path) else { log::error!("Could not get network in frontend_exports"); return None; }; - let Some(export) = network.exports.get(*export_index) else { + let Some(export) = network.exports.get(export_index) else { log::error!("Could not get export {export_index} in frontend_exports"); return None; }; @@ -817,7 +839,7 @@ impl NodeNetworkInterface { }; // First import index is visually connected to the root node instead of its actual export input so previewing does not change the connection - let connected_to = if *export_index == 0 { + let connected_to = if export_index == 0 { self.root_node(network_path).map(|root_node| OutputConnector::node(root_node.node_id, root_node.output_index)) } else if let NodeInput::Node { node_id, output_index, .. } = export { Some(OutputConnector::node(*node_id, *output_index)) @@ -833,7 +855,7 @@ impl NodeNetworkInterface { "Canvas".to_string() } else { self.encapsulating_node_metadata(network_path) - .and_then(|encapsulating_metadata| encapsulating_metadata.persistent_metadata.output_names.get(*export_index).cloned()) + .and_then(|encapsulating_metadata| encapsulating_metadata.persistent_metadata.output_names.get(export_index).cloned()) .unwrap_or_default() }; @@ -1517,8 +1539,11 @@ impl NodeNetworkInterface { nested_network_metadata.persistent_metadata.node_metadata.insert(node_id, node_metadata); } } + //TODO: Add metadata to this + let metadata_network = NodeNetwork::default(); Self { network: node_network, + metadata_network, network_metadata, document_metadata: DocumentMetadata::default(), resolved_types: ResolvedDocumentNodeTypes::default(), @@ -1551,6 +1576,11 @@ impl NodeNetworkInterface { self.network.nested_network_mut(network_path) } + fn metadata_network_mut(&mut self, network_path: &[NodeId]) -> Option<&mut NodeNetwork> { + self.metadata_network.nested_network_mut(network_path) + } + + // TODO: Remove fn network_metadata_mut(&mut self, network_path: &[NodeId]) -> Option<&mut NodeNetworkMetadata> { self.network_metadata.nested_metadata_mut(network_path) } @@ -1568,15 +1598,15 @@ impl NodeNetworkInterface { } /// Mutably get the network which the encapsulating node of the currently viewed network is part of. Will always be None in the document network. - fn encapsulating_network_metadata_mut(&mut self, network_path: &[NodeId]) -> Option<&mut NodeNetworkMetadata> { - let mut encapsulating_path = network_path.to_vec(); - encapsulating_path.pop()?; - let Some(parent_metadata) = self.network_metadata_mut(&encapsulating_path) else { - log::error!("Could not get parent network in encapsulating_node_metadata"); - return None; - }; - Some(parent_metadata) - } + // fn encapsulating_network_metadata_mut(&mut self, network_path: &[NodeId]) -> Option<&mut NodeNetworkMetadata> { + // let mut encapsulating_path = network_path.to_vec(); + // encapsulating_path.pop()?; + // let Some(parent_metadata) = self.network_metadata_mut(&encapsulating_path) else { + // log::error!("Could not get parent network in encapsulating_node_metadata"); + // return None; + // }; + // Some(parent_metadata) + // } /// Mutably get the node which encapsulates the currently viewed network. Will always be None in the document network. // fn encapsulating_node_mut(&mut self, network_path: &[NodeId]) -> Option<&mut DocumentNode> { @@ -1646,22 +1676,12 @@ impl NodeNetworkInterface { } } - let network = self.network_mut(&[]).unwrap(); - let metadata_node_id = Self::metadata_node_id(MetadataType::SelectionUndoHistory, network_path); - let Some(metadata_node) = network.nodes.get_mut(&metadata_node_id) else { - log::error!("Could not get metadata node with id {metadata_node_id} in set_metadata"); - return; - }; - let Some(metadata_input) = metadata_node.inputs.get_mut(0) else { - log::error!("Could not get metadata input in set_metadata"); - return; - }; - let Some(mut value) = metadata_input.as_value_mut() else { - log::error!("Could not get tagged value in set_metadata"); + let Some(mut value) = self.metadata_value_mut(MetadataType::SelectionUndoHistory, network_path) else { + log::error!("Could not get tagged value in mutate_selected_nodes"); return; }; let TaggedValue::SelectionHistory(selection_undo_history) = value.deref_mut() else { - log::error!("Tagged value should be SelectionUndoHistory in set_metadata"); + log::error!("Tagged value should be SelectionUndoHistory in mutate_selected_nodes"); return; }; selection_undo_history.push_back(last_selection_state); @@ -1683,22 +1703,12 @@ impl NodeNetworkInterface { self.mutate_selected_nodes(nodes, SelectionOperation::Set, network_path); } pub fn remove_selection_history_step(&mut self, network_path: &[NodeId]) { - let network = self.network_mut(&[]).unwrap(); - let metadata_node_id = Self::metadata_node_id(MetadataType::SelectionUndoHistory, network_path); - let Some(metadata_node) = network.nodes.get_mut(&metadata_node_id) else { - log::error!("Could not get metadata node with id {metadata_node_id} in set_metadata"); - return; - }; - let Some(metadata_input) = metadata_node.inputs.get_mut(0) else { - log::error!("Could not get metadata input in set_metadata"); - return; - }; - let Some(mut value) = metadata_input.as_value_mut() else { - log::error!("Could not get tagged value in set_metadata"); + let Some(mut value) = self.metadata_value_mut(MetadataType::SelectionUndoHistory, network_path) else { + log::error!("Could not get tagged value in remove_selection_history_step"); return; }; let TaggedValue::SelectionHistory(selection_undo_history) = value.deref_mut() else { - log::error!("Tagged value should be SelectionUndoHistory in set_metadata"); + log::error!("Tagged value should be SelectionUndoHistory in remove_selection_history_step"); return; }; selection_undo_history.pop_back(); @@ -1718,17 +1728,7 @@ impl NodeNetworkInterface { SelectionDirection::Forward => (MetadataType::SelectionRedoHistory, MetadataType::SelectionUndoHistory), }; - let network = self.network_mut(&[]).unwrap(); - let metadata_node_id = Self::metadata_node_id(adding_to, network_path); - let Some(metadata_node) = network.nodes.get_mut(&metadata_node_id) else { - log::error!("Could not get metadata node with id {metadata_node_id} in selection_step"); - return; - }; - let Some(metadata_input) = metadata_node.inputs.get_mut(0) else { - log::error!("Could not get metadata input in selection_step"); - return; - }; - let Some(mut value) = metadata_input.as_value_mut() else { + let Some(mut value) = self.metadata_value_mut(adding_to, network_path) else { log::error!("Could not get tagged value in selection_step"); return; }; @@ -1738,17 +1738,7 @@ impl NodeNetworkInterface { }; if let Some(selection_state) = selection_history.pop_back() { drop(value); - let network = self.network_mut(&[]).unwrap(); - let metadata_node_id = Self::metadata_node_id(removing_from, network_path); - let Some(metadata_node) = network.nodes.get_mut(&metadata_node_id) else { - log::error!("Could not get metadata node with id {metadata_node_id} in selection_step"); - return; - }; - let Some(metadata_input) = metadata_node.inputs.get_mut(0) else { - log::error!("Could not get metadata input in selection_step"); - return; - }; - let Some(mut value) = metadata_input.as_value_mut() else { + let Some(mut value) = self.metadata_value_mut(removing_from, network_path) else { log::error!("Could not get tagged value in selection_step"); return; }; @@ -1766,23 +1756,23 @@ impl NodeNetworkInterface { } fn try_load_stack_dependents(&mut self, network_path: &[NodeId]) { - let Some(network_metadata) = self.network_metadata(network_path) else { + let Some(TaggedValue::StackDependents(stack_dependents)) = self.metadata_value(MetadataType::StackDependents, network_path) else { log::error!("Could not get nested network_metadata in stack_dependents"); return; }; - if !network_metadata.transient_metadata.stack_dependents.is_loaded() { + if !stack_dependents.is_loaded() { self.load_stack_dependents(network_path); } } fn try_get_stack_dependents(&self, network_path: &[NodeId]) -> Option<&HashMap> { - let Some(network_metadata) = self.network_metadata(network_path) else { - log::error!("Could not get nested network_metadata in try_get_stack_dependents"); + let Some(stack_dependents) = self.metadata_value(MetadataType::StackDependents, network_path) else { + log::error!("Could not get stack_dependents in try_get_stack_dependents"); return None; }; - let TransientMetadata::Loaded(stack_dependents) = &network_metadata.transient_metadata.stack_dependents else { - log::error!("could not load stack_dependents"); + let TaggedValue::StackDependents(TransientMetadata::Loaded(stack_dependents)) = stack_dependents else { + log::error!("Could not get stack_dependents in try_get_stack_dependents"); return None; }; Some(stack_dependents) @@ -1928,30 +1918,20 @@ impl NodeNetworkInterface { } } - let Some(network_metadata) = self.network_metadata_mut(network_path) else { - log::error!("Could not get current network in load_export_ports"); - return; - }; - - network_metadata.transient_metadata.stack_dependents = TransientMetadata::Loaded(stack_dependents); + self.set_metadata(MetadataType::StackDependents, TaggedValue::StackDependents(TransientMetadata::Loaded(stack_dependents)), network_path); } pub fn unload_stack_dependents(&mut self, network_path: &[NodeId]) { - let Some(network_metadata) = self.network_metadata_mut(network_path) else { - log::error!("Could not get nested network_metadata in unload_stack_dependents"); - return; - }; - network_metadata.transient_metadata.stack_dependents.unload(); + self.set_metadata(MetadataType::StackDependents, TaggedValue::StackDependents(TransientMetadata::Unloaded), network_path) } /// Resets all the offsets for nodes with no LayerOwner when the drag ends pub fn unload_stack_dependents_y_offset(&mut self, network_path: &[NodeId]) { - let Some(network_metadata) = self.network_metadata_mut(network_path) else { - log::error!("Could not get nested network_metadata in unload_stack_dependents_y_offset"); + let Some(mut value) = self.metadata_value_mut(MetadataType::StackDependents, network_path) else { + log::error!("Could not get stack_dependents in unload_stack_dependents_y_offset"); return; }; - - if let TransientMetadata::Loaded(stack_dependents) = &mut network_metadata.transient_metadata.stack_dependents { + if let TaggedValue::StackDependents(TransientMetadata::Loaded(stack_dependents)) = value.deref_mut() { for layer_owner in stack_dependents.values_mut() { if let LayerOwner::None(offset) = layer_owner { *offset = 0; @@ -1961,22 +1941,18 @@ impl NodeNetworkInterface { } pub fn import_export_ports(&mut self, network_path: &[NodeId]) -> Option<&Ports> { - let Some(network_metadata) = self.network_metadata(network_path) else { + let Some(TaggedValue::ImportExportPorts(import_export_ports)) = self.metadata_value(MetadataType::ImportExportPorts, network_path) else { log::error!("Could not get nested network_metadata in export_ports"); return None; }; - if !network_metadata.transient_metadata.import_export_ports.is_loaded() { + if !import_export_ports.is_loaded() { self.load_import_export_ports(network_path); } - let Some(network_metadata) = self.network_metadata(network_path) else { - log::error!("Could not get nested network_metadata in export_ports"); - return None; - }; - let TransientMetadata::Loaded(ports) = &network_metadata.transient_metadata.import_export_ports else { + let Some(TaggedValue::ImportExportPorts(TransientMetadata::Loaded(import_export_ports))) = self.metadata_value(MetadataType::ImportExportPorts, network_path) else { log::error!("could not load import ports"); return None; }; - Some(ports) + Some(import_export_ports) } pub fn load_import_export_ports(&mut self, network_path: &[NodeId]) { @@ -2034,35 +2010,27 @@ impl NodeNetworkInterface { for output_index in 0..self.number_of_displayed_imports(network_path) { import_export_ports.insert_output_port_at_center(output_index, import_top_left + DVec2::new(0., output_index as f64 * 24.)); } - let Some(network_metadata) = self.network_metadata_mut(network_path) else { - log::error!("Could not get current network in load_export_ports"); - return; - }; - - network_metadata.transient_metadata.import_export_ports = TransientMetadata::Loaded(import_export_ports); + self.set_metadata( + MetadataType::ImportExportPorts, + TaggedValue::ImportExportPorts(TransientMetadata::Loaded(import_export_ports)), + network_path, + ); } fn unload_import_export_ports(&mut self, network_path: &[NodeId]) { - let Some(network_metadata) = self.network_metadata_mut(network_path) else { - log::error!("Could not get nested network_metadata in unload_export_ports"); - return; - }; - network_metadata.transient_metadata.import_export_ports.unload(); + self.set_metadata(MetadataType::ImportExportPorts, TaggedValue::ImportExportPorts(TransientMetadata::Unloaded), network_path); } pub fn rounded_network_edge_distance(&mut self, network_path: &[NodeId]) -> Option<&NetworkEdgeDistance> { - let Some(network_metadata) = self.network_metadata(network_path) else { + let Some(TaggedValue::RoundedNetworkEdgeDistance(rounded_network_edge_distance)) = self.metadata_value(MetadataType::RoundedNetworkEdgeDistance, network_path) else { log::error!("Could not get nested network_metadata in rounded_network_edge_distance"); return None; }; - if !network_metadata.transient_metadata.rounded_network_edge_distance.is_loaded() { + if !rounded_network_edge_distance.is_loaded() { self.load_rounded_network_edge_distance(network_path); } - let Some(network_metadata) = self.network_metadata(network_path) else { - log::error!("Could not get nested network_metadata in rounded_network_edge_distance"); - return None; - }; - let TransientMetadata::Loaded(rounded_network_edge_distance) = &network_metadata.transient_metadata.rounded_network_edge_distance else { + let Some(TaggedValue::RoundedNetworkEdgeDistance(TransientMetadata::Loaded(rounded_network_edge_distance))) = self.metadata_value(MetadataType::RoundedNetworkEdgeDistance, network_path) + else { log::error!("could not load import rounded_network_edge_distance"); return None; }; @@ -2101,19 +2069,19 @@ impl NodeNetworkInterface { exports_to_edge_distance: rounded_viewport_exports_distance, imports_to_edge_distance: rounded_viewport_imports_distance, }; - let Some(network_metadata) = self.network_metadata_mut(network_path) else { - log::error!("Could not get current network in load_export_ports"); - return; - }; - network_metadata.transient_metadata.rounded_network_edge_distance = TransientMetadata::Loaded(network_edge_distance); + self.set_metadata( + MetadataType::RoundedNetworkEdgeDistance, + TaggedValue::RoundedNetworkEdgeDistance(TransientMetadata::Loaded(network_edge_distance)), + network_path, + ); } fn unload_rounded_network_edge_distance(&mut self, network_path: &[NodeId]) { - let Some(network_metadata) = self.network_metadata_mut(network_path) else { - log::error!("Could not get nested network_metadata in unload_export_ports"); - return; - }; - network_metadata.transient_metadata.rounded_network_edge_distance.unload(); + self.set_metadata( + MetadataType::RoundedNetworkEdgeDistance, + TaggedValue::RoundedNetworkEdgeDistance(TransientMetadata::Unloaded), + network_path, + ); } fn owned_nodes(&self, node_id: &NodeId, network_path: &[NodeId]) -> Option<&HashSet> { @@ -2128,31 +2096,28 @@ impl NodeNetworkInterface { } pub fn all_nodes_bounding_box(&mut self, network_path: &[NodeId]) -> Option<&[DVec2; 2]> { - let Some(network_metadata) = self.network_metadata(network_path) else { + let Some(TaggedValue::AllNodesBoundingBox(all_nodes_bounding_box)) = self.metadata_value(MetadataType::AllNodesBoundingBox, network_path) else { log::error!("Could not get nested network_metadata in all_nodes_bounding_box"); return None; }; - - if !network_metadata.transient_metadata.all_nodes_bounding_box.is_loaded() { + if !all_nodes_bounding_box.is_loaded() { self.load_all_nodes_bounding_box(network_path); } - let network_metadata = self.network_metadata(network_path)?; - - let TransientMetadata::Loaded(bounding_box) = &network_metadata.transient_metadata.all_nodes_bounding_box else { + let Some(TaggedValue::AllNodesBoundingBox(TransientMetadata::Loaded(all_nodes_bounding_box))) = self.metadata_value(MetadataType::AllNodesBoundingBox, network_path) else { log::error!("could not load all nodes bounding box"); return None; }; - Some(bounding_box) + Some(all_nodes_bounding_box) } pub fn load_all_nodes_bounding_box(&mut self, network_path: &[NodeId]) { - let Some(network_metadata) = self.network_metadata(network_path) else { + let Some(network) = self.network(network_path) else { log::error!("Could not get nested network_metadata in load_all_nodes_bounding_box"); return; }; - let nodes = network_metadata.persistent_metadata.node_metadata.keys().copied().collect::>(); + let nodes = network.nodes.keys().copied().collect::>(); let all_nodes_bounding_box = nodes .iter() @@ -2163,33 +2128,29 @@ impl NodeNetworkInterface { .reduce(Quad::combine_bounds) .unwrap_or([DVec2::new(0., 0.), DVec2::new(0., 0.)]); - let Some(network_metadata) = self.network_metadata_mut(network_path) else { return }; - - network_metadata.transient_metadata.all_nodes_bounding_box = TransientMetadata::Loaded(all_nodes_bounding_box); + self.set_metadata( + MetadataType::AllNodesBoundingBox, + TaggedValue::AllNodesBoundingBox(TransientMetadata::Loaded(all_nodes_bounding_box)), + network_path, + ); } pub fn unload_all_nodes_bounding_box(&mut self, network_path: &[NodeId]) { - let Some(network_metadata) = self.network_metadata_mut(network_path) else { - log::error!("Could not get nested network_metadata in unload_all_nodes_bounding_box"); - return; - }; - network_metadata.transient_metadata.all_nodes_bounding_box.unload(); - network_metadata.transient_metadata.import_export_ports.unload(); + self.set_metadata(MetadataType::AllNodesBoundingBox, TaggedValue::AllNodesBoundingBox(TransientMetadata::Unloaded), network_path); + self.set_metadata(MetadataType::ImportExportPorts, TaggedValue::ImportExportPorts(TransientMetadata::Unloaded), network_path); } pub fn outward_wires(&mut self, network_path: &[NodeId]) -> Option<&HashMap>> { - let Some(network_metadata) = self.network_metadata(network_path) else { + let Some(TaggedValue::OutwardWires(outward_wires)) = self.metadata_value(MetadataType::OutwardWires, network_path) else { log::error!("Could not get nested network_metadata in outward_wires"); return None; }; - if !network_metadata.transient_metadata.outward_wires.is_loaded() { + if !outward_wires.is_loaded() { self.load_outward_wires(network_path); } - let network_metadata = self.network_metadata(network_path)?; - - let TransientMetadata::Loaded(outward_wires) = &network_metadata.transient_metadata.outward_wires else { + let Some(TaggedValue::OutwardWires(TransientMetadata::Loaded(outward_wires))) = self.metadata_value(MetadataType::OutwardWires, network_path) else { log::error!("could not load outward wires"); return None; }; @@ -2240,17 +2201,11 @@ impl NodeNetworkInterface { } } - let Some(network_metadata) = self.network_metadata_mut(network_path) else { return }; - - network_metadata.transient_metadata.outward_wires = TransientMetadata::Loaded(outward_wires); + self.set_metadata(MetadataType::OutwardWires, TaggedValue::OutwardWires(TransientMetadata::Loaded(outward_wires)), network_path); } fn unload_outward_wires(&mut self, network_path: &[NodeId]) { - let Some(network_metadata) = self.network_metadata_mut(network_path) else { - log::error!("Could not get nested network_metadata in unload_outward_wires"); - return; - }; - network_metadata.transient_metadata.outward_wires.unload(); + self.set_metadata(MetadataType::OutwardWires, TaggedValue::OutwardWires(TransientMetadata::Unloaded), network_path); } pub fn layer_width(&mut self, node_id: &NodeId, network_path: &[NodeId]) -> Option { @@ -3164,9 +3119,11 @@ impl NodeNetworkInterface { self.unload_outward_wires(network_path); // Update the outward wires and bounding box for all nodes in the encapsulating network - if let Some(encapsulating_network_metadata) = self.encapsulating_network_metadata_mut(network_path) { - encapsulating_network_metadata.transient_metadata.outward_wires.unload(); - encapsulating_network_metadata.transient_metadata.all_nodes_bounding_box.unload(); + if network_path.len() > 1 { + let mut encapsulating_network_path = network_path.to_vec(); + encapsulating_network_path.pop(); + self.unload_outward_wires(&encapsulating_network_path); + self.unload_all_nodes_bounding_box(&encapsulating_network_path); } // Update the click targets for the encapsulating node, if it exists. There is no encapsulating node if the network is the document network @@ -3216,9 +3173,11 @@ impl NodeNetworkInterface { } // Update the internal network import ports and outwards connections (if has a network implementation) - if let Some(internal_network) = &mut node_metadata.persistent_metadata.network_metadata { - internal_network.transient_metadata.import_export_ports.unload(); - internal_network.transient_metadata.outward_wires.unload(); + if node_metadata.persistent_metadata.network_metadata.is_some() { + let mut internal_network_path = network_path.to_vec(); + internal_network_path.push(*node_id); + self.unload_import_export_ports(&internal_network_path); + self.unload_outward_wires(&internal_network_path); } // Update the click targets for the node @@ -3545,6 +3504,8 @@ impl NodeNetworkInterface { }; network.nodes.insert(node_id, node_template.document_node); + // TODO: Remove this clone once the later usage is removed + self.insert_all_node_metadata(node_id, node_template.persistent_node_metadata.clone(), network_path); self.transaction_modified(); let Some(network_metadata) = self.network_metadata_mut(network_path) else { @@ -3635,7 +3596,15 @@ impl NodeNetworkInterface { TaggedValue::SelectionHistory(persistent_metadata.selection_redo_history), network_path, ); - // TODO: Add the rest of the network metadata nodes + self.insert_node_metadata(MetadataType::StackDependents, TaggedValue::StackDependents(TransientMetadata::Unloaded), network_path); + self.insert_node_metadata(MetadataType::AllNodesBoundingBox, TaggedValue::AllNodesBoundingBox(TransientMetadata::Unloaded), network_path); + self.insert_node_metadata(MetadataType::OutwardWires, TaggedValue::OutwardWires(TransientMetadata::Unloaded), network_path); + self.insert_node_metadata(MetadataType::ImportExportPorts, TaggedValue::ImportExportPorts(TransientMetadata::Unloaded), network_path); + self.insert_node_metadata( + MetadataType::RoundedNetworkEdgeDistance, + TaggedValue::RoundedNetworkEdgeDistance(TransientMetadata::Unloaded), + network_path, + ); for (node_id, node_metadata) in persistent_metadata.node_metadata { self.insert_all_node_metadata(node_id, node_metadata.persistent_metadata, network_path); @@ -3645,8 +3614,8 @@ impl NodeNetworkInterface { /// Adds a node for the metadata. TODO: Consider calling this in set_metadata if a metadata node cannot be found. fn insert_node_metadata(&mut self, metadata: MetadataType, tagged_value: TaggedValue, node_path: &[NodeId]) { let metadata_node_id = Self::metadata_node_id(metadata, node_path); - let network = self.network_mut(&[]).unwrap(); - log::debug!("Inserting metadata node with id {metadata_node_id}"); + log::debug!("Inserting metadata {metadata:?} for node {node_path:?} with id {metadata_node_id}"); + let network = self.metadata_network_mut(&[]).unwrap(); network.nodes.insert( metadata_node_id, DocumentNode { @@ -3866,20 +3835,8 @@ impl NodeNetworkInterface { // } pub fn set_metadata(&mut self, metadata: MetadataType, tagged_value: TaggedValue, node_path: &[NodeId]) { - let network = self.network_mut(&[]).unwrap(); - - let metadata_node_id = Self::metadata_node_id(metadata, node_path); - - let Some(metadata_node) = network.nodes.get_mut(&metadata_node_id) else { - log::error!("Could not get metadata node with id {metadata_node_id} in set_metadata"); - return; - }; - let Some(metadata_input) = metadata_node.inputs.get_mut(0) else { - log::error!("Could not get metadata input in set_metadata"); - return; - }; - let Some(mut value) = metadata_input.as_value_mut() else { - log::error!("Could not get tagged value in set_metadata"); + let Some(mut value) = self.metadata_value_mut(metadata, node_path) else { + log::error!("Could not set tagged value {tagged_value:?} for metadata {metadata:?} and node {node_path:?} in set_metadata"); return; }; *value.deref_mut() = tagged_value; @@ -4487,16 +4444,22 @@ impl NodeNetworkInterface { shifted_nodes.insert(*node_id); self.shift_node(node_id, IVec2::new(0, shift_sign), network_path); - let Some(network_metadata) = self.network_metadata_mut(network_path) else { - log::error!("Could not get nested network_metadata in export_ports"); - continue; + let Some(mut value) = self.metadata_value_mut(MetadataType::StackDependents, network_path) else { + log::error!("Could not get stack dependents in shift_selected_nodes"); + return; }; - if let TransientMetadata::Loaded(stack_dependents) = &mut network_metadata.transient_metadata.stack_dependents { + let mut transaction_modified = false; + if let TaggedValue::StackDependents(TransientMetadata::Loaded(stack_dependents)) = value.deref_mut() { if let Some(LayerOwner::None(offset)) = stack_dependents.get_mut(node_id) { *offset += shift_sign; - self.transaction_modified(); + transaction_modified = true; }; }; + drop(value); + + if transaction_modified { + self.transaction_modified(); + } // Shift the upstream layer so that it stays in the same place if self.is_layer(node_id, network_path) { @@ -4592,11 +4555,11 @@ impl NodeNetworkInterface { self.shift_node(node_id, IVec2::new(0, shift_sign), network_path); - let Some(network_metadata) = self.network_metadata_mut(network_path) else { + let Some(mut stack_dependents_value) = self.metadata_value_mut(MetadataType::StackDependents, network_path) else { log::error!("Could not get nested network_metadata in export_ports"); return; }; - let TransientMetadata::Loaded(stack_dependents) = &mut network_metadata.transient_metadata.stack_dependents else { + let TaggedValue::StackDependents(TransientMetadata::Loaded(stack_dependents)) = stack_dependents_value.deref_mut() else { log::error!("Stack dependents should be loaded in vertical_shift_with_push"); return; }; @@ -4607,16 +4570,20 @@ impl NodeNetworkInterface { &mut default_layer_owner }); + let mut transaction_modified = false; match layer_owner { LayerOwner::None(offset) => { *offset += shift_sign; - self.transaction_modified(); + transaction_modified = true; } LayerOwner::Layer(_) => { log::error!("Node being shifted with a push should not be owned"); } } - + drop(stack_dependents_value); + if transaction_modified { + self.transaction_modified(); + } // Shift the upstream layer so that it stays in the same place if self.is_layer(node_id, network_path) { let upstream_layer = { @@ -5085,91 +5052,6 @@ impl<'a> Iterator for FlowIter<'a> { } } -#[derive(Debug, Clone)] -pub struct Ports { - input_ports: Vec<(usize, ClickTarget)>, - output_ports: Vec<(usize, ClickTarget)>, -} - -impl Default for Ports { - fn default() -> Self { - Self::new() - } -} - -impl Ports { - pub fn new() -> Ports { - Ports { - input_ports: Vec::new(), - output_ports: Vec::new(), - } - } - - pub fn click_targets(&self) -> impl Iterator { - self.input_ports - .iter() - .map(|(_, click_target)| click_target) - .chain(self.output_ports.iter().map(|(_, click_target)| click_target)) - } - - pub fn insert_input_port_at_center(&mut self, input_index: usize, center: DVec2) { - let subpath = Subpath::new_ellipse(center - DVec2::new(8., 8.), center + DVec2::new(8., 8.)); - self.input_ports.push((input_index, ClickTarget::new(subpath, 0.))); - } - - pub fn insert_output_port_at_center(&mut self, output_index: usize, center: DVec2) { - let subpath = Subpath::new_ellipse(center - DVec2::new(8., 8.), center + DVec2::new(8., 8.)); - self.output_ports.push((output_index, ClickTarget::new(subpath, 0.))); - } - - fn insert_node_input(&mut self, input_index: usize, row_index: usize, node_top_left: DVec2) { - // The center of the click target is always 24 px down from the top left corner of the node - let center = node_top_left + DVec2::new(0., 24. + 24. * row_index as f64); - self.insert_input_port_at_center(input_index, center); - } - - fn insert_node_output(&mut self, output_index: usize, row_index: usize, node_top_left: DVec2) { - // The center of the click target is always 24 px down from the top left corner of the node - let center = node_top_left + DVec2::new(5. * 24., 24. + 24. * row_index as f64); - self.insert_output_port_at_center(output_index, center); - } - - fn insert_layer_input(&mut self, input_index: usize, node_top_left: DVec2) { - let center = if input_index == 0 { - node_top_left + DVec2::new(2. * 24., 24. * 2. + 8.) - } else { - node_top_left + DVec2::new(0., 24. * 1.) - }; - self.insert_input_port_at_center(input_index, center); - } - - fn insert_layer_output(&mut self, node_top_left: DVec2) { - // The center of the click target is always 24 px down from the top left corner of the node - let center = node_top_left + DVec2::new(2. * 24., -8.0); - self.insert_output_port_at_center(0, center); - } - - pub fn clicked_input_port_from_point(&self, point: DVec2) -> Option { - self.input_ports.iter().find_map(|(port, click_target)| click_target.intersect_point_no_stroke(point).then_some(*port)) - } - - pub fn clicked_output_port_from_point(&self, point: DVec2) -> Option { - self.output_ports.iter().find_map(|(port, click_target)| click_target.intersect_point_no_stroke(point).then_some(*port)) - } - - pub fn input_port_position(&self, index: usize) -> Option { - self.input_ports - .get(index) - .and_then(|(_, click_target)| click_target.bounding_box().map(|bounds| bounds[0] + DVec2::new(8., 8.))) - } - - pub fn output_port_position(&self, index: usize) -> Option { - self.output_ports - .get(index) - .and_then(|(_, click_target)| click_target.bounding_box().map(|bounds| bounds[0] + DVec2::new(8., 8.))) - } -} - /// All fields in NetworkMetadata should automatically be updated by using the network interface API. If a field is none then it should be calculated based on the network state. #[derive(Debug, Default, serde::Serialize, serde::Deserialize)] pub struct NodeNetworkMetadata { @@ -5236,25 +5118,6 @@ pub struct NodeNetworkPersistentMetadata { pub selection_redo_history: VecDeque>, } -/// This is the same as Option, but more clear in the context of having cached metadata either being loaded or unloaded -#[derive(Debug, Default, Clone)] -pub enum TransientMetadata { - Loaded(T), - #[default] - Unloaded, -} - -impl TransientMetadata { - /// Set the current transient metadata to unloaded - pub fn unload(&mut self) { - *self = TransientMetadata::Unloaded; - } - - pub fn is_loaded(&self) -> bool { - matches!(self, TransientMetadata::Loaded(_)) - } -} - /// If some network calculation is too slow to compute for every usage, cache the data here #[derive(Debug, Default, Clone)] pub struct NodeNetworkTransientMetadata { @@ -5275,22 +5138,6 @@ pub struct NodeNetworkTransientMetadata { pub rounded_network_edge_distance: TransientMetadata, } -#[derive(Debug, Clone)] -pub struct NetworkEdgeDistance { - /// The viewport pixel distance distance between the left edge of the node graph and the exports. - pub exports_to_edge_distance: DVec2, - /// The viewport pixel distance between the left edge of the node graph and the imports. - pub imports_to_edge_distance: DVec2, -} - -#[derive(Debug, Clone)] -pub enum LayerOwner { - // Used to get the layer that should be shifted when there is a collision. - Layer(NodeId), - // The vertical offset of a node from the start of its shift. Should be reset when the drag ends. - None(i32), -} - /// Utility function for providing a default boolean value to serde. #[inline(always)] fn return_true() -> bool { diff --git a/node-graph/gcore/src/graphic_element/renderer.rs b/node-graph/gcore/src/graphic_element/renderer.rs index 53a84dcdab..4f2037f714 100644 --- a/node-graph/gcore/src/graphic_element/renderer.rs +++ b/node-graph/gcore/src/graphic_element/renderer.rs @@ -21,7 +21,7 @@ use std::fmt::Write; use vello::*; /// Represents a clickable target for the layer -#[derive(Clone, Debug)] +#[derive(Clone, Debug, PartialEq)] pub struct ClickTarget { subpath: bezier_rs::Subpath, stroke_width: f64, @@ -38,6 +38,10 @@ impl ClickTarget { &self.subpath } + pub fn stroke_width(&self) -> f64 { + self.stroke_width + } + pub fn bounding_box(&self) -> Option<[DVec2; 2]> { self.bounding_box } diff --git a/node-graph/graph-craft/src/document.rs b/node-graph/graph-craft/src/document.rs index 5d45074222..4fecd60c4a 100644 --- a/node-graph/graph-craft/src/document.rs +++ b/node-graph/graph-craft/src/document.rs @@ -1,8 +1,10 @@ use crate::document::value::TaggedValue; use crate::proto::{ConstructionArgs, ProtoNetwork, ProtoNode, ProtoNodeInput}; +use bezier_rs::Subpath; use dyn_any::{DynAny, StaticType}; use graphene_core::memo::MemoHashGuard; +use graphene_core::renderer::ClickTarget; pub use graphene_core::uuid::generate_uuid; use graphene_core::{Cow, MemoHash, ProtoNodeIdentifier, Type}; @@ -73,7 +75,7 @@ pub enum OldNodeInput { } // TODO: Eventually remove this (probably starting late 2024) -use serde::Deserialize; +use serde::{Deserialize, Serialize}; fn deserialize_inputs<'de, D>(deserializer: D) -> Result, D::Error> where D: serde::Deserializer<'de>, @@ -1381,7 +1383,7 @@ impl RootNode { } /// Represents an input connector with index based on the [`DocumentNode::inputs`] index, not the visible input index -#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize, specta::Type)] +#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize, specta::Type, Hash, DynAny)] pub enum InputConnector { #[serde(rename = "node")] Node { @@ -1421,7 +1423,7 @@ impl InputConnector { } /// Represents an output connector -#[derive(Debug, Clone, Hash, PartialEq, Eq, serde::Serialize, serde::Deserialize, specta::Type)] +#[derive(Debug, Clone, Hash, PartialEq, Eq, serde::Serialize, serde::Deserialize, specta::Type, DynAny)] pub enum OutputConnector { #[serde(rename = "node")] Node { @@ -1484,6 +1486,150 @@ impl PTZ { } } +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, PartialEq, Hash, DynAny)] +pub enum LayerOwner { + // Used to get the layer that should be shifted when there is a collision. + Layer(NodeId), + // The vertical offset of a node from the start of its shift. Should be reset when the drag ends. + None(i32), +} + +#[derive(Debug, Clone, PartialEq, DynAny, serde::Serialize, serde::Deserialize)] +pub struct Ports { + #[serde(skip)] + input_ports: Vec<(usize, ClickTarget)>, + #[serde(skip)] + output_ports: Vec<(usize, ClickTarget)>, +} + +impl Default for Ports { + fn default() -> Self { + Self::new() + } +} + +impl Ports { + pub fn new() -> Ports { + Ports { + input_ports: Vec::new(), + output_ports: Vec::new(), + } + } + + pub fn input_ports(&self) -> impl Iterator { + self.input_ports.iter().map(|(index, click_target)| (*index, click_target)) + } + + pub fn output_ports(&self) -> impl Iterator { + self.output_ports.iter().map(|(index, click_target)| (*index, click_target)) + } + + pub fn click_targets(&self) -> impl Iterator { + self.input_ports + .iter() + .map(|(_, click_target)| click_target) + .chain(self.output_ports.iter().map(|(_, click_target)| click_target)) + } + + pub fn insert_input_port_at_center(&mut self, input_index: usize, center: DVec2) { + let subpath = Subpath::new_ellipse(center - DVec2::new(8., 8.), center + DVec2::new(8., 8.)); + self.input_ports.push((input_index, ClickTarget::new(subpath, 0.))); + } + + pub fn insert_output_port_at_center(&mut self, output_index: usize, center: DVec2) { + let subpath = Subpath::new_ellipse(center - DVec2::new(8., 8.), center + DVec2::new(8., 8.)); + self.output_ports.push((output_index, ClickTarget::new(subpath, 0.))); + } + + pub fn insert_node_input(&mut self, input_index: usize, row_index: usize, node_top_left: DVec2) { + // The center of the click target is always 24 px down from the top left corner of the node + let center = node_top_left + DVec2::new(0., 24. + 24. * row_index as f64); + self.insert_input_port_at_center(input_index, center); + } + + pub fn insert_node_output(&mut self, output_index: usize, row_index: usize, node_top_left: DVec2) { + // The center of the click target is always 24 px down from the top left corner of the node + let center = node_top_left + DVec2::new(5. * 24., 24. + 24. * row_index as f64); + self.insert_output_port_at_center(output_index, center); + } + + pub fn insert_layer_input(&mut self, input_index: usize, node_top_left: DVec2) { + let center = if input_index == 0 { + node_top_left + DVec2::new(2. * 24., 24. * 2. + 8.) + } else { + node_top_left + DVec2::new(0., 24. * 1.) + }; + self.insert_input_port_at_center(input_index, center); + } + + pub fn insert_layer_output(&mut self, node_top_left: DVec2) { + // The center of the click target is always 24 px down from the top left corner of the node + let center = node_top_left + DVec2::new(2. * 24., -8.0); + self.insert_output_port_at_center(0, center); + } + + pub fn clicked_input_port_from_point(&self, point: DVec2) -> Option { + self.input_ports.iter().find_map(|(port, click_target)| click_target.intersect_point_no_stroke(point).then_some(*port)) + } + + pub fn clicked_output_port_from_point(&self, point: DVec2) -> Option { + self.output_ports.iter().find_map(|(port, click_target)| click_target.intersect_point_no_stroke(point).then_some(*port)) + } + + pub fn input_port_position(&self, index: usize) -> Option { + self.input_ports + .get(index) + .and_then(|(_, click_target)| click_target.bounding_box().map(|bounds| bounds[0] + DVec2::new(8., 8.))) + } + + pub fn output_port_position(&self, index: usize) -> Option { + self.output_ports + .get(index) + .and_then(|(_, click_target)| click_target.bounding_box().map(|bounds| bounds[0] + DVec2::new(8., 8.))) + } +} + +/// This is the same as Option, but more clear in the context of having cached metadata either being loaded or unloaded +#[derive(Debug, Default, Clone, PartialEq, serde::Deserialize, Hash)] +pub enum TransientMetadata { + Loaded(T), + #[default] + Unloaded, +} + +unsafe impl StaticType for TransientMetadata { + type Static = TransientMetadata; +} + +// Ensure transient metadata is always serialized as Unloaded +impl Serialize for TransientMetadata { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + // Always serialize as Unloaded + serializer.serialize_unit_variant("TransientMetadata", 1, "Unloaded") + } +} + +impl TransientMetadata { + /// Set the current transient metadata to unloaded + pub fn unload(&mut self) { + *self = TransientMetadata::Unloaded; + } + + pub fn is_loaded(&self) -> bool { + matches!(self, TransientMetadata::Loaded(_)) + } +} + +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, PartialEq, DynAny)] +pub struct NetworkEdgeDistance { + /// The viewport pixel distance distance between the left edge of the node graph and the exports. + pub exports_to_edge_distance: DVec2, + /// The viewport pixel distance between the left edge of the node graph and the imports. + pub imports_to_edge_distance: DVec2, +} #[cfg(test)] mod test { use super::*; diff --git a/node-graph/graph-craft/src/document/value.rs b/node-graph/graph-craft/src/document/value.rs index d392f7235a..7350108206 100644 --- a/node-graph/graph-craft/src/document/value.rs +++ b/node-graph/graph-craft/src/document/value.rs @@ -1,4 +1,4 @@ -use super::DocumentNode; +use super::{DocumentNode, TransientMetadata}; use crate::document::NodeId; pub use crate::imaginate_input::{ImaginateCache, ImaginateController, ImaginateMaskStartingFill, ImaginateSamplingMethod}; use crate::proto::{Any as DAny, FutureAny}; @@ -11,7 +11,7 @@ use graphene_core::{Color, MemoHash, Node, Type}; use dyn_any::DynAny; pub use dyn_any::StaticType; pub use glam::{DAffine2, DVec2, IVec2, UVec2}; -use std::collections::VecDeque; +use std::collections::{HashMap, VecDeque}; use std::fmt::Display; use std::hash::Hash; use std::marker::PhantomData; @@ -179,9 +179,16 @@ tagged_value! { CentroidType(graphene_core::vector::misc::CentroidType), BooleanOperation(graphene_core::vector::misc::BooleanOperation), FontCache(Arc), + // Persistent Network Metadata Previewing(crate::document::Previewing), PTZ(crate::document::PTZ), SelectionHistory(VecDeque>), + // Transient Network Metadata + StackDependents(TransientMetadata>), + AllNodesBoundingBox(TransientMetadata<[DVec2; 2]>), + OutwardWires(TransientMetadata>>), + ImportExportPorts(TransientMetadata), + RoundedNetworkEdgeDistance(TransientMetadata), } impl TaggedValue { @@ -258,6 +265,10 @@ trait FakeHash { fn hash(&self, state: &mut H); } mod fake_hash { + use std::collections::HashMap; + + use crate::document::{InputConnector, OutputConnector, Ports, TransientMetadata}; + use super::*; impl FakeHash for f64 { fn hash(&self, state: &mut H) { @@ -274,6 +285,22 @@ mod fake_hash { self.to_cols_array().iter().for_each(|x| x.to_bits().hash(state)) } } + // impl FakeHash for HashMap { + // fn hash(&self, state: &mut H) { + // self.iter().for_each(|(k, v)| { + // k.hash(state); + // v.hash(state); + // }) + // } + // } + impl FakeHash for HashMap { + fn hash(&self, state: &mut H) { + self.iter().for_each(|(k, v)| { + k.hash(state); + v.hash(state); + }) + } + } impl FakeHash for Option { fn hash(&self, state: &mut H) { if let Some(x) = self { @@ -284,6 +311,16 @@ mod fake_hash { } } } + impl FakeHash for TransientMetadata { + fn hash(&self, state: &mut H) { + if let TransientMetadata::Loaded(x) = self { + 1.hash(state); + x.hash(state); + } else { + 0.hash(state); + } + } + } impl FakeHash for Vec { fn hash(&self, state: &mut H) { self.len().hash(state); @@ -308,4 +345,71 @@ mod fake_hash { self.zoom.hash(state); } } + // impl FakeHash for Option> { + // fn hash(&self, state: &mut H) { + // if let Some(x) = self { + // 1.hash(state); + // x.iter().for_each(|(k, v)| { + // k.hash(state); + // v.hash(state); + // }); + // } else { + // 0.hash(state); + // } + // } + // } + // impl FakeHash for HashMap> { + // fn hash(&self, state: &mut H) { + // self.iter().for_each(|(k, v)| { + // k.hash(state); + // v.hash(state); + // }); + // } + // } + impl FakeHash for OutputConnector { + fn hash(&self, state: &mut H) { + match self { + OutputConnector::Node { node_id, output_index } => { + 0.hash(state); + node_id.hash(state); + output_index.hash(state); + } + OutputConnector::Import(import_index) => { + 1.hash(state); + import_index.hash(state); + } + } + } + } + impl FakeHash for InputConnector { + fn hash(&self, state: &mut H) { + match self { + InputConnector::Node { node_id, input_index } => { + 0.hash(state); + node_id.hash(state); + input_index.hash(state); + } + InputConnector::Export(export_index) => { + 1.hash(state); + export_index.hash(state); + } + } + } + } + impl FakeHash for crate::document::NetworkEdgeDistance { + fn hash(&self, state: &mut H) { + self.exports_to_edge_distance.hash(state); + self.imports_to_edge_distance.hash(state); + } + } + impl FakeHash for Ports { + fn hash(&self, state: &mut H) { + self.input_ports.iter().chain(self.output_ports.iter()).for_each(|(index, click_target)| { + index.hash(state); + click_target.subpath().hash(state); + click_target.stroke_width().hash(state); + click_target.bounding_box().hash(state) + }); + } + } }