Merge pull request #65574 from YuriSizov/graphedit-slot-port-conundrum

This commit is contained in:
Yuri Sizov 2022-09-10 14:23:11 +03:00 committed by GitHub
commit 461037203c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 288 additions and 239 deletions

View file

@ -1,37 +1,38 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="GraphEdit" inherits="Control" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
GraphEdit is an area capable of showing various GraphNodes. It manages connection events between them.
GraphEdit is a control responsible for displaying and manipulating graph-like data using [GraphNode]s. It provides access to creation, removal, connection, and disconnection of nodes.
</brief_description>
<description>
GraphEdit manages the showing of GraphNodes it contains, as well as connections and disconnections between them. Signals are sent for each of these two events. Disconnection between GraphNode slots is disabled by default.
It is greatly advised to enable low-processor usage mode (see [member OS.low_processor_usage_mode]) when using GraphEdits.
GraphEdit provides tools for creation, manipulation, and display of various graphs. Its main purpose in the engine is to power the visual programming systems, such as visual shaders, but it is also available for use in user projects.
GraphEdit by itself is only an empty container, representing an infinite grid where [GraphNode]s can be placed. Each [GraphNode] represent a node in the graph, a single unit of data in the connected scheme. GraphEdit, in turn, helps to control various interactions with nodes and between nodes. When the user attempts to connect, disconnect, or close a [GraphNode], a signal is emitted in the GraphEdit, but no action is taken by default. It is the responsibility of the programmer utilizing this control to implement the necessary logic to determine how each request should be handled.
[b]Performance:[/b] It is greatly advised to enable low-processor usage mode (see [member OS.low_processor_usage_mode]) when using GraphEdits.
</description>
<tutorials>
</tutorials>
<methods>
<method name="_get_connection_line" qualifiers="virtual const">
<return type="PackedVector2Array" />
<param index="0" name="from" type="Vector2" />
<param index="1" name="to" type="Vector2" />
<param index="0" name="from_position" type="Vector2" />
<param index="1" name="to_position" type="Vector2" />
<description>
Virtual method which can be overridden to customize how connections are drawn.
</description>
</method>
<method name="_is_in_input_hotzone" qualifiers="virtual">
<return type="bool" />
<param index="0" name="graph_node" type="Object" />
<param index="1" name="slot_index" type="int" />
<param index="0" name="in_node" type="Object" />
<param index="1" name="in_port" type="int" />
<param index="2" name="mouse_position" type="Vector2" />
<description>
Returns whether the [param mouse_position] is in the input hot zone.
By default, a hot zone is a [Rect2] positioned such that its center is at [param graph_node].[method GraphNode.get_connection_input_position]([param slot_index]) (For output's case, call [method GraphNode.get_connection_output_position] instead). The hot zone's width is twice the Theme Property [code]port_grab_distance_horizontal[/code], and its height is twice the [code]port_grab_distance_vertical[/code].
By default, a hot zone is a [Rect2] positioned such that its center is at [param in_node].[method GraphNode.get_connection_input_position]([param in_port]) (For output's case, call [method GraphNode.get_connection_output_position] instead). The hot zone's width is twice the Theme Property [code]port_grab_distance_horizontal[/code], and its height is twice the [code]port_grab_distance_vertical[/code].
Below is a sample code to help get started:
[codeblock]
func _is_in_input_hotzone(graph_node, slot_index, mouse_position):
var slot_size : Vector2 = Vector2(get_theme_constant("port_grab_distance_horizontal"), get_theme_constant("port_grab_distance_vertical"))
var slot_pos : Vector2 = graph_node.get_position() + graph_node.get_connection_input_position(slot_index) - slot_size / 2
var rect = Rect2(slot_pos, slot_size)
func _is_in_input_hotzone(in_node, in_port, mouse_position):
var port_size : Vector2 = Vector2(get_theme_constant("port_grab_distance_horizontal"), get_theme_constant("port_grab_distance_vertical"))
var port_pos : Vector2 = in_node.get_position() + in_node.get_connection_input_position(in_port) - port_size / 2
var rect = Rect2(port_pos, port_size)
return rect.has_point(mouse_position)
[/codeblock]
@ -39,17 +40,17 @@
</method>
<method name="_is_in_output_hotzone" qualifiers="virtual">
<return type="bool" />
<param index="0" name="graph_node" type="Object" />
<param index="1" name="slot_index" type="int" />
<param index="0" name="in_node" type="Object" />
<param index="1" name="in_port" type="int" />
<param index="2" name="mouse_position" type="Vector2" />
<description>
Returns whether the [param mouse_position] is in the output hot zone. For more information on hot zones, see [method _is_in_input_hotzone].
Below is a sample code to help get started:
[codeblock]
func _is_in_output_hotzone(graph_node, slot_index, mouse_position):
var slot_size : Vector2 = Vector2(get_theme_constant("port_grab_distance_horizontal"), get_theme_constant("port_grab_distance_vertical"))
var slot_pos : Vector2 = graph_node.get_position() + graph_node.get_connection_output_position(slot_index) - slot_size / 2
var rect = Rect2(slot_pos, slot_size)
func _is_in_output_hotzone(in_node, in_port, mouse_position):
var port_size : Vector2 = Vector2(get_theme_constant("port_grab_distance_horizontal"), get_theme_constant("port_grab_distance_vertical"))
var port_pos : Vector2 = in_node.get_position() + in_node.get_connection_output_position(in_port) - port_size / 2
var rect = Rect2(port_pos, port_size)
return rect.has_point(mouse_position)
[/codeblock]
@ -57,17 +58,17 @@
</method>
<method name="_is_node_hover_valid" qualifiers="virtual">
<return type="bool" />
<param index="0" name="from" type="StringName" />
<param index="1" name="from_slot" type="int" />
<param index="2" name="to" type="StringName" />
<param index="3" name="to_slot" type="int" />
<param index="0" name="from_node" type="StringName" />
<param index="1" name="from_port" type="int" />
<param index="2" name="to_node" type="StringName" />
<param index="3" name="to_port" type="int" />
<description>
This virtual method can be used to insert additional error detection while the user is dragging a connection over a valid port.
Return [code]true[/code] if the connection is indeed valid or return [code]false[/code] if the connection is impossible. If the connection is impossible, no snapping to the port and thus no connection request to that port will happen.
In this example a connection to same node is suppressed:
[codeblocks]
[gdscript]
func _is_node_hover_valid(from, from_slot, to, to_slot):
func _is_node_hover_valid(from, from_port, to, to_port):
return from != to
[/gdscript]
[csharp]
@ -83,21 +84,22 @@
<param index="0" name="from_type" type="int" />
<param index="1" name="to_type" type="int" />
<description>
Makes possible the connection between two different slot types. The type is defined with the [method GraphNode.set_slot] method.
Allows the connection between two different port types. The port type is defined individually for the left and the right port of each slot with the [method GraphNode.set_slot] method.
See also [method is_valid_connection_type] and [method remove_valid_connection_type].
</description>
</method>
<method name="add_valid_left_disconnect_type">
<return type="void" />
<param index="0" name="type" type="int" />
<description>
Makes possible to disconnect nodes when dragging from the slot at the left if it has the specified type.
Allows to disconnect nodes when dragging from the left port of the [GraphNode]'s slot if it has the specified type. See also [method remove_valid_left_disconnect_type].
</description>
</method>
<method name="add_valid_right_disconnect_type">
<return type="void" />
<param index="0" name="type" type="int" />
<description>
Makes possible to disconnect nodes when dragging from the slot at the right if it has the specified type.
Allows to disconnect nodes when dragging from the right port of the [GraphNode]'s slot if it has the specified type. See also [method remove_valid_right_disconnect_type].
</description>
</method>
<method name="arrange_nodes">
@ -114,22 +116,22 @@
</method>
<method name="connect_node">
<return type="int" enum="Error" />
<param index="0" name="from" type="StringName" />
<param index="0" name="from_node" type="StringName" />
<param index="1" name="from_port" type="int" />
<param index="2" name="to" type="StringName" />
<param index="2" name="to_node" type="StringName" />
<param index="3" name="to_port" type="int" />
<description>
Create a connection between the [param from_port] slot of the [param from] GraphNode and the [param to_port] slot of the [param to] GraphNode. If the connection already exists, no connection is created.
Create a connection between the [param from_port] of the [param from_node] [GraphNode] and the [param to_port] of the [param to_node] [GraphNode]. If the connection already exists, no connection is created.
</description>
</method>
<method name="disconnect_node">
<return type="void" />
<param index="0" name="from" type="StringName" />
<param index="0" name="from_node" type="StringName" />
<param index="1" name="from_port" type="int" />
<param index="2" name="to" type="StringName" />
<param index="2" name="to_node" type="StringName" />
<param index="3" name="to_port" type="int" />
<description>
Removes the connection between the [param from_port] slot of the [param from] GraphNode and the [param to_port] slot of the [param to] GraphNode. If the connection does not exist, no connection is removed.
Removes the connection between the [param from_port] of the [param from_node] [GraphNode] and the [param to_port] of the [param to_node] [GraphNode]. If the connection does not exist, no connection is removed.
</description>
</method>
<method name="force_connection_drag_end">
@ -142,10 +144,10 @@
</method>
<method name="get_connection_line">
<return type="PackedVector2Array" />
<param index="0" name="from" type="Vector2" />
<param index="1" name="to" type="Vector2" />
<param index="0" name="from_node" type="Vector2" />
<param index="1" name="to_node" type="Vector2" />
<description>
Returns the points which would make up a connection between [param from] and [param to].
Returns the points which would make up a connection between [param from_node] and [param to_node].
</description>
</method>
<method name="get_connection_list" qualifiers="const">
@ -163,12 +165,12 @@
</method>
<method name="is_node_connected">
<return type="bool" />
<param index="0" name="from" type="StringName" />
<param index="0" name="from_node" type="StringName" />
<param index="1" name="from_port" type="int" />
<param index="2" name="to" type="StringName" />
<param index="2" name="to_node" type="StringName" />
<param index="3" name="to_port" type="int" />
<description>
Returns [code]true[/code] if the [param from_port] slot of the [param from] GraphNode is connected to the [param to_port] slot of the [param to] GraphNode.
Returns [code]true[/code] if the [param from_port] of the [param from_node] [GraphNode] is connected to the [param to_port] of the [param to_node] [GraphNode].
</description>
</method>
<method name="is_valid_connection_type" qualifiers="const">
@ -176,7 +178,8 @@
<param index="0" name="from_type" type="int" />
<param index="1" name="to_type" type="int" />
<description>
Returns whether it's possible to connect slots of the specified types.
Returns whether it's possible to make a connection between two different port types. The port type is defined individually for the left and the right port of each slot with the [method GraphNode.set_slot] method.
See also [method add_valid_connection_type] and [method remove_valid_connection_type].
</description>
</method>
<method name="remove_valid_connection_type">
@ -184,32 +187,33 @@
<param index="0" name="from_type" type="int" />
<param index="1" name="to_type" type="int" />
<description>
Makes it not possible to connect between two different slot types. The type is defined with the [method GraphNode.set_slot] method.
Disallows the connection between two different port types previously allowed by [method add_valid_connection_type]. The port type is defined individually for the left and the right port of each slot with the [method GraphNode.set_slot] method.
See also [method is_valid_connection_type].
</description>
</method>
<method name="remove_valid_left_disconnect_type">
<return type="void" />
<param index="0" name="type" type="int" />
<description>
Removes the possibility to disconnect nodes when dragging from the slot at the left if it has the specified type.
Disallows to disconnect nodes when dragging from the left port of the [GraphNode]'s slot if it has the specified type. Use this to disable disconnection previously allowed with [method add_valid_left_disconnect_type].
</description>
</method>
<method name="remove_valid_right_disconnect_type">
<return type="void" />
<param index="0" name="type" type="int" />
<description>
Removes the possibility to disconnect nodes when dragging from the slot at the right if it has the specified type.
Disallows to disconnect nodes when dragging from the right port of the [GraphNode]'s slot if it has the specified type. Use this to disable disconnection previously allowed with [method add_valid_right_disconnect_type].
</description>
</method>
<method name="set_connection_activity">
<return type="void" />
<param index="0" name="from" type="StringName" />
<param index="0" name="from_node" type="StringName" />
<param index="1" name="from_port" type="int" />
<param index="2" name="to" type="StringName" />
<param index="2" name="to_node" type="StringName" />
<param index="3" name="to_port" type="int" />
<param index="4" name="amount" type="float" />
<description>
Sets the coloration of the connection between [param from]'s [param from_port] and [param to]'s [param to_port] with the color provided in the [theme_item activity] theme property.
Sets the coloration of the connection between [param from_node]'s [param from_port] and [param to_node]'s [param to_port] with the color provided in the [theme_item activity] theme property.
</description>
</method>
<method name="set_selected">
@ -287,36 +291,36 @@
</description>
</signal>
<signal name="connection_drag_started">
<param index="0" name="from" type="String" />
<param index="1" name="slot" type="int" />
<param index="0" name="from_node" type="String" />
<param index="1" name="from_port" type="int" />
<param index="2" name="is_output" type="bool" />
<description>
Emitted at the beginning of a connection drag.
</description>
</signal>
<signal name="connection_from_empty">
<param index="0" name="to" type="StringName" />
<param index="1" name="to_slot" type="int" />
<param index="0" name="to_node" type="StringName" />
<param index="1" name="to_port" type="int" />
<param index="2" name="release_position" type="Vector2" />
<description>
Emitted when user dragging connection from input port into empty space of the graph.
Emitted when user drags a connection from an input port into the empty space of the graph.
</description>
</signal>
<signal name="connection_request">
<param index="0" name="from" type="StringName" />
<param index="1" name="from_slot" type="int" />
<param index="2" name="to" type="StringName" />
<param index="3" name="to_slot" type="int" />
<param index="0" name="from_node" type="StringName" />
<param index="1" name="from_port" type="int" />
<param index="2" name="to_node" type="StringName" />
<param index="3" name="to_port" type="int" />
<description>
Emitted to the GraphEdit when the connection between the [param from_slot] slot of the [param from] GraphNode and the [param to_slot] slot of the [param to] GraphNode is attempted to be created.
Emitted to the GraphEdit when the connection between the [param from_port] of the [param from_node] [GraphNode] and the [param to_port] of the [param to_node] [GraphNode] is attempted to be created.
</description>
</signal>
<signal name="connection_to_empty">
<param index="0" name="from" type="StringName" />
<param index="1" name="from_slot" type="int" />
<param index="0" name="from_node" type="StringName" />
<param index="1" name="from_port" type="int" />
<param index="2" name="release_position" type="Vector2" />
<description>
Emitted when user dragging connection from output port into empty space of the graph.
Emitted when user drags a connection from an output port into the empty space of the graph.
</description>
</signal>
<signal name="copy_nodes_request">
@ -331,12 +335,12 @@
</description>
</signal>
<signal name="disconnection_request">
<param index="0" name="from" type="StringName" />
<param index="1" name="from_slot" type="int" />
<param index="2" name="to" type="StringName" />
<param index="3" name="to_slot" type="int" />
<param index="0" name="from_node" type="StringName" />
<param index="1" name="from_port" type="int" />
<param index="2" name="to_node" type="StringName" />
<param index="3" name="to_port" type="int" />
<description>
Emitted to the GraphEdit when the connection between [param from_slot] slot of [param from] GraphNode and [param to_slot] slot of [param to] GraphNode is attempted to be removed.
Emitted to the GraphEdit when the connection between [param from_port] of [param from_node] [GraphNode] and [param to_port] of [param to_node] [GraphNode] is attempted to be removed.
</description>
</signal>
<signal name="duplicate_nodes_request">

View file

@ -1,12 +1,13 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="GraphNode" inherits="Container" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A GraphNode is a container with potentially several input and output slots allowing connections between GraphNodes. Slots can have different, incompatible types.
GraphNode is a [Container] control that represents a single data unit in a [GraphEdit] graph. You can customize the number, type, and color of left- and right-side connection ports.
</brief_description>
<description>
A GraphNode is a container. Each GraphNode can have several input and output slots, sometimes referred to as ports, allowing connections between GraphNodes. To add a slot to GraphNode, add any [Control]-derived child node to it.
After adding at least one child to GraphNode new sections will be automatically created in the Inspector called 'Slot'. When 'Slot' is expanded you will see list with index number for each slot. You can click on each of them to expand further.
In the Inspector you can enable (show) or disable (hide) slots. By default, all slots are disabled so you may not see any slots on your GraphNode initially. You can assign a type to each slot. Only slots of the same type will be able to connect to each other. You can also assign colors to slots. A tuple of input and output slots is defined for each GUI element included in the GraphNode. Input connections are on the left and output connections are on the right side of GraphNode. Only enabled slots are counted as connections.
GraphNode allows to create nodes for a [GraphEdit] graph with customizable content based on its child [Control]s. GraphNode is a [Container] and is responsible for placing its children on screen. This works similar to [VBoxContainer]. Children, in turn, provide GraphNode with so-called slots, each of which can have a connection port on either side. This is similar to how [TabContainer] uses children to create the tabs.
Each GraphNode slot is defined by its index and can provide the node with up to two ports: one on the left, and one on the right. By convention the left port is also referred to as the input port and the right port is referred to as the output port. Each port can be enabled and configured individually, using different type and color. The type is an arbitrary value that you can define using your own considerations. The parent [GraphEdit] will receive this information on each connect and disconnect request.
Slots can be configured in the Inspector dock once you add at least one child [Control]. The properties are grouped by each slot's index in the "Slot" section.
[b]Note:[/b] While GraphNode is set up using slots and slot indices, connections are made between the ports which are enabled. Because of that [GraphEdit] uses port's index and not slot's index. You can use [method get_connection_input_slot] and [method get_connection_output_slot] to get the slot index from the port index.
</description>
<tutorials>
</tutorials>
@ -19,16 +20,16 @@
</method>
<method name="clear_slot">
<return type="void" />
<param index="0" name="idx" type="int" />
<param index="0" name="slot_index" type="int" />
<description>
Disables input and output slot whose index is [param idx].
Disables input and output slot whose index is [param slot_index].
</description>
</method>
<method name="get_connection_input_color">
<return type="Color" />
<param index="0" name="idx" type="int" />
<param index="0" name="port" type="int" />
<description>
Returns the [Color] of the input connection [param idx].
Returns the [Color] of the input connection [param port].
</description>
</method>
<method name="get_connection_input_count">
@ -39,30 +40,37 @@
</method>
<method name="get_connection_input_height">
<return type="int" />
<param index="0" name="idx" type="int" />
<param index="0" name="port" type="int" />
<description>
Returns the height of the input connection [param idx].
Returns the height of the input connection [param port].
</description>
</method>
<method name="get_connection_input_position">
<return type="Vector2" />
<param index="0" name="idx" type="int" />
<param index="0" name="port" type="int" />
<description>
Returns the position of the input connection [param idx].
Returns the position of the input connection [param port].
</description>
</method>
<method name="get_connection_input_slot">
<return type="int" />
<param index="0" name="port" type="int" />
<description>
Returns the corresponding slot index of the input connection [param port].
</description>
</method>
<method name="get_connection_input_type">
<return type="int" />
<param index="0" name="idx" type="int" />
<param index="0" name="port" type="int" />
<description>
Returns the type of the input connection [param idx].
Returns the type of the input connection [param port].
</description>
</method>
<method name="get_connection_output_color">
<return type="Color" />
<param index="0" name="idx" type="int" />
<param index="0" name="port" type="int" />
<description>
Returns the [Color] of the output connection [param idx].
Returns the [Color] of the output connection [param port].
</description>
</method>
<method name="get_connection_output_count">
@ -73,150 +81,157 @@
</method>
<method name="get_connection_output_height">
<return type="int" />
<param index="0" name="idx" type="int" />
<param index="0" name="port" type="int" />
<description>
Returns the height of the output connection [param idx].
Returns the height of the output connection [param port].
</description>
</method>
<method name="get_connection_output_position">
<return type="Vector2" />
<param index="0" name="idx" type="int" />
<param index="0" name="port" type="int" />
<description>
Returns the position of the output connection [param idx].
Returns the position of the output connection [param port].
</description>
</method>
<method name="get_connection_output_slot">
<return type="int" />
<param index="0" name="port" type="int" />
<description>
Returns the corresponding slot index of the output connection [param port].
</description>
</method>
<method name="get_connection_output_type">
<return type="int" />
<param index="0" name="idx" type="int" />
<param index="0" name="port" type="int" />
<description>
Returns the type of the output connection [param idx].
Returns the type of the output connection [param port].
</description>
</method>
<method name="get_slot_color_left" qualifiers="const">
<return type="Color" />
<param index="0" name="idx" type="int" />
<param index="0" name="slot_index" type="int" />
<description>
Returns the left (input) [Color] of the slot [param idx].
Returns the left (input) [Color] of the slot [param slot_index].
</description>
</method>
<method name="get_slot_color_right" qualifiers="const">
<return type="Color" />
<param index="0" name="idx" type="int" />
<param index="0" name="slot_index" type="int" />
<description>
Returns the right (output) [Color] of the slot [param idx].
Returns the right (output) [Color] of the slot [param slot_index].
</description>
</method>
<method name="get_slot_type_left" qualifiers="const">
<return type="int" />
<param index="0" name="idx" type="int" />
<param index="0" name="slot_index" type="int" />
<description>
Returns the left (input) type of the slot [param idx].
Returns the left (input) type of the slot [param slot_index].
</description>
</method>
<method name="get_slot_type_right" qualifiers="const">
<return type="int" />
<param index="0" name="idx" type="int" />
<param index="0" name="slot_index" type="int" />
<description>
Returns the right (output) type of the slot [param idx].
Returns the right (output) type of the slot [param slot_index].
</description>
</method>
<method name="is_slot_draw_stylebox" qualifiers="const">
<return type="bool" />
<param index="0" name="idx" type="int" />
<param index="0" name="slot_index" type="int" />
<description>
Returns true if the background [StyleBox] of the slot [param idx] is drawn.
Returns true if the background [StyleBox] of the slot [param slot_index] is drawn.
</description>
</method>
<method name="is_slot_enabled_left" qualifiers="const">
<return type="bool" />
<param index="0" name="idx" type="int" />
<param index="0" name="slot_index" type="int" />
<description>
Returns [code]true[/code] if left (input) side of the slot [param idx] is enabled.
Returns [code]true[/code] if left (input) side of the slot [param slot_index] is enabled.
</description>
</method>
<method name="is_slot_enabled_right" qualifiers="const">
<return type="bool" />
<param index="0" name="idx" type="int" />
<param index="0" name="slot_index" type="int" />
<description>
Returns [code]true[/code] if right (output) side of the slot [param idx] is enabled.
Returns [code]true[/code] if right (output) side of the slot [param slot_index] is enabled.
</description>
</method>
<method name="set_slot">
<return type="void" />
<param index="0" name="idx" type="int" />
<param index="1" name="enable_left" type="bool" />
<param index="0" name="slot_index" type="int" />
<param index="1" name="enable_left_port" type="bool" />
<param index="2" name="type_left" type="int" />
<param index="3" name="color_left" type="Color" />
<param index="4" name="enable_right" type="bool" />
<param index="4" name="enable_right_port" type="bool" />
<param index="5" name="type_right" type="int" />
<param index="6" name="color_right" type="Color" />
<param index="7" name="custom_left" type="Texture2D" default="null" />
<param index="8" name="custom_right" type="Texture2D" default="null" />
<param index="9" name="enable" type="bool" default="true" />
<param index="7" name="custom_icon_left" type="Texture2D" default="null" />
<param index="8" name="custom_icon_right" type="Texture2D" default="null" />
<param index="9" name="draw_stylebox" type="bool" default="true" />
<description>
Sets properties of the slot with ID [param idx].
If [param enable_left]/[param enable_right], a port will appear and the slot will be able to be connected from this side.
[param type_left]/[param type_right] is an arbitrary type of the port. Only ports with the same type values can be connected and negative values will disallow all connections to be made via user inputs.
[param color_left]/[param color_right] is the tint of the port's icon on this side.
[param custom_left]/[param custom_right] is a custom texture for this side's port.
[b]Note:[/b] This method only sets properties of the slot. To create the slot, add a [Control]-derived child to the GraphNode.
Individual properties can be set using one of the [code]set_slot_*[/code] methods. You must enable at least one side of the slot to do so.
Sets properties of the slot with the [param slot_index] index.
If [param enable_left_port]/[param enable_right_port] is [code]true[/code], a port will appear and the slot will be able to be connected from this side.
With [param type_left]/[param type_right] an arbitrary type can be assigned to each port. Two ports can be connected if they share the same type, or if the connection between their types is allowed in the parent [GraphEdit] (see [method GraphEdit.add_valid_connection_type]). Keep in mind that the [GraphEdit] has the final say in accepting the connection. Type compatibility simply allows the [signal GraphEdit.connection_request] signal to be emitted.
Ports can be further customized using [param color_left]/[param color_right] and [param custom_icon_left]/[param custom_icon_right]. The color parameter adds a tint to the icon. The custom icon can be used to override the default port dot.
Additionally, [param draw_stylebox] can be used to enable or disable drawing of the background stylebox for each slot. See [theme_item slot].
Individual properties can also be set using one of the [code]set_slot_*[/code] methods.
[b]Note:[/b] This method only sets properties of the slot. To create the slot itself, add a [Control]-derived child to the GraphNode.
</description>
</method>
<method name="set_slot_color_left">
<return type="void" />
<param index="0" name="idx" type="int" />
<param index="1" name="color_left" type="Color" />
<param index="0" name="slot_index" type="int" />
<param index="1" name="color" type="Color" />
<description>
Sets the [Color] of the left (input) side of the slot [param idx] to [param color_left].
Sets the [Color] of the left (input) side of the slot [param slot_index] to [param color].
</description>
</method>
<method name="set_slot_color_right">
<return type="void" />
<param index="0" name="idx" type="int" />
<param index="1" name="color_right" type="Color" />
<param index="0" name="slot_index" type="int" />
<param index="1" name="color" type="Color" />
<description>
Sets the [Color] of the right (output) side of the slot [param idx] to [param color_right].
Sets the [Color] of the right (output) side of the slot [param slot_index] to [param color].
</description>
</method>
<method name="set_slot_draw_stylebox">
<return type="void" />
<param index="0" name="idx" type="int" />
<param index="1" name="draw_stylebox" type="bool" />
<param index="0" name="slot_index" type="int" />
<param index="1" name="enable" type="bool" />
<description>
Toggles the background [StyleBox] of the slot [param idx].
Toggles the background [StyleBox] of the slot [param slot_index].
</description>
</method>
<method name="set_slot_enabled_left">
<return type="void" />
<param index="0" name="idx" type="int" />
<param index="1" name="enable_left" type="bool" />
<param index="0" name="slot_index" type="int" />
<param index="1" name="enable" type="bool" />
<description>
Toggles the left (input) side of the slot [param idx]. If [param enable_left] is [code]true[/code], a port will appear on the left side and the slot will be able to be connected from this side.
Toggles the left (input) side of the slot [param slot_index]. If [param enable] is [code]true[/code], a port will appear on the left side and the slot will be able to be connected from this side.
</description>
</method>
<method name="set_slot_enabled_right">
<return type="void" />
<param index="0" name="idx" type="int" />
<param index="1" name="enable_right" type="bool" />
<param index="0" name="slot_index" type="int" />
<param index="1" name="enable" type="bool" />
<description>
Toggles the right (output) side of the slot [param idx]. If [param enable_right] is [code]true[/code], a port will appear on the right side and the slot will be able to be connected from this side.
Toggles the right (output) side of the slot [param slot_index]. If [param enable] is [code]true[/code], a port will appear on the right side and the slot will be able to be connected from this side.
</description>
</method>
<method name="set_slot_type_left">
<return type="void" />
<param index="0" name="idx" type="int" />
<param index="1" name="type_left" type="int" />
<param index="0" name="slot_index" type="int" />
<param index="1" name="type" type="int" />
<description>
Sets the left (input) type of the slot [param idx] to [param type_left]. If the value is negative, all connections will be disallowed to be created via user inputs.
Sets the left (input) type of the slot [param slot_index] to [param type]. If the value is negative, all connections will be disallowed to be created via user inputs.
</description>
</method>
<method name="set_slot_type_right">
<return type="void" />
<param index="0" name="idx" type="int" />
<param index="1" name="type_right" type="int" />
<param index="0" name="slot_index" type="int" />
<param index="1" name="type" type="int" />
<description>
Sets the right (output) type of the slot [param idx] to [param type_right]. If the value is negative, all connections will be disallowed to be created via user inputs.
Sets the right (output) type of the slot [param slot_index] to [param type]. If the value is negative, all connections will be disallowed to be created via user inputs.
</description>
</method>
</methods>

View file

@ -773,25 +773,25 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) {
if (connecting_valid) {
if (connecting && connecting_target) {
String from = connecting_from;
int from_slot = connecting_index;
int from_port = connecting_index;
String to = connecting_target_to;
int to_slot = connecting_target_index;
int to_port = connecting_target_index;
if (!connecting_out) {
SWAP(from, to);
SWAP(from_slot, to_slot);
SWAP(from_port, to_port);
}
emit_signal(SNAME("connection_request"), from, from_slot, to, to_slot);
emit_signal(SNAME("connection_request"), from, from_port, to, to_port);
} else if (!just_disconnected) {
String from = connecting_from;
int from_slot = connecting_index;
int from_port = connecting_index;
Vector2 ofs = mb->get_position();
if (!connecting_out) {
emit_signal(SNAME("connection_from_empty"), from, from_slot, ofs);
emit_signal(SNAME("connection_from_empty"), from, from_port, ofs);
} else {
emit_signal(SNAME("connection_to_empty"), from, from_slot, ofs);
emit_signal(SNAME("connection_to_empty"), from, from_port, ofs);
}
}
}
@ -830,22 +830,22 @@ bool GraphEdit::_check_clickable_control(Control *p_control, const Vector2 &mpos
}
}
bool GraphEdit::is_in_input_hotzone(GraphNode *p_graph_node, int p_slot_index, const Vector2 &p_mouse_pos, const Vector2i &p_port_size) {
bool GraphEdit::is_in_input_hotzone(GraphNode *p_node, int p_port, const Vector2 &p_mouse_pos, const Vector2i &p_port_size) {
bool success;
if (GDVIRTUAL_CALL(_is_in_input_hotzone, p_graph_node, p_slot_index, p_mouse_pos, success)) {
if (GDVIRTUAL_CALL(_is_in_input_hotzone, p_node, p_port, p_mouse_pos, success)) {
return success;
} else {
Vector2 pos = p_graph_node->get_connection_input_position(p_slot_index) + p_graph_node->get_position();
Vector2 pos = p_node->get_connection_input_position(p_port) + p_node->get_position();
return is_in_port_hotzone(pos / zoom, p_mouse_pos, p_port_size, true);
}
}
bool GraphEdit::is_in_output_hotzone(GraphNode *p_graph_node, int p_slot_index, const Vector2 &p_mouse_pos, const Vector2i &p_port_size) {
bool GraphEdit::is_in_output_hotzone(GraphNode *p_node, int p_port, const Vector2 &p_mouse_pos, const Vector2i &p_port_size) {
bool success;
if (GDVIRTUAL_CALL(_is_in_output_hotzone, p_graph_node, p_slot_index, p_mouse_pos, success)) {
if (GDVIRTUAL_CALL(_is_in_output_hotzone, p_node, p_port, p_mouse_pos, success)) {
return success;
} else {
Vector2 pos = p_graph_node->get_connection_output_position(p_slot_index) + p_graph_node->get_position();
Vector2 pos = p_node->get_connection_output_position(p_port) + p_node->get_position();
return is_in_port_hotzone(pos / zoom, p_mouse_pos, p_port_size, false);
}
}
@ -1100,11 +1100,11 @@ void GraphEdit::_minimap_draw() {
continue;
}
Vector2 from_slot_position = gfrom->get_position_offset() * zoom + gfrom->get_connection_output_position(E.from_port);
Vector2 from_position = minimap->_convert_from_graph_position(from_slot_position - graph_offset) + minimap_offset;
Vector2 from_port_position = gfrom->get_position_offset() * zoom + gfrom->get_connection_output_position(E.from_port);
Vector2 from_position = minimap->_convert_from_graph_position(from_port_position - graph_offset) + minimap_offset;
Color from_color = gfrom->get_connection_output_color(E.from_port);
Vector2 to_slot_position = gto->get_position_offset() * zoom + gto->get_connection_input_position(E.to_port);
Vector2 to_position = minimap->_convert_from_graph_position(to_slot_position - graph_offset) + minimap_offset;
Vector2 to_port_position = gto->get_position_offset() * zoom + gto->get_connection_input_position(E.to_port);
Vector2 to_position = minimap->_convert_from_graph_position(to_port_position - graph_offset) + minimap_offset;
Color to_color = gto->get_connection_input_color(E.to_port);
if (E.activity > 0) {
@ -2303,10 +2303,10 @@ void GraphEdit::arrange_nodes() {
}
void GraphEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("connect_node", "from", "from_port", "to", "to_port"), &GraphEdit::connect_node);
ClassDB::bind_method(D_METHOD("is_node_connected", "from", "from_port", "to", "to_port"), &GraphEdit::is_node_connected);
ClassDB::bind_method(D_METHOD("disconnect_node", "from", "from_port", "to", "to_port"), &GraphEdit::disconnect_node);
ClassDB::bind_method(D_METHOD("set_connection_activity", "from", "from_port", "to", "to_port", "amount"), &GraphEdit::set_connection_activity);
ClassDB::bind_method(D_METHOD("connect_node", "from_node", "from_port", "to_node", "to_port"), &GraphEdit::connect_node);
ClassDB::bind_method(D_METHOD("is_node_connected", "from_node", "from_port", "to_node", "to_port"), &GraphEdit::is_node_connected);
ClassDB::bind_method(D_METHOD("disconnect_node", "from_node", "from_port", "to_node", "to_port"), &GraphEdit::disconnect_node);
ClassDB::bind_method(D_METHOD("set_connection_activity", "from_node", "from_port", "to_node", "to_port", "amount"), &GraphEdit::set_connection_activity);
ClassDB::bind_method(D_METHOD("get_connection_list"), &GraphEdit::_get_connection_list);
ClassDB::bind_method(D_METHOD("clear_connections"), &GraphEdit::clear_connections);
ClassDB::bind_method(D_METHOD("force_connection_drag_end"), &GraphEdit::force_connection_drag_end);
@ -2320,7 +2320,7 @@ void GraphEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("add_valid_connection_type", "from_type", "to_type"), &GraphEdit::add_valid_connection_type);
ClassDB::bind_method(D_METHOD("remove_valid_connection_type", "from_type", "to_type"), &GraphEdit::remove_valid_connection_type);
ClassDB::bind_method(D_METHOD("is_valid_connection_type", "from_type", "to_type"), &GraphEdit::is_valid_connection_type);
ClassDB::bind_method(D_METHOD("get_connection_line", "from", "to"), &GraphEdit::get_connection_line);
ClassDB::bind_method(D_METHOD("get_connection_line", "from_node", "to_node"), &GraphEdit::get_connection_line);
ClassDB::bind_method(D_METHOD("set_panning_scheme", "scheme"), &GraphEdit::set_panning_scheme);
ClassDB::bind_method(D_METHOD("get_panning_scheme"), &GraphEdit::get_panning_scheme);
@ -2370,8 +2370,8 @@ void GraphEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_right_disconnects_enabled"), &GraphEdit::is_right_disconnects_enabled);
ClassDB::bind_method(D_METHOD("_update_scroll_offset"), &GraphEdit::_update_scroll_offset);
GDVIRTUAL_BIND(_is_in_input_hotzone, "graph_node", "slot_index", "mouse_position");
GDVIRTUAL_BIND(_is_in_output_hotzone, "graph_node", "slot_index", "mouse_position");
GDVIRTUAL_BIND(_is_in_input_hotzone, "in_node", "in_port", "mouse_position");
GDVIRTUAL_BIND(_is_in_output_hotzone, "in_node", "in_port", "mouse_position");
ClassDB::bind_method(D_METHOD("get_zoom_hbox"), &GraphEdit::get_zoom_hbox);
@ -2379,8 +2379,8 @@ void GraphEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_selected", "node"), &GraphEdit::set_selected);
GDVIRTUAL_BIND(_get_connection_line, "from", "to")
GDVIRTUAL_BIND(_is_node_hover_valid, "from", "from_slot", "to", "to_slot");
GDVIRTUAL_BIND(_get_connection_line, "from_position", "to_position")
GDVIRTUAL_BIND(_is_node_hover_valid, "from_node", "from_port", "to_node", "to_port");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "right_disconnects"), "set_right_disconnects", "is_right_disconnects_enabled");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "scroll_offset", PROPERTY_HINT_NONE, "suffix:px"), "set_scroll_ofs", "get_scroll_ofs");
@ -2408,21 +2408,21 @@ void GraphEdit::_bind_methods() {
ADD_GROUP("UI", "");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "arrange_nodes_button_hidden"), "set_arrange_nodes_button_hidden", "is_arrange_nodes_button_hidden");
ADD_SIGNAL(MethodInfo("connection_request", PropertyInfo(Variant::STRING_NAME, "from"), PropertyInfo(Variant::INT, "from_slot"), PropertyInfo(Variant::STRING_NAME, "to"), PropertyInfo(Variant::INT, "to_slot")));
ADD_SIGNAL(MethodInfo("disconnection_request", PropertyInfo(Variant::STRING_NAME, "from"), PropertyInfo(Variant::INT, "from_slot"), PropertyInfo(Variant::STRING_NAME, "to"), PropertyInfo(Variant::INT, "to_slot")));
ADD_SIGNAL(MethodInfo("connection_request", PropertyInfo(Variant::STRING_NAME, "from_node"), PropertyInfo(Variant::INT, "from_port"), PropertyInfo(Variant::STRING_NAME, "to_node"), PropertyInfo(Variant::INT, "to_port")));
ADD_SIGNAL(MethodInfo("disconnection_request", PropertyInfo(Variant::STRING_NAME, "from_node"), PropertyInfo(Variant::INT, "from_port"), PropertyInfo(Variant::STRING_NAME, "to_node"), PropertyInfo(Variant::INT, "to_port")));
ADD_SIGNAL(MethodInfo("popup_request", PropertyInfo(Variant::VECTOR2, "position")));
ADD_SIGNAL(MethodInfo("duplicate_nodes_request"));
ADD_SIGNAL(MethodInfo("copy_nodes_request"));
ADD_SIGNAL(MethodInfo("paste_nodes_request"));
ADD_SIGNAL(MethodInfo("node_selected", PropertyInfo(Variant::OBJECT, "node", PROPERTY_HINT_RESOURCE_TYPE, "Node")));
ADD_SIGNAL(MethodInfo("node_deselected", PropertyInfo(Variant::OBJECT, "node", PROPERTY_HINT_RESOURCE_TYPE, "Node")));
ADD_SIGNAL(MethodInfo("connection_to_empty", PropertyInfo(Variant::STRING_NAME, "from"), PropertyInfo(Variant::INT, "from_slot"), PropertyInfo(Variant::VECTOR2, "release_position")));
ADD_SIGNAL(MethodInfo("connection_from_empty", PropertyInfo(Variant::STRING_NAME, "to"), PropertyInfo(Variant::INT, "to_slot"), PropertyInfo(Variant::VECTOR2, "release_position")));
ADD_SIGNAL(MethodInfo("connection_to_empty", PropertyInfo(Variant::STRING_NAME, "from_node"), PropertyInfo(Variant::INT, "from_port"), PropertyInfo(Variant::VECTOR2, "release_position")));
ADD_SIGNAL(MethodInfo("connection_from_empty", PropertyInfo(Variant::STRING_NAME, "to_node"), PropertyInfo(Variant::INT, "to_port"), PropertyInfo(Variant::VECTOR2, "release_position")));
ADD_SIGNAL(MethodInfo("delete_nodes_request", PropertyInfo(Variant::ARRAY, "nodes", PROPERTY_HINT_ARRAY_TYPE, "StringName")));
ADD_SIGNAL(MethodInfo("begin_node_move"));
ADD_SIGNAL(MethodInfo("end_node_move"));
ADD_SIGNAL(MethodInfo("scroll_offset_changed", PropertyInfo(Variant::VECTOR2, "offset")));
ADD_SIGNAL(MethodInfo("connection_drag_started", PropertyInfo(Variant::STRING, "from"), PropertyInfo(Variant::INT, "slot"), PropertyInfo(Variant::BOOL, "is_output")));
ADD_SIGNAL(MethodInfo("connection_drag_started", PropertyInfo(Variant::STRING, "from_node"), PropertyInfo(Variant::INT, "from_port"), PropertyInfo(Variant::BOOL, "is_output")));
ADD_SIGNAL(MethodInfo("connection_drag_ended"));
BIND_ENUM_CONSTANT(SCROLL_ZOOMS);

View file

@ -201,8 +201,8 @@ private:
GraphEditMinimap *minimap = nullptr;
void _top_layer_input(const Ref<InputEvent> &p_ev);
bool is_in_input_hotzone(GraphNode *p_graph_node, int p_slot_index, const Vector2 &p_mouse_pos, const Vector2i &p_port_size);
bool is_in_output_hotzone(GraphNode *p_graph_node, int p_slot_index, const Vector2 &p_mouse_pos, const Vector2i &p_port_size);
bool is_in_input_hotzone(GraphNode *p_node, int p_port, const Vector2 &p_mouse_pos, const Vector2i &p_port_size);
bool is_in_output_hotzone(GraphNode *p_node, int p_port, const Vector2 &p_mouse_pos, const Vector2i &p_port_size);
bool is_in_port_hotzone(const Vector2 &pos, const Vector2 &p_mouse_pos, const Vector2i &p_port_size, bool p_left);
void _top_layer_draw();

View file

@ -779,8 +779,8 @@ void GraphNode::_connpos_update() {
int sep = get_theme_constant(SNAME("separation"));
Ref<StyleBox> sb = get_theme_stylebox(SNAME("frame"));
conn_input_cache.clear();
conn_output_cache.clear();
left_port_cache.clear();
right_port_cache.clear();
int vofs = 0;
int idx = 0;
@ -801,20 +801,26 @@ void GraphNode::_connpos_update() {
if (slot_info.has(idx)) {
if (slot_info[idx].enable_left) {
ConnCache cc;
cc.pos = Point2i(edgeofs, y + h / 2);
PortCache cc;
cc.position = Point2i(edgeofs, y + h / 2);
cc.height = size.height;
cc.slot_idx = idx;
cc.type = slot_info[idx].type_left;
cc.color = slot_info[idx].color_left;
cc.height = size.height;
conn_input_cache.push_back(cc);
left_port_cache.push_back(cc);
}
if (slot_info[idx].enable_right) {
ConnCache cc;
cc.pos = Point2i(get_size().width - edgeofs, y + h / 2);
PortCache cc;
cc.position = Point2i(get_size().width - edgeofs, y + h / 2);
cc.height = size.height;
cc.slot_idx = idx;
cc.type = slot_info[idx].type_right;
cc.color = slot_info[idx].color_right;
cc.height = size.height;
conn_output_cache.push_back(cc);
right_port_cache.push_back(cc);
}
}
@ -831,46 +837,55 @@ int GraphNode::get_connection_input_count() {
_connpos_update();
}
return conn_input_cache.size();
return left_port_cache.size();
}
int GraphNode::get_connection_input_height(int p_idx) {
int GraphNode::get_connection_input_height(int p_port) {
if (connpos_dirty) {
_connpos_update();
}
ERR_FAIL_INDEX_V(p_idx, conn_input_cache.size(), 0);
return conn_input_cache[p_idx].height;
ERR_FAIL_INDEX_V(p_port, left_port_cache.size(), 0);
return left_port_cache[p_port].height;
}
Vector2 GraphNode::get_connection_input_position(int p_idx) {
Vector2 GraphNode::get_connection_input_position(int p_port) {
if (connpos_dirty) {
_connpos_update();
}
ERR_FAIL_INDEX_V(p_idx, conn_input_cache.size(), Vector2());
Vector2 pos = conn_input_cache[p_idx].pos;
ERR_FAIL_INDEX_V(p_port, left_port_cache.size(), Vector2());
Vector2 pos = left_port_cache[p_port].position;
pos.x *= get_scale().x;
pos.y *= get_scale().y;
return pos;
}
int GraphNode::get_connection_input_type(int p_idx) {
int GraphNode::get_connection_input_type(int p_port) {
if (connpos_dirty) {
_connpos_update();
}
ERR_FAIL_INDEX_V(p_idx, conn_input_cache.size(), 0);
return conn_input_cache[p_idx].type;
ERR_FAIL_INDEX_V(p_port, left_port_cache.size(), 0);
return left_port_cache[p_port].type;
}
Color GraphNode::get_connection_input_color(int p_idx) {
Color GraphNode::get_connection_input_color(int p_port) {
if (connpos_dirty) {
_connpos_update();
}
ERR_FAIL_INDEX_V(p_idx, conn_input_cache.size(), Color());
return conn_input_cache[p_idx].color;
ERR_FAIL_INDEX_V(p_port, left_port_cache.size(), Color());
return left_port_cache[p_port].color;
}
int GraphNode::get_connection_input_slot(int p_port) {
if (connpos_dirty) {
_connpos_update();
}
ERR_FAIL_INDEX_V(p_port, left_port_cache.size(), -1);
return left_port_cache[p_port].slot_idx;
}
int GraphNode::get_connection_output_count() {
@ -878,46 +893,55 @@ int GraphNode::get_connection_output_count() {
_connpos_update();
}
return conn_output_cache.size();
return right_port_cache.size();
}
int GraphNode::get_connection_output_height(int p_idx) {
int GraphNode::get_connection_output_height(int p_port) {
if (connpos_dirty) {
_connpos_update();
}
ERR_FAIL_INDEX_V(p_idx, conn_output_cache.size(), 0);
return conn_output_cache[p_idx].height;
ERR_FAIL_INDEX_V(p_port, right_port_cache.size(), 0);
return right_port_cache[p_port].height;
}
Vector2 GraphNode::get_connection_output_position(int p_idx) {
Vector2 GraphNode::get_connection_output_position(int p_port) {
if (connpos_dirty) {
_connpos_update();
}
ERR_FAIL_INDEX_V(p_idx, conn_output_cache.size(), Vector2());
Vector2 pos = conn_output_cache[p_idx].pos;
ERR_FAIL_INDEX_V(p_port, right_port_cache.size(), Vector2());
Vector2 pos = right_port_cache[p_port].position;
pos.x *= get_scale().x;
pos.y *= get_scale().y;
return pos;
}
int GraphNode::get_connection_output_type(int p_idx) {
int GraphNode::get_connection_output_type(int p_port) {
if (connpos_dirty) {
_connpos_update();
}
ERR_FAIL_INDEX_V(p_idx, conn_output_cache.size(), 0);
return conn_output_cache[p_idx].type;
ERR_FAIL_INDEX_V(p_port, right_port_cache.size(), 0);
return right_port_cache[p_port].type;
}
Color GraphNode::get_connection_output_color(int p_idx) {
Color GraphNode::get_connection_output_color(int p_port) {
if (connpos_dirty) {
_connpos_update();
}
ERR_FAIL_INDEX_V(p_idx, conn_output_cache.size(), Color());
return conn_output_cache[p_idx].color;
ERR_FAIL_INDEX_V(p_port, right_port_cache.size(), Color());
return right_port_cache[p_port].color;
}
int GraphNode::get_connection_output_slot(int p_port) {
if (connpos_dirty) {
_connpos_update();
}
ERR_FAIL_INDEX_V(p_port, right_port_cache.size(), -1);
return right_port_cache[p_port].slot_idx;
}
void GraphNode::gui_input(const Ref<InputEvent> &p_ev) {
@ -1050,30 +1074,30 @@ void GraphNode::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_language", "language"), &GraphNode::set_language);
ClassDB::bind_method(D_METHOD("get_language"), &GraphNode::get_language);
ClassDB::bind_method(D_METHOD("set_slot", "idx", "enable_left", "type_left", "color_left", "enable_right", "type_right", "color_right", "custom_left", "custom_right", "enable"), &GraphNode::set_slot, DEFVAL(Ref<Texture2D>()), DEFVAL(Ref<Texture2D>()), DEFVAL(true));
ClassDB::bind_method(D_METHOD("clear_slot", "idx"), &GraphNode::clear_slot);
ClassDB::bind_method(D_METHOD("set_slot", "slot_index", "enable_left_port", "type_left", "color_left", "enable_right_port", "type_right", "color_right", "custom_icon_left", "custom_icon_right", "draw_stylebox"), &GraphNode::set_slot, DEFVAL(Ref<Texture2D>()), DEFVAL(Ref<Texture2D>()), DEFVAL(true));
ClassDB::bind_method(D_METHOD("clear_slot", "slot_index"), &GraphNode::clear_slot);
ClassDB::bind_method(D_METHOD("clear_all_slots"), &GraphNode::clear_all_slots);
ClassDB::bind_method(D_METHOD("is_slot_enabled_left", "idx"), &GraphNode::is_slot_enabled_left);
ClassDB::bind_method(D_METHOD("set_slot_enabled_left", "idx", "enable_left"), &GraphNode::set_slot_enabled_left);
ClassDB::bind_method(D_METHOD("set_slot_enabled_left", "slot_index", "enable"), &GraphNode::set_slot_enabled_left);
ClassDB::bind_method(D_METHOD("is_slot_enabled_left", "slot_index"), &GraphNode::is_slot_enabled_left);
ClassDB::bind_method(D_METHOD("set_slot_type_left", "idx", "type_left"), &GraphNode::set_slot_type_left);
ClassDB::bind_method(D_METHOD("get_slot_type_left", "idx"), &GraphNode::get_slot_type_left);
ClassDB::bind_method(D_METHOD("set_slot_type_left", "slot_index", "type"), &GraphNode::set_slot_type_left);
ClassDB::bind_method(D_METHOD("get_slot_type_left", "slot_index"), &GraphNode::get_slot_type_left);
ClassDB::bind_method(D_METHOD("set_slot_color_left", "idx", "color_left"), &GraphNode::set_slot_color_left);
ClassDB::bind_method(D_METHOD("get_slot_color_left", "idx"), &GraphNode::get_slot_color_left);
ClassDB::bind_method(D_METHOD("set_slot_color_left", "slot_index", "color"), &GraphNode::set_slot_color_left);
ClassDB::bind_method(D_METHOD("get_slot_color_left", "slot_index"), &GraphNode::get_slot_color_left);
ClassDB::bind_method(D_METHOD("is_slot_enabled_right", "idx"), &GraphNode::is_slot_enabled_right);
ClassDB::bind_method(D_METHOD("set_slot_enabled_right", "idx", "enable_right"), &GraphNode::set_slot_enabled_right);
ClassDB::bind_method(D_METHOD("set_slot_enabled_right", "slot_index", "enable"), &GraphNode::set_slot_enabled_right);
ClassDB::bind_method(D_METHOD("is_slot_enabled_right", "slot_index"), &GraphNode::is_slot_enabled_right);
ClassDB::bind_method(D_METHOD("set_slot_type_right", "idx", "type_right"), &GraphNode::set_slot_type_right);
ClassDB::bind_method(D_METHOD("get_slot_type_right", "idx"), &GraphNode::get_slot_type_right);
ClassDB::bind_method(D_METHOD("set_slot_type_right", "slot_index", "type"), &GraphNode::set_slot_type_right);
ClassDB::bind_method(D_METHOD("get_slot_type_right", "slot_index"), &GraphNode::get_slot_type_right);
ClassDB::bind_method(D_METHOD("set_slot_color_right", "idx", "color_right"), &GraphNode::set_slot_color_right);
ClassDB::bind_method(D_METHOD("get_slot_color_right", "idx"), &GraphNode::get_slot_color_right);
ClassDB::bind_method(D_METHOD("set_slot_color_right", "slot_index", "color"), &GraphNode::set_slot_color_right);
ClassDB::bind_method(D_METHOD("get_slot_color_right", "slot_index"), &GraphNode::get_slot_color_right);
ClassDB::bind_method(D_METHOD("is_slot_draw_stylebox", "idx"), &GraphNode::is_slot_draw_stylebox);
ClassDB::bind_method(D_METHOD("set_slot_draw_stylebox", "idx", "draw_stylebox"), &GraphNode::set_slot_draw_stylebox);
ClassDB::bind_method(D_METHOD("is_slot_draw_stylebox", "slot_index"), &GraphNode::is_slot_draw_stylebox);
ClassDB::bind_method(D_METHOD("set_slot_draw_stylebox", "slot_index", "enable"), &GraphNode::set_slot_draw_stylebox);
ClassDB::bind_method(D_METHOD("set_position_offset", "offset"), &GraphNode::set_position_offset);
ClassDB::bind_method(D_METHOD("get_position_offset"), &GraphNode::get_position_offset);
@ -1094,16 +1118,18 @@ void GraphNode::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_selected"), &GraphNode::is_selected);
ClassDB::bind_method(D_METHOD("get_connection_input_count"), &GraphNode::get_connection_input_count);
ClassDB::bind_method(D_METHOD("get_connection_input_height", "idx"), &GraphNode::get_connection_input_height);
ClassDB::bind_method(D_METHOD("get_connection_input_position", "idx"), &GraphNode::get_connection_input_position);
ClassDB::bind_method(D_METHOD("get_connection_input_type", "idx"), &GraphNode::get_connection_input_type);
ClassDB::bind_method(D_METHOD("get_connection_input_color", "idx"), &GraphNode::get_connection_input_color);
ClassDB::bind_method(D_METHOD("get_connection_input_height", "port"), &GraphNode::get_connection_input_height);
ClassDB::bind_method(D_METHOD("get_connection_input_position", "port"), &GraphNode::get_connection_input_position);
ClassDB::bind_method(D_METHOD("get_connection_input_type", "port"), &GraphNode::get_connection_input_type);
ClassDB::bind_method(D_METHOD("get_connection_input_color", "port"), &GraphNode::get_connection_input_color);
ClassDB::bind_method(D_METHOD("get_connection_input_slot", "port"), &GraphNode::get_connection_input_slot);
ClassDB::bind_method(D_METHOD("get_connection_output_count"), &GraphNode::get_connection_output_count);
ClassDB::bind_method(D_METHOD("get_connection_output_height", "idx"), &GraphNode::get_connection_output_height);
ClassDB::bind_method(D_METHOD("get_connection_output_position", "idx"), &GraphNode::get_connection_output_position);
ClassDB::bind_method(D_METHOD("get_connection_output_type", "idx"), &GraphNode::get_connection_output_type);
ClassDB::bind_method(D_METHOD("get_connection_output_color", "idx"), &GraphNode::get_connection_output_color);
ClassDB::bind_method(D_METHOD("get_connection_output_height", "port"), &GraphNode::get_connection_output_height);
ClassDB::bind_method(D_METHOD("get_connection_output_position", "port"), &GraphNode::get_connection_output_position);
ClassDB::bind_method(D_METHOD("get_connection_output_type", "port"), &GraphNode::get_connection_output_type);
ClassDB::bind_method(D_METHOD("get_connection_output_color", "port"), &GraphNode::get_connection_output_color);
ClassDB::bind_method(D_METHOD("get_connection_output_slot", "port"), &GraphNode::get_connection_output_slot);
ClassDB::bind_method(D_METHOD("set_show_close_button", "show"), &GraphNode::set_show_close_button);
ClassDB::bind_method(D_METHOD("is_close_button_visible"), &GraphNode::is_close_button_visible);

View file

@ -78,15 +78,17 @@ private:
Vector<int> cache_y;
struct ConnCache {
Vector2 pos;
struct PortCache {
Vector2 position;
int height;
int slot_idx;
int type = 0;
Color color;
int height;
};
Vector<ConnCache> conn_input_cache;
Vector<ConnCache> conn_output_cache;
Vector<PortCache> left_port_cache;
Vector<PortCache> right_port_cache;
HashMap<int, Slot> slot_info;
@ -165,16 +167,18 @@ public:
bool is_close_button_visible() const;
int get_connection_input_count();
int get_connection_input_height(int p_idx);
Vector2 get_connection_input_position(int p_idx);
int get_connection_input_type(int p_idx);
Color get_connection_input_color(int p_idx);
int get_connection_input_height(int p_port);
Vector2 get_connection_input_position(int p_port);
int get_connection_input_type(int p_port);
Color get_connection_input_color(int p_port);
int get_connection_input_slot(int p_port);
int get_connection_output_count();
int get_connection_output_height(int p_idx);
Vector2 get_connection_output_position(int p_idx);
int get_connection_output_type(int p_idx);
Color get_connection_output_color(int p_idx);
int get_connection_output_height(int p_port);
Vector2 get_connection_output_position(int p_port);
int get_connection_output_type(int p_port);
Color get_connection_output_color(int p_port);
int get_connection_output_slot(int p_port);
void set_overlay(Overlay p_overlay);
Overlay get_overlay() const;