mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-10-04 00:48:12 +08:00
Separate svelte node graph rendering
This commit is contained in:
@@ -53,6 +53,7 @@ const SIDE_EFFECT_FREE_MESSAGES: &[MessageDiscriminant] = &[
|
|||||||
/// Since we don't need to update the frontend multiple times per frame,
|
/// Since we don't need to update the frontend multiple times per frame,
|
||||||
/// we have a set of messages which we will buffer until the next frame is requested.
|
/// we have a set of messages which we will buffer until the next frame is requested.
|
||||||
const FRONTEND_UPDATE_MESSAGES: &[MessageDiscriminant] = &[
|
const FRONTEND_UPDATE_MESSAGES: &[MessageDiscriminant] = &[
|
||||||
|
MessageDiscriminant::Portfolio(PortfolioMessageDiscriminant::Document(DocumentMessageDiscriminant::NodeGraph(NodeGraphMessageDiscriminant::SendGraph))),
|
||||||
MessageDiscriminant::Portfolio(PortfolioMessageDiscriminant::Document(DocumentMessageDiscriminant::PropertiesPanel(
|
MessageDiscriminant::Portfolio(PortfolioMessageDiscriminant::Document(DocumentMessageDiscriminant::PropertiesPanel(
|
||||||
PropertiesPanelMessageDiscriminant::Refresh,
|
PropertiesPanelMessageDiscriminant::Refresh,
|
||||||
))),
|
))),
|
||||||
|
|||||||
@@ -2,14 +2,14 @@ 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, FrontendNodeType, NodeGraphError, Transform,
|
BoxSelection, ContextMenuInformation, FrontendClickTargets, FrontendExports, FrontendImport, FrontendNodeOld, FrontendNodeType, NodeGraphError,
|
||||||
};
|
};
|
||||||
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::{WirePathInProgress, WirePathUpdateOld};
|
||||||
use crate::messages::prelude::*;
|
use crate::messages::prelude::*;
|
||||||
use crate::messages::tool::utility_types::HintData;
|
use crate::messages::tool::utility_types::HintData;
|
||||||
use glam::IVec2;
|
|
||||||
use graph_craft::document::NodeId;
|
use graph_craft::document::NodeId;
|
||||||
|
use graphene_std::node_graph_overlay::types::{FrontendXY, NodeGraphTransform};
|
||||||
use graphene_std::raster::Image;
|
use graphene_std::raster::Image;
|
||||||
use graphene_std::raster::color::Color;
|
use graphene_std::raster::color::Color;
|
||||||
use graphene_std::text::{Font, TextAlign};
|
use graphene_std::text::{Font, TextAlign};
|
||||||
@@ -131,24 +131,23 @@ pub enum FrontendMessage {
|
|||||||
},
|
},
|
||||||
UpdateImportsExports {
|
UpdateImportsExports {
|
||||||
/// If the primary import is not visible, then it is None.
|
/// If the primary import is not visible, then it is None.
|
||||||
imports: Vec<Option<FrontendGraphOutput>>,
|
imports: Vec<Option<FrontendImport>>,
|
||||||
/// If the primary export is not visible, then it is None.
|
exports: FrontendExports,
|
||||||
exports: Vec<Option<FrontendGraphInput>>,
|
|
||||||
/// The primary import location.
|
/// The primary import location.
|
||||||
#[serde(rename = "importPosition")]
|
#[serde(rename = "importPosition")]
|
||||||
import_position: IVec2,
|
import_position: FrontendXY,
|
||||||
/// The primary export location.
|
/// The primary export location.
|
||||||
#[serde(rename = "exportPosition")]
|
#[serde(rename = "exportPosition")]
|
||||||
export_position: IVec2,
|
export_position: FrontendXY,
|
||||||
/// The document network does not have an add import or export button.
|
/// The document network does not have an add import or export button.
|
||||||
#[serde(rename = "addImportExport")]
|
#[serde(rename = "addImportExport")]
|
||||||
add_import_export: bool,
|
add_import_export: bool,
|
||||||
},
|
},
|
||||||
UpdateInSelectedNetwork {
|
UpdateInSelectedNetworkOld {
|
||||||
#[serde(rename = "inSelectedNetwork")]
|
#[serde(rename = "inSelectedNetwork")]
|
||||||
in_selected_network: bool,
|
in_selected_network: bool,
|
||||||
},
|
},
|
||||||
UpdateBox {
|
UpdateNodeGraphSelectionBox {
|
||||||
#[serde(rename = "box")]
|
#[serde(rename = "box")]
|
||||||
box_selection: Option<BoxSelection>,
|
box_selection: Option<BoxSelection>,
|
||||||
},
|
},
|
||||||
@@ -185,7 +184,7 @@ pub enum FrontendMessage {
|
|||||||
#[serde(rename = "exportIndex")]
|
#[serde(rename = "exportIndex")]
|
||||||
index: Option<usize>,
|
index: Option<usize>,
|
||||||
},
|
},
|
||||||
UpdateLayerWidths {
|
UpdateLayerWidthsOld {
|
||||||
#[serde(rename = "layerWidths")]
|
#[serde(rename = "layerWidths")]
|
||||||
layer_widths: HashMap<NodeId, u32>,
|
layer_widths: HashMap<NodeId, u32>,
|
||||||
#[serde(rename = "chainWidths")]
|
#[serde(rename = "chainWidths")]
|
||||||
@@ -256,7 +255,7 @@ pub enum FrontendMessage {
|
|||||||
#[serde(rename = "setColorChoice")]
|
#[serde(rename = "setColorChoice")]
|
||||||
set_color_choice: Option<String>,
|
set_color_choice: Option<String>,
|
||||||
},
|
},
|
||||||
UpdateGraphFadeArtwork {
|
UpdateGraphFadeArtworkOld {
|
||||||
percentage: f64,
|
percentage: f64,
|
||||||
},
|
},
|
||||||
UpdateInputHints {
|
UpdateInputHints {
|
||||||
@@ -286,29 +285,33 @@ pub enum FrontendMessage {
|
|||||||
UpdateMouseCursor {
|
UpdateMouseCursor {
|
||||||
cursor: MouseCursorIcon,
|
cursor: MouseCursorIcon,
|
||||||
},
|
},
|
||||||
UpdateNodeGraphNodes {
|
UpdateNodeGraphNodesOld {
|
||||||
nodes: Vec<FrontendNode>,
|
nodes: Vec<FrontendNodeOld>,
|
||||||
|
},
|
||||||
|
UpdateRenderNativeNodeGraph {
|
||||||
|
#[serde(rename = "renderNativeNodeGraph")]
|
||||||
|
render_native_node_graph: bool,
|
||||||
},
|
},
|
||||||
UpdateNodeGraphError {
|
UpdateNodeGraphError {
|
||||||
error: Option<NodeGraphError>,
|
error: Option<NodeGraphError>,
|
||||||
},
|
},
|
||||||
UpdateVisibleNodes {
|
UpdateVisibleNodesOld {
|
||||||
nodes: Vec<NodeId>,
|
nodes: Vec<NodeId>,
|
||||||
},
|
},
|
||||||
UpdateNodeGraphWires {
|
UpdateNodeGraphWiresOld {
|
||||||
wires: Vec<WirePathUpdate>,
|
wires: Vec<WirePathUpdateOld>,
|
||||||
},
|
},
|
||||||
ClearAllNodeGraphWires,
|
ClearAllNodeGraphWiresOld,
|
||||||
UpdateNodeGraphControlBarLayout {
|
UpdateNodeGraphControlBarLayout {
|
||||||
#[serde(rename = "layoutTarget")]
|
#[serde(rename = "layoutTarget")]
|
||||||
layout_target: LayoutTarget,
|
layout_target: LayoutTarget,
|
||||||
diff: Vec<WidgetDiff>,
|
diff: Vec<WidgetDiff>,
|
||||||
},
|
},
|
||||||
UpdateNodeGraphSelection {
|
UpdateNodeGraphSelectionOld {
|
||||||
selected: Vec<NodeId>,
|
selected: Vec<NodeId>,
|
||||||
},
|
},
|
||||||
UpdateNodeGraphTransform {
|
UpdateNodeGraphTransform {
|
||||||
transform: Transform,
|
transform: NodeGraphTransform,
|
||||||
},
|
},
|
||||||
UpdateNodeThumbnail {
|
UpdateNodeThumbnail {
|
||||||
id: NodeId,
|
id: NodeId,
|
||||||
@@ -334,8 +337,8 @@ pub enum FrontendMessage {
|
|||||||
diff: Vec<WidgetDiff>,
|
diff: Vec<WidgetDiff>,
|
||||||
},
|
},
|
||||||
UpdateWirePathInProgress {
|
UpdateWirePathInProgress {
|
||||||
#[serde(rename = "wirePath")]
|
#[serde(rename = "wirePathInProgress")]
|
||||||
wire_path: Option<WirePath>,
|
wire_path_in_progress: Option<WirePathInProgress>,
|
||||||
},
|
},
|
||||||
UpdateWorkingColorsLayout {
|
UpdateWorkingColorsLayout {
|
||||||
#[serde(rename = "layoutTarget")]
|
#[serde(rename = "layoutTarget")]
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
use crate::messages::input_mapper::utility_types::misc::ActionKeys;
|
use crate::messages::input_mapper::utility_types::misc::ActionKeys;
|
||||||
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::FrontendGraphDataType;
|
|
||||||
use crate::messages::tool::tool_messages::tool_prelude::WidgetCallback;
|
use crate::messages::tool::tool_messages::tool_prelude::WidgetCallback;
|
||||||
use derivative::*;
|
use derivative::*;
|
||||||
|
use graphene_std::node_graph_overlay::types::FrontendGraphDataType;
|
||||||
use graphene_std::vector::style::FillChoice;
|
use graphene_std::vector::style::FillChoice;
|
||||||
use graphite_proc_macros::WidgetBuilder;
|
use graphite_proc_macros::WidgetBuilder;
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
use super::node_graph::document_node_definitions;
|
use super::node_graph::document_node_definitions;
|
||||||
use super::node_graph::utility_types::Transform;
|
|
||||||
use super::overlays::utility_types::Pivot;
|
use super::overlays::utility_types::Pivot;
|
||||||
use super::utility_types::error::EditorError;
|
use super::utility_types::error::EditorError;
|
||||||
use super::utility_types::misc::{GroupFolderType, SNAP_FUNCTIONS_FOR_BOUNDING_BOXES, SNAP_FUNCTIONS_FOR_PATHS, SnappingOptions, SnappingState};
|
use super::utility_types::misc::{GroupFolderType, SNAP_FUNCTIONS_FOR_BOUNDING_BOXES, SNAP_FUNCTIONS_FOR_PATHS, SnappingOptions, SnappingState};
|
||||||
@@ -31,6 +30,7 @@ use glam::{DAffine2, DVec2, IVec2};
|
|||||||
use graph_craft::document::value::TaggedValue;
|
use graph_craft::document::value::TaggedValue;
|
||||||
use graph_craft::document::{NodeId, NodeInput, NodeNetwork, OldNodeNetwork};
|
use graph_craft::document::{NodeId, NodeInput, NodeNetwork, OldNodeNetwork};
|
||||||
use graphene_std::math::quad::Quad;
|
use graphene_std::math::quad::Quad;
|
||||||
|
use graphene_std::node_graph_overlay::types::NodeGraphTransform;
|
||||||
use graphene_std::path_bool::{boolean_intersect, path_bool_lib};
|
use graphene_std::path_bool::{boolean_intersect, path_bool_lib};
|
||||||
use graphene_std::raster::BlendMode;
|
use graphene_std::raster::BlendMode;
|
||||||
use graphene_std::raster_types::Raster;
|
use graphene_std::raster_types::Raster;
|
||||||
@@ -55,6 +55,7 @@ pub struct DocumentMessageContext<'a> {
|
|||||||
pub data_panel_open: bool,
|
pub data_panel_open: bool,
|
||||||
pub layers_panel_open: bool,
|
pub layers_panel_open: bool,
|
||||||
pub properties_panel_open: bool,
|
pub properties_panel_open: bool,
|
||||||
|
pub render_native_node_graph: bool,
|
||||||
pub viewport: &'a ViewportMessageHandler,
|
pub viewport: &'a ViewportMessageHandler,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -201,6 +202,7 @@ impl MessageHandler<DocumentMessage, DocumentMessageContext<'_>> for DocumentMes
|
|||||||
data_panel_open,
|
data_panel_open,
|
||||||
layers_panel_open,
|
layers_panel_open,
|
||||||
properties_panel_open,
|
properties_panel_open,
|
||||||
|
render_native_node_graph,
|
||||||
} = context;
|
} = context;
|
||||||
|
|
||||||
match message {
|
match message {
|
||||||
@@ -263,6 +265,7 @@ impl MessageHandler<DocumentMessage, DocumentMessageContext<'_>> for DocumentMes
|
|||||||
preferences,
|
preferences,
|
||||||
layers_panel_open,
|
layers_panel_open,
|
||||||
viewport,
|
viewport,
|
||||||
|
render_native_node_graph,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -470,7 +473,7 @@ impl MessageHandler<DocumentMessage, DocumentMessageContext<'_>> for DocumentMes
|
|||||||
DocumentMessage::EnterNestedNetwork { node_id } => {
|
DocumentMessage::EnterNestedNetwork { node_id } => {
|
||||||
self.breadcrumb_network_path.push(node_id);
|
self.breadcrumb_network_path.push(node_id);
|
||||||
self.selection_network_path.clone_from(&self.breadcrumb_network_path);
|
self.selection_network_path.clone_from(&self.breadcrumb_network_path);
|
||||||
responses.add(NodeGraphMessage::UnloadWires);
|
responses.add(NodeGraphMessage::UnloadWiresOld);
|
||||||
responses.add(NodeGraphMessage::SendGraph);
|
responses.add(NodeGraphMessage::SendGraph);
|
||||||
responses.add(DocumentMessage::ZoomCanvasToFitAll);
|
responses.add(DocumentMessage::ZoomCanvasToFitAll);
|
||||||
responses.add(NodeGraphMessage::UpdateNodeGraphWidth);
|
responses.add(NodeGraphMessage::UpdateNodeGraphWidth);
|
||||||
@@ -490,7 +493,7 @@ impl MessageHandler<DocumentMessage, DocumentMessageContext<'_>> for DocumentMes
|
|||||||
responses.add(FrontendMessage::UpdateContextMenuInformation { context_menu_information: None });
|
responses.add(FrontendMessage::UpdateContextMenuInformation { context_menu_information: None });
|
||||||
self.node_graph_handler.wire_in_progress_from_connector = None;
|
self.node_graph_handler.wire_in_progress_from_connector = None;
|
||||||
self.node_graph_handler.wire_in_progress_to_connector = None;
|
self.node_graph_handler.wire_in_progress_to_connector = None;
|
||||||
responses.add(FrontendMessage::UpdateWirePathInProgress { wire_path: None });
|
responses.add(FrontendMessage::UpdateWirePathInProgress { wire_path_in_progress: None });
|
||||||
} else if !self.breadcrumb_network_path.is_empty() {
|
} else if !self.breadcrumb_network_path.is_empty() {
|
||||||
// Exit one level up if inside a nested network
|
// Exit one level up if inside a nested network
|
||||||
responses.add(DocumentMessage::ExitNestedNetwork { steps_back: 1 });
|
responses.add(DocumentMessage::ExitNestedNetwork { steps_back: 1 });
|
||||||
@@ -503,7 +506,7 @@ impl MessageHandler<DocumentMessage, DocumentMessageContext<'_>> for DocumentMes
|
|||||||
self.breadcrumb_network_path.pop();
|
self.breadcrumb_network_path.pop();
|
||||||
self.selection_network_path.clone_from(&self.breadcrumb_network_path);
|
self.selection_network_path.clone_from(&self.breadcrumb_network_path);
|
||||||
}
|
}
|
||||||
responses.add(NodeGraphMessage::UnloadWires);
|
responses.add(NodeGraphMessage::UnloadWiresOld);
|
||||||
responses.add(NodeGraphMessage::SendGraph);
|
responses.add(NodeGraphMessage::SendGraph);
|
||||||
responses.add(DocumentMessage::PTZUpdate);
|
responses.add(DocumentMessage::PTZUpdate);
|
||||||
responses.add(NodeGraphMessage::UpdateNodeGraphWidth);
|
responses.add(NodeGraphMessage::UpdateNodeGraphWidth);
|
||||||
@@ -560,7 +563,7 @@ impl MessageHandler<DocumentMessage, DocumentMessageContext<'_>> for DocumentMes
|
|||||||
self.graph_view_overlay_open = open;
|
self.graph_view_overlay_open = open;
|
||||||
|
|
||||||
responses.add(FrontendMessage::UpdateGraphViewOverlay { open });
|
responses.add(FrontendMessage::UpdateGraphViewOverlay { open });
|
||||||
responses.add(FrontendMessage::UpdateGraphFadeArtwork {
|
responses.add(FrontendMessage::UpdateGraphFadeArtworkOld {
|
||||||
percentage: self.graph_fade_artwork_percentage,
|
percentage: self.graph_fade_artwork_percentage,
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -570,20 +573,21 @@ impl MessageHandler<DocumentMessage, DocumentMessageContext<'_>> for DocumentMes
|
|||||||
responses.add(DocumentMessage::RenderRulers);
|
responses.add(DocumentMessage::RenderRulers);
|
||||||
responses.add(DocumentMessage::RenderScrollbars);
|
responses.add(DocumentMessage::RenderScrollbars);
|
||||||
if opened {
|
if opened {
|
||||||
responses.add(NodeGraphMessage::UnloadWires);
|
responses.add(NodeGraphMessage::UnloadWiresOld);
|
||||||
}
|
}
|
||||||
if open {
|
if open {
|
||||||
responses.add(ToolMessage::DeactivateTools);
|
responses.add(ToolMessage::DeactivateTools);
|
||||||
responses.add(OverlaysMessage::Draw); // Clear the overlays
|
responses.add(OverlaysMessage::Draw); // Clear the overlays
|
||||||
responses.add(NavigationMessage::CanvasTiltSet { angle_radians: 0. });
|
responses.add(NavigationMessage::CanvasTiltSet { angle_radians: 0. });
|
||||||
responses.add(NodeGraphMessage::UpdateGraphBarRight);
|
responses.add(NodeGraphMessage::UpdateGraphBarRight);
|
||||||
responses.add(NodeGraphMessage::SendGraph);
|
|
||||||
responses.add(NodeGraphMessage::UpdateHints);
|
responses.add(NodeGraphMessage::UpdateHints);
|
||||||
responses.add(NodeGraphMessage::UpdateEdges);
|
responses.add(NodeGraphMessage::UpdateEdges);
|
||||||
} else {
|
} else {
|
||||||
responses.add(ToolMessage::ActivateTool { tool_type: *current_tool });
|
responses.add(ToolMessage::ActivateTool { tool_type: *current_tool });
|
||||||
responses.add(OverlaysMessage::Draw); // Redraw overlays when graph is closed
|
responses.add(OverlaysMessage::Draw); // Redraw overlays when graph is closed
|
||||||
}
|
}
|
||||||
|
|
||||||
|
responses.add(NodeGraphMessage::SendGraph);
|
||||||
}
|
}
|
||||||
DocumentMessage::GraphViewOverlayToggle => {
|
DocumentMessage::GraphViewOverlayToggle => {
|
||||||
responses.add(DocumentMessage::GraphViewOverlay { open: !self.graph_view_overlay_open });
|
responses.add(DocumentMessage::GraphViewOverlay { open: !self.graph_view_overlay_open });
|
||||||
@@ -1196,7 +1200,7 @@ impl MessageHandler<DocumentMessage, DocumentMessageContext<'_>> for DocumentMes
|
|||||||
}
|
}
|
||||||
responses.add(PropertiesPanelMessage::Refresh);
|
responses.add(PropertiesPanelMessage::Refresh);
|
||||||
responses.add(NodeGraphMessage::UpdateLayerPanel);
|
responses.add(NodeGraphMessage::UpdateLayerPanel);
|
||||||
responses.add(NodeGraphMessage::UpdateInSelectedNetwork);
|
responses.add(NodeGraphMessage::SendGraph);
|
||||||
}
|
}
|
||||||
DocumentMessage::SetBlendModeForSelectedLayers { blend_mode } => {
|
DocumentMessage::SetBlendModeForSelectedLayers { blend_mode } => {
|
||||||
for layer in self.network_interface.selected_nodes().selected_layers_except_artboards(&self.network_interface) {
|
for layer in self.network_interface.selected_nodes().selected_layers_except_artboards(&self.network_interface) {
|
||||||
@@ -1205,7 +1209,10 @@ impl MessageHandler<DocumentMessage, DocumentMessageContext<'_>> for DocumentMes
|
|||||||
}
|
}
|
||||||
DocumentMessage::SetGraphFadeArtwork { percentage } => {
|
DocumentMessage::SetGraphFadeArtwork { percentage } => {
|
||||||
self.graph_fade_artwork_percentage = percentage;
|
self.graph_fade_artwork_percentage = percentage;
|
||||||
responses.add(FrontendMessage::UpdateGraphFadeArtwork { percentage });
|
responses.add(FrontendMessage::UpdateGraphFadeArtworkOld { percentage });
|
||||||
|
if render_native_node_graph {
|
||||||
|
responses.add(NodeGraphMessage::SendGraph);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
DocumentMessage::SetNodePinned { node_id, pinned } => {
|
DocumentMessage::SetNodePinned { node_id, pinned } => {
|
||||||
responses.add(DocumentMessage::AddTransaction);
|
responses.add(DocumentMessage::AddTransaction);
|
||||||
@@ -1507,7 +1514,7 @@ impl MessageHandler<DocumentMessage, DocumentMessageContext<'_>> for DocumentMes
|
|||||||
responses.add(NodeGraphMessage::UpdateImportsExports);
|
responses.add(NodeGraphMessage::UpdateImportsExports);
|
||||||
|
|
||||||
responses.add(FrontendMessage::UpdateNodeGraphTransform {
|
responses.add(FrontendMessage::UpdateNodeGraphTransform {
|
||||||
transform: Transform {
|
transform: NodeGraphTransform {
|
||||||
scale: transform.matrix2.x_axis.x,
|
scale: transform.matrix2.x_axis.x,
|
||||||
x: transform.translation.x,
|
x: transform.translation.x,
|
||||||
y: transform.translation.y,
|
y: transform.translation.y,
|
||||||
@@ -1971,7 +1978,7 @@ impl DocumentMessageHandler {
|
|||||||
responses.add(NodeGraphMessage::ForceRunDocumentGraph);
|
responses.add(NodeGraphMessage::ForceRunDocumentGraph);
|
||||||
|
|
||||||
// TODO: Remove once the footprint is used to load the imports/export distances from the edge
|
// TODO: Remove once the footprint is used to load the imports/export distances from the edge
|
||||||
responses.add(NodeGraphMessage::UnloadWires);
|
responses.add(NodeGraphMessage::UnloadWiresOld);
|
||||||
|
|
||||||
Some(previous_network)
|
Some(previous_network)
|
||||||
}
|
}
|
||||||
@@ -2002,8 +2009,8 @@ impl DocumentMessageHandler {
|
|||||||
responses.add(PortfolioMessage::UpdateOpenDocumentsList);
|
responses.add(PortfolioMessage::UpdateOpenDocumentsList);
|
||||||
responses.add(NodeGraphMessage::SelectedNodesUpdated);
|
responses.add(NodeGraphMessage::SelectedNodesUpdated);
|
||||||
responses.add(NodeGraphMessage::ForceRunDocumentGraph);
|
responses.add(NodeGraphMessage::ForceRunDocumentGraph);
|
||||||
responses.add(NodeGraphMessage::UnloadWires);
|
responses.add(NodeGraphMessage::UnloadWiresOld);
|
||||||
responses.add(NodeGraphMessage::SendWires);
|
responses.add(NodeGraphMessage::SendWiresOld);
|
||||||
Some(previous_network)
|
Some(previous_network)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -141,10 +141,12 @@ pub enum NodeGraphMessage {
|
|||||||
},
|
},
|
||||||
SendClickTargets,
|
SendClickTargets,
|
||||||
EndSendClickTargets,
|
EndSendClickTargets,
|
||||||
UnloadWires,
|
UnloadWiresOld,
|
||||||
SendWires,
|
SendWiresOld,
|
||||||
UpdateVisibleNodes,
|
UpdateVisibleNodesOld,
|
||||||
SendGraph,
|
SendGraph,
|
||||||
|
SendGraphOld,
|
||||||
|
SendGraphNew,
|
||||||
SetInputValue {
|
SetInputValue {
|
||||||
node_id: NodeId,
|
node_id: NodeId,
|
||||||
input_index: usize,
|
input_index: usize,
|
||||||
@@ -232,7 +234,7 @@ pub enum NodeGraphMessage {
|
|||||||
},
|
},
|
||||||
UpdateActionButtons,
|
UpdateActionButtons,
|
||||||
UpdateGraphBarRight,
|
UpdateGraphBarRight,
|
||||||
UpdateInSelectedNetwork,
|
UpdateInSelectedNetworkOld,
|
||||||
UpdateHints,
|
UpdateHints,
|
||||||
SendSelectedNodes,
|
SendSelectedNodesOld,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use super::utility_types::{BoxSelection, ContextMenuInformation, DragStart, FrontendNode};
|
use super::utility_types::{BoxSelection, ContextMenuInformation, DragStart};
|
||||||
use super::{document_node_definitions, node_properties};
|
use super::{document_node_definitions, node_properties};
|
||||||
use crate::consts::GRID_SIZE;
|
use crate::consts::GRID_SIZE;
|
||||||
use crate::messages::input_mapper::utility_types::macros::action_keys;
|
use crate::messages::input_mapper::utility_types::macros::action_keys;
|
||||||
@@ -6,14 +6,14 @@ 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::{ContextMenuData, Direction, FrontendGraphDataType, NodeGraphError};
|
use crate::messages::portfolio::document::node_graph::utility_types::{ContextMenuData, Direction, FrontendNodeOld, NodeGraphError};
|
||||||
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::{
|
||||||
self, FlowType, InputConnector, NodeNetworkInterface, NodeTemplate, NodeTypePersistentMetadata, OutputConnector, Previewing,
|
self, FlowType, InputConnector, NodeNetworkInterface, NodeTemplate, NodeTypePersistentMetadata, OutputConnector, Previewing,
|
||||||
};
|
};
|
||||||
use crate::messages::portfolio::document::utility_types::nodes::{CollapsedLayers, LayerPanelEntry};
|
use crate::messages::portfolio::document::utility_types::nodes::{CollapsedLayers, LayerPanelEntry};
|
||||||
use crate::messages::portfolio::document::utility_types::wires::{GraphWireStyle, WirePath, WirePathUpdate, build_vector_wire};
|
use crate::messages::portfolio::document::utility_types::wires::{GraphWireStyle, WirePathInProgress, WirePathUpdateOld, build_vector_wire};
|
||||||
use crate::messages::prelude::*;
|
use crate::messages::prelude::*;
|
||||||
use crate::messages::tool::common_functionality::auto_panning::AutoPanning;
|
use crate::messages::tool::common_functionality::auto_panning::AutoPanning;
|
||||||
use crate::messages::tool::common_functionality::graph_modification_utils::get_clip_mode;
|
use crate::messages::tool::common_functionality::graph_modification_utils::get_clip_mode;
|
||||||
@@ -24,6 +24,7 @@ use crate::messages::viewport::Position;
|
|||||||
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 graphene_std::math::math_ext::QuadExt;
|
use graphene_std::math::math_ext::QuadExt;
|
||||||
|
use graphene_std::node_graph_overlay::types::{FrontendGraphDataType, FrontendXY};
|
||||||
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::*;
|
||||||
use kurbo::{DEFAULT_ACCURACY, Shape};
|
use kurbo::{DEFAULT_ACCURACY, Shape};
|
||||||
@@ -44,6 +45,7 @@ pub struct NodeGraphMessageContext<'a> {
|
|||||||
pub preferences: &'a PreferencesMessageHandler,
|
pub preferences: &'a PreferencesMessageHandler,
|
||||||
pub layers_panel_open: bool,
|
pub layers_panel_open: bool,
|
||||||
pub viewport: &'a ViewportMessageHandler,
|
pub viewport: &'a ViewportMessageHandler,
|
||||||
|
pub render_native_node_graph: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, ExtractField)]
|
#[derive(Debug, Clone, ExtractField)]
|
||||||
@@ -92,9 +94,9 @@ pub struct NodeGraphMessageHandler {
|
|||||||
/// The end index of the moved connector
|
/// The end index of the moved connector
|
||||||
end_index: Option<usize>,
|
end_index: Option<usize>,
|
||||||
/// Used to keep track of what nodes are sent to the front end so that only visible ones are sent to the frontend
|
/// Used to keep track of what nodes are sent to the front end so that only visible ones are sent to the frontend
|
||||||
frontend_nodes: Vec<NodeId>,
|
frontend_nodes_old: Vec<NodeId>,
|
||||||
/// Used to keep track of what wires are sent to the front end so the old ones can be removed
|
/// Used to keep track of what wires are sent to the front end so the old ones can be removed
|
||||||
frontend_wires: HashSet<(NodeId, usize)>,
|
frontend_wires_old: HashSet<(NodeId, usize)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// NodeGraphMessageHandler always modifies the network which the selected nodes are in. No GraphOperationMessages should be added here, since those messages will always affect the document network.
|
/// NodeGraphMessageHandler always modifies the network which the selected nodes are in. No GraphOperationMessages should be added here, since those messages will always affect the document network.
|
||||||
@@ -114,6 +116,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
|
|||||||
preferences,
|
preferences,
|
||||||
layers_panel_open,
|
layers_panel_open,
|
||||||
viewport,
|
viewport,
|
||||||
|
render_native_node_graph,
|
||||||
} = context;
|
} = context;
|
||||||
|
|
||||||
match message {
|
match message {
|
||||||
@@ -193,7 +196,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
|
|||||||
responses.add(MenuBarMessage::SendLayout);
|
responses.add(MenuBarMessage::SendLayout);
|
||||||
responses.add(NodeGraphMessage::UpdateLayerPanel);
|
responses.add(NodeGraphMessage::UpdateLayerPanel);
|
||||||
responses.add(PropertiesPanelMessage::Refresh);
|
responses.add(PropertiesPanelMessage::Refresh);
|
||||||
responses.add(NodeGraphMessage::SendSelectedNodes);
|
responses.add(NodeGraphMessage::SendSelectedNodesOld);
|
||||||
responses.add(ArtboardToolMessage::UpdateSelectedArtboard);
|
responses.add(ArtboardToolMessage::UpdateSelectedArtboard);
|
||||||
responses.add(DocumentMessage::DocumentStructureChanged);
|
responses.add(DocumentMessage::DocumentStructureChanged);
|
||||||
responses.add(OverlaysMessage::Draw);
|
responses.add(OverlaysMessage::Draw);
|
||||||
@@ -298,7 +301,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
|
|||||||
self.wire_in_progress_type = FrontendGraphDataType::General;
|
self.wire_in_progress_type = FrontendGraphDataType::General;
|
||||||
self.wire_in_progress_to_connector = None;
|
self.wire_in_progress_to_connector = None;
|
||||||
}
|
}
|
||||||
responses.add(FrontendMessage::UpdateWirePathInProgress { wire_path: None });
|
responses.add(FrontendMessage::UpdateWirePathInProgress { wire_path_in_progress: None });
|
||||||
responses.add(FrontendMessage::UpdateContextMenuInformation {
|
responses.add(FrontendMessage::UpdateContextMenuInformation {
|
||||||
context_menu_information: self.context_menu.clone(),
|
context_menu_information: self.context_menu.clone(),
|
||||||
});
|
});
|
||||||
@@ -471,7 +474,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
|
|||||||
}
|
}
|
||||||
|
|
||||||
responses.add(NodeGraphMessage::UpdateImportsExports);
|
responses.add(NodeGraphMessage::UpdateImportsExports);
|
||||||
responses.add(NodeGraphMessage::SendWires);
|
responses.add(NodeGraphMessage::SendWiresOld);
|
||||||
}
|
}
|
||||||
NodeGraphMessage::ExposePrimaryExport { exposed } => {
|
NodeGraphMessage::ExposePrimaryExport { exposed } => {
|
||||||
let export_connector: InputConnector = InputConnector::Export(0);
|
let export_connector: InputConnector = InputConnector::Export(0);
|
||||||
@@ -762,7 +765,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
|
|||||||
responses.add(NodeGraphMessage::SelectedNodesSet {
|
responses.add(NodeGraphMessage::SelectedNodesSet {
|
||||||
nodes: self.selection_before_pointer_down.clone(),
|
nodes: self.selection_before_pointer_down.clone(),
|
||||||
});
|
});
|
||||||
responses.add(FrontendMessage::UpdateBox { box_selection: None });
|
responses.add(FrontendMessage::UpdateNodeGraphSelectionBox { box_selection: None });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Abort dragging a wire
|
// Abort dragging a wire
|
||||||
@@ -771,7 +774,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
|
|||||||
self.wire_in_progress_type = FrontendGraphDataType::General;
|
self.wire_in_progress_type = FrontendGraphDataType::General;
|
||||||
self.wire_in_progress_to_connector = None;
|
self.wire_in_progress_to_connector = None;
|
||||||
responses.add(DocumentMessage::AbortTransaction);
|
responses.add(DocumentMessage::AbortTransaction);
|
||||||
responses.add(FrontendMessage::UpdateWirePathInProgress { wire_path: None });
|
responses.add(FrontendMessage::UpdateWirePathInProgress { wire_path_in_progress: None });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -856,7 +859,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
|
|||||||
responses.add(FrontendMessage::UpdateContextMenuInformation {
|
responses.add(FrontendMessage::UpdateContextMenuInformation {
|
||||||
context_menu_information: self.context_menu.clone(),
|
context_menu_information: self.context_menu.clone(),
|
||||||
});
|
});
|
||||||
responses.add(FrontendMessage::UpdateWirePathInProgress { wire_path: None });
|
responses.add(FrontendMessage::UpdateWirePathInProgress { wire_path_in_progress: None });
|
||||||
}
|
}
|
||||||
|
|
||||||
// Toggle visibility of clicked node and return
|
// Toggle visibility of clicked node and return
|
||||||
@@ -1063,14 +1066,14 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
|
|||||||
to_connector_is_layer,
|
to_connector_is_layer,
|
||||||
GraphWireStyle::Direct,
|
GraphWireStyle::Direct,
|
||||||
);
|
);
|
||||||
let path_string = vector_wire.to_svg();
|
let wire_path = WirePathInProgress {
|
||||||
let wire_path = WirePath {
|
wire: vector_wire.to_svg(),
|
||||||
path_string,
|
|
||||||
data_type: self.wire_in_progress_type,
|
data_type: self.wire_in_progress_type,
|
||||||
thick: false,
|
thick: false,
|
||||||
dashed: false,
|
|
||||||
};
|
};
|
||||||
responses.add(FrontendMessage::UpdateWirePathInProgress { wire_path: Some(wire_path) });
|
responses.add(FrontendMessage::UpdateWirePathInProgress {
|
||||||
|
wire_path_in_progress: Some(wire_path),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
} else if let Some((drag_start, dragged)) = &mut self.drag_start {
|
} else if let Some((drag_start, dragged)) = &mut self.drag_start {
|
||||||
if drag_start.start_x != point.x || drag_start.start_y != point.y {
|
if drag_start.start_x != point.x || drag_start.start_y != point.y {
|
||||||
@@ -1321,7 +1324,8 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
|
|||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let (wire, is_stack) = network_interface.vector_wire_from_input(&input, preferences.graph_wire_style, selection_network_path)?;
|
let wire = network_interface.wire_from_input_new(&input, preferences.graph_wire_style, selection_network_path)?;
|
||||||
|
let thick = network_interface.wire_is_thick(&input, selection_network_path);
|
||||||
|
|
||||||
let node_bbox = kurbo::Rect::new(node_bbox[0].x, node_bbox[0].y, node_bbox[1].x, node_bbox[1].y).to_path(DEFAULT_ACCURACY);
|
let node_bbox = kurbo::Rect::new(node_bbox[0].x, node_bbox[0].y, node_bbox[1].x, node_bbox[1].y).to_path(DEFAULT_ACCURACY);
|
||||||
let inside = bezpath_is_inside_bezpath(&wire, &node_bbox, None, None);
|
let inside = bezpath_is_inside_bezpath(&wire, &node_bbox, None, None);
|
||||||
@@ -1330,7 +1334,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
|
|||||||
.segments()
|
.segments()
|
||||||
.any(|segment| node_bbox.segments().filter_map(|segment| segment.as_line()).any(|line| !segment.intersect_line(line).is_empty()));
|
.any(|segment| node_bbox.segments().filter_map(|segment| segment.as_line()).any(|line| !segment.intersect_line(line).is_empty()));
|
||||||
|
|
||||||
(intersect || inside).then_some((input, is_stack))
|
(intersect || inside).then_some((input, thick))
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
@@ -1397,8 +1401,8 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
|
|||||||
self.reordering_export = None;
|
self.reordering_export = None;
|
||||||
self.reordering_import = None;
|
self.reordering_import = None;
|
||||||
responses.add(DocumentMessage::EndTransaction);
|
responses.add(DocumentMessage::EndTransaction);
|
||||||
responses.add(FrontendMessage::UpdateWirePathInProgress { wire_path: None });
|
responses.add(FrontendMessage::UpdateWirePathInProgress { wire_path_in_progress: None });
|
||||||
responses.add(FrontendMessage::UpdateBox { box_selection: None });
|
responses.add(FrontendMessage::UpdateNodeGraphSelectionBox { box_selection: None });
|
||||||
responses.add(FrontendMessage::UpdateImportReorderIndex { index: None });
|
responses.add(FrontendMessage::UpdateImportReorderIndex { index: None });
|
||||||
responses.add(FrontendMessage::UpdateExportReorderIndex { index: None });
|
responses.add(FrontendMessage::UpdateExportReorderIndex { index: None });
|
||||||
self.update_node_graph_hints(responses);
|
self.update_node_graph_hints(responses);
|
||||||
@@ -1601,18 +1605,18 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
|
|||||||
click_targets: Some(network_interface.collect_frontend_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::EndSendClickTargets => responses.add(FrontendMessage::UpdateClickTargets { click_targets: None }),
|
||||||
NodeGraphMessage::UnloadWires => {
|
NodeGraphMessage::UnloadWiresOld => {
|
||||||
for input in network_interface.node_graph_input_connectors(breadcrumb_network_path) {
|
for input in network_interface.node_graph_input_connectors(breadcrumb_network_path) {
|
||||||
network_interface.unload_wire(&input, breadcrumb_network_path);
|
network_interface.unload_wire_old(&input, breadcrumb_network_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
responses.add(FrontendMessage::ClearAllNodeGraphWires);
|
responses.add(FrontendMessage::ClearAllNodeGraphWiresOld);
|
||||||
}
|
}
|
||||||
NodeGraphMessage::SendWires => {
|
NodeGraphMessage::SendWiresOld => {
|
||||||
let wires = self.collect_wires(network_interface, preferences.graph_wire_style, breadcrumb_network_path);
|
let wires = self.collect_wires_old(network_interface, preferences.graph_wire_style, breadcrumb_network_path);
|
||||||
responses.add(FrontendMessage::UpdateNodeGraphWires { wires });
|
responses.add(FrontendMessage::UpdateNodeGraphWiresOld { wires });
|
||||||
}
|
}
|
||||||
NodeGraphMessage::UpdateVisibleNodes => {
|
NodeGraphMessage::UpdateVisibleNodesOld => {
|
||||||
let Some(network_metadata) = network_interface.network_metadata(breadcrumb_network_path) else {
|
let Some(network_metadata) = network_interface.network_metadata(breadcrumb_network_path) else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
@@ -1621,7 +1625,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
|
|||||||
let document_bbox: [DVec2; 2] = viewport_bbox.map(|p| network_metadata.persistent_metadata.navigation_metadata.node_graph_to_viewport.inverse().transform_point2(p));
|
let document_bbox: [DVec2; 2] = viewport_bbox.map(|p| network_metadata.persistent_metadata.navigation_metadata.node_graph_to_viewport.inverse().transform_point2(p));
|
||||||
|
|
||||||
let mut nodes = Vec::new();
|
let mut nodes = Vec::new();
|
||||||
for node_id in &self.frontend_nodes {
|
for node_id in &self.frontend_nodes_old {
|
||||||
let Some(node_bbox) = network_interface.node_bounding_box(node_id, breadcrumb_network_path) else {
|
let Some(node_bbox) = network_interface.node_bounding_box(node_id, breadcrumb_network_path) else {
|
||||||
log::error!("Could not get bbox for node: {node_id:?}");
|
log::error!("Could not get bbox for node: {node_id:?}");
|
||||||
continue;
|
continue;
|
||||||
@@ -1637,32 +1641,60 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
responses.add(FrontendMessage::UpdateVisibleNodes { nodes });
|
responses.add(FrontendMessage::UpdateVisibleNodesOld { nodes });
|
||||||
}
|
}
|
||||||
NodeGraphMessage::SendGraph => {
|
NodeGraphMessage::SendGraph => {
|
||||||
|
if render_native_node_graph {
|
||||||
|
responses.add(NodeGraphMessage::SendGraphNew);
|
||||||
|
} else {
|
||||||
|
responses.add(NodeGraphMessage::SendGraphOld);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
NodeGraphMessage::SendGraphOld => {
|
||||||
responses.add(NodeGraphMessage::UpdateLayerPanel);
|
responses.add(NodeGraphMessage::UpdateLayerPanel);
|
||||||
responses.add(DocumentMessage::DocumentStructureChanged);
|
responses.add(DocumentMessage::DocumentStructureChanged);
|
||||||
responses.add(PropertiesPanelMessage::Refresh);
|
responses.add(PropertiesPanelMessage::Refresh);
|
||||||
if breadcrumb_network_path == selection_network_path && graph_view_overlay_open {
|
if breadcrumb_network_path == selection_network_path && graph_view_overlay_open {
|
||||||
let nodes = self.collect_nodes(network_interface, breadcrumb_network_path);
|
let nodes = self.collect_nodes_old(network_interface, breadcrumb_network_path);
|
||||||
self.frontend_nodes = nodes.iter().map(|node| node.id).collect();
|
self.frontend_nodes_old = nodes.iter().map(|node| node.id).collect();
|
||||||
responses.add(FrontendMessage::UpdateNodeGraphNodes { nodes });
|
responses.add(FrontendMessage::UpdateNodeGraphNodesOld { nodes });
|
||||||
responses.add(NodeGraphMessage::UpdateVisibleNodes);
|
responses.add(NodeGraphMessage::UpdateVisibleNodesOld);
|
||||||
|
|
||||||
let error = self.node_graph_error(network_interface, breadcrumb_network_path);
|
let error = self.node_graph_error(network_interface, breadcrumb_network_path);
|
||||||
responses.add(FrontendMessage::UpdateNodeGraphError { error });
|
responses.add(FrontendMessage::UpdateNodeGraphError { error });
|
||||||
let (layer_widths, chain_widths, has_left_input_wire) = network_interface.collect_layer_widths(breadcrumb_network_path);
|
let (layer_widths, chain_widths, has_left_input_wire) = network_interface.collect_layer_widths_old(breadcrumb_network_path);
|
||||||
|
|
||||||
responses.add(NodeGraphMessage::UpdateImportsExports);
|
responses.add(NodeGraphMessage::UpdateImportsExports);
|
||||||
responses.add(FrontendMessage::UpdateLayerWidths {
|
responses.add(FrontendMessage::UpdateLayerWidthsOld {
|
||||||
layer_widths,
|
layer_widths,
|
||||||
chain_widths,
|
chain_widths,
|
||||||
has_left_input_wire,
|
has_left_input_wire,
|
||||||
});
|
});
|
||||||
responses.add(NodeGraphMessage::SendSelectedNodes);
|
responses.add(NodeGraphMessage::SendSelectedNodesOld);
|
||||||
|
responses.add(NodeGraphMessage::UnloadWiresOld);
|
||||||
|
responses.add(NodeGraphMessage::SendWiresOld);
|
||||||
self.update_node_graph_hints(responses);
|
self.update_node_graph_hints(responses);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
NodeGraphMessage::SendGraphNew => {
|
||||||
|
responses.add(NodeGraphMessage::UpdateLayerPanel);
|
||||||
|
responses.add(DocumentMessage::DocumentStructureChanged);
|
||||||
|
responses.add(PropertiesPanelMessage::Refresh);
|
||||||
|
responses.add(NodeGraphMessage::UpdateActionButtons);
|
||||||
|
// let nodes_to_render = network_interface.collect_nodes_new(&self.node_graph_errors, preferences.graph_wire_style, breadcrumb_network_path);
|
||||||
|
// let previewed_node = network_interface.previewed_node(breadcrumb_network_path);
|
||||||
|
// responses.add(FrontendMessage::UpdateNodeGraphRenderNew {
|
||||||
|
// nodes_to_render,
|
||||||
|
// open: graph_view_overlay_open,
|
||||||
|
// opacity: graph_fade_artwork_percentage,
|
||||||
|
// in_selected_network: selection_network_path == breadcrumb_network_path,
|
||||||
|
// previewed_node,
|
||||||
|
// });
|
||||||
|
responses.add(NodeGraphMessage::UpdateImportsExports);
|
||||||
|
let error = self.node_graph_error(network_interface, breadcrumb_network_path);
|
||||||
|
responses.add(FrontendMessage::UpdateNodeGraphError { error });
|
||||||
|
self.update_node_graph_hints(responses);
|
||||||
|
}
|
||||||
NodeGraphMessage::SetInputValue { node_id, input_index, value } => {
|
NodeGraphMessage::SetInputValue { node_id, input_index, value } => {
|
||||||
let input = NodeInput::value(value, false);
|
let input = NodeInput::value(value, false);
|
||||||
responses.add(NodeGraphMessage::SetInput {
|
responses.add(NodeGraphMessage::SetInput {
|
||||||
@@ -1729,7 +1761,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
responses.add(NodeGraphMessage::SendWires);
|
responses.add(NodeGraphMessage::SendWiresOld);
|
||||||
}
|
}
|
||||||
NodeGraphMessage::ToggleSelectedAsLayersOrNodes => {
|
NodeGraphMessage::ToggleSelectedAsLayersOrNodes => {
|
||||||
let Some(selected_nodes) = network_interface.selected_nodes_in_nested_network(selection_network_path) else {
|
let Some(selected_nodes) = network_interface.selected_nodes_in_nested_network(selection_network_path) else {
|
||||||
@@ -1750,7 +1782,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
|
|||||||
NodeGraphMessage::ShiftNodePosition { node_id, x, y } => {
|
NodeGraphMessage::ShiftNodePosition { node_id, x, y } => {
|
||||||
network_interface.shift_absolute_node_position(&node_id, IVec2::new(x, y), selection_network_path);
|
network_interface.shift_absolute_node_position(&node_id, IVec2::new(x, y), selection_network_path);
|
||||||
|
|
||||||
responses.add(NodeGraphMessage::SendWires);
|
responses.add(NodeGraphMessage::SendWiresOld);
|
||||||
}
|
}
|
||||||
NodeGraphMessage::SetToNodeOrLayer { node_id, is_layer } => {
|
NodeGraphMessage::SetToNodeOrLayer { node_id, is_layer } => {
|
||||||
if is_layer && !network_interface.is_eligible_to_be_layer(&node_id, selection_network_path) {
|
if is_layer && !network_interface.is_eligible_to_be_layer(&node_id, selection_network_path) {
|
||||||
@@ -1764,7 +1796,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
|
|||||||
});
|
});
|
||||||
responses.add(NodeGraphMessage::RunDocumentGraph);
|
responses.add(NodeGraphMessage::RunDocumentGraph);
|
||||||
responses.add(NodeGraphMessage::SendGraph);
|
responses.add(NodeGraphMessage::SendGraph);
|
||||||
responses.add(NodeGraphMessage::SendWires);
|
responses.add(NodeGraphMessage::SendWiresOld);
|
||||||
}
|
}
|
||||||
NodeGraphMessage::SetDisplayName {
|
NodeGraphMessage::SetDisplayName {
|
||||||
node_id,
|
node_id,
|
||||||
@@ -1953,23 +1985,31 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
|
|||||||
nodes: nodes.into_iter().collect::<Vec<_>>(),
|
nodes: nodes.into_iter().collect::<Vec<_>>(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
responses.add(FrontendMessage::UpdateBox { box_selection })
|
responses.add(FrontendMessage::UpdateNodeGraphSelectionBox { box_selection })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
NodeGraphMessage::UpdateImportsExports => {
|
NodeGraphMessage::UpdateImportsExports => {
|
||||||
let imports = network_interface.frontend_imports(breadcrumb_network_path);
|
let imports = network_interface.frontend_imports(preferences.graph_wire_style, breadcrumb_network_path);
|
||||||
let exports = network_interface.frontend_exports(breadcrumb_network_path);
|
let exports = network_interface.frontend_exports(preferences.graph_wire_style, breadcrumb_network_path);
|
||||||
|
|
||||||
let Some((import_position, export_position)) = network_interface.import_export_position(breadcrumb_network_path) else {
|
let Some((import_position, export_position)) = network_interface.import_export_position(breadcrumb_network_path) else {
|
||||||
log::error!("Could not get import export positions");
|
log::error!("Could not get import export positions");
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let import_position = FrontendXY {
|
||||||
|
x: import_position.x,
|
||||||
|
y: import_position.y,
|
||||||
|
};
|
||||||
|
let export_position = FrontendXY {
|
||||||
|
x: export_position.x,
|
||||||
|
y: export_position.y,
|
||||||
|
};
|
||||||
|
|
||||||
// Do not show the add import or add export button in the document network;
|
// Do not show the add import or add export button in the document network;
|
||||||
let add_import_export = !breadcrumb_network_path.is_empty();
|
let add_import_export = !breadcrumb_network_path.is_empty();
|
||||||
|
|
||||||
responses.add(NodeGraphMessage::UpdateVisibleNodes);
|
responses.add(NodeGraphMessage::UpdateVisibleNodesOld);
|
||||||
responses.add(NodeGraphMessage::SendWires);
|
|
||||||
responses.add(FrontendMessage::UpdateImportsExports {
|
responses.add(FrontendMessage::UpdateImportsExports {
|
||||||
imports,
|
imports,
|
||||||
exports,
|
exports,
|
||||||
@@ -1977,6 +2017,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
|
|||||||
export_position,
|
export_position,
|
||||||
add_import_export,
|
add_import_export,
|
||||||
});
|
});
|
||||||
|
responses.add(NodeGraphMessage::SendWiresOld)
|
||||||
}
|
}
|
||||||
|
|
||||||
NodeGraphMessage::UpdateLayerPanel => {
|
NodeGraphMessage::UpdateLayerPanel => {
|
||||||
@@ -2008,19 +2049,19 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
|
|||||||
self.update_graph_bar_right(graph_fade_artwork_percentage, network_interface, breadcrumb_network_path, navigation_handler);
|
self.update_graph_bar_right(graph_fade_artwork_percentage, network_interface, breadcrumb_network_path, navigation_handler);
|
||||||
self.send_node_bar_layout(responses);
|
self.send_node_bar_layout(responses);
|
||||||
}
|
}
|
||||||
NodeGraphMessage::UpdateInSelectedNetwork => responses.add(FrontendMessage::UpdateInSelectedNetwork {
|
NodeGraphMessage::UpdateInSelectedNetworkOld => responses.add(FrontendMessage::UpdateInSelectedNetworkOld {
|
||||||
in_selected_network: selection_network_path == breadcrumb_network_path,
|
in_selected_network: selection_network_path == breadcrumb_network_path,
|
||||||
}),
|
}),
|
||||||
NodeGraphMessage::UpdateHints => {
|
NodeGraphMessage::UpdateHints => {
|
||||||
self.update_node_graph_hints(responses);
|
self.update_node_graph_hints(responses);
|
||||||
}
|
}
|
||||||
NodeGraphMessage::SendSelectedNodes => {
|
NodeGraphMessage::SendSelectedNodesOld => {
|
||||||
let Some(selected_nodes) = network_interface.selected_nodes_in_nested_network(breadcrumb_network_path) else {
|
let Some(selected_nodes) = network_interface.selected_nodes_in_nested_network(breadcrumb_network_path) else {
|
||||||
log::error!("Could not get selected nodes in NodeGraphMessage::SendSelectedNodes");
|
log::error!("Could not get selected nodes in NodeGraphMessage::SendSelectedNodes");
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
responses.add(NodeGraphMessage::UpdateActionButtons);
|
responses.add(NodeGraphMessage::UpdateActionButtons);
|
||||||
responses.add(FrontendMessage::UpdateNodeGraphSelection {
|
responses.add(FrontendMessage::UpdateNodeGraphSelectionOld {
|
||||||
selected: selected_nodes.selected_nodes().cloned().collect::<Vec<_>>(),
|
selected: selected_nodes.selected_nodes().cloned().collect::<Vec<_>>(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -2472,7 +2513,7 @@ impl NodeGraphMessageHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn collect_wires(&mut self, network_interface: &mut NodeNetworkInterface, graph_wire_style: GraphWireStyle, breadcrumb_network_path: &[NodeId]) -> Vec<WirePathUpdate> {
|
fn collect_wires_old(&mut self, network_interface: &mut NodeNetworkInterface, graph_wire_style: GraphWireStyle, breadcrumb_network_path: &[NodeId]) -> Vec<WirePathUpdateOld> {
|
||||||
let mut added_wires = network_interface
|
let mut added_wires = network_interface
|
||||||
.node_graph_input_connectors(breadcrumb_network_path)
|
.node_graph_input_connectors(breadcrumb_network_path)
|
||||||
.iter()
|
.iter()
|
||||||
@@ -2480,24 +2521,24 @@ impl NodeGraphMessageHandler {
|
|||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
let changed_wire_inputs = added_wires.iter().map(|update| (update.id, update.input_index)).collect::<Vec<_>>();
|
let changed_wire_inputs = added_wires.iter().map(|update| (update.id, update.input_index)).collect::<Vec<_>>();
|
||||||
self.frontend_wires.extend(changed_wire_inputs);
|
self.frontend_wires_old.extend(changed_wire_inputs);
|
||||||
|
|
||||||
let mut orphaned_wire_inputs = self.frontend_wires.clone();
|
let mut orphaned_wire_inputs = self.frontend_wires_old.clone();
|
||||||
self.frontend_wires = network_interface
|
self.frontend_wires_old = network_interface
|
||||||
.node_graph_wire_inputs(breadcrumb_network_path)
|
.node_graph_wire_inputs(breadcrumb_network_path)
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|visible_wire_input| orphaned_wire_inputs.take(visible_wire_input))
|
.filter_map(|visible_wire_input| orphaned_wire_inputs.take(visible_wire_input))
|
||||||
.collect::<HashSet<_>>();
|
.collect::<HashSet<_>>();
|
||||||
added_wires.extend(orphaned_wire_inputs.into_iter().map(|(id, input_index)| WirePathUpdate {
|
added_wires.extend(orphaned_wire_inputs.into_iter().map(|(id, input_index)| WirePathUpdateOld {
|
||||||
id,
|
id,
|
||||||
input_index,
|
input_index,
|
||||||
wire_path_update: None,
|
wire_path_update: None,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
if let Some(wire_to_root) = network_interface.wire_to_root(graph_wire_style, breadcrumb_network_path) {
|
if let Some(wire_to_root) = network_interface.wire_to_root_old(graph_wire_style, breadcrumb_network_path) {
|
||||||
added_wires.push(wire_to_root);
|
added_wires.push(wire_to_root);
|
||||||
} else {
|
} else {
|
||||||
added_wires.push(WirePathUpdate {
|
added_wires.push(WirePathUpdateOld {
|
||||||
id: NodeId(u64::MAX),
|
id: NodeId(u64::MAX),
|
||||||
input_index: u32::MAX as usize,
|
input_index: u32::MAX as usize,
|
||||||
wire_path_update: None,
|
wire_path_update: None,
|
||||||
@@ -2507,7 +2548,7 @@ impl NodeGraphMessageHandler {
|
|||||||
added_wires
|
added_wires
|
||||||
}
|
}
|
||||||
|
|
||||||
fn collect_nodes(&self, network_interface: &mut NodeNetworkInterface, breadcrumb_network_path: &[NodeId]) -> Vec<FrontendNode> {
|
fn collect_nodes_old(&self, network_interface: &mut NodeNetworkInterface, breadcrumb_network_path: &[NodeId]) -> Vec<FrontendNodeOld> {
|
||||||
let Some(network) = network_interface.nested_network(breadcrumb_network_path) else {
|
let Some(network) = network_interface.nested_network(breadcrumb_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();
|
||||||
@@ -2520,18 +2561,18 @@ impl NodeGraphMessageHandler {
|
|||||||
.input_from_connector(&primary_input_connector, breadcrumb_network_path)
|
.input_from_connector(&primary_input_connector, breadcrumb_network_path)
|
||||||
.is_some_and(|input| input.is_exposed())
|
.is_some_and(|input| input.is_exposed())
|
||||||
{
|
{
|
||||||
network_interface.frontend_input_from_connector(&primary_input_connector, breadcrumb_network_path)
|
network_interface.frontend_input_from_connector_old(&primary_input_connector, breadcrumb_network_path)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
let exposed_inputs = (1..network_interface.number_of_inputs(&node_id, breadcrumb_network_path))
|
let exposed_inputs = (1..network_interface.number_of_inputs(&node_id, breadcrumb_network_path))
|
||||||
.filter_map(|input_index| network_interface.frontend_input_from_connector(&InputConnector::node(node_id, input_index), breadcrumb_network_path))
|
.filter_map(|input_index| network_interface.frontend_input_from_connector_old(&InputConnector::node(node_id, input_index), breadcrumb_network_path))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let primary_output = network_interface.frontend_output_from_connector(&OutputConnector::node(node_id, 0), breadcrumb_network_path);
|
let primary_output = network_interface.frontend_output_from_connector_old(&OutputConnector::node(node_id, 0), breadcrumb_network_path);
|
||||||
|
|
||||||
let exposed_outputs = (1..network_interface.number_of_outputs(&node_id, breadcrumb_network_path))
|
let exposed_outputs = (1..network_interface.number_of_outputs(&node_id, breadcrumb_network_path))
|
||||||
.filter_map(|output_index| network_interface.frontend_output_from_connector(&OutputConnector::node(node_id, output_index), breadcrumb_network_path))
|
.filter_map(|output_index| network_interface.frontend_output_from_connector_old(&OutputConnector::node(node_id, output_index), breadcrumb_network_path))
|
||||||
.collect();
|
.collect();
|
||||||
let (primary_output_connected_to_layer, primary_input_connected_to_layer) = if network_interface.is_layer(&node_id, breadcrumb_network_path) {
|
let (primary_output_connected_to_layer, primary_input_connected_to_layer) = if network_interface.is_layer(&node_id, breadcrumb_network_path) {
|
||||||
(
|
(
|
||||||
@@ -2555,7 +2596,7 @@ impl NodeGraphMessageHandler {
|
|||||||
|
|
||||||
let locked = network_interface.is_locked(&node_id, breadcrumb_network_path);
|
let locked = network_interface.is_locked(&node_id, breadcrumb_network_path);
|
||||||
|
|
||||||
nodes.push(FrontendNode {
|
nodes.push(FrontendNodeOld {
|
||||||
id: node_id,
|
id: node_id,
|
||||||
is_layer: network_interface
|
is_layer: network_interface
|
||||||
.node_metadata(&node_id, breadcrumb_network_path)
|
.node_metadata(&node_id, breadcrumb_network_path)
|
||||||
@@ -2774,8 +2815,8 @@ impl Default for NodeGraphMessageHandler {
|
|||||||
reordering_export: None,
|
reordering_export: None,
|
||||||
reordering_import: None,
|
reordering_import: None,
|
||||||
end_index: None,
|
end_index: None,
|
||||||
frontend_nodes: Vec::new(),
|
frontend_nodes_old: Vec::new(),
|
||||||
frontend_wires: HashSet::new(),
|
frontend_wires_old: HashSet::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
#![allow(clippy::too_many_arguments)]
|
#![allow(clippy::too_many_arguments)]
|
||||||
|
|
||||||
use super::document_node_definitions::{NODE_OVERRIDES, NodePropertiesContext};
|
use super::document_node_definitions::{NODE_OVERRIDES, NodePropertiesContext};
|
||||||
use super::utility_types::FrontendGraphDataType;
|
|
||||||
use crate::messages::layout::utility_types::widget_prelude::*;
|
use crate::messages::layout::utility_types::widget_prelude::*;
|
||||||
use crate::messages::portfolio::document::utility_types::network_interface::InputConnector;
|
use crate::messages::portfolio::document::utility_types::network_interface::InputConnector;
|
||||||
use crate::messages::prelude::*;
|
use crate::messages::prelude::*;
|
||||||
@@ -14,6 +13,7 @@ use graph_craft::{Type, concrete};
|
|||||||
use graphene_std::NodeInputDecleration;
|
use graphene_std::NodeInputDecleration;
|
||||||
use graphene_std::animation::RealTimeMode;
|
use graphene_std::animation::RealTimeMode;
|
||||||
use graphene_std::extract_xy::XY;
|
use graphene_std::extract_xy::XY;
|
||||||
|
use graphene_std::node_graph_overlay::types::FrontendGraphDataType;
|
||||||
use graphene_std::path_bool::BooleanOperation;
|
use graphene_std::path_bool::BooleanOperation;
|
||||||
use graphene_std::raster::curve::Curve;
|
use graphene_std::raster::curve::Curve;
|
||||||
use graphene_std::raster::{
|
use graphene_std::raster::{
|
||||||
|
|||||||
@@ -1,50 +1,10 @@
|
|||||||
use glam::{DVec2, IVec2};
|
use glam::IVec2;
|
||||||
use graph_craft::document::NodeId;
|
use graph_craft::document::NodeId;
|
||||||
use graph_craft::document::value::TaggedValue;
|
use graphene_std::node_graph_overlay::types::{FrontendGraphDataType, FrontendGraphInputNew, FrontendGraphOutputNew, FrontendXY};
|
||||||
use graphene_std::Type;
|
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Hash, serde::Serialize, serde::Deserialize, specta::Type)]
|
#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize, specta::Type)]
|
||||||
pub enum FrontendGraphDataType {
|
pub struct FrontendGraphInputOld {
|
||||||
#[default]
|
|
||||||
General,
|
|
||||||
Number,
|
|
||||||
Artboard,
|
|
||||||
Graphic,
|
|
||||||
Raster,
|
|
||||||
Vector,
|
|
||||||
Color,
|
|
||||||
Gradient,
|
|
||||||
Typography,
|
|
||||||
Invalid,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FrontendGraphDataType {
|
|
||||||
pub fn from_type(input: &Type) -> Self {
|
|
||||||
match TaggedValue::from_type_or_none(input) {
|
|
||||||
TaggedValue::U32(_)
|
|
||||||
| TaggedValue::U64(_)
|
|
||||||
| TaggedValue::F32(_)
|
|
||||||
| TaggedValue::F64(_)
|
|
||||||
| TaggedValue::DVec2(_)
|
|
||||||
| TaggedValue::F64Array4(_)
|
|
||||||
| TaggedValue::VecF64(_)
|
|
||||||
| TaggedValue::VecDVec2(_)
|
|
||||||
| TaggedValue::DAffine2(_) => Self::Number,
|
|
||||||
TaggedValue::Artboard(_) => Self::Artboard,
|
|
||||||
TaggedValue::Graphic(_) => Self::Graphic,
|
|
||||||
TaggedValue::Raster(_) => Self::Raster,
|
|
||||||
TaggedValue::Vector(_) => Self::Vector,
|
|
||||||
TaggedValue::Color(_) => Self::Color,
|
|
||||||
TaggedValue::Gradient(_) | TaggedValue::GradientStops(_) | TaggedValue::GradientTable(_) => Self::Gradient,
|
|
||||||
TaggedValue::String(_) | TaggedValue::VecString(_) => Self::Typography,
|
|
||||||
_ => Self::General,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize, specta::Type)]
|
|
||||||
pub struct FrontendGraphInput {
|
|
||||||
#[serde(rename = "dataType")]
|
#[serde(rename = "dataType")]
|
||||||
pub data_type: FrontendGraphDataType,
|
pub data_type: FrontendGraphDataType,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
@@ -58,8 +18,8 @@ pub struct FrontendGraphInput {
|
|||||||
pub connected_to: String,
|
pub connected_to: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize, specta::Type)]
|
#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize, specta::Type)]
|
||||||
pub struct FrontendGraphOutput {
|
pub struct FrontendGraphOutputOld {
|
||||||
#[serde(rename = "dataType")]
|
#[serde(rename = "dataType")]
|
||||||
pub data_type: FrontendGraphDataType,
|
pub data_type: FrontendGraphDataType,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
@@ -72,8 +32,8 @@ pub struct FrontendGraphOutput {
|
|||||||
pub connected_to: Vec<String>,
|
pub connected_to: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize, specta::Type)]
|
#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize, specta::Type)]
|
||||||
pub struct FrontendNode {
|
pub struct FrontendNodeOld {
|
||||||
pub id: graph_craft::document::NodeId,
|
pub id: graph_craft::document::NodeId,
|
||||||
#[serde(rename = "isLayer")]
|
#[serde(rename = "isLayer")]
|
||||||
pub is_layer: bool,
|
pub is_layer: bool,
|
||||||
@@ -83,13 +43,13 @@ pub struct FrontendNode {
|
|||||||
#[serde(rename = "displayName")]
|
#[serde(rename = "displayName")]
|
||||||
pub display_name: String,
|
pub display_name: String,
|
||||||
#[serde(rename = "primaryInput")]
|
#[serde(rename = "primaryInput")]
|
||||||
pub primary_input: Option<FrontendGraphInput>,
|
pub primary_input: Option<FrontendGraphInputOld>,
|
||||||
#[serde(rename = "exposedInputs")]
|
#[serde(rename = "exposedInputs")]
|
||||||
pub exposed_inputs: Vec<FrontendGraphInput>,
|
pub exposed_inputs: Vec<FrontendGraphInputOld>,
|
||||||
#[serde(rename = "primaryOutput")]
|
#[serde(rename = "primaryOutput")]
|
||||||
pub primary_output: Option<FrontendGraphOutput>,
|
pub primary_output: Option<FrontendGraphOutputOld>,
|
||||||
#[serde(rename = "exposedOutputs")]
|
#[serde(rename = "exposedOutputs")]
|
||||||
pub exposed_outputs: Vec<FrontendGraphOutput>,
|
pub exposed_outputs: Vec<FrontendGraphOutputOld>,
|
||||||
#[serde(rename = "primaryOutputConnectedToLayer")]
|
#[serde(rename = "primaryOutputConnectedToLayer")]
|
||||||
pub primary_output_connected_to_layer: bool,
|
pub primary_output_connected_to_layer: bool,
|
||||||
#[serde(rename = "primaryInputConnectedToLayer")]
|
#[serde(rename = "primaryInputConnectedToLayer")]
|
||||||
@@ -100,6 +60,26 @@ pub struct FrontendNode {
|
|||||||
pub previewed: bool,
|
pub previewed: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize, specta::Type)]
|
||||||
|
pub struct FrontendExport {
|
||||||
|
pub port: FrontendGraphInputNew,
|
||||||
|
pub wire: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Default, PartialEq, serde::Serialize, serde::Deserialize, specta::Type)]
|
||||||
|
pub struct FrontendExports {
|
||||||
|
/// If the primary export is not visible, then it is None.
|
||||||
|
pub exports: Vec<Option<FrontendExport>>,
|
||||||
|
#[serde(rename = "previewWire")]
|
||||||
|
pub preview_wire: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize, specta::Type)]
|
||||||
|
pub struct FrontendImport {
|
||||||
|
pub port: FrontendGraphOutputNew,
|
||||||
|
pub wires: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
#[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>,
|
||||||
@@ -207,22 +187,3 @@ pub struct NodeGraphError {
|
|||||||
pub position: FrontendXY,
|
pub position: FrontendXY,
|
||||||
pub error: String,
|
pub error: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Stores node graph coordinates which are then transformed in svelte based on the node graph transform
|
|
||||||
#[derive(Clone, Debug, PartialEq, Default, serde::Serialize, serde::Deserialize, specta::Type)]
|
|
||||||
pub struct FrontendXY {
|
|
||||||
pub x: i32,
|
|
||||||
pub y: i32,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<DVec2> for FrontendXY {
|
|
||||||
fn from(v: DVec2) -> Self {
|
|
||||||
FrontendXY { x: v.x as i32, y: v.y as i32 }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<IVec2> for FrontendXY {
|
|
||||||
fn from(v: IVec2) -> Self {
|
|
||||||
FrontendXY { x: v.x as i32, y: v.y as i32 }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,16 +1,18 @@
|
|||||||
mod deserialization;
|
mod deserialization;
|
||||||
mod memo_network;
|
mod memo_network;
|
||||||
|
pub mod node_graph;
|
||||||
|
pub mod old_node_graph_render;
|
||||||
mod resolved_types;
|
mod resolved_types;
|
||||||
|
|
||||||
use super::document_metadata::{DocumentMetadata, LayerNodeIdentifier, NodeRelations};
|
use super::document_metadata::{DocumentMetadata, LayerNodeIdentifier, NodeRelations};
|
||||||
use super::misc::PTZ;
|
use super::misc::PTZ;
|
||||||
use super::nodes::SelectedNodes;
|
use super::nodes::SelectedNodes;
|
||||||
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};
|
use crate::consts::GRID_SIZE;
|
||||||
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::{DocumentNodeDefinition, resolve_document_node_type};
|
use crate::messages::portfolio::document::node_graph::document_node_definitions::{DocumentNodeDefinition, resolve_document_node_type};
|
||||||
use crate::messages::portfolio::document::node_graph::utility_types::{Direction, FrontendClickTargets, FrontendGraphDataType, FrontendGraphInput, FrontendGraphOutput};
|
use crate::messages::portfolio::document::node_graph::utility_types::{Direction, FrontendClickTargets};
|
||||||
use crate::messages::portfolio::document::utility_types::network_interface::resolved_types::ResolvedDocumentNodeTypes;
|
use crate::messages::portfolio::document::utility_types::network_interface::resolved_types::ResolvedDocumentNodeTypes;
|
||||||
use crate::messages::portfolio::document::utility_types::wires::{GraphWireStyle, WirePath, WirePathUpdate, build_vector_wire};
|
use crate::messages::portfolio::document::utility_types::wires::WirePathUpdateOld;
|
||||||
use crate::messages::tool::common_functionality::graph_modification_utils;
|
use crate::messages::tool::common_functionality::graph_modification_utils;
|
||||||
use crate::messages::tool::tool_messages::tool_prelude::NumberInputMode;
|
use crate::messages::tool::tool_messages::tool_prelude::NumberInputMode;
|
||||||
use deserialization::deserialize_node_persistent_metadata;
|
use deserialization::deserialize_node_persistent_metadata;
|
||||||
@@ -24,7 +26,6 @@ use graphene_std::subpath::Subpath;
|
|||||||
use graphene_std::transform::Footprint;
|
use graphene_std::transform::Footprint;
|
||||||
use graphene_std::vector::click_target::{ClickTarget, ClickTargetType};
|
use graphene_std::vector::click_target::{ClickTarget, ClickTargetType};
|
||||||
use graphene_std::vector::{PointId, Vector, VectorModificationType};
|
use graphene_std::vector::{PointId, Vector, VectorModificationType};
|
||||||
use kurbo::BezPath;
|
|
||||||
use memo_network::MemoNetwork;
|
use memo_network::MemoNetwork;
|
||||||
use serde_json::{Value, json};
|
use serde_json::{Value, json};
|
||||||
use std::collections::{HashMap, HashSet, VecDeque};
|
use std::collections::{HashMap, HashSet, VecDeque};
|
||||||
@@ -236,31 +237,6 @@ impl NodeNetworkInterface {
|
|||||||
layers
|
layers
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn chain_width(&self, node_id: &NodeId, network_path: &[NodeId]) -> u32 {
|
|
||||||
if self.number_of_displayed_inputs(node_id, network_path) > 1 {
|
|
||||||
let mut last_chain_node_distance = 0u32;
|
|
||||||
// Iterate upstream from the layer, and get the number of nodes distance to the last node with Position::Chain
|
|
||||||
for (index, node_id) in self
|
|
||||||
.upstream_flow_back_from_nodes(vec![*node_id], network_path, FlowType::HorizontalPrimaryOutputFlow)
|
|
||||||
.skip(1)
|
|
||||||
.enumerate()
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
{
|
|
||||||
// Check if the node is positioned as a chain
|
|
||||||
if self.is_chain(&node_id, network_path) {
|
|
||||||
last_chain_node_distance = (index as u32) + 1;
|
|
||||||
} else {
|
|
||||||
return last_chain_node_distance * 7 + 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
last_chain_node_distance * 7 + 1
|
|
||||||
} else {
|
|
||||||
// Layer with no inputs has no chain
|
|
||||||
0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Check if the specified node id is connected to the output
|
/// Check if the specified node id is connected to the output
|
||||||
pub fn connected_to_output(&self, target_node_id: &NodeId, network_path: &[NodeId]) -> bool {
|
pub fn connected_to_output(&self, target_node_id: &NodeId, network_path: &[NodeId]) -> bool {
|
||||||
let Some(network) = self.nested_network(network_path) else {
|
let Some(network) = self.nested_network(network_path) else {
|
||||||
@@ -509,245 +485,6 @@ impl NodeNetworkInterface {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn frontend_imports(&mut self, network_path: &[NodeId]) -> Vec<Option<FrontendGraphOutput>> {
|
|
||||||
match network_path.split_last() {
|
|
||||||
Some((node_id, encapsulating_network_path)) => {
|
|
||||||
let Some(node) = self.document_node(node_id, encapsulating_network_path) else {
|
|
||||||
log::error!("Could not get node {node_id} in network {encapsulating_network_path:?}");
|
|
||||||
return Vec::new();
|
|
||||||
};
|
|
||||||
let mut frontend_imports = (0..node.inputs.len())
|
|
||||||
.map(|import_index| self.frontend_output_from_connector(&OutputConnector::Import(import_index), network_path))
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
if frontend_imports.is_empty() {
|
|
||||||
frontend_imports.push(None);
|
|
||||||
}
|
|
||||||
frontend_imports
|
|
||||||
}
|
|
||||||
// In the document network display no imports
|
|
||||||
None => Vec::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn frontend_exports(&mut self, network_path: &[NodeId]) -> Vec<Option<FrontendGraphInput>> {
|
|
||||||
let Some(network) = self.nested_network(network_path) else { return Vec::new() };
|
|
||||||
let mut frontend_exports = ((0..network.exports.len()).map(|export_index| self.frontend_input_from_connector(&InputConnector::Export(export_index), network_path))).collect::<Vec<_>>();
|
|
||||||
if frontend_exports.is_empty() {
|
|
||||||
frontend_exports.push(None);
|
|
||||||
}
|
|
||||||
frontend_exports
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn import_export_position(&mut self, network_path: &[NodeId]) -> Option<(IVec2, IVec2)> {
|
|
||||||
let Some(all_nodes_bounding_box) = self.all_nodes_bounding_box(network_path).cloned() else {
|
|
||||||
log::error!("Could not get all nodes bounding box in load_export_ports");
|
|
||||||
return None;
|
|
||||||
};
|
|
||||||
let Some(network) = self.nested_network(network_path) else {
|
|
||||||
log::error!("Could not get current network in load_export_ports");
|
|
||||||
return None;
|
|
||||||
};
|
|
||||||
|
|
||||||
let Some(network_metadata) = self.network_metadata(network_path) else {
|
|
||||||
log::error!("Could not get nested network_metadata in load_export_ports");
|
|
||||||
return None;
|
|
||||||
};
|
|
||||||
let node_graph_to_viewport = network_metadata.persistent_metadata.navigation_metadata.node_graph_to_viewport;
|
|
||||||
let target_viewport_top_left = DVec2::new(IMPORTS_TO_LEFT_EDGE_PIXEL_GAP as f64, IMPORTS_TO_TOP_EDGE_PIXEL_GAP as f64);
|
|
||||||
|
|
||||||
let node_graph_pixel_offset_top_left = node_graph_to_viewport.inverse().transform_point2(target_viewport_top_left);
|
|
||||||
|
|
||||||
// A 5x5 grid offset from the top left corner
|
|
||||||
let node_graph_grid_space_offset_top_left = node_graph_to_viewport.inverse().transform_point2(DVec2::ZERO) + DVec2::new(5. * GRID_SIZE as f64, 4. * GRID_SIZE as f64);
|
|
||||||
|
|
||||||
// The inner bound of the import is the highest/furthest left of the two offsets
|
|
||||||
let top_left_inner_bound = DVec2::new(
|
|
||||||
node_graph_pixel_offset_top_left.x.min(node_graph_grid_space_offset_top_left.x),
|
|
||||||
node_graph_pixel_offset_top_left.y.min(node_graph_grid_space_offset_top_left.y),
|
|
||||||
);
|
|
||||||
|
|
||||||
let offset_from_top_left = if network
|
|
||||||
.exports
|
|
||||||
.first()
|
|
||||||
.is_some_and(|export| export.as_node().is_some_and(|export_node| self.is_layer(&export_node, network_path)))
|
|
||||||
{
|
|
||||||
DVec2::new(-4. * GRID_SIZE as f64, -2. * GRID_SIZE as f64)
|
|
||||||
} else {
|
|
||||||
DVec2::new(-4. * GRID_SIZE as f64, 0.)
|
|
||||||
};
|
|
||||||
|
|
||||||
let bounding_box_top_left = DVec2::new((all_nodes_bounding_box[0].x / 24. + 0.5).floor() * 24., (all_nodes_bounding_box[0].y / 24. + 0.5).floor() * 24.) + offset_from_top_left;
|
|
||||||
let import_top_left = DVec2::new(top_left_inner_bound.x.min(bounding_box_top_left.x), top_left_inner_bound.y.min(bounding_box_top_left.y));
|
|
||||||
let rounded_import_top_left = DVec2::new((import_top_left.x / 24.).round() * 24., (import_top_left.y / 24.).round() * 24.);
|
|
||||||
|
|
||||||
let viewport_width = network_metadata.persistent_metadata.navigation_metadata.node_graph_width;
|
|
||||||
|
|
||||||
let target_viewport_top_right = DVec2::new(viewport_width - EXPORTS_TO_RIGHT_EDGE_PIXEL_GAP as f64, EXPORTS_TO_TOP_EDGE_PIXEL_GAP as f64);
|
|
||||||
|
|
||||||
// An offset from the right edge in viewport pixels
|
|
||||||
let node_graph_pixel_offset_top_right = node_graph_to_viewport.inverse().transform_point2(target_viewport_top_right);
|
|
||||||
|
|
||||||
// A 5x5 grid offset from the right corner
|
|
||||||
let node_graph_grid_space_offset_top_right = node_graph_to_viewport.inverse().transform_point2(DVec2::new(viewport_width, 0.)) + DVec2::new(-5. * GRID_SIZE as f64, 4. * GRID_SIZE as f64);
|
|
||||||
|
|
||||||
// The inner bound of the export is the highest/furthest right of the two offsets.
|
|
||||||
// When zoomed out this keeps it a constant grid space away from the edge, but when zoomed in it prevents the exports from getting too far in
|
|
||||||
let top_right_inner_bound = DVec2::new(
|
|
||||||
node_graph_pixel_offset_top_right.x.max(node_graph_grid_space_offset_top_right.x),
|
|
||||||
node_graph_pixel_offset_top_right.y.min(node_graph_grid_space_offset_top_right.y),
|
|
||||||
);
|
|
||||||
|
|
||||||
let offset_from_top_right = if network
|
|
||||||
.exports
|
|
||||||
.first()
|
|
||||||
.is_some_and(|export| export.as_node().is_some_and(|export_node| self.is_layer(&export_node, network_path)))
|
|
||||||
{
|
|
||||||
DVec2::new(2. * GRID_SIZE as f64, -2. * GRID_SIZE as f64)
|
|
||||||
} else {
|
|
||||||
DVec2::new(4. * GRID_SIZE as f64, 0.)
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut bounding_box_top_right = DVec2::new((all_nodes_bounding_box[1].x / 24. + 0.5).floor() * 24., (all_nodes_bounding_box[0].y / 24. + 0.5).floor() * 24.);
|
|
||||||
bounding_box_top_right += offset_from_top_right;
|
|
||||||
let export_top_right = DVec2::new(top_right_inner_bound.x.max(bounding_box_top_right.x), top_right_inner_bound.y.min(bounding_box_top_right.y));
|
|
||||||
let rounded_export_top_right = DVec2::new((export_top_right.x / 24.).round() * 24., (export_top_right.y / 24.).round() * 24.);
|
|
||||||
|
|
||||||
Some((rounded_import_top_left.as_ivec2(), rounded_export_top_right.as_ivec2()))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns None if there is an error, it is a hidden primary export, or a hidden input
|
|
||||||
pub fn frontend_input_from_connector(&mut self, input_connector: &InputConnector, network_path: &[NodeId]) -> Option<FrontendGraphInput> {
|
|
||||||
// Return None if it is a hidden input
|
|
||||||
if self.input_from_connector(input_connector, network_path).is_some_and(|input| !input.is_exposed()) {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
let input_type = self.input_type(input_connector, network_path);
|
|
||||||
let data_type = input_type.displayed_type();
|
|
||||||
let resolved_type = input_type.resolved_type_node_string();
|
|
||||||
|
|
||||||
let connected_to = self
|
|
||||||
.upstream_output_connector(input_connector, network_path)
|
|
||||||
.map(|output_connector| match output_connector {
|
|
||||||
OutputConnector::Node { node_id, output_index } => {
|
|
||||||
let mut name = self.display_name(&node_id, network_path);
|
|
||||||
if cfg!(debug_assertions) {
|
|
||||||
name.push_str(&format!(" (id: {node_id})"));
|
|
||||||
}
|
|
||||||
format!("{name} output {output_index}")
|
|
||||||
}
|
|
||||||
OutputConnector::Import(import_index) => format!("Import index {import_index}"),
|
|
||||||
})
|
|
||||||
.unwrap_or("nothing".to_string());
|
|
||||||
|
|
||||||
let (name, description) = match input_connector {
|
|
||||||
InputConnector::Node { node_id, input_index } => self.displayed_input_name_and_description(node_id, *input_index, network_path),
|
|
||||||
InputConnector::Export(export_index) => {
|
|
||||||
// Get export name from parent node metadata input, which must match the number of exports.
|
|
||||||
// Empty string means to use type, or "Export + index" if type is empty determined
|
|
||||||
let export_name = if network_path.is_empty() {
|
|
||||||
"Canvas".to_string()
|
|
||||||
} else {
|
|
||||||
self.encapsulating_node_metadata(network_path)
|
|
||||||
.and_then(|encapsulating_metadata| encapsulating_metadata.persistent_metadata.output_names.get(*export_index).cloned())
|
|
||||||
.unwrap_or_default()
|
|
||||||
};
|
|
||||||
|
|
||||||
let export_name = if !export_name.is_empty() {
|
|
||||||
export_name
|
|
||||||
} else if let Some(export_type_name) = input_type.compiled_nested_type().map(|nested| nested.to_string()) {
|
|
||||||
export_type_name
|
|
||||||
} else {
|
|
||||||
format!("Export index {}", export_index)
|
|
||||||
};
|
|
||||||
|
|
||||||
(export_name, String::new())
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Some(FrontendGraphInput {
|
|
||||||
data_type,
|
|
||||||
resolved_type,
|
|
||||||
name,
|
|
||||||
description,
|
|
||||||
valid_types: self.potential_valid_input_types(input_connector, network_path).iter().map(|ty| ty.to_string()).collect(),
|
|
||||||
connected_to,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns None if there is an error, it is the document network, a hidden primary output or import
|
|
||||||
pub fn frontend_output_from_connector(&mut self, output_connector: &OutputConnector, network_path: &[NodeId]) -> Option<FrontendGraphOutput> {
|
|
||||||
let output_type = self.output_type(output_connector, network_path);
|
|
||||||
|
|
||||||
let (name, description) = match output_connector {
|
|
||||||
OutputConnector::Node { node_id, output_index } => {
|
|
||||||
// Do not display the primary output port for a node if it is a network node with a hidden primary export
|
|
||||||
if *output_index == 0 && self.hidden_primary_output(node_id, network_path) {
|
|
||||||
return None;
|
|
||||||
};
|
|
||||||
// Get the output name from the interior network export name
|
|
||||||
let node_metadata = self.node_metadata(node_id, network_path)?;
|
|
||||||
let output_name = node_metadata.persistent_metadata.output_names.get(*output_index).cloned().unwrap_or_default();
|
|
||||||
|
|
||||||
let output_name = if !output_name.is_empty() { output_name } else { output_type.resolved_type_node_string() };
|
|
||||||
(output_name, String::new())
|
|
||||||
}
|
|
||||||
OutputConnector::Import(import_index) => {
|
|
||||||
// Get the import name from the encapsulating node input metadata
|
|
||||||
let Some((encapsulating_node_id, encapsulating_path)) = network_path.split_last() else {
|
|
||||||
// Return None if it is an import in the document network
|
|
||||||
return None;
|
|
||||||
};
|
|
||||||
// Return None if the primary input is hidden and this is the primary import
|
|
||||||
if *import_index == 0 && self.hidden_primary_import(network_path) {
|
|
||||||
return None;
|
|
||||||
};
|
|
||||||
let (import_name, description) = self.displayed_input_name_and_description(encapsulating_node_id, *import_index, encapsulating_path);
|
|
||||||
|
|
||||||
let import_name = if !import_name.is_empty() {
|
|
||||||
import_name
|
|
||||||
} else if let Some(import_type_name) = output_type.compiled_nested_type().map(|nested| nested.to_string()) {
|
|
||||||
import_type_name
|
|
||||||
} else {
|
|
||||||
format!("Import index {}", import_index)
|
|
||||||
};
|
|
||||||
|
|
||||||
(import_name, description)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let data_type = output_type.displayed_type();
|
|
||||||
let resolved_type = output_type.resolved_type_node_string();
|
|
||||||
let mut connected_to = self
|
|
||||||
.outward_wires(network_path)
|
|
||||||
.and_then(|outward_wires| outward_wires.get(output_connector))
|
|
||||||
.cloned()
|
|
||||||
.unwrap_or_default()
|
|
||||||
.iter()
|
|
||||||
.map(|input| match input {
|
|
||||||
InputConnector::Node { node_id, input_index } => {
|
|
||||||
let mut name = self.display_name(node_id, network_path);
|
|
||||||
if cfg!(debug_assertions) {
|
|
||||||
name.push_str(&format!(" (id: {node_id})"));
|
|
||||||
}
|
|
||||||
format!("{name} input {input_index}")
|
|
||||||
}
|
|
||||||
InputConnector::Export(export_index) => format!("Export index {export_index}"),
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
if connected_to.is_empty() {
|
|
||||||
connected_to.push("nothing".to_string());
|
|
||||||
}
|
|
||||||
|
|
||||||
Some(FrontendGraphOutput {
|
|
||||||
data_type,
|
|
||||||
resolved_type,
|
|
||||||
name,
|
|
||||||
description,
|
|
||||||
connected_to,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn height_from_click_target(&mut self, node_id: &NodeId, network_path: &[NodeId]) -> Option<u32> {
|
pub fn height_from_click_target(&mut self, node_id: &NodeId, network_path: &[NodeId]) -> Option<u32> {
|
||||||
let mut node_height: Option<u32> = self
|
let mut node_height: Option<u32> = self
|
||||||
.node_click_targets(node_id, network_path)
|
.node_click_targets(node_id, network_path)
|
||||||
@@ -950,7 +687,7 @@ impl NodeNetworkInterface {
|
|||||||
Some(&metadata.persistent_metadata)
|
Some(&metadata.persistent_metadata)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn transient_input_metadata(&self, node_id: &NodeId, index: usize, network_path: &[NodeId]) -> Option<&InputTransientMetadata> {
|
fn transient_input_metadata_old(&self, node_id: &NodeId, index: usize, network_path: &[NodeId]) -> Option<&InputTransientMetadata> {
|
||||||
let metadata = self
|
let metadata = self
|
||||||
.node_metadata(node_id, network_path)
|
.node_metadata(node_id, network_path)
|
||||||
.and_then(|node_metadata| node_metadata.persistent_metadata.input_metadata.get(index))?;
|
.and_then(|node_metadata| node_metadata.persistent_metadata.input_metadata.get(index))?;
|
||||||
@@ -1050,25 +787,6 @@ impl NodeNetworkInterface {
|
|||||||
node_metadata.persistent_metadata.is_layer()
|
node_metadata.persistent_metadata.is_layer()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn primary_output_connected_to_layer(&mut self, node_id: &NodeId, network_path: &[NodeId]) -> bool {
|
|
||||||
let Some(outward_wires) = self.outward_wires(network_path) else {
|
|
||||||
log::error!("Could not get outward_wires in primary_output_connected_to_layer");
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
let Some(downstream_connectors) = outward_wires.get(&OutputConnector::node(*node_id, 0)) else {
|
|
||||||
log::error!("Could not get downstream_connectors in primary_output_connected_to_layer");
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
let downstream_nodes = downstream_connectors.iter().filter_map(|connector| connector.node_id()).collect::<Vec<_>>();
|
|
||||||
downstream_nodes.iter().any(|node_id| self.is_layer(node_id, network_path))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn primary_input_connected_to_layer(&mut self, node_id: &NodeId, network_path: &[NodeId]) -> bool {
|
|
||||||
self.input_from_connector(&InputConnector::node(*node_id, 0), network_path)
|
|
||||||
.and_then(|input| input.as_node())
|
|
||||||
.is_some_and(|node_id| self.is_layer(&node_id, network_path))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn hidden_primary_export(&self, network_path: &[NodeId]) -> bool {
|
pub fn hidden_primary_export(&self, network_path: &[NodeId]) -> bool {
|
||||||
let Some((node_id, network_path)) = network_path.split_last() else {
|
let Some((node_id, network_path)) = network_path.split_last() else {
|
||||||
// The document network does not have a hidden primary export
|
// The document network does not have a hidden primary export
|
||||||
@@ -1834,30 +1552,7 @@ impl NodeNetworkInterface {
|
|||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
network_metadata.transient_metadata.import_export_ports.unload();
|
network_metadata.transient_metadata.import_export_ports.unload();
|
||||||
|
self.unload_import_export_wires_old(network_path);
|
||||||
// Always unload all wires connected to them as well
|
|
||||||
let number_of_imports = self.number_of_imports(network_path);
|
|
||||||
let Some(outward_wires) = self.outward_wires(network_path) else {
|
|
||||||
log::error!("Could not get outward wires in remove_import");
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
let mut input_connectors = Vec::new();
|
|
||||||
for import_index in 0..number_of_imports {
|
|
||||||
let Some(outward_wires_for_import) = outward_wires.get(&OutputConnector::Import(import_index)).cloned() else {
|
|
||||||
log::error!("Could not get outward wires for import in remove_import");
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
input_connectors.extend(outward_wires_for_import);
|
|
||||||
}
|
|
||||||
let Some(network) = self.nested_network(network_path) else {
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
for export_index in 0..network.exports.len() {
|
|
||||||
input_connectors.push(InputConnector::Export(export_index));
|
|
||||||
}
|
|
||||||
for input in &input_connectors {
|
|
||||||
self.unload_wire(input, network_path);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn modify_import_export(&mut self, network_path: &[NodeId]) -> Option<&ModifyImportExportClickTarget> {
|
pub fn modify_import_export(&mut self, network_path: &[NodeId]) -> Option<&ModifyImportExportClickTarget> {
|
||||||
@@ -2214,99 +1909,6 @@ impl NodeNetworkInterface {
|
|||||||
.find_map(|(input_index, click_target)| if index == input_index { click_target.bounding_box_center() } else { None })
|
.find_map(|(input_index, click_target)| if index == input_index { click_target.bounding_box_center() } else { None })
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn newly_loaded_input_wire(&mut self, input: &InputConnector, graph_wire_style: GraphWireStyle, network_path: &[NodeId]) -> Option<WirePathUpdate> {
|
|
||||||
if !self.wire_is_loaded(input, network_path) {
|
|
||||||
self.load_wire(input, graph_wire_style, network_path);
|
|
||||||
} else {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
let wire = match input {
|
|
||||||
InputConnector::Node { node_id, input_index } => {
|
|
||||||
let input_metadata = self.transient_input_metadata(node_id, *input_index, network_path)?;
|
|
||||||
let TransientMetadata::Loaded(wire) = &input_metadata.wire else {
|
|
||||||
log::error!("Could not load wire for input: {input:?}");
|
|
||||||
return None;
|
|
||||||
};
|
|
||||||
wire.clone()
|
|
||||||
}
|
|
||||||
InputConnector::Export(export_index) => {
|
|
||||||
let network_metadata = self.network_metadata(network_path)?;
|
|
||||||
let Some(TransientMetadata::Loaded(wire)) = network_metadata.transient_metadata.wires.get(*export_index) else {
|
|
||||||
log::error!("Could not load wire for input: {input:?}");
|
|
||||||
return None;
|
|
||||||
};
|
|
||||||
wire.clone()
|
|
||||||
}
|
|
||||||
};
|
|
||||||
Some(wire)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn wire_is_loaded(&mut self, input: &InputConnector, network_path: &[NodeId]) -> bool {
|
|
||||||
match input {
|
|
||||||
InputConnector::Node { node_id, input_index } => {
|
|
||||||
let Some(input_metadata) = self.transient_input_metadata(node_id, *input_index, network_path) else {
|
|
||||||
log::error!("Input metadata should always exist for input");
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
input_metadata.wire.is_loaded()
|
|
||||||
}
|
|
||||||
InputConnector::Export(export_index) => {
|
|
||||||
let Some(network_metadata) = self.network_metadata(network_path) else {
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
match network_metadata.transient_metadata.wires.get(*export_index) {
|
|
||||||
Some(wire) => wire.is_loaded(),
|
|
||||||
None => false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn load_wire(&mut self, input: &InputConnector, graph_wire_style: GraphWireStyle, network_path: &[NodeId]) {
|
|
||||||
let dashed = match self.previewing(network_path) {
|
|
||||||
Previewing::Yes { .. } => match input {
|
|
||||||
InputConnector::Node { .. } => false,
|
|
||||||
InputConnector::Export(export_index) => *export_index == 0,
|
|
||||||
},
|
|
||||||
Previewing::No => false,
|
|
||||||
};
|
|
||||||
let Some(wire) = self.wire_path_from_input(input, graph_wire_style, dashed, network_path) else {
|
|
||||||
log::error!("Could not load wire path from input");
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
match input {
|
|
||||||
InputConnector::Node { node_id, input_index } => {
|
|
||||||
let Some(node_metadata) = self.node_metadata_mut(node_id, network_path) else { return };
|
|
||||||
let Some(input_metadata) = node_metadata.persistent_metadata.input_metadata.get_mut(*input_index) else {
|
|
||||||
// log::warn!("Node metadata must exist on node: {input:?}");
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
let wire_update = WirePathUpdate {
|
|
||||||
id: *node_id,
|
|
||||||
input_index: *input_index,
|
|
||||||
wire_path_update: Some(wire),
|
|
||||||
};
|
|
||||||
input_metadata.transient_metadata.wire = TransientMetadata::Loaded(wire_update);
|
|
||||||
}
|
|
||||||
InputConnector::Export(export_index) => {
|
|
||||||
let Some(network_metadata) = self.network_metadata_mut(network_path) else { return };
|
|
||||||
if *export_index >= network_metadata.transient_metadata.wires.len() {
|
|
||||||
network_metadata.transient_metadata.wires.resize(export_index + 1, TransientMetadata::Unloaded);
|
|
||||||
}
|
|
||||||
let Some(input_metadata) = network_metadata.transient_metadata.wires.get_mut(*export_index) else {
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
let wire_update = WirePathUpdate {
|
|
||||||
id: NodeId(u64::MAX),
|
|
||||||
input_index: *export_index,
|
|
||||||
wire_path_update: Some(wire),
|
|
||||||
};
|
|
||||||
*input_metadata = TransientMetadata::Loaded(wire_update);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn all_input_connectors(&self, network_path: &[NodeId]) -> Vec<InputConnector> {
|
pub fn all_input_connectors(&self, network_path: &[NodeId]) -> Vec<InputConnector> {
|
||||||
let mut input_connectors = Vec::new();
|
let mut input_connectors = Vec::new();
|
||||||
let Some(network) = self.nested_network(network_path) else {
|
let Some(network) = self.nested_network(network_path) else {
|
||||||
@@ -2331,144 +1933,6 @@ impl NodeNetworkInterface {
|
|||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Maps to the frontend representation of a wire start. Includes disconnected value wire inputs.
|
|
||||||
pub fn node_graph_wire_inputs(&self, network_path: &[NodeId]) -> Vec<(NodeId, usize)> {
|
|
||||||
self.node_graph_input_connectors(network_path)
|
|
||||||
.iter()
|
|
||||||
.map(|input| match input {
|
|
||||||
InputConnector::Node { node_id, input_index } => (*node_id, *input_index),
|
|
||||||
InputConnector::Export(export_index) => (NodeId(u64::MAX), *export_index),
|
|
||||||
})
|
|
||||||
.chain(std::iter::once((NodeId(u64::MAX), u32::MAX as usize)))
|
|
||||||
.collect()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn unload_wires_for_node(&mut self, node_id: &NodeId, network_path: &[NodeId]) {
|
|
||||||
let number_of_outputs = self.number_of_outputs(node_id, network_path);
|
|
||||||
let Some(outward_wires) = self.outward_wires(network_path) else {
|
|
||||||
log::error!("Could not get outward wires in reorder_export");
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
let mut input_connectors = Vec::new();
|
|
||||||
for output_index in 0..number_of_outputs {
|
|
||||||
let Some(inputs) = outward_wires.get(&OutputConnector::node(*node_id, output_index)) else {
|
|
||||||
continue;
|
|
||||||
};
|
|
||||||
input_connectors.extend(inputs.clone())
|
|
||||||
}
|
|
||||||
for input_index in 0..self.number_of_inputs(node_id, network_path) {
|
|
||||||
input_connectors.push(InputConnector::node(*node_id, input_index));
|
|
||||||
}
|
|
||||||
for input in input_connectors {
|
|
||||||
self.unload_wire(&input, network_path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn unload_wire(&mut self, input: &InputConnector, network_path: &[NodeId]) {
|
|
||||||
match input {
|
|
||||||
InputConnector::Node { node_id, input_index } => {
|
|
||||||
let Some(node_metadata) = self.node_metadata_mut(node_id, network_path) else {
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
let Some(input_metadata) = node_metadata.persistent_metadata.input_metadata.get_mut(*input_index) else {
|
|
||||||
// log::warn!("Node metadata must exist on node: {input:?}");
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
input_metadata.transient_metadata.wire = TransientMetadata::Unloaded;
|
|
||||||
}
|
|
||||||
InputConnector::Export(export_index) => {
|
|
||||||
let Some(network_metadata) = self.network_metadata_mut(network_path) else {
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
if *export_index >= network_metadata.transient_metadata.wires.len() {
|
|
||||||
network_metadata.transient_metadata.wires.resize(export_index + 1, TransientMetadata::Unloaded);
|
|
||||||
}
|
|
||||||
let Some(input_metadata) = network_metadata.transient_metadata.wires.get_mut(*export_index) else {
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
*input_metadata = TransientMetadata::Unloaded;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// When previewing, there may be a second path to the root node.
|
|
||||||
pub fn wire_to_root(&mut self, graph_wire_style: GraphWireStyle, network_path: &[NodeId]) -> Option<WirePathUpdate> {
|
|
||||||
let input = InputConnector::Export(0);
|
|
||||||
let current_export = self.upstream_output_connector(&input, network_path)?;
|
|
||||||
|
|
||||||
let root_node = match self.previewing(network_path) {
|
|
||||||
Previewing::Yes { root_node_to_restore } => root_node_to_restore,
|
|
||||||
Previewing::No => None,
|
|
||||||
}?;
|
|
||||||
|
|
||||||
if Some(root_node.node_id) == current_export.node_id() {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
let Some(input_position) = self.get_input_center(&input, network_path) else {
|
|
||||||
log::error!("Could not get input position for wire end in root node: {input:?}");
|
|
||||||
return None;
|
|
||||||
};
|
|
||||||
let upstream_output = OutputConnector::node(root_node.node_id, root_node.output_index);
|
|
||||||
let Some(output_position) = self.get_output_center(&upstream_output, network_path) else {
|
|
||||||
log::error!("Could not get output position for wire start in root node: {upstream_output:?}");
|
|
||||||
return None;
|
|
||||||
};
|
|
||||||
let vertical_end = input.node_id().is_some_and(|node_id| self.is_layer(&node_id, network_path) && input.input_index() == 0);
|
|
||||||
let vertical_start: bool = upstream_output.node_id().is_some_and(|node_id| self.is_layer(&node_id, network_path));
|
|
||||||
let thick = vertical_end && vertical_start;
|
|
||||||
let vector_wire = build_vector_wire(output_position, input_position, vertical_start, vertical_end, graph_wire_style);
|
|
||||||
|
|
||||||
let path_string = vector_wire.to_svg();
|
|
||||||
let data_type = self.input_type(&input, network_path).displayed_type();
|
|
||||||
let wire_path_update = Some(WirePath {
|
|
||||||
path_string,
|
|
||||||
data_type,
|
|
||||||
thick,
|
|
||||||
dashed: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
Some(WirePathUpdate {
|
|
||||||
id: NodeId(u64::MAX),
|
|
||||||
input_index: u32::MAX as usize,
|
|
||||||
wire_path_update,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the vector subpath and a boolean of whether the wire should be thick.
|
|
||||||
pub fn vector_wire_from_input(&mut self, input: &InputConnector, wire_style: GraphWireStyle, network_path: &[NodeId]) -> Option<(BezPath, bool)> {
|
|
||||||
let Some(input_position) = self.get_input_center(input, network_path) else {
|
|
||||||
log::error!("Could not get dom rect for wire end: {input:?}");
|
|
||||||
return None;
|
|
||||||
};
|
|
||||||
// An upstream output could not be found, so the wire does not exist, but it should still be loaded as as empty vector
|
|
||||||
let Some(upstream_output) = self.upstream_output_connector(input, network_path) else {
|
|
||||||
return Some((BezPath::new(), false));
|
|
||||||
};
|
|
||||||
let Some(output_position) = self.get_output_center(&upstream_output, network_path) else {
|
|
||||||
log::error!("Could not get output port for wire start: {:?}", upstream_output);
|
|
||||||
return None;
|
|
||||||
};
|
|
||||||
let vertical_end = input.node_id().is_some_and(|node_id| self.is_layer(&node_id, network_path) && input.input_index() == 0);
|
|
||||||
let vertical_start = upstream_output.node_id().is_some_and(|node_id| self.is_layer(&node_id, network_path));
|
|
||||||
let thick = vertical_end && vertical_start;
|
|
||||||
Some((build_vector_wire(output_position, input_position, vertical_start, vertical_end, wire_style), thick))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn wire_path_from_input(&mut self, input: &InputConnector, graph_wire_style: GraphWireStyle, dashed: bool, network_path: &[NodeId]) -> Option<WirePath> {
|
|
||||||
let (vector_wire, thick) = self.vector_wire_from_input(input, graph_wire_style, network_path)?;
|
|
||||||
let path_string = vector_wire.to_svg();
|
|
||||||
let data_type = self
|
|
||||||
.upstream_output_connector(input, network_path)
|
|
||||||
.map(|output| self.output_type(&output, network_path).displayed_type())
|
|
||||||
.unwrap_or(FrontendGraphDataType::General);
|
|
||||||
Some(WirePath {
|
|
||||||
path_string,
|
|
||||||
data_type,
|
|
||||||
thick,
|
|
||||||
dashed,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn node_click_targets(&mut self, node_id: &NodeId, network_path: &[NodeId]) -> Option<&DocumentNodeClickTargets> {
|
pub fn node_click_targets(&mut self, node_id: &NodeId, network_path: &[NodeId]) -> Option<&DocumentNodeClickTargets> {
|
||||||
self.try_load_node_click_targets(node_id, network_path);
|
self.try_load_node_click_targets(node_id, network_path);
|
||||||
self.try_get_node_click_targets(node_id, network_path)
|
self.try_get_node_click_targets(node_id, network_path)
|
||||||
@@ -2706,7 +2170,7 @@ impl NodeNetworkInterface {
|
|||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
node_metadata.transient_metadata.click_targets.unload();
|
node_metadata.transient_metadata.click_targets.unload();
|
||||||
self.unload_wires_for_node(node_id, network_path);
|
self.unload_wires_for_node_old(node_id, network_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn unload_upstream_node_click_targets(&mut self, node_ids: Vec<NodeId>, network_path: &[NodeId]) {
|
pub fn unload_upstream_node_click_targets(&mut self, node_ids: Vec<NodeId>, network_path: &[NodeId]) {
|
||||||
@@ -3062,38 +2526,6 @@ impl NodeNetworkInterface {
|
|||||||
bounding_box_subpath.bounding_box_with_transform(network_metadata.persistent_metadata.navigation_metadata.node_graph_to_viewport)
|
bounding_box_subpath.bounding_box_with_transform(network_metadata.persistent_metadata.navigation_metadata.node_graph_to_viewport)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn collect_layer_widths(&mut self, network_path: &[NodeId]) -> (HashMap<NodeId, u32>, HashMap<NodeId, u32>, HashMap<NodeId, bool>) {
|
|
||||||
let Some(network_metadata) = self.network_metadata(network_path) else {
|
|
||||||
log::error!("Could not get nested network_metadata in collect_layer_widths");
|
|
||||||
return (HashMap::new(), HashMap::new(), HashMap::new());
|
|
||||||
};
|
|
||||||
let nodes = network_metadata
|
|
||||||
.persistent_metadata
|
|
||||||
.node_metadata
|
|
||||||
.iter()
|
|
||||||
.filter_map(|(node_id, _)| if self.is_layer(node_id, network_path) { Some(*node_id) } else { None })
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
let layer_widths = nodes
|
|
||||||
.iter()
|
|
||||||
.filter_map(|node_id| self.layer_width(node_id, network_path).map(|layer_width| (*node_id, layer_width)))
|
|
||||||
.collect::<HashMap<NodeId, u32>>();
|
|
||||||
let chain_widths = nodes.iter().map(|node_id| (*node_id, self.chain_width(node_id, network_path))).collect::<HashMap<NodeId, u32>>();
|
|
||||||
let has_left_input_wire = nodes
|
|
||||||
.iter()
|
|
||||||
.map(|node_id| {
|
|
||||||
(
|
|
||||||
*node_id,
|
|
||||||
!self
|
|
||||||
.upstream_flow_back_from_nodes(vec![*node_id], network_path, FlowType::HorizontalFlow)
|
|
||||||
.skip(1)
|
|
||||||
.all(|node_id| self.is_chain(&node_id, network_path)),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.collect::<HashMap<NodeId, bool>>();
|
|
||||||
|
|
||||||
(layer_widths, chain_widths, has_left_input_wire)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn compute_modified_vector(&self, layer: LayerNodeIdentifier) -> Option<Vector> {
|
pub fn compute_modified_vector(&self, layer: LayerNodeIdentifier) -> Option<Vector> {
|
||||||
let graph_layer = graph_modification_utils::NodeGraphLayer::new(layer, self);
|
let graph_layer = graph_modification_utils::NodeGraphLayer::new(layer, self);
|
||||||
|
|
||||||
@@ -3278,7 +2710,6 @@ impl NodeNetworkInterface {
|
|||||||
self.unload_import_export_ports(network_path);
|
self.unload_import_export_ports(network_path);
|
||||||
self.unload_modify_import_export(network_path);
|
self.unload_modify_import_export(network_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn vector_modify(&mut self, node_id: &NodeId, modification_type: VectorModificationType) {
|
pub fn vector_modify(&mut self, node_id: &NodeId, modification_type: VectorModificationType) {
|
||||||
let Some(node) = self.network_mut(&[]).unwrap().nodes.get_mut(node_id) else {
|
let Some(node) = self.network_mut(&[]).unwrap().nodes.get_mut(node_id) else {
|
||||||
log::error!("Could not get node in vector_modification");
|
log::error!("Could not get node in vector_modification");
|
||||||
@@ -4013,17 +3444,14 @@ impl NodeNetworkInterface {
|
|||||||
// If a connection is made to the imports
|
// If a connection is made to the imports
|
||||||
(NodeInput::Value { .. } | NodeInput::Scope { .. } | NodeInput::Inline { .. }, NodeInput::Import { .. }) => {
|
(NodeInput::Value { .. } | NodeInput::Scope { .. } | NodeInput::Inline { .. }, NodeInput::Import { .. }) => {
|
||||||
self.unload_outward_wires(network_path);
|
self.unload_outward_wires(network_path);
|
||||||
self.unload_wire(input_connector, network_path);
|
|
||||||
}
|
}
|
||||||
// If a connection to the imports is disconnected
|
// If a connection to the imports is disconnected
|
||||||
(NodeInput::Import { .. }, NodeInput::Value { .. } | NodeInput::Scope { .. } | NodeInput::Inline { .. }) => {
|
(NodeInput::Import { .. }, NodeInput::Value { .. } | NodeInput::Scope { .. } | NodeInput::Inline { .. }) => {
|
||||||
self.unload_outward_wires(network_path);
|
self.unload_outward_wires(network_path);
|
||||||
self.unload_wire(input_connector, network_path);
|
|
||||||
}
|
}
|
||||||
// If a node is disconnected.
|
// If a node is disconnected.
|
||||||
(NodeInput::Node { .. }, NodeInput::Value { .. } | NodeInput::Scope { .. } | NodeInput::Inline { .. }) => {
|
(NodeInput::Node { .. }, NodeInput::Value { .. } | NodeInput::Scope { .. } | NodeInput::Inline { .. }) => {
|
||||||
self.unload_outward_wires(network_path);
|
self.unload_outward_wires(network_path);
|
||||||
self.unload_wire(input_connector, network_path);
|
|
||||||
|
|
||||||
if let Some((old_upstream_node_id, previous_position)) = previous_metadata {
|
if let Some((old_upstream_node_id, previous_position)) = previous_metadata {
|
||||||
let old_upstream_node_is_layer = self.is_layer(&old_upstream_node_id, network_path);
|
let old_upstream_node_is_layer = self.is_layer(&old_upstream_node_id, network_path);
|
||||||
@@ -6069,7 +5497,7 @@ pub struct NodeNetworkTransientMetadata {
|
|||||||
pub modify_import_export: TransientMetadata<ModifyImportExportClickTarget>,
|
pub modify_import_export: TransientMetadata<ModifyImportExportClickTarget>,
|
||||||
|
|
||||||
// Wires from the exports
|
// Wires from the exports
|
||||||
pub wires: Vec<TransientMetadata<WirePathUpdate>>,
|
pub wires: Vec<TransientMetadata<WirePathUpdateOld>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
@@ -6250,7 +5678,7 @@ impl InputPersistentMetadata {
|
|||||||
|
|
||||||
#[derive(Debug, Clone, Default)]
|
#[derive(Debug, Clone, Default)]
|
||||||
struct InputTransientMetadata {
|
struct InputTransientMetadata {
|
||||||
wire: TransientMetadata<WirePathUpdate>,
|
wire: TransientMetadata<WirePathUpdateOld>,
|
||||||
// downstream_protonode: populated for all inputs after each compile
|
// downstream_protonode: populated for all inputs after each compile
|
||||||
// types: populated for each protonode after each
|
// types: populated for each protonode after each
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,360 @@
|
|||||||
|
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};
|
||||||
|
use crate::messages::portfolio::document::node_graph::utility_types::{FrontendExport, FrontendExports, FrontendImport};
|
||||||
|
use crate::messages::portfolio::document::utility_types::{
|
||||||
|
network_interface::{FlowType, InputConnector, NodeNetworkInterface, OutputConnector, Previewing},
|
||||||
|
wires::{GraphWireStyle, build_vector_wire},
|
||||||
|
};
|
||||||
|
use glam::{DVec2, IVec2};
|
||||||
|
use graphene_std::{
|
||||||
|
node_graph_overlay::types::{FrontendGraphInputNew, FrontendGraphOutputNew},
|
||||||
|
uuid::NodeId,
|
||||||
|
};
|
||||||
|
use kurbo::BezPath;
|
||||||
|
|
||||||
|
// Functions used to collect data from the network interface for use in rendering the node graph
|
||||||
|
impl NodeNetworkInterface {
|
||||||
|
/// Returns None if there is an error, it is a hidden primary export, or a hidden input
|
||||||
|
pub fn frontend_input_from_connector(&mut self, input_connector: &InputConnector, network_path: &[NodeId]) -> Option<FrontendGraphInputNew> {
|
||||||
|
// Return None if it is a hidden input or doesn't exist
|
||||||
|
if self.input_from_connector(input_connector, network_path).is_some_and(|input| !input.is_exposed()) {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let input_type = self.input_type(input_connector, network_path);
|
||||||
|
let data_type = input_type.displayed_type();
|
||||||
|
|
||||||
|
let name = match input_connector {
|
||||||
|
InputConnector::Node { node_id, input_index } => self.displayed_input_name_and_description(node_id, *input_index, network_path).0,
|
||||||
|
InputConnector::Export(export_index) => {
|
||||||
|
// Get export name from parent node metadata input, which must match the number of exports.
|
||||||
|
// Empty string means to use type, or "Export + index" if type is empty determined
|
||||||
|
let export_name = if network_path.is_empty() {
|
||||||
|
"Canvas".to_string()
|
||||||
|
} else {
|
||||||
|
self.encapsulating_node_metadata(network_path)
|
||||||
|
.and_then(|encapsulating_metadata| encapsulating_metadata.persistent_metadata.output_names.get(*export_index).cloned())
|
||||||
|
.unwrap_or_default()
|
||||||
|
};
|
||||||
|
|
||||||
|
if !export_name.is_empty() {
|
||||||
|
export_name
|
||||||
|
} else if let Some(export_type_name) = input_type.compiled_nested_type().map(|nested| nested.to_string()) {
|
||||||
|
export_type_name
|
||||||
|
} else {
|
||||||
|
format!("Export index {}", export_index)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let connected_to_node = self.upstream_output_connector(input_connector, network_path).and_then(|output_connector| output_connector.node_id());
|
||||||
|
|
||||||
|
Some(FrontendGraphInputNew { data_type, name, connected_to_node })
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns None if there is an error, it is the document network, a hidden primary output or import
|
||||||
|
pub fn frontend_output_from_connector(&mut self, output_connector: &OutputConnector, network_path: &[NodeId]) -> Option<FrontendGraphOutputNew> {
|
||||||
|
let output_type = self.output_type(output_connector, network_path);
|
||||||
|
|
||||||
|
let name = match output_connector {
|
||||||
|
OutputConnector::Node { node_id, output_index } => {
|
||||||
|
// Do not display the primary output port for a node if it is a network node with a hidden primary export
|
||||||
|
if *output_index == 0 && self.hidden_primary_output(node_id, network_path) {
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
// Get the output name from the interior network export name
|
||||||
|
let node_metadata = self.node_metadata(node_id, network_path)?;
|
||||||
|
let output_name = node_metadata.persistent_metadata.output_names.get(*output_index).cloned().unwrap_or_default();
|
||||||
|
|
||||||
|
if !output_name.is_empty() { output_name } else { output_type.resolved_type_node_string() }
|
||||||
|
}
|
||||||
|
OutputConnector::Import(import_index) => {
|
||||||
|
// Get the import name from the encapsulating node input metadata
|
||||||
|
let Some((encapsulating_node_id, encapsulating_path)) = network_path.split_last() else {
|
||||||
|
// Return None if it is an import in the document network
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
// Return None if the primary input is hidden and this is the primary import
|
||||||
|
if *import_index == 0 && self.hidden_primary_import(network_path) {
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
let import_name = self.displayed_input_name_and_description(encapsulating_node_id, *import_index, encapsulating_path).0;
|
||||||
|
|
||||||
|
if !import_name.is_empty() {
|
||||||
|
import_name
|
||||||
|
} else if let Some(import_type_name) = output_type.compiled_nested_type().map(|nested| nested.to_string()) {
|
||||||
|
import_type_name
|
||||||
|
} else {
|
||||||
|
format!("Import index {}", *import_index)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let connected = self
|
||||||
|
.outward_wires(network_path)
|
||||||
|
.and_then(|outward_wires| outward_wires.get(output_connector))
|
||||||
|
.is_some_and(|downstream| downstream.len() > 0);
|
||||||
|
let data_type = output_type.displayed_type();
|
||||||
|
Some(FrontendGraphOutputNew { data_type, name, connected })
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn chain_width(&self, node_id: &NodeId, network_path: &[NodeId]) -> u32 {
|
||||||
|
if self.number_of_displayed_inputs(node_id, network_path) > 1 {
|
||||||
|
let mut last_chain_node_distance = 0u32;
|
||||||
|
// Iterate upstream from the layer, and get the number of nodes distance to the last node with Position::Chain
|
||||||
|
for (index, node_id) in self
|
||||||
|
.upstream_flow_back_from_nodes(vec![*node_id], network_path, FlowType::HorizontalPrimaryOutputFlow)
|
||||||
|
.skip(1)
|
||||||
|
.enumerate()
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
{
|
||||||
|
// Check if the node is positioned as a chain
|
||||||
|
if self.is_chain(&node_id, network_path) {
|
||||||
|
last_chain_node_distance = (index as u32) + 1;
|
||||||
|
} else {
|
||||||
|
return last_chain_node_distance * 7 + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
last_chain_node_distance * 7 + 1
|
||||||
|
} else {
|
||||||
|
// Layer with no inputs has no chain
|
||||||
|
0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Checks if a layer should display a gap in its left border
|
||||||
|
pub fn layer_has_left_border_gap(&self, node_id: &NodeId, network_path: &[NodeId]) -> bool {
|
||||||
|
self.upstream_flow_back_from_nodes(vec![*node_id], network_path, FlowType::HorizontalFlow).skip(1).any(|node_id| {
|
||||||
|
!self.is_chain(&node_id, network_path)
|
||||||
|
|| self
|
||||||
|
.upstream_output_connector(&InputConnector::node(node_id, 0), network_path)
|
||||||
|
.is_some_and(|output_connector| matches!(output_connector, OutputConnector::Import(_)))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the node which should have a dashed border drawn around it
|
||||||
|
pub fn previewed_node(&self, network_path: &[NodeId]) -> Option<NodeId> {
|
||||||
|
self.upstream_output_connector(&InputConnector::Export(0), network_path)
|
||||||
|
.and_then(|output_connector| output_connector.node_id())
|
||||||
|
.filter(|output_node| self.root_node(network_path).is_some_and(|root_node| root_node.node_id != *output_node))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// If any downstream input are bottom layer inputs, then the thick cap should be displayed above the output port
|
||||||
|
pub fn primary_output_connected_to_layer(&mut self, node_id: &NodeId, network_path: &[NodeId]) -> bool {
|
||||||
|
let Some(outward_wires) = self.outward_wires(network_path) else {
|
||||||
|
log::error!("Could not get outward_wires in primary_output_connected_to_layer");
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
let Some(downstream_connectors) = outward_wires.get(&OutputConnector::node(*node_id, 0)) else {
|
||||||
|
log::error!("Could not get downstream_connectors in primary_output_connected_to_layer");
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
let downstream_nodes = downstream_connectors
|
||||||
|
.iter()
|
||||||
|
.filter_map(|connector| if connector.input_index() == 0 { connector.node_id() } else { None })
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
downstream_nodes.iter().any(|node_id| self.is_layer(node_id, network_path))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// If any upstream nodes are layers, then the thick cap should be displayed below the primary input port
|
||||||
|
pub fn primary_input_connected_to_layer(&mut self, node_id: &NodeId, network_path: &[NodeId]) -> bool {
|
||||||
|
self.input_from_connector(&InputConnector::node(*node_id, 0), network_path)
|
||||||
|
.and_then(|input| input.as_node())
|
||||||
|
.is_some_and(|node_id| self.is_layer(&node_id, network_path))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The imports contain both the output port and the outward wires
|
||||||
|
pub fn frontend_imports(&mut self, graph_wire_style: GraphWireStyle, network_path: &[NodeId]) -> Vec<Option<FrontendImport>> {
|
||||||
|
match network_path.split_last() {
|
||||||
|
Some((node_id, encapsulating_network_path)) => {
|
||||||
|
let Some(node) = self.document_node(node_id, encapsulating_network_path) else {
|
||||||
|
log::error!("Could not get node {node_id} in network {encapsulating_network_path:?}");
|
||||||
|
return Vec::new();
|
||||||
|
};
|
||||||
|
let mut frontend_imports = (0..node.inputs.len())
|
||||||
|
.map(|import_index| {
|
||||||
|
let port = self.frontend_output_from_connector(&OutputConnector::Import(import_index), network_path);
|
||||||
|
port.and_then(|port| {
|
||||||
|
let outward_wires = self.outward_wires(network_path)?;
|
||||||
|
let downstream_inputs = outward_wires.get(&OutputConnector::Import(import_index)).cloned()?;
|
||||||
|
let wires = downstream_inputs
|
||||||
|
.iter()
|
||||||
|
.filter_map(|input_connector| {
|
||||||
|
let Some(wire) = self.wire_from_input_new(&input_connector, graph_wire_style, network_path) else {
|
||||||
|
log::error!("Could not get wire path for import input: {input_connector:?}");
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
Some(wire.to_svg())
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
Some(FrontendImport { port, wires })
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
if frontend_imports.is_empty() {
|
||||||
|
frontend_imports.push(None);
|
||||||
|
}
|
||||||
|
frontend_imports
|
||||||
|
}
|
||||||
|
// In the document network display no imports
|
||||||
|
None => Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The imports contain the export port, the outward wires, and the preview wire if it exists
|
||||||
|
pub fn frontend_exports(&mut self, graph_wire_style: GraphWireStyle, network_path: &[NodeId]) -> FrontendExports {
|
||||||
|
let Some(network) = self.nested_network(network_path) else {
|
||||||
|
log::error!("Could not get nested network in frontend exports");
|
||||||
|
return FrontendExports::default();
|
||||||
|
};
|
||||||
|
let mut exports = (0..network.exports.len())
|
||||||
|
.map(|export_index| {
|
||||||
|
let export_connector = InputConnector::Export(export_index);
|
||||||
|
let frontend_export = self.frontend_input_from_connector(&export_connector, network_path);
|
||||||
|
|
||||||
|
frontend_export.and_then(|export| {
|
||||||
|
let wire = self.wire_from_input_new(&export_connector, graph_wire_style, network_path).map(|path| path.to_svg());
|
||||||
|
Some(FrontendExport { port: export, wire })
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
if exports.is_empty() {
|
||||||
|
exports.push(None);
|
||||||
|
}
|
||||||
|
let preview_wire = self.wire_to_root_new(graph_wire_style, network_path).map(|wire| wire.to_svg());
|
||||||
|
FrontendExports { exports, preview_wire }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn import_export_position(&mut self, network_path: &[NodeId]) -> Option<(IVec2, IVec2)> {
|
||||||
|
let Some(all_nodes_bounding_box) = self.all_nodes_bounding_box(network_path).cloned() else {
|
||||||
|
log::error!("Could not get all nodes bounding box in load_export_ports");
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
let Some(network) = self.nested_network(network_path) else {
|
||||||
|
log::error!("Could not get current network in load_export_ports");
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
|
||||||
|
let Some(network_metadata) = self.network_metadata(network_path) else {
|
||||||
|
log::error!("Could not get nested network_metadata in load_export_ports");
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
let node_graph_to_viewport = network_metadata.persistent_metadata.navigation_metadata.node_graph_to_viewport;
|
||||||
|
let target_viewport_top_left = DVec2::new(IMPORTS_TO_LEFT_EDGE_PIXEL_GAP as f64, IMPORTS_TO_TOP_EDGE_PIXEL_GAP as f64);
|
||||||
|
|
||||||
|
let node_graph_pixel_offset_top_left = node_graph_to_viewport.inverse().transform_point2(target_viewport_top_left);
|
||||||
|
|
||||||
|
// A 5x5 grid offset from the top left corner
|
||||||
|
let node_graph_grid_space_offset_top_left = node_graph_to_viewport.inverse().transform_point2(DVec2::ZERO) + DVec2::new(5. * GRID_SIZE as f64, 4. * GRID_SIZE as f64);
|
||||||
|
|
||||||
|
// The inner bound of the import is the highest/furthest left of the two offsets
|
||||||
|
let top_left_inner_bound = DVec2::new(
|
||||||
|
node_graph_pixel_offset_top_left.x.min(node_graph_grid_space_offset_top_left.x),
|
||||||
|
node_graph_pixel_offset_top_left.y.min(node_graph_grid_space_offset_top_left.y),
|
||||||
|
);
|
||||||
|
|
||||||
|
let offset_from_top_left = if network
|
||||||
|
.exports
|
||||||
|
.first()
|
||||||
|
.is_some_and(|export| export.as_node().is_some_and(|export_node| self.is_layer(&export_node, network_path)))
|
||||||
|
{
|
||||||
|
DVec2::new(-4. * GRID_SIZE as f64, -2. * GRID_SIZE as f64)
|
||||||
|
} else {
|
||||||
|
DVec2::new(-4. * GRID_SIZE as f64, 0.)
|
||||||
|
};
|
||||||
|
|
||||||
|
let bounding_box_top_left = DVec2::new((all_nodes_bounding_box[0].x / 24. + 0.5).floor() * 24., (all_nodes_bounding_box[0].y / 24. + 0.5).floor() * 24.) + offset_from_top_left;
|
||||||
|
let import_top_left = DVec2::new(top_left_inner_bound.x.min(bounding_box_top_left.x), top_left_inner_bound.y.min(bounding_box_top_left.y));
|
||||||
|
let rounded_import_top_left = DVec2::new((import_top_left.x / 24.).round() * 24., (import_top_left.y / 24.).round() * 24.);
|
||||||
|
|
||||||
|
let viewport_width = network_metadata.persistent_metadata.navigation_metadata.node_graph_width;
|
||||||
|
|
||||||
|
let target_viewport_top_right = DVec2::new(viewport_width - EXPORTS_TO_RIGHT_EDGE_PIXEL_GAP as f64, EXPORTS_TO_TOP_EDGE_PIXEL_GAP as f64);
|
||||||
|
|
||||||
|
// An offset from the right edge in viewport pixels
|
||||||
|
let node_graph_pixel_offset_top_right = node_graph_to_viewport.inverse().transform_point2(target_viewport_top_right);
|
||||||
|
|
||||||
|
// A 5x5 grid offset from the right corner
|
||||||
|
let node_graph_grid_space_offset_top_right = node_graph_to_viewport.inverse().transform_point2(DVec2::new(viewport_width, 0.)) + DVec2::new(-5. * GRID_SIZE as f64, 4. * GRID_SIZE as f64);
|
||||||
|
|
||||||
|
// The inner bound of the export is the highest/furthest right of the two offsets.
|
||||||
|
// When zoomed out this keeps it a constant grid space away from the edge, but when zoomed in it prevents the exports from getting too far in
|
||||||
|
let top_right_inner_bound = DVec2::new(
|
||||||
|
node_graph_pixel_offset_top_right.x.max(node_graph_grid_space_offset_top_right.x),
|
||||||
|
node_graph_pixel_offset_top_right.y.min(node_graph_grid_space_offset_top_right.y),
|
||||||
|
);
|
||||||
|
|
||||||
|
let offset_from_top_right = if network
|
||||||
|
.exports
|
||||||
|
.first()
|
||||||
|
.is_some_and(|export| export.as_node().is_some_and(|export_node| self.is_layer(&export_node, network_path)))
|
||||||
|
{
|
||||||
|
DVec2::new(2. * GRID_SIZE as f64, -2. * GRID_SIZE as f64)
|
||||||
|
} else {
|
||||||
|
DVec2::new(4. * GRID_SIZE as f64, 0.)
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut bounding_box_top_right = DVec2::new((all_nodes_bounding_box[1].x / 24. + 0.5).floor() * 24., (all_nodes_bounding_box[0].y / 24. + 0.5).floor() * 24.);
|
||||||
|
bounding_box_top_right += offset_from_top_right;
|
||||||
|
let export_top_right = DVec2::new(top_right_inner_bound.x.max(bounding_box_top_right.x), top_right_inner_bound.y.min(bounding_box_top_right.y));
|
||||||
|
let rounded_export_top_right = DVec2::new((export_top_right.x / 24.).round() * 24., (export_top_right.y / 24.).round() * 24.);
|
||||||
|
|
||||||
|
Some((rounded_import_top_left.as_ivec2(), rounded_export_top_right.as_ivec2()))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn wire_is_thick(&self, input: &InputConnector, network_path: &[NodeId]) -> bool {
|
||||||
|
let Some(upstream_output) = self.upstream_output_connector(input, network_path) else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
let vertical_end = input.node_id().is_some_and(|node_id| self.is_layer(&node_id, network_path) && input.input_index() == 0);
|
||||||
|
let vertical_start = upstream_output.node_id().is_some_and(|node_id| self.is_layer(&node_id, network_path));
|
||||||
|
vertical_end && vertical_start
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the vector subpath and a boolean of whether the wire should be thick.
|
||||||
|
pub fn wire_from_input_new(&mut self, input: &InputConnector, wire_style: GraphWireStyle, network_path: &[NodeId]) -> Option<BezPath> {
|
||||||
|
let Some(input_position) = self.get_input_center(input, network_path) else {
|
||||||
|
log::error!("Could not get dom rect for wire end: {input:?}");
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
// An upstream output could not be found
|
||||||
|
let Some(upstream_output) = self.upstream_output_connector(input, network_path) else {
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
let Some(output_position) = self.get_output_center(&upstream_output, network_path) else {
|
||||||
|
log::error!("Could not get output port for wire start: {:?}", upstream_output);
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
let vertical_end = input.node_id().is_some_and(|node_id| self.is_layer(&node_id, network_path) && input.input_index() == 0);
|
||||||
|
let vertical_start = upstream_output.node_id().is_some_and(|node_id| self.is_layer(&node_id, network_path));
|
||||||
|
Some(build_vector_wire(output_position, input_position, vertical_start, vertical_end, wire_style))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// When previewing, there may be a second path to the root node.
|
||||||
|
pub fn wire_to_root_new(&mut self, graph_wire_style: GraphWireStyle, network_path: &[NodeId]) -> Option<BezPath> {
|
||||||
|
let input = InputConnector::Export(0);
|
||||||
|
let current_export = self.upstream_output_connector(&input, network_path)?;
|
||||||
|
|
||||||
|
let root_node = match self.previewing(network_path) {
|
||||||
|
Previewing::Yes { root_node_to_restore } => root_node_to_restore,
|
||||||
|
Previewing::No => None,
|
||||||
|
}?;
|
||||||
|
|
||||||
|
if Some(root_node.node_id) == current_export.node_id() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let Some(input_position) = self.get_input_center(&input, network_path) else {
|
||||||
|
log::error!("Could not get input position for wire end in root node: {input:?}");
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
let upstream_output = OutputConnector::node(root_node.node_id, root_node.output_index);
|
||||||
|
let Some(output_position) = self.get_output_center(&upstream_output, network_path) else {
|
||||||
|
log::error!("Could not get output position for wire start in root node: {upstream_output:?}");
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
let vertical_start = upstream_output.node_id().is_some_and(|node_id| self.is_layer(&node_id, network_path));
|
||||||
|
let vector_wire = build_vector_wire(output_position, input_position, vertical_start, false, graph_wire_style);
|
||||||
|
|
||||||
|
Some(vector_wire)
|
||||||
|
}
|
||||||
|
}
|
||||||
+435
@@ -0,0 +1,435 @@
|
|||||||
|
use crate::messages::portfolio::document::node_graph::utility_types::{FrontendGraphInputOld, FrontendGraphOutputOld};
|
||||||
|
use crate::messages::portfolio::document::utility_types::network_interface::FlowType;
|
||||||
|
use crate::messages::portfolio::document::utility_types::network_interface::NodeNetworkInterface;
|
||||||
|
use crate::messages::portfolio::document::utility_types::network_interface::Previewing;
|
||||||
|
use crate::messages::portfolio::document::utility_types::network_interface::{InputConnector, OutputConnector, TransientMetadata};
|
||||||
|
use crate::messages::portfolio::document::utility_types::wires::{GraphWireStyle, WirePathOld, WirePathUpdateOld, build_vector_wire};
|
||||||
|
use graphene_std::node_graph_overlay::types::FrontendGraphDataType;
|
||||||
|
use graphene_std::uuid::NodeId;
|
||||||
|
use kurbo::BezPath;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
// All these functions will be deleted once the svelte node graph rendering is removed
|
||||||
|
impl NodeNetworkInterface {
|
||||||
|
/// Returns None if there is an error, it is a hidden primary export, or a hidden input
|
||||||
|
pub fn frontend_input_from_connector_old(&mut self, input_connector: &InputConnector, network_path: &[NodeId]) -> Option<FrontendGraphInputOld> {
|
||||||
|
// Return None if it is a hidden input
|
||||||
|
if self.input_from_connector(input_connector, network_path).is_some_and(|input| !input.is_exposed()) {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let input_type = self.input_type(input_connector, network_path);
|
||||||
|
let data_type = input_type.displayed_type();
|
||||||
|
let resolved_type = input_type.resolved_type_node_string();
|
||||||
|
|
||||||
|
let connected_to = self
|
||||||
|
.upstream_output_connector(input_connector, network_path)
|
||||||
|
.map(|output_connector| match output_connector {
|
||||||
|
OutputConnector::Node { node_id, output_index } => {
|
||||||
|
let mut name = self.display_name(&node_id, network_path);
|
||||||
|
if cfg!(debug_assertions) {
|
||||||
|
name.push_str(&format!(" (id: {node_id})"));
|
||||||
|
}
|
||||||
|
format!("{name} output {output_index}")
|
||||||
|
}
|
||||||
|
OutputConnector::Import(import_index) => format!("Import index {import_index}"),
|
||||||
|
})
|
||||||
|
.unwrap_or("nothing".to_string());
|
||||||
|
|
||||||
|
let (name, description) = match input_connector {
|
||||||
|
InputConnector::Node { node_id, input_index } => self.displayed_input_name_and_description(node_id, *input_index, network_path),
|
||||||
|
InputConnector::Export(export_index) => {
|
||||||
|
// Get export name from parent node metadata input, which must match the number of exports.
|
||||||
|
// Empty string means to use type, or "Export + index" if type is empty determined
|
||||||
|
let export_name = if network_path.is_empty() {
|
||||||
|
"Canvas".to_string()
|
||||||
|
} else {
|
||||||
|
self.encapsulating_node_metadata(network_path)
|
||||||
|
.and_then(|encapsulating_metadata| encapsulating_metadata.persistent_metadata.output_names.get(*export_index).cloned())
|
||||||
|
.unwrap_or_default()
|
||||||
|
};
|
||||||
|
|
||||||
|
let export_name = if !export_name.is_empty() {
|
||||||
|
export_name
|
||||||
|
} else if let Some(export_type_name) = input_type.compiled_nested_type().map(|nested| nested.to_string()) {
|
||||||
|
export_type_name
|
||||||
|
} else {
|
||||||
|
format!("Export index {}", export_index)
|
||||||
|
};
|
||||||
|
|
||||||
|
(export_name, String::new())
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Some(FrontendGraphInputOld {
|
||||||
|
data_type,
|
||||||
|
resolved_type,
|
||||||
|
name,
|
||||||
|
description,
|
||||||
|
valid_types: self.potential_valid_input_types(input_connector, network_path).iter().map(|ty| ty.to_string()).collect(),
|
||||||
|
connected_to,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns None if there is an error, it is the document network, a hidden primary output or import
|
||||||
|
pub fn frontend_output_from_connector_old(&mut self, output_connector: &OutputConnector, network_path: &[NodeId]) -> Option<FrontendGraphOutputOld> {
|
||||||
|
let output_type = self.output_type(output_connector, network_path);
|
||||||
|
|
||||||
|
let (name, description) = match output_connector {
|
||||||
|
OutputConnector::Node { node_id, output_index } => {
|
||||||
|
// Do not display the primary output port for a node if it is a network node with a hidden primary export
|
||||||
|
if *output_index == 0 && self.hidden_primary_output(node_id, network_path) {
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
// Get the output name from the interior network export name
|
||||||
|
let node_metadata = self.node_metadata(node_id, network_path)?;
|
||||||
|
let output_name = node_metadata.persistent_metadata.output_names.get(*output_index).cloned().unwrap_or_default();
|
||||||
|
|
||||||
|
let output_name = if !output_name.is_empty() { output_name } else { output_type.resolved_type_node_string() };
|
||||||
|
(output_name, String::new())
|
||||||
|
}
|
||||||
|
OutputConnector::Import(import_index) => {
|
||||||
|
// Get the import name from the encapsulating node input metadata
|
||||||
|
let Some((encapsulating_node_id, encapsulating_path)) = network_path.split_last() else {
|
||||||
|
// Return None if it is an import in the document network
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
// Return None if the primary input is hidden and this is the primary import
|
||||||
|
if *import_index == 0 && self.hidden_primary_import(network_path) {
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
let (import_name, description) = self.displayed_input_name_and_description(encapsulating_node_id, *import_index, encapsulating_path);
|
||||||
|
|
||||||
|
let import_name = if !import_name.is_empty() {
|
||||||
|
import_name
|
||||||
|
} else if let Some(import_type_name) = output_type.compiled_nested_type().map(|nested| nested.to_string()) {
|
||||||
|
import_type_name
|
||||||
|
} else {
|
||||||
|
format!("Import index {}", import_index)
|
||||||
|
};
|
||||||
|
|
||||||
|
(import_name, description)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let data_type = output_type.displayed_type();
|
||||||
|
let resolved_type = output_type.resolved_type_node_string();
|
||||||
|
let mut connected_to = self
|
||||||
|
.outward_wires(network_path)
|
||||||
|
.and_then(|outward_wires| outward_wires.get(output_connector))
|
||||||
|
.cloned()
|
||||||
|
.unwrap_or_default()
|
||||||
|
.iter()
|
||||||
|
.map(|input| match input {
|
||||||
|
InputConnector::Node { node_id, input_index } => {
|
||||||
|
let mut name = self.display_name(node_id, network_path);
|
||||||
|
if cfg!(debug_assertions) {
|
||||||
|
name.push_str(&format!(" (id: {node_id})"));
|
||||||
|
}
|
||||||
|
format!("{name} input {input_index}")
|
||||||
|
}
|
||||||
|
InputConnector::Export(export_index) => format!("Export index {export_index}"),
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
if connected_to.is_empty() {
|
||||||
|
connected_to.push("nothing".to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(FrontendGraphOutputOld {
|
||||||
|
data_type,
|
||||||
|
resolved_type,
|
||||||
|
name,
|
||||||
|
description,
|
||||||
|
connected_to,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn unload_import_export_wires_old(&mut self, network_path: &[NodeId]) {
|
||||||
|
// Always unload all wires connected to them as well
|
||||||
|
let number_of_imports = self.number_of_imports(network_path);
|
||||||
|
let Some(outward_wires) = self.outward_wires(network_path) else {
|
||||||
|
log::error!("Could not get outward wires in remove_import");
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let mut input_connectors = Vec::new();
|
||||||
|
for import_index in 0..number_of_imports {
|
||||||
|
let Some(outward_wires_for_import) = outward_wires.get(&OutputConnector::Import(import_index)).cloned() else {
|
||||||
|
log::error!("Could not get outward wires for import in remove_import");
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
input_connectors.extend(outward_wires_for_import);
|
||||||
|
}
|
||||||
|
let Some(network) = self.nested_network(network_path) else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
for export_index in 0..network.exports.len() {
|
||||||
|
input_connectors.push(InputConnector::Export(export_index));
|
||||||
|
}
|
||||||
|
for input in &input_connectors {
|
||||||
|
self.unload_wire_old(input, network_path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn newly_loaded_input_wire(&mut self, input: &InputConnector, graph_wire_style: GraphWireStyle, network_path: &[NodeId]) -> Option<WirePathUpdateOld> {
|
||||||
|
if !self.wire_is_loaded_old(input, network_path) {
|
||||||
|
self.load_wire_old(input, graph_wire_style, network_path);
|
||||||
|
} else {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let wire = match input {
|
||||||
|
InputConnector::Node { node_id, input_index } => {
|
||||||
|
let input_metadata = self.transient_input_metadata_old(node_id, *input_index, network_path)?;
|
||||||
|
let TransientMetadata::Loaded(wire) = &input_metadata.wire else {
|
||||||
|
log::error!("Could not load wire for input: {input:?}");
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
wire.clone()
|
||||||
|
}
|
||||||
|
InputConnector::Export(export_index) => {
|
||||||
|
let network_metadata = self.network_metadata(network_path)?;
|
||||||
|
let Some(TransientMetadata::Loaded(wire)) = network_metadata.transient_metadata.wires.get(*export_index) else {
|
||||||
|
log::error!("Could not load wire for input: {input:?}");
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
wire.clone()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Some(wire)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn wire_is_loaded_old(&mut self, input: &InputConnector, network_path: &[NodeId]) -> bool {
|
||||||
|
match input {
|
||||||
|
InputConnector::Node { node_id, input_index } => {
|
||||||
|
let Some(input_metadata) = self.transient_input_metadata_old(node_id, *input_index, network_path) else {
|
||||||
|
log::error!("Input metadata should always exist for input");
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
input_metadata.wire.is_loaded()
|
||||||
|
}
|
||||||
|
InputConnector::Export(export_index) => {
|
||||||
|
let Some(network_metadata) = self.network_metadata(network_path) else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
match network_metadata.transient_metadata.wires.get(*export_index) {
|
||||||
|
Some(wire) => wire.is_loaded(),
|
||||||
|
None => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load_wire_old(&mut self, input: &InputConnector, graph_wire_style: GraphWireStyle, network_path: &[NodeId]) {
|
||||||
|
let dashed = match self.previewing(network_path) {
|
||||||
|
Previewing::Yes { .. } => match input {
|
||||||
|
InputConnector::Node { .. } => false,
|
||||||
|
InputConnector::Export(export_index) => *export_index == 0,
|
||||||
|
},
|
||||||
|
Previewing::No => false,
|
||||||
|
};
|
||||||
|
let Some(wire) = self.wire_path_from_input_old(input, graph_wire_style, dashed, network_path) else {
|
||||||
|
log::error!("Could not load wire path from input");
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
match input {
|
||||||
|
InputConnector::Node { node_id, input_index } => {
|
||||||
|
let Some(node_metadata) = self.node_metadata_mut(node_id, network_path) else { return };
|
||||||
|
let Some(input_metadata) = node_metadata.persistent_metadata.input_metadata.get_mut(*input_index) else {
|
||||||
|
// log::warn!("Node metadata must exist on node: {input:?}");
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let wire_update = WirePathUpdateOld {
|
||||||
|
id: *node_id,
|
||||||
|
input_index: *input_index,
|
||||||
|
wire_path_update: Some(wire),
|
||||||
|
};
|
||||||
|
input_metadata.transient_metadata.wire = TransientMetadata::Loaded(wire_update);
|
||||||
|
}
|
||||||
|
InputConnector::Export(export_index) => {
|
||||||
|
let Some(network_metadata) = self.network_metadata_mut(network_path) else { return };
|
||||||
|
if *export_index >= network_metadata.transient_metadata.wires.len() {
|
||||||
|
network_metadata.transient_metadata.wires.resize(export_index + 1, TransientMetadata::Unloaded);
|
||||||
|
}
|
||||||
|
let Some(input_metadata) = network_metadata.transient_metadata.wires.get_mut(*export_index) else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let wire_update = WirePathUpdateOld {
|
||||||
|
id: NodeId(u64::MAX),
|
||||||
|
input_index: *export_index,
|
||||||
|
wire_path_update: Some(wire),
|
||||||
|
};
|
||||||
|
*input_metadata = TransientMetadata::Loaded(wire_update);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Maps to the frontend representation of a wire start. Includes disconnected value wire inputs.
|
||||||
|
pub fn node_graph_wire_inputs(&self, network_path: &[NodeId]) -> Vec<(NodeId, usize)> {
|
||||||
|
self.node_graph_input_connectors(network_path)
|
||||||
|
.iter()
|
||||||
|
.map(|input| match input {
|
||||||
|
InputConnector::Node { node_id, input_index } => (*node_id, *input_index),
|
||||||
|
InputConnector::Export(export_index) => (NodeId(u64::MAX), *export_index),
|
||||||
|
})
|
||||||
|
.chain(std::iter::once((NodeId(u64::MAX), u32::MAX as usize)))
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn unload_wires_for_node_old(&mut self, node_id: &NodeId, network_path: &[NodeId]) {
|
||||||
|
let number_of_outputs = self.number_of_outputs(node_id, network_path);
|
||||||
|
let Some(outward_wires) = self.outward_wires(network_path) else {
|
||||||
|
log::error!("Could not get outward wires in reorder_export");
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let mut input_connectors = Vec::new();
|
||||||
|
for output_index in 0..number_of_outputs {
|
||||||
|
let Some(inputs) = outward_wires.get(&OutputConnector::node(*node_id, output_index)) else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
input_connectors.extend(inputs.clone())
|
||||||
|
}
|
||||||
|
for input_index in 0..self.number_of_inputs(node_id, network_path) {
|
||||||
|
input_connectors.push(InputConnector::node(*node_id, input_index));
|
||||||
|
}
|
||||||
|
for input in input_connectors {
|
||||||
|
self.unload_wire_old(&input, network_path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn unload_wire_old(&mut self, input: &InputConnector, network_path: &[NodeId]) {
|
||||||
|
match input {
|
||||||
|
InputConnector::Node { node_id, input_index } => {
|
||||||
|
let Some(node_metadata) = self.node_metadata_mut(node_id, network_path) else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let Some(input_metadata) = node_metadata.persistent_metadata.input_metadata.get_mut(*input_index) else {
|
||||||
|
// log::warn!("Node metadata must exist on node: {input:?}");
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
input_metadata.transient_metadata.wire = TransientMetadata::Unloaded;
|
||||||
|
}
|
||||||
|
InputConnector::Export(export_index) => {
|
||||||
|
let Some(network_metadata) = self.network_metadata_mut(network_path) else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
if *export_index >= network_metadata.transient_metadata.wires.len() {
|
||||||
|
network_metadata.transient_metadata.wires.resize(export_index + 1, TransientMetadata::Unloaded);
|
||||||
|
}
|
||||||
|
let Some(input_metadata) = network_metadata.transient_metadata.wires.get_mut(*export_index) else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
*input_metadata = TransientMetadata::Unloaded;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// When previewing, there may be a second path to the root node.
|
||||||
|
pub fn wire_to_root_old(&mut self, graph_wire_style: GraphWireStyle, network_path: &[NodeId]) -> Option<WirePathUpdateOld> {
|
||||||
|
let input = InputConnector::Export(0);
|
||||||
|
let current_export = self.upstream_output_connector(&input, network_path)?;
|
||||||
|
|
||||||
|
let root_node = match self.previewing(network_path) {
|
||||||
|
Previewing::Yes { root_node_to_restore } => root_node_to_restore,
|
||||||
|
Previewing::No => None,
|
||||||
|
}?;
|
||||||
|
|
||||||
|
if Some(root_node.node_id) == current_export.node_id() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let Some(input_position) = self.get_input_center(&input, network_path) else {
|
||||||
|
log::error!("Could not get input position for wire end in root node: {input:?}");
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
let upstream_output = OutputConnector::node(root_node.node_id, root_node.output_index);
|
||||||
|
let Some(output_position) = self.get_output_center(&upstream_output, network_path) else {
|
||||||
|
log::error!("Could not get output position for wire start in root node: {upstream_output:?}");
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
let vertical_end = input.node_id().is_some_and(|node_id| self.is_layer(&node_id, network_path) && input.input_index() == 0);
|
||||||
|
let vertical_start: bool = upstream_output.node_id().is_some_and(|node_id| self.is_layer(&node_id, network_path));
|
||||||
|
let thick = vertical_end && vertical_start;
|
||||||
|
let vector_wire = build_vector_wire(output_position, input_position, vertical_start, vertical_end, graph_wire_style);
|
||||||
|
|
||||||
|
let path_string = vector_wire.to_svg();
|
||||||
|
let data_type = self.input_type(&input, network_path).displayed_type();
|
||||||
|
let wire_path_update = Some(WirePathOld {
|
||||||
|
path_string,
|
||||||
|
data_type,
|
||||||
|
thick,
|
||||||
|
dashed: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
Some(WirePathUpdateOld {
|
||||||
|
id: NodeId(u64::MAX),
|
||||||
|
input_index: u32::MAX as usize,
|
||||||
|
wire_path_update,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the vector subpath and a boolean of whether the wire should be thick.
|
||||||
|
pub fn vector_wire_from_input_old(&mut self, input: &InputConnector, wire_style: GraphWireStyle, network_path: &[NodeId]) -> Option<(BezPath, bool)> {
|
||||||
|
let Some(input_position) = self.get_input_center(input, network_path) else {
|
||||||
|
log::error!("Could not get dom rect for wire end: {input:?}");
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
// An upstream output could not be found, so the wire does not exist, but it should still be loaded as as empty vector
|
||||||
|
let Some(upstream_output) = self.upstream_output_connector(input, network_path) else {
|
||||||
|
return Some((BezPath::new(), false));
|
||||||
|
};
|
||||||
|
let Some(output_position) = self.get_output_center(&upstream_output, network_path) else {
|
||||||
|
log::error!("Could not get output port for wire start: {:?}", upstream_output);
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
let vertical_end = input.node_id().is_some_and(|node_id| self.is_layer(&node_id, network_path) && input.input_index() == 0);
|
||||||
|
let vertical_start = upstream_output.node_id().is_some_and(|node_id| self.is_layer(&node_id, network_path));
|
||||||
|
let thick = vertical_end && vertical_start;
|
||||||
|
Some((build_vector_wire(output_position, input_position, vertical_start, vertical_end, wire_style), thick))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn wire_path_from_input_old(&mut self, input: &InputConnector, graph_wire_style: GraphWireStyle, dashed: bool, network_path: &[NodeId]) -> Option<WirePathOld> {
|
||||||
|
let (vector_wire, thick) = self.vector_wire_from_input_old(input, graph_wire_style, network_path)?;
|
||||||
|
let path_string = vector_wire.to_svg();
|
||||||
|
let data_type = self
|
||||||
|
.upstream_output_connector(input, network_path)
|
||||||
|
.as_ref()
|
||||||
|
.map(|output| self.output_type(output, network_path).displayed_type())
|
||||||
|
.unwrap_or(FrontendGraphDataType::General);
|
||||||
|
Some(WirePathOld {
|
||||||
|
path_string,
|
||||||
|
data_type,
|
||||||
|
thick,
|
||||||
|
dashed,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn collect_layer_widths_old(&mut self, network_path: &[NodeId]) -> (HashMap<NodeId, u32>, HashMap<NodeId, u32>, HashMap<NodeId, bool>) {
|
||||||
|
let Some(network_metadata) = self.network_metadata(network_path) else {
|
||||||
|
log::error!("Could not get nested network_metadata in collect_layer_widths");
|
||||||
|
return (HashMap::new(), HashMap::new(), HashMap::new());
|
||||||
|
};
|
||||||
|
let nodes = network_metadata
|
||||||
|
.persistent_metadata
|
||||||
|
.node_metadata
|
||||||
|
.iter()
|
||||||
|
.filter_map(|(node_id, _)| if self.is_layer(node_id, network_path) { Some(*node_id) } else { None })
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
let layer_widths = nodes
|
||||||
|
.iter()
|
||||||
|
.filter_map(|node_id| self.layer_width(node_id, network_path).map(|layer_width| (*node_id, layer_width)))
|
||||||
|
.collect::<HashMap<NodeId, u32>>();
|
||||||
|
let chain_widths = nodes.iter().map(|node_id| (*node_id, self.chain_width(node_id, network_path))).collect::<HashMap<NodeId, u32>>();
|
||||||
|
let has_left_input_wire = nodes
|
||||||
|
.iter()
|
||||||
|
.map(|node_id| {
|
||||||
|
(
|
||||||
|
*node_id,
|
||||||
|
!self
|
||||||
|
.upstream_flow_back_from_nodes(vec![*node_id], network_path, FlowType::HorizontalFlow)
|
||||||
|
.skip(1)
|
||||||
|
.all(|node_id| self.is_chain(&node_id, network_path)),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.collect::<HashMap<NodeId, bool>>();
|
||||||
|
|
||||||
|
(layer_widths, chain_widths, has_left_input_wire)
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
-1
@@ -4,11 +4,11 @@ use graph_craft::document::value::TaggedValue;
|
|||||||
use graph_craft::document::{DocumentNodeImplementation, InlineRust, NodeInput};
|
use graph_craft::document::{DocumentNodeImplementation, InlineRust, NodeInput};
|
||||||
use graph_craft::proto::GraphErrors;
|
use graph_craft::proto::GraphErrors;
|
||||||
use graph_craft::{Type, concrete};
|
use graph_craft::{Type, concrete};
|
||||||
|
use graphene_std::node_graph_overlay::types::FrontendGraphDataType;
|
||||||
use graphene_std::uuid::NodeId;
|
use graphene_std::uuid::NodeId;
|
||||||
use interpreted_executor::dynamic_executor::{NodeTypes, ResolvedDocumentNodeTypesDelta};
|
use interpreted_executor::dynamic_executor::{NodeTypes, ResolvedDocumentNodeTypesDelta};
|
||||||
use interpreted_executor::node_registry::NODE_REGISTRY;
|
use interpreted_executor::node_registry::NODE_REGISTRY;
|
||||||
|
|
||||||
use crate::messages::portfolio::document::node_graph::utility_types::FrontendGraphDataType;
|
|
||||||
use crate::messages::portfolio::document::utility_types::network_interface::{InputConnector, NodeNetworkInterface, OutputConnector};
|
use crate::messages::portfolio::document::utility_types::network_interface::{InputConnector, NodeNetworkInterface, OutputConnector};
|
||||||
|
|
||||||
// This file contains utility methods for interfacing with the resolved types returned from the compiler
|
// This file contains utility methods for interfacing with the resolved types returned from the compiler
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
use crate::messages::portfolio::document::node_graph::utility_types::FrontendGraphDataType;
|
|
||||||
use glam::{DVec2, IVec2};
|
use glam::{DVec2, IVec2};
|
||||||
|
use graphene_std::node_graph_overlay::types::FrontendGraphDataType;
|
||||||
use graphene_std::{uuid::NodeId, vector::misc::dvec2_to_point};
|
use graphene_std::{uuid::NodeId, vector::misc::dvec2_to_point};
|
||||||
use kurbo::{BezPath, DEFAULT_ACCURACY, Line, Point, Shape};
|
use kurbo::{BezPath, DEFAULT_ACCURACY, Line, Point, Shape};
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize, specta::Type)]
|
#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize, specta::Type)]
|
||||||
pub struct WirePath {
|
pub struct WirePathOld {
|
||||||
#[serde(rename = "pathString")]
|
#[serde(rename = "pathString")]
|
||||||
pub path_string: String,
|
pub path_string: String,
|
||||||
#[serde(rename = "dataType")]
|
#[serde(rename = "dataType")]
|
||||||
@@ -14,13 +14,21 @@ pub struct WirePath {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize, specta::Type)]
|
#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize, specta::Type)]
|
||||||
pub struct WirePathUpdate {
|
pub struct WirePathUpdateOld {
|
||||||
pub id: NodeId,
|
pub id: NodeId,
|
||||||
#[serde(rename = "inputIndex")]
|
#[serde(rename = "inputIndex")]
|
||||||
pub input_index: usize,
|
pub input_index: usize,
|
||||||
// If none, then remove the wire from the map
|
// If none, then remove the wire from the map
|
||||||
#[serde(rename = "wirePathUpdate")]
|
#[serde(rename = "wirePathUpdate")]
|
||||||
pub wire_path_update: Option<WirePath>,
|
pub wire_path_update: Option<WirePathOld>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize, specta::Type)]
|
||||||
|
pub struct WirePathInProgress {
|
||||||
|
pub wire: String,
|
||||||
|
#[serde(rename = "dataType")]
|
||||||
|
pub data_type: FrontendGraphDataType,
|
||||||
|
pub thick: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Default, serde::Serialize, serde::Deserialize, specta::Type)]
|
#[derive(Copy, Clone, Debug, PartialEq, Default, serde::Serialize, serde::Deserialize, specta::Type)]
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ pub struct MenuBarMessageHandler {
|
|||||||
pub has_selection_history: (bool, bool),
|
pub has_selection_history: (bool, bool),
|
||||||
pub message_logging_verbosity: MessageLoggingVerbosity,
|
pub message_logging_verbosity: MessageLoggingVerbosity,
|
||||||
pub reset_node_definitions_on_open: bool,
|
pub reset_node_definitions_on_open: bool,
|
||||||
|
pub render_native_node_graph: bool,
|
||||||
pub make_path_editable_is_allowed: bool,
|
pub make_path_editable_is_allowed: bool,
|
||||||
pub data_panel_open: bool,
|
pub data_panel_open: bool,
|
||||||
pub layers_panel_open: bool,
|
pub layers_panel_open: bool,
|
||||||
@@ -48,6 +49,7 @@ impl LayoutHolder for MenuBarMessageHandler {
|
|||||||
let message_logging_verbosity_names = self.message_logging_verbosity == MessageLoggingVerbosity::Names;
|
let message_logging_verbosity_names = self.message_logging_verbosity == MessageLoggingVerbosity::Names;
|
||||||
let message_logging_verbosity_contents = self.message_logging_verbosity == MessageLoggingVerbosity::Contents;
|
let message_logging_verbosity_contents = self.message_logging_verbosity == MessageLoggingVerbosity::Contents;
|
||||||
let reset_node_definitions_on_open = self.reset_node_definitions_on_open;
|
let reset_node_definitions_on_open = self.reset_node_definitions_on_open;
|
||||||
|
let render_native_node_graph = self.render_native_node_graph;
|
||||||
let make_path_editable_is_allowed = self.make_path_editable_is_allowed;
|
let make_path_editable_is_allowed = self.make_path_editable_is_allowed;
|
||||||
|
|
||||||
let menu_bar_entries = vec![
|
let menu_bar_entries = vec![
|
||||||
@@ -696,6 +698,12 @@ impl LayoutHolder for MenuBarMessageHandler {
|
|||||||
action: MenuBarEntry::create_action(|_| PortfolioMessage::ToggleResetNodesToDefinitionsOnOpen.into()),
|
action: MenuBarEntry::create_action(|_| PortfolioMessage::ToggleResetNodesToDefinitionsOnOpen.into()),
|
||||||
..MenuBarEntry::default()
|
..MenuBarEntry::default()
|
||||||
}],
|
}],
|
||||||
|
vec![MenuBarEntry {
|
||||||
|
label: " Render Native Node Graph UI".into(),
|
||||||
|
icon: Some(if render_native_node_graph { "CheckboxChecked" } else { "CheckboxUnchecked" }.into()),
|
||||||
|
action: MenuBarEntry::create_action(|_| PortfolioMessage::ToggleRenderNativeNodeGraph.into()),
|
||||||
|
..MenuBarEntry::default()
|
||||||
|
}],
|
||||||
vec![
|
vec![
|
||||||
MenuBarEntry {
|
MenuBarEntry {
|
||||||
label: "Print Trace Logs".into(),
|
label: "Print Trace Logs".into(),
|
||||||
|
|||||||
@@ -81,6 +81,7 @@ pub enum PortfolioMessage {
|
|||||||
to_front: bool,
|
to_front: bool,
|
||||||
select_after_open: bool,
|
select_after_open: bool,
|
||||||
},
|
},
|
||||||
|
ToggleRenderNativeNodeGraph,
|
||||||
ToggleResetNodesToDefinitionsOnOpen,
|
ToggleResetNodesToDefinitionsOnOpen,
|
||||||
PasteIntoFolder {
|
PasteIntoFolder {
|
||||||
clipboard: Clipboard,
|
clipboard: Clipboard,
|
||||||
|
|||||||
@@ -63,6 +63,7 @@ pub struct PortfolioMessageHandler {
|
|||||||
pub layers_panel_open: bool,
|
pub layers_panel_open: bool,
|
||||||
#[derivative(Default(value = "true"))]
|
#[derivative(Default(value = "true"))]
|
||||||
pub properties_panel_open: bool,
|
pub properties_panel_open: bool,
|
||||||
|
pub render_native_node_graph: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[message_handler_data]
|
#[message_handler_data]
|
||||||
@@ -111,6 +112,7 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageContext<'_>> for Portfolio
|
|||||||
(!metadata.selection_undo_history.is_empty(), !metadata.selection_redo_history.is_empty())
|
(!metadata.selection_undo_history.is_empty(), !metadata.selection_redo_history.is_empty())
|
||||||
};
|
};
|
||||||
self.menu_bar_message_handler.make_path_editable_is_allowed = make_path_editable_is_allowed(&mut document.network_interface).is_some();
|
self.menu_bar_message_handler.make_path_editable_is_allowed = make_path_editable_is_allowed(&mut document.network_interface).is_some();
|
||||||
|
self.menu_bar_message_handler.render_native_node_graph = self.render_native_node_graph;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.menu_bar_message_handler.process_message(message, responses, ());
|
self.menu_bar_message_handler.process_message(message, responses, ());
|
||||||
@@ -129,6 +131,7 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageContext<'_>> for Portfolio
|
|||||||
data_panel_open: self.data_panel_open,
|
data_panel_open: self.data_panel_open,
|
||||||
layers_panel_open: self.layers_panel_open,
|
layers_panel_open: self.layers_panel_open,
|
||||||
properties_panel_open: self.properties_panel_open,
|
properties_panel_open: self.properties_panel_open,
|
||||||
|
render_native_node_graph: self.render_native_node_graph,
|
||||||
};
|
};
|
||||||
document.process_message(message, responses, document_inputs)
|
document.process_message(message, responses, document_inputs)
|
||||||
}
|
}
|
||||||
@@ -170,6 +173,7 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageContext<'_>> for Portfolio
|
|||||||
data_panel_open: self.data_panel_open,
|
data_panel_open: self.data_panel_open,
|
||||||
layers_panel_open: self.layers_panel_open,
|
layers_panel_open: self.layers_panel_open,
|
||||||
properties_panel_open: self.properties_panel_open,
|
properties_panel_open: self.properties_panel_open,
|
||||||
|
render_native_node_graph: self.render_native_node_graph,
|
||||||
};
|
};
|
||||||
document.process_message(message, responses, document_inputs)
|
document.process_message(message, responses, document_inputs)
|
||||||
}
|
}
|
||||||
@@ -442,6 +446,13 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageContext<'_>> for Portfolio
|
|||||||
select_after_open: true,
|
select_after_open: true,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
PortfolioMessage::ToggleRenderNativeNodeGraph => {
|
||||||
|
self.render_native_node_graph = !self.render_native_node_graph;
|
||||||
|
responses.add(FrontendMessage::UpdateRenderNativeNodeGraph {
|
||||||
|
render_native_node_graph: self.render_native_node_graph,
|
||||||
|
});
|
||||||
|
responses.add(NodeGraphMessage::SendGraph);
|
||||||
|
}
|
||||||
PortfolioMessage::ToggleResetNodesToDefinitionsOnOpen => {
|
PortfolioMessage::ToggleResetNodesToDefinitionsOnOpen => {
|
||||||
self.reset_node_definitions_on_open = !self.reset_node_definitions_on_open;
|
self.reset_node_definitions_on_open = !self.reset_node_definitions_on_open;
|
||||||
responses.add(MenuBarMessage::SendLayout);
|
responses.add(MenuBarMessage::SendLayout);
|
||||||
@@ -914,8 +925,8 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageContext<'_>> for Portfolio
|
|||||||
responses.add(DocumentMessage::GraphViewOverlay { open: node_graph_open });
|
responses.add(DocumentMessage::GraphViewOverlay { open: node_graph_open });
|
||||||
if node_graph_open {
|
if node_graph_open {
|
||||||
responses.add(NodeGraphMessage::UpdateGraphBarRight);
|
responses.add(NodeGraphMessage::UpdateGraphBarRight);
|
||||||
responses.add(NodeGraphMessage::UnloadWires);
|
responses.add(NodeGraphMessage::UnloadWiresOld);
|
||||||
responses.add(NodeGraphMessage::SendWires)
|
responses.add(NodeGraphMessage::SendWiresOld)
|
||||||
} else {
|
} else {
|
||||||
responses.add(PortfolioMessage::UpdateDocumentWidgets);
|
responses.add(PortfolioMessage::UpdateDocumentWidgets);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -87,8 +87,7 @@ impl MessageHandler<PreferencesMessage, ()> for PreferencesMessageHandler {
|
|||||||
}
|
}
|
||||||
PreferencesMessage::GraphWireStyle { style } => {
|
PreferencesMessage::GraphWireStyle { style } => {
|
||||||
self.graph_wire_style = style;
|
self.graph_wire_style = style;
|
||||||
responses.add(NodeGraphMessage::UnloadWires);
|
responses.add(NodeGraphMessage::SendGraph);
|
||||||
responses.add(NodeGraphMessage::SendWires);
|
|
||||||
}
|
}
|
||||||
PreferencesMessage::ViewportZoomWheelRate { rate } => {
|
PreferencesMessage::ViewportZoomWheelRate { rate } => {
|
||||||
self.viewport_zoom_wheel_rate = rate;
|
self.viewport_zoom_wheel_rate = rate;
|
||||||
|
|||||||
@@ -326,11 +326,11 @@ pub trait FrontendMessageTestUtils {
|
|||||||
|
|
||||||
impl FrontendMessageTestUtils for FrontendMessage {
|
impl FrontendMessageTestUtils for FrontendMessage {
|
||||||
fn check_node_graph_error(&self) {
|
fn check_node_graph_error(&self) {
|
||||||
let FrontendMessage::UpdateNodeGraphNodes { nodes, .. } = self else { return };
|
let FrontendMessage::UpdateNodeGraphRenderNew { nodes_to_render, .. } = self else { return };
|
||||||
|
|
||||||
for node in nodes {
|
for node in nodes_to_render {
|
||||||
if let Some(error) = &node.errors {
|
if let Some(error) = &node.metadata.errors {
|
||||||
panic!("error on {}: {}", node.display_name, error);
|
panic!("error on {}: {}", node.metadata.display_name, error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -569,7 +569,7 @@
|
|||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="graph-view" class:open={$document.graphViewOverlayOpen} style:--fade-artwork={`${$document.fadeArtwork}%`} data-graph>
|
<div class="graph-view" class:open={$document.graphViewOverlayOpen} data-graph>
|
||||||
<Graph />
|
<Graph />
|
||||||
</div>
|
</div>
|
||||||
</LayoutCol>
|
</LayoutCol>
|
||||||
@@ -768,7 +768,7 @@
|
|||||||
.viewport-container-inner-2 {
|
.viewport-container-inner-2 {
|
||||||
flex: 1 1 100%;
|
flex: 1 1 100%;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
.viewport {
|
.viewport {
|
||||||
background: var(--color-2-mildblack);
|
background: var(--color-2-mildblack);
|
||||||
}
|
}
|
||||||
@@ -852,7 +852,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.fade-artwork,
|
|
||||||
.graph {
|
.graph {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,14 @@
|
|||||||
|
These components will continue to be rendered in svelte after the first stage of native node graph rendering.
|
||||||
|
- Import and export ports
|
||||||
|
- Wires to import and export
|
||||||
|
- Wire in progress
|
||||||
|
- Add Node context menu
|
||||||
|
- Toggle Layer context menu
|
||||||
|
- Error dialog
|
||||||
|
- Node/Input/Output Tooltips (disabled until tooltip system)
|
||||||
|
- Solo drag grip tooltip (disabled until tooltip system)
|
||||||
|
|
||||||
|
These elements will be not be rendered in svelte when rendering the native node graph. They are rendered below all other components
|
||||||
|
- Dot grid background
|
||||||
|
- Nodes/Layers
|
||||||
|
- Wires between nodes/layers
|
||||||
+96
-53
@@ -25,33 +25,46 @@ export type XY = { x: number; y: number };
|
|||||||
// for details about how to transform the JSON from wasm-bindgen into classes.
|
// for details about how to transform the JSON from wasm-bindgen into classes.
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
export class UpdateBox extends JsMessage {
|
|
||||||
readonly box!: Box | undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class UpdateClickTargets extends JsMessage {
|
export class UpdateClickTargets extends JsMessage {
|
||||||
readonly clickTargets!: FrontendClickTargets | undefined;
|
readonly clickTargets!: FrontendClickTargets | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class FrontendSelectionBox {
|
||||||
|
readonly startX!: number;
|
||||||
|
|
||||||
|
readonly startY!: number;
|
||||||
|
|
||||||
|
readonly endX!: number;
|
||||||
|
|
||||||
|
readonly endY!: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class UpdateNodeGraphSelectionBox extends JsMessage {
|
||||||
|
readonly box!: FrontendSelectionBox | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
export class UpdateContextMenuInformation extends JsMessage {
|
export class UpdateContextMenuInformation extends JsMessage {
|
||||||
readonly contextMenuInformation!: ContextMenuInformation | undefined;
|
readonly contextMenuInformation!: ContextMenuInformation | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type ContextMenuInformation = {
|
||||||
|
contextMenuCoordinates: XY;
|
||||||
|
contextMenuData: { type: "CreateNode"; data: { compatibleType: string | undefined } } | { type: "ModifyNode"; data: { canBeLayer: boolean; currentlyIsNode: boolean; nodeId: bigint } };
|
||||||
|
};
|
||||||
|
|
||||||
export class UpdateImportsExports extends JsMessage {
|
export class UpdateImportsExports extends JsMessage {
|
||||||
readonly imports!: (FrontendGraphOutput | undefined)[];
|
readonly imports!: (FrontendImport | undefined)[];
|
||||||
|
|
||||||
readonly exports!: (FrontendGraphInput | undefined)[];
|
readonly exports!: FrontendExports;
|
||||||
|
|
||||||
@TupleToVec2
|
|
||||||
readonly importPosition!: XY;
|
readonly importPosition!: XY;
|
||||||
|
|
||||||
@TupleToVec2
|
|
||||||
readonly exportPosition!: XY;
|
readonly exportPosition!: XY;
|
||||||
|
|
||||||
readonly addImportExport!: boolean;
|
readonly addImportExport!: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class UpdateInSelectedNetwork extends JsMessage {
|
export class UpdateInSelectedNetworkOld extends JsMessage {
|
||||||
readonly inSelectedNetwork!: boolean;
|
readonly inSelectedNetwork!: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,7 +80,7 @@ const LayerWidths = Transform(({ obj }) => obj.layerWidths);
|
|||||||
const ChainWidths = Transform(({ obj }) => obj.chainWidths);
|
const ChainWidths = Transform(({ obj }) => obj.chainWidths);
|
||||||
const HasLeftInputWire = Transform(({ obj }) => obj.hasLeftInputWire);
|
const HasLeftInputWire = Transform(({ obj }) => obj.hasLeftInputWire);
|
||||||
|
|
||||||
export class UpdateLayerWidths extends JsMessage {
|
export class UpdateLayerWidthsOld extends JsMessage {
|
||||||
@LayerWidths
|
@LayerWidths
|
||||||
readonly layerWidths!: Map<bigint, number>;
|
readonly layerWidths!: Map<bigint, number>;
|
||||||
@ChainWidths
|
@ChainWidths
|
||||||
@@ -76,9 +89,9 @@ export class UpdateLayerWidths extends JsMessage {
|
|||||||
readonly hasLeftInputWire!: Map<bigint, boolean>;
|
readonly hasLeftInputWire!: Map<bigint, boolean>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class UpdateNodeGraphNodes extends JsMessage {
|
export class UpdateNodeGraphNodesOld extends JsMessage {
|
||||||
@Type(() => FrontendNode)
|
@Type(() => FrontendNodeOld)
|
||||||
readonly nodes!: FrontendNode[];
|
readonly nodes!: FrontendNodeOld[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export class UpdateNodeGraphError extends JsMessage {
|
export class UpdateNodeGraphError extends JsMessage {
|
||||||
@@ -90,15 +103,15 @@ export class NodeGraphError {
|
|||||||
readonly error!: string;
|
readonly error!: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class UpdateVisibleNodes extends JsMessage {
|
export class UpdateVisibleNodesOld extends JsMessage {
|
||||||
readonly nodes!: bigint[];
|
readonly nodes!: bigint[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export class UpdateNodeGraphWires extends JsMessage {
|
export class UpdateNodeGraphWiresOld extends JsMessage {
|
||||||
readonly wires!: WireUpdate[];
|
readonly wires!: WireUpdateOld[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ClearAllNodeGraphWires extends JsMessage {}
|
export class ClearAllNodeGraphWiresOld extends JsMessage {}
|
||||||
|
|
||||||
export class UpdateNodeGraphTransform extends JsMessage {
|
export class UpdateNodeGraphTransform extends JsMessage {
|
||||||
readonly transform!: NodeGraphTransform;
|
readonly transform!: NodeGraphTransform;
|
||||||
@@ -109,7 +122,7 @@ const NodeDescriptions = Transform(({ obj }) => new Map(obj.nodeDescriptions));
|
|||||||
export class SendUIMetadata extends JsMessage {
|
export class SendUIMetadata extends JsMessage {
|
||||||
@NodeDescriptions
|
@NodeDescriptions
|
||||||
readonly nodeDescriptions!: Map<string, string>;
|
readonly nodeDescriptions!: Map<string, string>;
|
||||||
@Type(() => FrontendNode)
|
@Type(() => FrontendNodeOld)
|
||||||
readonly nodeTypes!: FrontendNodeType[];
|
readonly nodeTypes!: FrontendNodeType[];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -119,7 +132,7 @@ export class UpdateNodeThumbnail extends JsMessage {
|
|||||||
readonly value!: string;
|
readonly value!: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class UpdateNodeGraphSelection extends JsMessage {
|
export class UpdateNodeGraphSelectionOld extends JsMessage {
|
||||||
@Type(() => BigInt)
|
@Type(() => BigInt)
|
||||||
readonly selected!: bigint[];
|
readonly selected!: bigint[];
|
||||||
}
|
}
|
||||||
@@ -129,8 +142,18 @@ export class UpdateOpenDocumentsList extends JsMessage {
|
|||||||
readonly openDocuments!: OpenDocument[];
|
readonly openDocuments!: OpenDocument[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class WirePathInProgress {
|
||||||
|
readonly wire!: string;
|
||||||
|
readonly thick!: boolean;
|
||||||
|
readonly dataType!: FrontendGraphDataType;
|
||||||
|
}
|
||||||
|
|
||||||
export class UpdateWirePathInProgress extends JsMessage {
|
export class UpdateWirePathInProgress extends JsMessage {
|
||||||
readonly wirePath!: WirePath | undefined;
|
readonly wirePathInProgress!: WirePathInProgress | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class UpdateRenderNativeNodeGraph extends JsMessage {
|
||||||
|
readonly renderNativeNodeGraph!: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class OpenDocument {
|
export class OpenDocument {
|
||||||
@@ -148,14 +171,8 @@ export class DocumentDetails {
|
|||||||
readonly isSaved!: boolean;
|
readonly isSaved!: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Box {
|
export class FrontendDocumentDetails extends DocumentDetails {
|
||||||
readonly startX!: number;
|
readonly id!: bigint;
|
||||||
|
|
||||||
readonly startY!: number;
|
|
||||||
|
|
||||||
readonly endX!: number;
|
|
||||||
|
|
||||||
readonly endY!: number;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export type FrontendClickTargets = {
|
export type FrontendClickTargets = {
|
||||||
@@ -167,14 +184,9 @@ export type FrontendClickTargets = {
|
|||||||
readonly modifyImportExport: string[];
|
readonly modifyImportExport: string[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export type ContextMenuInformation = {
|
|
||||||
contextMenuCoordinates: XY;
|
|
||||||
contextMenuData: { type: "CreateNode"; data: { compatibleType: string | undefined } } | { type: "ModifyNode"; data: { canBeLayer: boolean; currentlyIsNode: boolean; nodeId: bigint } };
|
|
||||||
};
|
|
||||||
|
|
||||||
export type FrontendGraphDataType = "General" | "Number" | "Artboard" | "Graphic" | "Raster" | "Vector" | "Color" | "Invalid";
|
export type FrontendGraphDataType = "General" | "Number" | "Artboard" | "Graphic" | "Raster" | "Vector" | "Color" | "Invalid";
|
||||||
|
|
||||||
export class FrontendGraphInput {
|
export class FrontendGraphInputOld {
|
||||||
readonly dataType!: FrontendGraphDataType;
|
readonly dataType!: FrontendGraphDataType;
|
||||||
|
|
||||||
readonly name!: string;
|
readonly name!: string;
|
||||||
@@ -188,7 +200,15 @@ export class FrontendGraphInput {
|
|||||||
readonly connectedTo!: string;
|
readonly connectedTo!: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class FrontendGraphOutput {
|
export class FrontendGraphInputNew {
|
||||||
|
readonly dataType!: FrontendGraphDataType;
|
||||||
|
|
||||||
|
readonly name!: string;
|
||||||
|
|
||||||
|
readonly connectedToNode!: bigint | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class FrontendGraphOutputOld {
|
||||||
readonly dataType!: FrontendGraphDataType;
|
readonly dataType!: FrontendGraphDataType;
|
||||||
|
|
||||||
readonly name!: string;
|
readonly name!: string;
|
||||||
@@ -199,8 +219,30 @@ export class FrontendGraphOutput {
|
|||||||
|
|
||||||
readonly connectedTo!: string[];
|
readonly connectedTo!: string[];
|
||||||
}
|
}
|
||||||
|
export class FrontendGraphOutputNew {
|
||||||
|
readonly dataType!: FrontendGraphDataType;
|
||||||
|
|
||||||
export class FrontendNode {
|
readonly name!: string;
|
||||||
|
|
||||||
|
readonly connected!: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class FrontendExport {
|
||||||
|
readonly port!: FrontendGraphInputNew;
|
||||||
|
readonly wire!: string | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class FrontendExports {
|
||||||
|
readonly exports!: (FrontendExport | undefined)[];
|
||||||
|
readonly previewWire!: string | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class FrontendImport {
|
||||||
|
readonly port!: FrontendGraphOutputNew;
|
||||||
|
readonly wires!: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export class FrontendNodeOld {
|
||||||
readonly isLayer!: boolean;
|
readonly isLayer!: boolean;
|
||||||
|
|
||||||
readonly canBeLayer!: boolean;
|
readonly canBeLayer!: boolean;
|
||||||
@@ -211,13 +253,13 @@ export class FrontendNode {
|
|||||||
|
|
||||||
readonly displayName!: string;
|
readonly displayName!: string;
|
||||||
|
|
||||||
readonly primaryInput!: FrontendGraphInput | undefined;
|
readonly primaryInput!: FrontendGraphInputOld | undefined;
|
||||||
|
|
||||||
readonly exposedInputs!: FrontendGraphInput[];
|
readonly exposedInputs!: FrontendGraphInputOld[];
|
||||||
|
|
||||||
readonly primaryOutput!: FrontendGraphOutput | undefined;
|
readonly primaryOutput!: FrontendGraphOutputOld | undefined;
|
||||||
|
|
||||||
readonly exposedOutputs!: FrontendGraphOutput[];
|
readonly exposedOutputs!: FrontendGraphOutputOld[];
|
||||||
|
|
||||||
readonly primaryInputConnectedToLayer!: boolean;
|
readonly primaryInputConnectedToLayer!: boolean;
|
||||||
|
|
||||||
@@ -251,17 +293,17 @@ export class NodeGraphTransform {
|
|||||||
readonly y!: number;
|
readonly y!: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class WirePath {
|
export class WirePathOld {
|
||||||
readonly pathString!: string;
|
readonly pathString!: string;
|
||||||
readonly dataType!: FrontendGraphDataType;
|
readonly dataType!: FrontendGraphDataType;
|
||||||
readonly thick!: boolean;
|
readonly thick!: boolean;
|
||||||
readonly dashed!: boolean;
|
readonly dashed!: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class WireUpdate {
|
export class WireUpdateOld {
|
||||||
readonly id!: bigint;
|
readonly id!: bigint;
|
||||||
readonly inputIndex!: number;
|
readonly inputIndex!: number;
|
||||||
readonly wirePathUpdate!: WirePath | undefined;
|
readonly wirePathUpdate!: WirePathOld | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class TriggerPersistenceWriteDocument extends JsMessage {
|
export class TriggerPersistenceWriteDocument extends JsMessage {
|
||||||
@@ -695,7 +737,7 @@ export class UpdateGraphViewOverlay extends JsMessage {
|
|||||||
open!: boolean;
|
open!: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class UpdateGraphFadeArtwork extends JsMessage {
|
export class UpdateGraphFadeArtworkOld extends JsMessage {
|
||||||
readonly percentage!: number;
|
readonly percentage!: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1627,7 +1669,7 @@ type JSMessageFactory = (data: any, wasm: WebAssembly.Memory, handle: EditorHand
|
|||||||
type MessageMaker = typeof JsMessage | JSMessageFactory;
|
type MessageMaker = typeof JsMessage | JSMessageFactory;
|
||||||
|
|
||||||
export const messageMakers: Record<string, MessageMaker> = {
|
export const messageMakers: Record<string, MessageMaker> = {
|
||||||
ClearAllNodeGraphWires,
|
ClearAllNodeGraphWiresOld,
|
||||||
DisplayDialog,
|
DisplayDialog,
|
||||||
DisplayDialogDismiss,
|
DisplayDialogDismiss,
|
||||||
DisplayDialogPanic,
|
DisplayDialogPanic,
|
||||||
@@ -1656,7 +1698,6 @@ export const messageMakers: Record<string, MessageMaker> = {
|
|||||||
TriggerTextCopy,
|
TriggerTextCopy,
|
||||||
TriggerVisitLink,
|
TriggerVisitLink,
|
||||||
UpdateActiveDocument,
|
UpdateActiveDocument,
|
||||||
UpdateBox,
|
|
||||||
UpdateClickTargets,
|
UpdateClickTargets,
|
||||||
UpdateContextMenuInformation,
|
UpdateContextMenuInformation,
|
||||||
UpdateDialogButtons,
|
UpdateDialogButtons,
|
||||||
@@ -1671,25 +1712,26 @@ export const messageMakers: Record<string, MessageMaker> = {
|
|||||||
UpdateDocumentScrollbars,
|
UpdateDocumentScrollbars,
|
||||||
UpdateExportReorderIndex,
|
UpdateExportReorderIndex,
|
||||||
UpdateEyedropperSamplingState,
|
UpdateEyedropperSamplingState,
|
||||||
UpdateGraphFadeArtwork,
|
UpdateGraphFadeArtworkOld,
|
||||||
UpdateGraphViewOverlay,
|
UpdateGraphViewOverlay,
|
||||||
UpdateImportReorderIndex,
|
UpdateImportReorderIndex,
|
||||||
UpdateImportsExports,
|
UpdateImportsExports,
|
||||||
UpdateInputHints,
|
UpdateInputHints,
|
||||||
UpdateInSelectedNetwork,
|
UpdateInSelectedNetworkOld,
|
||||||
UpdateLayersPanelBottomBarLayout,
|
UpdateLayersPanelBottomBarLayout,
|
||||||
UpdateLayersPanelControlBarLeftLayout,
|
UpdateLayersPanelControlBarLeftLayout,
|
||||||
UpdateLayersPanelControlBarRightLayout,
|
UpdateLayersPanelControlBarRightLayout,
|
||||||
UpdateLayerWidths,
|
UpdateLayerWidthsOld,
|
||||||
UpdateMaximized,
|
UpdateMaximized,
|
||||||
UpdateMenuBarLayout,
|
UpdateMenuBarLayout,
|
||||||
UpdateMouseCursor,
|
UpdateMouseCursor,
|
||||||
UpdateNodeGraphControlBarLayout,
|
UpdateNodeGraphControlBarLayout,
|
||||||
UpdateNodeGraphNodes,
|
UpdateNodeGraphNodesOld,
|
||||||
UpdateNodeGraphError,
|
UpdateNodeGraphError,
|
||||||
UpdateNodeGraphSelection,
|
UpdateNodeGraphSelectionOld,
|
||||||
|
UpdateNodeGraphSelectionBox,
|
||||||
UpdateNodeGraphTransform,
|
UpdateNodeGraphTransform,
|
||||||
UpdateNodeGraphWires,
|
UpdateNodeGraphWiresOld,
|
||||||
UpdateNodeThumbnail,
|
UpdateNodeThumbnail,
|
||||||
UpdateOpenDocumentsList,
|
UpdateOpenDocumentsList,
|
||||||
UpdatePlatform,
|
UpdatePlatform,
|
||||||
@@ -1701,8 +1743,9 @@ export const messageMakers: Record<string, MessageMaker> = {
|
|||||||
UpdateToolOptionsLayout,
|
UpdateToolOptionsLayout,
|
||||||
UpdateToolShelfLayout,
|
UpdateToolShelfLayout,
|
||||||
UpdateViewportHolePunch,
|
UpdateViewportHolePunch,
|
||||||
UpdateVisibleNodes,
|
UpdateVisibleNodesOld,
|
||||||
UpdateWirePathInProgress,
|
UpdateWirePathInProgress,
|
||||||
|
UpdateRenderNativeNodeGraph,
|
||||||
UpdateWorkingColorsLayout,
|
UpdateWorkingColorsLayout,
|
||||||
} as const;
|
} as const;
|
||||||
export type JsMessageType = keyof typeof messageMakers;
|
export type JsMessageType = keyof typeof messageMakers;
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ import {
|
|||||||
UpdateWorkingColorsLayout,
|
UpdateWorkingColorsLayout,
|
||||||
UpdateNodeGraphControlBarLayout,
|
UpdateNodeGraphControlBarLayout,
|
||||||
UpdateGraphViewOverlay,
|
UpdateGraphViewOverlay,
|
||||||
UpdateGraphFadeArtwork,
|
|
||||||
} from "@graphite/messages";
|
} from "@graphite/messages";
|
||||||
|
|
||||||
export function createDocumentState(editor: Editor) {
|
export function createDocumentState(editor: Editor) {
|
||||||
@@ -25,19 +24,11 @@ export function createDocumentState(editor: Editor) {
|
|||||||
toolShelfLayout: defaultWidgetLayout(),
|
toolShelfLayout: defaultWidgetLayout(),
|
||||||
workingColorsLayout: defaultWidgetLayout(),
|
workingColorsLayout: defaultWidgetLayout(),
|
||||||
nodeGraphControlBarLayout: defaultWidgetLayout(),
|
nodeGraphControlBarLayout: defaultWidgetLayout(),
|
||||||
// Graph view overlay
|
|
||||||
graphViewOverlayOpen: false,
|
graphViewOverlayOpen: false,
|
||||||
fadeArtwork: 100,
|
|
||||||
});
|
});
|
||||||
const { subscribe, update } = state;
|
const { subscribe, update } = state;
|
||||||
|
|
||||||
// Update layouts
|
// Update layouts
|
||||||
editor.subscriptions.subscribeJsMessage(UpdateGraphFadeArtwork, (updateGraphFadeArtwork) => {
|
|
||||||
update((state) => {
|
|
||||||
state.fadeArtwork = updateGraphFadeArtwork.percentage;
|
|
||||||
return state;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
editor.subscriptions.subscribeJsMessage(UpdateDocumentModeLayout, async (updateDocumentModeLayout) => {
|
editor.subscriptions.subscribeJsMessage(UpdateDocumentModeLayout, async (updateDocumentModeLayout) => {
|
||||||
await tick();
|
await tick();
|
||||||
|
|
||||||
|
|||||||
@@ -3,55 +3,63 @@ import { writable } from "svelte/store";
|
|||||||
import { type Editor } from "@graphite/editor";
|
import { type Editor } from "@graphite/editor";
|
||||||
import type { NodeGraphError } from "@graphite/messages";
|
import type { NodeGraphError } from "@graphite/messages";
|
||||||
import {
|
import {
|
||||||
type Box,
|
type FrontendSelectionBox,
|
||||||
type FrontendClickTargets,
|
type FrontendClickTargets,
|
||||||
type ContextMenuInformation,
|
type ContextMenuInformation,
|
||||||
type FrontendNode,
|
type FrontendNodeOld,
|
||||||
type FrontendNodeType,
|
type FrontendNodeType,
|
||||||
type WirePath,
|
type WirePathInProgress,
|
||||||
ClearAllNodeGraphWires,
|
type WirePathOld,
|
||||||
|
ClearAllNodeGraphWiresOld,
|
||||||
SendUIMetadata,
|
SendUIMetadata,
|
||||||
UpdateBox,
|
UpdateNodeGraphSelectionBox,
|
||||||
UpdateClickTargets,
|
UpdateClickTargets,
|
||||||
UpdateContextMenuInformation,
|
UpdateContextMenuInformation,
|
||||||
UpdateInSelectedNetwork,
|
UpdateInSelectedNetworkOld,
|
||||||
UpdateImportReorderIndex,
|
UpdateImportReorderIndex,
|
||||||
UpdateExportReorderIndex,
|
UpdateExportReorderIndex,
|
||||||
UpdateImportsExports,
|
UpdateImportsExports,
|
||||||
UpdateLayerWidths,
|
UpdateLayerWidthsOld,
|
||||||
UpdateNodeGraphNodes,
|
UpdateNodeGraphNodesOld,
|
||||||
UpdateVisibleNodes,
|
UpdateVisibleNodesOld,
|
||||||
UpdateNodeGraphWires,
|
UpdateNodeGraphWiresOld,
|
||||||
UpdateNodeGraphSelection,
|
UpdateNodeGraphSelectionOld,
|
||||||
UpdateNodeGraphTransform,
|
UpdateNodeGraphTransform,
|
||||||
UpdateNodeThumbnail,
|
UpdateNodeThumbnail,
|
||||||
UpdateWirePathInProgress,
|
UpdateWirePathInProgress,
|
||||||
UpdateNodeGraphError,
|
UpdateNodeGraphError,
|
||||||
|
UpdateRenderNativeNodeGraph,
|
||||||
|
UpdateGraphFadeArtworkOld,
|
||||||
} from "@graphite/messages";
|
} from "@graphite/messages";
|
||||||
|
|
||||||
export function createNodeGraphState(editor: Editor) {
|
export function createNodeGraphState(editor: Editor) {
|
||||||
const { subscribe, update } = writable({
|
const { subscribe, update } = writable({
|
||||||
box: undefined as Box | undefined,
|
// Data that will continue to be rendered in Svelte
|
||||||
|
selectionBox: undefined as FrontendSelectionBox | undefined,
|
||||||
clickTargets: undefined as FrontendClickTargets | undefined,
|
clickTargets: undefined as FrontendClickTargets | undefined,
|
||||||
contextMenuInformation: undefined as ContextMenuInformation | undefined,
|
|
||||||
error: undefined as NodeGraphError | undefined,
|
error: undefined as NodeGraphError | undefined,
|
||||||
layerWidths: new Map<bigint, number>(),
|
wirePathInProgress: undefined as WirePathInProgress | undefined,
|
||||||
chainWidths: new Map<bigint, number>(),
|
importsExports: undefined as UpdateImportsExports | undefined,
|
||||||
hasLeftInputWire: new Map<bigint, boolean>(),
|
|
||||||
updateImportsExports: undefined as UpdateImportsExports | undefined,
|
|
||||||
nodes: new Map<bigint, FrontendNode>(),
|
|
||||||
visibleNodes: new Set<bigint>(),
|
|
||||||
/// The index is the exposed input index. The exports have a first key value of u32::MAX.
|
|
||||||
wires: new Map<bigint, Map<number, WirePath>>(),
|
|
||||||
wirePathInProgress: undefined as WirePath | undefined,
|
|
||||||
nodeDescriptions: new Map<string, string>(),
|
|
||||||
nodeTypes: [] as FrontendNodeType[],
|
|
||||||
thumbnails: new Map<bigint, string>(),
|
|
||||||
selected: [] as bigint[],
|
|
||||||
transform: { scale: 1, x: 0, y: 0 },
|
|
||||||
inSelectedNetwork: true,
|
|
||||||
reorderImportIndex: undefined as number | undefined,
|
reorderImportIndex: undefined as number | undefined,
|
||||||
reorderExportIndex: undefined as number | undefined,
|
reorderExportIndex: undefined as number | undefined,
|
||||||
|
contextMenuInformation: undefined as ContextMenuInformation | undefined,
|
||||||
|
nodeTypes: [] as FrontendNodeType[],
|
||||||
|
nodeDescriptions: new Map<string, string>(),
|
||||||
|
thumbnails: new Map<bigint, string>(),
|
||||||
|
transform: { scale: 1, x: 0, y: 0 },
|
||||||
|
|
||||||
|
// Data that will be removed when the node graph is rendered natively
|
||||||
|
nodesOld: new Map<bigint, FrontendNodeOld>(),
|
||||||
|
selectedOld: [] as bigint[],
|
||||||
|
wiresOld: new Map<bigint, Map<number, WirePathOld>>(),
|
||||||
|
opacityOld: 80,
|
||||||
|
inSelectedNetworkOld: true,
|
||||||
|
previewedNodeOld: undefined as bigint | undefined,
|
||||||
|
visibleNodesOld: new Set<bigint>(),
|
||||||
|
layerWidthsOld: new Map<bigint, number>(),
|
||||||
|
chainWidthsOld: new Map<bigint, number>(),
|
||||||
|
hasLeftInputWireOld: new Map<bigint, boolean>(),
|
||||||
|
renderNativeNodeGraphOld: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Set up message subscriptions on creation
|
// Set up message subscriptions on creation
|
||||||
@@ -62,15 +70,21 @@ export function createNodeGraphState(editor: Editor) {
|
|||||||
return state;
|
return state;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
editor.subscriptions.subscribeJsMessage(UpdateBox, (updateBox) => {
|
editor.subscriptions.subscribeJsMessage(UpdateNodeGraphSelectionBox, (updateBox) => {
|
||||||
update((state) => {
|
update((state) => {
|
||||||
state.box = updateBox.box;
|
state.selectionBox = updateBox.box;
|
||||||
return state;
|
return state;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
editor.subscriptions.subscribeJsMessage(UpdateClickTargets, (UpdateClickTargets) => {
|
editor.subscriptions.subscribeJsMessage(UpdateClickTargets, (updateClickTargets) => {
|
||||||
update((state) => {
|
update((state) => {
|
||||||
state.clickTargets = UpdateClickTargets.clickTargets;
|
state.clickTargets = updateClickTargets.clickTargets;
|
||||||
|
return state;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
editor.subscriptions.subscribeJsMessage(UpdateWirePathInProgress, (updateWirePathInProgress) => {
|
||||||
|
update((state) => {
|
||||||
|
state.wirePathInProgress = updateWirePathInProgress.wirePathInProgress;
|
||||||
return state;
|
return state;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -94,29 +108,29 @@ export function createNodeGraphState(editor: Editor) {
|
|||||||
});
|
});
|
||||||
editor.subscriptions.subscribeJsMessage(UpdateImportsExports, (updateImportsExports) => {
|
editor.subscriptions.subscribeJsMessage(UpdateImportsExports, (updateImportsExports) => {
|
||||||
update((state) => {
|
update((state) => {
|
||||||
state.updateImportsExports = updateImportsExports;
|
state.importsExports = updateImportsExports;
|
||||||
return state;
|
return state;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
editor.subscriptions.subscribeJsMessage(UpdateInSelectedNetwork, (updateInSelectedNetwork) => {
|
editor.subscriptions.subscribeJsMessage(UpdateInSelectedNetworkOld, (updateInSelectedNetwork) => {
|
||||||
update((state) => {
|
update((state) => {
|
||||||
state.inSelectedNetwork = updateInSelectedNetwork.inSelectedNetwork;
|
state.inSelectedNetworkOld = updateInSelectedNetwork.inSelectedNetwork;
|
||||||
return state;
|
return state;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
editor.subscriptions.subscribeJsMessage(UpdateLayerWidths, (updateLayerWidths) => {
|
editor.subscriptions.subscribeJsMessage(UpdateLayerWidthsOld, (updateLayerWidths) => {
|
||||||
update((state) => {
|
update((state) => {
|
||||||
state.layerWidths = updateLayerWidths.layerWidths;
|
state.layerWidthsOld = updateLayerWidths.layerWidths;
|
||||||
state.chainWidths = updateLayerWidths.chainWidths;
|
state.chainWidthsOld = updateLayerWidths.chainWidths;
|
||||||
state.hasLeftInputWire = updateLayerWidths.hasLeftInputWire;
|
state.hasLeftInputWireOld = updateLayerWidths.hasLeftInputWire;
|
||||||
return state;
|
return state;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
editor.subscriptions.subscribeJsMessage(UpdateNodeGraphNodes, (updateNodeGraphNodes) => {
|
editor.subscriptions.subscribeJsMessage(UpdateNodeGraphNodesOld, (updateNodeGraphNodesOld) => {
|
||||||
update((state) => {
|
update((state) => {
|
||||||
state.nodes.clear();
|
state.nodesOld.clear();
|
||||||
updateNodeGraphNodes.nodes.forEach((node) => {
|
updateNodeGraphNodesOld.nodes.forEach((node) => {
|
||||||
state.nodes.set(node.id, node);
|
state.nodesOld.set(node.id, node);
|
||||||
});
|
});
|
||||||
return state;
|
return state;
|
||||||
});
|
});
|
||||||
@@ -127,20 +141,20 @@ export function createNodeGraphState(editor: Editor) {
|
|||||||
return state;
|
return state;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
editor.subscriptions.subscribeJsMessage(UpdateVisibleNodes, (updateVisibleNodes) => {
|
editor.subscriptions.subscribeJsMessage(UpdateVisibleNodesOld, (updateVisibleNodesOld) => {
|
||||||
update((state) => {
|
update((state) => {
|
||||||
state.visibleNodes = new Set<bigint>(updateVisibleNodes.nodes);
|
state.visibleNodesOld = new Set<bigint>(updateVisibleNodesOld.nodes);
|
||||||
return state;
|
return state;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
editor.subscriptions.subscribeJsMessage(UpdateNodeGraphWires, (updateNodeWires) => {
|
editor.subscriptions.subscribeJsMessage(UpdateNodeGraphWiresOld, (updateNodeWires) => {
|
||||||
update((state) => {
|
update((state) => {
|
||||||
updateNodeWires.wires.forEach((wireUpdate) => {
|
updateNodeWires.wires.forEach((wireUpdate) => {
|
||||||
let inputMap = state.wires.get(wireUpdate.id);
|
let inputMap = state.wiresOld.get(wireUpdate.id);
|
||||||
// If it doesn't exist, create it and set it in the outer map
|
// If it doesn't exist, create it and set it in the outer map
|
||||||
if (!inputMap) {
|
if (!inputMap) {
|
||||||
inputMap = new Map();
|
inputMap = new Map();
|
||||||
state.wires.set(wireUpdate.id, inputMap);
|
state.wiresOld.set(wireUpdate.id, inputMap);
|
||||||
}
|
}
|
||||||
if (wireUpdate.wirePathUpdate !== undefined) {
|
if (wireUpdate.wirePathUpdate !== undefined) {
|
||||||
inputMap.set(wireUpdate.inputIndex, wireUpdate.wirePathUpdate);
|
inputMap.set(wireUpdate.inputIndex, wireUpdate.wirePathUpdate);
|
||||||
@@ -151,15 +165,15 @@ export function createNodeGraphState(editor: Editor) {
|
|||||||
return state;
|
return state;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
editor.subscriptions.subscribeJsMessage(ClearAllNodeGraphWires, (_) => {
|
editor.subscriptions.subscribeJsMessage(ClearAllNodeGraphWiresOld, (_) => {
|
||||||
update((state) => {
|
update((state) => {
|
||||||
state.wires.clear();
|
state.wiresOld.clear();
|
||||||
return state;
|
return state;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
editor.subscriptions.subscribeJsMessage(UpdateNodeGraphSelection, (updateNodeGraphSelection) => {
|
editor.subscriptions.subscribeJsMessage(UpdateNodeGraphSelectionOld, (updateNodeGraphSelection) => {
|
||||||
update((state) => {
|
update((state) => {
|
||||||
state.selected = updateNodeGraphSelection.selected;
|
state.selectedOld = updateNodeGraphSelection.selected;
|
||||||
return state;
|
return state;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -177,11 +191,22 @@ export function createNodeGraphState(editor: Editor) {
|
|||||||
});
|
});
|
||||||
editor.subscriptions.subscribeJsMessage(UpdateWirePathInProgress, (updateWirePathInProgress) => {
|
editor.subscriptions.subscribeJsMessage(UpdateWirePathInProgress, (updateWirePathInProgress) => {
|
||||||
update((state) => {
|
update((state) => {
|
||||||
state.wirePathInProgress = updateWirePathInProgress.wirePath;
|
state.wirePathInProgress = updateWirePathInProgress.wirePathInProgress;
|
||||||
|
return state;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
editor.subscriptions.subscribeJsMessage(UpdateRenderNativeNodeGraph, (updateRenderNativeNodeGraph) => {
|
||||||
|
update((state) => {
|
||||||
|
state.renderNativeNodeGraphOld = updateRenderNativeNodeGraph.renderNativeNodeGraph;
|
||||||
|
return state;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
editor.subscriptions.subscribeJsMessage(UpdateGraphFadeArtworkOld, (updateGraphFadeArtwork) => {
|
||||||
|
update((state) => {
|
||||||
|
state.opacityOld = updateGraphFadeArtwork.percentage;
|
||||||
return state;
|
return state;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
subscribe,
|
subscribe,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ pub mod logic;
|
|||||||
pub mod math;
|
pub mod math;
|
||||||
pub mod memo;
|
pub mod memo;
|
||||||
pub mod misc;
|
pub mod misc;
|
||||||
|
pub mod node_graph_overlay;
|
||||||
pub mod ops;
|
pub mod ops;
|
||||||
pub mod raster;
|
pub mod raster;
|
||||||
pub mod raster_types;
|
pub mod raster_types;
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
pub mod types;
|
||||||
@@ -0,0 +1,163 @@
|
|||||||
|
use glam::{DAffine2, DVec2, IVec2};
|
||||||
|
use kurbo::BezPath;
|
||||||
|
|
||||||
|
use crate::{Graphic, uuid::NodeId};
|
||||||
|
use std::{
|
||||||
|
collections::HashMap,
|
||||||
|
hash::{Hash, Hasher},
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Default, PartialEq, dyn_any::DynAny, serde::Serialize, serde::Deserialize, specta::Type)]
|
||||||
|
pub struct NodeGraphTransform {
|
||||||
|
pub scale: f64,
|
||||||
|
pub x: f64,
|
||||||
|
pub y: f64,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Stores node graph coordinates which are then transformed in svelte based on the node graph transform
|
||||||
|
#[derive(Clone, Debug, Default, PartialEq, Hash, dyn_any::DynAny, serde::Serialize, serde::Deserialize, specta::Type)]
|
||||||
|
pub struct FrontendXY {
|
||||||
|
pub x: i32,
|
||||||
|
pub y: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<DVec2> for FrontendXY {
|
||||||
|
fn from(v: DVec2) -> Self {
|
||||||
|
FrontendXY { x: v.x as i32, y: v.y as i32 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<IVec2> for FrontendXY {
|
||||||
|
fn from(v: IVec2) -> Self {
|
||||||
|
FrontendXY { x: v.x as i32, y: v.y as i32 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Hash for NodeGraphTransform {
|
||||||
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||||
|
// Convert f64 to u64 bit pattern for hashing
|
||||||
|
self.scale.to_bits().hash(state);
|
||||||
|
self.x.to_bits().hash(state);
|
||||||
|
self.y.to_bits().hash(state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NodeGraphTransform {
|
||||||
|
pub fn to_daffine2(&self) -> DAffine2 {
|
||||||
|
DAffine2::from_scale_angle_translation(DVec2::splat(self.scale), 0.0, DVec2::new(self.x, self.y))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Default, PartialEq, Hash, dyn_any::DynAny, serde::Serialize, serde::Deserialize, specta::Type)]
|
||||||
|
pub struct FrontendGraphInputNew {
|
||||||
|
#[serde(rename = "dataType")]
|
||||||
|
pub data_type: FrontendGraphDataType,
|
||||||
|
pub name: String,
|
||||||
|
/// Used to render the upstream node once this node is rendered
|
||||||
|
#[serde(rename = "connectedToNode")]
|
||||||
|
pub connected_to_node: Option<NodeId>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Default, PartialEq, Hash, dyn_any::DynAny, serde::Serialize, serde::Deserialize, specta::Type)]
|
||||||
|
pub struct FrontendGraphOutputNew {
|
||||||
|
#[serde(rename = "dataType")]
|
||||||
|
pub data_type: FrontendGraphDataType,
|
||||||
|
pub name: String,
|
||||||
|
pub connected: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, Default, PartialEq, Hash, dyn_any::DynAny, serde::Serialize, serde::Deserialize, specta::Type)]
|
||||||
|
pub enum FrontendGraphDataType {
|
||||||
|
#[default]
|
||||||
|
General,
|
||||||
|
Number,
|
||||||
|
Artboard,
|
||||||
|
Graphic,
|
||||||
|
Raster,
|
||||||
|
Vector,
|
||||||
|
Color,
|
||||||
|
Gradient,
|
||||||
|
Typography,
|
||||||
|
Invalid,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Default, PartialEq, dyn_any::DynAny)]
|
||||||
|
pub struct NodeGraphOverlayData {
|
||||||
|
pub nodes_to_render: Vec<FrontendNodeToRenderNew>,
|
||||||
|
pub in_selected_network: bool,
|
||||||
|
// Displays a dashed border around the node
|
||||||
|
pub previewed_node: Option<NodeId>,
|
||||||
|
pub thumbnails: HashMap<NodeId, Graphic>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Hash for NodeGraphOverlayData {
|
||||||
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||||
|
self.nodes_to_render.hash(state);
|
||||||
|
self.in_selected_network.hash(state);
|
||||||
|
self.previewed_node.hash(state);
|
||||||
|
let mut entries: Vec<_> = self.thumbnails.iter().collect();
|
||||||
|
entries.sort_by(|a, b| a.0.cmp(b.0));
|
||||||
|
let mut hasher = std::collections::hash_map::DefaultHasher::new();
|
||||||
|
entries.hash(&mut hasher);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, dyn_any::DynAny)]
|
||||||
|
pub struct FrontendNodeToRenderNew {
|
||||||
|
pub metadata: FrontendNodeMetadataNew,
|
||||||
|
pub node_or_layer: FrontendNodeOrLayer,
|
||||||
|
//TODO: Remove and replace with method of generating wires when generating nodes
|
||||||
|
pub wires: Vec<(BezPath, bool, FrontendGraphDataType)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Hash for FrontendNodeToRenderNew {
|
||||||
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||||
|
self.metadata.hash(state);
|
||||||
|
self.node_or_layer.hash(state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Metadata that is common to nodes and layers
|
||||||
|
#[derive(Clone, Debug, Default, PartialEq, Hash, dyn_any::DynAny)]
|
||||||
|
pub struct FrontendNodeMetadataNew {
|
||||||
|
pub node_id: NodeId,
|
||||||
|
pub display_name: String,
|
||||||
|
pub selected: bool,
|
||||||
|
// Used to get the description, which is stored in a global hashmap
|
||||||
|
pub reference: Option<String>,
|
||||||
|
// Reduces opacity of node/hidden eye icon
|
||||||
|
pub visible: bool,
|
||||||
|
// The svg string for each input
|
||||||
|
// pub wires: Vec<Option<String>>,
|
||||||
|
pub errors: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Default, PartialEq, Hash, dyn_any::DynAny)]
|
||||||
|
pub struct FrontendNodeNew {
|
||||||
|
// pub position: FrontendNodePosition,
|
||||||
|
pub position: FrontendXY,
|
||||||
|
pub primary_output: Option<FrontendGraphOutputNew>,
|
||||||
|
pub primary_input: Option<FrontendGraphInputNew>,
|
||||||
|
pub secondary_inputs: Vec<FrontendGraphInputNew>,
|
||||||
|
pub secondary_outputs: Vec<FrontendGraphOutputNew>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Default, PartialEq, Hash, dyn_any::DynAny)]
|
||||||
|
pub struct FrontendLayerNew {
|
||||||
|
pub bottom_input: FrontendGraphInputNew,
|
||||||
|
pub side_input: Option<FrontendGraphInputNew>,
|
||||||
|
pub output: FrontendGraphOutputNew,
|
||||||
|
// pub position: FrontendLayerPosition,
|
||||||
|
pub position: FrontendXY,
|
||||||
|
pub locked: bool,
|
||||||
|
pub chain_width: u32,
|
||||||
|
pub layer_has_left_border_gap: bool,
|
||||||
|
pub primary_input_connected_to_layer: bool,
|
||||||
|
pub primary_output_connected_to_layer: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, Hash, dyn_any::DynAny)]
|
||||||
|
pub enum FrontendNodeOrLayer {
|
||||||
|
Node(FrontendNodeNew),
|
||||||
|
Layer(FrontendLayerNew),
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user