Skip to content

Commit 9046684

Browse files
committed
finish adding node graph lasso select (also with alt-subtract)
1 parent 469355c commit 9046684

File tree

3 files changed

+123
-7
lines changed

3 files changed

+123
-7
lines changed

editor/src/messages/input_mapper/input_mappings.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ pub fn input_mappings() -> Mapping {
5858
entry!(KeyDown(MouseLeft); modifiers=[Shift], action_dispatch=NodeGraphMessage::PointerDown { shift_click: true, control_click: false, alt_click: false, right_click: false }),
5959
entry!(KeyDown(MouseLeft); modifiers=[Accel], action_dispatch=NodeGraphMessage::PointerDown { shift_click: false, control_click: true, alt_click: false, right_click: false }),
6060
entry!(KeyDown(MouseLeft); modifiers=[Shift, Accel], action_dispatch=NodeGraphMessage::PointerDown { shift_click: true, control_click: true, alt_click: false, right_click: false }),
61+
entry!(KeyDown(MouseLeft); modifiers=[Accel, Alt], action_dispatch=NodeGraphMessage::PointerDown { shift_click: false, control_click: true, alt_click: true, right_click: false }),
6162
entry!(KeyDown(MouseLeft); modifiers=[Alt], action_dispatch=NodeGraphMessage::PointerDown { shift_click: false, control_click: false, alt_click: true, right_click: false }),
6263
entry!(KeyDown(MouseRight); action_dispatch=NodeGraphMessage::PointerDown { shift_click: false, control_click: false, alt_click: false, right_click: true }),
6364
entry!(DoubleClick(MouseButton::Left); action_dispatch=NodeGraphMessage::EnterNestedNetwork),

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
@@ -221,6 +221,7 @@ pub enum NodeGraphMessage {
221221
},
222222
UpdateEdges,
223223
UpdateBoxSelection,
224+
UpdateLassoSelection,
224225
UpdateImportsExports,
225226
UpdateLayerPanel,
226227
UpdateNewNodeGraph,

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

Lines changed: 121 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use crate::messages::layout::utility_types::widget_prelude::*;
66
use crate::messages::portfolio::document::document_message_handler::navigation_controls;
77
use crate::messages::portfolio::document::graph_operation::utility_types::ModifyInputsContext;
88
use crate::messages::portfolio::document::node_graph::document_node_definitions::NodePropertiesContext;
9-
use crate::messages::portfolio::document::node_graph::utility_types::{ContextMenuData, Direction, FrontendGraphDataType};
9+
use crate::messages::portfolio::document::node_graph::utility_types::{ContextMenuData, Direction, FrontendGraphDataType, LassoSelection};
1010
use crate::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
1111
use crate::messages::portfolio::document::utility_types::misc::GroupFolderType;
1212
use crate::messages::portfolio::document::utility_types::network_interface::{
@@ -26,8 +26,9 @@ use graph_craft::document::{DocumentNodeImplementation, NodeId, NodeInput};
2626
use graph_craft::proto::GraphErrors;
2727
use graphene_std::math::math_ext::QuadExt;
2828
use graphene_std::vector::algorithms::bezpath_algorithms::bezpath_is_inside_bezpath;
29+
use graphene_std::vector::misc::dvec2_to_point;
2930
use graphene_std::*;
30-
use kurbo::{DEFAULT_ACCURACY, Shape};
31+
use kurbo::{DEFAULT_ACCURACY, Line, PathSeg, Shape};
3132
use renderer::Quad;
3233
use std::cmp::Ordering;
3334

@@ -66,6 +67,9 @@ pub struct NodeGraphMessageHandler {
6667
/// If dragging the background to create a box selection, this stores its starting point in node graph coordinates,
6768
/// plus a flag indicating if it has been dragged since the mousedown began.
6869
box_selection_start: Option<(DVec2, bool)>,
70+
/// If dragging the background to create a lasso selection, this stores its current lasso polygon in node graph coordinates,
71+
/// plus a flag indicating if it has been dragged since the mousedown began.
72+
lasso_selection_curr: Option<(Vec<DVec2>, bool)>,
6973
/// Restore the selection before box selection if it is aborted
7074
selection_before_pointer_down: Vec<NodeId>,
7175
/// If the grip icon is held during a drag, then shift without pushing other nodes
@@ -767,6 +771,15 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
767771
responses.add(FrontendMessage::UpdateBox { box_selection: None });
768772
return;
769773
}
774+
// Abort a lasso selection
775+
if self.lasso_selection_curr.is_some() {
776+
self.lasso_selection_curr = None;
777+
responses.add(NodeGraphMessage::SelectedNodesSet {
778+
nodes: self.selection_before_pointer_down.clone(),
779+
});
780+
responses.add(FrontendMessage::UpdateLasso { lasso_selection: None });
781+
return;
782+
}
770783
// Abort dragging a wire
771784
if self.wire_in_progress_from_connector.is_some() {
772785
self.wire_in_progress_from_connector = None;
@@ -972,7 +985,13 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
972985
if !shift_click && !alt_click {
973986
responses.add(NodeGraphMessage::SelectedNodesSet { nodes: Vec::new() })
974987
}
975-
self.box_selection_start = Some((node_graph_point, false));
988+
989+
if control_click {
990+
self.lasso_selection_curr = Some((vec![node_graph_point], false));
991+
} else {
992+
self.box_selection_start = Some((node_graph_point, false));
993+
}
994+
976995
self.update_node_graph_hints(responses);
977996
}
978997
NodeGraphMessage::PointerMove { shift } => {
@@ -1106,6 +1125,10 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
11061125
*box_selection_dragged = true;
11071126
responses.add(NodeGraphMessage::UpdateBoxSelection);
11081127
self.update_node_graph_hints(responses);
1128+
} else if let Some((_, lasso_selection_dragged)) = &mut self.lasso_selection_curr {
1129+
*lasso_selection_dragged = true;
1130+
responses.add(NodeGraphMessage::UpdateLassoSelection);
1131+
self.update_node_graph_hints(responses);
11091132
} else if self.reordering_import.is_some() {
11101133
let Some(modify_import_export) = network_interface.modify_import_export(selection_network_path) else {
11111134
log::error!("Could not get modify import export in PointerMove");
@@ -1392,6 +1415,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
13921415
self.drag_start = None;
13931416
self.begin_dragging = false;
13941417
self.box_selection_start = None;
1418+
self.lasso_selection_curr = None;
13951419
self.wire_in_progress_from_connector = None;
13961420
self.wire_in_progress_type = FrontendGraphDataType::General;
13971421
self.wire_in_progress_to_connector = None;
@@ -1400,12 +1424,17 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
14001424
responses.add(DocumentMessage::EndTransaction);
14011425
responses.add(FrontendMessage::UpdateWirePathInProgress { wire_path: None });
14021426
responses.add(FrontendMessage::UpdateBox { box_selection: None });
1427+
responses.add(FrontendMessage::UpdateLasso { lasso_selection: None });
14031428
responses.add(FrontendMessage::UpdateImportReorderIndex { index: None });
14041429
responses.add(FrontendMessage::UpdateExportReorderIndex { index: None });
14051430
self.update_node_graph_hints(responses);
14061431
}
14071432
NodeGraphMessage::PointerOutsideViewport { shift } => {
1408-
if self.drag_start.is_some() || self.box_selection_start.is_some() || (self.wire_in_progress_from_connector.is_some() && self.context_menu.is_none()) {
1433+
if self.drag_start.is_some()
1434+
|| self.box_selection_start.is_some()
1435+
|| self.lasso_selection_curr.is_some()
1436+
|| (self.wire_in_progress_from_connector.is_some() && self.context_menu.is_none())
1437+
{
14091438
let _ = self.auto_panning.shift_viewport(ipp, viewport, responses);
14101439
} else {
14111440
// Auto-panning
@@ -1959,6 +1988,88 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
19591988
responses.add(FrontendMessage::UpdateBox { box_selection })
19601989
}
19611990
}
1991+
NodeGraphMessage::UpdateLassoSelection => {
1992+
if let Some((lasso_selection_curr, _)) = &mut self.lasso_selection_curr {
1993+
// WARNING WARNING WARNING: this commented-out code is copy pasted from UpdateBoxSelection above and has not been edited for lasso
1994+
// The mouse button was released but we missed the pointer up event
1995+
// if ((e.buttons & 1) === 0) {
1996+
// completeBoxSelection();
1997+
// boxSelection = undefined;
1998+
// } else if ((e.buttons & 2) !== 0) {
1999+
// editor.handle.selectNodes(new BigUint64Array(previousSelection));
2000+
// boxSelection = undefined;
2001+
// }
2002+
2003+
let Some(network_metadata) = network_interface.network_metadata(selection_network_path) else {
2004+
log::error!("Could not get network metadata in UpdateBoxSelection");
2005+
return;
2006+
};
2007+
2008+
{
2009+
let node_graph_point = network_metadata
2010+
.persistent_metadata
2011+
.navigation_metadata
2012+
.node_graph_to_viewport
2013+
.inverse()
2014+
.transform_point2(ipp.mouse.position);
2015+
2016+
lasso_selection_curr.push(node_graph_point);
2017+
}
2018+
2019+
let lasso_selection_viewport: Vec<DVec2> = lasso_selection_curr
2020+
.iter()
2021+
.map(|selection_point| network_metadata.persistent_metadata.navigation_metadata.node_graph_to_viewport.transform_point2(*selection_point))
2022+
.collect();
2023+
2024+
let shift = ipp.keyboard.get(Key::Shift as usize);
2025+
let alt = ipp.keyboard.get(Key::Alt as usize);
2026+
let Some(selected_nodes) = network_interface.selected_nodes_in_nested_network(selection_network_path) else {
2027+
log::error!("Could not get selected nodes in UpdateBoxSelection");
2028+
return;
2029+
};
2030+
let previous_selection = selected_nodes.selected_nodes_ref().iter().cloned().collect::<HashSet<_>>();
2031+
let mut nodes = if shift || alt {
2032+
selected_nodes.selected_nodes_ref().iter().cloned().collect::<HashSet<_>>()
2033+
} else {
2034+
HashSet::new()
2035+
};
2036+
let all_nodes = network_metadata.persistent_metadata.node_metadata.keys().cloned().collect::<Vec<_>>();
2037+
let path: Vec<PathSeg> = {
2038+
fn points_to_polygon(points: &[DVec2]) -> Vec<PathSeg> {
2039+
points
2040+
.windows(2)
2041+
.map(|w| PathSeg::Line(Line::new(dvec2_to_point(w[0]), dvec2_to_point(w[1]))))
2042+
.chain(std::iter::once(PathSeg::Line(Line::new(
2043+
dvec2_to_point(*points.last().unwrap()),
2044+
dvec2_to_point(*points.first().unwrap()),
2045+
))))
2046+
.collect()
2047+
}
2048+
points_to_polygon(lasso_selection_curr)
2049+
};
2050+
for node_id in all_nodes {
2051+
let Some(click_targets) = network_interface.node_click_targets(&node_id, selection_network_path) else {
2052+
log::error!("Could not get transient metadata for node {node_id}");
2053+
continue;
2054+
};
2055+
if click_targets.node_click_target.intersect_path(|| path.iter().cloned(), DAffine2::IDENTITY) {
2056+
if alt {
2057+
nodes.remove(&node_id);
2058+
} else {
2059+
nodes.insert(node_id);
2060+
}
2061+
}
2062+
}
2063+
if nodes != previous_selection {
2064+
responses.add(NodeGraphMessage::SelectedNodesSet {
2065+
nodes: nodes.into_iter().collect::<Vec<_>>(),
2066+
});
2067+
}
2068+
responses.add(FrontendMessage::UpdateLasso {
2069+
lasso_selection: Some(LassoSelection::from_iter(lasso_selection_viewport.into_iter())),
2070+
})
2071+
}
2072+
}
19622073
NodeGraphMessage::UpdateImportsExports => {
19632074
let imports = network_interface.frontend_imports(breadcrumb_network_path);
19642075
let exports = network_interface.frontend_exports(breadcrumb_network_path);
@@ -2729,11 +2840,12 @@ impl NodeGraphMessageHandler {
27292840
// Node gragging is in progress (having already moved at least one pixel from the mouse down position)
27302841
let dragging_nodes = self.drag_start.as_ref().is_some_and(|(_, dragged)| *dragged);
27312842

2732-
// A box selection is in progress
2733-
let dragging_box_selection = self.box_selection_start.is_some_and(|(_, box_selection_dragged)| box_selection_dragged);
2843+
// A box or lasso selection is in progress
2844+
let dragging_selection = self.box_selection_start.as_ref().is_some_and(|(_, box_selection_dragged)| *box_selection_dragged)
2845+
|| self.lasso_selection_curr.as_ref().is_some_and(|(_, lasso_selection_dragged)| *lasso_selection_dragged);
27342846

27352847
// Cancel the ongoing action
2736-
if wiring || dragging_nodes || dragging_box_selection {
2848+
if wiring || dragging_nodes || dragging_selection {
27372849
let hint_data = HintData(vec![HintGroup(vec![HintInfo::mouse(MouseMotion::Rmb, ""), HintInfo::keys([Key::Escape], "Cancel").prepend_slash()])]);
27382850
responses.add(FrontendMessage::UpdateInputHints { hint_data });
27392851
return;
@@ -2779,6 +2891,7 @@ impl Default for NodeGraphMessageHandler {
27792891
node_has_moved_in_drag: false,
27802892
shift_without_push: false,
27812893
box_selection_start: None,
2894+
lasso_selection_curr: None,
27822895
drag_start_chain_nodes: Vec::new(),
27832896
selection_before_pointer_down: Vec::new(),
27842897
disconnecting: None,
@@ -2810,6 +2923,7 @@ impl PartialEq for NodeGraphMessageHandler {
28102923
&& self.begin_dragging == other.begin_dragging
28112924
&& self.node_has_moved_in_drag == other.node_has_moved_in_drag
28122925
&& self.box_selection_start == other.box_selection_start
2926+
&& self.lasso_selection_curr == other.lasso_selection_curr
28132927
&& self.initial_disconnecting == other.initial_disconnecting
28142928
&& self.select_if_not_dragged == other.select_if_not_dragged
28152929
&& self.wire_in_progress_from_connector == other.wire_in_progress_from_connector

0 commit comments

Comments
 (0)