mirror of
				https://github.com/godotengine/godot.git
				synced 2025-11-04 07:31:16 +00:00 
			
		
		
		
	Also start organizing editor-specific GUI components into a dedicated folder, `editor/gui`. Also move `editor_file_server` next to the rest of debugger classes.
		
			
				
	
	
		
			794 lines
		
	
	
	
		
			30 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			794 lines
		
	
	
	
		
			30 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/**************************************************************************/
 | 
						|
/*  animation_library_editor.cpp                                          */
 | 
						|
/**************************************************************************/
 | 
						|
/*                         This file is part of:                          */
 | 
						|
/*                             GODOT ENGINE                               */
 | 
						|
/*                        https://godotengine.org                         */
 | 
						|
/**************************************************************************/
 | 
						|
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
 | 
						|
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */
 | 
						|
/*                                                                        */
 | 
						|
/* Permission is hereby granted, free of charge, to any person obtaining  */
 | 
						|
/* a copy of this software and associated documentation files (the        */
 | 
						|
/* "Software"), to deal in the Software without restriction, including    */
 | 
						|
/* without limitation the rights to use, copy, modify, merge, publish,    */
 | 
						|
/* distribute, sublicense, and/or sell copies of the Software, and to     */
 | 
						|
/* permit persons to whom the Software is furnished to do so, subject to  */
 | 
						|
/* the following conditions:                                              */
 | 
						|
/*                                                                        */
 | 
						|
/* The above copyright notice and this permission notice shall be         */
 | 
						|
/* included in all copies or substantial portions of the Software.        */
 | 
						|
/*                                                                        */
 | 
						|
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */
 | 
						|
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */
 | 
						|
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
 | 
						|
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */
 | 
						|
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */
 | 
						|
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */
 | 
						|
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
 | 
						|
/**************************************************************************/
 | 
						|
 | 
						|
#include "animation_library_editor.h"
 | 
						|
#include "editor/editor_node.h"
 | 
						|
#include "editor/editor_scale.h"
 | 
						|
#include "editor/editor_settings.h"
 | 
						|
#include "editor/editor_undo_redo_manager.h"
 | 
						|
#include "editor/gui/editor_file_dialog.h"
 | 
						|
 | 
						|
void AnimationLibraryEditor::set_animation_player(Object *p_player) {
 | 
						|
	player = p_player;
 | 
						|
}
 | 
						|
 | 
						|
void AnimationLibraryEditor::_add_library() {
 | 
						|
	add_library_dialog->set_title(TTR("Library Name:"));
 | 
						|
	add_library_name->set_text("");
 | 
						|
	add_library_dialog->popup_centered();
 | 
						|
	add_library_name->grab_focus();
 | 
						|
	adding_animation = false;
 | 
						|
	adding_animation_to_library = StringName();
 | 
						|
	_add_library_validate("");
 | 
						|
}
 | 
						|
 | 
						|
void AnimationLibraryEditor::_add_library_validate(const String &p_name) {
 | 
						|
	String error;
 | 
						|
 | 
						|
	if (adding_animation) {
 | 
						|
		Ref<AnimationLibrary> al = player->call("get_animation_library", adding_animation_to_library);
 | 
						|
		ERR_FAIL_COND(al.is_null());
 | 
						|
		if (p_name == "") {
 | 
						|
			error = TTR("Animation name can't be empty.");
 | 
						|
		} else if (!AnimationLibrary::is_valid_animation_name(p_name)) {
 | 
						|
			error = TTR("Animation name contains invalid characters: '/', ':', ',' or '['.");
 | 
						|
		} else if (al->has_animation(p_name)) {
 | 
						|
			error = TTR("Animation with the same name already exists.");
 | 
						|
		}
 | 
						|
	} else {
 | 
						|
		if (p_name == "" && bool(player->call("has_animation_library", ""))) {
 | 
						|
			error = TTR("Enter a library name.");
 | 
						|
		} else if (!AnimationLibrary::is_valid_library_name(p_name)) {
 | 
						|
			error = TTR("Library name contains invalid characters: '/', ':', ',' or '['.");
 | 
						|
		} else if (bool(player->call("has_animation_library", p_name))) {
 | 
						|
			error = TTR("Library with the same name already exists.");
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if (error != "") {
 | 
						|
		add_library_validate->add_theme_color_override("font_color", get_theme_color(SNAME("error_color"), SNAME("Editor")));
 | 
						|
		add_library_validate->set_text(error);
 | 
						|
		add_library_dialog->get_ok_button()->set_disabled(true);
 | 
						|
	} else {
 | 
						|
		if (adding_animation) {
 | 
						|
			add_library_validate->set_text(TTR("Animation name is valid."));
 | 
						|
		} else {
 | 
						|
			if (p_name == "") {
 | 
						|
				add_library_validate->set_text(TTR("Global library will be created."));
 | 
						|
			} else {
 | 
						|
				add_library_validate->set_text(TTR("Library name is valid."));
 | 
						|
			}
 | 
						|
		}
 | 
						|
		add_library_validate->add_theme_color_override("font_color", get_theme_color(SNAME("success_color"), SNAME("Editor")));
 | 
						|
		add_library_dialog->get_ok_button()->set_disabled(false);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
void AnimationLibraryEditor::_add_library_confirm() {
 | 
						|
	if (adding_animation) {
 | 
						|
		String anim_name = add_library_name->get_text();
 | 
						|
		EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
 | 
						|
 | 
						|
		Ref<AnimationLibrary> al = player->call("get_animation_library", adding_animation_to_library);
 | 
						|
		ERR_FAIL_COND(!al.is_valid());
 | 
						|
 | 
						|
		Ref<Animation> anim;
 | 
						|
		anim.instantiate();
 | 
						|
 | 
						|
		undo_redo->create_action(vformat(TTR("Add Animation to Library: %s"), anim_name));
 | 
						|
		undo_redo->add_do_method(al.ptr(), "add_animation", anim_name, anim);
 | 
						|
		undo_redo->add_undo_method(al.ptr(), "remove_animation", anim_name);
 | 
						|
		undo_redo->add_do_method(this, "_update_editor", player);
 | 
						|
		undo_redo->add_undo_method(this, "_update_editor", player);
 | 
						|
		undo_redo->commit_action();
 | 
						|
 | 
						|
	} else {
 | 
						|
		String lib_name = add_library_name->get_text();
 | 
						|
		EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
 | 
						|
 | 
						|
		Ref<AnimationLibrary> al;
 | 
						|
		al.instantiate();
 | 
						|
 | 
						|
		undo_redo->create_action(vformat(TTR("Add Animation Library: %s"), lib_name));
 | 
						|
		undo_redo->add_do_method(player, "add_animation_library", lib_name, al);
 | 
						|
		undo_redo->add_undo_method(player, "remove_animation_library", lib_name);
 | 
						|
		undo_redo->add_do_method(this, "_update_editor", player);
 | 
						|
		undo_redo->add_undo_method(this, "_update_editor", player);
 | 
						|
		undo_redo->commit_action();
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
void AnimationLibraryEditor::_load_library() {
 | 
						|
	List<String> extensions;
 | 
						|
	ResourceLoader::get_recognized_extensions_for_type("AnimationLibrary", &extensions);
 | 
						|
 | 
						|
	file_dialog->set_title(TTR("Load Animation"));
 | 
						|
	file_dialog->clear_filters();
 | 
						|
	for (const String &K : extensions) {
 | 
						|
		file_dialog->add_filter("*." + K);
 | 
						|
	}
 | 
						|
 | 
						|
	file_dialog->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE);
 | 
						|
	file_dialog->set_current_file("");
 | 
						|
	file_dialog->popup_centered_ratio();
 | 
						|
 | 
						|
	file_dialog_action = FILE_DIALOG_ACTION_OPEN_LIBRARY;
 | 
						|
}
 | 
						|
 | 
						|
void AnimationLibraryEditor::_file_popup_selected(int p_id) {
 | 
						|
	Ref<AnimationLibrary> al = player->call("get_animation_library", file_dialog_library);
 | 
						|
	Ref<Animation> anim;
 | 
						|
	if (file_dialog_animation != StringName()) {
 | 
						|
		anim = al->get_animation(file_dialog_animation);
 | 
						|
		ERR_FAIL_COND(anim.is_null());
 | 
						|
	}
 | 
						|
	switch (p_id) {
 | 
						|
		case FILE_MENU_SAVE_LIBRARY: {
 | 
						|
			if (al->get_path().is_resource_file() && !FileAccess::exists(al->get_path() + ".import")) {
 | 
						|
				EditorNode::get_singleton()->save_resource(al);
 | 
						|
				break;
 | 
						|
			}
 | 
						|
			[[fallthrough]];
 | 
						|
		}
 | 
						|
		case FILE_MENU_SAVE_AS_LIBRARY: {
 | 
						|
			// Check if we're allowed to save this
 | 
						|
			{
 | 
						|
				String al_path = al->get_path();
 | 
						|
				if (!al_path.is_resource_file()) {
 | 
						|
					int srpos = al_path.find("::");
 | 
						|
					if (srpos != -1) {
 | 
						|
						String base = al_path.substr(0, srpos);
 | 
						|
						if (!get_tree()->get_edited_scene_root() || get_tree()->get_edited_scene_root()->get_scene_file_path() != base) {
 | 
						|
							error_dialog->set_text(TTR("This animation library can't be saved because it does not belong to the edited scene. Make it unique first."));
 | 
						|
							error_dialog->popup_centered();
 | 
						|
							return;
 | 
						|
						}
 | 
						|
					}
 | 
						|
				} else {
 | 
						|
					if (FileAccess::exists(al_path + ".import")) {
 | 
						|
						error_dialog->set_text(TTR("This animation library can't be saved because it was imported from another file. Make it unique first."));
 | 
						|
						error_dialog->popup_centered();
 | 
						|
						return;
 | 
						|
					}
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
			file_dialog->set_file_mode(EditorFileDialog::FILE_MODE_SAVE_FILE);
 | 
						|
			file_dialog->set_title(TTR("Save Library"));
 | 
						|
			if (al->get_path().is_resource_file()) {
 | 
						|
				file_dialog->set_current_path(al->get_path());
 | 
						|
			} else {
 | 
						|
				file_dialog->set_current_file(String(file_dialog_library) + ".res");
 | 
						|
			}
 | 
						|
			file_dialog->clear_filters();
 | 
						|
			List<String> exts;
 | 
						|
			ResourceLoader::get_recognized_extensions_for_type("AnimationLibrary", &exts);
 | 
						|
			for (const String &K : exts) {
 | 
						|
				file_dialog->add_filter("*." + K);
 | 
						|
			}
 | 
						|
 | 
						|
			file_dialog->popup_centered_ratio();
 | 
						|
			file_dialog_action = FILE_DIALOG_ACTION_SAVE_LIBRARY;
 | 
						|
		} break;
 | 
						|
		case FILE_MENU_MAKE_LIBRARY_UNIQUE: {
 | 
						|
			StringName lib_name = file_dialog_library;
 | 
						|
			List<StringName> animation_list;
 | 
						|
 | 
						|
			Ref<AnimationLibrary> ald = memnew(AnimationLibrary);
 | 
						|
			al->get_animation_list(&animation_list);
 | 
						|
			for (const StringName &animation_name : animation_list) {
 | 
						|
				Ref<Animation> animation = al->get_animation(animation_name);
 | 
						|
				if (EditorNode::get_singleton()->is_resource_read_only(animation)) {
 | 
						|
					animation = animation->duplicate();
 | 
						|
				}
 | 
						|
				ald->add_animation(animation_name, animation);
 | 
						|
			}
 | 
						|
 | 
						|
			EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
 | 
						|
			undo_redo->create_action(vformat(TTR("Make Animation Library Unique: %s"), lib_name));
 | 
						|
			undo_redo->add_do_method(player, "remove_animation_library", lib_name);
 | 
						|
			undo_redo->add_do_method(player, "add_animation_library", lib_name, ald);
 | 
						|
			undo_redo->add_undo_method(player, "remove_animation_library", lib_name);
 | 
						|
			undo_redo->add_undo_method(player, "add_animation_library", lib_name, al);
 | 
						|
			undo_redo->add_do_method(this, "_update_editor", player);
 | 
						|
			undo_redo->add_undo_method(this, "_update_editor", player);
 | 
						|
			undo_redo->commit_action();
 | 
						|
 | 
						|
			update_tree();
 | 
						|
 | 
						|
		} break;
 | 
						|
		case FILE_MENU_EDIT_LIBRARY: {
 | 
						|
			EditorNode::get_singleton()->push_item(al.ptr());
 | 
						|
		} break;
 | 
						|
 | 
						|
		case FILE_MENU_SAVE_ANIMATION: {
 | 
						|
			if (anim->get_path().is_resource_file() && !FileAccess::exists(anim->get_path() + ".import")) {
 | 
						|
				EditorNode::get_singleton()->save_resource(anim);
 | 
						|
				break;
 | 
						|
			}
 | 
						|
			[[fallthrough]];
 | 
						|
		}
 | 
						|
		case FILE_MENU_SAVE_AS_ANIMATION: {
 | 
						|
			// Check if we're allowed to save this
 | 
						|
			{
 | 
						|
				String anim_path = al->get_path();
 | 
						|
				if (!anim_path.is_resource_file()) {
 | 
						|
					int srpos = anim_path.find("::");
 | 
						|
					if (srpos != -1) {
 | 
						|
						String base = anim_path.substr(0, srpos);
 | 
						|
						if (!get_tree()->get_edited_scene_root() || get_tree()->get_edited_scene_root()->get_scene_file_path() != base) {
 | 
						|
							error_dialog->set_text(TTR("This animation can't be saved because it does not belong to the edited scene. Make it unique first."));
 | 
						|
							error_dialog->popup_centered();
 | 
						|
							return;
 | 
						|
						}
 | 
						|
					}
 | 
						|
				} else {
 | 
						|
					if (FileAccess::exists(anim_path + ".import")) {
 | 
						|
						error_dialog->set_text(TTR("This animation can't be saved because it was imported from another file. Make it unique first."));
 | 
						|
						error_dialog->popup_centered();
 | 
						|
						return;
 | 
						|
					}
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
			file_dialog->set_file_mode(EditorFileDialog::FILE_MODE_SAVE_FILE);
 | 
						|
			file_dialog->set_title(TTR("Save Animation"));
 | 
						|
			if (anim->get_path().is_resource_file()) {
 | 
						|
				file_dialog->set_current_path(anim->get_path());
 | 
						|
			} else {
 | 
						|
				file_dialog->set_current_file(String(file_dialog_animation) + ".res");
 | 
						|
			}
 | 
						|
			file_dialog->clear_filters();
 | 
						|
			List<String> exts;
 | 
						|
			ResourceLoader::get_recognized_extensions_for_type("Animation", &exts);
 | 
						|
			for (const String &K : exts) {
 | 
						|
				file_dialog->add_filter("*." + K);
 | 
						|
			}
 | 
						|
 | 
						|
			file_dialog->popup_centered_ratio();
 | 
						|
			file_dialog_action = FILE_DIALOG_ACTION_SAVE_ANIMATION;
 | 
						|
		} break;
 | 
						|
		case FILE_MENU_MAKE_ANIMATION_UNIQUE: {
 | 
						|
			StringName anim_name = file_dialog_animation;
 | 
						|
 | 
						|
			Ref<Animation> animd = anim->duplicate();
 | 
						|
 | 
						|
			EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
 | 
						|
			undo_redo->create_action(vformat(TTR("Make Animation Unique: %s"), anim_name));
 | 
						|
			undo_redo->add_do_method(al.ptr(), "remove_animation", anim_name);
 | 
						|
			undo_redo->add_do_method(al.ptr(), "add_animation", anim_name, animd);
 | 
						|
			undo_redo->add_undo_method(al.ptr(), "remove_animation", anim_name);
 | 
						|
			undo_redo->add_undo_method(al.ptr(), "add_animation", anim_name, anim);
 | 
						|
			undo_redo->add_do_method(this, "_update_editor", player);
 | 
						|
			undo_redo->add_undo_method(this, "_update_editor", player);
 | 
						|
			undo_redo->commit_action();
 | 
						|
 | 
						|
			update_tree();
 | 
						|
		} break;
 | 
						|
		case FILE_MENU_EDIT_ANIMATION: {
 | 
						|
			EditorNode::get_singleton()->push_item(anim.ptr());
 | 
						|
		} break;
 | 
						|
	}
 | 
						|
}
 | 
						|
void AnimationLibraryEditor::_load_file(String p_path) {
 | 
						|
	switch (file_dialog_action) {
 | 
						|
		case FILE_DIALOG_ACTION_OPEN_LIBRARY: {
 | 
						|
			Ref<AnimationLibrary> al = ResourceLoader::load(p_path);
 | 
						|
			if (al.is_null()) {
 | 
						|
				error_dialog->set_text(TTR("Invalid AnimationLibrary file."));
 | 
						|
				error_dialog->popup_centered();
 | 
						|
				return;
 | 
						|
			}
 | 
						|
 | 
						|
			TypedArray<StringName> libs = player->call("get_animation_library_list");
 | 
						|
			for (int i = 0; i < libs.size(); i++) {
 | 
						|
				const StringName K = libs[i];
 | 
						|
				Ref<AnimationLibrary> al2 = player->call("get_animation_library", K);
 | 
						|
				if (al2 == al) {
 | 
						|
					error_dialog->set_text(TTR("This library is already added to the player."));
 | 
						|
					error_dialog->popup_centered();
 | 
						|
 | 
						|
					return;
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
			String name = AnimationLibrary::validate_library_name(p_path.get_file().get_basename());
 | 
						|
 | 
						|
			int attempt = 1;
 | 
						|
 | 
						|
			while (bool(player->call("has_animation_library", name))) {
 | 
						|
				attempt++;
 | 
						|
				name = p_path.get_file().get_basename() + " " + itos(attempt);
 | 
						|
			}
 | 
						|
 | 
						|
			EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
 | 
						|
 | 
						|
			undo_redo->create_action(vformat(TTR("Add Animation Library: %s"), name));
 | 
						|
			undo_redo->add_do_method(player, "add_animation_library", name, al);
 | 
						|
			undo_redo->add_undo_method(player, "remove_animation_library", name);
 | 
						|
			undo_redo->add_do_method(this, "_update_editor", player);
 | 
						|
			undo_redo->add_undo_method(this, "_update_editor", player);
 | 
						|
			undo_redo->commit_action();
 | 
						|
		} break;
 | 
						|
		case FILE_DIALOG_ACTION_OPEN_ANIMATION: {
 | 
						|
			Ref<Animation> anim = ResourceLoader::load(p_path);
 | 
						|
			if (anim.is_null()) {
 | 
						|
				error_dialog->set_text(TTR("Invalid Animation file."));
 | 
						|
				error_dialog->popup_centered();
 | 
						|
				return;
 | 
						|
			}
 | 
						|
 | 
						|
			Ref<AnimationLibrary> al = player->call("get_animation_library", adding_animation_to_library);
 | 
						|
			List<StringName> anims;
 | 
						|
			al->get_animation_list(&anims);
 | 
						|
			for (const StringName &K : anims) {
 | 
						|
				Ref<Animation> a2 = al->get_animation(K);
 | 
						|
				if (a2 == anim) {
 | 
						|
					error_dialog->set_text(TTR("This animation is already added to the library."));
 | 
						|
					error_dialog->popup_centered();
 | 
						|
					return;
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
			String name = p_path.get_file().get_basename();
 | 
						|
 | 
						|
			int attempt = 1;
 | 
						|
 | 
						|
			while (al->has_animation(name)) {
 | 
						|
				attempt++;
 | 
						|
				name = p_path.get_file().get_basename() + " " + itos(attempt);
 | 
						|
			}
 | 
						|
 | 
						|
			EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
 | 
						|
 | 
						|
			undo_redo->create_action(vformat(TTR("Load Animation into Library: %s"), name));
 | 
						|
			undo_redo->add_do_method(al.ptr(), "add_animation", name, anim);
 | 
						|
			undo_redo->add_undo_method(al.ptr(), "remove_animation", name);
 | 
						|
			undo_redo->add_do_method(this, "_update_editor", player);
 | 
						|
			undo_redo->add_undo_method(this, "_update_editor", player);
 | 
						|
			undo_redo->commit_action();
 | 
						|
		} break;
 | 
						|
 | 
						|
		case FILE_DIALOG_ACTION_SAVE_LIBRARY: {
 | 
						|
			Ref<AnimationLibrary> al = player->call("get_animation_library", file_dialog_library);
 | 
						|
			String prev_path = al->get_path();
 | 
						|
			EditorNode::get_singleton()->save_resource_in_path(al, p_path);
 | 
						|
 | 
						|
			if (al->get_path() != prev_path) { // Save successful.
 | 
						|
				EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
 | 
						|
 | 
						|
				undo_redo->create_action(vformat(TTR("Save Animation library to File: %s"), file_dialog_library));
 | 
						|
				undo_redo->add_do_method(al.ptr(), "set_path", al->get_path());
 | 
						|
				undo_redo->add_undo_method(al.ptr(), "set_path", prev_path);
 | 
						|
				undo_redo->add_do_method(this, "_update_editor", player);
 | 
						|
				undo_redo->add_undo_method(this, "_update_editor", player);
 | 
						|
				undo_redo->commit_action();
 | 
						|
			}
 | 
						|
 | 
						|
		} break;
 | 
						|
		case FILE_DIALOG_ACTION_SAVE_ANIMATION: {
 | 
						|
			Ref<AnimationLibrary> al = player->call("get_animation_library", file_dialog_library);
 | 
						|
			Ref<Animation> anim;
 | 
						|
			if (file_dialog_animation != StringName()) {
 | 
						|
				anim = al->get_animation(file_dialog_animation);
 | 
						|
				ERR_FAIL_COND(anim.is_null());
 | 
						|
			}
 | 
						|
			String prev_path = anim->get_path();
 | 
						|
			EditorNode::get_singleton()->save_resource_in_path(anim, p_path);
 | 
						|
			if (anim->get_path() != prev_path) { // Save successful.
 | 
						|
				EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
 | 
						|
 | 
						|
				undo_redo->create_action(vformat(TTR("Save Animation to File: %s"), file_dialog_animation));
 | 
						|
				undo_redo->add_do_method(anim.ptr(), "set_path", anim->get_path());
 | 
						|
				undo_redo->add_undo_method(anim.ptr(), "set_path", prev_path);
 | 
						|
				undo_redo->add_do_method(this, "_update_editor", player);
 | 
						|
				undo_redo->add_undo_method(this, "_update_editor", player);
 | 
						|
				undo_redo->commit_action();
 | 
						|
			}
 | 
						|
		} break;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
void AnimationLibraryEditor::_item_renamed() {
 | 
						|
	TreeItem *ti = tree->get_edited();
 | 
						|
	String text = ti->get_text(0);
 | 
						|
	String old_text = ti->get_metadata(0);
 | 
						|
	bool restore_text = false;
 | 
						|
	EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
 | 
						|
 | 
						|
	if (String(text).contains("/") || String(text).contains(":") || String(text).contains(",") || String(text).contains("[")) {
 | 
						|
		restore_text = true;
 | 
						|
	} else {
 | 
						|
		if (ti->get_parent() == tree->get_root()) {
 | 
						|
			// Renamed library
 | 
						|
 | 
						|
			if (player->call("has_animation_library", text)) {
 | 
						|
				restore_text = true;
 | 
						|
			} else {
 | 
						|
				undo_redo->create_action(vformat(TTR("Rename Animation Library: %s"), text));
 | 
						|
				undo_redo->add_do_method(player, "rename_animation_library", old_text, text);
 | 
						|
				undo_redo->add_undo_method(player, "rename_animation_library", text, old_text);
 | 
						|
				undo_redo->add_do_method(this, "_update_editor", player);
 | 
						|
				undo_redo->add_undo_method(this, "_update_editor", player);
 | 
						|
				updating = true;
 | 
						|
				undo_redo->commit_action();
 | 
						|
				updating = false;
 | 
						|
				ti->set_metadata(0, text);
 | 
						|
				if (text == "") {
 | 
						|
					ti->set_suffix(0, TTR("[Global]"));
 | 
						|
				} else {
 | 
						|
					ti->set_suffix(0, "");
 | 
						|
				}
 | 
						|
			}
 | 
						|
		} else {
 | 
						|
			// Renamed anim
 | 
						|
			StringName library = ti->get_parent()->get_metadata(0);
 | 
						|
			Ref<AnimationLibrary> al = player->call("get_animation_library", library);
 | 
						|
 | 
						|
			if (al.is_valid()) {
 | 
						|
				if (al->has_animation(text)) {
 | 
						|
					restore_text = true;
 | 
						|
				} else {
 | 
						|
					undo_redo->create_action(vformat(TTR("Rename Animation: %s"), text));
 | 
						|
					undo_redo->add_do_method(al.ptr(), "rename_animation", old_text, text);
 | 
						|
					undo_redo->add_undo_method(al.ptr(), "rename_animation", text, old_text);
 | 
						|
					undo_redo->add_do_method(this, "_update_editor", player);
 | 
						|
					undo_redo->add_undo_method(this, "_update_editor", player);
 | 
						|
					updating = true;
 | 
						|
					undo_redo->commit_action();
 | 
						|
					updating = false;
 | 
						|
 | 
						|
					ti->set_metadata(0, text);
 | 
						|
				}
 | 
						|
			} else {
 | 
						|
				restore_text = true;
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if (restore_text) {
 | 
						|
		ti->set_text(0, old_text);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
void AnimationLibraryEditor::_button_pressed(TreeItem *p_item, int p_column, int p_id, MouseButton p_button) {
 | 
						|
	if (p_item->get_parent() == tree->get_root()) {
 | 
						|
		// Library
 | 
						|
		StringName lib_name = p_item->get_metadata(0);
 | 
						|
		Ref<AnimationLibrary> al = player->call("get_animation_library", lib_name);
 | 
						|
		switch (p_id) {
 | 
						|
			case LIB_BUTTON_ADD: {
 | 
						|
				add_library_dialog->set_title(TTR("Animation Name:"));
 | 
						|
				add_library_name->set_text("");
 | 
						|
				add_library_dialog->popup_centered();
 | 
						|
				add_library_name->grab_focus();
 | 
						|
				adding_animation = true;
 | 
						|
				adding_animation_to_library = p_item->get_metadata(0);
 | 
						|
				_add_library_validate("");
 | 
						|
			} break;
 | 
						|
			case LIB_BUTTON_LOAD: {
 | 
						|
				adding_animation_to_library = p_item->get_metadata(0);
 | 
						|
				List<String> extensions;
 | 
						|
				ResourceLoader::get_recognized_extensions_for_type("Animation", &extensions);
 | 
						|
 | 
						|
				file_dialog->clear_filters();
 | 
						|
				for (const String &K : extensions) {
 | 
						|
					file_dialog->add_filter("*." + K);
 | 
						|
				}
 | 
						|
 | 
						|
				file_dialog->set_title(TTR("Load Animation"));
 | 
						|
				file_dialog->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE);
 | 
						|
				file_dialog->set_current_file("");
 | 
						|
				file_dialog->popup_centered_ratio();
 | 
						|
 | 
						|
				file_dialog_action = FILE_DIALOG_ACTION_OPEN_ANIMATION;
 | 
						|
 | 
						|
			} break;
 | 
						|
			case LIB_BUTTON_PASTE: {
 | 
						|
				Ref<Animation> anim = EditorSettings::get_singleton()->get_resource_clipboard();
 | 
						|
				if (!anim.is_valid()) {
 | 
						|
					error_dialog->set_text(TTR("No animation resource in clipboard!"));
 | 
						|
					error_dialog->popup_centered();
 | 
						|
					return;
 | 
						|
				}
 | 
						|
 | 
						|
				anim = anim->duplicate(); // Users simply dont care about referencing, so making a copy works better here.
 | 
						|
 | 
						|
				String base_name;
 | 
						|
				if (anim->get_name() != "") {
 | 
						|
					base_name = anim->get_name();
 | 
						|
				} else {
 | 
						|
					base_name = TTR("Pasted Animation");
 | 
						|
				}
 | 
						|
 | 
						|
				String name = base_name;
 | 
						|
				int attempt = 1;
 | 
						|
				while (al->has_animation(name)) {
 | 
						|
					attempt++;
 | 
						|
					name = base_name + " (" + itos(attempt) + ")";
 | 
						|
				}
 | 
						|
 | 
						|
				EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
 | 
						|
 | 
						|
				undo_redo->create_action(vformat(TTR("Add Animation to Library: %s"), name));
 | 
						|
				undo_redo->add_do_method(al.ptr(), "add_animation", name, anim);
 | 
						|
				undo_redo->add_undo_method(al.ptr(), "remove_animation", name);
 | 
						|
				undo_redo->add_do_method(this, "_update_editor", player);
 | 
						|
				undo_redo->add_undo_method(this, "_update_editor", player);
 | 
						|
				undo_redo->commit_action();
 | 
						|
 | 
						|
			} break;
 | 
						|
			case LIB_BUTTON_FILE: {
 | 
						|
				file_popup->clear();
 | 
						|
				file_popup->add_item(TTR("Save"), FILE_MENU_SAVE_LIBRARY);
 | 
						|
				file_popup->add_item(TTR("Save As"), FILE_MENU_SAVE_AS_LIBRARY);
 | 
						|
				file_popup->add_separator();
 | 
						|
				file_popup->add_item(TTR("Make Unique"), FILE_MENU_MAKE_LIBRARY_UNIQUE);
 | 
						|
				file_popup->add_separator();
 | 
						|
				file_popup->add_item(TTR("Open in Inspector"), FILE_MENU_EDIT_LIBRARY);
 | 
						|
				Rect2 pos = tree->get_item_rect(p_item, 1, 0);
 | 
						|
				Vector2 popup_pos = tree->get_screen_transform().xform(pos.position + Vector2(0, pos.size.height));
 | 
						|
				file_popup->popup(Rect2(popup_pos, Size2()));
 | 
						|
 | 
						|
				file_dialog_animation = StringName();
 | 
						|
				file_dialog_library = lib_name;
 | 
						|
			} break;
 | 
						|
			case LIB_BUTTON_DELETE: {
 | 
						|
				EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
 | 
						|
				undo_redo->create_action(vformat(TTR("Remove Animation Library: %s"), lib_name));
 | 
						|
				undo_redo->add_do_method(player, "remove_animation_library", lib_name);
 | 
						|
				undo_redo->add_undo_method(player, "add_animation_library", lib_name, al);
 | 
						|
				undo_redo->add_do_method(this, "_update_editor", player);
 | 
						|
				undo_redo->add_undo_method(this, "_update_editor", player);
 | 
						|
				undo_redo->commit_action();
 | 
						|
			} break;
 | 
						|
		}
 | 
						|
 | 
						|
	} else {
 | 
						|
		// Animation
 | 
						|
		StringName lib_name = p_item->get_parent()->get_metadata(0);
 | 
						|
		StringName anim_name = p_item->get_metadata(0);
 | 
						|
		Ref<AnimationLibrary> al = player->call("get_animation_library", lib_name);
 | 
						|
		Ref<Animation> anim = al->get_animation(anim_name);
 | 
						|
		ERR_FAIL_COND(!anim.is_valid());
 | 
						|
		switch (p_id) {
 | 
						|
			case ANIM_BUTTON_COPY: {
 | 
						|
				if (anim->get_name() == "") {
 | 
						|
					anim->set_name(anim_name); // Keep the name around
 | 
						|
				}
 | 
						|
				EditorSettings::get_singleton()->set_resource_clipboard(anim);
 | 
						|
			} break;
 | 
						|
			case ANIM_BUTTON_FILE: {
 | 
						|
				file_popup->clear();
 | 
						|
				file_popup->add_item(TTR("Save"), FILE_MENU_SAVE_ANIMATION);
 | 
						|
				file_popup->add_item(TTR("Save As"), FILE_MENU_SAVE_AS_ANIMATION);
 | 
						|
				file_popup->add_separator();
 | 
						|
				file_popup->add_item(TTR("Make Unique"), FILE_MENU_MAKE_ANIMATION_UNIQUE);
 | 
						|
				file_popup->add_separator();
 | 
						|
				file_popup->add_item(TTR("Open in Inspector"), FILE_MENU_EDIT_ANIMATION);
 | 
						|
				Rect2 pos = tree->get_item_rect(p_item, 1, 0);
 | 
						|
				Vector2 popup_pos = tree->get_screen_transform().xform(pos.position + Vector2(0, pos.size.height));
 | 
						|
				file_popup->popup(Rect2(popup_pos, Size2()));
 | 
						|
 | 
						|
				file_dialog_animation = anim_name;
 | 
						|
				file_dialog_library = lib_name;
 | 
						|
 | 
						|
			} break;
 | 
						|
			case ANIM_BUTTON_DELETE: {
 | 
						|
				EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
 | 
						|
				undo_redo->create_action(vformat(TTR("Remove Animation from Library: %s"), anim_name));
 | 
						|
				undo_redo->add_do_method(al.ptr(), "remove_animation", anim_name);
 | 
						|
				undo_redo->add_undo_method(al.ptr(), "add_animation", anim_name, anim);
 | 
						|
				undo_redo->add_do_method(this, "_update_editor", player);
 | 
						|
				undo_redo->add_undo_method(this, "_update_editor", player);
 | 
						|
				undo_redo->commit_action();
 | 
						|
			} break;
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
void AnimationLibraryEditor::update_tree() {
 | 
						|
	if (updating) {
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	tree->clear();
 | 
						|
	ERR_FAIL_COND(!player);
 | 
						|
 | 
						|
	Color ss_color = get_theme_color(SNAME("prop_subsection"), SNAME("Editor"));
 | 
						|
 | 
						|
	TreeItem *root = tree->create_item();
 | 
						|
	TypedArray<StringName> libs = player->call("get_animation_library_list");
 | 
						|
 | 
						|
	for (int i = 0; i < libs.size(); i++) {
 | 
						|
		const StringName K = libs[i];
 | 
						|
		TreeItem *libitem = tree->create_item(root);
 | 
						|
		libitem->set_text(0, K);
 | 
						|
		if (K == StringName()) {
 | 
						|
			libitem->set_suffix(0, TTR("[Global]"));
 | 
						|
		} else {
 | 
						|
			libitem->set_suffix(0, "");
 | 
						|
		}
 | 
						|
 | 
						|
		Ref<AnimationLibrary> al = player->call("get_animation_library", K);
 | 
						|
		bool animation_library_is_foreign = false;
 | 
						|
		String al_path = al->get_path();
 | 
						|
		if (!al_path.is_resource_file()) {
 | 
						|
			libitem->set_text(1, TTR("[built-in]"));
 | 
						|
			libitem->set_tooltip_text(1, al_path);
 | 
						|
			int srpos = al_path.find("::");
 | 
						|
			if (srpos != -1) {
 | 
						|
				String base = al_path.substr(0, srpos);
 | 
						|
				if (ResourceLoader::get_resource_type(base) == "PackedScene") {
 | 
						|
					if (!get_tree()->get_edited_scene_root() || get_tree()->get_edited_scene_root()->get_scene_file_path() != base) {
 | 
						|
						animation_library_is_foreign = true;
 | 
						|
						libitem->set_text(1, TTR("[foreign]"));
 | 
						|
					}
 | 
						|
				} else {
 | 
						|
					if (FileAccess::exists(base + ".import")) {
 | 
						|
						animation_library_is_foreign = true;
 | 
						|
						libitem->set_text(1, TTR("[imported]"));
 | 
						|
					}
 | 
						|
				}
 | 
						|
			}
 | 
						|
		} else {
 | 
						|
			if (FileAccess::exists(al_path + ".import")) {
 | 
						|
				animation_library_is_foreign = true;
 | 
						|
				libitem->set_text(1, TTR("[imported]"));
 | 
						|
			} else {
 | 
						|
				libitem->set_text(1, al_path.get_file());
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		libitem->set_editable(0, !animation_library_is_foreign);
 | 
						|
		libitem->set_metadata(0, K);
 | 
						|
		libitem->set_icon(0, get_theme_icon("AnimationLibrary", "EditorIcons"));
 | 
						|
 | 
						|
		libitem->add_button(0, get_theme_icon("Add", "EditorIcons"), LIB_BUTTON_ADD, animation_library_is_foreign, TTR("Add Animation to Library"));
 | 
						|
		libitem->add_button(0, get_theme_icon("Load", "EditorIcons"), LIB_BUTTON_LOAD, animation_library_is_foreign, TTR("Load animation from file and add to library"));
 | 
						|
		libitem->add_button(0, get_theme_icon("ActionPaste", "EditorIcons"), LIB_BUTTON_PASTE, animation_library_is_foreign, TTR("Paste Animation to Library from clipboard"));
 | 
						|
 | 
						|
		libitem->add_button(1, get_theme_icon("Save", "EditorIcons"), LIB_BUTTON_FILE, false, TTR("Save animation library to resource on disk"));
 | 
						|
		libitem->add_button(1, get_theme_icon("Remove", "EditorIcons"), LIB_BUTTON_DELETE, false, TTR("Remove animation library"));
 | 
						|
 | 
						|
		libitem->set_custom_bg_color(0, ss_color);
 | 
						|
 | 
						|
		List<StringName> animations;
 | 
						|
		al->get_animation_list(&animations);
 | 
						|
		for (const StringName &L : animations) {
 | 
						|
			TreeItem *anitem = tree->create_item(libitem);
 | 
						|
			anitem->set_text(0, L);
 | 
						|
			anitem->set_editable(0, !animation_library_is_foreign);
 | 
						|
			anitem->set_metadata(0, L);
 | 
						|
			anitem->set_icon(0, get_theme_icon("Animation", "EditorIcons"));
 | 
						|
			anitem->add_button(0, get_theme_icon("ActionCopy", "EditorIcons"), ANIM_BUTTON_COPY, animation_library_is_foreign, TTR("Copy animation to clipboard"));
 | 
						|
 | 
						|
			Ref<Animation> anim = al->get_animation(L);
 | 
						|
			String anim_path = anim->get_path();
 | 
						|
			if (!anim_path.is_resource_file()) {
 | 
						|
				anitem->set_text(1, TTR("[built-in]"));
 | 
						|
				anitem->set_tooltip_text(1, anim_path);
 | 
						|
				int srpos = anim_path.find("::");
 | 
						|
				if (srpos != -1) {
 | 
						|
					String base = anim_path.substr(0, srpos);
 | 
						|
					if (ResourceLoader::get_resource_type(base) == "PackedScene") {
 | 
						|
						if (!get_tree()->get_edited_scene_root() || get_tree()->get_edited_scene_root()->get_scene_file_path() != base) {
 | 
						|
							anitem->set_text(1, TTR("[foreign]"));
 | 
						|
						}
 | 
						|
					} else {
 | 
						|
						if (FileAccess::exists(base + ".import")) {
 | 
						|
							anitem->set_text(1, TTR("[imported]"));
 | 
						|
						}
 | 
						|
					}
 | 
						|
				}
 | 
						|
			} else {
 | 
						|
				if (FileAccess::exists(anim_path + ".import")) {
 | 
						|
					anitem->set_text(1, TTR("[imported]"));
 | 
						|
				} else {
 | 
						|
					anitem->set_text(1, anim_path.get_file());
 | 
						|
				}
 | 
						|
			}
 | 
						|
			anitem->add_button(1, get_theme_icon("Save", "EditorIcons"), ANIM_BUTTON_FILE, animation_library_is_foreign, TTR("Save animation to resource on disk"));
 | 
						|
			anitem->add_button(1, get_theme_icon("Remove", "EditorIcons"), ANIM_BUTTON_DELETE, animation_library_is_foreign, TTR("Remove animation from Library"));
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
void AnimationLibraryEditor::show_dialog() {
 | 
						|
	update_tree();
 | 
						|
	popup_centered_ratio(0.5);
 | 
						|
}
 | 
						|
 | 
						|
void AnimationLibraryEditor::_update_editor(Object *p_player) {
 | 
						|
	emit_signal("update_editor", p_player);
 | 
						|
}
 | 
						|
 | 
						|
void AnimationLibraryEditor::_bind_methods() {
 | 
						|
	ClassDB::bind_method(D_METHOD("_update_editor", "player"), &AnimationLibraryEditor::_update_editor);
 | 
						|
	ADD_SIGNAL(MethodInfo("update_editor"));
 | 
						|
}
 | 
						|
 | 
						|
AnimationLibraryEditor::AnimationLibraryEditor() {
 | 
						|
	set_title(TTR("Edit Animation Libraries"));
 | 
						|
 | 
						|
	file_dialog = memnew(EditorFileDialog);
 | 
						|
	add_child(file_dialog);
 | 
						|
	file_dialog->connect("file_selected", callable_mp(this, &AnimationLibraryEditor::_load_file));
 | 
						|
 | 
						|
	add_library_dialog = memnew(ConfirmationDialog);
 | 
						|
	VBoxContainer *dialog_vb = memnew(VBoxContainer);
 | 
						|
	add_library_name = memnew(LineEdit);
 | 
						|
	dialog_vb->add_child(add_library_name);
 | 
						|
	add_library_name->connect("text_changed", callable_mp(this, &AnimationLibraryEditor::_add_library_validate));
 | 
						|
	add_child(add_library_dialog);
 | 
						|
 | 
						|
	add_library_validate = memnew(Label);
 | 
						|
	dialog_vb->add_child(add_library_validate);
 | 
						|
	add_library_dialog->add_child(dialog_vb);
 | 
						|
	add_library_dialog->connect("confirmed", callable_mp(this, &AnimationLibraryEditor::_add_library_confirm));
 | 
						|
	add_library_dialog->register_text_enter(add_library_name);
 | 
						|
 | 
						|
	VBoxContainer *vb = memnew(VBoxContainer);
 | 
						|
	HBoxContainer *hb = memnew(HBoxContainer);
 | 
						|
	hb->add_spacer(true);
 | 
						|
	Button *b = memnew(Button(TTR("Add Library")));
 | 
						|
	b->connect("pressed", callable_mp(this, &AnimationLibraryEditor::_add_library));
 | 
						|
	hb->add_child(b);
 | 
						|
	b = memnew(Button(TTR("Load Library")));
 | 
						|
	b->connect("pressed", callable_mp(this, &AnimationLibraryEditor::_load_library));
 | 
						|
	hb->add_child(b);
 | 
						|
	vb->add_child(hb);
 | 
						|
	tree = memnew(Tree);
 | 
						|
	vb->add_child(tree);
 | 
						|
 | 
						|
	tree->set_columns(2);
 | 
						|
	tree->set_column_titles_visible(true);
 | 
						|
	tree->set_column_title(0, TTR("Resource"));
 | 
						|
	tree->set_column_title(1, TTR("Storage"));
 | 
						|
	tree->set_column_expand(0, true);
 | 
						|
	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_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));
 | 
						|
 | 
						|
	file_popup = memnew(PopupMenu);
 | 
						|
	add_child(file_popup);
 | 
						|
	file_popup->connect("id_pressed", callable_mp(this, &AnimationLibraryEditor::_file_popup_selected));
 | 
						|
 | 
						|
	add_child(vb);
 | 
						|
 | 
						|
	error_dialog = memnew(AcceptDialog);
 | 
						|
	error_dialog->set_title(TTR("Error:"));
 | 
						|
	add_child(error_dialog);
 | 
						|
}
 |