Skip to content

Commit 9e255fa

Browse files
committed
finish adding node graph lasso select (also with alt-subtract)
1 parent bcba72f commit 9e255fa

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::{
@@ -25,8 +25,9 @@ use graph_craft::document::{DocumentNodeImplementation, NodeId, NodeInput};
2525
use graph_craft::proto::GraphErrors;
2626
use graphene_std::math::math_ext::QuadExt;
2727
use graphene_std::vector::algorithms::bezpath_algorithms::bezpath_is_inside_bezpath;
28+
use graphene_std::vector::misc::dvec2_to_point;
2829
use graphene_std::*;
29-
use kurbo::{DEFAULT_ACCURACY, Shape};
30+
use kurbo::{DEFAULT_ACCURACY, Line, PathSeg, Shape};
3031
use renderer::Quad;
3132
use std::cmp::Ordering;
3233

@@ -64,6 +65,9 @@ pub struct NodeGraphMessageHandler {
6465
/// If dragging the background to create a box selection, this stores its starting point in node graph coordinates,
6566
/// plus a flag indicating if it has been dragged since the mousedown began.
6667
box_selection_start: Option<(DVec2, bool)>,
68+
/// If dragging the background to create a lasso selection, this stores its current lasso polygon in node graph coordinates,
69+
/// plus a flag indicating if it has been dragged since the mousedown began.
70+
lasso_selection_curr: Option<(Vec<DVec2>, bool)>,
6771
/// Restore the selection before box selection if it is aborted
6872
selection_before_pointer_down: Vec<NodeId>,
6973
/// If the grip icon is held during a drag, then shift without pushing other nodes
@@ -764,6 +768,15 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
764768
responses.add(FrontendMessage::UpdateBox { box_selection: None });
765769
return;
766770
}
771+
// Abort a lasso selection
772+
if self.lasso_selection_curr.is_some() {
773+
self.lasso_selection_curr = None;
774+
responses.add(NodeGraphMessage::SelectedNodesSet {
775+
nodes: self.selection_before_pointer_down.clone(),
776+
});
777+
responses.add(FrontendMessage::UpdateLasso { lasso_selection: None });
778+
return;
779+
}
767780
// Abort dragging a wire
768781
if self.wire_in_progress_from_connector.is_some() {
769782
self.wire_in_progress_from_connector = None;
@@ -969,7 +982,13 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
969982
if !shift_click && !alt_click {
970983
responses.add(NodeGraphMessage::SelectedNodesSet { nodes: Vec::new() })
971984
}
972-
self.box_selection_start = Some((node_graph_point, false));
985+
986+
if control_click {
987+
self.lasso_selection_curr = Some((vec![node_graph_point], false));
988+
} else {
989+
self.box_selection_start = Some((node_graph_point, false));
990+
}
991+
973992
self.update_node_graph_hints(responses);
974993
}
975994
NodeGraphMessage::PointerMove { shift } => {
@@ -1103,6 +1122,10 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
11031122
*box_selection_dragged = true;
11041123
responses.add(NodeGraphMessage::UpdateBoxSelection);
11051124
self.update_node_graph_hints(responses);
1125+
} else if let Some((_, lasso_selection_dragged)) = &mut self.lasso_selection_curr {
1126+
*lasso_selection_dragged = true;
1127+
responses.add(NodeGraphMessage::UpdateLassoSelection);
1128+
self.update_node_graph_hints(responses);
11061129
} else if self.reordering_import.is_some() {
11071130
let Some(modify_import_export) = network_interface.modify_import_export(selection_network_path) else {
11081131
log::error!("Could not get modify import export in PointerMove");
@@ -1389,6 +1412,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
13891412
self.drag_start = None;
13901413
self.begin_dragging = false;
13911414
self.box_selection_start = None;
1415+
self.lasso_selection_curr = None;
13921416
self.wire_in_progress_from_connector = None;
13931417
self.wire_in_progress_type = FrontendGraphDataType::General;
13941418
self.wire_in_progress_to_connector = None;
@@ -1397,12 +1421,17 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
13971421
responses.add(DocumentMessage::EndTransaction);
13981422
responses.add(FrontendMessage::UpdateWirePathInProgress { wire_path: None });
13991423
responses.add(FrontendMessage::UpdateBox { box_selection: None });
1424+
responses.add(FrontendMessage::UpdateLasso { lasso_selection: None });
14001425
responses.add(FrontendMessage::UpdateImportReorderIndex { index: None });
14011426
responses.add(FrontendMessage::UpdateExportReorderIndex { index: None });
14021427
self.update_node_graph_hints(responses);
14031428
}
14041429
NodeGraphMessage::PointerOutsideViewport { shift } => {
1405-
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()) {
1430+
if self.drag_start.is_some()
1431+
|| self.box_selection_start.is_some()
1432+
|| self.lasso_selection_curr.is_some()
1433+
|| (self.wire_in_progress_from_connector.is_some() && self.context_menu.is_none())
1434+
{
14061435
let _ = self.auto_panning.shift_viewport(ipp, responses);
14071436
} else {
14081437
// Auto-panning
@@ -1955,6 +1984,88 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
19551984
responses.add(FrontendMessage::UpdateBox { box_selection })
19561985
}
19571986
}
1987+
NodeGraphMessage::UpdateLassoSelection => {
1988+
if let Some((lasso_selection_curr, _)) = &mut self.lasso_selection_curr {
1989+
// WARNING WARNING WARNING: this commented-out code is copy pasted from UpdateBoxSelection above and has not been edited for lasso
1990+
// The mouse button was released but we missed the pointer up event
1991+
// if ((e.buttons & 1) === 0) {
1992+
// completeBoxSelection();
1993+
// boxSelection = undefined;
1994+
// } else if ((e.buttons & 2) !== 0) {
1995+
// editor.handle.selectNodes(new BigUint64Array(previousSelection));
1996+
// boxSelection = undefined;
1997+
// }
1998+
1999+
let Some(network_metadata) = network_interface.network_metadata(selection_network_path) else {
2000+
log::error!("Could not get network metadata in UpdateBoxSelection");
2001+
return;
2002+
};
2003+
2004+
{
2005+
let node_graph_point = network_metadata
2006+
.persistent_metadata
2007+
.navigation_metadata
2008+
.node_graph_to_viewport
2009+
.inverse()
2010+
.transform_point2(ipp.mouse.position);
2011+
2012+
lasso_selection_curr.push(node_graph_point);
2013+
}
2014+
2015+
let lasso_selection_viewport: Vec<DVec2> = lasso_selection_curr
2016+
.iter()
2017+
.map(|selection_point| network_metadata.persistent_metadata.navigation_metadata.node_graph_to_viewport.transform_point2(*selection_point))
2018+
.collect();
2019+
2020+
let shift = ipp.keyboard.get(Key::Shift as usize);
2021+
let alt = ipp.keyboard.get(Key::Alt as usize);
2022+
let Some(selected_nodes) = network_interface.selected_nodes_in_nested_network(selection_network_path) else {
2023+
log::error!("Could not get selected nodes in UpdateBoxSelection");
2024+
return;
2025+
};
2026+
let previous_selection = selected_nodes.selected_nodes_ref().iter().cloned().collect::<HashSet<_>>();
2027+
let mut nodes = if shift || alt {
2028+
selected_nodes.selected_nodes_ref().iter().cloned().collect::<HashSet<_>>()
2029+
} else {
2030+
HashSet::new()
2031+
};
2032+
let all_nodes = network_metadata.persistent_metadata.node_metadata.keys().cloned().collect::<Vec<_>>();
2033+
let path: Vec<PathSeg> = {
2034+
fn points_to_polygon(points: &[DVec2]) -> Vec<PathSeg> {
2035+
points
2036+
.windows(2)
2037+
.map(|w| PathSeg::Line(Line::new(dvec2_to_point(w[0]), dvec2_to_point(w[1]))))
2038+
.chain(std::iter::once(PathSeg::Line(Line::new(
2039+
dvec2_to_point(*points.last().unwrap()),
2040+
dvec2_to_point(*points.first().unwrap()),
2041+
))))
2042+
.collect()
2043+
}
2044+
points_to_polygon(lasso_selection_curr)
2045+
};
2046+
for node_id in all_nodes {
2047+
let Some(click_targets) = network_interface.node_click_targets(&node_id, selection_network_path) else {
2048+
log::error!("Could not get transient metadata for node {node_id}");
2049+
continue;
2050+
};
2051+
if click_targets.node_click_target.intersect_path(|| path.iter().cloned(), DAffine2::IDENTITY) {
2052+
if alt {
2053+
nodes.remove(&node_id);
2054+
} else {
2055+
nodes.insert(node_id);
2056+
}
2057+
}
2058+
}
2059+
if nodes != previous_selection {
2060+
responses.add(NodeGraphMessage::SelectedNodesSet {
2061+
nodes: nodes.into_iter().collect::<Vec<_>>(),
2062+
});
2063+
}
2064+
responses.add(FrontendMessage::UpdateLasso {
2065+
lasso_selection: Some(LassoSelection::from_iter(lasso_selection_viewport.into_iter())),
2066+
})
2067+
}
2068+
}
19582069
NodeGraphMessage::UpdateImportsExports => {
19592070
let imports = network_interface.frontend_imports(breadcrumb_network_path);
19602071
let exports = network_interface.frontend_exports(breadcrumb_network_path);
@@ -2725,11 +2836,12 @@ impl NodeGraphMessageHandler {
27252836
// Node gragging is in progress (having already moved at least one pixel from the mouse down position)
27262837
let dragging_nodes = self.drag_start.as_ref().is_some_and(|(_, dragged)| *dragged);
27272838

2728-
// A box selection is in progress
2729-
let dragging_box_selection = self.box_selection_start.is_some_and(|(_, box_selection_dragged)| box_selection_dragged);
2839+
// A box or lasso selection is in progress
2840+
let dragging_selection = self.box_selection_start.as_ref().is_some_and(|(_, box_selection_dragged)| *box_selection_dragged)
2841+
|| self.lasso_selection_curr.as_ref().is_some_and(|(_, lasso_selection_dragged)| *lasso_selection_dragged);
27302842

27312843
// Cancel the ongoing action
2732-
if wiring || dragging_nodes || dragging_box_selection {
2844+
if wiring || dragging_nodes || dragging_selection {
27332845
let hint_data = HintData(vec![HintGroup(vec![HintInfo::mouse(MouseMotion::Rmb, ""), HintInfo::keys([Key::Escape], "Cancel").prepend_slash()])]);
27342846
responses.add(FrontendMessage::UpdateInputHints { hint_data });
27352847
return;
@@ -2775,6 +2887,7 @@ impl Default for NodeGraphMessageHandler {
27752887
node_has_moved_in_drag: false,
27762888
shift_without_push: false,
27772889
box_selection_start: None,
2890+
lasso_selection_curr: None,
27782891
drag_start_chain_nodes: Vec::new(),
27792892
selection_before_pointer_down: Vec::new(),
27802893
disconnecting: None,
@@ -2806,6 +2919,7 @@ impl PartialEq for NodeGraphMessageHandler {
28062919
&& self.begin_dragging == other.begin_dragging
28072920
&& self.node_has_moved_in_drag == other.node_has_moved_in_drag
28082921
&& self.box_selection_start == other.box_selection_start
2922+
&& self.lasso_selection_curr == other.lasso_selection_curr
28092923
&& self.initial_disconnecting == other.initial_disconnecting
28102924
&& self.select_if_not_dragged == other.select_if_not_dragged
28112925
&& self.wire_in_progress_from_connector == other.wire_in_progress_from_connector

0 commit comments

Comments
 (0)