Skip to content

Commit 2993289

Browse files
committed
Merge pull request #86481 from Illauriel/add-animlib-folding
Add persistent folding to Animation Library Editor
2 parents 5289709 + 5de38f7 commit 2993289

File tree

4 files changed

+222
-1
lines changed

4 files changed

+222
-1
lines changed

editor/plugins/animation_library_editor.cpp

Lines changed: 202 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,12 @@
3030

3131
#include "animation_library_editor.h"
3232

33+
#include "core/string/print_string.h"
34+
#include "core/string/ustring.h"
35+
#include "core/templates/vector.h"
36+
#include "core/variant/variant.h"
3337
#include "editor/editor_node.h"
38+
#include "editor/editor_paths.h"
3439
#include "editor/editor_settings.h"
3540
#include "editor/editor_string_names.h"
3641
#include "editor/editor_undo_redo_manager.h"
@@ -518,6 +523,8 @@ void AnimationLibraryEditor::_item_renamed() {
518523
if (restore_text) {
519524
ti->set_text(0, old_text);
520525
}
526+
527+
_save_mixer_lib_folding(ti);
521528
}
522529

523530
void AnimationLibraryEditor::_button_pressed(TreeItem *p_item, int p_column, int p_id, MouseButton p_button) {
@@ -670,6 +677,8 @@ void AnimationLibraryEditor::update_tree() {
670677

671678
TreeItem *root = tree->create_item();
672679
List<StringName> libs;
680+
Vector<uint64_t> collapsed_lib_ids = _load_mixer_libs_folding();
681+
673682
mixer->get_animation_library_list(&libs);
674683

675684
for (const StringName &K : libs) {
@@ -759,12 +768,203 @@ void AnimationLibraryEditor::update_tree() {
759768
anitem->set_text(1, anim_path.get_file());
760769
}
761770
}
771+
762772
anitem->add_button(1, get_editor_theme_icon("Save"), ANIM_BUTTON_FILE, animation_library_is_foreign, TTR("Save animation to resource on disk."));
763773
anitem->add_button(1, get_editor_theme_icon("Remove"), ANIM_BUTTON_DELETE, animation_library_is_foreign, TTR("Remove animation from Library."));
774+
775+
for (const uint64_t &lib_id : collapsed_lib_ids) {
776+
Object *lib_obj = ObjectDB::get_instance(ObjectID(lib_id));
777+
AnimationLibrary *cur_lib = Object::cast_to<AnimationLibrary>(lib_obj);
778+
StringName M = mixer->get_animation_library_name(cur_lib);
779+
780+
if (M == K) {
781+
libitem->set_collapsed_recursive(true);
782+
}
783+
}
764784
}
765785
}
766786
}
767787

788+
void AnimationLibraryEditor::_save_mixer_lib_folding(TreeItem *p_item) {
789+
//Check if ti is a library or animation
790+
if (p_item->get_parent()->get_parent() != nullptr) {
791+
return;
792+
}
793+
794+
Ref<ConfigFile> config;
795+
config.instantiate();
796+
797+
String path = EditorPaths::get_singleton()->get_project_settings_dir().path_join("lib_folding.cfg");
798+
Error err = config->load(path);
799+
if (err != OK && err != ERR_FILE_NOT_FOUND) {
800+
ERR_PRINT("Error loading lib_folding.cfg: " + itos(err));
801+
}
802+
803+
// Get unique identifier for this scene+mixer combination
804+
String md = (mixer->get_tree()->get_edited_scene_root()->get_scene_file_path() + mixer->get_path()).md5_text();
805+
806+
PackedStringArray collapsed_lib_names;
807+
PackedStringArray collapsed_lib_ids;
808+
809+
if (config->has_section(md)) {
810+
collapsed_lib_names = String(config->get_value(md, "folding")).split("\n");
811+
collapsed_lib_ids = String(config->get_value(md, "id")).split("\n");
812+
}
813+
814+
String lib_name = p_item->get_text(0);
815+
816+
// Get library reference and check validity
817+
Ref<AnimationLibrary> al;
818+
uint64_t lib_id = 0;
819+
820+
if (mixer->has_animation_library(lib_name)) {
821+
al = mixer->get_animation_library(lib_name);
822+
ERR_FAIL_COND(al.is_null());
823+
lib_id = uint64_t(al->get_instance_id());
824+
} else {
825+
ERR_PRINT("Library not found: " + lib_name);
826+
}
827+
828+
int at = collapsed_lib_names.find(lib_name);
829+
if (p_item->is_collapsed()) {
830+
if (at != -1) {
831+
//Entry exists and needs updating
832+
collapsed_lib_ids.set(at, String::num_int64(lib_id + INT64_MIN));
833+
} else {
834+
//Check if it's a rename
835+
int id_at = collapsed_lib_ids.find(String::num_int64(lib_id + INT64_MIN));
836+
if (id_at != -1) {
837+
//It's actually a rename
838+
collapsed_lib_names.set(id_at, lib_name);
839+
} else {
840+
//It's a new entry
841+
collapsed_lib_names.append(lib_name);
842+
collapsed_lib_ids.append(String::num_int64(lib_id + INT64_MIN));
843+
}
844+
}
845+
} else {
846+
if (at != -1) {
847+
collapsed_lib_names.remove_at(at);
848+
collapsed_lib_ids.remove_at(at);
849+
}
850+
}
851+
852+
//Runtime IDs
853+
config->set_value(md, "root", uint64_t(mixer->get_tree()->get_edited_scene_root()->get_instance_id()));
854+
config->set_value(md, "mixer", uint64_t(mixer->get_instance_id()));
855+
856+
//Plan B recovery mechanism
857+
config->set_value(md, "mixer_signature", _get_mixer_signature());
858+
859+
//Save folding state as text and runtime ID
860+
config->set_value(md, "folding", String("\n").join(collapsed_lib_names));
861+
config->set_value(md, "id", String("\n").join(collapsed_lib_ids));
862+
863+
err = config->save(path);
864+
if (err != OK) {
865+
ERR_PRINT("Error saving lib_folding.cfg: " + itos(err));
866+
}
867+
}
868+
869+
Vector<uint64_t> AnimationLibraryEditor::_load_mixer_libs_folding() {
870+
Ref<ConfigFile> config;
871+
config.instantiate();
872+
873+
String path = EditorPaths::get_singleton()->get_project_settings_dir().path_join("lib_folding.cfg");
874+
Error err = config->load(path);
875+
if (err != OK && err != ERR_FILE_NOT_FOUND) {
876+
ERR_PRINT("Error loading lib_folding.cfg: " + itos(err));
877+
return Vector<uint64_t>();
878+
}
879+
880+
// Get unique identifier for this scene+mixer combination
881+
String md = (mixer->get_tree()->get_edited_scene_root()->get_scene_file_path() + mixer->get_path()).md5_text();
882+
883+
Vector<uint64_t> collapsed_lib_ids;
884+
885+
if (config->has_section(md)) {
886+
_load_config_libs_folding(collapsed_lib_ids, config.ptr(), md);
887+
888+
} else {
889+
//The scene/mixer combination is no longer valid and we'll try to recover
890+
uint64_t current_mixer_id = uint64_t(mixer->get_instance_id());
891+
String current_mixer_signature = _get_mixer_signature();
892+
List<String> sections;
893+
config->get_sections(&sections);
894+
895+
for (const String &section : sections) {
896+
Variant mixer_id = config->get_value(section, "mixer");
897+
if ((mixer_id.get_type() == Variant::INT && uint64_t(mixer_id) == current_mixer_id) || config->get_value(section, "mixer_signature") == current_mixer_signature) { // Ensure value exists and is correct type
898+
// Found the mixer in a different section!
899+
_load_config_libs_folding(collapsed_lib_ids, config.ptr(), section);
900+
901+
//Cleanup old entry and copy fold data into new one!
902+
String collapsed_lib_names_str = String(config->get_value(section, "folding"));
903+
String collapsed_lib_ids_str = String(config->get_value(section, "id"));
904+
config->erase_section(section);
905+
906+
config->set_value(md, "root", uint64_t(mixer->get_tree()->get_edited_scene_root()->get_instance_id()));
907+
config->set_value(md, "mixer", uint64_t(mixer->get_instance_id()));
908+
config->set_value(md, "mixer_signature", _get_mixer_signature());
909+
config->set_value(md, "folding", collapsed_lib_names_str);
910+
config->set_value(md, "id", collapsed_lib_ids_str);
911+
912+
err = config->save(path);
913+
if (err != OK) {
914+
ERR_PRINT("Error saving lib_folding.cfg: " + itos(err));
915+
}
916+
break;
917+
}
918+
}
919+
}
920+
921+
return collapsed_lib_ids;
922+
}
923+
924+
void AnimationLibraryEditor::_load_config_libs_folding(Vector<uint64_t> &p_lib_ids, ConfigFile *p_config, String p_section) {
925+
if (uint64_t(p_config->get_value(p_section, "root", 0)) != uint64_t(mixer->get_tree()->get_edited_scene_root()->get_instance_id())) {
926+
// Root changed - tries to match by library names
927+
PackedStringArray collapsed_lib_names = String(p_config->get_value(p_section, "folding", "")).split("\n");
928+
for (const String &lib_name : collapsed_lib_names) {
929+
if (mixer->has_animation_library(lib_name)) {
930+
p_lib_ids.append(mixer->get_animation_library(lib_name)->get_instance_id());
931+
} else {
932+
print_line("Can't find ", lib_name, " in mixer");
933+
}
934+
}
935+
} else {
936+
// Root same - uses saved instance IDs
937+
for (const String &saved_id : String(p_config->get_value(p_section, "id")).split("\n")) {
938+
p_lib_ids.append(uint64_t(saved_id.to_int() - INT64_MIN));
939+
}
940+
}
941+
}
942+
943+
String AnimationLibraryEditor::_get_mixer_signature() const {
944+
String signature = String();
945+
946+
// Get all libraries sorted for consistency
947+
List<StringName> libs;
948+
mixer->get_animation_library_list(&libs);
949+
libs.sort_custom<StringName::AlphCompare>();
950+
951+
// Add libraries and their animations to signature
952+
for (const StringName &lib_name : libs) {
953+
signature += "::" + String(lib_name);
954+
Ref<AnimationLibrary> lib = mixer->get_animation_library(lib_name);
955+
if (lib.is_valid()) {
956+
List<StringName> anims;
957+
lib->get_animation_list(&anims);
958+
anims.sort_custom<StringName::AlphCompare>();
959+
for (const StringName &anim_name : anims) {
960+
signature += "," + String(anim_name);
961+
}
962+
}
963+
}
964+
965+
return signature.md5_text();
966+
}
967+
768968
void AnimationLibraryEditor::show_dialog() {
769969
update_tree();
770970
popup_centered_ratio(0.5);
@@ -855,11 +1055,12 @@ AnimationLibraryEditor::AnimationLibraryEditor() {
8551055
tree->set_column_custom_minimum_width(1, EDSCALE * 250);
8561056
tree->set_column_expand(1, false);
8571057
tree->set_hide_root(true);
858-
tree->set_hide_folding(true);
1058+
tree->set_hide_folding(false);
8591059
tree->set_v_size_flags(Control::SIZE_EXPAND_FILL);
8601060

8611061
tree->connect("item_edited", callable_mp(this, &AnimationLibraryEditor::_item_renamed));
8621062
tree->connect("button_clicked", callable_mp(this, &AnimationLibraryEditor::_button_pressed));
1063+
tree->connect("item_collapsed", callable_mp(this, &AnimationLibraryEditor::_save_mixer_lib_folding));
8631064

8641065
file_popup = memnew(PopupMenu);
8651066
add_child(file_popup);

editor/plugins/animation_library_editor.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@
3131
#ifndef ANIMATION_LIBRARY_EDITOR_H
3232
#define ANIMATION_LIBRARY_EDITOR_H
3333

34+
#include "core/io/config_file.h"
35+
#include "core/templates/vector.h"
3436
#include "editor/animation_track_editor.h"
3537
#include "editor/plugins/editor_plugin.h"
3638
#include "scene/animation/animation_mixer.h"
@@ -103,6 +105,11 @@ class AnimationLibraryEditor : public AcceptDialog {
103105
void _load_file(const String &p_path);
104106
void _load_files(const PackedStringArray &p_paths);
105107

108+
void _save_mixer_lib_folding(TreeItem *p_item);
109+
Vector<uint64_t> _load_mixer_libs_folding();
110+
void _load_config_libs_folding(Vector<uint64_t> &p_lib_ids, ConfigFile *p_config, String p_section);
111+
String _get_mixer_signature() const;
112+
106113
void _item_renamed();
107114
void _button_pressed(TreeItem *p_item, int p_column, int p_id, MouseButton p_button);
108115

scene/animation/animation_mixer.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@
3333

3434
#include "core/config/engine.h"
3535
#include "core/config/project_settings.h"
36+
#include "core/string/print_string.h"
37+
#include "core/string/string_name.h"
3638
#include "scene/2d/audio_stream_player_2d.h"
3739
#include "scene/animation/animation_player.h"
3840
#include "scene/audio/audio_stream_player.h"
@@ -267,6 +269,16 @@ bool AnimationMixer::has_animation_library(const StringName &p_name) const {
267269
return false;
268270
}
269271

272+
StringName AnimationMixer::get_animation_library_name(const Ref<AnimationLibrary> &p_animation_library) const {
273+
ERR_FAIL_COND_V(p_animation_library.is_null(), StringName());
274+
for (const AnimationLibraryData &lib : animation_libraries) {
275+
if (lib.library == p_animation_library) {
276+
return lib.name;
277+
}
278+
}
279+
return StringName();
280+
}
281+
270282
StringName AnimationMixer::find_animation_library(const Ref<Animation> &p_animation) const {
271283
for (const KeyValue<StringName, AnimationData> &E : animation_set) {
272284
if (E.value.animation == p_animation) {

scene/animation/animation_mixer.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -409,6 +409,7 @@ class AnimationMixer : public Node {
409409
void get_animation_library_list(List<StringName> *p_animations) const;
410410
Ref<AnimationLibrary> get_animation_library(const StringName &p_name) const;
411411
bool has_animation_library(const StringName &p_name) const;
412+
StringName get_animation_library_name(const Ref<AnimationLibrary> &p_animation_library) const;
412413
StringName find_animation_library(const Ref<Animation> &p_animation) const;
413414
Error add_animation_library(const StringName &p_name, const Ref<AnimationLibrary> &p_animation_library);
414415
void remove_animation_library(const StringName &p_name);

0 commit comments

Comments
 (0)