From cb1fb756b1397cc92807cd6f4eaa33fade80f7ca Mon Sep 17 00:00:00 2001 From: Adam Date: Fri, 5 Sep 2025 02:33:27 -0700 Subject: [PATCH] Add icons --- .../src/messages/frontend/frontend_message.rs | 9 +- .../input_preprocessor_message_handler.rs | 1 - .../document/document_message_handler.rs | 8 - .../navigation/navigation_message_handler.rs | 6 - .../document/node_graph/node_graph_message.rs | 4 - .../node_graph/node_graph_message_handler.rs | 62 +------- .../document/node_graph/utility_types.rs | 2 - .../utility_types/network_interface.rs | 126 +-------------- .../network_interface/node_graph.rs | 18 ++- .../portfolio/document/utility_types/wires.rs | 15 +- .../menu_bar/menu_bar_message_handler.rs | 8 - .../src/components/panels/Document.svelte | 1 - frontend/src/components/views/Graph.svelte | 1 - frontend/src/messages.ts | 26 +-- frontend/src/state-providers/node-graph.ts | 46 +----- frontend/wasm/src/editor_api.rs | 7 - node-graph/gcore/src/node_graph_overlay.rs | 4 +- .../src/node_graph_overlay/nodes_and_wires.rs | 148 +++++++++++++++--- .../gcore/src/node_graph_overlay/types.rs | 6 +- 19 files changed, 166 insertions(+), 332 deletions(-) diff --git a/editor/src/messages/frontend/frontend_message.rs b/editor/src/messages/frontend/frontend_message.rs index 6042c9bfca..1f8aafcf44 100644 --- a/editor/src/messages/frontend/frontend_message.rs +++ b/editor/src/messages/frontend/frontend_message.rs @@ -7,7 +7,7 @@ use crate::messages::portfolio::document::utility_types::wires::WirePathInProgre use crate::messages::prelude::*; use crate::messages::tool::utility_types::HintData; use graph_craft::document::NodeId; -use graphene_std::node_graph_overlay::types::{FrontendExports, FrontendImport, FrontendNodeToRender, FrontendXY, NodeGraphTransform}; +use graphene_std::node_graph_overlay::types::{FrontendExports, FrontendImport, FrontendXY, NodeGraphTransform}; use graphene_std::raster::Image; use graphene_std::raster::color::Color; use graphene_std::text::{Font, TextAlign}; @@ -270,17 +270,10 @@ pub enum FrontendMessage { cursor: MouseCursorIcon, }, RequestNativeNodeGraphRender, - UpdateShouldRenderSvelteNodes { - #[serde(rename = "shouldRenderSvelteNodes")] - should_render_svelte_nodes: bool, - }, UpdateNativeNodeGraphSVG { #[serde(rename = "svgString")] svg_string: String, }, - UpdateVisibleNodes { - nodes: Vec, - }, UpdateNodeGraphControlBarLayout { #[serde(rename = "layoutTarget")] layout_target: LayoutTarget, diff --git a/editor/src/messages/input_preprocessor/input_preprocessor_message_handler.rs b/editor/src/messages/input_preprocessor/input_preprocessor_message_handler.rs index 52e20d1d7b..a7bcfa37b9 100644 --- a/editor/src/messages/input_preprocessor/input_preprocessor_message_handler.rs +++ b/editor/src/messages/input_preprocessor/input_preprocessor_message_handler.rs @@ -34,7 +34,6 @@ impl MessageHandler f self.viewport_bounds = bounds; responses.add(NavigationMessage::CanvasPan { delta: DVec2::ZERO }); - responses.add(NodeGraphMessage::SetGridAlignedEdges); } responses.add(DeferMessage::AfterGraphRun { messages: vec![ diff --git a/editor/src/messages/portfolio/document/document_message_handler.rs b/editor/src/messages/portfolio/document/document_message_handler.rs index 5bafd46ede..71373d0ebb 100644 --- a/editor/src/messages/portfolio/document/document_message_handler.rs +++ b/editor/src/messages/portfolio/document/document_message_handler.rs @@ -476,7 +476,6 @@ impl MessageHandler> for DocumentMes self.selection_network_path.clone_from(&self.breadcrumb_network_path); responses.add(NodeGraphMessage::SendGraph); responses.add(DocumentMessage::ZoomCanvasToFitAll); - responses.add(NodeGraphMessage::SetGridAlignedEdges); } DocumentMessage::Escape => { if self.node_graph_handler.drag_start.is_some() { @@ -505,7 +504,6 @@ impl MessageHandler> for DocumentMes } responses.add(NodeGraphMessage::SendGraph); responses.add(DocumentMessage::PTZUpdate); - responses.add(NodeGraphMessage::SetGridAlignedEdges); } DocumentMessage::FlipSelectedLayers { flip_axis } => { let scale = match flip_axis { @@ -568,7 +566,6 @@ impl MessageHandler> for DocumentMes responses.add(ToolMessage::DeactivateTools); responses.add(OverlaysMessage::Draw); // Clear the overlays responses.add(NavigationMessage::CanvasTiltSet { angle_radians: 0. }); - responses.add(NodeGraphMessage::SetGridAlignedEdges); responses.add(NodeGraphMessage::UpdateGraphBarRight); responses.add(NodeGraphMessage::UpdateHints); } else { @@ -1489,10 +1486,8 @@ impl MessageHandler> for DocumentMes responses.add(DocumentMessage::RenderRulers); responses.add(DocumentMessage::RenderScrollbars); - responses.add(NodeGraphMessage::UpdateEdges); responses.add(NodeGraphMessage::UpdateBoxSelection); responses.add(NodeGraphMessage::UpdateImportsExports); - responses.add(FrontendMessage::UpdateNodeGraphTransform { transform: NodeGraphTransform { scale: transform.matrix2.x_axis.x, @@ -1942,9 +1937,6 @@ impl DocumentMessageHandler { responses.add(NodeGraphMessage::SelectedNodesUpdated); responses.add(NodeGraphMessage::ForceRunDocumentGraph); - // TODO: Remove once the footprint is used to load the imports/export distances from the edge - responses.add(NodeGraphMessage::SetGridAlignedEdges); - Some(previous_network) } pub fn redo_with_history(&mut self, ipp: &InputPreprocessorMessageHandler, responses: &mut VecDeque) { diff --git a/editor/src/messages/portfolio/document/navigation/navigation_message_handler.rs b/editor/src/messages/portfolio/document/navigation/navigation_message_handler.rs index 259b60e995..63f8817511 100644 --- a/editor/src/messages/portfolio/document/navigation/navigation_message_handler.rs +++ b/editor/src/messages/portfolio/document/navigation/navigation_message_handler.rs @@ -178,7 +178,6 @@ impl MessageHandler> for Navigat NavigationMessage::CanvasPanMouseWheel { use_y_as_x } => { let delta = if use_y_as_x { (-ipp.mouse.scroll_delta.y, 0.).into() } else { -ipp.mouse.scroll_delta.as_dvec2() } * VIEWPORT_SCROLL_RATE; responses.add(NavigationMessage::CanvasPan { delta }); - responses.add(NodeGraphMessage::SetGridAlignedEdges); } NavigationMessage::CanvasTiltResetAndZoomTo100Percent => { let Some(ptz) = get_ptz_mut(document_ptz, network_interface, graph_view_overlay_open, breadcrumb_network_path) else { @@ -193,7 +192,6 @@ impl MessageHandler> for Navigat responses.add(PortfolioMessage::UpdateDocumentWidgets); } responses.add(DocumentMessage::PTZUpdate); - responses.add(NodeGraphMessage::SetGridAlignedEdges); } NavigationMessage::CanvasTiltSet { angle_radians } => { let Some(ptz) = get_ptz_mut(document_ptz, network_interface, graph_view_overlay_open, breadcrumb_network_path) else { @@ -272,7 +270,6 @@ impl MessageHandler> for Navigat responses.add(PortfolioMessage::UpdateDocumentWidgets); } responses.add(DocumentMessage::PTZUpdate); - responses.add(NodeGraphMessage::SetGridAlignedEdges); } NavigationMessage::CanvasFlip => { if graph_view_overlay_open { @@ -320,7 +317,6 @@ impl MessageHandler> for Navigat } else { responses.add(PortfolioMessage::UpdateDocumentWidgets); } - responses.add(NodeGraphMessage::SetGridAlignedEdges); // Reset the navigation operation now that it's done self.navigation_operation = NavigationOperation::None; @@ -382,7 +378,6 @@ impl MessageHandler> for Navigat responses.add(PortfolioMessage::UpdateDocumentWidgets); } responses.add(DocumentMessage::PTZUpdate); - responses.add(NodeGraphMessage::SetGridAlignedEdges); } // Fully zooms in on the selected NavigationMessage::FitViewportToSelection => { @@ -476,7 +471,6 @@ impl MessageHandler> for Navigat }; responses.add(NavigationMessage::CanvasZoomSet { zoom_factor: ptz.zoom() }); - responses.add(NodeGraphMessage::SetGridAlignedEdges); } } diff --git a/editor/src/messages/portfolio/document/node_graph/node_graph_message.rs b/editor/src/messages/portfolio/document/node_graph/node_graph_message.rs index 15ef3ab246..6f0b606ed0 100644 --- a/editor/src/messages/portfolio/document/node_graph/node_graph_message.rs +++ b/editor/src/messages/portfolio/document/node_graph/node_graph_message.rs @@ -139,9 +139,7 @@ pub enum NodeGraphMessage { }, SendClickTargets, EndSendClickTargets, - UpdateVisibleNodes, SendGraph, - SetGridAlignedEdges, SetInputValue { node_id: NodeId, input_index: usize, @@ -183,7 +181,6 @@ pub enum NodeGraphMessage { TogglePreviewImpl { node_id: NodeId, }, - ToggleNativeNodeGraphRender, SetImportExportName { name: String, index: ImportOrExport, @@ -217,7 +214,6 @@ pub enum NodeGraphMessage { SetLockedOrVisibilitySideEffects { node_ids: Vec, }, - UpdateEdges, UpdateBoxSelection, UpdateImportsExports, UpdateLayerPanel, diff --git a/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler.rs b/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler.rs index 9e75fdcbd8..a83056207e 100644 --- a/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler.rs +++ b/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler.rs @@ -92,8 +92,6 @@ pub struct NodeGraphMessageHandler { reordering_export: Option, /// The end index of the moved connector end_index: Option, - /// 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, } /// 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. @@ -1590,61 +1588,16 @@ impl<'a> MessageHandler> for NodeG click_targets: Some(network_interface.collect_frontend_click_targets(breadcrumb_network_path)), }), NodeGraphMessage::EndSendClickTargets => responses.add(FrontendMessage::UpdateClickTargets { click_targets: None }), - NodeGraphMessage::UpdateVisibleNodes => { - let Some(network_metadata) = network_interface.network_metadata(breadcrumb_network_path) else { - return; - }; - - let viewport_bbox = ipp.document_bounds(); - 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(); - for node_id in &self.frontend_nodes { - 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:?}"); - continue; - }; - - if node_bbox[1].x >= document_bbox[0].x && node_bbox[0].x <= document_bbox[1].x && node_bbox[1].y >= document_bbox[0].y && node_bbox[0].y <= document_bbox[1].y { - nodes.push(*node_id); - } - for error in &self.node_graph_errors { - if error.node_path.contains(node_id) { - nodes.push(*node_id); - } - } - } - - responses.add(FrontendMessage::UpdateVisibleNodes { nodes }); - } NodeGraphMessage::SendGraph => { responses.add(NodeGraphMessage::UpdateLayerPanel); responses.add(DocumentMessage::DocumentStructureChanged); responses.add(PropertiesPanelMessage::Refresh); responses.add(NodeGraphMessage::UpdateActionButtons); - if !self.should_render_svelte_nodes { - // Generate and render node graph overlay network - } else { - let nodes_to_render = network_interface.collect_nodes(&self.node_graph_errors, preferences.graph_wire_style, breadcrumb_network_path); - self.frontend_nodes = nodes_to_render.iter().map(|node| node.metadata.node_id).collect(); - let previewed_node = network_interface.previewed_node(breadcrumb_network_path); - } - responses.add(NodeGraphMessage::UpdateVisibleNodes); - - let layer_widths = network_interface.collect_layer_widths(breadcrumb_network_path); - + responses.add(FrontendMessage::RequestNativeNodeGraphRender); responses.add(NodeGraphMessage::UpdateImportsExports); - responses.add(FrontendMessage::UpdateLayerWidths { layer_widths }); self.update_node_graph_hints(responses); } - NodeGraphMessage::SetGridAlignedEdges => { - if graph_view_overlay_open { - network_interface.set_grid_aligned_edges(DVec2::new(ipp.viewport_bounds.bottom_right.x - ipp.viewport_bounds.top_left.x, 0.), breadcrumb_network_path); - // Send the new edges to the frontend - responses.add(NodeGraphMessage::UpdateImportsExports); - } - } NodeGraphMessage::SetInputValue { node_id, input_index, value } => { let input = NodeInput::value(value, false); responses.add(NodeGraphMessage::SetInput { @@ -1780,14 +1733,6 @@ impl<'a> MessageHandler> for NodeG NodeGraphMessage::TogglePreviewImpl { node_id } => { network_interface.toggle_preview(node_id, selection_network_path); } - NodeGraphMessage::ToggleNativeNodeGraphRender => { - self.should_render_svelte_nodes = !self.should_render_svelte_nodes; - responses.add(FrontendMessage::UpdateShouldRenderSvelteNodes { - should_render_svelte_nodes: self.should_render_svelte_nodes, - }); - responses.add(NodeGraphMessage::SendGraph); - responses.add(MenuBarMessage::SendLayout); - } NodeGraphMessage::ToggleSelectedLocked => { let Some(selected_nodes) = network_interface.selected_nodes_in_nested_network(selection_network_path) else { log::error!("Could not get selected nodes in NodeGraphMessage::ToggleSelectedLocked"); @@ -1957,7 +1902,6 @@ impl<'a> MessageHandler> for NodeG // Do not show the add import or add export button in the document network; let add_import_export = !breadcrumb_network_path.is_empty(); - responses.add(NodeGraphMessage::UpdateVisibleNodes); responses.add(FrontendMessage::UpdateImportsExports { imports, exports, @@ -1970,9 +1914,6 @@ impl<'a> MessageHandler> for NodeG NodeGraphMessage::UpdateLayerPanel => { Self::update_layer_panel(network_interface, selection_network_path, collapsed, layers_panel_open, responses); } - NodeGraphMessage::UpdateEdges => { - // Update the import/export UI edges whenever the PTZ changes or the bounding box of all nodes changes - } NodeGraphMessage::UpdateNewNodeGraph => { let Some(selected_nodes) = network_interface.selected_nodes_mut(selection_network_path) else { log::error!("Could not get selected nodes in NodeGraphMessage::UpdateNewNodeGraph"); @@ -2618,7 +2559,6 @@ impl Default for NodeGraphMessageHandler { reordering_export: None, reordering_import: None, end_index: None, - frontend_nodes: Vec::new(), } } } diff --git a/editor/src/messages/portfolio/document/node_graph/utility_types.rs b/editor/src/messages/portfolio/document/node_graph/utility_types.rs index 5e46218f19..1a637758a1 100644 --- a/editor/src/messages/portfolio/document/node_graph/utility_types.rs +++ b/editor/src/messages/portfolio/document/node_graph/utility_types.rs @@ -262,8 +262,6 @@ pub struct FrontendClickTargets { pub icon_click_targets: Vec, #[serde(rename = "allNodesBoundingBox")] pub all_nodes_bounding_box: String, - #[serde(rename = "importExportsBoundingBox")] - pub import_exports_bounding_box: String, #[serde(rename = "modifyImportExport")] pub modify_import_export: Vec, } diff --git a/editor/src/messages/portfolio/document/utility_types/network_interface.rs b/editor/src/messages/portfolio/document/utility_types/network_interface.rs index a6c090e84b..0a0728df77 100644 --- a/editor/src/messages/portfolio/document/utility_types/network_interface.rs +++ b/editor/src/messages/portfolio/document/utility_types/network_interface.rs @@ -1,7 +1,7 @@ use super::document_metadata::{DocumentMetadata, LayerNodeIdentifier, NodeRelations}; use super::misc::PTZ; 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::node_graph::document_node_definitions::{DocumentNodeDefinition, resolve_document_node_type}; use crate::messages::portfolio::document::node_graph::utility_types::{Direction, FrontendClickTargets}; @@ -1620,68 +1620,6 @@ impl NodeNetworkInterface { network_metadata.transient_metadata.modify_import_export.unload(); } - pub fn rounded_network_edge_distance(&mut self, network_path: &[NodeId]) -> Option<&NetworkEdgeDistance> { - let Some(network_metadata) = self.network_metadata(network_path) else { - log::error!("Could not get nested network_metadata in rounded_network_edge_distance"); - return None; - }; - if !network_metadata.transient_metadata.rounded_network_edge_distance.is_loaded() { - self.load_rounded_network_edge_distance(network_path); - } - let Some(network_metadata) = self.network_metadata(network_path) else { - log::error!("Could not get nested network_metadata in rounded_network_edge_distance"); - return None; - }; - let TransientMetadata::Loaded(rounded_network_edge_distance) = &network_metadata.transient_metadata.rounded_network_edge_distance else { - log::error!("could not load import rounded_network_edge_distance"); - return None; - }; - Some(rounded_network_edge_distance) - } - - fn load_rounded_network_edge_distance(&mut self, network_path: &[NodeId]) { - let Some(network_metadata) = self.network_metadata_mut(network_path) else { - log::error!("Could not get nested network in set_grid_aligned_edges"); - return; - }; - // When setting the edges to be grid aligned, update the pixel offset to ensure the next pan starts from the snapped import/export position - let node_graph_to_viewport = network_metadata.persistent_metadata.navigation_metadata.node_graph_to_viewport; - // TODO: Eventually replace node graph top right with the footprint when trying to get the network edge distance - let node_graph_top_right = network_metadata.persistent_metadata.navigation_metadata.node_graph_top_right; - let target_exports_distance = node_graph_to_viewport.inverse().transform_point2(DVec2::new( - node_graph_top_right.x - EXPORTS_TO_RIGHT_EDGE_PIXEL_GAP as f64, - node_graph_top_right.y + EXPORTS_TO_TOP_EDGE_PIXEL_GAP as f64, - )); - - let target_imports_distance = node_graph_to_viewport - .inverse() - .transform_point2(DVec2::new(IMPORTS_TO_LEFT_EDGE_PIXEL_GAP as f64, IMPORTS_TO_TOP_EDGE_PIXEL_GAP as f64)); - - let rounded_exports_distance = DVec2::new((target_exports_distance.x / 24. + 0.5).floor() * 24., (target_exports_distance.y / 24. + 0.5).floor() * 24.); - let rounded_imports_distance = DVec2::new((target_imports_distance.x / 24. + 0.5).floor() * 24., (target_imports_distance.y / 24. + 0.5).floor() * 24.); - - let rounded_viewport_exports_distance = node_graph_to_viewport.transform_point2(rounded_exports_distance); - let rounded_viewport_imports_distance = node_graph_to_viewport.transform_point2(rounded_imports_distance); - - let network_edge_distance = NetworkEdgeDistance { - exports_to_edge_distance: rounded_viewport_exports_distance, - imports_to_edge_distance: rounded_viewport_imports_distance, - }; - let Some(network_metadata) = self.network_metadata_mut(network_path) else { - log::error!("Could not get current network in load_export_ports"); - return; - }; - network_metadata.transient_metadata.rounded_network_edge_distance = TransientMetadata::Loaded(network_edge_distance); - } - - fn unload_rounded_network_edge_distance(&mut self, network_path: &[NodeId]) { - let Some(network_metadata) = self.network_metadata_mut(network_path) else { - log::error!("Could not get nested network_metadata in unload_export_ports"); - return; - }; - network_metadata.transient_metadata.rounded_network_edge_distance.unload(); - } - fn owned_nodes(&self, node_id: &NodeId, network_path: &[NodeId]) -> Option<&HashSet> { let layer_node = self.node_metadata(node_id, network_path)?; let NodeTypePersistentMetadata::Layer(LayerPersistentMetadata { owned_nodes, .. }) = &layer_node.persistent_metadata.node_type_metadata else { @@ -2299,33 +2237,6 @@ impl NodeNetworkInterface { let rect = Subpath::::new_rect(bounds[0], bounds[1]); let all_nodes_bounding_box = rect.to_bezpath().to_svg(); - let Some(rounded_network_edge_distance) = self.rounded_network_edge_distance(network_path).cloned() else { - log::error!("Could not get rounded_network_edge_distance in collect_frontend_click_targets"); - return FrontendClickTargets::default(); - }; - let Some(network_metadata) = self.network_metadata(network_path) else { - log::error!("Could not get nested network_metadata in collect_frontend_click_targets"); - return FrontendClickTargets::default(); - }; - let import_exports_viewport_top_left = rounded_network_edge_distance.imports_to_edge_distance; - let import_exports_viewport_bottom_right = rounded_network_edge_distance.exports_to_edge_distance; - - let node_graph_top_left = network_metadata - .persistent_metadata - .navigation_metadata - .node_graph_to_viewport - .inverse() - .transform_point2(import_exports_viewport_top_left); - let node_graph_bottom_right = network_metadata - .persistent_metadata - .navigation_metadata - .node_graph_to_viewport - .inverse() - .transform_point2(import_exports_viewport_bottom_right); - - let import_exports_target = Subpath::::new_rect(node_graph_top_left, node_graph_bottom_right); - let import_exports_bounding_box = import_exports_target.to_bezpath().to_svg(); - let mut modify_import_export = Vec::new(); if let Some(modify_import_export_click_targets) = self.modify_import_export(network_path) { for click_target in modify_import_export_click_targets @@ -2344,7 +2255,6 @@ impl NodeNetworkInterface { connector_click_targets, icon_click_targets, all_nodes_bounding_box, - import_exports_bounding_box, modify_import_export, } } @@ -2591,26 +2501,6 @@ impl NodeNetworkInterface { bounding_box_subpath.bounding_box_with_transform(network_metadata.persistent_metadata.navigation_metadata.node_graph_to_viewport) } - // TODO: Remove and get layer click targets from render output - pub fn collect_layer_widths(&mut self, network_path: &[NodeId]) -> HashMap { - 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(); - }; - 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::>(); - let layer_widths = nodes - .iter() - .filter_map(|node_id| self.layer_width(node_id, network_path).map(|layer_width| (*node_id, layer_width))) - .collect::>(); - - layer_widths - } - pub fn compute_modified_vector(&self, layer: LayerNodeIdentifier) -> Option { let graph_layer = graph_modification_utils::NodeGraphLayer::new(layer, self); @@ -2785,18 +2675,6 @@ impl NodeNetworkInterface { self.unload_modify_import_export(network_path); } - // This should be run whenever the pan ends, a zoom occurs, or the network is opened - pub fn set_grid_aligned_edges(&mut self, node_graph_top_right: DVec2, network_path: &[NodeId]) { - let Some(network_metadata) = self.network_metadata_mut(network_path) else { - log::error!("Could not get nested network_metadata in set_grid_aligned_edges"); - return; - }; - network_metadata.persistent_metadata.navigation_metadata.node_graph_top_right = node_graph_top_right; - self.unload_rounded_network_edge_distance(network_path); - self.unload_import_export_ports(network_path); - self.unload_modify_import_export(network_path); - } - 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 { log::error!("Could not get node in vector_modification"); @@ -5581,8 +5459,6 @@ pub struct NodeNetworkTransientMetadata { pub import_export_ports: TransientMetadata, /// Click targets for adding, removing, and moving import/export ports pub modify_import_export: TransientMetadata, - // Distance to the edges of the network, where the import/export ports are displayed. Rounded to nearest grid space when the panning ends. - pub rounded_network_edge_distance: TransientMetadata, } #[derive(Debug, Clone)] diff --git a/editor/src/messages/portfolio/document/utility_types/network_interface/node_graph.rs b/editor/src/messages/portfolio/document/utility_types/network_interface/node_graph.rs index 537cda8e80..5d459fcf8a 100644 --- a/editor/src/messages/portfolio/document/utility_types/network_interface/node_graph.rs +++ b/editor/src/messages/portfolio/document/utility_types/network_interface/node_graph.rs @@ -90,15 +90,23 @@ impl NodeNetworkInterface { let position = FrontendXY { x: position.x, y: position.y }; - let inputs = (0..self.number_of_inputs(&node_id, network_path)) - .map(|input_index| self.frontend_input_from_connector(&InputConnector::node(node_id, input_index), network_path)) + let primary_input = self.frontend_input_from_connector(&InputConnector::node(node_id, 0), network_path); + let secondary_inputs = (1..self.number_of_inputs(&node_id, network_path)) + .filter_map(|input_index| self.frontend_input_from_connector(&InputConnector::node(node_id, input_index), network_path)) .collect(); - let outputs = (0..self.number_of_outputs(&node_id, network_path)) - .map(|output_index| self.frontend_output_from_connector(&OutputConnector::node(node_id, output_index), network_path)) + let primary_output = self.frontend_output_from_connector(&OutputConnector::node(node_id, 0), network_path); + let secondary_outputs = (1..self.number_of_outputs(&node_id, network_path)) + .filter_map(|output_index| self.frontend_output_from_connector(&OutputConnector::node(node_id, output_index), network_path)) .collect(); - let node = Some(FrontendNode { position, inputs, outputs }); + let node = Some(FrontendNode { + position, + primary_input, + primary_output, + secondary_inputs, + secondary_outputs, + }); FrontendNodeOrLayer { node, layer: None } } diff --git a/editor/src/messages/portfolio/document/utility_types/wires.rs b/editor/src/messages/portfolio/document/utility_types/wires.rs index f8e0559f31..a29c84c8e8 100644 --- a/editor/src/messages/portfolio/document/utility_types/wires.rs +++ b/editor/src/messages/portfolio/document/utility_types/wires.rs @@ -54,8 +54,19 @@ pub fn build_vector_wire(output_position: DVec2, input_position: DVec2, vertical let horizontal_curve = horizontal_curve_amount * curve_length; let vertical_curve = vertical_curve_amount * curve_length; + let wire_start = if vertical_in && vertical_out { output_position + DVec2::new(0., -4.) } else { output_position }; + let wire_end = if vertical_in && vertical_in { + DVec2::new(input_position.x, input_position.y) + DVec2::new(0., 4.) + } else { + DVec2::new(input_position.x, input_position.y) + }; + + if vertical_in && vertical_in && wire_end.y + 5. > wire_start.y { + return BezPath::new(); + } + let locations = [ - output_position, + wire_start, DVec2::new( if vertical_out { output_position.x } else { output_position.x + horizontal_curve }, if vertical_out { output_position.y - vertical_curve } else { output_position.y }, @@ -64,7 +75,7 @@ pub fn build_vector_wire(output_position: DVec2, input_position: DVec2, vertical if vertical_in { input_position.x } else { input_position.x - horizontal_curve }, if vertical_in { input_position.y + vertical_curve } else { input_position.y }, ), - DVec2::new(input_position.x, input_position.y), + wire_end, ]; let smoothing = 0.5; diff --git a/editor/src/messages/portfolio/menu_bar/menu_bar_message_handler.rs b/editor/src/messages/portfolio/menu_bar/menu_bar_message_handler.rs index 8ed797f360..9b86761d87 100644 --- a/editor/src/messages/portfolio/menu_bar/menu_bar_message_handler.rs +++ b/editor/src/messages/portfolio/menu_bar/menu_bar_message_handler.rs @@ -18,7 +18,6 @@ pub struct MenuBarMessageHandler { pub has_selection_history: (bool, bool), pub message_logging_verbosity: MessageLoggingVerbosity, pub reset_node_definitions_on_open: bool, - pub should_render_svelte_nodes: bool, pub make_path_editable_is_allowed: bool, pub data_panel_open: bool, pub layers_panel_open: bool, @@ -49,7 +48,6 @@ impl LayoutHolder for MenuBarMessageHandler { let message_logging_verbosity_names = self.message_logging_verbosity == MessageLoggingVerbosity::Names; let message_logging_verbosity_contents = self.message_logging_verbosity == MessageLoggingVerbosity::Contents; let reset_node_definitions_on_open = self.reset_node_definitions_on_open; - let should_render_svelte_nodes = self.should_render_svelte_nodes; let make_path_editable_is_allowed = self.make_path_editable_is_allowed; let menu_bar_entries = vec![ @@ -698,12 +696,6 @@ impl LayoutHolder for MenuBarMessageHandler { action: MenuBarEntry::create_action(|_| PortfolioMessage::ToggleResetNodesToDefinitionsOnOpen.into()), ..MenuBarEntry::default() }], - vec![MenuBarEntry { - label: "HTML Node Graph Render".into(), - icon: Some(if should_render_svelte_nodes { "CheckboxChecked" } else { "CheckboxUnchecked" }.into()), - action: MenuBarEntry::create_action(|_| NodeGraphMessage::ToggleNativeNodeGraphRender.into()), - ..MenuBarEntry::default() - }], vec![ MenuBarEntry { label: "Print Trace Logs".into(), diff --git a/frontend/src/components/panels/Document.svelte b/frontend/src/components/panels/Document.svelte index dd10a5f7b3..5079189ce7 100644 --- a/frontend/src/components/panels/Document.svelte +++ b/frontend/src/components/panels/Document.svelte @@ -587,7 +587,6 @@ thumbPosition={scrollbarPos.x} on:trackShift={({ detail }) => editor.handle.panCanvasByFraction(detail, 0)} on:thumbPosition={({ detail }) => panCanvasX(detail)} - on:thumbDragEnd={() => editor.handle.setGridAlignedEdges()} on:thumbDragStart={() => editor.handle.panCanvasAbortPrepare(true)} on:thumbDragAbort={() => editor.handle.panCanvasAbort(true)} /> diff --git a/frontend/src/components/views/Graph.svelte b/frontend/src/components/views/Graph.svelte index 9bfe167f7c..82a30011f7 100644 --- a/frontend/src/components/views/Graph.svelte +++ b/frontend/src/components/views/Graph.svelte @@ -617,7 +617,6 @@ {/each} - {#each $nodeGraph.clickTargets.modifyImportExport as pathString} {/each} diff --git a/frontend/src/messages.ts b/frontend/src/messages.ts index 0f656232d2..656cb9863c 100644 --- a/frontend/src/messages.ts +++ b/frontend/src/messages.ts @@ -35,7 +35,6 @@ export class FrontendClickTargets { readonly connectorClickTargets!: string[]; readonly iconClickTargets!: string[]; readonly allNodesBoundingBox!: string; - readonly importExportsBoundingBox!: string; readonly modifyImportExport!: string[]; } @@ -106,30 +105,10 @@ export class UpdateLayerWidths extends JsMessage { readonly layerWidths!: Map; } -export class UpdateNodeGraphSvelteRender extends JsMessage { - readonly nodesToRender!: FrontendNodeToRender[]; - - readonly open!: boolean; - - readonly opacity!: number; - - readonly inSelectedNetwork!: boolean; - - readonly previewedNode!: bigint | undefined; -} - -export class UpdateShouldRenderSvelteNodes extends JsMessage { - readonly shouldRenderSvelteNodes!: boolean; -} - export class UpdateNativeNodeGraphSVG extends JsMessage { readonly svgString!: string; } -export class UpdateVisibleNodes extends JsMessage { - readonly nodes!: bigint[]; -} - export class UpdateNodeGraphTransform extends JsMessage { readonly transform!: NodeGraphTransform; } @@ -1762,9 +1741,9 @@ export const messageMakers: Record = { UpdateMenuBarLayout, UpdateMouseCursor, UpdateNodeGraphControlBarLayout, - UpdateNodeGraphRender, - UpdateNodeGraphSelectionBox, + UpdateNativeNodeGraphSVG, UpdateNodeGraphTransform, + UpdateNodeGraphSelectionBox, UpdateNodeThumbnail, UpdateOpenDocumentsList, UpdatePlatform, @@ -1776,7 +1755,6 @@ export const messageMakers: Record = { UpdateToolOptionsLayout, UpdateToolShelfLayout, UpdateViewportHolePunch, - UpdateVisibleNodes, UpdateWirePathInProgress, UpdateWorkingColorsLayout, } as const; diff --git a/frontend/src/state-providers/node-graph.ts b/frontend/src/state-providers/node-graph.ts index 7b6f3fc173..74762825df 100644 --- a/frontend/src/state-providers/node-graph.ts +++ b/frontend/src/state-providers/node-graph.ts @@ -15,14 +15,11 @@ import { UpdateExportReorderIndex, UpdateImportsExports, UpdateLayerWidths, - UpdateNodeGraphSvelteRender, - UpdateShouldRenderSvelteNodes, UpdateNativeNodeGraphSVG, - UpdateVisibleNodes, - UpdateNodeGraphTransform, UpdateNodeThumbnail, UpdateWirePathInProgress, UpdateNodeGraphSelectionBox, + UpdateNodeGraphTransform, } from "@graphite/messages"; export function createNodeGraphState(editor: Editor) { @@ -46,11 +43,6 @@ export function createNodeGraphState(editor: Editor) { inSelectedNetwork: true, previewedNode: undefined as bigint | undefined, - // TODO: Remove these fields - visibleNodes: new Set(), - layerWidths: new Map(), - shouldRenderSvelteNodes: false, - // Data that will be passed in the context thumbnails: new Map(), transform: { scale: 1, x: 0, y: 0 }, @@ -107,42 +99,12 @@ export function createNodeGraphState(editor: Editor) { }); }); - editor.subscriptions.subscribeJsMessage(UpdateLayerWidths, (updateLayerWidths) => { - update((state) => { - state.layerWidths = updateLayerWidths.layerWidths; - return state; - }); - }); - editor.subscriptions.subscribeJsMessage(UpdateNodeGraphSvelteRender, (updateNodeGraphSvelteRender) => { - update((state) => { - state.nodesToRender.clear(); - updateNodeGraphSvelteRender.nodesToRender.forEach((node) => { - state.nodesToRender.set(node.metadata.nodeId, node); - }); - state.opacity = updateNodeGraphSvelteRender.opacity; - state.inSelectedNetwork = updateNodeGraphSvelteRender.inSelectedNetwork; - state.previewedNode = updateNodeGraphSvelteRender.previewedNode; - return state; - }); - }); - editor.subscriptions.subscribeJsMessage(UpdateShouldRenderSvelteNodes, (UpdateShouldRenderSvelteNodes) => { - update((state) => { - state.shouldRenderSvelteNodes = UpdateShouldRenderSvelteNodes.shouldRenderSvelteNodes; - return state; - }); - }); editor.subscriptions.subscribeJsMessage(UpdateNativeNodeGraphSVG, (updateNativeNodeGraphRender) => { update((state) => { state.nativeNodeGraphSVGString = updateNativeNodeGraphRender.svgString; return state; }); }); - editor.subscriptions.subscribeJsMessage(UpdateVisibleNodes, (updateVisibleNodes) => { - update((state) => { - state.visibleNodes = new Set(updateVisibleNodes.nodes); - return state; - }); - }); editor.subscriptions.subscribeJsMessage(UpdateNodeGraphTransform, (updateNodeGraphTransform) => { update((state) => { state.transform = updateNodeGraphTransform.transform; @@ -155,12 +117,6 @@ export function createNodeGraphState(editor: Editor) { return state; }); }); - editor.subscriptions.subscribeJsMessage(UpdateWirePathInProgress, (updateWirePathInProgress) => { - update((state) => { - state.wirePathInProgress = updateWirePathInProgress.wirePathInProgress; - return state; - }); - }); return { subscribe, diff --git a/frontend/wasm/src/editor_api.rs b/frontend/wasm/src/editor_api.rs index da1901815d..30e18ba831 100644 --- a/frontend/wasm/src/editor_api.rs +++ b/frontend/wasm/src/editor_api.rs @@ -785,13 +785,6 @@ impl EditorHandle { self.dispatch(message); } - /// Snaps the import/export edges to a grid space when the scroll bar is released - #[wasm_bindgen(js_name = setGridAlignedEdges)] - pub fn set_grid_aligned_edges(&self) { - let message = NodeGraphMessage::SetGridAlignedEdges; - self.dispatch(message); - } - /// Merge the selected nodes into a subnetwork #[wasm_bindgen(js_name = mergeSelectedNodes)] pub fn merge_nodes(&self) { diff --git a/node-graph/gcore/src/node_graph_overlay.rs b/node-graph/gcore/src/node_graph_overlay.rs index bebeb0a102..874332d638 100644 --- a/node-graph/gcore/src/node_graph_overlay.rs +++ b/node-graph/gcore/src/node_graph_overlay.rs @@ -21,12 +21,14 @@ pub mod ui_context; #[node_macro::node(skip_impl)] pub fn generate_nodes(_: impl Ctx, mut node_graph_overlay_data: NodeGraphOverlayData) -> Table { let mut nodes_and_wires = Table::new(); - let layers = draw_layers(&node_graph_overlay_data.nodes_to_render); + let (layers, side_ports) = draw_layers(&node_graph_overlay_data.nodes_to_render); nodes_and_wires.extend(layers); let wires = draw_wires(&mut node_graph_overlay_data.nodes_to_render); nodes_and_wires.extend(wires); + nodes_and_wires.extend(side_ports); + let nodes = draw_nodes(&node_graph_overlay_data.nodes_to_render); nodes_and_wires.extend(nodes); diff --git a/node-graph/gcore/src/node_graph_overlay/nodes_and_wires.rs b/node-graph/gcore/src/node_graph_overlay/nodes_and_wires.rs index 48ba8cf9ed..571173790c 100644 --- a/node-graph/gcore/src/node_graph_overlay/nodes_and_wires.rs +++ b/node-graph/gcore/src/node_graph_overlay/nodes_and_wires.rs @@ -1,6 +1,6 @@ use glam::{DAffine2, DVec2}; use graphene_core_shaders::color::{AlphaMut, Color}; -use kurbo::{BezPath, Rect, RoundedRect, Shape}; +use kurbo::{BezPath, Circle, Rect, RoundedRect, Shape}; use crate::{ Graphic, @@ -26,9 +26,9 @@ pub fn draw_nodes(nodes: &Vec) -> Table { let x = frontend_node.position.x as f64 * GRID_SIZE; let y = frontend_node.position.y as f64 * GRID_SIZE + GRID_SIZE / 2.; let node_width = GRID_SIZE * 5.0; - let number_of_exposed_inputs = frontend_node.inputs.iter().skip(1).filter(|x| x.is_some()).count(); - let number_of_exposed_outputs = frontend_node.outputs.iter().skip(1).filter(|x| x.is_some()).count(); - let number_of_rows = 1 + number_of_exposed_inputs.max(number_of_exposed_outputs); + let number_of_secondary_inputs = frontend_node.secondary_inputs.len(); + let number_of_secondary_outputs = frontend_node.secondary_outputs.len(); + let number_of_rows = 1 + number_of_secondary_inputs.max(number_of_secondary_outputs); let node_height = number_of_rows as f64 * GRID_SIZE; let node_rect = RoundedRect::new(x, y, x + node_width, y + node_height, 2.); @@ -49,7 +49,7 @@ pub fn draw_nodes(nodes: &Vec) -> Table { bg_vector.style.fill = crate::vector::style::Fill::Solid(node_color.clone()); bg_table.push(TableRow::new_from_element(bg_vector)); // Make primary input brighter - if number_of_exposed_inputs == 0 { + if number_of_secondary_inputs == 0 { // Draw the first row with rounded bottom corners bg_table.push(TableRow::new_from_element(node_first_row(x, y, false))); } else { @@ -62,7 +62,7 @@ pub fn draw_nodes(nodes: &Vec) -> Table { let mut border_mask_path = BezPath::new(); border_mask_path.move_to((-2., -2.)); border_mask_path.line_to((node_width + 2., -2.)); - if frontend_node.outputs[0].is_some() { + if frontend_node.primary_output.is_some() { border_mask_path.line_to((node_width + 2., 4.)); border_mask_path.line_to((node_width - 2., 4.)); border_mask_path.line_to((node_width - 2., 20.)); @@ -70,7 +70,7 @@ pub fn draw_nodes(nodes: &Vec) -> Table { border_mask_path.line_to((node_width + 2., 20.)); for row in 1..number_of_rows { border_mask_path.line_to((node_width + 2., row as f64 * GRID_SIZE + 4.)); - if frontend_node.outputs.get(row).is_some_and(|output| output.is_some()) { + if row <= number_of_secondary_outputs { border_mask_path.line_to((node_width - 2., row as f64 * GRID_SIZE + 4.)); border_mask_path.line_to((node_width - 2., row as f64 * GRID_SIZE + 20.)); border_mask_path.line_to((node_width + 2., row as f64 * GRID_SIZE + 20.)); @@ -80,13 +80,13 @@ pub fn draw_nodes(nodes: &Vec) -> Table { border_mask_path.line_to((-2., number_of_rows as f64 * GRID_SIZE + 2.)); for row in (1..number_of_rows).rev() { border_mask_path.line_to((-2., row as f64 * GRID_SIZE + 20.)); - if frontend_node.inputs.iter().skip(1).filter(|input| input.is_some()).nth(row - 1).is_some_and(|input| input.is_some()) { + if row <= number_of_secondary_inputs { border_mask_path.line_to((2., row as f64 * GRID_SIZE + 20.)); border_mask_path.line_to((2., row as f64 * GRID_SIZE + 4.)); border_mask_path.line_to((2., row as f64 * GRID_SIZE + 4.)); } } - if frontend_node.inputs[0].is_some() { + if frontend_node.primary_input.is_some() { border_mask_path.line_to((-2., 20.)); border_mask_path.line_to((2., 20.)); border_mask_path.line_to((2., 4.)); @@ -105,7 +105,8 @@ pub fn draw_nodes(nodes: &Vec) -> Table { // Border table is implemented as a clip mask let mut border_table = Table::new(); let mut border_vector = Vector::from_bezpath(node_bez_path); - let primary_output_color = frontend_node.outputs[0] + let primary_output_color = frontend_node + .primary_output .as_ref() .map(|primary_output| primary_output.data_type.data_color_dim()) .unwrap_or(FrontendGraphDataType::General.data_color_dim()); @@ -132,15 +133,16 @@ pub fn draw_nodes(nodes: &Vec) -> Table { for text_row in node_text.iter_mut() { *text_row.transform = DAffine2::from_translation(DVec2::new(x + 8., y + 3.)); } - for (row, input) in frontend_node.inputs.iter().enumerate().skip(1) { - if let Some(input) = input { + + for row in 1..=number_of_rows { + if let Some(input) = frontend_node.secondary_inputs.get(row - 1) { let font_blob = Some(text::load_font(SOURCE_SANS_FONT_DATA)); let mut input_row_text = crate::text::to_path(&input.name, font_blob, typesetting, false); for text_row in input_row_text.iter_mut() { *text_row.transform = DAffine2::from_translation(DVec2::new(x + 8., y + 24. * row as f64 + 3.)); } node_text.extend(input_row_text); - } else if let Some(Some(output)) = frontend_node.outputs.get(row) { + } else if let Some(output) = frontend_node.secondary_outputs.get(row - 1) { let font_blob = Some(text::load_font(SOURCE_SANS_FONT_DATA)); let mut output_row_text = crate::text::to_path(&output.name, font_blob, typesetting, false); // Find width to right align text @@ -176,14 +178,41 @@ pub fn draw_nodes(nodes: &Vec) -> Table { text_area_row.alpha_blending.clip = true; let text_area_table = Table::new_from_row(text_area_row); node_table.push(TableRow::new_from_element(Graphic::Vector(text_area_table))); + + // Input and output ports + let mut ports_table = Table::new(); + if let Some(primary_input) = &frontend_node.primary_input { + let mut row = port_row(&primary_input.data_type); + row.transform = DAffine2::from_translation(DVec2::new(0., 12.)); + ports_table.push(row); + } + for (index, secondary_input) in frontend_node.secondary_inputs.iter().enumerate() { + let mut row = port_row(&secondary_input.data_type); + row.transform = DAffine2::from_translation(DVec2::new(0., 12. + GRID_SIZE * (index + 1) as f64)); + ports_table.push(row); + } + if let Some(primary_output) = &frontend_node.primary_output { + let mut row = port_row(&primary_output.data_type); + row.transform = DAffine2::from_translation(DVec2::new(5. * GRID_SIZE, 12.)); + ports_table.push(row); + } + for (index, secondary_output) in frontend_node.secondary_outputs.iter().enumerate() { + let mut row = port_row(&secondary_output.data_type); + row.transform = DAffine2::from_translation(DVec2::new(5. * GRID_SIZE, 12. + GRID_SIZE * (index + 1) as f64)); + ports_table.push(row); + } + let mut graphic_ports_row = TableRow::new_from_element(Graphic::Vector(ports_table)); + graphic_ports_row.transform = DAffine2::from_translation(DVec2::new(x - 3., y - 4.)); + node_table.push(graphic_ports_row); } } node_table } -pub fn draw_layers(nodes: &Vec) -> Table { +pub fn draw_layers(nodes: &Vec) -> (Table, Table) { let mut layer_table = Table::new(); + let mut side_ports = Table::new(); for node_to_render in nodes { if let Some(frontend_layer) = node_to_render.node_or_layer.layer.as_ref() { // The layer position is the top left of the thumbnail @@ -219,12 +248,12 @@ pub fn draw_layers(nodes: &Vec) -> Table { // Text starts at thumbnail + left padding let text_start = 12. + 8.; - let right_text_edge = text_start + text_width; + let right_text_edge = 8. + text_width; let rounded_text_edge = (right_text_edge as f64 / 24.).ceil() * 24.; let rounded_layer_width_pixels = rounded_text_edge + 24.; - // Subtract the left thumbnail - let layer_right_edge_width = rounded_layer_width_pixels - 12.; + // add the left thumbnail gap + let layer_right_edge_width = rounded_layer_width_pixels + 12.; let right_layer_width = layer_right_edge_width.max(4.5 * GRID_SIZE); let thumbnail_width = 3. * GRID_SIZE; @@ -305,10 +334,84 @@ pub fn draw_layers(nodes: &Vec) -> Table { } let top_layer = text_table; layer_table.push(TableRow::new_from_element(Graphic::Vector(top_layer))); + + // Ports + let mut ports_table = Table::new(); + if let Some(side_input) = &frontend_layer.side_input { + let mut port = port_row(&side_input.data_type); + port.transform = DAffine2::from_translation(DVec2::new(layer_position.x - 15., layer_position.y + GRID_SIZE - 4.)); + ports_table.push(port); + } + let top_port = BezPath::from_svg("M0,6.953l2.521,-1.694a2.649,2.649,0,0,1,2.959,0l2.52,1.694v5.047h-8z").unwrap(); + let mut vector = Vector::from_bezpath(top_port); + vector.style.fill = Fill::Solid(Color::from_rgba8_no_srgb(frontend_layer.output.data_type.data_color()).unwrap()); + let mut side_port = TableRow::new_from_element(vector); + side_port.transform = DAffine2::from_translation(DVec2::new(frontend_layer.position.x as f64 * 24. + GRID_SIZE * 2. - 4., layer_position.y - 12.)); + side_ports.push(side_port); + if frontend_layer.primary_output_connected_to_layer { + let top_wire_cap = BezPath::from_svg("M0,-3.5h8v8l-2.521,-1.681a2.666,2.666,0,0,0,-2.959,0l-2.52,1.681z").unwrap(); + let mut vector = Vector::from_bezpath(top_wire_cap); + vector.style.fill = Fill::Solid(Color::from_rgba8_no_srgb(frontend_layer.output.data_type.data_color_dim()).unwrap()); + let mut vector_row = TableRow::new_from_element(vector); + vector_row.transform = DAffine2::from_translation(DVec2::new(frontend_layer.position.x as f64 * 24. + GRID_SIZE * 2. - 4., layer_position.y - 12.)); + ports_table.push(vector_row); + } + let bottom_port = BezPath::from_svg("M0,0H8V8L5.479,6.319a2.666,2.666,0,0,0-2.959,0L0,8Z").unwrap(); + let mut vector = Vector::from_bezpath(bottom_port); + vector.style.fill = Fill::Solid(Color::from_rgba8_no_srgb(frontend_layer.bottom_input.data_type.data_color()).unwrap()); + let mut vector_row = TableRow::new_from_element(vector); + vector_row.transform = DAffine2::from_translation(DVec2::new(frontend_layer.position.x as f64 * 24. + GRID_SIZE * 2. - 4., layer_position.y + 2. * GRID_SIZE)); + ports_table.push(vector_row); + if frontend_layer.primary_input_connected_to_layer { + let bottom_port_cap = BezPath::from_svg("M0,10.95l2.52,-1.69c0.89,-0.6,2.06,-0.6,2.96,0l2.52,1.69v5.05h-8v-5.05z").unwrap(); + let mut vector = Vector::from_bezpath(bottom_port_cap); + vector.style.fill = Fill::Solid(Color::from_rgba8_no_srgb(frontend_layer.bottom_input.data_type.data_color_dim()).unwrap()); + let mut vector_row = TableRow::new_from_element(vector); + vector_row.transform = DAffine2::from_translation(DVec2::new(frontend_layer.position.x as f64 * 24. + GRID_SIZE * 2. - 4., layer_position.y + 2. * GRID_SIZE)); + ports_table.push(vector_row); + } + layer_table.push(TableRow::new_from_element(Graphic::Vector(ports_table))); + + // Eye and grip icon + let mut icons_table = Table::new(); + let icon_svg = if node_to_render.metadata.visible { + BezPath::from_svg("M8,3C3,3,0,8,0,8s3,5,8,5s8-5,8-5S13,3,8,3z M8,12c-2.2,0-4-1.8-4-4s1.8-4,4-4s4,1.8,4,4S10.2,12,8,12z").unwrap() + } else { + BezPath::from_svg("M8,4c3.5,0,5.9,2.8,6.8,4c-0.9,1.2-3.3,4-6.8,4S2.1,9.2,1.2,8C2.1,6.8,4.5,4,8,4 M8,3C3,3,0,8,0,8s3,5,8,5s8-5,8-5S13,3,8,3L8,3z").unwrap() + }; + let mut icon_vector = Vector::from_bezpath(icon_svg); + icon_vector.style.fill = Fill::Solid(Color::WHITE); + let mut icon_row = TableRow::new_from_element(icon_vector); + icon_row.transform = DAffine2::from_translation(layer_position + DVec2::new(thumbnail_width + right_layer_width - 8., 16.)); + icons_table.push(icon_row); + + if node_to_render.metadata.selected { + let mut grip_path = BezPath::new(); + let circle = Circle::new((0.5, 1.5), 0.5); + grip_path.extend(circle.to_path(BEZ_PATH_TOLERANCE)); + let circle = Circle::new((0.5, 4.5), 0.5); + grip_path.extend(circle.to_path(BEZ_PATH_TOLERANCE)); + let circle = Circle::new((0.5, 7.5), 0.5); + grip_path.extend(circle.to_path(BEZ_PATH_TOLERANCE)); + let circle = Circle::new((3.5, 1.5), 0.5); + grip_path.extend(circle.to_path(BEZ_PATH_TOLERANCE)); + let circle = Circle::new((3.5, 4.5), 0.5); + grip_path.extend(circle.to_path(BEZ_PATH_TOLERANCE)); + let circle = Circle::new((3.5, 7.5), 0.5); + grip_path.extend(circle.to_path(BEZ_PATH_TOLERANCE)); + let mut grip_vector = Vector::from_bezpath(grip_path); + grip_vector.style.fill = Fill::Solid(Color::from_rgba8_no_srgb(COLOR_E_NEARWHITE).unwrap()); + let mut grip_row = TableRow::new_from_element(grip_vector); + grip_row.transform = DAffine2::from_translation(layer_position + DVec2::new(thumbnail_width + right_layer_width + 6. - GRID_SIZE, 19.5)); + icons_table.push(grip_row); + } + layer_table.push(TableRow::new_from_element(Graphic::Vector(icons_table))); } } - layer_table + let mut ports_table = Table::new(); + ports_table.push(TableRow::new_from_element(Graphic::Vector(side_ports))); + (layer_table, ports_table) } fn node_first_row(x0: f64, y0: f64, rounded_bottom: bool) -> Vector { @@ -352,10 +455,13 @@ fn node_first_row(x0: f64, y0: f64, rounded_bottom: bool) -> Vector { vector } -fn port() -> BezPath { - BezPath::from_svg("M0,6.306A1.474,1.474,0,0,0,2.356,7.724L7.028,5.248c1.3-.687,1.3-1.809,0-2.5L2.356.276A1.474,1.474,0,0,0,0,1.694Z").unwrap_or_else(|e| { +fn port_row(data_type: &FrontendGraphDataType) -> TableRow { + let path = BezPath::from_svg("M0,6.306A1.474,1.474,0,0,0,2.356,7.724L7.028,5.248c1.3-.687,1.3-1.809,0-2.5L2.356.276A1.474,1.474,0,0,0,0,1.694Z").unwrap_or_else(|e| { panic!("Could not parse port svg from string: {}", e); - }) + }); + let mut vector = Vector::from_bezpath(path); + vector.style.fill = Fill::Solid(Color::from_rgba8_no_srgb(data_type.data_color()).unwrap()); + TableRow::new_from_element(vector) } pub fn draw_wires(nodes: &mut Vec) -> Table { diff --git a/node-graph/gcore/src/node_graph_overlay/types.rs b/node-graph/gcore/src/node_graph_overlay/types.rs index ff85dee33b..1acfcc3a0b 100644 --- a/node-graph/gcore/src/node_graph_overlay/types.rs +++ b/node-graph/gcore/src/node_graph_overlay/types.rs @@ -75,8 +75,10 @@ pub struct FrontendNodeMetadata { pub struct FrontendNode { // pub position: FrontendNodePosition, pub position: FrontendXY, - pub inputs: Vec>, - pub outputs: Vec>, + pub primary_output: Option, + pub primary_input: Option, + pub secondary_inputs: Vec, + pub secondary_outputs: Vec, } #[derive(Clone, Debug, Default, PartialEq, Hash, dyn_any::DynAny, serde::Serialize, serde::Deserialize, specta::Type)]