Improve collect_nodes

This commit is contained in:
Adam
2025-08-31 14:49:02 -07:00
parent 8a6aa46488
commit 8bab555357
6 changed files with 90 additions and 57 deletions

View File

@@ -2,7 +2,7 @@ use super::utility_types::{DocumentDetails, MouseCursorIcon, OpenDocument};
use crate::messages::app_window::app_window_message_handler::AppWindowPlatform;
use crate::messages::layout::utility_types::widget_prelude::*;
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::wires::{WirePath, WirePathUpdate};

View File

@@ -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::graph_operation::utility_types::ModifyInputsContext;
use crate::messages::portfolio::document::node_graph::document_node_definitions::NodePropertiesContext;
use crate::messages::portfolio::document::node_graph::utility_types::{
ContextMenuData, Direction, FrontendGraphDataType, FrontendLayer, FrontendNodeMetadata, FrontendNodeOrLayer, FrontendXY, FrontendXY,
};
use crate::messages::portfolio::document::node_graph::utility_types::{ContextMenuData, Direction, FrontendGraphDataType, FrontendXY};
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::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 glam::{DAffine2, DVec2, IVec2};
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::vector::algorithms::bezpath_algorithms::bezpath_is_inside_bezpath;
use graphene_std::*;
@@ -1638,7 +1636,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
responses.add(NodeGraphMessage::UpdateActionButtons);
if graph_view_overlay_open {
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);
responses.add(FrontendMessage::UpdateNodeGraphNodes {
nodes_to_render,

View File

@@ -89,6 +89,8 @@ pub struct FrontendGraphOutput {
// Metadata that is common to nodes and layers
#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize, specta::Type)]
pub struct FrontendNodeMetadata {
#[serde(rename = "node_id")]
pub node_id: NodeId,
// TODO: Remove and replace with popup manager system
#[serde(rename = "canBeLayer")]
pub can_be_layer: bool,
@@ -125,7 +127,7 @@ pub struct FrontendLayer {
#[serde(rename = "chainWidth")]
pub chain_width: u32,
#[serde(rename = "layerHasLeftBorderGap")]
layer_has_left_border_gap: bool,
pub layer_has_left_border_gap: bool,
#[serde(rename = "primaryInputConnectedToLayer")]
pub primary_input_connected_to_layer: bool,
#[serde(rename = "primaryOutputConnectedToLayer")]
@@ -148,11 +150,17 @@ pub struct FrontendLayer {
#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize, specta::Type)]
pub struct FrontendNodeOrLayer {
pub metadata: FrontendNodeMetadata,
pub node: Option<FrontendNode>,
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)]
pub struct FrontendNodeType {
pub name: Cow<'static, str>,

View File

@@ -5,14 +5,16 @@ use graphene_std::uuid::NodeId;
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},
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},
},
};
// Functions used to collect data from the network interface for use in rendering the node graph
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 {
log::error!("Could not get nested network when collecting nodes");
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<_>>() {
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
.iter()
.find(|error| error.node_path == node_id_path)
@@ -60,31 +36,73 @@ impl NodeNetworkInterface {
}
});
nodes.push(FrontendNode {
id: node_id,
is_layer: self.node_metadata(&node_id, network_path).is_some_and(|node_metadata| node_metadata.persistent_metadata.is_layer()),
let metadata = FrontendNodeMetadata {
node_id,
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),
reference: self.reference(&node_id, network_path).cloned().unwrap_or_default(),
display_name: self.display_name(&node_id, network_path),
previewed,
visible,
errors,
};
primary_input,
exposed_inputs,
primary_output,
exposed_outputs,
position,
let node_or_layer = match self.is_layer(&node_id, network_path) {
true => {
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 };
locked,
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),
});
let Some(bottom_input) = self.frontend_input_from_connector(&InputConnector::node(node_id, 0), network_path) else {
log::error!("Layer must have a visible primary input");
continue;
};
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
}
@@ -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 {
data_type,
resolved_type,
name,
description,
connected_to,
connected_to_node,
})
}

View File

@@ -78,7 +78,7 @@ export class UpdateLayerWidths extends JsMessage {
}
export class UpdateNodeGraphNodes extends JsMessage {
readonly nodesToRender!: FrontendNode[];
readonly nodesToRender!: FrontendNodeToRender[];
readonly inSelectedNetwork!: boolean;
@@ -199,6 +199,8 @@ export class FrontendGraphOutput {
}
export class FrontendNodeMetadata {
readonly nodeId!: bigint;
readonly canBeLayer!: boolean;
readonly displayName!: string;
@@ -255,11 +257,15 @@ export class FrontendLayerPosition {
}
export class FrontendNodeOrLayer {
readonly metadata!: FrontendNodeMetadata;
readonly node!: FrontendNode | undefined;
readonly layer!: FrontendLayer | undefined;
}
export class FrontendNodeToRender {
readonly metadata!: FrontendNodeMetadata;
readonly nodeOrLayer!: FrontendNodeOrLayer;
}
export class UpdateCentralNodeGraph extends JsMessage {
readonly nodeOrLayer!: FrontendNodeOrLayer[];
readonly inSelectedNetwork!: boolean;

View File

@@ -1,11 +1,11 @@
import { writable } from "svelte/store";
import { type Editor } from "@graphite/editor";
import type { FrontendNodeOrLayer } from "@graphite/messages";
import {
type Box,
type FrontendClickTargets,
type ContextMenuInformation,
type FrontendNodeToRender,
type FrontendNodeType,
type WirePath,
ClearAllNodeGraphWires,
@@ -102,7 +102,7 @@ export function createNodeGraphState(editor: Editor) {
update((state) => {
state.nodesToRender.clear();
updateNodeGraphNodes.nodesToRender.forEach((node) => {
state.nodesToRender.set(node.id, node);
state.nodesToRender.set(node.metadata.nodeId, node);
});
state.inSelectedNetwork = updateNodeGraphNodes.inSelectedNetwork;
state.previewedNode = updateNodeGraphNodes.previewedNode;