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 <keavon@keavon.com>
This commit is contained in:
parent
6f46f21e21
commit
4427e97f73
|
|
@ -16,6 +16,7 @@ pub enum NodeGraphMessage {
|
||||||
nodes: Vec<(NodeId, NodeTemplate)>,
|
nodes: Vec<(NodeId, NodeTemplate)>,
|
||||||
new_ids: HashMap<NodeId, NodeId>,
|
new_ids: HashMap<NodeId, NodeId>,
|
||||||
},
|
},
|
||||||
|
AddPathNode,
|
||||||
AddImport,
|
AddImport,
|
||||||
AddExport,
|
AddExport,
|
||||||
Init,
|
Init,
|
||||||
|
|
|
||||||
|
|
@ -16,10 +16,11 @@ use crate::messages::portfolio::document::utility_types::nodes::{CollapsedLayers
|
||||||
use crate::messages::portfolio::document::utility_types::wires::{GraphWireStyle, WirePath, WirePathUpdate, build_vector_wire};
|
use crate::messages::portfolio::document::utility_types::wires::{GraphWireStyle, WirePath, WirePathUpdate, build_vector_wire};
|
||||||
use crate::messages::prelude::*;
|
use crate::messages::prelude::*;
|
||||||
use crate::messages::tool::common_functionality::auto_panning::AutoPanning;
|
use crate::messages::tool::common_functionality::auto_panning::AutoPanning;
|
||||||
use crate::messages::tool::common_functionality::graph_modification_utils::get_clip_mode;
|
use crate::messages::tool::common_functionality::graph_modification_utils::{self, get_clip_mode};
|
||||||
use crate::messages::tool::tool_messages::tool_prelude::{Key, MouseMotion};
|
use crate::messages::tool::tool_messages::tool_prelude::{Key, MouseMotion};
|
||||||
use crate::messages::tool::utility_types::{HintData, HintGroup, HintInfo};
|
use crate::messages::tool::utility_types::{HintData, HintGroup, HintInfo};
|
||||||
use glam::{DAffine2, DVec2, IVec2};
|
use glam::{DAffine2, DVec2, IVec2};
|
||||||
|
use graph_craft::document::value::TaggedValue;
|
||||||
use graph_craft::document::{DocumentNodeImplementation, NodeId, NodeInput};
|
use graph_craft::document::{DocumentNodeImplementation, NodeId, NodeInput};
|
||||||
use graph_craft::proto::GraphErrors;
|
use graph_craft::proto::GraphErrors;
|
||||||
use graphene_std::math::math_ext::QuadExt;
|
use graphene_std::math::math_ext::QuadExt;
|
||||||
|
|
@ -119,6 +120,38 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
|
||||||
|
|
||||||
responses.add(NodeGraphMessage::SelectedNodesSet { nodes: vec![new_layer_id] });
|
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<VectorData>");
|
||||||
|
|
||||||
|
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 {
|
||||||
|
responses.add(NodeGraphMessage::CreateNodeInLayerWithTransaction {
|
||||||
|
node_type: node_type.clone(),
|
||||||
|
layer: LayerNodeIdentifier::new_unchecked(layer.to_node()),
|
||||||
|
});
|
||||||
|
responses.add(BroadcastEvent::SelectionChanged);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
NodeGraphMessage::AddImport => {
|
NodeGraphMessage::AddImport => {
|
||||||
network_interface.add_import(graph_craft::document::value::TaggedValue::None, true, -1, "", "", breadcrumb_network_path);
|
network_interface.add_import(graph_craft::document::value::TaggedValue::None, true, -1, "", "", breadcrumb_network_path);
|
||||||
responses.add(NodeGraphMessage::SendGraph);
|
responses.add(NodeGraphMessage::SendGraph);
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ pub struct MenuBarMessageHandler {
|
||||||
pub spreadsheet_view_open: bool,
|
pub spreadsheet_view_open: bool,
|
||||||
pub message_logging_verbosity: MessageLoggingVerbosity,
|
pub message_logging_verbosity: MessageLoggingVerbosity,
|
||||||
pub reset_node_definitions_on_open: bool,
|
pub reset_node_definitions_on_open: bool,
|
||||||
|
pub single_path_node_compatible_layer_selected: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[message_handler_data]
|
#[message_handler_data]
|
||||||
|
|
@ -45,6 +46,7 @@ impl LayoutHolder for MenuBarMessageHandler {
|
||||||
let message_logging_verbosity_names = self.message_logging_verbosity == MessageLoggingVerbosity::Names;
|
let message_logging_verbosity_names = self.message_logging_verbosity == MessageLoggingVerbosity::Names;
|
||||||
let message_logging_verbosity_contents = self.message_logging_verbosity == MessageLoggingVerbosity::Contents;
|
let message_logging_verbosity_contents = self.message_logging_verbosity == MessageLoggingVerbosity::Contents;
|
||||||
let reset_node_definitions_on_open = self.reset_node_definitions_on_open;
|
let reset_node_definitions_on_open = self.reset_node_definitions_on_open;
|
||||||
|
let single_path_node_compatible_layer_selected = self.single_path_node_compatible_layer_selected;
|
||||||
|
|
||||||
let menu_bar_entries = vec![
|
let menu_bar_entries = vec![
|
||||||
MenuBarEntry {
|
MenuBarEntry {
|
||||||
|
|
@ -418,9 +420,8 @@ impl LayoutHolder for MenuBarMessageHandler {
|
||||||
disabled: no_active_document || !has_selected_layers,
|
disabled: no_active_document || !has_selected_layers,
|
||||||
children: MenuBarEntryChildren(vec![{
|
children: MenuBarEntryChildren(vec![{
|
||||||
let list = <BooleanOperation as graphene_std::registry::ChoiceTypeStatic>::list();
|
let list = <BooleanOperation as graphene_std::registry::ChoiceTypeStatic>::list();
|
||||||
list.into_iter()
|
list.iter()
|
||||||
.map(|i| i.into_iter())
|
.flat_map(|i| i.iter())
|
||||||
.flatten()
|
|
||||||
.map(move |(operation, info)| MenuBarEntry {
|
.map(move |(operation, info)| MenuBarEntry {
|
||||||
label: info.label.to_string(),
|
label: info.label.to_string(),
|
||||||
icon: info.icon.as_ref().map(|i| i.to_string()),
|
icon: info.icon.as_ref().map(|i| i.to_string()),
|
||||||
|
|
@ -436,6 +437,14 @@ impl LayoutHolder for MenuBarMessageHandler {
|
||||||
..MenuBarEntry::default()
|
..MenuBarEntry::default()
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
vec![MenuBarEntry {
|
||||||
|
label: "Make Path Editable".into(),
|
||||||
|
icon: Some("NodeShape".into()),
|
||||||
|
shortcut: None,
|
||||||
|
action: MenuBarEntry::create_action(|_| NodeGraphMessage::AddPathNode.into()),
|
||||||
|
disabled: !single_path_node_compatible_layer_selected,
|
||||||
|
..MenuBarEntry::default()
|
||||||
|
}],
|
||||||
]),
|
]),
|
||||||
),
|
),
|
||||||
MenuBarEntry::new_root(
|
MenuBarEntry::new_root(
|
||||||
|
|
|
||||||
|
|
@ -18,10 +18,12 @@ use crate::messages::portfolio::document::utility_types::nodes::SelectedNodes;
|
||||||
use crate::messages::portfolio::document_migration::*;
|
use crate::messages::portfolio::document_migration::*;
|
||||||
use crate::messages::preferences::SelectionMode;
|
use crate::messages::preferences::SelectionMode;
|
||||||
use crate::messages::prelude::*;
|
use crate::messages::prelude::*;
|
||||||
|
use crate::messages::tool::common_functionality::graph_modification_utils;
|
||||||
use crate::messages::tool::utility_types::{HintData, HintGroup, ToolType};
|
use crate::messages::tool::utility_types::{HintData, HintGroup, ToolType};
|
||||||
use crate::node_graph_executor::{ExportConfig, NodeGraphExecutor};
|
use crate::node_graph_executor::{ExportConfig, NodeGraphExecutor};
|
||||||
use glam::{DAffine2, DVec2};
|
use glam::{DAffine2, DVec2};
|
||||||
use graph_craft::document::NodeId;
|
use graph_craft::document::NodeId;
|
||||||
|
use graph_craft::document::value::TaggedValue;
|
||||||
use graphene_std::renderer::Quad;
|
use graphene_std::renderer::Quad;
|
||||||
use graphene_std::text::Font;
|
use graphene_std::text::Font;
|
||||||
use std::vec;
|
use std::vec;
|
||||||
|
|
@ -78,6 +80,7 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageContext<'_>> for Portfolio
|
||||||
self.menu_bar_message_handler.has_selected_nodes = false;
|
self.menu_bar_message_handler.has_selected_nodes = false;
|
||||||
self.menu_bar_message_handler.has_selected_layers = 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.has_selection_history = (false, false);
|
||||||
|
self.menu_bar_message_handler.single_path_node_compatible_layer_selected = false;
|
||||||
self.menu_bar_message_handler.spreadsheet_view_open = self.spreadsheet.spreadsheet_view_open;
|
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.message_logging_verbosity = message_logging_verbosity;
|
||||||
self.menu_bar_message_handler.reset_node_definitions_on_open = reset_node_definitions_on_open;
|
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
|
||||||
let metadata = &document.network_interface.document_network_metadata().persistent_metadata;
|
let metadata = &document.network_interface.document_network_metadata().persistent_metadata;
|
||||||
(!metadata.selection_undo_history.is_empty(), !metadata.selection_redo_history.is_empty())
|
(!metadata.selection_undo_history.is_empty(), !metadata.selection_redo_history.is_empty())
|
||||||
};
|
};
|
||||||
|
self.menu_bar_message_handler.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).and_then(|node_id| {
|
||||||
|
let (output_type, _) = document.network_interface.output_type(&node_id, 0, &[]);
|
||||||
|
Some(format!("type:{}", output_type.nested_type()))
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
let is_compatible = compatible_type.as_deref() == Some("type:Instances<VectorData>");
|
||||||
|
|
||||||
|
let is_modifiable = first_layer.map_or(false, |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.process_message(message, responses, ());
|
self.menu_bar_message_handler.process_message(message, responses, ());
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ use crate::messages::portfolio::document::utility_types::network_interface::Node
|
||||||
use crate::messages::portfolio::document::utility_types::transformation::Axis;
|
use crate::messages::portfolio::document::utility_types::transformation::Axis;
|
||||||
use crate::messages::preferences::SelectionMode;
|
use crate::messages::preferences::SelectionMode;
|
||||||
use crate::messages::tool::common_functionality::auto_panning::AutoPanning;
|
use crate::messages::tool::common_functionality::auto_panning::AutoPanning;
|
||||||
|
use crate::messages::tool::common_functionality::graph_modification_utils;
|
||||||
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::pivot::{PivotGizmo, PivotGizmoType, PivotToolSource, pin_pivot_widget, pivot_gizmo_type_widget, pivot_reference_point_widget};
|
||||||
use crate::messages::tool::common_functionality::shape_editor::{
|
use crate::messages::tool::common_functionality::shape_editor::{
|
||||||
ClosestSegment, ManipulatorAngle, OpposingHandleLengths, SelectedLayerState, SelectedPointsInfo, SelectionChange, SelectionShape, SelectionShapeType, ShapeState,
|
ClosestSegment, ManipulatorAngle, OpposingHandleLengths, SelectedLayerState, SelectedPointsInfo, SelectionChange, SelectionShape, SelectionShapeType, ShapeState,
|
||||||
|
|
@ -18,6 +19,7 @@ use crate::messages::tool::common_functionality::shape_editor::{
|
||||||
use crate::messages::tool::common_functionality::snapping::{SnapCache, SnapCandidatePoint, SnapConstraint, SnapData, SnapManager};
|
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};
|
||||||
use bezier_rs::{Bezier, BezierHandles, TValue};
|
use bezier_rs::{Bezier, BezierHandles, TValue};
|
||||||
|
use graph_craft::document::value::TaggedValue;
|
||||||
use graphene_std::renderer::Quad;
|
use graphene_std::renderer::Quad;
|
||||||
use graphene_std::transform::ReferencePoint;
|
use graphene_std::transform::ReferencePoint;
|
||||||
use graphene_std::vector::click_target::ClickTargetType;
|
use graphene_std::vector::click_target::ClickTargetType;
|
||||||
|
|
@ -264,6 +266,14 @@ impl LayoutHolder for PathTool {
|
||||||
.selected_index(Some(self.options.path_overlay_mode as u32))
|
.selected_index(Some(self.options.path_overlay_mode as u32))
|
||||||
.widget_holder();
|
.widget_holder();
|
||||||
|
|
||||||
|
// Works only if a single layer is selected and its type is vectordata
|
||||||
|
let path_node_button = TextButton::new("Make Path Editable")
|
||||||
|
.icon(Some("NodeShape".into()))
|
||||||
|
.tooltip("Make Path Editable")
|
||||||
|
.on_update(|_| NodeGraphMessage::AddPathNode.into())
|
||||||
|
.disabled(!self.tool_data.single_path_node_compatible_layer_selected)
|
||||||
|
.widget_holder();
|
||||||
|
|
||||||
let [_checkbox, _dropdown] = {
|
let [_checkbox, _dropdown] = {
|
||||||
let pivot_gizmo_type_widget = pivot_gizmo_type_widget(self.tool_data.pivot_gizmo.state, PivotToolSource::Path);
|
let pivot_gizmo_type_widget = pivot_gizmo_type_widget(self.tool_data.pivot_gizmo.state, PivotToolSource::Path);
|
||||||
[pivot_gizmo_type_widget[0].clone(), pivot_gizmo_type_widget[2].clone()]
|
[pivot_gizmo_type_widget[0].clone(), pivot_gizmo_type_widget[2].clone()]
|
||||||
|
|
@ -294,6 +304,7 @@ impl LayoutHolder for PathTool {
|
||||||
unrelated_seperator.clone(),
|
unrelated_seperator.clone(),
|
||||||
path_overlay_mode_widget,
|
path_overlay_mode_widget,
|
||||||
unrelated_seperator.clone(),
|
unrelated_seperator.clone(),
|
||||||
|
path_node_button,
|
||||||
// checkbox.clone(),
|
// checkbox.clone(),
|
||||||
// related_seperator.clone(),
|
// related_seperator.clone(),
|
||||||
// dropdown.clone(),
|
// dropdown.clone(),
|
||||||
|
|
@ -522,6 +533,7 @@ struct PathToolData {
|
||||||
drill_through_cycle_count: usize,
|
drill_through_cycle_count: usize,
|
||||||
hovered_layers: Vec<LayerNodeIdentifier>,
|
hovered_layers: Vec<LayerNodeIdentifier>,
|
||||||
ghost_outline: Vec<(Vec<ClickTargetType>, DAffine2)>,
|
ghost_outline: Vec<(Vec<ClickTargetType>, DAffine2)>,
|
||||||
|
single_path_node_compatible_layer_selected: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PathToolData {
|
impl PathToolData {
|
||||||
|
|
@ -2383,6 +2395,31 @@ impl Fsm for PathToolFsmState {
|
||||||
point_select_state: shape_editor.get_dragging_state(&document.network_interface),
|
point_select_state: shape_editor.get_dragging_state(&document.network_interface),
|
||||||
colinear,
|
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).and_then(|node_id| {
|
||||||
|
let (output_type, _) = document.network_interface.output_type(&node_id, 0, &[]);
|
||||||
|
Some(format!("type:{}", output_type.nested_type()))
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
let is_compatible = compatible_type.as_deref() == Some("type:Instances<VectorData>");
|
||||||
|
|
||||||
|
let is_modifiable = first_layer.map_or(false, |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
|
||||||
|
};
|
||||||
tool_data.update_selection_status(shape_editor, document);
|
tool_data.update_selection_status(shape_editor, document);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue