Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GH-463 Adapt comment nodes to use GraphFrame #464

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
115 changes: 102 additions & 13 deletions src/editor/graph/graph_edit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
#include "editor/graph/graph_node_pin.h"
#include "editor/graph/graph_node_spawner.h"
#include "editor/graph/nodes/graph_node_comment.h"
#include "nodes/graph_node_factory.h"
#include "editor/graph/nodes/graph_node_default.h"
#include "script/language.h"
#include "script/nodes/script_nodes.h"
#include "script/script.h"
Expand Down Expand Up @@ -252,6 +252,9 @@ void OrchestratorGraphEdit::_notification(int p_what)
connect("copy_nodes_request", callable_mp(this, &OrchestratorGraphEdit::_on_copy_nodes_request));
connect("duplicate_nodes_request", callable_mp(this, &OrchestratorGraphEdit::_on_duplicate_nodes_request));
connect("paste_nodes_request", callable_mp(this, &OrchestratorGraphEdit::_on_paste_nodes_request));
#if GODOT_VERSION >= 0x040300
connect("graph_elements_linked_to_frame_request", callable_mp(this, &OrchestratorGraphEdit::_on_attach_to_frame));
#endif

_context_menu->connect("id_pressed", callable_mp(this, &OrchestratorGraphEdit::_on_context_menu_selection));

Expand Down Expand Up @@ -365,11 +368,7 @@ void OrchestratorGraphEdit::goto_class_help(const String& p_class_name)

void OrchestratorGraphEdit::for_each_graph_node(std::function<void(OrchestratorGraphNode*)> p_func)
{
for (int i = 0; i < get_child_count(); i++)
{
if (OrchestratorGraphNode* node = Object::cast_to<OrchestratorGraphNode>(get_child(i)))
p_func(node);
}
for_each_child_type<OrchestratorGraphNode>(p_func);
}

void OrchestratorGraphEdit::execute_action(const String& p_action_name)
Expand Down Expand Up @@ -1223,7 +1222,7 @@ void OrchestratorGraphEdit::_remove_connection_knots(uint64_t p_connection_id)
}
}

void OrchestratorGraphEdit::_synchronize_graph_node(Ref<OScriptNode> p_node)
void OrchestratorGraphEdit::_synchronize_graph_node(const Ref<OScriptNode>& p_node)
{
if (!p_node.is_valid())
return;
Expand All @@ -1233,11 +1232,32 @@ void OrchestratorGraphEdit::_synchronize_graph_node(Ref<OScriptNode> p_node)
{
const Vector2 node_size = p_node->get_size();

OrchestratorGraphNode* graph_node = OrchestratorGraphNodeFactory::create_node(this, p_node);
graph_node->set_title(p_node->get_node_title());
graph_node->set_position_offset(p_node->get_position());
graph_node->set_size(node_size.is_zero_approx() ? graph_node->get_size() : node_size);
add_child(graph_node);
Ref<OScriptNodeComment> comment = p_node;
if (comment.is_valid())
{
#if GODOT_VERSION >= 0x040300
OrchestratorGraphFrameComment* frame = memnew(OrchestratorGraphFrameComment(this, p_node));
frame->set_title(p_node->get_node_title());
frame->set_position_offset(p_node->get_position());
frame->set_size(node_size.is_zero_approx() ? frame->get_size() : node_size);
frame->set_name(vformat("%s", node_id));
add_child(frame);
#else
OrchestratorGraphNodeComment* node = memnew(OrchestratorGraphNodeComment(this, p_node));
node->set_title(p_node->get_node_title());
node->set_position_offset(p_node->get_position());
node->set_size(node_size.is_zero_approx() ? node->get_size() : node_size);
add_child(node);
#endif
}
else
{
OrchestratorGraphNode* graph_node = memnew(OrchestratorGraphNodeDefault(this, p_node));
graph_node->set_title(p_node->get_node_title());
graph_node->set_position_offset(p_node->get_position());
graph_node->set_size(node_size.is_zero_approx() ? graph_node->get_size() : node_size);
add_child(graph_node);
}
}
else
{
Expand All @@ -1256,6 +1276,51 @@ void OrchestratorGraphEdit::_synchronize_child_order()
comment->call_deferred("raise_request_node_reorder");
}
});

#if GODOT_VERSION >= 0x040300
// Performs a small update synchronization step for comment nodes to track their frame attachments
bool any_upgraded = false;
for_each_child_type<OrchestratorGraphFrameComment>([&, this](OrchestratorGraphFrameComment* frame) {
Ref<OScriptNodeComment> comment = frame->get_comment_node();
if (comment.is_valid())
{
if (comment->get_state() == OScriptNodeComment::State_Initial)
{
// Collect a list of nodes that overlap but are not attached to the frame
Vector<StringName> overlaps;
for_each_child_type<OrchestratorGraphNode>([&](OrchestratorGraphNode* node) {
if (frame->get_rect().intersects(node->get_rect()))
overlaps.push_back(node->get_name());
});

// Compare existing attachments with overlaps
PackedInt64Array attachment_node_ids;
for (const StringName& overlap : overlaps)
{
if (OrchestratorGraphNode* node = _get_by_name<OrchestratorGraphNode>(overlap))
{
attach_graph_element_to_frame(overlap, frame->get_name());
attachment_node_ids.push_back(node->get_script_node_id());
}
}

// Update attachment list
comment->set_attachments(attachment_node_ids);
any_upgraded = true;
}
else if (comment->get_state() >= OScriptNodeComment::State_Tracks_Attachments)
{
const PackedInt64Array attachments = comment->get_attachments();
for (int i = 0; i < attachments.size(); i++)
attach_graph_element_to_frame(itos(attachments[i]), frame->get_name());
}
}
});

if (any_upgraded)
UtilityFunctions::print(get_orchestration()->get_self()->get_path(), ": Graph '", _script_graph->get_graph_name(), "': Comment nodes have been upgraded to GraphFrame(s).");

#endif
}

void OrchestratorGraphEdit::_complete_spawn(const Ref<OScriptNode>& p_spawned, const Callable& p_callback)
Expand Down Expand Up @@ -1578,15 +1643,21 @@ void OrchestratorGraphEdit::_on_node_selected(Node* p_node)
return;

OrchestratorGraphNode* graph_node = Object::cast_to<OrchestratorGraphNode>(p_node);
#if GODOT_VERSION >= 0x040300
OrchestratorGraphFrameComment* frame_node = Object::cast_to<OrchestratorGraphFrameComment>(p_node);
if (!graph_node && !frame_node)
return;
#else
if (!graph_node)
return;
#endif

Ref<OScriptNode> node = p_node->get_meta("__script_node");
if (node.is_null())
return;

OrchestratorSettings* os = OrchestratorSettings::get_singleton();
if (os->get_setting("ui/nodes/highlight_selected_connections", false))
if (os->get_setting("ui/nodes/highlight_selected_connections", false) && !frame_node)
{
// Get list of all selected nodes
List<Ref<OScriptNode>> selected_nodes;
Expand Down Expand Up @@ -2035,4 +2106,22 @@ void OrchestratorGraphEdit::_on_grid_style_selected(int p_index)
const GridPattern pattern = static_cast<GridPattern>(int(_grid_pattern->get_item_metadata(p_index)));
set_grid_pattern(pattern);
}

void OrchestratorGraphEdit::_on_attach_to_frame(const TypedArray<StringName>& p_elements, const StringName& p_frame_name)
{
for (int i = 0; i < p_elements.size(); i++)
{
OrchestratorGraphFrameComment* frame = _get_by_name<OrchestratorGraphFrameComment>(p_frame_name);
OrchestratorGraphNode* node = _get_by_name<OrchestratorGraphNode>(p_elements[i]);
if (frame && node)
{
PackedInt64Array attachments = frame->get_comment_node()->get_attachments();
attachments.push_back(node->get_script_node_id());

attach_graph_element_to_frame(p_elements[i], p_frame_name);
frame->get_comment_node()->set_attachments(attachments);
}
}
}

#endif
21 changes: 20 additions & 1 deletion src/editor/graph/graph_edit.h
Original file line number Diff line number Diff line change
Expand Up @@ -207,8 +207,22 @@ class OrchestratorGraphEdit : public GraphEdit

/// Perform an action for each graph node
/// @param p_func the lambda to be applied
/// @deprecated use for_each_child_type
void for_each_graph_node(std::function<void(OrchestratorGraphNode*)> p_func);

/// Perform an action for each child type
/// @tparam T the child class type to only operate on
/// @param p_func the lambda to be applied
template <typename T>
void for_each_child_type(std::function<void(T*)> p_func)
{
for (int i = 0; i < get_child_count(); i++)
{
if (T* child = Object::cast_to<T>(get_child(i)))
p_func(child);
}
}

/// Execute the specified action
/// @param p_action_name the action to execute
void execute_action(const String& p_action_name);
Expand Down Expand Up @@ -338,7 +352,7 @@ class OrchestratorGraphEdit : public GraphEdit

/// Updates only the specific graph node
/// @param p_node the node to update.
void _synchronize_graph_node(Ref<OScriptNode> p_node);
void _synchronize_graph_node(const Ref<OScriptNode>& p_node);

/// Synchronizes the child order
void _synchronize_child_order();
Expand Down Expand Up @@ -486,6 +500,11 @@ class OrchestratorGraphEdit : public GraphEdit
/// Dispatched when a grid style option is selected
/// @param p_index the selected item index
void _on_grid_style_selected(int p_index);

/// Dispatched when dragging nodes to be attached to a frame
/// @param p_elements graph elements to be attached
/// @param p_frame_name the frame name to be linked
void _on_attach_to_frame(const TypedArray<StringName>& p_elements, const StringName& p_frame_name);
#endif
};

Expand Down
18 changes: 18 additions & 0 deletions src/editor/graph/graph_node.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include "script/nodes/functions/call_function.h"
#include "script/nodes/functions/call_script_function.h"
#include "script/nodes/variables/variable_get.h"
#include "script/nodes/utilities/comment.h"
#include "script/script.h"

#include <godot_cpp/classes/button.hpp>
Expand Down Expand Up @@ -491,6 +492,17 @@ void OrchestratorGraphNode::_show_context_menu(const Vector2& p_position)
#endif

#if GODOT_VERSION >= 0x040300
Ref<OScriptNodeComment> comment = _node;
if (comment.is_null())
{
// Anything but comments
if (GraphFrame* frame = get_graph()->get_element_frame(get_name()))
{
bool multiple = get_graph()->get_selected_nodes().size() > 1;
_context_menu->add_item(vformat("Detach %s from comment frame", multiple ? "selected nodes" : "node"), CM_DETACH_FRAME);
}
}

if (!multi_selections)
{
_context_menu->add_separator("Breakpoints");
Expand Down Expand Up @@ -820,6 +832,12 @@ void OrchestratorGraphNode::_handle_context_menu(int p_id)
_set_breakpoint_state(OScriptNode::BreakpointFlags::BREAKPOINT_DISABLED);
break;
}
case CM_DETACH_FRAME:
{
for (OrchestratorGraphNode* selected : get_graph()->get_selected_nodes())
get_graph()->detach_graph_element_from_frame(selected->get_name());
break;
}
#endif
case CM_ALIGN_TOP:
{
Expand Down
1 change: 1 addition & 0 deletions src/editor/graph/graph_node.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ class OrchestratorGraphNode : public GraphNode
CM_ALIGN_LEFT,
CM_ALIGN_CENTER,
CM_ALIGN_RIGHT,
CM_DETACH_FRAME,
CM_NODE_ACTION = 1000
};

Expand Down
Loading
Loading