mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-17 07:18:04 +08:00
Improve collect_nodes
This commit is contained in:
@@ -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};
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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>,
|
||||
|
||||
@@ -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,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user