summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/classes/GraphEdit.xml3
-rw-r--r--doc/classes/GraphNode.xml12
-rw-r--r--editor/editor_spin_slider.cpp4
-rw-r--r--editor/plugins/animation_blend_space_1d_editor.cpp160
-rw-r--r--editor/plugins/animation_blend_space_1d_editor.h1
-rw-r--r--editor/plugins/animation_blend_space_2d_editor.cpp163
-rw-r--r--editor/plugins/animation_blend_space_2d_editor.h1
-rw-r--r--editor/plugins/animation_blend_tree_editor_plugin.cpp85
-rw-r--r--editor/plugins/animation_blend_tree_editor_plugin.h5
-rw-r--r--editor/plugins/animation_state_machine_editor.cpp77
-rw-r--r--editor/plugins/animation_state_machine_editor.h2
-rw-r--r--scene/gui/graph_edit.cpp78
-rw-r--r--scene/gui/graph_edit.h5
-rw-r--r--scene/gui/graph_node.cpp24
-rw-r--r--scene/gui/graph_node.h8
15 files changed, 426 insertions, 202 deletions
diff --git a/doc/classes/GraphEdit.xml b/doc/classes/GraphEdit.xml
index e5aa78971e..dc093acdcd 100644
--- a/doc/classes/GraphEdit.xml
+++ b/doc/classes/GraphEdit.xml
@@ -221,6 +221,9 @@
</method>
</methods>
<members>
+ <member name="arrange_nodes_button_hidden" type="bool" setter="set_arrange_nodes_button_hidden" getter="is_arrange_nodes_button_hidden" default="false">
+ If [code]true[/code], the Arrange Nodes button is hidden.
+ </member>
<member name="clip_contents" type="bool" setter="set_clip_contents" getter="is_clipping_contents" overrides="Control" default="true" />
<member name="connection_lines_antialiased" type="bool" setter="set_connection_lines_antialiased" getter="is_connection_lines_antialiased" default="true">
If [code]true[/code], the lines between nodes will use antialiasing.
diff --git a/doc/classes/GraphNode.xml b/doc/classes/GraphNode.xml
index 009c329ee2..ebd4525b19 100644
--- a/doc/classes/GraphNode.xml
+++ b/doc/classes/GraphNode.xml
@@ -156,7 +156,7 @@
<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.
+ [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.
@@ -208,7 +208,7 @@
<param index="0" name="idx" type="int" />
<param index="1" name="type_left" type="int" />
<description>
- Sets the left (input) type of the slot [param idx] to [param type_left].
+ 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.
</description>
</method>
<method name="set_slot_type_right">
@@ -216,7 +216,7 @@
<param index="0" name="idx" type="int" />
<param index="1" name="type_right" type="int" />
<description>
- Sets the right (output) type of the slot [param idx] to [param type_right].
+ 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.
</description>
</method>
</methods>
@@ -224,6 +224,9 @@
<member name="comment" type="bool" setter="set_comment" getter="is_comment" default="false">
If [code]true[/code], the GraphNode is a comment node.
</member>
+ <member name="draggable" type="bool" setter="set_draggable" getter="is_draggable" default="true">
+ If [code]true[/code], the user can drag the GraphNode.
+ </member>
<member name="language" type="String" setter="set_language" getter="get_language" default="&quot;&quot;">
Language code used for line-breaking and text shaping algorithms, if left empty current locale is used instead.
</member>
@@ -239,6 +242,9 @@
If [code]true[/code], the user can resize the GraphNode.
[b]Note:[/b] Dragging the handle will only emit the [signal resize_request] signal, the GraphNode needs to be resized manually.
</member>
+ <member name="selectable" type="bool" setter="set_selectable" getter="is_selectable" default="true">
+ If [code]true[/code], the user can select the GraphNode.
+ </member>
<member name="selected" type="bool" setter="set_selected" getter="is_selected" default="false">
If [code]true[/code], the GraphNode is selected.
</member>
diff --git a/editor/editor_spin_slider.cpp b/editor/editor_spin_slider.cpp
index 5b98460e8e..b9a3e9decf 100644
--- a/editor/editor_spin_slider.cpp
+++ b/editor/editor_spin_slider.cpp
@@ -149,6 +149,10 @@ void EditorSpinSlider::gui_input(const Ref<InputEvent> &p_event) {
}
void EditorSpinSlider::_grabber_gui_input(const Ref<InputEvent> &p_event) {
+ if (read_only) {
+ return;
+ }
+
Ref<InputEventMouseButton> mb = p_event;
if (grabbing_grabber) {
diff --git a/editor/plugins/animation_blend_space_1d_editor.cpp b/editor/plugins/animation_blend_space_1d_editor.cpp
index 2578099a9f..1cc4894b7d 100644
--- a/editor/plugins/animation_blend_space_1d_editor.cpp
+++ b/editor/plugins/animation_blend_space_1d_editor.cpp
@@ -48,7 +48,9 @@ void AnimationNodeBlendSpace1DEditor::_blend_space_gui_input(const Ref<InputEven
if (tool_select->is_pressed() && k.is_valid() && k->is_pressed() && k->get_keycode() == Key::KEY_DELETE && !k->is_echo()) {
if (selected_point != -1) {
- _erase_selected();
+ if (!read_only) {
+ _erase_selected();
+ }
accept_event();
}
}
@@ -56,62 +58,64 @@ void AnimationNodeBlendSpace1DEditor::_blend_space_gui_input(const Ref<InputEven
Ref<InputEventMouseButton> mb = p_event;
if (mb.is_valid() && mb->is_pressed() && ((tool_select->is_pressed() && mb->get_button_index() == MouseButton::RIGHT) || (mb->get_button_index() == MouseButton::LEFT && tool_create->is_pressed()))) {
- menu->clear();
- animations_menu->clear();
- animations_to_add.clear();
+ if (!read_only) {
+ menu->clear();
+ animations_menu->clear();
+ animations_to_add.clear();
- List<StringName> classes;
- ClassDB::get_inheriters_from_class("AnimationRootNode", &classes);
- classes.sort_custom<StringName::AlphCompare>();
+ List<StringName> classes;
+ ClassDB::get_inheriters_from_class("AnimationRootNode", &classes);
+ classes.sort_custom<StringName::AlphCompare>();
- menu->add_submenu_item(TTR("Add Animation"), "animations");
+ menu->add_submenu_item(TTR("Add Animation"), "animations");
- AnimationTree *gp = AnimationTreeEditor::get_singleton()->get_tree();
- ERR_FAIL_COND(!gp);
+ AnimationTree *gp = AnimationTreeEditor::get_singleton()->get_tree();
+ ERR_FAIL_COND(!gp);
- if (gp->has_node(gp->get_animation_player())) {
- AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(gp->get_node(gp->get_animation_player()));
+ if (gp->has_node(gp->get_animation_player())) {
+ AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(gp->get_node(gp->get_animation_player()));
- if (ap) {
- List<StringName> names;
- ap->get_animation_list(&names);
+ if (ap) {
+ List<StringName> names;
+ ap->get_animation_list(&names);
- for (const StringName &E : names) {
- animations_menu->add_icon_item(get_theme_icon(SNAME("Animation"), SNAME("EditorIcons")), E);
- animations_to_add.push_back(E);
+ for (const StringName &E : names) {
+ animations_menu->add_icon_item(get_theme_icon(SNAME("Animation"), SNAME("EditorIcons")), E);
+ animations_to_add.push_back(E);
+ }
}
}
- }
- for (const StringName &E : classes) {
- String name = String(E).replace_first("AnimationNode", "");
- if (name == "Animation" || name == "StartState" || name == "EndState") {
- continue;
- }
+ for (const StringName &E : classes) {
+ String name = String(E).replace_first("AnimationNode", "");
+ if (name == "Animation" || name == "StartState" || name == "EndState") {
+ continue;
+ }
- int idx = menu->get_item_count();
- menu->add_item(vformat(TTR("Add %s"), name), idx);
- menu->set_item_metadata(idx, E);
- }
+ int idx = menu->get_item_count();
+ menu->add_item(vformat(TTR("Add %s"), name), idx);
+ menu->set_item_metadata(idx, E);
+ }
- Ref<AnimationNode> clipb = EditorSettings::get_singleton()->get_resource_clipboard();
- if (clipb.is_valid()) {
+ Ref<AnimationNode> clipb = EditorSettings::get_singleton()->get_resource_clipboard();
+ if (clipb.is_valid()) {
+ menu->add_separator();
+ menu->add_item(TTR("Paste"), MENU_PASTE);
+ }
menu->add_separator();
- menu->add_item(TTR("Paste"), MENU_PASTE);
- }
- menu->add_separator();
- menu->add_item(TTR("Load..."), MENU_LOAD_FILE);
+ menu->add_item(TTR("Load..."), MENU_LOAD_FILE);
- menu->set_position(blend_space_draw->get_screen_position() + mb->get_position());
- menu->reset_size();
- menu->popup();
+ menu->set_position(blend_space_draw->get_screen_position() + mb->get_position());
+ menu->reset_size();
+ menu->popup();
- add_point_pos = (mb->get_position() / blend_space_draw->get_size()).x;
- add_point_pos *= (blend_space->get_max_space() - blend_space->get_min_space());
- add_point_pos += blend_space->get_min_space();
+ add_point_pos = (mb->get_position() / blend_space_draw->get_size()).x;
+ add_point_pos *= (blend_space->get_max_space() - blend_space->get_min_space());
+ add_point_pos += blend_space->get_min_space();
- if (snap->is_pressed()) {
- add_point_pos = Math::snapped(add_point_pos, blend_space->get_snap());
+ if (snap->is_pressed()) {
+ add_point_pos = Math::snapped(add_point_pos, blend_space->get_snap());
+ }
}
}
@@ -138,31 +142,33 @@ void AnimationNodeBlendSpace1DEditor::_blend_space_gui_input(const Ref<InputEven
}
if (mb.is_valid() && !mb->is_pressed() && dragging_selected_attempt && mb->get_button_index() == MouseButton::LEFT) {
- if (dragging_selected) {
- // move
- float point = blend_space->get_blend_point_position(selected_point);
- point += drag_ofs.x;
+ if (!read_only) {
+ if (dragging_selected) {
+ // move
+ float point = blend_space->get_blend_point_position(selected_point);
+ point += drag_ofs.x;
+
+ if (snap->is_pressed()) {
+ point = Math::snapped(point, blend_space->get_snap());
+ }
- if (snap->is_pressed()) {
- point = Math::snapped(point, blend_space->get_snap());
+ updating = true;
+ undo_redo->create_action(TTR("Move Node Point"));
+ undo_redo->add_do_method(blend_space.ptr(), "set_blend_point_position", selected_point, point);
+ undo_redo->add_undo_method(blend_space.ptr(), "set_blend_point_position", selected_point, blend_space->get_blend_point_position(selected_point));
+ undo_redo->add_do_method(this, "_update_space");
+ undo_redo->add_undo_method(this, "_update_space");
+ undo_redo->add_do_method(this, "_update_edited_point_pos");
+ undo_redo->add_undo_method(this, "_update_edited_point_pos");
+ undo_redo->commit_action();
+ updating = false;
+ _update_edited_point_pos();
}
- updating = true;
- undo_redo->create_action(TTR("Move Node Point"));
- undo_redo->add_do_method(blend_space.ptr(), "set_blend_point_position", selected_point, point);
- undo_redo->add_undo_method(blend_space.ptr(), "set_blend_point_position", selected_point, blend_space->get_blend_point_position(selected_point));
- undo_redo->add_do_method(this, "_update_space");
- undo_redo->add_undo_method(this, "_update_space");
- undo_redo->add_do_method(this, "_update_edited_point_pos");
- undo_redo->add_undo_method(this, "_update_edited_point_pos");
- undo_redo->commit_action();
- updating = false;
- _update_edited_point_pos();
+ dragging_selected_attempt = false;
+ dragging_selected = false;
+ blend_space_draw->update();
}
-
- dragging_selected_attempt = false;
- dragging_selected = false;
- blend_space_draw->update();
}
// *set* the blend
@@ -255,10 +261,12 @@ void AnimationNodeBlendSpace1DEditor::_blend_space_draw() {
for (int i = 0; i < blend_space->get_blend_point_count(); i++) {
float point = blend_space->get_blend_point_position(i);
- if (dragging_selected && selected_point == i) {
- point += drag_ofs.x;
- if (snap->is_pressed()) {
- point = Math::snapped(point, blend_space->get_snap());
+ if (!read_only) {
+ if (dragging_selected && selected_point == i) {
+ point += drag_ofs.x;
+ if (snap->is_pressed()) {
+ point = Math::snapped(point, blend_space->get_snap());
+ }
}
}
@@ -475,7 +483,7 @@ void AnimationNodeBlendSpace1DEditor::_update_edited_point_pos() {
void AnimationNodeBlendSpace1DEditor::_update_tool_erase() {
bool point_valid = selected_point >= 0 && selected_point < blend_space->get_blend_point_count();
- tool_erase->set_disabled(!point_valid);
+ tool_erase->set_disabled(!point_valid || read_only);
if (point_valid) {
Ref<AnimationNode> an = blend_space->get_blend_point_node(selected_point);
@@ -486,7 +494,11 @@ void AnimationNodeBlendSpace1DEditor::_update_tool_erase() {
open_editor->hide();
}
- edit_hb->show();
+ if (!read_only) {
+ edit_hb->show();
+ } else {
+ edit_hb->hide();
+ }
} else {
edit_hb->hide();
}
@@ -590,10 +602,20 @@ bool AnimationNodeBlendSpace1DEditor::can_edit(const Ref<AnimationNode> &p_node)
void AnimationNodeBlendSpace1DEditor::edit(const Ref<AnimationNode> &p_node) {
blend_space = p_node;
+ read_only = false;
if (!blend_space.is_null()) {
+ read_only = EditorNode::get_singleton()->is_resource_read_only(blend_space);
+
_update_space();
}
+
+ tool_create->set_disabled(read_only);
+ edit_value->set_editable(!read_only);
+ label_value->set_editable(!read_only);
+ min_value->set_editable(!read_only);
+ max_value->set_editable(!read_only);
+ sync->set_disabled(read_only);
}
AnimationNodeBlendSpace1DEditor *AnimationNodeBlendSpace1DEditor::singleton = nullptr;
diff --git a/editor/plugins/animation_blend_space_1d_editor.h b/editor/plugins/animation_blend_space_1d_editor.h
index 125a3382fa..c8b01cb54b 100644
--- a/editor/plugins/animation_blend_space_1d_editor.h
+++ b/editor/plugins/animation_blend_space_1d_editor.h
@@ -46,6 +46,7 @@ class AnimationNodeBlendSpace1DEditor : public AnimationTreeNodeEditorPlugin {
GDCLASS(AnimationNodeBlendSpace1DEditor, AnimationTreeNodeEditorPlugin);
Ref<AnimationNodeBlendSpace1D> blend_space;
+ bool read_only = false;
HBoxContainer *goto_parent_hb = nullptr;
Button *goto_parent = nullptr;
diff --git a/editor/plugins/animation_blend_space_2d_editor.cpp b/editor/plugins/animation_blend_space_2d_editor.cpp
index c0723cef87..2730beb549 100644
--- a/editor/plugins/animation_blend_space_2d_editor.cpp
+++ b/editor/plugins/animation_blend_space_2d_editor.cpp
@@ -60,11 +60,29 @@ void AnimationNodeBlendSpace2DEditor::edit(const Ref<AnimationNode> &p_node) {
blend_space->disconnect("triangles_updated", callable_mp(this, &AnimationNodeBlendSpace2DEditor::_blend_space_changed));
}
blend_space = p_node;
+ read_only = false;
if (!blend_space.is_null()) {
+ read_only = EditorNode::get_singleton()->is_resource_read_only(blend_space);
+
blend_space->connect("triangles_updated", callable_mp(this, &AnimationNodeBlendSpace2DEditor::_blend_space_changed));
_update_space();
}
+
+ tool_create->set_disabled(read_only);
+ interpolation->set_disabled(read_only);
+ max_x_value->set_editable(!read_only);
+ min_x_value->set_editable(!read_only);
+ max_y_value->set_editable(!read_only);
+ min_y_value->set_editable(!read_only);
+ label_x->set_editable(!read_only);
+ label_y->set_editable(!read_only);
+ edit_x->set_editable(!read_only);
+ edit_y->set_editable(!read_only);
+ tool_triangle->set_disabled(read_only);
+ auto_triangles->set_disabled(read_only);
+ sync->set_disabled(read_only);
+ interpolation->set_disabled(read_only);
}
StringName AnimationNodeBlendSpace2DEditor::get_blend_position_path() const {
@@ -76,7 +94,9 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEven
Ref<InputEventKey> k = p_event;
if (tool_select->is_pressed() && k.is_valid() && k->is_pressed() && k->get_keycode() == Key::KEY_DELETE && !k->is_echo()) {
if (selected_point != -1 || selected_triangle != -1) {
- _erase_selected();
+ if (!read_only) {
+ _erase_selected();
+ }
accept_event();
}
}
@@ -84,57 +104,59 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEven
Ref<InputEventMouseButton> mb = p_event;
if (mb.is_valid() && mb->is_pressed() && ((tool_select->is_pressed() && mb->get_button_index() == MouseButton::RIGHT) || (mb->get_button_index() == MouseButton::LEFT && tool_create->is_pressed()))) {
- menu->clear();
- animations_menu->clear();
- animations_to_add.clear();
- List<StringName> classes;
- classes.sort_custom<StringName::AlphCompare>();
-
- ClassDB::get_inheriters_from_class("AnimationRootNode", &classes);
- menu->add_submenu_item(TTR("Add Animation"), "animations");
-
- AnimationTree *gp = AnimationTreeEditor::get_singleton()->get_tree();
- ERR_FAIL_COND(!gp);
- if (gp && gp->has_node(gp->get_animation_player())) {
- AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(gp->get_node(gp->get_animation_player()));
- if (ap) {
- List<StringName> names;
- ap->get_animation_list(&names);
- for (const StringName &E : names) {
- animations_menu->add_icon_item(get_theme_icon(SNAME("Animation"), SNAME("EditorIcons")), E);
- animations_to_add.push_back(E);
+ if (!read_only) {
+ menu->clear();
+ animations_menu->clear();
+ animations_to_add.clear();
+ List<StringName> classes;
+ classes.sort_custom<StringName::AlphCompare>();
+
+ ClassDB::get_inheriters_from_class("AnimationRootNode", &classes);
+ menu->add_submenu_item(TTR("Add Animation"), "animations");
+
+ AnimationTree *gp = AnimationTreeEditor::get_singleton()->get_tree();
+ ERR_FAIL_COND(!gp);
+ if (gp && gp->has_node(gp->get_animation_player())) {
+ AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(gp->get_node(gp->get_animation_player()));
+ if (ap) {
+ List<StringName> names;
+ ap->get_animation_list(&names);
+ for (const StringName &E : names) {
+ animations_menu->add_icon_item(get_theme_icon(SNAME("Animation"), SNAME("EditorIcons")), E);
+ animations_to_add.push_back(E);
+ }
}
}
- }
- for (const StringName &E : classes) {
- String name = String(E).replace_first("AnimationNode", "");
- if (name == "Animation" || name == "StartState" || name == "EndState") {
- continue; // nope
+ for (const StringName &E : classes) {
+ String name = String(E).replace_first("AnimationNode", "");
+ if (name == "Animation" || name == "StartState" || name == "EndState") {
+ continue; // nope
+ }
+ int idx = menu->get_item_count();
+ menu->add_item(vformat(TTR("Add %s"), name), idx);
+ menu->set_item_metadata(idx, E);
}
- int idx = menu->get_item_count();
- menu->add_item(vformat(TTR("Add %s"), name), idx);
- menu->set_item_metadata(idx, E);
- }
- Ref<AnimationNode> clipb = EditorSettings::get_singleton()->get_resource_clipboard();
- if (clipb.is_valid()) {
+ Ref<AnimationNode> clipb = EditorSettings::get_singleton()->get_resource_clipboard();
+ if (clipb.is_valid()) {
+ menu->add_separator();
+ menu->add_item(TTR("Paste"), MENU_PASTE);
+ }
menu->add_separator();
- menu->add_item(TTR("Paste"), MENU_PASTE);
- }
- menu->add_separator();
- menu->add_item(TTR("Load..."), MENU_LOAD_FILE);
-
- menu->set_position(blend_space_draw->get_screen_position() + mb->get_position());
- menu->reset_size();
- menu->popup();
- add_point_pos = (mb->get_position() / blend_space_draw->get_size());
- add_point_pos.y = 1.0 - add_point_pos.y;
- add_point_pos *= (blend_space->get_max_space() - blend_space->get_min_space());
- add_point_pos += blend_space->get_min_space();
-
- if (snap->is_pressed()) {
- add_point_pos = add_point_pos.snapped(blend_space->get_snap());
+ menu->add_item(TTR("Load..."), MENU_LOAD_FILE);
+
+ menu->set_position(blend_space_draw->get_screen_position() + mb->get_position());
+ menu->reset_size();
+ menu->popup();
+ add_point_pos = (mb->get_position() / blend_space_draw->get_size());
+ add_point_pos.y = 1.0 - add_point_pos.y;
+ add_point_pos *= (blend_space->get_max_space() - blend_space->get_min_space());
+ add_point_pos += blend_space->get_min_space();
+
+ if (snap->is_pressed()) {
+ add_point_pos = add_point_pos.snapped(blend_space->get_snap());
+ }
}
}
@@ -222,17 +244,19 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEven
point = point.snapped(blend_space->get_snap());
}
- updating = true;
- undo_redo->create_action(TTR("Move Node Point"));
- undo_redo->add_do_method(blend_space.ptr(), "set_blend_point_position", selected_point, point);
- undo_redo->add_undo_method(blend_space.ptr(), "set_blend_point_position", selected_point, blend_space->get_blend_point_position(selected_point));
- undo_redo->add_do_method(this, "_update_space");
- undo_redo->add_undo_method(this, "_update_space");
- undo_redo->add_do_method(this, "_update_edited_point_pos");
- undo_redo->add_undo_method(this, "_update_edited_point_pos");
- undo_redo->commit_action();
- updating = false;
- _update_edited_point_pos();
+ if (!read_only) {
+ updating = true;
+ undo_redo->create_action(TTR("Move Node Point"));
+ undo_redo->add_do_method(blend_space.ptr(), "set_blend_point_position", selected_point, point);
+ undo_redo->add_undo_method(blend_space.ptr(), "set_blend_point_position", selected_point, blend_space->get_blend_point_position(selected_point));
+ undo_redo->add_do_method(this, "_update_space");
+ undo_redo->add_undo_method(this, "_update_space");
+ undo_redo->add_do_method(this, "_update_edited_point_pos");
+ undo_redo->add_undo_method(this, "_update_edited_point_pos");
+ undo_redo->commit_action();
+ updating = false;
+ _update_edited_point_pos();
+ }
}
dragging_selected_attempt = false;
dragging_selected = false;
@@ -259,7 +283,9 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEven
if (mm.is_valid() && dragging_selected_attempt) {
dragging_selected = true;
- drag_ofs = ((mm->get_position() - drag_from) / blend_space_draw->get_size()) * (blend_space->get_max_space() - blend_space->get_min_space()) * Vector2(1, -1);
+ if (!read_only) {
+ drag_ofs = ((mm->get_position() - drag_from) / blend_space_draw->get_size()) * (blend_space->get_max_space() - blend_space->get_min_space()) * Vector2(1, -1);
+ }
blend_space_draw->update();
_update_edited_point_pos();
}
@@ -355,7 +381,10 @@ void AnimationNodeBlendSpace2DEditor::_add_animation_type(int p_index) {
}
void AnimationNodeBlendSpace2DEditor::_update_tool_erase() {
- tool_erase->set_disabled(!(selected_point >= 0 && selected_point < blend_space->get_blend_point_count()) && !(selected_triangle >= 0 && selected_triangle < blend_space->get_triangle_count()));
+ tool_erase->set_disabled(
+ (!(selected_point >= 0 && selected_point < blend_space->get_blend_point_count()) && !(selected_triangle >= 0 && selected_triangle < blend_space->get_triangle_count())) ||
+ read_only);
+
if (selected_point >= 0 && selected_point < blend_space->get_blend_point_count()) {
Ref<AnimationNode> an = blend_space->get_blend_point_node(selected_point);
if (AnimationTreeEditor::get_singleton()->can_edit(an)) {
@@ -363,7 +392,11 @@ void AnimationNodeBlendSpace2DEditor::_update_tool_erase() {
} else {
open_editor->hide();
}
- edit_hb->show();
+ if (!read_only) {
+ edit_hb->show();
+ } else {
+ edit_hb->hide();
+ }
} else {
edit_hb->hide();
}
@@ -503,10 +536,12 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_draw() {
points.clear();
for (int i = 0; i < blend_space->get_blend_point_count(); i++) {
Vector2 point = blend_space->get_blend_point_position(i);
- if (dragging_selected && selected_point == i) {
- point += drag_ofs;
- if (snap->is_pressed()) {
- point = point.snapped(blend_space->get_snap());
+ if (!read_only) {
+ if (dragging_selected && selected_point == i) {
+ point += drag_ofs;
+ if (snap->is_pressed()) {
+ point = point.snapped(blend_space->get_snap());
+ }
}
}
point = (point - blend_space->get_min_space()) / (blend_space->get_max_space() - blend_space->get_min_space());
diff --git a/editor/plugins/animation_blend_space_2d_editor.h b/editor/plugins/animation_blend_space_2d_editor.h
index df2bcf254d..1f015a1804 100644
--- a/editor/plugins/animation_blend_space_2d_editor.h
+++ b/editor/plugins/animation_blend_space_2d_editor.h
@@ -46,6 +46,7 @@ class AnimationNodeBlendSpace2DEditor : public AnimationTreeNodeEditorPlugin {
GDCLASS(AnimationNodeBlendSpace2DEditor, AnimationTreeNodeEditorPlugin);
Ref<AnimationNodeBlendSpace2D> blend_space;
+ bool read_only = false;
PanelContainer *panel = nullptr;
Button *tool_blend = nullptr;
diff --git a/editor/plugins/animation_blend_tree_editor_plugin.cpp b/editor/plugins/animation_blend_tree_editor_plugin.cpp
index e4f5576d66..8dd3223b19 100644
--- a/editor/plugins/animation_blend_tree_editor_plugin.cpp
+++ b/editor/plugins/animation_blend_tree_editor_plugin.cpp
@@ -134,6 +134,8 @@ void AnimationNodeBlendTreeEditor::_update_graph() {
GraphNode *node = memnew(GraphNode);
graph->add_child(node);
+ node->set_draggable(!read_only);
+
Ref<AnimationNode> agnode = blend_tree->get_node(E);
ERR_CONTINUE(!agnode.is_valid());
@@ -146,9 +148,10 @@ void AnimationNodeBlendTreeEditor::_update_graph() {
if (String(E) != "output") {
LineEdit *name = memnew(LineEdit);
name->set_text(E);
+ name->set_editable(!read_only);
name->set_expand_to_text_length_enabled(true);
node->add_child(name);
- node->set_slot(0, false, 0, Color(), true, 0, get_theme_color(SNAME("font_color"), SNAME("Label")));
+ node->set_slot(0, false, 0, Color(), true, read_only ? -1 : 0, get_theme_color(SNAME("font_color"), SNAME("Label")));
name->connect("text_submitted", callable_mp(this, &AnimationNodeBlendTreeEditor::_node_renamed).bind(agnode), CONNECT_DEFERRED);
name->connect("focus_exited", callable_mp(this, &AnimationNodeBlendTreeEditor::_node_renamed_focus_out).bind(name, agnode), CONNECT_DEFERRED);
base = 1;
@@ -160,7 +163,7 @@ void AnimationNodeBlendTreeEditor::_update_graph() {
Label *in_name = memnew(Label);
node->add_child(in_name);
in_name->set_text(agnode->get_input_name(i));
- node->set_slot(base + i, true, 0, get_theme_color(SNAME("font_color"), SNAME("Label")), false, 0, Color());
+ node->set_slot(base + i, true, read_only ? -1 : 0, get_theme_color(SNAME("font_color"), SNAME("Label")), false, 0, Color());
}
List<PropertyInfo> pinfo;
@@ -172,6 +175,7 @@ void AnimationNodeBlendTreeEditor::_update_graph() {
String base_path = AnimationTreeEditor::get_singleton()->get_base_path() + String(E) + "/" + F.name;
EditorProperty *prop = EditorInspector::instantiate_property_editor(AnimationTreeEditor::get_singleton()->get_tree(), F.type, base_path, F.hint, F.hint_string, F.usage);
if (prop) {
+ prop->set_read_only(read_only);
prop->set_object_and_property(AnimationTreeEditor::get_singleton()->get_tree(), base_path);
prop->update_property();
prop->set_name_split_ratio(0);
@@ -195,12 +199,16 @@ void AnimationNodeBlendTreeEditor::_update_graph() {
if (agnode->has_filter()) {
node->add_child(memnew(HSeparator));
- Button *edit_filters = memnew(Button);
- edit_filters->set_text(TTR("Edit Filters"));
- edit_filters->set_icon(get_theme_icon(SNAME("AnimationFilter"), SNAME("EditorIcons")));
- node->add_child(edit_filters);
- edit_filters->connect("pressed", callable_mp(this, &AnimationNodeBlendTreeEditor::_edit_filters).bind(E), CONNECT_DEFERRED);
- edit_filters->set_h_size_flags(SIZE_SHRINK_CENTER);
+ Button *inspect_filters = memnew(Button);
+ if (read_only) {
+ inspect_filters->set_text(TTR("Inspect Filters"));
+ } else {
+ inspect_filters->set_text(TTR("Edit Filters"));
+ }
+ inspect_filters->set_icon(get_theme_icon(SNAME("AnimationFilter"), SNAME("EditorIcons")));
+ node->add_child(inspect_filters);
+ inspect_filters->connect("pressed", callable_mp(this, &AnimationNodeBlendTreeEditor::_inspect_filters).bind(E), CONNECT_DEFERRED);
+ inspect_filters->set_h_size_flags(SIZE_SHRINK_CENTER);
}
Ref<AnimationNodeAnimation> anim = agnode;
@@ -208,6 +216,7 @@ void AnimationNodeBlendTreeEditor::_update_graph() {
MenuButton *mb = memnew(MenuButton);
mb->set_text(anim->get_animation());
mb->set_icon(get_theme_icon(SNAME("Animation"), SNAME("EditorIcons")));
+ mb->set_disabled(read_only);
Array options;
node->add_child(memnew(HSeparator));
@@ -370,10 +379,18 @@ void AnimationNodeBlendTreeEditor::_popup(bool p_has_input_ports, const Vector2
}
void AnimationNodeBlendTreeEditor::_popup_request(const Vector2 &p_position) {
+ if (read_only) {
+ return;
+ }
+
_popup(false, graph->get_screen_position() + graph->get_local_mouse_position(), p_position);
}
void AnimationNodeBlendTreeEditor::_connection_to_empty(const String &p_from, int p_from_slot, const Vector2 &p_release_position) {
+ if (read_only) {
+ return;
+ }
+
Ref<AnimationNode> node = blend_tree->get_node(p_from);
if (node.is_valid()) {
from_node = p_from;
@@ -382,6 +399,10 @@ void AnimationNodeBlendTreeEditor::_connection_to_empty(const String &p_from, in
}
void AnimationNodeBlendTreeEditor::_connection_from_empty(const String &p_to, int p_to_slot, const Vector2 &p_release_position) {
+ if (read_only) {
+ return;
+ }
+
Ref<AnimationNode> node = blend_tree->get_node(p_to);
if (node.is_valid()) {
to_node = p_to;
@@ -402,6 +423,10 @@ void AnimationNodeBlendTreeEditor::_node_dragged(const Vector2 &p_from, const Ve
}
void AnimationNodeBlendTreeEditor::_connection_request(const String &p_from, int p_from_index, const String &p_to, int p_to_index) {
+ if (read_only) {
+ return;
+ }
+
AnimationNodeBlendTree::ConnectionError err = blend_tree->can_connect_node(p_to, p_to_index, p_from);
if (err != AnimationNodeBlendTree::CONNECTION_OK) {
@@ -418,6 +443,10 @@ void AnimationNodeBlendTreeEditor::_connection_request(const String &p_from, int
}
void AnimationNodeBlendTreeEditor::_disconnection_request(const String &p_from, int p_from_index, const String &p_to, int p_to_index) {
+ if (read_only) {
+ return;
+ }
+
graph->disconnect_node(p_from, p_from_index, p_to, p_to_index);
updating = true;
@@ -445,6 +474,10 @@ void AnimationNodeBlendTreeEditor::_anim_selected(int p_index, Array p_options,
}
void AnimationNodeBlendTreeEditor::_delete_request(const String &p_which) {
+ if (read_only) {
+ return;
+ }
+
undo_redo->create_action(TTR("Delete Node"));
undo_redo->add_do_method(blend_tree.ptr(), "remove_node", p_which);
undo_redo->add_undo_method(blend_tree.ptr(), "add_node", p_which, blend_tree->get_node(p_which), blend_tree.ptr()->get_node_position(p_which));
@@ -464,6 +497,10 @@ void AnimationNodeBlendTreeEditor::_delete_request(const String &p_which) {
}
void AnimationNodeBlendTreeEditor::_delete_nodes_request(const TypedArray<StringName> &p_nodes) {
+ if (read_only) {
+ return;
+ }
+
List<StringName> to_erase;
if (p_nodes.is_empty()) {
@@ -495,6 +532,10 @@ void AnimationNodeBlendTreeEditor::_delete_nodes_request(const TypedArray<String
}
void AnimationNodeBlendTreeEditor::_node_selected(Object *p_node) {
+ if (read_only) {
+ return;
+ }
+
GraphNode *gn = Object::cast_to<GraphNode>(p_node);
ERR_FAIL_COND(!gn);
@@ -679,7 +720,7 @@ bool AnimationNodeBlendTreeEditor::_update_filters(const Ref<AnimationNode> &ano
}
}
- ti->set_editable(0, true);
+ ti->set_editable(0, !read_only);
ti->set_selectable(0, true);
ti->set_cell_mode(0, TreeItem::CELL_MODE_CHECK);
ti->set_text(0, concat);
@@ -692,7 +733,7 @@ bool AnimationNodeBlendTreeEditor::_update_filters(const Ref<AnimationNode> &ano
ti = filters->create_item(ti);
ti->set_cell_mode(0, TreeItem::CELL_MODE_CHECK);
ti->set_text(0, concat);
- ti->set_editable(0, true);
+ ti->set_editable(0, !read_only);
ti->set_selectable(0, true);
ti->set_checked(0, anode->is_path_filtered(path));
ti->set_metadata(0, path);
@@ -714,7 +755,7 @@ bool AnimationNodeBlendTreeEditor::_update_filters(const Ref<AnimationNode> &ano
ti = filters->create_item(ti);
ti->set_cell_mode(0, TreeItem::CELL_MODE_CHECK);
ti->set_text(0, types_text);
- ti->set_editable(0, true);
+ ti->set_editable(0, !read_only);
ti->set_selectable(0, true);
ti->set_checked(0, anode->is_path_filtered(path));
ti->set_metadata(0, path);
@@ -727,7 +768,15 @@ bool AnimationNodeBlendTreeEditor::_update_filters(const Ref<AnimationNode> &ano
return true;
}
-void AnimationNodeBlendTreeEditor::_edit_filters(const String &p_which) {
+void AnimationNodeBlendTreeEditor::_inspect_filters(const String &p_which) {
+ if (read_only) {
+ filter_dialog->set_title(TTR("Inspect Filtered Tracks:"));
+ } else {
+ filter_dialog->set_title(TTR("Edit Filtered Tracks:"));
+ }
+
+ filter_enabled->set_disabled(read_only);
+
Ref<AnimationNode> anode = blend_tree->get_node(p_which);
ERR_FAIL_COND(!anode.is_valid());
@@ -838,6 +887,10 @@ void AnimationNodeBlendTreeEditor::_notification(int p_what) {
}
void AnimationNodeBlendTreeEditor::_scroll_changed(const Vector2 &p_scroll) {
+ if (read_only) {
+ return;
+ }
+
if (updating) {
return;
}
@@ -944,13 +997,20 @@ void AnimationNodeBlendTreeEditor::edit(const Ref<AnimationNode> &p_node) {
blend_tree = p_node;
+ read_only = false;
+
if (blend_tree.is_null()) {
hide();
} else {
+ read_only = EditorNode::get_singleton()->is_resource_read_only(blend_tree);
+
blend_tree->connect("removed_from_graph", callable_mp(this, &AnimationNodeBlendTreeEditor::_removed_from_graph));
_update_graph();
}
+
+ add_node->set_disabled(read_only);
+ graph->set_arrange_nodes_button_hidden(read_only);
}
AnimationNodeBlendTreeEditor::AnimationNodeBlendTreeEditor() {
@@ -986,6 +1046,7 @@ AnimationNodeBlendTreeEditor::AnimationNodeBlendTreeEditor() {
graph->get_zoom_hbox()->move_child(add_node, 0);
add_node->get_popup()->connect("id_pressed", callable_mp(this, &AnimationNodeBlendTreeEditor::_add_node));
add_node->connect("about_to_popup", callable_mp(this, &AnimationNodeBlendTreeEditor::_update_options_menu).bind(false));
+ add_node->set_disabled(read_only);
add_options.push_back(AddOption("Animation", "AnimationNodeAnimation"));
add_options.push_back(AddOption("OneShot", "AnimationNodeOneShot", 2));
diff --git a/editor/plugins/animation_blend_tree_editor_plugin.h b/editor/plugins/animation_blend_tree_editor_plugin.h
index af43da6197..30a54930a2 100644
--- a/editor/plugins/animation_blend_tree_editor_plugin.h
+++ b/editor/plugins/animation_blend_tree_editor_plugin.h
@@ -47,6 +47,9 @@ class AnimationNodeBlendTreeEditor : public AnimationTreeNodeEditorPlugin {
GDCLASS(AnimationNodeBlendTreeEditor, AnimationTreeNodeEditorPlugin);
Ref<AnimationNodeBlendTree> blend_tree;
+
+ bool read_only = false;
+
GraphEdit *graph = nullptr;
MenuButton *add_node = nullptr;
Vector2 position_from_popup_menu;
@@ -106,7 +109,7 @@ class AnimationNodeBlendTreeEditor : public AnimationTreeNodeEditorPlugin {
void _delete_nodes_request(const TypedArray<StringName> &p_nodes);
bool _update_filters(const Ref<AnimationNode> &anode);
- void _edit_filters(const String &p_which);
+ void _inspect_filters(const String &p_which);
void _filter_edited();
void _filter_toggled();
Ref<AnimationNode> _filter_edit;
diff --git a/editor/plugins/animation_state_machine_editor.cpp b/editor/plugins/animation_state_machine_editor.cpp
index ef4ae3dca4..ecba4ba888 100644
--- a/editor/plugins/animation_state_machine_editor.cpp
+++ b/editor/plugins/animation_state_machine_editor.cpp
@@ -56,7 +56,11 @@ bool AnimationNodeStateMachineEditor::can_edit(const Ref<AnimationNode> &p_node)
void AnimationNodeStateMachineEditor::edit(const Ref<AnimationNode> &p_node) {
state_machine = p_node;
+ read_only = false;
+
if (state_machine.is_valid()) {
+ read_only = EditorNode::get_singleton()->is_resource_read_only(state_machine);
+
selected_transition_from = StringName();
selected_transition_to = StringName();
selected_transition_index = -1;
@@ -66,6 +70,9 @@ void AnimationNodeStateMachineEditor::edit(const Ref<AnimationNode> &p_node) {
_update_mode();
_update_graph();
}
+
+ tool_create->set_disabled(read_only);
+ tool_connect->set_disabled(read_only);
}
void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEvent> &p_event) {
@@ -77,7 +84,9 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
Ref<InputEventKey> k = p_event;
if (tool_select->is_pressed() && k.is_valid() && k->is_pressed() && k->get_keycode() == Key::KEY_DELETE && !k->is_echo()) {
if (selected_node != StringName() || !selected_nodes.is_empty() || selected_transition_to != StringName() || selected_transition_from != StringName()) {
- _erase_selected();
+ if (!read_only) {
+ _erase_selected();
+ }
accept_event();
}
}
@@ -95,9 +104,11 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
Ref<InputEventMouseButton> mb = p_event;
// Add new node
- if (mb.is_valid() && mb->is_pressed() && !box_selecting && !connecting && ((tool_select->is_pressed() && mb->get_button_index() == MouseButton::RIGHT) || (tool_create->is_pressed() && mb->get_button_index() == MouseButton::LEFT))) {
- connecting_from = StringName();
- _open_menu(mb->get_position());
+ if (!read_only) {
+ if (mb.is_valid() && mb->is_pressed() && !box_selecting && !connecting && ((tool_select->is_pressed() && mb->get_button_index() == MouseButton::RIGHT) || (tool_create->is_pressed() && mb->get_button_index() == MouseButton::LEFT))) {
+ connecting_from = StringName();
+ _open_menu(mb->get_position());
+ }
}
// Select node or push a field inside
@@ -121,22 +132,24 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
return;
}
- if (node_rects[i].name.has_point(mb->get_position()) && state_machine->can_edit_node(node_rects[i].node_name)) { // edit name
- Ref<StyleBox> line_sb = get_theme_stylebox(SNAME("normal"), SNAME("LineEdit"));
+ if (!read_only) {
+ if (node_rects[i].name.has_point(mb->get_position()) && state_machine->can_edit_node(node_rects[i].node_name)) { // edit name
+ Ref<StyleBox> line_sb = get_theme_stylebox(SNAME("normal"), SNAME("LineEdit"));
- Rect2 edit_rect = node_rects[i].name;
- edit_rect.position -= line_sb->get_offset();
- edit_rect.size += line_sb->get_minimum_size();
+ Rect2 edit_rect = node_rects[i].name;
+ edit_rect.position -= line_sb->get_offset();
+ edit_rect.size += line_sb->get_minimum_size();
- name_edit_popup->set_position(state_machine_draw->get_screen_position() + edit_rect.position);
- name_edit_popup->set_size(edit_rect.size);
- name_edit->set_text(node_rects[i].node_name);
- name_edit_popup->popup();
- name_edit->grab_focus();
- name_edit->select_all();
+ name_edit_popup->set_position(state_machine_draw->get_screen_position() + edit_rect.position);
+ name_edit_popup->set_size(edit_rect.size);
+ name_edit->set_text(node_rects[i].node_name);
+ name_edit_popup->popup();
+ name_edit->grab_focus();
+ name_edit->select_all();
- prev_name = node_rects[i].node_name;
- return;
+ prev_name = node_rects[i].node_name;
+ return;
+ }
}
if (node_rects[i].edit.has_point(mb->get_position())) { //edit name
@@ -319,7 +332,7 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
}
// Move mouse while connecting
- if (mm.is_valid() && connecting) {
+ if (mm.is_valid() && connecting && !read_only) {
connecting_to = mm->get_position();
connecting_to_node = StringName();
state_machine_draw->update();
@@ -333,7 +346,7 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
}
// Move mouse while moving a node
- if (mm.is_valid() && dragging_selected_attempt) {
+ if (mm.is_valid() && dragging_selected_attempt && !read_only) {
dragging_selected = true;
drag_ofs = mm->get_position() - drag_from;
snap_x = StringName();
@@ -478,17 +491,21 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
}
Control::CursorShape AnimationNodeStateMachineEditor::get_cursor_shape(const Point2 &p_pos) const {
- // Put ibeam (text cursor) over names to make it clearer that they are editable.
- Transform2D xform = panel->get_transform() * state_machine_draw->get_transform();
- Point2 pos = xform.xform_inv(p_pos);
Control::CursorShape cursor_shape = get_default_cursor_shape();
-
- for (int i = node_rects.size() - 1; i >= 0; i--) { // Inverse to draw order.
- if (node_rects[i].node.has_point(pos)) {
- if (node_rects[i].name.has_point(pos)) {
- cursor_shape = Control::CURSOR_IBEAM;
+ if (!read_only) {
+ // Put ibeam (text cursor) over names to make it clearer that they are editable.
+ Transform2D xform = panel->get_transform() * state_machine_draw->get_transform();
+ Point2 pos = xform.xform_inv(p_pos);
+
+ for (int i = node_rects.size() - 1; i >= 0; i--) { // Inverse to draw order.
+ if (node_rects[i].node.has_point(pos)) {
+ if (node_rects[i].name.has_point(pos)) {
+ if (state_machine->can_edit_node(node_rects[i].node_name)) {
+ cursor_shape = Control::CURSOR_IBEAM;
+ }
+ }
+ break;
}
- break;
}
}
return cursor_shape;
@@ -1848,9 +1865,9 @@ void AnimationNodeStateMachineEditor::_update_mode() {
tool_erase_hb->show();
bool nothing_selected = selected_nodes.is_empty() && selected_transition_from == StringName() && selected_transition_to == StringName();
bool start_end_selected = selected_nodes.size() == 1 && (*selected_nodes.begin() == state_machine->start_node || *selected_nodes.begin() == state_machine->end_node);
- tool_erase->set_disabled(nothing_selected || start_end_selected);
+ tool_erase->set_disabled(nothing_selected || start_end_selected || read_only);
- if (selected_nodes.is_empty() || start_end_selected) {
+ if (selected_nodes.is_empty() || start_end_selected || read_only) {
tool_group->set_disabled(true);
tool_group->set_visible(true);
tool_ungroup->set_visible(false);
diff --git a/editor/plugins/animation_state_machine_editor.h b/editor/plugins/animation_state_machine_editor.h
index fdd1af0f6d..3a59e94a5f 100644
--- a/editor/plugins/animation_state_machine_editor.h
+++ b/editor/plugins/animation_state_machine_editor.h
@@ -47,6 +47,8 @@ class AnimationNodeStateMachineEditor : public AnimationTreeNodeEditorPlugin {
Ref<AnimationNodeStateMachine> state_machine;
+ bool read_only = false;
+
Button *tool_select = nullptr;
Button *tool_create = nullptr;
Button *tool_connect = nullptr;
diff --git a/scene/gui/graph_edit.cpp b/scene/gui/graph_edit.cpp
index e6198b44ff..a4c2236706 100644
--- a/scene/gui/graph_edit.cpp
+++ b/scene/gui/graph_edit.cpp
@@ -607,13 +607,16 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) {
connecting_color = Object::cast_to<GraphNode>(to)->get_connection_input_color(E.to_port);
connecting_target = false;
connecting_to = pos;
- just_disconnected = true;
- emit_signal(SNAME("disconnection_request"), E.from, E.from_port, E.to, E.to_port);
- to = get_node(String(connecting_from)); //maybe it was erased
- if (Object::cast_to<GraphNode>(to)) {
- connecting = true;
- emit_signal(SNAME("connection_drag_started"), connecting_from, connecting_index, false);
+ if (connecting_type >= 0) {
+ just_disconnected = true;
+
+ emit_signal(SNAME("disconnection_request"), E.from, E.from_port, E.to, E.to_port);
+ to = get_node(String(connecting_from)); //maybe it was erased
+ if (Object::cast_to<GraphNode>(to)) {
+ connecting = true;
+ emit_signal(SNAME("connection_drag_started"), connecting_from, connecting_index, false);
+ }
}
return;
}
@@ -621,7 +624,6 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) {
}
}
- connecting = true;
connecting_from = gn->get_name();
connecting_index = j;
connecting_out = true;
@@ -629,8 +631,11 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) {
connecting_color = gn->get_connection_output_color(j);
connecting_target = false;
connecting_to = pos;
- just_disconnected = false;
- emit_signal(SNAME("connection_drag_started"), connecting_from, connecting_index, true);
+ if (connecting_type >= 0) {
+ connecting = true;
+ just_disconnected = false;
+ emit_signal(SNAME("connection_drag_started"), connecting_from, connecting_index, true);
+ }
return;
}
}
@@ -657,11 +662,13 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) {
connecting_to = pos;
just_disconnected = true;
- emit_signal(SNAME("disconnection_request"), E.from, E.from_port, E.to, E.to_port);
- fr = get_node(String(connecting_from)); //maybe it was erased
- if (Object::cast_to<GraphNode>(fr)) {
- connecting = true;
- emit_signal(SNAME("connection_drag_started"), connecting_from, connecting_index, true);
+ if (connecting_type >= 0) {
+ emit_signal(SNAME("disconnection_request"), E.from, E.from_port, E.to, E.to_port);
+ fr = get_node(String(connecting_from)); //maybe it was erased
+ if (Object::cast_to<GraphNode>(fr)) {
+ connecting = true;
+ emit_signal(SNAME("connection_drag_started"), connecting_from, connecting_index, true);
+ }
}
return;
}
@@ -669,7 +676,6 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) {
}
}
- connecting = true;
connecting_from = gn->get_name();
connecting_index = j;
connecting_out = false;
@@ -677,8 +683,11 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) {
connecting_color = gn->get_connection_input_color(j);
connecting_target = false;
connecting_to = pos;
- just_disconnected = false;
- emit_signal(SNAME("connection_drag_started"), connecting_from, connecting_index, false);
+ if (connecting_type >= 0) {
+ connecting = true;
+ just_disconnected = false;
+ emit_signal(SNAME("connection_drag_started"), connecting_from, connecting_index, false);
+ }
return;
}
}
@@ -1127,7 +1136,7 @@ void GraphEdit::gui_input(const Ref<InputEvent> &p_ev) {
drag_accum += mm->get_relative();
for (int i = get_child_count() - 1; i >= 0; i--) {
GraphNode *gn = Object::cast_to<GraphNode>(get_child(i));
- if (gn && gn->is_selected()) {
+ if (gn && gn->is_selected() && gn->is_draggable()) {
Vector2 pos = (gn->get_drag_from() * zoom + drag_accum) / zoom;
// Snapping can be toggled temporarily by holding down Ctrl.
@@ -1166,7 +1175,9 @@ void GraphEdit::gui_input(const Ref<InputEvent> &p_ev) {
} else if (gn->is_selected() && !box_selection_mode_additive) {
emit_signal(SNAME("node_deselected"), gn);
}
- gn->set_selected(box_selection_mode_additive);
+ if (gn->is_selectable()) {
+ gn->set_selected(box_selection_mode_additive);
+ }
} else {
bool select = (previous_selected.find(gn) != nullptr);
if (gn->is_selected() && !select) {
@@ -1174,7 +1185,9 @@ void GraphEdit::gui_input(const Ref<InputEvent> &p_ev) {
} else if (!gn->is_selected() && select) {
emit_signal(SNAME("node_selected"), gn);
}
- gn->set_selected(select);
+ if (gn->is_selectable()) {
+ gn->set_selected(select);
+ }
}
}
@@ -1193,7 +1206,7 @@ void GraphEdit::gui_input(const Ref<InputEvent> &p_ev) {
continue;
}
- bool select = (previous_selected.find(gn) != nullptr);
+ bool select = (gn->is_selectable() && previous_selected.find(gn) != nullptr);
if (gn->is_selected() && !select) {
emit_signal(SNAME("node_deselected"), gn);
} else if (!gn->is_selected() && select) {
@@ -1285,7 +1298,7 @@ void GraphEdit::gui_input(const Ref<InputEvent> &p_ev) {
GraphNode *o_gn = Object::cast_to<GraphNode>(get_child(i));
if (o_gn) {
if (o_gn == gn) {
- o_gn->set_selected(true);
+ o_gn->set_selected(o_gn->is_selectable());
} else {
if (o_gn->is_selected()) {
emit_signal(SNAME("node_deselected"), o_gn);
@@ -1296,7 +1309,7 @@ void GraphEdit::gui_input(const Ref<InputEvent> &p_ev) {
}
}
- gn->set_selected(true);
+ gn->set_selected(gn->is_selectable());
for (int i = 0; i < get_child_count(); i++) {
GraphNode *o_gn = Object::cast_to<GraphNode>(get_child(i));
if (!o_gn) {
@@ -1711,6 +1724,19 @@ bool GraphEdit::is_minimap_enabled() const {
return minimap_button->is_pressed();
}
+void GraphEdit::set_arrange_nodes_button_hidden(bool p_enable) {
+ arrange_nodes_button_hidden = p_enable;
+ if (arrange_nodes_button_hidden) {
+ layout_button->hide();
+ } else {
+ layout_button->show();
+ }
+}
+
+bool GraphEdit::is_arrange_nodes_button_hidden() const {
+ return arrange_nodes_button_hidden;
+}
+
void GraphEdit::_minimap_toggled() {
if (is_minimap_enabled()) {
minimap->set_visible(true);
@@ -2343,6 +2369,9 @@ void GraphEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_minimap_enabled", "enable"), &GraphEdit::set_minimap_enabled);
ClassDB::bind_method(D_METHOD("is_minimap_enabled"), &GraphEdit::is_minimap_enabled);
+ ClassDB::bind_method(D_METHOD("set_arrange_nodes_button_hidden", "enable"), &GraphEdit::set_arrange_nodes_button_hidden);
+ ClassDB::bind_method(D_METHOD("is_arrange_nodes_button_hidden"), &GraphEdit::is_arrange_nodes_button_hidden);
+
ClassDB::bind_method(D_METHOD("set_right_disconnects", "enable"), &GraphEdit::set_right_disconnects);
ClassDB::bind_method(D_METHOD("is_right_disconnects_enabled"), &GraphEdit::is_right_disconnects_enabled);
@@ -2382,6 +2411,9 @@ void GraphEdit::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "minimap_size", PROPERTY_HINT_NONE, "suffix:px"), "set_minimap_size", "get_minimap_size");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "minimap_opacity"), "set_minimap_opacity", "get_minimap_opacity");
+ 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("popup_request", PropertyInfo(Variant::VECTOR2, "position")));
diff --git a/scene/gui/graph_edit.h b/scene/gui/graph_edit.h
index b8c9be9983..0a0676699f 100644
--- a/scene/gui/graph_edit.h
+++ b/scene/gui/graph_edit.h
@@ -133,6 +133,8 @@ private:
void _pan_callback(Vector2 p_scroll_vec);
void _zoom_callback(Vector2 p_scroll_vec, Vector2 p_origin, bool p_alt);
+ bool arrange_nodes_button_hidden = false;
+
bool connecting = false;
String connecting_from;
bool connecting_out = false;
@@ -323,6 +325,9 @@ public:
void set_minimap_enabled(bool p_enable);
bool is_minimap_enabled() const;
+ void set_arrange_nodes_button_hidden(bool p_enable);
+ bool is_arrange_nodes_button_hidden() const;
+
GraphEditFilter *get_top_layer() const { return top_layer; }
GraphEditMinimap *get_minimap() const { return minimap; }
void get_connection_list(List<Connection> *r_connections) const;
diff --git a/scene/gui/graph_node.cpp b/scene/gui/graph_node.cpp
index 1a478a5fe1..22ad7850ad 100644
--- a/scene/gui/graph_node.cpp
+++ b/scene/gui/graph_node.cpp
@@ -1005,6 +1005,22 @@ bool GraphNode::is_resizable() const {
return resizable;
}
+void GraphNode::set_draggable(bool p_draggable) {
+ draggable = p_draggable;
+}
+
+bool GraphNode::is_draggable() {
+ return draggable;
+}
+
+void GraphNode::set_selectable(bool p_selectable) {
+ selectable = p_selectable;
+}
+
+bool GraphNode::is_selectable() {
+ return selectable;
+}
+
Vector<int> GraphNode::get_allowed_size_flags_horizontal() const {
Vector<int> flags;
flags.append(SIZE_FILL);
@@ -1066,6 +1082,12 @@ void GraphNode::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_resizable", "resizable"), &GraphNode::set_resizable);
ClassDB::bind_method(D_METHOD("is_resizable"), &GraphNode::is_resizable);
+ ClassDB::bind_method(D_METHOD("set_draggable", "draggable"), &GraphNode::set_draggable);
+ ClassDB::bind_method(D_METHOD("is_draggable"), &GraphNode::is_draggable);
+
+ ClassDB::bind_method(D_METHOD("set_selectable", "selectable"), &GraphNode::set_selectable);
+ ClassDB::bind_method(D_METHOD("is_selectable"), &GraphNode::is_selectable);
+
ClassDB::bind_method(D_METHOD("set_selected", "selected"), &GraphNode::set_selected);
ClassDB::bind_method(D_METHOD("is_selected"), &GraphNode::is_selected);
@@ -1091,6 +1113,8 @@ void GraphNode::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "position_offset", PROPERTY_HINT_NONE, "suffix:px"), "set_position_offset", "get_position_offset");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "show_close"), "set_show_close_button", "is_close_button_visible");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "resizable"), "set_resizable", "is_resizable");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "draggable"), "set_draggable", "is_draggable");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "selectable"), "set_selectable", "is_selectable");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "selected"), "set_selected", "is_selected");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "comment"), "set_comment", "is_comment");
ADD_PROPERTY(PropertyInfo(Variant::INT, "overlay", PROPERTY_HINT_ENUM, "Disabled,Breakpoint,Position"), "set_overlay", "get_overlay");
diff --git a/scene/gui/graph_node.h b/scene/gui/graph_node.h
index 6d5bb4361e..c02eb30696 100644
--- a/scene/gui/graph_node.h
+++ b/scene/gui/graph_node.h
@@ -67,6 +67,8 @@ private:
Vector2 position_offset;
bool comment = false;
bool resizable = false;
+ bool draggable = true;
+ bool selectable = true;
bool resizing = false;
Vector2 resizing_from;
@@ -183,6 +185,12 @@ public:
void set_resizable(bool p_enable);
bool is_resizable() const;
+ void set_draggable(bool p_draggable);
+ bool is_draggable();
+
+ void set_selectable(bool p_selectable);
+ bool is_selectable();
+
virtual Size2 get_minimum_size() const override;
virtual Vector<int> get_allowed_size_flags_horizontal() const override;