Skip to content

Commit 0ec28b9

Browse files
committed
finish adding node graph lasso select (also with alt-subtract)
1 parent 451f762 commit 0ec28b9

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, NodeGraphErrorDiagnostic};
9+
use crate::messages::portfolio::document::node_graph::utility_types::{ContextMenuData, Direction, FrontendGraphDataType, LassoSelection, NodeGraphErrorDiagnostic};
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 glam::{DAffine2, DVec2, IVec2};
2525
use graph_craft::document::{DocumentNodeImplementation, NodeId, NodeInput};
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
@@ -765,6 +769,15 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
765769
responses.add(FrontendMessage::UpdateBox { box_selection: None });
766770
return;
767771
}
772+
// Abort a lasso selection
773+
if self.lasso_selection_curr.is_some() {
774+
self.lasso_selection_curr = None;
775+
responses.add(NodeGraphMessage::SelectedNodesSet {
776+
nodes: self.selection_before_pointer_down.clone(),
777+
});
778+
responses.add(FrontendMessage::UpdateLasso { lasso_selection: None });
779+
return;
780+
}
768781
// Abort dragging a wire
769782
if self.wire_in_progress_from_connector.is_some() {
770783
self.wire_in_progress_from_connector = None;
@@ -974,7 +987,13 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
974987
if !shift_click && !alt_click {
975988
responses.add(NodeGraphMessage::SelectedNodesSet { nodes: Vec::new() })
976989
}
977-
self.box_selection_start = Some((node_graph_point, false));
990+
991+
if control_click {
992+
self.lasso_selection_curr = Some((vec![node_graph_point], false));
993+
} else {
994+
self.box_selection_start = Some((node_graph_point, false));
995+
}
996+
978997
self.update_node_graph_hints(responses);
979998
}
980999
NodeGraphMessage::PointerMove { shift } => {
@@ -1109,6 +1128,10 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
11091128
*box_selection_dragged = true;
11101129
responses.add(NodeGraphMessage::UpdateBoxSelection);
11111130
self.update_node_graph_hints(responses);
1131+
} else if let Some((_, lasso_selection_dragged)) = &mut self.lasso_selection_curr {
1132+
*lasso_selection_dragged = true;
1133+
responses.add(NodeGraphMessage::UpdateLassoSelection);
1134+
self.update_node_graph_hints(responses);
11121135
} else if self.reordering_import.is_some() {
11131136
let Some(modify_import_export) = network_interface.modify_import_export(selection_network_path) else {
11141137
log::error!("Could not get modify import export in PointerMove");
@@ -1391,6 +1414,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
13911414
self.drag_start = None;
13921415
self.begin_dragging = false;
13931416
self.box_selection_start = None;
1417+
self.lasso_selection_curr = None;
13941418
self.wire_in_progress_from_connector = None;
13951419
self.wire_in_progress_type = FrontendGraphDataType::General;
13961420
self.wire_in_progress_to_connector = None;
@@ -1399,12 +1423,17 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
13991423
responses.add(DocumentMessage::EndTransaction);
14001424
responses.add(FrontendMessage::UpdateWirePathInProgress { wire_path: None });
14011425
responses.add(FrontendMessage::UpdateBox { box_selection: None });
1426+
responses.add(FrontendMessage::UpdateLasso { lasso_selection: None });
14021427
responses.add(FrontendMessage::UpdateImportReorderIndex { index: None });
14031428
responses.add(FrontendMessage::UpdateExportReorderIndex { index: None });
14041429
self.update_node_graph_hints(responses);
14051430
}
14061431
NodeGraphMessage::PointerOutsideViewport { shift } => {
1407-
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()) {
1432+
if self.drag_start.is_some()
1433+
|| self.box_selection_start.is_some()
1434+
|| self.lasso_selection_curr.is_some()
1435+
|| (self.wire_in_progress_from_connector.is_some() && self.context_menu.is_none())
1436+
{
14081437
let _ = self.auto_panning.shift_viewport(ipp, viewport, responses);
14091438
} else {
14101439
// Auto-panning
@@ -1956,6 +1985,88 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
19561985
responses.add(FrontendMessage::UpdateBox { box_selection })
19571986
}
19581987
}
1988+
NodeGraphMessage::UpdateLassoSelection => {
1989+
if let Some((lasso_selection_curr, _)) = &mut self.lasso_selection_curr {
1990+
// WARNING WARNING WARNING: this commented-out code is copy pasted from UpdateBoxSelection above and has not been edited for lasso
1991+
// The mouse button was released but we missed the pointer up event
1992+
// if ((e.buttons & 1) === 0) {
1993+
// completeBoxSelection();
1994+
// boxSelection = undefined;
1995+
// } else if ((e.buttons & 2) !== 0) {
1996+
// editor.handle.selectNodes(new BigUint64Array(previousSelection));
1997+
// boxSelection = undefined;
1998+
// }
1999+
2000+
let Some(network_metadata) = network_interface.network_metadata(selection_network_path) else {
2001+
log::error!("Could not get network metadata in UpdateBoxSelection");
2002+
return;
2003+
};
2004+
2005+
{
2006+
let node_graph_point = network_metadata
2007+
.persistent_metadata
2008+
.navigation_metadata
2009+
.node_graph_to_viewport
2010+
.inverse()
2011+
.transform_point2(ipp.mouse.position);
2012+
2013+
lasso_selection_curr.push(node_graph_point);
2014+
}
2015+
2016+
let lasso_selection_viewport: Vec<DVec2> = lasso_selection_curr
2017+
.iter()
2018+
.map(|selection_point| network_metadata.persistent_metadata.navigation_metadata.node_graph_to_viewport.transform_point2(*selection_point))
2019+
.collect();
2020+
2021+
let shift = ipp.keyboard.get(Key::Shift as usize);
2022+
let alt = ipp.keyboard.get(Key::Alt as usize);
2023+
let Some(selected_nodes) = network_interface.selected_nodes_in_nested_network(selection_network_path) else {
2024+
log::error!("Could not get selected nodes in UpdateBoxSelection");
2025+
return;
2026+
};
2027+
let previous_selection = selected_nodes.selected_nodes_ref().iter().cloned().collect::<HashSet<_>>();
2028+
let mut nodes = if shift || alt {
2029+
selected_nodes.selected_nodes_ref().iter().cloned().collect::<HashSet<_>>()
2030+
} else {
2031+
HashSet::new()
2032+
};
2033+
let all_nodes = network_metadata.persistent_metadata.node_metadata.keys().cloned().collect::<Vec<_>>();
2034+
let path: Vec<PathSeg> = {
2035+
fn points_to_polygon(points: &[DVec2]) -> Vec<PathSeg> {
2036+
points
2037+
.windows(2)
2038+
.map(|w| PathSeg::Line(Line::new(dvec2_to_point(w[0]), dvec2_to_point(w[1]))))
2039+
.chain(std::iter::once(PathSeg::Line(Line::new(
2040+
dvec2_to_point(*points.last().unwrap()),
2041+
dvec2_to_point(*points.first().unwrap()),
2042+
))))
2043+
.collect()
2044+
}
2045+
points_to_polygon(lasso_selection_curr)
2046+
};
2047+
for node_id in all_nodes {
2048+
let Some(click_targets) = network_interface.node_click_targets(&node_id, selection_network_path) else {
2049+
log::error!("Could not get transient metadata for node {node_id}");
2050+
continue;
2051+
};
2052+
if click_targets.node_click_target.intersect_path(|| path.iter().cloned(), DAffine2::IDENTITY) {
2053+
if alt {
2054+
nodes.remove(&node_id);
2055+
} else {
2056+
nodes.insert(node_id);
2057+
}
2058+
}
2059+
}
2060+
if nodes != previous_selection {
2061+
responses.add(NodeGraphMessage::SelectedNodesSet {
2062+
nodes: nodes.into_iter().collect::<Vec<_>>(),
2063+
});
2064+
}
2065+
responses.add(FrontendMessage::UpdateLasso {
2066+
lasso_selection: Some(LassoSelection::from_iter(lasso_selection_viewport.into_iter())),
2067+
})
2068+
}
2069+
}
19592070
NodeGraphMessage::UpdateImportsExports => {
19602071
let imports = network_interface.frontend_imports(breadcrumb_network_path);
19612072
let exports = network_interface.frontend_exports(breadcrumb_network_path);
@@ -2711,11 +2822,12 @@ impl NodeGraphMessageHandler {
27112822
// Node gragging is in progress (having already moved at least one pixel from the mouse down position)
27122823
let dragging_nodes = self.drag_start.as_ref().is_some_and(|(_, dragged)| *dragged);
27132824

2714-
// A box selection is in progress
2715-
let dragging_box_selection = self.box_selection_start.is_some_and(|(_, box_selection_dragged)| box_selection_dragged);
2825+
// A box or lasso selection is in progress
2826+
let dragging_selection = self.box_selection_start.as_ref().is_some_and(|(_, box_selection_dragged)| *box_selection_dragged)
2827+
|| self.lasso_selection_curr.as_ref().is_some_and(|(_, lasso_selection_dragged)| *lasso_selection_dragged);
27162828

27172829
// Cancel the ongoing action
2718-
if wiring || dragging_nodes || dragging_box_selection {
2830+
if wiring || dragging_nodes || dragging_selection {
27192831
let hint_data = HintData(vec![HintGroup(vec![HintInfo::mouse(MouseMotion::Rmb, ""), HintInfo::keys([Key::Escape], "Cancel").prepend_slash()])]);
27202832
responses.add(FrontendMessage::UpdateInputHints { hint_data });
27212833
return;
@@ -2760,6 +2872,7 @@ impl Default for NodeGraphMessageHandler {
27602872
node_has_moved_in_drag: false,
27612873
shift_without_push: false,
27622874
box_selection_start: None,
2875+
lasso_selection_curr: None,
27632876
drag_start_chain_nodes: Vec::new(),
27642877
selection_before_pointer_down: Vec::new(),
27652878
disconnecting: None,
@@ -2790,6 +2903,7 @@ impl PartialEq for NodeGraphMessageHandler {
27902903
&& self.begin_dragging == other.begin_dragging
27912904
&& self.node_has_moved_in_drag == other.node_has_moved_in_drag
27922905
&& self.box_selection_start == other.box_selection_start
2906+
&& self.lasso_selection_curr == other.lasso_selection_curr
27932907
&& self.initial_disconnecting == other.initial_disconnecting
27942908
&& self.select_if_not_dragged == other.select_if_not_dragged
27952909
&& self.wire_in_progress_from_connector == other.wire_in_progress_from_connector

0 commit comments

Comments
 (0)