summaryrefslogtreecommitdiff
path: root/editor
diff options
context:
space:
mode:
Diffstat (limited to 'editor')
-rw-r--r--editor/animation_bezier_editor.cpp4
-rw-r--r--editor/animation_track_editor.cpp4
-rw-r--r--editor/code_editor.cpp36
-rw-r--r--editor/create_dialog.cpp754
-rw-r--r--editor/create_dialog.h65
-rw-r--r--editor/debugger/editor_performance_profiler.cpp394
-rw-r--r--editor/debugger/editor_performance_profiler.h90
-rw-r--r--editor/debugger/script_editor_debugger.cpp204
-rw-r--r--editor/debugger/script_editor_debugger.h12
-rw-r--r--editor/editor_asset_installer.cpp2
-rw-r--r--editor/editor_autoload_settings.cpp8
-rw-r--r--editor/editor_feature_profile.cpp2
-rw-r--r--editor/editor_file_dialog.cpp6
-rw-r--r--editor/editor_file_system.cpp8
-rw-r--r--editor/editor_folding.cpp2
-rw-r--r--editor/editor_fonts.cpp2
-rw-r--r--editor/editor_help_search.cpp19
-rw-r--r--editor/editor_inspector.cpp120
-rw-r--r--editor/editor_inspector.h1
-rw-r--r--editor/editor_log.h2
-rw-r--r--editor/editor_node.cpp233
-rw-r--r--editor/editor_node.h8
-rw-r--r--editor/editor_plugin.cpp40
-rw-r--r--editor/editor_plugin.h11
-rw-r--r--editor/editor_plugin_settings.cpp2
-rw-r--r--editor/editor_properties.cpp48
-rw-r--r--editor/editor_resource_preview.cpp6
-rw-r--r--editor/editor_run.cpp42
-rw-r--r--editor/editor_run.h2
-rw-r--r--editor/editor_spin_slider.cpp4
-rw-r--r--editor/editor_themes.cpp9
-rw-r--r--editor/editor_translation_parser.cpp163
-rw-r--r--editor/editor_translation_parser.h72
-rw-r--r--editor/filesystem_dock.cpp14
-rw-r--r--editor/icons/InterpolatedCamera.svg1
-rw-r--r--editor/icons/ToolButton.svg1
-rw-r--r--editor/import/resource_importer_scene.cpp9
-rw-r--r--editor/plugins/abstract_polygon_2d_editor.cpp2
-rw-r--r--editor/plugins/animation_player_editor_plugin.cpp30
-rw-r--r--editor/plugins/animation_tree_editor_plugin.cpp2
-rw-r--r--editor/plugins/animation_tree_editor_plugin.h2
-rw-r--r--editor/plugins/canvas_item_editor_plugin.cpp17
-rw-r--r--editor/plugins/collision_shape_2d_editor_plugin.cpp2
-rw-r--r--editor/plugins/node_3d_editor_plugin.cpp66
-rw-r--r--editor/plugins/node_3d_editor_plugin.h4
-rw-r--r--editor/plugins/packed_scene_translation_parser_plugin.cpp114
-rw-r--r--editor/plugins/packed_scene_translation_parser_plugin.h (renamed from editor/pane_drag.cpp)54
-rw-r--r--editor/plugins/polygon_2d_editor_plugin.cpp51
-rw-r--r--editor/plugins/script_editor_plugin.cpp19
-rw-r--r--editor/plugins/script_text_editor.cpp33
-rw-r--r--editor/plugins/script_text_editor.h1
-rw-r--r--editor/plugins/shader_editor_plugin.cpp2
-rw-r--r--editor/plugins/shader_file_editor_plugin.cpp2
-rw-r--r--editor/plugins/texture_region_editor_plugin.cpp2
-rw-r--r--editor/plugins/tile_map_editor_plugin.cpp209
-rw-r--r--editor/plugins/tile_map_editor_plugin.h3
-rw-r--r--editor/plugins/visual_shader_editor_plugin.cpp1
-rw-r--r--editor/pot_generator.cpp166
-rw-r--r--editor/pot_generator.h (renamed from editor/pane_drag.h)31
-rw-r--r--editor/project_manager.cpp9
-rw-r--r--editor/project_settings_editor.cpp128
-rw-r--r--editor/project_settings_editor.h11
-rw-r--r--editor/property_editor.cpp8
-rw-r--r--editor/quick_open.cpp137
-rw-r--r--editor/quick_open.h7
-rw-r--r--editor/scene_tree_dock.cpp52
-rw-r--r--editor/scene_tree_editor.cpp6
-rw-r--r--editor/script_create_dialog.cpp4
-rw-r--r--editor/translations/af.po5
-rw-r--r--editor/translations/ar.po60
-rw-r--r--editor/translations/bg.po4
-rw-r--r--editor/translations/bn.po5
-rw-r--r--editor/translations/ca.po5
-rw-r--r--editor/translations/cs.po14
-rw-r--r--editor/translations/da.po18
-rw-r--r--editor/translations/de.po8
-rw-r--r--editor/translations/editor.pot4
-rw-r--r--editor/translations/el.po29
-rw-r--r--editor/translations/eo.po5
-rw-r--r--editor/translations/es.po53
-rw-r--r--editor/translations/es_AR.po8
-rw-r--r--editor/translations/et.po4
-rw-r--r--editor/translations/eu.po4
-rw-r--r--editor/translations/fa.po5
-rw-r--r--editor/translations/fi.po8
-rw-r--r--editor/translations/fil.po4
-rw-r--r--editor/translations/fr.po18
-rw-r--r--editor/translations/ga.po4
-rw-r--r--editor/translations/he.po4
-rw-r--r--editor/translations/hi.po5
-rw-r--r--editor/translations/hr.po5
-rw-r--r--editor/translations/hu.po5
-rw-r--r--editor/translations/id.po5
-rw-r--r--editor/translations/is.po4
-rw-r--r--editor/translations/it.po64
-rw-r--r--editor/translations/ja.po47
-rw-r--r--editor/translations/ka.po5
-rw-r--r--editor/translations/ko.po71
-rw-r--r--editor/translations/lt.po5
-rw-r--r--editor/translations/lv.po5
-rw-r--r--editor/translations/mi.po4
-rw-r--r--editor/translations/ml.po4
-rw-r--r--editor/translations/mr.po4
-rw-r--r--editor/translations/ms.po4
-rw-r--r--editor/translations/nb.po14
-rw-r--r--editor/translations/nl.po19
-rw-r--r--editor/translations/or.po4
-rw-r--r--editor/translations/pl.po117
-rw-r--r--editor/translations/pr.po22
-rw-r--r--editor/translations/pt_BR.po215
-rw-r--r--editor/translations/pt_PT.po5
-rw-r--r--editor/translations/ro.po5
-rw-r--r--editor/translations/ru.po182
-rw-r--r--editor/translations/si.po4
-rw-r--r--editor/translations/sk.po5
-rw-r--r--editor/translations/sl.po5
-rw-r--r--editor/translations/sq.po4
-rw-r--r--editor/translations/sr_Cyrl.po5
-rw-r--r--editor/translations/sr_Latn.po4
-rw-r--r--editor/translations/sv.po5
-rw-r--r--editor/translations/ta.po4
-rw-r--r--editor/translations/te.po4
-rw-r--r--editor/translations/th.po5
-rw-r--r--editor/translations/tr.po5
-rw-r--r--editor/translations/uk.po10
-rw-r--r--editor/translations/ur_PK.po4
-rw-r--r--editor/translations/vi.po5
-rw-r--r--editor/translations/zh_CN.po85
-rw-r--r--editor/translations/zh_HK.po4
-rw-r--r--editor/translations/zh_TW.po11
130 files changed, 3258 insertions, 1575 deletions
diff --git a/editor/animation_bezier_editor.cpp b/editor/animation_bezier_editor.cpp
index f880ece88b..17b03fd479 100644
--- a/editor/animation_bezier_editor.cpp
+++ b/editor/animation_bezier_editor.cpp
@@ -31,6 +31,7 @@
#include "animation_bezier_editor.h"
#include "editor/editor_node.h"
+#include "editor_scale.h"
float AnimationBezierTrackEdit::_bezier_h_to_pixel(float p_h) {
float h = p_h;
@@ -539,7 +540,7 @@ void AnimationBezierTrackEdit::_play_position_draw() {
if (px >= timeline->get_name_limit() && px < (get_size().width - timeline->get_buttons_width())) {
Color color = get_theme_color("accent_color", "Editor");
- play_position->draw_line(Point2(px, 0), Point2(px, h), color);
+ play_position->draw_line(Point2(px, 0), Point2(px, h), color, Math::round(2 * EDSCALE));
}
}
@@ -558,6 +559,7 @@ void AnimationBezierTrackEdit::set_root(Node *p_root) {
void AnimationBezierTrackEdit::_zoom_changed() {
update();
+ play_position->update();
}
String AnimationBezierTrackEdit::get_tooltip(const Point2 &p_pos) const {
diff --git a/editor/animation_track_editor.cpp b/editor/animation_track_editor.cpp
index f36e84dab6..1d6770a32e 100644
--- a/editor/animation_track_editor.cpp
+++ b/editor/animation_track_editor.cpp
@@ -3557,7 +3557,7 @@ void AnimationTrackEditor::insert_node_value_key(Node *p_node, const String &p_p
if (track_path == np) {
value = p_value; //all good
} else {
- int sep = track_path.find_last(":");
+ int sep = track_path.rfind(":");
if (sep != -1) {
String base_path = track_path.substr(0, sep);
if (base_path == np) {
@@ -3656,7 +3656,7 @@ void AnimationTrackEditor::insert_value_key(const String &p_property, const Vari
value = p_value; //all good
} else {
String tpath = animation->track_get_path(i);
- int index = tpath.find_last(":");
+ int index = tpath.rfind(":");
if (NodePath(tpath.substr(0, index + 1)) == np) {
String subindex = tpath.substr(index + 1, tpath.length() - index);
value = p_value.get(subindex);
diff --git a/editor/code_editor.cpp b/editor/code_editor.cpp
index c5df947d64..70747b4956 100644
--- a/editor/code_editor.cpp
+++ b/editor/code_editor.cpp
@@ -108,22 +108,25 @@ void FindReplaceBar::_notification(int p_what) {
void FindReplaceBar::_unhandled_input(const Ref<InputEvent> &p_event) {
Ref<InputEventKey> k = p_event;
- if (k.is_valid()) {
- if (k->is_pressed() && (text_edit->has_focus() || vbc_lineedit->is_a_parent_of(get_focus_owner()))) {
- bool accepted = true;
-
- switch (k->get_keycode()) {
- case KEY_ESCAPE: {
- _hide_bar();
- } break;
- default: {
- accepted = false;
- } break;
- }
+ if (!k.is_valid() || !k->is_pressed()) {
+ return;
+ }
- if (accepted) {
- accept_event();
- }
+ Control *focus_owner = get_focus_owner();
+ if (text_edit->has_focus() || (focus_owner && vbc_lineedit->is_a_parent_of(focus_owner))) {
+ bool accepted = true;
+
+ switch (k->get_keycode()) {
+ case KEY_ESCAPE: {
+ _hide_bar();
+ } break;
+ default: {
+ accepted = false;
+ } break;
+ }
+
+ if (accepted) {
+ accept_event();
}
}
}
@@ -1541,7 +1544,7 @@ void CodeTextEditor::_toggle_scripts_pressed() {
void CodeTextEditor::_error_pressed(const Ref<InputEvent> &p_event) {
Ref<InputEventMouseButton> mb = p_event;
if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
- emit_signal("error_pressed");
+ goto_error();
}
}
@@ -1651,7 +1654,6 @@ void CodeTextEditor::_bind_methods() {
ADD_SIGNAL(MethodInfo("validate_script"));
ADD_SIGNAL(MethodInfo("load_theme_settings"));
ADD_SIGNAL(MethodInfo("show_warnings_panel"));
- ADD_SIGNAL(MethodInfo("error_pressed"));
}
void CodeTextEditor::set_code_complete_func(CodeTextEditorCodeCompleteFunc p_code_complete_func, void *p_ud) {
diff --git a/editor/create_dialog.cpp b/editor/create_dialog.cpp
index 310de9dd90..99a2a73a75 100644
--- a/editor/create_dialog.cpp
+++ b/editor/create_dialog.cpp
@@ -32,60 +32,38 @@
#include "core/class_db.h"
#include "core/os/keyboard.h"
-#include "core/print_string.h"
#include "editor_feature_profile.h"
-#include "editor_help.h"
#include "editor_node.h"
#include "editor_scale.h"
#include "editor_settings.h"
-#include "scene/gui/box_container.h"
void CreateDialog::popup_create(bool p_dont_clear, bool p_replace_mode, const String &p_select_type) {
- type_list.clear();
- ClassDB::get_class_list(&type_list);
- ScriptServer::get_global_class_list(&type_list);
- type_list.sort_custom<StringName::AlphCompare>();
-
- recent->clear();
-
- FileAccess *f = FileAccess::open(EditorSettings::get_singleton()->get_project_settings_dir().plus_file("create_recent." + base_type), FileAccess::READ);
+ _fill_type_list();
- if (f) {
- TreeItem *root = recent->create_item();
+ icon_fallback = search_options->has_theme_icon(base_type, "EditorIcons") ? base_type : "Object";
- String icon_fallback = search_options->has_theme_icon(base_type, "EditorIcons") ? base_type : "Object";
-
- while (!f->eof_reached()) {
- String l = f->get_line().strip_edges();
- String name = l.split(" ")[0];
- if ((ClassDB::class_exists(name) || ScriptServer::is_global_class(name)) && !_is_class_disabled_by_feature_profile(name)) {
- TreeItem *ti = recent->create_item(root);
- ti->set_text(0, l);
- ti->set_icon(0, EditorNode::get_singleton()->get_class_icon(name, icon_fallback));
- }
- }
-
- memdelete(f);
+ if (p_dont_clear) {
+ search_box->select_all();
+ } else {
+ search_box->clear();
}
- favorites->clear();
-
- f = FileAccess::open(EditorSettings::get_singleton()->get_project_settings_dir().plus_file("favorites." + base_type), FileAccess::READ);
-
- favorite_list.clear();
-
- if (f) {
- while (!f->eof_reached()) {
- String l = f->get_line().strip_edges();
+ if (p_replace_mode) {
+ search_box->set_text(p_select_type);
+ }
- if (l != String()) {
- favorite_list.push_back(l);
- }
- }
+ search_box->grab_focus();
+ _update_search();
- memdelete(f);
+ if (p_replace_mode) {
+ set_title(vformat(TTR("Change %s Type"), base_type));
+ get_ok()->set_text(TTR("Change"));
+ } else {
+ set_title(vformat(TTR("Create New %s"), base_type));
+ get_ok()->set_text(TTR("Create"));
}
+ _load_favorites_and_history();
_save_and_update_favorite_list();
// Restore valid window bounds or pop up at default size.
@@ -95,357 +73,263 @@ void CreateDialog::popup_create(bool p_dont_clear, bool p_replace_mode, const St
} else {
popup_centered_clamped(Size2(900, 700) * EDSCALE, 0.8);
}
+}
- if (p_dont_clear) {
- search_box->select_all();
- } else {
- search_box->clear();
- }
+void CreateDialog::_fill_type_list() {
+ List<StringName> complete_type_list;
+ ClassDB::get_class_list(&complete_type_list);
+ ScriptServer::get_global_class_list(&complete_type_list);
- search_box->grab_focus();
+ EditorData &ed = EditorNode::get_editor_data();
- _update_search();
+ for (List<StringName>::Element *I = complete_type_list.front(); I; I = I->next()) {
+ String type = I->get();
+ if (!_should_hide_type(type)) {
+ type_list.push_back(type);
- is_replace_mode = p_replace_mode;
+ if (!ed.get_custom_types().has(type)) {
+ continue;
+ }
- if (p_replace_mode) {
- select_type(p_select_type);
- set_title(vformat(TTR("Change %s Type"), base_type));
- get_ok()->set_text(TTR("Change"));
- } else {
- set_title(vformat(TTR("Create New %s"), base_type));
- get_ok()->set_text(TTR("Create"));
+ const Vector<EditorData::CustomType> &ct = ed.get_custom_types()[type];
+ for (int i = 0; i < ct.size(); i++) {
+ custom_type_parents[ct[i].name] = type;
+ custom_type_indices[ct[i].name] = i;
+ type_list.push_back(ct[i].name);
+ }
+ }
}
+ type_list.sort_custom<StringName::AlphCompare>();
}
-void CreateDialog::_text_changed(const String &p_newtext) {
- _update_search();
+bool CreateDialog::_is_type_preferred(const String &p_type) const {
+ if (ClassDB::class_exists(p_type)) {
+ return ClassDB::is_parent_class(p_type, preferred_search_result_type);
+ }
+
+ return EditorNode::get_editor_data().script_class_is_parent(p_type, preferred_search_result_type);
}
-void CreateDialog::_sbox_input(const Ref<InputEvent> &p_ie) {
- Ref<InputEventKey> k = p_ie;
- if (k.is_valid() && (k->get_keycode() == KEY_UP ||
- k->get_keycode() == KEY_DOWN ||
- k->get_keycode() == KEY_PAGEUP ||
- k->get_keycode() == KEY_PAGEDOWN)) {
- search_options->call("_gui_input", k);
- search_box->accept_event();
- }
+bool CreateDialog::_is_class_disabled_by_feature_profile(const StringName &p_class) const {
+ Ref<EditorFeatureProfile> profile = EditorFeatureProfileManager::get_singleton()->get_current_profile();
+
+ return !profile.is_null() && profile->is_class_disabled(p_class);
}
-void CreateDialog::add_type(const String &p_type, HashMap<String, TreeItem *> &p_types, TreeItem *p_root, TreeItem **to_select) {
- if (p_types.has(p_type)) {
- return;
+bool CreateDialog::_should_hide_type(const String &p_type) const {
+ if (_is_class_disabled_by_feature_profile(p_type)) {
+ return true;
}
- bool cpp_type = ClassDB::class_exists(p_type);
- EditorData &ed = EditorNode::get_editor_data();
+ if (base_type == "Node" && p_type.begins_with("Editor")) {
+ return true; // Do not show editor nodes.
+ }
if (p_type == base_type) {
- return;
+ return true; // Root is already added.
}
- if (cpp_type) {
+ if (ClassDB::class_exists(p_type)) {
+ if (!ClassDB::can_instance(p_type)) {
+ return true; // Can't create abstract class.
+ }
+
if (!ClassDB::is_parent_class(p_type, base_type)) {
- return;
+ return true; // Wrong inheritance.
+ }
+
+ for (Set<StringName>::Element *E = type_blacklist.front(); E; E = E->next()) {
+ if (ClassDB::is_parent_class(p_type, E->get())) {
+ return true; // Parent type is blacklisted.
+ }
}
} else {
- if (!search_loaded_scripts.has(p_type)) {
- search_loaded_scripts[p_type] = ed.script_class_load_script(p_type);
+ if (!EditorNode::get_editor_data().script_class_is_parent(p_type, base_type)) {
+ return true; // Wrong inheritance.
}
-
- if (!ScriptServer::is_global_class(p_type) || !ed.script_class_is_parent(p_type, base_type)) {
- return;
+ if (!ScriptServer::is_global_class(p_type)) {
+ return true;
}
String script_path = ScriptServer::get_global_class_path(p_type);
- if (script_path.find("res://addons/", 0) != -1) {
+ if (script_path.begins_with("res://addons/")) {
if (!EditorNode::get_singleton()->is_addon_plugin_enabled(script_path.get_slicec('/', 3))) {
- return;
+ return true; // Plugin is not enabled.
}
}
}
- String inherits = cpp_type ? ClassDB::get_parent_class(p_type) : ed.script_class_get_base(p_type);
-
- TreeItem *parent = p_root;
+ return false;
+}
- if (inherits.length()) {
- if (!p_types.has(inherits)) {
- add_type(inherits, p_types, p_root, to_select);
- }
+void CreateDialog::_update_search() {
+ search_options->clear();
+ search_options_types.clear();
- if (p_types.has(inherits)) {
- parent = p_types[inherits];
- } else if (ScriptServer::is_global_class(inherits)) {
- return;
- }
- }
+ TreeItem *root = search_options->create_item();
+ root->set_text(0, base_type);
+ root->set_icon(0, search_options->get_theme_icon(icon_fallback, "EditorIcons"));
+ search_options_types[base_type] = root;
- bool can_instance = (cpp_type && ClassDB::can_instance(p_type)) || ScriptServer::is_global_class(p_type);
+ const String search_text = search_box->get_text();
+ bool empty_search = search_text == "";
- TreeItem *item = search_options->create_item(parent);
- if (cpp_type) {
- item->set_text(0, p_type);
- } else {
- item->set_metadata(0, p_type);
- item->set_text(0, p_type + " (" + ScriptServer::get_global_class_path(p_type).get_file() + ")");
+ // Filter all candidate results.
+ Vector<String> candidates;
+ for (List<StringName>::Element *I = type_list.front(); I; I = I->next()) {
+ if (empty_search || search_text.is_subsequence_ofi(I->get())) {
+ candidates.push_back(I->get());
+ }
}
- if (!can_instance) {
- item->set_custom_color(0, search_options->get_theme_color("disabled_font_color", "Editor"));
- item->set_selectable(0, false);
- } else if (!(*to_select && (*to_select)->get_text(0) == search_box->get_text())) {
- String search_term = search_box->get_text().to_lower();
-
- // if the node name matches exactly as the search, the node should be selected.
- // this also fixes when the user clicks on recent nodes.
- if (p_type.to_lower() == search_term) {
- *to_select = item;
- } else {
- bool current_type_prefered = _is_type_prefered(p_type);
- bool selected_type_prefered = *to_select ? _is_type_prefered((*to_select)->get_text(0).split(" ")[0]) : false;
-
- bool is_subsequence_of_type = search_box->get_text().is_subsequence_ofi(p_type);
- bool is_substring_of_type = p_type.to_lower().find(search_term) >= 0;
- bool is_substring_of_selected = false;
- bool is_subsequence_of_selected = false;
- bool is_selected_equal = false;
-
- if (*to_select) {
- String name = (*to_select)->get_text(0).split(" ")[0].to_lower();
- is_substring_of_selected = name.find(search_term) >= 0;
- is_subsequence_of_selected = search_term.is_subsequence_of(name);
- is_selected_equal = name == search_term;
- }
- if (is_subsequence_of_type && !is_selected_equal) {
- if (is_substring_of_type) {
- if (!is_substring_of_selected || (current_type_prefered && !selected_type_prefered)) {
- *to_select = item;
- }
- } else {
- // substring results weigh more than subsequences, so let's make sure we don't override them
- if (!is_substring_of_selected) {
- if (!is_subsequence_of_selected || (current_type_prefered && !selected_type_prefered)) {
- *to_select = item;
- }
- }
- }
- }
- }
+ // Build the type tree.
+ for (int i = 0; i < candidates.size(); i++) {
+ _add_type(candidates[i], ClassDB::class_exists(candidates[i]));
}
- if (bool(EditorSettings::get_singleton()->get("docks/scene_tree/start_create_dialog_fully_expanded"))) {
- item->set_collapsed(false);
+ // Select the best result.
+ if (empty_search) {
+ select_type(base_type);
+ } else if (candidates.size() > 0) {
+ select_type(_top_result(candidates, search_text));
} else {
- // don't collapse search results
- bool collapse = (search_box->get_text() == "");
- // don't collapse the root node
- collapse &= (item != p_root);
- // don't collapse abstract nodes on the first tree level
- collapse &= ((parent != p_root) || (can_instance));
- item->set_collapsed(collapse);
+ favorite->set_disabled(true);
+ help_bit->set_text("");
+ get_ok()->set_disabled(true);
+ search_options->deselect_all();
}
-
- const String &description = DTR(EditorHelp::get_doc_data()->class_list[p_type].brief_description);
- item->set_tooltip(0, description);
-
- String icon_fallback = search_options->has_theme_icon(base_type, "EditorIcons") ? base_type : "Object";
- item->set_icon(0, EditorNode::get_singleton()->get_class_icon(p_type, icon_fallback));
-
- p_types[p_type] = item;
}
-bool CreateDialog::_is_type_prefered(const String &type) {
- bool cpp_type = ClassDB::class_exists(type);
- EditorData &ed = EditorNode::get_editor_data();
-
- if (cpp_type) {
- return ClassDB::is_parent_class(type, preferred_search_result_type);
+void CreateDialog::_add_type(const String &p_type, bool p_cpp_type) {
+ if (search_options_types.has(p_type)) {
+ return;
}
- return ed.script_class_is_parent(type, preferred_search_result_type);
-}
-bool CreateDialog::_is_class_disabled_by_feature_profile(const StringName &p_class) {
- Ref<EditorFeatureProfile> profile = EditorFeatureProfileManager::get_singleton()->get_current_profile();
- if (profile.is_null()) {
- return false;
+ String inherits;
+ if (p_cpp_type) {
+ inherits = ClassDB::get_parent_class(p_type);
+ } else if (ScriptServer::is_global_class(p_type)) {
+ inherits = EditorNode::get_editor_data().script_class_get_base(p_type);
+ } else {
+ inherits = custom_type_parents[p_type];
}
- return profile->is_class_disabled(p_class);
+ _add_type(inherits, p_cpp_type || ClassDB::class_exists(inherits));
+
+ TreeItem *item = search_options->create_item(search_options_types[inherits]);
+ search_options_types[p_type] = item;
+ _configure_search_option_item(item, p_type, p_cpp_type);
}
-void CreateDialog::select_type(const String &p_type) {
- TreeItem *to_select;
- if (search_options_types.has(p_type)) {
- to_select = search_options_types[p_type];
+void CreateDialog::_configure_search_option_item(TreeItem *r_item, const String &p_type, const bool p_cpp_type) {
+ bool script_type = ScriptServer::is_global_class(p_type);
+ if (p_cpp_type) {
+ r_item->set_text(0, p_type);
+ } else if (script_type) {
+ r_item->set_metadata(0, p_type);
+ r_item->set_text(0, p_type + " (" + ScriptServer::get_global_class_path(p_type).get_file() + ")");
} else {
- to_select = search_options->get_root();
+ r_item->set_metadata(0, custom_type_parents[p_type]);
+ r_item->set_text(0, p_type);
}
- // uncollapse from selected type to top level
- // TODO: should this be in tree?
- TreeItem *cur = to_select;
- while (cur) {
- cur->set_collapsed(false);
- cur = cur->get_parent();
+ bool can_instance = (p_cpp_type && ClassDB::can_instance(p_type)) || !p_cpp_type;
+ if (!can_instance) {
+ r_item->set_custom_color(0, search_options->get_theme_color("disabled_font_color", "Editor"));
+ r_item->set_selectable(0, false);
}
- to_select->select(0);
-
- search_options->scroll_to_item(to_select);
-}
-
-void CreateDialog::_update_search() {
- search_options->clear();
- favorite->set_disabled(true);
-
- help_bit->set_text("");
-
- search_options_types.clear();
-
- TreeItem *root = search_options->create_item();
- EditorData &ed = EditorNode::get_editor_data();
-
- root->set_text(0, base_type);
- String base_icon = search_options->has_theme_icon(base_type, "EditorIcons") ? base_type : "Object";
- root->set_icon(0, search_options->get_theme_icon(base_icon, "EditorIcons"));
-
- TreeItem *to_select = search_box->get_text() == base_type ? root : nullptr;
-
- for (List<StringName>::Element *I = type_list.front(); I; I = I->next()) {
- String type = I->get();
+ if (search_box->get_text() != "") {
+ r_item->set_collapsed(false);
+ } else {
+ // Don't collapse the root node or an abstract node on the first tree level.
+ bool should_collapse = p_type != base_type && (r_item->get_parent()->get_text(0) != base_type || can_instance);
- if (_is_class_disabled_by_feature_profile(type)) {
- continue;
+ if (should_collapse && bool(EditorSettings::get_singleton()->get("docks/scene_tree/start_create_dialog_fully_expanded"))) {
+ should_collapse = false; // Collapse all nodes anyway.
}
- bool cpp_type = ClassDB::class_exists(type);
+ r_item->set_collapsed(should_collapse);
+ }
- if (base_type == "Node" && type.begins_with("Editor")) {
- continue; // do not show editor nodes
- }
+ const String &description = DTR(EditorHelp::get_doc_data()->class_list[p_type].brief_description);
+ r_item->set_tooltip(0, description);
+ r_item->set_icon(0, EditorNode::get_singleton()->get_class_icon(p_type, icon_fallback));
- if (cpp_type && !ClassDB::can_instance(type)) {
- continue; // can't create what can't be instanced
+ if (!p_cpp_type && !script_type) {
+ Ref<Texture2D> icon = EditorNode::get_editor_data().get_custom_types()[custom_type_parents[p_type]][custom_type_indices[p_type]].icon;
+ if (icon.is_valid()) {
+ r_item->set_icon(0, icon);
}
+ }
+}
- if (cpp_type) {
- bool skip = false;
-
- for (Set<StringName>::Element *E = type_blacklist.front(); E && !skip; E = E->next()) {
- if (ClassDB::is_parent_class(type, E->get())) {
- skip = true;
- }
- }
- if (skip) {
- continue;
- }
+String CreateDialog::_top_result(const Vector<String> p_candidates, const String &p_search_text) const {
+ float highest_score = 0;
+ int highest_index = 0;
+ for (int i = 0; i < p_candidates.size(); i++) {
+ float score = _score_type(p_candidates[i].get_slicec(' ', 0), p_search_text);
+ if (score > highest_score) {
+ highest_score = score;
+ highest_index = i;
}
+ }
- if (search_box->get_text() == "") {
- add_type(type, search_options_types, root, &to_select);
- } else {
- bool found = false;
- String type2 = type;
- bool cpp_type2 = cpp_type;
-
- if (!cpp_type && !search_loaded_scripts.has(type)) {
- search_loaded_scripts[type] = ed.script_class_load_script(type);
- }
+ return p_candidates[highest_index];
+}
- while (type2 != "" && (cpp_type2 ? ClassDB::is_parent_class(type2, base_type) : ed.script_class_is_parent(type2, base_type)) && type2 != base_type) {
- if (search_box->get_text().is_subsequence_ofi(type2)) {
- found = true;
- break;
- }
+float CreateDialog::_score_type(const String &p_type, const String &p_search) const {
+ float inverse_length = 1.f / float(p_type.length());
- type2 = cpp_type2 ? ClassDB::get_parent_class(type2) : ed.script_class_get_base(type2);
- cpp_type2 = cpp_type2 || ClassDB::class_exists(type2); // Built-in class can't inherit from custom type, so we can skip the check if it's already true.
+ // Favor types where search term is a substring close to the start of the type.
+ float w = 0.5f;
+ int pos = p_type.findn(p_search);
+ float score = (pos > -1) ? 1.0f - w * MIN(1, 3 * pos * inverse_length) : MAX(0.f, .9f - w);
- if (!cpp_type2 && !search_loaded_scripts.has(type2)) {
- search_loaded_scripts[type2] = ed.script_class_load_script(type2);
- }
- }
+ // Favor shorter items: they resemble the search term more.
+ w = 0.1f;
+ score *= (1 - w) + w * (p_search.length() * inverse_length);
- if (found) {
- add_type(type, search_options_types, root, &to_select);
- }
- }
+ score *= _is_type_preferred(p_type) ? 1.0f : 0.8f;
- if (EditorNode::get_editor_data().get_custom_types().has(type) && ClassDB::is_parent_class(type, base_type)) {
- //there are custom types based on this... cool.
+ // Add score for being a favorite type.
+ score *= (favorite_list.find(p_type) > -1) ? 1.0f : 0.7f;
- const Vector<EditorData::CustomType> &ct = EditorNode::get_editor_data().get_custom_types()[type];
- for (int i = 0; i < ct.size(); i++) {
- bool show = search_box->get_text().is_subsequence_ofi(ct[i].name);
-
- if (!show) {
- continue;
- }
-
- if (!search_options_types.has(type)) {
- add_type(type, search_options_types, root, &to_select);
- }
-
- TreeItem *ti;
- if (search_options_types.has(type)) {
- ti = search_options_types[type];
- } else {
- ti = search_options->get_root();
- }
-
- TreeItem *item = search_options->create_item(ti);
- item->set_metadata(0, type);
- item->set_text(0, ct[i].name);
- item->set_icon(0, ct[i].icon.is_valid() ? ct[i].icon : search_options->get_theme_icon(base_icon, "EditorIcons"));
-
- if (!to_select || ct[i].name == search_box->get_text()) {
- to_select = item;
- }
- }
+ // Look through at most 5 recent items
+ bool in_recent = false;
+ for (int i = 0; i < MIN(5, recent->get_item_count()); i++) {
+ if (recent->get_item_text(i) == p_type) {
+ in_recent = true;
+ break;
}
}
+ score *= in_recent ? 1.0f : 0.8f;
- if (search_box->get_text() == "") {
- to_select = root;
- }
-
- if (to_select) {
- to_select->select(0);
- search_options->scroll_to_item(to_select);
- favorite->set_disabled(false);
- favorite->set_pressed(favorite_list.find(to_select->get_text(0)) != -1);
- }
+ return score;
+}
- get_ok()->set_disabled(root->get_children() == nullptr);
+void CreateDialog::_cleanup() {
+ type_list.clear();
+ favorite_list.clear();
+ favorites->clear();
+ recent->clear();
+ custom_type_parents.clear();
+ custom_type_indices.clear();
}
void CreateDialog::_confirmed() {
- TreeItem *ti = search_options->get_selected();
- if (!ti) {
+ String selected_item = get_selected_type();
+ if (selected_item == String()) {
return;
}
FileAccess *f = FileAccess::open(EditorSettings::get_singleton()->get_project_settings_dir().plus_file("create_recent." + base_type), FileAccess::WRITE);
-
if (f) {
- f->store_line(get_selected_type());
- TreeItem *t = recent->get_root();
- if (t) {
- t = t->get_children();
- }
- int count = 0;
- while (t) {
- if (t->get_text(0) != get_selected_type()) {
- f->store_line(t->get_text(0));
- }
+ f->store_line(selected_item);
- if (count > 32) {
- //limit it to 32 entries..
- break;
+ for (int i = 0; i < MIN(32, recent->get_item_count()); i++) {
+ if (recent->get_item_text(i) != selected_item) {
+ f->store_line(recent->get_item_text(i));
}
- t = t->get_next();
- count++;
}
memdelete(f);
@@ -453,6 +337,26 @@ void CreateDialog::_confirmed() {
emit_signal("create");
hide();
+ _cleanup();
+}
+
+void CreateDialog::_text_changed(const String &p_newtext) {
+ _update_search();
+}
+
+void CreateDialog::_sbox_input(const Ref<InputEvent> &p_ie) {
+ Ref<InputEventKey> k = p_ie;
+ if (k.is_valid()) {
+ switch (k->get_keycode()) {
+ case KEY_UP:
+ case KEY_DOWN:
+ case KEY_PAGEUP:
+ case KEY_PAGEDOWN: {
+ search_options->call("_gui_input", k);
+ search_box->accept_event();
+ } break;
+ }
+ }
}
void CreateDialog::_notification(int p_what) {
@@ -472,42 +376,36 @@ void CreateDialog::_notification(int p_what) {
search_box->select_all();
} else {
EditorSettings::get_singleton()->get_project_metadata("dialog_bounds", "create_new_node", Rect2(get_position(), get_size()));
- search_loaded_scripts.clear();
}
} break;
}
}
-void CreateDialog::set_base_type(const String &p_base) {
- base_type = p_base;
- if (is_replace_mode) {
- set_title(vformat(TTR("Change %s Type"), p_base));
- } else {
- set_title(vformat(TTR("Create New %s"), p_base));
+void CreateDialog::select_type(const String &p_type) {
+ if (!search_options_types.has(p_type)) {
+ return;
}
- _update_search();
-}
-
-String CreateDialog::get_base_type() const {
- return base_type;
-}
+ TreeItem *to_select = search_options_types[p_type];
+ to_select->select(0);
+ search_options->scroll_to_item(to_select);
-void CreateDialog::set_preferred_search_result_type(const String &p_preferred_type) {
- preferred_search_result_type = p_preferred_type;
-}
+ if (EditorHelp::get_doc_data()->class_list.has(p_type)) {
+ help_bit->set_text(DTR(EditorHelp::get_doc_data()->class_list[p_type].brief_description));
+ }
-String CreateDialog::get_preferred_search_result_type() {
- return preferred_search_result_type;
+ favorite->set_disabled(false);
+ favorite->set_pressed(favorite_list.find(p_type) != -1);
+ get_ok()->set_disabled(false);
}
String CreateDialog::get_selected_type() {
TreeItem *selected = search_options->get_selected();
- if (selected) {
- return selected->get_text(0);
- } else {
+ if (!selected) {
return String();
}
+
+ return selected->get_text(0);
}
Object *CreateDialog::instance_selected() {
@@ -518,21 +416,15 @@ Object *CreateDialog::instance_selected() {
}
Variant md = selected->get_metadata(0);
- String custom;
- if (md.get_type() != Variant::NIL) {
- custom = md;
- }
-
Object *obj = nullptr;
-
- if (!custom.empty()) {
+ if (md.get_type() != Variant::NIL) {
+ String custom = md;
if (ScriptServer::is_global_class(custom)) {
obj = EditorNode::get_editor_data().script_class_instance(custom);
Node *n = Object::cast_to<Node>(obj);
if (n) {
n->set_name(custom);
}
- obj = n;
} else {
obj = EditorNode::get_editor_data().instance_custom_type(selected->get_text(0), custom);
}
@@ -545,9 +437,10 @@ Object *CreateDialog::instance_selected() {
obj->get_property_list(&pinfo);
for (List<PropertyInfo>::Element *E = pinfo.front(); E; E = E->next()) {
- if (E->get().type == Variant::OBJECT && E->get().usage & PROPERTY_USAGE_EDITOR_INSTANTIATE_OBJECT) {
- Object *prop = ClassDB::instance(E->get().class_name);
- obj->set(E->get().name, prop);
+ PropertyInfo pi = E->get();
+ if (pi.type == Variant::OBJECT && pi.usage & PROPERTY_USAGE_EDITOR_INSTANTIATE_OBJECT) {
+ Object *prop = ClassDB::instance(pi.class_name);
+ obj->set(pi.name, prop);
}
}
@@ -555,29 +448,18 @@ Object *CreateDialog::instance_selected() {
}
void CreateDialog::_item_selected() {
- TreeItem *item = search_options->get_selected();
- if (!item) {
- return;
- }
-
- String name = item->get_text(0);
-
- favorite->set_disabled(false);
- favorite->set_pressed(favorite_list.find(name) != -1);
-
- if (!EditorHelp::get_doc_data()->class_list.has(name)) {
- return;
- }
-
- help_bit->set_text(DTR(EditorHelp::get_doc_data()->class_list[name].brief_description));
-
- get_ok()->set_disabled(false);
+ String name = get_selected_type();
+ select_type(name);
}
void CreateDialog::_hide_requested() {
_cancel_pressed(); // From AcceptDialog.
}
+void CreateDialog::cancel_pressed() {
+ _cleanup();
+}
+
void CreateDialog::_favorite_toggled() {
TreeItem *item = search_options->get_selected();
if (!item) {
@@ -597,50 +479,8 @@ void CreateDialog::_favorite_toggled() {
_save_and_update_favorite_list();
}
-void CreateDialog::_save_favorite_list() {
- FileAccess *f = FileAccess::open(EditorSettings::get_singleton()->get_project_settings_dir().plus_file("favorites." + base_type), FileAccess::WRITE);
-
- if (f) {
- for (int i = 0; i < favorite_list.size(); i++) {
- String l = favorite_list[i];
- String name = l.split(" ")[0];
- if (!(ClassDB::class_exists(name) || ScriptServer::is_global_class(name))) {
- continue;
- }
- f->store_line(l);
- }
- memdelete(f);
- }
-}
-
-void CreateDialog::_update_favorite_list() {
- favorites->clear();
-
- TreeItem *root = favorites->create_item();
-
- String icon_fallback = search_options->has_theme_icon(base_type, "EditorIcons") ? base_type : "Object";
-
- for (int i = 0; i < favorite_list.size(); i++) {
- String l = favorite_list[i];
- String name = l.split(" ")[0];
- if (!((ClassDB::class_exists(name) || ScriptServer::is_global_class(name)) && !_is_class_disabled_by_feature_profile(name))) {
- continue;
- }
-
- TreeItem *ti = favorites->create_item(root);
- ti->set_text(0, l);
- ti->set_icon(0, EditorNode::get_singleton()->get_class_icon(name, icon_fallback));
- }
- emit_signal("favorites_updated");
-}
-
-void CreateDialog::_history_selected() {
- TreeItem *item = recent->get_selected();
- if (!item) {
- return;
- }
-
- search_box->set_text(item->get_text(0).get_slicec(' ', 0));
+void CreateDialog::_history_selected(int p_idx) {
+ search_box->set_text(recent->get_item_text(p_idx).get_slicec(' ', 0));
favorites->deselect_all();
_update_search();
}
@@ -652,12 +492,12 @@ void CreateDialog::_favorite_selected() {
}
search_box->set_text(item->get_text(0).get_slicec(' ', 0));
- recent->deselect_all();
+ recent->unselect_all();
_update_search();
}
-void CreateDialog::_history_activated() {
- _history_selected();
+void CreateDialog::_history_activated(int p_idx) {
+ _history_selected(p_idx);
_confirmed();
}
@@ -740,8 +580,61 @@ void CreateDialog::drop_data_fw(const Point2 &p_point, const Variant &p_data, Co
}
void CreateDialog::_save_and_update_favorite_list() {
- _save_favorite_list();
- _update_favorite_list();
+ favorites->clear();
+ TreeItem *root = favorites->create_item();
+
+ FileAccess *f = FileAccess::open(EditorSettings::get_singleton()->get_project_settings_dir().plus_file("favorites." + base_type), FileAccess::WRITE);
+ if (f) {
+ for (int i = 0; i < favorite_list.size(); i++) {
+ String l = favorite_list[i];
+ String name = l.get_slicec(' ', 0);
+ if (!(ClassDB::class_exists(name) || ScriptServer::is_global_class(name))) {
+ continue;
+ }
+ f->store_line(l);
+
+ if (_is_class_disabled_by_feature_profile(name)) {
+ continue;
+ }
+
+ TreeItem *ti = favorites->create_item(root);
+ ti->set_text(0, l);
+ ti->set_icon(0, EditorNode::get_singleton()->get_class_icon(name, icon_fallback));
+ }
+ memdelete(f);
+ }
+
+ emit_signal("favorites_updated");
+}
+
+void CreateDialog::_load_favorites_and_history() {
+ String dir = EditorSettings::get_singleton()->get_project_settings_dir();
+ FileAccess *f = FileAccess::open(dir.plus_file("create_recent." + base_type), FileAccess::READ);
+ if (f) {
+ while (!f->eof_reached()) {
+ String l = f->get_line().strip_edges();
+ String name = l.get_slicec(' ', 0);
+
+ if ((ClassDB::class_exists(name) || ScriptServer::is_global_class(name)) && !_is_class_disabled_by_feature_profile(name)) {
+ recent->add_item(l, EditorNode::get_singleton()->get_class_icon(name, icon_fallback));
+ }
+ }
+
+ memdelete(f);
+ }
+
+ f = FileAccess::open(dir.plus_file("favorites." + base_type), FileAccess::READ);
+ if (f) {
+ while (!f->eof_reached()) {
+ String l = f->get_line().strip_edges();
+
+ if (l != String()) {
+ favorite_list.push_back(l);
+ }
+ }
+
+ memdelete(f);
+ }
}
void CreateDialog::_bind_methods() {
@@ -756,7 +649,11 @@ void CreateDialog::_bind_methods() {
}
CreateDialog::CreateDialog() {
- is_replace_mode = false;
+ base_type = "Object";
+ preferred_search_result_type = "";
+
+ type_blacklist.insert("PluginScript"); // PluginScript must be initialized before use, which is not possible here.
+ type_blacklist.insert("ScriptCreateDialog"); // This is an exposed editor Node that doesn't have an Editor prefix.
HSplitContainer *hsc = memnew(HSplitContainer);
add_child(hsc);
@@ -765,67 +662,64 @@ CreateDialog::CreateDialog() {
hsc->add_child(vsc);
VBoxContainer *fav_vb = memnew(VBoxContainer);
- vsc->add_child(fav_vb);
fav_vb->set_custom_minimum_size(Size2(150, 100) * EDSCALE);
fav_vb->set_v_size_flags(Control::SIZE_EXPAND_FILL);
+ vsc->add_child(fav_vb);
favorites = memnew(Tree);
- fav_vb->add_margin_child(TTR("Favorites:"), favorites, true);
favorites->set_hide_root(true);
favorites->set_hide_folding(true);
favorites->set_allow_reselect(true);
favorites->connect("cell_selected", callable_mp(this, &CreateDialog::_favorite_selected));
favorites->connect("item_activated", callable_mp(this, &CreateDialog::_favorite_activated));
+ favorites->add_theme_constant_override("draw_guides", 1);
#ifndef _MSC_VER
#warning cant forward drag data to a non control, must be fixed
#endif
//favorites->set_drag_forwarding(this);
- favorites->add_theme_constant_override("draw_guides", 1);
+ fav_vb->add_margin_child(TTR("Favorites:"), favorites, true);
VBoxContainer *rec_vb = memnew(VBoxContainer);
vsc->add_child(rec_vb);
rec_vb->set_custom_minimum_size(Size2(150, 100) * EDSCALE);
rec_vb->set_v_size_flags(Control::SIZE_EXPAND_FILL);
- recent = memnew(Tree);
+ recent = memnew(ItemList);
rec_vb->add_margin_child(TTR("Recent:"), recent, true);
- recent->set_hide_root(true);
- recent->set_hide_folding(true);
recent->set_allow_reselect(true);
- recent->connect("cell_selected", callable_mp(this, &CreateDialog::_history_selected));
+ recent->connect("item_selected", callable_mp(this, &CreateDialog::_history_selected));
recent->connect("item_activated", callable_mp(this, &CreateDialog::_history_activated));
recent->add_theme_constant_override("draw_guides", 1);
VBoxContainer *vbc = memnew(VBoxContainer);
- hsc->add_child(vbc);
vbc->set_custom_minimum_size(Size2(300, 0) * EDSCALE);
vbc->set_h_size_flags(Control::SIZE_EXPAND_FILL);
- HBoxContainer *search_hb = memnew(HBoxContainer);
+ hsc->add_child(vbc);
+
search_box = memnew(LineEdit);
search_box->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ search_box->connect("text_changed", callable_mp(this, &CreateDialog::_text_changed));
+ search_box->connect("gui_input", callable_mp(this, &CreateDialog::_sbox_input));
+
+ HBoxContainer *search_hb = memnew(HBoxContainer);
search_hb->add_child(search_box);
+
favorite = memnew(Button);
favorite->set_flat(true);
favorite->set_toggle_mode(true);
- search_hb->add_child(favorite);
favorite->connect("pressed", callable_mp(this, &CreateDialog::_favorite_toggled));
+ search_hb->add_child(favorite);
vbc->add_margin_child(TTR("Search:"), search_hb);
- search_box->connect("text_changed", callable_mp(this, &CreateDialog::_text_changed));
- search_box->connect("gui_input", callable_mp(this, &CreateDialog::_sbox_input));
+
search_options = memnew(Tree);
- vbc->add_margin_child(TTR("Matches:"), search_options, true);
- get_ok()->set_disabled(true);
- register_text_enter(search_box);
- set_hide_on_ok(false);
search_options->connect("item_activated", callable_mp(this, &CreateDialog::_confirmed));
search_options->connect("cell_selected", callable_mp(this, &CreateDialog::_item_selected));
- base_type = "Object";
- preferred_search_result_type = "";
+ vbc->add_margin_child(TTR("Matches:"), search_options, true);
help_bit = memnew(EditorHelpBit);
- vbc->add_margin_child(TTR("Description:"), help_bit);
help_bit->connect("request_hide", callable_mp(this, &CreateDialog::_hide_requested));
+ vbc->add_margin_child(TTR("Description:"), help_bit);
- type_blacklist.insert("PluginScript"); // PluginScript must be initialized before use, which is not possible here
- type_blacklist.insert("ScriptCreateDialog"); // This is an exposed editor Node that doesn't have an Editor prefix.
+ register_text_enter(search_box);
+ set_hide_on_ok(false);
}
diff --git a/editor/create_dialog.h b/editor/create_dialog.h
index cdc91ae535..52eb9945af 100644
--- a/editor/create_dialog.h
+++ b/editor/create_dialog.h
@@ -35,60 +35,65 @@
#include "scene/gui/button.h"
#include "scene/gui/dialogs.h"
#include "scene/gui/item_list.h"
-#include "scene/gui/label.h"
#include "scene/gui/line_edit.h"
#include "scene/gui/tree.h"
class CreateDialog : public ConfirmationDialog {
GDCLASS(CreateDialog, ConfirmationDialog);
- Vector<String> favorite_list;
- Tree *favorites;
- Tree *recent;
-
- Button *favorite;
LineEdit *search_box;
Tree *search_options;
- HashMap<String, TreeItem *> search_options_types;
- HashMap<String, RES> search_loaded_scripts;
- bool is_replace_mode;
+
String base_type;
+ String icon_fallback;
String preferred_search_result_type;
+
+ Button *favorite;
+ Vector<String> favorite_list;
+ Tree *favorites;
+ ItemList *recent;
EditorHelpBit *help_bit;
+
+ HashMap<String, TreeItem *> search_options_types;
+ HashMap<String, String> custom_type_parents;
+ HashMap<String, int> custom_type_indices;
List<StringName> type_list;
Set<StringName> type_blacklist;
- void _item_selected();
- void _hide_requested();
-
void _update_search();
- void _update_favorite_list();
- void _save_favorite_list();
- void _favorite_toggled();
+ bool _should_hide_type(const String &p_type) const;
+ void _add_type(const String &p_current, bool p_cpp_type);
+ void _configure_search_option_item(TreeItem *r_item, const String &p_type, const bool p_cpp_type);
+ String _top_result(const Vector<String> p_candidates, const String &p_search_text) const;
+ float _score_type(const String &p_type, const String &p_search) const;
+ bool _is_type_preferred(const String &p_type) const;
- void _history_selected();
- void _favorite_selected();
-
- void _history_activated();
- void _favorite_activated();
+ void _fill_type_list();
+ void _cleanup();
void _sbox_input(const Ref<InputEvent> &p_ie);
+ void _text_changed(const String &p_newtext);
+ void select_type(const String &p_type);
+ void _item_selected();
+ void _hide_requested();
void _confirmed();
- void _text_changed(const String &p_newtext);
+ virtual void cancel_pressed();
- Ref<Texture2D> _get_editor_icon(const String &p_type) const;
+ void _favorite_toggled();
- void add_type(const String &p_type, HashMap<String, TreeItem *> &p_types, TreeItem *p_root, TreeItem **to_select);
+ void _history_selected(int p_idx);
+ void _favorite_selected();
- void select_type(const String &p_type);
+ void _history_activated(int p_idx);
+ void _favorite_activated();
Variant get_drag_data_fw(const Point2 &p_point, Control *p_from);
bool can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const;
void drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from);
- bool _is_class_disabled_by_feature_profile(const StringName &p_class);
- bool _is_type_prefered(const String &type);
+ bool _is_class_disabled_by_feature_profile(const StringName &p_class) const;
+ void _load_favorites_and_history();
protected:
void _notification(int p_what);
@@ -100,11 +105,11 @@ public:
Object *instance_selected();
String get_selected_type();
- void set_base_type(const String &p_base);
- String get_base_type() const;
+ void set_base_type(const String &p_base) { base_type = p_base; }
+ String get_base_type() const { return base_type; }
- void set_preferred_search_result_type(const String &p_preferred_type);
- String get_preferred_search_result_type();
+ void set_preferred_search_result_type(const String &p_preferred_type) { preferred_search_result_type = p_preferred_type; }
+ String get_preferred_search_result_type() { return preferred_search_result_type; }
void popup_create(bool p_dont_clear, bool p_replace_mode = false, const String &p_select_type = "Node");
diff --git a/editor/debugger/editor_performance_profiler.cpp b/editor/debugger/editor_performance_profiler.cpp
new file mode 100644
index 0000000000..47fe282758
--- /dev/null
+++ b/editor/debugger/editor_performance_profiler.cpp
@@ -0,0 +1,394 @@
+/*************************************************************************/
+/* editor_performance_profiler.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "editor_performance_profiler.h"
+
+#include "editor/editor_scale.h"
+#include "editor/editor_settings.h"
+#include "main/performance.h"
+
+EditorPerformanceProfiler::Monitor::Monitor() {}
+
+EditorPerformanceProfiler::Monitor::Monitor(String p_name, String p_base, int p_frame_index, Performance::MonitorType p_type, TreeItem *p_item) {
+ type = p_type;
+ item = p_item;
+ frame_index = p_frame_index;
+ name = p_name;
+ base = p_base;
+}
+
+void EditorPerformanceProfiler::Monitor::update_value(float p_value) {
+ ERR_FAIL_COND(!item);
+ String label = EditorPerformanceProfiler::_create_label(p_value, type);
+ String tooltip = label;
+ switch (type) {
+ case Performance::MONITOR_TYPE_MEMORY: {
+ tooltip = label;
+ } break;
+ case Performance::MONITOR_TYPE_TIME: {
+ tooltip = label;
+ } break;
+ default: {
+ tooltip += " " + item->get_text(0);
+ } break;
+ }
+ item->set_text(1, label);
+ item->set_tooltip(1, tooltip);
+
+ if (p_value > max) {
+ max = p_value;
+ }
+}
+
+void EditorPerformanceProfiler::Monitor::reset() {
+ history.clear();
+ max = 0.0f;
+ if (item) {
+ item->set_text(1, "");
+ item->set_tooltip(1, "");
+ }
+}
+
+String EditorPerformanceProfiler::_create_label(float p_value, Performance::MonitorType p_type) {
+ switch (p_type) {
+ case Performance::MONITOR_TYPE_MEMORY: {
+ return String::humanize_size(p_value);
+ }
+ case Performance::MONITOR_TYPE_TIME: {
+ return rtos(p_value * 1000).pad_decimals(2) + " ms";
+ }
+ default: {
+ return rtos(p_value);
+ }
+ }
+}
+
+void EditorPerformanceProfiler::_monitor_select() {
+ monitor_draw->update();
+}
+
+void EditorPerformanceProfiler::_monitor_draw() {
+ Vector<StringName> active;
+ for (OrderedHashMap<StringName, Monitor>::Element i = monitors.front(); i; i = i.next()) {
+ if (i.value().item->is_checked(0)) {
+ active.push_back(i.key());
+ }
+ }
+
+ if (active.empty()) {
+ info_message->show();
+ return;
+ }
+
+ info_message->hide();
+
+ Ref<StyleBox> graph_style_box = get_theme_stylebox("normal", "TextEdit");
+ Ref<Font> graph_font = get_theme_font("font", "TextEdit");
+
+ int columns = int(Math::ceil(Math::sqrt(float(active.size()))));
+ int rows = int(Math::ceil(float(active.size()) / float(columns)));
+ if (active.size() == 1) {
+ rows = 1;
+ }
+ Size2i cell_size = Size2i(monitor_draw->get_size()) / Size2i(columns, rows);
+ float spacing = float(POINT_SEPARATION) / float(columns);
+ float value_multiplier = EditorSettings::get_singleton()->is_dark_theme() ? 1.4f : 0.55f;
+ float hue_shift = 1.0f / float(monitors.size());
+
+ for (int i = 0; i < active.size(); i++) {
+ Monitor &current = monitors[active[i]];
+ Rect2i rect(Point2i(i % columns, i / columns) * cell_size + Point2i(MARGIN, MARGIN), cell_size - Point2i(MARGIN, MARGIN) * 2);
+ monitor_draw->draw_style_box(graph_style_box, rect);
+
+ rect.position += graph_style_box->get_offset();
+ rect.size -= graph_style_box->get_minimum_size();
+ Color draw_color = get_theme_color("accent_color", "Editor");
+ draw_color.set_hsv(Math::fmod(hue_shift * float(current.frame_index), 0.9f), draw_color.get_s() * 0.9f, draw_color.get_v() * value_multiplier, 0.6f);
+ monitor_draw->draw_string(graph_font, rect.position + Point2(0, graph_font->get_ascent()), current.item->get_text(0), draw_color, rect.size.x);
+
+ draw_color.a = 0.9f;
+ float value_position = rect.size.width - graph_font->get_string_size(current.item->get_text(1)).width;
+ if (value_position < 0) {
+ value_position = 0;
+ }
+ monitor_draw->draw_string(graph_font, rect.position + Point2(value_position, graph_font->get_ascent()), current.item->get_text(1), draw_color, rect.size.x);
+
+ rect.position.y += graph_font->get_height();
+ rect.size.height -= graph_font->get_height();
+
+ int line_count = rect.size.height / (graph_font->get_height() * 2);
+ if (line_count > 5) {
+ line_count = 5;
+ }
+ if (line_count > 0) {
+ Color horizontal_line_color;
+ horizontal_line_color.set_hsv(draw_color.get_h(), draw_color.get_s() * 0.5f, draw_color.get_v() * 0.5f, 0.3f);
+ monitor_draw->draw_line(rect.position, rect.position + Vector2(rect.size.width, 0), horizontal_line_color, Math::round(EDSCALE));
+ monitor_draw->draw_string(graph_font, rect.position + Vector2(0, graph_font->get_ascent()), _create_label(current.max, current.type), horizontal_line_color, rect.size.width);
+
+ for (int j = 0; j < line_count; j++) {
+ Vector2 y_offset = Vector2(0, rect.size.height * (1.0f - float(j) / float(line_count)));
+ monitor_draw->draw_line(rect.position + y_offset, rect.position + Vector2(rect.size.width, 0) + y_offset, horizontal_line_color, Math::round(EDSCALE));
+ monitor_draw->draw_string(graph_font, rect.position - Vector2(0, graph_font->get_descent()) + y_offset, _create_label(current.max * float(j) / float(line_count), current.type), horizontal_line_color, rect.size.width);
+ }
+ }
+
+ float from = rect.size.width;
+ float prev = -1.0f;
+ int count = 0;
+ List<float>::Element *e = current.history.front();
+
+ while (from >= 0 && e) {
+ float m = current.max;
+ float h2 = 0;
+ if (m != 0) {
+ h2 = (e->get() / m);
+ }
+ h2 = (1.0f - h2) * float(rect.size.y);
+ if (e != current.history.front()) {
+ monitor_draw->draw_line(rect.position + Point2(from, h2), rect.position + Point2(from + spacing, prev), draw_color, Math::round(EDSCALE));
+ }
+
+ if (marker_key == active[i] && count == marker_frame) {
+ Color line_color;
+ line_color.set_hsv(draw_color.get_h(), draw_color.get_s() * 0.8f, draw_color.get_v(), 0.5f);
+ monitor_draw->draw_line(rect.position + Point2(from, 0), rect.position + Point2(from, rect.size.y), line_color, Math::round(EDSCALE));
+
+ String label = _create_label(e->get(), current.type);
+ Size2 size = graph_font->get_string_size(label);
+ Vector2 text_top_left_position = Vector2(from, h2) - (size + Vector2(MARKER_MARGIN, MARKER_MARGIN));
+ if (text_top_left_position.x < 0) {
+ text_top_left_position.x = from + MARKER_MARGIN;
+ }
+ if (text_top_left_position.y < 0) {
+ text_top_left_position.y = h2 + MARKER_MARGIN;
+ }
+ monitor_draw->draw_string(graph_font, rect.position + text_top_left_position + Point2(0, graph_font->get_ascent()), label, line_color, rect.size.x);
+ }
+ prev = h2;
+ e = e->next();
+ from -= spacing;
+ count++;
+ }
+ }
+}
+
+void EditorPerformanceProfiler::_build_monitor_tree() {
+ Set<StringName> monitor_checked;
+ for (OrderedHashMap<StringName, Monitor>::Element i = monitors.front(); i; i = i.next()) {
+ if (i.value().item && i.value().item->is_checked(0)) {
+ monitor_checked.insert(i.key());
+ }
+ }
+
+ base_map.clear();
+ monitor_tree->get_root()->clear_children();
+
+ for (OrderedHashMap<StringName, Monitor>::Element i = monitors.front(); i; i = i.next()) {
+ TreeItem *base = _get_monitor_base(i.value().base);
+ TreeItem *item = _create_monitor_item(i.value().name, base);
+ item->set_checked(0, monitor_checked.has(i.key()));
+ i.value().item = item;
+ if (!i.value().history.empty()) {
+ i.value().update_value(i.value().history.front()->get());
+ }
+ }
+}
+
+TreeItem *EditorPerformanceProfiler::_get_monitor_base(const StringName &p_base_name) {
+ if (base_map.has(p_base_name)) {
+ return base_map[p_base_name];
+ }
+
+ TreeItem *base = monitor_tree->create_item(monitor_tree->get_root());
+ base->set_text(0, p_base_name);
+ base->set_editable(0, false);
+ base->set_selectable(0, false);
+ base->set_expand_right(0, true);
+ base_map.insert(p_base_name, base);
+ return base;
+}
+
+TreeItem *EditorPerformanceProfiler::_create_monitor_item(const StringName &p_monitor_name, TreeItem *p_base) {
+ TreeItem *item = monitor_tree->create_item(p_base);
+ item->set_cell_mode(0, TreeItem::CELL_MODE_CHECK);
+ item->set_editable(0, true);
+ item->set_selectable(0, false);
+ item->set_selectable(1, false);
+ item->set_text(0, p_monitor_name);
+ return item;
+}
+
+void EditorPerformanceProfiler::_marker_input(const Ref<InputEvent> &p_event) {
+ Ref<InputEventMouseButton> mb = p_event;
+ if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
+ Vector<StringName> active;
+ for (OrderedHashMap<StringName, Monitor>::Element i = monitors.front(); i; i = i.next()) {
+ if (i.value().item->is_checked(0)) {
+ active.push_back(i.key());
+ }
+ }
+ if (active.size() > 0) {
+ int columns = int(Math::ceil(Math::sqrt(float(active.size()))));
+ int rows = int(Math::ceil(float(active.size()) / float(columns)));
+ if (active.size() == 1) {
+ rows = 1;
+ }
+ Size2i cell_size = Size2i(monitor_draw->get_size()) / Size2i(columns, rows);
+ Vector2i index = mb->get_position() / cell_size;
+ Rect2i rect(index * cell_size + Point2i(MARGIN, MARGIN), cell_size - Point2i(MARGIN, MARGIN) * 2);
+ if (rect.has_point(mb->get_position())) {
+ if (index.x + index.y * columns < active.size()) {
+ marker_key = active[index.x + index.y * columns];
+ } else {
+ marker_key = "";
+ }
+ Ref<StyleBox> graph_style_box = get_theme_stylebox("normal", "TextEdit");
+ rect.position += graph_style_box->get_offset();
+ rect.size -= graph_style_box->get_minimum_size();
+ Vector2 point = mb->get_position() - rect.position;
+ if (point.x >= rect.size.x) {
+ marker_frame = 0;
+ } else {
+ int point_sep = 5;
+ float spacing = float(point_sep) / float(columns);
+ marker_frame = (rect.size.x - point.x) / spacing;
+ }
+ monitor_draw->update();
+ return;
+ }
+ }
+ marker_key = "";
+ monitor_draw->update();
+ }
+}
+
+void EditorPerformanceProfiler::reset() {
+ for (OrderedHashMap<StringName, Monitor>::Element i = monitors.front(); i; i = i.next()) {
+ if (String(i.key()).begins_with("custom:")) {
+ monitors.erase(i);
+ } else {
+ i.value().reset();
+ }
+ }
+
+ _build_monitor_tree();
+ marker_key = "";
+ marker_frame = 0;
+ monitor_draw->update();
+}
+
+void EditorPerformanceProfiler::update_monitors(const Vector<StringName> &p_names) {
+ OrderedHashMap<StringName, int> names;
+ for (int i = 0; i < p_names.size(); i++) {
+ names.insert("custom:" + p_names[i], Performance::MONITOR_MAX + i);
+ }
+
+ for (OrderedHashMap<StringName, Monitor>::Element i = monitors.front(); i; i = i.next()) {
+ if (String(i.key()).begins_with("custom:")) {
+ if (!names.has(i.key())) {
+ monitors.erase(i);
+ } else {
+ i.value().frame_index = names[i.key()];
+ names.erase(i.key());
+ }
+ }
+ }
+
+ for (OrderedHashMap<StringName, int>::Element i = names.front(); i; i = i.next()) {
+ String name = String(i.key()).replace_first("custom:", "");
+ String base = "Custom";
+ if (name.get_slice_count("/") == 2) {
+ base = name.get_slicec('/', 0);
+ name = name.get_slicec('/', 1);
+ }
+ monitors.insert(i.key(), Monitor(name, base, i.value(), Performance::MONITOR_TYPE_QUANTITY, nullptr));
+ }
+
+ _build_monitor_tree();
+}
+
+void EditorPerformanceProfiler::add_profile_frame(const Vector<float> &p_values) {
+ for (OrderedHashMap<StringName, Monitor>::Element i = monitors.front(); i; i = i.next()) {
+ float data = 0.0f;
+ if (i.value().frame_index >= 0 && i.value().frame_index < p_values.size()) {
+ data = p_values[i.value().frame_index];
+ }
+ i.value().history.push_front(data);
+ i.value().update_value(data);
+ }
+ marker_frame++;
+ monitor_draw->update();
+}
+
+List<float> *EditorPerformanceProfiler::get_monitor_data(const StringName &p_name) {
+ if (monitors.has(p_name)) {
+ return &monitors[p_name].history;
+ }
+ return nullptr;
+}
+
+EditorPerformanceProfiler::EditorPerformanceProfiler() {
+ set_name(TTR("Monitors"));
+ set_split_offset(340 * EDSCALE);
+
+ monitor_tree = memnew(Tree);
+ monitor_tree->set_columns(2);
+ monitor_tree->set_column_title(0, TTR("Monitor"));
+ monitor_tree->set_column_title(1, TTR("Value"));
+ monitor_tree->set_column_titles_visible(true);
+ monitor_tree->connect("item_edited", callable_mp(this, &EditorPerformanceProfiler::_monitor_select));
+ monitor_tree->create_item();
+ monitor_tree->set_hide_root(true);
+ add_child(monitor_tree);
+
+ monitor_draw = memnew(Control);
+ monitor_draw->set_clip_contents(true);
+ monitor_draw->connect("draw", callable_mp(this, &EditorPerformanceProfiler::_monitor_draw));
+ monitor_draw->connect("gui_input", callable_mp(this, &EditorPerformanceProfiler::_marker_input));
+ add_child(monitor_draw);
+
+ info_message = memnew(Label);
+ info_message->set_text(TTR("Pick one or more items from the list to display the graph."));
+ info_message->set_valign(Label::VALIGN_CENTER);
+ info_message->set_align(Label::ALIGN_CENTER);
+ info_message->set_autowrap(true);
+ info_message->set_custom_minimum_size(Size2(100 * EDSCALE, 0));
+ info_message->set_anchors_and_margins_preset(PRESET_WIDE, PRESET_MODE_KEEP_SIZE, 8 * EDSCALE);
+ monitor_draw->add_child(info_message);
+
+ for (int i = 0; i < Performance::MONITOR_MAX; i++) {
+ String base = Performance::get_singleton()->get_monitor_name(Performance::Monitor(i)).get_slicec('/', 0).capitalize();
+ String name = Performance::get_singleton()->get_monitor_name(Performance::Monitor(i)).get_slicec('/', 1).capitalize();
+ monitors.insert(Performance::get_singleton()->get_monitor_name(Performance::Monitor(i)), Monitor(name, base, i, Performance::get_singleton()->get_monitor_type(Performance::Monitor(i)), nullptr));
+ }
+
+ _build_monitor_tree();
+}
diff --git a/editor/debugger/editor_performance_profiler.h b/editor/debugger/editor_performance_profiler.h
new file mode 100644
index 0000000000..144dd34103
--- /dev/null
+++ b/editor/debugger/editor_performance_profiler.h
@@ -0,0 +1,90 @@
+/*************************************************************************/
+/* editor_performance_profiler.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef EDITOR_PERFORMANCE_PROFILER_H
+#define EDITOR_PERFORMANCE_PROFILER_H
+
+#include "core/map.h"
+#include "core/ordered_hash_map.h"
+#include "main/performance.h"
+#include "scene/gui/control.h"
+#include "scene/gui/label.h"
+#include "scene/gui/split_container.h"
+#include "scene/gui/tree.h"
+
+class EditorPerformanceProfiler : public HSplitContainer {
+ GDCLASS(EditorPerformanceProfiler, HSplitContainer);
+
+private:
+ class Monitor {
+ public:
+ String name;
+ String base;
+ List<float> history;
+ float max = 0.0f;
+ TreeItem *item = nullptr;
+ Performance::MonitorType type = Performance::MONITOR_TYPE_QUANTITY;
+ int frame_index = 0;
+
+ Monitor();
+ Monitor(String p_name, String p_base, int p_frame_index, Performance::MonitorType p_type, TreeItem *p_item);
+ void update_value(float p_value);
+ void reset();
+ };
+
+ OrderedHashMap<StringName, Monitor> monitors;
+
+ Map<StringName, TreeItem *> base_map;
+ Tree *monitor_tree;
+ Control *monitor_draw;
+ Label *info_message;
+ StringName marker_key;
+ int marker_frame;
+ const int MARGIN = 4;
+ const int POINT_SEPARATION = 5;
+ const int MARKER_MARGIN = 2;
+
+ static String _create_label(float p_value, Performance::MonitorType p_type);
+ void _monitor_select();
+ void _monitor_draw();
+ void _build_monitor_tree();
+ TreeItem *_get_monitor_base(const StringName &p_base_name);
+ TreeItem *_create_monitor_item(const StringName &p_monitor_name, TreeItem *p_base);
+ void _marker_input(const Ref<InputEvent> &p_event);
+
+public:
+ void reset();
+ void update_monitors(const Vector<StringName> &p_names);
+ void add_profile_frame(const Vector<float> &p_values);
+ List<float> *get_monitor_data(const StringName &p_name);
+ EditorPerformanceProfiler();
+};
+
+#endif // EDITOR_PERFORMANCE_PROFILER_H
diff --git a/editor/debugger/script_editor_debugger.cpp b/editor/debugger/script_editor_debugger.cpp
index a042afc788..a828e29558 100644
--- a/editor/debugger/script_editor_debugger.cpp
+++ b/editor/debugger/script_editor_debugger.cpp
@@ -36,6 +36,7 @@
#include "core/project_settings.h"
#include "core/ustring.h"
#include "editor/debugger/editor_network_profiler.h"
+#include "editor/debugger/editor_performance_profiler.h"
#include "editor/debugger/editor_profiler.h"
#include "editor/debugger/editor_visual_profiler.h"
#include "editor/editor_log.h"
@@ -172,14 +173,25 @@ void ScriptEditorDebugger::_file_selected(const String &p_file) {
file->store_csv_line(line);
// values
- List<Vector<float>>::Element *E = perf_history.back();
- while (E) {
- Vector<float> &perf_data = E->get();
- for (int i = 0; i < perf_data.size(); i++) {
- line.write[i] = String::num_real(perf_data[i]);
+ Vector<List<float>::Element *> iterators;
+ iterators.resize(Performance::MONITOR_MAX);
+ bool continue_iteration = false;
+ for (int i = 0; i < Performance::MONITOR_MAX; i++) {
+ iterators.write[i] = performance_profiler->get_monitor_data(Performance::get_singleton()->get_monitor_name(Performance::Monitor(i)))->back();
+ continue_iteration = continue_iteration || iterators[i];
+ }
+ while (continue_iteration) {
+ continue_iteration = false;
+ for (int i = 0; i < Performance::MONITOR_MAX; i++) {
+ if (iterators[i]) {
+ line.write[i] = String::num_real(iterators[i]->get());
+ iterators.write[i] = iterators[i]->prev();
+ } else {
+ line.write[i] = "";
+ }
+ continue_iteration = continue_iteration || iterators[i];
}
file->store_csv_line(line);
- E = E->prev();
}
file->store_string("\n");
@@ -409,37 +421,12 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_da
EditorNode::get_log()->add_message(output_strings[i], msg_type);
}
} else if (p_msg == "performance:profile_frame") {
- Vector<float> p;
- p.resize(p_data.size());
+ Vector<float> frame_data;
+ frame_data.resize(p_data.size());
for (int i = 0; i < p_data.size(); i++) {
- p.write[i] = p_data[i];
- if (i < perf_items.size()) {
- const float value = p[i];
- String label = rtos(value);
- String tooltip = label;
- switch (Performance::MonitorType((int)perf_items[i]->get_metadata(1))) {
- case Performance::MONITOR_TYPE_MEMORY: {
- label = String::humanize_size(value);
- tooltip = label;
- } break;
- case Performance::MONITOR_TYPE_TIME: {
- label = rtos(value * 1000).pad_decimals(2) + " ms";
- tooltip = label;
- } break;
- default: {
- tooltip += " " + perf_items[i]->get_text(0);
- } break;
- }
-
- perf_items[i]->set_text(1, label);
- perf_items[i]->set_tooltip(1, tooltip);
- if (p[i] > perf_max[i]) {
- perf_max.write[i] = p[i];
- }
- }
+ frame_data.write[i] = p_data[i];
}
- perf_history.push_front(p);
- perf_draw->update();
+ performance_profiler->add_profile_frame(frame_data);
} else if (p_msg == "visual:profile_frame") {
DebuggerMarshalls::VisualProfilerFrame frame;
@@ -704,6 +691,15 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_da
emit_signal("stop_requested");
_stop_and_notify();
+ } else if (p_msg == "performance:profile_names") {
+ Vector<StringName> monitors;
+ monitors.resize(p_data.size());
+ for (int i = 0; i < p_data.size(); i++) {
+ ERR_FAIL_COND(p_data[i].get_type() != Variant::STRING_NAME);
+ monitors.set(i, p_data[i]);
+ }
+ performance_profiler->update_monitors(monitors);
+
} else {
WARN_PRINT("unknown message " + p_msg);
}
@@ -724,80 +720,6 @@ void ScriptEditorDebugger::_set_reason_text(const String &p_reason, MessageType
reason->set_tooltip(p_reason.word_wrap(80));
}
-void ScriptEditorDebugger::_performance_select() {
- perf_draw->update();
-}
-
-void ScriptEditorDebugger::_performance_draw() {
- Vector<int> which;
- for (int i = 0; i < perf_items.size(); i++) {
- if (perf_items[i]->is_checked(0)) {
- which.push_back(i);
- }
- }
-
- if (which.empty()) {
- info_message->show();
- return;
- }
-
- info_message->hide();
-
- Ref<StyleBox> graph_sb = get_theme_stylebox("normal", "TextEdit");
- Ref<Font> graph_font = get_theme_font("font", "TextEdit");
-
- int cols = Math::ceil(Math::sqrt((float)which.size()));
- int rows = Math::ceil((float)which.size() / cols);
- if (which.size() == 1) {
- rows = 1;
- }
-
- int margin = 3;
- int point_sep = 5;
- Size2i s = Size2i(perf_draw->get_size()) / Size2i(cols, rows);
- for (int i = 0; i < which.size(); i++) {
- Point2i p(i % cols, i / cols);
- Rect2i r(p * s, s);
- r.position += Point2(margin, margin);
- r.size -= Point2(margin, margin) * 2.0;
- perf_draw->draw_style_box(graph_sb, r);
- r.position += graph_sb->get_offset();
- r.size -= graph_sb->get_minimum_size();
- int pi = which[i];
- Color c = get_theme_color("accent_color", "Editor");
- float h = (float)which[i] / (float)(perf_items.size());
- // Use a darker color on light backgrounds for better visibility
- float value_multiplier = EditorSettings::get_singleton()->is_dark_theme() ? 1.4 : 0.55;
- c.set_hsv(Math::fmod(h + 0.4, 0.9), c.get_s() * 0.9, c.get_v() * value_multiplier);
-
- c.a = 0.6;
- perf_draw->draw_string(graph_font, r.position + Point2(0, graph_font->get_ascent()), perf_items[pi]->get_text(0), c, r.size.x);
- c.a = 0.9;
- perf_draw->draw_string(graph_font, r.position + Point2(0, graph_font->get_ascent() + graph_font->get_height()), perf_items[pi]->get_text(1), c, r.size.y);
-
- float spacing = point_sep / float(cols);
- float from = r.size.width;
-
- List<Vector<float>>::Element *E = perf_history.front();
- float prev = -1;
- while (from >= 0 && E) {
- float m = perf_max[pi];
- if (m == 0) {
- m = 0.00001;
- }
- float h2 = E->get()[pi] / m;
- h2 = (1.0 - h2) * r.size.y;
-
- if (E != perf_history.front()) {
- perf_draw->draw_line(r.position + Point2(from, h2), r.position + Point2(from + spacing, prev), c, Math::round(EDSCALE));
- }
- prev = h2;
- E = E->next();
- from -= spacing;
- }
- }
-}
-
void ScriptEditorDebugger::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
@@ -915,10 +837,7 @@ void ScriptEditorDebugger::start(Ref<RemoteDebuggerPeer> p_peer) {
peer = p_peer;
ERR_FAIL_COND(p_peer.is_null());
- perf_history.clear();
- for (int i = 0; i < Performance::MONITOR_MAX; i++) {
- perf_max.write[i] = 0;
- }
+ performance_profiler->reset();
set_process(true);
breaked = false;
@@ -1666,63 +1585,8 @@ ScriptEditorDebugger::ScriptEditorDebugger(EditorNode *p_editor) {
}
{ //monitors
-
- HSplitContainer *hsp = memnew(HSplitContainer);
-
- perf_monitors = memnew(Tree);
- perf_monitors->set_columns(2);
- perf_monitors->set_column_title(0, TTR("Monitor"));
- perf_monitors->set_column_title(1, TTR("Value"));
- perf_monitors->set_column_titles_visible(true);
- perf_monitors->connect("item_edited", callable_mp(this, &ScriptEditorDebugger::_performance_select));
- hsp->add_child(perf_monitors);
-
- perf_draw = memnew(Control);
- perf_draw->set_clip_contents(true);
- perf_draw->connect("draw", callable_mp(this, &ScriptEditorDebugger::_performance_draw));
- hsp->add_child(perf_draw);
-
- hsp->set_name(TTR("Monitors"));
- hsp->set_split_offset(340 * EDSCALE);
- tabs->add_child(hsp);
- perf_max.resize(Performance::MONITOR_MAX);
-
- Map<String, TreeItem *> bases;
- TreeItem *root = perf_monitors->create_item();
- perf_monitors->set_hide_root(true);
- for (int i = 0; i < Performance::MONITOR_MAX; i++) {
- String n = Performance::get_singleton()->get_monitor_name(Performance::Monitor(i));
- Performance::MonitorType mtype = Performance::get_singleton()->get_monitor_type(Performance::Monitor(i));
- String base = n.get_slice("/", 0);
- String name = n.get_slice("/", 1);
- if (!bases.has(base)) {
- TreeItem *b = perf_monitors->create_item(root);
- b->set_text(0, base.capitalize());
- b->set_editable(0, false);
- b->set_selectable(0, false);
- b->set_expand_right(0, true);
- bases[base] = b;
- }
-
- TreeItem *it = perf_monitors->create_item(bases[base]);
- it->set_metadata(1, mtype);
- it->set_cell_mode(0, TreeItem::CELL_MODE_CHECK);
- it->set_editable(0, true);
- it->set_selectable(0, false);
- it->set_selectable(1, false);
- it->set_text(0, name.capitalize());
- perf_items.push_back(it);
- perf_max.write[i] = 0;
- }
-
- info_message = memnew(Label);
- info_message->set_text(TTR("Pick one or more items from the list to display the graph."));
- info_message->set_valign(Label::VALIGN_CENTER);
- info_message->set_align(Label::ALIGN_CENTER);
- info_message->set_autowrap(true);
- info_message->set_custom_minimum_size(Size2(100 * EDSCALE, 0));
- info_message->set_anchors_and_margins_preset(PRESET_WIDE, PRESET_MODE_KEEP_SIZE, 8 * EDSCALE);
- perf_draw->add_child(info_message);
+ performance_profiler = memnew(EditorPerformanceProfiler);
+ tabs->add_child(performance_profiler);
}
{ //vmem inspect
diff --git a/editor/debugger/script_editor_debugger.h b/editor/debugger/script_editor_debugger.h
index 2984051aa1..12fb82cc6f 100644
--- a/editor/debugger/script_editor_debugger.h
+++ b/editor/debugger/script_editor_debugger.h
@@ -52,6 +52,7 @@ class ItemList;
class EditorProfiler;
class EditorVisualProfiler;
class EditorNetworkProfiler;
+class EditorPerformanceProfiler;
class SceneDebuggerTree;
class ScriptEditorDebugger : public MarginContainer {
@@ -113,16 +114,8 @@ private:
// Each debugger should have it's tree in the future I guess.
const Tree *editor_remote_tree = nullptr;
- List<Vector<float>> perf_history;
- Vector<float> perf_max;
- Vector<TreeItem *> perf_items;
-
Map<int, String> profiler_signature;
- Tree *perf_monitors;
- Control *perf_draw;
- Label *info_message;
-
Tree *vmem_tree;
Button *vmem_refresh;
Button *vmem_export;
@@ -141,6 +134,7 @@ private:
EditorProfiler *profiler;
EditorVisualProfiler *visual_profiler;
EditorNetworkProfiler *network_profiler;
+ EditorPerformanceProfiler *performance_profiler;
EditorNode *editor;
@@ -152,8 +146,6 @@ private:
EditorDebuggerNode::CameraOverride camera_override;
- void _performance_draw();
- void _performance_select();
void _stack_dump_frame_selected();
void _file_selected(const String &p_file);
diff --git a/editor/editor_asset_installer.cpp b/editor/editor_asset_installer.cpp
index b43ee0e245..edb299bb90 100644
--- a/editor/editor_asset_installer.cpp
+++ b/editor/editor_asset_installer.cpp
@@ -159,7 +159,7 @@ void EditorAssetInstaller::open(const String &p_path, int p_depth) {
isdir = true;
}
- int pp = path.find_last("/");
+ int pp = path.rfind("/");
TreeItem *parent;
if (pp == -1) {
diff --git a/editor/editor_autoload_settings.cpp b/editor/editor_autoload_settings.cpp
index da0ff9f18f..4cd4f68fa2 100644
--- a/editor/editor_autoload_settings.cpp
+++ b/editor/editor_autoload_settings.cpp
@@ -477,6 +477,8 @@ void EditorAutoloadSettings::update_autoload() {
info.node->queue_delete();
info.node = nullptr;
}
+
+ ProjectSettings::get_singleton()->remove_autoload(info.name);
}
// Load new/changed autoloads
@@ -503,6 +505,12 @@ void EditorAutoloadSettings::update_autoload() {
}
}
+ ProjectSettings::AutoloadInfo prop_info;
+ prop_info.name = info->name;
+ prop_info.path = info->path;
+ prop_info.is_singleton = info->is_singleton;
+ ProjectSettings::get_singleton()->add_autoload(prop_info);
+
if (!info->in_editor && !info->is_singleton) {
// No reason to keep this node
memdelete(info->node);
diff --git a/editor/editor_feature_profile.cpp b/editor/editor_feature_profile.cpp
index 2a410c03e7..0d349eb247 100644
--- a/editor/editor_feature_profile.cpp
+++ b/editor/editor_feature_profile.cpp
@@ -335,7 +335,7 @@ void EditorFeatureProfileManager::_update_profile_list(const String &p_select_pr
}
if (!d->current_is_dir()) {
- int last_pos = f.find_last(".profile");
+ int last_pos = f.rfind(".profile");
if (last_pos != -1) {
profiles.push_back(f.substr(0, last_pos));
}
diff --git a/editor/editor_file_dialog.cpp b/editor/editor_file_dialog.cpp
index 663f3dd856..50be291c91 100644
--- a/editor/editor_file_dialog.cpp
+++ b/editor/editor_file_dialog.cpp
@@ -55,7 +55,7 @@ VBoxContainer *EditorFileDialog::get_vbox() {
}
void EditorFileDialog::_notification(int p_what) {
- if (p_what == NOTIFICATION_ENTER_TREE) {
+ if (p_what == NOTIFICATION_READY || p_what == NOTIFICATION_THEME_CHANGED) {
// update icons
mode_thumbnails->set_icon(item_list->get_theme_icon("FileThumbnail", "EditorIcons"));
mode_list->set_icon(item_list->get_theme_icon("FileList", "EditorIcons"));
@@ -936,7 +936,7 @@ void EditorFileDialog::set_current_file(const String &p_file) {
file->set_text(p_file);
update_dir();
invalidate();
- int lp = p_file.find_last(".");
+ int lp = p_file.rfind(".");
if (lp != -1) {
file->select(0, lp);
file->grab_focus();
@@ -951,7 +951,7 @@ void EditorFileDialog::set_current_path(const String &p_path) {
if (!p_path.size()) {
return;
}
- int pos = MAX(p_path.find_last("/"), p_path.find_last("\\"));
+ int pos = MAX(p_path.rfind("/"), p_path.rfind("\\"));
if (pos == -1) {
set_current_file(p_path);
} else {
diff --git a/editor/editor_file_system.cpp b/editor/editor_file_system.cpp
index d88c61d7b2..e367ed4989 100644
--- a/editor/editor_file_system.cpp
+++ b/editor/editor_file_system.cpp
@@ -233,9 +233,9 @@ void EditorFileSystem::_scan_filesystem() {
FileCache fc;
fc.type = split[1];
- fc.modification_time = split[2].to_int64();
- fc.import_modification_time = split[3].to_int64();
- fc.import_valid = split[4].to_int64() != 0;
+ fc.modification_time = split[2].to_int();
+ fc.import_modification_time = split[3].to_int();
+ fc.import_valid = split[4].to_int() != 0;
fc.import_group_file = split[5].strip_edges();
fc.script_class_name = split[6].get_slice("<>", 0);
fc.script_class_extends = split[6].get_slice("<>", 1);
@@ -1107,7 +1107,7 @@ void EditorFileSystem::_notification(int p_what) {
_queue_update_script_classes();
first_scan = false;
}
- } else if (!scanning) {
+ } else if (!scanning && thread) {
set_process(false);
if (filesystem) {
diff --git a/editor/editor_folding.cpp b/editor/editor_folding.cpp
index f0e6e3a799..a7e76e9b2b 100644
--- a/editor/editor_folding.cpp
+++ b/editor/editor_folding.cpp
@@ -251,7 +251,7 @@ void EditorFolding::_do_object_unfolds(Object *p_object, Set<RES> &resources) {
}
}
} else { //path
- int last = E->get().name.find_last("/");
+ int last = E->get().name.rfind("/");
if (last != -1) {
bool can_revert = EditorPropertyRevert::can_property_revert(p_object, E->get().name);
if (can_revert) {
diff --git a/editor/editor_fonts.cpp b/editor/editor_fonts.cpp
index cf00c536a7..100c76c32b 100644
--- a/editor/editor_fonts.cpp
+++ b/editor/editor_fonts.cpp
@@ -231,7 +231,7 @@ void editor_register_fonts(Ref<Theme> p_theme) {
// Default font
MAKE_DEFAULT_FONT(df, default_font_size);
- p_theme->set_font("font", "Node", df); // Default theme font
+ p_theme->set_default_font(df); // Default theme font
p_theme->set_font("main", "EditorFonts", df);
// Bold font
diff --git a/editor/editor_help_search.cpp b/editor/editor_help_search.cpp
index d2b9405552..4392538737 100644
--- a/editor/editor_help_search.cpp
+++ b/editor/editor_help_search.cpp
@@ -332,17 +332,10 @@ bool EditorHelpSearch::Runner::_phase_match_classes() {
if (search_flags & SEARCH_METHODS) {
for (int i = 0; i < class_doc.methods.size(); i++) {
String method_name = (search_flags & SEARCH_CASE_SENSITIVE) ? class_doc.methods[i].name : class_doc.methods[i].name.to_lower();
- String aux_term = (search_flags & SEARCH_CASE_SENSITIVE) ? term : term.to_lower();
-
- if (aux_term.begins_with(".")) {
- aux_term = aux_term.right(1);
- }
-
- if (aux_term.ends_with("(")) {
- aux_term = aux_term.left(aux_term.length() - 1).strip_edges();
- }
-
- if (aux_term.is_subsequence_of(method_name)) {
+ if (method_name.find(term) > -1 ||
+ (term.begins_with(".") && method_name.begins_with(term.right(1))) ||
+ (term.ends_with("(") && method_name.ends_with(term.left(term.length() - 1).strip_edges())) ||
+ (term.begins_with(".") && term.ends_with("(") && method_name == term.substr(1, term.length() - 2).strip_edges())) {
match.methods.push_back(const_cast<DocData::MethodDoc *>(&class_doc.methods[i]));
}
}
@@ -448,9 +441,9 @@ bool EditorHelpSearch::Runner::_phase_select_match() {
bool EditorHelpSearch::Runner::_match_string(const String &p_term, const String &p_string) const {
if (search_flags & SEARCH_CASE_SENSITIVE) {
- return p_term.is_subsequence_of(p_string);
+ return p_string.find(p_term) > -1;
} else {
- return p_term.is_subsequence_ofi(p_string);
+ return p_string.findn(p_term) > -1;
}
}
diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp
index a8ded44323..cf32ffb4e0 100644
--- a/editor/editor_inspector.cpp
+++ b/editor/editor_inspector.cpp
@@ -1504,9 +1504,9 @@ void EditorInspector::update_tree() {
String subgroup_base;
VBoxContainer *category_vbox = nullptr;
- List<PropertyInfo>
- plist;
+ List<PropertyInfo> plist;
object->get_property_list(&plist, true);
+ _update_script_class_properties(*object, plist);
HashMap<String, VBoxContainer *> item_path;
Map<VBoxContainer *, EditorInspectorSection *> section_map;
@@ -1572,7 +1572,30 @@ void EditorInspector::update_tree() {
category_vbox = nullptr; //reset
String type = p.name;
- category->icon = EditorNode::get_singleton()->get_class_icon(type, "Object");
+ if (!ClassDB::class_exists(type) && !ScriptServer::is_global_class(type) && p.hint_string.length() && FileAccess::exists(p.hint_string)) {
+ Ref<Script> s = ResourceLoader::load(p.hint_string, "Script");
+ String base_type;
+ if (s.is_valid()) {
+ base_type = s->get_instance_base_type();
+ }
+ while (s.is_valid()) {
+ StringName name = EditorNode::get_editor_data().script_class_get_name(s->get_path());
+ String icon_path = EditorNode::get_editor_data().script_class_get_icon_path(name);
+ if (name != StringName() && icon_path.length()) {
+ category->icon = ResourceLoader::load(icon_path, "Texture");
+ break;
+ }
+ s = s->get_base_script();
+ }
+ if (category->icon.is_null() && has_theme_icon(base_type, "EditorIcons")) {
+ category->icon = get_theme_icon(base_type, "EditorIcons");
+ }
+ }
+ if (category->icon.is_null()) {
+ if (type != String()) { // Can happen for built-in scripts.
+ category->icon = EditorNode::get_singleton()->get_class_icon(type, "Object");
+ }
+ }
category->label = type;
category->bg_color = get_theme_color("prop_category", "Editor");
@@ -1643,7 +1666,7 @@ void EditorInspector::update_tree() {
basename = group + "/" + basename;
}
- String name = (basename.find("/") != -1) ? basename.right(basename.find_last("/") + 1) : basename;
+ String name = (basename.find("/") != -1) ? basename.right(basename.rfind("/") + 1) : basename;
if (capitalize_paths) {
int dot = name.find(".");
@@ -1658,7 +1681,7 @@ void EditorInspector::update_tree() {
}
}
- String path = basename.left(basename.find_last("/"));
+ String path = basename.left(basename.rfind("/"));
if (use_filter && filter != "") {
String cat = path;
@@ -2370,6 +2393,93 @@ void EditorInspector::_feature_profile_changed() {
update_tree();
}
+void EditorInspector::_update_script_class_properties(const Object &p_object, List<PropertyInfo> &r_list) const {
+ Ref<Script> script = p_object.get_script();
+ if (script.is_null()) {
+ return;
+ }
+
+ List<StringName> classes;
+ Map<StringName, String> paths;
+
+ // NodeC -> NodeB -> NodeA
+ while (script.is_valid()) {
+ String n = EditorNode::get_editor_data().script_class_get_name(script->get_path());
+ if (n.length()) {
+ classes.push_front(n);
+ } else if (script->get_path() != String() && script->get_path().find("::") == -1) {
+ n = script->get_path().get_file();
+ classes.push_front(n);
+ } else {
+ n = TTR("Built-in script");
+ classes.push_front(n);
+ }
+ paths[n] = script->get_path();
+ script = script->get_base_script();
+ }
+
+ if (classes.empty()) {
+ return;
+ }
+
+ // Script Variables -> to insert: NodeC..B..A -> bottom (insert_here)
+ List<PropertyInfo>::Element *script_variables = NULL;
+ List<PropertyInfo>::Element *bottom = NULL;
+ List<PropertyInfo>::Element *insert_here = NULL;
+ for (List<PropertyInfo>::Element *E = r_list.front(); E; E = E->next()) {
+ PropertyInfo &pi = E->get();
+ if (pi.name != "Script Variables") {
+ continue;
+ }
+ script_variables = E;
+ bottom = r_list.insert_after(script_variables, PropertyInfo());
+ insert_here = bottom;
+ break;
+ }
+
+ Set<StringName> added;
+ for (List<StringName>::Element *E = classes.front(); E; E = E->next()) {
+ StringName name = E->get();
+ String path = paths[name];
+ Ref<Script> s;
+ if (path == String()) {
+ // Built-in script. It can't be inherited, so must be the script attached to the object.
+ s = p_object.get_script();
+ } else {
+ s = ResourceLoader::load(path, "Script");
+ }
+ ERR_FAIL_COND(!s->is_valid());
+ List<PropertyInfo> props;
+ s->get_script_property_list(&props);
+
+ // Script Variables -> NodeA -> bottom (insert_here)
+ List<PropertyInfo>::Element *category = r_list.insert_before(insert_here, PropertyInfo(Variant::NIL, name, PROPERTY_HINT_NONE, path, PROPERTY_USAGE_CATEGORY));
+
+ // Script Variables -> NodeA -> A props... -> bottom (insert_here)
+ for (List<PropertyInfo>::Element *P = props.front(); P; P = P->next()) {
+ PropertyInfo &pi = P->get();
+ if (added.has(pi.name)) {
+ continue;
+ }
+ added.insert(pi.name);
+
+ r_list.insert_before(insert_here, pi);
+ }
+
+ // Script Variables -> NodeA (insert_here) -> A props... -> bottom
+ insert_here = category;
+ }
+
+ // NodeC -> C props... -> NodeB..C..
+ r_list.erase(script_variables);
+ List<PropertyInfo>::Element *to_delete = bottom->next();
+ while (to_delete && !(to_delete->get().usage & PROPERTY_USAGE_CATEGORY)) {
+ r_list.erase(to_delete);
+ to_delete = bottom->next();
+ }
+ r_list.erase(bottom);
+}
+
void EditorInspector::_bind_methods() {
ClassDB::bind_method("_edit_request_change", &EditorInspector::_edit_request_change);
diff --git a/editor/editor_inspector.h b/editor/editor_inspector.h
index 90d995e36d..615ad97766 100644
--- a/editor/editor_inspector.h
+++ b/editor/editor_inspector.h
@@ -332,6 +332,7 @@ class EditorInspector : public ScrollContainer {
void _vscroll_changed(double);
void _feature_profile_changed();
+ void _update_script_class_properties(const Object &p_object, List<PropertyInfo> &r_list) const;
bool _is_property_disabled_by_feature_profile(const StringName &p_property);
diff --git a/editor/editor_log.h b/editor/editor_log.h
index 3bf5615346..73a8c3f0c5 100644
--- a/editor/editor_log.h
+++ b/editor/editor_log.h
@@ -32,7 +32,6 @@
#define EDITOR_LOG_H
#include "core/os/thread.h"
-#include "pane_drag.h"
#include "scene/gui/box_container.h"
#include "scene/gui/button.h"
#include "scene/gui/control.h"
@@ -50,7 +49,6 @@ class EditorLog : public VBoxContainer {
Label *title;
RichTextLabel *log;
HBoxContainer *title_hb;
- //PaneDrag *pd;
Button *tool_button;
static void _error_handler(void *p_self, const char *p_func, const char *p_file, int p_line, const char *p_error, const char *p_errorexp, ErrorHandlerType p_type);
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index bb34a45938..454170647f 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -85,6 +85,7 @@
#include "editor/editor_settings.h"
#include "editor/editor_spin_slider.h"
#include "editor/editor_themes.h"
+#include "editor/editor_translation_parser.h"
#include "editor/export_template_manager.h"
#include "editor/filesystem_dock.h"
#include "editor/import/editor_import_collada.h"
@@ -103,7 +104,6 @@
#include "editor/import_dock.h"
#include "editor/multi_node_edit.h"
#include "editor/node_dock.h"
-#include "editor/pane_drag.h"
#include "editor/plugin_config_dialog.h"
#include "editor/plugins/animation_blend_space_1d_editor.h"
#include "editor/plugins/animation_blend_space_2d_editor.h"
@@ -138,6 +138,7 @@
#include "editor/plugins/multimesh_editor_plugin.h"
#include "editor/plugins/navigation_polygon_editor_plugin.h"
#include "editor/plugins/node_3d_editor_plugin.h"
+#include "editor/plugins/packed_scene_translation_parser_plugin.h"
#include "editor/plugins/path_2d_editor_plugin.h"
#include "editor/plugins/path_3d_editor_plugin.h"
#include "editor/plugins/physical_bone_3d_editor_plugin.h"
@@ -178,6 +179,111 @@
EditorNode *EditorNode::singleton = nullptr;
+void EditorNode::disambiguate_filenames(const Vector<String> p_full_paths, Vector<String> &r_filenames) {
+ // Keep track of a list of "index sets," i.e. sets of indices
+ // within disambiguated_scene_names which contain the same name.
+ Vector<Set<int>> index_sets;
+ Map<String, int> scene_name_to_set_index;
+ for (int i = 0; i < r_filenames.size(); i++) {
+ String scene_name = r_filenames[i];
+ if (!scene_name_to_set_index.has(scene_name)) {
+ index_sets.append(Set<int>());
+ scene_name_to_set_index.insert(r_filenames[i], index_sets.size() - 1);
+ }
+ index_sets.write[scene_name_to_set_index[scene_name]].insert(i);
+ }
+
+ // For each index set with a size > 1, we need to disambiguate
+ for (int i = 0; i < index_sets.size(); i++) {
+ Set<int> iset = index_sets[i];
+ while (iset.size() > 1) {
+ // Append the parent folder to each scene name
+ for (Set<int>::Element *E = iset.front(); E; E = E->next()) {
+ int set_idx = E->get();
+ String scene_name = r_filenames[set_idx];
+ String full_path = p_full_paths[set_idx];
+
+ // Get rid of file extensions and res:// prefixes
+ if (scene_name.rfind(".") >= 0) {
+ scene_name = scene_name.substr(0, scene_name.rfind("."));
+ }
+ if (full_path.begins_with("res://")) {
+ full_path = full_path.substr(6);
+ }
+ if (full_path.rfind(".") >= 0) {
+ full_path = full_path.substr(0, full_path.rfind("."));
+ }
+
+ int scene_name_size = scene_name.size();
+ int full_path_size = full_path.size();
+ int difference = full_path_size - scene_name_size;
+
+ // Find just the parent folder of the current path and append it.
+ // If the current name is foo.tscn, and the full path is /some/folder/foo.tscn
+ // then slash_idx is the second '/', so that we select just "folder", and
+ // append that to yield "folder/foo.tscn".
+ if (difference > 0) {
+ String parent = full_path.substr(0, difference);
+ int slash_idx = parent.rfind("/");
+ slash_idx = parent.rfind("/", slash_idx - 1);
+ parent = slash_idx >= 0 ? parent.substr(slash_idx + 1) : parent;
+ r_filenames.write[set_idx] = parent + r_filenames[set_idx];
+ }
+ }
+
+ // Loop back through scene names and remove non-ambiguous names
+ bool can_proceed = false;
+ Set<int>::Element *E = iset.front();
+ while (E) {
+ String scene_name = r_filenames[E->get()];
+ bool duplicate_found = false;
+ for (Set<int>::Element *F = iset.front(); F; F = F->next()) {
+ if (E->get() == F->get()) {
+ continue;
+ }
+ String other_scene_name = r_filenames[F->get()];
+ if (other_scene_name == scene_name) {
+ duplicate_found = true;
+ break;
+ }
+ }
+
+ Set<int>::Element *to_erase = duplicate_found ? nullptr : E;
+
+ // We need to check that we could actually append anymore names
+ // if we wanted to for disambiguation. If we can't, then we have
+ // to abort even with ambiguous names. We clean the full path
+ // and the scene name first to remove extensions so that this
+ // comparison actually works.
+ String path = p_full_paths[E->get()];
+ if (path.begins_with("res://")) {
+ path = path.substr(6);
+ }
+ if (path.rfind(".") >= 0) {
+ path = path.substr(0, path.rfind("."));
+ }
+ if (scene_name.rfind(".") >= 0) {
+ scene_name = scene_name.substr(0, scene_name.rfind("."));
+ }
+
+ // We can proceed iff the full path is longer than the scene name,
+ // meaning that there is at least one more parent folder we can
+ // tack onto the name.
+ can_proceed = can_proceed || (path.size() - scene_name.size()) >= 1;
+
+ E = E->next();
+ if (to_erase) {
+ iset.erase(to_erase);
+ }
+ }
+
+ if (!can_proceed) {
+ break;
+ }
+ }
+ }
+}
+
void EditorNode::_update_scene_tabs() {
bool show_rb = EditorSettings::get_singleton()->get("interface/scene_tabs/show_script_button");
@@ -185,6 +291,16 @@ void EditorNode::_update_scene_tabs() {
DisplayServer::get_singleton()->global_menu_clear("_dock");
}
+ // Get all scene names, which may be ambiguous
+ Vector<String> disambiguated_scene_names;
+ Vector<String> full_path_names;
+ for (int i = 0; i < editor_data.get_edited_scene_count(); i++) {
+ disambiguated_scene_names.append(editor_data.get_scene_title(i));
+ full_path_names.append(editor_data.get_scene_path(i));
+ }
+
+ disambiguate_filenames(full_path_names, disambiguated_scene_names);
+
scene_tabs->clear_tabs();
Ref<Texture2D> script_icon = gui_base->get_theme_icon("Script", "EditorIcons");
for (int i = 0; i < editor_data.get_edited_scene_count(); i++) {
@@ -196,7 +312,7 @@ void EditorNode::_update_scene_tabs() {
int current = editor_data.get_edited_scene();
bool unsaved = (i == current) ? saved_version != editor_data.get_undo_redo().get_version() : editor_data.get_scene_version(i) != 0;
- scene_tabs->add_tab(editor_data.get_scene_title(i) + (unsaved ? "(*)" : ""), icon);
+ scene_tabs->add_tab(disambiguated_scene_names[i] + (unsaved ? "(*)" : ""), icon);
if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_GLOBAL_MENU)) {
DisplayServer::get_singleton()->global_menu_add_item("_dock", editor_data.get_scene_title(i) + (unsaved ? "(*)" : ""), callable_mp(this, &EditorNode::_global_menu_scene), i);
@@ -360,7 +476,7 @@ void EditorNode::_notification(int p_what) {
bool dof_jitter = GLOBAL_GET("rendering/quality/depth_of_field/depth_of_field_use_jitter");
RS::get_singleton()->camera_effects_set_dof_blur_quality(dof_quality, dof_jitter);
RS::get_singleton()->environment_set_ssao_quality(RS::EnvironmentSSAOQuality(int(GLOBAL_GET("rendering/quality/ssao/quality"))), GLOBAL_GET("rendering/quality/ssao/half_size"));
- RS::get_singleton()->screen_space_roughness_limiter_set_active(GLOBAL_GET("rendering/quality/screen_filters/screen_space_roughness_limiter"), GLOBAL_GET("rendering/quality/screen_filters/screen_space_roughness_limiter_curve"));
+ RS::get_singleton()->screen_space_roughness_limiter_set_active(GLOBAL_GET("rendering/quality/screen_filters/screen_space_roughness_limiter_enabled"), GLOBAL_GET("rendering/quality/screen_filters/screen_space_roughness_limiter_amount"), GLOBAL_GET("rendering/quality/screen_filters/screen_space_roughness_limiter_limit"));
bool glow_bicubic = int(GLOBAL_GET("rendering/quality/glow/upscale_mode")) > 0;
RS::get_singleton()->environment_glow_set_use_bicubic_upscale(glow_bicubic);
RS::EnvironmentSSRRoughnessQuality ssr_roughness_quality = RS::EnvironmentSSRRoughnessQuality(int(GLOBAL_GET("rendering/quality/screen_space_reflection/roughness_quality")));
@@ -376,6 +492,12 @@ void EditorNode::_notification(int p_what) {
RS::get_singleton()->directional_shadow_quality_set(directional_shadow_quality);
float probe_update_speed = GLOBAL_GET("rendering/lightmapper/probe_capture_update_speed");
RS::get_singleton()->lightmap_set_probe_capture_update_speed(probe_update_speed);
+ RS::EnvironmentSDFGIFramesToConverge frames_to_converge = RS::EnvironmentSDFGIFramesToConverge(int(GLOBAL_GET("rendering/sdfgi/frames_to_converge")));
+ RS::get_singleton()->environment_set_sdfgi_frames_to_converge(frames_to_converge);
+ RS::EnvironmentSDFGIRayCount ray_count = RS::EnvironmentSDFGIRayCount(int(GLOBAL_GET("rendering/sdfgi/probe_ray_count")));
+ RS::get_singleton()->environment_set_sdfgi_ray_count(ray_count);
+ RS::GIProbeQuality gi_probe_quality = RS::GIProbeQuality(int(GLOBAL_GET("rendering/quality/gi_probes/quality")));
+ RS::get_singleton()->gi_probe_set_quality(gi_probe_quality);
}
ResourceImporterTexture::get_singleton()->update_imports();
@@ -429,14 +551,14 @@ void EditorNode::_notification(int p_what) {
/* DO NOT LOAD SCENES HERE, WAIT FOR FILE SCANNING AND REIMPORT TO COMPLETE */
} break;
- case NOTIFICATION_WM_FOCUS_IN: {
+ case NOTIFICATION_APPLICATION_FOCUS_IN: {
// Restore the original FPS cap after focusing back on the editor
OS::get_singleton()->set_low_processor_usage_mode_sleep_usec(int(EDITOR_GET("interface/editor/low_processor_mode_sleep_usec")));
EditorFileSystem::get_singleton()->scan_changes();
} break;
- case NOTIFICATION_WM_FOCUS_OUT: {
+ case NOTIFICATION_APPLICATION_FOCUS_OUT: {
// Set a low FPS cap to decrease CPU/GPU usage while the editor is unfocused
OS::get_singleton()->set_low_processor_usage_mode_sleep_usec(int(EDITOR_GET("interface/editor/unfocused_low_processor_mode_sleep_usec")));
} break;
@@ -1103,20 +1225,25 @@ void EditorNode::_save_scene_with_preview(String p_file, int p_idx) {
_find_node_types(editor_data.get_edited_scene_root(), c2d, c3d);
- bool is2d;
- if (c3d < c2d) {
- is2d = true;
- } else {
- is2d = false;
- }
save.step(TTR("Creating Thumbnail"), 1);
//current view?
Ref<Image> img;
- if (is2d) {
+ // If neither 3D or 2D nodes are present, make a 1x1 black texture.
+ // We cannot fallback on the 2D editor, because it may not have been used yet,
+ // which would result in an invalid texture.
+ if (c3d == 0 && c2d == 0) {
+ img.instance();
+ img->create(1, 1, 0, Image::FORMAT_RGB8);
+ } else if (c3d < c2d) {
img = scene_root->get_texture()->get_data();
} else {
- img = Node3DEditor::get_singleton()->get_editor_viewport(0)->get_viewport_node()->get_texture()->get_data();
+ // The 3D editor may be disabled as a feature, but scenes can still be opened.
+ // This check prevents the preview from regenerating in case those scenes are then saved.
+ Ref<EditorFeatureProfile> profile = feature_profile_manager->get_current_profile();
+ if (!profile->is_feature_disabled(EditorFeatureProfile::FEATURE_3D)) {
+ img = Node3DEditor::get_singleton()->get_editor_viewport(0)->get_viewport_node()->get_texture()->get_data();
+ }
}
if (img.is_valid()) {
@@ -1921,7 +2048,6 @@ void EditorNode::_run(bool p_current, const String &p_custom) {
play_custom_scene_button->set_pressed(false);
play_custom_scene_button->set_icon(gui_base->get_theme_icon("PlayCustom", "EditorIcons"));
- String main_scene;
String run_filename;
String args;
bool skip_breakpoints;
@@ -2342,8 +2468,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
} break;
case RUN_PLAY: {
- _menu_option_confirm(RUN_STOP, true);
- _run(false);
+ run_play();
} break;
case RUN_PLAY_CUSTOM_SCENE: {
@@ -2354,8 +2479,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
play_custom_scene_button->set_pressed(false);
} else {
String last_custom_scene = run_custom_filename;
- _menu_option_confirm(RUN_STOP, true);
- _run(false, last_custom_scene);
+ run_play_custom(last_custom_scene);
}
} break;
@@ -2395,9 +2519,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
} break;
case RUN_PLAY_SCENE: {
- _save_default_environment();
- _menu_option_confirm(RUN_STOP, true);
- _run(true);
+ run_play_current();
} break;
case RUN_SCENE_SETTINGS: {
@@ -3405,10 +3527,14 @@ void EditorNode::_update_recent_scenes() {
void EditorNode::_quick_opened() {
Vector<String> files = quick_open->get_selected_files();
+ bool open_scene_dialog = quick_open->get_base_type() == "PackedScene";
for (int i = 0; i < files.size(); i++) {
String res_path = files[i];
- if (quick_open->get_base_type() == "PackedScene") {
+ List<String> scene_extensions;
+ ResourceLoader::get_recognized_extensions_for_type("PackedScene", &scene_extensions);
+
+ if (open_scene_dialog || scene_extensions.find(files[i].get_extension())) {
open_request(res_path);
} else {
load_resource(res_path);
@@ -3464,6 +3590,7 @@ void EditorNode::register_editor_types() {
ResourceSaver::set_timestamp_on_save(true);
ClassDB::register_class<EditorPlugin>();
+ ClassDB::register_class<EditorTranslationParserPlugin>();
ClassDB::register_class<EditorImportPlugin>();
ClassDB::register_class<EditorScript>();
ClassDB::register_class<EditorSelection>();
@@ -3637,22 +3764,14 @@ Ref<Texture2D> EditorNode::get_object_icon(const Object *p_object, const String
Ref<Texture2D> EditorNode::get_class_icon(const String &p_class, const String &p_fallback) const {
ERR_FAIL_COND_V_MSG(p_class.empty(), nullptr, "Class name cannot be empty.");
- if (gui_base->has_theme_icon(p_class, "EditorIcons")) {
- return gui_base->get_theme_icon(p_class, "EditorIcons");
- }
-
if (ScriptServer::is_global_class(p_class)) {
- String icon_path = EditorNode::get_editor_data().script_class_get_icon_path(p_class);
- Ref<ImageTexture> icon = _load_custom_class_icon(icon_path);
- if (icon.is_valid()) {
- return icon;
- }
-
- Ref<Script> script = ResourceLoader::load(ScriptServer::get_global_class_path(p_class), "Script");
+ Ref<ImageTexture> icon;
+ Ref<Script> script = EditorNode::get_editor_data().script_class_load_script(p_class);
+ StringName name = p_class;
while (script.is_valid()) {
- String current_icon_path;
- script->get_language()->get_global_class_name(script->get_path(), nullptr, &current_icon_path);
+ name = EditorNode::get_editor_data().script_class_get_name(script->get_path());
+ String current_icon_path = EditorNode::get_editor_data().script_class_get_icon_path(name);
icon = _load_custom_class_icon(current_icon_path);
if (icon.is_valid()) {
return icon;
@@ -3661,10 +3780,8 @@ Ref<Texture2D> EditorNode::get_class_icon(const String &p_class, const String &p
}
if (icon.is_null()) {
- icon = gui_base->get_theme_icon(ScriptServer::get_global_class_base(p_class), "EditorIcons");
+ icon = gui_base->get_theme_icon(ScriptServer::get_global_class_base(name), "EditorIcons");
}
-
- return icon;
}
const Map<String, Vector<EditorData::CustomType>> &p_map = EditorNode::get_editor_data().get_custom_types();
@@ -3679,6 +3796,10 @@ Ref<Texture2D> EditorNode::get_class_icon(const String &p_class, const String &p
}
}
+ if (gui_base->has_theme_icon(p_class, "EditorIcons")) {
+ return gui_base->get_theme_icon(p_class, "EditorIcons");
+ }
+
if (p_fallback.length() && gui_base->has_theme_icon(p_fallback, "EditorIcons")) {
return gui_base->get_theme_icon(p_fallback, "EditorIcons");
}
@@ -4157,7 +4278,6 @@ void EditorNode::_update_dock_slots_visibility() {
}
right_hsplit->hide();
- bottom_panel->hide();
} else {
for (int i = 0; i < DOCK_SLOT_MAX; i++) {
int tabs_visible = 0;
@@ -4187,7 +4307,6 @@ void EditorNode::_update_dock_slots_visibility() {
dock_slot[i]->set_current_tab(0);
}
}
- bottom_panel->show();
if (right_l_vsplit->is_visible() || right_r_vsplit->is_visible()) {
right_hsplit->show();
@@ -4405,10 +4524,35 @@ void EditorNode::run_play() {
_run(false);
}
+void EditorNode::run_play_current() {
+ _save_default_environment();
+ _menu_option_confirm(RUN_STOP, true);
+ _run(true);
+}
+
+void EditorNode::run_play_custom(const String &p_custom) {
+ _menu_option_confirm(RUN_STOP, true);
+ _run(false, p_custom);
+}
+
void EditorNode::run_stop() {
_menu_option_confirm(RUN_STOP, false);
}
+bool EditorNode::is_run_playing() const {
+ EditorRun::Status status = editor_run.get_status();
+ return (status == EditorRun::STATUS_PLAY || status == EditorRun::STATUS_PAUSED);
+}
+
+String EditorNode::get_run_playing_scene() const {
+ String run_filename = editor_run.get_running_scene();
+ if (run_filename == "" && is_run_playing()) {
+ run_filename = GLOBAL_DEF("application/run/main_scene", ""); // Must be the main scene then.
+ }
+
+ return run_filename;
+}
+
int EditorNode::get_current_tab() {
return scene_tabs->get_current_tab();
}
@@ -5401,10 +5545,10 @@ EditorNode::EditorNode() {
switch (display_scale) {
case 0: {
// Try applying a suitable display scale automatically
- const int screen = DisplayServer::get_singleton()->window_get_current_screen();
#ifdef OSX_ENABLED
- editor_set_scale(DisplayServer::get_singleton()->screen_get_scale(screen));
+ editor_set_scale(DisplayServer::get_singleton()->screen_get_max_scale());
#else
+ const int screen = DisplayServer::get_singleton()->window_get_current_screen();
editor_set_scale(DisplayServer::get_singleton()->screen_get_dpi(screen) >= 192 && DisplayServer::get_singleton()->screen_get_size(screen).x > 2000 ? 2.0 : 1.0);
#endif
} break;
@@ -6488,6 +6632,7 @@ EditorNode::EditorNode() {
}
resource_preview->add_preview_generator(Ref<EditorTexturePreviewPlugin>(memnew(EditorTexturePreviewPlugin)));
+ resource_preview->add_preview_generator(Ref<EditorImagePreviewPlugin>(memnew(EditorImagePreviewPlugin)));
resource_preview->add_preview_generator(Ref<EditorPackedScenePreviewPlugin>(memnew(EditorPackedScenePreviewPlugin)));
resource_preview->add_preview_generator(Ref<EditorMaterialPreviewPlugin>(memnew(EditorMaterialPreviewPlugin)));
resource_preview->add_preview_generator(Ref<EditorScriptPreviewPlugin>(memnew(EditorScriptPreviewPlugin)));
@@ -6539,6 +6684,10 @@ EditorNode::EditorNode() {
EditorExport::get_singleton()->add_export_plugin(export_text_to_binary_plugin);
+ Ref<PackedSceneEditorTranslationParserPlugin> packed_scene_translation_parser_plugin;
+ packed_scene_translation_parser_plugin.instance();
+ EditorTranslationParser::get_singleton()->add_parser(packed_scene_translation_parser_plugin, EditorTranslationParser::STANDARD);
+
_edit_current();
current = nullptr;
saving_resource = Ref<Resource>();
diff --git a/editor/editor_node.h b/editor/editor_node.h
index b0e0c5614c..dec28b0d2b 100644
--- a/editor/editor_node.h
+++ b/editor/editor_node.h
@@ -71,7 +71,6 @@ class ImportDock;
class MenuButton;
class NodeDock;
class OrphanResourcesDialog;
-class PaneDrag;
class Panel;
class PanelContainer;
class PluginConfigDialog;
@@ -255,7 +254,6 @@ private:
VSplitContainer *top_split;
HBoxContainer *bottom_hb;
Control *vp_base;
- PaneDrag *pd;
HBoxContainer *menu_hb;
Control *viewport;
@@ -687,6 +685,8 @@ public:
static void add_editor_plugin(EditorPlugin *p_editor, bool p_config_changed = false);
static void remove_editor_plugin(EditorPlugin *p_editor, bool p_config_changed = false);
+ static void disambiguate_filenames(const Vector<String> p_full_paths, Vector<String> &r_filenames);
+
void new_inherited_scene() { _menu_option_confirm(FILE_NEW_INHERITED_SCENE, false); }
void set_docks_visible(bool p_show);
@@ -865,7 +865,11 @@ public:
bool ensure_main_scene(bool p_from_native);
void run_play();
+ void run_play_current();
+ void run_play_custom(const String &p_custom);
void run_stop();
+ bool is_run_playing() const;
+ String get_run_playing_scene() const;
};
struct EditorProgress {
diff --git a/editor/editor_plugin.cpp b/editor/editor_plugin.cpp
index 32b799cd61..da0a0827d2 100644
--- a/editor/editor_plugin.cpp
+++ b/editor/editor_plugin.cpp
@@ -176,6 +176,30 @@ void EditorInterface::reload_scene_from_path(const String &scene_path) {
EditorNode::get_singleton()->reload_scene(scene_path);
}
+void EditorInterface::play_main_scene() {
+ EditorNode::get_singleton()->run_play();
+}
+
+void EditorInterface::play_current_scene() {
+ EditorNode::get_singleton()->run_play_current();
+}
+
+void EditorInterface::play_custom_scene(const String &scene_path) {
+ EditorNode::get_singleton()->run_play_custom(scene_path);
+}
+
+void EditorInterface::stop_playing_scene() {
+ EditorNode::get_singleton()->run_stop();
+}
+
+bool EditorInterface::is_playing_scene() const {
+ return EditorNode::get_singleton()->is_run_playing();
+}
+
+String EditorInterface::get_playing_scene() const {
+ return EditorNode::get_singleton()->get_run_playing_scene();
+}
+
Node *EditorInterface::get_edited_scene_root() {
return EditorNode::get_singleton()->get_edited_scene();
}
@@ -285,6 +309,12 @@ void EditorInterface::_bind_methods() {
ClassDB::bind_method(D_METHOD("edit_resource", "resource"), &EditorInterface::edit_resource);
ClassDB::bind_method(D_METHOD("open_scene_from_path", "scene_filepath"), &EditorInterface::open_scene_from_path);
ClassDB::bind_method(D_METHOD("reload_scene_from_path", "scene_filepath"), &EditorInterface::reload_scene_from_path);
+ ClassDB::bind_method(D_METHOD("play_main_scene"), &EditorInterface::play_main_scene);
+ ClassDB::bind_method(D_METHOD("play_current_scene"), &EditorInterface::play_current_scene);
+ ClassDB::bind_method(D_METHOD("play_custom_scene", "scene_filepath"), &EditorInterface::play_custom_scene);
+ ClassDB::bind_method(D_METHOD("stop_playing_scene"), &EditorInterface::stop_playing_scene);
+ ClassDB::bind_method(D_METHOD("is_playing_scene"), &EditorInterface::is_playing_scene);
+ ClassDB::bind_method(D_METHOD("get_playing_scene"), &EditorInterface::get_playing_scene);
ClassDB::bind_method(D_METHOD("get_open_scenes"), &EditorInterface::get_open_scenes);
ClassDB::bind_method(D_METHOD("get_edited_scene_root"), &EditorInterface::get_edited_scene_root);
ClassDB::bind_method(D_METHOD("get_resource_previewer"), &EditorInterface::get_resource_previewer);
@@ -663,6 +693,14 @@ bool EditorPlugin::get_remove_list(List<Node *> *p_list) {
void EditorPlugin::restore_global_state() {}
void EditorPlugin::save_global_state() {}
+void EditorPlugin::add_translation_parser_plugin(const Ref<EditorTranslationParserPlugin> &p_parser) {
+ EditorTranslationParser::get_singleton()->add_parser(p_parser, EditorTranslationParser::CUSTOM);
+}
+
+void EditorPlugin::remove_translation_parser_plugin(const Ref<EditorTranslationParserPlugin> &p_parser) {
+ EditorTranslationParser::get_singleton()->remove_parser(p_parser, EditorTranslationParser::CUSTOM);
+}
+
void EditorPlugin::add_import_plugin(const Ref<EditorImportPlugin> &p_importer) {
ResourceFormatImporter::get_singleton()->add_importer(p_importer);
EditorFileSystem::get_singleton()->call_deferred("scan");
@@ -796,6 +834,8 @@ void EditorPlugin::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_undo_redo"), &EditorPlugin::_get_undo_redo);
ClassDB::bind_method(D_METHOD("queue_save_layout"), &EditorPlugin::queue_save_layout);
+ ClassDB::bind_method(D_METHOD("add_translation_parser_plugin", "parser"), &EditorPlugin::add_translation_parser_plugin);
+ ClassDB::bind_method(D_METHOD("remove_translation_parser_plugin", "parser"), &EditorPlugin::remove_translation_parser_plugin);
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);
diff --git a/editor/editor_plugin.h b/editor/editor_plugin.h
index e84984d57a..685f69bf3f 100644
--- a/editor/editor_plugin.h
+++ b/editor/editor_plugin.h
@@ -34,6 +34,7 @@
#include "core/io/config_file.h"
#include "core/undo_redo.h"
#include "editor/editor_inspector.h"
+#include "editor/editor_translation_parser.h"
#include "editor/import/editor_import_plugin.h"
#include "editor/import/resource_importer_scene.h"
#include "editor/script_create_dialog.h"
@@ -72,6 +73,13 @@ public:
void open_scene_from_path(const String &scene_path);
void reload_scene_from_path(const String &scene_path);
+ void play_main_scene();
+ void play_current_scene();
+ void play_custom_scene(const String &scene_path);
+ void stop_playing_scene();
+ bool is_playing_scene() const;
+ String get_playing_scene() const;
+
Node *get_edited_scene_root();
Array get_open_scenes() const;
ScriptEditor *get_script_editor();
@@ -220,6 +228,9 @@ public:
virtual void restore_global_state();
virtual void save_global_state();
+ void add_translation_parser_plugin(const Ref<EditorTranslationParserPlugin> &p_parser);
+ void remove_translation_parser_plugin(const Ref<EditorTranslationParserPlugin> &p_parser);
+
void add_import_plugin(const Ref<EditorImportPlugin> &p_importer);
void remove_import_plugin(const Ref<EditorImportPlugin> &p_importer);
diff --git a/editor/editor_plugin_settings.cpp b/editor/editor_plugin_settings.cpp
index b5f1133a9e..fe49198e8f 100644
--- a/editor/editor_plugin_settings.cpp
+++ b/editor/editor_plugin_settings.cpp
@@ -39,7 +39,7 @@
#include "scene/gui/margin_container.h"
void EditorPluginSettings::_notification(int p_what) {
- if (p_what == NOTIFICATION_WM_FOCUS_IN) {
+ if (p_what == NOTIFICATION_WM_WINDOW_FOCUS_IN) {
update_plugins();
} else if (p_what == Node::NOTIFICATION_READY) {
plugin_config_dialog->connect_compat("plugin_ready", EditorNode::get_singleton(), "_on_plugin_ready");
diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp
index eee610e9a8..8f9c92ea15 100644
--- a/editor/editor_properties.cpp
+++ b/editor/editor_properties.cpp
@@ -377,13 +377,13 @@ void EditorPropertyMember::_property_select() {
selector->select_method_from_base_type(hint_text, current);
} else if (hint == MEMBER_METHOD_OF_INSTANCE) {
- Object *instance = ObjectDB::get_instance(ObjectID(hint_text.to_int64()));
+ Object *instance = ObjectDB::get_instance(ObjectID(hint_text.to_int()));
if (instance) {
selector->select_method_from_instance(instance, current);
}
} else if (hint == MEMBER_METHOD_OF_SCRIPT) {
- Object *obj = ObjectDB::get_instance(ObjectID(hint_text.to_int64()));
+ Object *obj = ObjectDB::get_instance(ObjectID(hint_text.to_int()));
if (Object::cast_to<Script>(obj)) {
selector->select_method_from_script(Object::cast_to<Script>(obj), current);
}
@@ -408,13 +408,13 @@ void EditorPropertyMember::_property_select() {
selector->select_property_from_base_type(hint_text, current);
} else if (hint == MEMBER_PROPERTY_OF_INSTANCE) {
- Object *instance = ObjectDB::get_instance(ObjectID(hint_text.to_int64()));
+ Object *instance = ObjectDB::get_instance(ObjectID(hint_text.to_int()));
if (instance) {
selector->select_property_from_instance(instance, current);
}
} else if (hint == MEMBER_PROPERTY_OF_SCRIPT) {
- Object *obj = ObjectDB::get_instance(ObjectID(hint_text.to_int64()));
+ Object *obj = ObjectDB::get_instance(ObjectID(hint_text.to_int()));
if (Object::cast_to<Script>(obj)) {
selector->select_property_from_script(Object::cast_to<Script>(obj), current);
}
@@ -488,7 +488,7 @@ void EditorPropertyEnum::setup(const Vector<String> &p_options) {
for (int i = 0; i < p_options.size(); i++) {
Vector<String> text_split = p_options[i].split(":");
if (text_split.size() != 1) {
- current_val = text_split[1].to_int64();
+ current_val = text_split[1].to_int();
}
options->add_item(text_split[0]);
options->set_item_metadata(i, current_val);
@@ -2983,8 +2983,16 @@ bool EditorPropertyResource::_is_drop_valid(const Dictionary &p_drag_data) const
String allowed_type = base_type;
Dictionary drag_data = p_drag_data;
- if (drag_data.has("type") && String(drag_data["type"]) == "resource") {
- Ref<Resource> res = drag_data["resource"];
+
+ Ref<Resource> res;
+ if (drag_data.has("type") && String(drag_data["type"]) == "script_list_element") {
+ ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(drag_data["script_list_element"]);
+ res = se->get_edited_resource();
+ } else if (drag_data.has("type") && String(drag_data["type"]) == "resource") {
+ res = drag_data["resource"];
+ }
+
+ if (res.is_valid()) {
for (int i = 0; i < allowed_type.get_slice_count(","); i++) {
String at = allowed_type.get_slice(",", i).strip_edges();
if (res.is_valid() && ClassDB::is_parent_class(res->get_class(), at)) {
@@ -3022,13 +3030,19 @@ void EditorPropertyResource::drop_data_fw(const Point2 &p_point, const Variant &
ERR_FAIL_COND(!_is_drop_valid(p_data));
Dictionary drag_data = p_data;
- if (drag_data.has("type") && String(drag_data["type"]) == "resource") {
- Ref<Resource> res = drag_data["resource"];
- if (res.is_valid()) {
- emit_changed(get_edited_property(), res);
- update_property();
- return;
- }
+
+ Ref<Resource> res;
+ if (drag_data.has("type") && String(drag_data["type"]) == "script_list_element") {
+ ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(drag_data["script_list_element"]);
+ res = se->get_edited_resource();
+ } else if (drag_data.has("type") && String(drag_data["type"]) == "resource") {
+ res = drag_data["resource"];
+ }
+
+ if (res.is_valid()) {
+ emit_changed(get_edited_property(), res);
+ update_property();
+ return;
}
if (drag_data.has("type") && String(drag_data["type"]) == "files") {
@@ -3036,9 +3050,9 @@ void EditorPropertyResource::drop_data_fw(const Point2 &p_point, const Variant &
if (files.size() == 1) {
String file = files[0];
- RES res = ResourceLoader::load(file);
- if (res.is_valid()) {
- emit_changed(get_edited_property(), res);
+ RES file_res = ResourceLoader::load(file);
+ if (file_res.is_valid()) {
+ emit_changed(get_edited_property(), file_res);
update_property();
return;
}
diff --git a/editor/editor_resource_preview.cpp b/editor/editor_resource_preview.cpp
index 7ac8fae156..d2250fed7a 100644
--- a/editor/editor_resource_preview.cpp
+++ b/editor/editor_resource_preview.cpp
@@ -110,7 +110,7 @@ void EditorResourcePreview::_preview_ready(const String &p_str, const Ref<Textur
uint64_t modified_time = 0;
if (p_str.begins_with("ID:")) {
- hash = uint32_t(p_str.get_slicec(':', 2).to_int64());
+ hash = uint32_t(p_str.get_slicec(':', 2).to_int());
path = "ID:" + p_str.get_slicec(':', 1);
} else {
modified_time = FileAccess::get_modified_time(path);
@@ -257,9 +257,9 @@ void EditorResourcePreview::_thread() {
_generate_preview(texture, small_texture, item, cache_base);
} else {
uint64_t modtime = FileAccess::get_modified_time(item.path);
- int tsize = f->get_line().to_int64();
+ int tsize = f->get_line().to_int();
bool has_small_texture = f->get_line().to_int();
- uint64_t last_modtime = f->get_line().to_int64();
+ uint64_t last_modtime = f->get_line().to_int();
bool cache_valid = true;
diff --git a/editor/editor_run.cpp b/editor/editor_run.cpp
index 1148a6c7ec..b49c50fa31 100644
--- a/editor/editor_run.cpp
+++ b/editor/editor_run.cpp
@@ -38,6 +38,10 @@ EditorRun::Status EditorRun::get_status() const {
return status;
}
+String EditorRun::get_running_scene() const {
+ return running_scene;
+}
+
Error EditorRun::run(const String &p_scene, const String &p_custom_args, const List<String> &p_breakpoints, const bool &p_skip_breakpoints) {
List<String> args;
@@ -108,24 +112,33 @@ Error EditorRun::run(const String &p_scene, const String &p_custom_args, const L
}
int window_placement = EditorSettings::get_singleton()->get("run/window_placement/rect");
+ bool hidpi_proj = ProjectSettings::get_singleton()->get("display/window/dpi/allow_hidpi");
+ int display_scale = 1;
+ if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_HIDPI)) {
+ if (OS::get_singleton()->is_hidpi_allowed()) {
+ if (hidpi_proj) {
+ display_scale = 1; // Both editor and project runs in hiDPI mode, do not scale.
+ } else {
+ display_scale = DisplayServer::get_singleton()->screen_get_max_scale(); // Editor is in hiDPI mode, project is not, scale down.
+ }
+ } else {
+ if (hidpi_proj) {
+ display_scale = (1.f / DisplayServer::get_singleton()->screen_get_max_scale()); // Editor is not in hiDPI mode, project is, scale up.
+ } else {
+ display_scale = 1; // Both editor and project runs in lowDPI mode, do not scale.
+ }
+ }
+ screen_rect.position /= display_scale;
+ screen_rect.size /= display_scale;
+ }
switch (window_placement) {
case 0: { // top left
-
args.push_back("--position");
args.push_back(itos(screen_rect.position.x) + "," + itos(screen_rect.position.y));
} break;
case 1: { // centered
- int display_scale = 1;
-#ifdef OSX_ENABLED
- display_scale = DisplayServer::get_singleton()->screen_get_scale(screen);
-#else
- if (DisplayServer::get_singleton()->screen_get_dpi(screen) >= 192 && DisplayServer::get_singleton()->screen_get_size(screen).x > 2000) {
- display_scale = 2;
- }
-#endif
-
- Vector2 pos = screen_rect.position + ((screen_rect.size / display_scale - desired_size) / 2).floor();
+ Vector2 pos = (screen_rect.position) + ((screen_rect.size - desired_size) / 2).floor();
args.push_back("--position");
args.push_back(itos(pos.x) + "," + itos(pos.y));
} break;
@@ -140,10 +153,8 @@ Error EditorRun::run(const String &p_scene, const String &p_custom_args, const L
args.push_back("--position");
args.push_back(itos(pos.x) + "," + itos(pos.y));
args.push_back("--maximized");
-
} break;
case 4: { // force fullscreen
-
Vector2 pos = screen_rect.position;
args.push_back("--position");
args.push_back(itos(pos.x) + "," + itos(pos.y));
@@ -196,6 +207,9 @@ Error EditorRun::run(const String &p_scene, const String &p_custom_args, const L
}
status = STATUS_PLAY;
+ if (p_scene != "") {
+ running_scene = p_scene;
+ }
return OK;
}
@@ -224,8 +238,10 @@ void EditorRun::stop() {
}
status = STATUS_STOP;
+ running_scene = "";
}
EditorRun::EditorRun() {
status = STATUS_STOP;
+ running_scene = "";
}
diff --git a/editor/editor_run.h b/editor/editor_run.h
index 06050436a9..a15d65d91b 100644
--- a/editor/editor_run.h
+++ b/editor/editor_run.h
@@ -46,9 +46,11 @@ public:
private:
Status status;
+ String running_scene;
public:
Status get_status() const;
+ String get_running_scene() const;
Error run(const String &p_scene, const String &p_custom_args, const List<String> &p_breakpoints, const bool &p_skip_breakpoints = false);
void run_native_notify() { status = STATUS_PLAY; }
void stop();
diff --git a/editor/editor_spin_slider.cpp b/editor/editor_spin_slider.cpp
index 67d92c4839..d76a3d2da7 100644
--- a/editor/editor_spin_slider.cpp
+++ b/editor/editor_spin_slider.cpp
@@ -182,8 +182,8 @@ void EditorSpinSlider::_grabber_gui_input(const Ref<InputEvent> &p_event) {
}
void EditorSpinSlider::_notification(int p_what) {
- if (p_what == NOTIFICATION_WM_FOCUS_OUT ||
- p_what == NOTIFICATION_WM_FOCUS_IN ||
+ if (p_what == NOTIFICATION_WM_WINDOW_FOCUS_OUT ||
+ p_what == NOTIFICATION_WM_WINDOW_FOCUS_IN ||
p_what == NOTIFICATION_EXIT_TREE) {
if (grabbing_spinner) {
grabber->hide();
diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp
index 5f59e6e70a..a93763810b 100644
--- a/editor/editor_themes.cpp
+++ b/editor/editor_themes.cpp
@@ -570,17 +570,8 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_stylebox("focus", "PopupMenu", style_menu);
theme->set_stylebox("disabled", "PopupMenu", style_menu);
- theme->set_stylebox("normal", "Button", style_menu);
- theme->set_stylebox("hover", "Button", style_menu);
- theme->set_stylebox("pressed", "Button", style_menu);
- theme->set_stylebox("focus", "Button", style_menu);
- theme->set_stylebox("disabled", "Button", style_menu);
-
theme->set_color("font_color", "MenuButton", font_color);
theme->set_color("font_color_hover", "MenuButton", font_color_hl);
- theme->set_color("font_color", "Button", font_color);
- theme->set_color("font_color_hover", "Button", font_color_hl);
- theme->set_color("font_color_pressed", "Button", accent_color);
theme->set_stylebox("MenuHover", "EditorStyles", style_menu_hover_border);
diff --git a/editor/editor_translation_parser.cpp b/editor/editor_translation_parser.cpp
new file mode 100644
index 0000000000..3f4864ad1e
--- /dev/null
+++ b/editor/editor_translation_parser.cpp
@@ -0,0 +1,163 @@
+/*************************************************************************/
+/* editor_translation_parser.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "editor_translation_parser.h"
+
+#include "core/error_macros.h"
+#include "core/os/file_access.h"
+#include "core/script_language.h"
+#include "core/set.h"
+
+EditorTranslationParser *EditorTranslationParser::singleton = nullptr;
+
+Error EditorTranslationParserPlugin::parse_file(const String &p_path, Vector<String> *r_extracted_strings) {
+ if (!get_script_instance())
+ return ERR_UNAVAILABLE;
+
+ if (get_script_instance()->has_method("parse_file")) {
+ Array extracted_strings;
+ get_script_instance()->call("parse_file", p_path, extracted_strings);
+ for (int i = 0; i < extracted_strings.size(); i++) {
+ r_extracted_strings->append(extracted_strings[i]);
+ }
+ return OK;
+ } else {
+ ERR_PRINT("Custom translation parser plugin's \"func parse_file(path, extracted_strings)\" is undefined.");
+ return ERR_UNAVAILABLE;
+ }
+}
+
+void EditorTranslationParserPlugin::get_recognized_extensions(List<String> *r_extensions) const {
+ if (!get_script_instance())
+ return;
+
+ if (get_script_instance()->has_method("get_recognized_extensions")) {
+ Array extensions = get_script_instance()->call("get_recognized_extensions");
+ for (int i = 0; i < extensions.size(); i++) {
+ r_extensions->push_back(extensions[i]);
+ }
+ } else {
+ ERR_PRINT("Custom translation parser plugin's \"func get_recognized_extensions()\" is undefined.");
+ }
+}
+
+void EditorTranslationParserPlugin::_bind_methods() {
+ ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::NIL, "parse_file", PropertyInfo(Variant::STRING, "path"), PropertyInfo(Variant::ARRAY, "extracted_strings")));
+ ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::ARRAY, "get_recognized_extensions"));
+}
+
+/////////////////////////
+
+void EditorTranslationParser::get_recognized_extensions(List<String> *r_extensions) const {
+ Set<String> extensions;
+ List<String> temp;
+ for (int i = 0; i < standard_parsers.size(); i++) {
+ standard_parsers[i]->get_recognized_extensions(&temp);
+ }
+ for (int i = 0; i < custom_parsers.size(); i++) {
+ custom_parsers[i]->get_recognized_extensions(&temp);
+ }
+ // Remove duplicates.
+ for (int i = 0; i < temp.size(); i++) {
+ extensions.insert(temp[i]);
+ }
+ for (auto E = extensions.front(); E; E = E->next()) {
+ r_extensions->push_back(E->get());
+ }
+}
+
+bool EditorTranslationParser::can_parse(const String &p_extension) const {
+ List<String> extensions;
+ get_recognized_extensions(&extensions);
+ for (int i = 0; i < extensions.size(); i++) {
+ if (p_extension == extensions[i]) {
+ return true;
+ }
+ }
+ return false;
+}
+
+Ref<EditorTranslationParserPlugin> EditorTranslationParser::get_parser(const String &p_extension) const {
+ // Consider user-defined parsers first.
+ for (int i = 0; i < custom_parsers.size(); i++) {
+ List<String> temp;
+ custom_parsers[i]->get_recognized_extensions(&temp);
+ for (int j = 0; j < temp.size(); j++) {
+ if (temp[j] == p_extension) {
+ return custom_parsers[i];
+ }
+ }
+ }
+
+ for (int i = 0; i < standard_parsers.size(); i++) {
+ List<String> temp;
+ standard_parsers[i]->get_recognized_extensions(&temp);
+ for (int j = 0; j < temp.size(); j++) {
+ if (temp[j] == p_extension) {
+ return standard_parsers[i];
+ }
+ }
+ }
+
+ WARN_PRINT("No translation parser available for \"" + p_extension + "\" extension.");
+
+ return nullptr;
+}
+
+void EditorTranslationParser::add_parser(const Ref<EditorTranslationParserPlugin> &p_parser, ParserType p_type) {
+ if (p_type == ParserType::STANDARD) {
+ standard_parsers.push_back(p_parser);
+ } else if (p_type == ParserType::CUSTOM) {
+ custom_parsers.push_back(p_parser);
+ }
+}
+
+void EditorTranslationParser::remove_parser(const Ref<EditorTranslationParserPlugin> &p_parser, ParserType p_type) {
+ if (p_type == ParserType::STANDARD) {
+ standard_parsers.erase(p_parser);
+ } else if (p_type == ParserType::CUSTOM) {
+ custom_parsers.erase(p_parser);
+ }
+}
+
+EditorTranslationParser *EditorTranslationParser::get_singleton() {
+ if (!singleton) {
+ singleton = memnew(EditorTranslationParser);
+ }
+ return singleton;
+}
+
+EditorTranslationParser::EditorTranslationParser() {
+}
+
+EditorTranslationParser::~EditorTranslationParser() {
+ memdelete(singleton);
+ singleton = nullptr;
+}
diff --git a/editor/editor_translation_parser.h b/editor/editor_translation_parser.h
new file mode 100644
index 0000000000..6d00bedfa4
--- /dev/null
+++ b/editor/editor_translation_parser.h
@@ -0,0 +1,72 @@
+/*************************************************************************/
+/* editor_translation_parser.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef EDITOR_TRANSLATION_PARSER_H
+#define EDITOR_TRANSLATION_PARSER_H
+
+#include "core/error_list.h"
+#include "core/reference.h"
+
+class EditorTranslationParserPlugin : public Reference {
+ GDCLASS(EditorTranslationParserPlugin, Reference);
+
+protected:
+ static void _bind_methods();
+
+public:
+ virtual Error parse_file(const String &p_path, Vector<String> *r_extracted_strings);
+ virtual void get_recognized_extensions(List<String> *r_extensions) const;
+};
+
+class EditorTranslationParser {
+ static EditorTranslationParser *singleton;
+
+public:
+ enum ParserType {
+ STANDARD, // GDScript, CSharp, ...
+ CUSTOM // User-defined parser plugins. This will override standard parsers if the same extension type is defined.
+ };
+
+ static EditorTranslationParser *get_singleton();
+
+ Vector<Ref<EditorTranslationParserPlugin>> standard_parsers;
+ Vector<Ref<EditorTranslationParserPlugin>> custom_parsers;
+
+ void get_recognized_extensions(List<String> *r_extensions) const;
+ bool can_parse(const String &p_extension) const;
+ Ref<EditorTranslationParserPlugin> get_parser(const String &p_extension) const;
+ void add_parser(const Ref<EditorTranslationParserPlugin> &p_parser, ParserType p_type);
+ void remove_parser(const Ref<EditorTranslationParserPlugin> &p_parser, ParserType p_type);
+
+ EditorTranslationParser();
+ ~EditorTranslationParser();
+};
+
+#endif // EDITOR_TRANSLATION_PARSER_H
diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp
index c700fdccad..4f37fcf39c 100644
--- a/editor/filesystem_dock.cpp
+++ b/editor/filesystem_dock.cpp
@@ -1688,7 +1688,7 @@ void FileSystemDock::_file_option(int p_option, const Vector<String> &p_selected
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("."));
+ rename_dialog_text->select(0, name.rfind("."));
} else {
String name = to_rename.path.substr(0, to_rename.path.length() - 1).get_file();
rename_dialog->set_title(TTR("Renaming folder:") + " " + name);
@@ -1732,7 +1732,7 @@ void FileSystemDock::_file_option(int p_option, const Vector<String> &p_selected
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("."));
+ duplicate_dialog_text->select(0, name.rfind("."));
} else {
String name = to_duplicate.path.substr(0, to_duplicate.path.length() - 1).get_file();
duplicate_dialog->set_title(TTR("Duplicating folder:") + " " + name);
@@ -2313,7 +2313,7 @@ void FileSystemDock::_tree_rmb_select(const Vector2 &p_pos) {
tree_popup->clear();
tree_popup->set_size(Size2(1, 1));
_file_and_folders_fill_popup(tree_popup, paths);
- tree_popup->set_position(tree->get_global_position() + p_pos);
+ tree_popup->set_position(tree->get_screen_position() + p_pos);
tree_popup->popup();
}
}
@@ -2508,10 +2508,10 @@ void FileSystemDock::_bind_methods() {
ClassDB::bind_method(D_METHOD("_tree_thumbnail_done"), &FileSystemDock::_tree_thumbnail_done);
ClassDB::bind_method(D_METHOD("_select_file"), &FileSystemDock::_select_file);
- ClassDB::bind_method(D_METHOD("get_drag_data_fw"), &FileSystemDock::get_drag_data_fw);
- ClassDB::bind_method(D_METHOD("can_drop_data_fw"), &FileSystemDock::can_drop_data_fw);
- ClassDB::bind_method(D_METHOD("drop_data_fw"), &FileSystemDock::drop_data_fw);
- ClassDB::bind_method(D_METHOD("navigate_to_path"), &FileSystemDock::navigate_to_path);
+ ClassDB::bind_method(D_METHOD("get_drag_data_fw", "position", "from"), &FileSystemDock::get_drag_data_fw);
+ ClassDB::bind_method(D_METHOD("can_drop_data_fw", "position", "data", "from"), &FileSystemDock::can_drop_data_fw);
+ ClassDB::bind_method(D_METHOD("drop_data_fw", "position", "data", "from"), &FileSystemDock::drop_data_fw);
+ ClassDB::bind_method(D_METHOD("navigate_to_path", "path"), &FileSystemDock::navigate_to_path);
ClassDB::bind_method(D_METHOD("_update_import_dock"), &FileSystemDock::_update_import_dock);
diff --git a/editor/icons/InterpolatedCamera.svg b/editor/icons/InterpolatedCamera.svg
deleted file mode 100644
index 4bc4ba1ee9..0000000000
--- a/editor/icons/InterpolatedCamera.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m9.5.00004c-1.5691.0017903-2.8718 1.2125-2.9883 2.7773-.55103-.49952-1.268-.77655-2.0117-.77734-1.6569 0-3 1.3431-3 3 .00179 1.2698.80282 2.4009 2 2.8242v2.1758c0 .554.44599 1 1 1h6c.55401 0 .9853-.4462 1-1v-1l3 2v-6l-3 2v-1.7695c.63486-.56783.99842-1.3788 1-2.2305 0-1.6569-1.3431-3-3-3zm-6 12v4h1v-4zm3 0v4h1v-1h1c.55228 0 1-.44772 1-1v-1c0-.55228-.44824-1.024-1-1h-1zm5 0c-.55228 0-1 .44772-1 1v2c0 .55228.44772 1 1 1h1c.55228 0 1-.44772 1-1v-2c0-.55228-.44772-1-1-1zm-4 1h1v1h-1zm4 0h1v2h-1z" fill="#fc9c9c"/></svg> \ No newline at end of file
diff --git a/editor/icons/ToolButton.svg b/editor/icons/ToolButton.svg
deleted file mode 100644
index 98a41d2a08..0000000000
--- a/editor/icons/ToolButton.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m11 1.1738c-1.1979.4235-1.999 1.5557-2 2.8262.0009552 1.2705.80214 2.4027 2 2.8262v7.1738c0 .554.446 1 1 1s1-.446 1-1v-7.1758c1.1972-.4232 1.9982-1.5544 2-2.8242-.0018-1.2698-.80282-2.401-2-2.8242v2.8242c0 .5523-.44772 1-1 1s-1-.4477-1-1zm-7 1.8262v3.1328l-1.4453-.96484-1.1094 1.6641 3 2c.3359.22389.77347.22389 1.1094 0l3-2-1.1094-1.6641-1.4453.96484v-3.1328zm-.5 8c-.831 0-1.5.669-1.5 1.5v.5h-1v2h8v-2h-1v-.5c0-.831-.669-1.5-1.5-1.5z" fill="#a5efac"/></svg> \ No newline at end of file
diff --git a/editor/import/resource_importer_scene.cpp b/editor/import/resource_importer_scene.cpp
index 65ebf9dc4f..5dcdf6bec4 100644
--- a/editor/import/resource_importer_scene.cpp
+++ b/editor/import/resource_importer_scene.cpp
@@ -943,9 +943,9 @@ void ResourceImporterScene::_make_external_resources(Node *p_node, const String
ERR_CONTINUE(anim.is_null());
if (!p_animations.has(anim)) {
- // We are making external files so they are modifiable
+ // Tracks from source file should be set as imported, anything else is a custom track.
for (int i = 0; i < anim->get_track_count(); i++) {
- anim->track_set_imported(i, false);
+ anim->track_set_imported(i, true);
}
String ext_name;
@@ -957,10 +957,9 @@ void ResourceImporterScene::_make_external_resources(Node *p_node, const String
}
if (FileAccess::exists(ext_name) && p_keep_animations) {
- //try to keep custom animation tracks
+ // Copy custom animation tracks from previously imported files.
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);
@@ -970,7 +969,7 @@ void ResourceImporterScene::_make_external_resources(Node *p_node, const String
}
}
- anim->set_path(ext_name, true); //if not set, then its never saved externally
+ anim->set_path(ext_name, true); // Set path to save externally.
ResourceSaver::save(ext_name, anim, ResourceSaver::FLAG_CHANGE_PATH);
p_animations[anim] = anim;
}
diff --git a/editor/plugins/abstract_polygon_2d_editor.cpp b/editor/plugins/abstract_polygon_2d_editor.cpp
index e99ffe2b83..49e67f3605 100644
--- a/editor/plugins/abstract_polygon_2d_editor.cpp
+++ b/editor/plugins/abstract_polygon_2d_editor.cpp
@@ -369,7 +369,7 @@ bool AbstractPolygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event)
} else {
const real_t grab_threshold = EDITOR_GET("editors/poly_editor/point_grab_radius");
- if (!_is_line() && wip.size() > 1 && xform.xform(wip[0]).distance_to(gpoint) < grab_threshold) {
+ if (!_is_line() && wip.size() > 1 && xform.xform(wip[0]).distance_to(xform.xform(cpoint)) < grab_threshold) {
//wip closed
_wip_close();
diff --git a/editor/plugins/animation_player_editor_plugin.cpp b/editor/plugins/animation_player_editor_plugin.cpp
index 035526ca55..de04a299fb 100644
--- a/editor/plugins/animation_player_editor_plugin.cpp
+++ b/editor/plugins/animation_player_editor_plugin.cpp
@@ -702,30 +702,26 @@ void AnimationPlayerEditor::_animation_edit() {
}
}
-void AnimationPlayerEditor::_dialog_action(String p_file) {
+void AnimationPlayerEditor::_dialog_action(String p_path) {
switch (current_option) {
case RESOURCE_LOAD: {
ERR_FAIL_COND(!player);
- Ref<Resource> res = ResourceLoader::load(p_file, "Animation");
- ERR_FAIL_COND_MSG(res.is_null(), "Cannot load Animation from file '" + p_file + "'.");
- ERR_FAIL_COND_MSG(!res->is_class("Animation"), "Loaded resource from file '" + p_file + "' is not Animation.");
- if (p_file.find_last("/") != -1) {
- p_file = p_file.substr(p_file.find_last("/") + 1, p_file.length());
- }
- if (p_file.find_last("\\") != -1) {
- p_file = p_file.substr(p_file.find_last("\\") + 1, p_file.length());
- }
+ Ref<Resource> res = ResourceLoader::load(p_path, "Animation");
+ ERR_FAIL_COND_MSG(res.is_null(), "Cannot load Animation from file '" + p_path + "'.");
+ ERR_FAIL_COND_MSG(!res->is_class("Animation"), "Loaded resource from file '" + p_path + "' is not Animation.");
- if (p_file.find(".") != -1) {
- p_file = p_file.substr(0, p_file.find("."));
+ String anim_name = p_path.get_file();
+ int ext_pos = anim_name.rfind(".");
+ if (ext_pos != -1) {
+ anim_name = anim_name.substr(0, ext_pos);
}
undo_redo->create_action(TTR("Load Animation"));
- undo_redo->add_do_method(player, "add_animation", p_file, res);
- undo_redo->add_undo_method(player, "remove_animation", p_file);
- if (player->has_animation(p_file)) {
- undo_redo->add_undo_method(player, "add_animation", p_file, player->get_animation(p_file));
+ undo_redo->add_do_method(player, "add_animation", anim_name, res);
+ undo_redo->add_undo_method(player, "remove_animation", anim_name);
+ if (player->has_animation(anim_name)) {
+ undo_redo->add_undo_method(player, "add_animation", anim_name, player->get_animation(anim_name));
}
undo_redo->add_do_method(this, "_animation_player_changed", player);
undo_redo->add_undo_method(this, "_animation_player_changed", player);
@@ -741,7 +737,7 @@ void AnimationPlayerEditor::_dialog_action(String p_file) {
RES current_res = RES(Object::cast_to<Resource>(*anim));
- _animation_save_in_path(current_res, p_file);
+ _animation_save_in_path(current_res, p_path);
}
}
}
diff --git a/editor/plugins/animation_tree_editor_plugin.cpp b/editor/plugins/animation_tree_editor_plugin.cpp
index ec3e25f999..dc813896ff 100644
--- a/editor/plugins/animation_tree_editor_plugin.cpp
+++ b/editor/plugins/animation_tree_editor_plugin.cpp
@@ -238,7 +238,7 @@ AnimationTreeEditor::AnimationTreeEditor() {
add_child(memnew(HSeparator));
singleton = this;
- editor_base = memnew(PanelContainer);
+ editor_base = memnew(MarginContainer);
editor_base->set_v_size_flags(SIZE_EXPAND_FILL);
add_child(editor_base);
diff --git a/editor/plugins/animation_tree_editor_plugin.h b/editor/plugins/animation_tree_editor_plugin.h
index 25af81ea9b..79a010b0c0 100644
--- a/editor/plugins/animation_tree_editor_plugin.h
+++ b/editor/plugins/animation_tree_editor_plugin.h
@@ -55,7 +55,7 @@ class AnimationTreeEditor : public VBoxContainer {
HBoxContainer *path_hb;
AnimationTree *tree;
- PanelContainer *editor_base;
+ MarginContainer *editor_base;
Vector<String> button_path;
Vector<String> edited_path;
diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp
index bf698a5ceb..3af0b0d4e1 100644
--- a/editor/plugins/canvas_item_editor_plugin.cpp
+++ b/editor/plugins/canvas_item_editor_plugin.cpp
@@ -1326,6 +1326,18 @@ bool CanvasItemEditor::_gui_input_zoom_or_pan(const Ref<InputEvent> &p_event, bo
Ref<InputEventPanGesture> pan_gesture = p_event;
if (pan_gesture.is_valid() && !p_already_accepted) {
+ // If control key pressed, then zoom instead of pan
+ if (pan_gesture->get_control()) {
+ const float factor = pan_gesture->get_delta().y;
+ float new_zoom = _get_next_zoom_value(-1);
+
+ if (factor != 1.f) {
+ new_zoom = zoom * ((new_zoom / zoom - 1.f) * factor + 1.f);
+ }
+ _zoom_on_position(new_zoom, pan_gesture->get_position());
+ return true;
+ }
+
// Pan gesture
const Vector2 delta = (int(EditorSettings::get_singleton()->get("editors/2d/pan_speed")) / zoom) * pan_gesture->get_delta();
view_offset.x += delta.x;
@@ -6137,6 +6149,11 @@ bool CanvasItemEditorViewport::_create_instance(Node *parent, String &path, cons
Vector2 target_pos = canvas_item_editor->get_canvas_transform().affine_inverse().xform(p_point);
target_pos = canvas_item_editor->snap_point(target_pos);
target_pos = parent_ci->get_global_transform_with_canvas().affine_inverse().xform(target_pos);
+ // Preserve instance position of the original scene.
+ CanvasItem *instance_ci = Object::cast_to<CanvasItem>(instanced_scene);
+ if (instance_ci) {
+ target_pos += instance_ci->_edit_get_position();
+ }
editor_data->get_undo_redo().add_do_method(instanced_scene, "set_position", target_pos);
}
diff --git a/editor/plugins/collision_shape_2d_editor_plugin.cpp b/editor/plugins/collision_shape_2d_editor_plugin.cpp
index 596629f8e8..105ac24950 100644
--- a/editor/plugins/collision_shape_2d_editor_plugin.cpp
+++ b/editor/plugins/collision_shape_2d_editor_plugin.cpp
@@ -242,9 +242,11 @@ void CollisionShape2DEditor::commit_handle(int idx, Variant &p_org) {
} break;
case CONCAVE_POLYGON_SHAPE: {
+ // Cannot be edited directly, use CollisionPolygon2D instead.
} break;
case CONVEX_POLYGON_SHAPE: {
+ // Cannot be edited directly, use CollisionPolygon2D instead.
} break;
case LINE_SHAPE: {
diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp
index 896471dab5..b51ea9e1c6 100644
--- a/editor/plugins/node_3d_editor_plugin.cpp
+++ b/editor/plugins/node_3d_editor_plugin.cpp
@@ -487,6 +487,10 @@ ObjectID Node3DEditorViewport::_select_ray(const Point2 &p_pos, bool p_append, b
Vector3 pos = _get_ray_pos(p_pos);
Vector2 shrinked_pos = p_pos / subviewport_container->get_stretch_shrink();
+ if (viewport->get_debug_draw() == Viewport::DEBUG_DRAW_SDFGI_PROBES) {
+ RS::get_singleton()->sdfgi_set_debug_probe_select(pos, ray);
+ }
+
Vector<ObjectID> instances = RenderingServer::get_singleton()->instances_cull_ray(pos, ray, get_tree()->get_root()->get_world_3d()->get_scenario());
Set<Ref<EditorNode3DGizmo>> found_gizmos;
@@ -2106,12 +2110,7 @@ void Node3DEditorViewport::_nav_orbit(Ref<InputEventWithModifiers> p_event, cons
cursor.x_rot += p_relative.y * radians_per_pixel;
}
cursor.y_rot += p_relative.x * radians_per_pixel;
- if (cursor.x_rot > Math_PI / 2.0) {
- cursor.x_rot = Math_PI / 2.0;
- }
- if (cursor.x_rot < -Math_PI / 2.0) {
- cursor.x_rot = -Math_PI / 2.0;
- }
+ cursor.x_rot = CLAMP(cursor.x_rot, -1.57, 1.57);
name = "";
_update_name();
}
@@ -2139,12 +2138,7 @@ void Node3DEditorViewport::_nav_look(Ref<InputEventWithModifiers> p_event, const
cursor.x_rot += p_relative.y * radians_per_pixel;
}
cursor.y_rot += p_relative.x * radians_per_pixel;
- if (cursor.x_rot > Math_PI / 2.0) {
- cursor.x_rot = Math_PI / 2.0;
- }
- if (cursor.x_rot < -Math_PI / 2.0) {
- cursor.x_rot = -Math_PI / 2.0;
- }
+ cursor.x_rot = CLAMP(cursor.x_rot, -1.57, 1.57);
// Look is like the opposite of Orbit: the focus point rotates around the camera
Transform camera_transform = to_camera_transform(cursor);
@@ -2994,7 +2988,9 @@ void Node3DEditorViewport::_menu_option(int p_option) {
case VIEW_DISPLAY_DEBUG_SSAO:
case VIEW_DISPLAY_DEBUG_PSSM_SPLITS:
case VIEW_DISPLAY_DEBUG_DECAL_ATLAS:
- case VIEW_DISPLAY_DEBUG_ROUGHNESS_LIMITER: {
+ case VIEW_DISPLAY_DEBUG_SDFGI:
+ case VIEW_DISPLAY_DEBUG_SDFGI_PROBES:
+ case VIEW_DISPLAY_DEBUG_GI_BUFFER: {
static const int display_options[] = {
VIEW_DISPLAY_NORMAL,
VIEW_DISPLAY_WIREFRAME,
@@ -3010,9 +3006,11 @@ void Node3DEditorViewport::_menu_option(int p_option) {
VIEW_DISPLAY_DEBUG_GIPROBE_EMISSION,
VIEW_DISPLAY_DEBUG_SCENE_LUMINANCE,
VIEW_DISPLAY_DEBUG_SSAO,
- VIEW_DISPLAY_DEBUG_ROUGHNESS_LIMITER,
+ VIEW_DISPLAY_DEBUG_GI_BUFFER,
VIEW_DISPLAY_DEBUG_PSSM_SPLITS,
VIEW_DISPLAY_DEBUG_DECAL_ATLAS,
+ VIEW_DISPLAY_DEBUG_SDFGI,
+ VIEW_DISPLAY_DEBUG_SDFGI_PROBES,
VIEW_MAX
};
static const Viewport::DebugDraw debug_draw_modes[] = {
@@ -3030,9 +3028,11 @@ void Node3DEditorViewport::_menu_option(int p_option) {
Viewport::DEBUG_DRAW_GI_PROBE_EMISSION,
Viewport::DEBUG_DRAW_SCENE_LUMINANCE,
Viewport::DEBUG_DRAW_SSAO,
- Viewport::DEBUG_DRAW_ROUGHNESS_LIMITER,
+ Viewport::DEBUG_DRAW_GI_BUFFER,
Viewport::DEBUG_DRAW_PSSM_SPLITS,
Viewport::DEBUG_DRAW_DECAL_ATLAS,
+ Viewport::DEBUG_DRAW_SDFGI,
+ Viewport::DEBUG_DRAW_SDFGI_PROBES,
};
int idx = 0;
@@ -3218,7 +3218,7 @@ void Node3DEditorViewport::update_transform_gizmo_view() {
Vector3 camz = -camera_xform.get_basis().get_axis(2).normalized();
Vector3 camy = -camera_xform.get_basis().get_axis(1).normalized();
Plane p(camera_xform.origin, camz);
- float gizmo_d = Math::abs(p.distance_to(xform.origin));
+ float gizmo_d = MAX(Math::abs(p.distance_to(xform.origin)), CMP_EPSILON);
float d0 = camera->unproject_position(camera_xform.origin + camz * gizmo_d).y;
float d1 = camera->unproject_position(camera_xform.origin + camz * gizmo_d + camy).y;
float dd = Math::abs(d0 - d1);
@@ -3908,11 +3908,14 @@ Node3DEditorViewport::Node3DEditorViewport(Node3DEditor *p_spatial_editor, Edito
display_submenu->add_radio_check_item(TTR("GIProbe Albedo"), VIEW_DISPLAY_DEBUG_GIPROBE_ALBEDO);
display_submenu->add_radio_check_item(TTR("GIProbe Emission"), VIEW_DISPLAY_DEBUG_GIPROBE_EMISSION);
display_submenu->add_separator();
+ display_submenu->add_radio_check_item(TTR("SDFGI Cascades"), VIEW_DISPLAY_DEBUG_SDFGI);
+ display_submenu->add_radio_check_item(TTR("SDFGI Probes"), VIEW_DISPLAY_DEBUG_SDFGI_PROBES);
+ display_submenu->add_separator();
display_submenu->add_radio_check_item(TTR("Scene Luminance"), VIEW_DISPLAY_DEBUG_SCENE_LUMINANCE);
display_submenu->add_separator();
display_submenu->add_radio_check_item(TTR("SSAO"), VIEW_DISPLAY_DEBUG_SSAO);
display_submenu->add_separator();
- display_submenu->add_radio_check_item(TTR("Roughness Limiter"), VIEW_DISPLAY_DEBUG_ROUGHNESS_LIMITER);
+ display_submenu->add_radio_check_item(TTR("GI Buffer"), VIEW_DISPLAY_DEBUG_GI_BUFFER);
display_submenu->set_name("display_advanced");
view_menu->get_popup()->add_submenu_item(TTR("Display Advanced..."), "display_advanced", VIEW_DISPLAY_ADVANCED);
view_menu->get_popup()->add_separator();
@@ -4958,7 +4961,7 @@ void Node3DEditor::_menu_item_pressed(int p_option) {
for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
Node3D *spatial = Object::cast_to<Node3D>(E->get());
- if (!spatial || !spatial->is_visible_in_tree()) {
+ if (!spatial || !spatial->is_inside_tree()) {
continue;
}
@@ -4972,8 +4975,8 @@ void Node3DEditor::_menu_item_pressed(int p_option) {
undo_redo->add_undo_method(this, "emit_signal", "item_lock_status_changed");
}
- undo_redo->add_do_method(this, "_refresh_menu_icons", Variant());
- undo_redo->add_undo_method(this, "_refresh_menu_icons", Variant());
+ undo_redo->add_do_method(this, "_refresh_menu_icons");
+ undo_redo->add_undo_method(this, "_refresh_menu_icons");
undo_redo->commit_action();
} break;
case MENU_UNLOCK_SELECTED: {
@@ -4983,7 +4986,7 @@ void Node3DEditor::_menu_item_pressed(int p_option) {
for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
Node3D *spatial = Object::cast_to<Node3D>(E->get());
- if (!spatial || !spatial->is_visible_in_tree()) {
+ if (!spatial || !spatial->is_inside_tree()) {
continue;
}
@@ -4997,8 +5000,8 @@ void Node3DEditor::_menu_item_pressed(int p_option) {
undo_redo->add_undo_method(this, "emit_signal", "item_lock_status_changed");
}
- undo_redo->add_do_method(this, "_refresh_menu_icons", Variant());
- undo_redo->add_undo_method(this, "_refresh_menu_icons", Variant());
+ undo_redo->add_do_method(this, "_refresh_menu_icons");
+ undo_redo->add_undo_method(this, "_refresh_menu_icons");
undo_redo->commit_action();
} break;
case MENU_GROUP_SELECTED: {
@@ -5008,7 +5011,7 @@ void Node3DEditor::_menu_item_pressed(int p_option) {
for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
Node3D *spatial = Object::cast_to<Node3D>(E->get());
- if (!spatial || !spatial->is_visible_in_tree()) {
+ if (!spatial || !spatial->is_inside_tree()) {
continue;
}
@@ -5022,8 +5025,8 @@ void Node3DEditor::_menu_item_pressed(int p_option) {
undo_redo->add_undo_method(this, "emit_signal", "item_group_status_changed");
}
- undo_redo->add_do_method(this, "_refresh_menu_icons", Variant());
- undo_redo->add_undo_method(this, "_refresh_menu_icons", Variant());
+ undo_redo->add_do_method(this, "_refresh_menu_icons");
+ undo_redo->add_undo_method(this, "_refresh_menu_icons");
undo_redo->commit_action();
} break;
case MENU_UNGROUP_SELECTED: {
@@ -5032,7 +5035,7 @@ void Node3DEditor::_menu_item_pressed(int p_option) {
for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
Node3D *spatial = Object::cast_to<Node3D>(E->get());
- if (!spatial || !spatial->is_visible_in_tree()) {
+ if (!spatial || !spatial->is_inside_tree()) {
continue;
}
@@ -5046,8 +5049,8 @@ void Node3DEditor::_menu_item_pressed(int p_option) {
undo_redo->add_undo_method(this, "emit_signal", "item_group_status_changed");
}
- undo_redo->add_do_method(this, "_refresh_menu_icons", Variant());
- undo_redo->add_undo_method(this, "_refresh_menu_icons", Variant());
+ undo_redo->add_do_method(this, "_refresh_menu_icons");
+ undo_redo->add_undo_method(this, "_refresh_menu_icons");
undo_redo->commit_action();
} break;
}
@@ -5989,6 +5992,7 @@ void Node3DEditor::_bind_methods() {
ClassDB::bind_method("_unhandled_key_input", &Node3DEditor::_unhandled_key_input);
ClassDB::bind_method("_get_editor_data", &Node3DEditor::_get_editor_data);
ClassDB::bind_method("_request_gizmo", &Node3DEditor::_request_gizmo);
+ ClassDB::bind_method("_refresh_menu_icons", &Node3DEditor::_refresh_menu_icons);
ADD_SIGNAL(MethodInfo("transform_key_request"));
ADD_SIGNAL(MethodInfo("item_lock_status_changed"));
@@ -6096,24 +6100,28 @@ Node3DEditor::Node3DEditor(EditorNode *p_editor) {
tool_button[TOOL_LOCK_SELECTED] = memnew(Button);
hbc_menu->add_child(tool_button[TOOL_LOCK_SELECTED]);
+ tool_button[TOOL_LOCK_SELECTED]->set_flat(true);
button_binds.write[0] = MENU_LOCK_SELECTED;
tool_button[TOOL_LOCK_SELECTED]->connect("pressed", callable_mp(this, &Node3DEditor::_menu_item_pressed), button_binds);
tool_button[TOOL_LOCK_SELECTED]->set_tooltip(TTR("Lock the selected object in place (can't be moved)."));
tool_button[TOOL_UNLOCK_SELECTED] = memnew(Button);
hbc_menu->add_child(tool_button[TOOL_UNLOCK_SELECTED]);
+ tool_button[TOOL_UNLOCK_SELECTED]->set_flat(true);
button_binds.write[0] = MENU_UNLOCK_SELECTED;
tool_button[TOOL_UNLOCK_SELECTED]->connect("pressed", callable_mp(this, &Node3DEditor::_menu_item_pressed), button_binds);
tool_button[TOOL_UNLOCK_SELECTED]->set_tooltip(TTR("Unlock the selected object (can be moved)."));
tool_button[TOOL_GROUP_SELECTED] = memnew(Button);
hbc_menu->add_child(tool_button[TOOL_GROUP_SELECTED]);
+ tool_button[TOOL_GROUP_SELECTED]->set_flat(true);
button_binds.write[0] = MENU_GROUP_SELECTED;
tool_button[TOOL_GROUP_SELECTED]->connect("pressed", callable_mp(this, &Node3DEditor::_menu_item_pressed), button_binds);
tool_button[TOOL_GROUP_SELECTED]->set_tooltip(TTR("Makes sure the object's children are not selectable."));
tool_button[TOOL_UNGROUP_SELECTED] = memnew(Button);
hbc_menu->add_child(tool_button[TOOL_UNGROUP_SELECTED]);
+ tool_button[TOOL_UNGROUP_SELECTED]->set_flat(true);
button_binds.write[0] = MENU_UNGROUP_SELECTED;
tool_button[TOOL_UNGROUP_SELECTED]->connect("pressed", callable_mp(this, &Node3DEditor::_menu_item_pressed), button_binds);
tool_button[TOOL_UNGROUP_SELECTED]->set_tooltip(TTR("Restores the object's children's ability to be selected."));
diff --git a/editor/plugins/node_3d_editor_plugin.h b/editor/plugins/node_3d_editor_plugin.h
index 2fe1938f28..a40de78795 100644
--- a/editor/plugins/node_3d_editor_plugin.h
+++ b/editor/plugins/node_3d_editor_plugin.h
@@ -214,9 +214,11 @@ class Node3DEditorViewport : public Control {
VIEW_DISPLAY_DEBUG_GIPROBE_EMISSION,
VIEW_DISPLAY_DEBUG_SCENE_LUMINANCE,
VIEW_DISPLAY_DEBUG_SSAO,
- VIEW_DISPLAY_DEBUG_ROUGHNESS_LIMITER,
VIEW_DISPLAY_DEBUG_PSSM_SPLITS,
VIEW_DISPLAY_DEBUG_DECAL_ATLAS,
+ VIEW_DISPLAY_DEBUG_SDFGI,
+ VIEW_DISPLAY_DEBUG_SDFGI_PROBES,
+ VIEW_DISPLAY_DEBUG_GI_BUFFER,
VIEW_LOCK_ROTATION,
VIEW_CINEMATIC_PREVIEW,
VIEW_AUTO_ORTHOGONAL,
diff --git a/editor/plugins/packed_scene_translation_parser_plugin.cpp b/editor/plugins/packed_scene_translation_parser_plugin.cpp
new file mode 100644
index 0000000000..52af0008b7
--- /dev/null
+++ b/editor/plugins/packed_scene_translation_parser_plugin.cpp
@@ -0,0 +1,114 @@
+/*************************************************************************/
+/* packed_scene_translation_parser_plugin.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "packed_scene_translation_parser_plugin.h"
+
+#include "core/io/resource_loader.h"
+#include "scene/resources/packed_scene.h"
+
+void PackedSceneEditorTranslationParserPlugin::get_recognized_extensions(List<String> *r_extensions) const {
+ ResourceLoader::get_recognized_extensions_for_type("PackedScene", r_extensions);
+}
+
+Error PackedSceneEditorTranslationParserPlugin::parse_file(const String &p_path, Vector<String> *r_extracted_strings) {
+ // Parse specific scene Node's properties (see in constructor) that are auto-translated by the engine when set. E.g Label's text property.
+ // These properties are translated with the tr() function in the C++ code when being set or updated.
+
+ Error err;
+ RES loaded_res = ResourceLoader::load(p_path, "PackedScene", false, &err);
+ if (err) {
+ ERR_PRINT("Failed to load " + p_path);
+ return err;
+ }
+ Ref<SceneState> state = Ref<PackedScene>(loaded_res)->get_state();
+
+ Vector<String> parsed_strings;
+ String property_name;
+ Variant property_value;
+ for (int i = 0; i < state->get_node_count(); i++) {
+ if (!ClassDB::is_parent_class(state->get_node_type(i), "Control") && !ClassDB::is_parent_class(state->get_node_type(i), "Viewport")) {
+ continue;
+ }
+
+ for (int j = 0; j < state->get_node_property_count(i); j++) {
+ property_name = state->get_node_property_name(i, j);
+ if (!lookup_properties.has(property_name)) {
+ continue;
+ }
+
+ property_value = state->get_node_property_value(i, j);
+
+ if (property_name == "script" && property_value.get_type() == Variant::OBJECT && !property_value.is_null()) {
+ // Parse built-in script.
+ Ref<Script> s = Object::cast_to<Script>(property_value);
+ String extension = s->get_language()->get_extension();
+ if (EditorTranslationParser::get_singleton()->can_parse(extension)) {
+ Vector<String> temp;
+ EditorTranslationParser::get_singleton()->get_parser(extension)->parse_file(s->get_path(), &temp);
+ parsed_strings.append_array(temp);
+ }
+ } else if (property_name == "filters") {
+ // Extract FileDialog's filters property with values in format "*.png ; PNG Images","*.gd ; GDScript Files".
+ Vector<String> str_values = property_value;
+ for (int k = 0; k < str_values.size(); k++) {
+ String desc = str_values[k].get_slice(";", 1).strip_edges();
+ if (!desc.empty()) {
+ parsed_strings.push_back(desc);
+ }
+ }
+ } else if (property_value.get_type() == Variant::STRING) {
+ String str_value = String(property_value);
+ // Prevent reading text containing only spaces.
+ if (!str_value.strip_edges().empty()) {
+ parsed_strings.push_back(str_value);
+ }
+ }
+ }
+ }
+
+ r_extracted_strings->append_array(parsed_strings);
+
+ return OK;
+}
+
+PackedSceneEditorTranslationParserPlugin::PackedSceneEditorTranslationParserPlugin() {
+ // Scene Node's properties containing strings that will be fetched for translation.
+ lookup_properties.insert("text");
+ lookup_properties.insert("hint_tooltip");
+ lookup_properties.insert("placeholder_text");
+ lookup_properties.insert("dialog_text");
+ lookup_properties.insert("filters");
+ lookup_properties.insert("script");
+
+ //Add exception list (to prevent false positives)
+ //line edit, text edit, richtextlabel
+ //Set<String> exception_list;
+ //exception_list.insert("RichTextLabel");
+}
diff --git a/editor/pane_drag.cpp b/editor/plugins/packed_scene_translation_parser_plugin.h
index 09f2b90b90..9fead84c3f 100644
--- a/editor/pane_drag.cpp
+++ b/editor/plugins/packed_scene_translation_parser_plugin.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* pane_drag.cpp */
+/* packed_scene_translation_parser_plugin.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,48 +28,22 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "pane_drag.h"
+#ifndef PACKED_SCENE_TRANSLATION_PARSER_PLUGIN_H
+#define PACKED_SCENE_TRANSLATION_PARSER_PLUGIN_H
-void PaneDrag::_gui_input(const Ref<InputEvent> &p_input) {
- Ref<InputEventMouseMotion> mm = p_input;
- if (mm.is_valid() && mm->get_button_mask() & BUTTON_MASK_LEFT) {
- emit_signal("dragged", Point2(mm->get_relative().x, mm->get_relative().y));
- }
-}
+#include "editor/editor_translation_parser.h"
-void PaneDrag::_notification(int p_what) {
- switch (p_what) {
- case NOTIFICATION_DRAW: {
- Ref<Texture2D> icon = mouse_over ? get_theme_icon("PaneDragHover", "EditorIcons") : get_theme_icon("PaneDrag", "EditorIcons");
- if (!icon.is_null()) {
- icon->draw(get_canvas_item(), Point2(0, 0));
- }
+class PackedSceneEditorTranslationParserPlugin : public EditorTranslationParserPlugin {
+ GDCLASS(PackedSceneEditorTranslationParserPlugin, EditorTranslationParserPlugin);
- } break;
- case NOTIFICATION_MOUSE_ENTER:
- mouse_over = true;
- update();
- break;
- case NOTIFICATION_MOUSE_EXIT:
- mouse_over = false;
- update();
- break;
- }
-}
+ // Scene Node's properties that contain translation strings.
+ Set<String> lookup_properties;
-Size2 PaneDrag::get_minimum_size() const {
- Ref<Texture2D> icon = get_theme_icon("PaneDrag", "EditorIcons");
- if (!icon.is_null()) {
- return icon->get_size();
- }
- return Size2();
-}
+public:
+ virtual Error parse_file(const String &p_path, Vector<String> *r_extracted_strings);
+ virtual void get_recognized_extensions(List<String> *r_extensions) const;
-void PaneDrag::_bind_methods() {
- ClassDB::bind_method("_gui_input", &PaneDrag::_gui_input);
- ADD_SIGNAL(MethodInfo("dragged", PropertyInfo(Variant::VECTOR2, "amount")));
-}
+ PackedSceneEditorTranslationParserPlugin();
+};
-PaneDrag::PaneDrag() {
- mouse_over = false;
-}
+#endif // PACKED_SCENE_TRANSLATION_PARSER_PLUGIN_H
diff --git a/editor/plugins/polygon_2d_editor_plugin.cpp b/editor/plugins/polygon_2d_editor_plugin.cpp
index 1d273f74f0..dd1194d020 100644
--- a/editor/plugins/polygon_2d_editor_plugin.cpp
+++ b/editor/plugins/polygon_2d_editor_plugin.cpp
@@ -485,7 +485,8 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) {
} else {
Vector2 tuv = mtx.affine_inverse().xform(snap_point(Vector2(mb->get_position().x, mb->get_position().y)));
- if (points_prev.size() > 2 && tuv.distance_to(points_prev[0]) < 8) {
+ // Close the polygon if selected point is near start. Threshold for closing scaled by zoom level
+ if (points_prev.size() > 2 && tuv.distance_to(points_prev[0]) < (8 / uv_draw_zoom)) {
undo_redo->create_action(TTR("Create Polygon & UV"));
undo_redo->add_do_method(node, "set_uv", node->get_uv());
undo_redo->add_undo_method(node, "set_uv", uv_create_uv_prev);
@@ -727,35 +728,37 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) {
bone_painting_bone = bone_selected;
}
}
+ } else {
+ if (uv_drag && !uv_create) {
+ if (uv_edit_mode[0]->is_pressed()) { // Edit UV.
+ undo_redo->create_action(TTR("Transform UV Map"));
+ undo_redo->add_do_method(node, "set_uv", node->get_uv());
+ undo_redo->add_undo_method(node, "set_uv", points_prev);
+ undo_redo->add_do_method(uv_edit_draw, "update");
+ undo_redo->add_undo_method(uv_edit_draw, "update");
+ undo_redo->commit_action();
+ } else if (uv_edit_mode[1]->is_pressed() && uv_move_current == UV_MODE_EDIT_POINT) { // Edit polygon.
+ undo_redo->create_action(TTR("Transform Polygon"));
+ undo_redo->add_do_method(node, "set_polygon", node->get_polygon());
+ undo_redo->add_undo_method(node, "set_polygon", points_prev);
+ undo_redo->add_do_method(uv_edit_draw, "update");
+ undo_redo->add_undo_method(uv_edit_draw, "update");
+ undo_redo->commit_action();
+ }
- } else if (uv_drag && !uv_create) {
- if (uv_edit_mode[0]->is_pressed()) { // Edit UV.
- undo_redo->create_action(TTR("Transform UV Map"));
- undo_redo->add_do_method(node, "set_uv", node->get_uv());
- undo_redo->add_undo_method(node, "set_uv", points_prev);
- undo_redo->add_do_method(uv_edit_draw, "update");
- undo_redo->add_undo_method(uv_edit_draw, "update");
- undo_redo->commit_action();
- } else if (uv_edit_mode[1]->is_pressed() && uv_move_current == UV_MODE_EDIT_POINT) { // Edit polygon.
- undo_redo->create_action(TTR("Transform Polygon"));
- undo_redo->add_do_method(node, "set_polygon", node->get_polygon());
- undo_redo->add_undo_method(node, "set_polygon", points_prev);
+ uv_drag = false;
+ }
+
+ if (bone_painting) {
+ undo_redo->create_action(TTR("Paint Bone Weights"));
+ undo_redo->add_do_method(node, "set_bone_weights", bone_painting_bone, node->get_bone_weights(bone_painting_bone));
+ undo_redo->add_undo_method(node, "set_bone_weights", bone_painting_bone, prev_weights);
undo_redo->add_do_method(uv_edit_draw, "update");
undo_redo->add_undo_method(uv_edit_draw, "update");
undo_redo->commit_action();
+ bone_painting = false;
}
-
- uv_drag = false;
- } else if (bone_painting) {
- undo_redo->create_action(TTR("Paint Bone Weights"));
- undo_redo->add_do_method(node, "set_bone_weights", bone_painting_bone, node->get_bone_weights(bone_painting_bone));
- undo_redo->add_undo_method(node, "set_bone_weights", bone_painting_bone, prev_weights);
- undo_redo->add_do_method(uv_edit_draw, "update");
- undo_redo->add_undo_method(uv_edit_draw, "update");
- undo_redo->commit_action();
- bone_painting = false;
}
-
} else if (mb->get_button_index() == BUTTON_RIGHT && mb->is_pressed()) {
_cancel_editing();
diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp
index 3f17bf57c4..66f0155c6a 100644
--- a/editor/plugins/script_editor_plugin.cpp
+++ b/editor/plugins/script_editor_plugin.cpp
@@ -538,7 +538,7 @@ void ScriptEditor::_close_tab(int p_idx, bool p_save, bool p_history_back) {
ScriptEditorBase *current = Object::cast_to<ScriptEditorBase>(tab_container->get_child(selected));
if (current) {
if (p_save) {
- apply_scripts();
+ _menu_option(FILE_SAVE);
}
Ref<Script> script = current->get_edited_resource();
@@ -1337,7 +1337,7 @@ void ScriptEditor::_notification(int p_what) {
editor->disconnect("stop_pressed", callable_mp(this, &ScriptEditor::_editor_stop));
} break;
- case NOTIFICATION_WM_FOCUS_IN: {
+ case NOTIFICATION_WM_WINDOW_FOCUS_IN: {
_test_script_times_on_disk();
_update_modified_scripts_for_external_editor();
} break;
@@ -1731,6 +1731,19 @@ void ScriptEditor::_update_script_names() {
sedata.push_back(sd);
}
+ Vector<String> disambiguated_script_names;
+ Vector<String> full_script_paths;
+ for (int j = 0; j < sedata.size(); j++) {
+ disambiguated_script_names.append(sedata[j].name);
+ full_script_paths.append(sedata[j].tooltip);
+ }
+
+ EditorNode::disambiguate_filenames(full_script_paths, disambiguated_script_names);
+
+ for (int j = 0; j < sedata.size(); j++) {
+ sedata.write[j].name = disambiguated_script_names[j];
+ }
+
EditorHelp *eh = Object::cast_to<EditorHelp>(tab_container->get_child(i));
if (eh) {
String name = eh->get_class();
@@ -3050,7 +3063,7 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) {
file_menu->get_popup()->add_separator();
file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/save", TTR("Save"), KEY_MASK_ALT | KEY_MASK_CMD | KEY_S), FILE_SAVE);
file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/save_as", TTR("Save As...")), FILE_SAVE_AS);
- 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_shortcut(ED_SHORTCUT("script_editor/save_all", TTR("Save All"), 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_ALT | 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);
diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp
index 4b79d8c344..9304683d77 100644
--- a/editor/plugins/script_text_editor.cpp
+++ b/editor/plugins/script_text_editor.cpp
@@ -343,16 +343,11 @@ void ScriptTextEditor::_set_theme_for_script() {
}
//colorize singleton autoloads (as types, just as engine singletons are)
- List<PropertyInfo> props;
- ProjectSettings::get_singleton()->get_property_list(&props);
- for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) {
- String s = E->get().name;
- if (!s.begins_with("autoload/")) {
- continue;
- }
- String path = ProjectSettings::get_singleton()->get(s);
- if (path.begins_with("*")) {
- text_edit->add_keyword_color(s.get_slice("/", 1), colors_cache.usertype_color);
+ Map<StringName, ProjectSettings::AutoloadInfo> autoloads = ProjectSettings::get_singleton()->get_autoload_list();
+ for (Map<StringName, ProjectSettings::AutoloadInfo>::Element *E = autoloads.front(); E; E = E->next()) {
+ const ProjectSettings::AutoloadInfo &info = E->value();
+ if (info.is_singleton) {
+ text_edit->add_keyword_color(info.name, colors_cache.usertype_color);
}
}
@@ -383,10 +378,6 @@ void ScriptTextEditor::_show_warnings_panel(bool p_show) {
warnings_panel->set_visible(p_show);
}
-void ScriptTextEditor::_error_pressed() {
- code_editor->goto_error();
-}
-
void ScriptTextEditor::_warning_clicked(Variant p_line) {
if (p_line.get_type() == Variant::INT) {
code_editor->get_text_edit()->cursor_set_line(p_line.operator int64_t());
@@ -946,12 +937,11 @@ void ScriptTextEditor::_lookup_symbol(const String &p_symbol, int p_row, int p_c
emit_signal("go_to_help", "class_global:" + result.class_name + ":" + result.class_member);
} break;
}
- } else if (ProjectSettings::get_singleton()->has_setting("autoload/" + p_symbol)) {
- //check for Autoload scenes
- String path = ProjectSettings::get_singleton()->get("autoload/" + p_symbol);
- if (path.begins_with("*")) {
- path = path.substr(1, path.length());
- EditorNode::get_singleton()->load_scene(path);
+ } else if (ProjectSettings::get_singleton()->has_autoload(p_symbol)) {
+ // Check for Autoload scenes.
+ const ProjectSettings::AutoloadInfo &info = ProjectSettings::get_singleton()->get_autoload(p_symbol);
+ if (info.is_singleton) {
+ EditorNode::get_singleton()->load_scene(info.path);
}
} else if (p_symbol.is_rel_path()) {
// Every symbol other than absolute path is relative path so keep this condition at last.
@@ -978,7 +968,7 @@ void ScriptTextEditor::_validate_symbol(const String &p_symbol) {
}
ScriptLanguage::LookupResult result;
- if (ScriptServer::is_global_class(p_symbol) || p_symbol.is_resource_file() || script->get_language()->lookup_code(code_editor->get_text_edit()->get_text_for_lookup_completion(), p_symbol, script->get_path(), base, result) == OK || ProjectSettings::get_singleton()->has_setting("autoload/" + p_symbol)) {
+ if (ScriptServer::is_global_class(p_symbol) || p_symbol.is_resource_file() || script->get_language()->lookup_code(code_editor->get_text_edit()->get_text_for_lookup_completion(), p_symbol, script->get_path(), base, result) == OK || (ProjectSettings::get_singleton()->has_autoload(p_symbol) && ProjectSettings::get_singleton()->get_autoload(p_symbol).is_singleton)) {
text_edit->set_highlighted_word(p_symbol);
} else if (p_symbol.is_rel_path()) {
String path = _get_absolute_path(p_symbol);
@@ -1759,7 +1749,6 @@ ScriptTextEditor::ScriptTextEditor() {
warnings_panel->set_focus_mode(FOCUS_CLICK);
warnings_panel->hide();
- code_editor->connect("error_pressed", callable_mp(this, &ScriptTextEditor::_error_pressed));
code_editor->connect("show_warnings_panel", callable_mp(this, &ScriptTextEditor::_show_warnings_panel));
warnings_panel->connect("meta_clicked", callable_mp(this, &ScriptTextEditor::_warning_clicked));
diff --git a/editor/plugins/script_text_editor.h b/editor/plugins/script_text_editor.h
index adcd0218bc..8fa380b64d 100644
--- a/editor/plugins/script_text_editor.h
+++ b/editor/plugins/script_text_editor.h
@@ -159,7 +159,6 @@ protected:
void _load_theme_settings();
void _set_theme_for_script();
void _show_warnings_panel(bool p_show);
- void _error_pressed();
void _warning_clicked(Variant p_line);
void _notification(int p_what);
diff --git a/editor/plugins/shader_editor_plugin.cpp b/editor/plugins/shader_editor_plugin.cpp
index 0c3a44e4cd..7dd0b8a238 100644
--- a/editor/plugins/shader_editor_plugin.cpp
+++ b/editor/plugins/shader_editor_plugin.cpp
@@ -338,7 +338,7 @@ void ShaderEditor::_menu_option(int p_option) {
}
void ShaderEditor::_notification(int p_what) {
- if (p_what == NOTIFICATION_WM_FOCUS_IN) {
+ if (p_what == NOTIFICATION_WM_WINDOW_FOCUS_IN) {
_check_for_external_edit();
}
}
diff --git a/editor/plugins/shader_file_editor_plugin.cpp b/editor/plugins/shader_file_editor_plugin.cpp
index 0ac29f68f6..f15a801530 100644
--- a/editor/plugins/shader_file_editor_plugin.cpp
+++ b/editor/plugins/shader_file_editor_plugin.cpp
@@ -200,7 +200,7 @@ void ShaderFileEditor::_update_options() {
}
void ShaderFileEditor::_notification(int p_what) {
- if (p_what == NOTIFICATION_WM_FOCUS_IN) {
+ if (p_what == NOTIFICATION_WM_WINDOW_FOCUS_IN) {
if (is_visible_in_tree() && shader_file.is_valid()) {
_update_options();
}
diff --git a/editor/plugins/texture_region_editor_plugin.cpp b/editor/plugins/texture_region_editor_plugin.cpp
index 3a92818779..762f42abeb 100644
--- a/editor/plugins/texture_region_editor_plugin.cpp
+++ b/editor/plugins/texture_region_editor_plugin.cpp
@@ -780,7 +780,7 @@ void TextureRegionEditor::_notification(int p_what) {
_update_autoslice();
}
} break;
- case NOTIFICATION_WM_FOCUS_IN: {
+ case NOTIFICATION_WM_WINDOW_FOCUS_IN: {
// This happens when the user leaves the Editor and returns,
// they could have changed the textures, so the cache is cleared.
cache_map.clear();
diff --git a/editor/plugins/tile_map_editor_plugin.cpp b/editor/plugins/tile_map_editor_plugin.cpp
index 158f9e8587..307a8a9001 100644
--- a/editor/plugins/tile_map_editor_plugin.cpp
+++ b/editor/plugins/tile_map_editor_plugin.cpp
@@ -64,6 +64,8 @@ void TileMapEditor::_notification(int p_what) {
}
paint_button->set_icon(get_theme_icon("Edit", "EditorIcons"));
+ line_button->set_icon(get_theme_icon("CurveLinear", "EditorIcons"));
+ rectangle_button->set_icon(get_theme_icon("RectangleShape2D", "EditorIcons"));
bucket_fill_button->set_icon(get_theme_icon("Bucket", "EditorIcons"));
picker_button->set_icon(get_theme_icon("ColorPick", "EditorIcons"));
select_button->set_icon(get_theme_icon("ActionCopy", "EditorIcons"));
@@ -91,9 +93,10 @@ void TileMapEditor::_notification(int p_what) {
}
void TileMapEditor::_update_button_tool() {
- Button *tb[4] = { paint_button, bucket_fill_button, picker_button, select_button };
+ Button *tb[6] = { paint_button, line_button, rectangle_button, bucket_fill_button, picker_button, select_button };
+
// Unpress all buttons
- for (int i = 0; i < 4; i++) {
+ for (int i = 0; i < 6; i++) {
tb[i]->set_pressed(false);
}
@@ -103,6 +106,12 @@ void TileMapEditor::_update_button_tool() {
case TOOL_PAINTING: {
paint_button->set_pressed(true);
} break;
+ case TOOL_LINE_PAINT: {
+ line_button->set_pressed(true);
+ } break;
+ case TOOL_RECTANGLE_PAINT: {
+ rectangle_button->set_pressed(true);
+ } break;
case TOOL_BUCKET: {
bucket_fill_button->set_pressed(true);
} break;
@@ -993,19 +1002,8 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
}
if (tool == TOOL_NONE) {
- if (mb->get_shift()) {
- if (mb->get_command()) {
- tool = TOOL_RECTANGLE_PAINT;
- } else {
- tool = TOOL_LINE_PAINT;
- }
-
- selection_active = false;
- rectangle_begin = over_tile;
-
- _update_button_tool();
- return true;
- }
+ tool = TOOL_PAINTING;
+ _update_button_tool();
if (mb->get_command()) {
tool = TOOL_PICKING;
@@ -1014,12 +1012,14 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
return true;
}
-
- tool = TOOL_PAINTING;
- _update_button_tool();
}
- if (tool == TOOL_PAINTING) {
+ if (tool == TOOL_LINE_PAINT || tool == TOOL_RECTANGLE_PAINT) {
+ selection_active = false;
+ rectangle_begin = over_tile;
+
+ mouse_down = true;
+ } else if (tool == TOOL_PAINTING) {
Vector<int> ids = get_selected_tiles();
if (ids.size() > 0 && ids[0] != TileMap::INVALID_CELL) {
@@ -1050,6 +1050,10 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
paint_undo.clear();
}
} else if (tool == TOOL_LINE_PAINT) {
+ if (!mouse_down) {
+ return true;
+ }
+
Vector<int> ids = get_selected_tiles();
if (ids.size() > 0 && ids[0] != TileMap::INVALID_CELL) {
@@ -1062,8 +1066,17 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
paint_undo.clear();
CanvasItemEditor::get_singleton()->update_viewport();
+
+ mouse_down = false;
+ return true;
}
+
+ mouse_down = false;
} else if (tool == TOOL_RECTANGLE_PAINT) {
+ if (!mouse_down) {
+ return true;
+ }
+
Vector<int> ids = get_selected_tiles();
if (ids.size() > 0 && ids[0] != TileMap::INVALID_CELL) {
@@ -1076,7 +1089,12 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
_finish_undo();
CanvasItemEditor::get_singleton()->update_viewport();
+
+ mouse_down = false;
+ return true;
}
+
+ mouse_down = false;
} else if (tool == TOOL_PASTING) {
Point2 ofs = over_tile - rectangle.position;
Vector<int> ids;
@@ -1141,6 +1159,28 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
if (tool == TOOL_PASTING) {
tool = TOOL_NONE;
+
+ CanvasItemEditor::get_singleton()->update_viewport();
+
+ _update_button_tool();
+ return true;
+ }
+
+ if (tool == TOOL_LINE_PAINT) {
+ tool = TOOL_LINE_ERASE;
+ mouse_down = true;
+ rectangle_begin = over_tile;
+
+ CanvasItemEditor::get_singleton()->update_viewport();
+
+ _update_button_tool();
+ return true;
+ }
+
+ if (tool == TOOL_RECTANGLE_PAINT) {
+ tool = TOOL_RECTANGLE_ERASE;
+ mouse_down = true;
+ rectangle_begin = over_tile;
copydata.clear();
CanvasItemEditor::get_singleton()->update_viewport();
@@ -1155,39 +1195,74 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
Point2 local = node->world_to_map(xform_inv.xform(mb->get_position()));
_start_undo(TTR("Erase TileMap"));
+ tool = TOOL_ERASING;
+ _set_cell(local, invalid_cell);
- if (mb->get_shift()) {
- if (mb->get_command()) {
- tool = TOOL_RECTANGLE_ERASE;
- } else {
- tool = TOOL_LINE_ERASE;
+ _update_button_tool();
+ return true;
+ }
+
+ } else {
+ if (tool == TOOL_LINE_ERASE) {
+ if (!mouse_down) {
+ return true;
+ }
+
+ tool = TOOL_LINE_PAINT;
+ _update_button_tool();
+
+ Vector<int> ids = get_selected_tiles();
+
+ if (ids.size() > 0 && ids[0] != TileMap::INVALID_CELL) {
+ _start_undo(TTR("Line Erase"));
+ for (Map<Point2i, CellOp>::Element *E = paint_undo.front(); E; E = E->next()) {
+ _set_cell(E->key(), invalid_cell, flip_h, flip_v, transpose);
}
+ _finish_undo();
+ paint_undo.clear();
- selection_active = false;
- rectangle_begin = local;
- } else {
- tool = TOOL_ERASING;
+ CanvasItemEditor::get_singleton()->update_viewport();
- _set_cell(local, invalid_cell);
+ mouse_down = false;
+ return true;
}
+ mouse_down = false;
+ } else if (tool == TOOL_RECTANGLE_ERASE) {
+ if (!mouse_down) {
+ return true;
+ }
+
+ tool = TOOL_RECTANGLE_PAINT;
_update_button_tool();
- return true;
- }
- } else {
- if (tool == TOOL_ERASING || tool == TOOL_RECTANGLE_ERASE || tool == TOOL_LINE_ERASE) {
- _finish_undo();
+ Vector<int> ids = get_selected_tiles();
+
+ if (ids.size() > 0 && ids[0] != TileMap::INVALID_CELL) {
+ _start_undo(TTR("Rectangle Erase"));
+ for (int i = rectangle.position.y; i <= rectangle.position.y + rectangle.size.y; i++) {
+ for (int j = rectangle.position.x; j <= rectangle.position.x + rectangle.size.x; j++) {
+ _set_cell(Point2i(j, i), invalid_cell, flip_h, flip_v, transpose);
+ }
+ }
+ _finish_undo();
+ paint_undo.clear();
- if (tool == TOOL_RECTANGLE_ERASE || tool == TOOL_LINE_ERASE) {
CanvasItemEditor::get_singleton()->update_viewport();
+
+ mouse_down = false;
+ return true;
}
- tool = TOOL_NONE;
+ mouse_down = false;
+ tool = TOOL_RECTANGLE_PAINT;
+ }
+ if (tool == TOOL_ERASING) {
+ tool = TOOL_NONE;
_update_button_tool();
- return true;
+ return true;
} else if (tool == TOOL_BUCKET) {
Vector<int> ids;
ids.push_back(node->get_cell(over_tile.x, over_tile.y));
@@ -1278,6 +1353,10 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
Vector<int> tmp_cell;
bool erasing = (tool == TOOL_LINE_ERASE);
+ if (!mouse_down) {
+ return true;
+ }
+
tmp_cell.push_back(0);
if (erasing && paint_undo.size()) {
for (Map<Point2i, CellOp>::Element *E = paint_undo.front(); E; E = E->next()) {
@@ -1308,7 +1387,20 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
Vector<int> tmp_cell;
tmp_cell.push_back(0);
- _select(rectangle_begin, over_tile);
+ Point2i end_tile = over_tile;
+
+ if (!mouse_down) {
+ return true;
+ }
+
+ if (mm->get_shift()) {
+ int size = fmax(ABS(end_tile.x - rectangle_begin.x), ABS(end_tile.y - rectangle_begin.y));
+ int xDirection = MAX(MIN(end_tile.x - rectangle_begin.x, 1), -1);
+ int yDirection = MAX(MIN(end_tile.y - rectangle_begin.y, 1), -1);
+ end_tile = rectangle_begin + Point2i(xDirection * size, yDirection * size);
+ }
+
+ _select(rectangle_begin, end_tile);
if (tool == TOOL_RECTANGLE_ERASE) {
if (paint_undo.size()) {
@@ -1379,6 +1471,20 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
_update_button_tool();
return true;
}
+ if (ED_IS_SHORTCUT("tile_map_editor/line_fill", p_event)) {
+ tool = TOOL_LINE_PAINT;
+ CanvasItemEditor::get_singleton()->update_viewport();
+
+ _update_button_tool();
+ return true;
+ }
+ if (ED_IS_SHORTCUT("tile_map_editor/rectangle_fill", p_event)) {
+ tool = TOOL_RECTANGLE_PAINT;
+ CanvasItemEditor::get_singleton()->update_viewport();
+
+ _update_button_tool();
+ return true;
+ }
if (ED_IS_SHORTCUT("tile_map_editor/bucket_fill", p_event)) {
tool = TOOL_BUCKET;
CanvasItemEditor::get_singleton()->update_viewport();
@@ -1637,6 +1743,10 @@ void TileMapEditor::forward_canvas_draw_over_viewport(Control *p_overlay) {
}
if (tool == TOOL_LINE_PAINT) {
+ if (!mouse_down) {
+ return;
+ }
+
if (paint_undo.empty()) {
return;
}
@@ -1652,6 +1762,10 @@ void TileMapEditor::forward_canvas_draw_over_viewport(Control *p_overlay) {
}
} else if (tool == TOOL_RECTANGLE_PAINT) {
+ if (!mouse_down) {
+ return;
+ }
+
Vector<int> ids = get_selected_tiles();
if (ids.size() == 1 && ids[0] == TileMap::INVALID_CELL) {
@@ -1865,6 +1979,7 @@ TileMapEditor::TileMapEditor(EditorNode *p_editor) {
tool = TOOL_NONE;
selection_active = false;
mouse_over = false;
+ mouse_down = false;
flip_h = false;
flip_v = false;
@@ -1962,11 +2077,27 @@ TileMapEditor::TileMapEditor(EditorNode *p_editor) {
paint_button = memnew(Button);
paint_button->set_flat(true);
paint_button->set_shortcut(ED_SHORTCUT("tile_map_editor/paint_tile", TTR("Paint Tile"), KEY_P));
- paint_button->set_tooltip(TTR("Shift+LMB: Line Draw\nShift+Ctrl+LMB: Rectangle Paint"));
+ paint_button->set_tooltip(TTR("RMB: Erase"));
paint_button->connect("pressed", callable_mp(this, &TileMapEditor::_button_tool_select), make_binds(TOOL_NONE));
paint_button->set_toggle_mode(true);
toolbar->add_child(paint_button);
+ line_button = memnew(Button);
+ line_button->set_flat(true);
+ line_button->set_shortcut(ED_SHORTCUT("tile_map_editor/line_fill", TTR("Line Fill"), KEY_L));
+ line_button->set_tooltip(TTR("RMB: Erase"));
+ line_button->connect("pressed", callable_mp(this, &TileMapEditor::_button_tool_select), make_binds(TOOL_LINE_PAINT));
+ line_button->set_toggle_mode(true);
+ toolbar->add_child(line_button);
+
+ rectangle_button = memnew(Button);
+ rectangle_button->set_flat(true);
+ rectangle_button->set_shortcut(ED_SHORTCUT("tile_map_editor/rectangle_fill", TTR("Rectangle Fill"), KEY_O));
+ rectangle_button->set_tooltip(TTR("Shift+LMB: Keep 1:1 proporsions\nRMB: Erase"));
+ rectangle_button->connect("pressed", callable_mp(this, &TileMapEditor::_button_tool_select), make_binds(TOOL_RECTANGLE_PAINT));
+ rectangle_button->set_toggle_mode(true);
+ toolbar->add_child(rectangle_button);
+
bucket_fill_button = memnew(Button);
bucket_fill_button->set_flat(true);
bucket_fill_button->set_shortcut(ED_SHORTCUT("tile_map_editor/bucket_fill", TTR("Bucket Fill"), KEY_B));
diff --git a/editor/plugins/tile_map_editor_plugin.h b/editor/plugins/tile_map_editor_plugin.h
index 1d2ecdb61f..135a9bd5a5 100644
--- a/editor/plugins/tile_map_editor_plugin.h
+++ b/editor/plugins/tile_map_editor_plugin.h
@@ -88,6 +88,8 @@ class TileMapEditor : public VBoxContainer {
MenuButton *options;
Button *paint_button;
+ Button *line_button;
+ Button *rectangle_button;
Button *bucket_fill_button;
Button *picker_button;
Button *select_button;
@@ -106,6 +108,7 @@ class TileMapEditor : public VBoxContainer {
bool selection_active;
bool mouse_over;
+ bool mouse_down;
bool flip_h;
bool flip_v;
diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp
index 89ab747cde..13d8f0c856 100644
--- a/editor/plugins/visual_shader_editor_plugin.cpp
+++ b/editor/plugins/visual_shader_editor_plugin.cpp
@@ -2450,6 +2450,7 @@ VisualShaderEditor::VisualShaderEditor() {
members_dialog = memnew(ConfirmationDialog);
members_dialog->set_title(TTR("Create Shader Node"));
+ members_dialog->set_exclusive(false);
members_dialog->add_child(members_vb);
members_dialog->get_ok()->set_text(TTR("Create"));
members_dialog->get_ok()->connect("pressed", callable_mp(this, &VisualShaderEditor::_member_create));
diff --git a/editor/pot_generator.cpp b/editor/pot_generator.cpp
new file mode 100644
index 0000000000..f9b8722aad
--- /dev/null
+++ b/editor/pot_generator.cpp
@@ -0,0 +1,166 @@
+/*************************************************************************/
+/* pot_generator.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "pot_generator.h"
+
+#include "core/error_macros.h"
+#include "core/os/file_access.h"
+#include "core/project_settings.h"
+#include "editor_translation_parser.h"
+#include "plugins/packed_scene_translation_parser_plugin.h"
+
+POTGenerator *POTGenerator::singleton = nullptr;
+
+//#define DEBUG_POT
+
+#ifdef DEBUG_POT
+void _print_all_translation_strings(const OrderedHashMap<String, Set<String>> &p_all_translation_strings) {
+ for (auto E_pair = p_all_translation_strings.front(); E_pair; E_pair = E_pair.next()) {
+ String msg = static_cast<String>(E_pair.key()) + " : ";
+ for (Set<String>::Element *E = E_pair.value().front(); E; E = E->next()) {
+ msg += E->get() + " ";
+ }
+ print_line(msg);
+ }
+}
+#endif
+
+void POTGenerator::generate_pot(const String &p_file) {
+ if (!ProjectSettings::get_singleton()->has_setting("locale/translations_pot_files")) {
+ WARN_PRINT("No files selected for POT generation.");
+ return;
+ }
+
+ // Clear all_translation_strings of the previous round.
+ all_translation_strings.clear();
+
+ Vector<String> files = ProjectSettings::get_singleton()->get("locale/translations_pot_files");
+
+ // Collect all translatable strings according to files order in "POT Generation" setting.
+ for (int i = 0; i < files.size(); i++) {
+ Vector<String> translation_strings;
+ String file_path = files[i];
+ String file_extension = file_path.get_extension();
+
+ if (EditorTranslationParser::get_singleton()->can_parse(file_extension)) {
+ EditorTranslationParser::get_singleton()->get_parser(file_extension)->parse_file(file_path, &translation_strings);
+ } else {
+ ERR_PRINT("Unrecognized file extension " + file_extension + " in generate_pot()");
+ return;
+ }
+
+ // Store translation strings parsed in this iteration along with their corresponding source file - to write into POT later on.
+ for (int j = 0; j < translation_strings.size(); j++) {
+ all_translation_strings[translation_strings[j]].insert(file_path);
+ }
+ }
+
+#ifdef DEBUG_POT
+ _print_all_translation_strings(all_translation_strings);
+#endif
+
+ _write_to_pot(p_file);
+}
+
+void POTGenerator::_write_to_pot(const String &p_file) {
+ Error err;
+ FileAccess *file = FileAccess::open(p_file, FileAccess::WRITE, &err);
+ if (err != OK) {
+ ERR_PRINT("Failed to open " + p_file);
+ return;
+ }
+
+ String project_name = ProjectSettings::get_singleton()->get("application/config/name");
+ Vector<String> files = ProjectSettings::get_singleton()->get("locale/translations_pot_files");
+ String extracted_files = "";
+ for (int i = 0; i < files.size(); i++) {
+ extracted_files += "# " + files[i] + "\n";
+ }
+ const String header =
+ "# LANGUAGE translation for " + project_name + " for the following files:\n" + extracted_files +
+ "#\n"
+ "#\n"
+ "# FIRST AUTHOR < EMAIL @ADDRESS>, YEAR.\n"
+ "#\n"
+ "#, fuzzy\n"
+ "msgid \"\"\n"
+ "msgstr \"\"\n"
+ "\"Project-Id-Version: " +
+ project_name + "\\n\"\n"
+ "\"Content-Type: text/plain; charset=UTF-8\\n\"\n"
+ "\"Content-Transfer-Encoding: 8-bit\\n\"\n\n";
+
+ file->store_string(header);
+
+ for (OrderedHashMap<String, Set<String>>::Element E_pair = all_translation_strings.front(); E_pair; E_pair = E_pair.next()) {
+ String msg = E_pair.key();
+
+ // Write file locations.
+ for (Set<String>::Element *E = E_pair.value().front(); E; E = E->next()) {
+ file->store_line("#: " + E->get().trim_prefix("res://"));
+ }
+
+ // Split \\n and \n.
+ Vector<String> temp = msg.split("\\n");
+ Vector<String> msg_lines;
+ for (int i = 0; i < temp.size(); i++) {
+ msg_lines.append_array(temp[i].split("\n"));
+ if (i < temp.size() - 1) {
+ // Add \n.
+ msg_lines.set(msg_lines.size() - 1, msg_lines[msg_lines.size() - 1] + "\\n");
+ }
+ }
+
+ // Write msgid.
+ file->store_string("msgid ");
+ for (int i = 0; i < msg_lines.size(); i++) {
+ file->store_line("\"" + msg_lines[i] + "\"");
+ }
+
+ file->store_line("msgstr \"\"\n");
+ }
+
+ file->close();
+}
+
+POTGenerator *POTGenerator::get_singleton() {
+ if (!singleton) {
+ singleton = memnew(POTGenerator);
+ }
+ return singleton;
+}
+
+POTGenerator::POTGenerator() {
+}
+
+POTGenerator::~POTGenerator() {
+ memdelete(singleton);
+ singleton = nullptr;
+}
diff --git a/editor/pane_drag.h b/editor/pot_generator.h
index 81aff4b2a8..abe1a21d41 100644
--- a/editor/pane_drag.h
+++ b/editor/pot_generator.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* pane_drag.h */
+/* pot_generator.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,24 +28,25 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef PANE_DRAG_H
-#define PANE_DRAG_H
+#ifndef POT_GENERATOR_H
+#define POT_GENERATOR_H
-#include "scene/gui/control.h"
+#include "core/ordered_hash_map.h"
+#include "core/set.h"
-class PaneDrag : public Control {
- GDCLASS(PaneDrag, Control);
+class POTGenerator {
+ static POTGenerator *singleton;
+ // Stores all translatable strings and the source files containing them.
+ OrderedHashMap<String, Set<String>> all_translation_strings;
- bool mouse_over;
-
-protected:
- void _gui_input(const Ref<InputEvent> &p_input);
- void _notification(int p_what);
- virtual Size2 get_minimum_size() const;
- static void _bind_methods();
+ void _write_to_pot(const String &p_file);
public:
- PaneDrag();
+ static POTGenerator *get_singleton();
+ void generate_pot(const String &p_file);
+
+ POTGenerator();
+ ~POTGenerator();
};
-#endif // PANE_DRAG_H
+#endif // POT_GENERATOR_H
diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp
index a800f9e8eb..5184793760 100644
--- a/editor/project_manager.cpp
+++ b/editor/project_manager.cpp
@@ -294,7 +294,7 @@ private:
// If the project name is empty or default, infer the project name from the selected folder name
if (project_name->get_text() == "" || project_name->get_text() == TTR("New Game Project")) {
sp = sp.replace("\\", "/");
- int lidx = sp.find_last("/");
+ int lidx = sp.rfind("/");
if (lidx != -1) {
sp = sp.substr(lidx + 1, sp.length()).capitalize();
@@ -2336,10 +2336,10 @@ ProjectManager::ProjectManager() {
switch (display_scale) {
case 0: {
// Try applying a suitable display scale automatically
- const int screen = DisplayServer::get_singleton()->window_get_current_screen();
#ifdef OSX_ENABLED
- editor_set_scale(DisplayServer::get_singleton()->screen_get_scale(screen));
+ editor_set_scale(DisplayServer::get_singleton()->screen_get_max_scale());
#else
+ const int screen = DisplayServer::get_singleton()->window_get_current_screen();
editor_set_scale(DisplayServer::get_singleton()->screen_get_dpi(screen) >= 192 && DisplayServer::get_singleton()->screen_get_size(screen).x > 2000 ? 2.0 : 1.0);
#endif
} break;
@@ -2371,11 +2371,8 @@ ProjectManager::ProjectManager() {
// Define a minimum window size to prevent UI elements from overlapping or being cut off
DisplayServer::get_singleton()->window_set_min_size(Size2(750, 420) * EDSCALE);
-#ifndef OSX_ENABLED
- // The macOS platform implementation uses its own hiDPI window resizing code
// TODO: Resize windows on hiDPI displays on Windows and Linux and remove the line below
DisplayServer::get_singleton()->window_set_size(DisplayServer::get_singleton()->window_get_size() * MAX(1, EDSCALE));
-#endif
}
FileDialog::set_default_show_hidden_files(EditorSettings::get_singleton()->get("filesystem/file_dialog/show_hidden_files"));
diff --git a/editor/project_settings_editor.cpp b/editor/project_settings_editor.cpp
index f2c4a533ea..f84845179b 100644
--- a/editor/project_settings_editor.cpp
+++ b/editor/project_settings_editor.cpp
@@ -38,6 +38,8 @@
#include "editor/editor_export.h"
#include "editor/editor_node.h"
#include "editor/editor_scale.h"
+#include "editor/editor_translation_parser.h"
+#include "editor/pot_generator.h"
#include "scene/gui/margin_container.h"
#include "scene/gui/tab_container.h"
@@ -120,6 +122,7 @@ void ProjectSettingsEditor::_notification(int p_what) {
action_add_error->add_theme_color_override("font_color", input_editor->get_theme_color("error_color", "Editor"));
translation_list->connect("button_pressed", callable_mp(this, &ProjectSettingsEditor::_translation_delete));
+ translation_pot_list->connect("button_pressed", callable_mp(this, &ProjectSettingsEditor::_translation_pot_delete));
_update_actions();
popup_add->add_icon_item(input_editor->get_theme_icon("Keyboard", "EditorIcons"), TTR("Key"), INPUT_KEY);
popup_add->add_icon_item(input_editor->get_theme_icon("KeyboardPhysical", "EditorIcons"), TTR("Physical Key"), INPUT_KEY_PHYSICAL);
@@ -140,6 +143,9 @@ void ProjectSettingsEditor::_notification(int p_what) {
translation_res_option_file_open->add_filter("*." + E->get());
}
+ _update_translation_pot_file_extensions();
+ translation_pot_generate->add_filter("*.pot");
+
restart_close_button->set_icon(input_editor->get_theme_icon("Close", "EditorIcons"));
restart_container->add_theme_style_override("panel", input_editor->get_theme_stylebox("bg", "Tree"));
restart_icon->set_texture(input_editor->get_theme_icon("StatusWarning", "EditorIcons"));
@@ -865,6 +871,8 @@ void ProjectSettingsEditor::popup_project_settings() {
_update_translations();
autoload_settings->update_autoload();
plugin_settings->update_plugins();
+ // New translation parser plugin might extend possible file extensions in POT generation.
+ _update_translation_pot_file_extensions();
set_process_unhandled_input(true);
}
@@ -1519,8 +1527,71 @@ void ProjectSettingsEditor::_translation_filter_mode_changed(int p_mode) {
undo_redo->commit_action();
}
+void ProjectSettingsEditor::_translation_pot_add(const String &p_path) {
+ PackedStringArray pot_translations = ProjectSettings::get_singleton()->get("locale/translations_pot_files");
+
+ for (int i = 0; i < pot_translations.size(); i++) {
+ if (pot_translations[i] == p_path) {
+ return; //exists
+ }
+ }
+
+ pot_translations.push_back(p_path);
+ undo_redo->create_action(TTR("Add files for POT generation"));
+ undo_redo->add_do_property(ProjectSettings::get_singleton(), "locale/translations_pot_files", pot_translations);
+ undo_redo->add_undo_property(ProjectSettings::get_singleton(), "locale/translations_pot_files", ProjectSettings::get_singleton()->get("locale/translations_pot_files"));
+ undo_redo->add_do_method(this, "_update_translations");
+ undo_redo->add_undo_method(this, "_update_translations");
+ undo_redo->add_do_method(this, "_settings_changed");
+ undo_redo->add_undo_method(this, "_settings_changed");
+ undo_redo->commit_action();
+}
+
+void ProjectSettingsEditor::_translation_pot_delete(Object *p_item, int p_column, int p_button) {
+ TreeItem *ti = Object::cast_to<TreeItem>(p_item);
+ ERR_FAIL_COND(!ti);
+
+ int idx = ti->get_metadata(0);
+
+ PackedStringArray pot_translations = ProjectSettings::get_singleton()->get("locale/translations_pot_files");
+
+ ERR_FAIL_INDEX(idx, pot_translations.size());
+
+ pot_translations.remove(idx);
+
+ undo_redo->create_action(TTR("Remove file from POT generation"));
+ undo_redo->add_do_property(ProjectSettings::get_singleton(), "locale/translations_pot_files", pot_translations);
+ undo_redo->add_undo_property(ProjectSettings::get_singleton(), "locale/translations_pot_files", ProjectSettings::get_singleton()->get("locale/translations_pot_files"));
+ undo_redo->add_do_method(this, "_update_translations");
+ undo_redo->add_undo_method(this, "_update_translations");
+ undo_redo->add_do_method(this, "_settings_changed");
+ undo_redo->add_undo_method(this, "_settings_changed");
+ undo_redo->commit_action();
+}
+
+void ProjectSettingsEditor::_translation_pot_file_open() {
+ translation_pot_file_open->popup_centered_ratio();
+}
+
+void ProjectSettingsEditor::_translation_pot_generate_open() {
+ translation_pot_generate->popup_centered_ratio();
+}
+
+void ProjectSettingsEditor::_translation_pot_generate(const String &p_file) {
+ POTGenerator::get_singleton()->generate_pot(p_file);
+}
+
+void ProjectSettingsEditor::_update_translation_pot_file_extensions() {
+ translation_pot_file_open->clear_filters();
+ List<String> translation_parse_file_extensions;
+ EditorTranslationParser::get_singleton()->get_recognized_extensions(&translation_parse_file_extensions);
+ for (List<String>::Element *E = translation_parse_file_extensions.front(); E; E = E->next()) {
+ translation_pot_file_open->add_filter("*." + E->get());
+ }
+}
+
void ProjectSettingsEditor::_update_translations() {
- //update translations
+ // Update translations.
if (updating_translations) {
return;
@@ -1601,7 +1672,7 @@ void ProjectSettingsEditor::_update_translations() {
}
}
- //update translation remaps
+ // Update translation remaps.
String remap_selected;
if (translation_remap->get_selected()) {
@@ -1666,7 +1737,7 @@ void ProjectSettingsEditor::_update_translations() {
PackedStringArray selected = remaps[keys[i]];
for (int j = 0; j < selected.size(); j++) {
String s2 = selected[j];
- int qp = s2.find_last(":");
+ int qp = s2.rfind(":");
String path = s2.substr(0, qp);
String locale = s2.substr(qp + 1, s2.length());
@@ -1696,6 +1767,23 @@ void ProjectSettingsEditor::_update_translations() {
}
}
+ // Update translation POT files.
+
+ translation_pot_list->clear();
+ root = translation_pot_list->create_item(nullptr);
+ translation_pot_list->set_hide_root(true);
+ if (ProjectSettings::get_singleton()->has_setting("locale/translations_pot_files")) {
+ PackedStringArray pot_translations = ProjectSettings::get_singleton()->get("locale/translations_pot_files");
+ for (int i = 0; i < pot_translations.size(); i++) {
+ TreeItem *t = translation_pot_list->create_item(root);
+ t->set_editable(0, false);
+ t->set_text(0, pot_translations[i].replace_first("res://", ""));
+ t->set_tooltip(0, pot_translations[i]);
+ t->set_metadata(0, i);
+ t->add_button(0, input_editor->get_theme_icon("Remove", "EditorIcons"), 0, false, TTR("Remove"));
+ }
+ }
+
updating_translations = false;
}
@@ -1865,7 +1953,7 @@ ProjectSettingsEditor::ProjectSettingsEditor(EditorData *p_data) {
restart_icon->set_v_size_flags(Control::SIZE_SHRINK_CENTER);
restart_hb->add_child(restart_icon);
restart_label = memnew(Label);
- restart_label->set_text(TTR("The editor must be restarted for changes to take effect."));
+ restart_label->set_text(TTR("Changed settings will be applied to the editor after restarting."));
restart_hb->add_child(restart_label);
restart_hb->add_spacer();
Button *restart_button = memnew(Button);
@@ -2108,6 +2196,38 @@ ProjectSettingsEditor::ProjectSettingsEditor(EditorData *p_data) {
translation_filter->connect("item_edited", callable_mp(this, &ProjectSettingsEditor::_translation_filter_option_changed));
}
+ {
+ VBoxContainer *tvb = memnew(VBoxContainer);
+ translations->add_child(tvb);
+ tvb->set_name(TTR("POT Generation"));
+ HBoxContainer *thb = memnew(HBoxContainer);
+ tvb->add_child(thb);
+ thb->add_child(memnew(Label(TTR("Files with translation strings:"))));
+ thb->add_spacer();
+ Button *addtr = memnew(Button(TTR("Add...")));
+ addtr->connect("pressed", callable_mp(this, &ProjectSettingsEditor::_translation_pot_file_open));
+ thb->add_child(addtr);
+ Button *generate = memnew(Button(TTR("Generate POT")));
+ generate->connect("pressed", callable_mp(this, &ProjectSettingsEditor::_translation_pot_generate_open));
+ thb->add_child(generate);
+ VBoxContainer *tmc = memnew(VBoxContainer);
+ tvb->add_child(tmc);
+ tmc->set_v_size_flags(Control::SIZE_EXPAND_FILL);
+ translation_pot_list = memnew(Tree);
+ translation_pot_list->set_v_size_flags(Control::SIZE_EXPAND_FILL);
+ tmc->add_child(translation_pot_list);
+
+ translation_pot_generate = memnew(EditorFileDialog);
+ add_child(translation_pot_generate);
+ translation_pot_generate->set_file_mode(EditorFileDialog::FILE_MODE_SAVE_FILE);
+ translation_pot_generate->connect("file_selected", callable_mp(this, &ProjectSettingsEditor::_translation_pot_generate));
+
+ translation_pot_file_open = memnew(EditorFileDialog);
+ add_child(translation_pot_file_open);
+ translation_pot_file_open->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE);
+ translation_pot_file_open->connect("file_selected", callable_mp(this, &ProjectSettingsEditor::_translation_pot_add));
+ }
+
autoload_settings = memnew(EditorAutoloadSettings);
autoload_settings->set_name(TTR("AutoLoad"));
tab_container->add_child(autoload_settings);
diff --git a/editor/project_settings_editor.h b/editor/project_settings_editor.h
index 728f31efa8..cf47b1df4a 100644
--- a/editor/project_settings_editor.h
+++ b/editor/project_settings_editor.h
@@ -110,6 +110,10 @@ class ProjectSettingsEditor : public AcceptDialog {
Vector<TreeItem *> translation_filter_treeitems;
Vector<int> translation_locales_idxs_remap;
+ Tree *translation_pot_list;
+ EditorFileDialog *translation_pot_file_open;
+ EditorFileDialog *translation_pot_generate;
+
EditorAutoloadSettings *autoload_settings;
EditorPluginSettings *plugin_settings;
@@ -159,6 +163,13 @@ class ProjectSettingsEditor : public AcceptDialog {
void _translation_filter_option_changed();
void _translation_filter_mode_changed(int p_mode);
+ void _translation_pot_add(const String &p_path);
+ void _translation_pot_delete(Object *p_item, int p_column, int p_button);
+ void _translation_pot_file_open();
+ void _translation_pot_generate_open();
+ void _translation_pot_generate(const String &p_file);
+ void _update_translation_pot_file_extensions();
+
void _toggle_search_bar(bool p_pressed);
Variant get_drag_data_fw(const Point2 &p_point, Control *p_from);
diff --git a/editor/property_editor.cpp b/editor/property_editor.cpp
index 49b9ca167b..f4838d336f 100644
--- a/editor/property_editor.cpp
+++ b/editor/property_editor.cpp
@@ -597,7 +597,7 @@ bool CustomPropertyEditor::edit(Object *p_owner, const String &p_name, Variant::
} else if (hint == PROPERTY_HINT_METHOD_OF_INSTANCE) {
MAKE_PROPSELECT
- Object *instance = ObjectDB::get_instance(ObjectID(hint_text.to_int64()));
+ Object *instance = ObjectDB::get_instance(ObjectID(hint_text.to_int()));
if (instance) {
property_select->select_method_from_instance(instance, v);
}
@@ -607,7 +607,7 @@ bool CustomPropertyEditor::edit(Object *p_owner, const String &p_name, Variant::
} else if (hint == PROPERTY_HINT_METHOD_OF_SCRIPT) {
MAKE_PROPSELECT
- Object *obj = ObjectDB::get_instance(ObjectID(hint_text.to_int64()));
+ Object *obj = ObjectDB::get_instance(ObjectID(hint_text.to_int()));
if (Object::cast_to<Script>(obj)) {
property_select->select_method_from_script(Object::cast_to<Script>(obj), v);
}
@@ -646,7 +646,7 @@ bool CustomPropertyEditor::edit(Object *p_owner, const String &p_name, Variant::
} else if (hint == PROPERTY_HINT_PROPERTY_OF_INSTANCE) {
MAKE_PROPSELECT
- Object *instance = ObjectDB::get_instance(ObjectID(hint_text.to_int64()));
+ Object *instance = ObjectDB::get_instance(ObjectID(hint_text.to_int()));
if (instance) {
property_select->select_property_from_instance(instance, v);
}
@@ -657,7 +657,7 @@ bool CustomPropertyEditor::edit(Object *p_owner, const String &p_name, Variant::
} else if (hint == PROPERTY_HINT_PROPERTY_OF_SCRIPT) {
MAKE_PROPSELECT
- Object *obj = ObjectDB::get_instance(ObjectID(hint_text.to_int64()));
+ Object *obj = ObjectDB::get_instance(ObjectID(hint_text.to_int()));
if (Object::cast_to<Script>(obj)) {
property_select->select_property_from_script(Object::cast_to<Script>(obj), v);
}
diff --git a/editor/quick_open.cpp b/editor/quick_open.cpp
index bcef29dfa6..4af6fb2053 100644
--- a/editor/quick_open.cpp
+++ b/editor/quick_open.cpp
@@ -32,21 +32,18 @@
#include "core/os/keyboard.h"
-void EditorQuickOpen::popup_dialog(const StringName &p_base, bool p_enable_multi, bool p_add_dirs, bool p_dontclear) {
- add_directories = p_add_dirs;
- popup_centered_ratio(0.6);
+void EditorQuickOpen::popup_dialog(const StringName &p_base, bool p_enable_multi, bool p_dontclear) {
+ base_type = p_base;
+ search_options->set_select_mode(p_enable_multi ? Tree::SELECT_MULTI : Tree::SELECT_SINGLE);
+ popup_centered_ratio(0.4);
+
if (p_dontclear) {
search_box->select_all();
} else {
search_box->clear();
}
- if (p_enable_multi) {
- search_options->set_select_mode(Tree::SELECT_MULTI);
- } else {
- search_options->set_select_mode(Tree::SELECT_SINGLE);
- }
+
search_box->grab_focus();
- base_type = p_base;
_update_search();
}
@@ -65,7 +62,6 @@ Vector<String> EditorQuickOpen::get_selected_files() const {
TreeItem *item = search_options->get_next_selected(search_options->get_root());
while (item) {
files.push_back("res://" + item->get_text(0));
-
item = search_options->get_next_selected(item);
}
@@ -93,7 +89,6 @@ void EditorQuickOpen::_sbox_input(const Ref<InputEvent> &p_ie) {
}
TreeItem *current = search_options->get_selected();
-
TreeItem *item = search_options->get_next_selected(root);
while (item) {
item->deselect(0);
@@ -101,88 +96,55 @@ void EditorQuickOpen::_sbox_input(const Ref<InputEvent> &p_ie) {
}
current->select(0);
-
+ current->set_as_cursor(0);
} break;
}
}
}
-float EditorQuickOpen::_path_cmp(String search, String path) const {
- // Exact match.
- if (search == path) {
- return 1.2f;
+float EditorQuickOpen::_score_path(String search, String path) const {
+ // Positive bias for matches close to the _beginning of the file name_.
+ String file = path.get_file();
+ int pos = file.findn(search);
+ if (pos != -1) {
+ return 1.0f - 0.1f * (float(pos) / file.length());
}
- // Substring match, with positive bias for matches close to the end of the path.
- int pos = path.rfindn(search);
+ // Positive bias for matches close to the _end of the path_.
+ String base = path.get_base_dir();
+ pos = base.rfindn(search);
if (pos != -1) {
- return 1.1f + 0.09 / (path.length() - pos + 1);
+ return 0.9f - 0.1f * (float(base.length() - pos) / base.length());
}
- // Similarity.
- return path.to_lower().similarity(search.to_lower());
+ // Results that contain all characters but not the string.
+ return path.similarity(search) * 0.8f;
}
void EditorQuickOpen::_parse_fs(EditorFileSystemDirectory *efsd, Vector<Pair<String, Ref<Texture2D>>> &list) {
- if (!add_directories) {
- for (int i = 0; i < efsd->get_subdir_count(); i++) {
- _parse_fs(efsd->get_subdir(i), list);
- }
+ for (int i = 0; i < efsd->get_subdir_count(); i++) {
+ _parse_fs(efsd->get_subdir(i), list);
}
- String search_text = search_box->get_text();
-
- if (add_directories) {
- String path = efsd->get_path();
- if (!path.ends_with("/")) {
- path += "/";
- }
- if (path != "res://") {
- path = path.substr(6, path.length());
- if (search_text.is_subsequence_ofi(path)) {
- Pair<String, Ref<Texture2D>> pair;
- pair.first = path;
- pair.second = search_options->get_theme_icon("folder", "FileDialog");
-
- if (search_text != String() && list.size() > 0) {
- float this_sim = _path_cmp(search_text, path);
- float other_sim = _path_cmp(list[0].first, path);
- int pos = 1;
-
- while (pos < list.size() && this_sim <= other_sim) {
- other_sim = _path_cmp(list[pos++].first, path);
- }
+ for (int i = 0; i < efsd->get_file_count(); i++) {
+ StringName file_type = efsd->get_file_type(i);
- pos = this_sim >= other_sim ? pos - 1 : pos;
- list.insert(pos, pair);
+ if (ClassDB::is_parent_class(file_type, base_type)) {
+ String file = efsd->get_file_path(i);
+ file = file.substr(6, file.length());
- } else {
- list.push_back(pair);
- }
+ if (search_box->get_text().is_subsequence_ofi(file)) {
+ Pair<String, Ref<Texture2D>> pair;
+ pair.first = file;
+ pair.second = search_options->get_theme_icon(search_options->has_theme_icon(file_type, ei) ? file_type : ot, ei);
+ list.push_back(pair);
}
}
}
- for (int i = 0; i < efsd->get_file_count(); i++) {
- String file = efsd->get_file_path(i);
- file = file.substr(6, file.length());
-
- if (ClassDB::is_parent_class(efsd->get_file_type(i), base_type) && (search_text.is_subsequence_ofi(file))) {
- Pair<String, Ref<Texture2D>> pair;
- pair.first = file;
- pair.second = search_options->get_theme_icon((search_options->has_theme_icon(efsd->get_file_type(i), ei) ? efsd->get_file_type(i) : ot), ei);
- list.push_back(pair);
- }
- }
-
- if (add_directories) {
- for (int i = 0; i < efsd->get_subdir_count(); i++) {
- _parse_fs(efsd->get_subdir(i), list);
- }
- }
}
Vector<Pair<String, Ref<Texture2D>>> EditorQuickOpen::_sort_fs(Vector<Pair<String, Ref<Texture2D>>> &list) {
- String search_text = search_box->get_text();
+ String search_text = search_box->get_text().to_lower();
Vector<Pair<String, Ref<Texture2D>>> sorted_list;
if (search_text == String() || list.size() == 0) {
@@ -192,7 +154,7 @@ Vector<Pair<String, Ref<Texture2D>>> EditorQuickOpen::_sort_fs(Vector<Pair<Strin
Vector<float> scores;
scores.resize(list.size());
for (int i = 0; i < list.size(); i++) {
- scores.write[i] = _path_cmp(search_text, list[i].first);
+ scores.write[i] = _score_path(search_text, list[i].first.to_lower());
}
while (list.size() > 0) {
@@ -230,19 +192,17 @@ void EditorQuickOpen::_update_search() {
ti->set_icon(0, list[i].second);
}
- if (root->get_children()) {
- TreeItem *ti = root->get_children();
-
- ti->select(0);
- ti->set_as_cursor(0);
+ TreeItem *result = root->get_children();
+ if (result) {
+ result->select(0);
+ result->set_as_cursor(0);
}
- get_ok()->set_disabled(root->get_children() == nullptr);
+ get_ok()->set_disabled(!result);
}
void EditorQuickOpen::_confirmed() {
- TreeItem *ti = search_options->get_selected();
- if (!ti) {
+ if (!search_options->get_selected()) {
return;
}
emit_signal("quick_open");
@@ -250,7 +210,7 @@ void EditorQuickOpen::_confirmed() {
}
void EditorQuickOpen::_theme_changed() {
- search_box->set_right_icon(search_options->get_theme_icon("Search", "EditorIcons"));
+ search_box->set_right_icon(search_options->get_theme_icon("Search", ei));
}
void EditorQuickOpen::_notification(int p_what) {
@@ -277,23 +237,24 @@ void EditorQuickOpen::_bind_methods() {
EditorQuickOpen::EditorQuickOpen() {
VBoxContainer *vbc = memnew(VBoxContainer);
vbc->connect("theme_changed", callable_mp(this, &EditorQuickOpen::_theme_changed));
-
add_child(vbc);
+
search_box = memnew(LineEdit);
- vbc->add_margin_child(TTR("Search:"), search_box);
search_box->connect("text_changed", callable_mp(this, &EditorQuickOpen::_text_changed));
search_box->connect("gui_input", callable_mp(this, &EditorQuickOpen::_sbox_input));
+ vbc->add_margin_child(TTR("Search:"), search_box);
+
search_options = memnew(Tree);
- vbc->add_margin_child(TTR("Matches:"), search_options, true);
- get_ok()->set_text(TTR("Open"));
- get_ok()->set_disabled(true);
- register_text_enter(search_box);
- set_hide_on_ok(false);
search_options->connect("item_activated", callable_mp(this, &EditorQuickOpen::_confirmed));
search_options->set_hide_root(true);
search_options->set_hide_folding(true);
search_options->add_theme_constant_override("draw_guides", 1);
+ vbc->add_margin_child(TTR("Matches:"), search_options, true);
+
+ get_ok()->set_text(TTR("Open"));
+ register_text_enter(search_box);
+ set_hide_on_ok(false);
+
ei = "EditorIcons";
ot = "Object";
- add_directories = false;
}
diff --git a/editor/quick_open.h b/editor/quick_open.h
index e446ed6823..5bcdfc7bf2 100644
--- a/editor/quick_open.h
+++ b/editor/quick_open.h
@@ -35,22 +35,23 @@
#include "editor_file_system.h"
#include "scene/gui/dialogs.h"
#include "scene/gui/tree.h"
+
class EditorQuickOpen : public ConfirmationDialog {
GDCLASS(EditorQuickOpen, ConfirmationDialog);
LineEdit *search_box;
Tree *search_options;
+
StringName base_type;
StringName ei;
StringName ot;
- bool add_directories;
void _update_search();
void _sbox_input(const Ref<InputEvent> &p_ie);
void _parse_fs(EditorFileSystemDirectory *efsd, Vector<Pair<String, Ref<Texture2D>>> &list);
Vector<Pair<String, Ref<Texture2D>>> _sort_fs(Vector<Pair<String, Ref<Texture2D>>> &list);
- float _path_cmp(String search, String path) const;
+ float _score_path(String search, String path) const;
void _confirmed();
void _text_changed(const String &p_newtext);
@@ -67,7 +68,7 @@ public:
String get_selected() const;
Vector<String> get_selected_files() const;
- void popup_dialog(const StringName &p_base, bool p_enable_multi = false, bool p_add_dirs = false, bool p_dontclear = false);
+ void popup_dialog(const StringName &p_base, bool p_enable_multi = false, bool p_dontclear = false);
EditorQuickOpen();
};
diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp
index dd42ed9760..41b8baeb2f 100644
--- a/editor/scene_tree_dock.cpp
+++ b/editor/scene_tree_dock.cpp
@@ -350,17 +350,26 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
if (!profile_allow_editing) {
break;
}
- String preferred = "";
- Node *current_edited_scene_root = EditorNode::get_singleton()->get_edited_scene();
+ // Prefer nodes that inherit from the current scene root.
+ Node *current_edited_scene_root = EditorNode::get_singleton()->get_edited_scene();
if (current_edited_scene_root) {
- if (ClassDB::is_parent_class(current_edited_scene_root->get_class_name(), "Node2D")) {
- preferred = "Node2D";
- } else if (ClassDB::is_parent_class(current_edited_scene_root->get_class_name(), "Node3D")) {
- preferred = "Node3D";
+ String root_class = current_edited_scene_root->get_class_name();
+ static Vector<String> preferred_types;
+ if (preferred_types.empty()) {
+ preferred_types.push_back("Control");
+ preferred_types.push_back("Node2D");
+ preferred_types.push_back("Node3D");
+ }
+
+ for (int i = 0; i < preferred_types.size(); i++) {
+ if (ClassDB::is_parent_class(root_class, preferred_types[i])) {
+ create_dialog->set_preferred_search_result_type(preferred_types[i]);
+ break;
+ }
}
}
- create_dialog->set_preferred_search_result_type(preferred);
+
create_dialog->popup_create(true);
} break;
case TOOL_INSTANCE: {
@@ -736,17 +745,28 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
_delete_confirm();
} else {
- if (remove_list.size() >= 2) {
- delete_dialog->set_text(vformat(TTR("Delete %d nodes?"), remove_list.size()));
- } else if (remove_list.size() == 1 && remove_list[0] == editor_data->get_edited_scene_root()) {
- delete_dialog->set_text(vformat(TTR("Delete the root node \"%s\"?"), remove_list[0]->get_name()));
- } else if (remove_list.size() == 1 && remove_list[0]->get_filename() == "" && remove_list[0]->get_child_count() >= 1) {
- // Display this message only for non-instanced scenes
- delete_dialog->set_text(vformat(TTR("Delete node \"%s\" and its children?"), remove_list[0]->get_name()));
+ String msg;
+ if (remove_list.size() > 1) {
+ bool any_children = false;
+ for (int i = 0; !any_children && i < remove_list.size(); i++) {
+ any_children = remove_list[i]->get_child_count() > 0;
+ }
+
+ msg = vformat(any_children ? TTR("Delete %d nodes and any children?") : TTR("Delete %d nodes?"), remove_list.size());
} else {
- delete_dialog->set_text(vformat(TTR("Delete node \"%s\"?"), remove_list[0]->get_name()));
+ Node *node = remove_list[0];
+ if (node == editor_data->get_edited_scene_root()) {
+ msg = vformat(TTR("Delete the root node \"%s\"?"), node->get_name());
+ } else if (node->get_filename() == "" && node->get_child_count() > 0) {
+ // Display this message only for non-instanced scenes
+ msg = vformat(TTR("Delete node \"%s\" and its children?"), node->get_name());
+ } else {
+ msg = vformat(TTR("Delete node \"%s\"?"), node->get_name());
+ }
}
+ delete_dialog->set_text(msg);
+
// Resize the dialog to its minimum size.
// This prevents the dialog from being too wide after displaying
// a deletion confirmation for a node with a long name.
@@ -2383,7 +2403,7 @@ void SceneTreeDock::_tree_rmb(const Vector2 &p_menu_pos) {
}
menu->set_size(Size2(1, 1));
- menu->set_position(p_menu_pos);
+ menu->set_position(get_screen_position() + p_menu_pos);
menu->popup();
return;
}
diff --git a/editor/scene_tree_editor.cpp b/editor/scene_tree_editor.cpp
index 1b818036e1..f30e57579f 100644
--- a/editor/scene_tree_editor.cpp
+++ b/editor/scene_tree_editor.cpp
@@ -902,6 +902,10 @@ Variant SceneTreeEditor::get_drag_data_fw(const Point2 &p_point, Control *p_from
return Variant(); //not editable tree
}
+ if (tree->get_button_id_at_position(p_point) != -1) {
+ return Variant(); //dragging from button
+ }
+
Vector<Node *> selected;
Vector<Ref<Texture2D>> icons;
TreeItem *next = tree->get_next_selected(nullptr);
@@ -1072,7 +1076,7 @@ void SceneTreeEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data,
}
void SceneTreeEditor::_rmb_select(const Vector2 &p_pos) {
- emit_signal("rmb_pressed", tree->get_global_transform().xform(p_pos));
+ emit_signal("rmb_pressed", tree->get_screen_transform().xform(p_pos));
}
void SceneTreeEditor::_warning_changed(Node *p_for_node) {
diff --git a/editor/script_create_dialog.cpp b/editor/script_create_dialog.cpp
index ae5229b628..40e0582046 100644
--- a/editor/script_create_dialog.cpp
+++ b/editor/script_create_dialog.cpp
@@ -78,7 +78,7 @@ void ScriptCreateDialog::_notification(int p_what) {
void ScriptCreateDialog::_path_hbox_sorted() {
if (is_visible()) {
- int filename_start_pos = initial_bp.find_last("/") + 1;
+ int filename_start_pos = initial_bp.rfind("/") + 1;
int filename_end_pos = initial_bp.length();
if (!is_built_in) {
@@ -553,7 +553,7 @@ void ScriptCreateDialog::_file_selected(const String &p_file) {
_path_changed(p);
String filename = p.get_file().get_basename();
- int select_start = p.find_last(filename);
+ int select_start = p.rfind(filename);
file_path->select(select_start, select_start + filename.length());
file_path->set_cursor_position(select_start + filename.length());
file_path->grab_focus();
diff --git a/editor/translations/af.po b/editor/translations/af.po
index 1f598ef5e5..daa0737106 100644
--- a/editor/translations/af.po
+++ b/editor/translations/af.po
@@ -784,6 +784,11 @@ msgstr "Metode in teiken Nodus moet gespesifiseer word!"
#: editor/connections_dialog.cpp
#, fuzzy
+msgid "Method name must be a valid identifier."
+msgstr "Metode in teiken Nodus moet gespesifiseer word!"
+
+#: editor/connections_dialog.cpp
+#, fuzzy
msgid ""
"Target method not found. Specify a valid method or attach a script to the "
"target node."
diff --git a/editor/translations/ar.po b/editor/translations/ar.po
index a60de1a41e..5a0b6d1e17 100644
--- a/editor/translations/ar.po
+++ b/editor/translations/ar.po
@@ -45,8 +45,8 @@ msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2020-06-09 02:02+0000\n"
-"Last-Translator: HeroFight dev <abdkafi2002@gmail.com>\n"
+"PO-Revision-Date: 2020-06-25 08:40+0000\n"
+"Last-Translator: Airbus5717 <Abdussamadf350@gmail.com>\n"
"Language-Team: Arabic <https://hosted.weblate.org/projects/godot-engine/"
"godot/ar/>\n"
"Language: ar\n"
@@ -55,7 +55,7 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 "
"&& n%100<=10 ? 3 : n%100>=11 ? 4 : 5;\n"
-"X-Generator: Weblate 4.1-dev\n"
+"X-Generator: Weblate 4.2-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -785,6 +785,10 @@ msgid "Method in target node must be specified."
msgstr "يجب تحديد الدالة في العقدة المستهدفة."
#: editor/connections_dialog.cpp
+msgid "Method name must be a valid identifier."
+msgstr "اسم الدالة يجب أن تكون مميزاً و صالحاً."
+
+#: editor/connections_dialog.cpp
msgid ""
"Target method not found. Specify a valid method or attach a script to the "
"target node."
@@ -1477,7 +1481,7 @@ msgstr "اعادة ترتيب التحميلات التلقائية"
#: editor/editor_autoload_settings.cpp
msgid "Can't add autoload:"
-msgstr ""
+msgstr "لا يمكن اضافة التحميل التلقائي"
#: editor/editor_autoload_settings.cpp
msgid "Add AutoLoad"
@@ -2426,15 +2430,16 @@ msgid "Can't reload a scene that was never saved."
msgstr "لا يمكن إعادة تحميل مشهد لم يتم حفظه من قبل."
#: editor/editor_node.cpp
-#, fuzzy
msgid "Reload Saved Scene"
-msgstr "حفظ المشهد"
+msgstr "إعادة تحميل المشهد المحفوظ"
#: editor/editor_node.cpp
msgid ""
"The current scene has unsaved changes.\n"
"Reload the saved scene anyway? This action cannot be undone."
msgstr ""
+"يحتوي المشهد الحالي على تغييرات غير محفوظة.\n"
+"إعادة تحميل المشهد المحفوظ على أي حال؟ لا يمكن التراجع عن هذا الإجراء."
#: editor/editor_node.cpp
msgid "Quick Run Scene..."
@@ -3361,11 +3366,9 @@ msgid "Did you forget the '_run' method?"
msgstr "هل نسيت الطريقة '_run' ؟"
#: editor/editor_spin_slider.cpp
-#, fuzzy
msgid "Hold Ctrl to round to integers. Hold Shift for more precise changes."
msgstr ""
-"اضغط مطولاً على Ctrl لإسقاط جالب Getter. اضغط مطولاً على Shift لإسقاط توقيع "
-"عام generic signature."
+"امسك Ctrl للتدوير للأعداد الصحيحة. اضغط على Shift لإجراء تغييرات أكثر دقة."
#: editor/editor_sub_scene.cpp
msgid "Select Node(s) to Import"
@@ -3962,7 +3965,7 @@ msgstr "خطأ في تشغيل الكود الملصق- المستورد:"
#: editor/import/resource_importer_scene.cpp
msgid "Did you return a Node-derived object in the `post_import()` method?"
-msgstr ""
+msgstr "هل قمت بإرجاع كائن مشتق من العقدة في دالة`post_import ()`؟"
#: editor/import/resource_importer_scene.cpp
msgid "Saving..."
@@ -4181,14 +4184,12 @@ msgid "Move Node Point"
msgstr "تحريك نقطة العقدة"
#: editor/plugins/animation_blend_space_1d_editor.cpp
-#, fuzzy
msgid "Change BlendSpace1D Limits"
-msgstr "تغيير وقت الدمج"
+msgstr "تغيير حدود BlendSpace1D"
#: editor/plugins/animation_blend_space_1d_editor.cpp
-#, fuzzy
msgid "Change BlendSpace1D Labels"
-msgstr "تغيير وقت الدمج"
+msgstr "تغيير ملصقات BlendSpace1D"
#: editor/plugins/animation_blend_space_1d_editor.cpp
#: editor/plugins/animation_blend_space_2d_editor.cpp
@@ -4204,9 +4205,8 @@ msgstr "إضافة نقطة العقدة"
#: editor/plugins/animation_blend_space_1d_editor.cpp
#: editor/plugins/animation_blend_space_2d_editor.cpp
-#, fuzzy
msgid "Add Animation Point"
-msgstr "أضف حركة"
+msgstr "أضف نقطة حركة"
#: editor/plugins/animation_blend_space_1d_editor.cpp
msgid "Remove BlendSpace1D Point"
@@ -4240,7 +4240,6 @@ msgstr "حدد وحرك النقاط، أنشئ النقاط باستخدام RM
#: editor/plugins/animation_blend_space_1d_editor.cpp
#: editor/plugins/animation_blend_space_2d_editor.cpp scene/gui/graph_edit.cpp
-#, fuzzy
msgid "Enable snap and show grid."
msgstr "تمكين المحاذاة وإظهار الشبكة."
@@ -4452,14 +4451,12 @@ msgid "Remove Animation"
msgstr "مسح الحركة"
#: editor/plugins/animation_player_editor_plugin.cpp
-#, fuzzy
msgid "Invalid animation name!"
-msgstr "خطأ: إسم حركة خاطئ!"
+msgstr "خطأ: إسم الرسوم المتحركة خاطئ!"
#: editor/plugins/animation_player_editor_plugin.cpp
-#, fuzzy
msgid "Animation name already exists!"
-msgstr "خطأ: إسم الحركة موجود بالفعل!"
+msgstr "اسم الحركة موجود بالفعل!"
#: editor/plugins/animation_player_editor_plugin.cpp
#: editor/plugins/sprite_frames_editor_plugin.cpp
@@ -4675,19 +4672,16 @@ msgid "Start and end nodes are needed for a sub-transition."
msgstr "عُقد البداية والنهاية مطلوبة لأجل الانتقال الجزيئ sub-transition."
#: editor/plugins/animation_state_machine_editor.cpp
-#, fuzzy
msgid "No playback resource set at path: %s."
-msgstr "ليس في مسار الموارد."
+msgstr "لم يتم تعيين موارد التشغيل في المسار:٪ s."
#: editor/plugins/animation_state_machine_editor.cpp
-#, fuzzy
msgid "Node Removed"
-msgstr "مُسِح:"
+msgstr "مُسِحت العقدة"
#: editor/plugins/animation_state_machine_editor.cpp
-#, fuzzy
msgid "Transition Removed"
-msgstr "عقدة التنقل"
+msgstr "تمت إزالة النقل"
#: editor/plugins/animation_state_machine_editor.cpp
msgid "Set Start Node (Autoplay)"
@@ -4704,19 +4698,16 @@ msgstr ""
"LMB + Shift (زر الفأرة الأيسر) لإنشاء الوصلات."
#: editor/plugins/animation_state_machine_editor.cpp
-#, fuzzy
msgid "Create new nodes."
-msgstr "إنشاء %s جديد"
+msgstr "إنشاء عُقد جديدة."
#: editor/plugins/animation_state_machine_editor.cpp
-#, fuzzy
msgid "Connect nodes."
-msgstr "صلها بالعقدة:"
+msgstr "توصيل عقد."
#: editor/plugins/animation_state_machine_editor.cpp
-#, fuzzy
msgid "Remove selected node or transition."
-msgstr "ازالة المسار المحدد."
+msgstr "ازالة الكائن المحدد او الإنتقال المحدد."
#: editor/plugins/animation_state_machine_editor.cpp
msgid "Toggle autoplay this animation on start, restart or seek to zero."
@@ -4730,9 +4721,8 @@ msgstr ""
"تحديد الرسومية المتحركة الخاصة بالنهاية. سيكون ذلك مفيداً للحركات الفرعية."
#: editor/plugins/animation_state_machine_editor.cpp
-#, fuzzy
msgid "Transition: "
-msgstr "تحول"
+msgstr "التحريك "
#: editor/plugins/animation_state_machine_editor.cpp
#, fuzzy
diff --git a/editor/translations/bg.po b/editor/translations/bg.po
index f08f2b1362..c9f38d518a 100644
--- a/editor/translations/bg.po
+++ b/editor/translations/bg.po
@@ -746,6 +746,10 @@ msgid "Method in target node must be specified."
msgstr ""
#: editor/connections_dialog.cpp
+msgid "Method name must be a valid identifier."
+msgstr ""
+
+#: editor/connections_dialog.cpp
msgid ""
"Target method not found. Specify a valid method or attach a script to the "
"target node."
diff --git a/editor/translations/bn.po b/editor/translations/bn.po
index 3680e4ce6c..c438934246 100644
--- a/editor/translations/bn.po
+++ b/editor/translations/bn.po
@@ -809,6 +809,11 @@ msgstr "নির্দেশিত নোডের মেথড নির্দ
#: editor/connections_dialog.cpp
#, fuzzy
+msgid "Method name must be a valid identifier."
+msgstr "নামটি কার্যকর সনাক্তকারী নয়:"
+
+#: editor/connections_dialog.cpp
+#, fuzzy
msgid ""
"Target method not found. Specify a valid method or attach a script to the "
"target node."
diff --git a/editor/translations/ca.po b/editor/translations/ca.po
index 1640367701..5fb91db7b4 100644
--- a/editor/translations/ca.po
+++ b/editor/translations/ca.po
@@ -765,6 +765,11 @@ msgid "Method in target node must be specified."
msgstr "S'ha d'especificar el mètode al node de destinació."
#: editor/connections_dialog.cpp
+#, fuzzy
+msgid "Method name must be a valid identifier."
+msgstr "El nom no és un identificador vàlid:"
+
+#: editor/connections_dialog.cpp
msgid ""
"Target method not found. Specify a valid method or attach a script to the "
"target node."
diff --git a/editor/translations/cs.po b/editor/translations/cs.po
index fabec77283..722fa52d92 100644
--- a/editor/translations/cs.po
+++ b/editor/translations/cs.po
@@ -24,7 +24,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2020-06-06 10:15+0000\n"
+"PO-Revision-Date: 2020-06-25 08:40+0000\n"
"Last-Translator: Zbyněk <zbynek.fiala@gmail.com>\n"
"Language-Team: Czech <https://hosted.weblate.org/projects/godot-engine/godot/"
"cs/>\n"
@@ -33,7 +33,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n"
-"X-Generator: Weblate 4.1-dev\n"
+"X-Generator: Weblate 4.2-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -773,6 +773,11 @@ msgid "Method in target node must be specified."
msgstr "Je nutné zadat metodu v cílovém uzlu."
#: editor/connections_dialog.cpp
+#, fuzzy
+msgid "Method name must be a valid identifier."
+msgstr "Jméno není platný identifikátor:"
+
+#: editor/connections_dialog.cpp
msgid ""
"Target method not found. Specify a valid method or attach a script to the "
"target node."
@@ -10055,7 +10060,7 @@ msgstr "Přidat akci"
#: editor/project_settings_editor.cpp
msgid "Button"
-msgstr "Tlačítko"
+msgstr "Button"
#: editor/project_settings_editor.cpp
msgid "Left Button."
@@ -11013,9 +11018,8 @@ msgid "Copy Error"
msgstr "Kopírovat chybu"
#: editor/script_editor_debugger.cpp
-#, fuzzy
msgid "Video RAM"
-msgstr "Video pamět"
+msgstr "Video RAM"
#: editor/script_editor_debugger.cpp
#, fuzzy
diff --git a/editor/translations/da.po b/editor/translations/da.po
index 8eeaaafaea..70b05c08ff 100644
--- a/editor/translations/da.po
+++ b/editor/translations/da.po
@@ -16,12 +16,13 @@
# Kristoffer Andersen <kjaa@google.com>, 2019.
# Joe Osborne <reachjoe.o@gmail.com>, 2020.
# Autowinto <happymansi@hotmail.com>, 2020.
+# Mikkel Mouridsen <mikkelmouridsen@me.com>, 2020.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2020-02-02 08:51+0000\n"
-"Last-Translator: Autowinto <happymansi@hotmail.com>\n"
+"PO-Revision-Date: 2020-06-22 06:40+0000\n"
+"Last-Translator: Mikkel Mouridsen <mikkelmouridsen@me.com>\n"
"Language-Team: Danish <https://hosted.weblate.org/projects/godot-engine/"
"godot/da/>\n"
"Language: da\n"
@@ -29,7 +30,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
-"X-Generator: Weblate 3.11-dev\n"
+"X-Generator: Weblate 4.2-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -443,7 +444,7 @@ msgstr "Det er ikke muligt at tilføje et nyt spor uden en rod"
#: editor/animation_track_editor.cpp
msgid "Invalid track for Bezier (no suitable sub-properties)"
-msgstr ""
+msgstr "Ugyldigt spor for Bezier (ingen passende underegenskaber)"
#: editor/animation_track_editor.cpp
#, fuzzy
@@ -785,7 +786,7 @@ msgstr "Advarsler"
#: editor/code_editor.cpp
msgid "Line and column numbers."
-msgstr ""
+msgstr "Linje- og kolonnenumre."
#: editor/connections_dialog.cpp
#, fuzzy
@@ -794,6 +795,11 @@ msgstr "Metode i target Node skal angives!"
#: editor/connections_dialog.cpp
#, fuzzy
+msgid "Method name must be a valid identifier."
+msgstr "Navnet er ikke et gyldigt id:"
+
+#: editor/connections_dialog.cpp
+#, fuzzy
msgid ""
"Target method not found. Specify a valid method or attach a script to the "
"target node."
@@ -1252,7 +1258,7 @@ msgstr "Udpakker Aktiver"
#: editor/editor_asset_installer.cpp editor/project_manager.cpp
msgid "The following files failed extraction from package:"
-msgstr ""
+msgstr "De følgende filer kunne ikke trækkes ud af pakken:"
#: editor/editor_asset_installer.cpp
#, fuzzy
diff --git a/editor/translations/de.po b/editor/translations/de.po
index b52206e56e..eb533ff15e 100644
--- a/editor/translations/de.po
+++ b/editor/translations/de.po
@@ -56,7 +56,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2020-06-15 01:48+0000\n"
+"PO-Revision-Date: 2020-06-25 08:40+0000\n"
"Last-Translator: So Wieso <sowieso@dukun.de>\n"
"Language-Team: German <https://hosted.weblate.org/projects/godot-engine/"
"godot/de/>\n"
@@ -65,7 +65,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
-"X-Generator: Weblate 4.1-dev\n"
+"X-Generator: Weblate 4.2-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -806,6 +806,10 @@ msgid "Method in target node must be specified."
msgstr "Methode des Ziel-Nodes muss angegeben werden."
#: editor/connections_dialog.cpp
+msgid "Method name must be a valid identifier."
+msgstr "Methodenname muss ein gültiger Bezeichner sein."
+
+#: editor/connections_dialog.cpp
msgid ""
"Target method not found. Specify a valid method or attach a script to the "
"target node."
diff --git a/editor/translations/editor.pot b/editor/translations/editor.pot
index 4dca7e4c5f..01121a8156 100644
--- a/editor/translations/editor.pot
+++ b/editor/translations/editor.pot
@@ -730,6 +730,10 @@ msgid "Method in target node must be specified."
msgstr ""
#: editor/connections_dialog.cpp
+msgid "Method name must be a valid identifier."
+msgstr ""
+
+#: editor/connections_dialog.cpp
msgid ""
"Target method not found. Specify a valid method or attach a script to the "
"target node."
diff --git a/editor/translations/el.po b/editor/translations/el.po
index 127da8ec1f..8ff5881a9e 100644
--- a/editor/translations/el.po
+++ b/editor/translations/el.po
@@ -7,13 +7,13 @@
# Overloaded <manoschool@yahoo.gr>, 2019.
# Eternal Death <eternaldeath0001@gmail.com>, 2019.
# Overloaded @ Orama Interactive http://orama-interactive.com/ <manoschool@yahoo.gr>, 2020.
+# pandektis <pandektis@gmail.com>, 2020.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2020-05-10 12:37+0000\n"
-"Last-Translator: Overloaded @ Orama Interactive http://orama-interactive."
-"com/ <manoschool@yahoo.gr>\n"
+"PO-Revision-Date: 2020-06-25 08:40+0000\n"
+"Last-Translator: pandektis <pandektis@gmail.com>\n"
"Language-Team: Greek <https://hosted.weblate.org/projects/godot-engine/godot/"
"el/>\n"
"Language: el\n"
@@ -21,7 +21,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
-"X-Generator: Weblate 4.1-dev\n"
+"X-Generator: Weblate 4.2-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -744,11 +744,11 @@ msgstr "Μεγέθυνση"
#: editor/plugins/texture_region_editor_plugin.cpp
#: editor/plugins/tile_set_editor_plugin.cpp scene/gui/graph_edit.cpp
msgid "Zoom Out"
-msgstr "Σμύκρινση"
+msgstr "Σμίκρυνση"
#: editor/code_editor.cpp
msgid "Reset Zoom"
-msgstr "Επαναφορά μεγέθυνσης"
+msgstr "Επαναφορά μεγένθυνσης"
#: editor/code_editor.cpp
msgid "Warnings"
@@ -763,6 +763,10 @@ msgid "Method in target node must be specified."
msgstr "Πρέπει να οριστεί συνάρτηση στον στοχευμένο κόμβο."
#: editor/connections_dialog.cpp
+msgid "Method name must be a valid identifier."
+msgstr "Το όνομα δεν είναι έγκυρο αναγνωριστικό."
+
+#: editor/connections_dialog.cpp
msgid ""
"Target method not found. Specify a valid method or attach a script to the "
"target node."
@@ -1461,7 +1465,7 @@ msgstr "Αναδιάταξη των AutoLoad"
#: editor/editor_autoload_settings.cpp
msgid "Can't add autoload:"
-msgstr ""
+msgstr "Αδυναμία προσθήκης autoload:"
#: editor/editor_autoload_settings.cpp
msgid "Add AutoLoad"
@@ -2423,15 +2427,17 @@ msgstr ""
"Δεν είναι δυνατό να φορτώσετε εκ νέου μια σκηνή που δεν αποθηκεύτηκε ποτέ."
#: editor/editor_node.cpp
-#, fuzzy
msgid "Reload Saved Scene"
-msgstr "Αποθηκεύσετε σκηνής"
+msgstr "Ανανέωση Αποθηκευμένης Σκηνής"
#: editor/editor_node.cpp
msgid ""
"The current scene has unsaved changes.\n"
"Reload the saved scene anyway? This action cannot be undone."
msgstr ""
+"Η τρέχουσα σκηνή έχει μη αποθηκευμένες αλλαγές.\n"
+"Επαναφόρτωση της αποθηκευμένης σκηνής; Αυτή η ενέργεια δεν μπορεί να "
+"αναιρεθεί."
#: editor/editor_node.cpp
msgid "Quick Run Scene..."
@@ -3378,11 +3384,10 @@ msgid "Did you forget the '_run' method?"
msgstr "Μήπως ξεχάσατε τη μέθοδο '_run';"
#: editor/editor_spin_slider.cpp
-#, fuzzy
msgid "Hold Ctrl to round to integers. Hold Shift for more precise changes."
msgstr ""
-"Πατήστε παρατεταμένα το Ctrl για να προσθέσετε έναν Getter. Πατήστε "
-"παρατεταμένα το Shift για να προσθέσετε μία γενική υπογραφή."
+"Πατήστε παρατεταμένα το Ctrl για στρογγυλοποίηση ακεραίων και το Shift για "
+"πιο ακριβείς αλλαγές."
#: editor/editor_sub_scene.cpp
msgid "Select Node(s) to Import"
diff --git a/editor/translations/eo.po b/editor/translations/eo.po
index 3addde45ce..f98f043118 100644
--- a/editor/translations/eo.po
+++ b/editor/translations/eo.po
@@ -764,6 +764,11 @@ msgstr "Metodo en celo nodo devas esti specifita."
#: editor/connections_dialog.cpp
#, fuzzy
+msgid "Method name must be a valid identifier."
+msgstr "Metodo en celo nodo devas esti specifita."
+
+#: editor/connections_dialog.cpp
+#, fuzzy
msgid ""
"Target method not found. Specify a valid method or attach a script to the "
"target node."
diff --git a/editor/translations/es.po b/editor/translations/es.po
index f8c4134d07..a200653685 100644
--- a/editor/translations/es.po
+++ b/editor/translations/es.po
@@ -53,8 +53,8 @@ msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2020-06-15 01:48+0000\n"
-"Last-Translator: paco <pacosoftfree@protonmail.com>\n"
+"PO-Revision-Date: 2020-06-25 08:40+0000\n"
+"Last-Translator: Javier Ocampos <xavier.ocampos@gmail.com>\n"
"Language-Team: Spanish <https://hosted.weblate.org/projects/godot-engine/"
"godot/es/>\n"
"Language: es\n"
@@ -62,7 +62,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
-"X-Generator: Weblate 4.1-dev\n"
+"X-Generator: Weblate 4.2-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -79,7 +79,8 @@ msgstr "Se esperaba un string de longitud 1 (un carácter)."
#: modules/visual_script/visual_script_builtin_funcs.cpp
msgid "Not enough bytes for decoding bytes, or invalid format."
msgstr ""
-"No hay suficientes bytes para decodificar bytes, o el formato es invalido."
+"No hay suficientes bytes para decodificar los bytes, o el formato es "
+"inválido."
#: core/math/expression.cpp
msgid "Invalid input %i (not passed) in expression"
@@ -96,11 +97,11 @@ msgstr "Operandos inválidos para el operador %s, %s y %s."
#: core/math/expression.cpp
msgid "Invalid index of type %s for base type %s"
-msgstr "Indice inválido de tipo %s para tipo base %s"
+msgstr "Índice inválido de tipo %s para el tipo base %s"
#: core/math/expression.cpp
msgid "Invalid named index '%s' for base type %s"
-msgstr "El índice de nombre «%s» no es válido para el tipo de base %s"
+msgstr "El índice de nombre '%s' no es válido para el tipo de base %s"
#: core/math/expression.cpp
msgid "Invalid arguments to construct '%s'"
@@ -806,6 +807,10 @@ msgid "Method in target node must be specified."
msgstr "Se debe establecer un método en el nodo destino."
#: editor/connections_dialog.cpp
+msgid "Method name must be a valid identifier."
+msgstr "El nombre del método debe ser un identificador válido."
+
+#: editor/connections_dialog.cpp
msgid ""
"Target method not found. Specify a valid method or attach a script to the "
"target node."
@@ -2014,7 +2019,7 @@ msgstr "Propiedades del Tema"
#: editor/editor_help.cpp
msgid "Enumerations"
-msgstr "Enumeraciones"
+msgstr "Enumerados"
#: editor/editor_help.cpp
msgid "Constants"
@@ -3039,7 +3044,7 @@ msgstr "Reproducir Escena Personalizada"
#: editor/editor_node.cpp
msgid "Changing the video driver requires restarting the editor."
-msgstr "Cambiar el driver de video requiere reiniciar el editor."
+msgstr "Cambiar el driver de vídeo requiere reiniciar el editor."
#: editor/editor_node.cpp editor/project_settings_editor.cpp
#: editor/settings_config_dialog.cpp
@@ -3378,7 +3383,7 @@ msgstr "Página: "
#: editor/editor_properties_array_dict.cpp
#: editor/plugins/theme_editor_plugin.cpp
msgid "Remove Item"
-msgstr "Eliminar Item"
+msgstr "Eliminar Ítem"
#: editor/editor_properties_array_dict.cpp
msgid "New Key:"
@@ -5906,15 +5911,15 @@ msgstr "Degradado Editado"
#: editor/plugins/item_list_editor_plugin.cpp
msgid "Item %d"
-msgstr "Elemento %d"
+msgstr "Ítem %d"
#: editor/plugins/item_list_editor_plugin.cpp
msgid "Items"
-msgstr "Elementos"
+msgstr "Ítems"
#: editor/plugins/item_list_editor_plugin.cpp
msgid "Item List Editor"
-msgstr "Editor de Lista de Items"
+msgstr "Editor de Lista de Ítems"
#: editor/plugins/light_occluder_2d_editor_plugin.cpp
msgid "Create Occluder Polygon"
@@ -6104,7 +6109,7 @@ msgstr "Depuración del Canal UV"
#: editor/plugins/mesh_library_editor_plugin.cpp
msgid "Remove item %d?"
-msgstr "¿Quieres borrar el elemento %d?"
+msgstr "¿Eliminar el ítem %d?"
#: editor/plugins/mesh_library_editor_plugin.cpp
msgid ""
@@ -6121,11 +6126,11 @@ msgstr "Librería de Mallas"
#: editor/plugins/mesh_library_editor_plugin.cpp
#: editor/plugins/theme_editor_plugin.cpp
msgid "Add Item"
-msgstr "Añadir Item"
+msgstr "Añadir Ítem"
#: editor/plugins/mesh_library_editor_plugin.cpp
msgid "Remove Selected Item"
-msgstr "Borrar elemento seleccionado"
+msgstr "Eliminar Ítem Seleccionado"
#: editor/plugins/mesh_library_editor_plugin.cpp
msgid "Import from Scene"
@@ -7935,7 +7940,7 @@ msgstr "Región de Textura"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Add All Items"
-msgstr "Añadir Todos los Elementos"
+msgstr "Añadir Todos los Ítems"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Add All"
@@ -7959,11 +7964,11 @@ msgstr "Menú de edición de tema."
#: editor/plugins/theme_editor_plugin.cpp
msgid "Add Class Items"
-msgstr "Añadir elementos de clase"
+msgstr "Añadir Clases de Ítems"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Remove Class Items"
-msgstr "Eliminar Ítems de Clases"
+msgstr "Eliminar Clases de Ítems"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Create Empty Template"
@@ -9558,11 +9563,11 @@ msgstr "Exportar todos los recursos del proyecto"
#: editor/project_export.cpp
msgid "Export selected scenes (and dependencies)"
-msgstr "Exportar las escenas seleccionadas (incluyendo dependencias)"
+msgstr "Exportar escenas seleccionadas (y dependencias)"
#: editor/project_export.cpp
msgid "Export selected resources (and dependencies)"
-msgstr "Exportar los recursos seleccionado (incluyendo dependencias)"
+msgstr "Exportar los recursos seleccionados (y dependencias)"
#: editor/project_export.cpp
msgid "Export Mode:"
@@ -11106,7 +11111,7 @@ msgstr "Copiar Error"
#: editor/script_editor_debugger.cpp
msgid "Video RAM"
-msgstr "Vídeo RAM"
+msgstr "Memoria de Vídeo"
#: editor/script_editor_debugger.cpp
msgid "Skip Breakpoints"
@@ -11146,11 +11151,11 @@ msgstr "Monitores"
#: editor/script_editor_debugger.cpp
msgid "Pick one or more items from the list to display the graph."
-msgstr "Elige uno o más elementos de la lista para mostrar el gráfico."
+msgstr "Elige uno o más ítems de la lista para mostrar el gráfico."
#: editor/script_editor_debugger.cpp
msgid "List of Video Memory Usage by Resource:"
-msgstr "Lista de uso de memoria de video por recurso:"
+msgstr "Listado de la Memoria de Vídeo Utilizada por Recurso:"
#: editor/script_editor_debugger.cpp
msgid "Total:"
@@ -12606,7 +12611,7 @@ msgid ""
"GIProbes are not supported by the GLES2 video driver.\n"
"Use a BakedLightmap instead."
msgstr ""
-"Las GIProbes no están soportadas por el controlador de video GLES2.\n"
+"Las GIProbes no están soportadas por el controlador de vídeo GLES2.\n"
"Usa un BakedLightmap en su lugar."
#: scene/3d/light.cpp
diff --git a/editor/translations/es_AR.po b/editor/translations/es_AR.po
index 46cb219e14..ca9f5a7a49 100644
--- a/editor/translations/es_AR.po
+++ b/editor/translations/es_AR.po
@@ -19,7 +19,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2020-06-15 01:48+0000\n"
+"PO-Revision-Date: 2020-06-25 08:40+0000\n"
"Last-Translator: Lisandro Lorea <lisandrolorea@gmail.com>\n"
"Language-Team: Spanish (Argentina) <https://hosted.weblate.org/projects/"
"godot-engine/godot/es_AR/>\n"
@@ -28,7 +28,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
-"X-Generator: Weblate 4.1-dev\n"
+"X-Generator: Weblate 4.2-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -770,6 +770,10 @@ msgid "Method in target node must be specified."
msgstr "El método en el nodo objetivo debe ser especificado."
#: editor/connections_dialog.cpp
+msgid "Method name must be a valid identifier."
+msgstr "El nombre del método debe ser un identificador válido."
+
+#: editor/connections_dialog.cpp
msgid ""
"Target method not found. Specify a valid method or attach a script to the "
"target node."
diff --git a/editor/translations/et.po b/editor/translations/et.po
index 7be6996d69..5fd61347e1 100644
--- a/editor/translations/et.po
+++ b/editor/translations/et.po
@@ -744,6 +744,10 @@ msgid "Method in target node must be specified."
msgstr ""
#: editor/connections_dialog.cpp
+msgid "Method name must be a valid identifier."
+msgstr ""
+
+#: editor/connections_dialog.cpp
msgid ""
"Target method not found. Specify a valid method or attach a script to the "
"target node."
diff --git a/editor/translations/eu.po b/editor/translations/eu.po
index b47056d82b..e461c0f1ec 100644
--- a/editor/translations/eu.po
+++ b/editor/translations/eu.po
@@ -735,6 +735,10 @@ msgid "Method in target node must be specified."
msgstr ""
#: editor/connections_dialog.cpp
+msgid "Method name must be a valid identifier."
+msgstr ""
+
+#: editor/connections_dialog.cpp
msgid ""
"Target method not found. Specify a valid method or attach a script to the "
"target node."
diff --git a/editor/translations/fa.po b/editor/translations/fa.po
index 3f94d1112b..428b69062a 100644
--- a/editor/translations/fa.po
+++ b/editor/translations/fa.po
@@ -784,6 +784,11 @@ msgstr "متد در گره مقصد باید مشخص شده باشد!"
#: editor/connections_dialog.cpp
#, fuzzy
+msgid "Method name must be a valid identifier."
+msgstr "نام یک شناسه‌ی معتبر نیست:"
+
+#: editor/connections_dialog.cpp
+#, fuzzy
msgid ""
"Target method not found. Specify a valid method or attach a script to the "
"target node."
diff --git a/editor/translations/fi.po b/editor/translations/fi.po
index a95c65be41..8ea9a940f0 100644
--- a/editor/translations/fi.po
+++ b/editor/translations/fi.po
@@ -15,7 +15,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2020-06-15 01:48+0000\n"
+"PO-Revision-Date: 2020-06-25 08:40+0000\n"
"Last-Translator: Tapani Niemi <tapani.niemi@kapsi.fi>\n"
"Language-Team: Finnish <https://hosted.weblate.org/projects/godot-engine/"
"godot/fi/>\n"
@@ -24,7 +24,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
-"X-Generator: Weblate 4.1-dev\n"
+"X-Generator: Weblate 4.2-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -757,6 +757,10 @@ msgid "Method in target node must be specified."
msgstr "Kohdesolmun metodi täytyy määrittää."
#: editor/connections_dialog.cpp
+msgid "Method name must be a valid identifier."
+msgstr "Metodin nimen täytyy olla kelvollinen tunniste."
+
+#: editor/connections_dialog.cpp
msgid ""
"Target method not found. Specify a valid method or attach a script to the "
"target node."
diff --git a/editor/translations/fil.po b/editor/translations/fil.po
index 920b91a30c..ceda61c802 100644
--- a/editor/translations/fil.po
+++ b/editor/translations/fil.po
@@ -743,6 +743,10 @@ msgid "Method in target node must be specified."
msgstr ""
#: editor/connections_dialog.cpp
+msgid "Method name must be a valid identifier."
+msgstr ""
+
+#: editor/connections_dialog.cpp
msgid ""
"Target method not found. Specify a valid method or attach a script to the "
"target node."
diff --git a/editor/translations/fr.po b/editor/translations/fr.po
index fac3b9b84b..9dd9b3e166 100644
--- a/editor/translations/fr.po
+++ b/editor/translations/fr.po
@@ -79,7 +79,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2020-06-15 01:48+0000\n"
+"PO-Revision-Date: 2020-06-25 08:40+0000\n"
"Last-Translator: Nathan <bonnemainsnathan@gmail.com>\n"
"Language-Team: French <https://hosted.weblate.org/projects/godot-engine/"
"godot/fr/>\n"
@@ -88,7 +88,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n > 1;\n"
-"X-Generator: Weblate 4.1-dev\n"
+"X-Generator: Weblate 4.2-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -834,6 +834,10 @@ msgid "Method in target node must be specified."
msgstr "La méthode du nœud cible doit être spécifiée."
#: editor/connections_dialog.cpp
+msgid "Method name must be a valid identifier."
+msgstr "Le nom de la méthode doit être un identifiant valide."
+
+#: editor/connections_dialog.cpp
msgid ""
"Target method not found. Specify a valid method or attach a script to the "
"target node."
@@ -7066,7 +7070,7 @@ msgstr ""
#: editor/plugins/script_text_editor.cpp
msgid "Lookup Symbol"
-msgstr "Symbole de recherche"
+msgstr "Rechercher un symbole"
#: editor/plugins/script_text_editor.cpp
msgid "Pick Color"
@@ -8594,7 +8598,7 @@ msgstr "Détecter de nouveaux changements"
#: editor/plugins/version_control_editor_plugin.cpp
msgid "Changes"
-msgstr "Changements"
+msgstr "Modifications"
#: editor/plugins/version_control_editor_plugin.cpp
msgid "Modified"
@@ -9608,15 +9612,15 @@ msgstr "Ressources"
#: editor/project_export.cpp
msgid "Export all resources in the project"
-msgstr "Exporter toutes les ressources dans le projet"
+msgstr "Exporter toutes les ressources du projet"
#: editor/project_export.cpp
msgid "Export selected scenes (and dependencies)"
-msgstr "Exporter les scènes sélectionnées (y compris les dépendences)"
+msgstr "Exporter les scènes sélectionnées (y compris les dépendances)"
#: editor/project_export.cpp
msgid "Export selected resources (and dependencies)"
-msgstr "Exporter les ressources sélectionnées (y compris les dépendences)"
+msgstr "Exporter les ressources sélectionnées (y compris les dépendances)"
#: editor/project_export.cpp
msgid "Export Mode:"
diff --git a/editor/translations/ga.po b/editor/translations/ga.po
index b9e6ba69c6..70dd5eada7 100644
--- a/editor/translations/ga.po
+++ b/editor/translations/ga.po
@@ -736,6 +736,10 @@ msgid "Method in target node must be specified."
msgstr ""
#: editor/connections_dialog.cpp
+msgid "Method name must be a valid identifier."
+msgstr ""
+
+#: editor/connections_dialog.cpp
msgid ""
"Target method not found. Specify a valid method or attach a script to the "
"target node."
diff --git a/editor/translations/he.po b/editor/translations/he.po
index 56126249dc..7895ae48fe 100644
--- a/editor/translations/he.po
+++ b/editor/translations/he.po
@@ -777,6 +777,10 @@ msgid "Method in target node must be specified."
msgstr ""
#: editor/connections_dialog.cpp
+msgid "Method name must be a valid identifier."
+msgstr ""
+
+#: editor/connections_dialog.cpp
msgid ""
"Target method not found. Specify a valid method or attach a script to the "
"target node."
diff --git a/editor/translations/hi.po b/editor/translations/hi.po
index 4782afecb0..e3ae2aabe5 100644
--- a/editor/translations/hi.po
+++ b/editor/translations/hi.po
@@ -756,6 +756,11 @@ msgid "Method in target node must be specified."
msgstr "Method को target node में निर्दिष्ट कीजिए."
#: editor/connections_dialog.cpp
+#, fuzzy
+msgid "Method name must be a valid identifier."
+msgstr "Method को target node में निर्दिष्ट कीजिए."
+
+#: editor/connections_dialog.cpp
msgid ""
"Target method not found. Specify a valid method or attach a script to the "
"target node."
diff --git a/editor/translations/hr.po b/editor/translations/hr.po
index ad095145b2..5355ee1dc9 100644
--- a/editor/translations/hr.po
+++ b/editor/translations/hr.po
@@ -741,6 +741,11 @@ msgid "Method in target node must be specified."
msgstr "Metoda u ciljnom čvoru mora biti određena."
#: editor/connections_dialog.cpp
+#, fuzzy
+msgid "Method name must be a valid identifier."
+msgstr "Metoda u ciljnom čvoru mora biti određena."
+
+#: editor/connections_dialog.cpp
msgid ""
"Target method not found. Specify a valid method or attach a script to the "
"target node."
diff --git a/editor/translations/hu.po b/editor/translations/hu.po
index ef15f85977..b57028a426 100644
--- a/editor/translations/hu.po
+++ b/editor/translations/hu.po
@@ -790,6 +790,11 @@ msgstr "Nevezze meg a metódust a cél Node-ban!"
#: editor/connections_dialog.cpp
#, fuzzy
+msgid "Method name must be a valid identifier."
+msgstr "Nevezze meg a metódust a cél Node-ban!"
+
+#: editor/connections_dialog.cpp
+#, fuzzy
msgid ""
"Target method not found. Specify a valid method or attach a script to the "
"target node."
diff --git a/editor/translations/id.po b/editor/translations/id.po
index f7a86197b6..92c0c25da9 100644
--- a/editor/translations/id.po
+++ b/editor/translations/id.po
@@ -778,6 +778,11 @@ msgid "Method in target node must be specified."
msgstr "Method dalam node target harus ditentukan."
#: editor/connections_dialog.cpp
+#, fuzzy
+msgid "Method name must be a valid identifier."
+msgstr "Nama bukan sebuah pengidentifikasi yang sah:"
+
+#: editor/connections_dialog.cpp
msgid ""
"Target method not found. Specify a valid method or attach a script to the "
"target node."
diff --git a/editor/translations/is.po b/editor/translations/is.po
index 5a1ac9b73c..f0d93d1242 100644
--- a/editor/translations/is.po
+++ b/editor/translations/is.po
@@ -770,6 +770,10 @@ msgid "Method in target node must be specified."
msgstr ""
#: editor/connections_dialog.cpp
+msgid "Method name must be a valid identifier."
+msgstr ""
+
+#: editor/connections_dialog.cpp
msgid ""
"Target method not found. Specify a valid method or attach a script to the "
"target node."
diff --git a/editor/translations/it.po b/editor/translations/it.po
index eeec1e05eb..7c929b7779 100644
--- a/editor/translations/it.po
+++ b/editor/translations/it.po
@@ -50,12 +50,14 @@
# J. Lavoie <j.lavoie@net-c.ca>, 2020.
# Andrea Terenziani <andrea.terenziani.at@gmail.com>, 2020.
# Anonymous <noreply@weblate.org>, 2020.
+# riccardo boffelli <riccardo.boffelli.96@gmail.com>, 2020.
+# Lorenzo Asolan <brixiumx@gmail.com>, 2020.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2020-05-07 21:28+0000\n"
-"Last-Translator: Sean Bone <seanbone@zumguy.com>\n"
+"PO-Revision-Date: 2020-06-25 08:40+0000\n"
+"Last-Translator: Lorenzo Asolan <brixiumx@gmail.com>\n"
"Language-Team: Italian <https://hosted.weblate.org/projects/godot-engine/"
"godot/it/>\n"
"Language: it\n"
@@ -63,7 +65,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
-"X-Generator: Weblate 4.1-dev\n"
+"X-Generator: Weblate 4.2-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -802,6 +804,11 @@ msgid "Method in target node must be specified."
msgstr "Il metodo del nodo designato deve essere specificato."
#: editor/connections_dialog.cpp
+#, fuzzy
+msgid "Method name must be a valid identifier."
+msgstr "Il nome del metodo dev'essere un identificatore valido."
+
+#: editor/connections_dialog.cpp
msgid ""
"Target method not found. Specify a valid method or attach a script to the "
"target node."
@@ -1499,7 +1506,7 @@ msgstr "Riordina gli Autoload"
#: editor/editor_autoload_settings.cpp
msgid "Can't add autoload:"
-msgstr ""
+msgstr "Non è possibile aggiungere l'autoload:"
#: editor/editor_autoload_settings.cpp
msgid "Add AutoLoad"
@@ -2463,15 +2470,16 @@ msgid "Can't reload a scene that was never saved."
msgstr "Impossibile ricaricare una scena che non è mai stata salvata."
#: editor/editor_node.cpp
-#, fuzzy
msgid "Reload Saved Scene"
-msgstr "Salva Scena"
+msgstr "Ricarica scena salvata"
#: editor/editor_node.cpp
msgid ""
"The current scene has unsaved changes.\n"
"Reload the saved scene anyway? This action cannot be undone."
msgstr ""
+"La scena attuale ha dei cambiamenti non salvati.\n"
+"Ricaricare comunque la scena salvata? Questa azione non può essere annullata."
#: editor/editor_node.cpp
msgid "Quick Run Scene..."
@@ -3418,11 +3426,10 @@ msgid "Did you forget the '_run' method?"
msgstr "Hai dimenticato il metodo '_run'?"
#: editor/editor_spin_slider.cpp
-#, fuzzy
msgid "Hold Ctrl to round to integers. Hold Shift for more precise changes."
msgstr ""
-"Mantieni premuto Control per rilasciare un Getter. Mantieni premuto Shift "
-"per rilasciare una firma generica."
+"Tenere premuto il tasto Ctrl per arrotondare ai numeri interi. Tenere "
+"premuto Shift per modifiche più precise."
#: editor/editor_sub_scene.cpp
msgid "Select Node(s) to Import"
@@ -4022,8 +4029,10 @@ msgid "Error running post-import script:"
msgstr "Errore di esecuzione dello script di post-import:"
#: editor/import/resource_importer_scene.cpp
+#, fuzzy
msgid "Did you return a Node-derived object in the `post_import()` method?"
msgstr ""
+"Avete restituito un oggetto derivato da un Nodo nel metodo `post_import()`?"
#: editor/import/resource_importer_scene.cpp
msgid "Saving..."
@@ -6992,9 +7001,8 @@ msgstr ""
"Manca il metodo '%s' connesso per il segnale '%s' dal nodo '%s' al nodo '%s'."
#: editor/plugins/script_text_editor.cpp
-#, fuzzy
msgid "[Ignore]"
-msgstr "(ignora)"
+msgstr "[ignora]"
#: editor/plugins/script_text_editor.cpp
msgid "Line"
@@ -7480,6 +7488,12 @@ msgid ""
"Closed eye: Gizmo is hidden.\n"
"Half-open eye: Gizmo is also visible through opaque surfaces (\"x-ray\")."
msgstr ""
+"Fare clic per passare da uno stato di visibilità all'altro.\n"
+"\n"
+"Apri gli occhi: Gizmo è visibile.\n"
+"Occhio chiuso: Gizmo è nascosto.\n"
+"Occhio semiaperto: Gizmo è visibile anche attraverso superfici opache "
+"(\"raggi X\")."
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Snap Nodes To Floor"
@@ -10579,9 +10593,8 @@ msgid "Instance Child Scene"
msgstr "Istanzia Scena Figlia"
#: editor/scene_tree_dock.cpp
-#, fuzzy
msgid "Detach Script"
-msgstr "Allega Script"
+msgstr "Rimuovi Script"
#: editor/scene_tree_dock.cpp
msgid "This operation can't be done on the tree root."
@@ -10747,11 +10760,15 @@ msgid "Open Documentation"
msgstr "Apri la documentazione"
#: editor/scene_tree_dock.cpp
+#, fuzzy
msgid ""
"Cannot attach a script: there are no languages registered.\n"
"This is probably because this editor was built with all language modules "
"disabled."
msgstr ""
+"Non è possibile allegare uno script: non ci sono linguaggi registrati.\n"
+"Questo probabilmente perché questo editor è stato costruito con tutti i "
+"moduli di lingua disabilitati."
#: editor/scene_tree_dock.cpp
msgid "Add Child Node"
@@ -10802,14 +10819,12 @@ msgstr ""
"root esiste."
#: editor/scene_tree_dock.cpp
-#, fuzzy
msgid "Attach a new or existing script to the selected node."
-msgstr "Allega un nuovo script o uno esistente al nodo selezionato."
+msgstr "Allega un nuovo script o uno già esistente al nodo selezionato."
#: editor/scene_tree_dock.cpp
-#, fuzzy
msgid "Detach the script from the selected node."
-msgstr "Svuota uno script per il nodo selezionato."
+msgstr "Rimuovi lo script per il nodo selezionato."
#: editor/scene_tree_dock.cpp
msgid "Remote"
@@ -12041,7 +12056,8 @@ msgstr ""
#, fuzzy
msgid "Release keystore incorrectly configured in the export preset."
msgstr ""
-"Debug keystore non configurato nelle Impostazioni dell'Editor né nel preset."
+"Debug keystore non configurato correttamente nelle Impostazioni dell'Editor "
+"né nel preset."
#: platform/android/export/export.cpp
msgid "Custom build requires a valid Android SDK path in Editor Settings."
@@ -12072,30 +12088,40 @@ msgid "Invalid package name:"
msgstr "Nome del pacchetto non valido:"
#: platform/android/export/export.cpp
+#, fuzzy
msgid ""
"Invalid \"GodotPaymentV3\" module included in the \"android/modules\" "
"project setting (changed in Godot 3.2.2).\n"
msgstr ""
+"Modulo \"GodotPaymentV3\" non valido incluso nell'impostazione del progetto "
+"\"android/moduli\" (modificato in Godot 3.2.2).\n"
#: platform/android/export/export.cpp
msgid "\"Use Custom Build\" must be enabled to use the plugins."
-msgstr ""
+msgstr "Per utilizzare i plugin \"Use Custom Build\" deve essere abilitato."
#: platform/android/export/export.cpp
+#, fuzzy
msgid ""
"\"Degrees Of Freedom\" is only valid when \"Xr Mode\" is \"Oculus Mobile VR"
"\"."
msgstr ""
+"\"Degrees Of Freedom\" è valido solo quando \"Xr Mode\" è \"Oculus Mobile VR"
+"\"."
#: platform/android/export/export.cpp
+#, fuzzy
msgid ""
"\"Hand Tracking\" is only valid when \"Xr Mode\" is \"Oculus Mobile VR\"."
msgstr ""
+"\"Hand Tracking\" è valido solo quando \"Xr Mode\" è \"Oculus Mobile VR\"."
#: platform/android/export/export.cpp
+#, fuzzy
msgid ""
"\"Focus Awareness\" is only valid when \"Xr Mode\" is \"Oculus Mobile VR\"."
msgstr ""
+"\"Focus Awareness\" è valida solo quando \"Xr Mode\" è \"Oculus Mobile VR\"."
#: platform/android/export/export.cpp
msgid ""
diff --git a/editor/translations/ja.po b/editor/translations/ja.po
index 7d4aed4b29..35e590d629 100644
--- a/editor/translations/ja.po
+++ b/editor/translations/ja.po
@@ -36,8 +36,8 @@ msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2020-06-03 20:09+0000\n"
-"Last-Translator: BinotaLIU <me@binota.org>\n"
+"PO-Revision-Date: 2020-06-25 08:40+0000\n"
+"Last-Translator: Wataru Onuki <bettawat@yahoo.co.jp>\n"
"Language-Team: Japanese <https://hosted.weblate.org/projects/godot-engine/"
"godot/ja/>\n"
"Language: ja\n"
@@ -45,7 +45,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n"
-"X-Generator: Weblate 4.1-dev\n"
+"X-Generator: Weblate 4.2-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -786,6 +786,10 @@ msgid "Method in target node must be specified."
msgstr "対象ノードのメソッドを指定してください。"
#: editor/connections_dialog.cpp
+msgid "Method name must be a valid identifier."
+msgstr "メソッド名は有効な識別子である必要があります。"
+
+#: editor/connections_dialog.cpp
msgid ""
"Target method not found. Specify a valid method or attach a script to the "
"target node."
@@ -1595,8 +1599,9 @@ msgid ""
"Enabled'."
msgstr ""
"対象プラットフォームではGLES2へフォールバックするために'ETC'テクスチャ圧縮が"
-"必要です。プロジェクト設定より 'Import Etc' をオンにするか、'Fallback To "
-"Gles 2' をオフにしてください。"
+"必要です。\n"
+"プロジェクト設定より 'Import Etc' をオンにするか、'Fallback To Gles 2' をオフ"
+"にしてください。"
#: editor/editor_export.cpp platform/android/export/export.cpp
#: platform/iphone/export/export.cpp platform/javascript/export/export.cpp
@@ -2436,9 +2441,8 @@ msgid "Can't reload a scene that was never saved."
msgstr "保存されていないシーンを読み込むことはできません。"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Reload Saved Scene"
-msgstr "シーンを保存"
+msgstr "保存済みのシーンをリロード"
#: editor/editor_node.cpp
msgid ""
@@ -3378,11 +3382,8 @@ msgid "Did you forget the '_run' method?"
msgstr "'_run' メソッドを忘れていませんか?"
#: editor/editor_spin_slider.cpp
-#, fuzzy
msgid "Hold Ctrl to round to integers. Hold Shift for more precise changes."
-msgstr ""
-"Ctrlを押したままGetterを(ドラッグ&)ドロップする。Shiftを押したまま汎用シグネ"
-"チャを(ドラッグ&)ドロップする."
+msgstr "Ctrlを押したままで整数値に丸める。Shiftを押したままで精密調整。"
#: editor/editor_sub_scene.cpp
msgid "Select Node(s) to Import"
@@ -3518,8 +3519,8 @@ msgid ""
"Templates installation failed.\n"
"The problematic templates archives can be found at '%s'."
msgstr ""
-"テンプレートのインストールに失敗しました。 問題のテンプレートのアーカイブは "
-"'%s' にあります。"
+"テンプレートのインストールに失敗しました。\n"
+"問題のテンプレートのアーカイブは '%s' にあります。"
#: editor/export_template_manager.cpp
msgid "Error requesting URL:"
@@ -6924,9 +6925,8 @@ msgstr ""
"ド'%s'へのシグナル用です。"
#: editor/plugins/script_text_editor.cpp
-#, fuzzy
msgid "[Ignore]"
-msgstr "(無視)"
+msgstr "[無視]"
#: editor/plugins/script_text_editor.cpp
msgid "Line"
@@ -9451,8 +9451,9 @@ msgid ""
"Only one preset per platform may be marked as runnable."
msgstr ""
"チェックを入れると、1クリック・デプロイでもこのプリセットが使われるようにな"
-"ります。ひとつのプラットフォームに対し、ひとつのプリセットのみが実行可能とし"
-"てマークできます。"
+"ります。\n"
+"ひとつのプラットフォームに対し、ひとつのプリセットのみが実行可能としてマーク"
+"できます。"
#: editor/project_export.cpp
msgid "Export Path"
@@ -10493,9 +10494,8 @@ msgid "Instance Child Scene"
msgstr "子シーンをインスタンス化"
#: editor/scene_tree_dock.cpp
-#, fuzzy
msgid "Detach Script"
-msgstr "スクリプトをアタッチ"
+msgstr "スクリプトをデタッチ"
#: editor/scene_tree_dock.cpp
msgid "This operation can't be done on the tree root."
@@ -10714,14 +10714,12 @@ msgstr ""
"合は、継承されたシーンを作成します。"
#: editor/scene_tree_dock.cpp
-#, fuzzy
msgid "Attach a new or existing script to the selected node."
msgstr "選択したノードに新規または既存のスクリプトをアタッチする。"
#: editor/scene_tree_dock.cpp
-#, fuzzy
msgid "Detach the script from the selected node."
-msgstr "選択したノードのスクリプトをクリアする。"
+msgstr "選択したノードのスクリプトをデタッチする。"
#: editor/scene_tree_dock.cpp
msgid "Remote"
@@ -10768,7 +10766,7 @@ msgid ""
"Node has %s connection(s).\n"
"Click to show signals dock."
msgstr ""
-"ノードに %s 個接続があります。\n"
+"ノードに %s 個接続があります。\n"
"クリックでシグナル ドックを表示。"
#: editor/scene_tree_editor.cpp
@@ -11947,9 +11945,8 @@ msgid "Debug keystore not configured in the Editor Settings nor in the preset."
msgstr "デバッグキーストアがエディタ設定にもプリセットにも設定されていません。"
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Release keystore incorrectly configured in the export preset."
-msgstr "デバッグキーストアがエディタ設定にもプリセットにも設定されていません。"
+msgstr "エクスポート設定にてリリース キーストアが誤って設定されています。"
#: platform/android/export/export.cpp
msgid "Custom build requires a valid Android SDK path in Editor Settings."
diff --git a/editor/translations/ka.po b/editor/translations/ka.po
index 2435a50898..af03b1af9e 100644
--- a/editor/translations/ka.po
+++ b/editor/translations/ka.po
@@ -790,6 +790,11 @@ msgstr "სამიზნე კვანძში მეთოდი უნდ
#: editor/connections_dialog.cpp
#, fuzzy
+msgid "Method name must be a valid identifier."
+msgstr "სამიზნე კვანძში მეთოდი უნდა იყოს განსაზღვრული!"
+
+#: editor/connections_dialog.cpp
+#, fuzzy
msgid ""
"Target method not found. Specify a valid method or attach a script to the "
"target node."
diff --git a/editor/translations/ko.po b/editor/translations/ko.po
index c568dc19b8..462c59d319 100644
--- a/editor/translations/ko.po
+++ b/editor/translations/ko.po
@@ -22,8 +22,8 @@ msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2020-05-22 21:01+0000\n"
-"Last-Translator: Doyun Kwon <caen4516@gmail.com>\n"
+"PO-Revision-Date: 2020-06-25 08:40+0000\n"
+"Last-Translator: Ch. <ccwpc@hanmail.net>\n"
"Language-Team: Korean <https://hosted.weblate.org/projects/godot-engine/"
"godot/ko/>\n"
"Language: ko\n"
@@ -31,7 +31,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n"
-"X-Generator: Weblate 4.1-dev\n"
+"X-Generator: Weblate 4.2-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -768,6 +768,10 @@ msgid "Method in target node must be specified."
msgstr "대상 노드에 있는 메서드는 반드시 지정해야 합니다."
#: editor/connections_dialog.cpp
+msgid "Method name must be a valid identifier."
+msgstr "메서드 이름은 올바른 식별자여야 합니다."
+
+#: editor/connections_dialog.cpp
msgid ""
"Target method not found. Specify a valid method or attach a script to the "
"target node."
@@ -977,7 +981,7 @@ msgid ""
"Changes will only take effect when reloaded."
msgstr ""
"씬 '%s'이(가) 현재 편집중입니다.\n"
-"변경 사항은 다시 로드된 뒤에 반영됩니다."
+"변경 사항은 다시 불러온 뒤에 반영됩니다."
#: editor/dependency_editor.cpp
msgid ""
@@ -985,7 +989,7 @@ msgid ""
"Changes will only take effect when reloaded."
msgstr ""
"리소스 '%s'이(가) 현재 사용중입니다.\n"
-"변경 사항은 다시 로드된 뒤에 반영됩니다."
+"변경 사항은 다시 불러온 뒤에 반영됩니다."
#: editor/dependency_editor.cpp
#: modules/gdnative/gdnative_library_editor_plugin.cpp
@@ -1461,7 +1465,7 @@ msgstr "오토로드 다시 정렬"
#: editor/editor_autoload_settings.cpp
msgid "Can't add autoload:"
-msgstr ""
+msgstr "오토로드를 추가할 수 없음:"
#: editor/editor_autoload_settings.cpp
msgid "Add AutoLoad"
@@ -2413,15 +2417,16 @@ msgid "Can't reload a scene that was never saved."
msgstr "저장하지 않은 씬은 새로고침할 수 없습니다."
#: editor/editor_node.cpp
-#, fuzzy
msgid "Reload Saved Scene"
-msgstr "씬 저장"
+msgstr "저장된 씬 새로고침"
#: editor/editor_node.cpp
msgid ""
"The current scene has unsaved changes.\n"
"Reload the saved scene anyway? This action cannot be undone."
msgstr ""
+"현재 씬에는 저장하지 않은 변경사항이 있습니다.\n"
+"그래도 저장된 씬을 새로고침하시겠습니까? 이 동작은 되돌릴 수 없습니다."
#: editor/editor_node.cpp
msgid "Quick Run Scene..."
@@ -2841,8 +2846,8 @@ msgid ""
"When used remotely on a device, this is more efficient with network "
"filesystem."
msgstr ""
-"이 설정이 활성화된 경우, 어떤 스크립트든 저장하면 실행중인 게임에도 반영됩니"
-"다.\n"
+"이 설정이 활성화된 경우, 어떤 스크립트든 저장하면 실행중인 게임에도 새로고침"
+"되어 반영됩니다.\n"
"원격 장치에서 사용중인 경우 네트워크 파일 시스템 기능을 활성화하면 더욱 효율"
"적입니다."
@@ -3347,11 +3352,9 @@ msgid "Did you forget the '_run' method?"
msgstr "'_run' 메서드를 잊었나요?"
#: editor/editor_spin_slider.cpp
-#, fuzzy
msgid "Hold Ctrl to round to integers. Hold Shift for more precise changes."
msgstr ""
-"Ctrl을 누르고 있으면 Getter를 드롭합니다. Shift를 누르고 있으면 일반적인 시그"
-"니처를 드롭합니다."
+"Ctrl을 눌러 정수로 반올림합니다. Shift를 눌러 좀 더 정밀하게 조작합니다."
#: editor/editor_sub_scene.cpp
msgid "Select Node(s) to Import"
@@ -3948,7 +3951,7 @@ msgstr "후 가져오기 스크립트 실행 중 오류:"
#: editor/import/resource_importer_scene.cpp
msgid "Did you return a Node-derived object in the `post_import()` method?"
-msgstr ""
+msgstr "`post_import()` 메소드에서 Node에서 상속받은 객체를 반환했습니까?"
#: editor/import/resource_importer_scene.cpp
msgid "Saving..."
@@ -6646,7 +6649,7 @@ msgstr "실행하기 위한 스크립트를 가질 수 없습니다."
#: editor/plugins/script_editor_plugin.cpp
msgid "Script failed reloading, check console for errors."
-msgstr "스크립트 다시 불러오기에 실패했습니다. 콘솔에서 오류를 확인하세요."
+msgstr "스크립트 새로고침에 실패했습니다. 콘솔에서 오류를 확인하세요."
#: editor/plugins/script_editor_plugin.cpp
msgid "Script is not in tool mode, will not be able to run."
@@ -6743,7 +6746,7 @@ msgstr "모두 저장"
#: editor/plugins/script_editor_plugin.cpp
msgid "Soft Reload Script"
-msgstr "스크립트 다시 불러오기"
+msgstr "스크립트 새로고침"
#: editor/plugins/script_editor_plugin.cpp
msgid "Copy Script Path"
@@ -6768,7 +6771,7 @@ msgstr "테마 가져오기..."
#: editor/plugins/script_editor_plugin.cpp
msgid "Reload Theme"
-msgstr "테마 다시 불러오기"
+msgstr "테마 새로고침"
#: editor/plugins/script_editor_plugin.cpp
msgid "Save Theme"
@@ -6842,7 +6845,7 @@ msgstr ""
#: editor/plugins/script_editor_plugin.cpp
#: editor/plugins/shader_editor_plugin.cpp
msgid "Reload"
-msgstr "다시 불러오기"
+msgstr "새로고침"
#: editor/plugins/script_editor_plugin.cpp
#: editor/plugins/shader_editor_plugin.cpp
@@ -6881,9 +6884,8 @@ msgstr ""
"다."
#: editor/plugins/script_text_editor.cpp
-#, fuzzy
msgid "[Ignore]"
-msgstr "(무시함)"
+msgstr "[무시]"
#: editor/plugins/script_text_editor.cpp
msgid "Line"
@@ -7361,6 +7363,7 @@ msgid "XForm Dialog"
msgstr "XForm 대화 상자"
#: editor/plugins/spatial_editor_plugin.cpp
+#, fuzzy
msgid ""
"Click to toggle between visibility states.\n"
"\n"
@@ -7368,6 +7371,11 @@ msgid ""
"Closed eye: Gizmo is hidden.\n"
"Half-open eye: Gizmo is also visible through opaque surfaces (\"x-ray\")."
msgstr ""
+"표시 상태를 토글하려면 클릭하세요.\n"
+"\n"
+"열린 눈: 기즈모가 보입니다.\n"
+"닫힌 눈: 기즈모가 숨겨집니다.\n"
+"반 열린 눈: 불투명한 표면에도 기즈모가 보입니다 (\"엑스레이\")."
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Snap Nodes To Floor"
@@ -10419,9 +10427,8 @@ msgid "Instance Child Scene"
msgstr "자식 씬 인스턴스화"
#: editor/scene_tree_dock.cpp
-#, fuzzy
msgid "Detach Script"
-msgstr "스크립트 붙이기"
+msgstr "스크립트 떼기"
#: editor/scene_tree_dock.cpp
msgid "This operation can't be done on the tree root."
@@ -10589,6 +10596,8 @@ msgid ""
"This is probably because this editor was built with all language modules "
"disabled."
msgstr ""
+"스크립트를 붙일 수 없습니다: 언어가 하나도 등록되지 않았습니다.\n"
+"에디터가 모든 언어를 비활성화한 채로 빌드되어서 그럴 가능성이 높습니다."
#: editor/scene_tree_dock.cpp
msgid "Add Child Node"
@@ -10638,14 +10647,12 @@ msgstr ""
"씬 파일을 노드로 인스턴스합니다. 루트 노드가 없으면 상속된 씬을 만듭니다."
#: editor/scene_tree_dock.cpp
-#, fuzzy
msgid "Attach a new or existing script to the selected node."
-msgstr "선택한 노드에 새로운 혹은 존재하는 스크립트를 붙입니다."
+msgstr "선택한 노드에 새 스크립트나 기존 스크립트를 붙입니다."
#: editor/scene_tree_dock.cpp
-#, fuzzy
msgid "Detach the script from the selected node."
-msgstr "선택한 노드의 스크립트를 삭제합니다."
+msgstr "선택한 노드에서 스크립트를 뗍니다."
#: editor/scene_tree_dock.cpp
msgid "Remote"
@@ -11866,9 +11873,8 @@ msgid "Debug keystore not configured in the Editor Settings nor in the preset."
msgstr "Debug keystore를 편집기 설정과 프리셋에 설정하지 않았습니다."
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Release keystore incorrectly configured in the export preset."
-msgstr "Debug keystore를 편집기 설정과 프리셋에 설정하지 않았습니다."
+msgstr "내보내기 프리셋에 배포 keystorke가 잘못 설정되어 있습니다."
#: platform/android/export/export.cpp
msgid "Custom build requires a valid Android SDK path in Editor Settings."
@@ -11899,26 +11905,33 @@ msgid ""
"Invalid \"GodotPaymentV3\" module included in the \"android/modules\" "
"project setting (changed in Godot 3.2.2).\n"
msgstr ""
+"\"android/modules\" 프로젝트 세팅에 잘못된 \"GodotPaymentV3\" 모듈이 포함되"
+"어 있습니다. (Godot 3.2.2 에서 변경됨).\n"
#: platform/android/export/export.cpp
msgid "\"Use Custom Build\" must be enabled to use the plugins."
-msgstr ""
+msgstr "플러그인을 사용하려면 \"커스텀 빌드 사용\"이 활성화되어야 합니다."
#: platform/android/export/export.cpp
msgid ""
"\"Degrees Of Freedom\" is only valid when \"Xr Mode\" is \"Oculus Mobile VR"
"\"."
msgstr ""
+"\"자유도(DoF)\"는 \"Xr 모드\" 가 \"Oculus Mobile VR\" 일 때만 사용 가능합니"
+"다."
#: platform/android/export/export.cpp
msgid ""
"\"Hand Tracking\" is only valid when \"Xr Mode\" is \"Oculus Mobile VR\"."
msgstr ""
+"\"손 추적\" 은 \"Xr 모드\" 가 \"Oculus Mobile VR\"일 때만 사용 가능합니다."
#: platform/android/export/export.cpp
msgid ""
"\"Focus Awareness\" is only valid when \"Xr Mode\" is \"Oculus Mobile VR\"."
msgstr ""
+"\"포커스 인식\"은 \"Xr 모드\"가 \"Oculus Mobile VR\" 인 경우에만 사용 가능합"
+"니다."
#: platform/android/export/export.cpp
msgid ""
diff --git a/editor/translations/lt.po b/editor/translations/lt.po
index bbbe630d4a..fdf9ef15ae 100644
--- a/editor/translations/lt.po
+++ b/editor/translations/lt.po
@@ -773,6 +773,11 @@ msgstr "Metodas pasirinktame Node turi būti nurodytas!"
#: editor/connections_dialog.cpp
#, fuzzy
+msgid "Method name must be a valid identifier."
+msgstr "Metodas pasirinktame Node turi būti nurodytas!"
+
+#: editor/connections_dialog.cpp
+#, fuzzy
msgid ""
"Target method not found. Specify a valid method or attach a script to the "
"target node."
diff --git a/editor/translations/lv.po b/editor/translations/lv.po
index b69ecf7eef..8417a6b650 100644
--- a/editor/translations/lv.po
+++ b/editor/translations/lv.po
@@ -757,6 +757,11 @@ msgid "Method in target node must be specified."
msgstr "Metodi mērķa mezglā nepieciešams specificēt."
#: editor/connections_dialog.cpp
+#, fuzzy
+msgid "Method name must be a valid identifier."
+msgstr "Metodi mērķa mezglā nepieciešams specificēt."
+
+#: editor/connections_dialog.cpp
msgid ""
"Target method not found. Specify a valid method or attach a script to the "
"target node."
diff --git a/editor/translations/mi.po b/editor/translations/mi.po
index fbf4bce3d6..ab68a71ee2 100644
--- a/editor/translations/mi.po
+++ b/editor/translations/mi.po
@@ -728,6 +728,10 @@ msgid "Method in target node must be specified."
msgstr ""
#: editor/connections_dialog.cpp
+msgid "Method name must be a valid identifier."
+msgstr ""
+
+#: editor/connections_dialog.cpp
msgid ""
"Target method not found. Specify a valid method or attach a script to the "
"target node."
diff --git a/editor/translations/ml.po b/editor/translations/ml.po
index 77ac327f71..db5f5638f3 100644
--- a/editor/translations/ml.po
+++ b/editor/translations/ml.po
@@ -738,6 +738,10 @@ msgid "Method in target node must be specified."
msgstr ""
#: editor/connections_dialog.cpp
+msgid "Method name must be a valid identifier."
+msgstr ""
+
+#: editor/connections_dialog.cpp
msgid ""
"Target method not found. Specify a valid method or attach a script to the "
"target node."
diff --git a/editor/translations/mr.po b/editor/translations/mr.po
index 38e3ee7185..1700bcb138 100644
--- a/editor/translations/mr.po
+++ b/editor/translations/mr.po
@@ -735,6 +735,10 @@ msgid "Method in target node must be specified."
msgstr ""
#: editor/connections_dialog.cpp
+msgid "Method name must be a valid identifier."
+msgstr ""
+
+#: editor/connections_dialog.cpp
msgid ""
"Target method not found. Specify a valid method or attach a script to the "
"target node."
diff --git a/editor/translations/ms.po b/editor/translations/ms.po
index 233b5cb428..160fa6e69f 100644
--- a/editor/translations/ms.po
+++ b/editor/translations/ms.po
@@ -758,6 +758,10 @@ msgid "Method in target node must be specified."
msgstr ""
#: editor/connections_dialog.cpp
+msgid "Method name must be a valid identifier."
+msgstr ""
+
+#: editor/connections_dialog.cpp
msgid ""
"Target method not found. Specify a valid method or attach a script to the "
"target node."
diff --git a/editor/translations/nb.po b/editor/translations/nb.po
index 5c80321d03..4e7ca2dce1 100644
--- a/editor/translations/nb.po
+++ b/editor/translations/nb.po
@@ -19,7 +19,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2020-06-03 20:09+0000\n"
+"PO-Revision-Date: 2020-06-22 06:40+0000\n"
"Last-Translator: Allan Nordhøy <epost@anotheragency.no>\n"
"Language-Team: Norwegian Bokmål <https://hosted.weblate.org/projects/godot-"
"engine/godot/nb_NO/>\n"
@@ -28,7 +28,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
-"X-Generator: Weblate 4.1-dev\n"
+"X-Generator: Weblate 4.2-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -796,6 +796,11 @@ msgstr "Metode i mål-Node må spesifiseres!"
#: editor/connections_dialog.cpp
#, fuzzy
+msgid "Method name must be a valid identifier."
+msgstr "Navn er ikke en gyldig identifikator:"
+
+#: editor/connections_dialog.cpp
+#, fuzzy
msgid ""
"Target method not found. Specify a valid method or attach a script to the "
"target node."
@@ -3772,12 +3777,9 @@ msgid "Favorites"
msgstr "Favoritter:"
#: editor/filesystem_dock.cpp
-#, fuzzy
msgid "Status: Import of file failed. Please fix file and reimport manually."
msgstr ""
-"\n"
-"Status: Import av fil feilet. Vennligst reparer filen eller reimporter "
-"manuelt."
+"Status: Import av fil feilet. Reparer filen eller importer igjen manuelt."
#: editor/filesystem_dock.cpp
#, fuzzy
diff --git a/editor/translations/nl.po b/editor/translations/nl.po
index 8e6c4bcfa4..3d560d3d6d 100644
--- a/editor/translations/nl.po
+++ b/editor/translations/nl.po
@@ -44,7 +44,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2020-06-15 01:48+0000\n"
+"PO-Revision-Date: 2020-06-22 06:40+0000\n"
"Last-Translator: Stijn Hinlopen <f.a.hinlopen@gmail.com>\n"
"Language-Team: Dutch <https://hosted.weblate.org/projects/godot-engine/godot/"
"nl/>\n"
@@ -53,7 +53,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
-"X-Generator: Weblate 4.1-dev\n"
+"X-Generator: Weblate 4.2-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -790,6 +790,11 @@ msgid "Method in target node must be specified."
msgstr "Methode in doelknoop moet gespecificeerd worden."
#: editor/connections_dialog.cpp
+#, fuzzy
+msgid "Method name must be a valid identifier."
+msgstr "Naam is geen geldige identifier:"
+
+#: editor/connections_dialog.cpp
msgid ""
"Target method not found. Specify a valid method or attach a script to the "
"target node."
@@ -1987,15 +1992,15 @@ msgstr "standaard:"
#: editor/editor_help.cpp
msgid "Methods"
-msgstr "Methodes"
+msgstr "Methoden"
#: editor/editor_help.cpp
msgid "Theme Properties"
-msgstr "Thema Eigenschappen"
+msgstr "Thema-eigenschappen"
#: editor/editor_help.cpp
msgid "Enumerations"
-msgstr "Enumeraties"
+msgstr "Enumeratie"
#: editor/editor_help.cpp
msgid "Constants"
@@ -2003,7 +2008,7 @@ msgstr "Constanten"
#: editor/editor_help.cpp
msgid "Property Descriptions"
-msgstr "Eigenschap Beschrijvingen"
+msgstr "Eigenschapbeschrijvingen"
#: editor/editor_help.cpp
msgid "(value)"
@@ -2019,7 +2024,7 @@ msgstr ""
#: editor/editor_help.cpp
msgid "Method Descriptions"
-msgstr "Methode Beschrijvingen"
+msgstr "Methodebeschrijvingen"
#: editor/editor_help.cpp
msgid ""
diff --git a/editor/translations/or.po b/editor/translations/or.po
index afff834dee..d6678c2819 100644
--- a/editor/translations/or.po
+++ b/editor/translations/or.po
@@ -734,6 +734,10 @@ msgid "Method in target node must be specified."
msgstr ""
#: editor/connections_dialog.cpp
+msgid "Method name must be a valid identifier."
+msgstr ""
+
+#: editor/connections_dialog.cpp
msgid ""
"Target method not found. Specify a valid method or attach a script to the "
"target node."
diff --git a/editor/translations/pl.po b/editor/translations/pl.po
index 414e66685a..ed53a98bed 100644
--- a/editor/translations/pl.po
+++ b/editor/translations/pl.po
@@ -39,12 +39,13 @@
# Maciej Chamera <chameramaciej@gmail.com>, 2019.
# Cezary Stasiak <cezary.p.stasiak@gmail.com>, 2019.
# Jan Ligudziński <jan.ligudzinski@gmail.com>, 2020.
+# Adam Jagoda <kontakt@lukasz.xyz>, 2020.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2020-06-06 10:15+0000\n"
-"Last-Translator: Tomek <kobewi4e@gmail.com>\n"
+"PO-Revision-Date: 2020-06-25 08:40+0000\n"
+"Last-Translator: Adam Jagoda <kontakt@lukasz.xyz>\n"
"Language-Team: Polish <https://hosted.weblate.org/projects/godot-engine/"
"godot/pl/>\n"
"Language: pl\n"
@@ -53,7 +54,7 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 "
"|| n%100>=20) ? 1 : 2;\n"
-"X-Generator: Weblate 4.1-dev\n"
+"X-Generator: Weblate 4.2-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -791,6 +792,10 @@ msgid "Method in target node must be specified."
msgstr "Metoda w węźle docelowym musi zostać podana."
#: editor/connections_dialog.cpp
+msgid "Method name must be a valid identifier."
+msgstr "Nazwa metody musi być poprawnym identyfikatorem."
+
+#: editor/connections_dialog.cpp
msgid ""
"Target method not found. Specify a valid method or attach a script to the "
"target node."
@@ -1484,7 +1489,7 @@ msgstr "Przestaw Autoloady"
#: editor/editor_autoload_settings.cpp
msgid "Can't add autoload:"
-msgstr ""
+msgstr "Nie można dodać Autoload:"
#: editor/editor_autoload_settings.cpp
msgid "Add AutoLoad"
@@ -1858,11 +1863,11 @@ msgstr "Przełącz ukryte pliki"
#: editor/editor_file_dialog.cpp
msgid "Toggle Favorite"
-msgstr "Ustaw jako ulubione"
+msgstr "Przełącz ulubione"
#: editor/editor_file_dialog.cpp
msgid "Toggle Mode"
-msgstr "Przełącz tryby"
+msgstr "Przełącz tryb"
#: editor/editor_file_dialog.cpp
msgid "Focus Path"
@@ -1870,11 +1875,11 @@ msgstr "Przejdź do wprowadzania ścieżki"
#: editor/editor_file_dialog.cpp
msgid "Move Favorite Up"
-msgstr "Przesuń Ulubiony w górę"
+msgstr "Przesuń ulubiony w górę"
#: editor/editor_file_dialog.cpp
msgid "Move Favorite Down"
-msgstr "Przesuń Ulubiony w dół"
+msgstr "Przesuń ulubiony w dół"
#: editor/editor_file_dialog.cpp
msgid "Go to previous folder."
@@ -2122,7 +2127,7 @@ msgstr "Wyczyść"
#: editor/editor_log.cpp
msgid "Clear Output"
-msgstr "Wyczyść dane wyjściowe"
+msgstr "Wyczyść wyjście"
#: editor/editor_network_profiler.cpp editor/editor_node.cpp
#: editor/editor_profiler.cpp
@@ -2440,15 +2445,16 @@ msgid "Can't reload a scene that was never saved."
msgstr "Nie można przeładować sceny która nie została zapisana."
#: editor/editor_node.cpp
-#, fuzzy
msgid "Reload Saved Scene"
-msgstr "Zapisz scenę"
+msgstr "Przywróć zapisaną scenę"
#: editor/editor_node.cpp
msgid ""
"The current scene has unsaved changes.\n"
"Reload the saved scene anyway? This action cannot be undone."
msgstr ""
+"Aktualna scena ma niezapisane zmiany.\n"
+"Przywrócić zapisaną scenę tak czy inaczej? Ta akcja nie może zostać cofnięta."
#: editor/editor_node.cpp
msgid "Quick Run Scene..."
@@ -2854,8 +2860,10 @@ msgid ""
"When used remotely on a device, this is more efficient with network "
"filesystem."
msgstr ""
-"Wszelkie zmiany sceny w edytorze będą odtworzone w uruchomionej grze na "
-"urządzeniu zdalnym. Opcja ta działa szybciej na sieciowych systemach plików."
+"Kiedy ta opcja jest włączona, wszystkie zmiany na scenie w edytorze będą "
+"powtórzone w uruchomionej grze.\n"
+"Kiedy używane zdalnie na urządzeniu, ta opcja jest wydajniejsza w sieciowym "
+"systemie plików."
#: editor/editor_node.cpp
msgid "Sync Script Changes"
@@ -2868,9 +2876,10 @@ msgid ""
"When used remotely on a device, this is more efficient with network "
"filesystem."
msgstr ""
-"Wszelkie zmiany skryptów będą synchronizowane z urządzeniem zdalnym "
-"(działające instancje będą zrestartowane). Opcja ta działa szybciej z "
-"użyciem sieciowych systemów plików."
+"Kiedy ta opcja jest włączona, każdy zapisany skrypt będzie przeładowany w "
+"uruchomionej grze.\n"
+"Kiedy używane zdalnie na urządzeniu, ta opcja jest wydajniejsza w sieciowym "
+"systemie plików."
#: editor/editor_node.cpp editor/script_create_dialog.cpp
msgid "Editor"
@@ -2894,7 +2903,7 @@ msgstr "Zrzuty ekranu są przechowywane w folderze danych/ustawień edytora."
#: editor/editor_node.cpp
msgid "Toggle Fullscreen"
-msgstr "Pełny ekran"
+msgstr "Przełącz pełny ekran"
#: editor/editor_node.cpp
msgid "Toggle System Console"
@@ -3378,11 +3387,10 @@ msgid "Did you forget the '_run' method?"
msgstr "Zapomniano metody \"_run\"?"
#: editor/editor_spin_slider.cpp
-#, fuzzy
msgid "Hold Ctrl to round to integers. Hold Shift for more precise changes."
msgstr ""
-"Przytrzymaj Ctrl, by upuścić pobieracz (Getter). Przytrzymaj Shift, by "
-"upuścić generyczną sygnaturę."
+"Przytrzyma Ctrl, by zaokrąglić do liczb całkowitych. Przytrzymaj Shift dla "
+"bardziej precyzyjnych zmian."
#: editor/editor_sub_scene.cpp
msgid "Select Node(s) to Import"
@@ -3983,7 +3991,7 @@ msgstr "Błąd podczas uruchamiania skryptu po imporcie:"
#: editor/import/resource_importer_scene.cpp
msgid "Did you return a Node-derived object in the `post_import()` method?"
-msgstr ""
+msgstr "Czy zwracasz obiekt dziedziczący po Node w metodzie `post_import()`?"
#: editor/import/resource_importer_scene.cpp
msgid "Saving..."
@@ -5416,7 +5424,7 @@ msgstr "Tryb przesuwania"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Rotate Mode"
-msgstr "Tryb Rotacji"
+msgstr "Tryb obrotu"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
@@ -5556,7 +5564,7 @@ msgstr "Widok"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Always Show Grid"
-msgstr "Zawsze pokaż siatkę"
+msgstr "Zawsze pokazuj siatkę"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Show Helpers"
@@ -6938,9 +6946,8 @@ msgstr ""
"\"%s\"."
#: editor/plugins/script_text_editor.cpp
-#, fuzzy
msgid "[Ignore]"
-msgstr "(ignoruj)"
+msgstr "[Ignoruj]"
#: editor/plugins/script_text_editor.cpp
msgid "Line"
@@ -6978,7 +6985,7 @@ msgstr "Wielkie litery"
#: editor/plugins/script_text_editor.cpp editor/plugins/text_editor.cpp
msgid "Lowercase"
-msgstr "Małe Litery"
+msgstr "Małe litery"
#: editor/plugins/script_text_editor.cpp editor/plugins/text_editor.cpp
msgid "Capitalize"
@@ -7054,7 +7061,7 @@ msgstr "Wylicz wyrażenie"
#: editor/plugins/script_text_editor.cpp
msgid "Trim Trailing Whitespace"
-msgstr "Przytnij końcowe spacje"
+msgstr "Przytnij końcowe białe znaki"
#: editor/plugins/script_text_editor.cpp
msgid "Convert Indent to Spaces"
@@ -7387,7 +7394,7 @@ msgstr "\"Wolny widok\" w tył"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Freelook Up"
-msgstr "\"Wolny widok\" w góre"
+msgstr "\"Wolny widok\" w górę"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Freelook Down"
@@ -7425,6 +7432,12 @@ msgid ""
"Closed eye: Gizmo is hidden.\n"
"Half-open eye: Gizmo is also visible through opaque surfaces (\"x-ray\")."
msgstr ""
+"Kliknij, by przełączyć pomiędzy stanami widoczności.\n"
+"\n"
+"Otwarte oko: uchwyt jest widzialny.\n"
+"Zamknięte oko: uchwyt jest ukryty.\n"
+"Półotwarte oko: uchwyt jest również widoczny przez nieprzezroczyste "
+"powierzchnie (\"x-ray\")."
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Snap Nodes To Floor"
@@ -7519,7 +7532,7 @@ msgstr "2 widoki"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "2 Viewports (Alt)"
-msgstr "2 widoki (Alt)"
+msgstr "2 widoki (alternatywnie)"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "3 Viewports"
@@ -7527,7 +7540,7 @@ msgstr "3 widoki"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "3 Viewports (Alt)"
-msgstr "3 widoki (Alt)"
+msgstr "3 widoki (alternatywnie)"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "4 Viewports"
@@ -8807,7 +8820,7 @@ msgstr ""
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "'%s' input parameter for fragment and light shader modes."
-msgstr "Parametr wejściowy \"%s\" dla dla fragmentowego i światłowego shadera."
+msgstr "Parametr wejściowy \"%s\" dla fragmentowego i światłowego shadera."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "'%s' input parameter for fragment shader mode."
@@ -9507,16 +9520,16 @@ msgid ""
"Filters to export non-resource files/folders\n"
"(comma-separated, e.g: *.json, *.txt, docs/*)"
msgstr ""
-"Filtry do eksportowania plików/folderów nie będących zasobami (oddzielone "
-"przecinkami, np. *.json, *.txt)"
+"Filtry do eksportowania plików/folderów nie będących zasobami\n"
+"(oddzielone przecinkami, np. *.json, *.txt, docs/*)"
#: editor/project_export.cpp
msgid ""
"Filters to exclude files/folders from project\n"
"(comma-separated, e.g: *.json, *.txt, docs/*)"
msgstr ""
-"Filtry do wykluczenia plików/folderów z projektu (rozdzielone przecinkami, "
-"np. *.json, *.txt)"
+"Filtry do wykluczenia plików/folderów z projektu\n"
+"(oddzielone przecinkami, np. *.json, *.txt, docs/*)"
#: editor/project_export.cpp
msgid "Patches"
@@ -10515,9 +10528,8 @@ msgid "Instance Child Scene"
msgstr "Dodaj instancję sceny"
#: editor/scene_tree_dock.cpp
-#, fuzzy
msgid "Detach Script"
-msgstr "Dodaj skrypt"
+msgstr "Odłącz skrypt"
#: editor/scene_tree_dock.cpp
msgid "This operation can't be done on the tree root."
@@ -10635,7 +10647,7 @@ msgstr "Nie można działać na węzłach z których dziedziczy obecna scena!"
#: editor/scene_tree_dock.cpp
msgid "Attach Script"
-msgstr "Dodaj skrypt"
+msgstr "Dołącz skrypt"
#: editor/scene_tree_dock.cpp
msgid "Remove Node(s)"
@@ -10687,6 +10699,9 @@ msgid ""
"This is probably because this editor was built with all language modules "
"disabled."
msgstr ""
+"Nie można dołączyć skryptu: brak zarejestrowanych języków.\n"
+"To prawdopodobnie przez to, że ten edytor został zbudowany z wyłączonymi "
+"wszystkimi modułami języków."
#: editor/scene_tree_dock.cpp
msgid "Add Child Node"
@@ -10737,14 +10752,12 @@ msgstr ""
"główny nie istnieje."
#: editor/scene_tree_dock.cpp
-#, fuzzy
msgid "Attach a new or existing script to the selected node."
msgstr "Dołącz nowy lub istniejący skrypt do zaznaczonego węzła."
#: editor/scene_tree_dock.cpp
-#, fuzzy
msgid "Detach the script from the selected node."
-msgstr "Wyczyść skrypt dla zaznaczonego węzła."
+msgstr "Odłącz skrypt z zaznaczonego węzła."
#: editor/scene_tree_dock.cpp
msgid "Remote"
@@ -10783,7 +10796,7 @@ msgid ""
"Node has %s connection(s) and %s group(s).\n"
"Click to show signals dock."
msgstr ""
-"Węzeł posiada %s połączeń i %s grup.\n"
+"Węzeł posiada %s połączeń i %s grup.\n"
"Kliknij, aby wyświetlić panel sygnałów."
#: editor/scene_tree_editor.cpp
@@ -11839,15 +11852,15 @@ msgstr "Znajdź typ węzła"
#: modules/visual_script/visual_script_editor.cpp
msgid "Copy Nodes"
-msgstr "Skopiuj Węzeł"
+msgstr "Skopiuj węzły"
#: modules/visual_script/visual_script_editor.cpp
msgid "Cut Nodes"
-msgstr "Wytnij Węzły"
+msgstr "Wytnij węzły"
#: modules/visual_script/visual_script_editor.cpp
msgid "Make Function"
-msgstr "Zmień na funkcję"
+msgstr "Zamień na funkcję"
#: modules/visual_script/visual_script_editor.cpp
msgid "Refresh Graph"
@@ -11969,11 +11982,9 @@ msgstr ""
"eksportu."
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Release keystore incorrectly configured in the export preset."
msgstr ""
-"Debugowy keystore nieskonfigurowany w Ustawieniach Edytora ani w profilu "
-"eksportu."
+"Wydaniowy keystore jest niepoprawnie skonfigurowany w profilu eksportu."
#: platform/android/export/export.cpp
msgid "Custom build requires a valid Android SDK path in Editor Settings."
@@ -12007,26 +12018,34 @@ msgid ""
"Invalid \"GodotPaymentV3\" module included in the \"android/modules\" "
"project setting (changed in Godot 3.2.2).\n"
msgstr ""
+"Niepoprawny moduł \"GodotPaymentV3\" załączony w ustawieniu projektu "
+"\"android/modules\" (zmieniony w Godocie 3.2.2).\n"
#: platform/android/export/export.cpp
msgid "\"Use Custom Build\" must be enabled to use the plugins."
-msgstr ""
+msgstr "\"Use Custom Build\" musi być włączone, by używać wtyczek."
#: platform/android/export/export.cpp
msgid ""
"\"Degrees Of Freedom\" is only valid when \"Xr Mode\" is \"Oculus Mobile VR"
"\"."
msgstr ""
+"\"Degrees Of Freedom\" jest poprawne tylko gdy \"Xr Mode\" jest \"Oculus "
+"Mobile VR\"."
#: platform/android/export/export.cpp
msgid ""
"\"Hand Tracking\" is only valid when \"Xr Mode\" is \"Oculus Mobile VR\"."
msgstr ""
+"\"Hand Tracking\" jest poprawne tylko gdy \"Xr Mode\" jest \"Oculus Mobile VR"
+"\"."
#: platform/android/export/export.cpp
msgid ""
"\"Focus Awareness\" is only valid when \"Xr Mode\" is \"Oculus Mobile VR\"."
msgstr ""
+"\"Focus Awareness\" jest poprawne tylko gdy \"Xr Mode\" jest \"Oculus Mobile "
+"VR\"."
#: platform/android/export/export.cpp
msgid ""
diff --git a/editor/translations/pr.po b/editor/translations/pr.po
index 9d46edcbae..bfa3d0b52c 100644
--- a/editor/translations/pr.po
+++ b/editor/translations/pr.po
@@ -5,12 +5,13 @@
# Calum Knott <calum@calumk.com>, 2017.
# Zion Nimchuk <zionnimchuk@gmail.com>, 2016-2017.
# Allan Nordhøy <epost@anotheragency.no>, 2018.
+# David Fatheree <david.fathereewcchs@gmail.com>, 2020.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2018-12-13 14:42+0100\n"
-"Last-Translator: Allan Nordhøy <epost@anotheragency.no>\n"
+"PO-Revision-Date: 2020-06-22 06:40+0000\n"
+"Last-Translator: David Fatheree <david.fathereewcchs@gmail.com>\n"
"Language-Team: Pirate <https://hosted.weblate.org/projects/godot-engine/"
"godot/pr/>\n"
"Language: pr\n"
@@ -18,7 +19,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
-"X-Generator: Poedit 2.2\n"
+"X-Generator: Weblate 4.2-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -29,7 +30,7 @@ msgstr ""
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
msgid "Expected a string of length 1 (a character)."
-msgstr ""
+msgstr "Expected a strin' o' length 1 (a character)."
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/mono/glue/gd_glue.cpp
@@ -39,19 +40,17 @@ msgstr "Nah enough bytes fer decodin' bytes, or ye got th' wrong ship."
#: core/math/expression.cpp
msgid "Invalid input %i (not passed) in expression"
-msgstr ""
+msgstr "Shiver me timbers! Ye input %i (not passed) in ye expression!"
#: core/math/expression.cpp
msgid "self can't be used because instance is null (not passed)"
msgstr ""
#: core/math/expression.cpp
-#, fuzzy
msgid "Invalid operands to operator %s, %s and %s."
msgstr "Yer index property name '%s' in node %s be walkin' th' plank!"
#: core/math/expression.cpp
-#, fuzzy
msgid "Invalid index of type %s for base type %s"
msgstr "Yer index property name '%s' in node %s be walkin' th' plank!"
@@ -102,11 +101,11 @@ msgstr ""
#: editor/animation_bezier_editor.cpp
msgid "Balanced"
-msgstr ""
+msgstr "Smooth Sailin'"
#: editor/animation_bezier_editor.cpp
msgid "Mirror"
-msgstr ""
+msgstr "See'in Double"
#: editor/animation_bezier_editor.cpp editor/editor_profiler.cpp
msgid "Time:"
@@ -767,6 +766,11 @@ msgid "Method in target node must be specified."
msgstr ""
#: editor/connections_dialog.cpp
+#, fuzzy
+msgid "Method name must be a valid identifier."
+msgstr "Yer name's got no valid identifier:"
+
+#: editor/connections_dialog.cpp
msgid ""
"Target method not found. Specify a valid method or attach a script to the "
"target node."
diff --git a/editor/translations/pt_BR.po b/editor/translations/pt_BR.po
index 199d828897..70878acad2 100644
--- a/editor/translations/pt_BR.po
+++ b/editor/translations/pt_BR.po
@@ -16,7 +16,7 @@
# jonathan railarem <railarem@gmail.com>, 2017.
# Lucas Silva <lucasb.hpp@gmail.com>, 2018.
# Luiz G. Correia <luizgabriell2.0@gmail.com>, 2017.
-# Mailson Silva Marins <mailsons335@gmail.com>, 2016.
+# Mailson Silva Marins <mailsons335@gmail.com>, 2016, 2020.
# MalcomRF <malcomkbk@gmail.com>, 2017.
# Marcus Correia <marknokalt@live.com>, 2017-2018.
# Michael Alexsander Silva Dias <michaelalexsander@protonmail.com>, 2017-2018.
@@ -73,7 +73,7 @@
# Alan Tavares <alan1tavares@gmail.com>, 2019.
# Rafael Silveira <res883@gmail.com>, 2019.
# Luigi <luigimendeszanchett@gmail.com>, 2019.
-# Nicolas Abril <nicolas.abril@protonmail.ch>, 2019.
+# Nicolas Abril <nicolas.abril@protonmail.ch>, 2019, 2020.
# johnnybigoode <jamarson@gmail.com>, 2019, 2020.
# Zeero <igcdzeero@gmail.com>, 2019.
# Gian Penna <gianfrancopen@gmail.com>, 2020.
@@ -92,13 +92,14 @@
# Anonymous <noreply@weblate.org>, 2020.
# André Sousa <andrelvsousa@gmail.com>, 2020.
# Kleyton Luiz de Sousa Vieira <kleytonluizdesouzavieira@gmail.com>, 2020.
+# Felipe Jesus Macedo <fmacedo746@gmail.com>, 2020.
+# José Paulo <jose.paulo1919@gmail.com>, 2020.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: 2016-05-30\n"
-"PO-Revision-Date: 2020-06-15 01:48+0000\n"
-"Last-Translator: Kleyton Luiz de Sousa Vieira "
-"<kleytonluizdesouzavieira@gmail.com>\n"
+"PO-Revision-Date: 2020-06-25 08:40+0000\n"
+"Last-Translator: José Paulo <jose.paulo1919@gmail.com>\n"
"Language-Team: Portuguese (Brazil) <https://hosted.weblate.org/projects/"
"godot-engine/godot/pt_BR/>\n"
"Language: pt_BR\n"
@@ -106,7 +107,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n > 1;\n"
-"X-Generator: Weblate 4.1-dev\n"
+"X-Generator: Weblate 4.2-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -125,11 +126,11 @@ msgstr "Não há bytes suficientes para decodificar, ou o formato é inválido."
#: core/math/expression.cpp
msgid "Invalid input %i (not passed) in expression"
-msgstr "Entrada inválida %i (não passou) na expressão"
+msgstr "Entrada inválida %i (não passada) na expressão"
#: core/math/expression.cpp
msgid "self can't be used because instance is null (not passed)"
-msgstr "self não pode ser usado porque a instância é nula (não passou)"
+msgstr "self não pode ser usado porque a instância é nula (não passada)"
#: core/math/expression.cpp
msgid "Invalid operands to operator %s, %s and %s."
@@ -145,7 +146,7 @@ msgstr "Nome inválido de índice '%s' para base tipo %s"
#: core/math/expression.cpp
msgid "Invalid arguments to construct '%s'"
-msgstr "Argumento inválido para construir '%s'"
+msgstr "Argumentos inválidos para o construto '%s'"
#: core/math/expression.cpp
msgid "On call to '%s':"
@@ -579,7 +580,7 @@ msgstr ""
"Esta animação pertence a uma cena importada, dessa forma, mudanças das "
"trilhas importadas não serão salvas.\n"
"\n"
-"Para ativar a possibilidade de adicionar trilhas customizadas, navegue até "
+"Para ativar a possibilidade de adicionar trilhas customizadas, navegue até "
"as configurações de importação da cena e defina\n"
"\"Animação > Armazenamento\" para \"Arquivos\", ative \"Animação > Mantenha "
"Trilhas Customizadas\", então reimporte.\n"
@@ -843,6 +844,10 @@ msgid "Method in target node must be specified."
msgstr "O método no nó alvo precisa ser especificado."
#: editor/connections_dialog.cpp
+msgid "Method name must be a valid identifier."
+msgstr "O nome do método deve ser um identificador válido."
+
+#: editor/connections_dialog.cpp
msgid ""
"Target method not found. Specify a valid method or attach a script to the "
"target node."
@@ -1919,7 +1924,7 @@ msgstr "Alternar Modo"
#: editor/editor_file_dialog.cpp
msgid "Focus Path"
-msgstr "Focar no Caminho"
+msgstr "Habilitar"
#: editor/editor_file_dialog.cpp
msgid "Move Favorite Up"
@@ -2622,8 +2627,8 @@ msgid ""
"category."
msgstr ""
"A cena principal não foi definida, selecionar uma?\n"
-"Você pode alterá-la mais tarde nas \"Configurações do Projeto\" na "
-"categoria 'Application'."
+"Você pode alterá-la mais tarde nas \"Configurações do Projeto\" na categoria "
+"'Application'."
#: editor/editor_node.cpp
msgid ""
@@ -2899,8 +2904,8 @@ msgid ""
"Navigation meshes and polygons will be visible on the running game if this "
"option is turned on."
msgstr ""
-"Malhas e polígonos de navegação serão visíveis no jogo se esta opção estiver "
-"ligada."
+"Malhas e polígonos de navegação serão visíveis no jogo em execução se esta "
+"opção estiver ligada."
#: editor/editor_node.cpp
msgid "Sync Scene Changes"
@@ -3121,13 +3126,13 @@ msgid ""
"the \"Use Custom Build\" option should be enabled in the Android export "
"preset."
msgstr ""
-"Isso vai configurar seu projeto para construções customizadas do Android, "
-"instalando o modelo de fonte para \"res://android/build\".\n"
-"Você pode então aplicar modificações e construir seu próprio APK na guia "
-"Exportação (Adicionando módulos, trocando o AndroidManifest.xml, etc.).\n"
-"Note que para fazer uma construção customizada, em vez de usar APKs pre-"
-"construídos, a opção \"Usar Construção Customizada\" deve estar ativa nas "
-"predefinições de exportação Android."
+"Isso irá configurar o projeto para usar uma build do Android customizada "
+"instalando a template raiz para \"res://android/build\".\n"
+"Você poderá aplicar modificações e construir um APK customizado em exportar "
+"(adicionando módulos, changing the AndroidManifest.xml, etc.).\n"
+"Note que para fazer builds customizadas ao invés de usar APKs pré-"
+"construídas, a opção \"Usar Build Customizada\" deve sestar habilitada na "
+"pré-configuração de exportação Android."
#: editor/editor_node.cpp
msgid ""
@@ -4047,7 +4052,7 @@ msgstr "Erro ao rodar script pós-importação:"
#: editor/import/resource_importer_scene.cpp
msgid "Did you return a Node-derived object in the `post_import()` method?"
-msgstr ""
+msgstr "Você retornou um objeto derivado de nó no método `post import ()`?"
#: editor/import/resource_importer_scene.cpp
msgid "Saving..."
@@ -5659,7 +5664,7 @@ msgstr "Seleção de Frame"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Preview Canvas Scale"
-msgstr "Visualizar Canvas Scale"
+msgstr "Pré-visualização da escala do Canvas"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Translation mask for inserting keys."
@@ -5667,7 +5672,7 @@ msgstr "Máscara de tradução para inserção de chaves."
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Rotation mask for inserting keys."
-msgstr "Mascara de rotação para inserção de chaves."
+msgstr "Máscara de rotação para inserção de chaves."
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Scale mask for inserting keys."
@@ -7005,9 +7010,8 @@ msgid ""
msgstr "Falta método conectado '%s' para sinal '%s' do nó '%s' para nó '%s'."
#: editor/plugins/script_text_editor.cpp
-#, fuzzy
msgid "[Ignore]"
-msgstr "(ignore)"
+msgstr "(Ignore)"
#: editor/plugins/script_text_editor.cpp
msgid "Line"
@@ -7438,27 +7442,27 @@ msgstr "Não disponível ao usar o renderizador GLES2."
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Freelook Left"
-msgstr "Visão Livre Esquerda"
+msgstr "Visão Livre na Esquerda"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Freelook Right"
-msgstr "Visão Livre Direita"
+msgstr "Visão Livre na Direita"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Freelook Forward"
-msgstr "Visão Livre Frente"
+msgstr "Visão Livre na Frente"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Freelook Backwards"
-msgstr "Visão Livre Trás"
+msgstr "Visão Livre Atrás"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Freelook Up"
-msgstr "Visão Livre Cima"
+msgstr "Visão Livre em Cima"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Freelook Down"
-msgstr "Visão Livre Baixo"
+msgstr "Visão Livre Embaixo"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Freelook Speed Modifier"
@@ -7492,6 +7496,12 @@ msgid ""
"Closed eye: Gizmo is hidden.\n"
"Half-open eye: Gizmo is also visible through opaque surfaces (\"x-ray\")."
msgstr ""
+"Clique para alternar entre estados de visibilidade.\n"
+"\n"
+"Olhos abertos: Gizmo está visível.\n"
+"Olhos fechados: Gizmo não está visível.\n"
+"Olhos semi-abertos: Gizmo está visível através de superficies opacas (\"raio-"
+"x\")."
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Snap Nodes To Floor"
@@ -7517,7 +7527,7 @@ msgstr "Usar Espaço Local"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Use Snap"
-msgstr "Usar Snap"
+msgstr "Use Snap"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Bottom View"
@@ -8379,9 +8389,9 @@ msgid ""
"Shift+LMB: Set wildcard bit.\n"
"Click on another Tile to edit it."
msgstr ""
-"LMB: ligar bit.\n"
-"RMB: desligar bit.\n"
-"Shift+LMB: Escolher bit wildcard.\n"
+"LMB: Ligar bit.\n"
+"RMB: Desligar bit.\n"
+"Shift+LMB: Escolher bit curinga.\n"
"Clique em outro Mosaico para editá-lo."
#: editor/plugins/tile_set_editor_plugin.cpp
@@ -8516,7 +8526,7 @@ msgstr "Nenhuma mensagem de confirmação foi fornecida"
#: editor/plugins/version_control_editor_plugin.cpp
msgid "No files added to stage"
-msgstr "Nenhum arquivo adicionado ao palco"
+msgstr "Nenhum arquivo em espera"
#: editor/plugins/version_control_editor_plugin.cpp
msgid "Commit"
@@ -8524,11 +8534,11 @@ msgstr "Confirmação"
#: editor/plugins/version_control_editor_plugin.cpp
msgid "VCS Addon is not initialized"
-msgstr "Extensão VCS não está inicializada"
+msgstr "VCS Addon não inicializado"
#: editor/plugins/version_control_editor_plugin.cpp
msgid "Version Control System"
-msgstr "Sistema de Controle de Versionamento"
+msgstr "Sistema de Controle de Versão"
#: editor/plugins/version_control_editor_plugin.cpp
msgid "Initialize"
@@ -8536,7 +8546,7 @@ msgstr "Inicializar"
#: editor/plugins/version_control_editor_plugin.cpp
msgid "Staging area"
-msgstr "Área Temporária"
+msgstr "Área de espera"
#: editor/plugins/version_control_editor_plugin.cpp
msgid "Detect new changes"
@@ -8560,7 +8570,7 @@ msgstr "Excluído"
#: editor/plugins/version_control_editor_plugin.cpp
msgid "Typechange"
-msgstr "Alterar tipo"
+msgstr "Alteração de tipo"
#: editor/plugins/version_control_editor_plugin.cpp
msgid "Stage Selected"
@@ -8572,11 +8582,11 @@ msgstr "Salvar Tudo"
#: editor/plugins/version_control_editor_plugin.cpp
msgid "Add a commit message"
-msgstr "Adicione uma mensagem de confirmação"
+msgstr "Adicione uma mensagem ao commit"
#: editor/plugins/version_control_editor_plugin.cpp
msgid "Commit Changes"
-msgstr "Confirmar Mudanças de Script"
+msgstr "Confirmar Mudanças"
#: editor/plugins/version_control_editor_plugin.cpp
#: modules/gdnative/gdnative_library_singleton_editor.cpp
@@ -8774,7 +8784,7 @@ msgstr "Cor constante."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Color uniform."
-msgstr "Cor uniforme."
+msgstr "Uniformidade de cor."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Returns the boolean result of the %s comparison between two parameters."
@@ -8890,7 +8900,7 @@ msgstr "Parâmetro de entrada '%s' para o modo de sombra do vértice."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "'%s' input parameter for vertex and fragment shader mode."
msgstr ""
-"Parâmetro de entrada '%s' para os modos de sombra de vértice e fragmentada."
+"Parâmetro de entrada '%s' para os modo de sombra fragmentada e vértice."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Scalar function."
@@ -9144,7 +9154,7 @@ msgstr "Execute a pesquisa de textura cúbica."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Perform the texture lookup."
-msgstr "Faz uma busca de texturas."
+msgstr "Faz uma busca por texturas."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Cubic texture uniform lookup."
@@ -9160,7 +9170,7 @@ msgstr "Consulta de textura 2D uniforme com triplanar."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Transform function."
-msgstr "Função Transform."
+msgstr "Função Transformação..."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid ""
@@ -9182,7 +9192,7 @@ msgstr ""
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Composes transform from four vectors."
-msgstr "Compõe transformação a partir de quatro vetores."
+msgstr "Compõe a transformação de quatro vetores."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Decomposes transform to four vectors."
@@ -9190,19 +9200,19 @@ msgstr "Decompõe transformação em quatro vetores."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Calculates the determinant of a transform."
-msgstr "Calcula o determinante de uma transformada."
+msgstr "Calcula o determinante de uma transformação."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Calculates the inverse of a transform."
-msgstr "Calcula a inversa de uma transformada."
+msgstr "Calcula a inversa de uma transformação."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Calculates the transpose of a transform."
-msgstr "Calcula a transposta de uma transformada."
+msgstr "Calcula a transposta de uma transformação."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Multiplies transform by transform."
-msgstr "Multiplica a transformação por transformação."
+msgstr "Multiplica transformação por transformação."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Multiplies vector by transform."
@@ -9210,11 +9220,11 @@ msgstr "Multiplica vetor por transformação."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Transform constant."
-msgstr "Constante de transformação."
+msgstr "Transformar constante."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Transform uniform."
-msgstr "Uniforme de transformação."
+msgstr "Transformação uniforme."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Vector function."
@@ -9363,11 +9373,11 @@ msgstr "Subtrai vetor de vetor."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Vector constant."
-msgstr "Vetor constante."
+msgstr "Constante vetorial."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Vector uniform."
-msgstr "Vector uniforme."
+msgstr "Uniformidade vetorial."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid ""
@@ -9385,8 +9395,8 @@ msgid ""
"Returns falloff based on the dot product of surface normal and view "
"direction of camera (pass associated inputs to it)."
msgstr ""
-"Retorna falloff baseado no produto escalar do normal da superfície e da "
-"direção de visualização da câmera (passe entradas associadas a ela)."
+"Retorna decaimento com base no produto escalar da normal da superfície com o "
+"a direção de visão da câmera (passe as entradas associadas a ele)."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid ""
@@ -9413,7 +9423,7 @@ msgid ""
"(Fragment/Light mode only) (Vector) Derivative in 'x' using local "
"differencing."
msgstr ""
-"(Apenas modo Fragmento/Luz) (Vetor) Derivada em 'x' usando diferenciação "
+"(Apenas modo Fragmento/Luz) (Vetor) Derivativo em 'x' usando diferenciação "
"local."
#: editor/plugins/visual_shader_editor_plugin.cpp
@@ -9832,7 +9842,7 @@ msgstr "Projeto ausente"
#: editor/project_manager.cpp
msgid "Error: Project is missing on the filesystem."
-msgstr "Erro: O Projeto está ausente no sistema de arquivos."
+msgstr "Erro: Projeto não encontrado no sistema de arquivos."
#: editor/project_manager.cpp
msgid "Can't open project at '%s'."
@@ -9854,14 +9864,15 @@ msgid ""
"Warning: You won't be able to open the project with previous versions of the "
"engine anymore."
msgstr ""
-"O seguinte arquivo de configurações do projeto não especifica com qual "
-"versão do Godot ele foi criado.\n"
+"O seguinte arquivo de configurações do projeto não especifica a versão do "
+"Godot pelo qual ele foi criado.\n"
"\n"
"%s\n"
"\n"
-"Se escolher abrí-lo, será convertido para o formato atual de arquivo de "
-"configuração do Godot\n"
-"Aviso: Você não poderá mais abrir o projeto com versões anteriores do Godot."
+"Se você o abrir, ele será convertido para o formato de arquivo da "
+"configuração atual do Godot.\n"
+"Atenção: Você não será mais capaz de abrir o projeto com versões anteriores "
+"da engine."
#: editor/project_manager.cpp
msgid ""
@@ -9981,7 +9992,7 @@ msgstr "Novo Projeto"
#: editor/project_manager.cpp
msgid "Remove Missing"
-msgstr "Remover Ausentes"
+msgstr "Remover Ausente"
#: editor/project_manager.cpp
msgid "Templates"
@@ -10144,7 +10155,7 @@ msgstr "Botão Direito."
#: editor/project_settings_editor.cpp
msgid "Middle Button."
-msgstr "Botão do Meio."
+msgstr "Botão do Meio."
#: editor/project_settings_editor.cpp
msgid "Wheel Up."
@@ -10572,16 +10583,15 @@ msgstr "Instanciar Cena(s)"
#: editor/scene_tree_dock.cpp
msgid "Replace with Branch Scene"
-msgstr "Substituir com Ramo como Cena"
+msgstr "Substituir por cena ramo"
#: editor/scene_tree_dock.cpp
msgid "Instance Child Scene"
msgstr "Instânciar Cena Filha"
#: editor/scene_tree_dock.cpp
-#, fuzzy
msgid "Detach Script"
-msgstr "Adicionar Script"
+msgstr "Remover Script"
#: editor/scene_tree_dock.cpp
msgid "This operation can't be done on the tree root."
@@ -10751,6 +10761,9 @@ msgid ""
"This is probably because this editor was built with all language modules "
"disabled."
msgstr ""
+"Não pode associar um script: Não existem linguagens registradas.\n"
+"É provável que o editor tenha sido construido com todos os módulos de "
+"linguagem desabilitados."
#: editor/scene_tree_dock.cpp
msgid "Add Child Node"
@@ -10801,14 +10814,12 @@ msgstr ""
"existir um nó raiz."
#: editor/scene_tree_dock.cpp
-#, fuzzy
msgid "Attach a new or existing script to the selected node."
-msgstr "Adicionar um script novo ou existente para o nó selecionado."
+msgstr "Adicionar um novo script, ou um já existente, para o nó selecionado."
#: editor/scene_tree_dock.cpp
-#, fuzzy
msgid "Detach the script from the selected node."
-msgstr "Remove um script do nó selecionado."
+msgstr "Remove o script do nó selecionado."
#: editor/scene_tree_dock.cpp
msgid "Remote"
@@ -10920,7 +10931,7 @@ msgstr "Selecione um Nó"
#: editor/script_create_dialog.cpp
msgid "Path is empty."
-msgstr "O caminho está vazio."
+msgstr "Caminho vazio."
#: editor/script_create_dialog.cpp
msgid "Filename is empty."
@@ -11328,7 +11339,7 @@ msgstr "Singleton GDNative ativado"
#: modules/gdnative/gdnative_library_singleton_editor.cpp
msgid "Disabled GDNative Singleton"
-msgstr "Singleton GDNative Desabilitado"
+msgstr "GDNative Singleton desativado"
#: modules/gdnative/gdnative_library_singleton_editor.cpp
msgid "Library"
@@ -11589,8 +11600,8 @@ msgid ""
"Node yielded, but did not return a function state in the first working "
"memory."
msgstr ""
-"Nó entrou em yield, mas não retornou um estado de função na primeira memória "
-"de trabalho."
+"O nó cedeu, mas não retornou um estado de função na primeira memória de "
+"trabalho."
#: modules/visual_script/visual_script.cpp
msgid ""
@@ -12041,20 +12052,20 @@ msgstr ""
#, fuzzy
msgid "Release keystore incorrectly configured in the export preset."
msgstr ""
-"Porta-chaves de depuração não configurado nas Configurações do Editor e nem "
-"na predefinição."
+"Keystore de liberação icorretamente configurada na predefinição de "
+"exportação."
#: platform/android/export/export.cpp
msgid "Custom build requires a valid Android SDK path in Editor Settings."
msgstr ""
-"A compilação personalizada requer um caminho SDK do Android válido nas "
+"Build personalizada precisa de um caminho Android SDK válido em "
"Configurações do Editor."
#: platform/android/export/export.cpp
msgid "Invalid Android SDK path for custom build in Editor Settings."
msgstr ""
-"Caminho SDK do Android inválido para a compilação personalizada nas "
-"Configurações do Editor."
+"Caminho do Android SDK inválido para o build personalizado em Configurações "
+"do Editor."
#: platform/android/export/export.cpp
msgid ""
@@ -12066,7 +12077,7 @@ msgstr ""
#: platform/android/export/export.cpp
msgid "Invalid public key for APK expansion."
-msgstr "Chave pública inválida para expansão de APK."
+msgstr "Chave pública inválida para expansão do APK."
#: platform/android/export/export.cpp
msgid "Invalid package name:"
@@ -12077,34 +12088,45 @@ msgid ""
"Invalid \"GodotPaymentV3\" module included in the \"android/modules\" "
"project setting (changed in Godot 3.2.2).\n"
msgstr ""
+"Módulo inválido \"GodotPaymentV3\" incluido na configuração de projeto "
+"\"android/modules\" (changed in Godot 3.2.2).\n"
#: platform/android/export/export.cpp
msgid "\"Use Custom Build\" must be enabled to use the plugins."
msgstr ""
+"\"Use Custom Build\" precisa estar ativo para ser possível utilizar plugins."
#: platform/android/export/export.cpp
+#, fuzzy
msgid ""
"\"Degrees Of Freedom\" is only valid when \"Xr Mode\" is \"Oculus Mobile VR"
"\"."
msgstr ""
+"\"Degrees Of Freedom\" só é válido quando o \"Oculus Mobile VR\" está no "
+"\"Mode Xr\"."
#: platform/android/export/export.cpp
+#, fuzzy
msgid ""
"\"Hand Tracking\" is only valid when \"Xr Mode\" is \"Oculus Mobile VR\"."
msgstr ""
+"\"Hand Tracking\" só é válido quando o\"Oculus Mobile VR\" está no \"Xr Mode"
+"\"."
#: platform/android/export/export.cpp
msgid ""
"\"Focus Awareness\" is only valid when \"Xr Mode\" is \"Oculus Mobile VR\"."
msgstr ""
+"\"Focus Awareness\" só é válido quando o \"Oculus Mobile VR\" está no \"Xr "
+"Mode\"."
#: platform/android/export/export.cpp
msgid ""
"Trying to build from a custom built template, but no version info for it "
"exists. Please reinstall from the 'Project' menu."
msgstr ""
-"Tentando compilar a partir de um modelo compilado personalizado, mas nenhuma "
-"informação de versão para ele existe. Por favor, reinstale pelo menu "
+"Tentando construir a partir de um modelo compilado personalizado, mas "
+"nenhuma informação de versão para ele existe. Por favor, reinstale pelo menu "
"'Projeto'."
#: platform/android/export/export.cpp
@@ -12114,7 +12136,7 @@ msgid ""
" Godot Version: %s\n"
"Please reinstall Android build template from 'Project' menu."
msgstr ""
-"Diferença de versão da compilação do Android:\n"
+"Diferença na versão da build do Android:\n"
" Modelo instalado: %s\n"
" Versão do Godot: %s\n"
"Por favor reinstale o modelo de compilação do Android pelo menu 'Projeto'."
@@ -12128,13 +12150,13 @@ msgid ""
"Building of Android project failed, check output for the error.\n"
"Alternatively visit docs.godotengine.org for Android build documentation."
msgstr ""
-"A compilação do projeto Android falhou, verifique a saída pelo erro.\n"
+"A construção do projeto Android falhou, verifique a saída para detalhes.\n"
"Alternativamente, visite docs.godotengine.org para ver a documentação de "
"compilação do Android."
#: platform/android/export/export.cpp
msgid "No build apk generated at: "
-msgstr "Nenhuma compilação apk gerada em: "
+msgstr "Nenhuma construção apk gerada em: "
#: platform/iphone/export/export.cpp
msgid "Identifier is missing."
@@ -12545,7 +12567,8 @@ msgstr ""
#: scene/3d/collision_shape.cpp
msgid ""
"ConcavePolygonShape doesn't support RigidBody in another mode than static."
-msgstr "Lol."
+msgstr ""
+"ConcavePolygonShape não suporta um RigidBody em outro modo além do estático."
#: scene/3d/cpu_particles.cpp
msgid "Nothing is visible because no mesh has been assigned."
@@ -12718,7 +12741,7 @@ msgstr "Nada está ligado à entrada '%s' do nó '%s'."
#: scene/animation/animation_tree.cpp
msgid "No root AnimationNode for the graph is set."
-msgstr "Um AnimationNode raiz para o gráfico não está definido."
+msgstr "Nenhuma raiz AnimationNode para o gráfico está definida."
#: scene/animation/animation_tree.cpp
msgid "Path to an AnimationPlayer node containing animations is not set."
@@ -12784,9 +12807,9 @@ msgid ""
"The Hint Tooltip won't be displayed as the control's Mouse Filter is set to "
"\"Ignore\". To solve this, set the Mouse Filter to \"Stop\" or \"Pass\"."
msgstr ""
-"A Dica não será exibida quando o controle de Filtro do Mouse estiver "
-"definido como \"Ignorar\". Para resolver, defina o Filtro do Mouse como "
-"\"Parar\" ou \"Continuar\"."
+"A sugestão de dica não será exibida quando o Filtro do Mouse do controle "
+"estiver definido como \"Ignorar\". Para resolver isto, defina o Filtro do "
+"Mouse como \"Parar\" ou \"Passar\"."
#: scene/gui/dialogs.cpp
msgid "Alert!"
@@ -12831,7 +12854,7 @@ msgid ""
"Environment -> Default Environment) could not be loaded."
msgstr ""
"O Ambiente Padrão especificado nas Configurações de Projeto (Rendering -> "
-"Environment -> Default Environment) não pôde ser carregado."
+"Environment -> Default Environment) não pôde ser carregado."
#: scene/main/viewport.cpp
msgid ""
diff --git a/editor/translations/pt_PT.po b/editor/translations/pt_PT.po
index 40a83eaa87..54accb0d6f 100644
--- a/editor/translations/pt_PT.po
+++ b/editor/translations/pt_PT.po
@@ -768,6 +768,11 @@ msgid "Method in target node must be specified."
msgstr "Método no nó alvo deve ser especificado."
#: editor/connections_dialog.cpp
+#, fuzzy
+msgid "Method name must be a valid identifier."
+msgstr "O nome não é um identificador válido:"
+
+#: editor/connections_dialog.cpp
msgid ""
"Target method not found. Specify a valid method or attach a script to the "
"target node."
diff --git a/editor/translations/ro.po b/editor/translations/ro.po
index 5e362de330..cbf6a8f0a0 100644
--- a/editor/translations/ro.po
+++ b/editor/translations/ro.po
@@ -749,6 +749,11 @@ msgid "Method in target node must be specified."
msgstr "Metoda din nodul țintă trebuie specificată."
#: editor/connections_dialog.cpp
+#, fuzzy
+msgid "Method name must be a valid identifier."
+msgstr "Metoda din nodul țintă trebuie specificată."
+
+#: editor/connections_dialog.cpp
msgid ""
"Target method not found. Specify a valid method or attach a script to the "
"target node."
diff --git a/editor/translations/ru.po b/editor/translations/ru.po
index 8bae9207d0..a2e562446d 100644
--- a/editor/translations/ru.po
+++ b/editor/translations/ru.po
@@ -27,7 +27,7 @@
# Yan <uvokinuvokines@gmail.com>, 2018.
# V. <Unit68189@gmail.com>, 2018, 2019.
# Victor Butorin <mrwebsterchannel@gmail.com>, 2018.
-# Александр <ol-vin@mail.ru>, 2018, 2019.
+# Александр <ol-vin@mail.ru>, 2018, 2019, 2020.
# Анатолий Горбунов <afgorbunov@gmail.com>, 2018, 2019.
# Vadim Vergasov <vadim.vergasov2003@gmail.com>, 2018, 2019.
# Аслан Снупов <aslan170505@gmail.com>, 2018.
@@ -76,12 +76,14 @@
# Nikita <Kulacnikita@ya.ru>, 2020.
# Alexander <ramzi7208@gmail.com>, 2020.
# Alex Tern <ternvein@gmail.com>, 2020.
+# Varion Drakon Neonovich <variondrakon@gmail.com>, 2020.
+# d2cyb <dmitrydpb@gmail.com>, 2020.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2020-06-15 12:01+0000\n"
-"Last-Translator: Alex Tern <ternvein@gmail.com>\n"
+"PO-Revision-Date: 2020-06-22 06:40+0000\n"
+"Last-Translator: Александр <ol-vin@mail.ru>\n"
"Language-Team: Russian <https://hosted.weblate.org/projects/godot-engine/"
"godot/ru/>\n"
"Language: ru\n"
@@ -90,7 +92,7 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
-"X-Generator: Weblate 4.1\n"
+"X-Generator: Weblate 4.2-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -99,13 +101,13 @@ msgstr "Неверный тип аргумента для convert(), испол
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
msgid "Expected a string of length 1 (a character)."
-msgstr "Ожидалась строка длиной 1 (символ)."
+msgstr "Ожидалась строка длиной 1 (т.е. символ)."
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/mono/glue/gd_glue.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
msgid "Not enough bytes for decoding bytes, or invalid format."
-msgstr "Недостаточно байтов для декодирования или неверный формат."
+msgstr "Недостаточно байтов для декодирования байтов или неверный формат."
#: core/math/expression.cpp
msgid "Invalid input %i (not passed) in expression"
@@ -134,7 +136,7 @@ msgstr "Недопустимые аргументы для построения
#: core/math/expression.cpp
msgid "On call to '%s':"
-msgstr "На вызове '%s':"
+msgstr "При вызове '%s':"
#: core/ustring.cpp
msgid "B"
@@ -190,11 +192,11 @@ msgstr "Вставить ключ здесь"
#: editor/animation_bezier_editor.cpp
msgid "Duplicate Selected Key(s)"
-msgstr "Дублировать выделенные ключ(и)"
+msgstr "Дублировать выделенные ключи"
#: editor/animation_bezier_editor.cpp
msgid "Delete Selected Key(s)"
-msgstr "Удалить выделенные ключ(и)"
+msgstr "Удалить выделенные ключи"
#: editor/animation_bezier_editor.cpp
msgid "Add Bezier Point"
@@ -242,7 +244,7 @@ msgstr "Многократное изменение перехода"
#: editor/animation_track_editor.cpp
msgid "Anim Multi Change Transform"
-msgstr "Анимационное многократное изменение положения"
+msgstr "Анимационное многосменное преобразование"
#: editor/animation_track_editor.cpp
msgid "Anim Multi Change Keyframe Value"
@@ -250,7 +252,7 @@ msgstr "Изменить значение ключевого кадра"
#: editor/animation_track_editor.cpp
msgid "Anim Multi Change Call"
-msgstr "Анимационный многократный вызов изменения"
+msgstr "Изменить вызов анимации"
#: editor/animation_track_editor.cpp
msgid "Change Animation Length"
@@ -320,7 +322,7 @@ msgstr "Изменить Путь Следования"
#: editor/animation_track_editor.cpp
msgid "Toggle this track on/off."
-msgstr "Переключить этот трек вкл/выкл."
+msgstr "Включить/выключить этот трек."
#: editor/animation_track_editor.cpp
msgid "Update Mode (How this property is set)"
@@ -328,16 +330,15 @@ msgstr "Режим Обновления (Как это свойство уста
#: editor/animation_track_editor.cpp
msgid "Interpolation Mode"
-msgstr "Режим Перехода"
+msgstr "Режим интерполяции"
#: editor/animation_track_editor.cpp
msgid "Loop Wrap Mode (Interpolate end with beginning on loop)"
-msgstr ""
-"Режим Обработки Зацикливания (Переход заканчивается с началом нового цикла)"
+msgstr "Режим зацикливания (интерполировать начало и конец при зацикливании)"
#: editor/animation_track_editor.cpp
msgid "Remove this track."
-msgstr "Удалить этот трек."
+msgstr "Удалить эту дорожку."
#: editor/animation_track_editor.cpp
msgid "Time (s): "
@@ -403,7 +404,7 @@ msgstr "Изменить режим обновления анимации"
#: editor/animation_track_editor.cpp
msgid "Change Animation Interpolation Mode"
-msgstr "Изменить режим интерполяции анимации"
+msgstr "Изменить способ интерполяции анимации"
#: editor/animation_track_editor.cpp
msgid "Change Animation Loop Mode"
@@ -463,7 +464,8 @@ msgstr "Переставить дорожки"
#: editor/animation_track_editor.cpp
msgid "Transform tracks only apply to Spatial-based nodes."
-msgstr "Трек трансформации применяется только к основанным на Spatial узлам."
+msgstr ""
+"Дорожка преобразования применяется только к основанным на Spatial узлам."
#: editor/animation_track_editor.cpp
msgid ""
@@ -472,14 +474,14 @@ msgid ""
"-AudioStreamPlayer2D\n"
"-AudioStreamPlayer3D"
msgstr ""
-"Aудио треки могут указывать только на узлы типа:\n"
+"Аудио дорожки могут указывать только на узлы типа:\n"
"-AudioStreamPlayer\n"
"-AudioStreamPlayer2D\n"
"-AudioStreamPlayer3D"
#: editor/animation_track_editor.cpp
msgid "Animation tracks can only point to AnimationPlayer nodes."
-msgstr "Треки Анимации могут указывать только на узлы типа AnimationPlayer."
+msgstr "Дорожки анимации могут указывать только на узлы типа AnimationPlayer."
#: editor/animation_track_editor.cpp
msgid "An animation player can't animate itself, only other players."
@@ -487,11 +489,11 @@ msgstr "Проигрыватель анимации не может анимир
#: editor/animation_track_editor.cpp
msgid "Not possible to add a new track without a root"
-msgstr "Нельзя добавить новый трек без корневого узла"
+msgstr "Нельзя добавить новую дорожку без корневого узла"
#: editor/animation_track_editor.cpp
msgid "Invalid track for Bezier (no suitable sub-properties)"
-msgstr "Неверный трек для кривой Безье (нет подходящих подсвойств)"
+msgstr "Неверная дорожка для кривой Безье (нет подходящих подсвойств)"
#: editor/animation_track_editor.cpp
msgid "Add Bezier Track"
@@ -499,11 +501,11 @@ msgstr "Добавить дорожку Безье"
#: editor/animation_track_editor.cpp
msgid "Track path is invalid, so can't add a key."
-msgstr "Путь трека некорректен, потому нельзя добавить ключ."
+msgstr "Путь к дорожке некорректен, потому нельзя добавить ключ."
#: editor/animation_track_editor.cpp
msgid "Track is not of type Spatial, can't insert key"
-msgstr "Трек не имеет тип Spatial, нельзя добавить ключ"
+msgstr "Дорожка не имеет тип Spatial, нельзя добавить ключ"
#: editor/animation_track_editor.cpp
msgid "Add Transform Track Key"
@@ -515,11 +517,11 @@ msgstr "Добавить ключ дорожки"
#: editor/animation_track_editor.cpp
msgid "Track path is invalid, so can't add a method key."
-msgstr "Путь трека некорректен, потому нельзя добавить ключ метода."
+msgstr "Путь к дорожке некорректен, потому нельзя добавить ключ метода."
#: editor/animation_track_editor.cpp
msgid "Add Method Track Key"
-msgstr "Добавить ключ отслеживания метода"
+msgstr "Добавить ключ дорожки для метода"
#: editor/animation_track_editor.cpp
msgid "Method not found in object: "
@@ -546,7 +548,7 @@ msgid ""
"This option does not work for Bezier editing, as it's only a single track."
msgstr ""
"Эта опция не работает для редактирования кривыми Безье, так как это только "
-"один трек."
+"одна дорожка."
#: editor/animation_track_editor.cpp
msgid ""
@@ -561,14 +563,14 @@ msgid ""
"files."
msgstr ""
"Данная анимация принадлежит импортированной сцене, поэтому изменения, "
-"внесенные в импортированные треки, не будут сохранены.\n"
+"внесенные в импортированные дорожки, не будут сохранены.\n"
"\n"
-"Чтобы активировать возможность добавления пользовательских треков, перейдите "
-"к настройкам импорта сцены и установите\n"
+"Чтобы активировать возможность добавления пользовательских дорожек, "
+"перейдите к настройкам импорта сцены и установите\n"
"\"Анимация > Хранилище\" в значение \"Файлы\", а также включите пункт "
-"\"Анимация > Сохранять пользовательские треки\", и заново импортируйте "
+"\"Анимация > Сохранять пользовательские дорожки\", и заново импортируйте "
"сцену.\n"
-"В качестве альтернативы используйте пресет импорта, который импортирует "
+"В качестве альтернативы используйте шаблон импорта, который импортирует "
"анимации в отдельные файлы."
#: editor/animation_track_editor.cpp
@@ -581,11 +583,11 @@ msgstr "Выберите узел AnimationPlayer для создания и р
#: editor/animation_track_editor.cpp
msgid "Only show tracks from nodes selected in tree."
-msgstr "Показывать треки только выделенных в дереве узлов."
+msgstr "Показывать дорожки только выделенных в дереве узлов."
#: editor/animation_track_editor.cpp
msgid "Group tracks by node or display them as plain list."
-msgstr "Группировать треки по узлам или показывать их как простой список."
+msgstr "Группировать дорожки по узлам или показывать их как простой список."
#: editor/animation_track_editor.cpp
msgid "Snap:"
@@ -619,7 +621,7 @@ msgstr "Свойства анимации."
#: editor/animation_track_editor.cpp
msgid "Copy Tracks"
-msgstr "Копировать треки"
+msgstr "Копировать дорожки"
#: editor/animation_track_editor.cpp
msgid "Scale Selection"
@@ -635,7 +637,7 @@ msgstr "Дублировать выделенное"
#: editor/animation_track_editor.cpp
msgid "Duplicate Transposed"
-msgstr "Дублировать и переместить"
+msgstr "Дублировать и транспонировать"
#: editor/animation_track_editor.cpp
msgid "Delete Selection"
@@ -825,7 +827,12 @@ msgstr "Номера строк и столбцов."
#: editor/connections_dialog.cpp
msgid "Method in target node must be specified."
-msgstr "Метод должен быть указан в целевом узле."
+msgstr "Метод в целевом узле должен быть указан."
+
+#: editor/connections_dialog.cpp
+#, fuzzy
+msgid "Method name must be a valid identifier."
+msgstr "Имя не является допустимым идентификатором:"
#: editor/connections_dialog.cpp
msgid ""
@@ -837,7 +844,7 @@ msgstr ""
#: editor/connections_dialog.cpp
msgid "Connect to Node:"
-msgstr "Присоединить к узлу:"
+msgstr "Присоединить к Узлу:"
#: editor/connections_dialog.cpp
msgid "Connect to Script:"
@@ -849,7 +856,7 @@ msgstr "От сигнала:"
#: editor/connections_dialog.cpp
msgid "Scene does not contain any script."
-msgstr "Узел не содержит скрипт."
+msgstr "Сцена не содержит каких-либо скриптов."
#: editor/connections_dialog.cpp editor/editor_autoload_settings.cpp
#: editor/groups_editor.cpp editor/plugins/item_list_editor_plugin.cpp
@@ -870,7 +877,7 @@ msgstr "Удалить"
#: editor/connections_dialog.cpp
msgid "Add Extra Call Argument:"
-msgstr "Добавить дополнительный параметр вызова:"
+msgstr "Добавить дополнительный аргумент вызова:"
#: editor/connections_dialog.cpp
msgid "Extra Call Arguments:"
@@ -956,7 +963,7 @@ msgstr "Подключить сигнал к методу"
#: editor/connections_dialog.cpp
msgid "Edit Connection:"
-msgstr "Редактировать подключение:"
+msgstr "Редактировать соединение:"
#: editor/connections_dialog.cpp
msgid "Are you sure you want to remove all connections from the \"%s\" signal?"
@@ -1093,7 +1100,7 @@ msgstr "Владельцы:"
#: editor/dependency_editor.cpp
msgid "Remove selected files from the project? (Can't be restored)"
-msgstr "Удалить выбранные файлы из проекта? (Нельзя отменить!)"
+msgstr "Удалить выбранные файлы из проекта? (Нельзя восстановить)"
#: editor/dependency_editor.cpp
msgid ""
@@ -1522,7 +1529,7 @@ msgstr "Перестановка автозагрузок"
#: editor/editor_autoload_settings.cpp
msgid "Can't add autoload:"
-msgstr "Нельзя добваить автозагрузку:"
+msgstr "Не удаётся добавить автозагрузку:"
#: editor/editor_autoload_settings.cpp
msgid "Add AutoLoad"
@@ -2482,7 +2489,7 @@ msgstr "Не возможно загрузить сцену, которая не
#: editor/editor_node.cpp
msgid "Reload Saved Scene"
-msgstr "Перезагрузить сохранённую сцену"
+msgstr "Перезагрузить сохраненную сцену"
#: editor/editor_node.cpp
msgid ""
@@ -2768,12 +2775,12 @@ msgstr "Набор тайлов..."
#: editor/editor_node.cpp editor/plugins/script_text_editor.cpp
#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Undo"
-msgstr "Отменить"
+msgstr "Отменить (Undo)"
#: editor/editor_node.cpp editor/plugins/script_text_editor.cpp
#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Redo"
-msgstr "Повторить"
+msgstr "Повторить (Redo)"
#: editor/editor_node.cpp
msgid "Miscellaneous project or scene-wide tools."
@@ -2930,7 +2937,7 @@ msgstr "Макет редактора"
#: editor/editor_node.cpp
msgid "Take Screenshot"
-msgstr "Сделать снимок экрана"
+msgstr "Сделать скриншот"
#: editor/editor_node.cpp
msgid "Screenshots are stored in the Editor Data/Settings Folder."
@@ -3000,7 +3007,7 @@ msgstr "Сообщество"
#: editor/editor_node.cpp
msgid "About"
-msgstr "О движке"
+msgstr "О Godot Engine"
#: editor/editor_node.cpp
msgid "Play the project."
@@ -3181,7 +3188,7 @@ msgstr "Открыть предыдущий редактор"
#: editor/editor_node.h
msgid "Warning!"
-msgstr "Внимание!"
+msgstr "Предупреждение!"
#: editor/editor_path.cpp
msgid "No sub-resources found."
@@ -3290,7 +3297,7 @@ msgstr "[Пусто]"
#: editor/editor_properties.cpp editor/plugins/root_motion_editor_plugin.cpp
msgid "Assign..."
-msgstr "Назначается..."
+msgstr "Устанавливать.."
#: editor/editor_properties.cpp
msgid "Invalid RID"
@@ -4025,7 +4032,7 @@ msgstr "Ошибка запуска пост-импорт скрипта:"
#: editor/import/resource_importer_scene.cpp
msgid "Did you return a Node-derived object in the `post_import()` method?"
-msgstr ""
+msgstr "Вы вернули производный от Node объект в методе `post_import ()`?"
#: editor/import/resource_importer_scene.cpp
msgid "Saving..."
@@ -4243,7 +4250,7 @@ msgstr "Загрузка..."
#: editor/plugins/animation_blend_space_1d_editor.cpp
#: editor/plugins/animation_blend_space_2d_editor.cpp
msgid "Move Node Point"
-msgstr "Передвинуть узел"
+msgstr "Передвинуть точку узла"
#: editor/plugins/animation_blend_space_1d_editor.cpp
msgid "Change BlendSpace1D Limits"
@@ -4698,7 +4705,7 @@ msgstr "Переместить узел"
#: editor/plugins/animation_state_machine_editor.cpp
msgid "Transition exists!"
-msgstr "Переход уже существует!"
+msgstr "Переход существует!"
#: editor/plugins/animation_state_machine_editor.cpp
msgid "Add Transition"
@@ -5632,7 +5639,7 @@ msgstr "Масштаб при просмотре холста"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Translation mask for inserting keys."
-msgstr "Маска перемещения для добавляемых ключей."
+msgstr "Маска трансформации для вставки ключей."
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Rotation mask for inserting keys."
@@ -5665,7 +5672,7 @@ msgstr "Автовставка ключа"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Animation Key and Pose Options"
-msgstr "Настройки ключевых кадров и поз"
+msgstr "Опции анимационных ключей и поз"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Insert Key (Existing Tracks)"
@@ -5777,7 +5784,7 @@ msgstr "Маска излучения"
#: editor/plugins/cpu_particles_2d_editor_plugin.cpp
#: editor/plugins/particles_2d_editor_plugin.cpp
msgid "Solid Pixels"
-msgstr "Сплошные пиксели"
+msgstr "Залитые пиксели"
#: editor/plugins/cpu_particles_2d_editor_plugin.cpp
#: editor/plugins/particles_2d_editor_plugin.cpp
@@ -5923,16 +5930,15 @@ msgstr "Это не работает на корне сцены!"
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid "Create Trimesh Static Shape"
-msgstr "Создать треугольную сетку статической формы"
+msgstr "Создать сетку статической формы"
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid "Can't create a single convex collision shape for the scene root."
-msgstr ""
-"Не удается создать единственную выпуклую форму столкновения для корня сцены."
+msgstr "Нельзя создать единую выпуклую форму столкновения для корня сцены."
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid "Couldn't create a single convex collision shape."
-msgstr "Не удалось создать одну выпуклую форму столкновений."
+msgstr "Не удалось создать ни одной выпуклой формы столкновения."
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid "Create Single Convex Shape"
@@ -5945,11 +5951,11 @@ msgstr ""
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid "Couldn't create any collision shapes."
-msgstr "Не удалось создать ни одной форму столкновения."
+msgstr "Не удалось создать ни одну форму столкновения."
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid "Create Multiple Convex Shapes"
-msgstr "Создать несколько выпуклых форм"
+msgstr "Создать нескольких выпуклых фигур"
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid "Create Navigation Mesh"
@@ -6035,7 +6041,7 @@ msgstr ""
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid "Create Multiple Convex Collision Siblings"
-msgstr "Создать несколько соседних выпуклых форм столкновения"
+msgstr "Создать выпуклую область столкновения"
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid ""
@@ -6056,10 +6062,10 @@ msgid ""
"This can be used instead of the SpatialMaterial Grow property when using "
"that property isn't possible."
msgstr ""
-"Создаёт статичную обводочную полисетку. Её нормали переворачиваются "
-"автоматически.\n"
-"Она может быть использована в случае, если использовать свойство Grow "
-"материала SpatialMaterial не представляется возможным."
+"Создать статичную контурную полисетку. Контурная полисетка будет иметь свои "
+"нормали, перевернутые автоматически.\n"
+"Можно использовать вместо свойства Grow в SpatialMaterial, в случае когда "
+"оно не применимо."
#: editor/plugins/mesh_instance_editor_plugin.cpp
msgid "View UV1"
@@ -6974,7 +6980,6 @@ msgstr ""
"'%s'."
#: editor/plugins/script_text_editor.cpp
-#, fuzzy
msgid "[Ignore]"
msgstr "(игнорировать)"
@@ -7335,7 +7340,7 @@ msgstr "Выравнять преобразование с областью пр
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Align Rotation with View"
-msgstr "Выравнять поворот с областью просмотра"
+msgstr "Совместить поворот с направлением взгляда"
#: editor/plugins/spatial_editor_plugin.cpp editor/scene_tree_dock.cpp
msgid "No parent to instance a child at."
@@ -7462,6 +7467,12 @@ msgid ""
"Closed eye: Gizmo is hidden.\n"
"Half-open eye: Gizmo is also visible through opaque surfaces (\"x-ray\")."
msgstr ""
+"Нажмите для переключения между состояниями видимости.\n"
+"\n"
+"Открытый глаз: Гизмо видно.\n"
+"Закрытый глаз: Гизмо скрыто.\n"
+"Полуоткрытый глаз: Гизмо также видно сквозь непрозрачные поверхности "
+"(«рентген»)."
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Snap Nodes To Floor"
@@ -7694,7 +7705,7 @@ msgstr ""
#: editor/plugins/sprite_editor_plugin.cpp
msgid "Invalid geometry, can't replace by mesh."
-msgstr "Некорректная геометрия, не может быть заменена сеткой."
+msgstr "Недопустимая геометрия, не может быть заменена полисеткой."
#: editor/plugins/sprite_editor_plugin.cpp
msgid "Convert to Mesh2D"
@@ -8597,7 +8608,7 @@ msgstr "Добавить входной порт"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Add output port"
-msgstr "Добавить выходной порт"
+msgstr "Добавить исходящий порт"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Change input port type"
@@ -8678,7 +8689,7 @@ msgstr "Показать полученный код шейдера."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Create Shader Node"
-msgstr "Создать узел шейдера"
+msgstr "Создать Шейдерный узел"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Color function."
@@ -8722,7 +8733,7 @@ msgstr "Оператор выцветания."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "HardLight operator."
-msgstr "Оператор HardLight."
+msgstr "Оператор жёсткого света."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Lighten operator."
@@ -9239,7 +9250,7 @@ msgstr "Линейная интерполяция между двумя вект
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Linear interpolation between two vectors using scalar."
-msgstr "Линейная интерполяция между двумя векторами с использованием скаляра."
+msgstr "Линейная интерполяция между двумя векторами используя скаляр."
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "Calculates the normalize product of vector."
@@ -10166,7 +10177,7 @@ msgstr "Настройки сохранены нормально."
#: editor/project_settings_editor.cpp
msgid "Moved Input Action Event"
-msgstr "Событие ввода действия перемещено"
+msgstr "Перенесите событие ввода действия"
#: editor/project_settings_editor.cpp
msgid "Override for Feature"
@@ -10551,7 +10562,6 @@ msgid "Instance Child Scene"
msgstr "Добавить дочернюю сцену"
#: editor/scene_tree_dock.cpp
-#, fuzzy
msgid "Detach Script"
msgstr "Прикрепить скрипт"
@@ -10724,6 +10734,9 @@ msgid ""
"This is probably because this editor was built with all language modules "
"disabled."
msgstr ""
+"Невозможно прикрепить скрипт: нет зарегистрированных языков.\n"
+"Вероятно, это связано с тем, что этот редактор был построен с отключенными "
+"всеми языковыми модулями."
#: editor/scene_tree_dock.cpp
msgid "Add Child Node"
@@ -10774,12 +10787,10 @@ msgstr ""
"не существует."
#: editor/scene_tree_dock.cpp
-#, fuzzy
msgid "Attach a new or existing script to the selected node."
msgstr "Прикрепить новый или существующий скрипт к выбранному узлу."
#: editor/scene_tree_dock.cpp
-#, fuzzy
msgid "Detach the script from the selected node."
msgstr "Убрать скрипт у выбранного узла."
@@ -11387,7 +11398,7 @@ msgstr "Залить выделенную GridMap"
#: modules/gridmap/grid_map_editor_plugin.cpp
msgid "GridMap Paste Selection"
-msgstr "Вставить выделенную сетку"
+msgstr "Вставка выделенной сетки"
#: modules/gridmap/grid_map_editor_plugin.cpp
msgid "GridMap Paint"
@@ -12008,7 +12019,6 @@ msgstr ""
"предустановках."
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Release keystore incorrectly configured in the export preset."
msgstr ""
"Отладочная клавиатура не настроена ни в настройках редактора, ни в "
@@ -12046,26 +12056,34 @@ msgid ""
"Invalid \"GodotPaymentV3\" module included in the \"android/modules\" "
"project setting (changed in Godot 3.2.2).\n"
msgstr ""
+"Недопустимый модуль «GodotPaymentV3», включенный в настройку проекта "
+"«android/modules» (изменен в Godot 3.2.2).\n"
#: platform/android/export/export.cpp
msgid "\"Use Custom Build\" must be enabled to use the plugins."
-msgstr ""
+msgstr "«Use Custom Build» должен быть включен для использования плагинов."
#: platform/android/export/export.cpp
msgid ""
"\"Degrees Of Freedom\" is only valid when \"Xr Mode\" is \"Oculus Mobile VR"
"\"."
msgstr ""
+"«Степени свободы» действительны только тогда, когда «Xr Mode» - это «Oculus "
+"Mobile VR»."
#: platform/android/export/export.cpp
msgid ""
"\"Hand Tracking\" is only valid when \"Xr Mode\" is \"Oculus Mobile VR\"."
msgstr ""
+"«Отслеживание рук» действует только тогда, когда «Xr Mode» - это «Oculus "
+"Mobile VR»."
#: platform/android/export/export.cpp
msgid ""
"\"Focus Awareness\" is only valid when \"Xr Mode\" is \"Oculus Mobile VR\"."
msgstr ""
+"«Осведомленность о фокусе» действительна только в том случае, если «Режим "
+"Xr» - это «Oculus Mobile VR»."
#: platform/android/export/export.cpp
msgid ""
@@ -12298,7 +12316,7 @@ msgstr ""
#: scene/2d/light_occluder_2d.cpp
msgid "The occluder polygon for this occluder is empty. Please draw a polygon."
msgstr ""
-"Заслоняющий полигон для этого окклюдера пуст. Пожалуйста, нарисуйте полигон."
+"Заслоняющий полигон для этого окклюдера пуст. Пожалуйста, добавьте полигон."
#: scene/2d/navigation_polygon.cpp
msgid ""
diff --git a/editor/translations/si.po b/editor/translations/si.po
index 4d252a53d6..141696c00a 100644
--- a/editor/translations/si.po
+++ b/editor/translations/si.po
@@ -756,6 +756,10 @@ msgid "Method in target node must be specified."
msgstr ""
#: editor/connections_dialog.cpp
+msgid "Method name must be a valid identifier."
+msgstr ""
+
+#: editor/connections_dialog.cpp
msgid ""
"Target method not found. Specify a valid method or attach a script to the "
"target node."
diff --git a/editor/translations/sk.po b/editor/translations/sk.po
index a341552d1c..0920487af3 100644
--- a/editor/translations/sk.po
+++ b/editor/translations/sk.po
@@ -756,6 +756,11 @@ msgid "Method in target node must be specified."
msgstr "Metóda v target node-e musí byť špecifikovaná."
#: editor/connections_dialog.cpp
+#, fuzzy
+msgid "Method name must be a valid identifier."
+msgstr "Metóda v target node-e musí byť špecifikovaná."
+
+#: editor/connections_dialog.cpp
msgid ""
"Target method not found. Specify a valid method or attach a script to the "
"target node."
diff --git a/editor/translations/sl.po b/editor/translations/sl.po
index faec304f67..114dce1e63 100644
--- a/editor/translations/sl.po
+++ b/editor/translations/sl.po
@@ -799,6 +799,11 @@ msgstr "Metoda v ciljnem gradniku mora biti navedena!"
#: editor/connections_dialog.cpp
#, fuzzy
+msgid "Method name must be a valid identifier."
+msgstr "Ime ni pravilen identifikator:"
+
+#: editor/connections_dialog.cpp
+#, fuzzy
msgid ""
"Target method not found. Specify a valid method or attach a script to the "
"target node."
diff --git a/editor/translations/sq.po b/editor/translations/sq.po
index 5bcf15eb82..32d08c7bc9 100644
--- a/editor/translations/sq.po
+++ b/editor/translations/sq.po
@@ -744,6 +744,10 @@ msgid "Method in target node must be specified."
msgstr ""
#: editor/connections_dialog.cpp
+msgid "Method name must be a valid identifier."
+msgstr ""
+
+#: editor/connections_dialog.cpp
msgid ""
"Target method not found. Specify a valid method or attach a script to the "
"target node."
diff --git a/editor/translations/sr_Cyrl.po b/editor/translations/sr_Cyrl.po
index 4e7064f00c..01d8c4ca91 100644
--- a/editor/translations/sr_Cyrl.po
+++ b/editor/translations/sr_Cyrl.po
@@ -841,6 +841,11 @@ msgstr "Метода у циљаном чвору мора бити наведе
#: editor/connections_dialog.cpp
#, fuzzy
+msgid "Method name must be a valid identifier."
+msgstr "Име није важећи идентификатор:"
+
+#: editor/connections_dialog.cpp
+#, fuzzy
msgid ""
"Target method not found. Specify a valid method or attach a script to the "
"target node."
diff --git a/editor/translations/sr_Latn.po b/editor/translations/sr_Latn.po
index e62d152c45..fe13877f42 100644
--- a/editor/translations/sr_Latn.po
+++ b/editor/translations/sr_Latn.po
@@ -765,6 +765,10 @@ msgid "Method in target node must be specified."
msgstr ""
#: editor/connections_dialog.cpp
+msgid "Method name must be a valid identifier."
+msgstr ""
+
+#: editor/connections_dialog.cpp
msgid ""
"Target method not found. Specify a valid method or attach a script to the "
"target node."
diff --git a/editor/translations/sv.po b/editor/translations/sv.po
index e316c74160..ddd0188d5d 100644
--- a/editor/translations/sv.po
+++ b/editor/translations/sv.po
@@ -772,6 +772,11 @@ msgstr "Metod i Mål-Node måste specificeras!"
#: editor/connections_dialog.cpp
#, fuzzy
+msgid "Method name must be a valid identifier."
+msgstr "Metod i Mål-Node måste specificeras!"
+
+#: editor/connections_dialog.cpp
+#, fuzzy
msgid ""
"Target method not found. Specify a valid method or attach a script to the "
"target node."
diff --git a/editor/translations/ta.po b/editor/translations/ta.po
index b8ea8d3538..8f161acfc9 100644
--- a/editor/translations/ta.po
+++ b/editor/translations/ta.po
@@ -757,6 +757,10 @@ msgid "Method in target node must be specified."
msgstr ""
#: editor/connections_dialog.cpp
+msgid "Method name must be a valid identifier."
+msgstr ""
+
+#: editor/connections_dialog.cpp
msgid ""
"Target method not found. Specify a valid method or attach a script to the "
"target node."
diff --git a/editor/translations/te.po b/editor/translations/te.po
index 589064278d..87fb947dd0 100644
--- a/editor/translations/te.po
+++ b/editor/translations/te.po
@@ -736,6 +736,10 @@ msgid "Method in target node must be specified."
msgstr ""
#: editor/connections_dialog.cpp
+msgid "Method name must be a valid identifier."
+msgstr ""
+
+#: editor/connections_dialog.cpp
msgid ""
"Target method not found. Specify a valid method or attach a script to the "
"target node."
diff --git a/editor/translations/th.po b/editor/translations/th.po
index db7fd6adea..3af6fde5a0 100644
--- a/editor/translations/th.po
+++ b/editor/translations/th.po
@@ -744,6 +744,11 @@ msgid "Method in target node must be specified."
msgstr "ต้องระบุเมธอดในโหนดเป้าหมาย"
#: editor/connections_dialog.cpp
+#, fuzzy
+msgid "Method name must be a valid identifier."
+msgstr "ไม่สามารถใช้ชื่อนี้ได้:"
+
+#: editor/connections_dialog.cpp
msgid ""
"Target method not found. Specify a valid method or attach a script to the "
"target node."
diff --git a/editor/translations/tr.po b/editor/translations/tr.po
index 277cc2c807..27886e1d4d 100644
--- a/editor/translations/tr.po
+++ b/editor/translations/tr.po
@@ -798,6 +798,11 @@ msgid "Method in target node must be specified."
msgstr "Hedef düğümdeki metod tanımlanmalı."
#: editor/connections_dialog.cpp
+#, fuzzy
+msgid "Method name must be a valid identifier."
+msgstr "Ad doğru bir belirleyici değil:"
+
+#: editor/connections_dialog.cpp
msgid ""
"Target method not found. Specify a valid method or attach a script to the "
"target node."
diff --git a/editor/translations/uk.po b/editor/translations/uk.po
index 75cce04e0e..03990a655e 100644
--- a/editor/translations/uk.po
+++ b/editor/translations/uk.po
@@ -18,7 +18,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Ukrainian (Godot Engine)\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2020-06-15 01:48+0000\n"
+"PO-Revision-Date: 2020-06-25 08:40+0000\n"
"Last-Translator: Yuri Chornoivan <yurchor@ukr.net>\n"
"Language-Team: Ukrainian <https://hosted.weblate.org/projects/godot-engine/"
"godot/uk/>\n"
@@ -28,7 +28,7 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
-"X-Generator: Weblate 4.1-dev\n"
+"X-Generator: Weblate 4.2-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -773,6 +773,10 @@ msgid "Method in target node must be specified."
msgstr "Має бути вказано метод у цільовому вузлі."
#: editor/connections_dialog.cpp
+msgid "Method name must be a valid identifier."
+msgstr "Назва методу має бути коректним ідентифікатором."
+
+#: editor/connections_dialog.cpp
msgid ""
"Target method not found. Specify a valid method or attach a script to the "
"target node."
@@ -1976,7 +1980,7 @@ msgstr "Властивості теми"
#: editor/editor_help.cpp
msgid "Enumerations"
-msgstr "Перелічуваний"
+msgstr "Переліки"
#: editor/editor_help.cpp
msgid "Constants"
diff --git a/editor/translations/ur_PK.po b/editor/translations/ur_PK.po
index 10558ad98e..6985cbdc39 100644
--- a/editor/translations/ur_PK.po
+++ b/editor/translations/ur_PK.po
@@ -746,6 +746,10 @@ msgid "Method in target node must be specified."
msgstr ""
#: editor/connections_dialog.cpp
+msgid "Method name must be a valid identifier."
+msgstr ""
+
+#: editor/connections_dialog.cpp
msgid ""
"Target method not found. Specify a valid method or attach a script to the "
"target node."
diff --git a/editor/translations/vi.po b/editor/translations/vi.po
index fe846d5e08..ff214a7091 100644
--- a/editor/translations/vi.po
+++ b/editor/translations/vi.po
@@ -763,6 +763,11 @@ msgid "Method in target node must be specified."
msgstr "Phương thức trong nút đích phải được chỉ định."
#: editor/connections_dialog.cpp
+#, fuzzy
+msgid "Method name must be a valid identifier."
+msgstr "Phương thức trong nút đích phải được chỉ định."
+
+#: editor/connections_dialog.cpp
msgid ""
"Target method not found. Specify a valid method or attach a script to the "
"target node."
diff --git a/editor/translations/zh_CN.po b/editor/translations/zh_CN.po
index 5dc2b5948f..f9dc64aea2 100644
--- a/editor/translations/zh_CN.po
+++ b/editor/translations/zh_CN.po
@@ -64,12 +64,14 @@
# binotaliu <binota@protonmail.ch>, 2020.
# BinotaLIU <binota@protonmail.ch>, 2020.
# Tim Bao <honiebao@gmail.com>, 2020.
+# UnluckyNinja <unluckyninja1994@gmail.com>, 2020.
+# 无双流 <1257678024@qq.com>, 2020.
msgid ""
msgstr ""
"Project-Id-Version: Chinese (Simplified) (Godot Engine)\n"
"POT-Creation-Date: 2018-01-20 12:15+0200\n"
-"PO-Revision-Date: 2020-06-15 01:48+0000\n"
-"Last-Translator: Tim Bao <honiebao@gmail.com>\n"
+"PO-Revision-Date: 2020-06-25 08:40+0000\n"
+"Last-Translator: UnluckyNinja <unluckyninja1994@gmail.com>\n"
"Language-Team: Chinese (Simplified) <https://hosted.weblate.org/projects/"
"godot-engine/godot/zh_Hans/>\n"
"Language: zh_CN\n"
@@ -77,7 +79,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n"
-"X-Generator: Weblate 4.1-dev\n"
+"X-Generator: Weblate 4.2-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -806,6 +808,10 @@ msgid "Method in target node must be specified."
msgstr "必须指定目标节点的方法。"
#: editor/connections_dialog.cpp
+msgid "Method name must be a valid identifier."
+msgstr "方法名称必须是一个有效的标识符。"
+
+#: editor/connections_dialog.cpp
msgid ""
"Target method not found. Specify a valid method or attach a script to the "
"target node."
@@ -2438,6 +2444,8 @@ msgid ""
"The current scene has unsaved changes.\n"
"Reload the saved scene anyway? This action cannot be undone."
msgstr ""
+"当前场景有未保存的更改。\n"
+"是否重新加载保存的场景? 此操作无法撤消。"
#: editor/editor_node.cpp
msgid "Quick Run Scene..."
@@ -2655,7 +2663,7 @@ msgstr "下一个标签页"
#: editor/editor_node.cpp
msgid "Previous tab"
-msgstr "上一个标签页"
+msgstr "上一个标签"
#: editor/editor_node.cpp
msgid "Filter Files..."
@@ -2855,7 +2863,7 @@ msgstr "编辑器布局"
#: editor/editor_node.cpp
msgid "Take Screenshot"
-msgstr "截取屏幕"
+msgstr "截屏"
#: editor/editor_node.cpp
msgid "Screenshots are stored in the Editor Data/Settings Folder."
@@ -3339,9 +3347,8 @@ msgid "Did you forget the '_run' method?"
msgstr "您是否遗漏了_run()方法?"
#: editor/editor_spin_slider.cpp
-#, fuzzy
msgid "Hold Ctrl to round to integers. Hold Shift for more precise changes."
-msgstr "按住Ctrl键放置一个Getter节点。按住Shift键放置一个通用签名。"
+msgstr "按住Ctrl键来四舍五入至整数。 按住Shift键获取更精确的变化。"
#: editor/editor_sub_scene.cpp
msgid "Select Node(s) to Import"
@@ -3932,7 +3939,7 @@ msgstr "后处理脚本运行发生错误:"
#: editor/import/resource_importer_scene.cpp
msgid "Did you return a Node-derived object in the `post_import()` method?"
-msgstr ""
+msgstr "你是否在 `post_import()` 方法中返回了 Node 衍生对象?"
#: editor/import/resource_importer_scene.cpp
msgid "Saving..."
@@ -6652,7 +6659,7 @@ msgstr "查找下一项"
#: editor/plugins/script_editor_plugin.cpp
#: editor/plugins/script_text_editor.cpp
msgid "Find Previous"
-msgstr "查找上一项"
+msgstr "查找上一个"
#: editor/plugins/script_editor_plugin.cpp
msgid "Filter scripts"
@@ -6844,9 +6851,8 @@ msgid ""
msgstr "未找到方法“%s”(连接于信号“%s”、来自节点“%s”、目标节点“%s”)。"
#: editor/plugins/script_text_editor.cpp
-#, fuzzy
msgid "[Ignore]"
-msgstr "(忽略)"
+msgstr "[忽略]"
#: editor/plugins/script_text_editor.cpp
msgid "Line"
@@ -6935,7 +6941,7 @@ msgstr "切换注释"
#: editor/plugins/script_text_editor.cpp
msgid "Fold/Unfold Line"
-msgstr "折叠/展开当前行"
+msgstr "折叠/展开行"
#: editor/plugins/script_text_editor.cpp
msgid "Fold All Lines"
@@ -6951,7 +6957,7 @@ msgstr "拷贝到下一行"
#: editor/plugins/script_text_editor.cpp
msgid "Complete Symbol"
-msgstr "代码补全"
+msgstr "符号自动补全"
#: editor/plugins/script_text_editor.cpp
msgid "Evaluate Selection"
@@ -6959,7 +6965,7 @@ msgstr "所选内容求值"
#: editor/plugins/script_text_editor.cpp
msgid "Trim Trailing Whitespace"
-msgstr "修剪行后空白"
+msgstr "移除尾部空格"
#: editor/plugins/script_text_editor.cpp
msgid "Convert Indent to Spaces"
@@ -7276,27 +7282,27 @@ msgstr "使用GLES2渲染器时不可用。"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Freelook Left"
-msgstr "自由视图 左"
+msgstr "自由观看向左"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Freelook Right"
-msgstr "自由视图 右"
+msgstr "自由观看向右"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Freelook Forward"
-msgstr "自由视图 前"
+msgstr "自由观看向前"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Freelook Backwards"
-msgstr "自由视图 后"
+msgstr "自由观看向后"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Freelook Up"
-msgstr "自由视图 上"
+msgstr "自由观看向上"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Freelook Down"
-msgstr "自由视图 下"
+msgstr "自由观看向下"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Freelook Speed Modifier"
@@ -7330,6 +7336,11 @@ msgid ""
"Closed eye: Gizmo is hidden.\n"
"Half-open eye: Gizmo is also visible through opaque surfaces (\"x-ray\")."
msgstr ""
+"点击以切换可见状态。\n"
+"\n"
+"睁眼:标志可见。\n"
+"闭眼:标志隐藏。\n"
+"半睁眼:标志也可穿过不透明的表面可见(“X光”)。"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Snap Nodes To Floor"
@@ -7359,11 +7370,11 @@ msgstr "使用吸附"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Bottom View"
-msgstr "底视图"
+msgstr "仰视图。"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Top View"
-msgstr "顶视图"
+msgstr "俯视"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Rear View"
@@ -7371,7 +7382,7 @@ msgstr "后视图"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Front View"
-msgstr "前视图"
+msgstr "正视图"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Left View"
@@ -7383,7 +7394,7 @@ msgstr "右视图"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Switch Perspective/Orthogonal View"
-msgstr "切换投影/正交视图"
+msgstr "切换透视图/正交视图"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Insert Animation Key"
@@ -7399,7 +7410,7 @@ msgstr "聚焦选中项"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Toggle Freelook"
-msgstr "切换自由观察模式"
+msgstr "切换自由观看"
#: editor/plugins/spatial_editor_plugin.cpp
#: editor/plugins/visual_shader_editor_plugin.cpp
@@ -7408,7 +7419,7 @@ msgstr "变换"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Snap Object to Floor"
-msgstr "将对象吸附到地板"
+msgstr "吸附物体到地面"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Transform Dialog..."
@@ -10354,9 +10365,8 @@ msgid "Instance Child Scene"
msgstr "实例化子场景"
#: editor/scene_tree_dock.cpp
-#, fuzzy
msgid "Detach Script"
-msgstr "添加脚本"
+msgstr "分离脚本"
#: editor/scene_tree_dock.cpp
msgid "This operation can't be done on the tree root."
@@ -10519,6 +10529,8 @@ msgid ""
"This is probably because this editor was built with all language modules "
"disabled."
msgstr ""
+"无法附加脚本:没有语言被注册。\n"
+"这可能是因为这个编辑器是在所有语言模块被关闭的状态下被构建的。"
#: editor/scene_tree_dock.cpp
msgid "Add Child Node"
@@ -10567,14 +10579,12 @@ msgid ""
msgstr "实例化场景文件为一个节点,如果没有根节点则创建一个继承自该文件的场景。"
#: editor/scene_tree_dock.cpp
-#, fuzzy
msgid "Attach a new or existing script to the selected node."
msgstr "为选中节点创建或设置脚本。"
#: editor/scene_tree_dock.cpp
-#, fuzzy
msgid "Detach the script from the selected node."
-msgstr "清除选中节点的脚本。"
+msgstr "从选中节点分离脚本。"
#: editor/scene_tree_dock.cpp
msgid "Remote"
@@ -11780,9 +11790,8 @@ msgid "Debug keystore not configured in the Editor Settings nor in the preset."
msgstr "未在编辑器设置或预设中配置调试密钥库。"
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Release keystore incorrectly configured in the export preset."
-msgstr "未在编辑器设置或预设中配置调试密钥库。"
+msgstr "用于发布的密钥存储在导出预设中未被正确设置。"
#: platform/android/export/export.cpp
msgid "Custom build requires a valid Android SDK path in Editor Settings."
@@ -11811,26 +11820,28 @@ msgid ""
"Invalid \"GodotPaymentV3\" module included in the \"android/modules\" "
"project setting (changed in Godot 3.2.2).\n"
msgstr ""
+"“android/modules”项目设置(变更于Godot 3.2.2)中包含了无效模"
+"组“GodotPaymentV3”.\n"
#: platform/android/export/export.cpp
msgid "\"Use Custom Build\" must be enabled to use the plugins."
-msgstr ""
+msgstr "必须启用“使用自定义构建”才能使用插件。"
#: platform/android/export/export.cpp
msgid ""
"\"Degrees Of Freedom\" is only valid when \"Xr Mode\" is \"Oculus Mobile VR"
"\"."
-msgstr ""
+msgstr "“自由度”只有在当“Xr Mode”是“Oculus Mobile VR”时才有效。"
#: platform/android/export/export.cpp
msgid ""
"\"Hand Tracking\" is only valid when \"Xr Mode\" is \"Oculus Mobile VR\"."
-msgstr ""
+msgstr "“手部追踪”只有在当“Xr Mode”是“Oculus Mobile VR”时才有效。"
#: platform/android/export/export.cpp
msgid ""
"\"Focus Awareness\" is only valid when \"Xr Mode\" is \"Oculus Mobile VR\"."
-msgstr ""
+msgstr "“焦点感知”只有在当“Xr Mode”是“Oculus Mobile VR”时才有效。"
#: platform/android/export/export.cpp
msgid ""
diff --git a/editor/translations/zh_HK.po b/editor/translations/zh_HK.po
index 4832307ce5..90c85892f6 100644
--- a/editor/translations/zh_HK.po
+++ b/editor/translations/zh_HK.po
@@ -793,6 +793,10 @@ msgid "Method in target node must be specified."
msgstr ""
#: editor/connections_dialog.cpp
+msgid "Method name must be a valid identifier."
+msgstr ""
+
+#: editor/connections_dialog.cpp
msgid ""
"Target method not found. Specify a valid method or attach a script to the "
"target node."
diff --git a/editor/translations/zh_TW.po b/editor/translations/zh_TW.po
index 22051058ad..129a3fdad4 100644
--- a/editor/translations/zh_TW.po
+++ b/editor/translations/zh_TW.po
@@ -28,7 +28,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2020-06-15 01:48+0000\n"
+"PO-Revision-Date: 2020-06-22 06:40+0000\n"
"Last-Translator: BinotaLIU <me@binota.org>\n"
"Language-Team: Chinese (Traditional) <https://hosted.weblate.org/projects/"
"godot-engine/godot/zh_Hant/>\n"
@@ -37,7 +37,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n"
-"X-Generator: Weblate 4.1-dev\n"
+"X-Generator: Weblate 4.2-dev\n"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -766,6 +766,11 @@ msgid "Method in target node must be specified."
msgstr "必須指定目標節點的方法。"
#: editor/connections_dialog.cpp
+#, fuzzy
+msgid "Method name must be a valid identifier."
+msgstr "名稱不是一個有效的識別符:"
+
+#: editor/connections_dialog.cpp
msgid ""
"Target method not found. Specify a valid method or attach a script to the "
"target node."
@@ -9880,7 +9885,7 @@ msgstr "新增事件"
#: editor/project_settings_editor.cpp
msgid "Button"
-msgstr "Button(按鈕)"
+msgstr "Button (按鈕)"
#: editor/project_settings_editor.cpp
msgid "Left Button."