mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2025-08-04 13:30:48 +00:00
Add colors to all nodes in a graph, even if disconnected, and properly display hidden network imports (#1921)
* Get output/input types by iterating to proto node. Fix types when undoing/redoing * Remove unused code * Fix types not updating when modified * Improve code quality * Improve proto node type lookup * Nits * Fix crash when adding Extract --------- Co-authored-by: dennis@kobert.dev <dennis@kobert.dev> Co-authored-by: Keavon Chambers <keavon@keavon.com>
This commit is contained in:
parent
1f278799d6
commit
60707c0369
6 changed files with 203 additions and 152 deletions
|
@ -1375,6 +1375,7 @@ impl DocumentMessageHandler {
|
|||
|
||||
// Set the previous network navigation metadata to the current navigation metadata
|
||||
network_interface.copy_all_navigation_metadata(&self.network_interface);
|
||||
std::mem::swap(&mut network_interface.resolved_types, &mut self.network_interface.resolved_types);
|
||||
|
||||
//Update the metadata transform based on document PTZ
|
||||
let transform = self.navigation_handler.calculate_offset_transform(ipp.viewport_bounds.center(), &self.document_ptz);
|
||||
|
|
|
@ -11,10 +11,9 @@ use crate::messages::portfolio::document::utility_types::nodes::{CollapsedLayers
|
|||
use crate::messages::prelude::*;
|
||||
use crate::messages::tool::common_functionality::auto_panning::AutoPanning;
|
||||
|
||||
use graph_craft::document::{DocumentNode, DocumentNodeImplementation, NodeId, NodeInput};
|
||||
use graph_craft::document::{DocumentNodeImplementation, NodeId, NodeInput};
|
||||
use graph_craft::proto::GraphErrors;
|
||||
use graphene_core::*;
|
||||
use interpreted_executor::dynamic_executor::ResolvedDocumentNodeTypes;
|
||||
use renderer::{ClickTarget, Quad};
|
||||
|
||||
use glam::{DAffine2, DVec2, IVec2};
|
||||
|
@ -557,7 +556,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
|
|||
responses.add(NodeGraphMessage::DisconnectInput {
|
||||
input_connector: disconnecting.clone(),
|
||||
});
|
||||
// Update the front end that the node is disconnected
|
||||
// Update the frontend that the node is disconnected
|
||||
responses.add(NodeGraphMessage::RunDocumentGraph);
|
||||
responses.add(NodeGraphMessage::SendGraph);
|
||||
self.disconnecting = None;
|
||||
|
@ -927,7 +926,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
|
|||
responses.add(PropertiesPanelMessage::Refresh);
|
||||
}
|
||||
NodeGraphMessage::SendClickTargets => responses.add(FrontendMessage::UpdateClickTargets {
|
||||
click_targets: Some(network_interface.collect_front_end_click_targets(breadcrumb_network_path)),
|
||||
click_targets: Some(network_interface.collect_frontend_click_targets(breadcrumb_network_path)),
|
||||
}),
|
||||
NodeGraphMessage::EndSendClickTargets => responses.add(FrontendMessage::UpdateClickTargets { click_targets: None }),
|
||||
NodeGraphMessage::SendGraph => {
|
||||
|
@ -1578,14 +1577,9 @@ impl NodeGraphMessageHandler {
|
|||
let frontend_graph_inputs = node.inputs.iter().enumerate().map(|(index, _)| {
|
||||
// Convert the index in all inputs to the index in only the exposed inputs
|
||||
// TODO: Only display input type if potential inputs in node_registry are all the same type
|
||||
let node_types = network_interface.resolved_types.types.get(node_id_path.as_slice());
|
||||
|
||||
let node_type = network_interface.input_type(&InputConnector::node(node_id, index), breadcrumb_network_path);
|
||||
// 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 frontend_data_type = if let Some(node_types) = node_types {
|
||||
FrontendGraphDataType::with_type(&node_types.inputs[index])
|
||||
} else {
|
||||
FrontendGraphDataType::General
|
||||
};
|
||||
let data_type = FrontendGraphDataType::with_type(&node_type);
|
||||
|
||||
let input_name = node_metadata
|
||||
.persistent_metadata
|
||||
|
@ -1595,9 +1589,9 @@ impl NodeGraphMessageHandler {
|
|||
.unwrap_or(network_interface.input_type(&InputConnector::node(node_id, index), breadcrumb_network_path).nested_type().to_string());
|
||||
|
||||
FrontendGraphInput {
|
||||
data_type: frontend_data_type,
|
||||
data_type,
|
||||
name: input_name,
|
||||
resolved_type: node_types.map(|types| format!("{:?}", types.inputs[index])),
|
||||
resolved_type: Some(format!("{:?}", node_type)),
|
||||
connected_to: None,
|
||||
}
|
||||
});
|
||||
|
@ -1628,7 +1622,7 @@ impl NodeGraphMessageHandler {
|
|||
.map(|(_, input_type)| input_type)
|
||||
.collect();
|
||||
|
||||
let output_types = Self::get_output_types(node, &network_interface.resolved_types, node_id_path);
|
||||
let output_types = network_interface.output_types(&node_id, breadcrumb_network_path);
|
||||
let primary_output_type = output_types.first().expect("Primary output should always exist");
|
||||
let frontend_data_type = if let Some(output_type) = primary_output_type {
|
||||
FrontendGraphDataType::with_type(output_type)
|
||||
|
@ -1806,83 +1800,6 @@ impl NodeGraphMessageHandler {
|
|||
}
|
||||
}
|
||||
|
||||
/// Retrieves the output types for a given document node and its exports.
|
||||
///
|
||||
/// This function traverses the node and its nested network structure (if applicable) to determine
|
||||
/// the types of all outputs, including the primary output and any additional exports.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `node` - A reference to the `DocumentNode` for which to determine output types.
|
||||
/// * `resolved_types` - A reference to `ResolvedDocumentNodeTypes` containing pre-resolved type information.
|
||||
/// * `node_id_path` - A slice of `NodeId`s representing the path to the current node in the document graph.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// A `Vec<Option<Type>>` where:
|
||||
/// - The first element is the primary output type of the node.
|
||||
/// - Subsequent elements are types of additional exports (if the node is a network).
|
||||
/// - `None` values indicate that a type couldn't be resolved for a particular output.
|
||||
///
|
||||
/// # Behavior
|
||||
///
|
||||
/// 1. Retrieves the primary output type from `resolved_types`.
|
||||
/// 2. If the node is a network:
|
||||
/// - Iterates through its exports (skipping the first/primary export).
|
||||
/// - For each export, traverses the network until reaching a protonode or terminal condition.
|
||||
/// - Determines the output type based on the final node/value encountered.
|
||||
/// 3. Collects and returns all resolved types.
|
||||
///
|
||||
/// # Note
|
||||
///
|
||||
/// This function assumes that export indices and node IDs always exist within their respective
|
||||
/// collections. It will panic if these assumptions are violated.
|
||||
pub fn get_output_types(node: &DocumentNode, resolved_types: &ResolvedDocumentNodeTypes, node_id_path: &[NodeId]) -> Vec<Option<Type>> {
|
||||
let mut output_types = Vec::new();
|
||||
|
||||
let primary_output_type = resolved_types.types.get(node_id_path).map(|ty| ty.output.clone());
|
||||
|
||||
// If the node is not a protonode, get types by traversing across exports until a proto node is reached.
|
||||
if let graph_craft::document::DocumentNodeImplementation::Network(internal_network) = &node.implementation {
|
||||
for export in internal_network.exports.iter() {
|
||||
let mut current_export = export;
|
||||
let mut current_network = internal_network;
|
||||
let mut current_path = node_id_path.to_owned();
|
||||
|
||||
while let NodeInput::Node { node_id, output_index, .. } = current_export {
|
||||
current_path.push(*node_id);
|
||||
|
||||
let next_node = current_network.nodes.get(node_id).expect("Export node id should always exist");
|
||||
|
||||
if let graph_craft::document::DocumentNodeImplementation::Network(next_network) = &next_node.implementation {
|
||||
current_network = next_network;
|
||||
current_export = next_network.exports.get(*output_index).expect("Export at output index should always exist");
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
let output_type: Option<Type> = match current_export {
|
||||
NodeInput::Node { output_index, .. } => {
|
||||
// Current export is pointing to a proto node where type can be derived
|
||||
assert_eq!(*output_index, 0, "Output index for a proto node should always be 0");
|
||||
resolved_types.types.get(¤t_path).map(|ty| ty.output.clone())
|
||||
}
|
||||
NodeInput::Value { tagged_value, .. } => Some(tagged_value.ty()),
|
||||
NodeInput::Network { import_type, .. } => Some(import_type.clone()),
|
||||
_ => None,
|
||||
};
|
||||
output_types.push(output_type);
|
||||
}
|
||||
} else {
|
||||
if primary_output_type.is_none() {
|
||||
log::warn!("no output type found for {:?} {:?}", node_id_path, &node.implementation);
|
||||
}
|
||||
output_types.push(primary_output_type);
|
||||
}
|
||||
output_types
|
||||
}
|
||||
|
||||
fn build_wire_path_string(output_position: DVec2, input_position: DVec2, vertical_out: bool, vertical_in: bool) -> String {
|
||||
let locations = Self::build_wire_path_locations(output_position, input_position, vertical_out, vertical_in);
|
||||
let smoothing = 0.5;
|
||||
|
|
|
@ -3,7 +3,6 @@ use super::misc::PTZ;
|
|||
use super::nodes::SelectedNodes;
|
||||
use crate::messages::portfolio::document::graph_operation::utility_types::ModifyInputsContext;
|
||||
use crate::messages::portfolio::document::node_graph::utility_types::{FrontendClickTargets, FrontendGraphDataType, FrontendGraphInput, FrontendGraphOutput};
|
||||
use crate::messages::prelude::NodeGraphMessageHandler;
|
||||
|
||||
use bezier_rs::Subpath;
|
||||
use graph_craft::document::{value::TaggedValue, DocumentNode, DocumentNodeImplementation, NodeId, NodeInput, NodeNetwork, OldDocumentNodeImplementation, OldNodeNetwork};
|
||||
|
@ -378,20 +377,54 @@ impl NodeNetworkInterface {
|
|||
|
||||
/// Get the [`Type`] for any InputConnector
|
||||
pub fn input_type(&self, input_connector: &InputConnector, network_path: &[NodeId]) -> Type {
|
||||
let Some(network) = self.network(network_path) else {
|
||||
log::error!("Could not get network in input_type");
|
||||
return concrete!(());
|
||||
};
|
||||
|
||||
// TODO: If the input_connector is a NodeInput::Value, return the type of the tagged value
|
||||
// TODO: Store types for all document nodes, not just the compiled proto nodes, which currently skips isolated nodes
|
||||
let node_type_from_compiled_network = if let Some(node_id) = input_connector.node_id() {
|
||||
let Some(current_network) = self.network(network_path) else {
|
||||
log::error!("Could not get current network in input_type");
|
||||
return concrete!(());
|
||||
};
|
||||
let Some(node) = current_network.nodes.get(&node_id) else {
|
||||
log::error!("Could not get node {node_id} in input_type");
|
||||
return concrete!(());
|
||||
};
|
||||
let node_id_path = [network_path, &[node_id]].concat().clone();
|
||||
self.resolved_types
|
||||
.types
|
||||
.get(node_id_path.as_slice())
|
||||
.map(|node_types| node_types.inputs[input_connector.input_index()].clone())
|
||||
} else if let Some(encapsulating_node) = self.encapsulating_node(network_path) {
|
||||
let output_types = NodeGraphMessageHandler::get_output_types(encapsulating_node, &self.resolved_types, network_path);
|
||||
match &node.implementation {
|
||||
DocumentNodeImplementation::Network(nested_network) => {
|
||||
let downstream_connection = nested_network
|
||||
.nodes
|
||||
.iter()
|
||||
.flat_map(|(node_id, node)| node.inputs.iter().enumerate().map(|(input_index, input)| (InputConnector::node(*node_id, input_index), input)))
|
||||
.chain(nested_network.exports.iter().enumerate().map(|(export_index, export)| (InputConnector::Export(export_index), export)))
|
||||
.find(|(_, input)| {
|
||||
if let NodeInput::Network { import_index, .. } = input {
|
||||
*import_index == input_connector.input_index()
|
||||
} else {
|
||||
false
|
||||
}
|
||||
});
|
||||
if let Some((input_connector, _)) = downstream_connection {
|
||||
Some(self.input_type(&input_connector, &node_id_path))
|
||||
}
|
||||
// Nothing is connected to the import
|
||||
else {
|
||||
Some(concrete!(()))
|
||||
}
|
||||
}
|
||||
DocumentNodeImplementation::ProtoNode(_) => {
|
||||
// If a node has manual composition, then offset the input index by 1 since the proto node also includes the type of the parameter passed through manual composition.
|
||||
let manual_composition_offset = if node.manual_composition.is_some() { 1 } else { 0 };
|
||||
self.resolved_types
|
||||
.types
|
||||
.get(node_id_path.as_slice())
|
||||
.map(|node_types| node_types.inputs[input_connector.input_index() + manual_composition_offset].clone())
|
||||
}
|
||||
DocumentNodeImplementation::Extract => Some(concrete!(())),
|
||||
}
|
||||
} else if let Some(encapsulating_node_id) = network_path.last() {
|
||||
let mut encapsulating_node_id_path = network_path.to_vec();
|
||||
encapsulating_node_id_path.pop();
|
||||
let output_types: Vec<Option<Type>> = self.output_types(encapsulating_node_id, &encapsulating_node_id_path);
|
||||
output_types.get(input_connector.input_index()).map_or_else(
|
||||
|| {
|
||||
warn!("Could not find output type for export node");
|
||||
|
@ -406,7 +439,10 @@ impl NodeNetworkInterface {
|
|||
node_type_from_compiled_network.unwrap_or_else(|| {
|
||||
// TODO: Once there is type inference (#1621), replace this workaround approach when disconnecting node inputs with NodeInput::Node(ToDefaultNode),
|
||||
// TODO: which would be a new node that implements the Default trait (i.e. `Default::default()`)
|
||||
|
||||
let Some(network) = self.network(network_path) else {
|
||||
log::error!("Could not get network in input_type");
|
||||
return concrete!(());
|
||||
};
|
||||
// Resolve types from proto nodes in node_registry
|
||||
let Some(node_id) = input_connector.node_id() else {
|
||||
return concrete!(());
|
||||
|
@ -418,21 +454,7 @@ impl NodeNetworkInterface {
|
|||
fn type_from_node(node: &DocumentNode, input_index: usize) -> Type {
|
||||
match &node.implementation {
|
||||
DocumentNodeImplementation::ProtoNode(protonode) => {
|
||||
let Some(node_io_hashmap) = NODE_REGISTRY.get(protonode) else {
|
||||
log::error!("Could not get hashmap for proto node: {protonode:?}");
|
||||
return concrete!(());
|
||||
};
|
||||
|
||||
let mut all_node_io_types = node_io_hashmap.keys().collect::<Vec<_>>();
|
||||
all_node_io_types.sort_by_key(|node_io_types| {
|
||||
let mut hasher = DefaultHasher::new();
|
||||
node_io_types.hash(&mut hasher);
|
||||
hasher.finish()
|
||||
});
|
||||
let Some(node_types) = all_node_io_types.first() else {
|
||||
log::error!("Could not get node_types from hashmap");
|
||||
return concrete!(());
|
||||
};
|
||||
let Some(node_types) = proto_node_type(protonode) else { return concrete!(()) };
|
||||
|
||||
let skip_footprint = if node.manual_composition.is_some() { 1 } else { 0 };
|
||||
|
||||
|
@ -464,6 +486,96 @@ impl NodeNetworkInterface {
|
|||
})
|
||||
}
|
||||
|
||||
/// Retrieves the output types for a given document node and its exports.
|
||||
///
|
||||
/// This function traverses the node and its nested network structure (if applicable) to determine
|
||||
/// the types of all outputs, including the primary output and any additional exports.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `node` - A reference to the `DocumentNode` for which to determine output types.
|
||||
/// * `resolved_types` - A reference to `ResolvedDocumentNodeTypes` containing pre-resolved type information.
|
||||
/// * `node_id_path` - A slice of `NodeId`s representing the path to the current node in the document graph.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// A `Vec<Option<Type>>` where:
|
||||
/// - The first element is the primary output type of the node.
|
||||
/// - Subsequent elements are types of additional exports (if the node is a network).
|
||||
/// - `None` values indicate that a type couldn't be resolved for a particular output.
|
||||
///
|
||||
/// # Behavior
|
||||
///
|
||||
/// 1. Retrieves the primary output type from `resolved_types`.
|
||||
/// 2. If the node is a network:
|
||||
/// - Iterates through its exports (skipping the first/primary export).
|
||||
/// - For each export, traverses the network until reaching a protonode or terminal condition.
|
||||
/// - Determines the output type based on the final node/value encountered.
|
||||
/// 3. Collects and returns all resolved types.
|
||||
///
|
||||
/// # Note
|
||||
///
|
||||
/// This function assumes that export indices and node IDs always exist within their respective
|
||||
/// collections. It will panic if these assumptions are violated.
|
||||
pub fn output_types(&self, node_id: &NodeId, network_path: &[NodeId]) -> Vec<Option<Type>> {
|
||||
let Some(network) = self.network(network_path) else {
|
||||
log::error!("Could not get network in output_types");
|
||||
return Vec::new();
|
||||
};
|
||||
let Some(node) = network.nodes.get(node_id) else {
|
||||
log::error!("Could not get node {node_id} in output_types");
|
||||
return Vec::new();
|
||||
};
|
||||
|
||||
let mut output_types = Vec::new();
|
||||
|
||||
// If the node is not a protonode, get types by traversing across exports until a proto node is reached.
|
||||
match &node.implementation {
|
||||
graph_craft::document::DocumentNodeImplementation::Network(internal_network) => {
|
||||
for export in internal_network.exports.iter() {
|
||||
match export {
|
||||
NodeInput::Node {
|
||||
node_id: nested_node_id,
|
||||
output_index,
|
||||
..
|
||||
} => {
|
||||
let nested_output_types = self.output_types(nested_node_id, &[network_path, &[*node_id]].concat());
|
||||
let Some(nested_nodes_output_types) = nested_output_types.get(*output_index) else {
|
||||
log::error!("Could not get nested nodes output in output_types");
|
||||
return Vec::new();
|
||||
};
|
||||
output_types.push(nested_nodes_output_types.clone());
|
||||
}
|
||||
NodeInput::Value { tagged_value, .. } => {
|
||||
output_types.push(Some(tagged_value.ty()));
|
||||
}
|
||||
|
||||
NodeInput::Network { .. } => {
|
||||
// https://github.com/GraphiteEditor/Graphite/issues/1762
|
||||
log::error!("Network input type cannot be connected to export");
|
||||
return Vec::new();
|
||||
}
|
||||
NodeInput::Scope(_) => todo!(),
|
||||
NodeInput::Inline(_) => todo!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
graph_craft::document::DocumentNodeImplementation::ProtoNode(protonode) => {
|
||||
let node_id_path = &[network_path, &[*node_id]].concat();
|
||||
let primary_output_type = self.resolved_types.types.get(node_id_path).map(|ty| ty.output.clone()).or_else(|| {
|
||||
let node_types = proto_node_type(protonode)?;
|
||||
Some(node_types.output.clone())
|
||||
});
|
||||
|
||||
output_types.push(primary_output_type);
|
||||
}
|
||||
graph_craft::document::DocumentNodeImplementation::Extract => {
|
||||
output_types.push(Some(concrete!(())));
|
||||
}
|
||||
}
|
||||
output_types
|
||||
}
|
||||
|
||||
pub fn position(&mut self, node_id: &NodeId, network_path: &[NodeId]) -> Option<IVec2> {
|
||||
let top_left_position = self
|
||||
.node_click_targets(node_id, network_path)
|
||||
|
@ -501,19 +613,14 @@ impl NodeNetworkInterface {
|
|||
if !network_path.is_empty() {
|
||||
// TODO: https://github.com/GraphiteEditor/Graphite/issues/1767
|
||||
// TODO: Non exposed inputs are not added to the inputs_source_map, fix `pub fn document_node_types(&self) -> ResolvedDocumentNodeTypes`
|
||||
let input_type = self.resolved_types.types.get(network_path).map(|nt| nt.inputs[*import_index].clone());
|
||||
let mut encapsulating_path = network_path.to_vec();
|
||||
let encapsulating_node_id = encapsulating_path.pop().unwrap();
|
||||
|
||||
let frontend_data_type = if let Some(input_type) = input_type.clone() {
|
||||
FrontendGraphDataType::with_type(&input_type)
|
||||
} else {
|
||||
FrontendGraphDataType::General
|
||||
};
|
||||
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()
|
||||
.map(|input_type| TaggedValue::from_type(&input_type).ty().to_string())
|
||||
.unwrap_or(format!("Import {}", import_index + 1))
|
||||
TaggedValue::from_type(&input_type).ty().to_string()
|
||||
} else {
|
||||
import_name
|
||||
};
|
||||
|
@ -529,9 +636,9 @@ impl NodeNetworkInterface {
|
|||
|
||||
import_metadata = Some((
|
||||
FrontendGraphOutput {
|
||||
data_type: frontend_data_type,
|
||||
data_type,
|
||||
name: import_name,
|
||||
resolved_type: input_type.map(|input| format!("{input:?}")),
|
||||
resolved_type: Some(format!("{input_type:?}")),
|
||||
connected_to,
|
||||
},
|
||||
click_target,
|
||||
|
@ -561,9 +668,7 @@ impl NodeNetworkInterface {
|
|||
};
|
||||
|
||||
let (frontend_data_type, input_type) = if let NodeInput::Node { node_id, output_index, .. } = export {
|
||||
let node = network.nodes.get(node_id).expect("Node should always exist");
|
||||
let node_id_path = &[network_path, &[*node_id]].concat();
|
||||
let output_types = NodeGraphMessageHandler::get_output_types(node, &self.resolved_types, node_id_path);
|
||||
let output_types = self.output_types(node_id, network_path);
|
||||
|
||||
if let Some(output_type) = output_types.get(*output_index).cloned().flatten() {
|
||||
(FrontendGraphDataType::with_type(&output_type), Some(output_type.clone()))
|
||||
|
@ -1050,6 +1155,24 @@ impl NodeNetworkInterface {
|
|||
}
|
||||
}
|
||||
|
||||
fn proto_node_type(protonode: &graph_craft::ProtoNodeIdentifier) -> Option<&graphene_std::NodeIOTypes> {
|
||||
let Some(node_io_hashmap) = NODE_REGISTRY.get(protonode) else {
|
||||
log::error!("Could not get hashmap for proto node: {protonode:?}");
|
||||
return None;
|
||||
};
|
||||
|
||||
let node_types = node_io_hashmap.keys().min_by_key(|node_io_types| {
|
||||
let mut hasher = DefaultHasher::new();
|
||||
node_io_types.hash(&mut hasher);
|
||||
hasher.finish()
|
||||
});
|
||||
|
||||
if node_types.is_none() {
|
||||
log::error!("Could not get node_types from hashmap");
|
||||
};
|
||||
node_types
|
||||
}
|
||||
|
||||
// Private mutable getters for use within the network interface
|
||||
impl NodeNetworkInterface {
|
||||
fn network_mut(&mut self, network_path: &[NodeId]) -> Option<&mut NodeNetwork> {
|
||||
|
@ -1670,12 +1793,12 @@ impl NodeNetworkInterface {
|
|||
all_selected_nodes
|
||||
}
|
||||
|
||||
pub fn collect_front_end_click_targets(&mut self, network_path: &[NodeId]) -> FrontendClickTargets {
|
||||
pub fn collect_frontend_click_targets(&mut self, network_path: &[NodeId]) -> FrontendClickTargets {
|
||||
let mut all_node_click_targets = Vec::new();
|
||||
let mut port_click_targets = Vec::new();
|
||||
let mut visibility_click_targets = Vec::new();
|
||||
let Some(network_metadata) = self.network_metadata(network_path) else {
|
||||
log::error!("Could not get nested network_metadata in collect_front_end_click_targets");
|
||||
log::error!("Could not get nested network_metadata in collect_frontend_click_targets");
|
||||
return FrontendClickTargets::default();
|
||||
};
|
||||
network_metadata.persistent_metadata.node_metadata.keys().copied().collect::<Vec<_>>().into_iter().for_each(|node_id| {
|
||||
|
|
|
@ -26,10 +26,13 @@ const ImportsToVec2Array = Transform(({ obj }) => {
|
|||
const ExportsToVec2Array = Transform(({ obj }) => {
|
||||
const exports: { inputMetadata: FrontendGraphInput; position: XY }[] = [];
|
||||
obj.exports.forEach(([inputMetadata, x, y]: [FrontendGraphInput, number, number]) => {
|
||||
inputMetadata.connectedTo = ((connectedTo: any) => {
|
||||
if (connectedTo?.import !== undefined) return { index: connectedTo?.import.index };
|
||||
return { nodeId: connectedTo?.node.nodeId, index: connectedTo?.node.outputIndex };
|
||||
})(inputMetadata.connectedTo);
|
||||
if (inputMetadata.connectedTo !== undefined) {
|
||||
if (inputMetadata.connectedTo?.import !== undefined) {
|
||||
inputMetadata.connectedTo = { index: inputMetadata.connectedTo?.import.index };
|
||||
} else {
|
||||
inputMetadata.connectedTo = { nodeId: inputMetadata.connectedTo?.node.nodeId, index: inputMetadata.connectedTo?.node.outputIndex };
|
||||
}
|
||||
}
|
||||
exports.push({ inputMetadata, position: { x, y } });
|
||||
});
|
||||
return exports;
|
||||
|
@ -200,6 +203,9 @@ export type OutputConnector = Node | Import;
|
|||
export type InputConnector = Node | Export;
|
||||
|
||||
const CreateOutputConnectorOptional = Transform(({ obj }) => {
|
||||
if (obj.connectedTo == undefined) {
|
||||
return undefined;
|
||||
}
|
||||
if (obj.connectedTo?.export !== undefined) {
|
||||
return { index: obj.connectedTo?.export };
|
||||
} else if (obj.connectedTo?.import !== undefined) {
|
||||
|
@ -221,7 +227,7 @@ export class FrontendGraphInput {
|
|||
readonly resolvedType!: string | undefined;
|
||||
|
||||
@CreateOutputConnectorOptional
|
||||
readonly connectedTo!: OutputConnector | undefined;
|
||||
connectedTo!: OutputConnector | undefined;
|
||||
}
|
||||
|
||||
const CreateInputConnectorArray = Transform(({ obj }) => {
|
||||
|
|
|
@ -140,6 +140,12 @@ pub enum Type {
|
|||
Future(Box<Type>),
|
||||
}
|
||||
|
||||
impl Default for Type {
|
||||
fn default() -> Self {
|
||||
concrete!(())
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl StaticType for Type {
|
||||
type Static = Self;
|
||||
}
|
||||
|
|
|
@ -8,7 +8,6 @@ use graph_craft::proto::{ConstructionArgs, GraphError, LocalFuture, NodeContaine
|
|||
use graph_craft::proto::{GraphErrorType, GraphErrors};
|
||||
use graph_craft::Type;
|
||||
|
||||
use std::collections::hash_map::Entry;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::error::Error;
|
||||
use std::panic::UnwindSafe;
|
||||
|
@ -36,7 +35,7 @@ impl Default for DynamicExecutor {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Clone, Debug)]
|
||||
#[derive(PartialEq, Clone, Debug, Default)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
pub struct NodeTypes {
|
||||
pub inputs: Vec<Type>,
|
||||
|
@ -331,24 +330,23 @@ impl BorrowTree {
|
|||
|
||||
let node_path = &proto_node.original_location.path.as_ref().unwrap_or(const { &vec![] });
|
||||
|
||||
let entry = self.source_map.entry(node_path.to_vec().into());
|
||||
let newly_inserted = matches!(entry, Entry::Vacant(_));
|
||||
let entry = entry.or_insert((
|
||||
let entry = self.source_map.entry(node_path.to_vec().into()).or_default();
|
||||
|
||||
let update = (
|
||||
id,
|
||||
NodeTypes {
|
||||
inputs,
|
||||
output: node_io.output.clone(),
|
||||
},
|
||||
));
|
||||
|
||||
entry.0 = id;
|
||||
entry.1.output = node_io.output.clone();
|
||||
newly_inserted
|
||||
);
|
||||
let modified = *entry != update;
|
||||
*entry = update;
|
||||
modified
|
||||
}
|
||||
|
||||
/// Inserts a new node into the [`BorrowTree`], calling the constructor function from `node_registry.rs`.
|
||||
///
|
||||
/// This method creates a new node contianer based on the provided `ProtoNode`, updates the source map,
|
||||
/// This method creates a new node container based on the provided `ProtoNode`, updates the source map,
|
||||
/// and stores the node container in the `BorrowTree`.
|
||||
///
|
||||
///
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue