Skip to content

Commit 4427e97

Browse files
4adexKeavon
andauthored
Add "Make Path Editable" buttons in the Path tool control bar and Layer menu (#2900)
* Add graph message for adding a path * Disable options when adding path tool is not possible * Move Layer menu entry location --------- Co-authored-by: Keavon Chambers <[email protected]>
1 parent 6f46f21 commit 4427e97

File tree

5 files changed

+111
-4
lines changed

5 files changed

+111
-4
lines changed

editor/src/messages/portfolio/document/node_graph/node_graph_message.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ pub enum NodeGraphMessage {
1616
nodes: Vec<(NodeId, NodeTemplate)>,
1717
new_ids: HashMap<NodeId, NodeId>,
1818
},
19+
AddPathNode,
1920
AddImport,
2021
AddExport,
2122
Init,

editor/src/messages/portfolio/document/node_graph/node_graph_message_handler.rs

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,11 @@ use crate::messages::portfolio::document::utility_types::nodes::{CollapsedLayers
1616
use crate::messages::portfolio::document::utility_types::wires::{GraphWireStyle, WirePath, WirePathUpdate, build_vector_wire};
1717
use crate::messages::prelude::*;
1818
use crate::messages::tool::common_functionality::auto_panning::AutoPanning;
19-
use crate::messages::tool::common_functionality::graph_modification_utils::get_clip_mode;
19+
use crate::messages::tool::common_functionality::graph_modification_utils::{self, get_clip_mode};
2020
use crate::messages::tool::tool_messages::tool_prelude::{Key, MouseMotion};
2121
use crate::messages::tool::utility_types::{HintData, HintGroup, HintInfo};
2222
use glam::{DAffine2, DVec2, IVec2};
23+
use graph_craft::document::value::TaggedValue;
2324
use graph_craft::document::{DocumentNodeImplementation, NodeId, NodeInput};
2425
use graph_craft::proto::GraphErrors;
2526
use graphene_std::math::math_ext::QuadExt;
@@ -119,6 +120,38 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
119120

120121
responses.add(NodeGraphMessage::SelectedNodesSet { nodes: vec![new_layer_id] });
121122
}
123+
NodeGraphMessage::AddPathNode => {
124+
let selected_nodes = network_interface.selected_nodes();
125+
let mut selected_layers = selected_nodes.selected_layers(network_interface.document_metadata());
126+
let first_layer = selected_layers.next();
127+
let second_layer = selected_layers.next();
128+
let has_single_selection = first_layer.is_some() && second_layer.is_none();
129+
130+
let compatible_type = first_layer.and_then(|layer| {
131+
let graph_layer = graph_modification_utils::NodeGraphLayer::new(layer, &network_interface);
132+
graph_layer.horizontal_layer_flow().nth(1).and_then(|node_id| {
133+
let (output_type, _) = network_interface.output_type(&node_id, 0, &[]);
134+
Some(format!("type:{}", output_type.nested_type()))
135+
})
136+
});
137+
138+
let is_compatible = compatible_type.as_deref() == Some("type:Instances<VectorData>");
139+
140+
if first_layer.is_some() && has_single_selection && is_compatible {
141+
if let Some(layer) = first_layer {
142+
let node_type = "Path".to_string();
143+
let graph_layer = graph_modification_utils::NodeGraphLayer::new(layer, &network_interface);
144+
let is_modifiable = matches!(graph_layer.find_input("Path", 1), Some(TaggedValue::VectorModification(_)));
145+
if !is_modifiable {
146+
responses.add(NodeGraphMessage::CreateNodeInLayerWithTransaction {
147+
node_type: node_type.clone(),
148+
layer: LayerNodeIdentifier::new_unchecked(layer.to_node()),
149+
});
150+
responses.add(BroadcastEvent::SelectionChanged);
151+
}
152+
}
153+
}
154+
}
122155
NodeGraphMessage::AddImport => {
123156
network_interface.add_import(graph_craft::document::value::TaggedValue::None, true, -1, "", "", breadcrumb_network_path);
124157
responses.add(NodeGraphMessage::SendGraph);

editor/src/messages/portfolio/menu_bar/menu_bar_message_handler.rs

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ pub struct MenuBarMessageHandler {
1919
pub spreadsheet_view_open: bool,
2020
pub message_logging_verbosity: MessageLoggingVerbosity,
2121
pub reset_node_definitions_on_open: bool,
22+
pub single_path_node_compatible_layer_selected: bool,
2223
}
2324

2425
#[message_handler_data]
@@ -45,6 +46,7 @@ impl LayoutHolder for MenuBarMessageHandler {
4546
let message_logging_verbosity_names = self.message_logging_verbosity == MessageLoggingVerbosity::Names;
4647
let message_logging_verbosity_contents = self.message_logging_verbosity == MessageLoggingVerbosity::Contents;
4748
let reset_node_definitions_on_open = self.reset_node_definitions_on_open;
49+
let single_path_node_compatible_layer_selected = self.single_path_node_compatible_layer_selected;
4850

4951
let menu_bar_entries = vec![
5052
MenuBarEntry {
@@ -418,9 +420,8 @@ impl LayoutHolder for MenuBarMessageHandler {
418420
disabled: no_active_document || !has_selected_layers,
419421
children: MenuBarEntryChildren(vec![{
420422
let list = <BooleanOperation as graphene_std::registry::ChoiceTypeStatic>::list();
421-
list.into_iter()
422-
.map(|i| i.into_iter())
423-
.flatten()
423+
list.iter()
424+
.flat_map(|i| i.iter())
424425
.map(move |(operation, info)| MenuBarEntry {
425426
label: info.label.to_string(),
426427
icon: info.icon.as_ref().map(|i| i.to_string()),
@@ -436,6 +437,14 @@ impl LayoutHolder for MenuBarMessageHandler {
436437
..MenuBarEntry::default()
437438
},
438439
],
440+
vec![MenuBarEntry {
441+
label: "Make Path Editable".into(),
442+
icon: Some("NodeShape".into()),
443+
shortcut: None,
444+
action: MenuBarEntry::create_action(|_| NodeGraphMessage::AddPathNode.into()),
445+
disabled: !single_path_node_compatible_layer_selected,
446+
..MenuBarEntry::default()
447+
}],
439448
]),
440449
),
441450
MenuBarEntry::new_root(

editor/src/messages/portfolio/portfolio_message_handler.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,12 @@ use crate::messages::portfolio::document::utility_types::nodes::SelectedNodes;
1818
use crate::messages::portfolio::document_migration::*;
1919
use crate::messages::preferences::SelectionMode;
2020
use crate::messages::prelude::*;
21+
use crate::messages::tool::common_functionality::graph_modification_utils;
2122
use crate::messages::tool::utility_types::{HintData, HintGroup, ToolType};
2223
use crate::node_graph_executor::{ExportConfig, NodeGraphExecutor};
2324
use glam::{DAffine2, DVec2};
2425
use graph_craft::document::NodeId;
26+
use graph_craft::document::value::TaggedValue;
2527
use graphene_std::renderer::Quad;
2628
use graphene_std::text::Font;
2729
use std::vec;
@@ -78,6 +80,7 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageContext<'_>> for Portfolio
7880
self.menu_bar_message_handler.has_selected_nodes = false;
7981
self.menu_bar_message_handler.has_selected_layers = false;
8082
self.menu_bar_message_handler.has_selection_history = (false, false);
83+
self.menu_bar_message_handler.single_path_node_compatible_layer_selected = false;
8184
self.menu_bar_message_handler.spreadsheet_view_open = self.spreadsheet.spreadsheet_view_open;
8285
self.menu_bar_message_handler.message_logging_verbosity = message_logging_verbosity;
8386
self.menu_bar_message_handler.reset_node_definitions_on_open = reset_node_definitions_on_open;
@@ -95,6 +98,30 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageContext<'_>> for Portfolio
9598
let metadata = &document.network_interface.document_network_metadata().persistent_metadata;
9699
(!metadata.selection_undo_history.is_empty(), !metadata.selection_redo_history.is_empty())
97100
};
101+
self.menu_bar_message_handler.single_path_node_compatible_layer_selected = {
102+
let selected_nodes = document.network_interface.selected_nodes();
103+
let mut selected_layers = selected_nodes.selected_layers(document.metadata());
104+
let first_layer = selected_layers.next();
105+
let second_layer = selected_layers.next();
106+
let has_single_selection = first_layer.is_some() && second_layer.is_none();
107+
108+
let compatible_type = first_layer.and_then(|layer| {
109+
let graph_layer = graph_modification_utils::NodeGraphLayer::new(layer, &document.network_interface);
110+
graph_layer.horizontal_layer_flow().nth(1).and_then(|node_id| {
111+
let (output_type, _) = document.network_interface.output_type(&node_id, 0, &[]);
112+
Some(format!("type:{}", output_type.nested_type()))
113+
})
114+
});
115+
116+
let is_compatible = compatible_type.as_deref() == Some("type:Instances<VectorData>");
117+
118+
let is_modifiable = first_layer.map_or(false, |layer| {
119+
let graph_layer = graph_modification_utils::NodeGraphLayer::new(layer, &document.network_interface);
120+
matches!(graph_layer.find_input("Path", 1), Some(TaggedValue::VectorModification(_)))
121+
});
122+
123+
first_layer.is_some() && has_single_selection && is_compatible && !is_modifiable
124+
}
98125
}
99126

100127
self.menu_bar_message_handler.process_message(message, responses, ());

editor/src/messages/tool/tool_messages/path_tool.rs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,15 @@ use crate::messages::portfolio::document::utility_types::network_interface::Node
1111
use crate::messages::portfolio::document::utility_types::transformation::Axis;
1212
use crate::messages::preferences::SelectionMode;
1313
use crate::messages::tool::common_functionality::auto_panning::AutoPanning;
14+
use crate::messages::tool::common_functionality::graph_modification_utils;
1415
use crate::messages::tool::common_functionality::pivot::{PivotGizmo, PivotGizmoType, PivotToolSource, pin_pivot_widget, pivot_gizmo_type_widget, pivot_reference_point_widget};
1516
use crate::messages::tool::common_functionality::shape_editor::{
1617
ClosestSegment, ManipulatorAngle, OpposingHandleLengths, SelectedLayerState, SelectedPointsInfo, SelectionChange, SelectionShape, SelectionShapeType, ShapeState,
1718
};
1819
use crate::messages::tool::common_functionality::snapping::{SnapCache, SnapCandidatePoint, SnapConstraint, SnapData, SnapManager};
1920
use crate::messages::tool::common_functionality::utility_functions::{calculate_segment_angle, find_two_param_best_approximate};
2021
use bezier_rs::{Bezier, BezierHandles, TValue};
22+
use graph_craft::document::value::TaggedValue;
2123
use graphene_std::renderer::Quad;
2224
use graphene_std::transform::ReferencePoint;
2325
use graphene_std::vector::click_target::ClickTargetType;
@@ -264,6 +266,14 @@ impl LayoutHolder for PathTool {
264266
.selected_index(Some(self.options.path_overlay_mode as u32))
265267
.widget_holder();
266268

269+
// Works only if a single layer is selected and its type is vectordata
270+
let path_node_button = TextButton::new("Make Path Editable")
271+
.icon(Some("NodeShape".into()))
272+
.tooltip("Make Path Editable")
273+
.on_update(|_| NodeGraphMessage::AddPathNode.into())
274+
.disabled(!self.tool_data.single_path_node_compatible_layer_selected)
275+
.widget_holder();
276+
267277
let [_checkbox, _dropdown] = {
268278
let pivot_gizmo_type_widget = pivot_gizmo_type_widget(self.tool_data.pivot_gizmo.state, PivotToolSource::Path);
269279
[pivot_gizmo_type_widget[0].clone(), pivot_gizmo_type_widget[2].clone()]
@@ -294,6 +304,7 @@ impl LayoutHolder for PathTool {
294304
unrelated_seperator.clone(),
295305
path_overlay_mode_widget,
296306
unrelated_seperator.clone(),
307+
path_node_button,
297308
// checkbox.clone(),
298309
// related_seperator.clone(),
299310
// dropdown.clone(),
@@ -522,6 +533,7 @@ struct PathToolData {
522533
drill_through_cycle_count: usize,
523534
hovered_layers: Vec<LayerNodeIdentifier>,
524535
ghost_outline: Vec<(Vec<ClickTargetType>, DAffine2)>,
536+
single_path_node_compatible_layer_selected: bool,
525537
}
526538

527539
impl PathToolData {
@@ -2383,6 +2395,31 @@ impl Fsm for PathToolFsmState {
23832395
point_select_state: shape_editor.get_dragging_state(&document.network_interface),
23842396
colinear,
23852397
};
2398+
2399+
tool_data.single_path_node_compatible_layer_selected = {
2400+
let selected_nodes = document.network_interface.selected_nodes();
2401+
let mut selected_layers = selected_nodes.selected_layers(document.metadata());
2402+
let first_layer = selected_layers.next();
2403+
let second_layer = selected_layers.next();
2404+
let has_single_selection = first_layer.is_some() && second_layer.is_none();
2405+
2406+
let compatible_type = first_layer.and_then(|layer| {
2407+
let graph_layer = graph_modification_utils::NodeGraphLayer::new(layer, &document.network_interface);
2408+
graph_layer.horizontal_layer_flow().nth(1).and_then(|node_id| {
2409+
let (output_type, _) = document.network_interface.output_type(&node_id, 0, &[]);
2410+
Some(format!("type:{}", output_type.nested_type()))
2411+
})
2412+
});
2413+
2414+
let is_compatible = compatible_type.as_deref() == Some("type:Instances<VectorData>");
2415+
2416+
let is_modifiable = first_layer.map_or(false, |layer| {
2417+
let graph_layer = graph_modification_utils::NodeGraphLayer::new(layer, &document.network_interface);
2418+
matches!(graph_layer.find_input("Path", 1), Some(TaggedValue::VectorModification(_)))
2419+
});
2420+
2421+
first_layer.is_some() && has_single_selection && is_compatible && !is_modifiable
2422+
};
23862423
tool_data.update_selection_status(shape_editor, document);
23872424
self
23882425
}

0 commit comments

Comments
 (0)