Path: blob/master/editor/settings/editor_settings.cpp
21000 views
/**************************************************************************/1/* editor_settings.cpp */2/**************************************************************************/3/* This file is part of: */4/* GODOT ENGINE */5/* https://godotengine.org */6/**************************************************************************/7/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */8/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */9/* */10/* Permission is hereby granted, free of charge, to any person obtaining */11/* a copy of this software and associated documentation files (the */12/* "Software"), to deal in the Software without restriction, including */13/* without limitation the rights to use, copy, modify, merge, publish, */14/* distribute, sublicense, and/or sell copies of the Software, and to */15/* permit persons to whom the Software is furnished to do so, subject to */16/* the following conditions: */17/* */18/* The above copyright notice and this permission notice shall be */19/* included in all copies or substantial portions of the Software. */20/* */21/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */22/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */23/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */24/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */25/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */26/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */27/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */28/**************************************************************************/2930#include "editor_settings.h"3132#include "core/config/project_settings.h"33#include "core/input/input_event.h"34#include "core/input/input_map.h"35#include "core/input/shortcut.h"36#include "core/io/certs_compressed.gen.h"37#include "core/io/dir_access.h"38#include "core/io/file_access.h"39#include "core/io/ip.h"40#include "core/io/resource_loader.h"41#include "core/io/resource_saver.h"42#include "core/object/class_db.h"43#include "core/os/keyboard.h"44#include "core/os/os.h"45#include "core/string/translation_server.h"46#include "core/version.h"47#include "editor/editor_node.h"48#include "editor/file_system/editor_paths.h"49#include "editor/inspector/editor_property_name_processor.h"50#include "editor/project_manager/engine_update_label.h"51#include "editor/themes/editor_theme_manager.h"52#include "editor/translations/editor_translation.h"53#include "main/main.h"54#include "modules/regex/regex.h"55#include "scene/gui/color_picker.h"56#include "scene/gui/file_dialog.h"57#include "scene/main/node.h"58#include "scene/main/scene_tree.h"59#include "scene/main/window.h"60#include "scene/resources/animation.h"6162// PRIVATE METHODS6364Ref<EditorSettings> EditorSettings::singleton = nullptr;6566// Properties6768bool EditorSettings::_set(const StringName &p_name, const Variant &p_value) {69_THREAD_SAFE_METHOD_7071bool changed = _set_only(p_name, p_value);72if (changed && initialized) {73changed_settings.insert(p_name);74if (p_name == SNAME("text_editor/external/exec_path")) {75const StringName exec_args_name = "text_editor/external/exec_flags";76const String exec_args_value = _guess_exec_args_for_extenal_editor(p_value);77if (!exec_args_value.is_empty() && _set_only(exec_args_name, exec_args_value)) {78changed_settings.insert(exec_args_name);79}80}81emit_signal(SNAME("settings_changed"));8283if (p_name == SNAME("interface/editor/editor_language")) {84setup_language(false);85}86}87return true;88}8990bool EditorSettings::_set_only(const StringName &p_name, const Variant &p_value) {91_THREAD_SAFE_METHOD_9293if (p_name == "shortcuts") {94Array arr = p_value;95for (int i = 0; i < arr.size(); i++) {96Dictionary dict = arr[i];97String shortcut_name = dict["name"];9899Array shortcut_events = dict["shortcuts"];100101Ref<Shortcut> sc;102sc.instantiate();103sc->set_events(shortcut_events);104_add_shortcut_default(shortcut_name, sc);105}106107return false;108} else if (p_name == "builtin_action_overrides") {109Array actions_arr = p_value;110for (int i = 0; i < actions_arr.size(); i++) {111Dictionary action_dict = actions_arr[i];112113String action_name = action_dict["name"];114Array events = action_dict["events"];115116InputMap *im = InputMap::get_singleton();117im->action_erase_events(action_name);118119builtin_action_overrides[action_name].clear();120for (int ev_idx = 0; ev_idx < events.size(); ev_idx++) {121im->action_add_event(action_name, events[ev_idx]);122builtin_action_overrides[action_name].push_back(events[ev_idx]);123}124}125return false;126}127128bool changed = false;129130if (p_value.get_type() == Variant::NIL) {131if (props.has(p_name)) {132props.erase(p_name);133changed = true;134}135} else {136if (props.has(p_name)) {137if (p_value != props[p_name].variant) {138props[p_name].variant = p_value;139changed = true;140}141} else {142props[p_name] = VariantContainer(p_value, last_order++);143changed = true;144}145146if (save_changed_setting) {147if (!props[p_name].save) {148props[p_name].save = true;149changed = true;150}151}152}153154return changed;155}156157bool EditorSettings::_get(const StringName &p_name, Variant &r_ret) const {158_THREAD_SAFE_METHOD_159160if (p_name == "shortcuts") {161Array save_array;162const HashMap<String, List<Ref<InputEvent>>> &builtin_list = InputMap::get_singleton()->get_builtins();163for (const KeyValue<String, Ref<Shortcut>> &shortcut_definition : shortcuts) {164Ref<Shortcut> sc = shortcut_definition.value;165166if (builtin_list.has(shortcut_definition.key)) {167// This shortcut was auto-generated from built in actions: don't save.168// If the builtin is overridden, it will be saved in the "builtin_action_overrides" section below.169continue;170}171172Array shortcut_events = sc->get_events();173174Dictionary dict;175dict["name"] = shortcut_definition.key;176dict["shortcuts"] = shortcut_events;177178if (!sc->has_meta("original")) {179// Getting the meta when it doesn't exist will return an empty array. If the 'shortcut_events' have been cleared,180// we still want save the shortcut in this case so that shortcuts that the user has customized are not reset,181// even if the 'original' has not been populated yet. This can happen when calling save() from the Project Manager.182save_array.push_back(dict);183continue;184}185186Array original_events = sc->get_meta("original");187188bool is_same = Shortcut::is_event_array_equal(original_events, shortcut_events);189if (is_same) {190continue; // Not changed from default; don't save.191}192193save_array.push_back(dict);194}195r_ret = save_array;196return true;197} else if (p_name == "builtin_action_overrides") {198Array actions_arr;199for (const KeyValue<String, List<Ref<InputEvent>>> &action_override : builtin_action_overrides) {200const List<Ref<InputEvent>> *defaults = InputMap::get_singleton()->get_builtins().getptr(action_override.key);201if (!defaults) {202continue;203}204205List<Ref<InputEvent>> events = action_override.value;206207Dictionary action_dict;208action_dict["name"] = action_override.key;209210// Convert the list to an array, and only keep key events as this is for the editor.211Array events_arr;212for (const Ref<InputEvent> &ie : events) {213Ref<InputEventKey> iek = ie;214if (iek.is_valid()) {215events_arr.append(iek);216}217}218219Array defaults_arr;220for (const Ref<InputEvent> &default_input_event : *defaults) {221if (default_input_event.is_valid()) {222defaults_arr.append(default_input_event);223}224}225226bool same = Shortcut::is_event_array_equal(events_arr, defaults_arr);227228// Don't save if same as default.229if (same) {230continue;231}232233action_dict["events"] = events_arr;234actions_arr.push_back(action_dict);235}236237r_ret = actions_arr;238return true;239}240241const VariantContainer *v = props.getptr(p_name);242if (!v) {243return false;244}245r_ret = v->variant;246return true;247}248249void EditorSettings::_initial_set(const StringName &p_name, const Variant &p_value, bool p_basic) {250set(p_name, p_value);251props[p_name].initial = p_value;252props[p_name].has_default_value = true;253props[p_name].basic = p_basic;254}255256struct _EVCSort {257String name;258Variant::Type type = Variant::Type::NIL;259int order = 0;260bool basic = false;261bool save = false;262bool restart_if_changed = false;263264bool operator<(const _EVCSort &p_vcs) const { return order < p_vcs.order; }265};266267void EditorSettings::_get_property_list(List<PropertyInfo> *p_list) const {268_THREAD_SAFE_METHOD_269270RBSet<_EVCSort> vclist;271272for (const KeyValue<String, VariantContainer> &E : props) {273const VariantContainer *v = &E.value;274275if (v->hide_from_editor) {276continue;277}278279_EVCSort vc;280vc.name = E.key;281vc.order = v->order;282vc.type = v->variant.get_type();283vc.basic = v->basic;284vc.save = v->save;285if (vc.save) {286if (v->initial.get_type() != Variant::NIL && v->initial == v->variant) {287vc.save = false;288}289}290vc.restart_if_changed = v->restart_if_changed;291292vclist.insert(vc);293}294295for (const _EVCSort &E : vclist) {296uint32_t pusage = PROPERTY_USAGE_NONE;297if (E.save || !optimize_save) {298pusage |= PROPERTY_USAGE_STORAGE;299}300301if (!E.name.begins_with("_") && !E.name.begins_with("projects/")) {302pusage |= PROPERTY_USAGE_EDITOR;303} else {304pusage |= PROPERTY_USAGE_STORAGE; //hiddens must always be saved305}306307PropertyInfo pi(E.type, E.name);308pi.usage = pusage;309if (hints.has(E.name)) {310pi = hints[E.name];311}312313if (E.basic) {314pi.usage |= PROPERTY_USAGE_EDITOR_BASIC_SETTING;315}316317if (E.restart_if_changed) {318pi.usage |= PROPERTY_USAGE_RESTART_IF_CHANGED;319}320321p_list->push_back(pi);322}323324p_list->push_back(PropertyInfo(Variant::ARRAY, "shortcuts", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL)); //do not edit325p_list->push_back(PropertyInfo(Variant::ARRAY, "builtin_action_overrides", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL));326}327328void EditorSettings::_add_property_info_bind(const Dictionary &p_info) {329ERR_FAIL_COND_MSG(!p_info.has("name"), "Property info is missing \"name\" field.");330ERR_FAIL_COND_MSG(!p_info.has("type"), "Property info is missing \"type\" field.");331332if (p_info.has("usage")) {333WARN_PRINT("\"usage\" is not supported in add_property_info().");334}335336PropertyInfo pinfo;337pinfo.name = p_info["name"];338ERR_FAIL_COND(!props.has(pinfo.name));339pinfo.type = Variant::Type(p_info["type"].operator int());340ERR_FAIL_INDEX(pinfo.type, Variant::VARIANT_MAX);341342if (p_info.has("hint")) {343pinfo.hint = PropertyHint(p_info["hint"].operator int());344}345if (p_info.has("hint_string")) {346pinfo.hint_string = p_info["hint_string"];347}348349add_property_hint(pinfo);350}351352// Default configs353bool EditorSettings::has_default_value(const String &p_setting) const {354_THREAD_SAFE_METHOD_355356if (!props.has(p_setting)) {357return false;358}359return props[p_setting].has_default_value;360}361362void EditorSettings::_set_initialized() {363initialized = true;364}365366static LocalVector<String> _get_skipped_locales() {367// Skip locales if Text server lack required features.368LocalVector<String> locales_to_skip;369if (!TS->has_feature(TextServer::FEATURE_BIDI_LAYOUT) || !TS->has_feature(TextServer::FEATURE_SHAPING)) {370locales_to_skip.push_back("ar"); // Arabic.371locales_to_skip.push_back("fa"); // Persian.372locales_to_skip.push_back("ur"); // Urdu.373}374if (!TS->has_feature(TextServer::FEATURE_BIDI_LAYOUT)) {375locales_to_skip.push_back("he"); // Hebrew.376}377if (!TS->has_feature(TextServer::FEATURE_SHAPING)) {378locales_to_skip.push_back("bn"); // Bengali.379locales_to_skip.push_back("hi"); // Hindi.380locales_to_skip.push_back("ml"); // Malayalam.381locales_to_skip.push_back("si"); // Sinhala.382locales_to_skip.push_back("ta"); // Tamil.383locales_to_skip.push_back("te"); // Telugu.384}385return locales_to_skip;386}387388void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {389_THREAD_SAFE_METHOD_390// Sets up the editor setting with a default value and hint PropertyInfo.391#define EDITOR_SETTING(m_type, m_property_hint, m_name, m_default_value, m_hint_string) \392_initial_set(m_name, m_default_value); \393hints[m_name] = PropertyInfo(m_type, m_name, m_property_hint, m_hint_string);394395#define EDITOR_SETTING_BASIC(m_type, m_property_hint, m_name, m_default_value, m_hint_string) \396_initial_set(m_name, m_default_value, true); \397hints[m_name] = PropertyInfo(m_type, m_name, m_property_hint, m_hint_string);398399#define EDITOR_SETTING_USAGE(m_type, m_property_hint, m_name, m_default_value, m_hint_string, m_usage) \400_initial_set(m_name, m_default_value); \401hints[m_name] = PropertyInfo(m_type, m_name, m_property_hint, m_hint_string, m_usage);402403/* Languages */404405{406String lang_hint;407const String host_lang = OS::get_singleton()->get_locale();408409// Skip locales which we can't render properly.410const LocalVector<String> locales_to_skip = _get_skipped_locales();411if (!locales_to_skip.is_empty()) {412WARN_PRINT("Some locales are not properly supported by selected Text Server and are disabled.");413}414415String best = "en";416int best_score = 0;417for (const String &locale : get_editor_locales()) {418// Test against language code without regional variants (e.g. ur_PK).419String lang_code = locale.get_slicec('_', 0);420if (locales_to_skip.has(lang_code)) {421continue;422}423424lang_hint += ";";425const String lang_name = TranslationServer::get_singleton()->get_locale_name(locale);426lang_hint += vformat("%s/[%s] %s", locale, locale, lang_name);427428int score = TranslationServer::get_singleton()->compare_locales(host_lang, locale);429if (score > 0 && score >= best_score) {430best = locale;431best_score = score;432}433}434lang_hint = vformat(";auto/Auto (%s);en/[en] English", TranslationServer::get_singleton()->get_locale_name(best)) + lang_hint;435436EDITOR_SETTING_USAGE(Variant::STRING, PROPERTY_HINT_ENUM, "interface/editor/editor_language", "auto", lang_hint, PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED | PROPERTY_USAGE_EDITOR_BASIC_SETTING);437}438439// Asset library440_initial_set("asset_library/use_threads", true);441442/* Interface */443444// Editor445EDITOR_SETTING(Variant::BOOL, PROPERTY_HINT_NONE, "interface/editor/localize_settings", true, "")446EDITOR_SETTING_BASIC(Variant::INT, PROPERTY_HINT_ENUM, "interface/editor/dock_tab_style", 0, "Text Only,Icon Only,Text and Icon")447EDITOR_SETTING_BASIC(Variant::INT, PROPERTY_HINT_ENUM, "interface/editor/bottom_dock_tab_style", 0, "Text Only,Icon Only,Text and Icon")448EDITOR_SETTING_USAGE(Variant::INT, PROPERTY_HINT_ENUM, "interface/editor/ui_layout_direction", 0, "Based on Application Locale,Left-to-Right,Right-to-Left,Based on System Locale", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)449450// Display what the Auto display scale setting effectively corresponds to.451const String display_scale_hint_string = vformat("Auto (%d%%),75%%,100%%,125%%,150%%,175%%,200%%,Custom", Math::round(get_auto_display_scale() * 100));452EDITOR_SETTING_USAGE(Variant::INT, PROPERTY_HINT_ENUM, "interface/editor/display_scale", 0, display_scale_hint_string, PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED | PROPERTY_USAGE_EDITOR_BASIC_SETTING)453EDITOR_SETTING_USAGE(Variant::FLOAT, PROPERTY_HINT_RANGE, "interface/editor/custom_display_scale", 1.0, "0.5,3,0.01", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED | PROPERTY_USAGE_EDITOR_BASIC_SETTING)454455String ed_screen_hints = "Auto (Remembers last position):-5,Screen With Mouse Pointer:-4,Screen With Keyboard Focus:-3,Primary Screen:-2";456for (int i = 0; i < DisplayServer::get_singleton()->get_screen_count(); i++) {457ed_screen_hints += ",Screen " + itos(i + 1) + ":" + itos(i);458}459EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "interface/editor/editor_screen", EditorSettings::InitialScreen::INITIAL_SCREEN_AUTO, ed_screen_hints)460461#ifdef WINDOWS_ENABLED462String tablet_hints = "Use Project Settings:-1";463for (int i = 0; i < DisplayServer::get_singleton()->tablet_get_driver_count(); i++) {464String drv_name = DisplayServer::get_singleton()->tablet_get_driver_name(i);465if (EditorPropertyNameProcessor::get_singleton()) {466drv_name = EditorPropertyNameProcessor::get_singleton()->process_name(drv_name, EditorPropertyNameProcessor::STYLE_CAPITALIZED); // Note: EditorPropertyNameProcessor is not available when doctool is used, but this value is not part of docs.467}468tablet_hints += vformat(",%s:%d", drv_name, i);469}470EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "interface/editor/tablet_driver", -1, tablet_hints);471#else472EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "interface/editor/tablet_driver", -1, "Default:-1");473#endif474475String project_manager_screen_hints = "Screen With Mouse Pointer:-4,Screen With Keyboard Focus:-3,Primary Screen:-2";476for (int i = 0; i < DisplayServer::get_singleton()->get_screen_count(); i++) {477project_manager_screen_hints += ",Screen " + itos(i + 1) + ":" + itos(i);478}479EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "interface/editor/project_manager_screen", EditorSettings::InitialScreen::INITIAL_SCREEN_PRIMARY, project_manager_screen_hints)480481{482const String update_hint = vformat("Disable Update Checks,Auto (%s),Check Newest Preview,Check Newest Stable,Check Newest Patch", (str_compare(GODOT_VERSION_STATUS, "stable") == 0) ? "Stable" : "Preview");483EDITOR_SETTING_BASIC(Variant::INT, PROPERTY_HINT_ENUM, "network/connection/check_for_updates", EngineUpdateLabel::UpdateMode::AUTO, update_hint);484}485486EDITOR_SETTING_USAGE(Variant::BOOL, PROPERTY_HINT_NONE, "interface/editor/use_embedded_menu", false, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_EDITOR_BASIC_SETTING)487EDITOR_SETTING_USAGE(Variant::BOOL, PROPERTY_HINT_NONE, "interface/editor/use_native_file_dialogs", false, "", PROPERTY_USAGE_DEFAULT)488EDITOR_SETTING_USAGE(Variant::BOOL, PROPERTY_HINT_NONE, "interface/editor/expand_to_title", true, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED | PROPERTY_USAGE_EDITOR_BASIC_SETTING)489490EDITOR_SETTING_BASIC(Variant::INT, PROPERTY_HINT_RANGE, "interface/editor/main_font_size", 14, "8,48,1")491EDITOR_SETTING_BASIC(Variant::INT, PROPERTY_HINT_RANGE, "interface/editor/code_font_size", 14, "8,48,1")492_initial_set("interface/editor/main_font_custom_opentype_features", "");493EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "interface/editor/code_font_contextual_ligatures", 1, "Enabled,Disable Contextual Alternates (Coding Ligatures),Use Custom OpenType Feature Set")494_initial_set("interface/editor/code_font_custom_opentype_features", "");495_initial_set("interface/editor/code_font_custom_variations", "");496EDITOR_SETTING_BASIC(Variant::INT, PROPERTY_HINT_ENUM, "interface/editor/font_antialiasing", 1, "None,Grayscale,LCD Subpixel")497#ifdef MACOS_ENABLED498EDITOR_SETTING_BASIC(Variant::INT, PROPERTY_HINT_ENUM, "interface/editor/font_hinting", 0, "Auto (None),None,Light,Normal")499#else500EDITOR_SETTING_BASIC(Variant::INT, PROPERTY_HINT_ENUM, "interface/editor/font_hinting", 0, "Auto (Light),None,Light,Normal")501#endif502EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "interface/editor/font_subpixel_positioning", 1, "Disabled,Auto,One Half of a Pixel,One Quarter of a Pixel")503EDITOR_SETTING(Variant::BOOL, PROPERTY_HINT_NONE, "interface/editor/font_disable_embedded_bitmaps", true, "");504EDITOR_SETTING(Variant::BOOL, PROPERTY_HINT_NONE, "interface/editor/font_allow_msdf", true, "")505506EDITOR_SETTING(Variant::STRING, PROPERTY_HINT_GLOBAL_FILE, "interface/editor/main_font", "", "*.ttf,*.otf,*.woff,*.woff2,*.pfb,*.pfm")507EDITOR_SETTING(Variant::STRING, PROPERTY_HINT_GLOBAL_FILE, "interface/editor/main_font_bold", "", "*.ttf,*.otf,*.woff,*.woff2,*.pfb,*.pfm")508EDITOR_SETTING(Variant::STRING, PROPERTY_HINT_GLOBAL_FILE, "interface/editor/code_font", "", "*.ttf,*.otf,*.woff,*.woff2,*.pfb,*.pfm")509EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "interface/editor/dragging_hover_wait_seconds", 0.5, "0.01,10,0.01,or_greater,suffix:s");510_initial_set("interface/editor/separate_distraction_mode", false, true);511_initial_set("interface/editor/automatically_open_screenshots", true, true);512EDITOR_SETTING_USAGE(Variant::BOOL, PROPERTY_HINT_NONE, "interface/editor/single_window_mode", false, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED | PROPERTY_USAGE_EDITOR_BASIC_SETTING)513_initial_set("interface/editor/mouse_extra_buttons_navigate_history", true);514_initial_set("interface/editor/save_each_scene_on_quit", true, true); // Regression515EDITOR_SETTING_BASIC(Variant::BOOL, PROPERTY_HINT_NONE, "interface/editor/save_on_focus_loss", false, "")516EDITOR_SETTING_USAGE(Variant::INT, PROPERTY_HINT_ENUM, "interface/editor/accept_dialog_cancel_ok_buttons", 0,517vformat("Auto (%s),Cancel First,OK First", DisplayServer::get_singleton()->get_swap_cancel_ok() ? "OK First" : "Cancel First"),518PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED);519#ifdef DEV_ENABLED520EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "interface/editor/show_internal_errors_in_toast_notifications", 0, "Auto (Enabled),Enabled,Disabled")521EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "interface/editor/show_update_spinner", 0, "Auto (Enabled),Enabled,Disabled")522#else523EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "interface/editor/show_internal_errors_in_toast_notifications", 0, "Auto (Disabled),Enabled,Disabled")524EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "interface/editor/show_update_spinner", 0, "Auto (Disabled),Enabled,Disabled")525#endif526527_initial_set("interface/editor/keep_screen_on", false, true);528EDITOR_SETTING_USAGE(Variant::INT, PROPERTY_HINT_RANGE, "interface/editor/low_processor_mode_sleep_usec", 6900, "1,100000,1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)529// Default unfocused usec sleep is for 10 FPS. Allow an unfocused FPS limit530// as low as 1 FPS for those who really need low power usage (but don't need531// to preview particles or shaders while the editor is unfocused). With very532// low FPS limits, the editor can take a small while to become usable after533// being focused again, so this should be used at the user's discretion.534EDITOR_SETTING_USAGE(Variant::INT, PROPERTY_HINT_RANGE, "interface/editor/unfocused_low_processor_mode_sleep_usec", 100000, "1,1000000,1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)535536EDITOR_SETTING_BASIC(Variant::BOOL, PROPERTY_HINT_NONE, "interface/editor/import_resources_when_unfocused", false, "")537538EDITOR_SETTING_BASIC(Variant::INT, PROPERTY_HINT_ENUM, "interface/editor/vsync_mode", 1, "Disabled,Enabled,Adaptive,Mailbox")539EDITOR_SETTING(Variant::BOOL, PROPERTY_HINT_NONE, "interface/editor/update_continuously", false, "")540541bool is_android_editor = false;542#ifdef ANDROID_ENABLED543if (!OS::get_singleton()->has_feature("xr_editor")) {544is_android_editor = true;545}546#endif547EDITOR_SETTING(Variant::BOOL, PROPERTY_HINT_NONE, "interface/editor/collapse_main_menu", is_android_editor, "")548549_initial_set("interface/editors/show_scene_tree_root_selection", true);550_initial_set("interface/editors/derive_script_globals_by_name", true);551_initial_set("docks/scene_tree/ask_before_revoking_unique_name", true);552553// Inspector554EDITOR_SETTING_BASIC(Variant::INT, PROPERTY_HINT_RANGE, "interface/inspector/max_array_dictionary_items_per_page", 20, "10,100,1")555EDITOR_SETTING(Variant::BOOL, PROPERTY_HINT_NONE, "interface/inspector/show_low_level_opentype_features", false, "")556EDITOR_SETTING_BASIC(Variant::FLOAT, PROPERTY_HINT_RANGE, "interface/inspector/float_drag_speed", 5.0, "0.1,100,0.01")557EDITOR_SETTING_BASIC(Variant::FLOAT, PROPERTY_HINT_RANGE, "interface/inspector/integer_drag_speed", 0.5, "0.1,10,0.01")558EDITOR_SETTING_BASIC(Variant::INT, PROPERTY_HINT_ENUM, "interface/inspector/nested_color_mode", 0, "Containers & Resources,Resources,External Resources")559EDITOR_SETTING(Variant::BOOL, PROPERTY_HINT_NONE, "interface/inspector/delimitate_all_container_and_resources", true, "")560EDITOR_SETTING_USAGE(Variant::INT, PROPERTY_HINT_ENUM, "interface/inspector/default_property_name_style", EditorPropertyNameProcessor::STYLE_CAPITALIZED, "Raw (e.g. \"z_index\"),Capitalized (e.g. \"Z Index\"),Localized (e.g. \"Z Index\")", PROPERTY_USAGE_DEFAULT);561// The lowest value is equal to the minimum float step for 32-bit floats.562// The step must be set manually, as changing this setting should not change the step here.563EDITOR_SETTING_USAGE(Variant::FLOAT, PROPERTY_HINT_RANGE, "interface/inspector/default_float_step", 0.001, "0.0000001,1,0.0000001", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_EDITOR_BASIC_SETTING);564EDITOR_SETTING_USAGE(Variant::BOOL, PROPERTY_HINT_NONE, "interface/inspector/disable_folding", false, "", PROPERTY_USAGE_DEFAULT);565EDITOR_SETTING_USAGE(Variant::BOOL, PROPERTY_HINT_NONE, "interface/inspector/auto_unfold_foreign_scenes", true, "", PROPERTY_USAGE_DEFAULT)566EDITOR_SETTING(Variant::BOOL, PROPERTY_HINT_NONE, "interface/inspector/horizontal_vector2_editing", false, "")567EDITOR_SETTING(Variant::BOOL, PROPERTY_HINT_NONE, "interface/inspector/horizontal_vector_types_editing", true, "")568EDITOR_SETTING(Variant::BOOL, PROPERTY_HINT_NONE, "interface/inspector/open_resources_in_current_inspector", true, "")569570PackedStringArray open_in_new_inspector_defaults;571// Required for the script editor to work.572open_in_new_inspector_defaults.push_back("Script");573// Required for the GridMap editor to work.574open_in_new_inspector_defaults.push_back("MeshLibrary");575_initial_set("interface/inspector/resources_to_open_in_new_inspector", open_in_new_inspector_defaults);576577EDITOR_SETTING_BASIC(Variant::INT, PROPERTY_HINT_ENUM, "interface/accessibility/accessibility_support", 0, "Auto (When Screen Reader is Running),Always Active,Disabled")578set_restart_if_changed("interface/accessibility/accessibility_support", true);579580EDITOR_SETTING_BASIC(Variant::INT, PROPERTY_HINT_ENUM, "interface/inspector/default_color_picker_mode", (int32_t)ColorPicker::MODE_RGB, "RGB,HSV,RAW,OKHSL")581EDITOR_SETTING_BASIC(Variant::INT, PROPERTY_HINT_ENUM, "interface/inspector/default_color_picker_shape", (int32_t)ColorPicker::SHAPE_OKHSL_CIRCLE, "HSV Rectangle,HSV Rectangle Wheel,VHS Circle,OKHSL Circle,OK HS Rectangle:5,OK HL Rectangle") // `SHAPE_NONE` is 4.582EDITOR_SETTING_BASIC(Variant::BOOL, PROPERTY_HINT_NONE, "interface/inspector/color_picker_show_intensity", true, "");583584// Theme585EDITOR_SETTING_BASIC(Variant::BOOL, PROPERTY_HINT_ENUM, "interface/theme/follow_system_theme", false, "")586EDITOR_SETTING_BASIC(Variant::STRING, PROPERTY_HINT_ENUM, "interface/theme/style", "Modern", "Modern,Classic")587EDITOR_SETTING_BASIC(Variant::STRING, PROPERTY_HINT_ENUM, "interface/theme/color_preset", "Default", "Default,Breeze Dark,Godot 2,Godot 3,Gray,Light,Solarized (Dark),Solarized (Light),Black (OLED),Custom")588EDITOR_SETTING_BASIC(Variant::STRING, PROPERTY_HINT_ENUM, "interface/theme/spacing_preset", "Default", "Compact,Default,Spacious,Custom")589EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "interface/theme/icon_and_font_color", 0, "Auto,Dark,Light")590EDITOR_SETTING_BASIC(Variant::COLOR, PROPERTY_HINT_NONE, "interface/theme/base_color", Color(0.14, 0.14, 0.14), "")591EDITOR_SETTING_BASIC(Variant::COLOR, PROPERTY_HINT_NONE, "interface/theme/accent_color", Color(0.34, 0.62, 1.0), "")592EDITOR_SETTING_BASIC(Variant::BOOL, PROPERTY_HINT_NONE, "interface/theme/use_system_accent_color", false, "")593EDITOR_SETTING_BASIC(Variant::FLOAT, PROPERTY_HINT_RANGE, "interface/theme/contrast", 0.3, "-1,1,0.01")594EDITOR_SETTING(Variant::BOOL, PROPERTY_HINT_NONE, "interface/theme/draw_extra_borders", false, "")595EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "interface/theme/icon_saturation", 2.0, "0,2,0.01")596EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "interface/theme/draw_relationship_lines", (int32_t)EditorThemeManager::RELATIONSHIP_SELECTED_ONLY, "None,Selected Only,All")597EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "interface/theme/relationship_line_opacity", 0.1, "0.00,1,0.01")598EDITOR_SETTING(Variant::INT, PROPERTY_HINT_RANGE, "interface/theme/border_size", 0, "0,2,1")599EDITOR_SETTING(Variant::INT, PROPERTY_HINT_RANGE, "interface/theme/corner_radius", 4, "0,6,1")600EDITOR_SETTING(Variant::INT, PROPERTY_HINT_RANGE, "interface/theme/base_spacing", 4, "0,8,1")601EDITOR_SETTING(Variant::INT, PROPERTY_HINT_RANGE, "interface/theme/additional_spacing", 0, "0,8,1")602EDITOR_SETTING_USAGE(Variant::STRING, PROPERTY_HINT_GLOBAL_FILE, "interface/theme/custom_theme", "", "*.res,*.tres,*.theme", PROPERTY_USAGE_DEFAULT)603604// Touchscreen605bool has_touchscreen_ui = DisplayServer::get_singleton()->is_touchscreen_available();606bool is_native_touchscreen = has_touchscreen_ui && !OS::get_singleton()->has_feature("xr_editor"); // Disable some touchscreen settings by default for the XR Editor.607608EDITOR_SETTING(Variant::BOOL, PROPERTY_HINT_NONE, "interface/touchscreen/enable_touch_optimizations", is_native_touchscreen, "")609set_restart_if_changed("interface/touchscreen/enable_touch_optimizations", true);610EDITOR_SETTING(Variant::BOOL, PROPERTY_HINT_NONE, "interface/touchscreen/enable_long_press_as_right_click", is_native_touchscreen, "")611set_restart_if_changed("interface/touchscreen/enable_long_press_as_right_click", true);612613EDITOR_SETTING(Variant::BOOL, PROPERTY_HINT_NONE, "interface/touchscreen/enable_pan_and_scale_gestures", has_touchscreen_ui, "")614set_restart_if_changed("interface/touchscreen/enable_pan_and_scale_gestures", true);615EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "interface/touchscreen/scale_gizmo_handles", has_touchscreen_ui ? 2 : 1, "1,5,1")616set_restart_if_changed("interface/touchscreen/scale_gizmo_handles", true);617618// Only available in the Android/XR editor.619String touch_actions_panel_hints = "Disabled:0,Embedded Panel:1,Floating Panel:2";620EDITOR_SETTING_BASIC(Variant::INT, PROPERTY_HINT_ENUM, "interface/touchscreen/touch_actions_panel", 1, touch_actions_panel_hints)621622// Scene tabs623EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "interface/scene_tabs/display_close_button", 1, "Never,If Tab Active,Always"); // TabBar::CloseButtonDisplayPolicy624_initial_set("interface/scene_tabs/show_thumbnail_on_hover", true);625EDITOR_SETTING_USAGE(Variant::INT, PROPERTY_HINT_RANGE, "interface/scene_tabs/maximum_width", 350, "0,9999,1", PROPERTY_USAGE_DEFAULT)626_initial_set("interface/scene_tabs/show_script_button", false, true);627_initial_set("interface/scene_tabs/restore_scenes_on_load", true, true);628EDITOR_SETTING_BASIC(Variant::BOOL, PROPERTY_HINT_NONE, "interface/scene_tabs/auto_select_current_scene_file", false, "");629630// Multi Window631EDITOR_SETTING_BASIC(Variant::BOOL, PROPERTY_HINT_NONE, "interface/multi_window/enable", true, "");632EDITOR_SETTING_BASIC(Variant::BOOL, PROPERTY_HINT_NONE, "interface/multi_window/restore_windows_on_load", true, "");633EDITOR_SETTING_BASIC(Variant::BOOL, PROPERTY_HINT_NONE, "interface/multi_window/maximize_window", false, "");634set_restart_if_changed("interface/multi_window/enable", true);635636/* Filesystem */637638// External Programs639EDITOR_SETTING_BASIC(Variant::STRING, PROPERTY_HINT_GLOBAL_FILE, "filesystem/external_programs/raster_image_editor", "", "")640EDITOR_SETTING_BASIC(Variant::STRING, PROPERTY_HINT_GLOBAL_FILE, "filesystem/external_programs/vector_image_editor", "", "")641EDITOR_SETTING_BASIC(Variant::STRING, PROPERTY_HINT_GLOBAL_FILE, "filesystem/external_programs/audio_editor", "", "")642EDITOR_SETTING_BASIC(Variant::STRING, PROPERTY_HINT_GLOBAL_FILE, "filesystem/external_programs/3d_model_editor", "", "")643EDITOR_SETTING_BASIC(Variant::STRING, PROPERTY_HINT_GLOBAL_FILE, "filesystem/external_programs/terminal_emulator", "", "")644EDITOR_SETTING(Variant::STRING, PROPERTY_HINT_PLACEHOLDER_TEXT, "filesystem/external_programs/terminal_emulator_flags", "", "Call flags with placeholder: {directory}.");645646// Directories647EDITOR_SETTING(Variant::STRING, PROPERTY_HINT_GLOBAL_DIR, "filesystem/directories/autoscan_project_path", "", "")648const String fs_dir_default_project_path = OS::get_singleton()->has_environment("HOME") ? OS::get_singleton()->get_environment("HOME") : OS::get_singleton()->get_system_dir(OS::SYSTEM_DIR_DOCUMENTS);649EDITOR_SETTING_BASIC(Variant::STRING, PROPERTY_HINT_GLOBAL_DIR, "filesystem/directories/default_project_path", fs_dir_default_project_path, "")650651// On save652_initial_set("filesystem/on_save/compress_binary_resources", true);653_initial_set("filesystem/on_save/safe_save_on_backup_then_rename", true);654_initial_set("filesystem/on_save/warn_on_saving_large_text_resources", true);655656// EditorFileServer657_initial_set("filesystem/file_server/port", 6010);658_initial_set("filesystem/file_server/password", "");659660// File dialog661_initial_set("filesystem/file_dialog/show_hidden_files", false);662EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "filesystem/file_dialog/display_mode", 0, "Thumbnails,List")663EDITOR_SETTING(Variant::INT, PROPERTY_HINT_RANGE, "filesystem/file_dialog/thumbnail_size", 64, "32,128,16")664665// Quick Open dialog666EDITOR_SETTING_USAGE(Variant::INT, PROPERTY_HINT_RANGE, "filesystem/quick_open_dialog/max_results", 100, "0,10000,1", PROPERTY_USAGE_DEFAULT)667_initial_set("filesystem/quick_open_dialog/instant_preview", false);668_initial_set("filesystem/quick_open_dialog/show_search_highlight", true);669_initial_set("filesystem/quick_open_dialog/enable_fuzzy_matching", true);670EDITOR_SETTING_USAGE(Variant::INT, PROPERTY_HINT_RANGE, "filesystem/quick_open_dialog/max_fuzzy_misses", 2, "0,10,1", PROPERTY_USAGE_DEFAULT)671_initial_set("filesystem/quick_open_dialog/include_addons", false);672EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "filesystem/quick_open_dialog/default_display_mode", 0, "Adaptive,Last Used")673674// Import (for glft module)675EDITOR_SETTING_USAGE(Variant::STRING, PROPERTY_HINT_GLOBAL_FILE, "filesystem/import/blender/blender_path", "", "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED | PROPERTY_USAGE_EDITOR_BASIC_SETTING)676EDITOR_SETTING_USAGE(Variant::INT, PROPERTY_HINT_RANGE, "filesystem/import/blender/rpc_port", 6011, "0,65535,1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)677EDITOR_SETTING_USAGE(Variant::FLOAT, PROPERTY_HINT_RANGE, "filesystem/import/blender/rpc_server_uptime", 5, "0,300,1,or_greater,suffix:s", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)678EDITOR_SETTING_USAGE(Variant::STRING, PROPERTY_HINT_GLOBAL_FILE, "filesystem/import/fbx/fbx2gltf_path", "", "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)679680// Tools (denoise)681EDITOR_SETTING_USAGE(Variant::STRING, PROPERTY_HINT_GLOBAL_DIR, "filesystem/tools/oidn/oidn_denoise_path", "", "", PROPERTY_USAGE_DEFAULT)682683/* Docks */684685// SceneTree686_initial_set("docks/scene_tree/ask_before_deleting_related_animation_tracks", true);687_initial_set("docks/scene_tree/start_create_dialog_fully_expanded", false);688_initial_set("docks/scene_tree/auto_expand_to_selected", true);689_initial_set("docks/scene_tree/center_node_on_reparent", false);690_initial_set("docks/scene_tree/hide_filtered_out_parents", true);691_initial_set("docks/scene_tree/accessibility_warnings", false);692693// FileSystem694EDITOR_SETTING(Variant::INT, PROPERTY_HINT_RANGE, "docks/filesystem/thumbnail_size", 64, "32,128,16")695_initial_set("docks/filesystem/always_show_folders", true);696_initial_set("docks/filesystem/textfile_extensions", "txt,md,cfg,ini,log,json,yml,yaml,toml,xml");697_initial_set("docks/filesystem/other_file_extensions", "ico,icns");698_initial_set("docks/filesystem/automatically_open_created_scripts", true);699700// Property editor701EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "docks/property_editor/auto_refresh_interval", 0.2, "0.01,1,0.001"); // Update 5 times per second by default.702EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "docks/property_editor/subresource_hue_tint", 0.75, "0,1,0.01")703704/* Text editor */705706// Theme707EDITOR_SETTING_BASIC(Variant::STRING, PROPERTY_HINT_ENUM, "text_editor/theme/color_theme", "Default", "Default,Godot 2,Custom")708709// Theme: Highlighting710const LocalVector<StringName> basic_text_editor_settings = {711"text_editor/theme/highlighting/symbol_color",712"text_editor/theme/highlighting/keyword_color",713"text_editor/theme/highlighting/control_flow_keyword_color",714"text_editor/theme/highlighting/base_type_color",715"text_editor/theme/highlighting/engine_type_color",716"text_editor/theme/highlighting/user_type_color",717"text_editor/theme/highlighting/comment_color",718"text_editor/theme/highlighting/doc_comment_color",719"text_editor/theme/highlighting/string_color",720"text_editor/theme/highlighting/string_placeholder_color",721"text_editor/theme/highlighting/background_color",722"text_editor/theme/highlighting/text_color",723"text_editor/theme/highlighting/line_number_color",724"text_editor/theme/highlighting/safe_line_number_color",725"text_editor/theme/highlighting/caret_color",726"text_editor/theme/highlighting/caret_background_color",727"text_editor/theme/highlighting/text_selected_color",728"text_editor/theme/highlighting/selection_color",729"text_editor/theme/highlighting/brace_mismatch_color",730"text_editor/theme/highlighting/current_line_color",731"text_editor/theme/highlighting/line_length_guideline_color",732"text_editor/theme/highlighting/word_highlighted_color",733"text_editor/theme/highlighting/number_color",734"text_editor/theme/highlighting/function_color",735"text_editor/theme/highlighting/member_variable_color",736"text_editor/theme/highlighting/mark_color",737};738// These values will be overwritten by EditorThemeManager, but can still be seen in some edge cases.739const HashMap<StringName, Color> text_colors = get_godot2_text_editor_theme();740for (const KeyValue<StringName, Color> &text_color : text_colors) {741if (basic_text_editor_settings.has(text_color.key)) {742EDITOR_SETTING_BASIC(Variant::COLOR, PROPERTY_HINT_NONE, text_color.key, text_color.value, "")743} else {744EDITOR_SETTING(Variant::COLOR, PROPERTY_HINT_NONE, text_color.key, text_color.value, "")745}746}747748// The list is based on <https://github.com/KDE/syntax-highlighting/blob/master/data/syntax/alert.xml>.749_initial_set("text_editor/theme/highlighting/comment_markers/critical_list", "ALERT,ATTENTION,CAUTION,CRITICAL,DANGER,SECURITY");750_initial_set("text_editor/theme/highlighting/comment_markers/warning_list", "BUG,DEPRECATED,FIXME,HACK,TASK,TBD,TODO,WARNING");751_initial_set("text_editor/theme/highlighting/comment_markers/notice_list", "INFO,NOTE,NOTICE,TEST,TESTING");752753// Appearance754EDITOR_SETTING_BASIC(Variant::BOOL, PROPERTY_HINT_NONE, "text_editor/appearance/enable_inline_color_picker", true, "");755756// Appearance: Caret757EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "text_editor/appearance/caret/type", 0, "Line,Block")758_initial_set("text_editor/appearance/caret/caret_blink", true, true);759EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "text_editor/appearance/caret/caret_blink_interval", 0.5, "0.1,10,0.01")760_initial_set("text_editor/appearance/caret/highlight_current_line", true, true);761_initial_set("text_editor/appearance/caret/highlight_all_occurrences", true, true);762763// Appearance: Guidelines764_initial_set("text_editor/appearance/guidelines/show_line_length_guidelines", true, true);765EDITOR_SETTING(Variant::INT, PROPERTY_HINT_RANGE, "text_editor/appearance/guidelines/line_length_guideline_soft_column", 80, "20,160,1")766EDITOR_SETTING(Variant::INT, PROPERTY_HINT_RANGE, "text_editor/appearance/guidelines/line_length_guideline_hard_column", 100, "20,160,1")767768// Appearance: Gutters769_initial_set("text_editor/appearance/gutters/show_line_numbers", true, true);770_initial_set("text_editor/appearance/gutters/line_numbers_zero_padded", false, true);771_initial_set("text_editor/appearance/gutters/highlight_type_safe_lines", true, true);772_initial_set("text_editor/appearance/gutters/show_info_gutter", true, true);773774// Appearance: Minimap775_initial_set("text_editor/appearance/minimap/show_minimap", true, true);776EDITOR_SETTING(Variant::INT, PROPERTY_HINT_RANGE, "text_editor/appearance/minimap/minimap_width", 80, "50,250,1")777778// Appearance: Lines779_initial_set("text_editor/appearance/lines/code_folding", true, true);780EDITOR_SETTING_BASIC(Variant::INT, PROPERTY_HINT_ENUM, "text_editor/appearance/lines/word_wrap", 0, "None,Boundary")781EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "text_editor/appearance/lines/autowrap_mode", 3, "Arbitrary:1,Word:2,Word (Smart):3")782783// Appearance: Whitespace784_initial_set("text_editor/appearance/whitespace/draw_tabs", true, true);785_initial_set("text_editor/appearance/whitespace/draw_spaces", false, true);786EDITOR_SETTING(Variant::INT, PROPERTY_HINT_RANGE, "text_editor/appearance/whitespace/line_spacing", 4, "0,50,1")787788// Behavior789// Behavior: General790_initial_set("text_editor/behavior/general/empty_selection_clipboard", true);791792// Behavior: Navigation793_initial_set("text_editor/behavior/navigation/move_caret_on_right_click", true, true);794_initial_set("text_editor/behavior/navigation/scroll_past_end_of_file", false, true);795_initial_set("text_editor/behavior/navigation/smooth_scrolling", true, true);796EDITOR_SETTING(Variant::INT, PROPERTY_HINT_RANGE, "text_editor/behavior/navigation/v_scroll_speed", 80, "1,10000,1")797_initial_set("text_editor/behavior/navigation/drag_and_drop_selection", true, true);798_initial_set("text_editor/behavior/navigation/stay_in_script_editor_on_node_selected", true, true);799_initial_set("text_editor/behavior/navigation/open_script_when_connecting_signal_to_existing_method", true, true);800_initial_set("text_editor/behavior/navigation/use_default_word_separators", true); // Includes ´`~$^=+|<> General punctuation and CJK punctuation.801_initial_set("text_editor/behavior/navigation/use_custom_word_separators", false);802_initial_set("text_editor/behavior/navigation/custom_word_separators", ""); // Custom word separators.803804// Behavior: Indent805EDITOR_SETTING_BASIC(Variant::INT, PROPERTY_HINT_ENUM, "text_editor/behavior/indent/type", 0, "Tabs,Spaces")806EDITOR_SETTING_BASIC(Variant::INT, PROPERTY_HINT_RANGE, "text_editor/behavior/indent/size", 4, "1,64,1") // size of 0 crashes.807_initial_set("text_editor/behavior/indent/auto_indent", true);808_initial_set("text_editor/behavior/indent/indent_wrapped_lines", true);809810// Behavior: Files811_initial_set("text_editor/behavior/files/trim_trailing_whitespace_on_save", false);812_initial_set("text_editor/behavior/files/trim_final_newlines_on_save", true);813_initial_set("text_editor/behavior/files/autosave_interval_secs", 0);814_initial_set("text_editor/behavior/files/restore_scripts_on_load", true);815_initial_set("text_editor/behavior/files/convert_indent_on_save", true);816_initial_set("text_editor/behavior/files/auto_reload_scripts_on_external_change", true);817_initial_set("text_editor/behavior/files/auto_reload_and_parse_scripts_on_save", true);818_initial_set("text_editor/behavior/files/open_dominant_script_on_scene_change", false, true);819_initial_set("text_editor/behavior/files/drop_preload_resources_as_uid", true, true);820821// Behavior: Documentation822_initial_set("text_editor/behavior/documentation/enable_tooltips", true, true);823824// Script list825_initial_set("text_editor/script_list/show_members_overview", true, true);826_initial_set("text_editor/script_list/sort_members_outline_alphabetically", false, true);827_initial_set("text_editor/script_list/script_temperature_enabled", true);828_initial_set("text_editor/script_list/script_temperature_history_size", 15);829_initial_set("text_editor/script_list/highlight_scene_scripts", true);830_initial_set("text_editor/script_list/group_help_pages", true);831EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "text_editor/script_list/sort_scripts_by", 0, "None:2,Name:0,Path:1");832EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "text_editor/script_list/list_script_names_as", 0, "Name,Parent Directory And Name,Full Path");833EDITOR_SETTING(Variant::STRING, PROPERTY_HINT_GLOBAL_FILE, "text_editor/external/exec_path", "", "");834EDITOR_SETTING(Variant::STRING, PROPERTY_HINT_PLACEHOLDER_TEXT, "text_editor/external/exec_flags", "{file}", "Call flags with placeholders: {project}, {file}, {col}, {line}.");835836// Completion837EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "text_editor/completion/idle_parse_delay", 1.5, "0.1,10,0.01")838EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "text_editor/completion/idle_parse_delay_with_errors_found", 0.5, "0.1,5,0.01")839_initial_set("text_editor/completion/auto_brace_complete", true, true);840_initial_set("text_editor/completion/code_complete_enabled", true, true);841EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "text_editor/completion/code_complete_delay", 0.3, "0.01,5,0.01,or_greater")842_initial_set("text_editor/completion/put_callhint_tooltip_below_current_line", true);843_initial_set("text_editor/completion/complete_file_paths", true);844_initial_set("text_editor/completion/add_type_hints", true, true);845_initial_set("text_editor/completion/add_string_name_literals", false, true);846_initial_set("text_editor/completion/add_node_path_literals", false, true);847_initial_set("text_editor/completion/use_single_quotes", false, true);848_initial_set("text_editor/completion/colorize_suggestions", true);849850// External editor (ScriptEditorPlugin)851_initial_set("text_editor/external/use_external_editor", false, true);852_initial_set("text_editor/external/exec_path", "");853854// Help855_initial_set("text_editor/help/show_help_index", true);856EDITOR_SETTING_BASIC(Variant::INT, PROPERTY_HINT_RANGE, "text_editor/help/help_font_size", 16, "8,48,1")857EDITOR_SETTING_BASIC(Variant::INT, PROPERTY_HINT_RANGE, "text_editor/help/help_source_font_size", 15, "8,48,1")858EDITOR_SETTING_BASIC(Variant::INT, PROPERTY_HINT_RANGE, "text_editor/help/help_title_font_size", 23, "8,64,1")859EDITOR_SETTING_BASIC(Variant::INT, PROPERTY_HINT_ENUM, "text_editor/help/class_reference_examples", 0, "GDScript,C#,GDScript and C#")860_initial_set("text_editor/help/sort_functions_alphabetically", true);861862/* Editors */863864// GridMap865// GridMapEditor866EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "editors/grid_map/pick_distance", 5000.0, "1,8192,0.1,or_greater");867EDITOR_SETTING_BASIC(Variant::INT, PROPERTY_HINT_RANGE, "editors/grid_map/preview_size", 64, "16,128,1")868869// 3D870EDITOR_SETTING_BASIC(Variant::COLOR, PROPERTY_HINT_NONE, "editors/3d/primary_grid_color", Color(0.56, 0.56, 0.56, 0.5), "")871EDITOR_SETTING_BASIC(Variant::COLOR, PROPERTY_HINT_NONE, "editors/3d/secondary_grid_color", Color(0.38, 0.38, 0.38, 0.5), "")872873// Use a similar color to the 2D editor selection.874EDITOR_SETTING_USAGE(Variant::COLOR, PROPERTY_HINT_NONE, "editors/3d/selection_box_color", Color(1.0, 0.5, 0), "", PROPERTY_USAGE_DEFAULT)875EDITOR_SETTING_USAGE(Variant::COLOR, PROPERTY_HINT_NONE, "editors/3d/active_selection_box_color", Color(1.5, 0.75, 0, 1.0), "", PROPERTY_USAGE_DEFAULT)876EDITOR_SETTING_USAGE(Variant::COLOR, PROPERTY_HINT_NONE, "editors/3d_gizmos/gizmo_colors/instantiated", Color(0.7, 0.7, 0.7, 0.6), "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)877EDITOR_SETTING_USAGE(Variant::COLOR, PROPERTY_HINT_NONE, "editors/3d_gizmos/gizmo_colors/joint", Color(0.5, 0.8, 1), "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)878EDITOR_SETTING_USAGE(Variant::COLOR, PROPERTY_HINT_NONE, "editors/3d_gizmos/gizmo_colors/aabb", Color(0.28, 0.8, 0.82), "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)879EDITOR_SETTING_USAGE(Variant::COLOR, PROPERTY_HINT_NONE, "editors/3d_gizmos/gizmo_colors/stream_player_3d", Color(0.4, 0.8, 1), "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)880EDITOR_SETTING_USAGE(Variant::COLOR, PROPERTY_HINT_NONE, "editors/3d_gizmos/gizmo_colors/camera", Color(0.8, 0.4, 0.8), "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)881EDITOR_SETTING_USAGE(Variant::COLOR, PROPERTY_HINT_NONE, "editors/3d_gizmos/gizmo_colors/decal", Color(0.6, 0.5, 1.0), "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)882EDITOR_SETTING_USAGE(Variant::COLOR, PROPERTY_HINT_NONE, "editors/3d_gizmos/gizmo_colors/fog_volume", Color(0.5, 0.7, 1), "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)883EDITOR_SETTING_USAGE(Variant::COLOR, PROPERTY_HINT_NONE, "editors/3d_gizmos/gizmo_colors/particles", Color(0.8, 0.7, 0.4), "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)884EDITOR_SETTING_USAGE(Variant::COLOR, PROPERTY_HINT_NONE, "editors/3d_gizmos/gizmo_colors/particle_attractor", Color(1, 0.7, 0.5), "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)885EDITOR_SETTING_USAGE(Variant::COLOR, PROPERTY_HINT_NONE, "editors/3d_gizmos/gizmo_colors/particle_collision", Color(0.5, 0.7, 1), "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)886EDITOR_SETTING_USAGE(Variant::COLOR, PROPERTY_HINT_NONE, "editors/3d_gizmos/gizmo_colors/joint_body_a", Color(0.6, 0.8, 1), "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)887EDITOR_SETTING_USAGE(Variant::COLOR, PROPERTY_HINT_NONE, "editors/3d_gizmos/gizmo_colors/joint_body_b", Color(0.6, 0.9, 1), "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)888EDITOR_SETTING_USAGE(Variant::COLOR, PROPERTY_HINT_NONE, "editors/3d_gizmos/gizmo_colors/lightmap_lines", Color(0.5, 0.6, 1), "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)889EDITOR_SETTING_USAGE(Variant::COLOR, PROPERTY_HINT_NONE, "editors/3d_gizmos/gizmo_colors/lightprobe_lines", Color(0.5, 0.6, 1), "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)890EDITOR_SETTING_USAGE(Variant::COLOR, PROPERTY_HINT_NONE, "editors/3d_gizmos/gizmo_colors/occluder", Color(0.8, 0.5, 1), "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)891EDITOR_SETTING_USAGE(Variant::COLOR, PROPERTY_HINT_NONE, "editors/3d_gizmos/gizmo_colors/reflection_probe", Color(0.6, 1, 0.5), "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)892EDITOR_SETTING_USAGE(Variant::COLOR, PROPERTY_HINT_NONE, "editors/3d_gizmos/gizmo_colors/visibility_notifier", Color(0.8, 0.5, 0.7), "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)893EDITOR_SETTING_USAGE(Variant::COLOR, PROPERTY_HINT_NONE, "editors/3d_gizmos/gizmo_colors/voxel_gi", Color(0.5, 1, 0.6), "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)894EDITOR_SETTING_USAGE(Variant::COLOR, PROPERTY_HINT_NONE, "editors/3d_gizmos/gizmo_colors/path_tilt", Color(1.0, 1.0, 0.4, 0.9), "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)895EDITOR_SETTING_USAGE(Variant::COLOR, PROPERTY_HINT_NONE, "editors/3d_gizmos/gizmo_colors/skeleton", Color(1, 0.8, 0.4), "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)896EDITOR_SETTING_USAGE(Variant::COLOR, PROPERTY_HINT_NONE, "editors/3d_gizmos/gizmo_colors/selected_bone", Color(0.8, 0.3, 0.0), "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)897EDITOR_SETTING_USAGE(Variant::COLOR, PROPERTY_HINT_NONE, "editors/3d_gizmos/gizmo_colors/csg", Color(0.0, 0.4, 1, 0.15), "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)898EDITOR_SETTING(Variant::COLOR, PROPERTY_HINT_NONE, "editors/3d_gizmos/gizmo_colors/gridmap_grid", Color(0.8, 0.5, 0.1), "")899EDITOR_SETTING_USAGE(Variant::COLOR, PROPERTY_HINT_NONE, "editors/3d_gizmos/gizmo_colors/spring_bone_joint", Color(0.8, 0.9, 0.6), "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)900EDITOR_SETTING_USAGE(Variant::COLOR, PROPERTY_HINT_NONE, "editors/3d_gizmos/gizmo_colors/spring_bone_collision", Color(0.6, 0.8, 0.9), "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)901EDITOR_SETTING_USAGE(Variant::COLOR, PROPERTY_HINT_NONE, "editors/3d_gizmos/gizmo_colors/spring_bone_inside_collision", Color(0.9, 0.6, 0.8), "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)902EDITOR_SETTING_USAGE(Variant::COLOR, PROPERTY_HINT_NONE, "editors/3d_gizmos/gizmo_colors/ik_chain", Color(0.6, 0.9, 0.8), "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)903_initial_set("editors/3d_gizmos/gizmo_settings/bone_axis_length", (float)0.1);904EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "editors/3d_gizmos/gizmo_settings/bone_shape", 1, "Wire,Octahedron");905EDITOR_SETTING_USAGE(Variant::FLOAT, PROPERTY_HINT_RANGE, "editors/3d_gizmos/gizmo_settings/path3d_tilt_disk_size", 0.8, "0.01,4.0,0.001,or_greater", PROPERTY_USAGE_DEFAULT)906EDITOR_SETTING_USAGE(Variant::FLOAT, PROPERTY_HINT_RANGE, "editors/3d_gizmos/gizmo_settings/lightmap_gi_probe_size", 0.4, "0.0,1.0,0.001,or_greater", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)907_initial_set("editors/3d_gizmos/gizmo_settings/show_collision_shapes_only_when_selected", false);908909// If a line is a multiple of this, it uses the primary grid color.910// Use a power of 2 value by default as it's more common to use powers of 2 in level design.911EDITOR_SETTING_BASIC(Variant::INT, PROPERTY_HINT_RANGE, "editors/3d/primary_grid_steps", 8, "1,100,1")912EDITOR_SETTING_BASIC(Variant::INT, PROPERTY_HINT_RANGE, "editors/3d/grid_size", 200, "1,2000,1")913// Higher values produce graphical artifacts when far away unless View Z-Far914// is increased significantly more than it really should need to be.915EDITOR_SETTING(Variant::INT, PROPERTY_HINT_RANGE, "editors/3d/grid_division_level_max", 2, "-1,3,1")916// Lower values produce graphical artifacts regardless of view clipping planes, so limit to -2 as a lower bound.917EDITOR_SETTING(Variant::INT, PROPERTY_HINT_RANGE, "editors/3d/grid_division_level_min", 0, "-2,2,1")918// -0.2 seems like a sensible default. -1.0 gives Blender-like behavior, 0.5 gives huge grids.919EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "editors/3d/grid_division_level_bias", -0.2, "-1.0,0.5,0.1")920921_initial_set("editors/3d/grid_xz_plane", true);922_initial_set("editors/3d/grid_xy_plane", false);923_initial_set("editors/3d/grid_yz_plane", false);924925// Use a lower default FOV for the 3D camera compared to the926// Camera3D node as the 3D viewport doesn't span the whole screen.927// This means it's technically viewed from a further distance, which warrants a narrower FOV.928EDITOR_SETTING_BASIC(Variant::FLOAT, PROPERTY_HINT_RANGE, "editors/3d/default_fov", 70.0, "1,179,0.1,degrees")929EDITOR_SETTING_BASIC(Variant::FLOAT, PROPERTY_HINT_RANGE, "editors/3d/default_z_near", 0.05, "0.01,10,0.01,or_greater,suffix:m")930EDITOR_SETTING_BASIC(Variant::FLOAT, PROPERTY_HINT_RANGE, "editors/3d/default_z_far", 4000.0, "0.1,4000,0.1,or_greater,suffix:m")931932// 3D: Navigation933_initial_set("editors/3d/navigation/invert_x_axis", false, true);934_initial_set("editors/3d/navigation/invert_y_axis", false, true);935EDITOR_SETTING_BASIC(Variant::INT, PROPERTY_HINT_ENUM, "editors/3d/navigation/navigation_scheme", 0, "Godot:0,Maya:1,Modo:2,Tablet/Trackpad:4,Custom:3")936EDITOR_SETTING_BASIC(Variant::INT, PROPERTY_HINT_ENUM, "editors/3d/navigation/orbit_mouse_button", 1, "Left Mouse,Middle Mouse,Right Mouse,Mouse Button 4,Mouse Button 5")937EDITOR_SETTING_BASIC(Variant::INT, PROPERTY_HINT_ENUM, "editors/3d/navigation/pan_mouse_button", 1, "Left Mouse,Middle Mouse,Right Mouse,Mouse Button 4,Mouse Button 5")938EDITOR_SETTING_BASIC(Variant::INT, PROPERTY_HINT_ENUM, "editors/3d/navigation/zoom_mouse_button", 1, "Left Mouse,Middle Mouse,Right Mouse,Mouse Button 4,Mouse Button 5")939EDITOR_SETTING_BASIC(Variant::INT, PROPERTY_HINT_ENUM, "editors/3d/navigation/zoom_style", 0, "Vertical,Horizontal")940941_initial_set("editors/3d/navigation/emulate_numpad", true, true);942_initial_set("editors/3d/navigation/emulate_3_button_mouse", false, true);943_initial_set("editors/3d/navigation/warped_mouse_panning", true, true);944945// 3D: Navigation feel946EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "editors/3d/navigation_feel/orbit_sensitivity", 0.25, "0.01,20,0.001")947EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "editors/3d/navigation_feel/translation_sensitivity", 1.0, "0.01,20,0.001")948EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "editors/3d/navigation_feel/orbit_inertia", 0.0, "0,1,0.001")949EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "editors/3d/navigation_feel/translation_inertia", 0.05, "0,1,0.001")950EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "editors/3d/navigation_feel/zoom_inertia", 0.05, "0,1,0.001")951EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "editors/3d/navigation_feel/angle_snap_threshold", 10.0, "1,20,0.1,degrees")952_initial_set("editors/3d/navigation/show_viewport_rotation_gizmo", true);953_initial_set("editors/3d/navigation/show_viewport_navigation_gizmo", DisplayServer::get_singleton()->is_touchscreen_available());954955// 3D: Freelook956EDITOR_SETTING_BASIC(Variant::INT, PROPERTY_HINT_ENUM, "editors/3d/freelook/freelook_navigation_scheme", 0, "Default,Partially Axis-Locked (id Tech),Fully Axis-Locked (Minecraft)")957EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "editors/3d/freelook/freelook_sensitivity", 0.25, "0.01,2,0.001")958EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "editors/3d/freelook/freelook_inertia", 0.0, "0,1,0.001")959EDITOR_SETTING_BASIC(Variant::FLOAT, PROPERTY_HINT_RANGE, "editors/3d/freelook/freelook_base_speed", 5.0, "0,10,0.01,or_greater")960EDITOR_SETTING_BASIC(Variant::INT, PROPERTY_HINT_ENUM, "editors/3d/freelook/freelook_activation_modifier", 0, "None,Shift,Alt,Meta,Ctrl")961_initial_set("editors/3d/freelook/freelook_speed_zoom_link", false);962963// 3D: Manipulator964EDITOR_SETTING(Variant::INT, PROPERTY_HINT_RANGE, "editors/3d/manipulator_gizmo_size", 80, "16,160,1");965EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "editors/3d/manipulator_gizmo_opacity", 0.9, "0,1,0.01");966EDITOR_SETTING(Variant::INT, PROPERTY_HINT_FLAGS, "editors/3d/show_gizmo_during_rotation", 2, "Global,Local");967968// 2D969_initial_set("editors/2d/grid_color", Color(1.0, 1.0, 1.0, 0.07), true);970_initial_set("editors/2d/guides_color", Color(0.6, 0.0, 0.8), true);971_initial_set("editors/2d/smart_snapping_line_color", Color(0.9, 0.1, 0.1), true);972EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "editors/2d/bone_width", 5.0, "0.01,20,0.01,or_greater")973_initial_set("editors/2d/bone_color1", Color(1.0, 1.0, 1.0, 0.7));974_initial_set("editors/2d/bone_color2", Color(0.6, 0.6, 0.6, 0.7));975_initial_set("editors/2d/bone_selected_color", Color(0.9, 0.45, 0.45, 0.7));976_initial_set("editors/2d/bone_ik_color", Color(0.9, 0.9, 0.45, 0.7));977_initial_set("editors/2d/bone_outline_color", Color(0.35, 0.35, 0.35, 0.5));978EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "editors/2d/bone_outline_size", 2.0, "0.01,8,0.01,or_greater")979_initial_set("editors/2d/viewport_border_color", Color(0.4, 0.4, 1.0, 0.4), true);980_initial_set("editors/2d/use_integer_zoom_by_default", false, true);981EDITOR_SETTING_BASIC(Variant::FLOAT, PROPERTY_HINT_RANGE, "editors/2d/zoom_speed_factor", 1.1, "1.01,2,0.01")982EDITOR_SETTING_BASIC(Variant::FLOAT, PROPERTY_HINT_RANGE, "editors/2d/ruler_width", 16.0, "12.0,30.0,1.0")983EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "editors/2d/auto_resample_delay", 0.3, "0.1,2,0.1")984985// Bone mapper (BoneMapEditorPlugin)986_initial_set("editors/bone_mapper/handle_colors/unset", Color(0.3, 0.3, 0.3));987_initial_set("editors/bone_mapper/handle_colors/set", Color(0.1, 0.6, 0.25));988_initial_set("editors/bone_mapper/handle_colors/missing", Color(0.8, 0.2, 0.8));989_initial_set("editors/bone_mapper/handle_colors/error", Color(0.8, 0.2, 0.2));990991// Panning992// Enum should be in sync with ControlScheme in ViewPanner.993EDITOR_SETTING_BASIC(Variant::INT, PROPERTY_HINT_ENUM, "editors/panning/2d_editor_panning_scheme", 0, "Scroll Zooms,Scroll Pans");994EDITOR_SETTING_BASIC(Variant::INT, PROPERTY_HINT_ENUM, "editors/panning/sub_editors_panning_scheme", 0, "Scroll Zooms,Scroll Pans");995EDITOR_SETTING_BASIC(Variant::INT, PROPERTY_HINT_ENUM, "editors/panning/animation_editors_panning_scheme", 1, "Scroll Zooms,Scroll Pans");996_initial_set("editors/panning/simple_panning", false);997_initial_set("editors/panning/warped_mouse_panning", true);998_initial_set("editors/panning/2d_editor_pan_speed", 20, true);999EDITOR_SETTING_BASIC(Variant::INT, PROPERTY_HINT_ENUM, "editors/panning/zoom_style", 0, "Vertical,Horizontal");10001001// Tiles editor1002_initial_set("editors/tiles_editor/display_grid", true);1003_initial_set("editors/tiles_editor/highlight_selected_layer", true);1004_initial_set("editors/tiles_editor/grid_color", Color(1.0, 0.5, 0.2, 0.5));10051006// Polygon editor1007_initial_set("editors/polygon_editor/point_grab_radius", has_touchscreen_ui ? 32 : 8);1008_initial_set("editors/polygon_editor/show_previous_outline", true);1009EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "editors/polygon_editor/auto_bake_delay", 1.5, "-1.0,10.0,0.01");10101011// Animation1012EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "editors/animation/default_animation_step", Animation::DEFAULT_STEP, "0.0,10.0,0.00000001");1013EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "editors/animation/default_fps_mode", 0, "Seconds,FPS");1014_initial_set("editors/animation/default_fps_compatibility", true);1015_initial_set("editors/animation/autorename_animation_tracks", true);1016_initial_set("editors/animation/confirm_insert_track", true, true);1017_initial_set("editors/animation/default_create_bezier_tracks", false, true);1018_initial_set("editors/animation/default_create_reset_tracks", true, true);1019_initial_set("editors/animation/insert_at_current_time", false, true);1020_initial_set("editors/animation/onion_layers_past_color", Color(1, 0, 0));1021_initial_set("editors/animation/onion_layers_future_color", Color(0, 1, 0));10221023// Shader editor1024_initial_set("editors/shader_editor/behavior/files/restore_shaders_on_load", true, true);10251026// Visual editors1027EDITOR_SETTING(Variant::STRING, PROPERTY_HINT_ENUM, "editors/visual_editors/color_theme", "Default", "Default,Legacy,Custom")10281029_load_default_visual_shader_editor_theme();10301031EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "editors/visual_editors/minimap_opacity", 0.85, "0.0,1.0,0.01")1032EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "editors/visual_editors/lines_curvature", 0.5, "0.0,1.0,0.01")1033EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "editors/visual_editors/grid_pattern", 1, "Lines,Dots")1034EDITOR_SETTING(Variant::INT, PROPERTY_HINT_RANGE, "editors/visual_editors/visual_shader/port_preview_size", 160, "100,400,0.01")10351036// Export (EditorExportPlugin)1037_initial_set("export/ssh/ssh", "");1038_initial_set("export/ssh/scp", "");10391040/* Run */10411042// Window placement1043#ifndef ANDROID_ENABLED1044EDITOR_SETTING_BASIC(Variant::INT, PROPERTY_HINT_ENUM, "run/window_placement/rect", 1, "Top Left,Centered,Custom Position,Force Maximized,Force Fullscreen")1045// Keep the enum values in sync with the `DisplayServer::SCREEN_` enum.1046String screen_hints = "Same as Editor:-5,Previous Screen:-4,Next Screen:-3,Primary Screen:-2"; // Note: Main Window Screen:-1 is not used for the main window.1047for (int i = 0; i < DisplayServer::get_singleton()->get_screen_count(); i++) {1048screen_hints += ",Screen " + itos(i + 1) + ":" + itos(i);1049}1050_initial_set("run/window_placement/rect_custom_position", Vector2());1051EDITOR_SETTING_BASIC(Variant::INT, PROPERTY_HINT_ENUM, "run/window_placement/screen", -5, screen_hints)1052#endif1053// Should match the ANDROID_WINDOW_* constants in 'platform/android/java/editor/src/main/java/org/godotengine/editor/BaseGodotEditor.kt'.1054String android_window_hints = "Auto (based on screen size):0,Same as Editor:1,Side-by-side with Editor:2";1055EDITOR_SETTING_BASIC(Variant::INT, PROPERTY_HINT_ENUM, "run/window_placement/android_window", 0, android_window_hints)10561057String game_embed_mode_hints = "Disabled:-1,Use Per-Project Configuration:0,Embed Game:1,Make Game Workspace Floating:2";1058#ifdef ANDROID_ENABLED1059if (OS::get_singleton()->has_feature("xr_editor")) {1060game_embed_mode_hints = "Disabled:-1";1061} else {1062game_embed_mode_hints = "Disabled:-1,Auto (based on screen size):0,Enabled:1";1063}1064#endif1065int default_game_embed_mode = OS::get_singleton()->has_feature("xr_editor") ? -1 : 0;1066EDITOR_SETTING_BASIC(Variant::INT, PROPERTY_HINT_ENUM, "run/window_placement/game_embed_mode", default_game_embed_mode, game_embed_mode_hints);10671068// Auto save1069_initial_set("run/auto_save/save_before_running", true, true);10701071// Bottom panel1072EDITOR_SETTING_BASIC(Variant::INT, PROPERTY_HINT_ENUM, "run/bottom_panel/action_on_play", EditorNode::ACTION_ON_PLAY_OPEN_OUTPUT, "Do Nothing,Open Output,Open Debugger")1073EDITOR_SETTING_BASIC(Variant::INT, PROPERTY_HINT_ENUM, "run/bottom_panel/action_on_stop", EditorNode::ACTION_ON_STOP_DO_NOTHING, "Do Nothing,Close Bottom Panel")10741075// Output1076EDITOR_SETTING_BASIC(Variant::INT, PROPERTY_HINT_RANGE, "run/output/font_size", 13, "8,48,1")1077_initial_set("run/output/always_clear_output_on_play", true, true);10781079EDITOR_SETTING(Variant::INT, PROPERTY_HINT_RANGE, "run/output/max_lines", 10000, "100,100000,1")10801081// Platform1082_initial_set("run/platforms/linuxbsd/prefer_wayland", false, true);1083set_restart_if_changed("run/platforms/linuxbsd/prefer_wayland", true);10841085/* Network */10861087// General1088EDITOR_SETTING_BASIC(Variant::INT, PROPERTY_HINT_ENUM, "network/connection/network_mode", 0, "Offline,Online");10891090// HTTP Proxy1091_initial_set("network/http_proxy/host", "");1092EDITOR_SETTING(Variant::INT, PROPERTY_HINT_RANGE, "network/http_proxy/port", 8080, "1,65535,1")10931094// SSL1095EDITOR_SETTING_USAGE(Variant::STRING, PROPERTY_HINT_GLOBAL_FILE, "network/tls/editor_tls_certificates", _SYSTEM_CERTS_PATH, "*.crt,*.pem", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED);1096EDITOR_SETTING_BASIC(Variant::BOOL, PROPERTY_HINT_NONE, "network/tls/enable_tls_v1.3", true, "")10971098// Debug1099_initial_set("network/debug/remote_host", "127.0.0.1"); // Hints provided in setup_network1100EDITOR_SETTING(Variant::INT, PROPERTY_HINT_RANGE, "network/debug/remote_port", 6007, "1,65535,1")11011102/* Debugger/profiler */11031104EDITOR_SETTING_BASIC(Variant::BOOL, PROPERTY_HINT_NONE, "debugger/auto_switch_to_remote_scene_tree", false, "")1105EDITOR_SETTING_BASIC(Variant::BOOL, PROPERTY_HINT_NONE, "debugger/auto_switch_to_stack_trace", true, "")1106EDITOR_SETTING(Variant::INT, PROPERTY_HINT_RANGE, "debugger/max_node_selection", 20, "1,100,1")1107EDITOR_SETTING(Variant::INT, PROPERTY_HINT_RANGE, "debugger/profiler_frame_history_size", 3600, "60,10000,1")1108EDITOR_SETTING(Variant::INT, PROPERTY_HINT_RANGE, "debugger/profiler_frame_max_functions", 64, "16,512,1")1109EDITOR_SETTING(Variant::INT, PROPERTY_HINT_RANGE, "debugger/profiler_target_fps", 60, "1,1000,1")1110EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "debugger/remote_scene_tree_refresh_interval", 1.0, "0.1,10,0.01,or_greater")1111EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "debugger/remote_inspect_refresh_interval", 0.2, "0.02,10,0.01,or_greater")1112EDITOR_SETTING_BASIC(Variant::BOOL, PROPERTY_HINT_NONE, "debugger/profile_native_calls", false, "")11131114// Version control (VersionControlEditorPlugin)1115_initial_set("version_control/username", "", true);1116_initial_set("version_control/ssh_public_key_path", "");1117_initial_set("version_control/ssh_private_key_path", "");11181119/* Extra config */11201121EDITOR_SETTING_USAGE(Variant::BOOL, PROPERTY_HINT_NONE, "input/buffering/agile_event_flushing", false, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED | PROPERTY_USAGE_EDITOR_BASIC_SETTING)1122EDITOR_SETTING_USAGE(Variant::BOOL, PROPERTY_HINT_NONE, "input/buffering/use_accumulated_input", true, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED | PROPERTY_USAGE_EDITOR_BASIC_SETTING)11231124// TRANSLATORS: Project Manager here refers to the tool used to create/manage Godot projects.1125EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "project_manager/sorting_order", 0, "Last Edited,Name,Path")1126EDITOR_SETTING_BASIC(Variant::INT, PROPERTY_HINT_ENUM, "project_manager/directory_naming_convention", 1, "No Convention,kebab-case,snake_case,camelCase,PascalCase,Title Case")11271128#if defined(WEB_ENABLED)1129// Web platform only supports `gl_compatibility`.1130const String default_renderer = "gl_compatibility";1131#elif defined(ANDROID_ENABLED)1132// Use more suitable rendering method by default.1133const String default_renderer = "mobile";1134#else1135const String default_renderer = "forward_plus";1136#endif1137EDITOR_SETTING_BASIC(Variant::STRING, PROPERTY_HINT_ENUM, "project_manager/default_renderer", default_renderer, "forward_plus,mobile,gl_compatibility")11381139#undef EDITOR_SETTING1140#undef EDITOR_SETTING_BASIC1141#undef EDITOR_SETTING_USAGE11421143if (p_extra_config.is_valid()) {1144if (p_extra_config->has_section("init_projects") && p_extra_config->has_section_key("init_projects", "list")) {1145Vector<String> list = p_extra_config->get_value("init_projects", "list");1146for (int i = 0; i < list.size(); i++) {1147String proj_name = list[i].replace("/", "::");1148set("projects/" + proj_name, list[i]);1149}1150}11511152if (p_extra_config->has_section("presets")) {1153Vector<String> keys = p_extra_config->get_section_keys("presets");11541155for (const String &key : keys) {1156Variant val = p_extra_config->get_value("presets", key);1157set(key, val);1158}1159}1160}1161}11621163void EditorSettings::_load_default_visual_shader_editor_theme() {1164// Connection type colors1165_initial_set("editors/visual_editors/connection_colors/scalar_color", Color(0.55, 0.55, 0.55));1166_initial_set("editors/visual_editors/connection_colors/vector2_color", Color(0.44, 0.43, 0.64));1167_initial_set("editors/visual_editors/connection_colors/vector3_color", Color(0.337, 0.314, 0.71));1168_initial_set("editors/visual_editors/connection_colors/vector4_color", Color(0.7, 0.65, 0.147));1169_initial_set("editors/visual_editors/connection_colors/boolean_color", Color(0.243, 0.612, 0.349));1170_initial_set("editors/visual_editors/connection_colors/transform_color", Color(0.71, 0.357, 0.64));1171_initial_set("editors/visual_editors/connection_colors/sampler_color", Color(0.659, 0.4, 0.137));11721173// Node category colors (used for the node headers)1174_initial_set("editors/visual_editors/category_colors/output_color", Color(0.26, 0.10, 0.15));1175_initial_set("editors/visual_editors/category_colors/color_color", Color(0.5, 0.5, 0.1));1176_initial_set("editors/visual_editors/category_colors/conditional_color", Color(0.208, 0.522, 0.298));1177_initial_set("editors/visual_editors/category_colors/input_color", Color(0.502, 0.2, 0.204));1178_initial_set("editors/visual_editors/category_colors/scalar_color", Color(0.1, 0.5, 0.6));1179_initial_set("editors/visual_editors/category_colors/textures_color", Color(0.5, 0.3, 0.1));1180_initial_set("editors/visual_editors/category_colors/transform_color", Color(0.5, 0.3, 0.5));1181_initial_set("editors/visual_editors/category_colors/utility_color", Color(0.2, 0.2, 0.2));1182_initial_set("editors/visual_editors/category_colors/vector_color", Color(0.2, 0.2, 0.5));1183_initial_set("editors/visual_editors/category_colors/special_color", Color(0.098, 0.361, 0.294));1184_initial_set("editors/visual_editors/category_colors/particle_color", Color(0.12, 0.358, 0.8));1185}11861187String EditorSettings::_guess_exec_args_for_extenal_editor(const String &p_path) {1188Ref<RegEx> regex = RegEx::create_from_string(R"((?:jetbrains\s*)?rider(?:\s*(eap|\d{4}\.\d+|\d{4}\.\d+\s*dev)?)?|visual\s*studio\s*code|subl(ime\s*text)?|sublime_text|zed(it(or)?)?|(g)?vim|emacs|atom|geany|kate|code|(vs)?codium)");1189Ref<RegExMatch> editor_match = regex->search(p_path.to_lower().get_file().get_basename());11901191if (editor_match.is_null()) {1192return String();1193}11941195const String editor = editor_match->get_string(0).to_lower();1196String new_exec_flags = "{file}";11971198if (editor.begins_with("rider")) {1199new_exec_flags = "{project} --line {line} {file}";1200} else if (editor == "subl" || editor == "sublime text" || editor == "sublime_text" || editor == "zed" || editor == "zedit" || editor == "zeditor") {1201new_exec_flags = "{project} {file}:{line}:{col}";1202} else if (editor == "vim" || editor == "gvim") {1203new_exec_flags = "\"+call cursor({line}, {col})\" {file}";1204} else if (editor == "emacs") {1205new_exec_flags = "emacs +{line}:{col} {file}";1206} else if (editor == "atom") {1207new_exec_flags = "{file}:{line}";1208} else if (editor == "geany" || editor == "kate") {1209new_exec_flags = "{file} --line {line} --column {col}";1210} else if (editor == "code" || editor == "visual studio code" || editor == "codium" || editor == "vscodium") {1211new_exec_flags = "{project} --goto {file}:{line}:{col}";1212}12131214return new_exec_flags;1215}12161217const String EditorSettings::_get_project_metadata_path() const {1218return EditorPaths::get_singleton()->get_project_settings_dir().path_join("project_metadata.cfg");1219}12201221#ifndef DISABLE_DEPRECATED1222void EditorSettings::_remove_deprecated_settings() {1223erase("interface/theme/preset");1224erase("network/connection/engine_version_update_mode");1225erase("run/output/always_open_output_on_play");1226erase("run/output/always_close_output_on_stop");1227erase("text_editor/theme/line_spacing"); // See GH-106137.1228}1229#endif12301231// PUBLIC METHODS12321233EditorSettings *EditorSettings::get_singleton() {1234return singleton.ptr();1235}12361237String EditorSettings::get_existing_settings_path() {1238const String config_dir = EditorPaths::get_singleton()->get_config_dir();1239int minor = GODOT_VERSION_MINOR;1240String filename;12411242do {1243if (GODOT_VERSION_MAJOR == 4 && minor < 3) {1244// Minor version is used since 4.3, so special case to load older settings.1245filename = vformat("editor_settings-%d.tres", GODOT_VERSION_MAJOR);1246minor = -1;1247} else {1248filename = vformat("editor_settings-%d.%d.tres", GODOT_VERSION_MAJOR, minor);1249minor--;1250}1251} while (minor >= 0 && !FileAccess::exists(config_dir.path_join(filename)));1252return config_dir.path_join(filename);1253}12541255String EditorSettings::get_newest_settings_path() {1256const String config_file_name = vformat("editor_settings-%d.%d.tres", GODOT_VERSION_MAJOR, GODOT_VERSION_MINOR);1257return EditorPaths::get_singleton()->get_config_dir().path_join(config_file_name);1258}12591260void EditorSettings::create() {1261// IMPORTANT: create() *must* create a valid EditorSettings singleton,1262// as the rest of the engine code will assume it. As such, it should never1263// return (incl. via ERR_FAIL) without initializing the singleton member.12641265if (singleton.ptr()) {1266ERR_PRINT("Can't recreate EditorSettings as it already exists.");1267return;1268}12691270String config_file_path;1271Ref<ConfigFile> extra_config = memnew(ConfigFile);12721273if (!EditorPaths::get_singleton()) {1274ERR_PRINT("Bug (please report): EditorPaths haven't been initialized, EditorSettings cannot be created properly.");1275goto fail;1276}12771278if (EditorPaths::get_singleton()->is_self_contained()) {1279Error err = extra_config->load(EditorPaths::get_singleton()->get_self_contained_file());1280if (err != OK) {1281ERR_PRINT("Can't load extra config from path: " + EditorPaths::get_singleton()->get_self_contained_file());1282}1283}12841285if (EditorPaths::get_singleton()->are_paths_valid()) {1286// Validate editor config file.1287ERR_FAIL_COND(!DirAccess::dir_exists_absolute(EditorPaths::get_singleton()->get_config_dir()));12881289config_file_path = get_existing_settings_path();1290if (!FileAccess::exists(config_file_path)) {1291config_file_path = get_newest_settings_path();1292goto fail;1293}12941295singleton = ResourceLoader::load(config_file_path, "EditorSettings");1296if (singleton.is_null()) {1297ERR_PRINT("Could not load editor settings from path: " + config_file_path);1298config_file_path = get_newest_settings_path();1299goto fail;1300}13011302singleton->set_path(get_newest_settings_path()); // Settings can be loaded from older version file, so make sure it's newest.1303singleton->save_changed_setting = true;13041305print_verbose("EditorSettings: Load OK!");13061307singleton->setup_language(true);1308singleton->setup_network();1309singleton->load_favorites_and_recent_dirs();1310singleton->update_text_editor_themes_list();1311#ifndef DISABLE_DEPRECATED1312singleton->_remove_deprecated_settings();1313#endif13141315return;1316}13171318fail:1319// patch init projects1320String exe_path = OS::get_singleton()->get_executable_path().get_base_dir();13211322if (extra_config->has_section("init_projects")) {1323Vector<String> list = extra_config->get_value("init_projects", "list");1324for (int i = 0; i < list.size(); i++) {1325list.write[i] = exe_path.path_join(list[i]);1326}1327extra_config->set_value("init_projects", "list", list);1328}13291330singleton.instantiate();1331singleton->set_path(config_file_path, true);1332singleton->save_changed_setting = true;1333singleton->_load_defaults(extra_config);1334singleton->setup_language(true);1335singleton->setup_network();1336singleton->update_text_editor_themes_list();1337}13381339void EditorSettings::setup_language(bool p_initial_setup) {1340String lang = get_language();1341if (p_initial_setup) {1342String lang_ov = Main::get_locale_override();1343if (!lang_ov.is_empty()) {1344lang = lang_ov;1345}1346}13471348if (lang == "en") {1349TranslationServer::get_singleton()->set_locale(lang);1350return; // Default, nothing to do.1351}13521353load_editor_translations(lang);1354load_doc_translations(lang);13551356TranslationServer::get_singleton()->set_locale(lang);1357}13581359void EditorSettings::setup_network() {1360List<IPAddress> local_ip;1361IP::get_singleton()->get_local_addresses(&local_ip);1362String hint;1363String current = has_setting("network/debug/remote_host") ? get("network/debug/remote_host") : "";1364String selected = "127.0.0.1";13651366// Check that current remote_host is a valid interface address and populate hints.1367for (const IPAddress &ip : local_ip) {1368// link-local IPv6 addresses don't work, skipping them1369if (String(ip).begins_with("fe80:0:0:0:")) { // fe80::/641370continue;1371}1372// Same goes for IPv4 link-local (APIPA) addresses.1373if (String(ip).begins_with("169.254.")) { // 169.254.0.0/161374continue;1375}1376// Select current IP (found)1377if (ip == current) {1378selected = String(ip);1379}1380if (!hint.is_empty()) {1381hint += ",";1382}1383hint += String(ip);1384}13851386// Add hints with valid IP addresses to remote_host property.1387add_property_hint(PropertyInfo(Variant::STRING, "network/debug/remote_host", PROPERTY_HINT_ENUM, hint));1388// Fix potentially invalid remote_host due to network change.1389set("network/debug/remote_host", selected);1390}13911392void EditorSettings::save() {1393//_THREAD_SAFE_METHOD_13941395if (!singleton.ptr()) {1396return;1397}13981399Error err = ResourceSaver::save(singleton);14001401if (err != OK) {1402ERR_PRINT("Error saving editor settings to " + singleton->get_path());1403} else {1404singleton->changed_settings.clear();1405print_verbose("EditorSettings: Save OK!");1406}1407}14081409PackedStringArray EditorSettings::get_changed_settings() const {1410PackedStringArray arr;1411for (const String &setting : changed_settings) {1412arr.push_back(setting);1413}14141415return arr;1416}14171418bool EditorSettings::check_changed_settings_in_group(const String &p_setting_prefix) const {1419for (const String &setting : changed_settings) {1420if (setting.begins_with(p_setting_prefix)) {1421return true;1422}1423}14241425return false;1426}14271428void EditorSettings::mark_setting_changed(const String &p_setting) {1429changed_settings.insert(p_setting);1430}14311432void EditorSettings::destroy() {1433if (!singleton.ptr()) {1434return;1435}1436save();1437singleton = Ref<EditorSettings>();1438}14391440void EditorSettings::set_optimize_save(bool p_optimize) {1441optimize_save = p_optimize;1442}14431444// Properties14451446void EditorSettings::set_setting(const String &p_setting, const Variant &p_value) {1447_THREAD_SAFE_METHOD_1448set(p_setting, p_value);1449}14501451Variant EditorSettings::get_setting(const String &p_setting) const {1452_THREAD_SAFE_METHOD_1453if (ProjectSettings::get_singleton()->has_editor_setting_override(p_setting)) {1454return ProjectSettings::get_singleton()->get_editor_setting_override(p_setting);1455}1456return get(p_setting);1457}14581459bool EditorSettings::has_setting(const String &p_setting) const {1460_THREAD_SAFE_METHOD_14611462return props.has(p_setting);1463}14641465void EditorSettings::erase(const String &p_setting) {1466_THREAD_SAFE_METHOD_14671468props.erase(p_setting);1469}14701471void EditorSettings::raise_order(const String &p_setting) {1472_THREAD_SAFE_METHOD_14731474ERR_FAIL_COND(!props.has(p_setting));1475props[p_setting].order = ++last_order;1476}14771478void EditorSettings::set_restart_if_changed(const StringName &p_setting, bool p_restart) {1479_THREAD_SAFE_METHOD_14801481if (!props.has(p_setting)) {1482return;1483}1484props[p_setting].restart_if_changed = p_restart;1485}14861487void EditorSettings::set_basic(const StringName &p_setting, bool p_basic) {1488_THREAD_SAFE_METHOD_14891490if (!props.has(p_setting)) {1491return;1492}1493props[p_setting].basic = p_basic;1494}14951496void EditorSettings::set_initial_value(const StringName &p_setting, const Variant &p_value, bool p_update_current) {1497_THREAD_SAFE_METHOD_14981499if (!props.has(p_setting)) {1500return;1501}1502props[p_setting].initial = p_value;1503props[p_setting].has_default_value = true;1504if (p_update_current) {1505set(p_setting, p_value);1506}1507}15081509Variant _EDITOR_DEF(const String &p_setting, const Variant &p_default, bool p_restart_if_changed, bool p_basic) {1510ERR_FAIL_NULL_V_MSG(EditorSettings::get_singleton(), p_default, "EditorSettings not instantiated yet.");15111512Variant ret = p_default;1513if (EditorSettings::get_singleton()->has_setting(p_setting)) {1514ret = EDITOR_GET(p_setting);1515} else {1516EditorSettings::get_singleton()->set_manually(p_setting, p_default);1517}1518EditorSettings::get_singleton()->set_restart_if_changed(p_setting, p_restart_if_changed);1519EditorSettings::get_singleton()->set_basic(p_setting, p_basic);15201521if (!EditorSettings::get_singleton()->has_default_value(p_setting)) {1522EditorSettings::get_singleton()->set_initial_value(p_setting, p_default);1523}15241525return ret;1526}15271528Variant _EDITOR_GET(const String &p_setting) {1529ERR_FAIL_NULL_V_MSG(EditorSettings::get_singleton(), Variant(), vformat(R"(EditorSettings not instantiated yet when getting setting "%s".)", p_setting));1530ERR_FAIL_COND_V_MSG(!EditorSettings::get_singleton()->has_setting(p_setting), Variant(), vformat(R"(Editor setting "%s" does not exist.)", p_setting));1531return EditorSettings::get_singleton()->get_setting(p_setting);1532}15331534bool EditorSettings::_property_can_revert(const StringName &p_name) const {1535const VariantContainer *property = props.getptr(p_name);1536if (property) {1537return property->has_default_value;1538}1539return false;1540}15411542bool EditorSettings::_property_get_revert(const StringName &p_name, Variant &r_property) const {1543const VariantContainer *value = props.getptr(p_name);1544if (value && value->has_default_value) {1545r_property = value->initial;1546return true;1547}1548return false;1549}15501551void EditorSettings::add_property_hint(const PropertyInfo &p_hint) {1552_THREAD_SAFE_METHOD_15531554hints[p_hint.name] = p_hint;1555}15561557// Metadata15581559void EditorSettings::set_project_metadata(const String &p_section, const String &p_key, const Variant &p_data) {1560const String path = _get_project_metadata_path();15611562if (project_metadata.is_null()) {1563project_metadata.instantiate();15641565Error err = project_metadata->load(path);1566if (err != OK && err != ERR_FILE_NOT_FOUND) {1567ERR_PRINT("Cannot load project metadata from file '" + path + "'.");1568}1569}1570project_metadata->set_value(p_section, p_key, p_data);1571project_metadata_dirty = true;1572}15731574Variant EditorSettings::get_project_metadata(const String &p_section, const String &p_key, const Variant &p_default) const {1575if (project_metadata.is_null()) {1576project_metadata.instantiate();15771578const String path = _get_project_metadata_path();1579Error err = project_metadata->load(path);1580ERR_FAIL_COND_V_MSG(err != OK && err != ERR_FILE_NOT_FOUND, p_default, "Cannot load project metadata from file '" + path + "'.");1581}1582return project_metadata->get_value(p_section, p_key, p_default);1583}15841585void EditorSettings::save_project_metadata() {1586if (!project_metadata_dirty) {1587return;1588}1589const String path = _get_project_metadata_path();1590Error err = project_metadata->save(path);1591ERR_FAIL_COND_MSG(err != OK, "Cannot save project metadata to file '" + path + "'.");1592project_metadata_dirty = false;1593}15941595void EditorSettings::set_favorites(const Vector<String> &p_favorites, bool p_update_file_dialog) {1596set_favorites_bind(p_favorites);1597if (p_update_file_dialog) {1598FileDialog::set_favorite_list(get_favorite_folders());1599}1600emit_signal(SNAME("_favorites_changed"));1601}16021603void EditorSettings::set_favorites_bind(const Vector<String> &p_favorites) {1604favorites = p_favorites;1605String favorites_file;1606if (Engine::get_singleton()->is_project_manager_hint()) {1607favorites_file = EditorPaths::get_singleton()->get_config_dir().path_join("favorite_dirs");1608} else {1609favorites_file = EditorPaths::get_singleton()->get_project_settings_dir().path_join("favorites");1610}1611Ref<FileAccess> f = FileAccess::open(favorites_file, FileAccess::WRITE);1612if (f.is_valid()) {1613for (int i = 0; i < favorites.size(); i++) {1614f->store_line(favorites[i]);1615}1616}1617}16181619void EditorSettings::set_favorite_properties(const HashMap<String, PackedStringArray> &p_favorite_properties) {1620favorite_properties = p_favorite_properties;1621String favorite_properties_file = EditorPaths::get_singleton()->get_project_settings_dir().path_join("favorite_properties");16221623Ref<ConfigFile> cf;1624cf.instantiate();1625for (const KeyValue<String, PackedStringArray> &kv : p_favorite_properties) {1626cf->set_value(kv.key, "properties", kv.value);1627}1628cf->save(favorite_properties_file);1629}16301631Vector<String> EditorSettings::get_favorites() const {1632return favorites;1633}16341635Vector<String> EditorSettings::get_favorite_folders() const {1636Vector<String> folder_favorites;1637folder_favorites.resize(favorites.size());1638String *folder_write = folder_favorites.ptrw();16391640int i = 0;1641for (const String &fav : favorites) {1642if (fav.ends_with("/")) {1643folder_write[i] = fav;1644i++;1645}1646}1647folder_favorites.resize(i);1648return folder_favorites;1649}16501651HashMap<String, PackedStringArray> EditorSettings::get_favorite_properties() const {1652return HashMap<String, PackedStringArray>(favorite_properties);1653}16541655void EditorSettings::set_recent_dirs(const Vector<String> &p_recent_dirs, bool p_update_file_dialog) {1656if (p_update_file_dialog) {1657FileDialog::set_recent_list(p_recent_dirs);1658}1659set_recent_dirs_bind(p_recent_dirs);1660}16611662void EditorSettings::set_recent_dirs_bind(const Vector<String> &p_recent_dirs) {1663recent_dirs = p_recent_dirs;1664String recent_dirs_file;1665if (Engine::get_singleton()->is_project_manager_hint()) {1666recent_dirs_file = EditorPaths::get_singleton()->get_config_dir().path_join("recent_dirs");1667} else {1668recent_dirs_file = EditorPaths::get_singleton()->get_project_settings_dir().path_join("recent_dirs");1669}1670Ref<FileAccess> f = FileAccess::open(recent_dirs_file, FileAccess::WRITE);1671if (f.is_valid()) {1672for (int i = 0; i < recent_dirs.size(); i++) {1673f->store_line(recent_dirs[i]);1674}1675}1676}16771678Vector<String> EditorSettings::get_recent_dirs() const {1679return recent_dirs;1680}16811682void EditorSettings::load_favorites_and_recent_dirs() {1683String favorites_file;1684String favorite_properties_file;1685String recent_dirs_file;1686if (Engine::get_singleton()->is_project_manager_hint()) {1687favorites_file = EditorPaths::get_singleton()->get_config_dir().path_join("favorite_dirs");1688favorite_properties_file = EditorPaths::get_singleton()->get_config_dir().path_join("favorite_properties");1689recent_dirs_file = EditorPaths::get_singleton()->get_config_dir().path_join("recent_dirs");1690} else {1691favorites_file = EditorPaths::get_singleton()->get_project_settings_dir().path_join("favorites");1692favorite_properties_file = EditorPaths::get_singleton()->get_project_settings_dir().path_join("favorite_properties");1693recent_dirs_file = EditorPaths::get_singleton()->get_project_settings_dir().path_join("recent_dirs");1694}16951696/// File Favorites16971698Ref<FileAccess> f = FileAccess::open(favorites_file, FileAccess::READ);1699if (f.is_valid()) {1700String line = f->get_line().strip_edges();1701while (!line.is_empty()) {1702favorites.append(line);1703line = f->get_line().strip_edges();1704}1705}1706FileDialog::set_favorite_list(get_favorite_folders());17071708/// Inspector Favorites17091710Ref<ConfigFile> cf;1711cf.instantiate();1712if (cf->load(favorite_properties_file) == OK) {1713Vector<String> secs = cf->get_sections();17141715for (String &E : secs) {1716PackedStringArray properties = PackedStringArray(cf->get_value(E, "properties"));1717if (EditorNode::get_editor_data().is_type_recognized(E) || ResourceLoader::exists(E, "Script")) {1718for (const String &property : properties) {1719if (!favorite_properties[E].has(property)) {1720favorite_properties[E].push_back(property);1721}1722}1723}1724}1725}17261727/// Recent Directories17281729f = FileAccess::open(recent_dirs_file, FileAccess::READ);1730if (f.is_valid()) {1731String line = f->get_line().strip_edges();1732while (!line.is_empty()) {1733recent_dirs.push_back(line);1734line = f->get_line().strip_edges();1735}1736}1737FileDialog::set_recent_list(recent_dirs);1738}17391740HashMap<StringName, Color> EditorSettings::get_godot2_text_editor_theme() {1741// Godot 2 is only a dark theme; it doesn't have a light theme counterpart.1742HashMap<StringName, Color> colors;1743colors["text_editor/theme/highlighting/symbol_color"] = Color(0.73, 0.87, 1.0);1744colors["text_editor/theme/highlighting/keyword_color"] = Color(1.0, 1.0, 0.7);1745colors["text_editor/theme/highlighting/control_flow_keyword_color"] = Color(1.0, 0.85, 0.7);1746colors["text_editor/theme/highlighting/base_type_color"] = Color(0.64, 1.0, 0.83);1747colors["text_editor/theme/highlighting/engine_type_color"] = Color(0.51, 0.83, 1.0);1748colors["text_editor/theme/highlighting/user_type_color"] = Color(0.42, 0.67, 0.93);1749colors["text_editor/theme/highlighting/comment_color"] = Color(0.4, 0.4, 0.4);1750colors["text_editor/theme/highlighting/doc_comment_color"] = Color(0.5, 0.6, 0.7);1751colors["text_editor/theme/highlighting/string_color"] = Color(0.94, 0.43, 0.75);1752colors["text_editor/theme/highlighting/string_placeholder_color"] = Color(1, 0.75, 0.4);1753colors["text_editor/theme/highlighting/background_color"] = Color(0.13, 0.12, 0.15);1754colors["text_editor/theme/highlighting/completion_background_color"] = Color(0.17, 0.16, 0.2);1755colors["text_editor/theme/highlighting/completion_selected_color"] = Color(0.26, 0.26, 0.27);1756colors["text_editor/theme/highlighting/completion_existing_color"] = Color(0.87, 0.87, 0.87, 0.13);1757colors["text_editor/theme/highlighting/completion_scroll_color"] = Color(1, 1, 1, 0.29);1758colors["text_editor/theme/highlighting/completion_scroll_hovered_color"] = Color(1, 1, 1, 0.4);1759colors["text_editor/theme/highlighting/completion_font_color"] = Color(0.67, 0.67, 0.67);1760colors["text_editor/theme/highlighting/text_color"] = Color(0.67, 0.67, 0.67);1761colors["text_editor/theme/highlighting/line_number_color"] = Color(0.67, 0.67, 0.67, 0.4);1762colors["text_editor/theme/highlighting/safe_line_number_color"] = Color(0.67, 0.78, 0.67, 0.6);1763colors["text_editor/theme/highlighting/caret_color"] = Color(0.67, 0.67, 0.67);1764colors["text_editor/theme/highlighting/caret_background_color"] = Color(0, 0, 0);1765colors["text_editor/theme/highlighting/text_selected_color"] = Color(0, 0, 0, 0);1766colors["text_editor/theme/highlighting/selection_color"] = Color(0.41, 0.61, 0.91, 0.35);1767colors["text_editor/theme/highlighting/brace_mismatch_color"] = Color(1, 0.2, 0.2);1768colors["text_editor/theme/highlighting/current_line_color"] = Color(0.3, 0.5, 0.8, 0.15);1769colors["text_editor/theme/highlighting/line_length_guideline_color"] = Color(0.3, 0.5, 0.8, 0.1);1770colors["text_editor/theme/highlighting/word_highlighted_color"] = Color(0.8, 0.9, 0.9, 0.15);1771colors["text_editor/theme/highlighting/number_color"] = Color(0.92, 0.58, 0.2);1772colors["text_editor/theme/highlighting/function_color"] = Color(0.4, 0.64, 0.81);1773colors["text_editor/theme/highlighting/member_variable_color"] = Color(0.9, 0.31, 0.35);1774colors["text_editor/theme/highlighting/mark_color"] = Color(1.0, 0.4, 0.4, 0.4);1775colors["text_editor/theme/highlighting/warning_color"] = Color(1.0, 0.8, 0.4, 0.1);1776colors["text_editor/theme/highlighting/bookmark_color"] = Color(0.08, 0.49, 0.98);1777colors["text_editor/theme/highlighting/breakpoint_color"] = Color(0.9, 0.29, 0.3);1778colors["text_editor/theme/highlighting/executing_line_color"] = Color(0.98, 0.89, 0.27);1779colors["text_editor/theme/highlighting/code_folding_color"] = Color(0.8, 0.8, 0.8, 0.8);1780colors["text_editor/theme/highlighting/folded_code_region_color"] = Color(0.68, 0.46, 0.77, 0.2);1781colors["text_editor/theme/highlighting/search_result_color"] = Color(0.05, 0.25, 0.05, 1);1782colors["text_editor/theme/highlighting/search_result_border_color"] = Color(0.41, 0.61, 0.91, 0.38);1783colors["text_editor/theme/highlighting/gdscript/function_definition_color"] = Color(0.4, 0.9, 1.0);17841785colors["text_editor/theme/highlighting/gdscript/global_function_color"] = Color(0.64, 0.64, 0.96);1786colors["text_editor/theme/highlighting/gdscript/node_path_color"] = Color(0.72, 0.77, 0.49);1787colors["text_editor/theme/highlighting/gdscript/node_reference_color"] = Color(0.39, 0.76, 0.35);1788colors["text_editor/theme/highlighting/gdscript/annotation_color"] = Color(1.0, 0.7, 0.45);1789colors["text_editor/theme/highlighting/gdscript/string_name_color"] = Color(1.0, 0.76, 0.65);1790colors["text_editor/theme/highlighting/comment_markers/critical_color"] = Color(0.77, 0.35, 0.35);1791colors["text_editor/theme/highlighting/comment_markers/warning_color"] = Color(0.72, 0.61, 0.48);1792colors["text_editor/theme/highlighting/comment_markers/notice_color"] = Color(0.56, 0.67, 0.51);1793return colors;1794}17951796bool EditorSettings::is_default_text_editor_theme(const String &p_theme_name) {1797return p_theme_name == "default" || p_theme_name == "godot 2" || p_theme_name == "custom";1798}17991800void EditorSettings::update_text_editor_themes_list() {1801String themes = "Default,Godot 2,Custom";18021803Ref<DirAccess> d = DirAccess::open(EditorPaths::get_singleton()->get_text_editor_themes_dir());1804if (d.is_null()) {1805return;1806}18071808PackedStringArray custom_themes;1809d->list_dir_begin();1810String file = d->get_next();1811while (!file.is_empty()) {1812if (file.get_extension() == "tet" && !is_default_text_editor_theme(file.get_basename().to_lower())) {1813custom_themes.push_back(file.get_basename());1814}1815file = d->get_next();1816}1817d->list_dir_end();18181819if (!custom_themes.is_empty()) {1820custom_themes.sort();1821themes += "," + String(",").join(custom_themes);1822}1823add_property_hint(PropertyInfo(Variant::STRING, "text_editor/theme/color_theme", PROPERTY_HINT_ENUM, themes));1824}18251826Vector<String> EditorSettings::get_script_templates(const String &p_extension, const String &p_custom_path) {1827Vector<String> templates;1828String template_dir = EditorPaths::get_singleton()->get_script_templates_dir();1829if (!p_custom_path.is_empty()) {1830template_dir = p_custom_path;1831}1832Ref<DirAccess> d = DirAccess::open(template_dir);1833if (d.is_valid()) {1834d->list_dir_begin();1835String file = d->get_next();1836while (!file.is_empty()) {1837if (file.get_extension() == p_extension) {1838templates.push_back(file.get_basename());1839}1840file = d->get_next();1841}1842d->list_dir_end();1843}1844return templates;1845}18461847String EditorSettings::get_editor_layouts_config() const {1848return EditorPaths::get_singleton()->get_config_dir().path_join("editor_layouts.cfg");1849}18501851float EditorSettings::get_auto_display_scale() {1852#ifdef LINUXBSD_ENABLED1853if (DisplayServer::get_singleton()->get_name() == "Wayland") {1854float main_window_scale = DisplayServer::get_singleton()->screen_get_scale(DisplayServer::SCREEN_OF_MAIN_WINDOW);18551856if (DisplayServer::get_singleton()->get_screen_count() == 1 || Math::fract(main_window_scale) != 0) {1857// If we have a single screen or the screen of the window is fractional, all1858// bets are off. At this point, let's just return the current's window scale,1859// which is special-cased to the scale of `SCREEN_OF_MAIN_WINDOW`.1860return main_window_scale;1861}18621863// If the above branch didn't fire, fractional scaling isn't going to work1864// properly anyways (we're need the ability to change the UI scale at runtime).1865// At this point it's more convenient to "supersample" like we do with other1866// platforms, hoping that the user is only using integer-scaled screens.1867return DisplayServer::get_singleton()->screen_get_max_scale();1868}1869#endif18701871#if defined(MACOS_ENABLED) || defined(ANDROID_ENABLED)1872return DisplayServer::get_singleton()->screen_get_max_scale();1873#else1874const int screen = DisplayServer::get_singleton()->window_get_current_screen();18751876if (DisplayServer::get_singleton()->screen_get_size(screen) == Vector2i()) {1877// Invalid screen size, skip.1878return 1.0;1879}18801881#if defined(WINDOWS_ENABLED)1882return DisplayServer::get_singleton()->screen_get_dpi(screen) / 96.0;1883#else1884// Use the smallest dimension to use a correct display scale on portrait displays.1885const int smallest_dimension = MIN(DisplayServer::get_singleton()->screen_get_size(screen).x, DisplayServer::get_singleton()->screen_get_size(screen).y);1886if (DisplayServer::get_singleton()->screen_get_dpi(screen) >= 192 && smallest_dimension >= 1400) {1887// hiDPI display.1888return 2.0;1889} else if (smallest_dimension >= 1700) {1890// Likely a hiDPI display, but we aren't certain due to the returned DPI.1891// Use an intermediate scale to handle this situation.1892return 1.5;1893} else if (smallest_dimension <= 800) {1894// Small loDPI display. Use a smaller display scale so that editor elements fit more easily.1895// Icons won't look great, but this is better than having editor elements overflow from its window.1896return 0.75;1897}1898return 1.0;1899#endif // defined(WINDOWS_ENABLED)19001901#endif // defined(MACOS_ENABLED) || defined(ANDROID_ENABLED)1902}19031904String EditorSettings::get_language() const {1905const String language = has_setting("interface/editor/editor_language") ? get("interface/editor/editor_language") : "auto";1906if (language != "auto") {1907return language;1908}19091910if (auto_language.is_empty()) {1911// Skip locales which we can't render properly.1912const LocalVector<String> locales_to_skip = _get_skipped_locales();1913const String host_lang = OS::get_singleton()->get_locale();19141915String best = "en";1916int best_score = 0;1917for (const String &locale : get_editor_locales()) {1918// Test against language code without regional variants (e.g. ur_PK).1919String lang_code = locale.get_slicec('_', 0);1920if (locales_to_skip.has(lang_code)) {1921continue;1922}19231924int score = TranslationServer::get_singleton()->compare_locales(host_lang, locale);1925if (score > 0 && score >= best_score) {1926best = locale;1927best_score = score;1928}1929}1930auto_language = best;1931}1932return auto_language;1933}19341935// Shortcuts19361937void EditorSettings::_add_shortcut_default(const String &p_path, const Ref<Shortcut> &p_shortcut) {1938shortcuts[p_path] = p_shortcut;1939}19401941void EditorSettings::add_shortcut(const String &p_path, const Ref<Shortcut> &p_shortcut) {1942ERR_FAIL_COND_MSG(p_shortcut.is_null(), "Cannot add a null shortcut for path: " + p_path);19431944Array use_events = p_shortcut->get_events();1945if (shortcuts.has(p_path)) {1946Ref<Shortcut> existing = shortcuts.get(p_path);1947if (!existing->has_meta("original")) {1948// Loaded from editor settings, but plugin not loaded yet.1949// Keep the events from editor settings but still override the shortcut in the shortcuts map1950use_events = existing->get_events();1951} else if (!Shortcut::is_event_array_equal(existing->get_events(), existing->get_meta("original"))) {1952// Shortcut exists and is customized - don't override with default.1953return;1954}1955}19561957p_shortcut->set_meta("original", p_shortcut->get_events());1958p_shortcut->set_events(use_events);1959if (p_shortcut->get_name().is_empty()) {1960String shortcut_name = p_path.get_slicec('/', 1);1961if (shortcut_name.is_empty()) {1962shortcut_name = p_path;1963}1964p_shortcut->set_name(shortcut_name);1965}1966shortcuts[p_path] = p_shortcut;1967}19681969void EditorSettings::remove_shortcut(const String &p_path) {1970shortcuts.erase(p_path);1971}19721973bool EditorSettings::is_shortcut(const String &p_path, const Ref<InputEvent> &p_event) const {1974HashMap<String, Ref<Shortcut>>::ConstIterator E = shortcuts.find(p_path);1975ERR_FAIL_COND_V_MSG(!E, false, "Unknown Shortcut: " + p_path + ".");19761977return E->value->matches_event(p_event);1978}19791980bool EditorSettings::has_shortcut(const String &p_path) const {1981return get_shortcut(p_path).is_valid();1982}19831984Ref<Shortcut> EditorSettings::get_shortcut(const String &p_path) const {1985HashMap<String, Ref<Shortcut>>::ConstIterator SC = shortcuts.find(p_path);1986if (SC) {1987return SC->value;1988}19891990// If no shortcut with the provided name is found in the list, check the built-in shortcuts.1991// Use the first item in the action list for the shortcut event, since a shortcut can only have 1 linked event.19921993Ref<Shortcut> sc;1994HashMap<String, List<Ref<InputEvent>>>::ConstIterator builtin_override = builtin_action_overrides.find(p_path);1995if (builtin_override) {1996sc.instantiate();1997sc->set_events_list(&builtin_override->value);1998sc->set_name(InputMap::get_singleton()->get_builtin_display_name(p_path));1999}20002001// If there was no override, check the default builtins to see if it has an InputEvent for the provided name.2002if (sc.is_null()) {2003HashMap<String, List<Ref<InputEvent>>>::ConstIterator builtin_default = InputMap::get_singleton()->get_builtins_with_feature_overrides_applied().find(p_path);2004if (builtin_default) {2005sc.instantiate();2006sc->set_events_list(&builtin_default->value);2007sc->set_name(InputMap::get_singleton()->get_builtin_display_name(p_path));2008}2009}20102011if (sc.is_valid()) {2012// Add the shortcut to the list.2013shortcuts[p_path] = sc;2014return sc;2015}20162017return Ref<Shortcut>();2018}20192020Vector<String> EditorSettings::_get_shortcut_list() {2021List<String> shortcut_list;2022get_shortcut_list(&shortcut_list);2023Vector<String> ret;2024for (const String &shortcut : shortcut_list) {2025ret.push_back(shortcut);2026}2027return ret;2028}20292030void EditorSettings::get_shortcut_list(List<String> *r_shortcuts) {2031for (const KeyValue<String, Ref<Shortcut>> &E : shortcuts) {2032r_shortcuts->push_back(E.key);2033}2034}20352036Ref<Shortcut> ED_GET_SHORTCUT(const String &p_path) {2037ERR_FAIL_NULL_V_MSG(EditorSettings::get_singleton(), nullptr, "EditorSettings not instantiated yet.");20382039Ref<Shortcut> sc = EditorSettings::get_singleton()->get_shortcut(p_path);20402041ERR_FAIL_COND_V_MSG(sc.is_null(), sc, "Used ED_GET_SHORTCUT with invalid shortcut: " + p_path);20422043return sc;2044}20452046void ED_SHORTCUT_OVERRIDE(const String &p_path, const String &p_feature, Key p_keycode, bool p_physical) {2047if (!EditorSettings::get_singleton()) {2048return;2049}20502051Ref<Shortcut> sc = EditorSettings::get_singleton()->get_shortcut(p_path);2052ERR_FAIL_COND_MSG(sc.is_null(), "Used ED_SHORTCUT_OVERRIDE with invalid shortcut: " + p_path);20532054PackedInt32Array arr;2055arr.push_back((int32_t)p_keycode);20562057ED_SHORTCUT_OVERRIDE_ARRAY(p_path, p_feature, arr, p_physical);2058}20592060void ED_SHORTCUT_OVERRIDE_ARRAY(const String &p_path, const String &p_feature, const PackedInt32Array &p_keycodes, bool p_physical) {2061if (!EditorSettings::get_singleton()) {2062return;2063}20642065Ref<Shortcut> sc = EditorSettings::get_singleton()->get_shortcut(p_path);2066ERR_FAIL_COND_MSG(sc.is_null(), "Used ED_SHORTCUT_OVERRIDE_ARRAY with invalid shortcut: " + p_path);20672068// Only add the override if the OS supports the provided feature.2069if (!OS::get_singleton()->has_feature(p_feature)) {2070if (!(p_feature == "macos" && (OS::get_singleton()->has_feature("web_macos") || OS::get_singleton()->has_feature("web_ios")))) {2071return;2072}2073}20742075Array events;20762077for (int i = 0; i < p_keycodes.size(); i++) {2078Key keycode = (Key)p_keycodes[i];20792080if (OS::prefer_meta_over_ctrl()) {2081// Use Cmd+Backspace as a general replacement for Delete shortcuts on macOS2082if (keycode == Key::KEY_DELETE) {2083keycode = KeyModifierMask::META | Key::BACKSPACE;2084}2085}20862087Ref<InputEventKey> ie;2088if (keycode != Key::NONE) {2089ie = InputEventKey::create_reference(keycode, p_physical);2090events.push_back(ie);2091}2092}20932094// Override the existing shortcut only if it wasn't customized by the user.2095if (Shortcut::is_event_array_equal(sc->get_events(), sc->get_meta("original"))) {2096sc->set_events(events);2097}20982099sc->set_meta("original", events.duplicate(true));2100}21012102Ref<Shortcut> ED_SHORTCUT(const String &p_path, const String &p_name, Key p_keycode, bool p_physical) {2103PackedInt32Array arr;2104arr.push_back((int32_t)p_keycode);2105return ED_SHORTCUT_ARRAY(p_path, p_name, arr, p_physical);2106}21072108Ref<Shortcut> ED_SHORTCUT_ARRAY(const String &p_path, const String &p_name, const PackedInt32Array &p_keycodes, bool p_physical) {2109Array events;21102111for (int i = 0; i < p_keycodes.size(); i++) {2112Key keycode = (Key)p_keycodes[i];21132114if (OS::prefer_meta_over_ctrl()) {2115// Use Cmd+Backspace as a general replacement for Delete shortcuts on macOS2116if (keycode == Key::KEY_DELETE) {2117keycode = KeyModifierMask::META | Key::BACKSPACE;2118}2119}21202121Ref<InputEventKey> ie;2122if (keycode != Key::NONE) {2123ie = InputEventKey::create_reference(keycode, p_physical);2124events.push_back(ie);2125}2126}21272128if (!EditorSettings::get_singleton()) {2129Ref<Shortcut> sc;2130sc.instantiate();2131sc->set_name(p_name);2132sc->set_events(events);2133sc->set_meta("original", events.duplicate(true));2134return sc;2135}21362137Ref<Shortcut> sc = EditorSettings::get_singleton()->get_shortcut(p_path);2138if (sc.is_valid()) {2139sc->set_name(p_name); //keep name (the ones that come from disk have no name)2140sc->set_meta("original", events.duplicate(true)); //to compare against changes2141return sc;2142}21432144sc.instantiate();2145sc->set_name(p_name);2146sc->set_events(events);2147sc->set_meta("original", events.duplicate(true)); //to compare against changes2148EditorSettings::get_singleton()->_add_shortcut_default(p_path, sc);21492150return sc;2151}21522153void EditorSettings::set_builtin_action_override(const String &p_name, const TypedArray<InputEvent> &p_events) {2154List<Ref<InputEvent>> event_list;21552156// Override the whole list, since events may have their order changed or be added, removed or edited.2157InputMap::get_singleton()->action_erase_events(p_name);2158for (int i = 0; i < p_events.size(); i++) {2159event_list.push_back(p_events[i]);2160InputMap::get_singleton()->action_add_event(p_name, p_events[i]);2161}21622163// Check if the provided event array is same as built-in. If it is, it does not need to be added to the overrides.2164// Note that event order must also be the same.2165bool same_as_builtin = true;2166HashMap<String, List<Ref<InputEvent>>>::ConstIterator builtin_default = InputMap::get_singleton()->get_builtins_with_feature_overrides_applied().find(p_name);2167if (builtin_default) {2168const List<Ref<InputEvent>> &builtin_events = builtin_default->value;21692170// In the editor we only care about key events.2171List<Ref<InputEventKey>> builtin_key_events;2172for (Ref<InputEventKey> iek : builtin_events) {2173if (iek.is_valid()) {2174builtin_key_events.push_back(iek);2175}2176}21772178if (p_events.size() == builtin_key_events.size()) {2179int event_idx = 0;21802181// Check equality of each event.2182for (const Ref<InputEventKey> &E : builtin_key_events) {2183if (!E->is_match(p_events[event_idx])) {2184same_as_builtin = false;2185break;2186}2187event_idx++;2188}2189} else {2190same_as_builtin = false;2191}2192}21932194if (same_as_builtin && builtin_action_overrides.has(p_name)) {2195builtin_action_overrides.erase(p_name);2196} else {2197builtin_action_overrides[p_name] = event_list;2198}21992200// Update the shortcut (if it is used somewhere in the editor) to be the first event of the new list.2201if (shortcuts.has(p_name)) {2202shortcuts[p_name]->set_events_list(&event_list);2203}2204}22052206const Array EditorSettings::get_builtin_action_overrides(const String &p_name) const {2207HashMap<String, List<Ref<InputEvent>>>::ConstIterator AO = builtin_action_overrides.find(p_name);2208if (AO) {2209Array event_array;22102211List<Ref<InputEvent>> events_list = AO->value;2212for (const Ref<InputEvent> &E : events_list) {2213event_array.push_back(E);2214}2215return event_array;2216}22172218return Array();2219}22202221void EditorSettings::notify_changes() {2222_THREAD_SAFE_METHOD_22232224SceneTree *sml = Object::cast_to<SceneTree>(OS::get_singleton()->get_main_loop());22252226if (!sml) {2227return;2228}22292230Node *root = sml->get_root()->get_child(0);22312232if (!root) {2233return;2234}2235root->propagate_notification(NOTIFICATION_EDITOR_SETTINGS_CHANGED);2236}22372238void EditorSettings::get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const {2239const String pf = p_function;2240if (p_idx == 0) {2241if (pf == "has_setting" || pf == "set_setting" || pf == "get_setting" || pf == "erase" ||2242pf == "set_initial_value" || pf == "set_as_basic" || pf == "mark_setting_changed") {2243for (const KeyValue<String, VariantContainer> &E : props) {2244if (E.value.hide_from_editor) {2245continue;2246}22472248r_options->push_back(E.key.quote());2249}2250} else if (pf == "get_project_metadata" && project_metadata.is_valid()) {2251Vector<String> sections = project_metadata->get_sections();2252for (const String §ion : sections) {2253r_options->push_back(section.quote());2254}2255} else if (pf == "set_builtin_action_override") {2256for (const Variant &action : InputMap::get_singleton()->get_actions()) {2257r_options->push_back(String(action).quote());2258}2259}2260}2261Object::get_argument_options(p_function, p_idx, r_options);2262}22632264void EditorSettings::_bind_methods() {2265ClassDB::bind_method(D_METHOD("has_setting", "name"), &EditorSettings::has_setting);2266ClassDB::bind_method(D_METHOD("set_setting", "name", "value"), &EditorSettings::set_setting);2267ClassDB::bind_method(D_METHOD("get_setting", "name"), &EditorSettings::get_setting);2268ClassDB::bind_method(D_METHOD("erase", "property"), &EditorSettings::erase);2269ClassDB::bind_method(D_METHOD("set_initial_value", "name", "value", "update_current"), &EditorSettings::set_initial_value);2270ClassDB::bind_method(D_METHOD("add_property_info", "info"), &EditorSettings::_add_property_info_bind);22712272ClassDB::bind_method(D_METHOD("set_project_metadata", "section", "key", "data"), &EditorSettings::set_project_metadata);2273ClassDB::bind_method(D_METHOD("get_project_metadata", "section", "key", "default"), &EditorSettings::get_project_metadata, DEFVAL(Variant()));22742275ClassDB::bind_method(D_METHOD("set_favorites", "dirs"), &EditorSettings::set_favorites_bind);2276ClassDB::bind_method(D_METHOD("get_favorites"), &EditorSettings::get_favorites);2277ClassDB::bind_method(D_METHOD("set_recent_dirs", "dirs"), &EditorSettings::set_recent_dirs_bind);2278ClassDB::bind_method(D_METHOD("get_recent_dirs"), &EditorSettings::get_recent_dirs);22792280ClassDB::bind_method(D_METHOD("set_builtin_action_override", "name", "actions_list"), &EditorSettings::set_builtin_action_override);22812282ClassDB::bind_method(D_METHOD("add_shortcut", "path", "shortcut"), &EditorSettings::add_shortcut);2283ClassDB::bind_method(D_METHOD("remove_shortcut", "path"), &EditorSettings::remove_shortcut);2284ClassDB::bind_method(D_METHOD("is_shortcut", "path", "event"), &EditorSettings::is_shortcut);2285ClassDB::bind_method(D_METHOD("has_shortcut", "path"), &EditorSettings::has_shortcut);2286ClassDB::bind_method(D_METHOD("get_shortcut", "path"), &EditorSettings::get_shortcut);2287ClassDB::bind_method(D_METHOD("get_shortcut_list"), &EditorSettings::_get_shortcut_list);22882289ClassDB::bind_method(D_METHOD("check_changed_settings_in_group", "setting_prefix"), &EditorSettings::check_changed_settings_in_group);2290ClassDB::bind_method(D_METHOD("get_changed_settings"), &EditorSettings::get_changed_settings);2291ClassDB::bind_method(D_METHOD("mark_setting_changed", "setting"), &EditorSettings::mark_setting_changed);22922293ADD_SIGNAL(MethodInfo("settings_changed"));2294ADD_SIGNAL(MethodInfo("_favorites_changed"));22952296BIND_CONSTANT(NOTIFICATION_EDITOR_SETTINGS_CHANGED);2297}22982299EditorSettings::EditorSettings() {2300last_order = 0;23012302_load_defaults();2303callable_mp(this, &EditorSettings::_set_initialized).call_deferred();2304}230523062307