From 5a1f4e8855fa84b033f285ca9ae2bbade41fc082 Mon Sep 17 00:00:00 2001 From: Adesh Gupta Date: Sat, 2 Aug 2025 11:57:09 +0530 Subject: [PATCH 1/5] Fix add path node button enable --- .../node_graph/node_graph_message_handler.rs | 15 ++++++++++++--- .../src/messages/tool/tool_messages/path_tool.rs | 13 +++++++++---- 2 files changed, 21 insertions(+), 7 deletions(-) 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 f28d9d4e11..def98cca38 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 @@ -25,6 +25,7 @@ use graph_craft::document::value::TaggedValue; use graph_craft::document::{DocumentNodeImplementation, NodeId, NodeInput}; use graph_craft::proto::GraphErrors; use graphene_std::math::math_ext::QuadExt; +use graphene_std::vector::VectorModification; use graphene_std::vector::misc::subpath_to_kurbo_bezpath; use graphene_std::*; use kurbo::{Line, Point}; @@ -145,9 +146,17 @@ impl<'a> MessageHandler> for NodeG if first_layer.is_some() && has_single_selection && is_compatible { if let Some(layer) = first_layer { let node_type = "Path".to_string(); - let graph_layer = graph_modification_utils::NodeGraphLayer::new(layer, &network_interface); - let is_modifiable = matches!(graph_layer.find_input("Path", 1), Some(TaggedValue::VectorModification(_))); - if !is_modifiable { + let path_node_with_no_diffs_exist = first_layer.is_some_and(|layer| { + let graph_layer = graph_modification_utils::NodeGraphLayer::new(layer, &network_interface); + if let Some(TaggedValue::VectorModification(vector)) = graph_layer.find_input("Path", 1) { + let modification = *vector.clone(); + modification == VectorModification::default() + } else { + false + } + }); + + if !path_node_with_no_diffs_exist { responses.add(NodeGraphMessage::CreateNodeInLayerWithTransaction { node_type: node_type.clone(), layer: LayerNodeIdentifier::new_unchecked(layer.to_node()), diff --git a/editor/src/messages/tool/tool_messages/path_tool.rs b/editor/src/messages/tool/tool_messages/path_tool.rs index e5efc14afe..77293b2363 100644 --- a/editor/src/messages/tool/tool_messages/path_tool.rs +++ b/editor/src/messages/tool/tool_messages/path_tool.rs @@ -23,7 +23,7 @@ use graph_craft::document::value::TaggedValue; use graphene_std::renderer::Quad; use graphene_std::transform::ReferencePoint; use graphene_std::vector::click_target::ClickTargetType; -use graphene_std::vector::{HandleExt, HandleId, NoHashBuilder, SegmentId, VectorData}; +use graphene_std::vector::{HandleExt, HandleId, NoHashBuilder, SegmentId, VectorData, VectorModification}; use graphene_std::vector::{ManipulatorPointId, PointId, VectorModificationType}; use std::vec; @@ -2423,12 +2423,17 @@ impl Fsm for PathToolFsmState { let is_compatible = compatible_type.as_deref() == Some("type:Instances"); - let is_modifiable = first_layer.is_some_and(|layer| { + let path_node_with_no_diffs_exist = first_layer.is_some_and(|layer| { let graph_layer = graph_modification_utils::NodeGraphLayer::new(layer, &document.network_interface); - matches!(graph_layer.find_input("Path", 1), Some(TaggedValue::VectorModification(_))) + if let Some(TaggedValue::VectorModification(vector)) = graph_layer.find_input("Path", 1) { + let modification = *vector.clone(); + modification == VectorModification::default() + } else { + false + } }); - first_layer.is_some() && has_single_selection && is_compatible && !is_modifiable + first_layer.is_some() && has_single_selection && is_compatible && !path_node_with_no_diffs_exist }; tool_data.update_selection_status(shape_editor, document); self From 153c5e2f73fc38ea8630828574aabc6d72162352 Mon Sep 17 00:00:00 2001 From: Adesh Gupta Date: Sat, 2 Aug 2025 11:57:09 +0530 Subject: [PATCH 2/5] Fix add path node button enable --- .../node_graph/node_graph_message_handler.rs | 15 ++++++++++++--- .../src/messages/tool/tool_messages/path_tool.rs | 13 +++++++++---- 2 files changed, 21 insertions(+), 7 deletions(-) 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 f28d9d4e11..def98cca38 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 @@ -25,6 +25,7 @@ use graph_craft::document::value::TaggedValue; use graph_craft::document::{DocumentNodeImplementation, NodeId, NodeInput}; use graph_craft::proto::GraphErrors; use graphene_std::math::math_ext::QuadExt; +use graphene_std::vector::VectorModification; use graphene_std::vector::misc::subpath_to_kurbo_bezpath; use graphene_std::*; use kurbo::{Line, Point}; @@ -145,9 +146,17 @@ impl<'a> MessageHandler> for NodeG if first_layer.is_some() && has_single_selection && is_compatible { if let Some(layer) = first_layer { let node_type = "Path".to_string(); - let graph_layer = graph_modification_utils::NodeGraphLayer::new(layer, &network_interface); - let is_modifiable = matches!(graph_layer.find_input("Path", 1), Some(TaggedValue::VectorModification(_))); - if !is_modifiable { + let path_node_with_no_diffs_exist = first_layer.is_some_and(|layer| { + let graph_layer = graph_modification_utils::NodeGraphLayer::new(layer, &network_interface); + if let Some(TaggedValue::VectorModification(vector)) = graph_layer.find_input("Path", 1) { + let modification = *vector.clone(); + modification == VectorModification::default() + } else { + false + } + }); + + if !path_node_with_no_diffs_exist { responses.add(NodeGraphMessage::CreateNodeInLayerWithTransaction { node_type: node_type.clone(), layer: LayerNodeIdentifier::new_unchecked(layer.to_node()), diff --git a/editor/src/messages/tool/tool_messages/path_tool.rs b/editor/src/messages/tool/tool_messages/path_tool.rs index e5efc14afe..77293b2363 100644 --- a/editor/src/messages/tool/tool_messages/path_tool.rs +++ b/editor/src/messages/tool/tool_messages/path_tool.rs @@ -23,7 +23,7 @@ use graph_craft::document::value::TaggedValue; use graphene_std::renderer::Quad; use graphene_std::transform::ReferencePoint; use graphene_std::vector::click_target::ClickTargetType; -use graphene_std::vector::{HandleExt, HandleId, NoHashBuilder, SegmentId, VectorData}; +use graphene_std::vector::{HandleExt, HandleId, NoHashBuilder, SegmentId, VectorData, VectorModification}; use graphene_std::vector::{ManipulatorPointId, PointId, VectorModificationType}; use std::vec; @@ -2423,12 +2423,17 @@ impl Fsm for PathToolFsmState { let is_compatible = compatible_type.as_deref() == Some("type:Instances"); - let is_modifiable = first_layer.is_some_and(|layer| { + let path_node_with_no_diffs_exist = first_layer.is_some_and(|layer| { let graph_layer = graph_modification_utils::NodeGraphLayer::new(layer, &document.network_interface); - matches!(graph_layer.find_input("Path", 1), Some(TaggedValue::VectorModification(_))) + if let Some(TaggedValue::VectorModification(vector)) = graph_layer.find_input("Path", 1) { + let modification = *vector.clone(); + modification == VectorModification::default() + } else { + false + } }); - first_layer.is_some() && has_single_selection && is_compatible && !is_modifiable + first_layer.is_some() && has_single_selection && is_compatible && !path_node_with_no_diffs_exist }; tool_data.update_selection_status(shape_editor, document); self From 4ac905dde88ca3f146685b66688bb667a13b857a Mon Sep 17 00:00:00 2001 From: Adesh Gupta Date: Sat, 2 Aug 2025 12:58:46 +0530 Subject: [PATCH 3/5] Refactor code --- .../node_graph/node_graph_message_handler.rs | 46 +++---------------- .../portfolio/portfolio_message_handler.rs | 28 +---------- .../common_functionality/utility_functions.rs | 38 +++++++++++++-- .../messages/tool/tool_messages/path_tool.rs | 36 ++------------- 4 files changed, 47 insertions(+), 101 deletions(-) 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 def98cca38..55385429e5 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 @@ -17,15 +17,14 @@ use crate::messages::portfolio::document::utility_types::wires::{GraphWireStyle, use crate::messages::prelude::*; use crate::messages::tool::common_functionality::auto_panning::AutoPanning; use crate::messages::tool::common_functionality::graph_modification_utils::{self, get_clip_mode}; +use crate::messages::tool::common_functionality::utility_functions::single_path_node_compatible_layer_selected; use crate::messages::tool::tool_messages::tool_prelude::{Key, MouseMotion}; use crate::messages::tool::utility_types::{HintData, HintGroup, HintInfo}; use bezier_rs::Subpath; use glam::{DAffine2, DVec2, IVec2}; -use graph_craft::document::value::TaggedValue; use graph_craft::document::{DocumentNodeImplementation, NodeId, NodeInput}; use graph_craft::proto::GraphErrors; use graphene_std::math::math_ext::QuadExt; -use graphene_std::vector::VectorModification; use graphene_std::vector::misc::subpath_to_kurbo_bezpath; use graphene_std::*; use kurbo::{Line, Point}; @@ -127,43 +126,12 @@ impl<'a> MessageHandler> for NodeG responses.add(NodeGraphMessage::SelectedNodesSet { nodes: vec![new_layer_id] }); } NodeGraphMessage::AddPathNode => { - let selected_nodes = network_interface.selected_nodes(); - let mut selected_layers = selected_nodes.selected_layers(network_interface.document_metadata()); - let first_layer = selected_layers.next(); - let second_layer = selected_layers.next(); - let has_single_selection = first_layer.is_some() && second_layer.is_none(); - - let compatible_type = first_layer.and_then(|layer| { - let graph_layer = graph_modification_utils::NodeGraphLayer::new(layer, &network_interface); - graph_layer.horizontal_layer_flow().nth(1).and_then(|node_id| { - let (output_type, _) = network_interface.output_type(&node_id, 0, &[]); - Some(format!("type:{}", output_type.nested_type())) - }) - }); - - let is_compatible = compatible_type.as_deref() == Some("type:Instances"); - - if first_layer.is_some() && has_single_selection && is_compatible { - if let Some(layer) = first_layer { - let node_type = "Path".to_string(); - let path_node_with_no_diffs_exist = first_layer.is_some_and(|layer| { - let graph_layer = graph_modification_utils::NodeGraphLayer::new(layer, &network_interface); - if let Some(TaggedValue::VectorModification(vector)) = graph_layer.find_input("Path", 1) { - let modification = *vector.clone(); - modification == VectorModification::default() - } else { - false - } - }); - - if !path_node_with_no_diffs_exist { - responses.add(NodeGraphMessage::CreateNodeInLayerWithTransaction { - node_type: node_type.clone(), - layer: LayerNodeIdentifier::new_unchecked(layer.to_node()), - }); - responses.add(BroadcastEvent::SelectionChanged); - } - } + if let Some(layer) = single_path_node_compatible_layer_selected(&network_interface, network_interface.document_metadata()) { + responses.add(NodeGraphMessage::CreateNodeInLayerWithTransaction { + node_type: "Path".to_string(), + layer: layer, + }); + responses.add(BroadcastEvent::SelectionChanged); } } NodeGraphMessage::AddImport => { diff --git a/editor/src/messages/portfolio/portfolio_message_handler.rs b/editor/src/messages/portfolio/portfolio_message_handler.rs index b5baa703e5..628af9bdfe 100644 --- a/editor/src/messages/portfolio/portfolio_message_handler.rs +++ b/editor/src/messages/portfolio/portfolio_message_handler.rs @@ -18,12 +18,11 @@ use crate::messages::portfolio::document::utility_types::nodes::SelectedNodes; use crate::messages::portfolio::document_migration::*; use crate::messages::preferences::SelectionMode; use crate::messages::prelude::*; -use crate::messages::tool::common_functionality::graph_modification_utils; +use crate::messages::tool::common_functionality::utility_functions::single_path_node_compatible_layer_selected; use crate::messages::tool::utility_types::{HintData, HintGroup, ToolType}; use crate::node_graph_executor::{ExportConfig, NodeGraphExecutor}; use glam::{DAffine2, DVec2}; use graph_craft::document::NodeId; -use graph_craft::document::value::TaggedValue; use graphene_std::renderer::Quad; use graphene_std::text::Font; use std::vec; @@ -98,30 +97,7 @@ impl MessageHandler> for Portfolio let metadata = &document.network_interface.document_network_metadata().persistent_metadata; (!metadata.selection_undo_history.is_empty(), !metadata.selection_redo_history.is_empty()) }; - self.menu_bar_message_handler.single_path_node_compatible_layer_selected = { - let selected_nodes = document.network_interface.selected_nodes(); - let mut selected_layers = selected_nodes.selected_layers(document.metadata()); - let first_layer = selected_layers.next(); - let second_layer = selected_layers.next(); - let has_single_selection = first_layer.is_some() && second_layer.is_none(); - - let compatible_type = first_layer.and_then(|layer| { - let graph_layer = graph_modification_utils::NodeGraphLayer::new(layer, &document.network_interface); - graph_layer.horizontal_layer_flow().nth(1).map(|node_id| { - let (output_type, _) = document.network_interface.output_type(&node_id, 0, &[]); - format!("type:{}", output_type.nested_type()) - }) - }); - - let is_compatible = compatible_type.as_deref() == Some("type:Instances"); - - let is_modifiable = first_layer.is_some_and(|layer| { - let graph_layer = graph_modification_utils::NodeGraphLayer::new(layer, &document.network_interface); - matches!(graph_layer.find_input("Path", 1), Some(TaggedValue::VectorModification(_))) - }); - - first_layer.is_some() && has_single_selection && is_compatible && !is_modifiable - } + self.menu_bar_message_handler.single_path_node_compatible_layer_selected = single_path_node_compatible_layer_selected(&document.network_interface, document.metadata()).is_some(); } self.menu_bar_message_handler.process_message(message, responses, ()); diff --git a/editor/src/messages/tool/common_functionality/utility_functions.rs b/editor/src/messages/tool/common_functionality/utility_functions.rs index c6707ab3c0..a989854db3 100644 --- a/editor/src/messages/tool/common_functionality/utility_functions.rs +++ b/editor/src/messages/tool/common_functionality/utility_functions.rs @@ -1,18 +1,20 @@ use super::snapping::{SnapCandidatePoint, SnapData, SnapManager}; use super::transformation_cage::{BoundingBoxManager, SizeSnapData}; use crate::consts::ROTATE_INCREMENT; -use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier; +use crate::messages::portfolio::document::utility_types::document_metadata::{DocumentMetadata, LayerNodeIdentifier}; +use crate::messages::portfolio::document::utility_types::network_interface::NodeNetworkInterface; use crate::messages::portfolio::document::utility_types::transformation::Selected; use crate::messages::prelude::*; -use crate::messages::tool::common_functionality::graph_modification_utils::get_text; +use crate::messages::tool::common_functionality::graph_modification_utils::{self, get_text}; use crate::messages::tool::common_functionality::transformation_cage::SelectedEdges; use crate::messages::tool::tool_messages::path_tool::PathOverlayMode; use crate::messages::tool::utility_types::ToolType; use bezier_rs::{Bezier, BezierHandles}; use glam::{DAffine2, DVec2}; +use graph_craft::document::value::TaggedValue; use graphene_std::renderer::Quad; use graphene_std::text::{FontCache, load_font}; -use graphene_std::vector::{HandleExt, HandleId, ManipulatorPointId, PointId, SegmentId, VectorData, VectorModificationType}; +use graphene_std::vector::{HandleExt, HandleId, ManipulatorPointId, PointId, SegmentId, VectorData, VectorModification, VectorModificationType}; use kurbo::{CubicBez, Line, ParamCurveExtrema, PathSeg, Point, QuadBez}; /// Determines if a path should be extended. Goal in viewport space. Returns the path and if it is extending from the start, if applicable. @@ -586,3 +588,33 @@ pub fn find_two_param_best_approximate(p1: DVec2, p3: DVec2, d1: DVec2, d2: DVec (d1 * len1, d2 * len2) } + +pub fn single_path_node_compatible_layer_selected(network_interface: &NodeNetworkInterface, metadata: &DocumentMetadata) -> Option { + let selected_nodes = network_interface.selected_nodes(); + let mut selected_layers = selected_nodes.selected_layers(metadata); + let first_layer = selected_layers.next(); + let second_layer = selected_layers.next(); + let has_single_selection = first_layer.is_some() && second_layer.is_none(); + let compatible_type = first_layer.and_then(|layer| { + let graph_layer = graph_modification_utils::NodeGraphLayer::new(layer, &network_interface); + graph_layer.horizontal_layer_flow().nth(1).map(|node_id| { + let (output_type, _) = network_interface.output_type(&node_id, 0, &[]); + format!("type:{}", output_type.nested_type()) + }) + }); + let is_compatible = compatible_type.as_deref() == Some("type:Instances"); + let path_node_with_no_diffs_exist = first_layer.is_some_and(|layer| { + let graph_layer = graph_modification_utils::NodeGraphLayer::new(layer, &network_interface); + if let Some(TaggedValue::VectorModification(vector)) = graph_layer.find_input("Path", 1) { + let modification = *vector.clone(); + modification == VectorModification::default() + } else { + false + } + }); + if first_layer.is_some() && has_single_selection && is_compatible && !path_node_with_no_diffs_exist { + first_layer + } else { + None + } +} diff --git a/editor/src/messages/tool/tool_messages/path_tool.rs b/editor/src/messages/tool/tool_messages/path_tool.rs index 77293b2363..3ad5b7b482 100644 --- a/editor/src/messages/tool/tool_messages/path_tool.rs +++ b/editor/src/messages/tool/tool_messages/path_tool.rs @@ -11,19 +11,17 @@ use crate::messages::portfolio::document::utility_types::network_interface::Node use crate::messages::portfolio::document::utility_types::transformation::Axis; use crate::messages::preferences::SelectionMode; use crate::messages::tool::common_functionality::auto_panning::AutoPanning; -use crate::messages::tool::common_functionality::graph_modification_utils; use crate::messages::tool::common_functionality::pivot::{PivotGizmo, PivotGizmoType, PivotToolSource, pin_pivot_widget, pivot_gizmo_type_widget, pivot_reference_point_widget}; use crate::messages::tool::common_functionality::shape_editor::{ ClosestSegment, ManipulatorAngle, OpposingHandleLengths, SelectedLayerState, SelectedPointsInfo, SelectionChange, SelectionShape, SelectionShapeType, ShapeState, }; use crate::messages::tool::common_functionality::snapping::{SnapCache, SnapCandidatePoint, SnapConstraint, SnapData, SnapManager}; -use crate::messages::tool::common_functionality::utility_functions::{calculate_segment_angle, find_two_param_best_approximate}; +use crate::messages::tool::common_functionality::utility_functions::{calculate_segment_angle, find_two_param_best_approximate, single_path_node_compatible_layer_selected}; use bezier_rs::{Bezier, BezierHandles, TValue}; -use graph_craft::document::value::TaggedValue; use graphene_std::renderer::Quad; use graphene_std::transform::ReferencePoint; use graphene_std::vector::click_target::ClickTargetType; -use graphene_std::vector::{HandleExt, HandleId, NoHashBuilder, SegmentId, VectorData, VectorModification}; +use graphene_std::vector::{HandleExt, HandleId, NoHashBuilder, SegmentId, VectorData}; use graphene_std::vector::{ManipulatorPointId, PointId, VectorModificationType}; use std::vec; @@ -2406,35 +2404,7 @@ impl Fsm for PathToolFsmState { colinear, }; - tool_data.single_path_node_compatible_layer_selected = { - let selected_nodes = document.network_interface.selected_nodes(); - let mut selected_layers = selected_nodes.selected_layers(document.metadata()); - let first_layer = selected_layers.next(); - let second_layer = selected_layers.next(); - let has_single_selection = first_layer.is_some() && second_layer.is_none(); - - let compatible_type = first_layer.and_then(|layer| { - let graph_layer = graph_modification_utils::NodeGraphLayer::new(layer, &document.network_interface); - graph_layer.horizontal_layer_flow().nth(1).map(|node_id| { - let (output_type, _) = document.network_interface.output_type(&node_id, 0, &[]); - format!("type:{}", output_type.nested_type()) - }) - }); - - let is_compatible = compatible_type.as_deref() == Some("type:Instances"); - - let path_node_with_no_diffs_exist = first_layer.is_some_and(|layer| { - let graph_layer = graph_modification_utils::NodeGraphLayer::new(layer, &document.network_interface); - if let Some(TaggedValue::VectorModification(vector)) = graph_layer.find_input("Path", 1) { - let modification = *vector.clone(); - modification == VectorModification::default() - } else { - false - } - }); - - first_layer.is_some() && has_single_selection && is_compatible && !path_node_with_no_diffs_exist - }; + tool_data.single_path_node_compatible_layer_selected = single_path_node_compatible_layer_selected(&document.network_interface, document.metadata()).is_some(); tool_data.update_selection_status(shape_editor, document); self } From fb70a547607c8c7e7c2d6e1ba770e4bc17b95726 Mon Sep 17 00:00:00 2001 From: Adesh Gupta Date: Sat, 2 Aug 2025 13:04:08 +0530 Subject: [PATCH 4/5] Fix formatting --- .../portfolio/document/node_graph/node_graph_message_handler.rs | 1 - editor/src/messages/tool/tool_messages/path_tool.rs | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) 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 92e947faca..55385429e5 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 @@ -25,7 +25,6 @@ use glam::{DAffine2, DVec2, IVec2}; use graph_craft::document::{DocumentNodeImplementation, NodeId, NodeInput}; use graph_craft::proto::GraphErrors; use graphene_std::math::math_ext::QuadExt; -use graphene_std::vector::VectorModification; use graphene_std::vector::misc::subpath_to_kurbo_bezpath; use graphene_std::*; use kurbo::{Line, Point}; diff --git a/editor/src/messages/tool/tool_messages/path_tool.rs b/editor/src/messages/tool/tool_messages/path_tool.rs index b38d1f9124..3ad5b7b482 100644 --- a/editor/src/messages/tool/tool_messages/path_tool.rs +++ b/editor/src/messages/tool/tool_messages/path_tool.rs @@ -21,7 +21,7 @@ use bezier_rs::{Bezier, BezierHandles, TValue}; use graphene_std::renderer::Quad; use graphene_std::transform::ReferencePoint; use graphene_std::vector::click_target::ClickTargetType; -use graphene_std::vector::{HandleExt, HandleId, NoHashBuilder, SegmentId, VectorData, VectorModification}; +use graphene_std::vector::{HandleExt, HandleId, NoHashBuilder, SegmentId, VectorData}; use graphene_std::vector::{ManipulatorPointId, PointId, VectorModificationType}; use std::vec; From 708117533be2a38385719307955b96a2f247f0bb Mon Sep 17 00:00:00 2001 From: Keavon Chambers Date: Sat, 2 Aug 2025 03:02:02 -0700 Subject: [PATCH 5/5] Clean up logic --- .../node_graph/node_graph_message_handler.rs | 9 ++-- .../menu_bar/menu_bar_message_handler.rs | 6 +-- .../portfolio/portfolio_message_handler.rs | 6 +-- .../common_functionality/utility_functions.rs | 52 ++++++++++--------- .../messages/tool/tool_messages/path_tool.rs | 8 +-- 5 files changed, 41 insertions(+), 40 deletions(-) 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 55385429e5..e02856bcac 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 @@ -17,7 +17,7 @@ use crate::messages::portfolio::document::utility_types::wires::{GraphWireStyle, use crate::messages::prelude::*; use crate::messages::tool::common_functionality::auto_panning::AutoPanning; use crate::messages::tool::common_functionality::graph_modification_utils::{self, get_clip_mode}; -use crate::messages::tool::common_functionality::utility_functions::single_path_node_compatible_layer_selected; +use crate::messages::tool::common_functionality::utility_functions::make_path_editable_is_allowed; use crate::messages::tool::tool_messages::tool_prelude::{Key, MouseMotion}; use crate::messages::tool::utility_types::{HintData, HintGroup, HintInfo}; use bezier_rs::Subpath; @@ -126,11 +126,8 @@ impl<'a> MessageHandler> for NodeG responses.add(NodeGraphMessage::SelectedNodesSet { nodes: vec![new_layer_id] }); } NodeGraphMessage::AddPathNode => { - if let Some(layer) = single_path_node_compatible_layer_selected(&network_interface, network_interface.document_metadata()) { - responses.add(NodeGraphMessage::CreateNodeInLayerWithTransaction { - node_type: "Path".to_string(), - layer: layer, - }); + if let Some(layer) = make_path_editable_is_allowed(network_interface, network_interface.document_metadata()) { + responses.add(NodeGraphMessage::CreateNodeInLayerWithTransaction { node_type: "Path".to_string(), layer }); responses.add(BroadcastEvent::SelectionChanged); } } 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 d51ab70cca..fb59e1fb1e 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 @@ -19,7 +19,7 @@ pub struct MenuBarMessageHandler { pub spreadsheet_view_open: bool, pub message_logging_verbosity: MessageLoggingVerbosity, pub reset_node_definitions_on_open: bool, - pub single_path_node_compatible_layer_selected: bool, + pub make_path_editable_is_allowed: bool, } #[message_handler_data] @@ -46,7 +46,7 @@ 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 single_path_node_compatible_layer_selected = self.single_path_node_compatible_layer_selected; + let make_path_editable_is_allowed = self.make_path_editable_is_allowed; let menu_bar_entries = vec![ MenuBarEntry { @@ -442,7 +442,7 @@ impl LayoutHolder for MenuBarMessageHandler { icon: Some("NodeShape".into()), shortcut: None, action: MenuBarEntry::create_action(|_| NodeGraphMessage::AddPathNode.into()), - disabled: !single_path_node_compatible_layer_selected, + disabled: !make_path_editable_is_allowed, ..MenuBarEntry::default() }], ]), diff --git a/editor/src/messages/portfolio/portfolio_message_handler.rs b/editor/src/messages/portfolio/portfolio_message_handler.rs index 628af9bdfe..b87976557d 100644 --- a/editor/src/messages/portfolio/portfolio_message_handler.rs +++ b/editor/src/messages/portfolio/portfolio_message_handler.rs @@ -18,7 +18,7 @@ use crate::messages::portfolio::document::utility_types::nodes::SelectedNodes; use crate::messages::portfolio::document_migration::*; use crate::messages::preferences::SelectionMode; use crate::messages::prelude::*; -use crate::messages::tool::common_functionality::utility_functions::single_path_node_compatible_layer_selected; +use crate::messages::tool::common_functionality::utility_functions::make_path_editable_is_allowed; use crate::messages::tool::utility_types::{HintData, HintGroup, ToolType}; use crate::node_graph_executor::{ExportConfig, NodeGraphExecutor}; use glam::{DAffine2, DVec2}; @@ -79,7 +79,7 @@ impl MessageHandler> for Portfolio self.menu_bar_message_handler.has_selected_nodes = false; self.menu_bar_message_handler.has_selected_layers = false; self.menu_bar_message_handler.has_selection_history = (false, false); - self.menu_bar_message_handler.single_path_node_compatible_layer_selected = false; + self.menu_bar_message_handler.make_path_editable_is_allowed = false; self.menu_bar_message_handler.spreadsheet_view_open = self.spreadsheet.spreadsheet_view_open; self.menu_bar_message_handler.message_logging_verbosity = message_logging_verbosity; self.menu_bar_message_handler.reset_node_definitions_on_open = reset_node_definitions_on_open; @@ -97,7 +97,7 @@ impl MessageHandler> for Portfolio let metadata = &document.network_interface.document_network_metadata().persistent_metadata; (!metadata.selection_undo_history.is_empty(), !metadata.selection_redo_history.is_empty()) }; - self.menu_bar_message_handler.single_path_node_compatible_layer_selected = single_path_node_compatible_layer_selected(&document.network_interface, document.metadata()).is_some(); + self.menu_bar_message_handler.make_path_editable_is_allowed = make_path_editable_is_allowed(&document.network_interface, document.metadata()).is_some(); } self.menu_bar_message_handler.process_message(message, responses, ()); diff --git a/editor/src/messages/tool/common_functionality/utility_functions.rs b/editor/src/messages/tool/common_functionality/utility_functions.rs index 64bc783493..b331591698 100644 --- a/editor/src/messages/tool/common_functionality/utility_functions.rs +++ b/editor/src/messages/tool/common_functionality/utility_functions.rs @@ -5,16 +5,17 @@ use crate::messages::portfolio::document::utility_types::document_metadata::{Doc use crate::messages::portfolio::document::utility_types::network_interface::NodeNetworkInterface; use crate::messages::portfolio::document::utility_types::transformation::Selected; use crate::messages::prelude::*; -use crate::messages::tool::common_functionality::graph_modification_utils::{self, get_text}; +use crate::messages::tool::common_functionality::graph_modification_utils::{NodeGraphLayer, get_text}; use crate::messages::tool::common_functionality::transformation_cage::SelectedEdges; use crate::messages::tool::tool_messages::path_tool::PathOverlayMode; use crate::messages::tool::utility_types::ToolType; use bezier_rs::{Bezier, BezierHandles}; use glam::{DAffine2, DVec2}; +use graph_craft::concrete; use graph_craft::document::value::TaggedValue; use graphene_std::renderer::Quad; use graphene_std::text::{FontCache, load_font}; -use graphene_std::vector::{HandleExt, HandleId, ManipulatorPointId, PointId, SegmentId, VectorData, VectorModification, VectorModificationType}; +use graphene_std::vector::{HandleExt, HandleId, ManipulatorPointId, PointId, SegmentId, VectorData, VectorDataTable, VectorModification, VectorModificationType}; use kurbo::{CubicBez, Line, ParamCurveExtrema, PathSeg, Point, QuadBez}; /// Determines if a path should be extended. Goal in viewport space. Returns the path and if it is extending from the start, if applicable. @@ -589,32 +590,35 @@ pub fn find_two_param_best_approximate(p1: DVec2, p3: DVec2, d1: DVec2, d2: DVec (d1 * len1, d2 * len2) } -pub fn single_path_node_compatible_layer_selected(network_interface: &NodeNetworkInterface, metadata: &DocumentMetadata) -> Option { +pub fn make_path_editable_is_allowed(network_interface: &NodeNetworkInterface, metadata: &DocumentMetadata) -> Option { + // Must have exactly one layer selected let selected_nodes = network_interface.selected_nodes(); let mut selected_layers = selected_nodes.selected_layers(metadata); - let first_layer = selected_layers.next(); - let second_layer = selected_layers.next(); - let has_single_selection = first_layer.is_some() && second_layer.is_none(); - let compatible_type = first_layer.and_then(|layer| { - let graph_layer = graph_modification_utils::NodeGraphLayer::new(layer, &network_interface); - graph_layer.horizontal_layer_flow().nth(1).map(|node_id| { + let first_layer = selected_layers.next()?; + if selected_layers.next().is_some() { + return None; + } + + // Must be a layer of type VectorDataTable + let compatible_type = NodeGraphLayer::new(first_layer, network_interface) + .horizontal_layer_flow() + .nth(1) + .map(|node_id| { let (output_type, _) = network_interface.output_type(&node_id, 0, &[]); - format!("type:{}", output_type.nested_type()) + output_type.nested_type() == concrete!(VectorDataTable).nested_type() }) - }); - let is_compatible = compatible_type.as_deref() == Some("type:Instances"); - let path_node_with_no_diffs_exist = first_layer.is_some_and(|layer| { - let graph_layer = graph_modification_utils::NodeGraphLayer::new(layer, &network_interface); - if let Some(TaggedValue::VectorModification(vector)) = graph_layer.find_input("Path", 1) { - let modification = *vector.clone(); - modification == VectorModification::default() - } else { - false + .unwrap_or_default(); + if !compatible_type { + return None; + } + + // Must not already have an existing Path node, in the right-most part of the layer chain, which has an empty set of modifications + // (otherwise users could repeatedly keep running this command and stacking up empty Path nodes) + if let Some(TaggedValue::VectorModification(modifications)) = NodeGraphLayer::new(first_layer, network_interface).find_input("Path", 1) { + if modifications.as_ref() == &VectorModification::default() { + return None; } - }); - if first_layer.is_some() && has_single_selection && is_compatible && !path_node_with_no_diffs_exist { - first_layer - } else { - None } + + Some(first_layer) } diff --git a/editor/src/messages/tool/tool_messages/path_tool.rs b/editor/src/messages/tool/tool_messages/path_tool.rs index e3cfb5f48d..22d828fb9d 100644 --- a/editor/src/messages/tool/tool_messages/path_tool.rs +++ b/editor/src/messages/tool/tool_messages/path_tool.rs @@ -16,7 +16,7 @@ use crate::messages::tool::common_functionality::shape_editor::{ ClosestSegment, ManipulatorAngle, OpposingHandleLengths, SelectedLayerState, SelectedPointsInfo, SelectionChange, SelectionShape, SelectionShapeType, ShapeState, }; use crate::messages::tool::common_functionality::snapping::{SnapCache, SnapCandidatePoint, SnapConstraint, SnapData, SnapManager}; -use crate::messages::tool::common_functionality::utility_functions::{calculate_segment_angle, find_two_param_best_approximate, single_path_node_compatible_layer_selected}; +use crate::messages::tool::common_functionality::utility_functions::{calculate_segment_angle, find_two_param_best_approximate, make_path_editable_is_allowed}; use bezier_rs::{Bezier, BezierHandles, TValue}; use graphene_std::renderer::Quad; use graphene_std::transform::ReferencePoint; @@ -273,7 +273,7 @@ impl LayoutHolder for PathTool { .icon(Some("NodeShape".into())) .tooltip("Make Path Editable") .on_update(|_| NodeGraphMessage::AddPathNode.into()) - .disabled(!self.tool_data.single_path_node_compatible_layer_selected) + .disabled(!self.tool_data.make_path_editable_is_allowed) .widget_holder(); let [_checkbox, _dropdown] = { @@ -543,7 +543,7 @@ struct PathToolData { drill_through_cycle_count: usize, hovered_layers: Vec, ghost_outline: Vec<(Vec, LayerNodeIdentifier)>, - single_path_node_compatible_layer_selected: bool, + make_path_editable_is_allowed: bool, } impl PathToolData { @@ -2692,7 +2692,7 @@ impl Fsm for PathToolFsmState { colinear, }; - tool_data.single_path_node_compatible_layer_selected = single_path_node_compatible_layer_selected(&document.network_interface, document.metadata()).is_some(); + tool_data.make_path_editable_is_allowed = make_path_editable_is_allowed(&document.network_interface, document.metadata()).is_some(); tool_data.update_selection_status(shape_editor, document); self }