summaryrefslogtreecommitdiff
path: root/editor
diff options
context:
space:
mode:
Diffstat (limited to 'editor')
-rw-r--r--editor/dependency_editor.h1
-rw-r--r--editor/doc/doc_data.cpp2
-rw-r--r--editor/editor_export.cpp13
-rw-r--r--editor/editor_export.h5
-rw-r--r--editor/editor_file_dialog.cpp186
-rw-r--r--editor/editor_file_dialog.h20
-rw-r--r--editor/editor_file_system.cpp6
-rw-r--r--editor/editor_help.cpp154
-rw-r--r--editor/editor_help.h3
-rw-r--r--editor/editor_node.cpp29
-rw-r--r--editor/editor_plugin.cpp23
-rw-r--r--editor/editor_plugin.h5
-rw-r--r--editor/editor_settings.cpp4
-rw-r--r--editor/editor_themes.cpp3
-rw-r--r--editor/filesystem_dock.cpp124
-rw-r--r--editor/filesystem_dock.h16
-rw-r--r--editor/import/editor_import_collada.cpp4
-rw-r--r--editor/import/editor_import_collada.h2
-rw-r--r--editor/import/editor_scene_importer_gltf.cpp2
-rw-r--r--editor/import/editor_scene_importer_gltf.h2
-rw-r--r--editor/import/resource_importer_obj.cpp2
-rw-r--r--editor/import/resource_importer_obj.h2
-rw-r--r--editor/import/resource_importer_scene.cpp239
-rw-r--r--editor/import/resource_importer_scene.h22
-rw-r--r--editor/plugins/abstract_polygon_2d_editor.cpp32
-rw-r--r--editor/plugins/canvas_item_editor_plugin.cpp61
-rw-r--r--editor/plugins/canvas_item_editor_plugin.h1
-rw-r--r--editor/plugins/collision_polygon_2d_editor_plugin.cpp8
-rw-r--r--editor/plugins/curve_editor_plugin.cpp6
-rw-r--r--editor/plugins/editor_preview_plugins.cpp39
-rw-r--r--editor/plugins/line_2d_editor_plugin.cpp8
-rw-r--r--editor/plugins/mesh_instance_editor_plugin.cpp145
-rw-r--r--editor/plugins/mesh_instance_editor_plugin.h10
-rw-r--r--editor/plugins/navigation_polygon_editor_plugin.cpp8
-rw-r--r--editor/plugins/polygon_2d_editor_plugin.cpp8
-rw-r--r--editor/plugins/script_editor_plugin.cpp12
-rw-r--r--editor/plugins/script_editor_plugin.h3
-rw-r--r--editor/plugins/script_text_editor.cpp33
-rw-r--r--editor/plugins/script_text_editor.h3
-rw-r--r--editor/plugins/shader_editor_plugin.cpp3
-rw-r--r--editor/project_manager.cpp3
-rw-r--r--editor/project_settings_editor.cpp20
-rw-r--r--editor/property_editor.cpp90
-rw-r--r--editor/property_editor.h18
44 files changed, 1083 insertions, 297 deletions
diff --git a/editor/dependency_editor.h b/editor/dependency_editor.h
index 9b0aca67d5..0cc153945d 100644
--- a/editor/dependency_editor.h
+++ b/editor/dependency_editor.h
@@ -35,6 +35,7 @@
#include "scene/gui/tab_container.h"
#include "scene/gui/tree.h"
+class EditorFileDialog;
class EditorFileSystemDirectory;
class EditorNode;
diff --git a/editor/doc/doc_data.cpp b/editor/doc/doc_data.cpp
index 3a72f8e569..0bb059f425 100644
--- a/editor/doc/doc_data.cpp
+++ b/editor/doc/doc_data.cpp
@@ -235,7 +235,7 @@ void DocData::generate(bool p_basic_types) {
ClassDB::get_property_list(name, &properties, true);
for (List<PropertyInfo>::Element *E = properties.front(); E; E = E->next()) {
- if (E->get().usage & PROPERTY_USAGE_GROUP || E->get().usage & PROPERTY_USAGE_CATEGORY)
+ if (E->get().usage & PROPERTY_USAGE_GROUP || E->get().usage & PROPERTY_USAGE_CATEGORY || E->get().usage & PROPERTY_USAGE_INTERNAL)
continue;
PropertyDoc prop;
diff --git a/editor/editor_export.cpp b/editor/editor_export.cpp
index 8c8d9c4c79..3f618c3199 100644
--- a/editor/editor_export.cpp
+++ b/editor/editor_export.cpp
@@ -743,6 +743,18 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> &
custom_map["path_remap/remapped_paths"] = path_remaps;
}
+ // Store icon and splash images directly, they need to bypass the import system and be loaded as images
+ String icon = ProjectSettings::get_singleton()->get("application/config/icon");
+ String splash = ProjectSettings::get_singleton()->get("application/boot_splash/image");
+ if (icon != String() && FileAccess::exists(icon)) {
+ Vector<uint8_t> array = FileAccess::get_file_as_array(icon);
+ p_func(p_udata, icon, array, idx, total);
+ }
+ if (splash != String() && FileAccess::exists(splash)) {
+ Vector<uint8_t> array = FileAccess::get_file_as_array(splash);
+ p_func(p_udata, splash, array, idx, total);
+ }
+
String config_file = "project.binary";
String engine_cfb = EditorSettings::get_singleton()->get_cache_dir().plus_file("tmp" + config_file);
ProjectSettings::get_singleton()->save_custom(engine_cfb, custom_map, custom_list);
@@ -1249,6 +1261,7 @@ bool EditorExportPlatformPC::can_export(const Ref<EditorExportPreset> &p_preset,
if (custom_debug_binary == "" && custom_release_binary == "") {
if (!err.empty())
r_error = err;
+ r_missing_templates = !valid;
return valid;
}
diff --git a/editor/editor_export.h b/editor/editor_export.h
index 346c3b58e1..215a770a12 100644
--- a/editor/editor_export.h
+++ b/editor/editor_export.h
@@ -122,8 +122,9 @@ struct SharedObject {
String path;
Vector<String> tags;
- SharedObject(const String &p_path, const Vector<String> &p_tags)
- : path(p_path), tags(p_tags) {
+ SharedObject(const String &p_path, const Vector<String> &p_tags) :
+ path(p_path),
+ tags(p_tags) {
}
SharedObject() {}
diff --git a/editor/editor_file_dialog.cpp b/editor/editor_file_dialog.cpp
index eb5af2eaeb..eaa57fa46b 100644
--- a/editor/editor_file_dialog.cpp
+++ b/editor/editor_file_dialog.cpp
@@ -28,12 +28,13 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "editor_file_dialog.h"
-
+#include "dependency_editor.h"
#include "editor_resource_preview.h"
#include "editor_scale.h"
#include "editor_settings.h"
#include "os/file_access.h"
#include "os/keyboard.h"
+#include "os/os.h"
#include "print_string.h"
#include "scene/gui/center_container.h"
#include "scene/gui/label.h"
@@ -159,6 +160,10 @@ void EditorFileDialog::_unhandled_input(const Ref<InputEvent> &p_event) {
_make_dir();
handled = true;
}
+ if (ED_IS_SHORTCUT("file_dialog/delete", p_event)) {
+ _delete_items();
+ handled = true;
+ }
if (ED_IS_SHORTCUT("file_dialog/focus_path", p_event)) {
dir->grab_focus();
handled = true;
@@ -512,6 +517,106 @@ void EditorFileDialog::_item_dc_selected(int p_item) {
}
}
+void EditorFileDialog::_item_list_item_rmb_selected(int p_item, const Vector2 &p_pos) {
+
+ // Right click on specific file(s) or folder(s).
+ item_menu->clear();
+ item_menu->set_size(Size2(1, 1));
+
+ // Allow specific actions only on one item.
+ bool single_item_selected = item_list->get_selected_items().size() == 1;
+
+ // Disallow deleting the .import folder, Godot kills a cat if you do and it is possibly a senseless novice action.
+ bool allow_delete = true;
+ for (int i = 0; i < item_list->get_item_count(); i++) {
+ if (!item_list->is_selected(i)) {
+ continue;
+ }
+ Dictionary item_meta = item_list->get_item_metadata(i);
+ if (item_meta["path"] == "res://.import") {
+ allow_delete = false;
+ break;
+ }
+ }
+
+ if (single_item_selected) {
+ item_menu->add_icon_item(get_icon("CopyNodePath", "EditorIcons"), TTR("Copy Path"), ITEM_MENU_COPY_PATH);
+ }
+ if (allow_delete) {
+ item_menu->add_icon_item(get_icon("Remove", "EditorIcons"), TTR("Delete"), ITEM_MENU_DELETE, KEY_DELETE);
+ }
+ if (single_item_selected) {
+ item_menu->add_separator();
+ item_menu->add_icon_item(get_icon("Filesystem", "EditorIcons"), TTR("Show In File Manager"), ITEM_MENU_SHOW_IN_EXPLORER);
+ }
+
+ if (item_menu->get_item_count() > 0) {
+ item_menu->set_position(item_list->get_global_position() + p_pos);
+ item_menu->popup();
+ }
+}
+
+void EditorFileDialog::_item_list_rmb_clicked(const Vector2 &p_pos) {
+
+ // Right click on folder background. Deselect all files so that actions are applied on the current folder.
+ for (int i = 0; i < item_list->get_item_count(); i++) {
+ item_list->unselect(i);
+ }
+
+ item_menu->clear();
+ item_menu->set_size(Size2(1, 1));
+
+ if (can_create_dir) {
+ item_menu->add_icon_item(get_icon("folder", "FileDialog"), TTR("New Folder.."), ITEM_MENU_NEW_FOLDER, KEY_MASK_CMD | KEY_N);
+ }
+ item_menu->add_icon_item(get_icon("Reload", "EditorIcons"), TTR("Refresh"), ITEM_MENU_REFRESH, KEY_F5);
+ item_menu->add_separator();
+ item_menu->add_icon_item(get_icon("Filesystem", "EditorIcons"), TTR("Show In File Manager"), ITEM_MENU_SHOW_IN_EXPLORER);
+
+ item_menu->set_position(item_list->get_global_position() + p_pos);
+ item_menu->popup();
+}
+
+void EditorFileDialog::_item_menu_id_pressed(int p_option) {
+
+ switch (p_option) {
+
+ case ITEM_MENU_COPY_PATH: {
+ Dictionary item_meta = item_list->get_item_metadata(item_list->get_current());
+ OS::get_singleton()->set_clipboard(item_meta["path"]);
+ } break;
+
+ case ITEM_MENU_DELETE: {
+ _delete_items();
+ } break;
+
+ case ITEM_MENU_REFRESH: {
+ invalidate();
+ } break;
+
+ case ITEM_MENU_NEW_FOLDER: {
+ _make_dir();
+ } break;
+
+ case ITEM_MENU_SHOW_IN_EXPLORER: {
+ String path;
+ int idx = item_list->get_current();
+ if (idx == -1 || item_list->get_selected_items().size() == 0) {
+ // Folder background was clicked. Open this folder.
+ path = ProjectSettings::get_singleton()->globalize_path(dir_access->get_current_dir());
+ } else {
+ // Specific item was clicked. Open folders directly, or the folder containing a selected file.
+ Dictionary item_meta = item_list->get_item_metadata(idx);
+ path = ProjectSettings::get_singleton()->globalize_path(item_meta["path"]);
+ if (!item_meta["dir"]) {
+ path = path.get_base_dir();
+ }
+ }
+ OS::get_singleton()->shell_open(String("file://") + path);
+ } break;
+ }
+}
+
bool EditorFileDialog::_is_open_should_be_disabled() {
if (mode == MODE_OPEN_ANY || mode == MODE_SAVE_FILE)
@@ -617,7 +722,7 @@ void EditorFileDialog::update_file_list() {
Dictionary d;
d["name"] = dir_name;
- d["path"] = String();
+ d["path"] = cdir.plus_file(dir_name);
d["dir"] = true;
item_list->set_item_metadata(item_list->get_item_count() - 1, d);
@@ -657,8 +762,6 @@ void EditorFileDialog::update_file_list() {
}
}
- String base_dir = dir_access->get_current_dir();
-
while (!files.empty()) {
bool match = patterns.empty();
@@ -679,7 +782,7 @@ void EditorFileDialog::update_file_list() {
if (get_icon_func) {
- Ref<Texture> icon = get_icon_func(base_dir.plus_file(files.front()->get()));
+ Ref<Texture> icon = get_icon_func(cdir.plus_file(files.front()->get()));
//ti->set_icon(0,icon);
if (display_mode == DISPLAY_THUMBNAILS) {
@@ -698,12 +801,11 @@ void EditorFileDialog::update_file_list() {
Dictionary d;
d["name"] = files.front()->get();
d["dir"] = false;
- String fullpath = base_dir.plus_file(files.front()->get());
-
+ String fullpath = cdir.plus_file(files.front()->get());
if (display_mode == DISPLAY_THUMBNAILS) {
EditorResourcePreview::get_singleton()->queue_resource_preview(fullpath, this, "_thumbnail_result", fullpath);
}
- d["path"] = base_dir.plus_file(files.front()->get());
+ d["path"] = fullpath;
//ti->set_metadata(0,d);
item_list->set_item_metadata(item_list->get_item_count() - 1, d);
@@ -723,7 +825,7 @@ void EditorFileDialog::update_file_list() {
fav_down->set_disabled(true);
get_ok()->set_disabled(_is_open_should_be_disabled());
for (int i = 0; i < favorites->get_item_count(); i++) {
- if (favorites->get_item_metadata(i) == base_dir) {
+ if (favorites->get_item_metadata(i) == cdir) {
favorites->select(i);
favorite->set_pressed(true);
if (i > 0) {
@@ -854,27 +956,27 @@ void EditorFileDialog::set_mode(Mode p_mode) {
case MODE_OPEN_FILE:
get_ok()->set_text(TTR("Open"));
set_title(TTR("Open a File"));
- makedir->hide();
+ can_create_dir = false;
break;
case MODE_OPEN_FILES:
get_ok()->set_text(TTR("Open"));
set_title(TTR("Open File(s)"));
- makedir->hide();
+ can_create_dir = false;
break;
case MODE_OPEN_DIR:
get_ok()->set_text(TTR("Open"));
set_title(TTR("Open a Directory"));
- makedir->show();
+ can_create_dir = true;
break;
case MODE_OPEN_ANY:
get_ok()->set_text(TTR("Open"));
set_title(TTR("Open a File or Directory"));
- makedir->show();
+ can_create_dir = true;
break;
case MODE_SAVE_FILE:
get_ok()->set_text(TTR("Save"));
set_title(TTR("Save a File"));
- makedir->show();
+ can_create_dir = true;
break;
}
@@ -883,6 +985,12 @@ void EditorFileDialog::set_mode(Mode p_mode) {
} else {
item_list->set_select_mode(ItemList::SELECT_SINGLE);
}
+
+ if (can_create_dir) {
+ makedir->show();
+ } else {
+ makedir->hide();
+ }
}
EditorFileDialog::Mode EditorFileDialog::get_mode() const {
@@ -954,6 +1062,28 @@ void EditorFileDialog::_make_dir() {
makedirname->grab_focus();
}
+void EditorFileDialog::_delete_items() {
+
+ // Collect the selected folders and files to delete and check them in the deletion dependency dialog.
+ Vector<String> folders;
+ Vector<String> files;
+ for (int i = 0; i < item_list->get_item_count(); i++) {
+ if (!item_list->is_selected(i)) {
+ continue;
+ }
+ Dictionary item_meta = item_list->get_item_metadata(i);
+ if (item_meta["dir"]) {
+ folders.push_back(item_meta["path"]);
+ } else {
+ files.push_back(item_meta["path"]);
+ }
+ }
+ if (folders.size() + files.size() > 0) {
+ remove_dialog->set_size(Size2(1, 1));
+ remove_dialog->show(folders, files);
+ }
+}
+
void EditorFileDialog::_select_drive(int p_idx) {
String d = drives->get_item_text(p_idx);
@@ -1181,6 +1311,9 @@ void EditorFileDialog::_bind_methods() {
ClassDB::bind_method(D_METHOD("_item_selected"), &EditorFileDialog::_item_selected);
ClassDB::bind_method(D_METHOD("_items_clear_selection"), &EditorFileDialog::_items_clear_selection);
+ ClassDB::bind_method(D_METHOD("_item_list_item_rmb_selected"), &EditorFileDialog::_item_list_item_rmb_selected);
+ ClassDB::bind_method(D_METHOD("_item_list_rmb_clicked"), &EditorFileDialog::_item_list_rmb_clicked);
+ ClassDB::bind_method(D_METHOD("_item_menu_id_pressed"), &EditorFileDialog::_item_menu_id_pressed);
ClassDB::bind_method(D_METHOD("_item_db_selected"), &EditorFileDialog::_item_dc_selected);
ClassDB::bind_method(D_METHOD("_dir_entered"), &EditorFileDialog::_dir_entered);
ClassDB::bind_method(D_METHOD("_file_entered"), &EditorFileDialog::_file_entered);
@@ -1232,6 +1365,15 @@ void EditorFileDialog::_bind_methods() {
ADD_SIGNAL(MethodInfo("files_selected", PropertyInfo(Variant::POOL_STRING_ARRAY, "paths")));
ADD_SIGNAL(MethodInfo("dir_selected", PropertyInfo(Variant::STRING, "dir")));
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "access", PROPERTY_HINT_ENUM, "Resources,User data,File system"), "set_access", "get_access");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "display_mode", PROPERTY_HINT_ENUM, "Thumbnails,List"), "set_display_mode", "get_display_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_ENUM, "Open one,Open many,Open folder,Open any,Save"), "set_mode", "get_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "current_dir", PROPERTY_HINT_DIR), "set_current_dir", "get_current_dir");
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "current_file", PROPERTY_HINT_FILE, "*"), "set_current_file", "get_current_file");
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "current_path"), "set_current_path", "get_current_path");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "show_hidden_files"), "set_show_hidden_files", "is_showing_hidden_files");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "disable_overwrite_warning"), "set_disable_overwrite_warning", "is_overwrite_warning_disabled");
+
BIND_ENUM_CONSTANT(MODE_OPEN_FILE);
BIND_ENUM_CONSTANT(MODE_OPEN_FILES);
BIND_ENUM_CONSTANT(MODE_OPEN_DIR);
@@ -1317,6 +1459,7 @@ EditorFileDialog::EditorFileDialog() {
ED_SHORTCUT("file_dialog/toggle_favorite", TTR("Toggle Favorite"), KEY_MASK_ALT | KEY_F);
ED_SHORTCUT("file_dialog/toggle_mode", TTR("Toggle Mode"), KEY_MASK_ALT | KEY_V);
ED_SHORTCUT("file_dialog/create_folder", TTR("Create Folder"), KEY_MASK_CMD | KEY_N);
+ ED_SHORTCUT("file_dialog/delete", TTR("Delete"), KEY_DELETE);
ED_SHORTCUT("file_dialog/focus_path", TTR("Focus Path"), KEY_MASK_CMD | KEY_D);
ED_SHORTCUT("file_dialog/move_favorite_up", TTR("Move Favorite Up"), KEY_MASK_CMD | KEY_UP);
ED_SHORTCUT("file_dialog/move_favorite_down", TTR("Move Favorite Down"), KEY_MASK_CMD | KEY_DOWN);
@@ -1423,10 +1566,21 @@ EditorFileDialog::EditorFileDialog() {
list_vb->add_child(memnew(Label(TTR("Directories & Files:"))));
preview_hb->add_child(list_vb);
+ // Item (files and folders) list with context menu
+
item_list = memnew(ItemList);
item_list->set_v_size_flags(SIZE_EXPAND_FILL);
+ item_list->connect("item_rmb_selected", this, "_item_list_item_rmb_selected");
+ item_list->connect("rmb_clicked", this, "_item_list_rmb_clicked");
+ item_list->set_allow_rmb_select(true);
list_vb->add_child(item_list);
+ item_menu = memnew(PopupMenu);
+ item_menu->connect("id_pressed", this, "_item_menu_id_pressed");
+ add_child(item_menu);
+
+ // Other stuff
+
preview_vb = memnew(VBoxContainer);
preview_hb->add_child(preview_vb);
CenterContainer *prev_cc = memnew(CenterContainer);
@@ -1465,9 +1619,11 @@ EditorFileDialog::EditorFileDialog() {
confirm_save = memnew(ConfirmationDialog);
confirm_save->set_as_toplevel(true);
add_child(confirm_save);
-
confirm_save->connect("confirmed", this, "_save_confirm_pressed");
+ remove_dialog = memnew(DependencyRemoveDialog);
+ add_child(remove_dialog);
+
makedialog = memnew(ConfirmationDialog);
makedialog->set_title(TTR("Create Folder"));
VBoxContainer *makevb = memnew(VBoxContainer);
diff --git a/editor/editor_file_dialog.h b/editor/editor_file_dialog.h
index 0599d222f3..f4a9a174e7 100644
--- a/editor/editor_file_dialog.h
+++ b/editor/editor_file_dialog.h
@@ -39,6 +39,9 @@
#include "scene/gui/split_container.h"
#include "scene/gui/texture_rect.h"
#include "scene/gui/tool_button.h"
+
+class DependencyRemoveDialog;
+
/**
@author Juan Linietsky <reduzio@gmail.com>
*/
@@ -75,6 +78,14 @@ public:
static RegisterFunc unregister_func;
private:
+ enum ItemMenu {
+ ITEM_MENU_COPY_PATH,
+ ITEM_MENU_DELETE,
+ ITEM_MENU_REFRESH,
+ ITEM_MENU_NEW_FOLDER,
+ ITEM_MENU_SHOW_IN_EXPLORER
+ };
+
ConfirmationDialog *makedialog;
LineEdit *makedirname;
@@ -83,6 +94,7 @@ private:
//Button *action;
VBoxContainer *vbox;
Mode mode;
+ bool can_create_dir;
LineEdit *dir;
ToolButton *dir_prev;
@@ -91,6 +103,7 @@ private:
OptionButton *drives;
ItemList *item_list;
+ PopupMenu *item_menu;
TextureRect *preview;
VBoxContainer *preview_vb;
HSplitContainer *list_hb;
@@ -100,6 +113,7 @@ private:
OptionButton *filter;
DirAccess *dir_access;
ConfirmationDialog *confirm_save;
+ DependencyRemoveDialog *remove_dialog;
ToolButton *mode_thumbnails;
ToolButton *mode_list;
@@ -146,6 +160,10 @@ private:
void _items_clear_selection();
void _item_dc_selected(int p_item);
+ void _item_list_item_rmb_selected(int p_item, const Vector2 &p_pos);
+ void _item_list_rmb_clicked(const Vector2 &p_pos);
+ void _item_menu_id_pressed(int p_option);
+
void _select_drive(int p_idx);
void _dir_entered(String p_dir);
void _file_entered(const String &p_file);
@@ -156,6 +174,8 @@ private:
void _make_dir();
void _make_dir_confirm();
+ void _delete_items();
+
void _update_drives();
void _go_up();
diff --git a/editor/editor_file_system.cpp b/editor/editor_file_system.cpp
index 1cc518ff31..d462cce908 100644
--- a/editor/editor_file_system.cpp
+++ b/editor/editor_file_system.cpp
@@ -1244,8 +1244,10 @@ void EditorFileSystem::update_file(const String &p_file) {
if (!FileAccess::exists(p_file)) {
//was removed
_delete_internal_files(p_file);
- memdelete(fs->files[cpos]);
- fs->files.remove(cpos);
+ if (cpos != -1) { // Might've never been part of the editor file system (*.* files deleted in Open dialog).
+ memdelete(fs->files[cpos]);
+ fs->files.remove(cpos);
+ }
call_deferred("emit_signal", "filesystem_changed"); //update later
return;
}
diff --git a/editor/editor_help.cpp b/editor/editor_help.cpp
index 5fc27c2e3c..8f427582ae 100644
--- a/editor/editor_help.cpp
+++ b/editor/editor_help.cpp
@@ -78,50 +78,40 @@ void EditorHelpSearch::_sbox_input(const Ref<InputEvent> &p_ie) {
}
}
-void EditorHelpSearch::_update_search() {
+class EditorHelpSearch::IncrementalSearch : public Reference {
+ String term;
+ TreeItem *root;
- search_options->clear();
- search_options->set_hide_root(true);
+ EditorHelpSearch *search;
+ Tree *search_options;
- /*
- TreeItem *root = search_options->create_item();
- _parse_fs(EditorFileSystem::get_singleton()->get_filesystem());
-*/
+ DocData *doc;
+ Ref<Texture> def_icon;
- List<StringName> type_list;
- ClassDB::get_class_list(&type_list);
+ int phase;
+ Map<String, DocData::ClassDoc>::Element *iterator;
- DocData *doc = EditorHelp::get_doc_data();
- String term = search_box->get_text();
- if (term.length() < 2)
- return;
-
- TreeItem *root = search_options->create_item();
-
- Ref<Texture> def_icon = get_icon("Node", "EditorIcons");
- //classes first
- for (Map<String, DocData::ClassDoc>::Element *E = doc->class_list.front(); E; E = E->next()) {
+ void phase1(Map<String, DocData::ClassDoc>::Element *E) {
if (E->key().findn(term) != -1) {
TreeItem *item = search_options->create_item(root);
item->set_metadata(0, "class_name:" + E->key());
item->set_text(0, E->key() + " (Class)");
- if (has_icon(E->key(), "EditorIcons"))
- item->set_icon(0, get_icon(E->key(), "EditorIcons"));
+ if (search->has_icon(E->key(), "EditorIcons"))
+ item->set_icon(0, search->get_icon(E->key(), "EditorIcons"));
else
item->set_icon(0, def_icon);
}
}
- //class methods, etc second
- for (Map<String, DocData::ClassDoc>::Element *E = doc->class_list.front(); E; E = E->next()) {
+ void phase2(Map<String, DocData::ClassDoc>::Element *E) {
DocData::ClassDoc &c = E->get();
Ref<Texture> cicon;
- if (has_icon(E->key(), "EditorIcons"))
- cicon = get_icon(E->key(), "EditorIcons");
+ if (search->has_icon(E->key(), "EditorIcons"))
+ cicon = search->get_icon(E->key(), "EditorIcons");
else
cicon = def_icon;
@@ -180,72 +170,80 @@ void EditorHelpSearch::_update_search() {
}
}
- //same but descriptions
+ bool slice() {
- for (Map<String, DocData::ClassDoc>::Element *E = doc->class_list.front(); E; E = E->next()) {
+ if (phase > 2)
+ return true;
- DocData::ClassDoc &c = E->get();
+ if (iterator) {
- Ref<Texture> cicon;
- if (has_icon(E->key(), "EditorIcons"))
- cicon = get_icon(E->key(), "EditorIcons");
- else
- cicon = def_icon;
+ switch (phase) {
+
+ case 1: {
+ phase1(iterator);
+ } break;
+ case 2: {
+ phase2(iterator);
+ } break;
+ default: {
+ WARN_PRINT("illegal phase in IncrementalSearch");
+ return true;
+ }
+ }
- if (c.description.findn(term) != -1) {
+ iterator = iterator->next();
+ } else {
- TreeItem *item = search_options->create_item(root);
- item->set_metadata(0, "class_desc:" + E->key());
- item->set_text(0, E->key() + " (Class Description)");
- item->set_icon(0, cicon);
+ phase += 1;
+ iterator = doc->class_list.front();
}
- for (int i = 0; i < c.methods.size(); i++) {
+ return false;
+ }
- if (c.methods[i].description.findn(term) != -1) {
+public:
+ IncrementalSearch(EditorHelpSearch *p_search, Tree *p_search_options, const String &p_term)
+ : search(p_search), search_options(p_search_options) {
- TreeItem *item = search_options->create_item(root);
- item->set_metadata(0, "class_method_desc:" + E->key() + ":" + c.methods[i].name);
- item->set_text(0, E->key() + "." + c.methods[i].name + " (Method Description)");
- item->set_icon(0, cicon);
- }
- }
-
- for (int i = 0; i < c.signals.size(); i++) {
+ def_icon = search->get_icon("Node", "EditorIcons");
+ doc = EditorHelp::get_doc_data();
- if (c.signals[i].description.findn(term) != -1) {
+ term = p_term;
- TreeItem *item = search_options->create_item(root);
- item->set_metadata(0, "class_signal:" + E->key() + ":" + c.signals[i].name);
- item->set_text(0, E->key() + "." + c.signals[i].name + " (Signal Description)");
- item->set_icon(0, cicon);
- }
- }
+ root = search_options->create_item();
+ phase = 0;
+ iterator = 0;
+ }
- for (int i = 0; i < c.constants.size(); i++) {
+ bool empty() const {
- if (c.constants[i].description.findn(term) != -1) {
+ return root->get_children() == NULL;
+ }
- TreeItem *item = search_options->create_item(root);
- item->set_metadata(0, "class_constant:" + E->key() + ":" + c.constants[i].name);
- item->set_text(0, E->key() + "." + c.constants[i].name + " (Constant Description)");
- item->set_icon(0, cicon);
- }
- }
+ bool work(uint64_t slot = 1000000 / 10) {
- for (int i = 0; i < c.properties.size(); i++) {
+ const uint64_t until = OS::get_singleton()->get_ticks_usec() + slot;
- if (c.properties[i].description.findn(term) != -1) {
+ while (!slice()) {
- TreeItem *item = search_options->create_item(root);
- item->set_metadata(0, "class_property_desc:" + E->key() + ":" + c.properties[i].name);
- item->set_text(0, E->key() + "." + c.properties[i].name + " (Property Description)");
- item->set_icon(0, cicon);
- }
+ if (OS::get_singleton()->get_ticks_usec() > until)
+ return false;
}
+
+ return true;
}
+};
- get_ok()->set_disabled(root->get_children() == NULL);
+void EditorHelpSearch::_update_search() {
+ search_options->clear();
+ search_options->set_hide_root(true);
+
+ String term = search_box->get_text();
+ if (term.length() < 2)
+ return;
+
+ search = Ref<IncrementalSearch>(memnew(IncrementalSearch(this, search_options, term)));
+ set_process(true);
}
void EditorHelpSearch::_confirmed() {
@@ -281,6 +279,20 @@ void EditorHelpSearch::_notification(int p_what) {
//_update_icons
search_box->add_icon_override("right_icon", get_icon("Search", "EditorIcons"));
+ } else if (p_what == NOTIFICATION_PROCESS) {
+
+ if (search.is_valid()) {
+
+ if (search->work()) {
+
+ get_ok()->set_disabled(search->empty());
+ search = Ref<IncrementalSearch>();
+ set_process(false);
+ }
+ } else {
+
+ set_process(false);
+ }
}
}
diff --git a/editor/editor_help.h b/editor/editor_help.h
index 92c0e2f4d1..a224c7f8ee 100644
--- a/editor/editor_help.h
+++ b/editor/editor_help.h
@@ -53,6 +53,9 @@ class EditorHelpSearch : public ConfirmationDialog {
Tree *search_options;
String base_type;
+ class IncrementalSearch;
+ Ref<IncrementalSearch> search;
+
void _update_search();
void _sbox_input(const Ref<InputEvent> &p_ie);
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index d6c8d65193..0252358a27 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -269,6 +269,7 @@ void EditorNode::_notification(int p_what) {
Engine::get_singleton()->set_editor_hint(true);
+ get_tree()->get_root()->set_usage(Viewport::USAGE_2D_NO_SAMPLING); //reduce memory usage
get_tree()->get_root()->set_disable_3d(true);
get_tree()->get_root()->set_as_audio_listener(false);
get_tree()->get_root()->set_as_audio_listener_2d(false);
@@ -337,7 +338,13 @@ void EditorNode::_notification(int p_what) {
//_update_icons
for (int i = 0; i < singleton->main_editor_buttons.size(); i++) {
- main_editor_buttons[i]->set_icon(gui_base->get_icon(singleton->main_editor_buttons[i]->get_name(), "EditorIcons"));
+ Ref<Texture> icon = singleton->main_editor_buttons[i]->get_icon();
+
+ if (icon.is_valid()) {
+ main_editor_buttons[i]->set_icon(icon);
+ } else if (singleton->gui_base->has_icon(singleton->main_editor_buttons[i]->get_name(), "EditorIcons")) {
+ main_editor_buttons[i]->set_icon(gui_base->get_icon(singleton->main_editor_buttons[i]->get_name(), "EditorIcons"));
+ }
}
play_button->set_icon(gui_base->get_icon("MainPlay", "EditorIcons"));
play_scene_button->set_icon(gui_base->get_icon("PlayScene", "EditorIcons"));
@@ -1394,11 +1401,13 @@ void EditorNode::_property_editor_back() {
}
void EditorNode::_menu_collapseall() {
- property_editor->collapse_all_parent_nodes();
+
+ property_editor->collapse_all_folding();
}
void EditorNode::_menu_expandall() {
- property_editor->expand_all_parent_nodes();
+
+ property_editor->expand_all_folding();
}
void EditorNode::_save_default_environment() {
@@ -2670,7 +2679,14 @@ void EditorNode::add_editor_plugin(EditorPlugin *p_editor) {
tb->set_toggle_mode(true);
tb->connect("pressed", singleton, "_editor_select", varray(singleton->main_editor_buttons.size()));
tb->set_text(p_editor->get_name());
- tb->set_icon(singleton->gui_base->get_icon(p_editor->get_name(), "EditorIcons"));
+ Ref<Texture> icon = p_editor->get_icon();
+
+ if (icon.is_valid()) {
+ tb->set_icon(icon);
+ } else if (singleton->gui_base->has_icon(p_editor->get_name(), "EditorIcons")) {
+ tb->set_icon(singleton->gui_base->get_icon(p_editor->get_name(), "EditorIcons"));
+ }
+
tb->set_name(p_editor->get_name());
singleton->main_editor_buttons.push_back(tb);
singleton->main_editor_button_vb->add_child(tb);
@@ -3348,6 +3364,8 @@ void EditorNode::register_editor_types() {
ClassDB::register_virtual_class<EditorInterface>();
ClassDB::register_class<EditorExportPlugin>();
ClassDB::register_class<EditorResourceConversionPlugin>();
+ ClassDB::register_class<EditorSceneImporter>();
+
// FIXME: Is this stuff obsolete, or should it be ported to new APIs?
ClassDB::register_class<EditorScenePostImport>();
@@ -5019,6 +5037,7 @@ EditorNode::EditorNode() {
scene_root_parent->set_v_size_flags(Control::SIZE_EXPAND_FILL);
scene_root = memnew(Viewport);
+ scene_root->set_usage(Viewport::USAGE_2D);
scene_root->set_disable_3d(true);
VisualServer::get_singleton()->viewport_set_hide_scenario(scene_root->get_viewport_rid(), true);
@@ -5444,7 +5463,7 @@ EditorNode::EditorNode() {
property_editor->set_use_doc_hints(true);
property_editor->set_hide_script(false);
property_editor->set_enable_capitalize_paths(bool(EDITOR_DEF("interface/editor/capitalize_properties", true)));
- property_editor->set_use_folding(bool(EDITOR_DEF("interface/editor/expand_all_properties", false)) == false);
+ property_editor->set_use_folding(!bool(EDITOR_DEF("interface/editor/disable_inspector_folding", false)));
property_editor->hide_top_label();
property_editor->register_text_enter(search_box);
diff --git a/editor/editor_plugin.cpp b/editor/editor_plugin.cpp
index c1fbcde6ac..5c4c2b694f 100644
--- a/editor/editor_plugin.cpp
+++ b/editor/editor_plugin.cpp
@@ -466,6 +466,14 @@ String EditorPlugin::get_name() const {
return String();
}
+const Ref<Texture> EditorPlugin::get_icon() const {
+
+ if (get_script_instance() && get_script_instance()->has_method("get_plugin_icon")) {
+ return get_script_instance()->call("get_plugin_icon");
+ }
+
+ return Ref<Texture>();
+}
bool EditorPlugin::has_main_screen() const {
if (get_script_instance() && get_script_instance()->has_method("has_main_screen")) {
@@ -557,12 +565,12 @@ void EditorPlugin::save_global_state() {}
void EditorPlugin::add_import_plugin(const Ref<EditorImportPlugin> &p_importer) {
ResourceFormatImporter::get_singleton()->add_importer(p_importer);
- EditorFileSystem::get_singleton()->scan();
+ EditorFileSystem::get_singleton()->call_deferred("scan");
}
void EditorPlugin::remove_import_plugin(const Ref<EditorImportPlugin> &p_importer) {
ResourceFormatImporter::get_singleton()->remove_importer(p_importer);
- EditorFileSystem::get_singleton()->scan();
+ EditorFileSystem::get_singleton()->call_deferred("scan");
}
void EditorPlugin::add_export_plugin(const Ref<EditorExportPlugin> &p_exporter) {
@@ -573,6 +581,14 @@ void EditorPlugin::remove_export_plugin(const Ref<EditorExportPlugin> &p_exporte
EditorExport::get_singleton()->remove_export_plugin(p_exporter);
}
+void EditorPlugin::add_scene_import_plugin(const Ref<EditorSceneImporter> &p_importer) {
+ ResourceImporterScene::get_singleton()->add_importer(p_importer);
+}
+
+void EditorPlugin::remove_scene_import_plugin(const Ref<EditorSceneImporter> &p_importer) {
+ ResourceImporterScene::get_singleton()->remove_importer(p_importer);
+}
+
void EditorPlugin::set_window_layout(Ref<ConfigFile> p_layout) {
if (get_script_instance() && get_script_instance()->has_method("set_window_layout")) {
@@ -628,6 +644,8 @@ void EditorPlugin::_bind_methods() {
ClassDB::bind_method(D_METHOD("queue_save_layout"), &EditorPlugin::queue_save_layout);
ClassDB::bind_method(D_METHOD("add_import_plugin", "importer"), &EditorPlugin::add_import_plugin);
ClassDB::bind_method(D_METHOD("remove_import_plugin", "importer"), &EditorPlugin::remove_import_plugin);
+ ClassDB::bind_method(D_METHOD("add_scene_import_plugin", "scene_importer"), &EditorPlugin::add_scene_import_plugin);
+ ClassDB::bind_method(D_METHOD("remove_scene_import_plugin", "scene_importer"), &EditorPlugin::remove_scene_import_plugin);
ClassDB::bind_method(D_METHOD("add_export_plugin", "exporter"), &EditorPlugin::add_export_plugin);
ClassDB::bind_method(D_METHOD("remove_export_plugin", "exporter"), &EditorPlugin::remove_export_plugin);
ClassDB::bind_method(D_METHOD("set_input_event_forwarding_always_enabled"), &EditorPlugin::set_input_event_forwarding_always_enabled);
@@ -644,6 +662,7 @@ void EditorPlugin::_bind_methods() {
gizmo.return_val.hint_string = "EditorSpatialGizmo";
ClassDB::add_virtual_method(get_class_static(), gizmo);
ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::STRING, "get_plugin_name"));
+ ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::OBJECT, "get_plugin_icon"));
ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::BOOL, "has_main_screen"));
ClassDB::add_virtual_method(get_class_static(), MethodInfo("make_visible", PropertyInfo(Variant::BOOL, "visible")));
ClassDB::add_virtual_method(get_class_static(), MethodInfo("edit", PropertyInfo(Variant::OBJECT, "object")));
diff --git a/editor/editor_plugin.h b/editor/editor_plugin.h
index 11f4378667..89a6d3d250 100644
--- a/editor/editor_plugin.h
+++ b/editor/editor_plugin.h
@@ -35,6 +35,7 @@
#include "scene/gui/tool_button.h"
#include "scene/main/node.h"
#include "scene/resources/texture.h"
+#include "editor/import/resource_importer_scene.h"
#include "undo_redo.h"
/**
@@ -165,6 +166,7 @@ public:
virtual void forward_force_draw_over_viewport(Control *p_overlay);
virtual bool forward_spatial_gui_input(Camera *p_camera, const Ref<InputEvent> &p_event);
virtual String get_name() const;
+ virtual const Ref<Texture> get_icon() const;
virtual bool has_main_screen() const;
virtual void make_visible(bool p_visible);
virtual void selected_notify() {} //notify that it was raised by the user, not the editor
@@ -199,6 +201,9 @@ public:
void add_export_plugin(const Ref<EditorExportPlugin> &p_exporter);
void remove_export_plugin(const Ref<EditorExportPlugin> &p_exporter);
+ void add_scene_import_plugin(const Ref<EditorSceneImporter> &p_importer);
+ void remove_scene_import_plugin(const Ref<EditorSceneImporter> &p_importer);
+
EditorPlugin();
virtual ~EditorPlugin();
};
diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp
index 2f73e459ed..d199b27b83 100644
--- a/editor/editor_settings.cpp
+++ b/editor/editor_settings.cpp
@@ -348,7 +348,7 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
_initial_set("text_editor/files/autosave_interval_secs", 0);
_initial_set("text_editor/cursor/block_caret", false);
- _initial_set("text_editor/cursor/caret_blink", false);
+ _initial_set("text_editor/cursor/caret_blink", true);
_initial_set("text_editor/cursor/caret_blink_speed", 0.65);
hints["text_editor/cursor/caret_blink_speed"] = PropertyInfo(Variant::REAL, "text_editor/cursor/caret_blink_speed", PROPERTY_HINT_RANGE, "0.1, 10, 0.1");
@@ -543,6 +543,7 @@ void EditorSettings::_load_default_text_editor_theme() {
_initial_set("text_editor/highlighting/line_length_guideline_color", Color(0.3, 0.5, 0.8, 0.1));
_initial_set("text_editor/highlighting/mark_color", Color(1.0, 0.4, 0.4, 0.4));
_initial_set("text_editor/highlighting/breakpoint_color", Color(0.8, 0.8, 0.4, 0.2));
+ _initial_set("text_editor/highlighting/code_folding_color", Color(0.8, 0.8, 0.8, 0.8));
_initial_set("text_editor/highlighting/word_highlighted_color", Color(0.8, 0.9, 0.9, 0.15));
_initial_set("text_editor/highlighting/search_result_color", Color(0.05, 0.25, 0.05, 1));
_initial_set("text_editor/highlighting/search_result_border_color", Color(0.1, 0.45, 0.1, 1));
@@ -577,6 +578,7 @@ bool EditorSettings::_save_text_editor_theme(String p_file) {
cf->set_value(theme_section, "line_length_guideline_color", ((Color)get("text_editor/highlighting/line_length_guideline_color")).to_html());
cf->set_value(theme_section, "mark_color", ((Color)get("text_editor/highlighting/mark_color")).to_html());
cf->set_value(theme_section, "breakpoint_color", ((Color)get("text_editor/highlighting/breakpoint_color")).to_html());
+ cf->set_value(theme_section, "code_folding_color", ((Color)get("text_editor/highlighting/code_folding_color")).to_html());
cf->set_value(theme_section, "word_highlighted_color", ((Color)get("text_editor/highlighting/word_highlighted_color")).to_html());
cf->set_value(theme_section, "search_result_color", ((Color)get("text_editor/highlighting/search_result_color")).to_html());
cf->set_value(theme_section, "search_result_border_color", ((Color)get("text_editor/highlighting/search_result_border_color")).to_html());
diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp
index ae29b7420e..4661fcf668 100644
--- a/editor/editor_themes.cpp
+++ b/editor/editor_themes.cpp
@@ -793,6 +793,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
// TextEdit
theme->set_stylebox("normal", "TextEdit", style_widget);
theme->set_stylebox("focus", "TextEdit", style_widget_hover);
+ theme->set_stylebox("read_only", "TextEdit", style_widget_disabled);
theme->set_constant("side_margin", "TabContainer", 0);
theme->set_icon("tab", "TextEdit", theme->get_icon("GuiTab", "EditorIcons"));
theme->set_color("font_color", "TextEdit", font_color);
@@ -1038,6 +1039,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
const Color member_variable_color = mono_color;
const Color mark_color = Color(error_color.r, error_color.g, error_color.b, 0.3);
const Color breakpoint_color = error_color;
+ const Color code_folding_color = alpha4;
const Color search_result_color = alpha1;
const Color search_result_border_color = alpha4;
@@ -1068,6 +1070,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_color("text_editor/theme/member_variable_color", "Editor", member_variable_color);
theme->set_color("text_editor/theme/mark_color", "Editor", mark_color);
theme->set_color("text_editor/theme/breakpoint_color", "Editor", breakpoint_color);
+ theme->set_color("text_editor/theme/code_folding_color", "Editor", code_folding_color);
theme->set_color("text_editor/theme/search_result_color", "Editor", search_result_color);
theme->set_color("text_editor/theme/search_result_border_color", "Editor", search_result_border_color);
diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp
index 9fe3e2ad25..9ece36ea80 100644
--- a/editor/filesystem_dock.cpp
+++ b/editor/filesystem_dock.cpp
@@ -806,6 +806,39 @@ void FileSystemDock::_try_move_item(const FileOrFolder &p_item, const String &p_
memdelete(da);
}
+void FileSystemDock::_try_duplicate_item(const FileOrFolder &p_item, const String &p_new_path) const {
+ //Ensure folder paths end with "/"
+ String old_path = (p_item.is_file || p_item.path.ends_with("/")) ? p_item.path : (p_item.path + "/");
+ String new_path = (p_item.is_file || p_new_path.ends_with("/")) ? p_new_path : (p_new_path + "/");
+
+ if (new_path == old_path) {
+ return;
+ } else if (old_path == "res://") {
+ EditorNode::get_singleton()->add_io_error(TTR("Cannot move/rename resources root."));
+ return;
+ } else if (!p_item.is_file && new_path.begins_with(old_path)) {
+ //This check doesn't erroneously catch renaming to a longer name as folder paths always end with "/"
+ EditorNode::get_singleton()->add_io_error(TTR("Cannot move a folder into itself.\n") + old_path + "\n");
+ return;
+ }
+
+ DirAccess *da = DirAccess::create(DirAccess::ACCESS_RESOURCES);
+ print_line("Duplicating " + old_path + " -> " + new_path);
+ Error err = da->copy(old_path, new_path);
+ if (err == OK) {
+ //Move/Rename any corresponding import settings too
+ if (p_item.is_file && FileAccess::exists(old_path + ".import")) {
+ err = da->copy(old_path + ".import", new_path + ".import");
+ if (err != OK) {
+ EditorNode::get_singleton()->add_io_error(TTR("Error duplicating:\n") + old_path + ".import\n");
+ }
+ }
+ } else {
+ EditorNode::get_singleton()->add_io_error(TTR("Error duplicating:\n") + old_path + "\n");
+ }
+ memdelete(da);
+}
+
void FileSystemDock::_update_dependencies_after_move(const Map<String, String> &p_renames) const {
//The following code assumes that the following holds:
// 1) EditorFileSystem contains the old paths/folder structure from before the rename/move.
@@ -888,6 +921,39 @@ void FileSystemDock::_rename_operation_confirm() {
_rescan();
}
+void FileSystemDock::_duplicate_operation_confirm() {
+
+ String new_name = duplicate_dialog_text->get_text().strip_edges();
+ if (new_name.length() == 0) {
+ EditorNode::get_singleton()->show_warning(TTR("No name provided."));
+ return;
+ } else if (new_name.find("/") != -1 || new_name.find("\\") != -1 || new_name.find(":") != -1) {
+ EditorNode::get_singleton()->show_warning(TTR("Name contains invalid characters."));
+ return;
+ }
+
+ String old_path = to_duplicate.path.ends_with("/") ? to_duplicate.path.substr(0, to_duplicate.path.length() - 1) : to_rename.path;
+ String new_path = old_path.get_base_dir().plus_file(new_name);
+ if (old_path == new_path) {
+ return;
+ }
+
+ //Present a more user friendly warning for name conflict
+ DirAccess *da = DirAccess::create(DirAccess::ACCESS_RESOURCES);
+ if (da->file_exists(new_path) || da->dir_exists(new_path)) {
+ EditorNode::get_singleton()->show_warning(TTR("A file or folder with this name already exists."));
+ memdelete(da);
+ return;
+ }
+ memdelete(da);
+
+ _try_duplicate_item(to_duplicate, new_name);
+
+ //Rescan everything
+ print_line("call rescan!");
+ _rescan();
+}
+
void FileSystemDock::_move_operation_confirm(const String &p_to_path) {
Map<String, String> renames;
@@ -909,10 +975,11 @@ void FileSystemDock::_file_option(int p_option) {
OS::get_singleton()->shell_open(String("file://") + dir);
} break;
case FILE_OPEN: {
- int idx = files->get_current();
- if (idx < 0 || idx >= files->get_item_count())
- break;
- _select_file(idx);
+ for (int i = 0; i < files->get_item_count(); i++) {
+ if (files->is_selected(i)) {
+ _select_file(i);
+ }
+ }
} break;
case FILE_INSTANCE: {
@@ -1002,6 +1069,27 @@ void FileSystemDock::_file_option(int p_option) {
//2) warn
}
} break;
+ case FILE_DUPLICATE: {
+ int idx = files->get_current();
+ if (idx < 0 || idx >= files->get_item_count())
+ break;
+
+ to_duplicate.path = files->get_item_metadata(idx);
+ to_duplicate.is_file = !to_duplicate.path.ends_with("/");
+ if (to_duplicate.is_file) {
+ String name = to_duplicate.path.get_file();
+ duplicate_dialog->set_title(TTR("Duplicating file:") + " " + name);
+ duplicate_dialog_text->set_text(name);
+ duplicate_dialog_text->select(0, name.find_last("."));
+ } else {
+ String name = to_duplicate.path.substr(0, to_duplicate.path.length() - 1).get_file();
+ duplicate_dialog->set_title(TTR("Duplicating folder:") + " " + name);
+ duplicate_dialog_text->set_text(name);
+ duplicate_dialog_text->select(0, name.length());
+ }
+ duplicate_dialog->popup_centered_minsize(Size2(250, 80) * EDSCALE);
+ duplicate_dialog_text->grab_focus();
+ } break;
case FILE_INFO: {
} break;
@@ -1429,18 +1517,25 @@ void FileSystemDock::_files_list_rmb_select(int p_item, const Vector2 &p_pos) {
file_options->clear();
file_options->set_size(Size2(1, 1));
- if (all_files && filenames.size() > 0) {
- file_options->add_item(TTR("Open"), FILE_OPEN);
- if (all_files_scenes) {
+ if (all_files) {
+
+ if (all_files_scenes && filenames.size() >= 1) {
+ file_options->add_item(TTR("Open Scene(s)"), FILE_OPEN);
file_options->add_item(TTR("Instance"), FILE_INSTANCE);
+ file_options->add_separator();
+ }
+
+ if (!all_files_scenes && filenames.size() == 1) {
+ file_options->add_item(TTR("Open"), FILE_OPEN);
+ file_options->add_separator();
}
- file_options->add_separator();
if (filenames.size() == 1) {
file_options->add_item(TTR("Edit Dependencies.."), FILE_DEPENDENCIES);
file_options->add_item(TTR("View Owners.."), FILE_OWNERS);
file_options->add_separator();
}
+
} else if (all_folders && foldernames.size() > 0) {
file_options->add_item(TTR("Open"), FILE_OPEN);
file_options->add_separator();
@@ -1451,6 +1546,7 @@ void FileSystemDock::_files_list_rmb_select(int p_item, const Vector2 &p_pos) {
if (num_items == 1) {
file_options->add_item(TTR("Copy Path"), FILE_COPY_PATH);
file_options->add_item(TTR("Rename.."), FILE_RENAME);
+ file_options->add_item(TTR("Duplicate.."), FILE_DUPLICATE);
}
file_options->add_item(TTR("Move To.."), FILE_MOVE);
file_options->add_item(TTR("Delete"), FILE_REMOVE);
@@ -1562,6 +1658,7 @@ void FileSystemDock::_bind_methods() {
ClassDB::bind_method(D_METHOD("_make_dir_confirm"), &FileSystemDock::_make_dir_confirm);
ClassDB::bind_method(D_METHOD("_move_operation_confirm"), &FileSystemDock::_move_operation_confirm);
ClassDB::bind_method(D_METHOD("_rename_operation_confirm"), &FileSystemDock::_rename_operation_confirm);
+ ClassDB::bind_method(D_METHOD("_duplicate_operation_confirm"), &FileSystemDock::_duplicate_operation_confirm);
ClassDB::bind_method(D_METHOD("_search_changed"), &FileSystemDock::_search_changed);
@@ -1735,6 +1832,17 @@ FileSystemDock::FileSystemDock(EditorNode *p_editor) {
rename_dialog->register_text_enter(rename_dialog_text);
rename_dialog->connect("confirmed", this, "_rename_operation_confirm");
+ duplicate_dialog = memnew(ConfirmationDialog);
+ VBoxContainer *duplicate_dialog_vb = memnew(VBoxContainer);
+ duplicate_dialog->add_child(duplicate_dialog_vb);
+
+ duplicate_dialog_text = memnew(LineEdit);
+ duplicate_dialog_vb->add_margin_child(TTR("Name:"), duplicate_dialog_text);
+ duplicate_dialog->get_ok()->set_text(TTR("Duplicate"));
+ add_child(duplicate_dialog);
+ duplicate_dialog->register_text_enter(duplicate_dialog_text);
+ duplicate_dialog->connect("confirmed", this, "_duplicate_operation_confirm");
+
make_dir_dialog = memnew(ConfirmationDialog);
make_dir_dialog->set_title(TTR("Create Folder"));
VBoxContainer *make_folder_dialog_vb = memnew(VBoxContainer);
diff --git a/editor/filesystem_dock.h b/editor/filesystem_dock.h
index f1fd342052..bc8d835ba1 100644
--- a/editor/filesystem_dock.h
+++ b/editor/filesystem_dock.h
@@ -70,6 +70,7 @@ private:
FILE_MOVE,
FILE_RENAME,
FILE_REMOVE,
+ FILE_DUPLICATE,
FILE_REIMPORT,
FILE_INFO,
FILE_NEW_FOLDER,
@@ -120,6 +121,8 @@ private:
EditorDirDialog *move_dialog;
ConfirmationDialog *rename_dialog;
LineEdit *rename_dialog_text;
+ ConfirmationDialog *duplicate_dialog;
+ LineEdit *duplicate_dialog_text;
ConfirmationDialog *make_dir_dialog;
LineEdit *make_dir_dialog_text;
@@ -128,12 +131,15 @@ private:
String path;
bool is_file;
- FileOrFolder()
- : path(""), is_file(false) {}
- FileOrFolder(const String &p_path, bool p_is_file)
- : path(p_path), is_file(p_is_file) {}
+ FileOrFolder() :
+ path(""),
+ is_file(false) {}
+ FileOrFolder(const String &p_path, bool p_is_file) :
+ path(p_path),
+ is_file(p_is_file) {}
};
FileOrFolder to_rename;
+ FileOrFolder to_duplicate;
Vector<FileOrFolder> to_move;
Vector<String> history;
@@ -170,10 +176,12 @@ private:
void _get_all_files_in_dir(EditorFileSystemDirectory *efsd, Vector<String> &files) const;
void _find_remaps(EditorFileSystemDirectory *efsd, const Map<String, String> &renames, Vector<String> &to_remaps) const;
void _try_move_item(const FileOrFolder &p_item, const String &p_new_path, Map<String, String> &p_renames) const;
+ void _try_duplicate_item(const FileOrFolder &p_item, const String &p_new_path) const;
void _update_dependencies_after_move(const Map<String, String> &p_renames) const;
void _make_dir_confirm();
void _rename_operation_confirm();
+ void _duplicate_operation_confirm();
void _move_operation_confirm(const String &p_to_path);
void _file_option(int p_option);
diff --git a/editor/import/editor_import_collada.cpp b/editor/import/editor_import_collada.cpp
index 3c73411dee..c38391c71b 100644
--- a/editor/import/editor_import_collada.cpp
+++ b/editor/import/editor_import_collada.cpp
@@ -1913,8 +1913,6 @@ void ColladaImport::create_animation(int p_clip, bool p_make_tracks_in_all_bones
/*************************************** SCENE ***********************************/
/*********************************************************************************/
-#define DEBUG_ANIMATION
-
uint32_t EditorSceneImporterCollada::get_import_flags() const {
return IMPORT_SCENE | IMPORT_ANIMATION;
@@ -1981,7 +1979,7 @@ Node *EditorSceneImporterCollada::import_scene(const String &p_path, uint32_t p_
return state.scene;
}
-Ref<Animation> EditorSceneImporterCollada::import_animation(const String &p_path, uint32_t p_flags) {
+Ref<Animation> EditorSceneImporterCollada::import_animation(const String &p_path, uint32_t p_flags,int p_bake_fps) {
ColladaImport state;
diff --git a/editor/import/editor_import_collada.h b/editor/import/editor_import_collada.h
index 865a72739f..986b5b766f 100644
--- a/editor/import/editor_import_collada.h
+++ b/editor/import/editor_import_collada.h
@@ -40,7 +40,7 @@ public:
virtual uint32_t get_import_flags() const;
virtual void get_extensions(List<String> *r_extensions) const;
virtual Node *import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps, List<String> *r_missing_deps = NULL, Error *r_err = NULL);
- virtual Ref<Animation> import_animation(const String &p_path, uint32_t p_flags);
+ virtual Ref<Animation> import_animation(const String &p_path, uint32_t p_flags,int p_bake_fps);
EditorSceneImporterCollada();
};
diff --git a/editor/import/editor_scene_importer_gltf.cpp b/editor/import/editor_scene_importer_gltf.cpp
index f704d97373..e801f3e7c3 100644
--- a/editor/import/editor_scene_importer_gltf.cpp
+++ b/editor/import/editor_scene_importer_gltf.cpp
@@ -2106,7 +2106,7 @@ Node *EditorSceneImporterGLTF::import_scene(const String &p_path, uint32_t p_fla
return scene;
}
-Ref<Animation> EditorSceneImporterGLTF::import_animation(const String &p_path, uint32_t p_flags) {
+Ref<Animation> EditorSceneImporterGLTF::import_animation(const String &p_path, uint32_t p_flags, int p_bake_fps) {
return Ref<Animation>();
}
diff --git a/editor/import/editor_scene_importer_gltf.h b/editor/import/editor_scene_importer_gltf.h
index d9479fae6f..0c8000427e 100644
--- a/editor/import/editor_scene_importer_gltf.h
+++ b/editor/import/editor_scene_importer_gltf.h
@@ -296,7 +296,7 @@ public:
virtual uint32_t get_import_flags() const;
virtual void get_extensions(List<String> *r_extensions) const;
virtual Node *import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps, List<String> *r_missing_deps = NULL, Error *r_err = NULL);
- virtual Ref<Animation> import_animation(const String &p_path, uint32_t p_flags);
+ virtual Ref<Animation> import_animation(const String &p_path, uint32_t p_flags,int p_bake_fps);
EditorSceneImporterGLTF();
};
diff --git a/editor/import/resource_importer_obj.cpp b/editor/import/resource_importer_obj.cpp
index 14bda9bb4e..0297a6c24e 100644
--- a/editor/import/resource_importer_obj.cpp
+++ b/editor/import/resource_importer_obj.cpp
@@ -426,7 +426,7 @@ Node *EditorOBJImporter::import_scene(const String &p_path, uint32_t p_flags, in
return scene;
}
-Ref<Animation> EditorOBJImporter::import_animation(const String &p_path, uint32_t p_flags) {
+Ref<Animation> EditorOBJImporter::import_animation(const String &p_path, uint32_t p_flags, int p_bake_fps) {
return Ref<Animation>();
}
diff --git a/editor/import/resource_importer_obj.h b/editor/import/resource_importer_obj.h
index 7eeceeabbe..09dc8ac8a1 100644
--- a/editor/import/resource_importer_obj.h
+++ b/editor/import/resource_importer_obj.h
@@ -40,7 +40,7 @@ public:
virtual uint32_t get_import_flags() const;
virtual void get_extensions(List<String> *r_extensions) const;
virtual Node *import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps, List<String> *r_missing_deps, Error *r_err = NULL);
- virtual Ref<Animation> import_animation(const String &p_path, uint32_t p_flags);
+ virtual Ref<Animation> import_animation(const String &p_path, uint32_t p_flags,int p_bake_fps);
EditorOBJImporter();
};
diff --git a/editor/import/resource_importer_scene.cpp b/editor/import/resource_importer_scene.cpp
index 95445693b4..08d2897250 100644
--- a/editor/import/resource_importer_scene.cpp
+++ b/editor/import/resource_importer_scene.cpp
@@ -47,6 +47,85 @@
#include "scene/resources/ray_shape.h"
#include "scene/resources/sphere_shape.h"
+uint32_t EditorSceneImporter::get_import_flags() const {
+
+ if (get_script_instance()) {
+ return get_script_instance()->call("_get_import_flags");
+ }
+
+ ERR_FAIL_V(0);
+}
+void EditorSceneImporter::get_extensions(List<String> *r_extensions) const {
+
+ if (get_script_instance()) {
+ Array arr = get_script_instance()->call("_get_extensions");
+ for (int i = 0; i < arr.size(); i++) {
+ r_extensions->push_back(arr[i]);
+ }
+ return;
+ }
+
+ ERR_FAIL();
+}
+Node *EditorSceneImporter::import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps, List<String> *r_missing_deps, Error *r_err) {
+
+ if (get_script_instance()) {
+ return get_script_instance()->call("_import_scene", p_path, p_flags, p_bake_fps);
+ }
+
+ ERR_FAIL_V(NULL);
+}
+
+Ref<Animation> EditorSceneImporter::import_animation(const String &p_path, uint32_t p_flags, int p_bake_fps) {
+
+ if (get_script_instance()) {
+ return get_script_instance()->call("_import_animation", p_path, p_flags);
+ }
+
+ ERR_FAIL_V(NULL);
+}
+
+//for documenters, these functions are useful when an importer calls an external conversion helper (like, fbx2gltf),
+//and you want to load the resulting file
+
+Node *EditorSceneImporter::import_scene_from_other_importer(const String &p_path, uint32_t p_flags, int p_bake_fps) {
+
+ return ResourceImporterScene::get_singleton()->import_scene_from_other_importer(this, p_path, p_flags, p_bake_fps);
+}
+
+Ref<Animation> EditorSceneImporter::import_animation_from_other_importer(const String &p_path, uint32_t p_flags, int p_bake_fps) {
+
+ return ResourceImporterScene::get_singleton()->import_animation_from_other_importer(this, p_path, p_flags, p_bake_fps);
+}
+
+void EditorSceneImporter::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("import_scene_from_other_importer", "path", "flags", "bake_fps"), &EditorSceneImporter::import_scene_from_other_importer);
+ ClassDB::bind_method(D_METHOD("import_animation_from_other_importer", "path", "flags", "bake_fps"), &EditorSceneImporter::import_animation_from_other_importer);
+
+ BIND_VMETHOD(MethodInfo(Variant::INT, "_get_import_flags"));
+ BIND_VMETHOD(MethodInfo(Variant::ARRAY, "_get_extensions"));
+
+ MethodInfo mi = MethodInfo(Variant::OBJECT, "_import_scene", PropertyInfo(Variant::STRING, "path"), PropertyInfo(Variant::INT, "flags"), PropertyInfo(Variant::INT, "bake_fps"));
+ mi.return_val.class_name = "Node";
+ BIND_VMETHOD(mi);
+ mi = MethodInfo(Variant::OBJECT, "_import_animation", PropertyInfo(Variant::STRING, "path"), PropertyInfo(Variant::INT, "flags"), PropertyInfo(Variant::INT, "bake_fps"));
+ mi.return_val.class_name = "Animation";
+ BIND_VMETHOD(mi);
+
+ BIND_CONSTANT(IMPORT_SCENE);
+ BIND_CONSTANT(IMPORT_ANIMATION);
+ BIND_CONSTANT(IMPORT_ANIMATION_DETECT_LOOP);
+ BIND_CONSTANT(IMPORT_ANIMATION_OPTIMIZE);
+ BIND_CONSTANT(IMPORT_ANIMATION_FORCE_ALL_TRACKS_IN_ALL_CLIPS);
+ BIND_CONSTANT(IMPORT_ANIMATION_KEEP_VALUE_TRACKS);
+ BIND_CONSTANT(IMPORT_GENERATE_TANGENT_ARRAYS);
+ BIND_CONSTANT(IMPORT_FAIL_ON_MISSING_DEPENDENCIES);
+ BIND_CONSTANT(IMPORT_MATERIALS_IN_INSTANCES);
+ BIND_CONSTANT(IMPORT_USE_COMPRESSION);
+}
+
+/////////////////////////////////
void EditorScenePostImport::_bind_methods() {
BIND_VMETHOD(MethodInfo("post_import", PropertyInfo(Variant::OBJECT, "scene")));
@@ -95,6 +174,9 @@ bool ResourceImporterScene::get_option_visibility(const String &p_option, const
if (p_option != "animation/import" && !bool(p_options["animation/import"]))
return false;
+ if (p_option == "animation/keep_custom_tracks" && int(p_options["animation/storage"]) == 0)
+ return false;
+
if (p_option.begins_with("animation/optimizer/") && p_option != "animation/optimizer/enabled" && !bool(p_options["animation/optimizer/enabled"]))
return false;
@@ -110,6 +192,10 @@ bool ResourceImporterScene::get_option_visibility(const String &p_option, const
return false;
}
+ if (p_option == "meshes/lightmap_texel_size" && int(p_options["meshes/light_baking"]) < 2) {
+ return false;
+ }
+
return true;
}
@@ -870,7 +956,37 @@ static String _make_extname(const String &p_str) {
return ext_name;
}
-void ResourceImporterScene::_make_external_resources(Node *p_node, const String &p_base_path, bool p_make_animations, bool p_make_materials, bool p_keep_materials, bool p_make_meshes, Map<Ref<Animation>, Ref<Animation> > &p_animations, Map<Ref<Material>, Ref<Material> > &p_materials, Map<Ref<ArrayMesh>, Ref<ArrayMesh> > &p_meshes) {
+void ResourceImporterScene::_find_meshes(Node *p_node, Map<Ref<ArrayMesh>, Transform> &meshes) {
+
+ List<PropertyInfo> pi;
+ p_node->get_property_list(&pi);
+
+ MeshInstance *mi = Object::cast_to<MeshInstance>(p_node);
+
+ if (mi) {
+
+ Ref<ArrayMesh> mesh = mi->get_mesh();
+
+ if (mesh.is_valid() && !meshes.has(mesh)) {
+ Spatial *s = mi;
+ while (s->get_parent_spatial()) {
+ s = s->get_parent_spatial();
+ }
+
+ if (s == mi) {
+ meshes[mesh] = s->get_transform();
+ } else {
+ meshes[mesh] = s->get_transform() * mi->get_relative_transform(s);
+ }
+ }
+ }
+ for (int i = 0; i < p_node->get_child_count(); i++) {
+
+ _find_meshes(p_node->get_child(i), meshes);
+ }
+}
+
+void ResourceImporterScene::_make_external_resources(Node *p_node, const String &p_base_path, bool p_make_animations, bool p_keep_animations, bool p_make_materials, bool p_keep_materials, bool p_make_meshes, Map<Ref<Animation>, Ref<Animation> > &p_animations, Map<Ref<Material>, Ref<Material> > &p_materials, Map<Ref<ArrayMesh>, Ref<ArrayMesh> > &p_meshes) {
List<PropertyInfo> pi;
@@ -889,7 +1005,26 @@ void ResourceImporterScene::_make_external_resources(Node *p_node, const String
if (!p_animations.has(anim)) {
+ //mark what comes from the file first, this helps eventually keep user data
+ for (int i = 0; i < anim->get_track_count(); i++) {
+ anim->track_set_imported(i, true);
+ }
+
String ext_name = p_base_path.plus_file(_make_extname(E->get()) + ".anim");
+
+ if (FileAccess::exists(ext_name) && p_keep_animations) {
+ //try to keep custom animation tracks
+ Ref<Animation> old_anim = ResourceLoader::load(ext_name, "Animation", true);
+ if (old_anim.is_valid()) {
+ //meergeee
+ for (int i = 0; i < old_anim->get_track_count(); i++) {
+ if (!old_anim->track_is_imported(i)) {
+ old_anim->copy_track(i, anim);
+ }
+ }
+ }
+ }
+
ResourceSaver::save(ext_name, anim, ResourceSaver::FLAG_CHANGE_PATH);
p_animations[anim] = anim;
}
@@ -997,7 +1132,7 @@ void ResourceImporterScene::_make_external_resources(Node *p_node, const String
for (int i = 0; i < p_node->get_child_count(); i++) {
- _make_external_resources(p_node->get_child(i), p_base_path, p_make_animations, p_make_materials, p_keep_materials, p_make_meshes, p_animations, p_materials, p_meshes);
+ _make_external_resources(p_node->get_child(i), p_base_path, p_make_animations, p_keep_animations, p_make_materials, p_keep_materials, p_make_meshes, p_animations, p_materials, p_meshes);
}
}
@@ -1030,12 +1165,14 @@ void ResourceImporterScene::get_import_options(List<ImportOption> *r_options, in
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "meshes/compress"), true));
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "meshes/ensure_tangents"), true));
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "meshes/storage", PROPERTY_HINT_ENUM, "Built-In,Files"), meshes_out ? 1 : 0));
- r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "meshes/light_baking", PROPERTY_HINT_ENUM, "Disabled,Enable"), 0));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "meshes/light_baking", PROPERTY_HINT_ENUM, "Disabled,Enable,Gen Lightmaps"), 0));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::REAL, "meshes/lightmap_texel_size", PROPERTY_HINT_RANGE, "0.001,100,0.001"), 0.05));
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "external_files/store_in_subdir"), false));
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "animation/import", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), true));
r_options->push_back(ImportOption(PropertyInfo(Variant::REAL, "animation/fps", PROPERTY_HINT_RANGE, "1,120,1"), 15));
r_options->push_back(ImportOption(PropertyInfo(Variant::STRING, "animation/filter_script", PROPERTY_HINT_MULTILINE_TEXT), ""));
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "animation/storage", PROPERTY_HINT_ENUM, "Built-In,Files"), animations_out ? true : false));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "animation/keep_custom_tracks"), animations_out ? true : false));
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "animation/optimizer/enabled", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), true));
r_options->push_back(ImportOption(PropertyInfo(Variant::REAL, "animation/optimizer/max_linear_error"), 0.05));
r_options->push_back(ImportOption(PropertyInfo(Variant::REAL, "animation/optimizer/max_angular_error"), 0.01));
@@ -1062,6 +1199,68 @@ void ResourceImporterScene::_replace_owner(Node *p_node, Node *p_scene, Node *p_
}
}
+Node *ResourceImporterScene::import_scene_from_other_importer(EditorSceneImporter *p_exception, const String &p_path, uint32_t p_flags, int p_bake_fps) {
+
+ Ref<EditorSceneImporter> importer;
+ String ext = p_path.get_extension().to_lower();
+
+ for (Set<Ref<EditorSceneImporter> >::Element *E = importers.front(); E; E = E->next()) {
+
+ if (E->get().ptr() == p_exception)
+ continue;
+ List<String> extensions;
+ E->get()->get_extensions(&extensions);
+
+ for (List<String>::Element *F = extensions.front(); F; F = F->next()) {
+
+ if (F->get().to_lower() == ext) {
+
+ importer = E->get();
+ break;
+ }
+ }
+
+ if (importer.is_valid())
+ break;
+ }
+
+ ERR_FAIL_COND_V(!importer.is_valid(), NULL);
+
+ List<String> missing;
+ Error err;
+ return importer->import_scene(p_path, p_flags, p_bake_fps, &missing, &err);
+}
+
+Ref<Animation> ResourceImporterScene::import_animation_from_other_importer(EditorSceneImporter *p_exception, const String &p_path, uint32_t p_flags, int p_bake_fps) {
+
+ Ref<EditorSceneImporter> importer;
+ String ext = p_path.get_extension().to_lower();
+
+ for (Set<Ref<EditorSceneImporter> >::Element *E = importers.front(); E; E = E->next()) {
+
+ if (E->get().ptr() == p_exception)
+ continue;
+ List<String> extensions;
+ E->get()->get_extensions(&extensions);
+
+ for (List<String>::Element *F = extensions.front(); F; F = F->next()) {
+
+ if (F->get().to_lower() == ext) {
+
+ importer = E->get();
+ break;
+ }
+ }
+
+ if (importer.is_valid())
+ break;
+ }
+
+ ERR_FAIL_COND_V(!importer.is_valid(), NULL);
+
+ return importer->import_animation(p_path, p_flags, p_bake_fps);
+}
+
Error ResourceImporterScene::import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files) {
String src_path = p_source_file;
@@ -1176,6 +1375,7 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p
}
bool external_animations = int(p_options["animation/storage"]) == 1;
+ bool keep_custom_tracks = p_options["animation/keep_custom_tracks"];
bool external_materials = p_options["materials/storage"];
bool external_meshes = p_options["meshes/storage"];
bool external_scenes = int(p_options["nodes/storage"]) == 1;
@@ -1195,6 +1395,37 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p
}
}
+ if (light_bake_mode == 2 /* || generate LOD */) {
+
+ Map<Ref<ArrayMesh>, Transform> meshes;
+ _find_meshes(scene, meshes);
+
+ if (light_bake_mode == 2) {
+
+ float texel_size = p_options["meshes/lightmap_texel_size"];
+ texel_size = MAX(0.001, texel_size);
+
+ EditorProgress progress("gen_lightmaps", TTR("Generating Lightmaps"), meshes.size());
+ int step = 0;
+ for (Map<Ref<ArrayMesh>, Transform>::Element *E = meshes.front(); E; E = E->next()) {
+
+ Ref<ArrayMesh> mesh = E->key();
+ String name = mesh->get_name();
+ if (name == "") { //should not happen but..
+ name = "Mesh " + itos(step);
+ }
+
+ progress.step(TTR("Generating for Mesh: ") + name + " (" + itos(step) + "/" + itos(meshes.size()) + ")", step);
+
+ Error err = mesh->lightmap_unwrap(E->get(), texel_size);
+ if (err != OK) {
+ EditorNode::add_io_error("Mesh '" + name + "' failed lightmap generation. Please fix geometry.");
+ }
+ step++;
+ }
+ }
+ }
+
if (external_animations || external_materials || external_meshes) {
Map<Ref<Animation>, Ref<Animation> > anim_map;
Map<Ref<Material>, Ref<Material> > mat_map;
@@ -1202,7 +1433,7 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p
bool keep_materials = bool(p_options["materials/keep_on_reimport"]);
- _make_external_resources(scene, base_path, external_animations, external_materials, keep_materials, external_meshes, anim_map, mat_map, mesh_map);
+ _make_external_resources(scene, base_path, external_animations, keep_custom_tracks, external_materials, keep_materials, external_meshes, anim_map, mat_map, mesh_map);
}
progress.step(TTR("Running Custom Script.."), 2);
diff --git a/editor/import/resource_importer_scene.h b/editor/import/resource_importer_scene.h
index 92777fafb6..933585a48c 100644
--- a/editor/import/resource_importer_scene.h
+++ b/editor/import/resource_importer_scene.h
@@ -41,6 +41,12 @@ class EditorSceneImporter : public Reference {
GDCLASS(EditorSceneImporter, Reference);
+protected:
+ static void _bind_methods();
+
+ Node *import_scene_from_other_importer(const String &p_path, uint32_t p_flags, int p_bake_fps);
+ Ref<Animation> import_animation_from_other_importer(const String &p_path, uint32_t p_flags, int p_bake_fps);
+
public:
enum ImportFlags {
IMPORT_SCENE = 1,
@@ -56,10 +62,10 @@ public:
};
- virtual uint32_t get_import_flags() const = 0;
- virtual void get_extensions(List<String> *r_extensions) const = 0;
- virtual Node *import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps, List<String> *r_missing_deps, Error *r_err = NULL) = 0;
- virtual Ref<Animation> import_animation(const String &p_path, uint32_t p_flags) = 0;
+ virtual uint32_t get_import_flags() const;
+ virtual void get_extensions(List<String> *r_extensions) const;
+ virtual Node *import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps, List<String> *r_missing_deps, Error *r_err = NULL);
+ virtual Ref<Animation> import_animation(const String &p_path, uint32_t p_flags, int p_bake_fps);
EditorSceneImporter() {}
};
@@ -114,6 +120,7 @@ public:
const Set<Ref<EditorSceneImporter> > &get_importers() const { return importers; }
void add_importer(Ref<EditorSceneImporter> p_importer) { importers.insert(p_importer); }
+ void remove_importer(Ref<EditorSceneImporter> p_importer) { importers.erase(p_importer); }
virtual String get_importer_name() const;
virtual String get_visible_name() const;
@@ -128,7 +135,9 @@ public:
virtual bool get_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const;
virtual int get_import_order() const { return 100; } //after everything
- void _make_external_resources(Node *p_node, const String &p_base_path, bool p_make_animations, bool p_make_materials, bool p_keep_materials, bool p_make_meshes, Map<Ref<Animation>, Ref<Animation> > &p_animations, Map<Ref<Material>, Ref<Material> > &p_materials, Map<Ref<ArrayMesh>, Ref<ArrayMesh> > &p_meshes);
+ void _find_meshes(Node *p_node, Map<Ref<ArrayMesh>, Transform> &meshes);
+
+ void _make_external_resources(Node *p_node, const String &p_base_path, bool p_make_animations, bool p_keep_animations, bool p_make_materials, bool p_keep_materials, bool p_make_meshes, Map<Ref<Animation>, Ref<Animation> > &p_animations, Map<Ref<Material>, Ref<Material> > &p_materials, Map<Ref<ArrayMesh>, Ref<ArrayMesh> > &p_meshes);
Node *_fix_node(Node *p_node, Node *p_root, Map<Ref<ArrayMesh>, Ref<Shape> > &collision_map, LightBakeMode p_light_bake_mode);
@@ -139,6 +148,9 @@ public:
virtual Error import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files = NULL);
+ Node *import_scene_from_other_importer(EditorSceneImporter *p_exception, const String &p_path, uint32_t p_flags, int p_bake_fps);
+ Ref<Animation> import_animation_from_other_importer(EditorSceneImporter *p_exception, const String &p_path, uint32_t p_flags, int p_bake_fps);
+
ResourceImporterScene();
};
diff --git a/editor/plugins/abstract_polygon_2d_editor.cpp b/editor/plugins/abstract_polygon_2d_editor.cpp
index cabdfa761d..ff72a5a25e 100644
--- a/editor/plugins/abstract_polygon_2d_editor.cpp
+++ b/editor/plugins/abstract_polygon_2d_editor.cpp
@@ -32,18 +32,21 @@
#include "canvas_item_editor_plugin.h"
#include "core/os/keyboard.h"
-AbstractPolygon2DEditor::Vertex::Vertex()
- : polygon(-1), vertex(-1) {
+AbstractPolygon2DEditor::Vertex::Vertex() :
+ polygon(-1),
+ vertex(-1) {
// invalid vertex
}
-AbstractPolygon2DEditor::Vertex::Vertex(int p_vertex)
- : polygon(-1), vertex(p_vertex) {
+AbstractPolygon2DEditor::Vertex::Vertex(int p_vertex) :
+ polygon(-1),
+ vertex(p_vertex) {
// vertex p_vertex of current wip polygon
}
-AbstractPolygon2DEditor::Vertex::Vertex(int p_polygon, int p_vertex)
- : polygon(p_polygon), vertex(p_vertex) {
+AbstractPolygon2DEditor::Vertex::Vertex(int p_polygon, int p_vertex) :
+ polygon(p_polygon),
+ vertex(p_vertex) {
// vertex p_vertex of polygon p_polygon
}
@@ -66,12 +69,14 @@ AbstractPolygon2DEditor::PosVertex::PosVertex() {
// invalid vertex
}
-AbstractPolygon2DEditor::PosVertex::PosVertex(const Vertex &p_vertex, const Vector2 &p_pos)
- : Vertex(p_vertex.polygon, p_vertex.vertex), pos(p_pos) {
+AbstractPolygon2DEditor::PosVertex::PosVertex(const Vertex &p_vertex, const Vector2 &p_pos) :
+ Vertex(p_vertex.polygon, p_vertex.vertex),
+ pos(p_pos) {
}
-AbstractPolygon2DEditor::PosVertex::PosVertex(int p_polygon, int p_vertex, const Vector2 &p_pos)
- : Vertex(p_polygon, p_vertex), pos(p_pos) {
+AbstractPolygon2DEditor::PosVertex::PosVertex(int p_polygon, int p_vertex, const Vector2 &p_pos) :
+ Vertex(p_polygon, p_vertex),
+ pos(p_pos) {
}
bool AbstractPolygon2DEditor::_is_empty() const {
@@ -167,7 +172,7 @@ void AbstractPolygon2DEditor::_menu_option(int p_option) {
} break;
case MODE_EDIT: {
- wip_active = false;
+ _wip_close();
mode = MODE_EDIT;
button_create->set_pressed(false);
button_edit->set_pressed(true);
@@ -175,7 +180,7 @@ void AbstractPolygon2DEditor::_menu_option(int p_option) {
} break;
case MODE_DELETE: {
- wip_active = false;
+ _wip_close();
mode = MODE_DELETE;
button_create->set_pressed(false);
button_edit->set_pressed(false);
@@ -224,6 +229,9 @@ void AbstractPolygon2DEditor::_wip_changed() {
}
void AbstractPolygon2DEditor::_wip_close() {
+ if (!wip_active)
+ return;
+
if (_is_line()) {
_set_polygon(0, wip);
diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp
index a7733cd2d9..e63bc3ad9f 100644
--- a/editor/plugins/canvas_item_editor_plugin.cpp
+++ b/editor/plugins/canvas_item_editor_plugin.cpp
@@ -69,8 +69,8 @@ class SnapDialog : public ConfirmationDialog {
SpinBox *rotation_step;
public:
- SnapDialog()
- : ConfirmationDialog() {
+ SnapDialog() :
+ ConfirmationDialog() {
const int SPIN_BOX_GRID_RANGE = 256;
const int SPIN_BOX_ROTATION_RANGE = 360;
Label *label;
@@ -4489,15 +4489,24 @@ void CanvasItemEditorViewport::_create_nodes(Node *parent, Node *child, String &
Ref<Texture> texture = Ref<Texture>(Object::cast_to<Texture>(ResourceCache::get(path)));
Size2 texture_size = texture->get_size();
- editor_data->get_undo_redo().add_do_method(parent, "add_child", child);
- editor_data->get_undo_redo().add_do_method(child, "set_owner", editor->get_edited_scene());
- editor_data->get_undo_redo().add_do_reference(child);
- editor_data->get_undo_redo().add_undo_method(parent, "remove_child", child);
+ if (parent) {
+ editor_data->get_undo_redo().add_do_method(parent, "add_child", child);
+ editor_data->get_undo_redo().add_do_method(child, "set_owner", editor->get_edited_scene());
+ editor_data->get_undo_redo().add_do_reference(child);
+ editor_data->get_undo_redo().add_undo_method(parent, "remove_child", child);
+ } else { // if we haven't parent, lets try to make a child as a parent.
+ editor_data->get_undo_redo().add_do_method(editor, "set_edited_scene", child);
+ editor_data->get_undo_redo().add_do_method(child, "set_owner", editor->get_edited_scene());
+ editor_data->get_undo_redo().add_do_reference(child);
+ editor_data->get_undo_redo().add_undo_method(editor, "set_edited_scene", (Object *)NULL);
+ }
- String new_name = parent->validate_child_name(child);
- ScriptEditorDebugger *sed = ScriptEditor::get_singleton()->get_debugger();
- editor_data->get_undo_redo().add_do_method(sed, "live_debug_create_node", editor->get_edited_scene()->get_path_to(parent), child->get_class(), new_name);
- editor_data->get_undo_redo().add_undo_method(sed, "live_debug_remove_node", NodePath(String(editor->get_edited_scene()->get_path_to(parent)) + "/" + new_name));
+ if (parent) {
+ String new_name = parent->validate_child_name(child);
+ ScriptEditorDebugger *sed = ScriptEditor::get_singleton()->get_debugger();
+ editor_data->get_undo_redo().add_do_method(sed, "live_debug_create_node", editor->get_edited_scene()->get_path_to(parent), child->get_class(), new_name);
+ editor_data->get_undo_redo().add_undo_method(sed, "live_debug_remove_node", NodePath(String(editor->get_edited_scene()->get_path_to(parent)) + "/" + new_name));
+ }
// handle with different property for texture
String property = "texture";
@@ -4530,8 +4539,8 @@ void CanvasItemEditorViewport::_create_nodes(Node *parent, Node *child, String &
}
// locate at preview position
- Point2 pos;
- if (parent->has_method("get_global_position")) {
+ Point2 pos = Point2(0, 0);
+ if (parent && parent->has_method("get_global_position")) {
pos = parent->call("get_global_position");
}
Transform2D trans = canvas->get_canvas_transform();
@@ -4692,6 +4701,18 @@ bool CanvasItemEditorViewport::can_drop_data(const Point2 &p_point, const Varian
return false;
}
+void CanvasItemEditorViewport::_show_resource_type_selector() {
+ List<BaseButton *> btn_list;
+ button_group->get_buttons(&btn_list);
+
+ for (int i = 0; i < btn_list.size(); i++) {
+ CheckBox *check = Object::cast_to<CheckBox>(btn_list[i]);
+ check->set_pressed(check->get_text() == default_type);
+ }
+ selector->set_title(vformat(TTR("Add %s"), default_type));
+ selector->popup_centered_minsize();
+}
+
void CanvasItemEditorViewport::drop_data(const Point2 &p_point, const Variant &p_data) {
bool is_shift = Input::get_singleton()->is_key_pressed(KEY_SHIFT);
bool is_alt = Input::get_singleton()->is_key_pressed(KEY_ALT);
@@ -4708,10 +4729,8 @@ void CanvasItemEditorViewport::drop_data(const Point2 &p_point, const Variant &p
if (root_node) {
list.push_back(root_node);
} else {
- accept->get_ok()->set_text(TTR("OK :("));
- accept->set_text(TTR("No parent to instance a child at."));
- accept->popup_centered_minsize();
- _remove_preview();
+ drop_pos = p_point;
+ _show_resource_type_selector();
return;
}
}
@@ -4730,15 +4749,7 @@ void CanvasItemEditorViewport::drop_data(const Point2 &p_point, const Variant &p
drop_pos = p_point;
if (is_alt) {
- List<BaseButton *> btn_list;
- button_group->get_buttons(&btn_list);
-
- for (int i = 0; i < btn_list.size(); i++) {
- CheckBox *check = Object::cast_to<CheckBox>(btn_list[i]);
- check->set_pressed(check->get_text() == default_type);
- }
- selector->set_title(vformat(TTR("Add %s"), default_type));
- selector->popup_centered_minsize();
+ _show_resource_type_selector();
} else {
_perform_drop_data();
}
diff --git a/editor/plugins/canvas_item_editor_plugin.h b/editor/plugins/canvas_item_editor_plugin.h
index 457833e1a7..4be09a16e9 100644
--- a/editor/plugins/canvas_item_editor_plugin.h
+++ b/editor/plugins/canvas_item_editor_plugin.h
@@ -578,6 +578,7 @@ class CanvasItemEditorViewport : public Control {
void _create_nodes(Node *parent, Node *child, String &path, const Point2 &p_point);
bool _create_instance(Node *parent, String &path, const Point2 &p_point);
void _perform_drop_data();
+ void _show_resource_type_selector();
static void _bind_methods();
diff --git a/editor/plugins/collision_polygon_2d_editor_plugin.cpp b/editor/plugins/collision_polygon_2d_editor_plugin.cpp
index 00e6d617a1..6ac80caf94 100644
--- a/editor/plugins/collision_polygon_2d_editor_plugin.cpp
+++ b/editor/plugins/collision_polygon_2d_editor_plugin.cpp
@@ -39,10 +39,10 @@ void CollisionPolygon2DEditor::_set_node(Node *p_polygon) {
node = Object::cast_to<CollisionPolygon2D>(p_polygon);
}
-CollisionPolygon2DEditor::CollisionPolygon2DEditor(EditorNode *p_editor)
- : AbstractPolygon2DEditor(p_editor) {
+CollisionPolygon2DEditor::CollisionPolygon2DEditor(EditorNode *p_editor) :
+ AbstractPolygon2DEditor(p_editor) {
}
-CollisionPolygon2DEditorPlugin::CollisionPolygon2DEditorPlugin(EditorNode *p_node)
- : AbstractPolygon2DEditorPlugin(p_node, memnew(CollisionPolygon2DEditor(p_node)), "CollisionPolygon2D") {
+CollisionPolygon2DEditorPlugin::CollisionPolygon2DEditorPlugin(EditorNode *p_node) :
+ AbstractPolygon2DEditorPlugin(p_node, memnew(CollisionPolygon2DEditor(p_node)), "CollisionPolygon2D") {
}
diff --git a/editor/plugins/curve_editor_plugin.cpp b/editor/plugins/curve_editor_plugin.cpp
index 2754aeed06..f77016c1d6 100644
--- a/editor/plugins/curve_editor_plugin.cpp
+++ b/editor/plugins/curve_editor_plugin.cpp
@@ -586,8 +586,10 @@ struct CanvasItemPlotCurve {
Color color1;
Color color2;
- CanvasItemPlotCurve(CanvasItem &p_ci, Color p_color1, Color p_color2)
- : ci(p_ci), color1(p_color1), color2(p_color2) {}
+ CanvasItemPlotCurve(CanvasItem &p_ci, Color p_color1, Color p_color2) :
+ ci(p_ci),
+ color1(p_color1),
+ color2(p_color2) {}
void operator()(Vector2 pos0, Vector2 pos1, bool in_definition) {
ci.draw_line(pos0, pos1, in_definition ? color1 : color2);
diff --git a/editor/plugins/editor_preview_plugins.cpp b/editor/plugins/editor_preview_plugins.cpp
index ed04c90cc5..558f44769d 100644
--- a/editor/plugins/editor_preview_plugins.cpp
+++ b/editor/plugins/editor_preview_plugins.cpp
@@ -235,29 +235,34 @@ Ref<Texture> EditorMaterialPreviewPlugin::generate(const RES &p_from) {
Ref<Material> material = p_from;
ERR_FAIL_COND_V(material.is_null(), Ref<Texture>());
- VS::get_singleton()->mesh_surface_set_material(sphere, 0, material->get_rid());
+ if (material->get_shader_mode() == Shader::MODE_SPATIAL) {
- VS::get_singleton()->viewport_set_update_mode(viewport, VS::VIEWPORT_UPDATE_ONCE); //once used for capture
+ VS::get_singleton()->mesh_surface_set_material(sphere, 0, material->get_rid());
- preview_done = false;
- VS::get_singleton()->request_frame_drawn_callback(this, "_preview_done", Variant());
+ VS::get_singleton()->viewport_set_update_mode(viewport, VS::VIEWPORT_UPDATE_ONCE); //once used for capture
- while (!preview_done) {
- OS::get_singleton()->delay_usec(10);
- }
+ preview_done = false;
+ VS::get_singleton()->request_frame_drawn_callback(this, "_preview_done", Variant());
- Ref<Image> img = VS::get_singleton()->VS::get_singleton()->texture_get_data(viewport_texture);
- VS::get_singleton()->mesh_surface_set_material(sphere, 0, RID());
+ while (!preview_done) {
+ OS::get_singleton()->delay_usec(10);
+ }
- ERR_FAIL_COND_V(!img.is_valid(), Ref<ImageTexture>());
+ Ref<Image> img = VS::get_singleton()->VS::get_singleton()->texture_get_data(viewport_texture);
+ VS::get_singleton()->mesh_surface_set_material(sphere, 0, RID());
- int thumbnail_size = EditorSettings::get_singleton()->get("filesystem/file_dialog/thumbnail_size");
- thumbnail_size *= EDSCALE;
- img->convert(Image::FORMAT_RGBA8);
- img->resize(thumbnail_size, thumbnail_size);
- Ref<ImageTexture> ptex = Ref<ImageTexture>(memnew(ImageTexture));
- ptex->create_from_image(img, 0);
- return ptex;
+ ERR_FAIL_COND_V(!img.is_valid(), Ref<ImageTexture>());
+
+ int thumbnail_size = EditorSettings::get_singleton()->get("filesystem/file_dialog/thumbnail_size");
+ thumbnail_size *= EDSCALE;
+ img->convert(Image::FORMAT_RGBA8);
+ img->resize(thumbnail_size, thumbnail_size);
+ Ref<ImageTexture> ptex = Ref<ImageTexture>(memnew(ImageTexture));
+ ptex->create_from_image(img, 0);
+ return ptex;
+ }
+
+ return Ref<Texture>();
}
EditorMaterialPreviewPlugin::EditorMaterialPreviewPlugin() {
diff --git a/editor/plugins/line_2d_editor_plugin.cpp b/editor/plugins/line_2d_editor_plugin.cpp
index 51fa488b43..04d8519b2f 100644
--- a/editor/plugins/line_2d_editor_plugin.cpp
+++ b/editor/plugins/line_2d_editor_plugin.cpp
@@ -61,10 +61,10 @@ void Line2DEditor::_action_set_polygon(int p_idx, const Variant &p_previous, con
undo_redo->add_undo_method(node, "set_points", p_previous);
}
-Line2DEditor::Line2DEditor(EditorNode *p_editor)
- : AbstractPolygon2DEditor(p_editor) {
+Line2DEditor::Line2DEditor(EditorNode *p_editor) :
+ AbstractPolygon2DEditor(p_editor) {
}
-Line2DEditorPlugin::Line2DEditorPlugin(EditorNode *p_node)
- : AbstractPolygon2DEditorPlugin(p_node, memnew(Line2DEditor(p_node)), "Line2D") {
+Line2DEditorPlugin::Line2DEditorPlugin(EditorNode *p_node) :
+ AbstractPolygon2DEditorPlugin(p_node, memnew(Line2DEditor(p_node)), "Line2D") {
}
diff --git a/editor/plugins/mesh_instance_editor_plugin.cpp b/editor/plugins/mesh_instance_editor_plugin.cpp
index 84fc0cecf2..9d116349c0 100644
--- a/editor/plugins/mesh_instance_editor_plugin.cpp
+++ b/editor/plugins/mesh_instance_editor_plugin.cpp
@@ -195,7 +195,139 @@ void MeshInstanceEditor::_menu_option(int p_option) {
outline_dialog->popup_centered(Vector2(200, 90));
} break;
+ case MENU_OPTION_CREATE_UV2: {
+
+ Ref<ArrayMesh> mesh = node->get_mesh();
+ if (!mesh.is_valid()) {
+ err_dialog->set_text(TTR("Contained Mesh is not of type ArrayMesh."));
+ err_dialog->popup_centered_minsize();
+ return;
+ }
+
+ Error err = mesh->lightmap_unwrap(node->get_global_transform());
+ if (err != OK) {
+ err_dialog->set_text(TTR("UV Unwrap failed, mesh may not be manifold?"));
+ err_dialog->popup_centered_minsize();
+ return;
+ }
+
+ } break;
+ case MENU_OPTION_DEBUG_UV1: {
+ Ref<Mesh> mesh = node->get_mesh();
+ if (!mesh.is_valid()) {
+ err_dialog->set_text(TTR("No mesh to debug."));
+ err_dialog->popup_centered_minsize();
+ return;
+ }
+ _create_uv_lines(0);
+ } break;
+ case MENU_OPTION_DEBUG_UV2: {
+ Ref<Mesh> mesh = node->get_mesh();
+ if (!mesh.is_valid()) {
+ err_dialog->set_text(TTR("No mesh to debug."));
+ err_dialog->popup_centered_minsize();
+ return;
+ }
+ _create_uv_lines(1);
+ } break;
+ }
+}
+
+struct MeshInstanceEditorEdgeSort {
+
+ Vector2 a;
+ Vector2 b;
+
+ bool operator<(const MeshInstanceEditorEdgeSort &p_b) const {
+ if (a == p_b.a)
+ return b < p_b.b;
+ else
+ return a < p_b.a;
+ }
+
+ MeshInstanceEditorEdgeSort() {}
+ MeshInstanceEditorEdgeSort(const Vector2 &p_a, const Vector2 &p_b) {
+ if (p_a < p_b) {
+ a = p_a;
+ b = p_b;
+ } else {
+ b = p_a;
+ a = p_b;
+ }
+ }
+};
+
+void MeshInstanceEditor::_create_uv_lines(int p_layer) {
+
+ Ref<Mesh> mesh = node->get_mesh();
+ ERR_FAIL_COND(!mesh.is_valid());
+
+ Set<MeshInstanceEditorEdgeSort> edges;
+ uv_lines.clear();
+ for (int i = 0; i < mesh->get_surface_count(); i++) {
+ if (mesh->surface_get_primitive_type(i) != Mesh::PRIMITIVE_TRIANGLES)
+ continue;
+ Array a = mesh->surface_get_arrays(i);
+
+ PoolVector<Vector2> uv = a[p_layer == 0 ? Mesh::ARRAY_TEX_UV : Mesh::ARRAY_TEX_UV2];
+ if (uv.size() == 0) {
+ err_dialog->set_text(TTR("Model has no UV in this layer"));
+ err_dialog->popup_centered_minsize();
+ return;
+ }
+
+ PoolVector<Vector2>::Read r = uv.read();
+
+ PoolVector<int> indices = a[Mesh::ARRAY_INDEX];
+ PoolVector<int>::Read ri;
+
+ int ic;
+ bool use_indices;
+
+ if (indices.size()) {
+ ic = indices.size();
+ ri = indices.read();
+ use_indices = true;
+ } else {
+ ic = uv.size();
+ use_indices = false;
+ }
+
+ for (int j = 0; j < ic; j += 3) {
+
+ for (int k = 0; k < 3; k++) {
+
+ MeshInstanceEditorEdgeSort edge;
+ if (use_indices) {
+ edge.a = r[ri[j + k]];
+ edge.b = r[ri[j + ((k + 1) % 3)]];
+ } else {
+ edge.a = r[j + k];
+ edge.b = r[j + ((k + 1) % 3)];
+ }
+
+ if (edges.has(edge))
+ continue;
+
+ uv_lines.push_back(edge.a);
+ uv_lines.push_back(edge.b);
+ edges.insert(edge);
+ }
+ }
}
+
+ debug_uv_dialog->popup_centered_minsize();
+}
+
+void MeshInstanceEditor::_debug_uv_draw() {
+
+ if (uv_lines.size() == 0)
+ return;
+
+ debug_uv->set_clip_contents(true);
+ debug_uv->draw_rect(Rect2(Vector2(), debug_uv->get_size()), Color(0.2, 0.2, 0.0));
+ debug_uv->draw_set_transform(Vector2(), 0, debug_uv->get_size());
+ debug_uv->draw_multiline(uv_lines, Color(1.0, 0.8, 0.7));
}
void MeshInstanceEditor::_create_outline_mesh() {
@@ -244,6 +376,7 @@ void MeshInstanceEditor::_bind_methods() {
ClassDB::bind_method("_menu_option", &MeshInstanceEditor::_menu_option);
ClassDB::bind_method("_create_outline_mesh", &MeshInstanceEditor::_create_outline_mesh);
+ ClassDB::bind_method("_debug_uv_draw", &MeshInstanceEditor::_debug_uv_draw);
}
MeshInstanceEditor::MeshInstanceEditor() {
@@ -263,6 +396,10 @@ MeshInstanceEditor::MeshInstanceEditor() {
options->get_popup()->add_item(TTR("Create Navigation Mesh"), MENU_OPTION_CREATE_NAVMESH);
options->get_popup()->add_separator();
options->get_popup()->add_item(TTR("Create Outline Mesh.."), MENU_OPTION_CREATE_OUTLINE_MESH);
+ options->get_popup()->add_separator();
+ options->get_popup()->add_item(TTR("View UV1"), MENU_OPTION_DEBUG_UV1);
+ options->get_popup()->add_item(TTR("View UV2"), MENU_OPTION_DEBUG_UV2);
+ options->get_popup()->add_item(TTR("Unwrap UV2 for Lightmap/AO"), MENU_OPTION_CREATE_UV2);
options->get_popup()->connect("id_pressed", this, "_menu_option");
@@ -286,6 +423,14 @@ MeshInstanceEditor::MeshInstanceEditor() {
err_dialog = memnew(AcceptDialog);
add_child(err_dialog);
+
+ debug_uv_dialog = memnew(AcceptDialog);
+ debug_uv_dialog->set_title("UV Channel Debug");
+ add_child(debug_uv_dialog);
+ debug_uv = memnew(Control);
+ debug_uv->set_custom_minimum_size(Size2(600, 600) * EDSCALE);
+ debug_uv->connect("draw", this, "_debug_uv_draw");
+ debug_uv_dialog->add_child(debug_uv);
}
void MeshInstanceEditorPlugin::edit(Object *p_object) {
diff --git a/editor/plugins/mesh_instance_editor_plugin.h b/editor/plugins/mesh_instance_editor_plugin.h
index fa851458ce..68c149f98a 100644
--- a/editor/plugins/mesh_instance_editor_plugin.h
+++ b/editor/plugins/mesh_instance_editor_plugin.h
@@ -47,6 +47,9 @@ class MeshInstanceEditor : public Node {
MENU_OPTION_CREATE_CONVEX_COLLISION_SHAPE,
MENU_OPTION_CREATE_NAVMESH,
MENU_OPTION_CREATE_OUTLINE_MESH,
+ MENU_OPTION_CREATE_UV2,
+ MENU_OPTION_DEBUG_UV1,
+ MENU_OPTION_DEBUG_UV2,
};
MeshInstance *node;
@@ -58,11 +61,18 @@ class MeshInstanceEditor : public Node {
AcceptDialog *err_dialog;
+ AcceptDialog *debug_uv_dialog;
+ Control *debug_uv;
+ Vector<Vector2> uv_lines;
+
void _menu_option(int p_option);
void _create_outline_mesh();
+ void _create_uv_lines(int p_layer);
friend class MeshInstanceEditorPlugin;
+ void _debug_uv_draw();
+
protected:
void _node_removed(Node *p_node);
static void _bind_methods();
diff --git a/editor/plugins/navigation_polygon_editor_plugin.cpp b/editor/plugins/navigation_polygon_editor_plugin.cpp
index 6560a8dac7..36c608310b 100644
--- a/editor/plugins/navigation_polygon_editor_plugin.cpp
+++ b/editor/plugins/navigation_polygon_editor_plugin.cpp
@@ -120,10 +120,10 @@ void NavigationPolygonEditor::_create_resource() {
_menu_option(MODE_CREATE);
}
-NavigationPolygonEditor::NavigationPolygonEditor(EditorNode *p_editor)
- : AbstractPolygon2DEditor(p_editor) {
+NavigationPolygonEditor::NavigationPolygonEditor(EditorNode *p_editor) :
+ AbstractPolygon2DEditor(p_editor) {
}
-NavigationPolygonEditorPlugin::NavigationPolygonEditorPlugin(EditorNode *p_node)
- : AbstractPolygon2DEditorPlugin(p_node, memnew(NavigationPolygonEditor(p_node)), "NavigationPolygonInstance") {
+NavigationPolygonEditorPlugin::NavigationPolygonEditorPlugin(EditorNode *p_node) :
+ AbstractPolygon2DEditorPlugin(p_node, memnew(NavigationPolygonEditor(p_node)), "NavigationPolygonInstance") {
}
diff --git a/editor/plugins/polygon_2d_editor_plugin.cpp b/editor/plugins/polygon_2d_editor_plugin.cpp
index ebb5f57e99..25e734187d 100644
--- a/editor/plugins/polygon_2d_editor_plugin.cpp
+++ b/editor/plugins/polygon_2d_editor_plugin.cpp
@@ -459,8 +459,8 @@ Vector2 Polygon2DEditor::snap_point(Vector2 p_target) const {
return p_target;
}
-Polygon2DEditor::Polygon2DEditor(EditorNode *p_editor)
- : AbstractPolygon2DEditor(p_editor) {
+Polygon2DEditor::Polygon2DEditor(EditorNode *p_editor) :
+ AbstractPolygon2DEditor(p_editor) {
snap_step = Vector2(10, 10);
use_snap = false;
@@ -609,6 +609,6 @@ Polygon2DEditor::Polygon2DEditor(EditorNode *p_editor)
uv_edit_draw->set_clip_contents(true);
}
-Polygon2DEditorPlugin::Polygon2DEditorPlugin(EditorNode *p_node)
- : AbstractPolygon2DEditorPlugin(p_node, memnew(Polygon2DEditor(p_node)), "Polygon2D") {
+Polygon2DEditorPlugin::Polygon2DEditorPlugin(EditorNode *p_node) :
+ AbstractPolygon2DEditorPlugin(p_node, memnew(Polygon2DEditor(p_node)), "Polygon2D") {
}
diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp
index 3c2d52c128..c02b3458e5 100644
--- a/editor/plugins/script_editor_plugin.cpp
+++ b/editor/plugins/script_editor_plugin.cpp
@@ -586,6 +586,12 @@ void ScriptEditor::_close_docs_tab() {
}
}
+void ScriptEditor::_copy_script_path() {
+ ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(tab_container->get_current_tab()));
+ Ref<Script> script = se->get_edited_script();
+ OS::get_singleton()->set_clipboard(script->get_path());
+}
+
void ScriptEditor::_close_other_tabs() {
int child_count = tab_container->get_child_count();
@@ -1026,6 +1032,9 @@ void ScriptEditor::_menu_option(int p_option) {
_close_current_tab();
}
} break;
+ case FILE_COPY_PATH: {
+ _copy_script_path();
+ } break;
case CLOSE_DOCS: {
_close_docs_tab();
} break;
@@ -2175,6 +2184,7 @@ void ScriptEditor::_make_script_list_context_menu() {
context_menu->add_shortcut(ED_GET_SHORTCUT("script_editor/close_all"), CLOSE_ALL);
context_menu->add_shortcut(ED_GET_SHORTCUT("script_editor/close_other_tabs"), CLOSE_OTHER_TABS);
context_menu->add_separator();
+ context_menu->add_shortcut(ED_GET_SHORTCUT("script_editor/copy_path"), FILE_COPY_PATH);
context_menu->add_shortcut(ED_GET_SHORTCUT("script_editor/reload_script_soft"), FILE_TOOL_RELOAD_SOFT);
Ref<Script> scr = se->get_edited_script();
@@ -2507,6 +2517,7 @@ void ScriptEditor::_bind_methods() {
ClassDB::bind_method("_help_search", &ScriptEditor::_help_search);
ClassDB::bind_method("_help_index", &ScriptEditor::_help_index);
ClassDB::bind_method("_save_history", &ScriptEditor::_save_history);
+ ClassDB::bind_method("_copy_script_path", &ScriptEditor::_copy_script_path);
ClassDB::bind_method("_breaked", &ScriptEditor::_breaked);
ClassDB::bind_method("_show_debugger", &ScriptEditor::_show_debugger);
@@ -2626,6 +2637,7 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) {
file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/save_all", TTR("Save All"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_MASK_ALT | KEY_S), FILE_SAVE_ALL);
file_menu->get_popup()->add_separator();
file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/reload_script_soft", TTR("Soft Reload Script"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_R), FILE_TOOL_RELOAD_SOFT);
+ file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/copy_path", TTR("Copy Script Path")), FILE_COPY_PATH);
file_menu->get_popup()->add_separator();
file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/history_previous", TTR("History Prev"), KEY_MASK_ALT | KEY_LEFT), WINDOW_PREV);
diff --git a/editor/plugins/script_editor_plugin.h b/editor/plugins/script_editor_plugin.h
index 77ca4bc9d9..ffd42d18ca 100644
--- a/editor/plugins/script_editor_plugin.h
+++ b/editor/plugins/script_editor_plugin.h
@@ -137,6 +137,7 @@ class ScriptEditor : public PanelContainer {
CLOSE_ALL,
CLOSE_OTHER_TABS,
TOGGLE_SCRIPTS_PANEL,
+ FILE_COPY_PATH,
FILE_TOOL_RELOAD,
FILE_TOOL_RELOAD_SOFT,
DEBUG_NEXT,
@@ -255,6 +256,8 @@ class ScriptEditor : public PanelContainer {
void _close_other_tabs();
void _close_all_tabs();
+ void _copy_script_path();
+
void _ask_close_current_unsaved_tab(ScriptEditorBase *current);
bool grab_focus_block;
diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp
index 3a443e1bf7..95f2739927 100644
--- a/editor/plugins/script_text_editor.cpp
+++ b/editor/plugins/script_text_editor.cpp
@@ -96,10 +96,10 @@ void ScriptTextEditor::_load_theme_settings() {
Color member_variable_color = EDITOR_DEF("text_editor/highlighting/member_variable_color", Color(0.9, 0.3, 0.3));
Color mark_color = EDITOR_DEF("text_editor/highlighting/mark_color", Color(1.0, 0.4, 0.4, 0.4));
Color breakpoint_color = EDITOR_DEF("text_editor/highlighting/breakpoint_color", Color(0.8, 0.8, 0.4, 0.2));
+ Color code_folding_color = EDITOR_DEF("text_editor/highlighting/code_folding_color", Color(0.8, 0.8, 0.8, 0.8));
Color search_result_color = EDITOR_DEF("text_editor/highlighting/search_result_color", Color(0.05, 0.25, 0.05, 1));
Color search_result_border_color = EDITOR_DEF("text_editor/highlighting/search_result_border_color", Color(0.1, 0.45, 0.1, 1));
Color symbol_color = EDITOR_DEF("text_editor/highlighting/symbol_color", Color::hex(0x005291ff));
-
Color keyword_color = EDITOR_DEF("text_editor/highlighting/keyword_color", Color(0.5, 0.0, 0.2));
Color basetype_color = EDITOR_DEF("text_editor/highlighting/base_type_color", Color(0.3, 0.3, 0.0));
Color type_color = EDITOR_DEF("text_editor/highlighting/engine_type_color", Color(0.0, 0.2, 0.4));
@@ -137,6 +137,7 @@ void ScriptTextEditor::_load_theme_settings() {
member_variable_color = tm->get_color("text_editor/theme/member_variable_color", "Editor");
mark_color = tm->get_color("text_editor/theme/mark_color", "Editor");
breakpoint_color = tm->get_color("text_editor/theme/breakpoint_color", "Editor");
+ code_folding_color = tm->get_color("text_editor/theme/code_folding_color", "Editor");
search_result_color = tm->get_color("text_editor/theme/search_result_color", "Editor");
search_result_border_color = tm->get_color("text_editor/theme/search_result_border_color", "Editor");
}
@@ -160,8 +161,9 @@ void ScriptTextEditor::_load_theme_settings() {
text_edit->add_color_override("number_color", number_color);
text_edit->add_color_override("function_color", function_color);
text_edit->add_color_override("member_variable_color", member_variable_color);
- text_edit->add_color_override("mark_color", mark_color);
text_edit->add_color_override("breakpoint_color", breakpoint_color);
+ text_edit->add_color_override("mark_color", mark_color);
+ text_edit->add_color_override("code_folding_color", code_folding_color);
text_edit->add_color_override("search_result_color", search_result_color);
text_edit->add_color_override("search_result_border_color", search_result_border_color);
text_edit->add_color_override("symbol_color", symbol_color);
@@ -1013,14 +1015,9 @@ void ScriptTextEditor::_edit_option(int p_op) {
tx->end_complex_operation();
tx->update();
} break;
- case EDIT_FOLD_LINE: {
-
- tx->fold_line(tx->cursor_get_line());
- tx->update();
- } break;
- case EDIT_UNFOLD_LINE: {
+ case EDIT_TOGGLE_FOLD_LINE: {
- tx->unfold_line(tx->cursor_get_line());
+ tx->toggle_fold_line(tx->cursor_get_line());
tx->update();
} break;
case EDIT_FOLD_ALL_LINES: {
@@ -1509,17 +1506,15 @@ void ScriptTextEditor::_make_context_menu(bool p_selection, bool p_color, bool p
if (p_selection) {
context_menu->add_separator();
+ context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/convert_to_uppercase"), EDIT_TO_UPPERCASE);
+ context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/convert_to_lowercase"), EDIT_TO_LOWERCASE);
context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/indent_left"), EDIT_INDENT_LEFT);
context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/indent_right"), EDIT_INDENT_RIGHT);
context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/toggle_comment"), EDIT_TOGGLE_COMMENT);
}
- if (p_can_fold) {
- // can fold
- context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/fold_line"), EDIT_FOLD_LINE);
- } else if (p_is_folded) {
- // can unfold
- context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/unfold_line"), EDIT_UNFOLD_LINE);
- }
+ if (p_can_fold || p_is_folded)
+ context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/toggle_fold_line"), EDIT_TOGGLE_FOLD_LINE);
+
if (p_color) {
context_menu->add_separator();
context_menu->add_item(TTR("Pick Color"), EDIT_PICK_COLOR);
@@ -1583,9 +1578,8 @@ ScriptTextEditor::ScriptTextEditor() {
edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/delete_line"), EDIT_DELETE_LINE);
edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/toggle_comment"), EDIT_TOGGLE_COMMENT);
edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/clone_down"), EDIT_CLONE_DOWN);
- edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/fold_line"), EDIT_FOLD_LINE);
+ edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/toggle_fold_line"), EDIT_TOGGLE_FOLD_LINE);
edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/fold_all_lines"), EDIT_FOLD_ALL_LINES);
- edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/unfold_line"), EDIT_UNFOLD_LINE);
edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/unfold_all_lines"), EDIT_UNFOLD_ALL_LINES);
edit_menu->get_popup()->add_separator();
#ifdef OSX_ENABLED
@@ -1664,8 +1658,7 @@ void ScriptTextEditor::register_editor() {
ED_SHORTCUT("script_text_editor/indent_right", TTR("Indent Right"), 0);
ED_SHORTCUT("script_text_editor/toggle_comment", TTR("Toggle Comment"), KEY_MASK_CMD | KEY_K);
ED_SHORTCUT("script_text_editor/clone_down", TTR("Clone Down"), KEY_MASK_CMD | KEY_B);
- ED_SHORTCUT("script_text_editor/fold_line", TTR("Fold Line"), KEY_MASK_ALT | KEY_LEFT);
- ED_SHORTCUT("script_text_editor/unfold_line", TTR("Unfold Line"), KEY_MASK_ALT | KEY_RIGHT);
+ ED_SHORTCUT("script_text_editor/toggle_fold_line", TTR("Fold/Unfold Line"), KEY_MASK_ALT | KEY_F);
ED_SHORTCUT("script_text_editor/fold_all_lines", TTR("Fold All Lines"), 0);
ED_SHORTCUT("script_text_editor/unfold_all_lines", TTR("Unfold All Lines"), 0);
#ifdef OSX_ENABLED
diff --git a/editor/plugins/script_text_editor.h b/editor/plugins/script_text_editor.h
index 722015ef3e..e3b81e7c3f 100644
--- a/editor/plugins/script_text_editor.h
+++ b/editor/plugins/script_text_editor.h
@@ -91,8 +91,7 @@ class ScriptTextEditor : public ScriptEditorBase {
EDIT_TO_UPPERCASE,
EDIT_TO_LOWERCASE,
EDIT_CAPITALIZE,
- EDIT_FOLD_LINE,
- EDIT_UNFOLD_LINE,
+ EDIT_TOGGLE_FOLD_LINE,
EDIT_FOLD_ALL_LINES,
EDIT_UNFOLD_ALL_LINES,
SEARCH_FIND,
diff --git a/editor/plugins/shader_editor_plugin.cpp b/editor/plugins/shader_editor_plugin.cpp
index 49e4642049..b390070b4a 100644
--- a/editor/plugins/shader_editor_plugin.cpp
+++ b/editor/plugins/shader_editor_plugin.cpp
@@ -81,6 +81,7 @@ void ShaderTextEditor::_load_theme_settings() {
Color member_variable_color = EDITOR_DEF("text_editor/highlighting/member_variable_color", Color(0.9, 0.3, 0.3));
Color mark_color = EDITOR_DEF("text_editor/highlighting/mark_color", Color(1.0, 0.4, 0.4, 0.4));
Color breakpoint_color = EDITOR_DEF("text_editor/highlighting/breakpoint_color", Color(0.8, 0.8, 0.4, 0.2));
+ Color code_folding_color = EDITOR_DEF("text_editor/highlighting/code_folding_color", Color(0.8, 0.8, 0.8, 0.8));
Color search_result_color = EDITOR_DEF("text_editor/highlighting/search_result_color", Color(0.05, 0.25, 0.05, 1));
Color search_result_border_color = EDITOR_DEF("text_editor/highlighting/search_result_border_color", Color(0.1, 0.45, 0.1, 1));
Color symbol_color = EDITOR_DEF("text_editor/highlighting/symbol_color", Color::hex(0x005291ff));
@@ -122,6 +123,7 @@ void ShaderTextEditor::_load_theme_settings() {
member_variable_color = tm->get_color("text_editor/theme/member_variable_color", "Editor");
mark_color = tm->get_color("text_editor/theme/mark_color", "Editor");
breakpoint_color = tm->get_color("text_editor/theme/breakpoint_color", "Editor");
+ code_folding_color = tm->get_color("text_editor/theme/code_folding_color", "Editor");
search_result_color = tm->get_color("text_editor/theme/search_result_color", "Editor");
search_result_border_color = tm->get_color("text_editor/theme/search_result_border_color", "Editor");
}
@@ -147,6 +149,7 @@ void ShaderTextEditor::_load_theme_settings() {
get_text_edit()->add_color_override("member_variable_color", member_variable_color);
get_text_edit()->add_color_override("mark_color", mark_color);
get_text_edit()->add_color_override("breakpoint_color", breakpoint_color);
+ get_text_edit()->add_color_override("code_folding_color", code_folding_color);
get_text_edit()->add_color_override("search_result_color", search_result_color);
get_text_edit()->add_color_override("search_result_border_color", search_result_border_color);
get_text_edit()->add_color_override("symbol_color", symbol_color);
diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp
index 60d7e59991..00488a2a88 100644
--- a/editor/project_manager.cpp
+++ b/editor/project_manager.cpp
@@ -508,7 +508,8 @@ public:
} else if (current->has_setting("application/config/name")) {
project_name->set_text(current->get("application/config/name"));
}
- project_name->grab_focus();
+
+ project_name->call_deferred("grab_focus");
create_dir->hide();
status_btn->hide();
diff --git a/editor/project_settings_editor.cpp b/editor/project_settings_editor.cpp
index 900f7625bc..76fd20ca12 100644
--- a/editor/project_settings_editor.cpp
+++ b/editor/project_settings_editor.cpp
@@ -1776,7 +1776,6 @@ ProjectSettingsEditor::ProjectSettingsEditor(EditorData *p_data) {
//translations
TabContainer *translations = memnew(TabContainer);
- translations->add_style_override("panel", memnew(StyleBoxEmpty));
translations->set_tab_align(TabContainer::ALIGN_LEFT);
translations->set_name(TTR("Localization"));
tab_container->add_child(translations);
@@ -1888,19 +1887,14 @@ ProjectSettingsEditor::ProjectSettingsEditor(EditorData *p_data) {
translation_filter->connect("item_edited", this, "_translation_filter_option_changed");
}
- {
- autoload_settings = memnew(EditorAutoloadSettings);
- autoload_settings->set_name(TTR("AutoLoad"));
- tab_container->add_child(autoload_settings);
- autoload_settings->connect("autoload_changed", this, "_settings_changed");
- }
+ autoload_settings = memnew(EditorAutoloadSettings);
+ autoload_settings->set_name(TTR("AutoLoad"));
+ tab_container->add_child(autoload_settings);
+ autoload_settings->connect("autoload_changed", this, "_settings_changed");
- {
-
- plugin_settings = memnew(EditorPluginSettings);
- plugin_settings->set_name(TTR("Plugins"));
- tab_container->add_child(plugin_settings);
- }
+ plugin_settings = memnew(EditorPluginSettings);
+ plugin_settings->set_name(TTR("Plugins"));
+ tab_container->add_child(plugin_settings);
timer = memnew(Timer);
timer->set_wait_time(1.5);
diff --git a/editor/property_editor.cpp b/editor/property_editor.cpp
index 6f9454be2c..446a0ea35d 100644
--- a/editor/property_editor.cpp
+++ b/editor/property_editor.cpp
@@ -430,24 +430,19 @@ bool CustomPropertyEditor::edit(Object *p_owner, const String &p_name, Variant::
} else if (hint == PROPERTY_HINT_LAYERS_2D_PHYSICS || hint == PROPERTY_HINT_LAYERS_2D_RENDER || hint == PROPERTY_HINT_LAYERS_3D_PHYSICS || hint == PROPERTY_HINT_LAYERS_3D_RENDER) {
- String title;
String basename;
switch (hint) {
case PROPERTY_HINT_LAYERS_2D_RENDER:
basename = "layer_names/2d_render";
- title = "2D Render Layers";
break;
case PROPERTY_HINT_LAYERS_2D_PHYSICS:
basename = "layer_names/2d_physics";
- title = "2D Physics Layers";
break;
case PROPERTY_HINT_LAYERS_3D_RENDER:
basename = "layer_names/3d_render";
- title = "3D Render Layers";
break;
case PROPERTY_HINT_LAYERS_3D_PHYSICS:
basename = "layer_names/3d_physics";
- title = "3D Physics Layers";
break;
}
@@ -469,11 +464,7 @@ bool CustomPropertyEditor::edit(Object *p_owner, const String &p_name, Variant::
show();
- value_label[0]->set_text(title);
- value_label[0]->show();
- value_label[0]->set_position(Vector2(4, 4) * EDSCALE);
-
- checks20gc->set_position(Vector2(4, 4) * EDSCALE + Vector2(0, value_label[0]->get_size().height + 4 * EDSCALE));
+ checks20gc->set_position(Vector2(4, 4) * EDSCALE);
checks20gc->set_size(checks20gc->get_minimum_size());
set_size(Vector2(4, 4) * EDSCALE + checks20gc->get_position() + checks20gc->get_size());
@@ -2101,6 +2092,23 @@ bool PropertyEditor::_is_property_different(const Variant &p_current, const Vari
return bool(Variant::evaluate(Variant::OP_NOT_EQUAL, p_current, p_orig));
}
+bool PropertyEditor::_is_instanced_node_with_original_property_different(const String &p_name, TreeItem *item) {
+ bool mbi = _might_be_in_instance();
+ if (mbi) {
+ Variant vorig;
+ Dictionary d = item->get_metadata(0);
+ int usage = d.has("usage") ? int(int(d["usage"]) & (PROPERTY_USAGE_STORE_IF_NONONE | PROPERTY_USAGE_STORE_IF_NONZERO)) : 0;
+ if (_get_instanced_node_original_property(p_name, vorig) || usage) {
+ Variant v = obj->get(p_name);
+
+ if (_is_property_different(v, vorig, usage)) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
TreeItem *PropertyEditor::find_item(TreeItem *p_item, const String &p_name) {
if (!p_item)
@@ -2360,6 +2368,10 @@ void PropertyEditor::_check_reload_status(const String &p_name, TreeItem *item)
}
}
+ if (_is_instanced_node_with_original_property_different(p_name, item)) {
+ has_reload = true;
+ }
+
if (obj->call("property_can_revert", p_name).operator bool()) {
has_reload = true;
@@ -2665,18 +2677,14 @@ TreeItem *PropertyEditor::get_parent_node(String p_path, HashMap<String, TreeIte
item->set_editable(1, false);
item->set_selectable(1, subsection_selectable);
- if (use_folding || folding_behaviour != FB_UNDEFINED) { // Even if you disabled folding (expand all by default), you still can collapse all manually.
+ if (use_folding) { //
if (!obj->editor_is_section_unfolded(p_path)) {
updating_folding = true;
- if (folding_behaviour == FB_COLLAPSEALL)
- item->set_collapsed(true);
- else if (folding_behaviour == FB_EXPANDALL || is_expandall_enabled)
- item->set_collapsed(false);
- else
- item->set_collapsed(true);
+ item->set_collapsed(true);
updating_folding = false;
}
item->set_metadata(0, p_path);
+ foldable_property_cache.push_back(p_path);
}
if (item->get_parent() == root) {
@@ -2725,6 +2733,7 @@ void PropertyEditor::refresh() {
void PropertyEditor::update_tree() {
tree->clear();
+ foldable_property_cache.clear();
if (!obj)
return;
@@ -3512,20 +3521,9 @@ void PropertyEditor::update_tree() {
bool has_reload = false;
- bool mbi = _might_be_in_instance();
- if (mbi) {
-
- Variant vorig;
- Dictionary d = item->get_metadata(0);
- int usage = d.has("usage") ? int(int(d["usage"]) & (PROPERTY_USAGE_STORE_IF_NONONE | PROPERTY_USAGE_STORE_IF_NONZERO)) : 0;
- if (_get_instanced_node_original_property(p.name, vorig) || usage) {
- Variant v = obj->get(p.name);
-
- if (_is_property_different(v, vorig, usage)) {
- item->add_button(1, get_icon("ReloadSmall", "EditorIcons"), 3);
- has_reload = true;
- }
- }
+ if (_is_instanced_node_with_original_property_different(p.name, item)) {
+ item->add_button(1, get_icon("ReloadSmall", "EditorIcons"), 3);
+ has_reload = true;
}
if (obj->call("property_can_revert", p.name).operator bool()) {
@@ -3545,7 +3543,7 @@ void PropertyEditor::update_tree() {
}
}
- if (mbi && !has_reload && item->get_cell_mode(1) == TreeItem::CELL_MODE_RANGE && item->get_text(1) == String()) {
+ if (_might_be_in_instance() && !has_reload && item->get_cell_mode(1) == TreeItem::CELL_MODE_RANGE && item->get_text(1) == String()) {
item->add_button(1, get_icon("ReloadEmpty", "EditorIcons"), 3, true);
}
}
@@ -3733,8 +3731,8 @@ void PropertyEditor::_item_edited() {
_edit_set(name, item->get_text(1), refresh_all);
}
} break;
- // math types
+ // math types
case Variant::VECTOR3: {
} break;
@@ -4212,29 +4210,29 @@ void PropertyEditor::set_subsection_selectable(bool p_selectable) {
update_tree();
}
-bool PropertyEditor::is_expand_all_properties_enabled() const {
-
- return (use_folding == false);
-}
-
void PropertyEditor::set_use_folding(bool p_enable) {
use_folding = p_enable;
tree->set_hide_folding(false);
}
-void PropertyEditor::collapse_all_parent_nodes() {
-
- folding_behaviour = FB_COLLAPSEALL;
+void PropertyEditor::collapse_all_folding() {
+ if (!obj)
+ return;
+ for (List<String>::Element *E = foldable_property_cache.front(); E; E = E->next()) {
+ obj->editor_set_section_unfold(E->get(), false);
+ }
update_tree();
- folding_behaviour = FB_UNDEFINED;
}
-void PropertyEditor::expand_all_parent_nodes() {
+void PropertyEditor::expand_all_folding() {
- folding_behaviour = FB_EXPANDALL;
+ if (!obj)
+ return;
+ for (List<String>::Element *E = foldable_property_cache.front(); E; E = E->next()) {
+ obj->editor_set_section_unfold(E->get(), true);
+ }
update_tree();
- folding_behaviour = FB_UNDEFINED;
}
PropertyEditor::PropertyEditor() {
@@ -4309,8 +4307,6 @@ PropertyEditor::PropertyEditor() {
subsection_selectable = false;
property_selectable = false;
show_type_icons = false; // maybe one day will return.
- folding_behaviour = FB_UNDEFINED;
- is_expandall_enabled = bool(EDITOR_DEF("interface/editor/expand_all_properties", true));
}
PropertyEditor::~PropertyEditor() {
diff --git a/editor/property_editor.h b/editor/property_editor.h
index a337a05e46..f684f5768d 100644
--- a/editor/property_editor.h
+++ b/editor/property_editor.h
@@ -203,18 +203,9 @@ class PropertyEditor : public Control {
bool hide_script;
bool use_folding;
bool property_selectable;
- bool is_expandall_enabled;
-
bool updating_folding;
- enum FOLDING_BEHAVIOUR {
- FB_UNDEFINED,
- FB_COLLAPSEALL,
- FB_EXPANDALL,
- FB_EXPANDALL_FORCE
- };
- FOLDING_BEHAVIOUR folding_behaviour;
-
+ List<String> foldable_property_cache;
HashMap<String, String> pending;
String selected_property;
@@ -253,6 +244,7 @@ class PropertyEditor : public Control {
bool _might_be_in_instance();
bool _get_instanced_node_original_property(const StringName &p_prop, Variant &value);
bool _is_property_different(const Variant &p_current, const Variant &p_orig, int p_usage = 0);
+ bool _is_instanced_node_with_original_property_different(const String &p_name, TreeItem *item);
void _refresh_item(TreeItem *p_item);
void _set_range_def(Object *p_item, String prop, float p_frame);
@@ -314,10 +306,8 @@ public:
void set_use_folding(bool p_enable);
- bool is_expand_all_properties_enabled() const;
-
- void collapse_all_parent_nodes();
- void expand_all_parent_nodes();
+ void collapse_all_folding();
+ void expand_all_folding();
PropertyEditor();
~PropertyEditor();
};