Browse Source

added right click to replace a node

Jonathan Higgins 3 months ago
parent
commit
dd996858c4

+ 8 - 2
scenes/main/control.tscn

@@ -457,14 +457,20 @@ visible = false
 [node name="SearchMenu" type="PopupPanel" parent="." groups=["popup_windows"]]
 auto_translate_mode = 1
 position = Vector2i(100, 100)
-size = Vector2i(600, 53)
+size = Vector2i(600, 77)
 script = ExtResource("6_fyarh")
 
 [node name="VBoxContainer" type="VBoxContainer" parent="SearchMenu"]
 offset_left = 4.0
 offset_top = 4.0
 offset_right = 596.0
-offset_bottom = 49.0
+offset_bottom = 73.0
+
+[node name="ReplaceLabel" type="Label" parent="SearchMenu/VBoxContainer"]
+layout_mode = 2
+text = "Replace"
+clip_text = true
+text_overrun_behavior = 3
 
 [node name="SearchBar" type="LineEdit" parent="SearchMenu/VBoxContainer"]
 layout_mode = 2

+ 22 - 0
scenes/main/scripts/control.gd

@@ -79,6 +79,7 @@ func load_scripts():
 
 func make_signal_connections():
 	get_node("SearchMenu").make_node.connect(graph_edit._make_node)
+	get_node("SearchMenu").swap_node.connect(graph_edit._swap_node)
 	get_node("mainmenu").make_node.connect(graph_edit._make_node)
 	get_node("mainmenu").open_help.connect(open_help.show_help_for_node)
 	get_node("Settings").open_cdp_location.connect(show_cdp_location)
@@ -618,6 +619,27 @@ func _on_graph_edit_popup_request(at_position: Vector2) -> void:
 	#get the window size relative to its scaling for retina displays
 	var window_size = get_window().size * DisplayServer.screen_get_scale()
 
+	#see if it was empty space or a node that was right clicked
+	var clicked_node
+	for child in graph_edit.get_children():
+		if child is GraphNode:
+			if Rect2(child.position, child.size).has_point(effect_position):
+				clicked_node = child
+				break
+	
+	if clicked_node and clicked_node.get_meta("command") != "outputfile":
+		var title = clicked_node.title
+		$SearchMenu/VBoxContainer/ReplaceLabel.text = "Replace " + title
+		$SearchMenu/VBoxContainer/ReplaceLabel.show()
+		$SearchMenu.replace_node = true
+		$SearchMenu.node_to_replace = clicked_node
+	else:
+		$SearchMenu/VBoxContainer/ReplaceLabel.hide()
+		$SearchMenu.replace_node = false
+	
+	var closest_connection = graph_edit.get_closest_connection_at_point(effect_position)
+	print("closest_connection")
+	print(closest_connection)
 	#calculate the xy position of the mouse clamped to the size of the window and menu so it doesn't go off the screen
 	var clamped_x = clamp(mouse_screen_pos.x, window_screen_pos.x, window_screen_pos.x + window_size.x - $SearchMenu.size.x)
 	var clamped_y = clamp(mouse_screen_pos.y, window_screen_pos.y, window_screen_pos.y + window_size.y - (420 * DisplayServer.screen_get_scale()))

+ 84 - 37
scenes/main/scripts/graph_edit.gd

@@ -359,43 +359,42 @@ func _unhandled_key_input(event: InputEvent) -> void:
 
 func _on_graph_edit_delete_nodes_request(nodes: Array[StringName]) -> void:
 	control_script.undo_redo.create_action("Delete Nodes (Undo only)")
-			
-	for node in selected_nodes.keys():
-		if is_instance_valid(node) and selected_nodes[node]:
-			if selected_nodes[node]:
-				#check if node is the output or the last input node and do nothing
-				if node.get_meta("command") == "outputfile":
-					pass
-				else:
-					# Store duplicate and state for undo
-					var node_data = node.duplicate()
-					var position = node.position_offset
-
-					# Store all connections for undo
-					var conns = []
-					for con in get_connection_list():
-						if con["to_node"] == node.name or con["from_node"] == node.name:
-							conns.append(con)
-
-					# Delete
-					remove_connections_to_node(node)
-					node.queue_free()
-					control_script.changesmade = true
-
-					# Register undo restore
-					control_script.undo_redo.add_undo_method(Callable(self, "add_child").bind(node_data, true))
-					control_script.undo_redo.add_undo_method(Callable(node_data, "set_position_offset").bind(position))
-					for con in conns:
-						control_script.undo_redo.add_undo_method(Callable(self, "connect_node").bind(
-							con["from_node"], con["from_port"],
-							con["to_node"], con["to_port"]
-						))
-					control_script.undo_redo.add_undo_method(Callable(self, "set_node_selected").bind(node_data, true))
-					control_script.undo_redo.add_undo_method(Callable(self, "_track_changes"))
-					control_script.undo_redo.add_undo_method(Callable(self, "_register_inputs_in_node").bind(node_data)) #link sliders for changes tracking
-					control_script.undo_redo.add_undo_method(Callable(self, "_register_node_movement")) # link nodes for changes tracking
-
-	# Clear selection
+
+	for node_name in nodes:
+		var node: GraphNode = get_node_or_null(NodePath(node_name))
+		if node and is_instance_valid(node):
+			# Skip output nodes
+			if node.get_meta("command") == "outputfile":
+				continue
+
+			# Store duplicate and state for undo
+			var node_data = node.duplicate()
+			var position = node.position_offset
+
+			# Store all connections for undo
+			var conns := []
+			for con in get_connection_list():
+				if con["to_node"] == node.name or con["from_node"] == node.name:
+					conns.append(con)
+
+			# Delete
+			remove_connections_to_node(node)
+			node.queue_free()
+			control_script.changesmade = true
+
+			# Register undo restore
+			control_script.undo_redo.add_undo_method(Callable(self, "add_child").bind(node_data, true))
+			control_script.undo_redo.add_undo_method(Callable(node_data, "set_position_offset").bind(position))
+			for con in conns:
+				control_script.undo_redo.add_undo_method(Callable(self, "connect_node").bind(
+					con["from_node"], con["from_port"],
+					con["to_node"], con["to_port"]
+				))
+			control_script.undo_redo.add_undo_method(Callable(self, "set_node_selected").bind(node_data, true))
+			control_script.undo_redo.add_undo_method(Callable(self, "_track_changes"))
+			control_script.undo_redo.add_undo_method(Callable(self, "_register_inputs_in_node").bind(node_data))
+			control_script.undo_redo.add_undo_method(Callable(self, "_register_node_movement"))
+
 	selected_nodes = {}
 
 	control_script.undo_redo.commit_action()
@@ -591,3 +590,51 @@ func on_inlet_removed(node_name: StringName, port_index: int):
 	for conn in connections:
 		if conn.to_node == node_name and conn.to_port == port_index:
 			disconnect_node(conn.from_node, conn.from_port, conn.to_node, conn.to_port)
+			
+func _swap_node(old_node: GraphNode, command: String):
+	#store the position and name of the node to be replaced
+	var position = old_node.position_offset
+	var old_name = old_node.name
+	#gather all connections in the graph
+	var connections = get_connection_list()
+	var related_connections = []
+	
+	#filter the connections to get just those connected to the node to be replaced
+	for conn in connections:
+		if conn.from_node == old_name or conn.to_node == old_name:
+			related_connections.append(conn)
+			
+	#delete the old node
+	_on_graph_edit_delete_nodes_request([old_node.name])
+	
+	#make the new node and reposition it to the location of the old node
+	var new_node = _make_node(command)
+	new_node.position_offset = position
+	
+	#filter through all the connections to the old node
+	for conn in related_connections:
+		var from = conn.from_node
+		var from_port = conn.from_port
+		var to = conn.to_node
+		var to_port = conn.to_port
+		
+		#where the old node is referenced replace it with the name of the new node
+		if from == old_name:
+			from = new_node.name
+		if to == old_name:
+			to = new_node.name
+			
+		#check that the ports being connected to/from on the new node actually exist
+		if (from == new_node.name and new_node.is_slot_enabled_right(from_port)) or (to == new_node.name and new_node.is_slot_enabled_left(to_port)):
+			#if they do get the two nodes to be connected
+			var from_node = get_node_or_null(NodePath(from))
+			var to_node = get_node_or_null(NodePath(to))
+			#safety incase one somehow no longer exists
+			if from_node != null and to_node != null:
+				#check if the port types are the same e.g. both time or both pvoc
+				if from_node.get_output_port_type(from_port) == to_node.get_input_port_type(to_port):
+					#connect them together
+					_on_connection_request(from, from_port, to, to_port)
+	
+	
+	

+ 7 - 1
scenes/menu/search_menu.gd

@@ -4,7 +4,10 @@ extends PopupPanel
 @onready var scroll_container: ScrollContainer = $VBoxContainer/ScrollContainer
 @onready var search_bar = $VBoxContainer/SearchBar
 var node_data = {} #stores node data for each node to display in help popup
+var replace_node = false
+var node_to_replace
 signal make_node(command)
+signal swap_node(node_to_replace, command)
 
 
 func _ready() -> void:
@@ -101,7 +104,10 @@ func _on_search_bar_text_changed(new_text: String) -> void:
 	
 func _on_item_selected(key: String):
 	self.hide()
-	make_node.emit(key) # send out signal to main patch
+	if replace_node == true:
+		swap_node.emit(node_to_replace, key)
+	else:
+		make_node.emit(key) # send out signal to main patch
 
 func _on_search_bar_text_submitted(new_text: String) -> void:
 	var button = item_container.get_child(0)