diff options
author | Illauriel <gorionsl@gmail.com> | 2023-12-24 03:57:36 +0100 |
---|---|---|
committer | Illauriel <gorionsl@gmail.com> | 2024-11-19 20:01:30 +0100 |
commit | 5de38f7fd35606e1f494d81919f094e5e7baf0c0 (patch) | |
tree | 2ef1e6314ca3d8ab0bac04c3cc7f038ddbca379e /editor/plugins | |
parent | 673f396677654220d7e1d5b6fb5ed3b50126b4e6 (diff) | |
download | redot-engine-5de38f7fd35606e1f494d81919f094e5e7baf0c0.tar.gz |
Add persistent folding to Animation Library Editor
Diffstat (limited to 'editor/plugins')
-rw-r--r-- | editor/plugins/animation_library_editor.cpp | 203 | ||||
-rw-r--r-- | editor/plugins/animation_library_editor.h | 7 |
2 files changed, 209 insertions, 1 deletions
diff --git a/editor/plugins/animation_library_editor.cpp b/editor/plugins/animation_library_editor.cpp index 4e8a1bd89b..46410b581e 100644 --- a/editor/plugins/animation_library_editor.cpp +++ b/editor/plugins/animation_library_editor.cpp @@ -30,7 +30,12 @@ #include "animation_library_editor.h" +#include "core/string/print_string.h" +#include "core/string/ustring.h" +#include "core/templates/vector.h" +#include "core/variant/variant.h" #include "editor/editor_node.h" +#include "editor/editor_paths.h" #include "editor/editor_settings.h" #include "editor/editor_string_names.h" #include "editor/editor_undo_redo_manager.h" @@ -518,6 +523,8 @@ void AnimationLibraryEditor::_item_renamed() { if (restore_text) { ti->set_text(0, old_text); } + + _save_mixer_lib_folding(ti); } void AnimationLibraryEditor::_button_pressed(TreeItem *p_item, int p_column, int p_id, MouseButton p_button) { @@ -670,6 +677,8 @@ void AnimationLibraryEditor::update_tree() { TreeItem *root = tree->create_item(); List<StringName> libs; + Vector<uint64_t> collapsed_lib_ids = _load_mixer_libs_folding(); + mixer->get_animation_library_list(&libs); for (const StringName &K : libs) { @@ -759,12 +768,203 @@ void AnimationLibraryEditor::update_tree() { anitem->set_text(1, anim_path.get_file()); } } + anitem->add_button(1, get_editor_theme_icon("Save"), ANIM_BUTTON_FILE, animation_library_is_foreign, TTR("Save animation to resource on disk.")); anitem->add_button(1, get_editor_theme_icon("Remove"), ANIM_BUTTON_DELETE, animation_library_is_foreign, TTR("Remove animation from Library.")); + + for (const uint64_t &lib_id : collapsed_lib_ids) { + Object *lib_obj = ObjectDB::get_instance(ObjectID(lib_id)); + AnimationLibrary *cur_lib = Object::cast_to<AnimationLibrary>(lib_obj); + StringName M = mixer->get_animation_library_name(cur_lib); + + if (M == K) { + libitem->set_collapsed_recursive(true); + } + } } } } +void AnimationLibraryEditor::_save_mixer_lib_folding(TreeItem *p_item) { + //Check if ti is a library or animation + if (p_item->get_parent()->get_parent() != nullptr) { + return; + } + + Ref<ConfigFile> config; + config.instantiate(); + + String path = EditorPaths::get_singleton()->get_project_settings_dir().path_join("lib_folding.cfg"); + Error err = config->load(path); + if (err != OK && err != ERR_FILE_NOT_FOUND) { + ERR_PRINT("Error loading lib_folding.cfg: " + itos(err)); + } + + // Get unique identifier for this scene+mixer combination + String md = (mixer->get_tree()->get_edited_scene_root()->get_scene_file_path() + mixer->get_path()).md5_text(); + + PackedStringArray collapsed_lib_names; + PackedStringArray collapsed_lib_ids; + + if (config->has_section(md)) { + collapsed_lib_names = String(config->get_value(md, "folding")).split("\n"); + collapsed_lib_ids = String(config->get_value(md, "id")).split("\n"); + } + + String lib_name = p_item->get_text(0); + + // Get library reference and check validity + Ref<AnimationLibrary> al; + uint64_t lib_id = 0; + + if (mixer->has_animation_library(lib_name)) { + al = mixer->get_animation_library(lib_name); + ERR_FAIL_COND(al.is_null()); + lib_id = uint64_t(al->get_instance_id()); + } else { + ERR_PRINT("Library not found: " + lib_name); + } + + int at = collapsed_lib_names.find(lib_name); + if (p_item->is_collapsed()) { + if (at != -1) { + //Entry exists and needs updating + collapsed_lib_ids.set(at, String::num_int64(lib_id + INT64_MIN)); + } else { + //Check if it's a rename + int id_at = collapsed_lib_ids.find(String::num_int64(lib_id + INT64_MIN)); + if (id_at != -1) { + //It's actually a rename + collapsed_lib_names.set(id_at, lib_name); + } else { + //It's a new entry + collapsed_lib_names.append(lib_name); + collapsed_lib_ids.append(String::num_int64(lib_id + INT64_MIN)); + } + } + } else { + if (at != -1) { + collapsed_lib_names.remove_at(at); + collapsed_lib_ids.remove_at(at); + } + } + + //Runtime IDs + config->set_value(md, "root", uint64_t(mixer->get_tree()->get_edited_scene_root()->get_instance_id())); + config->set_value(md, "mixer", uint64_t(mixer->get_instance_id())); + + //Plan B recovery mechanism + config->set_value(md, "mixer_signature", _get_mixer_signature()); + + //Save folding state as text and runtime ID + config->set_value(md, "folding", String("\n").join(collapsed_lib_names)); + config->set_value(md, "id", String("\n").join(collapsed_lib_ids)); + + err = config->save(path); + if (err != OK) { + ERR_PRINT("Error saving lib_folding.cfg: " + itos(err)); + } +} + +Vector<uint64_t> AnimationLibraryEditor::_load_mixer_libs_folding() { + Ref<ConfigFile> config; + config.instantiate(); + + String path = EditorPaths::get_singleton()->get_project_settings_dir().path_join("lib_folding.cfg"); + Error err = config->load(path); + if (err != OK && err != ERR_FILE_NOT_FOUND) { + ERR_PRINT("Error loading lib_folding.cfg: " + itos(err)); + return Vector<uint64_t>(); + } + + // Get unique identifier for this scene+mixer combination + String md = (mixer->get_tree()->get_edited_scene_root()->get_scene_file_path() + mixer->get_path()).md5_text(); + + Vector<uint64_t> collapsed_lib_ids; + + if (config->has_section(md)) { + _load_config_libs_folding(collapsed_lib_ids, config.ptr(), md); + + } else { + //The scene/mixer combination is no longer valid and we'll try to recover + uint64_t current_mixer_id = uint64_t(mixer->get_instance_id()); + String current_mixer_signature = _get_mixer_signature(); + List<String> sections; + config->get_sections(§ions); + + for (const String §ion : sections) { + Variant mixer_id = config->get_value(section, "mixer"); + 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 + // Found the mixer in a different section! + _load_config_libs_folding(collapsed_lib_ids, config.ptr(), section); + + //Cleanup old entry and copy fold data into new one! + String collapsed_lib_names_str = String(config->get_value(section, "folding")); + String collapsed_lib_ids_str = String(config->get_value(section, "id")); + config->erase_section(section); + + config->set_value(md, "root", uint64_t(mixer->get_tree()->get_edited_scene_root()->get_instance_id())); + config->set_value(md, "mixer", uint64_t(mixer->get_instance_id())); + config->set_value(md, "mixer_signature", _get_mixer_signature()); + config->set_value(md, "folding", collapsed_lib_names_str); + config->set_value(md, "id", collapsed_lib_ids_str); + + err = config->save(path); + if (err != OK) { + ERR_PRINT("Error saving lib_folding.cfg: " + itos(err)); + } + break; + } + } + } + + return collapsed_lib_ids; +} + +void AnimationLibraryEditor::_load_config_libs_folding(Vector<uint64_t> &p_lib_ids, ConfigFile *p_config, String p_section) { + if (uint64_t(p_config->get_value(p_section, "root", 0)) != uint64_t(mixer->get_tree()->get_edited_scene_root()->get_instance_id())) { + // Root changed - tries to match by library names + PackedStringArray collapsed_lib_names = String(p_config->get_value(p_section, "folding", "")).split("\n"); + for (const String &lib_name : collapsed_lib_names) { + if (mixer->has_animation_library(lib_name)) { + p_lib_ids.append(mixer->get_animation_library(lib_name)->get_instance_id()); + } else { + print_line("Can't find ", lib_name, " in mixer"); + } + } + } else { + // Root same - uses saved instance IDs + for (const String &saved_id : String(p_config->get_value(p_section, "id")).split("\n")) { + p_lib_ids.append(uint64_t(saved_id.to_int() - INT64_MIN)); + } + } +} + +String AnimationLibraryEditor::_get_mixer_signature() const { + String signature = String(); + + // Get all libraries sorted for consistency + List<StringName> libs; + mixer->get_animation_library_list(&libs); + libs.sort_custom<StringName::AlphCompare>(); + + // Add libraries and their animations to signature + for (const StringName &lib_name : libs) { + signature += "::" + String(lib_name); + Ref<AnimationLibrary> lib = mixer->get_animation_library(lib_name); + if (lib.is_valid()) { + List<StringName> anims; + lib->get_animation_list(&anims); + anims.sort_custom<StringName::AlphCompare>(); + for (const StringName &anim_name : anims) { + signature += "," + String(anim_name); + } + } + } + + return signature.md5_text(); +} + void AnimationLibraryEditor::show_dialog() { update_tree(); popup_centered_ratio(0.5); @@ -855,11 +1055,12 @@ AnimationLibraryEditor::AnimationLibraryEditor() { tree->set_column_custom_minimum_width(1, EDSCALE * 250); tree->set_column_expand(1, false); tree->set_hide_root(true); - tree->set_hide_folding(true); + tree->set_hide_folding(false); tree->set_v_size_flags(Control::SIZE_EXPAND_FILL); tree->connect("item_edited", callable_mp(this, &AnimationLibraryEditor::_item_renamed)); tree->connect("button_clicked", callable_mp(this, &AnimationLibraryEditor::_button_pressed)); + tree->connect("item_collapsed", callable_mp(this, &AnimationLibraryEditor::_save_mixer_lib_folding)); file_popup = memnew(PopupMenu); add_child(file_popup); diff --git a/editor/plugins/animation_library_editor.h b/editor/plugins/animation_library_editor.h index beb34c6343..c4ad1684a6 100644 --- a/editor/plugins/animation_library_editor.h +++ b/editor/plugins/animation_library_editor.h @@ -31,6 +31,8 @@ #ifndef ANIMATION_LIBRARY_EDITOR_H #define ANIMATION_LIBRARY_EDITOR_H +#include "core/io/config_file.h" +#include "core/templates/vector.h" #include "editor/animation_track_editor.h" #include "editor/plugins/editor_plugin.h" #include "scene/animation/animation_mixer.h" @@ -103,6 +105,11 @@ class AnimationLibraryEditor : public AcceptDialog { void _load_file(const String &p_path); void _load_files(const PackedStringArray &p_paths); + void _save_mixer_lib_folding(TreeItem *p_item); + Vector<uint64_t> _load_mixer_libs_folding(); + void _load_config_libs_folding(Vector<uint64_t> &p_lib_ids, ConfigFile *p_config, String p_section); + String _get_mixer_signature() const; + void _item_renamed(); void _button_pressed(TreeItem *p_item, int p_column, int p_id, MouseButton p_button); |