Improve collect_nodes

This commit is contained in:
Adam
2025-09-08 16:39:22 -07:00
parent 8a6aa46488
commit 8bab555357
6 changed files with 90 additions and 57 deletions
@@ -2,7 +2,7 @@ use super::utility_types::{DocumentDetails, MouseCursorIcon, OpenDocument};
use crate::messages::app_window::app_window_message_handler::AppWindowPlatform; use crate::messages::app_window::app_window_message_handler::AppWindowPlatform;
use crate::messages::layout::utility_types::widget_prelude::*; use crate::messages::layout::utility_types::widget_prelude::*;
use crate::messages::portfolio::document::node_graph::utility_types::{ use crate::messages::portfolio::document::node_graph::utility_types::{
BoxSelection, ContextMenuInformation, FrontendClickTargets, FrontendGraphInput, FrontendGraphOutput, FrontendNode, FrontendNodeOrLayer, FrontendNodeType, FrontendXY, FrontendXY, Transform, BoxSelection, ContextMenuInformation, FrontendClickTargets, FrontendGraphInput, FrontendGraphOutput, FrontendNodeToRender, FrontendNodeType, FrontendXY, Transform,
}; };
use crate::messages::portfolio::document::utility_types::nodes::{JsRawBuffer, LayerPanelEntry, RawBuffer}; use crate::messages::portfolio::document::utility_types::nodes::{JsRawBuffer, LayerPanelEntry, RawBuffer};
use crate::messages::portfolio::document::utility_types::wires::{WirePath, WirePathUpdate}; use crate::messages::portfolio::document::utility_types::wires::{WirePath, WirePathUpdate};
@@ -6,9 +6,7 @@ use crate::messages::layout::utility_types::widget_prelude::*;
use crate::messages::portfolio::document::document_message_handler::navigation_controls; use crate::messages::portfolio::document::document_message_handler::navigation_controls;
use crate::messages::portfolio::document::graph_operation::utility_types::ModifyInputsContext; use crate::messages::portfolio::document::graph_operation::utility_types::ModifyInputsContext;
use crate::messages::portfolio::document::node_graph::document_node_definitions::NodePropertiesContext; use crate::messages::portfolio::document::node_graph::document_node_definitions::NodePropertiesContext;
use crate::messages::portfolio::document::node_graph::utility_types::{ use crate::messages::portfolio::document::node_graph::utility_types::{ContextMenuData, Direction, FrontendGraphDataType, FrontendXY};
ContextMenuData, Direction, FrontendGraphDataType, FrontendLayer, FrontendNodeMetadata, FrontendNodeOrLayer, FrontendXY, FrontendXY,
};
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier; use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
use crate::messages::portfolio::document::utility_types::misc::GroupFolderType; use crate::messages::portfolio::document::utility_types::misc::GroupFolderType;
use crate::messages::portfolio::document::utility_types::network_interface::{ use crate::messages::portfolio::document::utility_types::network_interface::{
@@ -24,7 +22,7 @@ use crate::messages::tool::tool_messages::tool_prelude::{Key, MouseMotion};
use crate::messages::tool::utility_types::{HintData, HintGroup, HintInfo}; use crate::messages::tool::utility_types::{HintData, HintGroup, HintInfo};
use glam::{DAffine2, DVec2, IVec2}; use glam::{DAffine2, DVec2, IVec2};
use graph_craft::document::{DocumentNodeImplementation, NodeId, NodeInput}; use graph_craft::document::{DocumentNodeImplementation, NodeId, NodeInput};
use graph_craft::proto::{GraphErrors, NodeMetadata}; use graph_craft::proto::GraphErrors;
use graphene_std::math::math_ext::QuadExt; use graphene_std::math::math_ext::QuadExt;
use graphene_std::vector::algorithms::bezpath_algorithms::bezpath_is_inside_bezpath; use graphene_std::vector::algorithms::bezpath_algorithms::bezpath_is_inside_bezpath;
use graphene_std::*; use graphene_std::*;
@@ -1638,7 +1636,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
responses.add(NodeGraphMessage::UpdateActionButtons); responses.add(NodeGraphMessage::UpdateActionButtons);
if graph_view_overlay_open { if graph_view_overlay_open {
let nodes_to_render = network_interface.collect_nodes(&self.node_graph_errors, breadcrumb_network_path); let nodes_to_render = network_interface.collect_nodes(&self.node_graph_errors, breadcrumb_network_path);
self.frontend_nodes = nodes_to_render.iter().map(|node| node.id).collect(); self.frontend_nodes = nodes_to_render.iter().map(|node| node.metadata.node_id).collect();
let previewed_node = network_interface.previewed_node(breadcrumb_network_path); let previewed_node = network_interface.previewed_node(breadcrumb_network_path);
responses.add(FrontendMessage::UpdateNodeGraphNodes { responses.add(FrontendMessage::UpdateNodeGraphNodes {
nodes_to_render, nodes_to_render,
@@ -89,6 +89,8 @@ pub struct FrontendGraphOutput {
// Metadata that is common to nodes and layers // Metadata that is common to nodes and layers
#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize, specta::Type)] #[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize, specta::Type)]
pub struct FrontendNodeMetadata { pub struct FrontendNodeMetadata {
#[serde(rename = "node_id")]
pub node_id: NodeId,
// TODO: Remove and replace with popup manager system // TODO: Remove and replace with popup manager system
#[serde(rename = "canBeLayer")] #[serde(rename = "canBeLayer")]
pub can_be_layer: bool, pub can_be_layer: bool,
@@ -125,7 +127,7 @@ pub struct FrontendLayer {
#[serde(rename = "chainWidth")] #[serde(rename = "chainWidth")]
pub chain_width: u32, pub chain_width: u32,
#[serde(rename = "layerHasLeftBorderGap")] #[serde(rename = "layerHasLeftBorderGap")]
layer_has_left_border_gap: bool, pub layer_has_left_border_gap: bool,
#[serde(rename = "primaryInputConnectedToLayer")] #[serde(rename = "primaryInputConnectedToLayer")]
pub primary_input_connected_to_layer: bool, pub primary_input_connected_to_layer: bool,
#[serde(rename = "primaryOutputConnectedToLayer")] #[serde(rename = "primaryOutputConnectedToLayer")]
@@ -148,11 +150,17 @@ pub struct FrontendLayer {
#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize, specta::Type)] #[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize, specta::Type)]
pub struct FrontendNodeOrLayer { pub struct FrontendNodeOrLayer {
pub metadata: FrontendNodeMetadata,
pub node: Option<FrontendNode>, pub node: Option<FrontendNode>,
pub layer: Option<FrontendLayer>, pub layer: Option<FrontendLayer>,
} }
#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize, specta::Type)]
pub struct FrontendNodeToRender {
pub metadata: FrontendNodeMetadata,
#[serde(rename = "nodeOrLayer")]
pub node_or_layer: FrontendNodeOrLayer,
}
#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize, specta::Type)] #[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize, specta::Type)]
pub struct FrontendNodeType { pub struct FrontendNodeType {
pub name: Cow<'static, str>, pub name: Cow<'static, str>,
@@ -5,14 +5,16 @@ use graphene_std::uuid::NodeId;
use crate::{ use crate::{
consts::{EXPORTS_TO_RIGHT_EDGE_PIXEL_GAP, EXPORTS_TO_TOP_EDGE_PIXEL_GAP, GRID_SIZE, IMPORTS_TO_LEFT_EDGE_PIXEL_GAP, IMPORTS_TO_TOP_EDGE_PIXEL_GAP}, consts::{EXPORTS_TO_RIGHT_EDGE_PIXEL_GAP, EXPORTS_TO_TOP_EDGE_PIXEL_GAP, GRID_SIZE, IMPORTS_TO_LEFT_EDGE_PIXEL_GAP, IMPORTS_TO_TOP_EDGE_PIXEL_GAP},
messages::portfolio::document::{ messages::portfolio::document::{
node_graph::utility_types::{FrontendGraphDataType, FrontendGraphInput, FrontendGraphOutput, FrontendNode, FrontendXY}, node_graph::utility_types::{
FrontendGraphDataType, FrontendGraphInput, FrontendGraphOutput, FrontendLayer, FrontendNode, FrontendNodeMetadata, FrontendNodeOrLayer, FrontendNodeToRender, FrontendXY,
},
utility_types::network_interface::{FlowType, InputConnector, NodeNetworkInterface, OutputConnector}, utility_types::network_interface::{FlowType, InputConnector, NodeNetworkInterface, OutputConnector},
}, },
}; };
// Functions used to collect data from the network interface for use in rendering the node graph // Functions used to collect data from the network interface for use in rendering the node graph
impl NodeNetworkInterface { impl NodeNetworkInterface {
pub fn collect_nodes(&mut self, node_graph_errors: &GraphErrors, network_path: &[NodeId]) -> Vec<FrontendNode> { pub fn collect_nodes(&mut self, node_graph_errors: &GraphErrors, network_path: &[NodeId]) -> Vec<FrontendNodeToRender> {
let Some(network) = self.nested_network(network_path) else { let Some(network) = self.nested_network(network_path) else {
log::error!("Could not get nested network when collecting nodes"); log::error!("Could not get nested network when collecting nodes");
return Vec::new(); return Vec::new();
@@ -22,32 +24,6 @@ impl NodeNetworkInterface {
for (node_id, visible) in network.nodes.iter().map(|(node_id, node)| (*node_id, node.visible)).collect::<Vec<_>>() { for (node_id, visible) in network.nodes.iter().map(|(node_id, node)| (*node_id, node.visible)).collect::<Vec<_>>() {
let node_id_path = [network_path, &[node_id]].concat(); let node_id_path = [network_path, &[node_id]].concat();
let primary_input_connector = InputConnector::node(node_id, 0);
let primary_input = if self.input_from_connector(&primary_input_connector, network_path).is_some_and(|input| input.is_exposed()) {
self.frontend_input_from_connector(&primary_input_connector, network_path)
} else {
None
};
let exposed_inputs = (1..self.number_of_inputs(&node_id, network_path))
.filter_map(|input_index| self.frontend_input_from_connector(&InputConnector::node(node_id, input_index), network_path))
.collect();
let primary_output = self.frontend_output_from_connector(&OutputConnector::node(node_id, 0), network_path);
let exposed_outputs = (1..self.number_of_outputs(&node_id, network_path))
.filter_map(|output_index| self.frontend_output_from_connector(&OutputConnector::node(node_id, output_index), network_path))
.collect();
let Some(position) = self.position(&node_id, network_path) else {
log::error!("Could not get position for node: {node_id}");
continue;
};
let position = FrontendXY { x: position.x, y: position.y };
let previewed = self.previewed_node(network_path) == Some(node_id);
let locked = self.is_locked(&node_id, network_path);
let errors = node_graph_errors let errors = node_graph_errors
.iter() .iter()
.find(|error| error.node_path == node_id_path) .find(|error| error.node_path == node_id_path)
@@ -60,31 +36,73 @@ impl NodeNetworkInterface {
} }
}); });
nodes.push(FrontendNode { let metadata = FrontendNodeMetadata {
id: node_id, node_id,
is_layer: self.node_metadata(&node_id, network_path).is_some_and(|node_metadata| node_metadata.persistent_metadata.is_layer()),
can_be_layer: self.is_eligible_to_be_layer(&node_id, network_path), can_be_layer: self.is_eligible_to_be_layer(&node_id, network_path),
display_name: self.display_name(&node_id, network_path),
selected: selected_nodes.0.contains(&node_id), selected: selected_nodes.0.contains(&node_id),
reference: self.reference(&node_id, network_path).cloned().unwrap_or_default(), reference: self.reference(&node_id, network_path).cloned().unwrap_or_default(),
display_name: self.display_name(&node_id, network_path),
previewed,
visible, visible,
errors, errors,
};
primary_input, let node_or_layer = match self.is_layer(&node_id, network_path) {
exposed_inputs, true => {
primary_output, let Some(position) = self.position(&node_id, network_path) else {
exposed_outputs, log::error!("Could not get position for node: {node_id}");
position, continue;
};
let position = FrontendXY { x: position.x, y: position.y };
locked, let Some(bottom_input) = self.frontend_input_from_connector(&InputConnector::node(node_id, 0), network_path) else {
chain_width: self.chain_width(&node_id, network_path), log::error!("Layer must have a visible primary input");
layer_has_left_border_gap: self.layer_has_left_border_gap(&node_id, network_path), continue;
primary_input_connected_to_layer: self.primary_output_connected_to_layer(&node_id, network_path), };
primary_output_connected_to_layer: self.primary_input_connected_to_layer(&node_id, network_path), let side_input = self.frontend_input_from_connector(&InputConnector::node(node_id, 1), network_path);
}); let Some(output) = self.frontend_output_from_connector(&OutputConnector::node(node_id, 0), network_path) else {
log::error!("Layer must have a visible primary output");
continue;
};
let layer = Some(FrontendLayer {
bottom_input,
side_input,
output,
position,
locked: self.is_locked(&node_id, network_path),
chain_width: self.chain_width(&node_id, network_path),
layer_has_left_border_gap: self.layer_has_left_border_gap(&node_id, network_path),
primary_input_connected_to_layer: self.primary_output_connected_to_layer(&node_id, network_path),
primary_output_connected_to_layer: self.primary_input_connected_to_layer(&node_id, network_path),
});
FrontendNodeOrLayer { node: None, layer }
}
false => {
let Some(position) = self.position(&node_id, network_path) else {
log::error!("Could not get position for node: {node_id}");
continue;
};
let position = FrontendXY { x: position.x, y: position.y };
let inputs = (0..self.number_of_inputs(&node_id, network_path))
.map(|input_index| self.frontend_input_from_connector(&InputConnector::node(node_id, input_index), network_path))
.collect();
let outputs = (0..self.number_of_outputs(&node_id, network_path))
.map(|output_index| self.frontend_output_from_connector(&OutputConnector::node(node_id, output_index), network_path))
.collect();
let node = Some(FrontendNode { position, inputs, outputs });
FrontendNodeOrLayer { node, layer: None }
}
};
let frontend_node_to_render = FrontendNodeToRender { metadata, node_or_layer };
nodes.push(frontend_node_to_render);
} }
nodes nodes
} }
@@ -146,12 +164,15 @@ impl NodeNetworkInterface {
// } // }
// }; // };
let connected_to_node = self.upstream_output_connector(input_connector, network_path).and_then(|output_connector| output_connector.node_id());
Some(FrontendGraphInput { Some(FrontendGraphInput {
data_type, data_type,
resolved_type, resolved_type,
name, name,
description, description,
connected_to, connected_to,
connected_to_node,
}) })
} }
+8 -2
View File
@@ -78,7 +78,7 @@ export class UpdateLayerWidths extends JsMessage {
} }
export class UpdateNodeGraphNodes extends JsMessage { export class UpdateNodeGraphNodes extends JsMessage {
readonly nodesToRender!: FrontendNode[]; readonly nodesToRender!: FrontendNodeToRender[];
readonly inSelectedNetwork!: boolean; readonly inSelectedNetwork!: boolean;
@@ -199,6 +199,8 @@ export class FrontendGraphOutput {
} }
export class FrontendNodeMetadata { export class FrontendNodeMetadata {
readonly nodeId!: bigint;
readonly canBeLayer!: boolean; readonly canBeLayer!: boolean;
readonly displayName!: string; readonly displayName!: string;
@@ -255,11 +257,15 @@ export class FrontendLayerPosition {
} }
export class FrontendNodeOrLayer { export class FrontendNodeOrLayer {
readonly metadata!: FrontendNodeMetadata;
readonly node!: FrontendNode | undefined; readonly node!: FrontendNode | undefined;
readonly layer!: FrontendLayer | undefined; readonly layer!: FrontendLayer | undefined;
} }
export class FrontendNodeToRender {
readonly metadata!: FrontendNodeMetadata;
readonly nodeOrLayer!: FrontendNodeOrLayer;
}
export class UpdateCentralNodeGraph extends JsMessage { export class UpdateCentralNodeGraph extends JsMessage {
readonly nodeOrLayer!: FrontendNodeOrLayer[]; readonly nodeOrLayer!: FrontendNodeOrLayer[];
readonly inSelectedNetwork!: boolean; readonly inSelectedNetwork!: boolean;
+2 -2
View File
@@ -1,11 +1,11 @@
import { writable } from "svelte/store"; import { writable } from "svelte/store";
import { type Editor } from "@graphite/editor"; import { type Editor } from "@graphite/editor";
import type { FrontendNodeOrLayer } from "@graphite/messages";
import { import {
type Box, type Box,
type FrontendClickTargets, type FrontendClickTargets,
type ContextMenuInformation, type ContextMenuInformation,
type FrontendNodeToRender,
type FrontendNodeType, type FrontendNodeType,
type WirePath, type WirePath,
ClearAllNodeGraphWires, ClearAllNodeGraphWires,
@@ -102,7 +102,7 @@ export function createNodeGraphState(editor: Editor) {
update((state) => { update((state) => {
state.nodesToRender.clear(); state.nodesToRender.clear();
updateNodeGraphNodes.nodesToRender.forEach((node) => { updateNodeGraphNodes.nodesToRender.forEach((node) => {
state.nodesToRender.set(node.id, node); state.nodesToRender.set(node.metadata.nodeId, node);
}); });
state.inSelectedNetwork = updateNodeGraphNodes.inSelectedNetwork; state.inSelectedNetwork = updateNodeGraphNodes.inSelectedNetwork;
state.previewedNode = updateNodeGraphNodes.previewedNode; state.previewedNode = updateNodeGraphNodes.previewedNode;