Path: blob/master/editor/scene/resource_preloader_editor_plugin.cpp
20873 views
/**************************************************************************/1/* resource_preloader_editor_plugin.cpp */2/**************************************************************************/3/* This file is part of: */4/* GODOT ENGINE */5/* https://godotengine.org */6/**************************************************************************/7/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */8/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */9/* */10/* Permission is hereby granted, free of charge, to any person obtaining */11/* a copy of this software and associated documentation files (the */12/* "Software"), to deal in the Software without restriction, including */13/* without limitation the rights to use, copy, modify, merge, publish, */14/* distribute, sublicense, and/or sell copies of the Software, and to */15/* permit persons to whom the Software is furnished to do so, subject to */16/* the following conditions: */17/* */18/* The above copyright notice and this permission notice shall be */19/* included in all copies or substantial portions of the Software. */20/* */21/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */22/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */23/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */24/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */25/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */26/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */27/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */28/**************************************************************************/2930#include "resource_preloader_editor_plugin.h"3132#include "core/io/resource_loader.h"33#include "editor/docks/editor_dock_manager.h"34#include "editor/editor_interface.h"35#include "editor/editor_node.h"36#include "editor/editor_undo_redo_manager.h"37#include "editor/gui/editor_file_dialog.h"38#include "editor/settings/editor_command_palette.h"39#include "editor/settings/editor_settings.h"40#include "editor/themes/editor_scale.h"41#include "scene/gui/dialogs.h"42#include "scene/gui/tree.h"43#include "scene/main/resource_preloader.h"4445void ResourcePreloaderEditor::_notification(int p_what) {46switch (p_what) {47case NOTIFICATION_TRANSLATION_CHANGED: {48if (preloader) {49_update_library();50}51} break;5253case NOTIFICATION_THEME_CHANGED: {54load->set_button_icon(get_editor_theme_icon(SNAME("Folder")));55} break;56}57}5859void ResourcePreloaderEditor::_files_load_request(const Vector<String> &p_paths) {60for (int i = 0; i < p_paths.size(); i++) {61const String &path = p_paths[i];6263Ref<Resource> resource;64resource = ResourceLoader::load(path);6566if (resource.is_null()) {67dialog->set_text(TTRC("ERROR: Couldn't load resource!"));68dialog->popup_centered();69return; /// Beh, should show an error I guess.70}7172String basename = path.get_file().get_basename();73String name = basename;74int counter = 1;75while (preloader->has_resource(name)) {76counter++;77name = basename + " " + itos(counter);78}7980EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();81undo_redo->create_action(TTR("Add Resource"));82undo_redo->add_do_method(preloader, "add_resource", name, resource);83undo_redo->add_undo_method(preloader, "remove_resource", name);84undo_redo->add_do_method(this, "_update_library");85undo_redo->add_undo_method(this, "_update_library");86undo_redo->commit_action();87}88}8990void ResourcePreloaderEditor::_load_pressed() {91loading_scene = false;9293file->clear_filters();94List<String> extensions;95ResourceLoader::get_recognized_extensions_for_type("", &extensions);96for (const String &extension : extensions) {97file->add_filter("*." + extension);98}99100file->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILES);101file->popup_file_dialog();102}103104void ResourcePreloaderEditor::_item_edited() {105if (!tree->get_selected()) {106return;107}108109TreeItem *s = tree->get_selected();110111if (tree->get_selected_column() == 0) {112// renamed113String old_name = s->get_metadata(0);114String new_name = s->get_text(0);115if (old_name == new_name) {116return;117}118119if (new_name.is_empty() || new_name.contains_char('\\') || new_name.contains_char('/') || preloader->has_resource(new_name)) {120s->set_text(0, old_name);121return;122}123124Ref<Resource> samp = preloader->get_resource(old_name);125EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();126undo_redo->create_action(TTR("Rename Resource"));127undo_redo->add_do_method(preloader, "remove_resource", old_name);128undo_redo->add_do_method(preloader, "add_resource", new_name, samp);129undo_redo->add_undo_method(preloader, "remove_resource", new_name);130undo_redo->add_undo_method(preloader, "add_resource", old_name, samp);131undo_redo->add_do_method(this, "_update_library");132undo_redo->add_undo_method(this, "_update_library");133undo_redo->commit_action();134}135}136137void ResourcePreloaderEditor::_remove_resource(const String &p_to_remove) {138EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();139undo_redo->create_action(TTR("Delete Resource"));140undo_redo->add_do_method(preloader, "remove_resource", p_to_remove);141undo_redo->add_undo_method(preloader, "add_resource", p_to_remove, preloader->get_resource(p_to_remove));142undo_redo->add_do_method(this, "_update_library");143undo_redo->add_undo_method(this, "_update_library");144undo_redo->commit_action();145}146147void ResourcePreloaderEditor::_paste_pressed() {148Ref<Resource> r = EditorSettings::get_singleton()->get_resource_clipboard();149if (r.is_null()) {150dialog->set_text(TTRC("Resource clipboard is empty!"));151dialog->popup_centered();152return; /// Beh, should show an error I guess.153}154155String name = r->get_name();156if (name.is_empty()) {157name = r->get_path().get_file();158}159if (name.is_empty()) {160name = r->get_class();161}162163String basename = name;164int counter = 1;165while (preloader->has_resource(name)) {166counter++;167name = basename + " " + itos(counter);168}169170EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();171undo_redo->create_action(TTR("Paste Resource"));172undo_redo->add_do_method(preloader, "add_resource", name, r);173undo_redo->add_undo_method(preloader, "remove_resource", name);174undo_redo->add_do_method(this, "_update_library");175undo_redo->add_undo_method(this, "_update_library");176undo_redo->commit_action();177}178179void ResourcePreloaderEditor::_update_library() {180tree->clear();181if (!preloader) {182return;183}184185TreeItem *root = tree->create_item(nullptr);186187List<StringName> rnames;188preloader->get_resource_list(&rnames);189190List<String> names;191for (const StringName &E : rnames) {192names.push_back(E);193}194195names.sort();196197for (const String &E : names) {198TreeItem *ti = tree->create_item(root);199ti->set_cell_mode(0, TreeItem::CELL_MODE_STRING);200ti->set_editable(0, true);201ti->set_selectable(0, true);202ti->set_text(0, E);203ti->set_metadata(0, E);204205Ref<Resource> r = preloader->get_resource(E);206207ERR_CONTINUE(r.is_null());208209String type = r->get_class();210ti->set_icon(0, EditorNode::get_singleton()->get_class_icon(type));211ti->set_tooltip_text(0, TTR("Instance:") + " " + r->get_path() + "\n" + TTR("Type:") + " " + type);212213ti->set_text(1, r->get_path());214ti->set_editable(1, false);215ti->set_selectable(1, false);216217if (type == "PackedScene") {218ti->add_button(1, get_editor_theme_icon(SNAME("InstanceOptions")), BUTTON_OPEN_SCENE, false, TTR("Open in Editor"));219} else {220ti->add_button(1, get_editor_theme_icon(SNAME("Load")), BUTTON_EDIT_RESOURCE, false, TTR("Open in Editor"));221}222ti->add_button(1, get_editor_theme_icon(SNAME("Remove")), BUTTON_REMOVE, false, TTR("Remove"));223}224}225226void ResourcePreloaderEditor::_cell_button_pressed(Object *p_item, int p_column, int p_id, MouseButton p_button) {227if (p_button != MouseButton::LEFT) {228return;229}230231TreeItem *item = Object::cast_to<TreeItem>(p_item);232ERR_FAIL_NULL(item);233234if (p_id == BUTTON_OPEN_SCENE) {235String rpath = item->get_text(p_column);236EditorInterface::get_singleton()->open_scene_from_path(rpath);237238} else if (p_id == BUTTON_EDIT_RESOURCE) {239Ref<Resource> r = preloader->get_resource(item->get_text(0));240EditorInterface::get_singleton()->edit_resource(r);241242} else if (p_id == BUTTON_REMOVE) {243_remove_resource(item->get_text(0));244}245}246247void ResourcePreloaderEditor::edit(ResourcePreloader *p_preloader) {248preloader = p_preloader;249_update_library();250}251252Variant ResourcePreloaderEditor::get_drag_data_fw(const Point2 &p_point, Control *p_from) {253TreeItem *ti = (p_point == Vector2(Math::INF, Math::INF)) ? tree->get_selected() : tree->get_item_at_position(p_point);254if (!ti) {255return Variant();256}257258String name = ti->get_metadata(0);259260Ref<Resource> res = preloader->get_resource(name);261if (res.is_null()) {262return Variant();263}264265return EditorNode::get_singleton()->drag_resource(res, p_from);266}267268bool ResourcePreloaderEditor::can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const {269Dictionary d = p_data;270271if (!d.has("type")) {272return false;273}274275if (d.has("from") && (Object *)(d["from"]) == tree) {276return false;277}278279if (String(d["type"]) == "resource" && d.has("resource")) {280Ref<Resource> r = d["resource"];281282return r.is_valid();283}284285if (String(d["type"]) == "files") {286Vector<String> files = d["files"];287288return files.size() != 0;289}290return false;291}292293void ResourcePreloaderEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) {294if (!can_drop_data_fw(p_point, p_data, p_from)) {295return;296}297298Dictionary d = p_data;299300if (!d.has("type")) {301return;302}303304if (String(d["type"]) == "resource" && d.has("resource")) {305Ref<Resource> r = d["resource"];306307if (r.is_valid()) {308String basename;309if (!r->get_name().is_empty()) {310basename = r->get_name();311} else if (r->get_path().is_resource_file()) {312basename = r->get_path().get_basename();313} else {314basename = "Resource";315}316317String name = basename;318int counter = 0;319while (preloader->has_resource(name)) {320counter++;321name = basename + "_" + itos(counter);322}323324EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();325undo_redo->create_action(TTR("Add Resource"));326undo_redo->add_do_method(preloader, "add_resource", name, r);327undo_redo->add_undo_method(preloader, "remove_resource", name);328undo_redo->add_do_method(this, "_update_library");329undo_redo->add_undo_method(this, "_update_library");330undo_redo->commit_action();331}332}333334if (String(d["type"]) == "files") {335Vector<String> files = d["files"];336337_files_load_request(files);338}339}340341void ResourcePreloaderEditor::update_layout(EditorDock::DockLayout p_layout) {342bool new_horizontal = (p_layout == EditorDock::DOCK_LAYOUT_HORIZONTAL);343if (horizontal == new_horizontal) {344return;345}346horizontal = new_horizontal;347348if (horizontal) {349mc->set_theme_type_variation("NoBorderHorizontal");350tree->set_scroll_hint_mode(Tree::SCROLL_HINT_MODE_BOTH);351} else {352mc->set_theme_type_variation("NoBorderHorizontalBottom");353tree->set_scroll_hint_mode(Tree::SCROLL_HINT_MODE_TOP);354}355}356357void ResourcePreloaderEditor::_bind_methods() {358ClassDB::bind_method(D_METHOD("_update_library"), &ResourcePreloaderEditor::_update_library);359ClassDB::bind_method(D_METHOD("_remove_resource", "to_remove"), &ResourcePreloaderEditor::_remove_resource);360}361362ResourcePreloaderEditor::ResourcePreloaderEditor() {363set_name(TTRC("ResourcePreloader"));364set_icon_name("ResourcePreloader");365set_dock_shortcut(ED_SHORTCUT_AND_COMMAND("bottom_panels/toggle_resource_preloader_bottom_panel", TTRC("Toggle ResourcePreloader Dock")));366set_default_slot(EditorDock::DOCK_SLOT_BOTTOM);367set_available_layouts(EditorDock::DOCK_LAYOUT_ALL);368set_global(false);369set_transient(true);370371set_custom_minimum_size(Size2(0, 250 * EDSCALE));372373VBoxContainer *vbc = memnew(VBoxContainer);374add_child(vbc);375376HBoxContainer *hbc = memnew(HBoxContainer);377vbc->add_child(hbc);378379load = memnew(Button);380load->set_tooltip_text(TTRC("Load Resource"));381hbc->add_child(load);382383paste = memnew(Button);384paste->set_text(TTRC("Paste"));385hbc->add_child(paste);386387file = memnew(EditorFileDialog);388add_child(file);389390mc = memnew(MarginContainer);391mc->set_v_size_flags(SIZE_EXPAND_FILL);392vbc->add_child(mc);393394tree = memnew(Tree);395tree->connect("button_clicked", callable_mp(this, &ResourcePreloaderEditor::_cell_button_pressed));396tree->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);397tree->set_hide_root(true);398tree->set_columns(2);399tree->set_column_expand_ratio(0, 2);400tree->set_column_clip_content(0, true);401tree->set_column_expand_ratio(1, 3);402tree->set_column_clip_content(1, true);403404SET_DRAG_FORWARDING_GCD(tree, ResourcePreloaderEditor);405mc->add_child(tree);406407dialog = memnew(AcceptDialog);408dialog->set_title(TTRC("Error!"));409dialog->set_ok_button_text(TTRC("Close"));410add_child(dialog);411412load->connect(SceneStringName(pressed), callable_mp(this, &ResourcePreloaderEditor::_load_pressed));413paste->connect(SceneStringName(pressed), callable_mp(this, &ResourcePreloaderEditor::_paste_pressed));414file->connect("files_selected", callable_mp(this, &ResourcePreloaderEditor::_files_load_request));415tree->connect("item_edited", callable_mp(this, &ResourcePreloaderEditor::_item_edited));416loading_scene = false;417}418419void ResourcePreloaderEditorPlugin::edit(Object *p_object) {420ResourcePreloader *s = Object::cast_to<ResourcePreloader>(p_object);421if (!s) {422return;423}424425preloader_editor->edit(s);426}427428bool ResourcePreloaderEditorPlugin::handles(Object *p_object) const {429return Object::cast_to<ResourcePreloader>(p_object);430}431432void ResourcePreloaderEditorPlugin::make_visible(bool p_visible) {433if (p_visible) {434preloader_editor->make_visible();435} else {436preloader_editor->close();437}438}439440ResourcePreloaderEditorPlugin::ResourcePreloaderEditorPlugin() {441preloader_editor = memnew(ResourcePreloaderEditor);442EditorDockManager::get_singleton()->add_dock(preloader_editor);443preloader_editor->close();444}445446447