Fix using Esc to abort box selection and wire dragging causing the graph to close (#3409)
Some checks are pending
Editor: Dev & CI / build (push) Waiting to run
Editor: Dev & CI / cargo-deny (push) Waiting to run

* Implement proper node graph interaction aborting when pressing Escape

* Fixes

---------

Co-authored-by: Keavon Chambers <keavon@keavon.com>
This commit is contained in:
Yuxiang Huang 2025-12-04 20:42:00 -05:00 committed by GitHub
parent 2ee8e56cef
commit 8ca546c164
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 45 additions and 18 deletions

View file

@ -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),

View file

@ -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<DocumentMessage, DocumentMessageContext<'_>> 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 });
}
}

View file

@ -63,20 +63,21 @@ pub struct NodeGraphMessageHandler {
pub drag_start_chain_nodes: Vec<NodeId>,
/// 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<NodeId>,
pub selection_before_pointer_down: Vec<NodeId>,
/// If the grip icon is held during a drag, then shift without pushing other nodes
shift_without_push: bool,
disconnecting: Option<InputConnector>,
initial_disconnecting: bool,
/// Node to select on pointer up if multiple nodes are selected and they were not dragged.
select_if_not_dragged: Option<NodeId>,
/// 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<DVec2>,
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<DVec2>,
/// 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<ContextMenuInformation>,
/// Index of selected node to be deselected on pointer up when shift clicking an already selected node
@ -295,8 +296,8 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> 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<NodeGraphMessage, NodeGraphMessageContext<'a>> 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<NodeGraphMessage, NodeGraphMessageContext<'a>> 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<NodeGraphMessage, NodeGraphMessageContext<'a>> 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 });