From 8ca546c164c53bba35020528f0ae5bf2337f08b1 Mon Sep 17 00:00:00 2001 From: Yuxiang Huang <78173038+Yuxiang-Huang@users.noreply.github.com> Date: Thu, 4 Dec 2025 20:42:00 -0500 Subject: [PATCH] Fix using Esc to abort box selection and wire dragging causing the graph to close (#3409) * Implement proper node graph interaction aborting when pressing Escape * Fixes --------- Co-authored-by: Keavon Chambers --- .../messages/input_mapper/input_mappings.rs | 2 +- .../document/document_message_handler.rs | 36 ++++++++++++++----- .../node_graph/node_graph_message_handler.rs | 25 ++++++++----- 3 files changed, 45 insertions(+), 18 deletions(-) diff --git a/editor/src/messages/input_mapper/input_mappings.rs b/editor/src/messages/input_mapper/input_mappings.rs index 9cffb25cc..8bc699b77 100644 --- a/editor/src/messages/input_mapper/input_mappings.rs +++ b/editor/src/messages/input_mapper/input_mappings.rs @@ -325,7 +325,7 @@ pub fn input_mappings() -> Mapping { // // DocumentMessage entry!(KeyDown(Space); modifiers=[Control], action_dispatch=DocumentMessage::GraphViewOverlayToggle), - entry!(KeyUp(Escape); action_dispatch=DocumentMessage::Escape), + entry!(KeyDownNoRepeat(Escape); action_dispatch=DocumentMessage::Escape), entry!(KeyDown(Delete); action_dispatch=DocumentMessage::DeleteSelectedLayers), entry!(KeyDown(Backspace); action_dispatch=DocumentMessage::DeleteSelectedLayers), entry!(KeyDown(KeyO); modifiers=[Alt], action_dispatch=DocumentMessage::ToggleOverlaysVisibility), diff --git a/editor/src/messages/portfolio/document/document_message_handler.rs b/editor/src/messages/portfolio/document/document_message_handler.rs index ac360321d..3f1648750 100644 --- a/editor/src/messages/portfolio/document/document_message_handler.rs +++ b/editor/src/messages/portfolio/document/document_message_handler.rs @@ -12,6 +12,7 @@ use crate::messages::layout::utility_types::widget_prelude::*; use crate::messages::portfolio::document::data_panel::{DataPanelMessageContext, DataPanelMessageHandler}; use crate::messages::portfolio::document::graph_operation::utility_types::TransformIn; use crate::messages::portfolio::document::node_graph::NodeGraphMessageContext; +use crate::messages::portfolio::document::node_graph::utility_types::FrontendGraphDataType; use crate::messages::portfolio::document::overlays::grid_overlays::{grid_overlay, overlay_options}; use crate::messages::portfolio::document::overlays::utility_types::{OverlaysType, OverlaysVisibilitySettings}; use crate::messages::portfolio::document::properties_panel::properties_panel_message_handler::PropertiesPanelMessageContext; @@ -476,25 +477,44 @@ impl MessageHandler> for DocumentMes responses.add(NodeGraphMessage::UpdateNodeGraphWidth); } DocumentMessage::Escape => { + // Abort dragging nodes if self.node_graph_handler.drag_start.is_some() { responses.add(DocumentMessage::AbortTransaction); self.node_graph_handler.drag_start = None; - } else if self + } + // Abort box selection + else if self.node_graph_handler.box_selection_start.is_some() { + self.node_graph_handler.box_selection_start = None; + responses.add(NodeGraphMessage::SelectedNodesSet { + nodes: self.node_graph_handler.selection_before_pointer_down.clone(), + }); + responses.add(FrontendMessage::UpdateBox { box_selection: None }); + } + // Abort wire in progress of being connected + else if self.node_graph_handler.wire_in_progress_from_connector.is_some() { + self.node_graph_handler.wire_in_progress_from_connector = None; + self.node_graph_handler.wire_in_progress_to_connector = None; + self.node_graph_handler.wire_in_progress_type = FrontendGraphDataType::General; + + responses.add(FrontendMessage::UpdateWirePathInProgress { wire_path: None }); + responses.add(DocumentMessage::AbortTransaction); + } + // Close the context menu if it's open + else if self .node_graph_handler .context_menu .as_ref() .is_some_and(|context_menu| matches!(context_menu.context_menu_data, super::node_graph::utility_types::ContextMenuData::CreateNode { compatible_type: None })) { - // Close the context menu self.node_graph_handler.context_menu = None; responses.add(FrontendMessage::UpdateContextMenuInformation { context_menu_information: None }); - self.node_graph_handler.wire_in_progress_from_connector = None; - self.node_graph_handler.wire_in_progress_to_connector = None; - responses.add(FrontendMessage::UpdateWirePathInProgress { wire_path: None }); - } else if !self.breadcrumb_network_path.is_empty() { - // Exit one level up if inside a nested network + } + // Exit one level up if inside a nested network + else if !self.breadcrumb_network_path.is_empty() { responses.add(DocumentMessage::ExitNestedNetwork { steps_back: 1 }); - } else { + } + // Close the graph view overlay if it's open + else { responses.add(DocumentMessage::GraphViewOverlay { open: false }); } } 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 8825fbb0b..01cc507ab 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 @@ -63,20 +63,21 @@ pub struct NodeGraphMessageHandler { pub drag_start_chain_nodes: Vec, /// If dragging the background to create a box selection, this stores its starting point in node graph coordinates, /// plus a flag indicating if it has been dragged since the mousedown began. - box_selection_start: Option<(DVec2, bool)>, + pub box_selection_start: Option<(DVec2, bool)>, /// Restore the selection before box selection if it is aborted - selection_before_pointer_down: Vec, + pub selection_before_pointer_down: Vec, /// If the grip icon is held during a drag, then shift without pushing other nodes shift_without_push: bool, disconnecting: Option, initial_disconnecting: bool, /// Node to select on pointer up if multiple nodes are selected and they were not dragged. select_if_not_dragged: Option, - /// The start of the dragged line (cannot be moved), stored in node graph coordinates + /// The start of the dragged line (cannot be moved), stored in node graph coordinates. pub wire_in_progress_from_connector: Option, - wire_in_progress_type: FrontendGraphDataType, - /// The end point of the dragged line (cannot be moved), stored in node graph coordinates + /// The end point of the dragged line (cannot be moved), stored in node graph coordinates. pub wire_in_progress_to_connector: Option, + /// The data type determining the color of the wire being dragged. + pub wire_in_progress_type: FrontendGraphDataType, /// State for the context menu popups. pub context_menu: Option, /// Index of selected node to be deselected on pointer up when shift clicking an already selected node @@ -295,8 +296,8 @@ impl<'a> MessageHandler> for NodeG } self.wire_in_progress_from_connector = None; - self.wire_in_progress_type = FrontendGraphDataType::General; self.wire_in_progress_to_connector = None; + self.wire_in_progress_type = FrontendGraphDataType::General; } responses.add(FrontendMessage::UpdateWirePathInProgress { wire_path: None }); responses.add(FrontendMessage::UpdateContextMenuInformation { @@ -768,8 +769,9 @@ impl<'a> MessageHandler> for NodeG // Abort dragging a wire if self.wire_in_progress_from_connector.is_some() { self.wire_in_progress_from_connector = None; - self.wire_in_progress_type = FrontendGraphDataType::General; self.wire_in_progress_to_connector = None; + self.wire_in_progress_type = FrontendGraphDataType::General; + responses.add(DocumentMessage::AbortTransaction); responses.add(FrontendMessage::UpdateWirePathInProgress { wire_path: None }); return; @@ -850,8 +852,9 @@ impl<'a> MessageHandler> for NodeG if self.context_menu.is_some() { self.context_menu = None; self.wire_in_progress_from_connector = None; - self.wire_in_progress_type = FrontendGraphDataType::General; self.wire_in_progress_to_connector = None; + self.wire_in_progress_type = FrontendGraphDataType::General; + responses.add(FrontendMessage::UpdateContextMenuInformation { context_menu_information: self.context_menu.clone(), }); @@ -1388,14 +1391,18 @@ impl<'a> MessageHandler> for NodeG }); responses.add(DocumentMessage::EndTransaction); } + self.drag_start = None; self.begin_dragging = false; self.box_selection_start = None; + self.wire_in_progress_from_connector = None; - self.wire_in_progress_type = FrontendGraphDataType::General; self.wire_in_progress_to_connector = None; + self.wire_in_progress_type = FrontendGraphDataType::General; + self.reordering_export = None; self.reordering_import = None; + responses.add(DocumentMessage::EndTransaction); responses.add(FrontendMessage::UpdateWirePathInProgress { wire_path: None }); responses.add(FrontendMessage::UpdateBox { box_selection: None });