From a81561cbd960d4787ea0dbd68f60f0af67323721 Mon Sep 17 00:00:00 2001 From: Hendrik Brucker Date: Wed, 7 Feb 2024 02:37:26 +0100 Subject: [PATCH] Add GraphFrame and integrate it in VisualShader --- doc/classes/GraphEdit.xml | 44 + doc/classes/GraphElement.xml | 10 +- doc/classes/GraphFrame.xml | 66 ++ doc/classes/VisualShader.xml | 17 + doc/classes/VisualShaderNode.xml | 3 + doc/classes/VisualShaderNodeComment.xml | 19 - doc/classes/VisualShaderNodeFrame.xml | 46 + editor/icons/GraphFrame.svg | 1 + .../animation_blend_tree_editor_plugin.cpp | 6 +- .../plugins/visual_shader_editor_plugin.cpp | 812 ++++++++++++++---- editor/plugins/visual_shader_editor_plugin.h | 59 +- editor/themes/editor_theme_manager.cpp | 37 +- .../4.2-stable.expected | 7 + scene/animation/animation_tree.cpp | 4 +- scene/animation/animation_tree.h | 4 +- scene/gui/graph_edit.cpp | 421 ++++++++- scene/gui/graph_edit.h | 30 +- scene/gui/graph_element.cpp | 9 +- scene/gui/graph_frame.cpp | 357 ++++++++ scene/gui/graph_frame.h | 108 +++ scene/gui/graph_node.h | 6 +- scene/register_scene_types.cpp | 4 +- scene/resources/visual_shader.cpp | 153 +++- scene/resources/visual_shader.h | 41 +- scene/theme/default_theme.cpp | 30 + 25 files changed, 1996 insertions(+), 298 deletions(-) create mode 100644 doc/classes/GraphFrame.xml delete mode 100644 doc/classes/VisualShaderNodeComment.xml create mode 100644 doc/classes/VisualShaderNodeFrame.xml create mode 100644 editor/icons/GraphFrame.svg create mode 100644 scene/gui/graph_frame.cpp create mode 100644 scene/gui/graph_frame.h diff --git a/doc/classes/GraphEdit.xml b/doc/classes/GraphEdit.xml index 18469b00a84..001839d7452 100644 --- a/doc/classes/GraphEdit.xml +++ b/doc/classes/GraphEdit.xml @@ -109,6 +109,14 @@ Rearranges selected nodes in a layout with minimum crossings between connections and uniform horizontal and vertical gap between nodes. + + + + + + Attaches the [param element] [GraphElement] to the [param frame] [GraphFrame]. + + @@ -125,6 +133,13 @@ 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. + + + + + Detaches the [param element] [GraphElement] from the [GraphFrame] it is currently attached to. + + @@ -143,6 +158,13 @@ [b]Note:[/b] This method suppresses any other connection request signals apart from [signal connection_drag_ended]. + + + + + Returns an array of node names that are attached to the [GraphFrame] with the given name. + + @@ -179,6 +201,13 @@ Returns an [Array] containing the list of connections that intersect with the given [Rect2]. A connection consists in a structure of the form [code]{ from_port: 0, from_node: "GraphNode name 0", to_port: 1, to_node: "GraphNode name 1" }[/code]. + + + + + Returns the [GraphFrame] that contains the [GraphElement] with the given name. + + @@ -395,6 +424,21 @@ Emitted at the end of a [GraphElement]'s movement. + + + + + Emitted when the [GraphFrame] [param frame] is resized to [param new_rect]. + + + + + + + Emitted when one or more [GraphElement]s are dropped onto the [GraphFrame] named [param frame], when they were not previously attached to any other one. + [param elements] is an array of [GraphElement]s to be attached. + + diff --git a/doc/classes/GraphElement.xml b/doc/classes/GraphElement.xml index 17c4184a20b..7cd6496773f 100644 --- a/doc/classes/GraphElement.xml +++ b/doc/classes/GraphElement.xml @@ -17,7 +17,7 @@ If [code]true[/code], the user can resize the GraphElement. - [b]Note:[/b] Dragging the handle will only emit the [signal resize_request] signal, the GraphElement needs to be resized manually. + [b]Note:[/b] Dragging the handle will only emit the [signal resize_request] and [signal resize_end] signals, the GraphElement needs to be resized manually. If [code]true[/code], the user can select the GraphElement. @@ -59,8 +59,14 @@ Emitted when displaying the GraphElement over other ones is requested. Happens on focusing (clicking into) the GraphElement. + + + + Emitted when releasing the mouse button after dragging the resizer handle (see [member resizable]). + + - + Emitted when resizing the GraphElement is requested. Happens on dragging the resizer handle (see [member resizable]). diff --git a/doc/classes/GraphFrame.xml b/doc/classes/GraphFrame.xml new file mode 100644 index 00000000000..52bb451d957 --- /dev/null +++ b/doc/classes/GraphFrame.xml @@ -0,0 +1,66 @@ + + + + GraphFrame is a special [GraphElement] that can be used to organize other [GraphElement]s inside a [GraphEdit]. + + + GraphFrame is a special [GraphElement] to which other [GraphElement]s can be attached. It can be configured to automatically resize to enclose all attached [GraphElement]s. If the frame is moved, all the attached [GraphElement]s inside it will be moved as well. + A GraphFrame is always kept behind the connection layer and other [GraphElement]s inside a [GraphEdit]. + + + + + + + + Returns the [HBoxContainer] used for the title bar, only containing a [Label] for displaying the title by default. + This can be used to add custom controls to the title bar such as option or close buttons. + + + + + + If [code]true[/code], the frame's rect will be adjusted automatically to enclose all attached [GraphElement]s. + + + The margin around the attached nodes that is used to calculate the size of the frame when [member autoshrink_enabled] is [code]true[/code]. + + + The margin inside the frame that can be used to drag the frame. + + + + The color of the frame when [member tint_color_enabled] is [code]true[/code]. + + + If [code]true[/code], the tint color will be used to tint the frame. + + + Title of the frame. + + + + + + Emitted when [member autoshrink_enabled] or [member autoshrink_margin] changes. + + + + + + The color modulation applied to the resizer icon. + + + The default [StyleBox] used for the background of the [GraphFrame]. + + + The [StyleBox] used for the background of the [GraphFrame] when it is selected. + + + The [StyleBox] used for the title bar of the [GraphFrame]. + + + The [StyleBox] used for the title bar of the [GraphFrame] when it is selected. + + + diff --git a/doc/classes/VisualShader.xml b/doc/classes/VisualShader.xml index 0b416214b53..c8230d94e4a 100644 --- a/doc/classes/VisualShader.xml +++ b/doc/classes/VisualShader.xml @@ -29,6 +29,15 @@ Adds a new varying value node to the shader. + + + + + + + Attaches the given node to the given frame. + + @@ -62,6 +71,14 @@ Connects the specified nodes and ports, even if they can't be connected. Such connection is invalid and will not function properly. + + + + + + Detaches the given node from the frame it is attached to. + + diff --git a/doc/classes/VisualShaderNode.xml b/doc/classes/VisualShaderNode.xml index cc6394e2da7..5b82d202462 100644 --- a/doc/classes/VisualShaderNode.xml +++ b/doc/classes/VisualShaderNode.xml @@ -61,6 +61,9 @@ + + Represents the index of the frame this node is linked to. If set to [code]-1[/code] the node is not linked to any frame. + Sets the output port index which will be showed for preview. If set to [code]-1[/code] no port will be open for preview. diff --git a/doc/classes/VisualShaderNodeComment.xml b/doc/classes/VisualShaderNodeComment.xml deleted file mode 100644 index b4063409b91..00000000000 --- a/doc/classes/VisualShaderNodeComment.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - A comment node to be placed on visual shader graph. - - - A resizable rectangular area with changeable [member title] and [member description] used for better organizing of other visual shader nodes. - - - - - - An additional description which placed below the title. - - - A title of the node. - - - diff --git a/doc/classes/VisualShaderNodeFrame.xml b/doc/classes/VisualShaderNodeFrame.xml new file mode 100644 index 00000000000..3126a56abe1 --- /dev/null +++ b/doc/classes/VisualShaderNodeFrame.xml @@ -0,0 +1,46 @@ + + + + A frame other visual shader nodes can be attached to for better organization. + + + A rectangular frame that can be used to group visual shader nodes together to improve organization. + Nodes attached to the frame will move with it when it is dragged and it can automatically resize to enclose all attached nodes. + Its title, description and color can be customized. + + + + + + + + + Adds a node to the list of nodes attached to the frame. Should not be called directly, use the [method VisualShader.attach_node_to_frame] method instead. + + + + + + + Removes a node from the list of nodes attached to the frame. Should not be called directly, use the [method VisualShader.detach_node_from_frame] method instead. + + + + + + The list of nodes attached to the frame. + + + If [code]true[/code], the frame will automatically resize to enclose all attached nodes. + + + The color of the frame when [member tint_color_enabled] is [code]true[/code]. + + + If [code]true[/code], the frame will be tinted with the color specified in [member tint_color]. + + + The title of the node. + + + diff --git a/editor/icons/GraphFrame.svg b/editor/icons/GraphFrame.svg new file mode 100644 index 00000000000..cd25c847561 --- /dev/null +++ b/editor/icons/GraphFrame.svg @@ -0,0 +1 @@ + diff --git a/editor/plugins/animation_blend_tree_editor_plugin.cpp b/editor/plugins/animation_blend_tree_editor_plugin.cpp index e75bb454aea..a7c64b79db1 100644 --- a/editor/plugins/animation_blend_tree_editor_plugin.cpp +++ b/editor/plugins/animation_blend_tree_editor_plugin.cpp @@ -170,7 +170,7 @@ void AnimationNodeBlendTreeEditor::update_graph() { name->connect("focus_exited", callable_mp(this, &AnimationNodeBlendTreeEditor::_node_renamed_focus_out).bind(agnode), CONNECT_DEFERRED); name->connect("text_changed", callable_mp(this, &AnimationNodeBlendTreeEditor::_node_rename_lineedit_changed), CONNECT_DEFERRED); base = 1; - agnode->set_closable(true); + agnode->set_deletable(true); if (!read_only) { Button *delete_button = memnew(Button); @@ -541,7 +541,7 @@ void AnimationNodeBlendTreeEditor::_delete_nodes_request(const TypedArray(graph->get_child(i)); if (gn && gn->is_selected()) { Ref anode = blend_tree->get_node(gn->get_name()); - if (anode->is_closable()) { + if (anode->is_deletable()) { to_erase.push_back(gn->get_name()); } } @@ -549,7 +549,7 @@ void AnimationNodeBlendTreeEditor::_delete_nodes_request(const TypedArray anode = blend_tree->get_node(p_nodes[i]); - if (anode->is_closable()) { + if (anode->is_deletable()) { to_erase.push_back(p_nodes[i]); } } diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp index c83c47577d3..71af1dadd9e 100644 --- a/editor/plugins/visual_shader_editor_plugin.cpp +++ b/editor/plugins/visual_shader_editor_plugin.cpp @@ -48,6 +48,7 @@ #include "scene/gui/button.h" #include "scene/gui/check_box.h" #include "scene/gui/code_edit.h" +#include "scene/gui/color_picker.h" #include "scene/gui/graph_edit.h" #include "scene/gui/menu_button.h" #include "scene/gui/option_button.h" @@ -120,6 +121,11 @@ void VisualShaderGraphPlugin::_bind_methods() { ClassDB::bind_method("set_expression", &VisualShaderGraphPlugin::set_expression); ClassDB::bind_method("update_curve", &VisualShaderGraphPlugin::update_curve); ClassDB::bind_method("update_curve_xyz", &VisualShaderGraphPlugin::update_curve_xyz); + ClassDB::bind_method(D_METHOD("attach_node_to_frame", "type", "id", "frame"), &VisualShaderGraphPlugin::attach_node_to_frame); + ClassDB::bind_method(D_METHOD("detach_node_from_frame", "type", "id"), &VisualShaderGraphPlugin::detach_node_from_frame); + ClassDB::bind_method(D_METHOD("set_frame_color_enabled", "type", "id", "enabled"), &VisualShaderGraphPlugin::set_frame_color_enabled); + ClassDB::bind_method(D_METHOD("set_frame_color", "type", "id", "color"), &VisualShaderGraphPlugin::set_frame_color); + ClassDB::bind_method(D_METHOD("set_frame_autoshrink_enabled", "type", "id", "enabled"), &VisualShaderGraphPlugin::set_frame_autoshrink_enabled); } void VisualShaderGraphPlugin::set_editor(VisualShaderEditor *p_editor) { @@ -191,7 +197,9 @@ void VisualShaderGraphPlugin::update_node(VisualShader::Type p_type, int p_node_ return; } remove_node(p_type, p_node_id, true); - add_node(p_type, p_node_id, true); + add_node(p_type, p_node_id, true, true); + + // TODO: Restore focus here? } void VisualShaderGraphPlugin::set_input_port_default_value(VisualShader::Type p_type, int p_node_id, int p_port_id, const Variant &p_value) { @@ -282,6 +290,92 @@ void VisualShaderGraphPlugin::set_expression(VisualShader::Type p_type, int p_no links[p_node_id].expression_edit->set_text(p_expression); } +void VisualShaderGraphPlugin::attach_node_to_frame(VisualShader::Type p_type, int p_node_id, int p_frame_id) { + if (p_type != visual_shader->get_shader_type() || !links.has(p_node_id) || !links.has(p_frame_id)) { + return; + } + + GraphEdit *graph = editor->graph; + if (!graph) { + return; + } + + // Get the hint label and hide it before attaching the node to prevent resizing issues with the frame. + GraphFrame *frame = Object::cast_to(links[p_frame_id].graph_element); + ERR_FAIL_COND_MSG(!frame, "VisualShader node to attach to is not a frame node."); + + Label *frame_hint_label = Object::cast_to