summaryrefslogtreecommitdiff
path: root/editor
diff options
context:
space:
mode:
Diffstat (limited to 'editor')
-rw-r--r--editor/animation_editor.cpp34
-rw-r--r--editor/dependency_editor.cpp154
-rw-r--r--editor/dependency_editor.h27
-rw-r--r--editor/editor_help.cpp9
-rw-r--r--editor/editor_node.cpp21
-rw-r--r--editor/editor_settings.cpp3
-rw-r--r--editor/editor_themes.cpp6
-rw-r--r--editor/filesystem_dock.cpp607
-rw-r--r--editor/filesystem_dock.h41
-rw-r--r--editor/plugins/script_editor_plugin.cpp12
-rw-r--r--editor/plugins/spatial_editor_plugin.cpp169
-rw-r--r--editor/plugins/spatial_editor_plugin.h12
-rw-r--r--editor/project_settings_editor.cpp2
-rw-r--r--editor/property_editor.cpp4
14 files changed, 650 insertions, 451 deletions
diff --git a/editor/animation_editor.cpp b/editor/animation_editor.cpp
index 5bb10f495e..54eb695178 100644
--- a/editor/animation_editor.cpp
+++ b/editor/animation_editor.cpp
@@ -64,6 +64,8 @@ private:
float transition;
Mode mode;
+ LineEdit *value_edit;
+
void _notification(int p_what) {
if (p_what == NOTIFICATION_DRAW) {
@@ -144,14 +146,11 @@ private:
}
}
- String txt = String::num(exp, 2);
if (mode == MODE_DISABLED) {
- txt = TTR("Disabled");
+ f->draw(ci, Point2(5, 5 + f->get_ascent()), TTR("Disabled"), color);
} else if (mode == MODE_MULTIPLE) {
- txt += " - " + TTR("All Selection");
+ f->draw(ci, Point2(5, 5 + f->get_ascent() + value_edit->get_size().height), TTR("All Selection"), color);
}
-
- f->draw(ci, Point2(10, 10 + f->get_ascent()), txt, color);
}
}
@@ -163,6 +162,8 @@ private:
if (mode == MODE_DISABLED)
return;
+ value_edit->release_focus();
+
float rel = mm->get_relative().x;
if (rel == 0)
return;
@@ -187,24 +188,28 @@ private:
if (sg)
val = -val;
- transition = val;
- update();
- //emit_signal("variant_changed");
- emit_signal("transition_changed", transition);
+ force_transition(val);
}
}
+ void _edit_value_changed(const String &p_value_str) {
+
+ force_transition(p_value_str.to_float());
+ }
+
public:
static void _bind_methods() {
//ClassDB::bind_method("_update_obj",&AnimationKeyEdit::_update_obj);
ClassDB::bind_method("_gui_input", &AnimationCurveEdit::_gui_input);
+ ClassDB::bind_method("_edit_value_changed", &AnimationCurveEdit::_edit_value_changed);
ADD_SIGNAL(MethodInfo("transition_changed"));
}
void set_mode(Mode p_mode) {
mode = p_mode;
+ value_edit->set_visible(mode != MODE_DISABLED);
update();
}
@@ -218,7 +223,8 @@ public:
}
void set_transition(float p_transition) {
- transition = p_transition;
+ transition = Math::stepify(p_transition, 0.01);
+ value_edit->set_text(String::num(transition));
update();
}
@@ -229,9 +235,8 @@ public:
void force_transition(float p_value) {
if (mode == MODE_DISABLED)
return;
- transition = p_value;
+ set_transition(p_value);
emit_signal("transition_changed", p_value);
- update();
}
AnimationCurveEdit() {
@@ -239,6 +244,11 @@ public:
transition = 1.0;
set_default_cursor_shape(CURSOR_HSPLIT);
mode = MODE_DISABLED;
+
+ value_edit = memnew(LineEdit);
+ value_edit->hide();
+ value_edit->connect("text_entered", this, "_edit_value_changed");
+ add_child(value_edit);
}
};
diff --git a/editor/dependency_editor.cpp b/editor/dependency_editor.cpp
index 5305c4f256..64f1c4ccb2 100644
--- a/editor/dependency_editor.cpp
+++ b/editor/dependency_editor.cpp
@@ -337,92 +337,142 @@ DependencyEditorOwners::DependencyEditorOwners() {
///////////////////////
-void DependencyRemoveDialog::_fill_owners(EditorFileSystemDirectory *efsd) {
+void DependencyRemoveDialog::_find_files_in_removed_folder(EditorFileSystemDirectory *efsd, const String &p_folder) {
+ if (!efsd)
+ return;
+
+ for (int i = 0; i < efsd->get_subdir_count(); ++i) {
+ _find_files_in_removed_folder(efsd->get_subdir(i), p_folder);
+ }
+ for (int i = 0; i < efsd->get_file_count(); i++) {
+ String file = efsd->get_file_path(i);
+ ERR_FAIL_COND(all_remove_files.has(file)); //We are deleting a directory which is contained in a directory we are deleting...
+ all_remove_files[file] = p_folder; //Point the file to the ancestor directory we are deleting so we know what to parent it under in the tree.
+ }
+}
+void DependencyRemoveDialog::_find_all_removed_dependencies(EditorFileSystemDirectory *efsd, Vector<RemovedDependency> &p_removed) {
if (!efsd)
return;
for (int i = 0; i < efsd->get_subdir_count(); i++) {
- _fill_owners(efsd->get_subdir(i));
+ _find_all_removed_dependencies(efsd->get_subdir(i), p_removed);
}
for (int i = 0; i < efsd->get_file_count(); i++) {
+ const String path = efsd->get_file_path(i);
- Vector<String> deps = efsd->get_file_deps(i);
- //print_line(":::"+efsd->get_file_path(i));
- Set<String> met;
- for (int j = 0; j < deps.size(); j++) {
- if (files.has(deps[j])) {
- met.insert(deps[j]);
- }
- }
- if (!met.size())
+ //It doesn't matter if a file we are about to delete will have some of its dependencies removed too
+ if (all_remove_files.has(path))
continue;
- exist = true;
-
- Ref<Texture> icon;
- String type = efsd->get_file_type(i);
- if (!has_icon(type, "EditorIcons")) {
- icon = get_icon("Object", "EditorIcons");
- } else {
- icon = get_icon(type, "EditorIcons");
+ Vector<String> all_deps = efsd->get_file_deps(i);
+ for (int j = 0; j < all_deps.size(); ++j) {
+ if (all_remove_files.has(all_deps[j])) {
+ RemovedDependency dep;
+ dep.file = path;
+ dep.file_type = efsd->get_file_type(i);
+ dep.dependency = all_deps[j];
+ dep.dependency_folder = all_remove_files[all_deps[j]];
+ p_removed.push_back(dep);
+ }
}
+ }
+}
- for (Set<String>::Element *E = met.front(); E; E = E->next()) {
+void DependencyRemoveDialog::_build_removed_dependency_tree(const Vector<RemovedDependency> &p_removed) {
+ owners->clear();
+ owners->create_item(); // root
- String which = E->get();
- if (!files[which]) {
- TreeItem *ti = owners->create_item(owners->get_root());
- ti->set_text(0, which.get_file());
- files[which] = ti;
+ Map<String, TreeItem *> tree_items;
+ for (int i = 0; i < p_removed.size(); i++) {
+ RemovedDependency rd = p_removed[i];
+
+ //Ensure that the dependency is already in the tree
+ if (!tree_items.has(rd.dependency)) {
+ if (rd.dependency_folder.length() > 0) {
+ //Ensure the ancestor folder is already in the tree
+ if (!tree_items.has(rd.dependency_folder)) {
+ TreeItem *folder_item = owners->create_item(owners->get_root());
+ folder_item->set_text(0, rd.dependency_folder);
+ folder_item->set_icon(0, get_icon("Folder", "EditorIcons"));
+ tree_items[rd.dependency_folder] = folder_item;
+ }
+ TreeItem *dependency_item = owners->create_item(tree_items[rd.dependency_folder]);
+ dependency_item->set_text(0, rd.dependency);
+ dependency_item->set_icon(0, get_icon("Warning", "EditorIcons"));
+ tree_items[rd.dependency] = dependency_item;
+ } else {
+ TreeItem *dependency_item = owners->create_item(owners->get_root());
+ dependency_item->set_text(0, rd.dependency);
+ dependency_item->set_icon(0, get_icon("Warning", "EditorIcons"));
+ tree_items[rd.dependency] = dependency_item;
}
- TreeItem *ti = owners->create_item(files[which]);
- ti->set_text(0, efsd->get_file_path(i));
- ti->set_icon(0, icon);
}
+
+ //List this file under this dependency
+ Ref<Texture> icon = has_icon(rd.file_type, "EditorIcons") ? get_icon(rd.file_type, "EditorIcons") : get_icon("Object", "EditorIcons");
+ TreeItem *file_item = owners->create_item(tree_items[rd.dependency]);
+ file_item->set_text(0, rd.file);
+ file_item->set_icon(0, icon);
}
}
-void DependencyRemoveDialog::show(const Vector<String> &to_erase) {
-
- exist = false;
+void DependencyRemoveDialog::show(const Vector<String> &p_folders, const Vector<String> &p_files) {
+ all_remove_files.clear();
+ to_delete.clear();
owners->clear();
- files.clear();
- owners->create_item(); // root
- for (int i = 0; i < to_erase.size(); i++) {
- files[to_erase[i]] = NULL;
+
+ for (int i = 0; i < p_folders.size(); ++i) {
+ String folder = p_folders[i].ends_with("/") ? p_folders[i] : (p_folders[i] + "/");
+ _find_files_in_removed_folder(EditorFileSystem::get_singleton()->get_filesystem_path(folder), folder);
+ to_delete.push_back(folder);
+ }
+ for (int i = 0; i < p_files.size(); ++i) {
+ all_remove_files[p_files[i]] = String();
+ to_delete.push_back(p_files[i]);
}
- _fill_owners(EditorFileSystem::get_singleton()->get_filesystem());
+ Vector<RemovedDependency> removed_deps;
+ _find_all_removed_dependencies(EditorFileSystem::get_singleton()->get_filesystem(), removed_deps);
+ removed_deps.sort();
- if (exist) {
- owners->show();
- text->set_text(TTR("The files being removed are required by other resources in order for them to work.\nRemove them anyway? (no undo)"));
- popup_centered_minsize(Size2(500, 220));
- } else {
+ if (removed_deps.empty()) {
owners->hide();
text->set_text(TTR("Remove selected files from the project? (no undo)"));
popup_centered_minsize(Size2(400, 100));
+ } else {
+ _build_removed_dependency_tree(removed_deps);
+ owners->show();
+ text->set_text(TTR("The files being removed are required by other resources in order for them to work.\nRemove them anyway? (no undo)"));
+ popup_centered_minsize(Size2(500, 350));
}
}
void DependencyRemoveDialog::ok_pressed() {
-
- bool changed = false;
-
- for (Map<String, TreeItem *>::Element *E = files.front(); E; E = E->next()) {
-
- if (ResourceCache::has(E->key())) {
- Resource *res = ResourceCache::get(E->key());
+ bool files_only = true;
+ for (int i = 0; i < to_delete.size(); ++i) {
+ if (to_delete[i].ends_with("/")) {
+ files_only = false;
+ } else if (ResourceCache::has(to_delete[i])) {
+ Resource *res = ResourceCache::get(to_delete[i]);
res->set_path(""); //clear reference to path
}
- String fpath = OS::get_singleton()->get_resource_dir() + E->key().replace_first("res://", "/");
- OS::get_singleton()->move_to_trash(fpath);
- changed = true;
+
+ String path = OS::get_singleton()->get_resource_dir() + to_delete[i].replace_first("res://", "/");
+ print_line("Moving to trash: " + path);
+ Error err = OS::get_singleton()->move_to_trash(path);
+ if (err != OK) {
+ EditorNode::get_singleton()->add_io_error(TTR("Cannot remove:\n") + to_delete[i] + "\n");
+ }
}
- if (changed) {
+ if (files_only) {
+ //If we only deleted files we should only need to tell the file system about the files we touched.
+ for (int i = 0; i < to_delete.size(); ++i) {
+ EditorFileSystem::get_singleton()->update_file(to_delete[i]);
+ }
+ } else {
EditorFileSystem::get_singleton()->scan_changes();
}
}
diff --git a/editor/dependency_editor.h b/editor/dependency_editor.h
index 4dfb9de268..c7e9baa5c2 100644
--- a/editor/dependency_editor.h
+++ b/editor/dependency_editor.h
@@ -84,14 +84,33 @@ class DependencyRemoveDialog : public ConfirmationDialog {
Label *text;
Tree *owners;
- bool exist;
- Map<String, TreeItem *> files;
- void _fill_owners(EditorFileSystemDirectory *efsd);
+
+ Map<String, String> all_remove_files;
+ Vector<String> to_delete;
+
+ struct RemovedDependency {
+ String file;
+ String file_type;
+ String dependency;
+ String dependency_folder;
+
+ bool operator<(const RemovedDependency &p_other) const {
+ if (dependency_folder.empty() != p_other.dependency_folder.empty()) {
+ return p_other.dependency_folder.empty();
+ } else {
+ return dependency < p_other.dependency;
+ }
+ }
+ };
+
+ void _find_files_in_removed_folder(EditorFileSystemDirectory *efsd, const String &p_folder);
+ void _find_all_removed_dependencies(EditorFileSystemDirectory *efsd, Vector<RemovedDependency> &p_removed);
+ void _build_removed_dependency_tree(const Vector<RemovedDependency> &p_removed);
void ok_pressed();
public:
- void show(const Vector<String> &to_erase);
+ void show(const Vector<String> &p_folders, const Vector<String> &p_files);
DependencyRemoveDialog();
};
diff --git a/editor/editor_help.cpp b/editor/editor_help.cpp
index 20ffbde378..2c4d3035a4 100644
--- a/editor/editor_help.cpp
+++ b/editor/editor_help.cpp
@@ -1699,7 +1699,7 @@ void EditorHelp::_notification(int p_what) {
case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
- class_desc->add_color_override("selection_color", EDITOR_DEF("text_editor/highlighting/selection_color", Color(0.2, 0.2, 1)));
+ class_desc->add_color_override("selection_color", get_color("text_editor/theme/selection_color", "Editor"));
} break;
@@ -1788,7 +1788,7 @@ EditorHelp::EditorHelp() {
class_desc = memnew(RichTextLabel);
vbc->add_child(class_desc);
class_desc->set_v_size_flags(SIZE_EXPAND_FILL);
- class_desc->add_color_override("selection_color", EDITOR_DEF("text_editor/highlighting/selection_color", Color(0.2, 0.2, 1)));
+ class_desc->add_color_override("selection_color", get_color("text_editor/theme/selection_color", "Editor"));
class_desc->connect("meta_clicked", this, "_class_desc_select");
class_desc->connect("gui_input", this, "_class_desc_input");
}
@@ -1879,7 +1879,7 @@ void EditorHelpBit::_notification(int p_what) {
switch (p_what) {
case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
- rich_text->add_color_override("selection_color", EDITOR_DEF("text_editor/highlighting/selection_color", Color(0.2, 0.2, 1)));
+ rich_text->add_color_override("selection_color", get_color("text_editor/theme/selection_color", "Editor"));
} break;
default: break;
@@ -1898,6 +1898,7 @@ EditorHelpBit::EditorHelpBit() {
add_child(rich_text);
rich_text->set_anchors_and_margins_preset(Control::PRESET_WIDE);
rich_text->connect("meta_clicked", this, "_meta_clicked");
- rich_text->add_color_override("selection_color", EDITOR_DEF("text_editor/highlighting/selection_color", Color(0.2, 0.2, 1)));
+ rich_text->add_color_override("selection_color", get_color("text_editor/theme/selection_color", "Editor"));
+ rich_text->set_override_selected_font_color(false);
set_custom_minimum_size(Size2(0, 70 * EDSCALE));
}
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index 1ca88133b8..aca2f59134 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -3156,12 +3156,19 @@ void EditorNode::_add_to_recent_scenes(const String &p_scene) {
void EditorNode::_open_recent_scene(int p_idx) {
String base = "_" + ProjectSettings::get_singleton()->get_resource_path().replace("\\", "::").replace("/", "::");
- Vector<String> rc = EDITOR_DEF(base + "/_recent_scenes", Array());
- ERR_FAIL_INDEX(p_idx, rc.size());
+ if (p_idx == recent_scenes->get_item_count() - 1) {
+
+ EditorSettings::get_singleton()->erase(base + "/_recent_scenes");
+ call_deferred("_update_recent_scenes");
+ } else {
+
+ Vector<String> rc = EDITOR_DEF(base + "/_recent_scenes", Array());
+ ERR_FAIL_INDEX(p_idx, rc.size());
- String path = "res://" + rc[p_idx];
- load_scene(path);
+ String path = "res://" + rc[p_idx];
+ load_scene(path);
+ }
}
void EditorNode::_update_recent_scenes() {
@@ -3169,10 +3176,15 @@ void EditorNode::_update_recent_scenes() {
String base = "_" + ProjectSettings::get_singleton()->get_resource_path().replace("\\", "::").replace("/", "::");
Vector<String> rc = EDITOR_DEF(base + "/_recent_scenes", Array());
recent_scenes->clear();
+
for (int i = 0; i < rc.size(); i++) {
recent_scenes->add_item(rc[i], i);
}
+
+ recent_scenes->add_separator();
+ recent_scenes->add_shortcut(ED_SHORTCUT("editor/clear_recent", TTR("Clear Recent Scenes")));
+ recent_scenes->set_as_minsize();
}
void EditorNode::_quick_opened() {
@@ -4513,6 +4525,7 @@ void EditorNode::_bind_methods() {
ClassDB::bind_method("_set_main_scene_state", &EditorNode::_set_main_scene_state);
ClassDB::bind_method("_update_scene_tabs", &EditorNode::_update_scene_tabs);
ClassDB::bind_method("_discard_changes", &EditorNode::_discard_changes);
+ ClassDB::bind_method("_update_recent_scenes", &EditorNode::_update_recent_scenes);
ClassDB::bind_method("_prepare_history", &EditorNode::_prepare_history);
ClassDB::bind_method("_select_history", &EditorNode::_select_history);
diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp
index b532bb793a..7c45e19f5f 100644
--- a/editor/editor_settings.cpp
+++ b/editor/editor_settings.cpp
@@ -719,12 +719,13 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
// freelook
_initial_set("editors/3d/freelook/freelook_inertia", 0.1);
hints["editors/3d/freelook/freelook_inertia"] = PropertyInfo(Variant::REAL, "editors/3d/freelook/freelook_inertia", PROPERTY_HINT_RANGE, "0.0, 1, 0.01");
- _initial_set("editors/3d/freelook/freelook_base_speed", 0.1);
+ _initial_set("editors/3d/freelook/freelook_base_speed", 5.0);
hints["editors/3d/freelook/freelook_base_speed"] = PropertyInfo(Variant::REAL, "editors/3d/freelook/freelook_base_speed", PROPERTY_HINT_RANGE, "0.0, 10, 0.01");
_initial_set("editors/3d/freelook/freelook_activation_modifier", 0);
hints["editors/3d/freelook/freelook_activation_modifier"] = PropertyInfo(Variant::INT, "editors/3d/freelook/freelook_activation_modifier", PROPERTY_HINT_ENUM, "None,Shift,Alt,Meta,Ctrl");
_initial_set("editors/3d/freelook/freelook_modifier_speed_factor", 3.0);
hints["editors/3d/freelook/freelook_modifier_speed_factor"] = PropertyInfo(Variant::REAL, "editors/3d/freelook/freelook_modifier_speed_factor", PROPERTY_HINT_RANGE, "0.0, 10.0, 0.1");
+ _initial_set("editors/3d/freelook/freelook_speed_zoom_link", false);
_initial_set("editors/2d/bone_width", 5);
_initial_set("editors/2d/bone_color1", Color(1.0, 1.0, 1.0, 0.9));
diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp
index 3fc1dcb0bd..13ed7a7f30 100644
--- a/editor/editor_themes.cpp
+++ b/editor/editor_themes.cpp
@@ -972,8 +972,8 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
const Color dim_color = Color(font_color.r, font_color.g, font_color.b, 0.5);
const float mono_value = mono_color.r;
- const Color alpha1 = Color(mono_value, mono_value, mono_value, 0.1);
- const Color alpha2 = Color(mono_value, mono_value, mono_value, 0.3);
+ const Color alpha1 = Color(mono_value, mono_value, mono_value, 0.07);
+ const Color alpha2 = Color(mono_value, mono_value, mono_value, 0.14);
const Color alpha3 = Color(mono_value, mono_value, mono_value, 0.5);
const Color alpha4 = Color(mono_value, mono_value, mono_value, 0.7);
@@ -998,7 +998,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
const Color caret_color = mono_color;
const Color caret_background_color = mono_color.inverted();
const Color text_selected_color = dark_color_3;
- const Color selection_color = alpha3;
+ const Color selection_color = alpha2;
const Color brace_mismatch_color = error_color;
const Color current_line_color = alpha1;
const Color line_length_guideline_color = warning_color;
diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp
index a9d72607b4..dfd35fdd96 100644
--- a/editor/filesystem_dock.cpp
+++ b/editor/filesystem_dock.cpp
@@ -458,9 +458,9 @@ void FileSystemDock::_update_files(bool p_keep_selection) {
if (path != "res://") {
if (use_thumbnails) {
- files->add_item("..", folder_thumbnail, true);
+ files->add_item("..", folder_thumbnail, false);
} else {
- files->add_item("..", get_icon("folder", "FileDialog"), true);
+ files->add_item("..", get_icon("folder", "FileDialog"), false);
}
String bd = path.get_base_dir();
@@ -567,9 +567,22 @@ void FileSystemDock::_update_files(bool p_keep_selection) {
}
void FileSystemDock::_select_file(int p_idx) {
-
- files->select(p_idx, true);
- _file_option(FILE_OPEN);
+ String path = files->get_item_metadata(p_idx);
+ if (path.ends_with("/")) {
+ if (path != "res://") {
+ path = path.substr(0, path.length() - 1);
+ }
+ this->path = path;
+ _update_files(false);
+ current_path->set_text(path);
+ _push_to_history();
+ } else {
+ if (ResourceLoader::get_resource_type(path) == "PackedScene") {
+ editor->open_request(path);
+ } else {
+ editor->load_resource(path);
+ }
+ }
}
void FileSystemDock::_go_to_tree() {
@@ -704,18 +717,19 @@ void FileSystemDock::_push_to_history() {
button_hist_next->set_disabled(history_pos + 1 == history.size());
}
-void FileSystemDock::_find_inside_move_files(EditorFileSystemDirectory *efsd, Vector<String> &files) {
+void FileSystemDock::_get_all_files_in_dir(EditorFileSystemDirectory *efsd, Vector<String> &files) const {
+ if (efsd == NULL)
+ return;
for (int i = 0; i < efsd->get_subdir_count(); i++) {
- _find_inside_move_files(efsd->get_subdir(i), files);
+ _get_all_files_in_dir(efsd->get_subdir(i), files);
}
for (int i = 0; i < efsd->get_file_count(); i++) {
files.push_back(efsd->get_file_path(i));
}
}
-void FileSystemDock::_find_remaps(EditorFileSystemDirectory *efsd, Map<String, String> &renames, List<String> &to_remaps) {
-
+void FileSystemDock::_find_remaps(EditorFileSystemDirectory *efsd, const Map<String, String> &renames, Vector<String> &to_remaps) const {
for (int i = 0; i < efsd->get_subdir_count(); i++) {
_find_remaps(efsd->get_subdir(i), renames, to_remaps);
}
@@ -730,199 +744,157 @@ void FileSystemDock::_find_remaps(EditorFileSystemDirectory *efsd, Map<String, S
}
}
-void FileSystemDock::_rename_operation(const String &p_to_path) {
+void FileSystemDock::_try_move_item(const FileOrFolder &p_item, const String &p_new_path, Map<String, String> &p_renames) 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 (move_files[0] == p_to_path) {
- EditorNode::get_singleton()->show_warning(TTR("Same source and destination files, doing nothing."));
+ if (new_path == old_path) {
return;
- }
- if (FileAccess::exists(p_to_path)) {
- EditorNode::get_singleton()->show_warning(TTR("Target file exists, can't overwrite. Delete first."));
+ } 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;
}
- Map<String, String> renames;
- renames[move_files[0]] = p_to_path;
-
- List<String> remap;
-
- _find_remaps(EditorFileSystem::get_singleton()->get_filesystem(), renames, remap);
- print_line("found files to remap: " + itos(remap.size()));
-
- //perform remaps
- for (List<String>::Element *E = remap.front(); E; E = E->next()) {
-
- Error err = ResourceLoader::rename_dependencies(E->get(), renames);
- print_line("remapping: " + E->get());
-
- if (err != OK) {
- EditorNode::get_singleton()->add_io_error("Can't rename deps for:\n" + E->get() + "\n");
- }
+ //Build a list of files which will have new paths as a result of this operation
+ Vector<String> changed_paths;
+ if (p_item.is_file) {
+ changed_paths.push_back(old_path);
+ } else {
+ _get_all_files_in_dir(EditorFileSystem::get_singleton()->get_filesystem_path(old_path), changed_paths);
}
- //finally, perform moves
-
DirAccess *da = DirAccess::create(DirAccess::ACCESS_RESOURCES);
+ print_line("Moving " + old_path + " -> " + new_path);
+ Error err = da->rename(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->rename(old_path + ".import", new_path + ".import");
+ if (err != OK) {
+ EditorNode::get_singleton()->add_io_error(TTR("Error moving:\n") + old_path + ".import\n");
+ }
+ }
- Error err = da->rename(move_files[0], p_to_path);
- print_line("moving file " + move_files[0] + " to " + p_to_path);
- if (err != OK) {
- EditorNode::get_singleton()->add_io_error("Error moving file:\n" + move_files[0] + "\n");
+ //Only treat as a changed dependency if it was successfully moved
+ for (int i = 0; i < changed_paths.size(); ++i) {
+ p_renames[changed_paths[i]] = changed_paths[i].replace_first(old_path, new_path);
+ print_line(" Remap: " + changed_paths[i] + " -> " + p_renames[changed_paths[i]]);
+ }
+ } else {
+ EditorNode::get_singleton()->add_io_error(TTR("Error moving:\n") + old_path + "\n");
}
-
- //rescan everything
memdelete(da);
- print_line("call rescan!");
- _rescan();
}
-void FileSystemDock::_move_operation(const String &p_to_path) {
-
- if (p_to_path == path) {
- EditorNode::get_singleton()->show_warning(TTR("Same source and destination paths, doing nothing."));
- return;
+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.
+ // 2) ResourceLoader can use the new paths without needing to call rescan.
+ Vector<String> remaps;
+ _find_remaps(EditorFileSystem::get_singleton()->get_filesystem(), p_renames, remaps);
+ for (int i = 0; i < remaps.size(); ++i) {
+ //Because we haven't called a rescan yet the found remap might still be an old path itself.
+ String file = p_renames.has(remaps[i]) ? p_renames[remaps[i]] : remaps[i];
+ print_line("Remapping dependencies for: " + file);
+ Error err = ResourceLoader::rename_dependencies(file, p_renames);
+ if (err != OK) {
+ EditorNode::get_singleton()->add_io_error(TTR("Unable to update dependencies:\n") + remaps[i] + "\n");
+ }
}
+}
- //find files inside dirs to be moved
-
- Vector<String> inside_files;
-
- for (int i = 0; i < move_dirs.size(); i++) {
- if (p_to_path.begins_with(move_dirs[i])) {
- EditorNode::get_singleton()->show_warning(TTR("Can't move directories to within themselves."));
- return;
- }
+void FileSystemDock::_make_dir_confirm() {
+ String dir_name = make_dir_dialog_text->get_text().strip_edges();
- EditorFileSystemDirectory *efsd = EditorFileSystem::get_singleton()->get_filesystem_path(move_dirs[i]);
- if (!efsd)
- continue;
- _find_inside_move_files(efsd, inside_files);
+ if (dir_name.length() == 0) {
+ EditorNode::get_singleton()->show_warning(TTR("No name provided"));
+ return;
+ } else if (dir_name.find("/") != -1 || dir_name.find("\\") != -1 || dir_name.find(":") != -1) {
+ EditorNode::get_singleton()->show_warning(TTR("Provided name contains invalid characters"));
+ return;
}
- //make list of remaps
- Map<String, String> renames;
- String repfrom = path == "res://" ? path : String(path + "/");
- String repto = p_to_path;
- if (!repto.ends_with("/")) {
- repto += "/";
+ print_line("Making folder " + dir_name + " in " + path);
+ DirAccess *da = DirAccess::create(DirAccess::ACCESS_RESOURCES);
+ Error err = da->change_dir(path);
+ if (err == OK) {
+ err = da->make_dir(dir_name);
}
+ memdelete(da);
- print_line("reprfrom: " + repfrom + " repto " + repto);
-
- for (int i = 0; i < move_files.size(); i++) {
- renames[move_files[i]] = move_files[i].replace_first(repfrom, repto);
- print_line("move file " + move_files[i] + " -> " + renames[move_files[i]]);
- }
- for (int i = 0; i < inside_files.size(); i++) {
- renames[inside_files[i]] = inside_files[i].replace_first(repfrom, repto);
- print_line("inside file " + inside_files[i] + " -> " + renames[inside_files[i]]);
+ if (err == OK) {
+ print_line("call rescan!");
+ _rescan();
+ } else {
+ EditorNode::get_singleton()->show_warning(TTR("Could not create folder."));
}
+}
- //make list of files that will be run the remapping
- List<String> remap;
-
- _find_remaps(EditorFileSystem::get_singleton()->get_filesystem(), renames, remap);
- print_line("found files to remap: " + itos(remap.size()));
-
- //perform remaps
- for (List<String>::Element *E = remap.front(); E; E = E->next()) {
-
- Error err = ResourceLoader::rename_dependencies(E->get(), renames);
- print_line("remapping: " + E->get());
+void FileSystemDock::_rename_operation_confirm() {
- if (err != OK) {
- EditorNode::get_singleton()->add_io_error(TTR("Can't rename deps for:\n") + E->get() + "\n");
- }
+ String new_name = rename_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;
}
- //finally, perform moves
+ String old_path = to_rename.path.ends_with("/") ? to_rename.path.substr(0, to_rename.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);
-
- for (int i = 0; i < move_files.size(); i++) {
-
- String to = move_files[i].replace_first(repfrom, repto);
- Error err = da->rename(move_files[i], to);
- print_line("moving file " + move_files[i] + " to " + to);
- if (err != OK) {
- EditorNode::get_singleton()->add_io_error(TTR("Error moving file:\n") + move_files[i] + "\n");
- }
- if (FileAccess::exists(move_files[i] + ".import")) { //move imported files too
- //@todo should remove the files in .import folder
- err = da->rename(move_files[i] + ".import", to + ".import");
- if (err != OK) {
- EditorNode::get_singleton()->add_io_error(TTR("Error moving file:\n") + move_files[i] + ".import\n");
- }
- }
+ 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);
- for (int i = 0; i < move_dirs.size(); i++) {
+ Map<String, String> renames;
+ _try_move_item(to_rename, new_path, renames);
+ _update_dependencies_after_move(renames);
- String mdir = move_dirs[i];
- if (mdir == "res://")
- continue;
+ //Rescan everything
+ print_line("call rescan!");
+ _rescan();
+}
- if (mdir.ends_with("/")) {
- mdir = mdir.substr(0, mdir.length() - 1);
- }
+void FileSystemDock::_move_operation_confirm(const String &p_to_path) {
- String to = p_to_path.plus_file(mdir.get_file());
- Error err = da->rename(mdir, to);
- print_line("moving dir " + mdir + " to " + to);
- if (err != OK) {
- EditorNode::get_singleton()->add_io_error(TTR("Error moving dir:\n") + move_dirs[i] + "\n");
- }
+ Map<String, String> renames;
+ for (int i = 0; i < to_move.size(); i++) {
+ String old_path = to_move[i].path.ends_with("/") ? to_move[i].path.substr(0, to_move[i].path.length() - 1) : to_move[i].path;
+ String new_path = p_to_path.plus_file(old_path.get_file());
+ _try_move_item(to_move[i], new_path, renames);
}
- memdelete(da);
- //rescan everything
+ _update_dependencies_after_move(renames);
print_line("call rescan!");
_rescan();
}
void FileSystemDock::_file_option(int p_option) {
-
switch (p_option) {
-
- case FILE_SHOW_IN_EXPLORER:
+ case FILE_SHOW_IN_EXPLORER: {
+ String dir = ProjectSettings::get_singleton()->globalize_path(this->path);
+ OS::get_singleton()->shell_open(String("file://") + dir);
+ } break;
case FILE_OPEN: {
- int idx = -1;
- for (int i = 0; i < files->get_item_count(); i++) {
- if (files->is_selected(i)) {
- idx = i;
- break;
- }
- }
-
- if (idx < 0)
- return;
-
- String path = files->get_item_metadata(idx);
- if (p_option == FILE_SHOW_IN_EXPLORER) {
- String dir = ProjectSettings::get_singleton()->globalize_path(path);
- dir = dir.substr(0, dir.find_last("/"));
- OS::get_singleton()->shell_open(String("file://") + dir);
- return;
- }
-
- if (path.ends_with("/")) {
- if (path != "res://") {
- path = path.substr(0, path.length() - 1);
- }
- this->path = path;
- _update_files(false);
- current_path->set_text(path);
- _push_to_history();
- } else {
-
- if (ResourceLoader::get_resource_type(path) == "PackedScene") {
-
- editor->open_request(path);
- } else {
-
- editor->load_resource(path);
- }
- }
+ int idx = files->get_current();
+ if (idx < 0 || idx >= files->get_item_count())
+ break;
+ _select_file(idx);
} break;
case FILE_INSTANCE: {
@@ -958,64 +930,59 @@ void FileSystemDock::_file_option(int p_option) {
owners_editor->show(path);
} break;
case FILE_MOVE: {
-
- move_dirs.clear();
- move_files.clear();
-
+ to_move.clear();
for (int i = 0; i < files->get_item_count(); i++) {
-
- String path = files->get_item_metadata(i);
if (!files->is_selected(i))
continue;
- if (files->get_item_text(i) == "..") {
- EditorNode::get_singleton()->show_warning(TTR("Can't operate on '..'"));
- return;
- }
-
- if (path.ends_with("/")) {
- move_dirs.push_back(path.substr(0, path.length() - 1));
- } else {
- move_files.push_back(path);
- }
+ String path = files->get_item_metadata(i);
+ to_move.push_back(FileOrFolder(path, !path.ends_with("/")));
}
-
- if (move_dirs.empty() && move_files.size() == 1) {
-
- rename_dialog->clear_filters();
- rename_dialog->add_filter("*." + move_files[0].get_extension());
- rename_dialog->set_mode(EditorFileDialog::MODE_SAVE_FILE);
- rename_dialog->set_current_path(move_files[0]);
- rename_dialog->popup_centered_ratio();
- rename_dialog->set_title(TTR("Pick New Name and Location For:") + " " + move_files[0].get_file());
-
- } else {
- //just move
+ if (to_move.size() > 0) {
move_dialog->popup_centered_ratio();
}
+ } break;
+ case FILE_RENAME: {
+ int idx = files->get_current();
+ if (idx < 0 || idx >= files->get_item_count())
+ break;
+ to_rename.path = files->get_item_metadata(idx);
+ to_rename.is_file = !to_rename.path.ends_with("/");
+ if (to_rename.is_file) {
+ String name = to_rename.path.get_file();
+ rename_dialog->set_title(TTR("Renaming file:") + " " + name);
+ rename_dialog_text->set_text(name);
+ rename_dialog_text->select(0, name.find_last("."));
+ } else {
+ String name = to_rename.path.substr(0, to_rename.path.length() - 1).get_file();
+ rename_dialog->set_title(TTR("Renaming folder:") + " " + name);
+ rename_dialog_text->set_text(name);
+ rename_dialog_text->select(0, name.length());
+ }
+ rename_dialog->popup_centered_minsize(Size2(250, 80) * EDSCALE);
+ rename_dialog_text->grab_focus();
} break;
case FILE_REMOVE: {
-
- Vector<String> torem;
+ Vector<String> remove_files;
+ Vector<String> remove_folders;
for (int i = 0; i < files->get_item_count(); i++) {
-
String path = files->get_item_metadata(i);
- if (!files->is_selected(i))
- continue;
- torem.push_back(path);
+ if (files->is_selected(i) && path != "res://") {
+ if (path.ends_with("/")) {
+ remove_folders.push_back(path);
+ } else {
+ remove_files.push_back(path);
+ }
+ }
}
- if (torem.empty()) {
- EditorNode::get_singleton()->show_warning(TTR("No files selected!"));
- break;
+ if (remove_files.size() + remove_folders.size() > 0) {
+ remove_dialog->show(remove_folders, remove_files);
+ //1) find if used
+ //2) warn
}
-
- remove_dialog->show(torem);
- //1) find if used
- //2) warn
-
} break;
case FILE_INFO: {
@@ -1052,15 +1019,20 @@ void FileSystemDock::_file_option(int p_option) {
}
*/
-
} break;
- case FILE_COPY_PATH:
-
+ case FILE_NEW_FOLDER: {
+ make_dir_dialog_text->set_text("new folder");
+ make_dir_dialog_text->select_all();
+ make_dir_dialog->popup_centered_minsize(Size2(250, 80) * EDSCALE);
+ make_dir_dialog_text->grab_focus();
+ } break;
+ case FILE_COPY_PATH: {
int idx = files->get_current();
if (idx < 0 || idx >= files->get_item_count())
break;
String path = files->get_item_metadata(idx);
OS::get_singleton()->set_clipboard(path);
+ } break;
}
}
@@ -1070,26 +1042,64 @@ void FileSystemDock::_folder_option(int p_option) {
TreeItem *child = item->get_children();
switch (p_option) {
-
- case FOLDER_EXPAND_ALL:
+ case FOLDER_EXPAND_ALL: {
item->set_collapsed(false);
while (child) {
child->set_collapsed(false);
child = child->get_next();
}
- break;
-
- case FOLDER_COLLAPSE_ALL:
+ } break;
+ case FOLDER_COLLAPSE_ALL: {
while (child) {
child->set_collapsed(true);
child = child->get_next();
}
- break;
- case FOLDER_SHOW_IN_EXPLORER:
+ } break;
+ case FOLDER_MOVE: {
+ to_move.clear();
+ String fpath = item->get_metadata(tree->get_selected_column());
+ if (fpath != "res://") {
+ fpath = fpath.ends_with("/") ? fpath.substr(0, fpath.length() - 1) : fpath;
+ to_move.push_back(FileOrFolder(fpath, false));
+ move_dialog->popup_centered_ratio();
+ }
+ } break;
+ case FOLDER_RENAME: {
+ to_rename.path = item->get_metadata(tree->get_selected_column());
+ to_rename.is_file = false;
+ if (to_rename.path != "res://") {
+ String name = to_rename.path.ends_with("/") ? to_rename.path.substr(0, to_rename.path.length() - 1).get_file() : to_rename.path.get_file();
+ rename_dialog->set_title(TTR("Renaming folder:") + " " + name);
+ rename_dialog_text->set_text(name);
+ rename_dialog_text->select(0, name.length());
+ rename_dialog->popup_centered_minsize(Size2(250, 80) * EDSCALE);
+ rename_dialog_text->grab_focus();
+ }
+ } break;
+ case FOLDER_REMOVE: {
+ Vector<String> remove_folders;
+ Vector<String> remove_files;
+ String path = item->get_metadata(tree->get_selected_column());
+ if (path != "res://") {
+ remove_folders.push_back(path);
+ remove_dialog->show(remove_folders, remove_files);
+ }
+ } break;
+ case FOLDER_NEW_FOLDER: {
+ make_dir_dialog_text->set_text("new folder");
+ make_dir_dialog_text->select_all();
+ make_dir_dialog->popup_centered_minsize(Size2(250, 80) * EDSCALE);
+ make_dir_dialog_text->grab_focus();
+ } break;
+ case FOLDER_COPY_PATH: {
+ String path = item->get_metadata(tree->get_selected_column());
+ OS::get_singleton()->set_clipboard(path);
+ } break;
+ case FOLDER_SHOW_IN_EXPLORER: {
String path = item->get_metadata(tree->get_selected_column());
String dir = ProjectSettings::get_singleton()->globalize_path(path);
OS::get_singleton()->shell_open(String("file://") + dir);
- return;
+ } break;
}
}
@@ -1128,9 +1138,20 @@ void FileSystemDock::_dir_rmb_pressed(const Vector2 &p_pos) {
folder_options->add_item(TTR("Expand all"), FOLDER_EXPAND_ALL);
folder_options->add_item(TTR("Collapse all"), FOLDER_COLLAPSE_ALL);
- folder_options->add_separator();
- folder_options->add_item(TTR("Show In File Manager"), FOLDER_SHOW_IN_EXPLORER);
-
+ TreeItem *item = tree->get_selected();
+ if (item) {
+ String fpath = item->get_metadata(tree->get_selected_column());
+ folder_options->add_separator();
+ folder_options->add_item(TTR("Copy Path"), FOLDER_COPY_PATH);
+ if (fpath != "res://") {
+ folder_options->add_item(TTR("Rename.."), FOLDER_RENAME);
+ folder_options->add_item(TTR("Move To.."), FOLDER_MOVE);
+ folder_options->add_item(TTR("Delete"), FOLDER_REMOVE);
+ }
+ folder_options->add_separator();
+ folder_options->add_item(TTR("New Folder.."), FOLDER_NEW_FOLDER);
+ folder_options->add_item(TTR("Show In File Manager"), FOLDER_SHOW_IN_EXPLORER);
+ }
folder_options->set_position(tree->get_global_position() + p_pos);
folder_options->popup();
}
@@ -1445,117 +1466,79 @@ void FileSystemDock::drop_data_fw(const Point2 &p_point, const Variant &p_data,
}
Vector<String> fnames = drag_data["files"];
- move_files.clear();
- move_dirs.clear();
-
+ to_move.clear();
for (int i = 0; i < fnames.size(); i++) {
- if (fnames[i].ends_with("/"))
- move_dirs.push_back(fnames[i]);
- else
- move_files.push_back(fnames[i]);
+ to_move.push_back(FileOrFolder(fnames[i], !fnames[i].ends_with("/")));
}
-
- _move_operation(to_dir);
+ _move_operation_confirm(to_dir);
}
}
}
void FileSystemDock::_files_list_rmb_select(int p_item, const Vector2 &p_pos) {
- Vector<String> filenames;
+ //Right clicking ".." should clear current selection
+ if (files->get_item_text(p_item) == "..") {
+ for (int i = 0; i < files->get_item_count(); i++) {
+ files->unselect(i);
+ }
+ }
- bool all_scenes = true;
- bool all_can_reimport = true;
- bool is_dir = false;
- Set<String> types;
+ Vector<String> filenames;
+ Vector<String> foldernames;
+ bool all_files = true;
+ bool all_files_scenes = true;
+ bool all_folders = true;
for (int i = 0; i < files->get_item_count(); i++) {
-
- if (!files->is_selected(i))
+ if (!files->is_selected(i)) {
continue;
-
- String path = files->get_item_metadata(i);
-
- if (files->get_item_text(i) == "..") {
- // no operate on ..
- return;
}
+ String path = files->get_item_metadata(i);
if (path.ends_with("/")) {
- is_dir = true;
- }
-
- int pos;
-
- EditorFileSystemDirectory *efsd = EditorFileSystem::get_singleton()->find_file(path, &pos);
-
- if (efsd) {
-
+ foldernames.push_back(path);
+ all_files = false;
} else {
- all_can_reimport = false;
+ filenames.push_back(path);
+ all_folders = false;
+ all_files_scenes &= (EditorFileSystem::get_singleton()->get_file_type(path) == "PackedScene");
}
-
- filenames.push_back(path);
- if (EditorFileSystem::get_singleton()->get_file_type(path) != "PackedScene")
- all_scenes = false;
}
- if (filenames.size() == 0)
- return;
-
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) {
+ file_options->add_item(TTR("Instance"), FILE_INSTANCE);
+ }
+ file_options->add_separator();
- file_options->add_item(TTR("Open"), FILE_OPEN);
- if (all_scenes) {
- file_options->add_item(TTR("Instance"), FILE_INSTANCE);
- }
-
- file_options->add_separator();
-
- if (filenames.size() == 1 && !is_dir) {
- file_options->add_item(TTR("Edit Dependencies.."), FILE_DEPENDENCIES);
- file_options->add_item(TTR("View Owners.."), FILE_OWNERS);
+ 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();
}
- if (!is_dir) {
- if (filenames.size() == 1) {
+ int num_items = filenames.size() + foldernames.size();
+ if (num_items >= 1) {
+ if (num_items == 1) {
file_options->add_item(TTR("Copy Path"), FILE_COPY_PATH);
- file_options->add_item(TTR("Rename or Move.."), FILE_MOVE);
- } else {
- file_options->add_item(TTR("Move To.."), FILE_MOVE);
+ file_options->add_item(TTR("Rename.."), FILE_RENAME);
}
+ file_options->add_item(TTR("Move To.."), FILE_MOVE);
+ file_options->add_item(TTR("Delete"), FILE_REMOVE);
+ file_options->add_separator();
}
- file_options->add_item(TTR("Delete"), FILE_REMOVE);
-
- //file_options->add_item(TTR("Info"),FILE_INFO);
-
- file_options->add_separator();
+ file_options->add_item(TTR("New Folder.."), FILE_NEW_FOLDER);
file_options->add_item(TTR("Show In File Manager"), FILE_SHOW_IN_EXPLORER);
- if (all_can_reimport && types.size() == 1) { //all can reimport and are of the same type
-
- /*
- bool valid=true;
- Ref<EditorImportPlugin> rimp = EditorImportExport::get_singleton()->get_import_plugin_by_name(types.front()->get());
- if (rimp.is_valid()) {
-
- if (filenames.size()>1 && !rimp->can_reimport_multiple_files()) {
- valid=false;
- }
- } else {
- valid=false;
- }
-
- if (valid) {
- file_options->add_separator();
- file_options->add_item(TTR("Re-Import.."),FILE_REIMPORT);
- }
- */
- }
-
file_options->set_position(files->get_global_position() + p_pos);
file_options->popup();
}
@@ -1640,8 +1623,9 @@ void FileSystemDock::_bind_methods() {
ClassDB::bind_method(D_METHOD("_dir_selected"), &FileSystemDock::_dir_selected);
ClassDB::bind_method(D_METHOD("_file_option"), &FileSystemDock::_file_option);
ClassDB::bind_method(D_METHOD("_folder_option"), &FileSystemDock::_folder_option);
- ClassDB::bind_method(D_METHOD("_move_operation"), &FileSystemDock::_move_operation);
- ClassDB::bind_method(D_METHOD("_rename_operation"), &FileSystemDock::_rename_operation);
+ 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("_search_changed"), &FileSystemDock::_search_changed);
@@ -1796,13 +1780,30 @@ FileSystemDock::FileSystemDock(EditorNode *p_editor) {
move_dialog = memnew(EditorDirDialog);
add_child(move_dialog);
- move_dialog->connect("dir_selected", this, "_move_operation");
+ move_dialog->connect("dir_selected", this, "_move_operation_confirm");
move_dialog->get_ok()->set_text(TTR("Move"));
- rename_dialog = memnew(EditorFileDialog);
- rename_dialog->set_mode(EditorFileDialog::MODE_SAVE_FILE);
- rename_dialog->connect("file_selected", this, "_rename_operation");
+ rename_dialog = memnew(ConfirmationDialog);
+ VBoxContainer *rename_dialog_vb = memnew(VBoxContainer);
+ rename_dialog->add_child(rename_dialog_vb);
+
+ rename_dialog_text = memnew(LineEdit);
+ rename_dialog_vb->add_margin_child(TTR("Name:"), rename_dialog_text);
+ rename_dialog->get_ok()->set_text(TTR("Rename"));
add_child(rename_dialog);
+ rename_dialog->register_text_enter(rename_dialog_text);
+ rename_dialog->connect("confirmed", this, "_rename_operation_confirm");
+
+ make_dir_dialog = memnew(ConfirmationDialog);
+ make_dir_dialog->set_title(TTR("Create Folder"));
+ VBoxContainer *make_folder_dialog_vb = memnew(VBoxContainer);
+ make_dir_dialog->add_child(make_folder_dialog_vb);
+
+ make_dir_dialog_text = memnew(LineEdit);
+ make_folder_dialog_vb->add_margin_child(TTR("Name:"), make_dir_dialog_text);
+ add_child(make_dir_dialog);
+ make_dir_dialog->register_text_enter(make_dir_dialog_text);
+ make_dir_dialog->connect("confirmed", this, "_make_dir_confirm");
updating_tree = false;
initialized = false;
diff --git a/editor/filesystem_dock.h b/editor/filesystem_dock.h
index aec049ba43..89b250e295 100644
--- a/editor/filesystem_dock.h
+++ b/editor/filesystem_dock.h
@@ -32,6 +32,7 @@
#include "scene/gui/box_container.h"
#include "scene/gui/control.h"
+#include "scene/gui/dialogs.h"
#include "scene/gui/item_list.h"
#include "scene/gui/label.h"
#include "scene/gui/menu_button.h"
@@ -67,9 +68,11 @@ private:
FILE_DEPENDENCIES,
FILE_OWNERS,
FILE_MOVE,
+ FILE_RENAME,
FILE_REMOVE,
FILE_REIMPORT,
FILE_INFO,
+ FILE_NEW_FOLDER,
FILE_SHOW_IN_EXPLORER,
FILE_COPY_PATH
};
@@ -77,7 +80,12 @@ private:
enum FolderMenu {
FOLDER_EXPAND_ALL,
FOLDER_COLLAPSE_ALL,
- FOLDER_SHOW_IN_EXPLORER
+ FOLDER_MOVE,
+ FOLDER_RENAME,
+ FOLDER_REMOVE,
+ FOLDER_NEW_FOLDER,
+ FOLDER_SHOW_IN_EXPLORER,
+ FOLDER_COPY_PATH
};
VBoxContainer *scanning_vb;
@@ -110,10 +118,23 @@ private:
DependencyRemoveDialog *remove_dialog;
EditorDirDialog *move_dialog;
- EditorFileDialog *rename_dialog;
+ ConfirmationDialog *rename_dialog;
+ LineEdit *rename_dialog_text;
+ ConfirmationDialog *make_dir_dialog;
+ LineEdit *make_dir_dialog_text;
- Vector<String> move_dirs;
- Vector<String> move_files;
+ class FileOrFolder {
+ public:
+ 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 to_rename;
+ Vector<FileOrFolder> to_move;
Vector<String> history;
int history_pos;
@@ -135,11 +156,15 @@ private:
bool _create_tree(TreeItem *p_parent, EditorFileSystemDirectory *p_dir);
void _thumbnail_done(const String &p_path, const Ref<Texture> &p_preview, const Variant &p_udata);
- void _find_inside_move_files(EditorFileSystemDirectory *efsd, Vector<String> &files);
- void _find_remaps(EditorFileSystemDirectory *efsd, Map<String, String> &renames, List<String> &to_remaps);
- void _rename_operation(const String &p_to_path);
- void _move_operation(const String &p_to_path);
+ 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 _update_dependencies_after_move(const Map<String, String> &p_renames) const;
+
+ void _make_dir_confirm();
+ void _rename_operation_confirm();
+ void _move_operation_confirm(const String &p_to_path);
void _file_option(int p_option);
void _folder_option(int p_option);
diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp
index d56756502d..84808cb876 100644
--- a/editor/plugins/script_editor_plugin.cpp
+++ b/editor/plugins/script_editor_plugin.cpp
@@ -1409,8 +1409,10 @@ void ScriptEditor::_update_members_overview() {
void ScriptEditor::_update_help_overview_visibility() {
int selected = tab_container->get_current_tab();
- if (selected < 0 || selected >= tab_container->get_child_count())
+ if (selected < 0 || selected >= tab_container->get_child_count()) {
+ help_overview->set_visible(false);
return;
+ }
Node *current = tab_container->get_child(tab_container->get_current_tab());
EditorHelp *se = Object::cast_to<EditorHelp>(current);
@@ -1427,6 +1429,7 @@ void ScriptEditor::_update_help_overview_visibility() {
}
void ScriptEditor::_update_help_overview() {
+ help_overview->clear();
int selected = tab_container->get_current_tab();
if (selected < 0 || selected >= tab_container->get_child_count())
@@ -1438,8 +1441,6 @@ void ScriptEditor::_update_help_overview() {
return;
}
- help_overview->clear();
-
Vector<Pair<String, int> > sections = se->get_sections();
for (int i = 0; i < sections.size(); i++) {
help_overview->add_item(sections[i].first);
@@ -1447,9 +1448,6 @@ void ScriptEditor::_update_help_overview() {
}
}
-void _help_overview_selected(int p_idx) {
-}
-
void ScriptEditor::_update_script_colors() {
bool script_temperature_enabled = EditorSettings::get_singleton()->get("text_editor/open_scripts/script_temperature_enabled");
@@ -1595,6 +1593,8 @@ void ScriptEditor::_update_script_names() {
_update_members_overview();
_update_help_overview();
+ _update_members_overview_visibility();
+ _update_help_overview_visibility();
_update_script_colors();
}
diff --git a/editor/plugins/spatial_editor_plugin.cpp b/editor/plugins/spatial_editor_plugin.cpp
index 32973db6ec..d216e47c02 100644
--- a/editor/plugins/spatial_editor_plugin.cpp
+++ b/editor/plugins/spatial_editor_plugin.cpp
@@ -63,7 +63,8 @@
#define ZOOM_MULTIPLIER 1.08
#define ZOOM_INDICATOR_DELAY_S 1.5
-#define FREELOOK_MIN_SPEED 0.1
+#define FREELOOK_MIN_SPEED 0.01
+#define FREELOOK_SPEED_MULTIPLIER 1.08
#define MIN_Z 0.01
#define MAX_Z 10000
@@ -75,34 +76,66 @@ void SpatialEditorViewport::_update_camera(float p_interp_delta) {
bool is_orthogonal = camera->get_projection() == Camera::PROJECTION_ORTHOGONAL;
- //when not being manipulated, move softly
- float free_orbit_inertia = EDITOR_GET("editors/3d/navigation_feel/orbit_inertia");
- float free_translation_inertia = EDITOR_GET("editors/3d/navigation_feel/translation_inertia");
- //when being manipulated, move more quickly
- float manip_orbit_inertia = EDITOR_GET("editors/3d/navigation_feel/manipulation_orbit_inertia");
- float manip_translation_inertia = EDITOR_GET("editors/3d/navigation_feel/manipulation_translation_inertia");
+ Cursor old_camera_cursor = camera_cursor;
+ camera_cursor = cursor;
- float zoom_inertia = EDITOR_GET("editors/3d/navigation_feel/zoom_inertia");
+ if (p_interp_delta > 0) {
- //determine if being manipulated
- bool manipulated = (Input::get_singleton()->get_mouse_button_mask() & (2 | 4)) || Input::get_singleton()->is_key_pressed(KEY_SHIFT) || Input::get_singleton()->is_key_pressed(KEY_ALT) || Input::get_singleton()->is_key_pressed(KEY_CONTROL);
+ //-------
+ // Perform smoothing
- float orbit_inertia = MAX(0.00001, manipulated ? manip_orbit_inertia : free_orbit_inertia);
- float translation_inertia = MAX(0.0001, manipulated ? manip_translation_inertia : free_translation_inertia);
+ if (is_freelook_active()) {
- Cursor old_camera_cursor = camera_cursor;
- camera_cursor = cursor;
+ // Higher inertia should increase "lag" (lerp with factor between 0 and 1)
+ // Inertia of zero should produce instant movement (lerp with factor of 1) in this case it returns a really high value and gets clamped to 1.
+ real_t inertia = EDITOR_GET("editors/3d/freelook/freelook_inertia");
+ inertia = MAX(0.001, inertia);
+ real_t factor = (1.0 / inertia) * p_interp_delta;
+
+ // We interpolate a different point here, because in freelook mode the focus point (cursor.pos) orbits around eye_pos
+ camera_cursor.eye_pos = old_camera_cursor.eye_pos.linear_interpolate(cursor.eye_pos, CLAMP(factor, 0, 1));
+ //camera_cursor.pos = camera_cursor.eye_pos + (cursor.pos - cursor.eye_pos);
+
+ float orbit_inertia = EDITOR_GET("editors/3d/navigation_feel/orbit_inertia");
+ orbit_inertia = MAX(0.0001, orbit_inertia);
+ camera_cursor.x_rot = Math::lerp(old_camera_cursor.x_rot, cursor.x_rot, MIN(1.f, p_interp_delta * (1 / orbit_inertia)));
+ camera_cursor.y_rot = Math::lerp(old_camera_cursor.y_rot, cursor.y_rot, MIN(1.f, p_interp_delta * (1 / orbit_inertia)));
+
+ Vector3 forward = to_camera_transform(camera_cursor).basis.xform(Vector3(0, 0, -1));
+ camera_cursor.pos = camera_cursor.eye_pos + forward * camera_cursor.distance;
+
+ } else {
+
+ //when not being manipulated, move softly
+ float free_orbit_inertia = EDITOR_GET("editors/3d/navigation_feel/orbit_inertia");
+ float free_translation_inertia = EDITOR_GET("editors/3d/navigation_feel/translation_inertia");
+ //when being manipulated, move more quickly
+ float manip_orbit_inertia = EDITOR_GET("editors/3d/navigation_feel/manipulation_orbit_inertia");
+ float manip_translation_inertia = EDITOR_GET("editors/3d/navigation_feel/manipulation_translation_inertia");
- camera_cursor.x_rot = Math::lerp(old_camera_cursor.x_rot, cursor.x_rot, MIN(1.f, p_interp_delta * (1 / orbit_inertia)));
- camera_cursor.y_rot = Math::lerp(old_camera_cursor.y_rot, cursor.y_rot, MIN(1.f, p_interp_delta * (1 / orbit_inertia)));
+ float zoom_inertia = EDITOR_GET("editors/3d/navigation_feel/zoom_inertia");
- camera_cursor.pos = old_camera_cursor.pos.linear_interpolate(cursor.pos, MIN(1.f, p_interp_delta * (1 / translation_inertia)));
- camera_cursor.distance = Math::lerp(old_camera_cursor.distance, cursor.distance, MIN(1.f, p_interp_delta * (1 / zoom_inertia)));
+ //determine if being manipulated
+ bool manipulated = Input::get_singleton()->get_mouse_button_mask() & (2 | 4);
+ manipulated |= Input::get_singleton()->is_key_pressed(KEY_SHIFT);
+ manipulated |= Input::get_singleton()->is_key_pressed(KEY_ALT);
+ manipulated |= Input::get_singleton()->is_key_pressed(KEY_CONTROL);
- if (p_interp_delta == 0 || is_freelook_active()) {
- camera_cursor = cursor;
+ float orbit_inertia = MAX(0.00001, manipulated ? manip_orbit_inertia : free_orbit_inertia);
+ float translation_inertia = MAX(0.0001, manipulated ? manip_translation_inertia : free_translation_inertia);
+ zoom_inertia = MAX(0.0001, zoom_inertia);
+
+ camera_cursor.x_rot = Math::lerp(old_camera_cursor.x_rot, cursor.x_rot, MIN(1.f, p_interp_delta * (1 / orbit_inertia)));
+ camera_cursor.y_rot = Math::lerp(old_camera_cursor.y_rot, cursor.y_rot, MIN(1.f, p_interp_delta * (1 / orbit_inertia)));
+
+ camera_cursor.pos = old_camera_cursor.pos.linear_interpolate(cursor.pos, MIN(1.f, p_interp_delta * (1 / translation_inertia)));
+ camera_cursor.distance = Math::lerp(old_camera_cursor.distance, cursor.distance, MIN(1.f, p_interp_delta * (1 / zoom_inertia)));
+ }
}
+ //-------
+ // Apply camera transform
+
float tolerance = 0.001;
bool equal = true;
if (Math::abs(old_camera_cursor.x_rot - camera_cursor.x_rot) > tolerance || Math::abs(old_camera_cursor.y_rot - camera_cursor.y_rot) > tolerance) {
@@ -845,11 +878,17 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
switch (b->get_button_index()) {
case BUTTON_WHEEL_UP: {
- scale_cursor_distance(is_freelook_active() ? zoom_factor : 1.0 / zoom_factor);
+ if (is_freelook_active())
+ scale_freelook_speed(zoom_factor);
+ else
+ scale_cursor_distance(1.0 / zoom_factor);
} break;
case BUTTON_WHEEL_DOWN: {
- scale_cursor_distance(is_freelook_active() ? 1.0 / zoom_factor : zoom_factor);
+ if (is_freelook_active())
+ scale_freelook_speed(1.0 / zoom_factor);
+ else
+ scale_cursor_distance(zoom_factor);
} break;
case BUTTON_RIGHT: {
@@ -901,10 +940,10 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
if (b->is_pressed()) {
int mod = _get_key_modifier(b);
if (mod == _get_key_modifier_setting("editors/3d/freelook/freelook_activation_modifier")) {
- freelook_active = true;
+ set_freelook_active(true);
}
} else {
- freelook_active = false;
+ set_freelook_active(false);
}
if (freelook_active && !surface->has_focus()) {
@@ -1645,6 +1684,9 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
real_t degrees_per_pixel = EditorSettings::get_singleton()->get("editors/3d/navigation_feel/orbit_sensitivity");
real_t radians_per_pixel = Math::deg2rad(degrees_per_pixel);
+ // Note: do NOT assume the camera has the "current" transform, because it is interpolated and may have "lag".
+ Transform prev_camera_transform = to_camera_transform(cursor);
+
cursor.x_rot += relative.y * radians_per_pixel;
cursor.y_rot += relative.x * radians_per_pixel;
if (cursor.x_rot > Math_PI / 2.0)
@@ -1652,12 +1694,12 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
if (cursor.x_rot < -Math_PI / 2.0)
cursor.x_rot = -Math_PI / 2.0;
- // Look is like Orbit, except the cursor translates, not the camera
+ // Look is like the opposite of Orbit: the focus point rotates around the camera
Transform camera_transform = to_camera_transform(cursor);
Vector3 pos = camera_transform.xform(Vector3(0, 0, 0));
- Vector3 diff = camera->get_translation() - pos;
+ Vector3 prev_pos = prev_camera_transform.xform(Vector3(0, 0, 0));
+ Vector3 diff = prev_pos - pos;
cursor.pos += diff;
- freelook_target_position += diff;
name = "";
_update_name();
@@ -1755,23 +1797,57 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
}
}
+void SpatialEditorViewport::set_freelook_active(bool active_now) {
+
+ if (!freelook_active && active_now) {
+ // Sync camera cursor to cursor to "cut" interpolation jumps due to changing referential
+ cursor = camera_cursor;
+
+ // Make sure eye_pos is synced, because freelook referential is eye pos rather than orbit pos
+ Vector3 forward = to_camera_transform(cursor).basis.xform(Vector3(0, 0, -1));
+ cursor.eye_pos = cursor.pos - cursor.distance * forward;
+ // Also sync the camera cursor, otherwise switching to freelook will be trippy if inertia is active
+ camera_cursor.eye_pos = cursor.eye_pos;
+
+ if (EditorSettings::get_singleton()->get("editors/3d/freelook/freelook_speed_zoom_link")) {
+ // Re-adjust freelook speed from the current zoom level
+ real_t base_speed = EditorSettings::get_singleton()->get("editors/3d/freelook/freelook_base_speed");
+ freelook_speed = base_speed * cursor.distance;
+ }
+
+ } else if (freelook_active && !active_now) {
+ // Sync camera cursor to cursor to "cut" interpolation jumps due to changing referential
+ cursor = camera_cursor;
+ }
+
+ freelook_active = active_now;
+}
+
void SpatialEditorViewport::scale_cursor_distance(real_t scale) {
// Prevents zero distance which would short-circuit any scaling
if (cursor.distance < ZOOM_MIN_DISTANCE)
cursor.distance = ZOOM_MIN_DISTANCE;
- real_t prev_distance = cursor.distance;
cursor.distance *= scale;
if (cursor.distance < ZOOM_MIN_DISTANCE)
cursor.distance = ZOOM_MIN_DISTANCE;
- if (is_freelook_active()) {
- // In freelook mode, cursor reference is reversed so it needs to be adjusted
- Vector3 forward = camera->get_transform().basis.xform(Vector3(0, 0, -1));
- cursor.pos += (cursor.distance - prev_distance) * forward;
- }
+ zoom_indicator_delay = ZOOM_INDICATOR_DELAY_S;
+ surface->update();
+}
+
+void SpatialEditorViewport::scale_freelook_speed(real_t scale) {
+
+ // Prevents zero distance which would short-circuit any scaling
+ if (freelook_speed < FREELOOK_MIN_SPEED)
+ freelook_speed = FREELOOK_MIN_SPEED;
+
+ freelook_speed *= scale;
+
+ if (freelook_speed < FREELOOK_MIN_SPEED)
+ freelook_speed = FREELOOK_MIN_SPEED;
zoom_indicator_delay = ZOOM_INDICATOR_DELAY_S;
surface->update();
@@ -1790,7 +1866,6 @@ Point2i SpatialEditorViewport::_get_warped_mouse_motion(const Ref<InputEventMous
void SpatialEditorViewport::_update_freelook(real_t delta) {
if (!is_freelook_active()) {
- freelook_target_position = cursor.pos;
return;
}
@@ -1833,21 +1908,15 @@ void SpatialEditorViewport::_update_freelook(real_t delta) {
speed_modifier = true;
}
- real_t inertia = EDITOR_DEF("editors/3d/freelook/freelook_inertia", 0.1);
- inertia = MAX(0, inertia);
- const real_t base_speed = EDITOR_DEF("editors/3d/freelook/freelook_base_speed", 0.5);
- const real_t modifier_speed_factor = EDITOR_DEF("editors/3d/freelook/freelook_modifier_speed_factor", 3);
-
- real_t speed = base_speed * cursor.distance;
- if (speed_modifier)
+ real_t speed = freelook_speed;
+ if (speed_modifier) {
+ real_t modifier_speed_factor = EditorSettings::get_singleton()->get("editors/3d/freelook/freelook_modifier_speed_factor");
speed *= modifier_speed_factor;
+ }
- // Higher inertia should increase "lag" (lerp with factor between 0 and 1)
- // Inertia of zero should produce instant movement (lerp with factor of 1) in this case it returns a really high value and gets clamped to 1.
-
- freelook_target_position += direction * speed;
- real_t factor = (1.0 / (inertia + 0.001)) * delta;
- cursor.pos = cursor.pos.linear_interpolate(freelook_target_position, CLAMP(factor, 0, 1));
+ Vector3 motion = direction * speed * delta;
+ cursor.pos += motion;
+ cursor.eye_pos += motion;
}
void SpatialEditorViewport::set_message(String p_message, float p_time) {
@@ -1886,7 +1955,7 @@ void SpatialEditorViewport::_notification(int p_what) {
}
*/
- real_t delta = get_tree()->get_idle_process_time();
+ real_t delta = get_process_delta_time();
if (zoom_indicator_delay > 0) {
zoom_indicator_delay -= delta;
@@ -1897,7 +1966,7 @@ void SpatialEditorViewport::_notification(int p_what) {
_update_freelook(delta);
- _update_camera(get_process_delta_time());
+ _update_camera(delta);
Map<Node *, Object *> &selection = editor_selection->get_selection();
@@ -2576,6 +2645,7 @@ void SpatialEditorViewport::reset() {
cursor.y_rot = 0.5;
cursor.distance = 4;
cursor.region_select = false;
+ cursor.pos = Vector3();
_update_name();
}
@@ -3036,6 +3106,7 @@ SpatialEditorViewport::SpatialEditorViewport(SpatialEditor *p_spatial_editor, Ed
accept = NULL;
freelook_active = false;
+ freelook_speed = EditorSettings::get_singleton()->get("editors/3d/freelook/freelook_base_speed");
selection_menu = memnew(PopupMenu);
add_child(selection_menu);
diff --git a/editor/plugins/spatial_editor_plugin.h b/editor/plugins/spatial_editor_plugin.h
index 4f4c540048..a9dd1f1327 100644
--- a/editor/plugins/spatial_editor_plugin.h
+++ b/editor/plugins/spatial_editor_plugin.h
@@ -131,7 +131,7 @@ private:
float gizmo_scale;
bool freelook_active;
- Vector3 freelook_target_position;
+ real_t freelook_speed;
PanelContainer *info;
Label *info_label;
@@ -231,6 +231,7 @@ private:
Vector3 pos;
float x_rot, y_rot, distance;
+ Vector3 eye_pos; // Used in freelook mode
bool region_select;
Point2 region_begin, region_end;
@@ -239,10 +240,17 @@ private:
distance = 4;
region_select = false;
}
- } cursor, camera_cursor;
+ };
+ // Viewport camera supports movement smoothing,
+ // so one cursor is the real cursor, while the other can be an interpolated version.
+ Cursor cursor; // Immediate cursor
+ Cursor camera_cursor; // That one may be interpolated (don't modify this one except for smoothing purposes)
void scale_cursor_distance(real_t scale);
+ void set_freelook_active(bool active_now);
+ void scale_freelook_speed(real_t scale);
+
real_t zoom_indicator_delay;
RID move_gizmo_instance[3], move_plane_gizmo_instance[3], rotate_gizmo_instance[3], scale_gizmo_instance[3];
diff --git a/editor/project_settings_editor.cpp b/editor/project_settings_editor.cpp
index 91ef9e36f3..723d7b14ff 100644
--- a/editor/project_settings_editor.cpp
+++ b/editor/project_settings_editor.cpp
@@ -1189,7 +1189,7 @@ void ProjectSettingsEditor::_translation_res_option_delete(Object *p_item, int p
ERR_FAIL_COND(!remaps.has(key));
PoolStringArray r = remaps[key];
- ERR_FAIL_INDEX(idx, remaps.size());
+ ERR_FAIL_INDEX(idx, r.size());
r.remove(idx);
remaps[key] = r;
diff --git a/editor/property_editor.cpp b/editor/property_editor.cpp
index 658f67d6a4..b7cc9347f2 100644
--- a/editor/property_editor.cpp
+++ b/editor/property_editor.cpp
@@ -376,7 +376,7 @@ bool CustomPropertyEditor::edit(Object *p_owner, const String &p_name, Variant::
if (hint == PROPERTY_HINT_RANGE) {
int c = hint_text.get_slice_count(",");
- float min = 0, max = 100, step = 1;
+ float min = 0, max = 100, step = type == Variant::REAL ? .01 : 1;
if (c >= 1) {
if (!hint_text.get_slice(",", 0).empty())
@@ -3032,7 +3032,7 @@ void PropertyEditor::update_tree() {
if (p.hint == PROPERTY_HINT_SPRITE_FRAME || p.hint == PROPERTY_HINT_RANGE || p.hint == PROPERTY_HINT_EXP_RANGE) {
int c = p.hint_string.get_slice_count(",");
- float min = 0, max = 100, step = 1;
+ float min = 0, max = 100, step = p.type == Variant::REAL ? .01 : 1;
if (c >= 1) {
min = p.hint_string.get_slice(",", 0).to_double();