mirror of
https://github.com/godotengine/godot.git
synced 2024-11-26 22:23:04 +00:00
Add support for resource conversion plugins in filesystem dock.
This commit is contained in:
parent
6681f2563b
commit
f44bce2ee0
@ -3436,6 +3436,98 @@ void EditorNode::_update_file_menu_closed() {
|
|||||||
file_menu->set_item_disabled(file_menu->get_item_index(FILE_OPEN_PREV), false);
|
file_menu->set_item_disabled(file_menu->get_item_index(FILE_OPEN_PREV), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EditorNode::replace_resources_in_object(Object *p_object, const Vector<Ref<Resource>> &p_source_resources, const Vector<Ref<Resource>> &p_target_resource) {
|
||||||
|
List<PropertyInfo> pi;
|
||||||
|
p_object->get_property_list(&pi);
|
||||||
|
|
||||||
|
for (const PropertyInfo &E : pi) {
|
||||||
|
if (!(E.usage & PROPERTY_USAGE_STORAGE)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (E.type) {
|
||||||
|
case Variant::OBJECT: {
|
||||||
|
if (E.hint == PROPERTY_HINT_RESOURCE_TYPE) {
|
||||||
|
const Variant &v = p_object->get(E.name);
|
||||||
|
Ref<Resource> res = v;
|
||||||
|
|
||||||
|
if (res.is_valid()) {
|
||||||
|
int res_idx = p_source_resources.find(res);
|
||||||
|
if (res_idx != -1) {
|
||||||
|
p_object->set(E.name, p_target_resource.get(res_idx));
|
||||||
|
} else {
|
||||||
|
replace_resources_in_object(v, p_source_resources, p_target_resource);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
case Variant::ARRAY: {
|
||||||
|
Array varray = p_object->get(E.name);
|
||||||
|
int len = varray.size();
|
||||||
|
bool array_requires_updating = false;
|
||||||
|
for (int i = 0; i < len; i++) {
|
||||||
|
const Variant &v = varray.get(i);
|
||||||
|
Ref<Resource> res = v;
|
||||||
|
|
||||||
|
if (res.is_valid()) {
|
||||||
|
int res_idx = p_source_resources.find(res);
|
||||||
|
if (res_idx != -1) {
|
||||||
|
varray.set(i, p_target_resource.get(res_idx));
|
||||||
|
array_requires_updating = true;
|
||||||
|
} else {
|
||||||
|
replace_resources_in_object(v, p_source_resources, p_target_resource);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (array_requires_updating) {
|
||||||
|
p_object->set(E.name, varray);
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
case Variant::DICTIONARY: {
|
||||||
|
Dictionary d = p_object->get(E.name);
|
||||||
|
List<Variant> keys;
|
||||||
|
bool dictionary_requires_updating = false;
|
||||||
|
d.get_key_list(&keys);
|
||||||
|
for (const Variant &F : keys) {
|
||||||
|
Variant v = d[F];
|
||||||
|
Ref<Resource> res = v;
|
||||||
|
|
||||||
|
if (res.is_valid()) {
|
||||||
|
int res_idx = p_source_resources.find(res);
|
||||||
|
if (res_idx != -1) {
|
||||||
|
d[F] = p_target_resource.get(res_idx);
|
||||||
|
dictionary_requires_updating = true;
|
||||||
|
} else {
|
||||||
|
replace_resources_in_object(v, p_source_resources, p_target_resource);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (dictionary_requires_updating) {
|
||||||
|
p_object->set(E.name, d);
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
default: {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Node *n = Object::cast_to<Node>(p_object);
|
||||||
|
if (n) {
|
||||||
|
for (int i = 0; i < n->get_child_count(); i++) {
|
||||||
|
replace_resources_in_object(n->get_child(i), p_source_resources, p_target_resource);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditorNode::replace_resources_in_scenes(const Vector<Ref<Resource>> &p_source_resources, const Vector<Ref<Resource>> &p_target_resource) {
|
||||||
|
for (int i = 0; i < editor_data.get_edited_scene_count(); i++) {
|
||||||
|
Node *edited_scene_root = editor_data.get_edited_scene_root(i);
|
||||||
|
if (edited_scene_root) {
|
||||||
|
replace_resources_in_object(edited_scene_root, p_source_resources, p_target_resource);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void EditorNode::add_editor_plugin(EditorPlugin *p_editor, bool p_config_changed) {
|
void EditorNode::add_editor_plugin(EditorPlugin *p_editor, bool p_config_changed) {
|
||||||
if (p_editor->has_main_screen()) {
|
if (p_editor->has_main_screen()) {
|
||||||
singleton->editor_main_screen->add_main_plugin(p_editor);
|
singleton->editor_main_screen->add_main_plugin(p_editor);
|
||||||
@ -6350,12 +6442,32 @@ void EditorNode::remove_resource_conversion_plugin(const Ref<EditorResourceConve
|
|||||||
resource_conversion_plugins.erase(p_plugin);
|
resource_conversion_plugins.erase(p_plugin);
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector<Ref<EditorResourceConversionPlugin>> EditorNode::find_resource_conversion_plugin(const Ref<Resource> &p_for_resource) {
|
Vector<Ref<EditorResourceConversionPlugin>> EditorNode::find_resource_conversion_plugin_for_resource(const Ref<Resource> &p_for_resource) {
|
||||||
|
if (p_for_resource.is_null()) {
|
||||||
|
return Vector<Ref<EditorResourceConversionPlugin>>();
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector<Ref<EditorResourceConversionPlugin>> ret;
|
||||||
|
for (Ref<EditorResourceConversionPlugin> resource_conversion_plugin : resource_conversion_plugins) {
|
||||||
|
if (resource_conversion_plugin.is_valid() && resource_conversion_plugin->handles(p_for_resource)) {
|
||||||
|
ret.push_back(resource_conversion_plugin);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector<Ref<EditorResourceConversionPlugin>> EditorNode::find_resource_conversion_plugin_for_type_name(const String &p_type) {
|
||||||
Vector<Ref<EditorResourceConversionPlugin>> ret;
|
Vector<Ref<EditorResourceConversionPlugin>> ret;
|
||||||
|
|
||||||
for (int i = 0; i < resource_conversion_plugins.size(); i++) {
|
if (ClassDB::can_instantiate(p_type)) {
|
||||||
if (resource_conversion_plugins[i].is_valid() && resource_conversion_plugins[i]->handles(p_for_resource)) {
|
Ref<Resource> temp = Object::cast_to<Resource>(ClassDB::instantiate(p_type));
|
||||||
ret.push_back(resource_conversion_plugins[i]);
|
if (temp.is_valid()) {
|
||||||
|
for (Ref<EditorResourceConversionPlugin> resource_conversion_plugin : resource_conversion_plugins) {
|
||||||
|
if (resource_conversion_plugin.is_valid() && resource_conversion_plugin->handles(temp)) {
|
||||||
|
ret.push_back(resource_conversion_plugin);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -754,6 +754,13 @@ public:
|
|||||||
void push_node_item(Node *p_node);
|
void push_node_item(Node *p_node);
|
||||||
void hide_unused_editors(const Object *p_editing_owner = nullptr);
|
void hide_unused_editors(const Object *p_editing_owner = nullptr);
|
||||||
|
|
||||||
|
void replace_resources_in_object(
|
||||||
|
Object *p_object,
|
||||||
|
const Vector<Ref<Resource>> &p_source_resources,
|
||||||
|
const Vector<Ref<Resource>> &p_target_resource);
|
||||||
|
void replace_resources_in_scenes(
|
||||||
|
const Vector<Ref<Resource>> &p_source_resources,
|
||||||
|
const Vector<Ref<Resource>> &p_target_resource);
|
||||||
void open_request(const String &p_path);
|
void open_request(const String &p_path);
|
||||||
void edit_foreign_resource(Ref<Resource> p_resource);
|
void edit_foreign_resource(Ref<Resource> p_resource);
|
||||||
|
|
||||||
@ -934,7 +941,8 @@ public:
|
|||||||
|
|
||||||
void add_resource_conversion_plugin(const Ref<EditorResourceConversionPlugin> &p_plugin);
|
void add_resource_conversion_plugin(const Ref<EditorResourceConversionPlugin> &p_plugin);
|
||||||
void remove_resource_conversion_plugin(const Ref<EditorResourceConversionPlugin> &p_plugin);
|
void remove_resource_conversion_plugin(const Ref<EditorResourceConversionPlugin> &p_plugin);
|
||||||
Vector<Ref<EditorResourceConversionPlugin>> find_resource_conversion_plugin(const Ref<Resource> &p_for_resource);
|
Vector<Ref<EditorResourceConversionPlugin>> find_resource_conversion_plugin_for_resource(const Ref<Resource> &p_for_resource);
|
||||||
|
Vector<Ref<EditorResourceConversionPlugin>> find_resource_conversion_plugin_for_type_name(const String &p_type);
|
||||||
|
|
||||||
bool ensure_main_scene(bool p_from_native);
|
bool ensure_main_scene(bool p_from_native);
|
||||||
};
|
};
|
||||||
|
@ -286,12 +286,13 @@ void EditorResourcePicker::_update_menu_items() {
|
|||||||
|
|
||||||
// Add options to convert existing resource to another type of resource.
|
// Add options to convert existing resource to another type of resource.
|
||||||
if (is_editable() && edited_resource.is_valid()) {
|
if (is_editable() && edited_resource.is_valid()) {
|
||||||
Vector<Ref<EditorResourceConversionPlugin>> conversions = EditorNode::get_singleton()->find_resource_conversion_plugin(edited_resource);
|
Vector<Ref<EditorResourceConversionPlugin>> conversions = EditorNode::get_singleton()->find_resource_conversion_plugin_for_resource(edited_resource);
|
||||||
if (conversions.size()) {
|
if (!conversions.is_empty()) {
|
||||||
edit_menu->add_separator();
|
edit_menu->add_separator();
|
||||||
}
|
}
|
||||||
for (int i = 0; i < conversions.size(); i++) {
|
int relative_id = 0;
|
||||||
String what = conversions[i]->converts_to();
|
for (const Ref<EditorResourceConversionPlugin> &conversion : conversions) {
|
||||||
|
String what = conversion->converts_to();
|
||||||
Ref<Texture2D> icon;
|
Ref<Texture2D> icon;
|
||||||
if (has_theme_icon(what, EditorStringName(EditorIcons))) {
|
if (has_theme_icon(what, EditorStringName(EditorIcons))) {
|
||||||
icon = get_editor_theme_icon(what);
|
icon = get_editor_theme_icon(what);
|
||||||
@ -299,7 +300,8 @@ void EditorResourcePicker::_update_menu_items() {
|
|||||||
icon = get_theme_icon(what, SNAME("Resource"));
|
icon = get_theme_icon(what, SNAME("Resource"));
|
||||||
}
|
}
|
||||||
|
|
||||||
edit_menu->add_icon_item(icon, vformat(TTR("Convert to %s"), what), CONVERT_BASE_ID + i);
|
edit_menu->add_icon_item(icon, vformat(TTR("Convert to %s"), what), CONVERT_BASE_ID + relative_id);
|
||||||
|
relative_id++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -451,7 +453,7 @@ void EditorResourcePicker::_edit_menu_cbk(int p_which) {
|
|||||||
|
|
||||||
if (p_which >= CONVERT_BASE_ID) {
|
if (p_which >= CONVERT_BASE_ID) {
|
||||||
int to_type = p_which - CONVERT_BASE_ID;
|
int to_type = p_which - CONVERT_BASE_ID;
|
||||||
Vector<Ref<EditorResourceConversionPlugin>> conversions = EditorNode::get_singleton()->find_resource_conversion_plugin(edited_resource);
|
Vector<Ref<EditorResourceConversionPlugin>> conversions = EditorNode::get_singleton()->find_resource_conversion_plugin_for_resource(edited_resource);
|
||||||
ERR_FAIL_INDEX(to_type, conversions.size());
|
ERR_FAIL_INDEX(to_type, conversions.size());
|
||||||
|
|
||||||
edited_resource = conversions[to_type]->convert(edited_resource);
|
edited_resource = conversions[to_type]->convert(edited_resource);
|
||||||
|
@ -45,11 +45,13 @@
|
|||||||
#include "editor/editor_resource_preview.h"
|
#include "editor/editor_resource_preview.h"
|
||||||
#include "editor/editor_settings.h"
|
#include "editor/editor_settings.h"
|
||||||
#include "editor/editor_string_names.h"
|
#include "editor/editor_string_names.h"
|
||||||
|
#include "editor/editor_undo_redo_manager.h"
|
||||||
#include "editor/gui/editor_dir_dialog.h"
|
#include "editor/gui/editor_dir_dialog.h"
|
||||||
#include "editor/gui/editor_scene_tabs.h"
|
#include "editor/gui/editor_scene_tabs.h"
|
||||||
#include "editor/import/3d/scene_import_settings.h"
|
#include "editor/import/3d/scene_import_settings.h"
|
||||||
#include "editor/import_dock.h"
|
#include "editor/import_dock.h"
|
||||||
#include "editor/plugins/editor_context_menu_plugin.h"
|
#include "editor/plugins/editor_context_menu_plugin.h"
|
||||||
|
#include "editor/plugins/editor_resource_conversion_plugin.h"
|
||||||
#include "editor/plugins/editor_resource_tooltip_plugins.h"
|
#include "editor/plugins/editor_resource_tooltip_plugins.h"
|
||||||
#include "editor/scene_create_dialog.h"
|
#include "editor/scene_create_dialog.h"
|
||||||
#include "editor/scene_tree_dock.h"
|
#include "editor/scene_tree_dock.h"
|
||||||
@ -1188,6 +1190,47 @@ void FileSystemDock::_update_file_list(bool p_keep_selection) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
HashSet<String> FileSystemDock::_get_valid_conversions_for_file_paths(const Vector<String> &p_paths) {
|
||||||
|
HashSet<String> all_valid_conversion_to_targets;
|
||||||
|
for (const String &fpath : p_paths) {
|
||||||
|
if (fpath.is_empty() || fpath == "res://" || !FileAccess::exists(fpath) || FileAccess::exists(fpath + ".import")) {
|
||||||
|
return HashSet<String>();
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector<Ref<EditorResourceConversionPlugin>> conversions = EditorNode::get_singleton()->find_resource_conversion_plugin_for_type_name(EditorFileSystem::get_singleton()->get_file_type(fpath));
|
||||||
|
|
||||||
|
if (conversions.is_empty()) {
|
||||||
|
// This resource can't convert to anything, so return an empty list.
|
||||||
|
return HashSet<String>();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get a list of all potentional conversion-to targets.
|
||||||
|
HashSet<String> current_valid_conversion_to_targets;
|
||||||
|
for (const Ref<EditorResourceConversionPlugin> &E : conversions) {
|
||||||
|
const String what = E->converts_to();
|
||||||
|
current_valid_conversion_to_targets.insert(what);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (all_valid_conversion_to_targets.is_empty()) {
|
||||||
|
// If we have no existing valid conversions, this is the first one, so copy them directly.
|
||||||
|
all_valid_conversion_to_targets = current_valid_conversion_to_targets;
|
||||||
|
} else {
|
||||||
|
// Check existing conversion targets and remove any which are not in the current list.
|
||||||
|
for (const String &S : all_valid_conversion_to_targets) {
|
||||||
|
if (!current_valid_conversion_to_targets.has(S)) {
|
||||||
|
all_valid_conversion_to_targets.erase(S);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// We have no more remaining valid conversions, so break the loop.
|
||||||
|
if (all_valid_conversion_to_targets.is_empty()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return all_valid_conversion_to_targets;
|
||||||
|
}
|
||||||
|
|
||||||
void FileSystemDock::_select_file(const String &p_path, bool p_select_in_favorites) {
|
void FileSystemDock::_select_file(const String &p_path, bool p_select_in_favorites) {
|
||||||
String fpath = p_path;
|
String fpath = p_path;
|
||||||
if (fpath.ends_with("/")) {
|
if (fpath.ends_with("/")) {
|
||||||
@ -1908,6 +1951,54 @@ void FileSystemDock::_overwrite_dialog_action(bool p_overwrite) {
|
|||||||
_move_operation_confirm(to_move_path, to_move_or_copy, p_overwrite ? OVERWRITE_REPLACE : OVERWRITE_RENAME);
|
_move_operation_confirm(to_move_path, to_move_or_copy, p_overwrite ? OVERWRITE_REPLACE : OVERWRITE_RENAME);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FileSystemDock::_convert_dialog_action() {
|
||||||
|
Vector<Ref<Resource>> selected_resources;
|
||||||
|
for (const String &S : to_convert) {
|
||||||
|
Ref<Resource> res = ResourceLoader::load(S);
|
||||||
|
ERR_FAIL_COND(res.is_null());
|
||||||
|
selected_resources.push_back(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector<Ref<Resource>> converted_resources;
|
||||||
|
HashSet<Ref<Resource>> resources_to_erase_history_for;
|
||||||
|
for (Ref<Resource> res : selected_resources) {
|
||||||
|
Vector<Ref<EditorResourceConversionPlugin>> conversions = EditorNode::get_singleton()->find_resource_conversion_plugin_for_resource(res);
|
||||||
|
for (const Ref<EditorResourceConversionPlugin> &conversion : conversions) {
|
||||||
|
int conversion_id = 0;
|
||||||
|
for (const String &target : cached_valid_conversion_targets) {
|
||||||
|
if (conversion_id == selected_conversion_id && conversion->converts_to() == target) {
|
||||||
|
Ref<Resource> converted_res = conversion->convert(res);
|
||||||
|
ERR_FAIL_COND(res.is_null());
|
||||||
|
converted_resources.push_back(converted_res);
|
||||||
|
resources_to_erase_history_for.insert(res);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
conversion_id++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear history for the objects being replaced.
|
||||||
|
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
|
||||||
|
for (Ref<Resource> res : resources_to_erase_history_for) {
|
||||||
|
undo_redo->clear_history(true, undo_redo->get_history_id_for_object(res.ptr()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Updates all the resources existing as node properties.
|
||||||
|
EditorNode::get_singleton()->replace_resources_in_scenes(selected_resources, converted_resources);
|
||||||
|
|
||||||
|
// Overwrite the old resources.
|
||||||
|
for (int i = 0; i < converted_resources.size(); i++) {
|
||||||
|
Ref<Resource> original_resource = selected_resources.get(i);
|
||||||
|
Ref<Resource> new_resource = converted_resources.get(i);
|
||||||
|
|
||||||
|
// Overwrite the path.
|
||||||
|
new_resource->set_path(original_resource->get_path(), true);
|
||||||
|
|
||||||
|
ResourceSaver::save(new_resource);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Vector<String> FileSystemDock::_check_existing() {
|
Vector<String> FileSystemDock::_check_existing() {
|
||||||
Vector<String> conflicting_items;
|
Vector<String> conflicting_items;
|
||||||
for (const FileOrFolder &item : to_move) {
|
for (const FileOrFolder &item : to_move) {
|
||||||
@ -2126,6 +2217,16 @@ void FileSystemDock::_file_list_rmb_option(int p_option) {
|
|||||||
_file_option(p_option, selected);
|
_file_option(p_option, selected);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FileSystemDock::_generic_rmb_option_selected(int p_option) {
|
||||||
|
// Used for submenu commands where we don't know whether we're
|
||||||
|
// calling from the file_list_rmb menu or the _tree_rmb option.
|
||||||
|
if (files->has_focus()) {
|
||||||
|
_file_list_rmb_option(p_option);
|
||||||
|
} else {
|
||||||
|
_tree_rmb_option(p_option);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void FileSystemDock::_file_option(int p_option, const Vector<String> &p_selected) {
|
void FileSystemDock::_file_option(int p_option, const Vector<String> &p_selected) {
|
||||||
// The first one should be the active item.
|
// The first one should be the active item.
|
||||||
|
|
||||||
@ -2568,9 +2669,31 @@ void FileSystemDock::_file_option(int p_option, const Vector<String> &p_selected
|
|||||||
} break;
|
} break;
|
||||||
|
|
||||||
default: {
|
default: {
|
||||||
if (!EditorContextMenuPluginManager::get_singleton()->activate_custom_option(EditorContextMenuPlugin::CONTEXT_SLOT_FILESYSTEM, p_option, p_selected)) {
|
// Resource conversion commands:
|
||||||
EditorContextMenuPluginManager::get_singleton()->activate_custom_option(EditorContextMenuPlugin::CONTEXT_SLOT_FILESYSTEM_CREATE, p_option, p_selected);
|
if (p_option >= CONVERT_BASE_ID) {
|
||||||
|
selected_conversion_id = p_option - CONVERT_BASE_ID;
|
||||||
|
ERR_FAIL_INDEX(selected_conversion_id, (int)cached_valid_conversion_targets.size());
|
||||||
|
|
||||||
|
to_convert.clear();
|
||||||
|
for (const String &S : p_selected) {
|
||||||
|
to_convert.push_back(S);
|
||||||
|
}
|
||||||
|
|
||||||
|
int conversion_id = 0;
|
||||||
|
for (const String &E : cached_valid_conversion_targets) {
|
||||||
|
if (conversion_id == selected_conversion_id) {
|
||||||
|
conversion_dialog->set_text(vformat(TTR("Do you wish to convert these files to %s? (This operation cannot be undone!)"), E));
|
||||||
|
conversion_dialog->popup_centered();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
conversion_id++;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!EditorContextMenuPluginManager::get_singleton()->activate_custom_option(EditorContextMenuPlugin::CONTEXT_SLOT_FILESYSTEM, p_option, p_selected)) {
|
||||||
|
EditorContextMenuPluginManager::get_singleton()->activate_custom_option(EditorContextMenuPlugin::CONTEXT_SLOT_FILESYSTEM_CREATE, p_option, p_selected);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3184,7 +3307,7 @@ void FileSystemDock::_file_and_folders_fill_popup(PopupMenu *p_popup, const Vect
|
|||||||
|
|
||||||
if (p_paths.size() == 1 && p_display_path_dependent_options) {
|
if (p_paths.size() == 1 && p_display_path_dependent_options) {
|
||||||
PopupMenu *new_menu = memnew(PopupMenu);
|
PopupMenu *new_menu = memnew(PopupMenu);
|
||||||
new_menu->connect(SceneStringName(id_pressed), callable_mp(this, &FileSystemDock::_tree_rmb_option));
|
new_menu->connect(SceneStringName(id_pressed), callable_mp(this, &FileSystemDock::_generic_rmb_option_selected));
|
||||||
|
|
||||||
p_popup->add_submenu_node_item(TTR("Create New"), new_menu, FILE_NEW);
|
p_popup->add_submenu_node_item(TTR("Create New"), new_menu, FILE_NEW);
|
||||||
p_popup->set_item_icon(p_popup->get_item_index(FILE_NEW), get_editor_theme_icon(SNAME("Add")));
|
p_popup->set_item_icon(p_popup->get_item_index(FILE_NEW), get_editor_theme_icon(SNAME("Add")));
|
||||||
@ -3256,6 +3379,41 @@ void FileSystemDock::_file_and_folders_fill_popup(PopupMenu *p_popup, const Vect
|
|||||||
p_popup->add_icon_item(get_editor_theme_icon(SNAME("NonFavorite")), TTR("Remove from Favorites"), FILE_REMOVE_FAVORITE);
|
p_popup->add_icon_item(get_editor_theme_icon(SNAME("NonFavorite")), TTR("Remove from Favorites"), FILE_REMOVE_FAVORITE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (p_paths.size() > 1 || p_paths[0] != "res://") {
|
||||||
|
cached_valid_conversion_targets = _get_valid_conversions_for_file_paths(p_paths);
|
||||||
|
|
||||||
|
int relative_id = 0;
|
||||||
|
if (!cached_valid_conversion_targets.is_empty()) {
|
||||||
|
p_popup->add_separator();
|
||||||
|
|
||||||
|
// If we have more than one type we can convert into, collapse it into a submenu.
|
||||||
|
const int CONVERSION_SUBMENU_THRESHOLD = 1;
|
||||||
|
|
||||||
|
PopupMenu *container_menu = p_popup;
|
||||||
|
String conversion_string_template = "Convert to %s";
|
||||||
|
|
||||||
|
if (cached_valid_conversion_targets.size() > CONVERSION_SUBMENU_THRESHOLD) {
|
||||||
|
container_menu = memnew(PopupMenu);
|
||||||
|
container_menu->connect("id_pressed", callable_mp(this, &FileSystemDock::_generic_rmb_option_selected));
|
||||||
|
|
||||||
|
p_popup->add_submenu_node_item(TTR("Convert to..."), container_menu, FILE_NEW);
|
||||||
|
conversion_string_template = "%s";
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const String &E : cached_valid_conversion_targets) {
|
||||||
|
Ref<Texture2D> icon;
|
||||||
|
if (has_theme_icon(E, SNAME("EditorIcons"))) {
|
||||||
|
icon = get_editor_theme_icon(E);
|
||||||
|
} else {
|
||||||
|
icon = get_editor_theme_icon(SNAME("Resource"));
|
||||||
|
}
|
||||||
|
|
||||||
|
container_menu->add_icon_item(icon, vformat(TTR(conversion_string_template), E), CONVERT_BASE_ID + relative_id);
|
||||||
|
relative_id++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
List<String> resource_extensions;
|
List<String> resource_extensions;
|
||||||
ResourceFormatImporter::get_singleton()->get_recognized_extensions_for_type("Resource", &resource_extensions);
|
ResourceFormatImporter::get_singleton()->get_recognized_extensions_for_type("Resource", &resource_extensions);
|
||||||
@ -4193,6 +4351,11 @@ FileSystemDock::FileSystemDock() {
|
|||||||
new_resource_dialog->set_base_type("Resource");
|
new_resource_dialog->set_base_type("Resource");
|
||||||
new_resource_dialog->connect("create", callable_mp(this, &FileSystemDock::_resource_created));
|
new_resource_dialog->connect("create", callable_mp(this, &FileSystemDock::_resource_created));
|
||||||
|
|
||||||
|
conversion_dialog = memnew(ConfirmationDialog);
|
||||||
|
add_child(conversion_dialog);
|
||||||
|
conversion_dialog->set_ok_button_text(TTR("Convert"));
|
||||||
|
conversion_dialog->connect(SceneStringName(confirmed), callable_mp(this, &FileSystemDock::_convert_dialog_action));
|
||||||
|
|
||||||
uncollapsed_paths_before_search = Vector<String>();
|
uncollapsed_paths_before_search = Vector<String>();
|
||||||
|
|
||||||
tree_update_id = 0;
|
tree_update_id = 0;
|
||||||
|
@ -140,6 +140,7 @@ private:
|
|||||||
FILE_NEW_FOLDER,
|
FILE_NEW_FOLDER,
|
||||||
FILE_NEW_SCRIPT,
|
FILE_NEW_SCRIPT,
|
||||||
FILE_NEW_SCENE,
|
FILE_NEW_SCENE,
|
||||||
|
CONVERT_BASE_ID = 1000,
|
||||||
};
|
};
|
||||||
|
|
||||||
HashMap<String, Color> folder_colors;
|
HashMap<String, Color> folder_colors;
|
||||||
@ -201,6 +202,8 @@ private:
|
|||||||
Label *overwrite_dialog_footer = nullptr;
|
Label *overwrite_dialog_footer = nullptr;
|
||||||
Label *overwrite_dialog_file_list = nullptr;
|
Label *overwrite_dialog_file_list = nullptr;
|
||||||
|
|
||||||
|
ConfirmationDialog *conversion_dialog = nullptr;
|
||||||
|
|
||||||
SceneCreateDialog *make_scene_dialog = nullptr;
|
SceneCreateDialog *make_scene_dialog = nullptr;
|
||||||
ScriptCreateDialog *make_script_dialog = nullptr;
|
ScriptCreateDialog *make_script_dialog = nullptr;
|
||||||
ShaderCreateDialog *make_shader_dialog = nullptr;
|
ShaderCreateDialog *make_shader_dialog = nullptr;
|
||||||
@ -226,6 +229,9 @@ private:
|
|||||||
String to_move_path;
|
String to_move_path;
|
||||||
bool to_move_or_copy = false;
|
bool to_move_or_copy = false;
|
||||||
|
|
||||||
|
Vector<String> to_convert;
|
||||||
|
int selected_conversion_id = 0;
|
||||||
|
|
||||||
Vector<String> history;
|
Vector<String> history;
|
||||||
int history_pos;
|
int history_pos;
|
||||||
int history_max_size;
|
int history_max_size;
|
||||||
@ -245,6 +251,8 @@ private:
|
|||||||
|
|
||||||
LocalVector<Ref<EditorResourceTooltipPlugin>> tooltip_plugins;
|
LocalVector<Ref<EditorResourceTooltipPlugin>> tooltip_plugins;
|
||||||
|
|
||||||
|
HashSet<String> cached_valid_conversion_targets;
|
||||||
|
|
||||||
void _tree_mouse_exited();
|
void _tree_mouse_exited();
|
||||||
void _reselect_items_selected_on_drag_begin(bool reset = false);
|
void _reselect_items_selected_on_drag_begin(bool reset = false);
|
||||||
|
|
||||||
@ -256,6 +264,8 @@ private:
|
|||||||
void _file_list_gui_input(Ref<InputEvent> p_event);
|
void _file_list_gui_input(Ref<InputEvent> p_event);
|
||||||
void _tree_gui_input(Ref<InputEvent> p_event);
|
void _tree_gui_input(Ref<InputEvent> p_event);
|
||||||
|
|
||||||
|
HashSet<String> _get_valid_conversions_for_file_paths(const Vector<String> &p_paths);
|
||||||
|
|
||||||
void _update_file_list(bool p_keep_selection);
|
void _update_file_list(bool p_keep_selection);
|
||||||
void _toggle_file_display();
|
void _toggle_file_display();
|
||||||
void _set_file_display(bool p_active);
|
void _set_file_display(bool p_active);
|
||||||
@ -292,11 +302,13 @@ private:
|
|||||||
void _rename_operation_confirm();
|
void _rename_operation_confirm();
|
||||||
void _duplicate_operation_confirm();
|
void _duplicate_operation_confirm();
|
||||||
void _overwrite_dialog_action(bool p_overwrite);
|
void _overwrite_dialog_action(bool p_overwrite);
|
||||||
|
void _convert_dialog_action();
|
||||||
Vector<String> _check_existing();
|
Vector<String> _check_existing();
|
||||||
void _move_operation_confirm(const String &p_to_path, bool p_copy = false, Overwrite p_overwrite = OVERWRITE_UNDECIDED);
|
void _move_operation_confirm(const String &p_to_path, bool p_copy = false, Overwrite p_overwrite = OVERWRITE_UNDECIDED);
|
||||||
|
|
||||||
void _tree_rmb_option(int p_option);
|
void _tree_rmb_option(int p_option);
|
||||||
void _file_list_rmb_option(int p_option);
|
void _file_list_rmb_option(int p_option);
|
||||||
|
void _generic_rmb_option_selected(int p_option);
|
||||||
void _file_option(int p_option, const Vector<String> &p_selected);
|
void _file_option(int p_option, const Vector<String> &p_selected);
|
||||||
|
|
||||||
void _fw_history();
|
void _fw_history();
|
||||||
|
@ -606,23 +606,25 @@ void ImportDock::_reimport_and_cleanup() {
|
|||||||
List<Ref<Resource>> external_resources;
|
List<Ref<Resource>> external_resources;
|
||||||
ResourceCache::get_cached_resources(&external_resources);
|
ResourceCache::get_cached_resources(&external_resources);
|
||||||
|
|
||||||
|
Vector<Ref<Resource>> old_resources_to_replace;
|
||||||
|
Vector<Ref<Resource>> new_resources_to_replace;
|
||||||
for (const String &path : need_cleanup) {
|
for (const String &path : need_cleanup) {
|
||||||
Ref<Resource> old_res = old_resources[path];
|
Ref<Resource> old_res = old_resources[path];
|
||||||
Ref<Resource> new_res;
|
|
||||||
if (params->importer.is_valid()) {
|
if (params->importer.is_valid()) {
|
||||||
new_res = ResourceLoader::load(path);
|
Ref<Resource> new_res = ResourceLoader::load(path);
|
||||||
}
|
if (new_res.is_valid()) {
|
||||||
|
old_resources_to_replace.append(old_res);
|
||||||
for (int i = 0; i < EditorNode::get_editor_data().get_edited_scene_count(); i++) {
|
new_resources_to_replace.append(new_res);
|
||||||
Node *edited_scene_root = EditorNode::get_editor_data().get_edited_scene_root(i);
|
|
||||||
if (likely(edited_scene_root)) {
|
|
||||||
_replace_resource_in_object(edited_scene_root, old_res, new_res);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (Ref<Resource> res : external_resources) {
|
|
||||||
_replace_resource_in_object(res.ptr(), old_res, new_res);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EditorNode::get_singleton()->replace_resources_in_scenes(old_resources_to_replace, new_resources_to_replace);
|
||||||
|
|
||||||
|
for (Ref<Resource> res : external_resources) {
|
||||||
|
EditorNode::get_singleton()->replace_resources_in_object(res.ptr(), old_resources_to_replace, new_resources_to_replace);
|
||||||
|
}
|
||||||
|
|
||||||
need_cleanup.clear();
|
need_cleanup.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -693,37 +695,6 @@ void ImportDock::_reimport() {
|
|||||||
_set_dirty(false);
|
_set_dirty(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImportDock::_replace_resource_in_object(Object *p_object, const Ref<Resource> &old_resource, const Ref<Resource> &new_resource) {
|
|
||||||
ERR_FAIL_NULL(p_object);
|
|
||||||
|
|
||||||
List<PropertyInfo> props;
|
|
||||||
p_object->get_property_list(&props);
|
|
||||||
|
|
||||||
for (const PropertyInfo &p : props) {
|
|
||||||
if (p.type != Variant::OBJECT || p.hint != PROPERTY_HINT_RESOURCE_TYPE) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ref<Resource> res = p_object->get(p.name);
|
|
||||||
if (res.is_null()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (res == old_resource) {
|
|
||||||
p_object->set(p.name, new_resource);
|
|
||||||
} else {
|
|
||||||
_replace_resource_in_object(res.ptr(), old_resource, new_resource);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Node *n = Object::cast_to<Node>(p_object);
|
|
||||||
if (n) {
|
|
||||||
for (int i = 0; i < n->get_child_count(); i++) {
|
|
||||||
_replace_resource_in_object(n->get_child(i), old_resource, new_resource);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ImportDock::_notification(int p_what) {
|
void ImportDock::_notification(int p_what) {
|
||||||
switch (p_what) {
|
switch (p_what) {
|
||||||
case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
|
case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
|
||||||
|
@ -81,8 +81,6 @@ class ImportDock : public VBoxContainer {
|
|||||||
void _reimport_and_cleanup();
|
void _reimport_and_cleanup();
|
||||||
void _reimport();
|
void _reimport();
|
||||||
|
|
||||||
void _replace_resource_in_object(Object *p_object, const Ref<Resource> &old_resource, const Ref<Resource> &new_resource);
|
|
||||||
|
|
||||||
void _advanced_options();
|
void _advanced_options();
|
||||||
enum {
|
enum {
|
||||||
ITEM_SET_AS_DEFAULT = 100,
|
ITEM_SET_AS_DEFAULT = 100,
|
||||||
|
Loading…
Reference in New Issue
Block a user