Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow to pick which Resources will be made unique #77855

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
122 changes: 115 additions & 7 deletions editor/editor_resource_picker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -352,7 +354,7 @@ void EditorResourcePicker::_edit_menu_cbk(int p_which) {
}

Ref<Resource> 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);
Expand All @@ -364,12 +366,30 @@ void EditorResourcePicker::_edit_menu_cbk(int p_which) {
return;
}

Ref<Resource> 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: {
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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<Resource> 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()) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that the check I've suggested originally follows a similar check used in a few places of this file, including a similar resolution for the assign_button. But I suppose this should also work.

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<String> 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<PropertyInfo> 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<Resource> 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<Resource> res = meta[0];
Ref<Resource> 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<Resource> 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);
Expand Down
19 changes: 12 additions & 7 deletions editor/editor_resource_picker.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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 {
Expand Down Expand Up @@ -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<Resource> p_resource, TreeItem *p_item, const String &p_property_name = "") const;
void _duplicate_selected_resources();

protected:
virtual void _update_resource();
Expand All @@ -107,10 +115,7 @@ class EditorResourcePicker : public HBoxContainer {
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)
Expand Down