@@ -52,10 +52,12 @@ enum ConnectionStyle {DIRECT, BEZIER, ROUNDED, MANHATTAN, DIAGONAL}
5252var connection_line_style : int = ConnectionStyle .BEZIER
5353
5454@onready var drag_cut_cursor = preload ("res://material_maker/icons/knife.png" )
55- var connections_to_cut : Array [Dictionary ]
56- var drag_cut_line : PackedVector2Array
57- var valid_drag_cut_entry : bool = false
58- const CURSOR_HOT_SPOT : Vector2 = Vector2 (1.02 , 17.34 )
55+ @onready var drag_reroute_cursor = preload ("res://material_maker/icons/cross.png" )
56+ const DRAG_CUT_CURSOR_HOT_SPOT : Vector2 = Vector2 (1.02 , 17.34 )
57+
58+ var drag_line : PackedVector2Array
59+ enum DragLineGesture {CUT , REROUTE , NONE }
60+ var drag_line_mode : int = DragLineGesture .NONE
5961
6062var lasso_points : PackedVector2Array
6163
@@ -76,7 +78,7 @@ func _ready() -> void:
7678 for t in range (41 ):
7779 add_valid_connection_type (t , 42 )
7880 add_valid_connection_type (42 , t )
79- node_popup .about_to_popup .connect (func (): valid_drag_cut_entry = false )
81+ node_popup .about_to_popup .connect (func (): drag_line_mode = DragLineGesture . NONE )
8082
8183func _exit_tree ():
8284 remove_crash_recovery_file ()
@@ -168,22 +170,45 @@ func _gui_input(event) -> void:
168170 accept_event ()
169171 node_popup .position = Vector2i (get_screen_transform ()* get_local_mouse_position ())
170172 node_popup .show_popup ()
171- elif event .is_action_released ("ui_cut_drag" ):
172- var conns : Array [Dictionary ]
173- for p in len (drag_cut_line ) - 1 :
174- var rect : Rect2
175- rect .position = drag_cut_line [p ]
176- rect .end = drag_cut_line [p + 1 ]
177- conns = get_connections_intersecting_with_rect (rect .abs ())
178- if conns .size ():
179- connections_to_cut .append_array (conns )
180- if connections_to_cut .size ():
181- on_cut_connections (connections_to_cut )
182- connections_to_cut .clear ()
183- Input .set_custom_mouse_cursor (null )
184- drag_cut_line .clear ()
185- conns .clear ()
186- queue_redraw ()
173+ elif event .is_action_released ("ui_cut_drag" ) or event .is_action_released ("ui_reroute_drag" ):
174+ match drag_line_mode :
175+ DragLineGesture .CUT :
176+ var connections_to_cut : Array [Dictionary ]
177+ var links : Array [Dictionary ]
178+ for p in len (drag_line ) - 1 :
179+ var rect : Rect2
180+ rect .position = drag_line [p ]
181+ rect .end = drag_line [p + 1 ]
182+ links = get_connections_intersecting_with_rect (rect .abs ())
183+ if links .size ():
184+ connections_to_cut .append_array (links )
185+ if connections_to_cut .size ():
186+ on_cut_connections (connections_to_cut )
187+ connections_to_cut .clear ()
188+ Input .set_custom_mouse_cursor (null )
189+ drag_line .clear ()
190+ links .clear ()
191+ queue_redraw ()
192+ DragLineGesture .REROUTE :
193+ if drag_line .size () >= 2 :
194+ var drag_reroute_line := Curve2D .new ()
195+ for p : Vector2 in drag_line :
196+ drag_reroute_line .add_point (p )
197+ var points := drag_reroute_line .tessellate_even_length (5 , connection_lines_thickness )
198+ var target_connections : Array [Dictionary ]
199+ for p : Vector2 in points :
200+ var link := get_closest_connection_at_point (p , connection_lines_thickness )
201+ if not link .is_empty () and target_connections .find_custom (func (d ):
202+ return (d .from_node == link .from_node and d .from_port == link .from_port
203+ and d .to_node == link .to_node and d .to_port == link .to_port )) == - 1 :
204+ link .position = p
205+ target_connections .append (link )
206+ if target_connections .size ():
207+ on_reroute_connections (target_connections )
208+ target_connections .clear ()
209+ Input .set_custom_mouse_cursor (null )
210+ drag_line .clear ()
211+ queue_redraw ()
187212 elif event .is_action_released ("ui_lasso_select" , true ):
188213 for node in get_children ():
189214 if node is GraphElement :
@@ -224,8 +249,10 @@ func _gui_input(event) -> void:
224249 event .control = true
225250 do_zoom (1.0 / 1.1 )
226251 elif event .button_index == MOUSE_BUTTON_RIGHT and event .is_pressed ():
227- valid_drag_cut_entry = true
228- if event .is_command_or_control_pressed () and event .shift_pressed :
252+ drag_line_mode = DragLineGesture .CUT
253+ if event .shift_pressed :
254+ add_reroute_under_mouse ()
255+ elif event .ctrl_pressed :
229256 create_portals ()
230257 elif event .shift_pressed :
231258 add_reroute_under_mouse ()
@@ -326,15 +353,24 @@ func _gui_input(event) -> void:
326353 if rect .has_point (get_global_mouse_position ()):
327354 mm_globals .set_tip_text ("Space/#RMB: Nodes menu, Arrow keys: Pan, Mouse wheel: Zoom" , 3 )
328355
329- if ((event .button_mask & MOUSE_BUTTON_MASK_RIGHT ) != 0 and valid_drag_cut_entry
330- and event .relative .length () > 1.0 ):
331- if event .ctrl_pressed :
332- Input .set_custom_mouse_cursor (
333- drag_cut_cursor , Input .CURSOR_ARROW , CURSOR_HOT_SPOT )
334- drag_cut_line .append (get_local_mouse_position ())
356+ # drag line gesture (cut/reroute)
357+ if (event .button_mask & MOUSE_BUTTON_MASK_RIGHT ) != 0 and event .relative .length () > 1.0 :
358+ if drag_line_mode != DragLineGesture .NONE :
359+ drag_line .append (get_local_mouse_position ())
335360 queue_redraw ()
336- elif drag_cut_line .size ():
337- drag_cut_line .append (get_local_mouse_position ())
361+ if event .ctrl_pressed :
362+ drag_line_mode = DragLineGesture .CUT
363+ Input .set_custom_mouse_cursor (drag_cut_cursor ,
364+ Input .CURSOR_ARROW , DRAG_CUT_CURSOR_HOT_SPOT )
365+ elif event .shift_pressed :
366+ drag_line_mode = DragLineGesture .REROUTE
367+ Input .set_custom_mouse_cursor (drag_reroute_cursor ,
368+ Input .CURSOR_ARROW , drag_reroute_cursor .get_size () * 0.5 )
369+ else :
370+ drag_line_mode = DragLineGesture .NONE
371+ Input .set_custom_mouse_cursor (null )
372+ if drag_line .size ():
373+ drag_line .clear ()
338374 queue_redraw ()
339375
340376 # lasso selection
@@ -355,8 +391,8 @@ func get_padded_node_rect(graph_node:GraphNode) -> Rect2:
355391 return Rect2 (rect .position , rect .size )
356392
357393func _draw () -> void :
358- if drag_cut_line .size () > 1 :
359- draw_polyline (drag_cut_line , get_theme_color ("connection_knife " , "GraphEdit" ), 1.0 )
394+ if drag_line .size () > 1 :
395+ draw_polyline (drag_line , get_theme_color ("line_gesture " , "GraphEdit" ), 1.0 )
360396 if lasso_points .size () > 1 :
361397 draw_polyline (lasso_points + PackedVector2Array ([lasso_points [0 ]]),
362398 get_theme_color ("lasso_stroke" , "GraphEdit" ), 1.0 )
@@ -479,6 +515,40 @@ func do_disconnect_node(from : String, from_slot : int, to : String, to_slot : i
479515 return true
480516 return false
481517
518+ func on_reroute_connections (target_connections : Array [Dictionary ]) -> void :
519+ var prev : Dictionary = generator .serialize ()
520+ var grouped_connections : Dictionary [String , Array ]
521+
522+ # group connections by their source node/port
523+ for link : Dictionary in target_connections :
524+ var key := "%s _%d " % [link .from_node , link .from_port ]
525+ if not grouped_connections .has (key ):
526+ grouped_connections [key ] = []
527+ grouped_connections [key ].append (link )
528+
529+ for group : String in grouped_connections :
530+ # find connection group center
531+ var group_rect := Rect2 (grouped_connections [group ][0 ].position , Vector2 .ZERO )
532+ for group_link : Dictionary in grouped_connections [group ]:
533+ group_rect = group_rect .expand (group_link .position )
534+ var group_center := (group_rect .abs ().get_center () + scroll_offset ) / zoom
535+
536+ # create reroute node
537+ var reroute : Array = await do_create_nodes ({nodes = [{name = "reroute" , type = "reroute" ,
538+ node_position = {x = group_center .x , y = group_center .y }}], connections = []})
539+ var group_reroute : GraphNode = reroute [0 ]
540+ group_reroute .position_offset -= group_reroute .size * 0.5
541+
542+ # reroute connections
543+ for link : Dictionary in grouped_connections [group ]:
544+ do_disconnect_node (link .from_node , link .from_port , link .to_node , link .to_port )
545+ do_connect_node (link .from_node , link .from_port , group_reroute .name , 0 )
546+ do_connect_node (group_reroute .name , 0 , link .to_node , link .to_port )
547+
548+ # undo/redo
549+ var next : Dictionary = generator .serialize ()
550+ undoredo_create_step ("Reroute multiple connections" , generator .get_hier_name (), prev , next )
551+
482552func on_cut_connections (connections_to_be_cut : Array ):
483553 var generator_hier_name : String = generator .get_hier_name ()
484554 var conns : Array = []
@@ -495,7 +565,6 @@ func on_cut_connections(connections_to_be_cut : Array):
495565 ]
496566 undoredo .add ("Cut node connections" , undo_actions , redo_actions )
497567
498-
499568func on_disconnect_node (from : String , from_slot : int , to : String , to_slot : int ) -> void :
500569 var from_gen = get_node (from ).generator
501570 var to_gen = get_node (to ).generator
0 commit comments