diff --git a/doc/classes/Control.xml b/doc/classes/Control.xml index b00bf1c250..6fa59a15ac 100644 --- a/doc/classes/Control.xml +++ b/doc/classes/Control.xml @@ -458,6 +458,27 @@ See [method get_theme_color] for details. + + + + Returns the default base scale value from the first matching [Theme] in the tree if that [Theme] has a valid [member Theme.default_base_scale] value. + See [method get_theme_color] for details. + + + + + + Returns the default font from the first matching [Theme] in the tree if that [Theme] has a valid [member Theme.default_font] value. + See [method get_theme_color] for details. + + + + + + Returns the default font size value from the first matching [Theme] in the tree if that [Theme] has a valid [member Theme.default_font_size] value. + See [method get_theme_color] for details. + + diff --git a/doc/classes/Theme.xml b/doc/classes/Theme.xml index edf5874432..2f5648dda9 100644 --- a/doc/classes/Theme.xml +++ b/doc/classes/Theme.xml @@ -273,6 +273,24 @@ Returns [code]false[/code] if the theme does not have [code]theme_type[/code]. + + + + Returns [code]true[/code] if this theme has a valid [member default_base_scale] value. + + + + + + Returns [code]true[/code] if this theme has a valid [member default_font] value. + + + + + + Returns [code]true[/code] if this theme has a valid [member default_font_size] value. + + @@ -484,11 +502,17 @@ + + The default base scale factor of this [Theme] resource. Used by some controls to scale their visual properties based on a global scale factor. If this value is set to [code]0.0[/code], the global scale factor is used. + Use [method has_default_base_scale] to check if this value is valid. + - The theme's default font. + The default font of this [Theme] resource. Used as a fallback value for font items defined in this theme, but having invalid values. If this value is also invalid, the global default value is used. + Use [method has_default_font] to check if this value is valid. - The theme's default font size. Set to [code]-1[/code] to ignore and use global default. + The default font size of this [Theme] resource. Used as a fallback value for font size items defined in this theme, but having invalid values. If this value is set to [code]-1[/code], the global default value is used. + Use [method has_default_font_size] to check if this value is valid. diff --git a/doc/classes/Window.xml b/doc/classes/Window.xml index 15d844aacb..0653c8b453 100644 --- a/doc/classes/Window.xml +++ b/doc/classes/Window.xml @@ -59,6 +59,21 @@ + + + + + + + + + + + + + + + diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp index 0579fb4cbd..6efbcbc61e 100644 --- a/editor/editor_themes.cpp +++ b/editor/editor_themes.cpp @@ -292,7 +292,8 @@ void editor_register_and_generate_icons(Ref p_theme, bool p_dark_theme = Ref create_editor_theme(const Ref p_theme) { Ref theme = Ref(memnew(Theme)); - const float default_contrast = 0.3; + // Controls may rely on the scale for their internal drawing logic. + theme->set_default_theme_base_scale(EDSCALE); // Theme settings Color accent_color = EDITOR_GET("interface/theme/accent_color"); @@ -310,6 +311,8 @@ Ref create_editor_theme(const Ref p_theme) { Color preset_base_color; float preset_contrast = 0; + const float default_contrast = 0.3; + // Please use alphabetical order if you're adding a new theme here // (after "Custom") diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp index 1b8b5e17ed..e2d3807b40 100644 --- a/scene/gui/control.cpp +++ b/scene/gui/control.cpp @@ -833,11 +833,12 @@ T Control::get_theme_item_in_types(Control *p_theme_owner, Window *p_theme_owner ERR_FAIL_COND_V_MSG(p_theme_types.size() == 0, T(), "At least one theme type must be specified."); // First, look through each control or window node in the branch, until no valid parent can be found. - // For each control iterate through its inheritance chain and see if p_name exists in any of them. + // Only nodes with a theme resource attached are considered. Control *theme_owner = p_theme_owner; Window *theme_owner_window = p_theme_owner_window; while (theme_owner || theme_owner_window) { + // For each theme resource check the theme types provided and see if p_name exists with any of them. for (const StringName &E : p_theme_types) { if (theme_owner && theme_owner->data.theme->has_theme_item(p_data_type, p_name, E)) { return theme_owner->data.theme->get_theme_item(p_data_type, p_name, E); @@ -888,11 +889,12 @@ bool Control::has_theme_item_in_types(Control *p_theme_owner, Window *p_theme_ow ERR_FAIL_COND_V_MSG(p_theme_types.size() == 0, false, "At least one theme type must be specified."); // First, look through each control or window node in the branch, until no valid parent can be found. - // For each control iterate through its inheritance chain and see if p_name exists in any of them. + // Only nodes with a theme resource attached are considered. Control *theme_owner = p_theme_owner; Window *theme_owner_window = p_theme_owner_window; while (theme_owner || theme_owner_window) { + // For each theme resource check the theme types provided and see if p_name exists with any of them. for (const StringName &E : p_theme_types) { if (theme_owner && theme_owner->data.theme->has_theme_item(p_data_type, p_name, E)) { return true; @@ -1130,6 +1132,150 @@ bool Control::has_theme_constant(const StringName &p_name, const StringName &p_t return has_theme_item_in_types(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_CONSTANT, p_name, theme_types); } +float Control::fetch_theme_default_base_scale(Control *p_theme_owner, Window *p_theme_owner_window) { + // First, look through each control or window node in the branch, until no valid parent can be found. + // Only nodes with a theme resource attached are considered. + // For each theme resource see if their assigned theme has the default value defined and valid. + Control *theme_owner = p_theme_owner; + Window *theme_owner_window = p_theme_owner_window; + + while (theme_owner || theme_owner_window) { + if (theme_owner && theme_owner->data.theme->has_default_theme_base_scale()) { + return theme_owner->data.theme->get_default_theme_base_scale(); + } + + if (theme_owner_window && theme_owner_window->theme->has_default_theme_base_scale()) { + return theme_owner_window->theme->get_default_theme_base_scale(); + } + + Node *parent = theme_owner ? theme_owner->get_parent() : theme_owner_window->get_parent(); + Control *parent_c = Object::cast_to(parent); + if (parent_c) { + theme_owner = parent_c->data.theme_owner; + theme_owner_window = parent_c->data.theme_owner_window; + } else { + Window *parent_w = Object::cast_to(parent); + if (parent_w) { + theme_owner = parent_w->theme_owner; + theme_owner_window = parent_w->theme_owner_window; + } else { + theme_owner = nullptr; + theme_owner_window = nullptr; + } + } + } + + // Secondly, check the project-defined Theme resource. + if (Theme::get_project_default().is_valid()) { + if (Theme::get_project_default()->has_default_theme_base_scale()) { + return Theme::get_project_default()->get_default_theme_base_scale(); + } + } + + // Lastly, fall back on the default Theme. + return Theme::get_default()->get_default_theme_base_scale(); +} + +float Control::get_theme_default_base_scale() const { + return fetch_theme_default_base_scale(data.theme_owner, data.theme_owner_window); +} + +Ref Control::fetch_theme_default_font(Control *p_theme_owner, Window *p_theme_owner_window) { + // First, look through each control or window node in the branch, until no valid parent can be found. + // Only nodes with a theme resource attached are considered. + // For each theme resource see if their assigned theme has the default value defined and valid. + Control *theme_owner = p_theme_owner; + Window *theme_owner_window = p_theme_owner_window; + + while (theme_owner || theme_owner_window) { + if (theme_owner && theme_owner->data.theme->has_default_theme_font()) { + return theme_owner->data.theme->get_default_theme_font(); + } + + if (theme_owner_window && theme_owner_window->theme->has_default_theme_font()) { + return theme_owner_window->theme->get_default_theme_font(); + } + + Node *parent = theme_owner ? theme_owner->get_parent() : theme_owner_window->get_parent(); + Control *parent_c = Object::cast_to(parent); + if (parent_c) { + theme_owner = parent_c->data.theme_owner; + theme_owner_window = parent_c->data.theme_owner_window; + } else { + Window *parent_w = Object::cast_to(parent); + if (parent_w) { + theme_owner = parent_w->theme_owner; + theme_owner_window = parent_w->theme_owner_window; + } else { + theme_owner = nullptr; + theme_owner_window = nullptr; + } + } + } + + // Secondly, check the project-defined Theme resource. + if (Theme::get_project_default().is_valid()) { + if (Theme::get_project_default()->has_default_theme_font()) { + return Theme::get_project_default()->get_default_theme_font(); + } + } + + // Lastly, fall back on the default Theme. + return Theme::get_default()->get_default_theme_font(); +} + +Ref Control::get_theme_default_font() const { + return fetch_theme_default_font(data.theme_owner, data.theme_owner_window); +} + +int Control::fetch_theme_default_font_size(Control *p_theme_owner, Window *p_theme_owner_window) { + // First, look through each control or window node in the branch, until no valid parent can be found. + // Only nodes with a theme resource attached are considered. + // For each theme resource see if their assigned theme has the default value defined and valid. + Control *theme_owner = p_theme_owner; + Window *theme_owner_window = p_theme_owner_window; + + while (theme_owner || theme_owner_window) { + if (theme_owner && theme_owner->data.theme->has_default_theme_font_size()) { + return theme_owner->data.theme->get_default_theme_font_size(); + } + + if (theme_owner_window && theme_owner_window->theme->has_default_theme_font_size()) { + return theme_owner_window->theme->get_default_theme_font_size(); + } + + Node *parent = theme_owner ? theme_owner->get_parent() : theme_owner_window->get_parent(); + Control *parent_c = Object::cast_to(parent); + if (parent_c) { + theme_owner = parent_c->data.theme_owner; + theme_owner_window = parent_c->data.theme_owner_window; + } else { + Window *parent_w = Object::cast_to(parent); + if (parent_w) { + theme_owner = parent_w->theme_owner; + theme_owner_window = parent_w->theme_owner_window; + } else { + theme_owner = nullptr; + theme_owner_window = nullptr; + } + } + } + + // Secondly, check the project-defined Theme resource. + if (Theme::get_project_default().is_valid()) { + if (Theme::get_project_default()->has_default_theme_font_size()) { + return Theme::get_project_default()->get_default_theme_font_size(); + } + } + + // Lastly, fall back on the default Theme. + return Theme::get_default()->get_default_theme_font_size(); +} + +int Control::get_theme_default_font_size() const { + return fetch_theme_default_font_size(data.theme_owner, data.theme_owner_window); +} + Rect2 Control::get_parent_anchorable_rect() const { if (!is_inside_tree()) { return Rect2(); @@ -2789,6 +2935,10 @@ void Control::_bind_methods() { ClassDB::bind_method(D_METHOD("has_theme_color", "name", "theme_type"), &Control::has_theme_color, DEFVAL("")); ClassDB::bind_method(D_METHOD("has_theme_constant", "name", "theme_type"), &Control::has_theme_constant, DEFVAL("")); + ClassDB::bind_method(D_METHOD("get_theme_default_base_scale"), &Control::get_theme_default_base_scale); + ClassDB::bind_method(D_METHOD("get_theme_default_font"), &Control::get_theme_default_font); + ClassDB::bind_method(D_METHOD("get_theme_default_font_size"), &Control::get_theme_default_font_size); + ClassDB::bind_method(D_METHOD("get_parent_control"), &Control::get_parent_control); ClassDB::bind_method(D_METHOD("set_h_grow_direction", "direction"), &Control::set_h_grow_direction); diff --git a/scene/gui/control.h b/scene/gui/control.h index 87ff3918cb..bdc06319ea 100644 --- a/scene/gui/control.h +++ b/scene/gui/control.h @@ -509,6 +509,14 @@ public: bool has_theme_color(const StringName &p_name, const StringName &p_theme_type = StringName()) const; bool has_theme_constant(const StringName &p_name, const StringName &p_theme_type = StringName()) const; + static float fetch_theme_default_base_scale(Control *p_theme_owner, Window *p_theme_owner_window); + static Ref fetch_theme_default_font(Control *p_theme_owner, Window *p_theme_owner_window); + static int fetch_theme_default_font_size(Control *p_theme_owner, Window *p_theme_owner_window); + + float get_theme_default_base_scale() const; + Ref get_theme_default_font() const; + int get_theme_default_font_size() const; + /* TOOLTIP */ void set_tooltip(const String &p_tooltip); diff --git a/scene/main/window.cpp b/scene/main/window.cpp index ca5a3915d0..a0f62c853f 100644 --- a/scene/main/window.cpp +++ b/scene/main/window.cpp @@ -1266,6 +1266,18 @@ bool Window::has_theme_constant(const StringName &p_name, const StringName &p_th return Control::has_theme_item_in_types(theme_owner, theme_owner_window, Theme::DATA_TYPE_CONSTANT, p_name, theme_types); } +float Window::get_theme_default_base_scale() const { + return Control::fetch_theme_default_base_scale(theme_owner, theme_owner_window); +} + +Ref Window::get_theme_default_font() const { + return Control::fetch_theme_default_font(theme_owner, theme_owner_window); +} + +int Window::get_theme_default_font_size() const { + return Control::fetch_theme_default_font_size(theme_owner, theme_owner_window); +} + Rect2i Window::get_parent_rect() const { ERR_FAIL_COND_V(!is_inside_tree(), Rect2i()); if (is_embedded()) { @@ -1480,6 +1492,10 @@ void Window::_bind_methods() { ClassDB::bind_method(D_METHOD("has_theme_color", "name", "theme_type"), &Window::has_theme_color, DEFVAL("")); ClassDB::bind_method(D_METHOD("has_theme_constant", "name", "theme_type"), &Window::has_theme_constant, DEFVAL("")); + ClassDB::bind_method(D_METHOD("get_theme_default_base_scale"), &Window::get_theme_default_base_scale); + ClassDB::bind_method(D_METHOD("get_theme_default_font"), &Window::get_theme_default_font); + ClassDB::bind_method(D_METHOD("get_theme_default_font_size"), &Window::get_theme_default_font_size); + ClassDB::bind_method(D_METHOD("set_layout_direction", "direction"), &Window::set_layout_direction); ClassDB::bind_method(D_METHOD("get_layout_direction"), &Window::get_layout_direction); ClassDB::bind_method(D_METHOD("is_layout_rtl"), &Window::is_layout_rtl); diff --git a/scene/main/window.h b/scene/main/window.h index 4f31d9cd1f..def6eab7b8 100644 --- a/scene/main/window.h +++ b/scene/main/window.h @@ -280,6 +280,10 @@ public: bool has_theme_color(const StringName &p_name, const StringName &p_theme_type = StringName()) const; bool has_theme_constant(const StringName &p_name, const StringName &p_theme_type = StringName()) const; + float get_theme_default_base_scale() const; + Ref get_theme_default_font() const; + int get_theme_default_font_size() const; + Rect2i get_parent_rect() const; virtual DisplayServer::WindowID get_window_id() const override; diff --git a/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp index 94cf826477..54bb7a82cf 100644 --- a/scene/resources/default_theme/default_theme.cpp +++ b/scene/resources/default_theme/default_theme.cpp @@ -1036,9 +1036,16 @@ void make_default_theme(bool p_hidpi, Ref p_font) { } Ref large_font = default_font; - fill_default_theme(t, default_font, large_font, default_icon, default_style, p_hidpi ? 2.0 : 1.0); + + float default_scale = 1.0; + if (p_hidpi) { + default_scale = 2.0; + } + + fill_default_theme(t, default_font, large_font, default_icon, default_style, default_scale); Theme::set_default(t); + Theme::set_default_base_scale(default_scale); Theme::set_default_icon(default_icon); Theme::set_default_style(default_style); Theme::set_default_font(default_font); diff --git a/scene/resources/theme.cpp b/scene/resources/theme.cpp index dab08d48c2..dd5f0b9c6c 100644 --- a/scene/resources/theme.cpp +++ b/scene/resources/theme.cpp @@ -36,6 +36,7 @@ Ref Theme::default_theme; Ref Theme::project_default_theme; // Universal default values, final fallback for every theme. +float Theme::default_base_scale = 1.0; Ref Theme::default_icon; Ref Theme::default_style; Ref Theme::default_font; @@ -219,6 +220,10 @@ void Theme::set_project_default(const Ref &p_project_default) { } // Universal fallback values for theme item types. +void Theme::set_default_base_scale(float p_base_scale) { + default_base_scale = p_base_scale; +} + void Theme::set_default_icon(const Ref &p_icon) { default_icon = p_icon; } @@ -236,6 +241,24 @@ void Theme::set_default_font_size(int p_font_size) { } // Fallback values for theme item types, configurable per theme. +void Theme::set_default_theme_base_scale(float p_base_scale) { + if (default_theme_base_scale == p_base_scale) { + return; + } + + default_theme_base_scale = p_base_scale; + + _emit_theme_changed(); +} + +float Theme::get_default_theme_base_scale() const { + return default_theme_base_scale; +} + +bool Theme::has_default_theme_base_scale() const { + return default_theme_base_scale > 0.0; +} + void Theme::set_default_theme_font(const Ref &p_default_font) { if (default_theme_font == p_default_font) { return; @@ -258,6 +281,10 @@ Ref Theme::get_default_theme_font() const { return default_theme_font; } +bool Theme::has_default_theme_font() const { + return default_theme_font.is_valid(); +} + void Theme::set_default_theme_font_size(int p_font_size) { if (default_theme_font_size == p_font_size) { return; @@ -272,6 +299,10 @@ int Theme::get_default_theme_font_size() const { return default_theme_font_size; } +bool Theme::has_default_theme_font_size() const { + return default_theme_font_size > 0; +} + // Icons. void Theme::set_icon(const StringName &p_name, const StringName &p_theme_type, const Ref &p_icon) { if (icon_map[p_theme_type].has(p_name) && icon_map[p_theme_type][p_name].is_valid()) { @@ -460,7 +491,7 @@ void Theme::set_font(const StringName &p_name, const StringName &p_theme_type, c Ref Theme::get_font(const StringName &p_name, const StringName &p_theme_type) const { if (font_map.has(p_theme_type) && font_map[p_theme_type].has(p_name) && font_map[p_theme_type][p_name].is_valid()) { return font_map[p_theme_type][p_name]; - } else if (default_theme_font.is_valid()) { + } else if (has_default_theme_font()) { return default_theme_font; } else { return default_font; @@ -468,7 +499,7 @@ Ref Theme::get_font(const StringName &p_name, const StringName &p_theme_ty } bool Theme::has_font(const StringName &p_name, const StringName &p_theme_type) const { - return ((font_map.has(p_theme_type) && font_map[p_theme_type].has(p_name) && font_map[p_theme_type][p_name].is_valid()) || default_theme_font.is_valid()); + return ((font_map.has(p_theme_type) && font_map[p_theme_type].has(p_name) && font_map[p_theme_type][p_name].is_valid()) || has_default_theme_font()); } bool Theme::has_font_nocheck(const StringName &p_name, const StringName &p_theme_type) const { @@ -539,7 +570,7 @@ void Theme::set_font_size(const StringName &p_name, const StringName &p_theme_ty int Theme::get_font_size(const StringName &p_name, const StringName &p_theme_type) const { if (font_size_map.has(p_theme_type) && font_size_map[p_theme_type].has(p_name) && (font_size_map[p_theme_type][p_name] > 0)) { return font_size_map[p_theme_type][p_name]; - } else if (default_theme_font_size > 0) { + } else if (has_default_theme_font_size()) { return default_theme_font_size; } else { return default_font_size; @@ -547,7 +578,7 @@ int Theme::get_font_size(const StringName &p_name, const StringName &p_theme_typ } bool Theme::has_font_size(const StringName &p_name, const StringName &p_theme_type) const { - return ((font_size_map.has(p_theme_type) && font_size_map[p_theme_type].has(p_name) && (font_size_map[p_theme_type][p_name] > 0)) || (default_theme_font_size > 0)); + return ((font_size_map.has(p_theme_type) && font_size_map[p_theme_type].has(p_name) && (font_size_map[p_theme_type][p_name] > 0)) || has_default_theme_font_size()); } bool Theme::has_font_size_nocheck(const StringName &p_name, const StringName &p_theme_type) const { @@ -1580,11 +1611,17 @@ void Theme::_bind_methods() { ClassDB::bind_method(D_METHOD("get_constant_list", "theme_type"), &Theme::_get_constant_list); ClassDB::bind_method(D_METHOD("get_constant_type_list"), &Theme::_get_constant_type_list); + ClassDB::bind_method(D_METHOD("set_default_base_scale", "font_size"), &Theme::set_default_theme_base_scale); + ClassDB::bind_method(D_METHOD("get_default_base_scale"), &Theme::get_default_theme_base_scale); + ClassDB::bind_method(D_METHOD("has_default_base_scale"), &Theme::has_default_theme_base_scale); + ClassDB::bind_method(D_METHOD("set_default_font", "font"), &Theme::set_default_theme_font); ClassDB::bind_method(D_METHOD("get_default_font"), &Theme::get_default_theme_font); + ClassDB::bind_method(D_METHOD("has_default_font"), &Theme::has_default_theme_font); ClassDB::bind_method(D_METHOD("set_default_font_size", "font_size"), &Theme::set_default_theme_font_size); ClassDB::bind_method(D_METHOD("get_default_font_size"), &Theme::get_default_theme_font_size); + ClassDB::bind_method(D_METHOD("has_default_font_size"), &Theme::has_default_theme_font_size); ClassDB::bind_method(D_METHOD("set_theme_item", "data_type", "name", "theme_type", "value"), &Theme::set_theme_item); ClassDB::bind_method(D_METHOD("get_theme_item", "data_type", "name", "theme_type"), &Theme::get_theme_item); @@ -1605,6 +1642,7 @@ void Theme::_bind_methods() { ClassDB::bind_method(D_METHOD("merge_with", "other"), &Theme::merge_with); ClassDB::bind_method(D_METHOD("clear"), &Theme::clear); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "default_base_scale", PROPERTY_HINT_RANGE, "0.0,2.0,0.01,or_greater"), "set_default_base_scale", "get_default_base_scale"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "default_font", PROPERTY_HINT_RESOURCE_TYPE, "Font"), "set_default_font", "get_default_font"); ADD_PROPERTY(PropertyInfo(Variant::INT, "default_font_size"), "set_default_font_size", "get_default_font_size"); diff --git a/scene/resources/theme.h b/scene/resources/theme.h index 35e466f899..50466d99c2 100644 --- a/scene/resources/theme.h +++ b/scene/resources/theme.h @@ -101,12 +101,14 @@ protected: static Ref project_default_theme; // Universal default values, final fallback for every theme. + static float default_base_scale; static Ref default_icon; static Ref default_style; static Ref default_font; static int default_font_size; // Default values configurable for each individual theme. + float default_theme_base_scale = 0.0; Ref default_theme_font; int default_theme_font_size = -1; @@ -124,16 +126,23 @@ public: static Ref get_project_default(); static void set_project_default(const Ref &p_project_default); + static void set_default_base_scale(float p_base_scale); static void set_default_icon(const Ref &p_icon); static void set_default_style(const Ref &p_style); static void set_default_font(const Ref &p_font); static void set_default_font_size(int p_font_size); + void set_default_theme_base_scale(float p_base_scale); + float get_default_theme_base_scale() const; + bool has_default_theme_base_scale() const; + void set_default_theme_font(const Ref &p_default_font); Ref get_default_theme_font() const; + bool has_default_theme_font() const; void set_default_theme_font_size(int p_font_size); int get_default_theme_font_size() const; + bool has_default_theme_font_size() const; void set_icon(const StringName &p_name, const StringName &p_theme_type, const Ref &p_icon); Ref get_icon(const StringName &p_name, const StringName &p_theme_type) const;