@@ -6,7 +6,7 @@ use crate::messages::layout::utility_types::widget_prelude::*;
66use crate :: messages:: portfolio:: document:: document_message_handler:: navigation_controls;
77use crate :: messages:: portfolio:: document:: graph_operation:: utility_types:: ModifyInputsContext ;
88use 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 } ;
1010use crate :: messages:: portfolio:: document:: utility_types:: document_metadata:: LayerNodeIdentifier ;
1111use crate :: messages:: portfolio:: document:: utility_types:: misc:: GroupFolderType ;
1212use crate :: messages:: portfolio:: document:: utility_types:: network_interface:: {
@@ -25,8 +25,9 @@ use graph_craft::document::{DocumentNodeImplementation, NodeId, NodeInput};
2525use graph_craft:: proto:: GraphErrors ;
2626use graphene_std:: math:: math_ext:: QuadExt ;
2727use graphene_std:: vector:: algorithms:: bezpath_algorithms:: bezpath_is_inside_bezpath;
28+ use graphene_std:: vector:: misc:: dvec2_to_point;
2829use graphene_std:: * ;
29- use kurbo:: { DEFAULT_ACCURACY , Shape } ;
30+ use kurbo:: { DEFAULT_ACCURACY , Line , PathSeg , Shape } ;
3031use renderer:: Quad ;
3132use 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.
6667box_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
6872selection_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
764768responses. add ( FrontendMessage :: UpdateBox { box_selection : None } ) ;
765769return ;
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
768781if self . wire_in_progress_from_connector . is_some ( ) {
769782self . wire_in_progress_from_connector = None ;
@@ -969,7 +982,13 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
969982if !shift_click && !alt_click {
970983responses. 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+
973992self . update_node_graph_hints ( responses) ;
974993}
975994NodeGraphMessage :: PointerMove { shift } => {
@@ -1103,6 +1122,10 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
11031122* box_selection_dragged = true ;
11041123responses. add ( NodeGraphMessage :: UpdateBoxSelection ) ;
11051124self . 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 ( ) {
11071130let Some ( modify_import_export) = network_interface. modify_import_export ( selection_network_path) else {
11081131log:: error!( "Could not get modify import export in PointerMove" ) ;
@@ -1389,6 +1412,7 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
13891412self . drag_start = None ;
13901413self . begin_dragging = false ;
13911414self . box_selection_start = None ;
1415+ self . lasso_selection_curr = None ;
13921416self . wire_in_progress_from_connector = None ;
13931417self . wire_in_progress_type = FrontendGraphDataType :: General ;
13941418self . wire_in_progress_to_connector = None ;
@@ -1397,12 +1421,17 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
13971421responses. add ( DocumentMessage :: EndTransaction ) ;
13981422responses. add ( FrontendMessage :: UpdateWirePathInProgress { wire_path : None } ) ;
13991423responses. add ( FrontendMessage :: UpdateBox { box_selection : None } ) ;
1424+ responses. add ( FrontendMessage :: UpdateLasso { lasso_selection : None } ) ;
14001425responses. add ( FrontendMessage :: UpdateImportReorderIndex { index : None } ) ;
14011426responses. add ( FrontendMessage :: UpdateExportReorderIndex { index : None } ) ;
14021427self . update_node_graph_hints ( responses) ;
14031428}
14041429NodeGraphMessage :: 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+ {
14061435let _ = self . auto_panning . shift_viewport ( ipp, responses) ;
14071436} else {
14081437// Auto-panning
@@ -1955,6 +1984,88 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphMessageContext<'a>> for NodeG
19551984responses. 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+ }
19582069NodeGraphMessage :: UpdateImportsExports => {
19592070let imports = network_interface. frontend_imports ( breadcrumb_network_path) ;
19602071let 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)
27262837let 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 {
27332845let hint_data = HintData ( vec ! [ HintGroup ( vec![ HintInfo :: mouse( MouseMotion :: Rmb , "" ) , HintInfo :: keys( [ Key :: Escape ] , "Cancel" ) . prepend_slash( ) ] ) ] ) ;
27342846responses. add ( FrontendMessage :: UpdateInputHints { hint_data } ) ;
27352847return ;
@@ -2775,6 +2887,7 @@ impl Default for NodeGraphMessageHandler {
27752887node_has_moved_in_drag : false ,
27762888shift_without_push : false ,
27772889box_selection_start : None ,
2890+ lasso_selection_curr : None ,
27782891drag_start_chain_nodes : Vec :: new ( ) ,
27792892selection_before_pointer_down : Vec :: new ( ) ,
27802893disconnecting : 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