This commit is contained in:
Spartan322
2025-06-20 02:38:24 -04:00
699 changed files with 21288 additions and 9565 deletions

View File

@@ -103,6 +103,7 @@
#include "editor/editor_property_name_processor.h"
#include "editor/editor_resource_picker.h"
#include "editor/editor_resource_preview.h"
#include "editor/editor_run.h"
#include "editor/editor_script.h"
#include "editor/editor_settings.h"
#include "editor/editor_settings_dialog.h"
@@ -572,17 +573,57 @@ void EditorNode::_update_translations() {
main->clear();
TranslationServer::get_singleton()->load_translations();
if (main->is_enabled() && !main->get_loaded_locales().has(main->get_locale_override())) {
// Translations for the current preview locale is removed.
main->set_enabled(false);
main->set_locale_override(String());
scene_root->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);
emit_signal(SNAME("preview_locale_changed"));
} else {
scene_root->propagate_notification(NOTIFICATION_TRANSLATION_CHANGED);
if (main->is_enabled()) {
// Check for the exact locale.
// `get_potential_translations("zh_CN")` could return translations for "zh".
if (main->get_loaded_locales().has(main->get_locale_override())) {
// The set of translation resources for the current locale changed.
const HashSet<Ref<Translation>> translations = main->get_potential_translations(main->get_locale_override());
if (translations != tracked_translations) {
_translation_resources_changed();
}
} else {
// Translations for the current preview locale is removed.
main->set_enabled(false);
main->set_locale_override(String());
_translation_resources_changed();
}
}
}
void EditorNode::_translation_resources_changed() {
for (const Ref<Translation> &E : tracked_translations) {
E->disconnect_changed(callable_mp(this, &EditorNode::_queue_translation_notification));
}
tracked_translations.clear();
const Ref<TranslationDomain> main = TranslationServer::get_singleton()->get_main_domain();
if (main->is_enabled()) {
const HashSet<Ref<Translation>> translations = main->get_potential_translations(main->get_locale_override());
tracked_translations.reserve(translations.size());
for (const Ref<Translation> &translation : translations) {
translation->connect_changed(callable_mp(this, &EditorNode::_queue_translation_notification));
tracked_translations.insert(translation);
}
}
_queue_translation_notification();
emit_signal(SNAME("preview_locale_changed"));
}
void EditorNode::_queue_translation_notification() {
if (pending_translation_notification) {
return;
}
pending_translation_notification = true;
callable_mp(this, &EditorNode::_propagate_translation_notification).call_deferred();
}
void EditorNode::_propagate_translation_notification() {
pending_translation_notification = false;
scene_root->propagate_notification(NOTIFICATION_TRANSLATION_CHANGED);
}
void EditorNode::_update_theme(bool p_skip_creation) {
if (!p_skip_creation) {
theme = EditorThemeManager::generate_theme(theme);
@@ -1015,7 +1056,7 @@ void EditorNode::_update_update_spinner() {
update_popup->set_item_checked(update_popup->get_item_index(SPINNER_UPDATE_WHEN_CHANGED), !update_continuously);
if (update_continuously) {
update_spinner->set_tooltip_text(TTR("Spins when the editor window redraws.\nUpdate Continuously is enabled, which can increase power usage. Click to disable it."));
update_spinner->set_tooltip_text(TTRC("Spins when the editor window redraws.\nUpdate Continuously is enabled, which can increase power usage. Click to disable it."));
// Use a different color for the update spinner when Update Continuously is enabled,
// as this feature should only be enabled for troubleshooting purposes.
@@ -1024,7 +1065,7 @@ void EditorNode::_update_update_spinner() {
const bool dark_theme = EditorThemeManager::is_dark_theme();
update_spinner->set_self_modulate(theme->get_color(SNAME("error_color"), EditorStringName(Editor)) * (dark_theme ? Color(1.1, 1.1, 1.1) : Color(4.25, 4.25, 4.25)));
} else {
update_spinner->set_tooltip_text(TTR("Spins when the editor window redraws."));
update_spinner->set_tooltip_text(TTRC("Spins when the editor window redraws."));
update_spinner->set_self_modulate(Color(1, 1, 1));
}
@@ -1964,7 +2005,7 @@ void EditorNode::_save_scene_silently() {
// when Save on Focus Loss kicks in.
Node *scene = editor_data.get_edited_scene_root();
if (scene && !scene->get_scene_file_path().is_empty() && DirAccess::exists(scene->get_scene_file_path().get_base_dir())) {
_save_scene(scene->get_scene_file_path());
_save_scene(scene->get_scene_file_path(), -1, false);
save_editor_layout_delayed();
}
}
@@ -1992,23 +2033,29 @@ static void _reset_animation_mixers(Node *p_node, List<Pair<AnimationMixer *, Re
}
}
void EditorNode::_save_scene(String p_file, int idx) {
void EditorNode::_save_scene(String p_file, int idx, bool show_progress) {
ERR_FAIL_COND_MSG(!saving_scene.is_empty() && saving_scene == p_file, "Scene saved while already being saved!");
Node *scene = editor_data.get_edited_scene_root(idx);
save_scene_progress = memnew(EditorProgress("save", TTR("Saving Scene"), 3));
save_scene_progress->step(TTR("Analyzing"), 0);
if (show_progress) {
save_scene_progress = memnew(EditorProgress("save", TTR("Saving Scene"), 3));
save_scene_progress->step(TTR("Analyzing"), 0);
}
if (!scene) {
show_accept(TTR("This operation can't be done without a tree root."), TTR("OK"));
_close_save_scene_progress();
if (show_progress) {
_close_save_scene_progress();
}
return;
}
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 instance inclusion.\nPlease resolve it and then attempt to save again."), TTR("OK"));
_close_save_scene_progress();
if (show_progress) {
_close_save_scene_progress();
}
return;
}
@@ -2020,7 +2067,9 @@ void EditorNode::_save_scene(String p_file, int idx) {
_reset_animation_mixers(scene, &anim_backups);
_save_editor_states(p_file, idx);
save_scene_progress->step(TTR("Packing Scene"), 1);
if (show_progress) {
save_scene_progress->step(TTR("Packing Scene"), 1);
}
Ref<PackedScene> sdata;
@@ -2042,11 +2091,15 @@ void EditorNode::_save_scene(String p_file, int idx) {
if (err != OK) {
show_accept(TTR("Couldn't save scene. Likely dependencies (instances or inheritance) couldn't be satisfied."), TTR("OK"));
_close_save_scene_progress();
if (show_progress) {
_close_save_scene_progress();
}
return;
}
save_scene_progress->step(TTR("Saving scene"), 2);
if (show_progress) {
save_scene_progress->step(TTR("Saving scene"), 2);
}
int flg = 0;
if (EDITOR_GET("filesystem/on_save/compress_binary_resources")) {
@@ -2060,7 +2113,9 @@ void EditorNode::_save_scene(String p_file, int idx) {
emit_signal(SNAME("scene_saved"), p_file);
editor_data.notify_scene_saved(p_file);
save_scene_progress->step(TTR("Saving external resources"), 3);
if (show_progress) {
save_scene_progress->step(TTR("Saving external resources"), 3);
}
_save_external_resources();
saving_scene = p_file; // Some editors may save scenes of built-in resources as external data, so avoid saving this scene again.
@@ -2086,7 +2141,9 @@ void EditorNode::_save_scene(String p_file, int idx) {
scene->propagate_notification(NOTIFICATION_EDITOR_POST_SAVE);
_update_unsaved_cache();
_close_save_scene_progress();
if (show_progress) {
_close_save_scene_progress();
}
}
void EditorNode::save_all_scenes() {
@@ -2521,7 +2578,7 @@ void EditorNode::edit_item(Object *p_object, Object *p_editing_owner) {
}
void EditorNode::push_node_item(Node *p_node) {
if (p_node || Object::cast_to<Node>(InspectorDock::get_inspector_singleton()->get_edited_object()) || Object::cast_to<MultiNodeEdit>(InspectorDock::get_inspector_singleton()->get_edited_object())) {
if (p_node || !InspectorDock::get_inspector_singleton()->get_edited_object() || Object::cast_to<Node>(InspectorDock::get_inspector_singleton()->get_edited_object()) || Object::cast_to<MultiNodeEdit>(InspectorDock::get_inspector_singleton()->get_edited_object())) {
// Don't push null if the currently edited object is not a Node.
push_item(p_node);
}
@@ -3426,14 +3483,39 @@ void EditorNode::_request_screenshot() {
void EditorNode::_screenshot(bool p_use_utc) {
String name = "editor_screenshot_" + Time::get_singleton()->get_datetime_string_from_system(p_use_utc).remove_char(':') + ".png";
NodePath path = String("user://") + name;
_save_screenshot(path);
if (EDITOR_GET("interface/editor/automatically_open_screenshots")) {
OS::get_singleton()->shell_show_in_file_manager(ProjectSettings::get_singleton()->globalize_path(path), true);
String path = String("user://") + name;
if (!EditorRun::request_screenshot(callable_mp(this, &EditorNode::_save_screenshot_with_embedded_process).bind(path))) {
_save_screenshot(path);
}
}
void EditorNode::_save_screenshot(NodePath p_path) {
void EditorNode::_save_screenshot_with_embedded_process(int64_t p_w, int64_t p_h, const String &p_emb_path, const Rect2i &p_rect, const String &p_path) {
Control *main_screen_control = editor_main_screen->get_control();
ERR_FAIL_NULL_MSG(main_screen_control, "Cannot get the editor main screen control.");
Viewport *viewport = main_screen_control->get_viewport();
ERR_FAIL_NULL_MSG(viewport, "Cannot get a viewport from the editor main screen.");
Ref<ViewportTexture> texture = viewport->get_texture();
ERR_FAIL_COND_MSG(texture.is_null(), "Cannot get a viewport texture from the editor main screen.");
Ref<Image> img = texture->get_image();
ERR_FAIL_COND_MSG(img.is_null(), "Cannot get an image from a viewport texture of the editor main screen.");
img->convert(Image::FORMAT_RGBA8);
ERR_FAIL_COND(p_emb_path.is_empty());
Ref<Image> overlay = Image::load_from_file(p_emb_path);
DirAccess::remove_absolute(p_emb_path);
ERR_FAIL_COND_MSG(overlay.is_null(), "Cannot get an image from a embedded process.");
overlay->convert(Image::FORMAT_RGBA8);
overlay->resize(p_rect.size.x, p_rect.size.y);
img->blend_rect(overlay, Rect2i(0, 0, p_w, p_h), p_rect.position);
Error error = img->save_png(p_path);
ERR_FAIL_COND_MSG(error != OK, "Cannot save screenshot to file '" + p_path + "'.");
if (EDITOR_GET("interface/editor/automatically_open_screenshots")) {
OS::get_singleton()->shell_show_in_file_manager(ProjectSettings::get_singleton()->globalize_path(p_path), true);
}
}
void EditorNode::_save_screenshot(const String &p_path) {
Control *main_screen_control = editor_main_screen->get_control();
ERR_FAIL_NULL_MSG(main_screen_control, "Cannot get the editor main screen control.");
Viewport *viewport = main_screen_control->get_viewport();
@@ -3444,6 +3526,10 @@ void EditorNode::_save_screenshot(NodePath p_path) {
ERR_FAIL_COND_MSG(img.is_null(), "Cannot get an image from a viewport texture of the editor main screen.");
Error error = img->save_png(p_path);
ERR_FAIL_COND_MSG(error != OK, "Cannot save screenshot to file '" + p_path + "'.");
if (EDITOR_GET("interface/editor/automatically_open_screenshots")) {
OS::get_singleton()->shell_show_in_file_manager(ProjectSettings::get_singleton()->globalize_path(p_path), true);
}
}
void EditorNode::_check_system_theme_changed() {
@@ -4017,14 +4103,7 @@ void EditorNode::set_preview_locale(const String &p_locale) {
main_domain->set_enabled(!p_locale.is_empty());
main_domain->set_locale_override(p_locale);
if (prev_locale.is_empty() == p_locale.is_empty()) {
// Switching between different locales.
scene_root->propagate_notification(NOTIFICATION_TRANSLATION_CHANGED);
} else {
// Switching between on/off.
scene_root->set_auto_translate_mode(p_locale.is_empty() ? AUTO_TRANSLATE_MODE_DISABLED : AUTO_TRANSLATE_MODE_ALWAYS);
}
emit_signal(SNAME("preview_locale_changed"));
_translation_resources_changed();
}
Dictionary EditorNode::_get_main_scene_state() {
@@ -6597,7 +6676,7 @@ void EditorNode::reload_instances_with_path_in_edited_scenes() {
// it's a multi-level inheritance scene. We should use
NodePath scene_path_to_node = current_edited_scene->get_path_to(original_node);
Ref<SceneState> scene_state = current_edited_scene->get_scene_inherited_state();
if (scene_path_to_node != "." && scene_state.is_valid() && scene_state->get_path() != instance_modifications.instance_path && scene_state->find_node_by_path(scene_path_to_node) >= 0) {
if (String(scene_path_to_node) != "." && scene_state.is_valid() && scene_state->get_path() != instance_modifications.instance_path && scene_state->find_node_by_path(scene_path_to_node) >= 0) {
Node *root_node = scene_state->instantiate(SceneState::GenEditState::GEN_EDIT_STATE_INSTANCE);
instantiated_node = root_node->get_node(scene_path_to_node);
@@ -7007,7 +7086,8 @@ void EditorNode::_add_renderer_entry(const String &p_renderer_name, bool p_mark_
item_text = TTR("Compatibility");
}
if (p_mark_overridden) {
item_text += " " + TTR("(Overridden)");
// TRANSLATORS: The placeholder is the rendering method that has overridden the default one.
item_text = vformat(TTR("%s (Overridden)"), item_text);
}
renderer->add_item(item_text);
}
@@ -7825,7 +7905,7 @@ EditorNode::EditorNode() {
editor_main_screen->set_v_size_flags(Control::SIZE_EXPAND_FILL);
scene_root = memnew(SubViewport);
scene_root->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);
scene_root->set_auto_translate_mode(AUTO_TRANSLATE_MODE_ALWAYS);
scene_root->set_translation_domain(StringName());
scene_root->set_embedding_subwindows(true);
scene_root->set_disable_3d(true);
@@ -7919,7 +7999,7 @@ EditorNode::EditorNode() {
recent_scenes = memnew(PopupMenu);
recent_scenes->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);
file_menu->add_submenu_node_item(TTR("Open Recent"), recent_scenes, SCENE_OPEN_RECENT);
file_menu->add_submenu_node_item(TTRC("Open Recent"), recent_scenes, SCENE_OPEN_RECENT);
recent_scenes->connect(SceneStringName(id_pressed), callable_mp(this, &EditorNode::_open_recent_scene));
file_menu->add_separator();
@@ -7936,7 +8016,7 @@ EditorNode::EditorNode() {
file_menu->add_separator();
export_as_menu = memnew(PopupMenu);
file_menu->add_submenu_node_item(TTR("Export As..."), export_as_menu);
file_menu->add_submenu_node_item(TTRC("Export As..."), export_as_menu);
export_as_menu->add_shortcut(ED_SHORTCUT("editor/export_as_mesh_library", TTRC("MeshLibrary...")), FILE_EXPORT_MESH_LIBRARY);
export_as_menu->connect("index_pressed", callable_mp(this, &EditorNode::_export_as_menu_option));
@@ -7979,21 +8059,21 @@ EditorNode::EditorNode() {
project_menu->add_shortcut(ED_GET_SHORTCUT("editor/find_in_files"), PROJECT_FIND_IN_FILES);
project_menu->add_separator();
project_menu->add_item(TTR("Version Control"), PROJECT_VERSION_CONTROL);
project_menu->add_item(TTRC("Version Control"), PROJECT_VERSION_CONTROL);
project_menu->add_separator();
project_menu->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/export", TTRC("Export..."), Key::NONE, TTRC("Export")), PROJECT_EXPORT);
project_menu->add_item(TTR("Pack Project as ZIP..."), PROJECT_PACK_AS_ZIP);
project_menu->add_item(TTRC("Pack Project as ZIP..."), PROJECT_PACK_AS_ZIP);
#ifndef ANDROID_ENABLED
project_menu->add_item(TTR("Install Android Build Template..."), PROJECT_INSTALL_ANDROID_SOURCE);
project_menu->add_item(TTR("Open User Data Folder"), PROJECT_OPEN_USER_DATA_FOLDER);
project_menu->add_item(TTRC("Install Android Build Template..."), PROJECT_INSTALL_ANDROID_SOURCE);
project_menu->add_item(TTRC("Open User Data Folder"), PROJECT_OPEN_USER_DATA_FOLDER);
#endif
project_menu->add_separator();
tool_menu = memnew(PopupMenu);
tool_menu->connect("index_pressed", callable_mp(this, &EditorNode::_tool_menu_option));
project_menu->add_submenu_node_item(TTR("Tools"), tool_menu);
project_menu->add_submenu_node_item(TTRC("Tools"), tool_menu);
tool_menu->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/orphan_resource_explorer", TTRC("Orphan Resource Explorer...")), TOOLS_ORPHAN_RESOURCES);
tool_menu->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/engine_compilation_configuration_editor", TTRC("Engine Compilation Configuration Editor...")), TOOLS_BUILD_PROFILE_MANAGER);
tool_menu->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/upgrade_project", TTRC("Upgrade Project Files...")), TOOLS_PROJECT_UPGRADE);
@@ -8045,10 +8125,10 @@ EditorNode::EditorNode() {
settings_menu->add_shortcut(ED_SHORTCUT("editor/command_palette", TTRC("Command Palette..."), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::SHIFT | Key::P), EDITOR_COMMAND_PALETTE);
settings_menu->add_separator();
settings_menu->add_submenu_node_item(TTR("Editor Docks"), editor_dock_manager->get_docks_menu());
settings_menu->add_submenu_node_item(TTRC("Editor Docks"), editor_dock_manager->get_docks_menu());
editor_layouts = memnew(PopupMenu);
settings_menu->add_submenu_node_item(TTR("Editor Layout"), editor_layouts);
settings_menu->add_submenu_node_item(TTRC("Editor Layout"), editor_layouts);
editor_layouts->connect(SceneStringName(id_pressed), callable_mp(this, &EditorNode::_layout_menu_option));
settings_menu->add_separator();
@@ -8056,7 +8136,7 @@ EditorNode::EditorNode() {
ED_SHORTCUT_OVERRIDE("editor/take_screenshot", "macos", KeyModifierMask::META | Key::F12);
settings_menu->add_shortcut(ED_GET_SHORTCUT("editor/take_screenshot"), EDITOR_TAKE_SCREENSHOT);
settings_menu->set_item_tooltip(-1, TTR("Screenshots are stored in the user data folder (\"user://\")."));
settings_menu->set_item_tooltip(-1, TTRC("Screenshots are stored in the user data folder (\"user://\")."));
ED_SHORTCUT_AND_COMMAND("editor/fullscreen_mode", TTRC("Toggle Fullscreen"), KeyModifierMask::SHIFT | Key::F11);
ED_SHORTCUT_OVERRIDE("editor/fullscreen_mode", "macos", KeyModifierMask::META | KeyModifierMask::CTRL | Key::F);
@@ -8066,19 +8146,19 @@ EditorNode::EditorNode() {
#ifndef ANDROID_ENABLED
if (OS::get_singleton()->get_data_path() == OS::get_singleton()->get_config_path()) {
// Configuration and data folders are located in the same place (Windows/macOS).
settings_menu->add_item(TTR("Open Editor Data/Settings Folder"), EDITOR_OPEN_DATA_FOLDER);
settings_menu->add_item(TTRC("Open Editor Data/Settings Folder"), EDITOR_OPEN_DATA_FOLDER);
} else {
// Separate configuration and data folders (Linux).
settings_menu->add_item(TTR("Open Editor Data Folder"), EDITOR_OPEN_DATA_FOLDER);
settings_menu->add_item(TTR("Open Editor Settings Folder"), EDITOR_OPEN_CONFIG_FOLDER);
settings_menu->add_item(TTRC("Open Editor Data Folder"), EDITOR_OPEN_DATA_FOLDER);
settings_menu->add_item(TTRC("Open Editor Settings Folder"), EDITOR_OPEN_CONFIG_FOLDER);
}
settings_menu->add_separator();
#endif
settings_menu->add_item(TTR("Manage Editor Features..."), EDITOR_MANAGE_FEATURE_PROFILES);
settings_menu->add_item(TTR("Manage Export Templates..."), EDITOR_MANAGE_EXPORT_TEMPLATES);
settings_menu->add_item(TTRC("Manage Editor Features..."), EDITOR_MANAGE_FEATURE_PROFILES);
settings_menu->add_item(TTRC("Manage Export Templates..."), EDITOR_MANAGE_EXPORT_TEMPLATES);
#if !defined(ANDROID_ENABLED) && !defined(WEB_ENABLED)
settings_menu->add_item(TTR("Configure FBX Importer..."), EDITOR_CONFIGURE_FBX_IMPORTER);
settings_menu->add_item(TTRC("Configure FBX Importer..."), EDITOR_CONFIGURE_FBX_IMPORTER);
#endif
help_menu = memnew(PopupMenu);
@@ -8132,7 +8212,9 @@ EditorNode::EditorNode() {
renderer->set_theme_type_variation("TopBarOptionButton");
renderer->set_fit_to_longest_item(false);
renderer->set_focus_mode(Control::FOCUS_ACCESSIBILITY);
renderer->set_tooltip_text(TTR("Choose a rendering method.\n\nNotes:\n- On mobile platforms, the Mobile rendering method is used if Forward+ is selected here.\n- On the web platform, the Compatibility rendering method is always used."));
renderer->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);
renderer->set_tooltip_auto_translate_mode(AUTO_TRANSLATE_MODE_ALWAYS);
renderer->set_tooltip_text(TTRC("Choose a rendering method.\n\nNotes:\n- On mobile platforms, the Mobile rendering method is used if Forward+ is selected here.\n- On the web platform, the Compatibility rendering method is always used."));
renderer->set_accessibility_name(TTRC("Rendering Method"));
right_menu_hb->add_child(renderer);
@@ -8196,10 +8278,10 @@ EditorNode::EditorNode() {
update_spinner->get_popup()->connect(SceneStringName(id_pressed), callable_mp(this, &EditorNode::_menu_option));
update_spinner->set_accessibility_name(TTRC("Update Mode"));
PopupMenu *p = update_spinner->get_popup();
p->add_radio_check_item(TTR("Update Continuously"), SPINNER_UPDATE_CONTINUOUSLY);
p->add_radio_check_item(TTR("Update When Changed"), SPINNER_UPDATE_WHEN_CHANGED);
p->add_radio_check_item(TTRC("Update Continuously"), SPINNER_UPDATE_CONTINUOUSLY);
p->add_radio_check_item(TTRC("Update When Changed"), SPINNER_UPDATE_WHEN_CHANGED);
p->add_separator();
p->add_item(TTR("Hide Update Spinner"), SPINNER_UPDATE_SPINNER_HIDE);
p->add_item(TTRC("Hide Update Spinner"), SPINNER_UPDATE_SPINNER_HIDE);
_update_update_spinner();
// Instantiate and place editor docks.
@@ -8267,7 +8349,7 @@ EditorNode::EditorNode() {
center_split->set_dragger_visibility(SplitContainer::DRAGGER_HIDDEN);
log = memnew(EditorLog);
Button *output_button = bottom_panel->add_item(TTR("Output"), log, ED_SHORTCUT_AND_COMMAND("bottom_panels/toggle_output_bottom_panel", TTRC("Toggle Output Bottom Panel"), KeyModifierMask::ALT | Key::O));
Button *output_button = bottom_panel->add_item(TTRC("Output"), log, ED_SHORTCUT_AND_COMMAND("bottom_panels/toggle_output_bottom_panel", TTRC("Toggle Output Bottom Panel"), KeyModifierMask::ALT | Key::O));
log->set_tool_button(output_button);
center_split->connect(SceneStringName(resized), callable_mp(this, &EditorNode::_vp_resized));
@@ -8455,8 +8537,8 @@ EditorNode::EditorNode() {
vcs_actions_menu = VersionControlEditorPlugin::get_singleton()->get_version_control_actions_panel();
vcs_actions_menu->connect("index_pressed", callable_mp(this, &EditorNode::_version_control_menu_option));
vcs_actions_menu->add_item(TTR("Create/Override Version Control Metadata..."), VCS_METADATA);
vcs_actions_menu->add_item(TTR("Version Control Settings..."), VCS_SETTINGS);
vcs_actions_menu->add_item(TTRC("Create/Override Version Control Metadata..."), VCS_METADATA);
vcs_actions_menu->add_item(TTRC("Version Control Settings..."), VCS_SETTINGS);
project_menu->set_item_submenu_node(project_menu->get_item_index(PROJECT_VERSION_CONTROL), vcs_actions_menu);
add_editor_plugin(memnew(AudioBusesEditorPlugin(audio_bus_editor)));