From 6276fd2695b007d4361558d180dc63917254d1a9 Mon Sep 17 00:00:00 2001 From: kobewi Date: Sun, 4 Jun 2023 23:59:03 +0200 Subject: [PATCH] Allow to pick which Resources will be made unique Co-authored-by: Yuri Sizov --- editor/editor_resource_picker.cpp | 122 ++++++++++++++++++++++++++++-- editor/editor_resource_picker.h | 19 +++-- 2 files changed, 127 insertions(+), 14 deletions(-) diff --git a/editor/editor_resource_picker.cpp b/editor/editor_resource_picker.cpp index 15cf96b92801..ea7e1549f58e 100644 --- a/editor/editor_resource_picker.cpp +++ b/editor/editor_resource_picker.cpp @@ -41,6 +41,8 @@ #include "editor/plugins/editor_resource_conversion_plugin.h" #include "editor/plugins/script_editor_plugin.h" #include "editor/scene_tree_dock.h" +#include "scene/gui/button.h" +#include "scene/gui/texture_rect.h" #include "scene/resources/gradient_texture.h" #include "scene/resources/image_texture.h" @@ -220,7 +222,7 @@ void EditorResourcePicker::_update_menu_items() { edited_resource->get_property_list(&property_list); bool has_subresources = false; for (PropertyInfo &p : property_list) { - if ((p.type == Variant::OBJECT) && (p.hint == PROPERTY_HINT_RESOURCE_TYPE) && (p.name != "script")) { + if ((p.type == Variant::OBJECT) && (p.hint == PROPERTY_HINT_RESOURCE_TYPE) && (p.name != "script") && ((Object *)edited_resource->get(p.name) != nullptr)) { has_subresources = true; break; } @@ -352,7 +354,7 @@ void EditorResourcePicker::_edit_menu_cbk(int p_which) { } Ref unique_resource = edited_resource->duplicate(); - ERR_FAIL_COND(unique_resource.is_null()); + ERR_FAIL_COND(unique_resource.is_null()); // duplicate() may fail. edited_resource = unique_resource; emit_signal(SNAME("resource_changed"), edited_resource); @@ -364,12 +366,30 @@ void EditorResourcePicker::_edit_menu_cbk(int p_which) { return; } - Ref unique_resource = edited_resource->duplicate(true); - ERR_FAIL_COND(unique_resource.is_null()); + if (!duplicate_resources_dialog) { + duplicate_resources_dialog = memnew(ConfirmationDialog); + add_child(duplicate_resources_dialog); + duplicate_resources_dialog->set_title(TTR("Make Unique (Recursive)")); + duplicate_resources_dialog->connect("confirmed", callable_mp(this, &EditorResourcePicker::_duplicate_selected_resources)); - edited_resource = unique_resource; - emit_signal(SNAME("resource_changed"), edited_resource); - _update_resource(); + VBoxContainer *vb = memnew(VBoxContainer); + duplicate_resources_dialog->add_child(vb); + + Label *label = memnew(Label(TTR("Select resources to make unique:"))); + vb->add_child(label); + + duplicate_resources_tree = memnew(Tree); + vb->add_child(duplicate_resources_tree); + duplicate_resources_tree->set_columns(2); + duplicate_resources_tree->set_v_size_flags(SIZE_EXPAND_FILL); + } + + duplicate_resources_tree->clear(); + TreeItem *root = duplicate_resources_tree->create_item(); + _gather_resources_to_duplicate(edited_resource, root); + + duplicate_resources_dialog->reset_size(); + duplicate_resources_dialog->popup_centered(Vector2(500, 400) * EDSCALE); } break; case OBJ_MENU_SAVE: { @@ -810,6 +830,11 @@ void EditorResourcePicker::_notification(int p_what) { } } +void EditorResourcePicker::set_assign_button_min_size(const Size2i &p_size) { + assign_button_min_size = p_size; + assign_button->set_custom_minimum_size(assign_button_min_size); +} + void EditorResourcePicker::set_base_type(const String &p_base_type) { base_type = p_base_type; @@ -922,6 +947,89 @@ void EditorResourcePicker::_ensure_resource_menu() { edit_menu->connect("popup_hide", callable_mp((BaseButton *)edit_button, &BaseButton::set_pressed).bind(false)); } +void EditorResourcePicker::_gather_resources_to_duplicate(const Ref p_resource, TreeItem *p_item, const String &p_property_name) const { + p_item->set_cell_mode(0, TreeItem::CELL_MODE_CHECK); + + String res_name = p_resource->get_name(); + if (res_name.is_empty() && !p_resource->is_built_in()) { + res_name = p_resource->get_path().get_file(); + } + + if (res_name.is_empty()) { + p_item->set_text(0, p_resource->get_class()); + } else { + p_item->set_text(0, vformat("%s (%s)", p_resource->get_class(), res_name)); + } + + p_item->set_icon(0, EditorNode::get_singleton()->get_object_icon(p_resource.ptr())); + p_item->set_editable(0, true); + + Array meta; + meta.append(p_resource); + p_item->set_metadata(0, meta); + + if (!p_property_name.is_empty()) { + p_item->set_text(1, p_property_name); + } + + static Vector unique_exceptions = { "Image", "Shader", "Mesh", "FontFile" }; + if (!unique_exceptions.has(p_resource->get_class())) { + // Automatically select resource, unless it's something that shouldn't be duplicated. + p_item->set_checked(0, true); + } + + List plist; + p_resource->get_property_list(&plist); + + for (const PropertyInfo &E : plist) { + if (!(E.usage & PROPERTY_USAGE_STORAGE) || E.type != Variant::OBJECT || E.hint != PROPERTY_HINT_RESOURCE_TYPE) { + continue; + } + + Ref res = p_resource->get(E.name); + if (res.is_null()) { + continue; + } + + TreeItem *child = p_item->create_child(); + _gather_resources_to_duplicate(res, child, E.name); + + meta = child->get_metadata(0); + // Remember property name. + meta.append(E.name); + + if ((E.usage & PROPERTY_USAGE_NEVER_DUPLICATE)) { + // The resource can't be duplicated, but make it appear on the list anyway. + child->set_checked(0, false); + child->set_editable(0, false); + } + } +} + +void EditorResourcePicker::_duplicate_selected_resources() { + for (TreeItem *item = duplicate_resources_tree->get_root(); item; item = item->get_next_in_tree()) { + if (!item->is_checked(0)) { + continue; + } + + Array meta = item->get_metadata(0); + Ref res = meta[0]; + Ref unique_resource = res->duplicate(); + ERR_FAIL_COND(unique_resource.is_null()); // duplicate() may fail. + meta[0] = unique_resource; + + if (meta.size() == 1) { // Root. + edited_resource = unique_resource; + emit_signal(SNAME("resource_changed"), edited_resource); + _update_resource(); + } else { + Array parent_meta = item->get_parent()->get_metadata(0); + Ref parent = parent_meta[0]; + parent->set(meta[1], unique_resource); + } + } +} + EditorResourcePicker::EditorResourcePicker(bool p_hide_assign_button_controls) { assign_button = memnew(Button); assign_button->set_flat(true); diff --git a/editor/editor_resource_picker.h b/editor/editor_resource_picker.h index a302e2495712..856ef974d31f 100644 --- a/editor/editor_resource_picker.h +++ b/editor/editor_resource_picker.h @@ -32,12 +32,15 @@ #define EDITOR_RESOURCE_PICKER_H #include "scene/gui/box_container.h" -#include "scene/gui/button.h" -#include "scene/gui/popup_menu.h" -#include "scene/gui/texture_rect.h" +class Button; +class ConfirmationDialog; class EditorFileDialog; class EditorQuickOpen; +class PopupMenu; +class TextureRect; +class Tree; +class TreeItem; class EditorResourcePicker : public HBoxContainer { GDCLASS(EditorResourcePicker, HBoxContainer); @@ -56,6 +59,9 @@ class EditorResourcePicker : public HBoxContainer { EditorFileDialog *file_dialog = nullptr; EditorQuickOpen *quick_open = nullptr; + ConfirmationDialog *duplicate_resources_dialog = nullptr; + Tree *duplicate_resources_tree = nullptr; + Size2i assign_button_min_size = Size2i(1, 1); enum MenuOption { @@ -99,6 +105,8 @@ class EditorResourcePicker : public HBoxContainer { void drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from); void _ensure_resource_menu(); + void _gather_resources_to_duplicate(const Ref p_resource, TreeItem *p_item, const String &p_property_name = "") const; + void _duplicate_selected_resources(); protected: virtual void _update_resource(); @@ -107,10 +115,7 @@ protected: static void _bind_methods(); void _notification(int p_what); - void set_assign_button_min_size(const Size2i &p_size) { - assign_button_min_size = p_size; - assign_button->set_custom_minimum_size(assign_button_min_size); - } + void set_assign_button_min_size(const Size2i &p_size); GDVIRTUAL1(_set_create_options, Object *) GDVIRTUAL1R(bool, _handle_menu_selected, int)