diff options
-rw-r--r-- | doc/classes/GraphEdit.xml | 3 | ||||
-rw-r--r-- | doc/classes/GraphNode.xml | 12 | ||||
-rw-r--r-- | editor/editor_spin_slider.cpp | 4 | ||||
-rw-r--r-- | editor/plugins/animation_blend_space_1d_editor.cpp | 160 | ||||
-rw-r--r-- | editor/plugins/animation_blend_space_1d_editor.h | 1 | ||||
-rw-r--r-- | editor/plugins/animation_blend_space_2d_editor.cpp | 163 | ||||
-rw-r--r-- | editor/plugins/animation_blend_space_2d_editor.h | 1 | ||||
-rw-r--r-- | editor/plugins/animation_blend_tree_editor_plugin.cpp | 85 | ||||
-rw-r--r-- | editor/plugins/animation_blend_tree_editor_plugin.h | 5 | ||||
-rw-r--r-- | editor/plugins/animation_state_machine_editor.cpp | 77 | ||||
-rw-r--r-- | editor/plugins/animation_state_machine_editor.h | 2 | ||||
-rw-r--r-- | scene/gui/graph_edit.cpp | 78 | ||||
-rw-r--r-- | scene/gui/graph_edit.h | 5 | ||||
-rw-r--r-- | scene/gui/graph_node.cpp | 24 | ||||
-rw-r--r-- | scene/gui/graph_node.h | 8 |
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=""""> 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; |