Move all persistent node metadata into the network

This commit is contained in:
Adam
2024-09-06 23:18:04 -07:00
parent de31dbfb19
commit 0f18438243
11 changed files with 539 additions and 388 deletions

View File

@@ -242,7 +242,12 @@ impl<'a> ModifyInputsContext<'a> {
// Take until another layer node is found (but not the first layer node)
let existing_node_id = upstream
.take_while(|node_id| is_traversal_start(*node_id) || !self.network_interface.is_layer(node_id, &[]))
.find(|node_id| self.network_interface.reference(node_id, &[]).is_some_and(|node_reference| node_reference == reference));
.find(|node_id| {
let Some(node_reference) = self.network_interface.reference(node_id, &[]) else {
log::error!("Node reference does not exist in ModifyInputsContext::existing_node_id");
return false;
};
node_reference.as_ref().is_some_and(|node_reference| node_reference == reference)});
// Create a new node if the node does not exist and update its inputs
existing_node_id.or_else(|| {

View File

@@ -2,7 +2,7 @@ use super::node_properties;
use super::utility_types::FrontendNodeType;
use crate::messages::layout::utility_types::widget_prelude::*;
use crate::messages::portfolio::document::utility_types::network_interface::{
DocumentNodeMetadata, DocumentNodePersistentMetadata, NodeNetworkInterface, NodeNetworkMetadata, NodeNetworkPersistentMetadata, NodeTemplate, NodeTypePersistentMetadata,
DocumentNodeMetadata, DocumentNodePersistentMetadata, NodeNetworkInterface, NodeNetworkMetadata, NodeNetworkPersistentMetadata, NodeTemplate,
};
use crate::messages::portfolio::utility_types::PersistentData;
use crate::messages::prelude::Message;

View File

@@ -1087,9 +1087,11 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
input,
});
responses.add(PropertiesPanelMessage::Refresh);
if (!network_interface.reference(&node_id, selection_network_path).is_some_and(|reference| reference == "Imaginate") || input_index == 0)
&& network_interface.connected_to_output(&node_id, selection_network_path)
{
let Some(reference) = network_interface.reference(&node_id, selection_network_path) else {
log::error!("Could not get reference for node: {node_id:?} in NodeGraphMessage::SetInputValue");
return;
};
if (!reference.as_ref().is_some_and(|reference| reference == "Imaginate") || input_index == 0) && network_interface.connected_to_output(&node_id, selection_network_path) {
responses.add(NodeGraphMessage::RunDocumentGraph);
}
}
@@ -1182,12 +1184,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
responses.add(NodeGraphMessage::SetLockedOrVisibilitySideEffects { node_ids })
}
NodeGraphMessage::ToggleLocked { node_id } => {
let Some(node_metadata) = network_interface.network_metadata(&[]).unwrap().persistent_metadata.node_metadata.get(&node_id) else {
log::error!("Cannot get node {:?} in NodeGraphMessage::ToggleLocked", node_id);
return;
};
let locked = !node_metadata.persistent_metadata.locked;
let locked = !network_interface.is_locked(&node_id, &[]);
responses.add(DocumentMessage::AddTransaction);
responses.add(NodeGraphMessage::SetLocked { node_id, locked });
@@ -1637,17 +1634,19 @@ impl NodeGraphMessageHandler {
log::error!("Could not get nested network when collecting nodes");
return Vec::new();
};
let Some(network_metadata) = network_interface.network_metadata(breadcrumb_network_path) else {
log::error!("Could not get network_metadata when collecting nodes");
return Vec::new();
};
let mut nodes = Vec::new();
for (&node_id, node) in &network.nodes {
let node_id_path = &[breadcrumb_network_path, (&[node_id])].concat();
let Some(node_metadata) = network_metadata.persistent_metadata.node_metadata.get(&node_id) else {
log::error!("Could not get node_metadata for {node_id_path:?}");
continue;
let Some(input_names) = network_interface.input_names(&node_id, breadcrumb_network_path) else {
log::error!("Could not get input names for node: {node_id}");
return Vec::new();
};
let Some(output_names) = network_interface.output_names(&node_id, breadcrumb_network_path) else {
log::error!("Could not get output names for node: {node_id}");
return Vec::new();
};
let frontend_graph_inputs = node.inputs.iter().enumerate().map(|(index, _)| {
@@ -1657,9 +1656,7 @@ impl NodeGraphMessageHandler {
// TODO: Should display the color of the "most commonly relevant" (we'd need some sort of precedence) data type it allows given the current generic form that's constrained by the other present connections.
let data_type = FrontendGraphDataType::with_type(&node_type);
let input_name = node_metadata
.persistent_metadata
.input_names
let input_name = input_names
.get(index)
.cloned()
.unwrap_or(network_interface.input_type(&InputConnector::node(node_id, index), breadcrumb_network_path).nested_type().to_string());
@@ -1727,16 +1724,8 @@ impl NodeGraphMessageHandler {
} else {
FrontendGraphDataType::General
};
let Some(node_metadata) = network_metadata.persistent_metadata.node_metadata.get(&node_id) else {
log::error!("Could not get node_metadata when getting output for {node_id}");
continue;
};
let output_name = node_metadata
.persistent_metadata
.output_names
.get(index)
.map(|output_name| output_name.to_string())
.unwrap_or(format!("Output {}", index + 1));
let output_name = output_names.get(index).map(|output_name| output_name.to_string()).unwrap_or(format!("Output {}", index + 1));
let connected_to = outward_wires.get(&OutputConnector::node(node_id, index)).cloned().unwrap_or_default();
exposed_outputs.push(FrontendGraphOutput {
@@ -1776,9 +1765,7 @@ impl NodeGraphMessageHandler {
nodes.push(FrontendNode {
id: node_id,
is_layer: network_interface
.node_metadata(&node_id, breadcrumb_network_path)
.is_some_and(|node_metadata| node_metadata.persistent_metadata.is_layer()),
is_layer: network_interface.is_layer(&node_id, breadcrumb_network_path),
can_be_layer: can_be_layer_lookup.contains(&node_id),
reference: None,
display_name: network_interface.frontend_display_name(&node_id, breadcrumb_network_path),
@@ -1836,8 +1823,8 @@ impl NodeGraphMessageHandler {
}
}
for (&node_id, node_metadata) in &network_interface.network_metadata(&[]).unwrap().persistent_metadata.node_metadata {
if node_metadata.persistent_metadata.is_layer() {
for &node_id in network_interface.network(&[]).unwrap().nodes.keys() {
if network_interface.is_layer(&node_id, &[]) {
let layer = LayerNodeIdentifier::new(node_id, network_interface, &[]);
let children_allowed =

View File

@@ -2343,7 +2343,15 @@ pub fn index_properties(document_node: &DocumentNode, node_id: NodeId, _context:
}
pub fn generate_node_properties(document_node: &DocumentNode, node_id: NodeId, context: &mut NodePropertiesContext) -> LayoutGroup {
let reference = context.network_interface.reference(&node_id, context.selection_network_path).clone();
let Some(reference) = context.network_interface.reference(&node_id, context.selection_network_path).cloned() else {
log::error!("Node {node_id} has no reference in generate_node_properties");
return LayoutGroup::Section {
name: "Unknown".to_string(),
visible: true,
id: node_id.0,
layout: unknown_node_properties(&"Unknown".to_string()),
};
};
let layout = if let Some(ref reference) = reference {
match super::document_node_definitions::resolve_document_node_type(reference) {
Some(document_node_type) => (document_node_type.properties)(document_node, node_id, context),

View File

@@ -415,15 +415,11 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageData<'_>> for PortfolioMes
.cloned()
.collect::<Vec<NodeId>>()
{
if let Some(reference) = document
.network_interface
.network_metadata(&[])
.unwrap()
.persistent_metadata
.node_metadata
.get(node_id)
.and_then(|node| node.persistent_metadata.reference.as_ref())
{
let Some(reference) = document.network_interface.reference(&node_id, &[]) else {
log::error!("could not get reference in deserialize_document");
continue;
};
if let Some(reference) = reference {
let node_definition = crate::messages::portfolio::document::node_graph::document_node_definitions::resolve_document_node_type(reference).unwrap();
let default_definition_node = node_definition.default_node_template();
document.network_interface.set_implementation(node_id, &[], default_definition_node.document_node.implementation);
@@ -433,14 +429,13 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageData<'_>> for PortfolioMes
if document
.network_interface
.network_metadata(&[])
.network(&[])
.unwrap()
.persistent_metadata
.node_metadata
.iter()
.any(|(node_id, node)| node.persistent_metadata.reference.as_ref().is_some_and(|reference| reference == "Output") && *node_id == NodeId(0))
.nodes
.keys()
.any(|node_id|*node_id == NodeId(0) && document.network_interface.reference(node_id, &[]).cloned().flatten().is_some_and(|reference| reference == "Output"))
{
document.network_interface.delete_nodes(vec![NodeId(0)], true, &[]);
document.network_interface.delete_nodes(vec![NodeId(0)], false, &[]);
}
let node_ids = document.network_interface.network(&[]).unwrap().nodes.keys().cloned().collect::<Vec<_>>();
@@ -449,14 +444,9 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageData<'_>> for PortfolioMes
log::error!("could not get node in deserialize_document");
continue;
};
let Some(node_metadata) = document.network_interface.network_metadata(&[]).unwrap().persistent_metadata.node_metadata.get(node_id) else {
log::error!("could not get node metadata for node {node_id} in deserialize_document");
continue;
};
// Upgrade Fill nodes to the format change in #1778
// TODO: Eventually remove this (probably starting late 2024)
let Some(ref reference) = node_metadata.persistent_metadata.reference.clone() else {
let Some(ref reference) = document.network_interface.reference(node_id, &[]).cloned().flatten() else {
continue;
};
if reference == "Fill" && node.inputs.len() == 8 {

View File

@@ -174,8 +174,14 @@ 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<NodeId> {
self.horizontal_layer_flow()
.find(|node_id| self.network_interface.reference(node_id, &[]).is_some_and(|reference| reference == node_name))
.find(|node_id| {
let Some(reference) = self.network_interface.reference(node_id, &[]) else {
log::error!("Reference could not be found for node {node_id} in upstream_node_id_from_name");
return false };
reference.as_ref().is_some_and(|reference| reference == node_name)
})
}
/// Find all of the inputs of a specific node within the layer's primary flow, up until the next layer is reached.
@@ -183,7 +189,13 @@ impl<'a> NodeGraphLayer<'a> {
self.horizontal_layer_flow()
.skip(1)// Skip self
.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 == node_name))
.find(|node_id|
{
let Some(reference) = self.network_interface.reference(node_id, &[]) else {
log::error!("Reference could not be found for node {node_id} in upstream_node_id_from_name");
return false };
reference.as_ref().is_some_and(|reference| reference == node_name)
})
.and_then(|node_id| self.network_interface.network(&[]).unwrap().nodes.get(&node_id).map(|node| &node.inputs))
}

View File

@@ -3,8 +3,8 @@ use crate::messages::portfolio::document::graph_operation::transform_utils::{get
use crate::messages::portfolio::document::node_graph::document_node_definitions::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};
use crate::messages::portfolio::document::utility_types::nodes::SelectedNodes;
use crate::messages::tool::common_functionality::color_selector::{ToolColorOptions, ToolColorType};
use graph_craft::document::value::TaggedValue;
use graph_craft::document::NodeId;
@@ -272,6 +272,10 @@ impl BrushToolData {
continue;
};
let Some(reference) = document.network_interface.reference(&node_id, &[]) else {
log::error!("Could not get reference for node {node_id} in load_existing_strokes");
continue;
};
let Some(reference) = reference else {
continue;
};
if reference == "Brush" && node_id != layer.to_node() {

View File

@@ -702,13 +702,12 @@ impl EditorHandle {
let document = editor.dispatcher.message_handlers.portfolio_message_handler.active_document_mut().unwrap();
for node in document
.network_interface
.network_metadata(&[])
.network(&[])
.unwrap()
.persistent_metadata
.node_metadata
.iter()
.filter(|(_, d)| d.persistent_metadata.reference.as_ref().is_some_and(|reference| reference == "Artboard"))
.map(|(id, _)| *id)
.nodes
.keys()
.filter(|node_id| document.network_interface.reference(node_id, &[]).cloned().flatten().is_some_and(|reference| reference == "Artboard"))
.cloned()
.collect::<Vec<_>>()
{
let Some(document_node) = document.network_interface.network(&[]).unwrap().nodes.get(&node) else {
@@ -718,7 +717,12 @@ impl EditorHandle {
if let Some(network) = document_node.implementation.get_network() {
let mut nodes_to_upgrade = Vec::new();
for (node_id, _) in network.nodes.iter().collect::<Vec<_>>() {
if document.network_interface.reference(node_id, &[]).is_some_and(|reference| reference == "To Artboard")
if document
.network_interface
.reference(node_id, &[])
.cloned()
.flatten()
.is_some_and(|reference| reference == "To Artboard")
&& document
.network_interface
.network(&[])
@@ -773,13 +777,12 @@ impl EditorHandle {
document.network_interface.load_structure();
for node in document
.network_interface
.network_metadata(&[])
.network(&[])
.unwrap()
.persistent_metadata
.node_metadata
.iter()
.filter(|(_, d)| d.persistent_metadata.reference.as_ref().is_some_and(|reference| reference == "Merge"))
.map(|(id, _)| *id)
.nodes
.keys()
.filter(|node_id| document.network_interface.reference(node_id, &[]).cloned().flatten().is_some_and(|reference| reference == "Merge"))
.cloned()
.collect::<Vec<_>>()
{
let layer = LayerNodeIdentifier::new(node, &document.network_interface, &[]);

View File

@@ -12,7 +12,7 @@ use glam::{DVec2, IVec2};
use log::Metadata;
use rustc_hash::FxHashMap;
use std::collections::hash_map::DefaultHasher;
use std::collections::HashMap;
use std::collections::{HashMap, HashSet};
use std::hash::{Hash, Hasher};
pub mod value;
@@ -1630,6 +1630,106 @@ pub struct NetworkEdgeDistance {
/// The viewport pixel distance between the left edge of the node graph and the imports.
pub imports_to_edge_distance: DVec2,
}
/// A layer can either be position as Absolute or in a Stack
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, Hash, DynAny)]
pub enum LayerPosition {
// Position of the layer in grid spaces. Measured from the top left corner of the layer, not including the left chain. This means it is always half a grid space to the left of the thumbnail.
Absolute(IVec2),
// A layer is in a Stack when it feeds into the bottom input of a layer. The Y position stores the vertical distance between the layer and its upstream sibling/parent.
Stack(u32),
}
/// A node can either be position as Absolute or in a Chain
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, Hash, DynAny)]
pub enum NodePosition {
// Position of the node in grid spaces
Absolute(IVec2),
// In a chain the position is based on the number of nodes to the first layer node
Chain,
}
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, Hash, DynAny)]
pub enum NodeTypePersistentMetadata {
Layer(LayerMetadata),
Node(NodePersistentMetadata),
}
impl Default for NodeTypePersistentMetadata {
fn default() -> Self {
NodeTypePersistentMetadata::node(IVec2::ZERO)
}
}
impl NodeTypePersistentMetadata {
pub fn node(position: IVec2) -> NodeTypePersistentMetadata {
NodeTypePersistentMetadata::Node(NodePersistentMetadata {
position: NodePosition::Absolute(position),
})
}
pub fn layer(position: IVec2) -> NodeTypePersistentMetadata {
NodeTypePersistentMetadata::Layer(LayerMetadata {
persistent_metadata: LayerPersistentMetadata {
position: LayerPosition::Absolute(position),
},
transient_metadata: Default::default(),
})
}
}
#[derive(Debug, serde::Serialize, serde::Deserialize, DynAny)]
pub struct LayerMetadata {
pub persistent_metadata: LayerPersistentMetadata,
#[serde(skip)]
pub transient_metadata: LayerTransientMetadata,
}
impl Hash for LayerMetadata {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.persistent_metadata.hash(state);
}
}
impl Clone for LayerMetadata {
fn clone(&self) -> Self {
LayerMetadata {
persistent_metadata: self.persistent_metadata.clone(),
transient_metadata: Default::default(),
}
}
}
impl PartialEq for LayerMetadata {
fn eq(&self, other: &Self) -> bool {
self.persistent_metadata == other.persistent_metadata
}
}
/// All fields in LayerMetadata should automatically be updated by using the network interface API
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, Hash, DynAny)]
pub struct LayerPersistentMetadata {
/// Stores the position of a layer node, which can either be Absolute or Stack
pub position: LayerPosition,
}
#[derive(Debug, Clone, PartialEq, Default, serde::Serialize, serde::Deserialize, DynAny)]
pub struct LayerTransientMetadata {
/// All nodes that should be moved when the layer is moved.
pub owned_nodes: TransientMetadata<HashSet<NodeId>>,
// Stores the width in grid cell units for layer nodes from the left edge of the thumbnail (+12px padding since thumbnail ends between grid spaces) to the left end of the node
/// This is necessary since calculating the layer width through web_sys is very slow
pub layer_width: TransientMetadata<u32>,
// Should not be a performance concern to calculate when needed with chain_width.
// Stores the width in grid cell units for layer nodes from the left edge of the thumbnail to the end of the chain
// chain_width: u32,
}
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, Hash, DynAny)]
pub struct NodePersistentMetadata {
/// Stores the position of a non layer node, which can either be Absolute or Chain
pub position: NodePosition,
}
#[cfg(test)]
mod test {
use super::*;

View File

@@ -189,6 +189,10 @@ tagged_value! {
OutwardWires(TransientMetadata<HashMap<crate::document::OutputConnector, Vec<crate::document::InputConnector>>>),
ImportExportPorts(TransientMetadata<crate::document::Ports>),
RoundedNetworkEdgeDistance(TransientMetadata<crate::document::NetworkEdgeDistance>),
// Persistent Node Metadata
OptionalString(Option<String>),
VecString(Vec<String>),
NodeTypeMetadata(crate::document::NodeTypePersistentMetadata),
}
impl TaggedValue {