summaryrefslogtreecommitdiff
path: root/editor/editor_node.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'editor/editor_node.cpp')
-rw-r--r--editor/editor_node.cpp1061
1 files changed, 697 insertions, 364 deletions
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index 8b7014fabe..ec8430e645 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 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 */
@@ -30,21 +30,21 @@
#include "editor_node.h"
-#include "core/bind/core_bind.h"
-#include "core/class_db.h"
+#include "core/config/project_settings.h"
+#include "core/core_bind.h"
#include "core/input/input.h"
#include "core/io/config_file.h"
#include "core/io/image_loader.h"
#include "core/io/resource_loader.h"
#include "core/io/resource_saver.h"
#include "core/io/stream_peer_ssl.h"
-#include "core/message_queue.h"
+#include "core/object/class_db.h"
+#include "core/object/message_queue.h"
#include "core/os/file_access.h"
#include "core/os/keyboard.h"
#include "core/os/os.h"
-#include "core/print_string.h"
-#include "core/project_settings.h"
-#include "core/translation.h"
+#include "core/string/print_string.h"
+#include "core/string/translation.h"
#include "core/version.h"
#include "main/main.h"
#include "scene/gui/center_container.h"
@@ -57,9 +57,10 @@
#include "scene/gui/split_container.h"
#include "scene/gui/tab_container.h"
#include "scene/gui/tabs.h"
-#include "scene/gui/texture_progress.h"
-#include "scene/gui/tool_button.h"
+#include "scene/gui/texture_progress_bar.h"
+#include "scene/main/window.h"
#include "scene/resources/packed_scene.h"
+#include "servers/display_server.h"
#include "servers/navigation_server_2d.h"
#include "servers/navigation_server_3d.h"
#include "servers/physics_server_2d.h"
@@ -86,10 +87,10 @@
#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"
-#include "editor/import/editor_scene_importer_gltf.h"
#include "editor/import/resource_importer_bitmask.h"
#include "editor/import/resource_importer_csv.h"
#include "editor/import/resource_importer_csv_translation.h"
@@ -101,10 +102,10 @@
#include "editor/import/resource_importer_texture.h"
#include "editor/import/resource_importer_texture_atlas.h"
#include "editor/import/resource_importer_wav.h"
+#include "editor/import/scene_importer_mesh_node_3d.h"
#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"
@@ -124,10 +125,13 @@
#include "editor/plugins/cpu_particles_3d_editor_plugin.h"
#include "editor/plugins/curve_editor_plugin.h"
#include "editor/plugins/debugger_editor_plugin.h"
+#include "editor/plugins/editor_debugger_plugin.h"
#include "editor/plugins/editor_preview_plugins.h"
+#include "editor/plugins/font_editor_plugin.h"
#include "editor/plugins/gi_probe_editor_plugin.h"
#include "editor/plugins/gpu_particles_2d_editor_plugin.h"
#include "editor/plugins/gpu_particles_3d_editor_plugin.h"
+#include "editor/plugins/gpu_particles_collision_sdf_editor_plugin.h"
#include "editor/plugins/gradient_editor_plugin.h"
#include "editor/plugins/item_list_editor_plugin.h"
#include "editor/plugins/light_occluder_2d_editor_plugin.h"
@@ -139,6 +143,8 @@
#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/ot_features_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"
@@ -156,6 +162,7 @@
#include "editor/plugins/sprite_frames_editor_plugin.h"
#include "editor/plugins/style_box_editor_plugin.h"
#include "editor/plugins/text_editor.h"
+#include "editor/plugins/texture_3d_editor_plugin.h"
#include "editor/plugins/texture_editor_plugin.h"
#include "editor/plugins/texture_layered_editor_plugin.h"
#include "editor/plugins/texture_region_editor_plugin.h"
@@ -167,18 +174,120 @@
#include "editor/progress_dialog.h"
#include "editor/project_export.h"
#include "editor/project_settings_editor.h"
-#include "editor/pvrtc_compress.h"
#include "editor/quick_open.h"
#include "editor/register_exporters.h"
-#include "editor/run_settings_dialog.h"
#include "editor/settings_config_dialog.h"
-#include "scene/main/window.h"
-#include "servers/display_server.h"
+
#include <stdio.h>
#include <stdlib.h>
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");
@@ -186,6 +295,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++) {
@@ -197,7 +316,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);
@@ -218,7 +337,11 @@ void EditorNode::_update_scene_tabs() {
if (scene_tabs->get_offset_buttons_visible()) {
// move add button to fixed position on the tabbar
if (scene_tab_add->get_parent() == scene_tabs) {
- scene_tab_add->set_position(Point2(0, 0));
+ if (scene_tabs->is_layout_rtl()) {
+ scene_tab_add->set_position(Point2(tabbar_container->get_size().x - scene_tab_add->get_size().x, 0));
+ } else {
+ scene_tab_add->set_position(Point2(0, 0));
+ }
scene_tabs->remove_child(scene_tab_add);
tabbar_container->add_child(scene_tab_add);
tabbar_container->move_child(scene_tab_add, 1);
@@ -233,7 +356,11 @@ void EditorNode::_update_scene_tabs() {
if (scene_tabs->get_tab_count() != 0) {
last_tab = scene_tabs->get_tab_rect(scene_tabs->get_tab_count() - 1);
}
- scene_tab_add->set_position(Point2(last_tab.get_position().x + last_tab.get_size().x + 3, last_tab.get_position().y));
+ if (scene_tabs->is_layout_rtl()) {
+ scene_tab_add->set_position(Point2(last_tab.get_position().x - scene_tab_add->get_size().x - 3, last_tab.get_position().y));
+ } else {
+ scene_tab_add->set_position(Point2(last_tab.get_position().x + last_tab.get_size().x + 3, last_tab.get_position().y));
+ }
}
}
@@ -250,9 +377,9 @@ void EditorNode::_version_control_menu_option(int p_idx) {
void EditorNode::_update_title() {
String appname = ProjectSettings::get_singleton()->get("application/config/name");
- String title = appname.empty() ? String(VERSION_FULL_NAME) : String(VERSION_NAME + String(" - ") + appname);
+ String title = appname.is_empty() ? String(VERSION_FULL_NAME) : String(VERSION_NAME + String(" - ") + appname);
String edited = editor_data.get_edited_scene_root() ? editor_data.get_edited_scene_root()->get_filename() : String();
- if (!edited.empty()) {
+ if (!edited.is_empty()) {
title += " - " + String(edited.get_file());
}
if (unsaved_cache) {
@@ -303,6 +430,74 @@ void EditorNode::_unhandled_input(const Ref<InputEvent> &p_event) {
}
}
+void EditorNode::_update_from_settings() {
+ int current_filter = GLOBAL_GET("rendering/textures/canvas_textures/default_texture_filter");
+ if (current_filter != scene_root->get_default_canvas_item_texture_filter()) {
+ Viewport::DefaultCanvasItemTextureFilter tf = (Viewport::DefaultCanvasItemTextureFilter)current_filter;
+ scene_root->set_default_canvas_item_texture_filter(tf);
+ }
+ int current_repeat = GLOBAL_GET("rendering/textures/canvas_textures/default_texture_repeat");
+ if (current_repeat != scene_root->get_default_canvas_item_texture_repeat()) {
+ Viewport::DefaultCanvasItemTextureRepeat tr = (Viewport::DefaultCanvasItemTextureRepeat)current_repeat;
+ scene_root->set_default_canvas_item_texture_repeat(tr);
+ }
+
+ RS::DOFBokehShape dof_shape = RS::DOFBokehShape(int(GLOBAL_GET("rendering/camera/depth_of_field/depth_of_field_bokeh_shape")));
+ RS::get_singleton()->camera_effects_set_dof_blur_bokeh_shape(dof_shape);
+ RS::DOFBlurQuality dof_quality = RS::DOFBlurQuality(int(GLOBAL_GET("rendering/camera/depth_of_field/depth_of_field_bokeh_quality")));
+ bool dof_jitter = GLOBAL_GET("rendering/camera/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/environment/ssao/quality"))), GLOBAL_GET("rendering/environment/ssao/half_size"), GLOBAL_GET("rendering/environment/ssao/adaptive_target"), GLOBAL_GET("rendering/environment/ssao/blur_passes"), GLOBAL_GET("rendering/environment/ssao/fadeout_from"), GLOBAL_GET("rendering/environment/ssao/fadeout_to"));
+ RS::get_singleton()->screen_space_roughness_limiter_set_active(GLOBAL_GET("rendering/anti_aliasing/screen_space_roughness_limiter/enabled"), GLOBAL_GET("rendering/anti_aliasing/screen_space_roughness_limiter/amount"), GLOBAL_GET("rendering/anti_aliasing/screen_space_roughness_limiter/limit"));
+ bool glow_bicubic = int(GLOBAL_GET("rendering/environment/glow/upscale_mode")) > 0;
+ RS::get_singleton()->environment_glow_set_use_bicubic_upscale(glow_bicubic);
+ bool glow_high_quality = GLOBAL_GET("rendering/environment/glow/use_high_quality");
+ RS::get_singleton()->environment_glow_set_use_high_quality(glow_high_quality);
+ RS::EnvironmentSSRRoughnessQuality ssr_roughness_quality = RS::EnvironmentSSRRoughnessQuality(int(GLOBAL_GET("rendering/environment/screen_space_reflection/roughness_quality")));
+ RS::get_singleton()->environment_set_ssr_roughness_quality(ssr_roughness_quality);
+ RS::SubSurfaceScatteringQuality sss_quality = RS::SubSurfaceScatteringQuality(int(GLOBAL_GET("rendering/environment/subsurface_scattering/subsurface_scattering_quality")));
+ RS::get_singleton()->sub_surface_scattering_set_quality(sss_quality);
+ float sss_scale = GLOBAL_GET("rendering/environment/subsurface_scattering/subsurface_scattering_scale");
+ float sss_depth_scale = GLOBAL_GET("rendering/environment/subsurface_scattering/subsurface_scattering_depth_scale");
+ RS::get_singleton()->sub_surface_scattering_set_scale(sss_scale, sss_depth_scale);
+
+ uint32_t directional_shadow_size = GLOBAL_GET("rendering/shadows/directional_shadow/size");
+ uint32_t directional_shadow_16_bits = GLOBAL_GET("rendering/shadows/directional_shadow/16_bits");
+ RS::get_singleton()->directional_shadow_atlas_set_size(directional_shadow_size, directional_shadow_16_bits);
+
+ RS::ShadowQuality shadows_quality = RS::ShadowQuality(int(GLOBAL_GET("rendering/shadows/shadows/soft_shadow_quality")));
+ RS::get_singleton()->shadows_quality_set(shadows_quality);
+ RS::ShadowQuality directional_shadow_quality = RS::ShadowQuality(int(GLOBAL_GET("rendering/shadows/directional_shadow/soft_shadow_quality")));
+ RS::get_singleton()->directional_shadow_quality_set(directional_shadow_quality);
+ float probe_update_speed = GLOBAL_GET("rendering/lightmapping/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/global_illumination/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/global_illumination/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/global_illumination/gi_probes/quality")));
+ RS::get_singleton()->gi_probe_set_quality(gi_probe_quality);
+ RS::get_singleton()->environment_set_volumetric_fog_volume_size(GLOBAL_GET("rendering/environment/volumetric_fog/volume_size"), GLOBAL_GET("rendering/environment/volumetric_fog/volume_depth"));
+ RS::get_singleton()->environment_set_volumetric_fog_filter_active(bool(GLOBAL_GET("rendering/environment/volumetric_fog/use_filter")));
+ RS::get_singleton()->canvas_set_shadow_texture_size(GLOBAL_GET("rendering/2d/shadow_atlas/size"));
+
+ bool use_half_res_gi = GLOBAL_DEF("rendering/global_illumination/gi/use_half_resolution", false);
+ RS::get_singleton()->gi_set_use_half_resolution(use_half_res_gi);
+
+ bool snap_2d_transforms = GLOBAL_GET("rendering/2d/snap/snap_2d_transforms_to_pixel");
+ scene_root->set_snap_2d_transforms_to_pixel(snap_2d_transforms);
+ bool snap_2d_vertices = GLOBAL_GET("rendering/2d/snap/snap_2d_vertices_to_pixel");
+ scene_root->set_snap_2d_vertices_to_pixel(snap_2d_vertices);
+
+ Viewport::SDFOversize sdf_oversize = Viewport::SDFOversize(int(GLOBAL_GET("rendering/2d/sdf/oversize")));
+ scene_root->set_sdf_oversize(sdf_oversize);
+ Viewport::SDFScale sdf_scale = Viewport::SDFScale(int(GLOBAL_GET("rendering/2d/sdf/scale")));
+ scene_root->set_sdf_scale(sdf_scale);
+
+ float lod_threshold = GLOBAL_GET("rendering/mesh_lod/lod_change/threshold_pixels");
+ scene_root->set_lod_threshold(lod_threshold);
+}
+
void EditorNode::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_PROCESS: {
@@ -341,45 +536,13 @@ void EditorNode::_notification(int p_what) {
editor_selection->update();
- //scene_root->set_size_override(true, Size2(ProjectSettings::get_singleton()->get("display/window/size/width"), ProjectSettings::get_singleton()->get("display/window/size/height")));
-
- { //TODO should only happen on settings changed
- int current_filter = GLOBAL_GET("rendering/canvas_textures/default_texture_filter");
- if (current_filter != scene_root->get_default_canvas_item_texture_filter()) {
- Viewport::DefaultCanvasItemTextureFilter tf = (Viewport::DefaultCanvasItemTextureFilter)current_filter;
- scene_root->set_default_canvas_item_texture_filter(tf);
- }
- int current_repeat = GLOBAL_GET("rendering/canvas_textures/default_texture_repeat");
- if (current_repeat != scene_root->get_default_canvas_item_texture_repeat()) {
- Viewport::DefaultCanvasItemTextureRepeat tr = (Viewport::DefaultCanvasItemTextureRepeat)current_repeat;
- scene_root->set_default_canvas_item_texture_repeat(tr);
- }
+ ResourceImporterTexture::get_singleton()->update_imports();
- RS::DOFBokehShape dof_shape = RS::DOFBokehShape(int(GLOBAL_GET("rendering/quality/depth_of_field/depth_of_field_bokeh_shape")));
- RS::get_singleton()->camera_effects_set_dof_blur_bokeh_shape(dof_shape);
- RS::DOFBlurQuality dof_quality = RS::DOFBlurQuality(int(GLOBAL_GET("rendering/quality/depth_of_field/depth_of_field_bokeh_quality")));
- 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"));
- 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")));
- RS::get_singleton()->environment_set_ssr_roughness_quality(ssr_roughness_quality);
- RS::SubSurfaceScatteringQuality sss_quality = RS::SubSurfaceScatteringQuality(int(GLOBAL_GET("rendering/quality/subsurface_scattering/subsurface_scattering_quality")));
- RS::get_singleton()->sub_surface_scattering_set_quality(sss_quality);
- float sss_scale = GLOBAL_GET("rendering/quality/subsurface_scattering/subsurface_scattering_scale");
- float sss_depth_scale = GLOBAL_GET("rendering/quality/subsurface_scattering/subsurface_scattering_depth_scale");
- RS::get_singleton()->sub_surface_scattering_set_scale(sss_scale, sss_depth_scale);
- RS::ShadowQuality shadows_quality = RS::ShadowQuality(int(GLOBAL_GET("rendering/quality/shadows/soft_shadow_quality")));
- RS::get_singleton()->shadows_quality_set(shadows_quality);
- RS::ShadowQuality directional_shadow_quality = RS::ShadowQuality(int(GLOBAL_GET("rendering/quality/directional_shadow/soft_shadow_quality")));
- 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);
+ if (settings_changed) {
+ _update_from_settings();
+ settings_changed = false;
+ emit_signal("project_settings_changed");
}
-
- ResourceImporterTexture::get_singleton()->update_imports();
} break;
case NOTIFICATION_ENTER_TREE: {
@@ -388,6 +551,8 @@ void EditorNode::_notification(int p_what) {
OS::get_singleton()->set_low_processor_usage_mode_sleep_usec(int(EDITOR_GET("interface/editor/low_processor_mode_sleep_usec")));
get_tree()->get_root()->set_as_audio_listener(false);
get_tree()->get_root()->set_as_audio_listener_2d(false);
+ get_tree()->get_root()->set_snap_2d_transforms_to_pixel(false);
+ get_tree()->get_root()->set_snap_2d_vertices_to_pixel(false);
get_tree()->set_auto_accept_quit(false);
get_tree()->get_root()->connect("files_dropped", callable_mp(this, &EditorNode::_dropped_files));
@@ -430,14 +595,15 @@ 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();
+ _scan_external_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;
@@ -460,8 +626,8 @@ void EditorNode::_notification(int p_what) {
gui_base->add_theme_style_override("panel", gui_base->get_theme_stylebox("Background", "EditorStyles"));
scene_root_parent->add_theme_style_override("panel", gui_base->get_theme_stylebox("Content", "EditorStyles"));
bottom_panel->add_theme_style_override("panel", gui_base->get_theme_stylebox("panel", "TabContainer"));
- scene_tabs->add_theme_style_override("tab_fg", gui_base->get_theme_stylebox("SceneTabFG", "EditorStyles"));
- scene_tabs->add_theme_style_override("tab_bg", gui_base->get_theme_stylebox("SceneTabBG", "EditorStyles"));
+ scene_tabs->add_theme_style_override("tab_selected", gui_base->get_theme_stylebox("SceneTabFG", "EditorStyles"));
+ scene_tabs->add_theme_style_override("tab_unselected", gui_base->get_theme_stylebox("SceneTabBG", "EditorStyles"));
file_menu->add_theme_style_override("hover", gui_base->get_theme_stylebox("MenuHover", "EditorStyles"));
project_menu->add_theme_style_override("hover", gui_base->get_theme_stylebox("MenuHover", "EditorStyles"));
@@ -485,7 +651,7 @@ void EditorNode::_notification(int p_what) {
// update_icons
for (int i = 0; i < singleton->main_editor_buttons.size(); i++) {
- ToolButton *tb = singleton->main_editor_buttons[i];
+ Button *tb = singleton->main_editor_buttons[i];
EditorPlugin *p_editor = singleton->editor_table[i];
Ref<Texture2D> icon = p_editor->get_icon();
@@ -511,8 +677,13 @@ void EditorNode::_notification(int p_what) {
bottom_panel_raise->set_icon(gui_base->get_theme_icon("ExpandBottomDock", "EditorIcons"));
// clear_button->set_icon(gui_base->get_icon("Close", "EditorIcons")); don't have access to that node. needs to become a class property
- dock_tab_move_left->set_icon(theme->get_icon("Back", "EditorIcons"));
- dock_tab_move_right->set_icon(theme->get_icon("Forward", "EditorIcons"));
+ if (gui_base->is_layout_rtl()) {
+ dock_tab_move_left->set_icon(theme->get_icon("Forward", "EditorIcons"));
+ dock_tab_move_right->set_icon(theme->get_icon("Back", "EditorIcons"));
+ } else {
+ dock_tab_move_left->set_icon(theme->get_icon("Back", "EditorIcons"));
+ dock_tab_move_right->set_icon(theme->get_icon("Forward", "EditorIcons"));
+ }
PopupMenu *p = help_menu->get_popup();
p->set_item_icon(p->get_item_index(HELP_SEARCH), gui_base->get_theme_icon("HelpSearch", "EditorIcons"));
@@ -619,18 +790,23 @@ void EditorNode::_fs_changed() {
preset.unref();
}
if (preset.is_null()) {
- export_error = vformat("Invalid export preset name: %s.", preset_name);
+ export_error = vformat(
+ "Invalid export preset name: %s. Make sure `export_presets.cfg` is present in the current directory.",
+ preset_name);
} else {
Ref<EditorExportPlatform> platform = preset->get_platform();
- if (platform.is_null()) {
+ const String export_path = export_defer.path.is_empty() ? preset->get_export_path() : export_defer.path;
+ if (export_path.is_empty()) {
+ export_error = vformat("Export preset '%s' doesn't have a default export path, and none was specified.", preset_name);
+ } else if (platform.is_null()) {
export_error = vformat("Export preset '%s' doesn't have a matching platform.", preset_name);
} else {
Error err = OK;
if (export_defer.pack_only) { // Only export .pck or .zip data pack.
- if (export_defer.path.ends_with(".zip")) {
- err = platform->export_zip(preset, export_defer.debug, export_defer.path);
- } else if (export_defer.path.ends_with(".pck")) {
- err = platform->export_pack(preset, export_defer.debug, export_defer.path);
+ if (export_path.ends_with(".zip")) {
+ err = platform->export_zip(preset, export_defer.debug, export_path);
+ } else if (export_path.ends_with(".pck")) {
+ err = platform->export_pack(preset, export_defer.debug, export_path);
}
} else { // Normal project export.
String config_error;
@@ -639,7 +815,7 @@ void EditorNode::_fs_changed() {
ERR_PRINT(vformat("Cannot export project with preset '%s' due to configuration errors:\n%s", preset_name, config_error));
err = missing_templates ? ERR_FILE_NOT_FOUND : ERR_UNCONFIGURED;
} else {
- err = platform->export_project(preset, export_defer.debug, export_defer.path);
+ err = platform->export_project(preset, export_defer.debug, export_path);
}
}
switch (err) {
@@ -649,7 +825,7 @@ void EditorNode::_fs_changed() {
export_error = vformat("Project export failed for preset '%s', the export template appears to be missing.", preset_name);
break;
case ERR_FILE_BAD_PATH:
- export_error = vformat("Project export failed for preset '%s', the target path '%s' appears to be invalid.", preset_name, export_defer.path);
+ export_error = vformat("Project export failed for preset '%s', the target path '%s' appears to be invalid.", preset_name, export_path);
break;
default:
export_error = vformat("Project export failed with error code %d for preset '%s'.", (int)err, preset_name);
@@ -658,7 +834,7 @@ void EditorNode::_fs_changed() {
}
}
- if (!export_error.empty()) {
+ if (!export_error.is_empty()) {
ERR_PRINT(export_error);
OS::get_singleton()->set_exit_code(EXIT_FAILURE);
}
@@ -717,6 +893,82 @@ void EditorNode::_sources_changed(bool p_exist) {
}
}
+void EditorNode::_scan_external_changes() {
+ disk_changed_list->clear();
+ TreeItem *r = disk_changed_list->create_item();
+ disk_changed_list->set_hide_root(true);
+ bool need_reload = false;
+
+ // Check if any edited scene has changed.
+
+ for (int i = 0; i < editor_data.get_edited_scene_count(); i++) {
+ if (editor_data.get_scene_path(i) == "") {
+ continue;
+ }
+
+ uint64_t last_date = editor_data.get_scene_modified_time(i);
+ uint64_t date = FileAccess::get_modified_time(editor_data.get_scene_path(i));
+
+ if (date > last_date) {
+ TreeItem *ti = disk_changed_list->create_item(r);
+ ti->set_text(0, editor_data.get_scene_path(i).get_file());
+ need_reload = true;
+ }
+ }
+
+ String project_settings_path = ProjectSettings::get_singleton()->get_resource_path().plus_file("project.godot");
+ if (FileAccess::get_modified_time(project_settings_path) > ProjectSettings::get_singleton()->get_last_saved_time()) {
+ TreeItem *ti = disk_changed_list->create_item(r);
+ ti->set_text(0, "project.godot");
+ need_reload = true;
+ }
+
+ if (need_reload) {
+ disk_changed->call_deferred("popup_centered_ratio", 0.5);
+ }
+}
+
+void EditorNode::_resave_scenes(String p_str) {
+ save_all_scenes();
+ ProjectSettings::get_singleton()->save();
+ disk_changed->hide();
+}
+
+void EditorNode::_reload_modified_scenes() {
+ int current_idx = editor_data.get_edited_scene();
+
+ for (int i = 0; i < editor_data.get_edited_scene_count(); i++) {
+ if (editor_data.get_scene_path(i) == "") {
+ continue;
+ }
+
+ uint64_t last_date = editor_data.get_scene_modified_time(i);
+ uint64_t date = FileAccess::get_modified_time(editor_data.get_scene_path(i));
+
+ if (date > last_date) {
+ String filename = editor_data.get_scene_path(i);
+ editor_data.set_edited_scene(i);
+ _remove_edited_scene(false);
+
+ Error err = load_scene(filename, false, false, true, false, true);
+ if (err != OK) {
+ ERR_PRINT(vformat("Failed to load scene: %s", filename));
+ }
+ editor_data.move_edited_scene_to_index(i);
+ }
+ }
+
+ get_undo_redo()->clear_history(false);
+ set_current_scene(current_idx);
+ _update_scene_tabs();
+ disk_changed->hide();
+}
+
+void EditorNode::_reload_project_settings() {
+ ProjectSettings::get_singleton()->setup(ProjectSettings::get_singleton()->get_resource_path(), String(), true);
+ settings_changed = true;
+}
+
void EditorNode::_vp_resized() {
}
@@ -758,7 +1010,7 @@ Error EditorNode::load_resource(const String &p_resource, bool p_ignore_broken_d
dependency_errors.clear();
Error err;
- RES res = ResourceLoader::load(p_resource, "", false, &err);
+ RES res = ResourceLoader::load(p_resource, "", ResourceFormatLoader::CACHE_MODE_REUSE, &err);
ERR_FAIL_COND_V(!res.is_valid(), ERR_CANT_OPEN);
if (!p_ignore_broken_deps && dependency_errors.has(p_resource)) {
@@ -871,8 +1123,8 @@ void EditorNode::save_resource_as(const Ref<Resource> &p_resource, const String
}
file->set_current_path(existing);
}
- file->popup_centered_ratio();
file->set_title(TTR("Save Resource As..."));
+ file->popup_file_dialog();
}
void EditorNode::_menu_option(int p_option) {
@@ -903,19 +1155,19 @@ void EditorNode::_dialog_display_load_error(String p_file, Error p_error) {
if (p_error) {
switch (p_error) {
case ERR_CANT_OPEN: {
- show_accept(vformat(TTR("Can't open '%s'. The file could have been moved or deleted."), p_file.get_file()), TTR("OK"));
+ show_accept(vformat(TTR("Can't open file '%s'. The file could have been moved or deleted."), p_file.get_file()), TTR("OK"));
} break;
case ERR_PARSE_ERROR: {
- show_accept(vformat(TTR("Error while parsing '%s'."), p_file.get_file()), TTR("OK"));
+ show_accept(vformat(TTR("Error while parsing file '%s'."), p_file.get_file()), TTR("OK"));
} break;
case ERR_FILE_CORRUPT: {
- show_accept(vformat(TTR("Unexpected end of file '%s'."), p_file.get_file()), TTR("OK"));
+ show_accept(vformat(TTR("Scene file '%s' appears to be invalid/corrupt."), p_file.get_file()), TTR("OK"));
} break;
case ERR_FILE_NOT_FOUND: {
- show_accept(vformat(TTR("Missing '%s' or its dependencies."), p_file.get_file()), TTR("OK"));
+ show_accept(vformat(TTR("Missing file '%s' or one its dependencies."), p_file.get_file()), TTR("OK"));
} break;
default: {
- show_accept(vformat(TTR("Error while loading '%s'."), p_file.get_file()), TTR("OK"));
+ show_accept(vformat(TTR("Error while loading file '%s'."), p_file.get_file()), TTR("OK"));
} break;
}
}
@@ -1102,23 +1354,31 @@ 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) {
- img = scene_root->get_texture()->get_data();
+ // 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) {
+ Ref<ViewportTexture> viewport_texture = scene_root->get_texture();
+ if (viewport_texture->get_width() > 0 && viewport_texture->get_height() > 0) {
+ img = viewport_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_valid() && !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()) {
+ if (img.is_valid() && img->get_width() > 0 && img->get_height() > 0) {
img = img->duplicate();
save.step(TTR("Creating Thumbnail"), 2);
@@ -1248,6 +1508,17 @@ int EditorNode::_save_external_resources() {
return saved;
}
+static void _reset_animation_players(Node *p_node, List<Ref<AnimatedValuesBackup>> *r_anim_backups) {
+ for (int i = 0; i < p_node->get_child_count(); i++) {
+ AnimationPlayer *player = Object::cast_to<AnimationPlayer>(p_node->get_child(i));
+ if (player && player->is_reset_on_save_enabled() && player->can_apply_reset()) {
+ Ref<AnimatedValuesBackup> old_values = player->apply_reset();
+ r_anim_backups->push_back(old_values);
+ }
+ _reset_animation_players(p_node->get_child(i), r_anim_backups);
+ }
+}
+
void EditorNode::_save_scene(String p_file, int idx) {
Node *scene = editor_data.get_edited_scene_root(idx);
@@ -1262,6 +1533,8 @@ void EditorNode::_save_scene(String p_file, int idx) {
}
editor_data.apply_changes_in_editors();
+ List<Ref<AnimatedValuesBackup>> anim_backups;
+ _reset_animation_players(scene, &anim_backups);
_save_default_environment();
_set_scene_metadata(p_file, idx);
@@ -1309,6 +1582,11 @@ void EditorNode::_save_scene(String p_file, int idx) {
_save_external_resources();
editor_data.save_editor_external_data();
+
+ for (List<Ref<AnimatedValuesBackup>>::Element *E = anim_backups.front(); E; E = E->next()) {
+ E->get()->restore();
+ }
+
if (err == OK) {
scene->set_filename(ProjectSettings::get_singleton()->localize_path(p_file));
if (idx < 0 || idx == editor_data.get_edited_scene()) {
@@ -1316,6 +1594,7 @@ void EditorNode::_save_scene(String p_file, int idx) {
} else {
editor_data.set_edited_scene_version(0, idx);
}
+ editor_data.set_scene_modified_time(idx, FileAccess::get_modified_time(p_file));
editor_folding.save_scene_folding(scene, p_file);
@@ -1519,10 +1798,10 @@ void EditorNode::_dialog_action(String p_file) {
ObjectID current = editor_history.get_current();
Object *current_obj = current.is_valid() ? ObjectDB::get_instance(current) : nullptr;
ERR_FAIL_COND(!current_obj);
- current_obj->_change_notify();
+ current_obj->notify_property_list_changed();
} break;
case SETTINGS_LAYOUT_SAVE: {
- if (p_file.empty()) {
+ if (p_file.is_empty()) {
return;
}
@@ -1533,7 +1812,7 @@ void EditorNode::_dialog_action(String p_file) {
if (err == ERR_FILE_CANT_OPEN || err == ERR_FILE_NOT_FOUND) {
config.instance(); // new config
} else if (err != OK) {
- show_warning(TTR("Error trying to save layout!"));
+ show_warning(TTR("An error occurred while trying to save the editor layout.\nMake sure the editor's user data path is writable."));
return;
}
@@ -1545,12 +1824,12 @@ void EditorNode::_dialog_action(String p_file) {
_update_layouts_menu();
if (p_file == "Default") {
- show_warning(TTR("Default editor layout overridden."));
+ show_warning(TTR("Default editor layout overridden.\nTo restore the Default layout to its base settings, use the Delete Layout option and delete the Default layout."));
}
} break;
case SETTINGS_LAYOUT_DELETE: {
- if (p_file.empty()) {
+ if (p_file.is_empty()) {
return;
}
@@ -1576,7 +1855,7 @@ void EditorNode::_dialog_action(String p_file) {
_update_layouts_menu();
if (p_file == "Default") {
- show_warning(TTR("Restored default layout to base settings."));
+ show_warning(TTR("Restored the Default layout to its base settings."));
}
} break;
@@ -1633,7 +1912,7 @@ void EditorNode::edit_item(Object *p_object) {
sub_plugins = editor_data.get_subeditors(p_object);
}
- if (!sub_plugins.empty()) {
+ if (!sub_plugins.is_empty()) {
bool same = true;
if (sub_plugins.size() == editor_plugins_over->get_plugins_list().size()) {
for (int i = 0; i < sub_plugins.size(); i++) {
@@ -1661,6 +1940,7 @@ void EditorNode::push_item(Object *p_object, const String &p_property, bool p_in
node_dock->set_node(nullptr);
scene_tree_dock->set_selected(nullptr);
inspector_dock->update(nullptr);
+ _display_top_editors(false);
return;
}
@@ -1809,7 +2089,7 @@ void EditorNode::_edit_current() {
multi_nodes.push_back(node);
}
}
- if (!multi_nodes.empty()) {
+ if (!multi_nodes.is_empty()) {
// Pick the top-most node
multi_nodes.sort_custom<Node::Comparator>();
selected_node = multi_nodes.front()->get();
@@ -1891,13 +2171,13 @@ void EditorNode::_edit_current() {
sub_plugins = editor_data.get_subeditors(current_obj);
}
- if (!sub_plugins.empty()) {
+ if (!sub_plugins.is_empty()) {
_display_top_editors(false);
_set_top_editors(sub_plugins);
_set_editing_top_editors(current_obj);
_display_top_editors(true);
- } else if (!editor_plugins_over->get_plugins_list().empty()) {
+ } else if (!editor_plugins_over->get_plugins_list().is_empty()) {
hide_top_editors();
}
}
@@ -1920,12 +2200,11 @@ 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;
- if (p_current || (editor_data.get_edited_scene_root() && p_custom == editor_data.get_edited_scene_root()->get_filename())) {
+ if (p_current || (editor_data.get_edited_scene_root() && p_custom != String() && p_custom == editor_data.get_edited_scene_root()->get_filename())) {
Node *scene = editor_data.get_edited_scene_root();
if (!scene) {
@@ -1935,7 +2214,10 @@ void EditorNode::_run(bool p_current, const String &p_custom) {
if (scene->get_filename() == "") {
current_option = -1;
- _menu_option_confirm(FILE_SAVE_BEFORE_RUN, false);
+ _menu_option(FILE_SAVE_AS_SCENE);
+ // Set the option to save and run so when the dialog is accepted, the scene runs.
+ current_option = FILE_SAVE_AND_RUN;
+ file->set_title(TTR("Save scene before running..."));
return;
}
@@ -1955,13 +2237,7 @@ void EditorNode::_run(bool p_current, const String &p_custom) {
if (unsaved_cache) {
Node *scene = editor_data.get_edited_scene_root();
- if (scene) { //only autosave if there is a scene obviously
-
- if (scene->get_filename() == "") {
- show_accept(TTR("Current scene was never saved, please save it prior to running."), TTR("OK"));
- return;
- }
-
+ if (scene && scene->get_filename() != "") { // Only autosave if there is a scene and if it has a path.
_save_scene_with_preview(scene->get_filename());
}
}
@@ -1984,7 +2260,7 @@ void EditorNode::_run(bool p_current, const String &p_custom) {
List<String> breakpoints;
editor_data.get_editor_breakpoints(&breakpoints);
- args = ProjectSettings::get_singleton()->get("editor/main_run_args");
+ args = ProjectSettings::get_singleton()->get("editor/run/main_run_args");
skip_breakpoints = EditorDebuggerNode::get_singleton()->is_skip_breakpoints();
EditorDebuggerNode::get_singleton()->start();
@@ -2055,7 +2331,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
file->set_current_path(scene->get_filename());
};
file->set_title(p_option == FILE_OPEN_SCENE ? TTR("Open Scene") : TTR("Open Base Scene"));
- file->popup_centered_ratio();
+ file->popup_file_dialog();
} break;
case FILE_QUICK_OPEN: {
@@ -2074,7 +2350,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
} break;
case FILE_OPEN_PREV: {
- if (previous_scenes.empty()) {
+ if (previous_scenes.is_empty()) {
break;
}
opening_prev = true;
@@ -2107,10 +2383,11 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
case FILE_CLOSE: {
if (!p_confirmed) {
tab_closing = p_option == FILE_CLOSE ? editor_data.get_edited_scene() : _next_unsaved_scene(false);
+ _scene_tab_changed(tab_closing);
if (unsaved_cache || p_option == FILE_CLOSE_ALL_AND_QUIT || p_option == FILE_CLOSE_ALL_AND_RUN_PROJECT_MANAGER) {
String scene_filename = editor_data.get_edited_scene_root(tab_closing)->get_filename();
- save_confirmation->get_ok()->set_text(TTR("Save & Close"));
+ save_confirmation->get_ok_button()->set_text(TTR("Save & Close"));
save_confirmation->set_text(vformat(TTR("Save changes to '%s' before closing?"), scene_filename != "" ? scene_filename : "unsaved scene"));
save_confirmation->popup_centered();
break;
@@ -2176,11 +2453,12 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
}
if (scene->get_filename() != "") {
- file->set_current_path(scene->get_filename());
+ String path = scene->get_filename();
+ file->set_current_path(path);
if (extensions.size()) {
- String ext = scene->get_filename().get_extension().to_lower();
+ String ext = path.get_extension().to_lower();
if (extensions.find(ext) == nullptr) {
- file->set_current_path(scene->get_filename().replacen("." + ext, "." + extensions.front()->get()));
+ file->set_current_path(path.replacen("." + ext, "." + extensions.front()->get()));
}
}
} else {
@@ -2191,7 +2469,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
}
file->set_current_path(existing);
}
- file->popup_centered_ratio();
+ file->popup_file_dialog();
file->set_title(TTR("Save Scene As..."));
} break;
@@ -2199,18 +2477,6 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
case FILE_SAVE_ALL_SCENES: {
_save_all_scenes();
} break;
- case FILE_SAVE_BEFORE_RUN: {
- if (!p_confirmed) {
- confirmation->get_cancel()->set_text(TTR("No"));
- confirmation->get_ok()->set_text(TTR("Yes"));
- confirmation->set_text(TTR("This scene has never been saved. Save before running?"));
- confirmation->popup_centered();
- break;
- }
-
- _menu_option(FILE_SAVE_AS_SCENE);
- _menu_option_confirm(FILE_SAVE_AND_RUN, false);
- } break;
case FILE_EXPORT_PROJECT: {
project_export->popup_export();
@@ -2230,7 +2496,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
file_export_lib->add_filter("*." + E->get());
}
- file_export_lib->popup_centered_ratio();
+ file_export_lib->popup_file_dialog();
file_export_lib->set_title(TTR("Export Mesh Library"));
} break;
@@ -2249,24 +2515,14 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
file_export_lib->add_filter("*." + E->get());
}
- file_export_lib->popup_centered_ratio();
+ file_export_lib->popup_file_dialog();
file_export_lib->set_title(TTR("Export Tile Set"));
} break;
- case FILE_IMPORT_SUBSCENE: {
- if (!editor_data.get_edited_scene_root()) {
- show_accept(TTR("This operation can't be done without a selected node."), TTR("OK"));
- break;
- }
-
- scene_tree_dock->import_subscene();
-
- } break;
-
case FILE_EXTERNAL_OPEN_SCENE: {
if (unsaved_cache && !p_confirmed) {
- confirmation->get_ok()->set_text(TTR("Open"));
+ confirmation->get_ok_button()->set_text(TTR("Open"));
confirmation->set_text(TTR("Current scene not saved. Open anyway?"));
confirmation->popup_centered();
break;
@@ -2322,7 +2578,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
}
if (unsaved_cache && !p_confirmed) {
- confirmation->get_ok()->set_text(TTR("Reload Saved Scene"));
+ confirmation->get_ok_button()->set_text(TTR("Reload Saved Scene"));
confirmation->set_text(
TTR("The current scene has unsaved changes.\nReload the saved scene anyway? This action cannot be undone."));
confirmation->popup_centered();
@@ -2341,20 +2597,18 @@ 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: {
- if (run_custom_filename.empty() || editor_run.get_status() == EditorRun::STATUS_STOP) {
+ if (run_custom_filename.is_empty() || editor_run.get_status() == EditorRun::STATUS_STOP) {
_menu_option_confirm(RUN_STOP, true);
quick_run->popup_dialog("PackedScene", true);
quick_run->set_title(TTR("Quick Run Scene..."));
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;
@@ -2394,14 +2648,9 @@ 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: {
- run_settings_dialog->popup_run_settings();
- } break;
case RUN_SETTINGS: {
project_settings->popup_project_settings();
} break;
@@ -2419,6 +2668,8 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
}
} break;
case RUN_PROJECT_DATA_FOLDER: {
+ // ensure_user_data_dir() to prevent the edge case: "Open Project Data Folder" won't work after the project was renamed in ProjectSettingsEditor unless the project is saved
+ OS::get_singleton()->ensure_user_data_dir();
OS::get_singleton()->shell_open(String("file://") + OS::get_singleton()->get_user_data_dir());
} break;
case FILE_EXPLORE_ANDROID_BUILD_TEMPLATES: {
@@ -2429,15 +2680,8 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
if (!p_confirmed) {
bool save_each = EDITOR_GET("interface/editor/save_each_scene_on_quit");
if (_next_unsaved_scene(!save_each) == -1) {
- bool confirm = EDITOR_GET("interface/editor/quit_confirmation");
- if (confirm) {
- confirmation->get_ok()->set_text(p_option == FILE_QUIT ? TTR("Quit") : TTR("Yes"));
- confirmation->set_text(p_option == FILE_QUIT ? TTR("Exit the editor?") : TTR("Open Project Manager?"));
- confirmation->popup_centered();
- } else {
- _discard_changes();
- break;
- }
+ _discard_changes();
+ break;
} else {
if (save_each) {
_menu_option_confirm(p_option == FILE_QUIT ? FILE_CLOSE_ALL_AND_QUIT : FILE_CLOSE_ALL_AND_RUN_PROJECT_MANAGER, false);
@@ -2449,7 +2693,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
i = _next_unsaved_scene(true, ++i);
}
- save_confirmation->get_ok()->set_text(TTR("Save & Quit"));
+ save_confirmation->get_ok_button()->set_text(TTR("Save & Quit"));
save_confirmation->set_text((p_option == FILE_QUIT ? TTR("Save changes to the following scene(s) before quitting?") : TTR("Save changes the following scene(s) before opening Project Manager?")) + unsaved_scenes);
save_confirmation->popup_centered();
}
@@ -2519,7 +2763,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
file->set_current_path(scene->get_filename());
};
file->set_title(TTR("Pick a Main Scene"));
- file->popup_centered_ratio();
+ file->popup_file_dialog();
} break;
case HELP_SEARCH: {
@@ -2545,7 +2789,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
} break;
case SET_VIDEO_DRIVER_SAVE_AND_RESTART: {
- ProjectSettings::get_singleton()->set("rendering/quality/driver/driver_name", video_driver_request);
+ ProjectSettings::get_singleton()->set("rendering/driver/driver_name", video_driver_request);
ProjectSettings::get_singleton()->save();
save_all_scenes();
@@ -2568,10 +2812,14 @@ void EditorNode::_screenshot(bool p_use_utc) {
}
void EditorNode::_save_screenshot(NodePath p_path) {
- SubViewport *viewport = Object::cast_to<SubViewport>(EditorInterface::get_singleton()->get_editor_viewport()->get_viewport());
- viewport->set_clear_mode(SubViewport::CLEAR_MODE_ONLY_NEXT_FRAME);
- Ref<Image> img = viewport->get_texture()->get_data();
- viewport->set_clear_mode(SubViewport::CLEAR_MODE_ALWAYS);
+ Control *editor_main_control = EditorInterface::get_singleton()->get_editor_main_control();
+ ERR_FAIL_COND_MSG(!editor_main_control, "Cannot get editor main control.");
+ Viewport *viewport = editor_main_control->get_viewport();
+ ERR_FAIL_COND_MSG(!viewport, "Cannot get editor main control viewport.");
+ Ref<ViewportTexture> texture = viewport->get_texture();
+ ERR_FAIL_COND_MSG(texture.is_null(), "Cannot get editor main control viewport texture.");
+ Ref<Image> img = texture->get_data();
+ ERR_FAIL_COND_MSG(img.is_null(), "Cannot get editor main control viewport texture image.");
Error error = img->save_png(p_path);
ERR_FAIL_COND_MSG(error != OK, "Cannot save screenshot to file '" + p_path + "'.");
}
@@ -2583,16 +2831,13 @@ void EditorNode::_tool_menu_option(int p_idx) {
} break;
case TOOLS_CUSTOM: {
if (tool_menu->get_item_submenu(p_idx) == "") {
- Array params = tool_menu->get_item_metadata(p_idx);
-
- Object *handler = ObjectDB::get_instance(params[0]);
- String callback = params[1];
- Variant *ud = &params[2];
+ Callable callback = tool_menu->get_item_metadata(p_idx);
Callable::CallError ce;
+ Variant result;
+ callback.call(nullptr, 0, result, ce);
- handler->call(callback, (const Variant **)&ud, 1, ce);
if (ce.error != Callable::CallError::CALL_OK) {
- String err = Variant::get_call_error_text(handler, callback, (const Variant **)&ud, 1, ce);
+ String err = Variant::get_callable_error_text(callback, nullptr, 0, ce);
ERR_PRINT("Error calling function from tool menu: " + err);
}
} // else it's a submenu so don't do anything.
@@ -2650,6 +2895,10 @@ void EditorNode::_discard_changes(const String &p_str) {
_update_scene_tabs();
if (current_option == FILE_CLOSE_ALL_AND_QUIT || current_option == FILE_CLOSE_ALL_AND_RUN_PROJECT_MANAGER) {
+ // If restore tabs is enabled, reopen the scene that has just been closed, so it's remembered properly.
+ if (bool(EDITOR_GET("interface/scene_tabs/restore_scenes_on_load"))) {
+ _menu_option_confirm(FILE_OPEN_PREV, true);
+ }
if (_next_unsaved_scene(false) == -1) {
current_option = current_option == FILE_CLOSE_ALL_AND_QUIT ? FILE_QUIT : RUN_PROJECT_MANAGER;
_discard_changes();
@@ -2685,20 +2934,19 @@ void EditorNode::_discard_changes(const String &p_str) {
args.push_back(exec.get_base_dir());
args.push_back("--project-manager");
- OS::ProcessID pid = 0;
- Error err = OS::get_singleton()->execute(exec, args, false, &pid);
+ Error err = OS::get_singleton()->create_process(exec, args);
ERR_FAIL_COND(err);
} break;
}
}
void EditorNode::_update_file_menu_opened() {
- Ref<ShortCut> close_scene_sc = ED_GET_SHORTCUT("editor/close_scene");
+ Ref<Shortcut> close_scene_sc = ED_GET_SHORTCUT("editor/close_scene");
close_scene_sc->set_name(TTR("Close Scene"));
- Ref<ShortCut> reopen_closed_scene_sc = ED_GET_SHORTCUT("editor/reopen_closed_scene");
+ Ref<Shortcut> reopen_closed_scene_sc = ED_GET_SHORTCUT("editor/reopen_closed_scene");
reopen_closed_scene_sc->set_name(TTR("Reopen Closed Scene"));
PopupMenu *pop = file_menu->get_popup();
- pop->set_item_disabled(pop->get_item_index(FILE_OPEN_PREV), previous_scenes.empty());
+ pop->set_item_disabled(pop->get_item_index(FILE_OPEN_PREV), previous_scenes.is_empty());
}
void EditorNode::_update_file_menu_closed() {
@@ -2706,8 +2954,8 @@ void EditorNode::_update_file_menu_closed() {
pop->set_item_disabled(pop->get_item_index(FILE_OPEN_PREV), false);
}
-Control *EditorNode::get_viewport() {
- return viewport;
+Control *EditorNode::get_main_control() {
+ return main_control;
}
void EditorNode::_editor_select(int p_which) {
@@ -2774,7 +3022,8 @@ void EditorNode::select_editor_by_name(const String &p_name) {
void EditorNode::add_editor_plugin(EditorPlugin *p_editor, bool p_config_changed) {
if (p_editor->has_main_screen()) {
- ToolButton *tb = memnew(ToolButton);
+ Button *tb = memnew(Button);
+ tb->set_flat(true);
tb->set_toggle_mode(true);
tb->connect("pressed", callable_mp(singleton, &EditorNode::_editor_select), varray(singleton->main_editor_buttons.size()));
tb->set_text(p_editor->get_name());
@@ -2863,8 +3112,7 @@ void EditorNode::set_addon_plugin_enabled(const String &p_addon, bool p_enabled,
Ref<ConfigFile> cf;
cf.instance();
- String addon_path = String("res://addons").plus_file(p_addon).plus_file("plugin.cfg");
- if (!DirAccess::exists(addon_path.get_base_dir())) {
+ if (!DirAccess::exists(p_addon.get_base_dir())) {
ProjectSettings *ps = ProjectSettings::get_singleton();
PackedStringArray enabled_plugins = ps->get("editor_plugins/enabled");
for (int i = 0; i < enabled_plugins.size(); ++i) {
@@ -2878,14 +3126,14 @@ void EditorNode::set_addon_plugin_enabled(const String &p_addon, bool p_enabled,
WARN_PRINT("Addon '" + p_addon + "' failed to load. No directory found. Removing from enabled plugins.");
return;
}
- Error err = cf->load(addon_path);
+ Error err = cf->load(p_addon);
if (err != OK) {
- show_warning(vformat(TTR("Unable to enable addon plugin at: '%s' parsing of config failed."), addon_path));
+ show_warning(vformat(TTR("Unable to enable addon plugin at: '%s' parsing of config failed."), p_addon));
return;
}
if (!cf->has_section_key("plugin", "script")) {
- show_warning(vformat(TTR("Unable to find script field for addon plugin at: 'res://addons/%s'."), p_addon));
+ show_warning(vformat(TTR("Unable to find script field for addon plugin at: '%s'."), p_addon));
return;
}
@@ -2894,7 +3142,7 @@ void EditorNode::set_addon_plugin_enabled(const String &p_addon, bool p_enabled,
// Only try to load the script if it has a name. Else, the plugin has no init script.
if (script_path.length() > 0) {
- script_path = String("res://addons").plus_file(p_addon).plus_file(script_path);
+ script_path = p_addon.get_base_dir().plus_file(script_path);
script = ResourceLoader::load(script_path);
if (script.is_null()) {
@@ -3152,7 +3400,7 @@ int EditorNode::new_scene() {
return idx;
}
-Error EditorNode::load_scene(const String &p_scene, bool p_ignore_broken_deps, bool p_set_inherited, bool p_clear_errors, bool p_force_open_imported) {
+Error EditorNode::load_scene(const String &p_scene, bool p_ignore_broken_deps, bool p_set_inherited, bool p_clear_errors, bool p_force_open_imported, bool p_silent_change_tab) {
if (!is_inside_tree()) {
defer_load_scene = p_scene;
return OK;
@@ -3192,14 +3440,16 @@ Error EditorNode::load_scene(const String &p_scene, bool p_ignore_broken_deps, b
if (!editor_data.get_edited_scene_root() && editor_data.get_edited_scene_count() == 2) {
_remove_edited_scene();
- } else {
+ } else if (!p_silent_change_tab) {
_scene_tab_changed(idx);
+ } else {
+ set_current_scene(idx);
}
dependency_errors.clear();
Error err;
- Ref<PackedScene> sdata = ResourceLoader::load(lpath, "", true, &err);
+ Ref<PackedScene> sdata = ResourceLoader::load(lpath, "", ResourceFormatLoader::CACHE_MODE_REPLACE, &err);
if (!sdata.is_valid()) {
_dialog_display_load_error(lpath, err);
opening_prev = false;
@@ -3254,13 +3504,13 @@ Error EditorNode::load_scene(const String &p_scene, bool p_ignore_broken_deps, b
if (!new_scene) {
sdata.unref();
- _dialog_display_load_error(lpath, ERR_FILE_NOT_FOUND);
+ _dialog_display_load_error(lpath, ERR_FILE_CORRUPT);
opening_prev = false;
if (prev != -1) {
set_current_scene(prev);
editor_data.remove_scene(idx);
}
- return ERR_FILE_NOT_FOUND;
+ return ERR_FILE_CORRUPT;
}
if (p_set_inherited) {
@@ -3403,10 +3653,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);
@@ -3462,6 +3716,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>();
@@ -3475,6 +3730,8 @@ void EditorNode::register_editor_types() {
ClassDB::register_class<EditorFileSystemDirectory>();
ClassDB::register_class<EditorVCSInterface>();
ClassDB::register_virtual_class<ScriptEditor>();
+ ClassDB::register_virtual_class<ScriptEditorBase>();
+ ClassDB::register_class<EditorSyntaxHighlighter>();
ClassDB::register_virtual_class<EditorInterface>();
ClassDB::register_class<EditorExportPlugin>();
ClassDB::register_class<EditorResourceConversionPlugin>();
@@ -3486,11 +3743,15 @@ void EditorNode::register_editor_types() {
ClassDB::register_class<ScriptCreateDialog>();
ClassDB::register_class<EditorFeatureProfile>();
ClassDB::register_class<EditorSpinSlider>();
+ ClassDB::register_class<EditorSceneImporterMesh>();
+ ClassDB::register_class<EditorSceneImporterMeshNode3D>();
+
ClassDB::register_virtual_class<FileSystemDock>();
// FIXME: Is this stuff obsolete, or should it be ported to new APIs?
ClassDB::register_class<EditorScenePostImport>();
//ClassDB::register_type<EditorImportExport>();
+ ClassDB::register_class<EditorDebuggerPlugin>();
}
void EditorNode::unregister_editor_types() {
@@ -3633,24 +3894,16 @@ 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");
- }
+ ERR_FAIL_COND_V_MSG(p_class.is_empty(), nullptr, "Class name cannot be empty.");
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;
@@ -3659,10 +3912,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();
@@ -3677,6 +3928,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");
}
@@ -3782,7 +4037,7 @@ Error EditorNode::export_preset(const String &p_preset, const String &p_path, bo
void EditorNode::show_accept(const String &p_text, const String &p_title) {
current_option = -1;
- accept->get_ok()->set_text(p_title);
+ accept->get_ok_button()->set_text(p_title);
accept->set_text(p_text);
accept->popup_centered();
}
@@ -3834,16 +4089,16 @@ void EditorNode::_dock_make_float() {
window->set_title(dock->get_name());
Panel *p = memnew(Panel);
p->set_mode(Panel::MODE_FOREGROUND);
- p->set_anchors_and_margins_preset(Control::PRESET_WIDE);
+ p->set_anchors_and_offsets_preset(Control::PRESET_WIDE);
window->add_child(p);
MarginContainer *margin = memnew(MarginContainer);
- margin->set_anchors_and_margins_preset(Control::PRESET_WIDE);
+ margin->set_anchors_and_offsets_preset(Control::PRESET_WIDE);
margin->add_theme_constant_override("margin_right", borders.width);
margin->add_theme_constant_override("margin_top", borders.height);
margin->add_theme_constant_override("margin_left", borders.width);
margin->add_theme_constant_override("margin_bottom", borders.height);
window->add_child(margin);
- dock->set_anchors_and_margins_preset(Control::PRESET_WIDE);
+ dock->set_anchors_and_offsets_preset(Control::PRESET_WIDE);
margin->add_child(dock);
window->set_wrap_controls(true);
window->set_size(dock_size);
@@ -4093,6 +4348,7 @@ void EditorNode::_save_docks_to_config(Ref<ConfigFile> p_layout, const String &p
p_layout->set_value(p_section, "dock_filesystem_split", filesystem_dock->get_split_offset());
p_layout->set_value(p_section, "dock_filesystem_display_mode", filesystem_dock->get_display_mode());
+ p_layout->set_value(p_section, "dock_filesystem_file_sort", filesystem_dock->get_file_sort());
p_layout->set_value(p_section, "dock_filesystem_file_list_display_mode", filesystem_dock->get_file_list_display_mode());
for (int i = 0; i < vsplits.size(); i++) {
@@ -4155,7 +4411,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;
@@ -4185,7 +4440,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();
@@ -4289,6 +4543,11 @@ void EditorNode::_load_docks_from_config(Ref<ConfigFile> p_layout, const String
filesystem_dock->set_display_mode(dock_filesystem_display_mode);
}
+ if (p_layout->has_section_key(p_section, "dock_filesystem_file_sort")) {
+ FileSystemDock::FileSortOption dock_filesystem_file_sort = FileSystemDock::FileSortOption(int(p_layout->get_value(p_section, "dock_filesystem_file_sort")));
+ filesystem_dock->set_file_sort(dock_filesystem_file_sort);
+ }
+
if (p_layout->has_section_key(p_section, "dock_filesystem_file_list_display_mode")) {
FileSystemDock::FileListDisplayMode dock_filesystem_file_list_display_mode = FileSystemDock::FileListDisplayMode(int(p_layout->get_value(p_section, "dock_filesystem_file_list_display_mode")));
filesystem_dock->set_file_list_display_mode(dock_filesystem_file_list_display_mode);
@@ -4367,7 +4626,7 @@ bool EditorNode::has_scenes_in_session() {
return false;
}
Array scenes = config->get_value("EditorNode", "open_scenes");
- return !scenes.empty();
+ return !scenes.is_empty();
}
bool EditorNode::ensure_main_scene(bool p_from_native) {
@@ -4403,10 +4662,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();
}
@@ -4452,14 +4736,14 @@ void EditorNode::_layout_menu_option(int p_id) {
case SETTINGS_LAYOUT_SAVE: {
current_option = p_id;
layout_dialog->set_title(TTR("Save Layout"));
- layout_dialog->get_ok()->set_text(TTR("Save"));
+ layout_dialog->get_ok_button()->set_text(TTR("Save"));
layout_dialog->popup_centered();
layout_dialog->set_name_line_enabled(true);
} break;
case SETTINGS_LAYOUT_DELETE: {
current_option = p_id;
layout_dialog->set_title(TTR("Delete Layout"));
- layout_dialog->get_ok()->set_text(TTR("Delete"));
+ layout_dialog->get_ok_button()->set_text(TTR("Delete"));
layout_dialog->popup_centered();
layout_dialog->set_name_line_enabled(false);
} break;
@@ -4498,10 +4782,10 @@ void EditorNode::_scene_tab_closed(int p_tab, int option) {
}
bool unsaved = (p_tab == editor_data.get_edited_scene()) ?
- saved_version != editor_data.get_undo_redo().get_version() :
- editor_data.get_scene_version(p_tab) != 0;
+ saved_version != editor_data.get_undo_redo().get_version() :
+ editor_data.get_scene_version(p_tab) != 0;
if (unsaved) {
- save_confirmation->get_ok()->set_text(TTR("Save & Close"));
+ save_confirmation->get_ok_button()->set_text(TTR("Save & Close"));
save_confirmation->set_text(vformat(TTR("Save changes to '%s' before closing?"), scene->get_filename() != "" ? scene->get_filename() : "unsaved scene"));
save_confirmation->popup_centered();
} else {
@@ -4512,7 +4796,7 @@ void EditorNode::_scene_tab_closed(int p_tab, int option) {
_update_scene_tabs();
}
-void EditorNode::_scene_tab_hover(int p_tab) {
+void EditorNode::_scene_tab_hovered(int p_tab) {
if (!bool(EDITOR_GET("interface/scene_tabs/show_thumbnail_on_hover"))) {
return;
}
@@ -4562,13 +4846,13 @@ void EditorNode::_scene_tab_input(const Ref<InputEvent> &p_input) {
scene_tabs_context_menu->add_item(TTR("Play This Scene"), RUN_PLAY_SCENE);
scene_tabs_context_menu->add_separator();
- Ref<ShortCut> close_tab_sc = ED_GET_SHORTCUT("editor/close_scene");
+ Ref<Shortcut> close_tab_sc = ED_GET_SHORTCUT("editor/close_scene");
close_tab_sc->set_name(TTR("Close Tab"));
scene_tabs_context_menu->add_shortcut(close_tab_sc, FILE_CLOSE);
- Ref<ShortCut> undo_close_tab_sc = ED_GET_SHORTCUT("editor/reopen_closed_scene");
+ Ref<Shortcut> undo_close_tab_sc = ED_GET_SHORTCUT("editor/reopen_closed_scene");
undo_close_tab_sc->set_name(TTR("Undo Close Tab"));
scene_tabs_context_menu->add_shortcut(undo_close_tab_sc, FILE_OPEN_PREV);
- if (previous_scenes.empty()) {
+ if (previous_scenes.is_empty()) {
scene_tabs_context_menu->set_item_disabled(scene_tabs_context_menu->get_item_index(FILE_OPEN_PREV), true);
}
scene_tabs_context_menu->add_item(TTR("Close Other Tabs"), FILE_CLOSE_OTHERS);
@@ -4619,8 +4903,9 @@ void EditorNode::_scene_tab_changed(int p_tab) {
editor_data.get_undo_redo().commit_action();
}
-ToolButton *EditorNode::add_bottom_panel_item(String p_text, Control *p_item) {
- ToolButton *tb = memnew(ToolButton);
+Button *EditorNode::add_bottom_panel_item(String p_text, Control *p_item) {
+ Button *tb = memnew(Button);
+ tb->set_flat(true);
tb->connect("toggled", callable_mp(this, &EditorNode::_bottom_panel_switch), varray(bottom_panel_items.size()));
tb->set_text(p_text);
tb->set_toggle_mode(true);
@@ -4639,16 +4924,6 @@ ToolButton *EditorNode::add_bottom_panel_item(String p_text, Control *p_item) {
return tb;
}
-bool EditorNode::are_bottom_panels_hidden() const {
- for (int i = 0; i < bottom_panel_items.size(); i++) {
- if (bottom_panel_items[i].button->is_pressed()) {
- return false;
- }
- }
-
- return true;
-}
-
void EditorNode::hide_bottom_panel() {
for (int i = 0; i < bottom_panel_items.size(); i++) {
if (bottom_panel_items[i].control->is_visible()) {
@@ -4782,7 +5057,7 @@ void EditorNode::set_distraction_free_mode(bool p_enter) {
}
}
-bool EditorNode::get_distraction_free_mode() const {
+bool EditorNode::is_distraction_free_mode_enabled() const {
return distraction_free->is_pressed();
}
@@ -4900,17 +5175,10 @@ Variant EditorNode::drag_files_and_dirs(const Vector<String> &p_paths, Control *
return drag_data;
}
-void EditorNode::add_tool_menu_item(const String &p_name, Object *p_handler, const String &p_callback, const Variant &p_ud) {
- ERR_FAIL_NULL(p_handler);
+void EditorNode::add_tool_menu_item(const String &p_name, const Callable &p_callback) {
int idx = tool_menu->get_item_count();
tool_menu->add_item(p_name, TOOLS_CUSTOM);
-
- Array parameters;
- parameters.push_back(p_handler->get_instance_id());
- parameters.push_back(p_callback);
- parameters.push_back(p_ud);
-
- tool_menu->set_item_metadata(idx, parameters);
+ tool_menu->set_item_metadata(idx, p_callback);
}
void EditorNode::add_tool_submenu_item(const String &p_name, PopupMenu *p_submenu) {
@@ -4950,9 +5218,7 @@ void EditorNode::_global_menu_new_window(const Variant &p_tag) {
List<String> args;
args.push_back("-p");
String exec = OS::get_singleton()->get_executable_path();
-
- OS::ProcessID pid = 0;
- OS::get_singleton()->execute(exec, args, false, &pid);
+ OS::get_singleton()->create_process(exec, args);
}
}
@@ -4966,7 +5232,6 @@ void EditorNode::_dropped_files(const Vector<String> &p_files, int p_screen) {
void EditorNode::_add_dropped_files_recursive(const Vector<String> &p_files, String to_path) {
DirAccessRef dir = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
- Vector<String> just_copy = String("ttf,otf").split(",");
for (int i = 0; i < p_files.size(); i++) {
String from = p_files[i];
@@ -4989,7 +5254,7 @@ void EditorNode::_add_dropped_files_recursive(const Vector<String> &p_files, Str
next_file = sub_dir->get_next();
}
- if (!sub_files.empty()) {
+ if (!sub_files.is_empty()) {
dir->make_dir(to);
_add_dropped_files_recursive(sub_files, to);
}
@@ -4997,9 +5262,6 @@ void EditorNode::_add_dropped_files_recursive(const Vector<String> &p_files, Str
continue;
}
- if (!ResourceFormatImporter::get_singleton()->can_be_imported(from) && (just_copy.find(from.get_extension().to_lower()) == -1)) {
- continue;
- }
dir->copy(from, to);
}
}
@@ -5009,6 +5271,8 @@ void EditorNode::_file_access_close_error_notify(const String &p_str) {
}
void EditorNode::reload_scene(const String &p_path) {
+ /*
+ * No longer necesary since scenes now reset and reload their internal resource if needed.
//first of all, reload internal textures, materials, meshes, etc. as they might have changed on disk
List<Ref<Resource>> cached;
@@ -5026,6 +5290,8 @@ void EditorNode::reload_scene(const String &p_path) {
to_clear.pop_front();
}
+ */
+
int scene_idx = -1;
for (int i = 0; i < editor_data.get_edited_scene_count(); i++) {
if (editor_data.get_scene_path(i) == p_path) {
@@ -5195,9 +5461,11 @@ void EditorNode::_feature_profile_changed() {
TabContainer *node_tabs = cast_to<TabContainer>(node_dock->get_parent());
TabContainer *fs_tabs = cast_to<TabContainer>(filesystem_dock->get_parent());
if (profile.is_valid()) {
- import_tabs->set_tab_hidden(import_dock->get_index(), profile->is_feature_disabled(EditorFeatureProfile::FEATURE_IMPORT_DOCK));
node_tabs->set_tab_hidden(node_dock->get_index(), profile->is_feature_disabled(EditorFeatureProfile::FEATURE_NODE_DOCK));
- fs_tabs->set_tab_hidden(filesystem_dock->get_index(), profile->is_feature_disabled(EditorFeatureProfile::FEATURE_FILESYSTEM_DOCK));
+ // The Import dock is useless without the FileSystem dock. Ensure the configuration is valid.
+ bool fs_dock_disabled = profile->is_feature_disabled(EditorFeatureProfile::FEATURE_FILESYSTEM_DOCK);
+ fs_tabs->set_tab_hidden(filesystem_dock->get_index(), fs_dock_disabled);
+ import_tabs->set_tab_hidden(import_dock->get_index(), fs_dock_disabled || profile->is_feature_disabled(EditorFeatureProfile::FEATURE_IMPORT_DOCK));
main_editor_buttons[EDITOR_3D]->set_visible(!profile->is_feature_disabled(EditorFeatureProfile::FEATURE_3D));
main_editor_buttons[EDITOR_SCRIPT]->set_visible(!profile->is_feature_disabled(EditorFeatureProfile::FEATURE_SCRIPT));
@@ -5267,6 +5535,7 @@ void EditorNode::_bind_methods() {
ADD_SIGNAL(MethodInfo("request_help_search"));
ADD_SIGNAL(MethodInfo("script_add_function_request", PropertyInfo(Variant::OBJECT, "obj"), PropertyInfo(Variant::STRING, "function"), PropertyInfo(Variant::PACKED_STRING_ARRAY, "args")));
ADD_SIGNAL(MethodInfo("resource_saved", PropertyInfo(Variant::OBJECT, "obj")));
+ ADD_SIGNAL(MethodInfo("project_settings_changed"));
}
static Node *_resource_get_edited_scene() {
@@ -5280,18 +5549,19 @@ void EditorNode::_print_handler(void *p_this, const String &p_string, bool p_err
static void _execute_thread(void *p_ud) {
EditorNode::ExecuteThreadArgs *eta = (EditorNode::ExecuteThreadArgs *)p_ud;
- Error err = OS::get_singleton()->execute(eta->path, eta->args, true, nullptr, &eta->output, &eta->exitcode, true, &eta->execute_output_mutex);
+ Error err = OS::get_singleton()->execute(eta->path, eta->args, &eta->output, &eta->exitcode, true, &eta->execute_output_mutex);
print_verbose("Thread exit status: " + itos(eta->exitcode));
if (err != OK) {
eta->exitcode = err;
}
- eta->done = true;
+ eta->done.set();
+ ;
}
int EditorNode::execute_and_show_output(const String &p_title, const String &p_path, const List<String> &p_arguments, bool p_close_on_ok, bool p_close_on_errors) {
execute_output_dialog->set_title(p_title);
- execute_output_dialog->get_ok()->set_disabled(true);
+ execute_output_dialog->get_ok_button()->set_disabled(true);
execute_outputs->clear();
execute_outputs->set_scroll_follow(true);
execute_output_dialog->popup_centered_ratio();
@@ -5300,15 +5570,12 @@ int EditorNode::execute_and_show_output(const String &p_title, const String &p_p
eta.path = p_path;
eta.args = p_arguments;
eta.exitcode = 255;
- eta.done = false;
int prev_len = 0;
- eta.execute_output_thread = Thread::create(_execute_thread, &eta);
+ eta.execute_output_thread.start(_execute_thread, &eta);
- ERR_FAIL_COND_V(!eta.execute_output_thread, 0);
-
- while (!eta.done) {
+ while (!eta.done.is_set()) {
{
MutexLock lock(eta.execute_output_mutex);
if (prev_len != eta.output.length()) {
@@ -5321,8 +5588,7 @@ int EditorNode::execute_and_show_output(const String &p_title, const String &p_p
OS::get_singleton()->delay_usec(1000);
}
- Thread::wait_to_finish(eta.execute_output_thread);
- memdelete(eta.execute_output_thread);
+ eta.execute_output_thread.wait_to_finish();
execute_outputs->add_text("\nExit Code: " + itos(eta.exitcode));
if (p_close_on_errors && eta.exitcode != 0) {
@@ -5332,11 +5598,15 @@ int EditorNode::execute_and_show_output(const String &p_title, const String &p_p
execute_output_dialog->hide();
}
- execute_output_dialog->get_ok()->set_disabled(false);
+ execute_output_dialog->get_ok_button()->set_disabled(false);
return eta.exitcode;
}
+void EditorNode::notify_settings_changed() {
+ settings_changed = true;
+}
+
EditorNode::EditorNode() {
Input::get_singleton()->set_use_accumulated_input(true);
Resource::_get_local_scene_func = _resource_get_edited_scene;
@@ -5393,46 +5663,57 @@ EditorNode::EditorNode() {
{
int display_scale = EditorSettings::get_singleton()->get("interface/editor/display_scale");
- float custom_display_scale = EditorSettings::get_singleton()->get("interface/editor/custom_display_scale");
switch (display_scale) {
case 0: {
- // Try applying a suitable display scale automatically
- const int screen = DisplayServer::get_singleton()->window_get_current_screen();
+ // Try applying a suitable display scale automatically.
+ // The code below is adapted in `editor/editor_settings.cpp` and `editor/project_manager.cpp`.
+ // Make sure to update those when modifying the code below.
#ifdef OSX_ENABLED
- editor_set_scale(DisplayServer::get_singleton()->screen_get_scale(screen));
+ editor_set_scale(DisplayServer::get_singleton()->screen_get_max_scale());
#else
- editor_set_scale(DisplayServer::get_singleton()->screen_get_dpi(screen) >= 192 && DisplayServer::get_singleton()->screen_get_size(screen).x > 2000 ? 2.0 : 1.0);
+ const int screen = DisplayServer::get_singleton()->window_get_current_screen();
+ float scale;
+ if (DisplayServer::get_singleton()->screen_get_dpi(screen) >= 192 && DisplayServer::get_singleton()->screen_get_size(screen).y >= 1400) {
+ // hiDPI display.
+ scale = 2.0;
+ } else if (DisplayServer::get_singleton()->screen_get_size(screen).y >= 1700) {
+ // Likely a hiDPI display, but we aren't certain due to the returned DPI.
+ // Use an intermediate scale to handle this situation.
+ scale = 1.5;
+ } else if (DisplayServer::get_singleton()->screen_get_size(screen).y <= 800) {
+ // Small loDPI display. Use a smaller display scale so that editor elements fit more easily.
+ // Icons won't look great, but this is better than having editor elements overflow from its window.
+ scale = 0.75;
+ } else {
+ scale = 1.0;
+ }
+
+ editor_set_scale(scale);
#endif
} break;
- case 1: {
+ case 1:
editor_set_scale(0.75);
- } break;
-
- case 2: {
+ break;
+ case 2:
editor_set_scale(1.0);
- } break;
-
- case 3: {
+ break;
+ case 3:
editor_set_scale(1.25);
- } break;
-
- case 4: {
+ break;
+ case 4:
editor_set_scale(1.5);
- } break;
-
- case 5: {
+ break;
+ case 5:
editor_set_scale(1.75);
- } break;
-
- case 6: {
+ break;
+ case 6:
editor_set_scale(2.0);
- } break;
-
- default: {
- editor_set_scale(custom_display_scale);
- } break;
+ break;
+ default:
+ editor_set_scale(EditorSettings::get_singleton()->get("interface/editor/custom_display_scale"));
+ break;
}
}
@@ -5466,10 +5747,10 @@ EditorNode::EditorNode() {
import_cubemap_array->set_mode(ResourceImporterLayeredTexture::MODE_CUBEMAP_ARRAY);
ResourceFormatImporter::get_singleton()->add_importer(import_cubemap_array);
- /*Ref<ResourceImporterLayeredTexture> import_3d;
+ Ref<ResourceImporterLayeredTexture> import_3d;
import_3d.instance();
import_3d->set_mode(ResourceImporterLayeredTexture::MODE_3D);
- ResourceFormatImporter::get_singleton()->add_importer(import_3d);*/
+ ResourceFormatImporter::get_singleton()->add_importer(import_3d);
Ref<ResourceImporterImage> import_image;
import_image.instance();
@@ -5512,10 +5793,6 @@ EditorNode::EditorNode() {
import_obj2.instance();
import_scene->add_importer(import_obj2);
- Ref<EditorSceneImporterGLTF> import_gltf;
- import_gltf.instance();
- import_scene->add_importer(import_gltf);
-
Ref<EditorSceneImporterESCN> import_escn;
import_escn.instance();
import_scene->add_importer(import_escn);
@@ -5540,8 +5817,6 @@ EditorNode::EditorNode() {
EditorInspector::add_inspector_plugin(smp);
}
- _pvrtc_register_compressors();
-
editor_selection = memnew(EditorSelection);
EditorFileSystem *efs = memnew(EditorFileSystem);
@@ -5564,7 +5839,7 @@ EditorNode::EditorNode() {
register_exporters();
- GLOBAL_DEF("editor/main_run_args", "");
+ GLOBAL_DEF("editor/run/main_run_args", "");
ClassDB::set_class_enabled("RootMotionView", true);
@@ -5577,7 +5852,6 @@ EditorNode::EditorNode() {
EDITOR_DEF("run/output/always_close_output_on_stop", true);
EDITOR_DEF("run/auto_save/save_before_running", true);
EDITOR_DEF_RST("interface/editor/save_each_scene_on_quit", true);
- EDITOR_DEF("interface/editor/quit_confirmation", true);
EDITOR_DEF("interface/editor/show_update_spinner", false);
EDITOR_DEF("interface/editor/update_continuously", false);
EDITOR_DEF_RST("interface/scene_tabs/restore_scenes_on_load", false);
@@ -5590,18 +5864,18 @@ EditorNode::EditorNode() {
EDITOR_DEF("interface/inspector/horizontal_vector2_editing", false);
EDITOR_DEF("interface/inspector/horizontal_vector_types_editing", true);
EDITOR_DEF("interface/inspector/open_resources_in_current_inspector", true);
- EDITOR_DEF("interface/inspector/resources_to_open_in_new_inspector", "StandardMaterial3D,ORMMaterial3D,Script,MeshLibrary,TileSet");
+ EDITOR_DEF("interface/inspector/resources_to_open_in_new_inspector", "Script,MeshLibrary,TileSet");
EDITOR_DEF("interface/inspector/default_color_picker_mode", 0);
EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::INT, "interface/inspector/default_color_picker_mode", PROPERTY_HINT_ENUM, "RGB,HSV,RAW", PROPERTY_USAGE_DEFAULT));
EDITOR_DEF("run/auto_save/save_before_running", true);
theme_base = memnew(Control);
add_child(theme_base);
- theme_base->set_anchors_and_margins_preset(Control::PRESET_WIDE);
+ theme_base->set_anchors_and_offsets_preset(Control::PRESET_WIDE);
gui_base = memnew(Panel);
theme_base->add_child(gui_base);
- gui_base->set_anchors_and_margins_preset(Control::PRESET_WIDE);
+ gui_base->set_anchors_and_offsets_preset(Control::PRESET_WIDE);
theme_base->set_theme(theme);
gui_base->set_theme(theme);
@@ -5613,13 +5887,13 @@ EditorNode::EditorNode() {
gui_base->add_child(progress_dialog);
// take up all screen
- gui_base->set_anchor(MARGIN_RIGHT, Control::ANCHOR_END);
- gui_base->set_anchor(MARGIN_BOTTOM, Control::ANCHOR_END);
+ gui_base->set_anchor(SIDE_RIGHT, Control::ANCHOR_END);
+ gui_base->set_anchor(SIDE_BOTTOM, Control::ANCHOR_END);
gui_base->set_end(Point2(0, 0));
main_vbox = memnew(VBoxContainer);
gui_base->add_child(main_vbox);
- main_vbox->set_anchors_and_margins_preset(Control::PRESET_WIDE, Control::PRESET_MODE_MINSIZE, 8);
+ main_vbox->set_anchors_and_offsets_preset(Control::PRESET_WIDE, Control::PRESET_MODE_MINSIZE, 8);
main_vbox->add_theme_constant_override("separation", 8 * EDSCALE);
menu_hb = memnew(HBoxContainer);
@@ -5696,8 +5970,13 @@ EditorNode::EditorNode() {
dock_select_popup->add_child(dock_vb);
HBoxContainer *dock_hb = memnew(HBoxContainer);
- dock_tab_move_left = memnew(ToolButton);
- dock_tab_move_left->set_icon(theme->get_icon("Back", "EditorIcons"));
+ dock_tab_move_left = memnew(Button);
+ dock_tab_move_left->set_flat(true);
+ if (gui_base->is_layout_rtl()) {
+ dock_tab_move_left->set_icon(theme->get_icon("Forward", "EditorIcons"));
+ } else {
+ dock_tab_move_left->set_icon(theme->get_icon("Back", "EditorIcons"));
+ }
dock_tab_move_left->set_focus_mode(Control::FOCUS_NONE);
dock_tab_move_left->connect("pressed", callable_mp(this, &EditorNode::_dock_move_left));
dock_hb->add_child(dock_tab_move_left);
@@ -5708,8 +5987,13 @@ EditorNode::EditorNode() {
dock_label->set_align(Label::ALIGN_CENTER);
dock_hb->add_child(dock_label);
- dock_tab_move_right = memnew(ToolButton);
- dock_tab_move_right->set_icon(theme->get_icon("Forward", "EditorIcons"));
+ dock_tab_move_right = memnew(Button);
+ dock_tab_move_right->set_flat(true);
+ if (gui_base->is_layout_rtl()) {
+ dock_tab_move_right->set_icon(theme->get_icon("Forward", "EditorIcons"));
+ } else {
+ dock_tab_move_right->set_icon(theme->get_icon("Back", "EditorIcons"));
+ }
dock_tab_move_right->set_focus_mode(Control::FOCUS_NONE);
dock_tab_move_right->connect("pressed", callable_mp(this, &EditorNode::_dock_move_right));
@@ -5776,8 +6060,8 @@ EditorNode::EditorNode() {
tab_preview_panel->add_child(tab_preview);
scene_tabs = memnew(Tabs);
- scene_tabs->add_theme_style_override("tab_fg", gui_base->get_theme_stylebox("SceneTabFG", "EditorStyles"));
- scene_tabs->add_theme_style_override("tab_bg", gui_base->get_theme_stylebox("SceneTabBG", "EditorStyles"));
+ scene_tabs->add_theme_style_override("tab_selected", gui_base->get_theme_stylebox("SceneTabFG", "EditorStyles"));
+ scene_tabs->add_theme_style_override("tab_unselected", gui_base->get_theme_stylebox("SceneTabBG", "EditorStyles"));
scene_tabs->set_select_with_rmb(true);
scene_tabs->add_tab("unsaved");
scene_tabs->set_tab_align(Tabs::ALIGN_LEFT);
@@ -5786,8 +6070,8 @@ EditorNode::EditorNode() {
scene_tabs->set_drag_to_rearrange_enabled(true);
scene_tabs->connect("tab_changed", callable_mp(this, &EditorNode::_scene_tab_changed));
scene_tabs->connect("right_button_pressed", callable_mp(this, &EditorNode::_scene_tab_script_edited));
- scene_tabs->connect("tab_close", callable_mp(this, &EditorNode::_scene_tab_closed), varray(SCENE_TAB_CLOSE));
- scene_tabs->connect("tab_hover", callable_mp(this, &EditorNode::_scene_tab_hover));
+ scene_tabs->connect("tab_closed", callable_mp(this, &EditorNode::_scene_tab_closed), varray(SCENE_TAB_CLOSE));
+ scene_tabs->connect("tab_hovered", callable_mp(this, &EditorNode::_scene_tab_hovered));
scene_tabs->connect("mouse_exited", callable_mp(this, &EditorNode::_scene_tab_exit));
scene_tabs->connect("gui_input", callable_mp(this, &EditorNode::_scene_tab_input));
scene_tabs->connect("reposition_active_tab_request", callable_mp(this, &EditorNode::_reposition_active_tab));
@@ -5802,7 +6086,8 @@ EditorNode::EditorNode() {
srt->add_child(tabbar_container);
tabbar_container->add_child(scene_tabs);
- distraction_free = memnew(ToolButton);
+ distraction_free = memnew(Button);
+ distraction_free->set_flat(true);
#ifdef OSX_ENABLED
distraction_free->set_shortcut(ED_SHORTCUT("editor/distraction_free_mode", TTR("Distraction Free Mode"), KEY_MASK_CMD | KEY_MASK_CTRL | KEY_D));
#else
@@ -5813,12 +6098,13 @@ EditorNode::EditorNode() {
distraction_free->set_icon(gui_base->get_theme_icon("DistractionFree", "EditorIcons"));
distraction_free->set_toggle_mode(true);
- scene_tab_add = memnew(ToolButton);
+ scene_tab_add = memnew(Button);
+ scene_tab_add->set_flat(true);
tabbar_container->add_child(scene_tab_add);
tabbar_container->add_child(distraction_free);
scene_tab_add->set_tooltip(TTR("Add a new scene."));
scene_tab_add->set_icon(gui_base->get_theme_icon("Add", "EditorIcons"));
- scene_tab_add->add_theme_color_override("icon_color_normal", Color(0.6f, 0.6f, 0.6f, 0.8f));
+ scene_tab_add->add_theme_color_override("icon_normal_color", Color(0.6f, 0.6f, 0.6f, 0.8f));
scene_tab_add->connect("pressed", callable_mp(this, &EditorNode::_menu_option), make_binds(FILE_NEW_SCENE));
scene_root_parent = memnew(PanelContainer);
@@ -5835,10 +6121,10 @@ EditorNode::EditorNode() {
scene_root->set_disable_input(true);
scene_root->set_as_audio_listener_2d(true);
- viewport = memnew(VBoxContainer);
- viewport->set_v_size_flags(Control::SIZE_EXPAND_FILL);
- viewport->add_theme_constant_override("separation", 0);
- scene_root_parent->add_child(viewport);
+ main_control = memnew(VBoxContainer);
+ main_control->set_v_size_flags(Control::SIZE_EXPAND_FILL);
+ main_control->add_theme_constant_override("separation", 0);
+ scene_root_parent->add_child(main_control);
HBoxContainer *left_menu_hb = memnew(HBoxContainer);
menu_hb->add_child(left_menu_hb);
@@ -5850,7 +6136,8 @@ EditorNode::EditorNode() {
file_menu->add_theme_style_override("hover", gui_base->get_theme_stylebox("MenuHover", "EditorStyles"));
left_menu_hb->add_child(file_menu);
- prev_scene = memnew(ToolButton);
+ prev_scene = memnew(Button);
+ prev_scene->set_flat(true);
prev_scene->set_icon(gui_base->get_theme_icon("PrevScene", "EditorIcons"));
prev_scene->set_tooltip(TTR("Go to previously opened scene."));
prev_scene->set_disabled(true);
@@ -5878,9 +6165,6 @@ EditorNode::EditorNode() {
project_settings = memnew(ProjectSettingsEditor(&editor_data));
gui_base->add_child(project_settings);
- run_settings_dialog = memnew(RunSettingsDialog);
- gui_base->add_child(run_settings_dialog);
-
export_template_manager = memnew(ExportTemplateManager);
gui_base->add_child(export_template_manager);
@@ -5931,8 +6215,8 @@ EditorNode::EditorNode() {
pm_export->connect("id_pressed", callable_mp(this, &EditorNode::_menu_option));
p->add_separator();
- p->add_shortcut(ED_SHORTCUT("editor/undo", TTR("Undo"), KEY_MASK_CMD + KEY_Z), EDIT_UNDO, true);
- p->add_shortcut(ED_SHORTCUT("editor/redo", TTR("Redo"), KEY_MASK_CMD + KEY_MASK_SHIFT + KEY_Z), EDIT_REDO, true);
+ p->add_shortcut(ED_GET_SHORTCUT("ui_undo"), EDIT_UNDO, true);
+ p->add_shortcut(ED_GET_SHORTCUT("ui_redo"), EDIT_REDO, true);
p->add_separator();
p->add_shortcut(ED_SHORTCUT("editor/reload_saved_scene", TTR("Reload Saved Scene")), EDIT_RELOAD_SAVED_SCENE);
@@ -6038,7 +6322,9 @@ EditorNode::EditorNode() {
#else
p->add_shortcut(ED_SHORTCUT("editor/fullscreen_mode", TTR("Toggle Fullscreen"), KEY_MASK_SHIFT | KEY_F11), SETTINGS_TOGGLE_FULLSCREEN);
#endif
-#ifdef WINDOWS_ENABLED
+#if defined(WINDOWS_ENABLED) && defined(WINDOWS_SUBSYSTEM_CONSOLE)
+ // The console can only be toggled if the application was built for the console subsystem,
+ // not the GUI subsystem.
p->add_item(TTR("Toggle System Console"), SETTINGS_TOGGLE_CONSOLE);
#endif
p->add_separator();
@@ -6066,7 +6352,7 @@ EditorNode::EditorNode() {
p = help_menu->get_popup();
p->connect("id_pressed", callable_mp(this, &EditorNode::_menu_option));
- p->add_icon_shortcut(gui_base->get_theme_icon("HelpSearch", "EditorIcons"), ED_SHORTCUT("editor/editor_help", TTR("Search"), KEY_MASK_SHIFT | KEY_F1), HELP_SEARCH);
+ p->add_icon_shortcut(gui_base->get_theme_icon("HelpSearch", "EditorIcons"), ED_SHORTCUT("editor/editor_help", TTR("Search")), HELP_SEARCH);
p->add_separator();
p->add_icon_shortcut(gui_base->get_theme_icon("Instance", "EditorIcons"), ED_SHORTCUT("editor/online_docs", TTR("Online Docs")), HELP_DOCS);
p->add_icon_shortcut(gui_base->get_theme_icon("Instance", "EditorIcons"), ED_SHORTCUT("editor/q&a", TTR("Q&A")), HELP_QA);
@@ -6079,7 +6365,8 @@ EditorNode::EditorNode() {
HBoxContainer *play_hb = memnew(HBoxContainer);
menu_hb->add_child(play_hb);
- play_button = memnew(ToolButton);
+ play_button = memnew(Button);
+ play_button->set_flat(true);
play_hb->add_child(play_button);
play_button->set_toggle_mode(true);
play_button->set_icon(gui_base->get_theme_icon("MainPlay", "EditorIcons"));
@@ -6092,7 +6379,8 @@ EditorNode::EditorNode() {
play_button->set_shortcut(ED_SHORTCUT("editor/play", TTR("Play"), KEY_F5));
#endif
- pause_button = memnew(ToolButton);
+ pause_button = memnew(Button);
+ pause_button->set_flat(true);
pause_button->set_toggle_mode(true);
pause_button->set_icon(gui_base->get_theme_icon("Pause", "EditorIcons"));
pause_button->set_focus_mode(Control::FOCUS_NONE);
@@ -6105,7 +6393,8 @@ EditorNode::EditorNode() {
pause_button->set_shortcut(ED_SHORTCUT("editor/pause_scene", TTR("Pause Scene"), KEY_F7));
#endif
- stop_button = memnew(ToolButton);
+ stop_button = memnew(Button);
+ stop_button->set_flat(true);
play_hb->add_child(stop_button);
stop_button->set_focus_mode(Control::FOCUS_NONE);
stop_button->set_icon(gui_base->get_theme_icon("Stop", "EditorIcons"));
@@ -6122,7 +6411,8 @@ EditorNode::EditorNode() {
play_hb->add_child(run_native);
run_native->connect("native_run", callable_mp(this, &EditorNode::_run_native));
- play_scene_button = memnew(ToolButton);
+ play_scene_button = memnew(Button);
+ play_scene_button->set_flat(true);
play_hb->add_child(play_scene_button);
play_scene_button->set_toggle_mode(true);
play_scene_button->set_focus_mode(Control::FOCUS_NONE);
@@ -6135,7 +6425,8 @@ EditorNode::EditorNode() {
play_scene_button->set_shortcut(ED_SHORTCUT("editor/play_scene", TTR("Play Scene"), KEY_F6));
#endif
- play_custom_scene_button = memnew(ToolButton);
+ play_custom_scene_button = memnew(Button);
+ play_custom_scene_button->set_flat(true);
play_hb->add_child(play_custom_scene_button);
play_custom_scene_button->set_toggle_mode(true);
play_custom_scene_button->set_focus_mode(Control::FOCUS_NONE);
@@ -6157,15 +6448,16 @@ EditorNode::EditorNode() {
video_driver->set_focus_mode(Control::FOCUS_NONE);
video_driver->connect("item_selected", callable_mp(this, &EditorNode::_video_driver_selected));
video_driver->add_theme_font_override("font", gui_base->get_theme_font("bold", "EditorFonts"));
+ video_driver->add_theme_font_size_override("font_size", gui_base->get_theme_font_size("bold_size", "EditorFonts"));
// TODO re-enable when GLES2 is ported
video_driver->set_disabled(true);
right_menu_hb->add_child(video_driver);
#ifndef _MSC_VER
-#warning neeeds to be reimplemented
+#warning needs to be reimplemented
#endif
#if 0
- String video_drivers = ProjectSettings::get_singleton()->get_custom_property_info()["rendering/quality/driver/driver_name"].hint_string;
+ String video_drivers = ProjectSettings::get_singleton()->get_custom_property_info()["rendering/driver/driver_name"].hint_string;
String current_video_driver = OS::get_singleton()->get_video_driver_name(OS::get_singleton()->get_current_video_driver());
video_driver_current = 0;
for (int i = 0; i < video_drivers.get_slice_count(","); i++) {
@@ -6183,7 +6475,7 @@ EditorNode::EditorNode() {
#endif
video_restart_dialog = memnew(ConfirmationDialog);
video_restart_dialog->set_text(TTR("Changing the video driver requires restarting the editor."));
- video_restart_dialog->get_ok()->set_text(TTR("Save & Restart"));
+ video_restart_dialog->get_ok_button()->set_text(TTR("Save & Restart"));
video_restart_dialog->connect("confirmed", callable_mp(this, &EditorNode::_menu_option), varray(SET_VIDEO_DRIVER_SAVE_AND_RESTART));
gui_base->add_child(video_restart_dialog);
@@ -6296,7 +6588,8 @@ EditorNode::EditorNode() {
version_label->set_self_modulate(Color(1, 1, 1, 0.6));
bottom_panel_hb->add_child(version_label);
- bottom_panel_raise = memnew(ToolButton);
+ bottom_panel_raise = memnew(Button);
+ bottom_panel_raise->set_flat(true);
bottom_panel_raise->set_icon(gui_base->get_theme_icon("ExpandBottomDock", "EditorIcons"));
bottom_panel_raise->set_shortcut(ED_SHORTCUT("editor/bottom_panel_expand", TTR("Expand Bottom Panel"), KEY_MASK_SHIFT | KEY_F12));
@@ -6307,13 +6600,16 @@ EditorNode::EditorNode() {
bottom_panel_raise->connect("toggled", callable_mp(this, &EditorNode::_bottom_panel_raise_toggled));
log = memnew(EditorLog);
- ToolButton *output_button = add_bottom_panel_item(TTR("Output"), log);
+ Button *output_button = add_bottom_panel_item(TTR("Output"), log);
log->set_tool_button(output_button);
old_split_ofs = 0;
center_split->connect("resized", callable_mp(this, &EditorNode::_vp_resized));
+ native_shader_source_visualizer = memnew(EditorNativeShaderSourceVisualizer);
+ gui_base->add_child(native_shader_source_visualizer);
+
orphan_resources = memnew(OrphanResourcesDialog);
gui_base->add_child(orphan_resources);
@@ -6322,26 +6618,26 @@ EditorNode::EditorNode() {
confirmation->connect("confirmed", callable_mp(this, &EditorNode::_menu_confirm_current));
save_confirmation = memnew(ConfirmationDialog);
- save_confirmation->add_button(TTR("Don't Save"), DisplayServer::get_singleton()->get_swap_ok_cancel(), "discard");
+ save_confirmation->add_button(TTR("Don't Save"), DisplayServer::get_singleton()->get_swap_cancel_ok(), "discard");
gui_base->add_child(save_confirmation);
save_confirmation->connect("confirmed", callable_mp(this, &EditorNode::_menu_confirm_current));
save_confirmation->connect("custom_action", callable_mp(this, &EditorNode::_discard_changes));
custom_build_manage_templates = memnew(ConfirmationDialog);
custom_build_manage_templates->set_text(TTR("Android build template is missing, please install relevant templates."));
- custom_build_manage_templates->get_ok()->set_text(TTR("Manage Templates"));
+ custom_build_manage_templates->get_ok_button()->set_text(TTR("Manage Templates"));
custom_build_manage_templates->connect("confirmed", callable_mp(this, &EditorNode::_menu_option), varray(SETTINGS_MANAGE_EXPORT_TEMPLATES));
gui_base->add_child(custom_build_manage_templates);
install_android_build_template = memnew(ConfirmationDialog);
install_android_build_template->set_text(TTR("This will set up your project for custom Android builds by installing the source template to \"res://android/build\".\nYou can then apply modifications and build your own custom APK on export (adding modules, changing the AndroidManifest.xml, etc.).\nNote that in order to make custom builds instead of using pre-built APKs, the \"Use Custom Build\" option should be enabled in the Android export preset."));
- install_android_build_template->get_ok()->set_text(TTR("Install"));
+ install_android_build_template->get_ok_button()->set_text(TTR("Install"));
install_android_build_template->connect("confirmed", callable_mp(this, &EditorNode::_menu_confirm_current));
gui_base->add_child(install_android_build_template);
remove_android_build_template = memnew(ConfirmationDialog);
remove_android_build_template->set_text(TTR("The Android build template is already installed in this project and it won't be overwritten.\nRemove the \"res://android/build\" directory manually before attempting this operation again."));
- remove_android_build_template->get_ok()->set_text(TTR("Show in File Manager"));
+ remove_android_build_template->get_ok_button()->set_text(TTR("Show in File Manager"));
remove_android_build_template->connect("confirmed", callable_mp(this, &EditorNode::_menu_option), varray(FILE_EXPLORE_ANDROID_BUILD_TEMPLATES));
gui_base->add_child(remove_android_build_template);
@@ -6394,6 +6690,30 @@ EditorNode::EditorNode() {
//plugin stuff
add_editor_plugin(memnew(DebuggerEditorPlugin(this, debug_menu)));
+
+ disk_changed = memnew(ConfirmationDialog);
+ {
+ VBoxContainer *vbc = memnew(VBoxContainer);
+ disk_changed->add_child(vbc);
+
+ Label *dl = memnew(Label);
+ dl->set_text(TTR("The following files are newer on disk.\nWhat action should be taken?"));
+ vbc->add_child(dl);
+
+ disk_changed_list = memnew(Tree);
+ vbc->add_child(disk_changed_list);
+ disk_changed_list->set_v_size_flags(Control::SIZE_EXPAND_FILL);
+
+ disk_changed->connect("confirmed", callable_mp(this, &EditorNode::_reload_modified_scenes));
+ disk_changed->connect("confirmed", callable_mp(this, &EditorNode::_reload_project_settings));
+ disk_changed->get_ok_button()->set_text(TTR("Reload"));
+
+ disk_changed->add_button(TTR("Resave"), !DisplayServer::get_singleton()->get_swap_cancel_ok(), "resave");
+ disk_changed->connect("custom_action", callable_mp(this, &EditorNode::_resave_scenes));
+ }
+
+ gui_base->add_child(disk_changed);
+
add_editor_plugin(memnew(AnimationPlayerEditorPlugin(this)));
add_editor_plugin(memnew(CanvasItemEditorPlugin(this)));
add_editor_plugin(memnew(Node3DEditorPlugin(this)));
@@ -6455,8 +6775,11 @@ EditorNode::EditorNode() {
add_editor_plugin(memnew(GradientEditorPlugin(this)));
add_editor_plugin(memnew(CollisionShape2DEditorPlugin(this)));
add_editor_plugin(memnew(CurveEditorPlugin(this)));
+ add_editor_plugin(memnew(FontEditorPlugin(this)));
+ add_editor_plugin(memnew(OpenTypeFeaturesEditorPlugin(this)));
add_editor_plugin(memnew(TextureEditorPlugin(this)));
add_editor_plugin(memnew(TextureLayeredEditorPlugin(this)));
+ add_editor_plugin(memnew(Texture3DEditorPlugin(this)));
add_editor_plugin(memnew(AudioStreamEditorPlugin(this)));
add_editor_plugin(memnew(AudioBusesEditorPlugin(audio_bus_editor)));
add_editor_plugin(memnew(Skeleton3DEditorPlugin(this)));
@@ -6464,6 +6787,7 @@ EditorNode::EditorNode() {
add_editor_plugin(memnew(PhysicalBone3DEditorPlugin(this)));
add_editor_plugin(memnew(MeshEditorPlugin(this)));
add_editor_plugin(memnew(MaterialEditorPlugin(this)));
+ add_editor_plugin(memnew(GPUParticlesCollisionSDFEditorPlugin(this)));
for (int i = 0; i < EditorPlugins::get_plugin_count(); i++) {
add_editor_plugin(EditorPlugins::create(i, this));
@@ -6474,6 +6798,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)));
@@ -6525,6 +6850,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>();
@@ -6535,8 +6864,8 @@ EditorNode::EditorNode() {
set_process(true);
open_imported = memnew(ConfirmationDialog);
- open_imported->get_ok()->set_text(TTR("Open Anyway"));
- new_inherited_button = open_imported->add_button(TTR("New Inherited"), !DisplayServer::get_singleton()->get_swap_ok_cancel(), "inherit");
+ open_imported->get_ok_button()->set_text(TTR("Open Anyway"));
+ new_inherited_button = open_imported->add_button(TTR("New Inherited"), !DisplayServer::get_singleton()->get_swap_cancel_ok(), "inherit");
open_imported->connect("confirmed", callable_mp(this, &EditorNode::_open_imported));
open_imported->connect("custom_action", callable_mp(this, &EditorNode::_inherit_imported));
gui_base->add_child(open_imported);
@@ -6568,6 +6897,7 @@ EditorNode::EditorNode() {
gui_base->add_child(load_error_dialog);
execute_outputs = memnew(RichTextLabel);
+ execute_outputs->set_selection_enabled(true);
execute_output_dialog = memnew(AcceptDialog);
execute_output_dialog->add_child(execute_outputs);
execute_output_dialog->set_title("");
@@ -6584,7 +6914,7 @@ EditorNode::EditorNode() {
pick_main_scene = memnew(ConfirmationDialog);
gui_base->add_child(pick_main_scene);
- pick_main_scene->get_ok()->set_text(TTR("Select"));
+ pick_main_scene->get_ok_button()->set_text(TTR("Select"));
pick_main_scene->connect("confirmed", callable_mp(this, &EditorNode::_menu_option), varray(SETTINGS_PICK_MAIN_SCENE));
for (int i = 0; i < _init_callbacks.size(); i++) {
@@ -6612,14 +6942,16 @@ EditorNode::EditorNode() {
ED_SHORTCUT("editor/editor_2d", TTR("Open 2D Editor"), KEY_MASK_ALT | KEY_1);
ED_SHORTCUT("editor/editor_3d", TTR("Open 3D Editor"), KEY_MASK_ALT | KEY_2);
ED_SHORTCUT("editor/editor_script", TTR("Open Script Editor"), KEY_MASK_ALT | KEY_3);
+ ED_SHORTCUT("editor/editor_assetlib", TTR("Open Asset Library"), KEY_MASK_ALT | KEY_4);
ED_SHORTCUT("editor/editor_help", TTR("Search Help"), KEY_MASK_ALT | KEY_SPACE);
#else
- ED_SHORTCUT("editor/editor_2d", TTR("Open 2D Editor"), KEY_F1);
- ED_SHORTCUT("editor/editor_3d", TTR("Open 3D Editor"), KEY_F2);
- ED_SHORTCUT("editor/editor_script", TTR("Open Script Editor"), KEY_F3); //hack needed for script editor F3 search to work :) Assign like this or don't use F3
- ED_SHORTCUT("editor/editor_help", TTR("Search Help"), KEY_MASK_SHIFT | KEY_F1);
+ // Use the Ctrl modifier so F2 can be used to rename nodes in the scene tree dock.
+ ED_SHORTCUT("editor/editor_2d", TTR("Open 2D Editor"), KEY_MASK_CTRL | KEY_F1);
+ ED_SHORTCUT("editor/editor_3d", TTR("Open 3D Editor"), KEY_MASK_CTRL | KEY_F2);
+ ED_SHORTCUT("editor/editor_script", TTR("Open Script Editor"), KEY_MASK_CTRL | KEY_F3);
+ ED_SHORTCUT("editor/editor_assetlib", TTR("Open Asset Library"), KEY_MASK_CTRL | KEY_F4);
+ ED_SHORTCUT("editor/editor_help", TTR("Search Help"), KEY_F1);
#endif
- ED_SHORTCUT("editor/editor_assetlib", TTR("Open Asset Library"));
ED_SHORTCUT("editor/editor_next", TTR("Open the next Editor"));
ED_SHORTCUT("editor/editor_prev", TTR("Open the previous Editor"));
@@ -6636,6 +6968,7 @@ EditorNode::EditorNode() {
EditorNode::~EditorNode() {
EditorInspector::cleanup_plugins();
+ EditorTranslationParser::get_singleton()->clean_parsers();
remove_print_handler(&print_handler);
memdelete(EditorHelp::get_doc_data());
@@ -6724,8 +7057,8 @@ void EditorPluginList::remove_plugin(EditorPlugin *p_plugin) {
plugins_list.erase(p_plugin);
}
-bool EditorPluginList::empty() {
- return plugins_list.empty();
+bool EditorPluginList::is_empty() {
+ return plugins_list.is_empty();
}
void EditorPluginList::clear() {