summaryrefslogtreecommitdiffstats
path: root/editor/plugins/animation_player_editor_plugin.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'editor/plugins/animation_player_editor_plugin.cpp')
-rw-r--r--editor/plugins/animation_player_editor_plugin.cpp349
1 files changed, 276 insertions, 73 deletions
diff --git a/editor/plugins/animation_player_editor_plugin.cpp b/editor/plugins/animation_player_editor_plugin.cpp
index 51d195e0e1..f2225fabad 100644
--- a/editor/plugins/animation_player_editor_plugin.cpp
+++ b/editor/plugins/animation_player_editor_plugin.cpp
@@ -44,6 +44,7 @@
#include "editor/plugins/canvas_item_editor_plugin.h" // For onion skinning.
#include "editor/plugins/node_3d_editor_plugin.h" // For onion skinning.
#include "editor/scene_tree_dock.h"
+#include "scene/animation/animation_tree.h"
#include "scene/gui/separator.h"
#include "scene/main/window.h"
#include "scene/resources/animation.h"
@@ -54,7 +55,11 @@
///////////////////////////////////
void AnimationPlayerEditor::_node_removed(Node *p_node) {
- if (player && player == p_node) {
+ if (player && original_node == p_node) {
+ if (is_dummy) {
+ plugin->_clear_dummy_player();
+ }
+
player = nullptr;
set_process(false);
@@ -63,12 +68,20 @@ void AnimationPlayerEditor::_node_removed(Node *p_node) {
track_editor->set_root(nullptr);
track_editor->show_select_node_warning(true);
_update_player();
+
+ _ensure_dummy_player();
}
}
void AnimationPlayerEditor::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_PROCESS: {
+ if (!player || is_dummy) {
+ track_editor->show_inactive_player_warning(false);
+ } else {
+ track_editor->show_inactive_player_warning(!player->is_active());
+ }
+
if (!player) {
return;
}
@@ -103,13 +116,13 @@ void AnimationPlayerEditor::_notification(int p_what) {
} break;
case NOTIFICATION_ENTER_TREE: {
- tool_anim->get_popup()->connect("id_pressed", callable_mp(this, &AnimationPlayerEditor::_animation_tool_menu));
+ tool_anim->get_popup()->connect(SNAME("id_pressed"), callable_mp(this, &AnimationPlayerEditor::_animation_tool_menu));
- onion_skinning->get_popup()->connect("id_pressed", callable_mp(this, &AnimationPlayerEditor::_onion_skinning_menu));
+ onion_skinning->get_popup()->connect(SNAME("id_pressed"), callable_mp(this, &AnimationPlayerEditor::_onion_skinning_menu));
- blend_editor.next->connect("item_selected", callable_mp(this, &AnimationPlayerEditor::_blend_editor_next_changed));
+ blend_editor.next->connect(SNAME("item_selected"), callable_mp(this, &AnimationPlayerEditor::_blend_editor_next_changed));
- get_tree()->connect("node_removed", callable_mp(this, &AnimationPlayerEditor::_node_removed));
+ get_tree()->connect(SNAME("node_removed"), callable_mp(this, &AnimationPlayerEditor::_node_removed));
add_theme_style_override("panel", EditorNode::get_singleton()->get_editor_theme()->get_stylebox(SNAME("panel"), SNAME("Panel")));
} break;
@@ -167,6 +180,10 @@ void AnimationPlayerEditor::_notification(int p_what) {
_update_animation_list_icons();
} break;
+
+ case NOTIFICATION_VISIBILITY_CHANGED: {
+ _ensure_dummy_player();
+ } break;
}
}
@@ -303,20 +320,19 @@ void AnimationPlayerEditor::_animation_selected(int p_which) {
bool animation_library_is_foreign = EditorNode::get_singleton()->is_resource_read_only(anim);
track_editor->set_animation(anim, animation_library_is_foreign);
- Node *root = player->get_node(player->get_root());
+ Node *root = player->get_node_or_null(player->get_root_node());
if (root) {
track_editor->set_root(root);
}
}
frame->set_max((double)anim->get_length());
-
+ autoplay->set_pressed(current == player->get_autoplay());
} else {
track_editor->set_animation(Ref<Animation>(), true);
track_editor->set_root(nullptr);
+ autoplay->set_pressed(false);
}
- autoplay->set_pressed(current == player->get_autoplay());
-
AnimationPlayerEditor::get_singleton()->get_track_editor()->update_keying();
_animation_key_editor_seek(timeline_position, false);
@@ -506,6 +522,9 @@ void AnimationPlayerEditor::_animation_name_edited() {
undo_redo->add_undo_method(this, "_animation_player_changed", player);
undo_redo->commit_action();
+ if (is_dummy) {
+ plugin->_update_dummy_player(original_node);
+ }
_select_anim_by_name(new_library_prefix + new_name);
} break;
@@ -534,7 +553,7 @@ void AnimationPlayerEditor::_animation_name_edited() {
if (al.is_null()) {
al.instantiate();
lib_added = true;
- undo_redo->add_do_method(player, "add_animation_library", "", al);
+ undo_redo->add_do_method(fetch_mixer_for_library(), "add_animation_library", "", al);
library_name = "";
}
@@ -547,13 +566,17 @@ void AnimationPlayerEditor::_animation_name_edited() {
undo_redo->add_undo_method(this, "_stop_onion_skinning");
}
if (lib_added) {
- undo_redo->add_undo_method(player, "remove_animation_library", "");
+ undo_redo->add_undo_method(fetch_mixer_for_library(), "remove_animation_library", "");
}
undo_redo->commit_action();
if (library_name != "") {
library_name = library_name + "/";
}
+
+ if (is_dummy) {
+ plugin->_update_dummy_player(original_node);
+ }
_select_anim_by_name(library_name + new_name);
} break;
@@ -602,6 +625,10 @@ void AnimationPlayerEditor::_animation_name_edited() {
if (library_name != "") {
library_name = library_name + "/";
}
+
+ if (is_dummy) {
+ plugin->_update_dummy_player(original_node);
+ }
_select_anim_by_name(library_name + new_name);
} break;
}
@@ -714,7 +741,7 @@ void AnimationPlayerEditor::_blend_edited() {
}
void AnimationPlayerEditor::ensure_visibility() {
- if (player && pin->is_pressed()) {
+ if (player) {
return; // another player is pinned, don't reset
}
@@ -724,11 +751,13 @@ void AnimationPlayerEditor::ensure_visibility() {
Dictionary AnimationPlayerEditor::get_state() const {
Dictionary d;
- d["visible"] = is_visible_in_tree();
- if (EditorNode::get_singleton()->get_edited_scene() && is_visible_in_tree() && player) {
- d["player"] = EditorNode::get_singleton()->get_edited_scene()->get_path_to(player);
- d["animation"] = player->get_assigned_animation();
- d["track_editor_state"] = track_editor->get_state();
+ if (!is_dummy) {
+ d["visible"] = is_visible_in_tree();
+ if (EditorNode::get_singleton()->get_edited_scene() && is_visible_in_tree() && player) {
+ d["player"] = EditorNode::get_singleton()->get_edited_scene()->get_path_to(player);
+ d["animation"] = player->get_assigned_animation();
+ d["track_editor_state"] = track_editor->get_state();
+ }
}
return d;
@@ -746,14 +775,20 @@ void AnimationPlayerEditor::set_state(const Dictionary &p_state) {
Node *n = EditorNode::get_singleton()->get_edited_scene()->get_node(p_state["player"]);
if (Object::cast_to<AnimationPlayer>(n) && EditorNode::get_singleton()->get_editor_selection()->is_selected(n)) {
if (player) {
- if (player->is_connected("animation_libraries_updated", callable_mp(this, &AnimationPlayerEditor::_animation_libraries_updated))) {
- player->disconnect("animation_libraries_updated", callable_mp(this, &AnimationPlayerEditor::_animation_libraries_updated));
+ if (player->is_connected(SNAME("animation_list_changed"), callable_mp(this, &AnimationPlayerEditor::_animation_libraries_updated))) {
+ player->disconnect(SNAME("animation_list_changed"), callable_mp(this, &AnimationPlayerEditor::_animation_libraries_updated));
+ }
+ if (player->is_connected(SNAME("current_animation_changed"), callable_mp(this, &AnimationPlayerEditor::_current_animation_changed))) {
+ player->disconnect(SNAME("current_animation_changed"), callable_mp(this, &AnimationPlayerEditor::_current_animation_changed));
}
}
player = Object::cast_to<AnimationPlayer>(n);
if (player) {
- if (!player->is_connected("animation_libraries_updated", callable_mp(this, &AnimationPlayerEditor::_animation_libraries_updated))) {
- player->connect("animation_libraries_updated", callable_mp(this, &AnimationPlayerEditor::_animation_libraries_updated));
+ if (!player->is_connected(SNAME("animation_list_changed"), callable_mp(this, &AnimationPlayerEditor::_animation_libraries_updated))) {
+ player->connect(SNAME("animation_list_changed"), callable_mp(this, &AnimationPlayerEditor::_animation_libraries_updated), CONNECT_DEFERRED);
+ }
+ if (!player->is_connected(SNAME("current_animation_changed"), callable_mp(this, &AnimationPlayerEditor::_current_animation_changed))) {
+ player->connect(SNAME("current_animation_changed"), callable_mp(this, &AnimationPlayerEditor::_current_animation_changed), CONNECT_DEFERRED);
}
}
@@ -794,7 +829,7 @@ void AnimationPlayerEditor::_animation_edit() {
track_editor->set_animation(anim, animation_library_is_foreign);
- Node *root = player->get_node(player->get_root());
+ Node *root = player->get_node_or_null(player->get_root_node());
if (root) {
track_editor->set_root(root);
}
@@ -935,7 +970,7 @@ void AnimationPlayerEditor::_update_player() {
bool animation_library_is_foreign = EditorNode::get_singleton()->is_resource_read_only(anim);
track_editor->set_animation(anim, animation_library_is_foreign);
- Node *root = player->get_node(player->get_root());
+ Node *root = player->get_node_or_null(player->get_root_node());
if (root) {
track_editor->set_root(root);
}
@@ -1007,21 +1042,69 @@ void AnimationPlayerEditor::_update_name_dialog_library_dropdown() {
}
}
-void AnimationPlayerEditor::edit(AnimationPlayer *p_player) {
+void AnimationPlayerEditor::_ensure_dummy_player() {
+ bool dummy_exists = is_dummy && player && original_node;
+ if (dummy_exists) {
+ if (is_visible()) {
+ player->set_active(true);
+ original_node->set_editing(true);
+ } else {
+ player->set_active(false);
+ original_node->set_editing(false);
+ }
+ }
+
+ // Make some options disabled.
+ tool_anim->get_popup()->set_item_disabled(tool_anim->get_popup()->get_item_index(TOOL_EDIT_TRANSITIONS), dummy_exists);
+ onion_toggle->set_disabled(dummy_exists);
+ onion_skinning->set_disabled(dummy_exists);
+ int selected = animation->get_selected();
+ autoplay->set_disabled(selected != -1 ? (animation->get_item_text(selected).is_empty() ? true : dummy_exists) : true);
+
+ // Show warning.
+ if (track_editor) {
+ track_editor->show_dummy_player_warning(dummy_exists);
+ }
+}
+
+void AnimationPlayerEditor::edit(AnimationMixer *p_node, AnimationPlayer *p_player, bool p_is_dummy) {
if (player && pin->is_pressed()) {
return; // Ignore, pinned.
}
if (player) {
- if (player->is_connected("animation_libraries_updated", callable_mp(this, &AnimationPlayerEditor::_animation_libraries_updated))) {
- player->disconnect("animation_libraries_updated", callable_mp(this, &AnimationPlayerEditor::_animation_libraries_updated));
+ if (player->is_connected(SNAME("animation_list_changed"), callable_mp(this, &AnimationPlayerEditor::_animation_libraries_updated))) {
+ player->disconnect(SNAME("animation_list_changed"), callable_mp(this, &AnimationPlayerEditor::_animation_libraries_updated));
+ }
+ if (player->is_connected(SNAME("current_animation_changed"), callable_mp(this, &AnimationPlayerEditor::_current_animation_changed))) {
+ player->disconnect(SNAME("current_animation_changed"), callable_mp(this, &AnimationPlayerEditor::_current_animation_changed));
}
}
+
+ AnimationTree *tree = Object::cast_to<AnimationTree>(p_node);
+
+ if (tree) {
+ if (tree->is_connected(SNAME("animation_player_changed"), callable_mp(this, &AnimationPlayerEditor::unpin))) {
+ tree->disconnect(SNAME("animation_player_changed"), callable_mp(this, &AnimationPlayerEditor::unpin));
+ }
+ }
+
+ original_node = p_node;
player = p_player;
+ is_dummy = p_is_dummy;
+
+ if (tree) {
+ if (!tree->is_connected(SNAME("animation_player_changed"), callable_mp(this, &AnimationPlayerEditor::unpin))) {
+ tree->connect(SNAME("animation_player_changed"), callable_mp(this, &AnimationPlayerEditor::unpin));
+ }
+ }
if (player) {
- if (!player->is_connected("animation_libraries_updated", callable_mp(this, &AnimationPlayerEditor::_animation_libraries_updated))) {
- player->connect("animation_libraries_updated", callable_mp(this, &AnimationPlayerEditor::_animation_libraries_updated));
+ if (!player->is_connected(SNAME("animation_list_changed"), callable_mp(this, &AnimationPlayerEditor::_animation_libraries_updated))) {
+ player->connect(SNAME("animation_list_changed"), callable_mp(this, &AnimationPlayerEditor::_animation_libraries_updated), CONNECT_DEFERRED);
+ }
+ if (!player->is_connected(SNAME("current_animation_changed"), callable_mp(this, &AnimationPlayerEditor::_current_animation_changed))) {
+ player->connect(SNAME("current_animation_changed"), callable_mp(this, &AnimationPlayerEditor::_current_animation_changed));
}
_update_player();
@@ -1042,7 +1125,9 @@ void AnimationPlayerEditor::edit(AnimationPlayer *p_player) {
track_editor->show_select_node_warning(true);
}
- library_editor->set_animation_player(player);
+ library_editor->set_animation_mixer(fetch_mixer_for_library());
+
+ _ensure_dummy_player();
}
void AnimationPlayerEditor::forward_force_draw_over_viewport(Control *p_overlay) {
@@ -1181,12 +1266,12 @@ void AnimationPlayerEditor::_seek_value_changed(float p_value, bool p_set, bool
if (!p_timeline_only) {
if (player->is_valid() && !p_set) {
- float cpos = player->get_current_animation_position();
-
- player->seek_delta(pos, pos - cpos);
+ double delta = pos - player->get_current_animation_position();
+ player->seek(pos, true, true);
+ player->seek(pos + delta, true, true);
} else {
player->stop();
- player->seek(pos, true);
+ player->seek(pos, true, true);
}
}
@@ -1194,14 +1279,12 @@ void AnimationPlayerEditor::_seek_value_changed(float p_value, bool p_set, bool
};
void AnimationPlayerEditor::_animation_player_changed(Object *p_pl) {
- if (player == p_pl && is_visible_in_tree()) {
- _update_player();
- if (blend_editor.dialog->is_visible()) {
- _animation_blend(); // Update.
- }
- if (library_editor->is_visible()) {
- library_editor->update_tree();
- }
+ _update_player();
+ if (blend_editor.dialog->is_visible()) {
+ _animation_blend(); // Update.
+ }
+ if (library_editor->is_visible()) {
+ library_editor->update_tree();
}
}
@@ -1215,6 +1298,25 @@ void AnimationPlayerEditor::_list_changed() {
}
}
+void AnimationPlayerEditor::_current_animation_changed(const String &p_name) {
+ if (is_visible_in_tree()) {
+ if (p_name.is_empty()) {
+ // Means [stop].
+ frame->set_value(0);
+ track_editor->set_anim_pos(0);
+ _update_animation();
+ return;
+ }
+ Ref<Animation> anim = player->get_animation(p_name);
+ if (anim.is_null()) {
+ return;
+ }
+ bool animation_library_is_foreign = EditorNode::get_singleton()->is_resource_read_only(anim);
+ track_editor->set_animation(anim, animation_library_is_foreign);
+ _update_animation();
+ }
+}
+
void AnimationPlayerEditor::_animation_key_editor_anim_len_changed(float p_len) {
frame->set_max(p_len);
}
@@ -1257,7 +1359,7 @@ void AnimationPlayerEditor::_animation_tool_menu(int p_option) {
_animation_new();
} break;
case TOOL_ANIM_LIBRARY: {
- library_editor->set_animation_player(player);
+ library_editor->set_animation_mixer(fetch_mixer_for_library());
library_editor->show_dialog();
} break;
case TOOL_DUPLICATE_ANIM: {
@@ -1267,6 +1369,9 @@ void AnimationPlayerEditor::_animation_tool_menu(int p_option) {
_animation_rename();
} break;
case TOOL_EDIT_TRANSITIONS: {
+ if (is_dummy) {
+ break;
+ }
_animation_blend();
} break;
case TOOL_REMOVE_ANIM: {
@@ -1506,7 +1611,7 @@ void AnimationPlayerEditor::_prepare_onion_layers_2() {
}
// Backup current animation state.
- Ref<AnimatedValuesBackup> values_backup = player->backup_animated_values();
+ Ref<AnimatedValuesBackup> backup_current = player->make_backup();
float cpos = player->get_current_animation_position();
// Render every past/future step with the capture shader.
@@ -1536,7 +1641,6 @@ void AnimationPlayerEditor::_prepare_onion_layers_2() {
if (valid) {
player->seek(pos, true);
get_tree()->flush_transform_notifications(); // Needed for transforms of Node3Ds.
- values_backup->update_skeletons(); // Needed for Skeletons (2D & 3D).
RS::get_singleton()->viewport_set_active(onion.captures[cidx], true);
RS::get_singleton()->viewport_set_parent_viewport(root_vp, onion.captures[cidx]);
@@ -1556,7 +1660,7 @@ void AnimationPlayerEditor::_prepare_onion_layers_2() {
// (Seeking with update=true wouldn't do the trick because the current value of the properties
// may not match their value for the current point in the animation).
player->seek(cpos, false);
- values_backup->restore();
+ player->restore(backup_current);
// Restore state of main editors.
if (Node3DEditor::get_singleton()->is_visible()) {
@@ -1574,14 +1678,14 @@ void AnimationPlayerEditor::_prepare_onion_layers_2() {
void AnimationPlayerEditor::_start_onion_skinning() {
// FIXME: Using "process_frame" makes onion layers update one frame behind the current.
- if (!get_tree()->is_connected("process_frame", callable_mp(this, &AnimationPlayerEditor::_prepare_onion_layers_1_deferred))) {
- get_tree()->connect("process_frame", callable_mp(this, &AnimationPlayerEditor::_prepare_onion_layers_1_deferred));
+ if (!get_tree()->is_connected(SNAME("process_frame"), callable_mp(this, &AnimationPlayerEditor::_prepare_onion_layers_1_deferred))) {
+ get_tree()->connect(SNAME("process_frame"), callable_mp(this, &AnimationPlayerEditor::_prepare_onion_layers_1_deferred));
}
}
void AnimationPlayerEditor::_stop_onion_skinning() {
- if (get_tree()->is_connected("process_frame", callable_mp(this, &AnimationPlayerEditor::_prepare_onion_layers_1_deferred))) {
- get_tree()->disconnect("process_frame", callable_mp(this, &AnimationPlayerEditor::_prepare_onion_layers_1_deferred));
+ if (get_tree()->is_connected(SNAME("process_frame"), callable_mp(this, &AnimationPlayerEditor::_prepare_onion_layers_1_deferred))) {
+ get_tree()->disconnect(SNAME("process_frame"), callable_mp(this, &AnimationPlayerEditor::_prepare_onion_layers_1_deferred));
_free_onion_layers();
@@ -1595,6 +1699,21 @@ void AnimationPlayerEditor::_pin_pressed() {
SceneTreeDock::get_singleton()->get_tree_editor()->update_tree();
}
+AnimationMixer *AnimationPlayerEditor::fetch_mixer_for_library() const {
+ if (!original_node) {
+ return nullptr;
+ }
+ // Does AnimationTree have AnimationPlayer?
+ if (original_node->is_class("AnimationTree")) {
+ AnimationTree *src_tree = Object::cast_to<AnimationTree>(original_node);
+ Node *src_player = src_tree->get_node_or_null(src_tree->get_animation_player());
+ if (src_player) {
+ return Object::cast_to<AnimationMixer>(src_player);
+ }
+ }
+ return original_node;
+}
+
bool AnimationPlayerEditor::_validate_tracks(const Ref<Animation> p_anim) {
bool is_valid = true;
if (!p_anim.is_valid()) {
@@ -1668,6 +1787,10 @@ AnimationPlayer *AnimationPlayerEditor::get_player() const {
return player;
}
+AnimationMixer *AnimationPlayerEditor::get_editing_node() const {
+ return original_node;
+}
+
AnimationPlayerEditor::AnimationPlayerEditor(AnimationPlayerEditorPlugin *p_plugin) {
plugin = p_plugin;
singleton = this;
@@ -1724,7 +1847,7 @@ AnimationPlayerEditor::AnimationPlayerEditor(AnimationPlayerEditorPlugin *p_plug
delete_dialog = memnew(ConfirmationDialog);
add_child(delete_dialog);
- delete_dialog->connect("confirmed", callable_mp(this, &AnimationPlayerEditor::_animation_remove_confirmed));
+ delete_dialog->connect(SNAME("confirmed"), callable_mp(this, &AnimationPlayerEditor::_animation_remove_confirmed));
tool_anim = memnew(MenuButton);
tool_anim->set_shortcut_context(this);
@@ -1769,7 +1892,7 @@ AnimationPlayerEditor::AnimationPlayerEditor(AnimationPlayerEditorPlugin *p_plug
onion_toggle->set_theme_type_variation("FlatButton");
onion_toggle->set_toggle_mode(true);
onion_toggle->set_tooltip_text(TTR("Enable Onion Skinning"));
- onion_toggle->connect("pressed", callable_mp(this, &AnimationPlayerEditor::_onion_skinning_menu).bind(ONION_SKINNING_ENABLE));
+ onion_toggle->connect(SNAME("pressed"), callable_mp(this, &AnimationPlayerEditor::_onion_skinning_menu).bind(ONION_SKINNING_ENABLE));
hb->add_child(onion_toggle);
onion_skinning = memnew(MenuButton);
@@ -1808,7 +1931,7 @@ AnimationPlayerEditor::AnimationPlayerEditor(AnimationPlayerEditorPlugin *p_plug
pin->set_toggle_mode(true);
pin->set_tooltip_text(TTR("Pin AnimationPlayer"));
hb->add_child(pin);
- pin->connect("pressed", callable_mp(this, &AnimationPlayerEditor::_pin_pressed));
+ pin->connect(SNAME("pressed"), callable_mp(this, &AnimationPlayerEditor::_pin_pressed));
file = memnew(EditorFileDialog);
add_child(file);
@@ -1838,7 +1961,7 @@ AnimationPlayerEditor::AnimationPlayerEditor(AnimationPlayerEditorPlugin *p_plug
error_dialog->set_title(TTR("Error!"));
add_child(error_dialog);
- name_dialog->connect("confirmed", callable_mp(this, &AnimationPlayerEditor::_animation_name_edited));
+ name_dialog->connect(SNAME("confirmed"), callable_mp(this, &AnimationPlayerEditor::_animation_name_edited));
blend_editor.dialog = memnew(AcceptDialog);
add_child(blend_editor.dialog);
@@ -1855,20 +1978,20 @@ AnimationPlayerEditor::AnimationPlayerEditor(AnimationPlayerEditorPlugin *p_plug
blend_editor.dialog->set_title(TTR("Cross-Animation Blend Times"));
updating_blends = false;
- blend_editor.tree->connect("item_edited", callable_mp(this, &AnimationPlayerEditor::_blend_edited));
+ blend_editor.tree->connect(SNAME("item_edited"), callable_mp(this, &AnimationPlayerEditor::_blend_edited));
- autoplay->connect("pressed", callable_mp(this, &AnimationPlayerEditor::_autoplay_pressed));
+ autoplay->connect(SNAME("pressed"), callable_mp(this, &AnimationPlayerEditor::_autoplay_pressed));
autoplay->set_toggle_mode(true);
- play->connect("pressed", callable_mp(this, &AnimationPlayerEditor::_play_pressed));
- play_from->connect("pressed", callable_mp(this, &AnimationPlayerEditor::_play_from_pressed));
- play_bw->connect("pressed", callable_mp(this, &AnimationPlayerEditor::_play_bw_pressed));
- play_bw_from->connect("pressed", callable_mp(this, &AnimationPlayerEditor::_play_bw_from_pressed));
- stop->connect("pressed", callable_mp(this, &AnimationPlayerEditor::_stop_pressed));
+ play->connect(SNAME("pressed"), callable_mp(this, &AnimationPlayerEditor::_play_pressed));
+ play_from->connect(SNAME("pressed"), callable_mp(this, &AnimationPlayerEditor::_play_from_pressed));
+ play_bw->connect(SNAME("pressed"), callable_mp(this, &AnimationPlayerEditor::_play_bw_pressed));
+ play_bw_from->connect(SNAME("pressed"), callable_mp(this, &AnimationPlayerEditor::_play_bw_from_pressed));
+ stop->connect(SNAME("pressed"), callable_mp(this, &AnimationPlayerEditor::_stop_pressed));
- animation->connect("item_selected", callable_mp(this, &AnimationPlayerEditor::_animation_selected));
+ animation->connect(SNAME("item_selected"), callable_mp(this, &AnimationPlayerEditor::_animation_selected));
- frame->connect("value_changed", callable_mp(this, &AnimationPlayerEditor::_seek_value_changed).bind(true, false));
- scale->connect("text_submitted", callable_mp(this, &AnimationPlayerEditor::_scale_changed));
+ frame->connect(SNAME("value_changed"), callable_mp(this, &AnimationPlayerEditor::_seek_value_changed).bind(true, false));
+ scale->connect(SNAME("text_submitted"), callable_mp(this, &AnimationPlayerEditor::_scale_changed));
last_active = false;
timeline_position = 0;
@@ -1877,18 +2000,18 @@ AnimationPlayerEditor::AnimationPlayerEditor(AnimationPlayerEditorPlugin *p_plug
add_child(track_editor);
track_editor->set_v_size_flags(SIZE_EXPAND_FILL);
- track_editor->connect("timeline_changed", callable_mp(this, &AnimationPlayerEditor::_animation_key_editor_seek));
- track_editor->connect("animation_len_changed", callable_mp(this, &AnimationPlayerEditor::_animation_key_editor_anim_len_changed));
+ track_editor->connect(SNAME("timeline_changed"), callable_mp(this, &AnimationPlayerEditor::_animation_key_editor_seek));
+ track_editor->connect(SNAME("animation_len_changed"), callable_mp(this, &AnimationPlayerEditor::_animation_key_editor_anim_len_changed));
_update_player();
library_editor = memnew(AnimationLibraryEditor);
add_child(library_editor);
- library_editor->connect("update_editor", callable_mp(this, &AnimationPlayerEditor::_animation_player_changed));
+ library_editor->connect(SNAME("update_editor"), callable_mp(this, &AnimationPlayerEditor::_animation_player_changed));
// Onion skinning.
- track_editor->connect("visibility_changed", callable_mp(this, &AnimationPlayerEditor::_editor_visibility_changed));
+ track_editor->connect(SNAME("visibility_changed"), callable_mp(this, &AnimationPlayerEditor::_editor_visibility_changed));
onion.enabled = false;
onion.past = true;
@@ -1943,10 +2066,10 @@ AnimationPlayerEditor::~AnimationPlayerEditor() {
void AnimationPlayerEditorPlugin::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
- Node3DEditor::get_singleton()->connect("transform_key_request", callable_mp(this, &AnimationPlayerEditorPlugin::_transform_key_request));
- InspectorDock::get_inspector_singleton()->connect("property_keyed", callable_mp(this, &AnimationPlayerEditorPlugin::_property_keyed));
- anim_editor->get_track_editor()->connect("keying_changed", callable_mp(this, &AnimationPlayerEditorPlugin::_update_keying));
- InspectorDock::get_inspector_singleton()->connect("edited_object_changed", callable_mp(anim_editor->get_track_editor(), &AnimationTrackEditor::update_keying));
+ Node3DEditor::get_singleton()->connect(SNAME("transform_key_request"), callable_mp(this, &AnimationPlayerEditorPlugin::_transform_key_request));
+ InspectorDock::get_inspector_singleton()->connect(SNAME("property_keyed"), callable_mp(this, &AnimationPlayerEditorPlugin::_property_keyed));
+ anim_editor->get_track_editor()->connect(SNAME("keying_changed"), callable_mp(this, &AnimationPlayerEditorPlugin::_update_keying));
+ InspectorDock::get_inspector_singleton()->connect(SNAME("edited_object_changed"), callable_mp(anim_editor->get_track_editor(), &AnimationTrackEditor::update_keying));
set_force_draw_over_forwarding_enabled();
} break;
}
@@ -1979,14 +2102,88 @@ void AnimationPlayerEditorPlugin::_update_keying() {
}
void AnimationPlayerEditorPlugin::edit(Object *p_object) {
+ if (player && anim_editor && anim_editor->is_pinned()) {
+ return; // Ignore, pinned.
+ }
+
+ player = nullptr;
if (!p_object) {
return;
}
- anim_editor->edit(Object::cast_to<AnimationPlayer>(p_object));
+ last_mixer = p_object->get_instance_id();
+
+ AnimationMixer *src_node = Object::cast_to<AnimationMixer>(p_object);
+ bool is_dummy = false;
+ if (!p_object->is_class("AnimationPlayer")) {
+ // If it needs dummy AnimationPlayer, assign original AnimationMixer to LibraryEditor.
+ _update_dummy_player(src_node);
+
+ is_dummy = true;
+
+ if (!src_node->is_connected(SNAME("mixer_updated"), callable_mp(this, &AnimationPlayerEditorPlugin::_update_dummy_player))) {
+ src_node->connect(SNAME("mixer_updated"), callable_mp(this, &AnimationPlayerEditorPlugin::_update_dummy_player).bind(src_node), CONNECT_DEFERRED);
+ }
+ if (!src_node->is_connected(SNAME("animation_libraries_updated"), callable_mp(this, &AnimationPlayerEditorPlugin::_update_dummy_player))) {
+ src_node->connect(SNAME("animation_libraries_updated"), callable_mp(this, &AnimationPlayerEditorPlugin::_update_dummy_player).bind(src_node), CONNECT_DEFERRED);
+ }
+ } else {
+ _clear_dummy_player();
+ player = Object::cast_to<AnimationPlayer>(p_object);
+ }
+ player->set_dummy(is_dummy);
+
+ anim_editor->edit(src_node, player, is_dummy);
+}
+
+void AnimationPlayerEditorPlugin::_clear_dummy_player() {
+ if (!dummy_player) {
+ return;
+ }
+ Node *parent = dummy_player->get_parent();
+ if (parent) {
+ parent->call_deferred("remove_child", dummy_player);
+ }
+ dummy_player->queue_free();
+ dummy_player = nullptr;
+}
+
+void AnimationPlayerEditorPlugin::_update_dummy_player(AnimationMixer *p_mixer) {
+ // Check current editing object.
+ if (p_mixer->get_instance_id() != last_mixer && p_mixer->is_connected(SNAME("mixer_updated"), callable_mp(this, &AnimationPlayerEditorPlugin::_update_dummy_player))) {
+ p_mixer->disconnect(SNAME("mixer_updated"), callable_mp(this, &AnimationPlayerEditorPlugin::_update_dummy_player));
+ return;
+ }
+
+ // Add dummy player to scene.
+ if (!dummy_player) {
+ Node *parent = p_mixer->get_parent();
+ ERR_FAIL_NULL(parent);
+ dummy_player = memnew(AnimationPlayer);
+ parent->add_child(dummy_player);
+ }
+ player = dummy_player;
+
+ // Convert AnimationTree (AnimationMixer) to AnimationPlayer.
+ AnimationMixer *default_node = memnew(AnimationMixer);
+ List<PropertyInfo> pinfo;
+ default_node->get_property_list(&pinfo);
+ for (const PropertyInfo &E : pinfo) {
+ if (!(E.usage & PROPERTY_USAGE_STORAGE)) {
+ continue;
+ }
+ if (E.name != "script" && E.name != "active" && E.name != "deterministic" && E.name != "root_motion_track") {
+ dummy_player->set(E.name, p_mixer->get(E.name));
+ }
+ }
+ memdelete(default_node);
+
+ if (anim_editor) {
+ anim_editor->_update_player();
+ }
}
bool AnimationPlayerEditorPlugin::handles(Object *p_object) const {
- return p_object->is_class("AnimationPlayer");
+ return p_object->is_class("AnimationPlayer") || p_object->is_class("AnimationTree") || p_object->is_class("AnimationMixer");
}
void AnimationPlayerEditorPlugin::make_visible(bool p_visible) {
@@ -2003,6 +2200,12 @@ AnimationPlayerEditorPlugin::AnimationPlayerEditorPlugin() {
}
AnimationPlayerEditorPlugin::~AnimationPlayerEditorPlugin() {
+ if (dummy_player) {
+ memdelete(dummy_player);
+ }
+ if (player) {
+ memdelete(player);
+ }
}
// AnimationTrackKeyEditEditorPlugin