diff --git a/doc/classes/EditorSettings.xml b/doc/classes/EditorSettings.xml index 5dcfdb21b109..8869d2a58995 100644 --- a/doc/classes/EditorSettings.xml +++ b/doc/classes/EditorSettings.xml @@ -755,6 +755,9 @@ If [code]true[/code], draws additional borders around interactive UI elements in the editor. This is automatically enabled when using the [b]Black (OLED)[/b] theme preset, as this theme preset uses a fully black background. + + If [code]true[/code], the editor theme preset will attempt to automatically match the system theme. + The icon and font color scheme to use in the editor. - [b]Auto[/b] determines the color scheme to use automatically based on [member interface/theme/base_color]. @@ -774,6 +777,10 @@ The editor theme spacing preset to use. See also [member interface/theme/base_spacing] and [member interface/theme/additional_spacing]. + + If [code]true[/code], set accent color based on system settings. + [b]Note:[/b] This setting is only effective on Windows and MacOS. + If [code]true[/code], long press on touchscreen is treated as right click. [b]Note:[/b] Defaults to [code]true[/code] on touchscreen devices. diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 04944a9143c7..84840a1c47b9 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -669,6 +669,8 @@ void EditorNode::_notification(int p_what) { callable_mp(this, &EditorNode::_begin_first_scan).call_deferred(); + DisplayServer::get_singleton()->set_system_theme_change_callback(callable_mp(this, &EditorNode::_update_theme)); + /* DO NOT LOAD SCENES HERE, WAIT FOR FILE SCANNING AND REIMPORT TO COMPLETE */ } break; @@ -773,6 +775,9 @@ void EditorNode::_notification(int p_what) { EditorFileDialog::set_default_display_mode((EditorFileDialog::DisplayMode)EDITOR_GET("filesystem/file_dialog/display_mode").operator int()); } + follow_system_theme = EDITOR_GET("interface/theme/follow_system_theme"); + use_system_accent_color = EDITOR_GET("interface/theme/use_system_accent_color"); + if (EditorThemeManager::is_generated_theme_outdated()) { _update_theme(); _build_icon_type_cache(); @@ -3130,6 +3135,35 @@ void EditorNode::_save_screenshot(NodePath p_path) { ERR_FAIL_COND_MSG(error != OK, "Cannot save screenshot to file '" + p_path + "'."); } +void EditorNode::_check_system_theme_changed() { + DisplayServer *display_server = DisplayServer::get_singleton(); + + bool system_theme_changed = false; + + if (follow_system_theme) { + if (display_server->get_base_color() != last_system_base_color) { + system_theme_changed = true; + last_system_base_color = display_server->get_base_color(); + } + + if (display_server->is_dark_mode_supported() && display_server->is_dark_mode() != last_dark_mode_state) { + system_theme_changed = true; + last_dark_mode_state = display_server->is_dark_mode(); + } + } + + if (use_system_accent_color) { + if (display_server->get_accent_color() != last_system_accent_color) { + system_theme_changed = true; + last_system_accent_color = display_server->get_accent_color(); + } + } + + if (system_theme_changed) { + _update_theme(); + } +} + void EditorNode::_tool_menu_option(int p_idx) { switch (tool_menu->get_item_id(p_idx)) { case TOOLS_ORPHAN_RESOURCES: { @@ -7568,6 +7602,15 @@ EditorNode::EditorNode() { String exec = OS::get_singleton()->get_executable_path(); // Save editor executable path for third-party tools. EditorSettings::get_singleton()->set_project_metadata("editor_metadata", "executable_path", exec); + + follow_system_theme = EDITOR_GET("interface/theme/follow_system_theme"); + use_system_accent_color = EDITOR_GET("interface/theme/use_system_accent_color"); + system_theme_timer = memnew(Timer); + system_theme_timer->set_wait_time(1.0); + system_theme_timer->connect("timeout", callable_mp(this, &EditorNode::_check_system_theme_changed)); + add_child(system_theme_timer); + system_theme_timer->set_owner(get_owner()); + system_theme_timer->set_autostart(true); } EditorNode::~EditorNode() { diff --git a/editor/editor_node.h b/editor/editor_node.h index 8a880a00cc22..2aa743343ee9 100644 --- a/editor/editor_node.h +++ b/editor/editor_node.h @@ -358,6 +358,13 @@ class EditorNode : public Node { Ref theme; + Timer *system_theme_timer = nullptr; + bool follow_system_theme = false; + bool use_system_accent_color = false; + bool last_dark_mode_state = false; + Color last_system_base_color = Color(0, 0, 0, 0); + Color last_system_accent_color = Color(0, 0, 0, 0); + PopupMenu *recent_scenes = nullptr; String _recent_scene; List previous_scenes; @@ -538,6 +545,8 @@ class EditorNode : public Node { void _screenshot(bool p_use_utc = false); void _save_screenshot(NodePath p_path); + void _check_system_theme_changed(); + void _tool_menu_option(int p_idx); void _export_as_menu_option(int p_idx); void _update_file_menu_opened(); diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp index 8192ac2eb497..e3c9996c97e7 100644 --- a/editor/editor_settings.cpp +++ b/editor/editor_settings.cpp @@ -489,11 +489,13 @@ void EditorSettings::_load_defaults(Ref p_extra_config) { EDITOR_SETTING(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") // Theme + EDITOR_SETTING(Variant::BOOL, PROPERTY_HINT_ENUM, "interface/theme/follow_system_theme", false, "") EDITOR_SETTING(Variant::STRING, PROPERTY_HINT_ENUM, "interface/theme/preset", "Default", "Default,Breeze Dark,Godot 2,Gray,Light,Solarized (Dark),Solarized (Light),Black (OLED),Custom") EDITOR_SETTING(Variant::STRING, PROPERTY_HINT_ENUM, "interface/theme/spacing_preset", "Default", "Compact,Default,Spacious,Custom") EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "interface/theme/icon_and_font_color", 0, "Auto,Dark,Light") EDITOR_SETTING(Variant::COLOR, PROPERTY_HINT_NONE, "interface/theme/base_color", Color(0.2, 0.23, 0.31), "") EDITOR_SETTING(Variant::COLOR, PROPERTY_HINT_NONE, "interface/theme/accent_color", Color(0.41, 0.61, 0.91), "") + EDITOR_SETTING(Variant::BOOL, PROPERTY_HINT_NONE, "interface/theme/use_system_accent_color", false, "") EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "interface/theme/contrast", 0.3, "-1,1,0.01") EDITOR_SETTING(Variant::BOOL, PROPERTY_HINT_NONE, "interface/theme/draw_extra_borders", false, "") EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "interface/theme/icon_saturation", 1.0, "0,2,0.01") diff --git a/editor/themes/editor_theme_manager.cpp b/editor/themes/editor_theme_manager.cpp index 052b19478c74..4ceffcc98c90 100644 --- a/editor/themes/editor_theme_manager.cpp +++ b/editor/themes/editor_theme_manager.cpp @@ -252,6 +252,29 @@ EditorThemeManager::ThemeConfiguration EditorThemeManager::_create_theme_config( // Handle main theme preset. { + const bool follow_system_theme = EDITOR_GET("interface/theme/follow_system_theme"); + const bool use_system_accent_color = EDITOR_GET("interface/theme/use_system_accent_color"); + DisplayServer *display_server = DisplayServer::get_singleton(); + Color system_base_color = display_server->get_base_color(); + Color system_accent_color = display_server->get_accent_color(); + + if (follow_system_theme) { + String dark_theme = "Default"; + String light_theme = "Light"; + + config.preset = light_theme; // Assume light theme if we can't detect system theme attributes. + + if (system_base_color == Color(0, 0, 0, 0)) { + if (display_server->is_dark_mode_supported() && display_server->is_dark_mode()) { + config.preset = dark_theme; + } + } else { + if (system_base_color.get_luminance() < 0.5) { + config.preset = dark_theme; + } + } + } + if (config.preset != "Custom") { Color preset_accent_color; Color preset_base_color; @@ -308,6 +331,16 @@ EditorThemeManager::ThemeConfiguration EditorThemeManager::_create_theme_config( EditorSettings::get_singleton()->set_initial_value("interface/theme/draw_extra_borders", config.draw_extra_borders); } + if (follow_system_theme && system_base_color != Color(0, 0, 0, 0)) { + config.base_color = system_base_color; + config.preset = "Custom"; + } + + if (use_system_accent_color && system_accent_color != Color(0, 0, 0, 0)) { + config.accent_color = system_accent_color; + config.preset = "Custom"; + } + // Enforce values in case they were adjusted or overridden. EditorSettings::get_singleton()->set_manually("interface/theme/preset", config.preset); EditorSettings::get_singleton()->set_manually("interface/theme/accent_color", config.accent_color);