diff --git a/doc/classes/@GlobalScope.xml b/doc/classes/@GlobalScope.xml index bd500f6b358..b2bc9265854 100644 --- a/doc/classes/@GlobalScope.xml +++ b/doc/classes/@GlobalScope.xml @@ -1297,6 +1297,9 @@ The [TextServerManager] singleton. + + The [ThemeDB] singleton. + The [Time] singleton. diff --git a/doc/classes/Control.xml b/doc/classes/Control.xml index a3cd4d07523..8490d79742d 100644 --- a/doc/classes/Control.xml +++ b/doc/classes/Control.xml @@ -436,7 +436,7 @@ Returns a [Color] from the first matching [Theme] in the tree if that [Theme] has a color item with the specified [param name] and [param theme_type]. If [param theme_type] is omitted the class name of the current control is used as the type, or [member theme_type_variation] if it is defined. If the type is a class name its parent classes are also checked, in order of inheritance. If the type is a variation its base types are checked, in order of dependency, then the control's class name and its parent classes are checked. - For the current control its local overrides are considered first (see [method add_theme_color_override]), then its assigned [member theme]. After the current control, each parent control and its assigned [member theme] are considered; controls without a [member theme] assigned are skipped. If no matching [Theme] is found in the tree, a custom project [Theme] (see [member ProjectSettings.gui/theme/custom]) and the default [Theme] are used. + For the current control its local overrides are considered first (see [method add_theme_color_override]), then its assigned [member theme]. After the current control, each parent control and its assigned [member theme] are considered; controls without a [member theme] assigned are skipped. If no matching [Theme] is found in the tree, the custom project [Theme] (see [member ProjectSettings.gui/theme/custom]) and the default [Theme] are used (see [ThemeDB]). [codeblocks] [gdscript] func _ready(): diff --git a/doc/classes/Theme.xml b/doc/classes/Theme.xml index 868933bdf76..7fc01ea3536 100644 --- a/doc/classes/Theme.xml +++ b/doc/classes/Theme.xml @@ -150,7 +150,7 @@ Returns the [Font] property defined by [param name] and [param theme_type], if it exists. Returns the default theme font if the property doesn't exist and the default theme font is set up (see [member default_font]). Use [method has_font] to check for existence of the property and [method has_default_font] to check for existence of the default theme font. - Returns the engine fallback font value, if neither exist. + Returns the engine fallback font value, if neither exist (see [member ThemeDB.fallback_font]). @@ -167,7 +167,7 @@ Returns the font size property defined by [param name] and [param theme_type], if it exists. Returns the default theme font size if the property doesn't exist and the default theme font size is set up (see [member default_font_size]). Use [method has_font_size] to check for existence of the property and [method has_default_font_size] to check for existence of the default theme font. - Returns the engine fallback font size value, if neither exist. + Returns the engine fallback font size value, if neither exist (see [member ThemeDB.fallback_font_size]). @@ -195,7 +195,7 @@ Returns the icon property defined by [param name] and [param theme_type], if it exists. - Returns the engine fallback icon value if the property doesn't exist. Use [method has_icon] to check for existence. + Returns the engine fallback icon value if the property doesn't exist (see [member ThemeDB.fallback_icon]). Use [method has_icon] to check for existence. @@ -217,7 +217,7 @@ Returns the [StyleBox] property defined by [param name] and [param theme_type], if it exists. - Returns the engine fallback stylebox value if the property doesn't exist. Use [method has_stylebox] to check for existence. + Returns the engine fallback stylebox value if the property doesn't exist (see [member ThemeDB.fallback_stylebox]). Use [method has_stylebox] to check for existence. @@ -240,7 +240,7 @@ Returns the theme property of [param data_type] defined by [param name] and [param theme_type], if it exists. - Returns the engine fallback icon value if the property doesn't exist. Use [method has_theme_item] to check for existence. + Returns the engine fallback icon value if the property doesn't exist (see [ThemeDB]). Use [method has_theme_item] to check for existence. [b]Note:[/b] This method is analogous to calling the corresponding data type specific method, but can be used for more generalized logic. @@ -542,15 +542,15 @@ - The default base scale factor of this theme resource. Used by some controls to scale their visual properties based on the global scale factor. If this value is set to [code]0.0[/code], the global scale factor is used. + The default base scale factor of this theme resource. Used by some controls to scale their visual properties based on the global scale factor. If this value is set to [code]0.0[/code], the global scale factor is used (see [member ThemeDB.fallback_base_scale]). Use [method has_default_base_scale] to check if this value is valid. - The default font of this theme resource. Used as the default value when trying to fetch a font resource that doesn't exist in this theme or is in invalid state. If the default font is also missing or invalid, the engine fallback value is used. + The default font of this theme resource. Used as the default value when trying to fetch a font resource that doesn't exist in this theme or is in invalid state. If the default font is also missing or invalid, the engine fallback value is used (see [member ThemeDB.fallback_font]). Use [method has_default_font] to check if this value is valid. - The default font size of this theme resource. Used as the default value when trying to fetch a font size value that doesn't exist in this theme or is in invalid state. If the default font size is also missing or invalid, the engine fallback value is used. + The default font size of this theme resource. Used as the default value when trying to fetch a font size value that doesn't exist in this theme or is in invalid state. If the default font size is also missing or invalid, the engine fallback value is used (see [member ThemeDB.fallback_font_size]). Values below [code]0[/code] are invalid and can be used to unset the property. Use [method has_default_font_size] to check if this value is valid. diff --git a/doc/classes/ThemeDB.xml b/doc/classes/ThemeDB.xml new file mode 100644 index 00000000000..6003ffb28e7 --- /dev/null +++ b/doc/classes/ThemeDB.xml @@ -0,0 +1,54 @@ + + + + An engine singleton providing access to static [Theme] information, such as default and project theme, and fallback values. + + + This engine singleton provides access to static information about [Theme] resources used by the engine and by your projects. You can fetch the default engine theme, as well as your project configured theme. + [ThemeDB] also contains fallback values for theme properties. + + + + + + + + Returns a reference to the default engine [Theme]. This theme resource is responsible for the out-of-the-box look of [Control] nodes and cannot be overridden. + + + + + + Returns a reference to the custom project [Theme]. This theme resources allows to override the default engine theme for every control node in the project. + To set the project theme, see [member ProjectSettings.gui/theme/custom]. + + + + + + The fallback base scale factor of every [Control] node and [Theme] resource. Used when no other value is available to the control. + See also [member Theme.default_base_scale]. + + + The fallback font of every [Control] node and [Theme] resource. Used when no other value is available to the control. + See also [member Theme.default_font]. + + + The fallback font size of every [Control] node and [Theme] resource. Used when no other value is available to the control. + See also [member Theme.default_font_size]. + + + The fallback icon of every [Control] node and [Theme] resource. Used when no other value is available to the control. + + + The fallback stylebox of every [Control] node and [Theme] resource. Used when no other value is available to the control. + + + + + + Emitted when one of the fallback values had been changed. Use it to refresh the look of controls that may rely on the fallback theme items. + + + + diff --git a/editor/doc_tools.cpp b/editor/doc_tools.cpp index 864871bb7e9..489a55ede08 100644 --- a/editor/doc_tools.cpp +++ b/editor/doc_tools.cpp @@ -41,6 +41,7 @@ #include "core/version.h" #include "editor/editor_settings.h" #include "scene/resources/theme.h" +#include "scene/theme/theme_db.h" // Used for a hack preserving Mono properties on non-Mono builds. #include "modules/modules_enabled.gen.h" // For mono. @@ -567,29 +568,29 @@ void DocTools::generate(bool p_basic_types) { { List l; - Theme::get_default()->get_color_list(cname, &l); + ThemeDB::get_singleton()->get_default_theme()->get_color_list(cname, &l); for (const StringName &E : l) { DocData::ThemeItemDoc tid; tid.name = E; tid.type = "Color"; tid.data_type = "color"; - tid.default_value = Variant(Theme::get_default()->get_color(E, cname)).get_construct_string().replace("\n", " "); + tid.default_value = Variant(ThemeDB::get_singleton()->get_default_theme()->get_color(E, cname)).get_construct_string().replace("\n", " "); c.theme_properties.push_back(tid); } l.clear(); - Theme::get_default()->get_constant_list(cname, &l); + ThemeDB::get_singleton()->get_default_theme()->get_constant_list(cname, &l); for (const StringName &E : l) { DocData::ThemeItemDoc tid; tid.name = E; tid.type = "int"; tid.data_type = "constant"; - tid.default_value = itos(Theme::get_default()->get_constant(E, cname)); + tid.default_value = itos(ThemeDB::get_singleton()->get_default_theme()->get_constant(E, cname)); c.theme_properties.push_back(tid); } l.clear(); - Theme::get_default()->get_font_list(cname, &l); + ThemeDB::get_singleton()->get_default_theme()->get_font_list(cname, &l); for (const StringName &E : l) { DocData::ThemeItemDoc tid; tid.name = E; @@ -599,7 +600,7 @@ void DocTools::generate(bool p_basic_types) { } l.clear(); - Theme::get_default()->get_font_size_list(cname, &l); + ThemeDB::get_singleton()->get_default_theme()->get_font_size_list(cname, &l); for (const StringName &E : l) { DocData::ThemeItemDoc tid; tid.name = E; @@ -609,7 +610,7 @@ void DocTools::generate(bool p_basic_types) { } l.clear(); - Theme::get_default()->get_icon_list(cname, &l); + ThemeDB::get_singleton()->get_default_theme()->get_icon_list(cname, &l); for (const StringName &E : l) { DocData::ThemeItemDoc tid; tid.name = E; @@ -619,7 +620,7 @@ void DocTools::generate(bool p_basic_types) { } l.clear(); - Theme::get_default()->get_stylebox_list(cname, &l); + ThemeDB::get_singleton()->get_default_theme()->get_stylebox_list(cname, &l); for (const StringName &E : l) { DocData::ThemeItemDoc tid; tid.name = E; diff --git a/editor/plugins/theme_editor_plugin.cpp b/editor/plugins/theme_editor_plugin.cpp index af3959d47cd..0882f9409da 100644 --- a/editor/plugins/theme_editor_plugin.cpp +++ b/editor/plugins/theme_editor_plugin.cpp @@ -38,6 +38,7 @@ #include "editor/editor_undo_redo_manager.h" #include "editor/progress_dialog.h" #include "scene/gui/color_picker.h" +#include "scene/theme/theme_db.h" void ThemeItemImportTree::_update_items_tree() { import_items_tree->clear(); @@ -1202,7 +1203,7 @@ void ThemeItemEditorDialog::_dialog_about_to_show() { _update_edit_types(); import_default_theme_items->set_edited_theme(edited_theme); - import_default_theme_items->set_base_theme(Theme::get_default()); + import_default_theme_items->set_base_theme(ThemeDB::get_singleton()->get_default_theme()); import_default_theme_items->reset_item_tree(); import_editor_theme_items->set_edited_theme(edited_theme); @@ -1214,7 +1215,7 @@ void ThemeItemEditorDialog::_dialog_about_to_show() { } void ThemeItemEditorDialog::_update_edit_types() { - Ref base_theme = Theme::get_default(); + Ref base_theme = ThemeDB::get_singleton()->get_default_theme(); List theme_types; edited_theme->get_type_list(&theme_types); @@ -1630,7 +1631,7 @@ void ThemeItemEditorDialog::_remove_class_items() { Theme::DataType data_type = (Theme::DataType)dt; names.clear(); - Theme::get_default()->get_theme_item_list(data_type, edited_item_type, &names); + ThemeDB::get_singleton()->get_default_theme()->get_theme_item_list(data_type, edited_item_type, &names); for (const StringName &E : names) { if (new_snapshot->has_theme_item_nocheck(data_type, E, edited_item_type)) { new_snapshot->clear_theme_item(data_type, E, edited_item_type); @@ -1668,7 +1669,7 @@ void ThemeItemEditorDialog::_remove_custom_items() { names.clear(); new_snapshot->get_theme_item_list(data_type, edited_item_type, &names); for (const StringName &E : names) { - if (!Theme::get_default()->has_theme_item_nocheck(data_type, E, edited_item_type)) { + if (!ThemeDB::get_singleton()->get_default_theme()->has_theme_item_nocheck(data_type, E, edited_item_type)) { new_snapshot->clear_theme_item(data_type, E, edited_item_type); if (dt == Theme::DATA_TYPE_STYLEBOX && theme_type_editor->is_stylebox_pinned(edited_theme->get_stylebox(E, edited_item_type))) { @@ -2129,7 +2130,7 @@ void ThemeTypeDialog::_update_add_type_options(const String &p_filter) { add_type_options->clear(); List names; - Theme::get_default()->get_type_list(&names); + ThemeDB::get_singleton()->get_default_theme()->get_type_list(&names); if (include_own_types) { edited_theme->get_type_list(&names); } @@ -2370,7 +2371,7 @@ HashMap ThemeTypeEditor::_get_type_items(String p_type_name, v default_type = edited_theme->get_type_variation_base(p_type_name); } - (Theme::get_default().operator->()->*get_list_func)(default_type, &names); + (ThemeDB::get_singleton()->get_default_theme().operator->()->*get_list_func)(default_type, &names); names.sort_custom(); for (const StringName &E : names) { items[E] = false; @@ -2496,7 +2497,7 @@ void ThemeTypeEditor::_update_type_items() { item_editor->connect("color_changed", callable_mp(this, &ThemeTypeEditor::_color_item_changed).bind(E.key)); item_editor->get_popup()->connect("about_to_popup", callable_mp(EditorNode::get_singleton(), &EditorNode::setup_color_picker).bind(item_editor->get_picker())); } else { - item_editor->set_pick_color(Theme::get_default()->get_color(E.key, edited_type)); + item_editor->set_pick_color(ThemeDB::get_singleton()->get_default_theme()->get_color(E.key, edited_type)); item_editor->set_disabled(true); } @@ -2529,7 +2530,7 @@ void ThemeTypeEditor::_update_type_items() { item_editor->set_value(edited_theme->get_constant(E.key, edited_type)); item_editor->connect("value_changed", callable_mp(this, &ThemeTypeEditor::_constant_item_changed).bind(E.key)); } else { - item_editor->set_value(Theme::get_default()->get_constant(E.key, edited_type)); + item_editor->set_value(ThemeDB::get_singleton()->get_default_theme()->get_constant(E.key, edited_type)); item_editor->set_editable(false); } @@ -2563,8 +2564,8 @@ void ThemeTypeEditor::_update_type_items() { item_editor->connect("resource_selected", callable_mp(this, &ThemeTypeEditor::_edit_resource_item)); item_editor->connect("resource_changed", callable_mp(this, &ThemeTypeEditor::_font_item_changed).bind(E.key)); } else { - if (Theme::get_default()->has_font(E.key, edited_type)) { - item_editor->set_edited_resource(Theme::get_default()->get_font(E.key, edited_type)); + if (ThemeDB::get_singleton()->get_default_theme()->has_font(E.key, edited_type)) { + item_editor->set_edited_resource(ThemeDB::get_singleton()->get_default_theme()->get_font(E.key, edited_type)); } else { item_editor->set_edited_resource(Ref()); } @@ -2600,7 +2601,7 @@ void ThemeTypeEditor::_update_type_items() { item_editor->set_value(edited_theme->get_font_size(E.key, edited_type)); item_editor->connect("value_changed", callable_mp(this, &ThemeTypeEditor::_font_size_item_changed).bind(E.key)); } else { - item_editor->set_value(Theme::get_default()->get_font_size(E.key, edited_type)); + item_editor->set_value(ThemeDB::get_singleton()->get_default_theme()->get_font_size(E.key, edited_type)); item_editor->set_editable(false); } @@ -2634,8 +2635,8 @@ void ThemeTypeEditor::_update_type_items() { item_editor->connect("resource_selected", callable_mp(this, &ThemeTypeEditor::_edit_resource_item)); item_editor->connect("resource_changed", callable_mp(this, &ThemeTypeEditor::_icon_item_changed).bind(E.key)); } else { - if (Theme::get_default()->has_icon(E.key, edited_type)) { - item_editor->set_edited_resource(Theme::get_default()->get_icon(E.key, edited_type)); + if (ThemeDB::get_singleton()->get_default_theme()->has_icon(E.key, edited_type)) { + item_editor->set_edited_resource(ThemeDB::get_singleton()->get_default_theme()->get_icon(E.key, edited_type)); } else { item_editor->set_edited_resource(Ref()); } @@ -2714,8 +2715,8 @@ void ThemeTypeEditor::_update_type_items() { item_control->add_child(pin_leader_button); pin_leader_button->connect("pressed", callable_mp(this, &ThemeTypeEditor::_on_pin_leader_button_pressed).bind(item_editor, E.key)); } else { - if (Theme::get_default()->has_stylebox(E.key, edited_type)) { - item_editor->set_edited_resource(Theme::get_default()->get_stylebox(E.key, edited_type)); + if (ThemeDB::get_singleton()->get_default_theme()->has_stylebox(E.key, edited_type)) { + item_editor->set_edited_resource(ThemeDB::get_singleton()->get_default_theme()->get_stylebox(E.key, edited_type)); } else { item_editor->set_edited_resource(Ref()); } @@ -2770,55 +2771,55 @@ void ThemeTypeEditor::_add_default_type_items() { { names.clear(); - Theme::get_default()->get_icon_list(default_type, &names); + ThemeDB::get_singleton()->get_default_theme()->get_icon_list(default_type, &names); for (const StringName &E : names) { if (!new_snapshot->has_icon(E, edited_type)) { - new_snapshot->set_icon(E, edited_type, Theme::get_default()->get_icon(E, edited_type)); + new_snapshot->set_icon(E, edited_type, ThemeDB::get_singleton()->get_default_theme()->get_icon(E, edited_type)); } } } { names.clear(); - Theme::get_default()->get_stylebox_list(default_type, &names); + ThemeDB::get_singleton()->get_default_theme()->get_stylebox_list(default_type, &names); for (const StringName &E : names) { if (!new_snapshot->has_stylebox(E, edited_type)) { - new_snapshot->set_stylebox(E, edited_type, Theme::get_default()->get_stylebox(E, edited_type)); + new_snapshot->set_stylebox(E, edited_type, ThemeDB::get_singleton()->get_default_theme()->get_stylebox(E, edited_type)); } } } { names.clear(); - Theme::get_default()->get_font_list(default_type, &names); + ThemeDB::get_singleton()->get_default_theme()->get_font_list(default_type, &names); for (const StringName &E : names) { if (!new_snapshot->has_font(E, edited_type)) { - new_snapshot->set_font(E, edited_type, Theme::get_default()->get_font(E, edited_type)); + new_snapshot->set_font(E, edited_type, ThemeDB::get_singleton()->get_default_theme()->get_font(E, edited_type)); } } } { names.clear(); - Theme::get_default()->get_font_size_list(default_type, &names); + ThemeDB::get_singleton()->get_default_theme()->get_font_size_list(default_type, &names); for (const StringName &E : names) { if (!new_snapshot->has_font_size(E, edited_type)) { - new_snapshot->set_font_size(E, edited_type, Theme::get_default()->get_font_size(E, edited_type)); + new_snapshot->set_font_size(E, edited_type, ThemeDB::get_singleton()->get_default_theme()->get_font_size(E, edited_type)); } } } { names.clear(); - Theme::get_default()->get_color_list(default_type, &names); + ThemeDB::get_singleton()->get_default_theme()->get_color_list(default_type, &names); for (const StringName &E : names) { if (!new_snapshot->has_color(E, edited_type)) { - new_snapshot->set_color(E, edited_type, Theme::get_default()->get_color(E, edited_type)); + new_snapshot->set_color(E, edited_type, ThemeDB::get_singleton()->get_default_theme()->get_color(E, edited_type)); } } } { names.clear(); - Theme::get_default()->get_constant_list(default_type, &names); + ThemeDB::get_singleton()->get_default_theme()->get_constant_list(default_type, &names); for (const StringName &E : names) { if (!new_snapshot->has_constant(E, edited_type)) { - new_snapshot->set_constant(E, edited_type, Theme::get_default()->get_constant(E, edited_type)); + new_snapshot->set_constant(E, edited_type, ThemeDB::get_singleton()->get_default_theme()->get_constant(E, edited_type)); } } } @@ -2895,11 +2896,11 @@ void ThemeTypeEditor::_item_override_cbk(int p_data_type, String p_item_name) { switch (p_data_type) { case Theme::DATA_TYPE_COLOR: { - ur->add_do_method(*edited_theme, "set_color", p_item_name, edited_type, Theme::get_default()->get_color(p_item_name, edited_type)); + ur->add_do_method(*edited_theme, "set_color", p_item_name, edited_type, ThemeDB::get_singleton()->get_default_theme()->get_color(p_item_name, edited_type)); ur->add_undo_method(*edited_theme, "clear_color", p_item_name, edited_type); } break; case Theme::DATA_TYPE_CONSTANT: { - ur->add_do_method(*edited_theme, "set_constant", p_item_name, edited_type, Theme::get_default()->get_constant(p_item_name, edited_type)); + ur->add_do_method(*edited_theme, "set_constant", p_item_name, edited_type, ThemeDB::get_singleton()->get_default_theme()->get_constant(p_item_name, edited_type)); ur->add_undo_method(*edited_theme, "clear_constant", p_item_name, edited_type); } break; case Theme::DATA_TYPE_FONT: { @@ -2907,7 +2908,7 @@ void ThemeTypeEditor::_item_override_cbk(int p_data_type, String p_item_name) { ur->add_undo_method(*edited_theme, "clear_font", p_item_name, edited_type); } break; case Theme::DATA_TYPE_FONT_SIZE: { - ur->add_do_method(*edited_theme, "set_font_size", p_item_name, edited_type, Theme::get_default()->get_font_size(p_item_name, edited_type)); + ur->add_do_method(*edited_theme, "set_font_size", p_item_name, edited_type, ThemeDB::get_singleton()->get_default_theme()->get_font_size(p_item_name, edited_type)); ur->add_undo_method(*edited_theme, "clear_font_size", p_item_name, edited_type); } break; case Theme::DATA_TYPE_ICON: { diff --git a/editor/plugins/theme_editor_preview.cpp b/editor/plugins/theme_editor_preview.cpp index b5c6c6d6519..9a32e9317c5 100644 --- a/editor/plugins/theme_editor_preview.cpp +++ b/editor/plugins/theme_editor_preview.cpp @@ -40,6 +40,7 @@ #include "scene/gui/color_picker.h" #include "scene/gui/progress_bar.h" #include "scene/resources/packed_scene.h" +#include "scene/theme/theme_db.h" constexpr double REFRESH_TIMER = 1.5; @@ -240,7 +241,7 @@ ThemeEditorPreview::ThemeEditorPreview() { MarginContainer *preview_root = memnew(MarginContainer); preview_container->add_child(preview_root); - preview_root->set_theme(Theme::get_default()); + preview_root->set_theme(ThemeDB::get_singleton()->get_default_theme()); preview_root->set_clip_contents(true); preview_root->set_custom_minimum_size(Size2(450, 0) * EDSCALE); preview_root->set_v_size_flags(SIZE_EXPAND_FILL); diff --git a/main/main.cpp b/main/main.cpp index 126ac590701..085a395ded8 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -63,6 +63,7 @@ #include "scene/main/window.h" #include "scene/register_scene_types.h" #include "scene/resources/packed_scene.h" +#include "scene/theme/theme_db.h" #include "servers/audio_server.h" #include "servers/camera_server.h" #include "servers/display_server.h" @@ -129,6 +130,7 @@ static PhysicsServer3D *physics_server_3d = nullptr; static PhysicsServer2D *physics_server_2d = nullptr; static NavigationServer3D *navigation_server_3d = nullptr; static NavigationServer2D *navigation_server_2d = nullptr; +static ThemeDB *theme_db = nullptr; // We error out if setup2() doesn't turn this true static bool _start_success = false; @@ -273,6 +275,16 @@ void finalize_navigation_server() { navigation_server_2d = nullptr; } +void initialize_theme_db() { + theme_db = memnew(ThemeDB); + theme_db->initialize_theme(); +} + +void finalize_theme_db() { + memdelete(theme_db); + theme_db = nullptr; +} + //#define DEBUG_INIT #ifdef DEBUG_INIT #define MAIN_PRINT(m_txt) print_line(m_txt) @@ -475,7 +487,8 @@ Error Main::test_setup() { register_platform_apis(); // Theme needs modules to be initialized so that sub-resources can be loaded. - initialize_theme(); + initialize_theme_db(); + register_scene_singletons(); ERR_FAIL_COND_V(TextServerManager::get_singleton()->get_interface_count() == 0, ERR_CANT_CREATE); @@ -526,6 +539,8 @@ void Main::test_cleanup() { unregister_driver_types(); unregister_scene_types(); + finalize_theme_db(); + NativeExtensionManager::get_singleton()->deinitialize_extensions(NativeExtension::INITIALIZATION_LEVEL_SERVERS); uninitialize_modules(MODULE_INITIALIZATION_LEVEL_SERVERS); unregister_server_types(); @@ -2126,7 +2141,8 @@ Error Main::setup2(Thread::ID p_main_tid_override) { register_platform_apis(); // Theme needs modules to be initialized so that sub-resources can be loaded. - initialize_theme(); + initialize_theme_db(); + register_scene_singletons(); GLOBAL_DEF_BASIC("display/mouse_cursor/custom_image", String()); GLOBAL_DEF_BASIC("display/mouse_cursor/custom_image_hotspot", Vector2()); @@ -3120,6 +3136,8 @@ void Main::cleanup(bool p_force) { unregister_driver_types(); unregister_scene_types(); + finalize_theme_db(); + NativeExtensionManager::get_singleton()->deinitialize_extensions(NativeExtension::INITIALIZATION_LEVEL_SERVERS); uninitialize_modules(MODULE_INITIALIZATION_LEVEL_SERVERS); unregister_server_types(); diff --git a/modules/mono/editor/code_completion.cpp b/modules/mono/editor/code_completion.cpp index 7bce6f2c219..36c46627e2a 100644 --- a/modules/mono/editor/code_completion.cpp +++ b/modules/mono/editor/code_completion.cpp @@ -35,6 +35,7 @@ #include "editor/editor_settings.h" #include "scene/gui/control.h" #include "scene/main/node.h" +#include "scene/theme/theme_db.h" namespace gdmono { @@ -195,7 +196,7 @@ PackedStringArray get_code_completion(CompletionKind p_kind, const String &p_scr Node *base = _try_find_owner_node_in_tree(script); if (base && Object::cast_to(base)) { List sn; - Theme::get_default()->get_color_list(base->get_class(), &sn); + ThemeDB::get_singleton()->get_default_theme()->get_color_list(base->get_class(), &sn); for (const StringName &E : sn) { suggestions.push_back(quoted(E)); @@ -207,7 +208,7 @@ PackedStringArray get_code_completion(CompletionKind p_kind, const String &p_scr Node *base = _try_find_owner_node_in_tree(script); if (base && Object::cast_to(base)) { List sn; - Theme::get_default()->get_constant_list(base->get_class(), &sn); + ThemeDB::get_singleton()->get_default_theme()->get_constant_list(base->get_class(), &sn); for (const StringName &E : sn) { suggestions.push_back(quoted(E)); @@ -219,7 +220,7 @@ PackedStringArray get_code_completion(CompletionKind p_kind, const String &p_scr Node *base = _try_find_owner_node_in_tree(script); if (base && Object::cast_to(base)) { List sn; - Theme::get_default()->get_font_list(base->get_class(), &sn); + ThemeDB::get_singleton()->get_default_theme()->get_font_list(base->get_class(), &sn); for (const StringName &E : sn) { suggestions.push_back(quoted(E)); @@ -231,7 +232,7 @@ PackedStringArray get_code_completion(CompletionKind p_kind, const String &p_scr Node *base = _try_find_owner_node_in_tree(script); if (base && Object::cast_to(base)) { List sn; - Theme::get_default()->get_font_size_list(base->get_class(), &sn); + ThemeDB::get_singleton()->get_default_theme()->get_font_size_list(base->get_class(), &sn); for (const StringName &E : sn) { suggestions.push_back(quoted(E)); @@ -243,7 +244,7 @@ PackedStringArray get_code_completion(CompletionKind p_kind, const String &p_scr Node *base = _try_find_owner_node_in_tree(script); if (base && Object::cast_to(base)) { List sn; - Theme::get_default()->get_stylebox_list(base->get_class(), &sn); + ThemeDB::get_singleton()->get_default_theme()->get_stylebox_list(base->get_class(), &sn); for (const StringName &E : sn) { suggestions.push_back(quoted(E)); diff --git a/scene/3d/label_3d.cpp b/scene/3d/label_3d.cpp index 40b8af7d635..e4a7cf6ee53 100644 --- a/scene/3d/label_3d.cpp +++ b/scene/3d/label_3d.cpp @@ -34,6 +34,7 @@ #include "scene/main/viewport.h" #include "scene/resources/theme.h" #include "scene/scene_string_names.h" +#include "scene/theme/theme_db.h" void Label3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_horizontal_alignment", "alignment"), &Label3D::set_horizontal_alignment); @@ -734,13 +735,13 @@ Ref Label3D::_get_font_or_default() const { } // Check the project-defined Theme resource. - if (Theme::get_project_default().is_valid()) { + if (ThemeDB::get_singleton()->get_project_theme().is_valid()) { List theme_types; - Theme::get_project_default()->get_type_dependencies(get_class_name(), StringName(), &theme_types); + ThemeDB::get_singleton()->get_project_theme()->get_type_dependencies(get_class_name(), StringName(), &theme_types); for (const StringName &E : theme_types) { - if (Theme::get_project_default()->has_theme_item(Theme::DATA_TYPE_FONT, "font", E)) { - Ref f = Theme::get_project_default()->get_theme_item(Theme::DATA_TYPE_FONT, "font", E); + if (ThemeDB::get_singleton()->get_project_theme()->has_theme_item(Theme::DATA_TYPE_FONT, "font", E)) { + Ref f = ThemeDB::get_singleton()->get_project_theme()->get_theme_item(Theme::DATA_TYPE_FONT, "font", E); if (f.is_valid()) { theme_font = f; theme_font->connect(CoreStringNames::get_singleton()->changed, Callable(const_cast(this), "_font_changed")); @@ -753,11 +754,11 @@ Ref Label3D::_get_font_or_default() const { // Lastly, fall back on the items defined in the default Theme, if they exist. { List theme_types; - Theme::get_default()->get_type_dependencies(get_class_name(), StringName(), &theme_types); + ThemeDB::get_singleton()->get_default_theme()->get_type_dependencies(get_class_name(), StringName(), &theme_types); for (const StringName &E : theme_types) { - if (Theme::get_default()->has_theme_item(Theme::DATA_TYPE_FONT, "font", E)) { - Ref f = Theme::get_default()->get_theme_item(Theme::DATA_TYPE_FONT, "font", E); + if (ThemeDB::get_singleton()->get_default_theme()->has_theme_item(Theme::DATA_TYPE_FONT, "font", E)) { + Ref f = ThemeDB::get_singleton()->get_default_theme()->get_theme_item(Theme::DATA_TYPE_FONT, "font", E); if (f.is_valid()) { theme_font = f; theme_font->connect(CoreStringNames::get_singleton()->changed, Callable(const_cast(this), "_font_changed")); @@ -768,7 +769,7 @@ Ref Label3D::_get_font_or_default() const { } // If they don't exist, use any type to return the default/empty value. - Ref f = Theme::get_default()->get_theme_item(Theme::DATA_TYPE_FONT, "font", StringName()); + Ref f = ThemeDB::get_singleton()->get_default_theme()->get_theme_item(Theme::DATA_TYPE_FONT, "font", StringName()); if (f.is_valid()) { theme_font = f; theme_font->connect(CoreStringNames::get_singleton()->changed, Callable(const_cast(this), "_font_changed")); diff --git a/scene/SCsub b/scene/SCsub index 92288211bbc..b4b2d6dd0a4 100644 --- a/scene/SCsub +++ b/scene/SCsub @@ -17,6 +17,7 @@ SConscript("animation/SCsub") SConscript("audio/SCsub") SConscript("resources/SCsub") SConscript("debugger/SCsub") +SConscript("theme/SCsub") # Build it all as a library lib = env.add_library("scene", env.scene_sources) diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp index 9b6a19c50a0..6dd3d46b279 100644 --- a/scene/gui/control.cpp +++ b/scene/gui/control.cpp @@ -43,6 +43,7 @@ #include "scene/main/canvas_layer.h" #include "scene/main/window.h" #include "scene/scene_string_names.h" +#include "scene/theme/theme_db.h" #include "servers/rendering_server.h" #include "servers/text_server.h" @@ -193,15 +194,15 @@ void Control::get_argument_options(const StringName &p_function, int p_idx, List List sn; String pf = p_function; if (pf == "add_theme_color_override" || pf == "has_theme_color" || pf == "has_theme_color_override" || pf == "get_theme_color") { - Theme::get_default()->get_color_list(get_class(), &sn); + ThemeDB::get_singleton()->get_default_theme()->get_color_list(get_class(), &sn); } else if (pf == "add_theme_style_override" || pf == "has_theme_style" || pf == "has_theme_style_override" || pf == "get_theme_style") { - Theme::get_default()->get_stylebox_list(get_class(), &sn); + ThemeDB::get_singleton()->get_default_theme()->get_stylebox_list(get_class(), &sn); } else if (pf == "add_theme_font_override" || pf == "has_theme_font" || pf == "has_theme_font_override" || pf == "get_theme_font") { - Theme::get_default()->get_font_list(get_class(), &sn); + ThemeDB::get_singleton()->get_default_theme()->get_font_list(get_class(), &sn); } else if (pf == "add_theme_font_size_override" || pf == "has_theme_font_size" || pf == "has_theme_font_size_override" || pf == "get_theme_font_size") { - Theme::get_default()->get_font_size_list(get_class(), &sn); + ThemeDB::get_singleton()->get_default_theme()->get_font_size_list(get_class(), &sn); } else if (pf == "add_theme_constant_override" || pf == "has_theme_constant" || pf == "has_theme_constant_override" || pf == "get_theme_constant") { - Theme::get_default()->get_constant_list(get_class(), &sn); + ThemeDB::get_singleton()->get_default_theme()->get_constant_list(get_class(), &sn); } sn.sort_custom(); @@ -344,7 +345,7 @@ bool Control::_get(const StringName &p_name, Variant &r_ret) const { } void Control::_get_property_list(List *p_list) const { - Ref theme = Theme::get_default(); + Ref theme = ThemeDB::get_singleton()->get_default_theme(); p_list->push_back(PropertyInfo(Variant::NIL, TTRC("Theme Overrides"), PROPERTY_HINT_NONE, "theme_override_", PROPERTY_USAGE_GROUP)); @@ -429,9 +430,9 @@ void Control::_validate_property(PropertyInfo &p_property) const { // Only the default theme and the project theme are used for the list of options. // This is an imposed limitation to simplify the logic needed to leverage those options. - Theme::get_default()->get_type_variation_list(get_class_name(), &names); - if (Theme::get_project_default().is_valid()) { - Theme::get_project_default()->get_type_variation_list(get_class_name(), &names); + ThemeDB::get_singleton()->get_default_theme()->get_type_variation_list(get_class_name(), &names); + if (ThemeDB::get_singleton()->get_project_theme().is_valid()) { + ThemeDB::get_singleton()->get_project_theme()->get_type_variation_list(get_class_name(), &names); } names.sort_custom(); @@ -2419,22 +2420,22 @@ T Control::get_theme_item_in_types(Control *p_theme_owner, Window *p_theme_owner } // Secondly, check the project-defined Theme resource. - if (Theme::get_project_default().is_valid()) { + if (ThemeDB::get_singleton()->get_project_theme().is_valid()) { for (const StringName &E : p_theme_types) { - if (Theme::get_project_default()->has_theme_item(p_data_type, p_name, E)) { - return Theme::get_project_default()->get_theme_item(p_data_type, p_name, E); + if (ThemeDB::get_singleton()->get_project_theme()->has_theme_item(p_data_type, p_name, E)) { + return ThemeDB::get_singleton()->get_project_theme()->get_theme_item(p_data_type, p_name, E); } } } // Lastly, fall back on the items defined in the default Theme, if they exist. for (const StringName &E : p_theme_types) { - if (Theme::get_default()->has_theme_item(p_data_type, p_name, E)) { - return Theme::get_default()->get_theme_item(p_data_type, p_name, E); + if (ThemeDB::get_singleton()->get_default_theme()->has_theme_item(p_data_type, p_name, E)) { + return ThemeDB::get_singleton()->get_default_theme()->get_theme_item(p_data_type, p_name, E); } } // If they don't exist, use any type to return the default/empty value. - return Theme::get_default()->get_theme_item(p_data_type, p_name, p_theme_types[0]); + return ThemeDB::get_singleton()->get_default_theme()->get_theme_item(p_data_type, p_name, p_theme_types[0]); } bool Control::has_theme_item_in_types(Control *p_theme_owner, Window *p_theme_owner_window, Theme::DataType p_data_type, const StringName &p_name, List p_theme_types) { @@ -2475,9 +2476,9 @@ bool Control::has_theme_item_in_types(Control *p_theme_owner, Window *p_theme_ow } // Secondly, check the project-defined Theme resource. - if (Theme::get_project_default().is_valid()) { + if (ThemeDB::get_singleton()->get_project_theme().is_valid()) { for (const StringName &E : p_theme_types) { - if (Theme::get_project_default()->has_theme_item(p_data_type, p_name, E)) { + if (ThemeDB::get_singleton()->get_project_theme()->has_theme_item(p_data_type, p_name, E)) { return true; } } @@ -2485,7 +2486,7 @@ bool Control::has_theme_item_in_types(Control *p_theme_owner, Window *p_theme_ow // Lastly, fall back on the items defined in the default Theme, if they exist. for (const StringName &E : p_theme_types) { - if (Theme::get_default()->has_theme_item(p_data_type, p_name, E)) { + if (ThemeDB::get_singleton()->get_default_theme()->has_theme_item(p_data_type, p_name, E)) { return true; } } @@ -2494,13 +2495,13 @@ bool Control::has_theme_item_in_types(Control *p_theme_owner, Window *p_theme_ow void Control::_get_theme_type_dependencies(const StringName &p_theme_type, List *p_list) const { if (p_theme_type == StringName() || p_theme_type == get_class_name() || p_theme_type == data.theme_type_variation) { - if (Theme::get_project_default().is_valid() && Theme::get_project_default()->get_type_variation_base(data.theme_type_variation) != StringName()) { - Theme::get_project_default()->get_type_dependencies(get_class_name(), data.theme_type_variation, p_list); + if (ThemeDB::get_singleton()->get_project_theme().is_valid() && ThemeDB::get_singleton()->get_project_theme()->get_type_variation_base(data.theme_type_variation) != StringName()) { + ThemeDB::get_singleton()->get_project_theme()->get_type_dependencies(get_class_name(), data.theme_type_variation, p_list); } else { - Theme::get_default()->get_type_dependencies(get_class_name(), data.theme_type_variation, p_list); + ThemeDB::get_singleton()->get_default_theme()->get_type_dependencies(get_class_name(), data.theme_type_variation, p_list); } } else { - Theme::get_default()->get_type_dependencies(p_theme_type, StringName(), p_list); + ThemeDB::get_singleton()->get_default_theme()->get_type_dependencies(p_theme_type, StringName(), p_list); } } @@ -2851,17 +2852,17 @@ float Control::fetch_theme_default_base_scale(Control *p_theme_owner, Window *p_ } // Secondly, check the project-defined Theme resource. - if (Theme::get_project_default().is_valid()) { - if (Theme::get_project_default()->has_default_base_scale()) { - return Theme::get_project_default()->get_default_base_scale(); + if (ThemeDB::get_singleton()->get_project_theme().is_valid()) { + if (ThemeDB::get_singleton()->get_project_theme()->has_default_base_scale()) { + return ThemeDB::get_singleton()->get_project_theme()->get_default_base_scale(); } } // Lastly, fall back on the default Theme. - if (Theme::get_default()->has_default_base_scale()) { - return Theme::get_default()->get_default_base_scale(); + if (ThemeDB::get_singleton()->get_default_theme()->has_default_base_scale()) { + return ThemeDB::get_singleton()->get_default_theme()->get_default_base_scale(); } - return Theme::get_fallback_base_scale(); + return ThemeDB::get_singleton()->get_fallback_base_scale(); } float Control::get_theme_default_base_scale() const { @@ -2902,17 +2903,17 @@ Ref Control::fetch_theme_default_font(Control *p_theme_owner, Window *p_th } // Secondly, check the project-defined Theme resource. - if (Theme::get_project_default().is_valid()) { - if (Theme::get_project_default()->has_default_font()) { - return Theme::get_project_default()->get_default_font(); + if (ThemeDB::get_singleton()->get_project_theme().is_valid()) { + if (ThemeDB::get_singleton()->get_project_theme()->has_default_font()) { + return ThemeDB::get_singleton()->get_project_theme()->get_default_font(); } } // Lastly, fall back on the default Theme. - if (Theme::get_default()->has_default_font()) { - return Theme::get_default()->get_default_font(); + if (ThemeDB::get_singleton()->get_default_theme()->has_default_font()) { + return ThemeDB::get_singleton()->get_default_theme()->get_default_font(); } - return Theme::get_fallback_font(); + return ThemeDB::get_singleton()->get_fallback_font(); } Ref Control::get_theme_default_font() const { @@ -2953,17 +2954,17 @@ int Control::fetch_theme_default_font_size(Control *p_theme_owner, Window *p_the } // Secondly, check the project-defined Theme resource. - if (Theme::get_project_default().is_valid()) { - if (Theme::get_project_default()->has_default_font_size()) { - return Theme::get_project_default()->get_default_font_size(); + if (ThemeDB::get_singleton()->get_project_theme().is_valid()) { + if (ThemeDB::get_singleton()->get_project_theme()->has_default_font_size()) { + return ThemeDB::get_singleton()->get_project_theme()->get_default_font_size(); } } // Lastly, fall back on the default Theme. - if (Theme::get_default()->has_default_font_size()) { - return Theme::get_default()->get_default_font_size(); + if (ThemeDB::get_singleton()->get_default_theme()->has_default_font_size()) { + return ThemeDB::get_singleton()->get_default_theme()->get_default_font_size(); } - return Theme::get_fallback_font_size(); + return ThemeDB::get_singleton()->get_fallback_font_size(); } int Control::get_theme_default_font_size() const { diff --git a/scene/main/window.cpp b/scene/main/window.cpp index 35414da9ed3..fa71040159b 100644 --- a/scene/main/window.cpp +++ b/scene/main/window.cpp @@ -35,6 +35,7 @@ #include "core/string/translation.h" #include "scene/gui/control.h" #include "scene/scene_string_names.h" +#include "scene/theme/theme_db.h" void Window::set_title(const String &p_title) { title = p_title; @@ -1330,13 +1331,13 @@ StringName Window::get_theme_type_variation() const { void Window::_get_theme_type_dependencies(const StringName &p_theme_type, List *p_list) const { if (p_theme_type == StringName() || p_theme_type == get_class_name() || p_theme_type == theme_type_variation) { - if (Theme::get_project_default().is_valid() && Theme::get_project_default()->get_type_variation_base(theme_type_variation) != StringName()) { - Theme::get_project_default()->get_type_dependencies(get_class_name(), theme_type_variation, p_list); + if (ThemeDB::get_singleton()->get_project_theme().is_valid() && ThemeDB::get_singleton()->get_project_theme()->get_type_variation_base(theme_type_variation) != StringName()) { + ThemeDB::get_singleton()->get_project_theme()->get_type_dependencies(get_class_name(), theme_type_variation, p_list); } else { - Theme::get_default()->get_type_dependencies(get_class_name(), theme_type_variation, p_list); + ThemeDB::get_singleton()->get_default_theme()->get_type_dependencies(get_class_name(), theme_type_variation, p_list); } } else { - Theme::get_default()->get_type_dependencies(p_theme_type, StringName(), p_list); + ThemeDB::get_singleton()->get_default_theme()->get_type_dependencies(p_theme_type, StringName(), p_list); } } @@ -1522,9 +1523,9 @@ void Window::_validate_property(PropertyInfo &p_property) const { // Only the default theme and the project theme are used for the list of options. // This is an imposed limitation to simplify the logic needed to leverage those options. - Theme::get_default()->get_type_variation_list(get_class_name(), &names); - if (Theme::get_project_default().is_valid()) { - Theme::get_project_default()->get_type_variation_list(get_class_name(), &names); + ThemeDB::get_singleton()->get_default_theme()->get_type_variation_list(get_class_name(), &names); + if (ThemeDB::get_singleton()->get_project_theme().is_valid()) { + ThemeDB::get_singleton()->get_project_theme()->get_type_variation_list(get_class_name(), &names); } names.sort_custom(); diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp index 9665873dceb..6bfb1907a28 100644 --- a/scene/register_scene_types.cpp +++ b/scene/register_scene_types.cpp @@ -193,12 +193,14 @@ #include "scene/resources/sky.h" #include "scene/resources/sky_material.h" #include "scene/resources/sphere_shape_3d.h" +#include "scene/resources/style_box.h" #include "scene/resources/surface_tool.h" #include "scene/resources/syntax_highlighter.h" #include "scene/resources/text_file.h" #include "scene/resources/text_line.h" #include "scene/resources/text_paragraph.h" #include "scene/resources/texture.h" +#include "scene/resources/theme.h" #include "scene/resources/tile_set.h" #include "scene/resources/video_stream.h" #include "scene/resources/visual_shader.h" @@ -210,6 +212,7 @@ #include "scene/resources/world_boundary_shape_2d.h" #include "scene/resources/world_boundary_shape_3d.h" #include "scene/scene_string_names.h" +#include "scene/theme/theme_db.h" #include "scene/main/shader_globals_override.h" @@ -1122,62 +1125,8 @@ void register_scene_types() { SceneDebugger::initialize(); } -void initialize_theme() { - // Allow creating the default theme at a different scale to suit higher/lower base resolutions. - float default_theme_scale = GLOBAL_DEF("gui/theme/default_theme_scale", 1.0); - ProjectSettings::get_singleton()->set_custom_property_info("gui/theme/default_theme_scale", PropertyInfo(Variant::FLOAT, "gui/theme/default_theme_scale", PROPERTY_HINT_RANGE, "0.5,8,0.01", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)); - - String theme_path = GLOBAL_DEF_RST("gui/theme/custom", ""); - ProjectSettings::get_singleton()->set_custom_property_info("gui/theme/custom", PropertyInfo(Variant::STRING, "gui/theme/custom", PROPERTY_HINT_FILE, "*.tres,*.res,*.theme", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)); - - String font_path = GLOBAL_DEF_RST("gui/theme/custom_font", ""); - ProjectSettings::get_singleton()->set_custom_property_info("gui/theme/custom_font", PropertyInfo(Variant::STRING, "gui/theme/custom_font", PROPERTY_HINT_FILE, "*.tres,*.res", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)); - - TextServer::FontAntialiasing font_antialiasing = (TextServer::FontAntialiasing)(int)GLOBAL_DEF_RST("gui/theme/default_font_antialiasing", 1); - ProjectSettings::get_singleton()->set_custom_property_info("gui/theme/default_font_antialiasing", PropertyInfo(Variant::INT, "gui/theme/default_font_antialiasing", PROPERTY_HINT_ENUM, "None,Grayscale,LCD sub-pixel", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)); - - TextServer::Hinting font_hinting = (TextServer::Hinting)(int)GLOBAL_DEF_RST("gui/theme/default_font_hinting", TextServer::HINTING_LIGHT); - ProjectSettings::get_singleton()->set_custom_property_info("gui/theme/default_font_hinting", PropertyInfo(Variant::INT, "gui/theme/default_font_hinting", PROPERTY_HINT_ENUM, "None,Light,Normal", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)); - - TextServer::SubpixelPositioning font_subpixel_positioning = (TextServer::SubpixelPositioning)(int)GLOBAL_DEF_RST("gui/theme/default_font_subpixel_positioning", TextServer::SUBPIXEL_POSITIONING_AUTO); - ProjectSettings::get_singleton()->set_custom_property_info("gui/theme/default_font_subpixel_positioning", PropertyInfo(Variant::INT, "gui/theme/default_font_subpixel_positioning", PROPERTY_HINT_ENUM, "Disabled,Auto,One half of a pixel,One quarter of a pixel", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)); - - const bool font_msdf = GLOBAL_DEF_RST("gui/theme/default_font_multichannel_signed_distance_field", false); - const bool font_generate_mipmaps = GLOBAL_DEF_RST("gui/theme/default_font_generate_mipmaps", false); - - GLOBAL_DEF_RST("gui/theme/lcd_subpixel_layout", 1); - ProjectSettings::get_singleton()->set_custom_property_info("gui/theme/lcd_subpixel_layout", PropertyInfo(Variant::INT, "gui/theme/lcd_subpixel_layout", PROPERTY_HINT_ENUM, "Disabled,Horizontal RGB,Horizontal BGR,Vertical RGB,Vertical BGR")); - ProjectSettings::get_singleton()->set_restart_if_changed("gui/theme/lcd_subpixel_layout", false); - - Ref font; - if (!font_path.is_empty()) { - font = ResourceLoader::load(font_path); - if (!font.is_valid()) { - ERR_PRINT("Error loading custom font '" + font_path + "'"); - } - } - - // Always make the default theme to avoid invalid default font/icon/style in the given theme. - if (RenderingServer::get_singleton()) { - make_default_theme(default_theme_scale, font, font_subpixel_positioning, font_hinting, font_antialiasing, font_msdf, font_generate_mipmaps); - } - - if (!theme_path.is_empty()) { - Ref theme = ResourceLoader::load(theme_path); - if (theme.is_valid()) { - Theme::set_project_default(theme); - if (font.is_valid()) { - Theme::set_fallback_font(font); - } - } else { - ERR_PRINT("Error loading custom theme '" + theme_path + "'"); - } - } -} - void unregister_scene_types() { SceneDebugger::deinitialize(); - clear_default_theme(); ResourceLoader::remove_resource_format_loader(resource_loader_texture_layered); resource_loader_texture_layered.unref(); @@ -1219,3 +1168,9 @@ void unregister_scene_types() { ColorPicker::finish_shaders(); SceneStringNames::free(); } + +void register_scene_singletons() { + GDREGISTER_CLASS(ThemeDB); + + Engine::get_singleton()->add_singleton(Engine::Singleton("ThemeDB", ThemeDB::get_singleton())); +} diff --git a/scene/register_scene_types.h b/scene/register_scene_types.h index dce87139766..cb3249c5d7b 100644 --- a/scene/register_scene_types.h +++ b/scene/register_scene_types.h @@ -33,7 +33,6 @@ void register_scene_types(); void unregister_scene_types(); - -void initialize_theme(); +void register_scene_singletons(); #endif // REGISTER_SCENE_TYPES_H diff --git a/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp index 5bfa1adfe59..410f35e5979 100644 --- a/scene/resources/default_theme/default_theme.cpp +++ b/scene/resources/default_theme/default_theme.cpp @@ -35,6 +35,7 @@ #include "default_theme_icons.gen.h" #include "scene/resources/font.h" #include "scene/resources/theme.h" +#include "scene/theme/theme_db.h" #include "servers/text_server.h" #include "modules/modules_enabled.gen.h" // For svg. @@ -1101,18 +1102,11 @@ void make_default_theme(float p_scale, Ref p_font, TextServer::SubpixelPos fill_default_theme(t, default_font, bold_font, bold_italics_font, italics_font, default_icon, default_style, default_scale); - Theme::set_default(t); - Theme::set_fallback_base_scale(default_scale); - Theme::set_fallback_icon(default_icon); - Theme::set_fallback_style(default_style); - Theme::set_fallback_font(default_font); - Theme::set_fallback_font_size(default_font_size * default_scale); -} + ThemeDB::get_singleton()->set_default_theme(t); -void clear_default_theme() { - Theme::set_project_default(nullptr); - Theme::set_default(nullptr); - Theme::set_fallback_icon(nullptr); - Theme::set_fallback_style(nullptr); - Theme::set_fallback_font(nullptr); + ThemeDB::get_singleton()->set_fallback_base_scale(default_scale); + ThemeDB::get_singleton()->set_fallback_icon(default_icon); + ThemeDB::get_singleton()->set_fallback_stylebox(default_style); + ThemeDB::get_singleton()->set_fallback_font(default_font); + ThemeDB::get_singleton()->set_fallback_font_size(default_font_size * default_scale); } diff --git a/scene/resources/default_theme/default_theme.h b/scene/resources/default_theme/default_theme.h index 15be5e676f8..003934ce900 100644 --- a/scene/resources/default_theme/default_theme.h +++ b/scene/resources/default_theme/default_theme.h @@ -37,6 +37,5 @@ const int default_font_size = 16; void fill_default_theme(Ref &theme, const Ref &default_font, const Ref &bold_font, const Ref &bold_italics_font, const Ref &italics_font, Ref &default_icon, Ref &default_style, float p_scale); void make_default_theme(float p_scale, Ref p_font, TextServer::SubpixelPositioning p_font_subpixel = TextServer::SUBPIXEL_POSITIONING_AUTO, TextServer::Hinting p_font_hinting = TextServer::HINTING_LIGHT, TextServer::FontAntialiasing p_font_antialiased = TextServer::FONT_ANTIALIASING_GRAY, bool p_font_msdf = false, bool p_font_generate_mipmaps = false); -void clear_default_theme(); #endif // DEFAULT_THEME_H diff --git a/scene/resources/font.cpp b/scene/resources/font.cpp index be57d9c965f..8ec5678f0a3 100644 --- a/scene/resources/font.cpp +++ b/scene/resources/font.cpp @@ -39,6 +39,7 @@ #include "scene/resources/text_line.h" #include "scene/resources/text_paragraph.h" #include "scene/resources/theme.h" +#include "scene/theme/theme_db.h" /*************************************************************************/ /* Font */ @@ -2552,13 +2553,13 @@ Ref FontVariation::_get_base_font_or_default() const { } // Check the project-defined Theme resource. - if (Theme::get_project_default().is_valid()) { + if (ThemeDB::get_singleton()->get_project_theme().is_valid()) { List theme_types; - Theme::get_project_default()->get_type_dependencies(get_class_name(), StringName(), &theme_types); + ThemeDB::get_singleton()->get_project_theme()->get_type_dependencies(get_class_name(), StringName(), &theme_types); for (const StringName &E : theme_types) { - if (Theme::get_project_default()->has_theme_item(Theme::DATA_TYPE_FONT, "font", E)) { - Ref f = Theme::get_project_default()->get_theme_item(Theme::DATA_TYPE_FONT, "font", E); + if (ThemeDB::get_singleton()->get_project_theme()->has_theme_item(Theme::DATA_TYPE_FONT, "font", E)) { + Ref f = ThemeDB::get_singleton()->get_project_theme()->get_theme_item(Theme::DATA_TYPE_FONT, "font", E); if (f.is_valid()) { theme_font = f; theme_font->connect(CoreStringNames::get_singleton()->changed, callable_mp(reinterpret_cast(const_cast(this)), &Font::_invalidate_rids), CONNECT_REFERENCE_COUNTED); @@ -2569,13 +2570,13 @@ Ref FontVariation::_get_base_font_or_default() const { } // Lastly, fall back on the items defined in the default Theme, if they exist. - if (Theme::get_default().is_valid()) { + if (ThemeDB::get_singleton()->get_default_theme().is_valid()) { List theme_types; - Theme::get_default()->get_type_dependencies(get_class_name(), StringName(), &theme_types); + ThemeDB::get_singleton()->get_default_theme()->get_type_dependencies(get_class_name(), StringName(), &theme_types); for (const StringName &E : theme_types) { - if (Theme::get_default()->has_theme_item(Theme::DATA_TYPE_FONT, "font", E)) { - Ref f = Theme::get_default()->get_theme_item(Theme::DATA_TYPE_FONT, "font", E); + if (ThemeDB::get_singleton()->get_default_theme()->has_theme_item(Theme::DATA_TYPE_FONT, "font", E)) { + Ref f = ThemeDB::get_singleton()->get_default_theme()->get_theme_item(Theme::DATA_TYPE_FONT, "font", E); if (f.is_valid()) { theme_font = f; theme_font->connect(CoreStringNames::get_singleton()->changed, callable_mp(reinterpret_cast(const_cast(this)), &Font::_invalidate_rids), CONNECT_REFERENCE_COUNTED); @@ -2585,7 +2586,7 @@ Ref FontVariation::_get_base_font_or_default() const { } // If they don't exist, use any type to return the default/empty value. - Ref f = Theme::get_default()->get_theme_item(Theme::DATA_TYPE_FONT, "font", StringName()); + Ref f = ThemeDB::get_singleton()->get_default_theme()->get_theme_item(Theme::DATA_TYPE_FONT, "font", StringName()); if (f.is_valid()) { theme_font = f; theme_font->connect(CoreStringNames::get_singleton()->changed, callable_mp(reinterpret_cast(const_cast(this)), &Font::_invalidate_rids), CONNECT_REFERENCE_COUNTED); @@ -2859,13 +2860,13 @@ Ref SystemFont::_get_base_font_or_default() const { } // Check the project-defined Theme resource. - if (Theme::get_project_default().is_valid()) { + if (ThemeDB::get_singleton()->get_project_theme().is_valid()) { List theme_types; - Theme::get_project_default()->get_type_dependencies(get_class_name(), StringName(), &theme_types); + ThemeDB::get_singleton()->get_project_theme()->get_type_dependencies(get_class_name(), StringName(), &theme_types); for (const StringName &E : theme_types) { - if (Theme::get_project_default()->has_theme_item(Theme::DATA_TYPE_FONT, "font", E)) { - Ref f = Theme::get_project_default()->get_theme_item(Theme::DATA_TYPE_FONT, "font", E); + if (ThemeDB::get_singleton()->get_project_theme()->has_theme_item(Theme::DATA_TYPE_FONT, "font", E)) { + Ref f = ThemeDB::get_singleton()->get_project_theme()->get_theme_item(Theme::DATA_TYPE_FONT, "font", E); if (f.is_valid()) { theme_font = f; theme_font->connect(CoreStringNames::get_singleton()->changed, callable_mp(reinterpret_cast(const_cast(this)), &Font::_invalidate_rids), CONNECT_REFERENCE_COUNTED); @@ -2876,13 +2877,13 @@ Ref SystemFont::_get_base_font_or_default() const { } // Lastly, fall back on the items defined in the default Theme, if they exist. - if (Theme::get_default().is_valid()) { + if (ThemeDB::get_singleton()->get_default_theme().is_valid()) { List theme_types; - Theme::get_default()->get_type_dependencies(get_class_name(), StringName(), &theme_types); + ThemeDB::get_singleton()->get_default_theme()->get_type_dependencies(get_class_name(), StringName(), &theme_types); for (const StringName &E : theme_types) { - if (Theme::get_default()->has_theme_item(Theme::DATA_TYPE_FONT, "font", E)) { - Ref f = Theme::get_default()->get_theme_item(Theme::DATA_TYPE_FONT, "font", E); + if (ThemeDB::get_singleton()->get_default_theme()->has_theme_item(Theme::DATA_TYPE_FONT, "font", E)) { + Ref f = ThemeDB::get_singleton()->get_default_theme()->get_theme_item(Theme::DATA_TYPE_FONT, "font", E); if (f.is_valid()) { theme_font = f; theme_font->connect(CoreStringNames::get_singleton()->changed, callable_mp(reinterpret_cast(const_cast(this)), &Font::_invalidate_rids), CONNECT_REFERENCE_COUNTED); @@ -2892,7 +2893,7 @@ Ref SystemFont::_get_base_font_or_default() const { } // If they don't exist, use any type to return the default/empty value. - Ref f = Theme::get_default()->get_theme_item(Theme::DATA_TYPE_FONT, "font", StringName()); + Ref f = ThemeDB::get_singleton()->get_default_theme()->get_theme_item(Theme::DATA_TYPE_FONT, "font", StringName()); if (f.is_valid()) { theme_font = f; theme_font->connect(CoreStringNames::get_singleton()->changed, callable_mp(reinterpret_cast(const_cast(this)), &Font::_invalidate_rids), CONNECT_REFERENCE_COUNTED); diff --git a/scene/resources/primitive_meshes.cpp b/scene/resources/primitive_meshes.cpp index e9939363506..fc5cf2a028c 100644 --- a/scene/resources/primitive_meshes.cpp +++ b/scene/resources/primitive_meshes.cpp @@ -32,6 +32,7 @@ #include "core/core_string_names.h" #include "scene/resources/theme.h" +#include "scene/theme/theme_db.h" #include "servers/rendering_server.h" #include "thirdparty/misc/clipper.hpp" #include "thirdparty/misc/polypartition.h" @@ -2984,13 +2985,13 @@ Ref TextMesh::_get_font_or_default() const { } // Check the project-defined Theme resource. - if (Theme::get_project_default().is_valid()) { + if (ThemeDB::get_singleton()->get_project_theme().is_valid()) { List theme_types; - Theme::get_project_default()->get_type_dependencies(get_class_name(), StringName(), &theme_types); + ThemeDB::get_singleton()->get_project_theme()->get_type_dependencies(get_class_name(), StringName(), &theme_types); for (const StringName &E : theme_types) { - if (Theme::get_project_default()->has_theme_item(Theme::DATA_TYPE_FONT, "font", E)) { - return Theme::get_project_default()->get_theme_item(Theme::DATA_TYPE_FONT, "font", E); + if (ThemeDB::get_singleton()->get_project_theme()->has_theme_item(Theme::DATA_TYPE_FONT, "font", E)) { + return ThemeDB::get_singleton()->get_project_theme()->get_theme_item(Theme::DATA_TYPE_FONT, "font", E); } } } @@ -2998,17 +2999,17 @@ Ref TextMesh::_get_font_or_default() const { // Lastly, fall back on the items defined in the default Theme, if they exist. { List theme_types; - Theme::get_default()->get_type_dependencies(get_class_name(), StringName(), &theme_types); + ThemeDB::get_singleton()->get_default_theme()->get_type_dependencies(get_class_name(), StringName(), &theme_types); for (const StringName &E : theme_types) { - if (Theme::get_default()->has_theme_item(Theme::DATA_TYPE_FONT, "font", E)) { - return Theme::get_default()->get_theme_item(Theme::DATA_TYPE_FONT, "font", E); + if (ThemeDB::get_singleton()->get_default_theme()->has_theme_item(Theme::DATA_TYPE_FONT, "font", E)) { + return ThemeDB::get_singleton()->get_default_theme()->get_theme_item(Theme::DATA_TYPE_FONT, "font", E); } } } // If they don't exist, use any type to return the default/empty value. - return Theme::get_default()->get_theme_item(Theme::DATA_TYPE_FONT, "font", StringName()); + return ThemeDB::get_singleton()->get_default_theme()->get_theme_item(Theme::DATA_TYPE_FONT, "font", StringName()); } void TextMesh::set_font_size(int p_size) { diff --git a/scene/resources/theme.cpp b/scene/resources/theme.cpp index 3f6eec8497a..33213928216 100644 --- a/scene/resources/theme.cpp +++ b/scene/resources/theme.cpp @@ -31,17 +31,7 @@ #include "theme.h" #include "core/string/print_string.h" - -// Universal Theme resources used when no other theme has the item. -Ref Theme::default_theme; -Ref Theme::project_default_theme; - -// Universal default values, final fallback for every theme. -float Theme::fallback_base_scale = 1.0; -Ref Theme::fallback_icon; -Ref Theme::fallback_style; -Ref Theme::fallback_font; -int Theme::fallback_font_size = 16; +#include "scene/theme/theme_db.h" // Dynamic properties. bool Theme::_set(const StringName &p_name, const Variant &p_value) { @@ -185,64 +175,7 @@ void Theme::_get_property_list(List *p_list) const { } } -// Universal fallback Theme resources. -Ref Theme::get_default() { - return default_theme; -} - -void Theme::set_default(const Ref &p_default) { - default_theme = p_default; -} - -Ref Theme::get_project_default() { - return project_default_theme; -} - -void Theme::set_project_default(const Ref &p_project_default) { - project_default_theme = p_project_default; -} - -// Universal fallback values for theme item types. -void Theme::set_fallback_base_scale(float p_base_scale) { - fallback_base_scale = p_base_scale; -} - -void Theme::set_fallback_icon(const Ref &p_icon) { - fallback_icon = p_icon; -} - -void Theme::set_fallback_style(const Ref &p_style) { - fallback_style = p_style; -} - -void Theme::set_fallback_font(const Ref &p_font) { - fallback_font = p_font; -} - -void Theme::set_fallback_font_size(int p_font_size) { - fallback_font_size = p_font_size; -} - -float Theme::get_fallback_base_scale() { - return fallback_base_scale; -} - -Ref Theme::get_fallback_icon() { - return fallback_icon; -} - -Ref Theme::get_fallback_style() { - return fallback_style; -} - -Ref Theme::get_fallback_font() { - return fallback_font; -} - -int Theme::get_fallback_font_size() { - return fallback_font_size; -} - +// Static helpers. bool Theme::is_valid_type_name(const String &p_name) { for (int i = 0; i < p_name.length(); i++) { if (!is_ascii_identifier_char(p_name[i])) { @@ -351,7 +284,7 @@ Ref Theme::get_icon(const StringName &p_name, const StringName &p_the if (icon_map.has(p_theme_type) && icon_map[p_theme_type].has(p_name) && icon_map[p_theme_type][p_name].is_valid()) { return icon_map[p_theme_type][p_name]; } else { - return fallback_icon; + return ThemeDB::get_singleton()->get_fallback_icon(); } } @@ -461,7 +394,7 @@ Ref Theme::get_stylebox(const StringName &p_name, const StringName &p_ if (style_map.has(p_theme_type) && style_map[p_theme_type].has(p_name) && style_map[p_theme_type][p_name].is_valid()) { return style_map[p_theme_type][p_name]; } else { - return fallback_style; + return ThemeDB::get_singleton()->get_fallback_stylebox(); } } @@ -573,7 +506,7 @@ Ref Theme::get_font(const StringName &p_name, const StringName &p_theme_ty } else if (has_default_font()) { return default_font; } else { - return fallback_font; + return ThemeDB::get_singleton()->get_fallback_font(); } } @@ -676,7 +609,7 @@ int Theme::get_font_size(const StringName &p_name, const StringName &p_theme_typ } else if (has_default_font_size()) { return default_font_size; } else { - return fallback_font_size; + return ThemeDB::get_singleton()->get_fallback_font_size(); } } diff --git a/scene/resources/theme.h b/scene/resources/theme.h index a2aca5e61f9..ed1dc7c938a 100644 --- a/scene/resources/theme.h +++ b/scene/resources/theme.h @@ -102,17 +102,6 @@ protected: bool _get(const StringName &p_name, Variant &r_ret) const; void _get_property_list(List *p_list) const; - // Universal Theme resources used when no other theme has the item. - static Ref default_theme; - static Ref project_default_theme; - - // Universal default values, final fallback for every theme. - static float fallback_base_scale; - static Ref fallback_icon; - static Ref fallback_style; - static Ref fallback_font; - static int fallback_font_size; - // Default values configurable for each individual theme. float default_base_scale = 0.0; Ref default_font; @@ -126,24 +115,6 @@ protected: virtual void reset_state() override; public: - static Ref get_default(); - static void set_default(const Ref &p_default); - - static Ref get_project_default(); - static void set_project_default(const Ref &p_project_default); - - static void set_fallback_base_scale(float p_base_scale); - static void set_fallback_icon(const Ref &p_icon); - static void set_fallback_style(const Ref &p_style); - static void set_fallback_font(const Ref &p_font); - static void set_fallback_font_size(int p_font_size); - - static float get_fallback_base_scale(); - static Ref get_fallback_icon(); - static Ref get_fallback_style(); - static Ref get_fallback_font(); - static int get_fallback_font_size(); - static bool is_valid_type_name(const String &p_name); static bool is_valid_item_name(const String &p_name); diff --git a/scene/theme/SCsub b/scene/theme/SCsub new file mode 100644 index 00000000000..fc61250247d --- /dev/null +++ b/scene/theme/SCsub @@ -0,0 +1,5 @@ +#!/usr/bin/env python + +Import("env") + +env.add_source_files(env.scene_sources, "*.cpp") diff --git a/scene/theme/theme_db.cpp b/scene/theme/theme_db.cpp new file mode 100644 index 00000000000..d6e892cd935 --- /dev/null +++ b/scene/theme/theme_db.cpp @@ -0,0 +1,237 @@ +/*************************************************************************/ +/* theme_db.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "theme_db.h" + +#include "core/config/project_settings.h" +#include "core/io/resource_loader.h" +#include "scene/resources/default_theme/default_theme.h" +#include "scene/resources/font.h" +#include "scene/resources/style_box.h" +#include "scene/resources/texture.h" +#include "scene/resources/theme.h" +#include "servers/text_server.h" + +// Default engine theme creation and configuration. +void ThemeDB::initialize_theme() { + // Allow creating the default theme at a different scale to suit higher/lower base resolutions. + float default_theme_scale = GLOBAL_DEF("gui/theme/default_theme_scale", 1.0); + ProjectSettings::get_singleton()->set_custom_property_info("gui/theme/default_theme_scale", PropertyInfo(Variant::FLOAT, "gui/theme/default_theme_scale", PROPERTY_HINT_RANGE, "0.5,8,0.01", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)); + + String theme_path = GLOBAL_DEF_RST("gui/theme/custom", ""); + ProjectSettings::get_singleton()->set_custom_property_info("gui/theme/custom", PropertyInfo(Variant::STRING, "gui/theme/custom", PROPERTY_HINT_FILE, "*.tres,*.res,*.theme", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)); + + String font_path = GLOBAL_DEF_RST("gui/theme/custom_font", ""); + ProjectSettings::get_singleton()->set_custom_property_info("gui/theme/custom_font", PropertyInfo(Variant::STRING, "gui/theme/custom_font", PROPERTY_HINT_FILE, "*.tres,*.res", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)); + + TextServer::FontAntialiasing font_antialiasing = (TextServer::FontAntialiasing)(int)GLOBAL_DEF_RST("gui/theme/default_font_antialiasing", 1); + ProjectSettings::get_singleton()->set_custom_property_info("gui/theme/default_font_antialiasing", PropertyInfo(Variant::INT, "gui/theme/default_font_antialiasing", PROPERTY_HINT_ENUM, "None,Grayscale,LCD sub-pixel", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)); + + TextServer::Hinting font_hinting = (TextServer::Hinting)(int)GLOBAL_DEF_RST("gui/theme/default_font_hinting", TextServer::HINTING_LIGHT); + ProjectSettings::get_singleton()->set_custom_property_info("gui/theme/default_font_hinting", PropertyInfo(Variant::INT, "gui/theme/default_font_hinting", PROPERTY_HINT_ENUM, "None,Light,Normal", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)); + + TextServer::SubpixelPositioning font_subpixel_positioning = (TextServer::SubpixelPositioning)(int)GLOBAL_DEF_RST("gui/theme/default_font_subpixel_positioning", TextServer::SUBPIXEL_POSITIONING_AUTO); + ProjectSettings::get_singleton()->set_custom_property_info("gui/theme/default_font_subpixel_positioning", PropertyInfo(Variant::INT, "gui/theme/default_font_subpixel_positioning", PROPERTY_HINT_ENUM, "Disabled,Auto,One half of a pixel,One quarter of a pixel", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)); + + const bool font_msdf = GLOBAL_DEF_RST("gui/theme/default_font_multichannel_signed_distance_field", false); + const bool font_generate_mipmaps = GLOBAL_DEF_RST("gui/theme/default_font_generate_mipmaps", false); + + GLOBAL_DEF_RST("gui/theme/lcd_subpixel_layout", 1); + ProjectSettings::get_singleton()->set_custom_property_info("gui/theme/lcd_subpixel_layout", PropertyInfo(Variant::INT, "gui/theme/lcd_subpixel_layout", PROPERTY_HINT_ENUM, "Disabled,Horizontal RGB,Horizontal BGR,Vertical RGB,Vertical BGR")); + ProjectSettings::get_singleton()->set_restart_if_changed("gui/theme/lcd_subpixel_layout", false); + + Ref font; + if (!font_path.is_empty()) { + font = ResourceLoader::load(font_path); + if (!font.is_valid()) { + ERR_PRINT("Error loading custom font '" + font_path + "'"); + } + } + + // Always make the default theme to avoid invalid default font/icon/style in the given theme. + if (RenderingServer::get_singleton()) { + make_default_theme(default_theme_scale, font, font_subpixel_positioning, font_hinting, font_antialiasing, font_msdf, font_generate_mipmaps); + } + + if (!theme_path.is_empty()) { + Ref theme = ResourceLoader::load(theme_path); + if (theme.is_valid()) { + set_project_theme(theme); + if (font.is_valid()) { + set_fallback_font(font); + } + } else { + ERR_PRINT("Error loading custom theme '" + theme_path + "'"); + } + } +} + +void ThemeDB::initialize_theme_noproject() { + if (RenderingServer::get_singleton()) { + make_default_theme(1.0, Ref()); + } +} + +// Universal fallback Theme resources. + +void ThemeDB::set_default_theme(const Ref &p_default) { + default_theme = p_default; +} + +Ref ThemeDB::get_default_theme() { + return default_theme; +} + +void ThemeDB::set_project_theme(const Ref &p_project_default) { + project_theme = p_project_default; +} + +Ref ThemeDB::get_project_theme() { + return project_theme; +} + +// Universal fallback values for theme item types. + +void ThemeDB::set_fallback_base_scale(float p_base_scale) { + if (fallback_base_scale == p_base_scale) { + return; + } + + fallback_base_scale = p_base_scale; + emit_signal(SNAME("fallback_changed")); +} + +float ThemeDB::get_fallback_base_scale() { + return fallback_base_scale; +} + +void ThemeDB::set_fallback_font(const Ref &p_font) { + if (fallback_font == p_font) { + return; + } + + fallback_font = p_font; + emit_signal(SNAME("fallback_changed")); +} + +Ref ThemeDB::get_fallback_font() { + return fallback_font; +} + +void ThemeDB::set_fallback_font_size(int p_font_size) { + if (fallback_font_size == p_font_size) { + return; + } + + fallback_font_size = p_font_size; + emit_signal(SNAME("fallback_changed")); +} + +int ThemeDB::get_fallback_font_size() { + return fallback_font_size; +} + +void ThemeDB::set_fallback_icon(const Ref &p_icon) { + if (fallback_icon == p_icon) { + return; + } + + fallback_icon = p_icon; + emit_signal(SNAME("fallback_changed")); +} + +Ref ThemeDB::get_fallback_icon() { + return fallback_icon; +} + +void ThemeDB::set_fallback_stylebox(const Ref &p_stylebox) { + if (fallback_stylebox == p_stylebox) { + return; + } + + fallback_stylebox = p_stylebox; + emit_signal(SNAME("fallback_changed")); +} + +Ref ThemeDB::get_fallback_stylebox() { + return fallback_stylebox; +} + +// Object methods. +void ThemeDB::_bind_methods() { + ClassDB::bind_method(D_METHOD("get_default_theme"), &ThemeDB::get_default_theme); + ClassDB::bind_method(D_METHOD("get_project_theme"), &ThemeDB::get_project_theme); + + ClassDB::bind_method(D_METHOD("set_fallback_base_scale", "base_scale"), &ThemeDB::set_fallback_base_scale); + ClassDB::bind_method(D_METHOD("get_fallback_base_scale"), &ThemeDB::get_fallback_base_scale); + ClassDB::bind_method(D_METHOD("set_fallback_font", "font"), &ThemeDB::set_fallback_font); + ClassDB::bind_method(D_METHOD("get_fallback_font"), &ThemeDB::get_fallback_font); + ClassDB::bind_method(D_METHOD("set_fallback_font_size", "font_size"), &ThemeDB::set_fallback_font_size); + ClassDB::bind_method(D_METHOD("get_fallback_font_size"), &ThemeDB::get_fallback_font_size); + ClassDB::bind_method(D_METHOD("set_fallback_icon", "icon"), &ThemeDB::set_fallback_icon); + ClassDB::bind_method(D_METHOD("get_fallback_icon"), &ThemeDB::get_fallback_icon); + ClassDB::bind_method(D_METHOD("set_fallback_stylebox", "stylebox"), &ThemeDB::set_fallback_stylebox); + ClassDB::bind_method(D_METHOD("get_fallback_stylebox"), &ThemeDB::get_fallback_stylebox); + + ADD_GROUP("Fallback values", "fallback_"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fallback_base_scale", PROPERTY_HINT_RANGE, "0.0,2.0,0.01,or_greater"), "set_fallback_base_scale", "get_fallback_base_scale"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "fallback_font", PROPERTY_HINT_RESOURCE_TYPE, "Font", PROPERTY_USAGE_NONE), "set_fallback_font", "get_fallback_font"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "fallback_font_size", PROPERTY_HINT_RANGE, "0,256,1,or_greater,suffix:px"), "set_fallback_font_size", "get_fallback_font_size"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "fallback_icon", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D", PROPERTY_USAGE_NONE), "set_fallback_icon", "get_fallback_icon"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "fallback_stylebox", PROPERTY_HINT_RESOURCE_TYPE, "StyleBox", PROPERTY_USAGE_NONE), "set_fallback_stylebox", "get_fallback_stylebox"); + + ADD_SIGNAL(MethodInfo("fallback_changed")); +} + +// Memory management, reference, and initialization +ThemeDB *ThemeDB::singleton = nullptr; + +ThemeDB *ThemeDB::get_singleton() { + return singleton; +} + +ThemeDB::ThemeDB() { + singleton = this; + + // Universal default values, final fallback for every theme. + fallback_base_scale = 1.0; + fallback_font_size = 16; +} + +ThemeDB::~ThemeDB() { + default_theme.unref(); + project_theme.unref(); + + fallback_font.unref(); + fallback_icon.unref(); + fallback_stylebox.unref(); + + singleton = nullptr; +} diff --git a/scene/theme/theme_db.h b/scene/theme/theme_db.h new file mode 100644 index 00000000000..aace33d82c2 --- /dev/null +++ b/scene/theme/theme_db.h @@ -0,0 +1,95 @@ +/*************************************************************************/ +/* theme_db.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef THEME_DB_H +#define THEME_DB_H + +#include "core/object/class_db.h" +#include "core/object/ref_counted.h" + +class Font; +class StyleBox; +class Texture2D; +class Theme; + +class ThemeDB : public Object { + GDCLASS(ThemeDB, Object); + + static ThemeDB *singleton; + + // Universal Theme resources used when no other theme has the item. + Ref default_theme; + Ref project_theme; + + // Universal default values, final fallback for every theme. + float fallback_base_scale; + Ref fallback_font; + int fallback_font_size; + Ref fallback_icon; + Ref fallback_stylebox; + +protected: + static void _bind_methods(); + +public: + void initialize_theme(); + void initialize_theme_noproject(); + + // Universal Theme resources + + void set_default_theme(const Ref &p_default); + Ref get_default_theme(); + + void set_project_theme(const Ref &p_project_default); + Ref get_project_theme(); + + // Universal default values. + + void set_fallback_base_scale(float p_base_scale); + float get_fallback_base_scale(); + + void set_fallback_font(const Ref &p_font); + Ref get_fallback_font(); + + void set_fallback_font_size(int p_font_size); + int get_fallback_font_size(); + + void set_fallback_icon(const Ref &p_icon); + Ref get_fallback_icon(); + + void set_fallback_stylebox(const Ref &p_stylebox); + Ref get_fallback_stylebox(); + + static ThemeDB *get_singleton(); + ThemeDB(); + ~ThemeDB(); +}; + +#endif // THEME_DB_H diff --git a/tests/test_main.cpp b/tests/test_main.cpp index 3d186711cba..a30d11342aa 100644 --- a/tests/test_main.cpp +++ b/tests/test_main.cpp @@ -99,7 +99,7 @@ #include "tests/test_macros.h" -#include "scene/resources/default_theme/default_theme.h" +#include "scene/theme/theme_db.h" #include "servers/navigation_server_2d.h" #include "servers/navigation_server_3d.h" #include "servers/physics_server_2d.h" @@ -179,6 +179,7 @@ struct GodotTestCaseListener : public doctest::IReporter { PhysicsServer2D *physics_server_2d = nullptr; NavigationServer3D *navigation_server_3d = nullptr; NavigationServer2D *navigation_server_2d = nullptr; + ThemeDB *theme_db = nullptr; void test_case_start(const doctest::TestCaseData &p_in) override { SignalWatcher::get_singleton()->_clear_signals(); @@ -217,7 +218,8 @@ struct GodotTestCaseListener : public doctest::IReporter { memnew(InputMap); InputMap::get_singleton()->load_default(); - make_default_theme(1.0, Ref()); + theme_db = memnew(ThemeDB); + theme_db->initialize_theme_noproject(); memnew(SceneTree); SceneTree::get_singleton()->initialize(); @@ -247,7 +249,10 @@ struct GodotTestCaseListener : public doctest::IReporter { memdelete(SceneTree::get_singleton()); } - clear_default_theme(); + if (theme_db) { + memdelete(theme_db); + theme_db = nullptr; + } if (navigation_server_3d) { memdelete(navigation_server_3d);