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.cpp126
1 files changed, 81 insertions, 45 deletions
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index 8ee82888f3..b1b26e4c74 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -110,9 +110,11 @@
#include "editor/export/export_template_manager.h"
#include "editor/export/project_export.h"
#include "editor/filesystem_dock.h"
+#include "editor/history_dock.h"
#include "editor/import/audio_stream_import_settings.h"
#include "editor/import/dynamic_font_import_settings.h"
#include "editor/import/editor_import_collada.h"
+#include "editor/import/editor_import_plugin.h"
#include "editor/import/resource_importer_bitmask.h"
#include "editor/import/resource_importer_bmfont.h"
#include "editor/import/resource_importer_csv_translation.h"
@@ -243,15 +245,11 @@ void EditorNode::disambiguate_filenames(const Vector<String> p_full_paths, Vecto
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("."));
- }
+ scene_name = scene_name.get_basename();
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("."));
- }
+ full_path = full_path.get_basename();
// Normalize trailing slashes when normalizing directory names.
scene_name = scene_name.trim_suffix("/");
@@ -269,7 +267,7 @@ void EditorNode::disambiguate_filenames(const Vector<String> p_full_paths, Vecto
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;
+ parent = (slash_idx >= 0 && parent.length() > 1) ? parent.substr(slash_idx + 1) : parent;
r_filenames.write[set_idx] = parent + r_filenames[set_idx];
}
}
@@ -301,15 +299,11 @@ void EditorNode::disambiguate_filenames(const Vector<String> p_full_paths, Vecto
String path = p_full_paths[E->get()];
// Get rid of file extensions and res:// prefixes.
- if (scene_name.rfind(".") >= 0) {
- scene_name = scene_name.substr(0, scene_name.rfind("."));
- }
+ scene_name = scene_name.get_basename();
if (path.begins_with("res://")) {
path = path.substr(6);
}
- if (path.rfind(".") >= 0) {
- path = path.substr(0, path.rfind("."));
- }
+ path = path.get_basename();
// Normalize trailing slashes when normalizing directory names.
scene_name = scene_name.trim_suffix("/");
@@ -335,7 +329,7 @@ void EditorNode::disambiguate_filenames(const Vector<String> p_full_paths, Vecto
// TODO: This REALLY should be done in a better way than replacing all tabs after almost EVERY action.
void EditorNode::_update_scene_tabs() {
- bool show_rb = EditorSettings::get_singleton()->get("interface/scene_tabs/show_script_button");
+ bool show_rb = EDITOR_GET("interface/scene_tabs/show_script_button");
if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_GLOBAL_MENU)) {
DisplayServer::get_singleton()->global_menu_clear("_dock");
@@ -428,7 +422,7 @@ void EditorNode::_version_control_menu_option(int p_idx) {
}
void EditorNode::_update_title() {
- const String appname = ProjectSettings::get_singleton()->get("application/config/name");
+ const String appname = GLOBAL_GET("application/config/name");
String title = (appname.is_empty() ? TTR("Unnamed Project") : appname);
const String edited = editor_data.get_edited_scene_root() ? editor_data.get_edited_scene_root()->get_scene_file_path() : String();
if (!edited.is_empty()) {
@@ -543,7 +537,7 @@ void EditorNode::_update_from_settings() {
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);
+ bool use_half_res_gi = GLOBAL_GET("rendering/global_illumination/gi/use_half_resolution");
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");
@@ -635,7 +629,7 @@ void EditorNode::_notification(int p_what) {
update_spinner_step_frame = frame + 1;
// Update the icon itself only when the spinner is visible.
- if (EditorSettings::get_singleton()->get("interface/editor/show_update_spinner")) {
+ if (EDITOR_GET("interface/editor/show_update_spinner")) {
update_spinner->set_icon(gui_base->get_theme_icon("Progress" + itos(update_spinner_step + 1), SNAME("EditorIcons")));
}
}
@@ -700,7 +694,7 @@ void EditorNode::_notification(int p_what) {
_initializing_plugins = true;
Vector<String> addons;
if (ProjectSettings::get_singleton()->has_setting("editor_plugins/enabled")) {
- addons = ProjectSettings::get_singleton()->get("editor_plugins/enabled");
+ addons = GLOBAL_GET("editor_plugins/enabled");
}
for (int i = 0; i < addons.size(); i++) {
@@ -847,7 +841,7 @@ void EditorNode::_notification(int p_what) {
HashSet<String> updated_textfile_extensions;
bool extensions_match = true;
- const Vector<String> textfile_ext = ((String)(EditorSettings::get_singleton()->get("docks/filesystem/textfile_extensions"))).split(",", false);
+ const Vector<String> textfile_ext = ((String)(EDITOR_GET("docks/filesystem/textfile_extensions"))).split(",", false);
for (const String &E : textfile_ext) {
updated_textfile_extensions.insert(E);
if (extensions_match && !textfile_extensions.has(E)) {
@@ -866,9 +860,9 @@ void EditorNode::_notification(int p_what) {
}
void EditorNode::_update_update_spinner() {
- update_spinner->set_visible(EditorSettings::get_singleton()->get("interface/editor/show_update_spinner"));
+ update_spinner->set_visible(EDITOR_GET("interface/editor/show_update_spinner"));
- const bool update_continuously = EditorSettings::get_singleton()->get("interface/editor/update_continuously");
+ const bool update_continuously = EDITOR_GET("interface/editor/update_continuously");
PopupMenu *update_popup = update_spinner->get_popup();
update_popup->set_item_checked(update_popup->get_item_index(SETTINGS_UPDATE_CONTINUOUSLY), update_continuously);
update_popup->set_item_checked(update_popup->get_item_index(SETTINGS_UPDATE_WHEN_CHANGED), !update_continuously);
@@ -1273,7 +1267,7 @@ void EditorNode::edit_node(Node *p_node) {
void EditorNode::save_resource_in_path(const Ref<Resource> &p_resource, const String &p_path) {
editor_data.apply_changes_in_editors();
int flg = 0;
- if (EditorSettings::get_singleton()->get("filesystem/on_save/compress_binary_resources")) {
+ if (EDITOR_GET("filesystem/on_save/compress_binary_resources")) {
flg |= ResourceSaver::FLAG_COMPRESS;
}
@@ -1640,7 +1634,7 @@ void EditorNode::_save_scene_with_preview(String p_file, int p_idx) {
save.step(TTR("Creating Thumbnail"), 2);
save.step(TTR("Creating Thumbnail"), 3);
- int preview_size = EditorSettings::get_singleton()->get("filesystem/file_dialog/thumbnail_size");
+ int preview_size = EDITOR_GET("filesystem/file_dialog/thumbnail_size");
preview_size *= EDSCALE;
// Consider a square region.
@@ -1701,7 +1695,7 @@ int EditorNode::_save_external_resources() {
// Save external resources and its subresources if any was modified.
int flg = 0;
- if (EditorSettings::get_singleton()->get("filesystem/on_save/compress_binary_resources")) {
+ if (EDITOR_GET("filesystem/on_save/compress_binary_resources")) {
flg |= ResourceSaver::FLAG_COMPRESS;
}
flg |= ResourceSaver::FLAG_REPLACE_SUBRESOURCE_PATHS;
@@ -1770,7 +1764,7 @@ void EditorNode::_save_scene(String p_file, int idx) {
}
if (!scene->get_scene_file_path().is_empty() && _validate_scene_recursive(scene->get_scene_file_path(), scene)) {
- show_accept(TTR("This scene can't be saved because there is a cyclic instancing inclusion.\nPlease resolve it and then attempt to save again."), TTR("OK"));
+ show_accept(TTR("This scene can't be saved because there is a cyclic instance inclusion.\nPlease resolve it and then attempt to save again."), TTR("OK"));
return;
}
@@ -1807,7 +1801,7 @@ void EditorNode::_save_scene(String p_file, int idx) {
}
int flg = 0;
- if (EditorSettings::get_singleton()->get("filesystem/on_save/compress_binary_resources")) {
+ if (EDITOR_GET("filesystem/on_save/compress_binary_resources")) {
flg |= ResourceSaver::FLAG_COMPRESS;
}
flg |= ResourceSaver::FLAG_REPLACE_SUBRESOURCE_PATHS;
@@ -2338,7 +2332,7 @@ void EditorNode::_edit_current(bool p_skip_foreign) {
if (get_edited_scene() && !get_edited_scene()->get_scene_file_path().is_empty()) {
String source_scene = get_edited_scene()->get_scene_file_path();
if (FileAccess::exists(source_scene + ".import")) {
- editable_info = TTR("This scene was imported, so changes to it won't be kept.\nInstancing it or inheriting will allow making changes to it.\nPlease read the documentation relevant to importing scenes to better understand this workflow.");
+ editable_info = TTR("This scene was imported, so changes to it won't be kept.\nInstantiating or inheriting it will allow you to make changes to it.\nPlease read the documentation relevant to importing scenes to better understand this workflow.");
info_is_warning = true;
}
}
@@ -2407,7 +2401,7 @@ void EditorNode::_edit_current(bool p_skip_foreign) {
if (main_plugin && !skip_main_plugin) {
// Special case if use of external editor is true.
Resource *current_res = Object::cast_to<Resource>(current_obj);
- if (main_plugin->get_name() == "Script" && !current_obj->is_class("VisualScript") && current_res && !current_res->is_built_in() && (bool(EditorSettings::get_singleton()->get("text_editor/external/use_external_editor")) || overrides_external_editor(current_obj))) {
+ if (main_plugin->get_name() == "Script" && !current_obj->is_class("VisualScript") && current_res && !current_res->is_built_in() && (bool(EDITOR_GET("text_editor/external/use_external_editor")) || overrides_external_editor(current_obj))) {
if (!changing_scene) {
main_plugin->edit(current_obj);
}
@@ -3105,7 +3099,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
}
String EditorNode::adjust_scene_name_casing(const String &root_name) {
- switch (ProjectSettings::get_singleton()->get("editor/scene/scene_naming").operator int()) {
+ switch (GLOBAL_GET("editor/scene/scene_naming").operator int()) {
case SCENE_NAME_CASING_AUTO:
// Use casing of the root node.
break;
@@ -3125,7 +3119,7 @@ void EditorNode::_screenshot(bool p_use_utc) {
String name = "editor_screenshot_" + Time::get_singleton()->get_datetime_string_from_system(p_use_utc).replace(":", "") + ".png";
NodePath path = String("user://") + name;
_save_screenshot(path);
- if (EditorSettings::get_singleton()->get("interface/editor/automatically_open_screenshots")) {
+ if (EDITOR_GET("interface/editor/automatically_open_screenshots")) {
OS::get_singleton()->shell_open(String("file://") + ProjectSettings::get_singleton()->globalize_path(path));
}
}
@@ -3370,7 +3364,7 @@ void EditorNode::editor_select(int p_which) {
editor_data.get_editor_plugin(i)->notify_main_screen_changed(editor_plugin_screen->get_name());
}
- if (EditorSettings::get_singleton()->get("interface/editor/separate_distraction_mode")) {
+ if (EDITOR_GET("interface/editor/separate_distraction_mode")) {
if (p_which == EDITOR_SCRIPT) {
set_distraction_free_mode(script_distraction_free);
} else {
@@ -3560,6 +3554,14 @@ bool EditorNode::is_addon_plugin_enabled(const String &p_addon) const {
return addon_name_to_plugin.has("res://addons/" + p_addon + "/plugin.cfg");
}
+void EditorNode::set_movie_maker_enabled(bool p_enabled) {
+ write_movie_button->set_pressed(p_enabled);
+}
+
+bool EditorNode::is_movie_maker_enabled() const {
+ return write_movie_button->is_pressed();
+}
+
void EditorNode::_remove_edited_scene(bool p_change_tab) {
int new_index = editor_data.get_edited_scene();
int old_index = new_index;
@@ -3689,6 +3691,7 @@ void EditorNode::_set_main_scene_state(Dictionary p_state, Node *p_for_scene) {
EditorDebuggerNode::get_singleton()->update_live_edit_root();
ScriptEditor::get_singleton()->set_scene_root_script(editor_data.get_scene_root_script(editor_data.get_edited_scene()));
editor_data.notify_edited_scene_changed();
+ emit_signal(SNAME("scene_changed"));
}
bool EditorNode::is_changing_scene() const {
@@ -3990,7 +3993,7 @@ bool EditorNode::is_resource_read_only(Ref<Resource> p_resource, bool p_foreign_
return false;
}
-void EditorNode::request_instance_scene(const String &p_path) {
+void EditorNode::request_instantiate_scene(const String &p_path) {
SceneTreeDock::get_singleton()->instantiate(p_path);
}
@@ -4075,7 +4078,7 @@ void EditorNode::_quick_opened() {
List<String> scene_extensions;
ResourceLoader::get_recognized_extensions_for_type("PackedScene", &scene_extensions);
- if (open_scene_dialog || scene_extensions.find(files[i].get_extension())) {
+ if (open_scene_dialog || scene_extensions.find(files[i].get_extension().to_lower())) {
open_request(res_path);
} else {
load_resource(res_path);
@@ -4171,6 +4174,7 @@ void EditorNode::register_editor_types() {
GDREGISTER_CLASS(EditorScenePostImport);
GDREGISTER_CLASS(EditorCommandPalette);
GDREGISTER_CLASS(EditorDebuggerPlugin);
+ GDREGISTER_ABSTRACT_CLASS(EditorDebuggerSession);
}
void EditorNode::unregister_editor_types() {
@@ -4392,6 +4396,27 @@ Ref<Texture2D> EditorNode::get_class_icon(const String &p_class, const String &p
return nullptr;
}
+bool EditorNode::is_object_of_custom_type(const Object *p_object, const StringName &p_class) {
+ ERR_FAIL_COND_V(!p_object, false);
+
+ Ref<Script> scr = p_object->get_script();
+ if (scr.is_null() && Object::cast_to<Script>(p_object)) {
+ scr = p_object;
+ }
+
+ if (scr.is_valid()) {
+ Ref<Script> base_script = scr;
+ while (base_script.is_valid()) {
+ StringName name = EditorNode::get_editor_data().script_class_get_name(base_script->get_path());
+ if (name == p_class) {
+ return true;
+ }
+ base_script = base_script->get_base_script();
+ }
+ }
+ return false;
+}
+
void EditorNode::progress_add_task(const String &p_task, const String &p_label, int p_steps, bool p_can_cancel) {
if (singleton->cmdline_export_mode) {
print_line(p_task + ": begin: " + p_label + " steps: " + itos(p_steps));
@@ -4534,7 +4559,7 @@ void EditorNode::_dock_floating_close_request(Control *p_control) {
dock_slot[window_slot]->move_child(p_control, MIN((int)window->get_meta("dock_index"), dock_slot[window_slot]->get_tab_count()));
dock_slot[window_slot]->set_current_tab(window->get_meta("dock_index"));
- window->queue_delete();
+ window->queue_free();
_update_dock_containers();
@@ -5111,7 +5136,7 @@ bool EditorNode::has_scenes_in_session() {
bool EditorNode::ensure_main_scene(bool p_from_native) {
pick_main_scene->set_meta("from_native", p_from_native); // Whether from play button or native run.
- String main_scene = GLOBAL_DEF_BASIC("application/run/main_scene", "");
+ String main_scene = GLOBAL_GET("application/run/main_scene");
if (main_scene.is_empty()) {
current_menu_option = -1;
@@ -5178,7 +5203,7 @@ bool EditorNode::is_run_playing() const {
String EditorNode::get_run_playing_scene() const {
String run_filename = editor_run.get_running_scene();
if (run_filename.is_empty() && is_run_playing()) {
- run_filename = GLOBAL_DEF_BASIC("application/run/main_scene", ""); // Must be the main scene then.
+ run_filename = GLOBAL_GET("application/run/main_scene"); // Must be the main scene then.
}
return run_filename;
@@ -5538,7 +5563,7 @@ bool EditorNode::get_docks_visible() const {
}
void EditorNode::_toggle_distraction_free_mode() {
- if (EditorSettings::get_singleton()->get("interface/editor/separate_distraction_mode")) {
+ if (EDITOR_GET("interface/editor/separate_distraction_mode")) {
int screen = -1;
for (int i = 0; i < editor_table.size(); i++) {
if (editor_plugin_screen == editor_table[i]) {
@@ -5738,7 +5763,7 @@ void EditorNode::_global_menu_new_window(const Variant &p_tag) {
}
void EditorNode::_dropped_files(const Vector<String> &p_files) {
- String to_path = ProjectSettings::get_singleton()->globalize_path(FileSystemDock::get_singleton()->get_selected_path());
+ String to_path = ProjectSettings::get_singleton()->globalize_path(FileSystemDock::get_singleton()->get_current_directory());
_add_dropped_files_recursive(p_files, to_path);
@@ -5945,12 +5970,14 @@ void EditorNode::_feature_profile_changed() {
TabContainer *import_tabs = cast_to<TabContainer>(ImportDock::get_singleton()->get_parent());
TabContainer *node_tabs = cast_to<TabContainer>(NodeDock::get_singleton()->get_parent());
TabContainer *fs_tabs = cast_to<TabContainer>(FileSystemDock::get_singleton()->get_parent());
+ TabContainer *history_tabs = cast_to<TabContainer>(history_dock->get_parent());
if (profile.is_valid()) {
node_tabs->set_tab_hidden(node_tabs->get_tab_idx_from_control(NodeDock::get_singleton()), profile->is_feature_disabled(EditorFeatureProfile::FEATURE_NODE_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(fs_tabs->get_tab_idx_from_control(FileSystemDock::get_singleton()), fs_dock_disabled);
import_tabs->set_tab_hidden(import_tabs->get_tab_idx_from_control(ImportDock::get_singleton()), fs_dock_disabled || profile->is_feature_disabled(EditorFeatureProfile::FEATURE_IMPORT_DOCK));
+ history_tabs->set_tab_hidden(history_tabs->get_tab_idx_from_control(history_dock), profile->is_feature_disabled(EditorFeatureProfile::FEATURE_HISTORY_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));
@@ -5966,6 +5993,8 @@ void EditorNode::_feature_profile_changed() {
import_tabs->set_tab_hidden(import_tabs->get_tab_idx_from_control(ImportDock::get_singleton()), false);
node_tabs->set_tab_hidden(node_tabs->get_tab_idx_from_control(NodeDock::get_singleton()), false);
fs_tabs->set_tab_hidden(fs_tabs->get_tab_idx_from_control(FileSystemDock::get_singleton()), false);
+ history_tabs->set_tab_hidden(history_tabs->get_tab_idx_from_control(history_dock), false);
+ history_dock->set_visible(true);
ImportDock::get_singleton()->set_visible(true);
NodeDock::get_singleton()->set_visible(true);
FileSystemDock::get_singleton()->set_visible(true);
@@ -6011,6 +6040,7 @@ void EditorNode::_bind_methods() {
ADD_SIGNAL(MethodInfo("resource_saved", PropertyInfo(Variant::OBJECT, "obj")));
ADD_SIGNAL(MethodInfo("scene_saved", PropertyInfo(Variant::STRING, "path")));
ADD_SIGNAL(MethodInfo("project_settings_changed"));
+ ADD_SIGNAL(MethodInfo("scene_changed"));
}
static Node *_resource_get_edited_scene() {
@@ -6147,7 +6177,7 @@ EditorNode::EditorNode() {
FileAccess::set_backup_save(EDITOR_GET("filesystem/on_save/safe_save_on_backup_then_rename"));
{
- int display_scale = EditorSettings::get_singleton()->get("interface/editor/display_scale");
+ int display_scale = EDITOR_GET("interface/editor/display_scale");
switch (display_scale) {
case 0:
@@ -6173,7 +6203,7 @@ EditorNode::EditorNode() {
editor_set_scale(2.0);
break;
default:
- editor_set_scale(EditorSettings::get_singleton()->get("interface/editor/custom_display_scale"));
+ editor_set_scale(EDITOR_GET("interface/editor/custom_display_scale"));
break;
}
}
@@ -6181,9 +6211,9 @@ EditorNode::EditorNode() {
// Define a minimum window size to prevent UI elements from overlapping or being cut off.
DisplayServer::get_singleton()->window_set_min_size(Size2(1024, 600) * EDSCALE);
- FileDialog::set_default_show_hidden_files(EditorSettings::get_singleton()->get("filesystem/file_dialog/show_hidden_files"));
- EditorFileDialog::set_default_show_hidden_files(EditorSettings::get_singleton()->get("filesystem/file_dialog/show_hidden_files"));
- EditorFileDialog::set_default_display_mode((EditorFileDialog::DisplayMode)EditorSettings::get_singleton()->get("filesystem/file_dialog/display_mode").operator int());
+ FileDialog::set_default_show_hidden_files(EDITOR_GET("filesystem/file_dialog/show_hidden_files"));
+ EditorFileDialog::set_default_show_hidden_files(EDITOR_GET("filesystem/file_dialog/show_hidden_files"));
+ EditorFileDialog::set_default_display_mode((EditorFileDialog::DisplayMode)EDITOR_GET("filesystem/file_dialog/display_mode").operator int());
int swap_cancel_ok = EDITOR_GET("interface/editor/accept_dialog_cancel_ok_buttons");
if (swap_cancel_ok != 0) { // 0 is auto, set in register_scene based on DisplayServer.
@@ -6352,7 +6382,7 @@ EditorNode::EditorNode() {
ED_SHORTCUT("canvas_item_editor/pan_view", TTR("Pan View"), Key::SPACE);
- const Vector<String> textfile_ext = ((String)(EditorSettings::get_singleton()->get("docks/filesystem/textfile_extensions"))).split(",", false);
+ const Vector<String> textfile_ext = ((String)(EDITOR_GET("docks/filesystem/textfile_extensions"))).split(",", false);
for (const String &E : textfile_ext) {
textfile_extensions.insert(E);
}
@@ -7072,10 +7102,12 @@ EditorNode::EditorNode() {
FileSystemDock *filesystem_dock = memnew(FileSystemDock);
filesystem_dock->connect("inherit", callable_mp(this, &EditorNode::_inherit_request));
- filesystem_dock->connect("instance", callable_mp(this, &EditorNode::_instantiate_request));
+ filesystem_dock->connect("instantiate", callable_mp(this, &EditorNode::_instantiate_request));
filesystem_dock->connect("display_mode_changed", callable_mp(this, &EditorNode::_save_docks));
get_project_settings()->connect_filesystem_dock_signals(filesystem_dock);
+ history_dock = memnew(HistoryDock);
+
// Scene: Top left.
dock_slot[DOCK_SLOT_LEFT_UR]->add_child(SceneTreeDock::get_singleton());
dock_slot[DOCK_SLOT_LEFT_UR]->set_tab_title(dock_slot[DOCK_SLOT_LEFT_UR]->get_tab_idx_from_control(SceneTreeDock::get_singleton()), TTR("Scene"));
@@ -7096,6 +7128,10 @@ EditorNode::EditorNode() {
dock_slot[DOCK_SLOT_RIGHT_UL]->add_child(NodeDock::get_singleton());
dock_slot[DOCK_SLOT_RIGHT_UL]->set_tab_title(dock_slot[DOCK_SLOT_RIGHT_UL]->get_tab_idx_from_control(NodeDock::get_singleton()), TTR("Node"));
+ // History: Full height right, behind Node.
+ dock_slot[DOCK_SLOT_RIGHT_UL]->add_child(history_dock);
+ dock_slot[DOCK_SLOT_RIGHT_UL]->set_tab_title(dock_slot[DOCK_SLOT_RIGHT_UL]->get_tab_idx_from_control(history_dock), TTR("History"));
+
// Hide unused dock slots and vsplits.
dock_slot[DOCK_SLOT_LEFT_UL]->hide();
dock_slot[DOCK_SLOT_LEFT_BL]->hide();