mirror of
https://github.com/godotengine/godot.git
synced 2024-11-10 22:23:07 +00:00
Merge pull request #65250 from YuriSizov/theme-owner-rises
This commit is contained in:
commit
597bc949a4
@ -44,6 +44,7 @@
|
||||
#include "scene/main/window.h"
|
||||
#include "scene/scene_string_names.h"
|
||||
#include "scene/theme/theme_db.h"
|
||||
#include "scene/theme/theme_owner.h"
|
||||
#include "servers/rendering_server.h"
|
||||
#include "servers/text_server.h"
|
||||
|
||||
@ -2261,57 +2262,9 @@ bool Control::is_clipping_contents() {
|
||||
|
||||
// Theming.
|
||||
|
||||
void Control::_propagate_theme_changed(Node *p_at, Control *p_owner, Window *p_owner_window, bool p_notify, bool p_assign) {
|
||||
Control *c = Object::cast_to<Control>(p_at);
|
||||
Window *w = c == nullptr ? Object::cast_to<Window>(p_at) : nullptr;
|
||||
|
||||
if (!c && !w) {
|
||||
// Theme inheritance chains are broken by nodes that aren't Control or Window.
|
||||
return;
|
||||
}
|
||||
|
||||
bool assign = p_assign;
|
||||
if (c) {
|
||||
if (c != p_owner && c->data.theme.is_valid()) {
|
||||
// Has a theme, so we don't want to change the theme owner,
|
||||
// but we still want to propagate in case this child has theme items
|
||||
// it inherits from the theme this node uses.
|
||||
// See https://github.com/godotengine/godot/issues/62844.
|
||||
assign = false;
|
||||
}
|
||||
|
||||
if (assign) {
|
||||
c->data.theme_owner = p_owner;
|
||||
c->data.theme_owner_window = p_owner_window;
|
||||
}
|
||||
|
||||
if (p_notify) {
|
||||
c->notification(Control::NOTIFICATION_THEME_CHANGED);
|
||||
}
|
||||
} else if (w) {
|
||||
if (w != p_owner_window && w->theme.is_valid()) {
|
||||
// Same as above.
|
||||
assign = false;
|
||||
}
|
||||
|
||||
if (assign) {
|
||||
w->theme_owner = p_owner;
|
||||
w->theme_owner_window = p_owner_window;
|
||||
}
|
||||
|
||||
if (p_notify) {
|
||||
w->notification(Window::NOTIFICATION_THEME_CHANGED);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < p_at->get_child_count(); i++) {
|
||||
_propagate_theme_changed(p_at->get_child(i), p_owner, p_owner_window, p_notify, assign);
|
||||
}
|
||||
}
|
||||
|
||||
void Control::_theme_changed() {
|
||||
if (is_inside_tree()) {
|
||||
_propagate_theme_changed(this, this, nullptr, true, false);
|
||||
data.theme_owner->propagate_theme_changed(this, this, true, false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2333,6 +2286,18 @@ void Control::_invalidate_theme_cache() {
|
||||
void Control::_update_theme_item_cache() {
|
||||
}
|
||||
|
||||
void Control::set_theme_owner_node(Node *p_node) {
|
||||
data.theme_owner->set_owner_node(p_node);
|
||||
}
|
||||
|
||||
Node *Control::get_theme_owner_node() const {
|
||||
return data.theme_owner->get_owner_node();
|
||||
}
|
||||
|
||||
bool Control::has_theme_owner_node() const {
|
||||
return data.theme_owner->has_owner_node();
|
||||
}
|
||||
|
||||
void Control::set_theme(const Ref<Theme> &p_theme) {
|
||||
if (data.theme == p_theme) {
|
||||
return;
|
||||
@ -2344,24 +2309,24 @@ void Control::set_theme(const Ref<Theme> &p_theme) {
|
||||
|
||||
data.theme = p_theme;
|
||||
if (data.theme.is_valid()) {
|
||||
_propagate_theme_changed(this, this, nullptr, is_inside_tree(), true);
|
||||
data.theme_owner->propagate_theme_changed(this, this, is_inside_tree(), true);
|
||||
data.theme->connect("changed", callable_mp(this, &Control::_theme_changed), CONNECT_DEFERRED);
|
||||
return;
|
||||
}
|
||||
|
||||
Control *parent_c = Object::cast_to<Control>(get_parent());
|
||||
if (parent_c && (parent_c->data.theme_owner || parent_c->data.theme_owner_window)) {
|
||||
_propagate_theme_changed(this, parent_c->data.theme_owner, parent_c->data.theme_owner_window, is_inside_tree(), true);
|
||||
if (parent_c && parent_c->has_theme_owner_node()) {
|
||||
data.theme_owner->propagate_theme_changed(this, parent_c->get_theme_owner_node(), is_inside_tree(), true);
|
||||
return;
|
||||
}
|
||||
|
||||
Window *parent_w = cast_to<Window>(get_parent());
|
||||
if (parent_w && (parent_w->theme_owner || parent_w->theme_owner_window)) {
|
||||
_propagate_theme_changed(this, parent_w->theme_owner, parent_w->theme_owner_window, is_inside_tree(), true);
|
||||
if (parent_w && parent_w->has_theme_owner_node()) {
|
||||
data.theme_owner->propagate_theme_changed(this, parent_w->get_theme_owner_node(), is_inside_tree(), true);
|
||||
return;
|
||||
}
|
||||
|
||||
_propagate_theme_changed(this, nullptr, nullptr, is_inside_tree(), true);
|
||||
data.theme_owner->propagate_theme_changed(this, nullptr, is_inside_tree(), true);
|
||||
}
|
||||
|
||||
Ref<Theme> Control::get_theme() const {
|
||||
@ -2384,130 +2349,6 @@ StringName Control::get_theme_type_variation() const {
|
||||
|
||||
/// Theme property lookup.
|
||||
|
||||
template <class T>
|
||||
T Control::get_theme_item_in_types(Control *p_theme_owner, Window *p_theme_owner_window, Theme::DataType p_data_type, const StringName &p_name, List<StringName> p_theme_types) {
|
||||
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.
|
||||
// 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);
|
||||
}
|
||||
|
||||
if (theme_owner_window && theme_owner_window->theme->has_theme_item(p_data_type, p_name, E)) {
|
||||
return theme_owner_window->theme->get_theme_item(p_data_type, p_name, E);
|
||||
}
|
||||
}
|
||||
|
||||
Node *parent = theme_owner ? theme_owner->get_parent() : theme_owner_window->get_parent();
|
||||
Control *parent_c = Object::cast_to<Control>(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<Window>(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 (ThemeDB::get_singleton()->get_project_theme().is_valid()) {
|
||||
for (const StringName &E : p_theme_types) {
|
||||
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 (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 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<StringName> p_theme_types) {
|
||||
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.
|
||||
// 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;
|
||||
}
|
||||
|
||||
if (theme_owner_window && theme_owner_window->theme->has_theme_item(p_data_type, p_name, E)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
Node *parent = theme_owner ? theme_owner->get_parent() : theme_owner_window->get_parent();
|
||||
Control *parent_c = Object::cast_to<Control>(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<Window>(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 (ThemeDB::get_singleton()->get_project_theme().is_valid()) {
|
||||
for (const StringName &E : p_theme_types) {
|
||||
if (ThemeDB::get_singleton()->get_project_theme()->has_theme_item(p_data_type, p_name, E)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Lastly, fall back on the items defined in the default Theme, if they exist.
|
||||
for (const StringName &E : p_theme_types) {
|
||||
if (ThemeDB::get_singleton()->get_default_theme()->has_theme_item(p_data_type, p_name, E)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Control::_get_theme_type_dependencies(const StringName &p_theme_type, List<StringName> *p_list) const {
|
||||
if (p_theme_type == StringName() || p_theme_type == get_class_name() || p_theme_type == data.theme_type_variation) {
|
||||
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 {
|
||||
ThemeDB::get_singleton()->get_default_theme()->get_type_dependencies(get_class_name(), data.theme_type_variation, p_list);
|
||||
}
|
||||
} else {
|
||||
ThemeDB::get_singleton()->get_default_theme()->get_type_dependencies(p_theme_type, StringName(), p_list);
|
||||
}
|
||||
}
|
||||
|
||||
Ref<Texture2D> Control::get_theme_icon(const StringName &p_name, const StringName &p_theme_type) const {
|
||||
if (p_theme_type == StringName() || p_theme_type == get_class_name() || p_theme_type == data.theme_type_variation) {
|
||||
const Ref<Texture2D> *tex = data.icon_override.getptr(p_name);
|
||||
@ -2521,8 +2362,8 @@ Ref<Texture2D> Control::get_theme_icon(const StringName &p_name, const StringNam
|
||||
}
|
||||
|
||||
List<StringName> theme_types;
|
||||
_get_theme_type_dependencies(p_theme_type, &theme_types);
|
||||
Ref<Texture2D> icon = get_theme_item_in_types<Ref<Texture2D>>(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_ICON, p_name, theme_types);
|
||||
data.theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types);
|
||||
Ref<Texture2D> icon = data.theme_owner->get_theme_item_in_types(Theme::DATA_TYPE_ICON, p_name, theme_types);
|
||||
data.theme_icon_cache[p_theme_type][p_name] = icon;
|
||||
return icon;
|
||||
}
|
||||
@ -2540,8 +2381,8 @@ Ref<StyleBox> Control::get_theme_stylebox(const StringName &p_name, const String
|
||||
}
|
||||
|
||||
List<StringName> theme_types;
|
||||
_get_theme_type_dependencies(p_theme_type, &theme_types);
|
||||
Ref<StyleBox> style = get_theme_item_in_types<Ref<StyleBox>>(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_STYLEBOX, p_name, theme_types);
|
||||
data.theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types);
|
||||
Ref<StyleBox> style = data.theme_owner->get_theme_item_in_types(Theme::DATA_TYPE_STYLEBOX, p_name, theme_types);
|
||||
data.theme_style_cache[p_theme_type][p_name] = style;
|
||||
return style;
|
||||
}
|
||||
@ -2559,8 +2400,8 @@ Ref<Font> Control::get_theme_font(const StringName &p_name, const StringName &p_
|
||||
}
|
||||
|
||||
List<StringName> theme_types;
|
||||
_get_theme_type_dependencies(p_theme_type, &theme_types);
|
||||
Ref<Font> font = get_theme_item_in_types<Ref<Font>>(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_FONT, p_name, theme_types);
|
||||
data.theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types);
|
||||
Ref<Font> font = data.theme_owner->get_theme_item_in_types(Theme::DATA_TYPE_FONT, p_name, theme_types);
|
||||
data.theme_font_cache[p_theme_type][p_name] = font;
|
||||
return font;
|
||||
}
|
||||
@ -2578,8 +2419,8 @@ int Control::get_theme_font_size(const StringName &p_name, const StringName &p_t
|
||||
}
|
||||
|
||||
List<StringName> theme_types;
|
||||
_get_theme_type_dependencies(p_theme_type, &theme_types);
|
||||
int font_size = get_theme_item_in_types<int>(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_FONT_SIZE, p_name, theme_types);
|
||||
data.theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types);
|
||||
int font_size = data.theme_owner->get_theme_item_in_types(Theme::DATA_TYPE_FONT_SIZE, p_name, theme_types);
|
||||
data.theme_font_size_cache[p_theme_type][p_name] = font_size;
|
||||
return font_size;
|
||||
}
|
||||
@ -2597,8 +2438,8 @@ Color Control::get_theme_color(const StringName &p_name, const StringName &p_the
|
||||
}
|
||||
|
||||
List<StringName> theme_types;
|
||||
_get_theme_type_dependencies(p_theme_type, &theme_types);
|
||||
Color color = get_theme_item_in_types<Color>(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_COLOR, p_name, theme_types);
|
||||
data.theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types);
|
||||
Color color = data.theme_owner->get_theme_item_in_types(Theme::DATA_TYPE_COLOR, p_name, theme_types);
|
||||
data.theme_color_cache[p_theme_type][p_name] = color;
|
||||
return color;
|
||||
}
|
||||
@ -2616,8 +2457,8 @@ int Control::get_theme_constant(const StringName &p_name, const StringName &p_th
|
||||
}
|
||||
|
||||
List<StringName> theme_types;
|
||||
_get_theme_type_dependencies(p_theme_type, &theme_types);
|
||||
int constant = get_theme_item_in_types<int>(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_CONSTANT, p_name, theme_types);
|
||||
data.theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types);
|
||||
int constant = data.theme_owner->get_theme_item_in_types(Theme::DATA_TYPE_CONSTANT, p_name, theme_types);
|
||||
data.theme_constant_cache[p_theme_type][p_name] = constant;
|
||||
return constant;
|
||||
}
|
||||
@ -2630,8 +2471,8 @@ bool Control::has_theme_icon(const StringName &p_name, const StringName &p_theme
|
||||
}
|
||||
|
||||
List<StringName> theme_types;
|
||||
_get_theme_type_dependencies(p_theme_type, &theme_types);
|
||||
return has_theme_item_in_types(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_ICON, p_name, theme_types);
|
||||
data.theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types);
|
||||
return data.theme_owner->has_theme_item_in_types(Theme::DATA_TYPE_ICON, p_name, theme_types);
|
||||
}
|
||||
|
||||
bool Control::has_theme_stylebox(const StringName &p_name, const StringName &p_theme_type) const {
|
||||
@ -2642,8 +2483,8 @@ bool Control::has_theme_stylebox(const StringName &p_name, const StringName &p_t
|
||||
}
|
||||
|
||||
List<StringName> theme_types;
|
||||
_get_theme_type_dependencies(p_theme_type, &theme_types);
|
||||
return has_theme_item_in_types(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_STYLEBOX, p_name, theme_types);
|
||||
data.theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types);
|
||||
return data.theme_owner->has_theme_item_in_types(Theme::DATA_TYPE_STYLEBOX, p_name, theme_types);
|
||||
}
|
||||
|
||||
bool Control::has_theme_font(const StringName &p_name, const StringName &p_theme_type) const {
|
||||
@ -2654,8 +2495,8 @@ bool Control::has_theme_font(const StringName &p_name, const StringName &p_theme
|
||||
}
|
||||
|
||||
List<StringName> theme_types;
|
||||
_get_theme_type_dependencies(p_theme_type, &theme_types);
|
||||
return has_theme_item_in_types(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_FONT, p_name, theme_types);
|
||||
data.theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types);
|
||||
return data.theme_owner->has_theme_item_in_types(Theme::DATA_TYPE_FONT, p_name, theme_types);
|
||||
}
|
||||
|
||||
bool Control::has_theme_font_size(const StringName &p_name, const StringName &p_theme_type) const {
|
||||
@ -2666,8 +2507,8 @@ bool Control::has_theme_font_size(const StringName &p_name, const StringName &p_
|
||||
}
|
||||
|
||||
List<StringName> theme_types;
|
||||
_get_theme_type_dependencies(p_theme_type, &theme_types);
|
||||
return has_theme_item_in_types(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_FONT_SIZE, p_name, theme_types);
|
||||
data.theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types);
|
||||
return data.theme_owner->has_theme_item_in_types(Theme::DATA_TYPE_FONT_SIZE, p_name, theme_types);
|
||||
}
|
||||
|
||||
bool Control::has_theme_color(const StringName &p_name, const StringName &p_theme_type) const {
|
||||
@ -2678,8 +2519,8 @@ bool Control::has_theme_color(const StringName &p_name, const StringName &p_them
|
||||
}
|
||||
|
||||
List<StringName> theme_types;
|
||||
_get_theme_type_dependencies(p_theme_type, &theme_types);
|
||||
return has_theme_item_in_types(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_COLOR, p_name, theme_types);
|
||||
data.theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types);
|
||||
return data.theme_owner->has_theme_item_in_types(Theme::DATA_TYPE_COLOR, p_name, theme_types);
|
||||
}
|
||||
|
||||
bool Control::has_theme_constant(const StringName &p_name, const StringName &p_theme_type) const {
|
||||
@ -2690,8 +2531,8 @@ bool Control::has_theme_constant(const StringName &p_name, const StringName &p_t
|
||||
}
|
||||
|
||||
List<StringName> theme_types;
|
||||
_get_theme_type_dependencies(p_theme_type, &theme_types);
|
||||
return has_theme_item_in_types(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_CONSTANT, p_name, theme_types);
|
||||
data.theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types);
|
||||
return data.theme_owner->has_theme_item_in_types(Theme::DATA_TYPE_CONSTANT, p_name, theme_types);
|
||||
}
|
||||
|
||||
/// Local property overrides.
|
||||
@ -2821,157 +2662,16 @@ bool Control::has_theme_constant_override(const StringName &p_name) const {
|
||||
|
||||
/// Default theme properties.
|
||||
|
||||
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_base_scale()) {
|
||||
return theme_owner->data.theme->get_default_base_scale();
|
||||
}
|
||||
|
||||
if (theme_owner_window && theme_owner_window->theme->has_default_base_scale()) {
|
||||
return theme_owner_window->theme->get_default_base_scale();
|
||||
}
|
||||
|
||||
Node *parent = theme_owner ? theme_owner->get_parent() : theme_owner_window->get_parent();
|
||||
Control *parent_c = Object::cast_to<Control>(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<Window>(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 (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 (ThemeDB::get_singleton()->get_default_theme()->has_default_base_scale()) {
|
||||
return ThemeDB::get_singleton()->get_default_theme()->get_default_base_scale();
|
||||
}
|
||||
return ThemeDB::get_singleton()->get_fallback_base_scale();
|
||||
}
|
||||
|
||||
float Control::get_theme_default_base_scale() const {
|
||||
return fetch_theme_default_base_scale(data.theme_owner, data.theme_owner_window);
|
||||
}
|
||||
|
||||
Ref<Font> 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_font()) {
|
||||
return theme_owner->data.theme->get_default_font();
|
||||
}
|
||||
|
||||
if (theme_owner_window && theme_owner_window->theme->has_default_font()) {
|
||||
return theme_owner_window->theme->get_default_font();
|
||||
}
|
||||
|
||||
Node *parent = theme_owner ? theme_owner->get_parent() : theme_owner_window->get_parent();
|
||||
Control *parent_c = Object::cast_to<Control>(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<Window>(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 (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 (ThemeDB::get_singleton()->get_default_theme()->has_default_font()) {
|
||||
return ThemeDB::get_singleton()->get_default_theme()->get_default_font();
|
||||
}
|
||||
return ThemeDB::get_singleton()->get_fallback_font();
|
||||
return data.theme_owner->get_theme_default_base_scale();
|
||||
}
|
||||
|
||||
Ref<Font> 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_font_size()) {
|
||||
return theme_owner->data.theme->get_default_font_size();
|
||||
}
|
||||
|
||||
if (theme_owner_window && theme_owner_window->theme->has_default_font_size()) {
|
||||
return theme_owner_window->theme->get_default_font_size();
|
||||
}
|
||||
|
||||
Node *parent = theme_owner ? theme_owner->get_parent() : theme_owner_window->get_parent();
|
||||
Control *parent_c = Object::cast_to<Control>(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<Window>(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 (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 (ThemeDB::get_singleton()->get_default_theme()->has_default_font_size()) {
|
||||
return ThemeDB::get_singleton()->get_default_theme()->get_default_font_size();
|
||||
}
|
||||
return ThemeDB::get_singleton()->get_fallback_font_size();
|
||||
return data.theme_owner->get_theme_default_font();
|
||||
}
|
||||
|
||||
int Control::get_theme_default_font_size() const {
|
||||
return fetch_theme_default_font_size(data.theme_owner, data.theme_owner_window);
|
||||
return data.theme_owner->get_theme_default_font_size();
|
||||
}
|
||||
|
||||
/// Bulk actions.
|
||||
@ -3089,21 +2789,6 @@ Control *Control::make_custom_tooltip(const String &p_text) const {
|
||||
|
||||
// Base object overrides.
|
||||
|
||||
void Control::add_child_notify(Node *p_child) {
|
||||
// We propagate when this node uses a custom theme, so it can pass it on to its children.
|
||||
if (data.theme_owner || data.theme_owner_window) {
|
||||
// `p_notify` is false here as `NOTIFICATION_THEME_CHANGED` will be handled by `NOTIFICATION_ENTER_TREE`.
|
||||
_propagate_theme_changed(p_child, data.theme_owner, data.theme_owner_window, false, true);
|
||||
}
|
||||
}
|
||||
|
||||
void Control::remove_child_notify(Node *p_child) {
|
||||
// If the removed child isn't inheriting any theme items through this node, then there's no need to propagate.
|
||||
if (data.theme_owner || data.theme_owner_window) {
|
||||
_propagate_theme_changed(p_child, nullptr, nullptr, false, true);
|
||||
}
|
||||
}
|
||||
|
||||
void Control::_notification(int p_notification) {
|
||||
switch (p_notification) {
|
||||
case NOTIFICATION_POSTINITIALIZE: {
|
||||
@ -3111,10 +2796,16 @@ void Control::_notification(int p_notification) {
|
||||
_update_theme_item_cache();
|
||||
} break;
|
||||
|
||||
case NOTIFICATION_PARENTED: {
|
||||
data.theme_owner->assign_theme_on_parented(this);
|
||||
} break;
|
||||
|
||||
case NOTIFICATION_UNPARENTED: {
|
||||
data.theme_owner->clear_theme_on_unparented(this);
|
||||
} break;
|
||||
|
||||
case NOTIFICATION_ENTER_TREE: {
|
||||
// Need to defer here, because theme owner information might be set in
|
||||
// add_child_notify, which doesn't get called until right after this.
|
||||
call_deferred(SNAME("notification"), NOTIFICATION_THEME_CHANGED);
|
||||
notification(NOTIFICATION_THEME_CHANGED);
|
||||
} break;
|
||||
|
||||
case NOTIFICATION_POST_ENTER_TREE: {
|
||||
@ -3611,7 +3302,13 @@ void Control::_bind_methods() {
|
||||
GDVIRTUAL_BIND(_gui_input, "event");
|
||||
}
|
||||
|
||||
Control::Control() {
|
||||
data.theme_owner = memnew(ThemeOwner);
|
||||
}
|
||||
|
||||
Control::~Control() {
|
||||
memdelete(data.theme_owner);
|
||||
|
||||
// Resources need to be disconnected.
|
||||
for (KeyValue<StringName, Ref<Texture2D>> &E : data.icon_override) {
|
||||
E.value->disconnect("changed", callable_mp(this, &Control::_notify_theme_override_changed));
|
||||
|
@ -41,6 +41,7 @@
|
||||
class Viewport;
|
||||
class Label;
|
||||
class Panel;
|
||||
class ThemeOwner;
|
||||
|
||||
class Control : public CanvasItem {
|
||||
GDCLASS(Control, CanvasItem);
|
||||
@ -219,9 +220,8 @@ private:
|
||||
|
||||
// Theming.
|
||||
|
||||
ThemeOwner *theme_owner = nullptr;
|
||||
Ref<Theme> theme;
|
||||
Control *theme_owner = nullptr;
|
||||
Window *theme_owner_window = nullptr;
|
||||
StringName theme_type_variation;
|
||||
|
||||
bool bulk_theme_override = false;
|
||||
@ -261,7 +261,6 @@ private:
|
||||
// Global relations.
|
||||
|
||||
friend class Viewport;
|
||||
friend class Window;
|
||||
|
||||
// Positioning and sizing.
|
||||
|
||||
@ -303,13 +302,6 @@ private:
|
||||
void _notify_theme_override_changed();
|
||||
void _invalidate_theme_cache();
|
||||
|
||||
static void _propagate_theme_changed(Node *p_at, Control *p_owner, Window *p_owner_window, bool p_notify, bool p_assign);
|
||||
|
||||
template <class T>
|
||||
static T get_theme_item_in_types(Control *p_theme_owner, Window *p_theme_owner_window, Theme::DataType p_data_type, const StringName &p_name, List<StringName> p_theme_types);
|
||||
static bool has_theme_item_in_types(Control *p_theme_owner, Window *p_theme_owner_window, Theme::DataType p_data_type, const StringName &p_name, List<StringName> p_theme_types);
|
||||
_FORCE_INLINE_ void _get_theme_type_dependencies(const StringName &p_theme_type, List<StringName> *p_list) const;
|
||||
|
||||
// Extra properties.
|
||||
|
||||
String get_tooltip_text() const;
|
||||
@ -335,9 +327,6 @@ protected:
|
||||
|
||||
// Base object overrides.
|
||||
|
||||
virtual void add_child_notify(Node *p_child) override;
|
||||
virtual void remove_child_notify(Node *p_child) override;
|
||||
|
||||
void _notification(int p_notification);
|
||||
static void _bind_methods();
|
||||
|
||||
@ -542,6 +531,10 @@ public:
|
||||
|
||||
// Theming.
|
||||
|
||||
void set_theme_owner_node(Node *p_node);
|
||||
Node *get_theme_owner_node() const;
|
||||
bool has_theme_owner_node() const;
|
||||
|
||||
void set_theme(const Ref<Theme> &p_theme);
|
||||
Ref<Theme> get_theme() const;
|
||||
|
||||
@ -586,10 +579,6 @@ 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<Font> 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<Font> get_theme_default_font() const;
|
||||
int get_theme_default_font_size() const;
|
||||
@ -612,7 +601,7 @@ public:
|
||||
virtual String get_tooltip(const Point2 &p_pos) const;
|
||||
virtual Control *make_custom_tooltip(const String &p_text) const;
|
||||
|
||||
Control() {}
|
||||
Control();
|
||||
~Control();
|
||||
};
|
||||
|
||||
|
@ -38,6 +38,7 @@
|
||||
#include "scene/gui/control.h"
|
||||
#include "scene/scene_string_names.h"
|
||||
#include "scene/theme/theme_db.h"
|
||||
#include "scene/theme/theme_owner.h"
|
||||
|
||||
void Window::set_title(const String &p_title) {
|
||||
title = p_title;
|
||||
@ -804,6 +805,14 @@ void Window::_notification(int p_what) {
|
||||
_update_theme_item_cache();
|
||||
} break;
|
||||
|
||||
case NOTIFICATION_PARENTED: {
|
||||
theme_owner->assign_theme_on_parented(this);
|
||||
} break;
|
||||
|
||||
case NOTIFICATION_UNPARENTED: {
|
||||
theme_owner->clear_theme_on_unparented(this);
|
||||
} break;
|
||||
|
||||
case NOTIFICATION_ENTER_TREE: {
|
||||
bool embedded = false;
|
||||
{
|
||||
@ -1289,28 +1298,29 @@ Rect2i Window::get_usable_parent_rect() const {
|
||||
}
|
||||
|
||||
void Window::add_child_notify(Node *p_child) {
|
||||
// We propagate when this node uses a custom theme, so it can pass it on to its children.
|
||||
if (theme_owner || theme_owner_window) {
|
||||
// `p_notify` is false here as `NOTIFICATION_THEME_CHANGED` will be handled by `NOTIFICATION_ENTER_TREE`.
|
||||
Control::_propagate_theme_changed(this, theme_owner, theme_owner_window, false, true);
|
||||
}
|
||||
|
||||
if (is_inside_tree() && wrap_controls) {
|
||||
child_controls_changed();
|
||||
}
|
||||
}
|
||||
|
||||
void Window::remove_child_notify(Node *p_child) {
|
||||
// If the removed child isn't inheriting any theme items through this node, then there's no need to propagate.
|
||||
if (theme_owner || theme_owner_window) {
|
||||
Control::_propagate_theme_changed(this, nullptr, nullptr, false, true);
|
||||
}
|
||||
|
||||
if (is_inside_tree() && wrap_controls) {
|
||||
child_controls_changed();
|
||||
}
|
||||
}
|
||||
|
||||
void Window::set_theme_owner_node(Node *p_node) {
|
||||
theme_owner->set_owner_node(p_node);
|
||||
}
|
||||
|
||||
Node *Window::get_theme_owner_node() const {
|
||||
return theme_owner->get_owner_node();
|
||||
}
|
||||
|
||||
bool Window::has_theme_owner_node() const {
|
||||
return theme_owner->has_owner_node();
|
||||
}
|
||||
|
||||
void Window::set_theme(const Ref<Theme> &p_theme) {
|
||||
if (theme == p_theme) {
|
||||
return;
|
||||
@ -1322,24 +1332,24 @@ void Window::set_theme(const Ref<Theme> &p_theme) {
|
||||
|
||||
theme = p_theme;
|
||||
if (theme.is_valid()) {
|
||||
Control::_propagate_theme_changed(this, nullptr, this, is_inside_tree(), true);
|
||||
theme_owner->propagate_theme_changed(this, this, is_inside_tree(), true);
|
||||
theme->connect("changed", callable_mp(this, &Window::_theme_changed), CONNECT_DEFERRED);
|
||||
return;
|
||||
}
|
||||
|
||||
Control *parent_c = Object::cast_to<Control>(get_parent());
|
||||
if (parent_c && (parent_c->data.theme_owner || parent_c->data.theme_owner_window)) {
|
||||
Control::_propagate_theme_changed(this, parent_c->data.theme_owner, parent_c->data.theme_owner_window, is_inside_tree(), true);
|
||||
if (parent_c && parent_c->has_theme_owner_node()) {
|
||||
theme_owner->propagate_theme_changed(this, parent_c->get_theme_owner_node(), is_inside_tree(), true);
|
||||
return;
|
||||
}
|
||||
|
||||
Window *parent_w = cast_to<Window>(get_parent());
|
||||
if (parent_w && (parent_w->theme_owner || parent_w->theme_owner_window)) {
|
||||
Control::_propagate_theme_changed(this, parent_w->theme_owner, parent_w->theme_owner_window, is_inside_tree(), true);
|
||||
if (parent_w && parent_w->has_theme_owner_node()) {
|
||||
theme_owner->propagate_theme_changed(this, parent_w->get_theme_owner_node(), is_inside_tree(), true);
|
||||
return;
|
||||
}
|
||||
|
||||
Control::_propagate_theme_changed(this, nullptr, nullptr, is_inside_tree(), true);
|
||||
theme_owner->propagate_theme_changed(this, nullptr, is_inside_tree(), true);
|
||||
}
|
||||
|
||||
Ref<Theme> Window::get_theme() const {
|
||||
@ -1348,7 +1358,7 @@ Ref<Theme> Window::get_theme() const {
|
||||
|
||||
void Window::_theme_changed() {
|
||||
if (is_inside_tree()) {
|
||||
Control::_propagate_theme_changed(this, nullptr, this, true, false);
|
||||
theme_owner->propagate_theme_changed(this, this, true, false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1375,26 +1385,14 @@ StringName Window::get_theme_type_variation() const {
|
||||
return theme_type_variation;
|
||||
}
|
||||
|
||||
void Window::_get_theme_type_dependencies(const StringName &p_theme_type, List<StringName> *p_list) const {
|
||||
if (p_theme_type == StringName() || p_theme_type == get_class_name() || p_theme_type == theme_type_variation) {
|
||||
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 {
|
||||
ThemeDB::get_singleton()->get_default_theme()->get_type_dependencies(get_class_name(), theme_type_variation, p_list);
|
||||
}
|
||||
} else {
|
||||
ThemeDB::get_singleton()->get_default_theme()->get_type_dependencies(p_theme_type, StringName(), p_list);
|
||||
}
|
||||
}
|
||||
|
||||
Ref<Texture2D> Window::get_theme_icon(const StringName &p_name, const StringName &p_theme_type) const {
|
||||
if (theme_icon_cache.has(p_theme_type) && theme_icon_cache[p_theme_type].has(p_name)) {
|
||||
return theme_icon_cache[p_theme_type][p_name];
|
||||
}
|
||||
|
||||
List<StringName> theme_types;
|
||||
_get_theme_type_dependencies(p_theme_type, &theme_types);
|
||||
Ref<Texture2D> icon = Control::get_theme_item_in_types<Ref<Texture2D>>(theme_owner, theme_owner_window, Theme::DATA_TYPE_ICON, p_name, theme_types);
|
||||
theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types);
|
||||
Ref<Texture2D> icon = theme_owner->get_theme_item_in_types(Theme::DATA_TYPE_ICON, p_name, theme_types);
|
||||
theme_icon_cache[p_theme_type][p_name] = icon;
|
||||
return icon;
|
||||
}
|
||||
@ -1405,8 +1403,8 @@ Ref<StyleBox> Window::get_theme_stylebox(const StringName &p_name, const StringN
|
||||
}
|
||||
|
||||
List<StringName> theme_types;
|
||||
_get_theme_type_dependencies(p_theme_type, &theme_types);
|
||||
Ref<StyleBox> style = Control::get_theme_item_in_types<Ref<StyleBox>>(theme_owner, theme_owner_window, Theme::DATA_TYPE_STYLEBOX, p_name, theme_types);
|
||||
theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types);
|
||||
Ref<StyleBox> style = theme_owner->get_theme_item_in_types(Theme::DATA_TYPE_STYLEBOX, p_name, theme_types);
|
||||
theme_style_cache[p_theme_type][p_name] = style;
|
||||
return style;
|
||||
}
|
||||
@ -1417,8 +1415,8 @@ Ref<Font> Window::get_theme_font(const StringName &p_name, const StringName &p_t
|
||||
}
|
||||
|
||||
List<StringName> theme_types;
|
||||
_get_theme_type_dependencies(p_theme_type, &theme_types);
|
||||
Ref<Font> font = Control::get_theme_item_in_types<Ref<Font>>(theme_owner, theme_owner_window, Theme::DATA_TYPE_FONT, p_name, theme_types);
|
||||
theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types);
|
||||
Ref<Font> font = theme_owner->get_theme_item_in_types(Theme::DATA_TYPE_FONT, p_name, theme_types);
|
||||
theme_font_cache[p_theme_type][p_name] = font;
|
||||
return font;
|
||||
}
|
||||
@ -1429,8 +1427,8 @@ int Window::get_theme_font_size(const StringName &p_name, const StringName &p_th
|
||||
}
|
||||
|
||||
List<StringName> theme_types;
|
||||
_get_theme_type_dependencies(p_theme_type, &theme_types);
|
||||
int font_size = Control::get_theme_item_in_types<int>(theme_owner, theme_owner_window, Theme::DATA_TYPE_FONT_SIZE, p_name, theme_types);
|
||||
theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types);
|
||||
int font_size = theme_owner->get_theme_item_in_types(Theme::DATA_TYPE_FONT_SIZE, p_name, theme_types);
|
||||
theme_font_size_cache[p_theme_type][p_name] = font_size;
|
||||
return font_size;
|
||||
}
|
||||
@ -1441,8 +1439,8 @@ Color Window::get_theme_color(const StringName &p_name, const StringName &p_them
|
||||
}
|
||||
|
||||
List<StringName> theme_types;
|
||||
_get_theme_type_dependencies(p_theme_type, &theme_types);
|
||||
Color color = Control::get_theme_item_in_types<Color>(theme_owner, theme_owner_window, Theme::DATA_TYPE_COLOR, p_name, theme_types);
|
||||
theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types);
|
||||
Color color = theme_owner->get_theme_item_in_types(Theme::DATA_TYPE_COLOR, p_name, theme_types);
|
||||
theme_color_cache[p_theme_type][p_name] = color;
|
||||
return color;
|
||||
}
|
||||
@ -1453,58 +1451,58 @@ int Window::get_theme_constant(const StringName &p_name, const StringName &p_the
|
||||
}
|
||||
|
||||
List<StringName> theme_types;
|
||||
_get_theme_type_dependencies(p_theme_type, &theme_types);
|
||||
int constant = Control::get_theme_item_in_types<int>(theme_owner, theme_owner_window, Theme::DATA_TYPE_CONSTANT, p_name, theme_types);
|
||||
theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types);
|
||||
int constant = theme_owner->get_theme_item_in_types(Theme::DATA_TYPE_CONSTANT, p_name, theme_types);
|
||||
theme_constant_cache[p_theme_type][p_name] = constant;
|
||||
return constant;
|
||||
}
|
||||
|
||||
bool Window::has_theme_icon(const StringName &p_name, const StringName &p_theme_type) const {
|
||||
List<StringName> theme_types;
|
||||
_get_theme_type_dependencies(p_theme_type, &theme_types);
|
||||
return Control::has_theme_item_in_types(theme_owner, theme_owner_window, Theme::DATA_TYPE_ICON, p_name, theme_types);
|
||||
theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types);
|
||||
return theme_owner->has_theme_item_in_types(Theme::DATA_TYPE_ICON, p_name, theme_types);
|
||||
}
|
||||
|
||||
bool Window::has_theme_stylebox(const StringName &p_name, const StringName &p_theme_type) const {
|
||||
List<StringName> theme_types;
|
||||
_get_theme_type_dependencies(p_theme_type, &theme_types);
|
||||
return Control::has_theme_item_in_types(theme_owner, theme_owner_window, Theme::DATA_TYPE_STYLEBOX, p_name, theme_types);
|
||||
theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types);
|
||||
return theme_owner->has_theme_item_in_types(Theme::DATA_TYPE_STYLEBOX, p_name, theme_types);
|
||||
}
|
||||
|
||||
bool Window::has_theme_font(const StringName &p_name, const StringName &p_theme_type) const {
|
||||
List<StringName> theme_types;
|
||||
_get_theme_type_dependencies(p_theme_type, &theme_types);
|
||||
return Control::has_theme_item_in_types(theme_owner, theme_owner_window, Theme::DATA_TYPE_FONT, p_name, theme_types);
|
||||
theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types);
|
||||
return theme_owner->has_theme_item_in_types(Theme::DATA_TYPE_FONT, p_name, theme_types);
|
||||
}
|
||||
|
||||
bool Window::has_theme_font_size(const StringName &p_name, const StringName &p_theme_type) const {
|
||||
List<StringName> theme_types;
|
||||
_get_theme_type_dependencies(p_theme_type, &theme_types);
|
||||
return Control::has_theme_item_in_types(theme_owner, theme_owner_window, Theme::DATA_TYPE_FONT_SIZE, p_name, theme_types);
|
||||
theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types);
|
||||
return theme_owner->has_theme_item_in_types(Theme::DATA_TYPE_FONT_SIZE, p_name, theme_types);
|
||||
}
|
||||
|
||||
bool Window::has_theme_color(const StringName &p_name, const StringName &p_theme_type) const {
|
||||
List<StringName> theme_types;
|
||||
_get_theme_type_dependencies(p_theme_type, &theme_types);
|
||||
return Control::has_theme_item_in_types(theme_owner, theme_owner_window, Theme::DATA_TYPE_COLOR, p_name, theme_types);
|
||||
theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types);
|
||||
return theme_owner->has_theme_item_in_types(Theme::DATA_TYPE_COLOR, p_name, theme_types);
|
||||
}
|
||||
|
||||
bool Window::has_theme_constant(const StringName &p_name, const StringName &p_theme_type) const {
|
||||
List<StringName> theme_types;
|
||||
_get_theme_type_dependencies(p_theme_type, &theme_types);
|
||||
return Control::has_theme_item_in_types(theme_owner, theme_owner_window, Theme::DATA_TYPE_CONSTANT, p_name, theme_types);
|
||||
theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types);
|
||||
return theme_owner->has_theme_item_in_types(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);
|
||||
return theme_owner->get_theme_default_base_scale();
|
||||
}
|
||||
|
||||
Ref<Font> Window::get_theme_default_font() const {
|
||||
return Control::fetch_theme_default_font(theme_owner, theme_owner_window);
|
||||
return theme_owner->get_theme_default_font();
|
||||
}
|
||||
|
||||
int Window::get_theme_default_font_size() const {
|
||||
return Control::fetch_theme_default_font_size(theme_owner, theme_owner_window);
|
||||
return theme_owner->get_theme_default_font_size();
|
||||
}
|
||||
|
||||
Rect2i Window::get_parent_rect() const {
|
||||
@ -1834,8 +1832,10 @@ void Window::_bind_methods() {
|
||||
}
|
||||
|
||||
Window::Window() {
|
||||
theme_owner = memnew(ThemeOwner);
|
||||
RS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), RS::VIEWPORT_UPDATE_DISABLED);
|
||||
}
|
||||
|
||||
Window::~Window() {
|
||||
memdelete(theme_owner);
|
||||
}
|
||||
|
@ -38,6 +38,7 @@ class Control;
|
||||
class Font;
|
||||
class Shortcut;
|
||||
class StyleBox;
|
||||
class ThemeOwner;
|
||||
|
||||
class Window : public Viewport {
|
||||
GDCLASS(Window, Viewport)
|
||||
@ -135,10 +136,8 @@ private:
|
||||
Window *exclusive_child = nullptr;
|
||||
HashSet<Window *> transient_children;
|
||||
|
||||
friend class Control;
|
||||
ThemeOwner *theme_owner = nullptr;
|
||||
Ref<Theme> theme;
|
||||
Control *theme_owner = nullptr;
|
||||
Window *theme_owner_window = nullptr;
|
||||
StringName theme_type_variation;
|
||||
|
||||
mutable HashMap<StringName, Theme::ThemeIconMap> theme_icon_cache;
|
||||
@ -148,8 +147,6 @@ private:
|
||||
mutable HashMap<StringName, Theme::ThemeColorMap> theme_color_cache;
|
||||
mutable HashMap<StringName, Theme::ThemeConstantMap> theme_constant_cache;
|
||||
|
||||
_FORCE_INLINE_ void _get_theme_type_dependencies(const StringName &p_theme_type, List<StringName> *p_list) const;
|
||||
|
||||
void _theme_changed();
|
||||
void _invalidate_theme_cache();
|
||||
|
||||
@ -271,6 +268,10 @@ public:
|
||||
void popup_centered(const Size2i &p_minsize = Size2i());
|
||||
void popup_centered_clamped(const Size2i &p_size = Size2i(), float p_fallback_ratio = 0.75);
|
||||
|
||||
void set_theme_owner_node(Node *p_node);
|
||||
Node *get_theme_owner_node() const;
|
||||
bool has_theme_owner_node() const;
|
||||
|
||||
void set_theme(const Ref<Theme> &p_theme);
|
||||
Ref<Theme> get_theme() const;
|
||||
|
||||
|
410
scene/theme/theme_owner.cpp
Normal file
410
scene/theme/theme_owner.cpp
Normal file
@ -0,0 +1,410 @@
|
||||
/*************************************************************************/
|
||||
/* theme_owner.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_owner.h"
|
||||
|
||||
#include "scene/gui/control.h"
|
||||
#include "scene/main/window.h"
|
||||
#include "scene/theme/theme_db.h"
|
||||
|
||||
// Theme owner node.
|
||||
|
||||
void ThemeOwner::set_owner_node(Node *p_node) {
|
||||
owner_control = nullptr;
|
||||
owner_window = nullptr;
|
||||
|
||||
Control *c = Object::cast_to<Control>(p_node);
|
||||
if (c) {
|
||||
owner_control = c;
|
||||
return;
|
||||
}
|
||||
|
||||
Window *w = Object::cast_to<Window>(p_node);
|
||||
if (w) {
|
||||
owner_window = w;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Node *ThemeOwner::get_owner_node() const {
|
||||
if (owner_control) {
|
||||
return owner_control;
|
||||
} else if (owner_window) {
|
||||
return owner_window;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool ThemeOwner::has_owner_node() const {
|
||||
return bool(owner_control || owner_window);
|
||||
}
|
||||
|
||||
// Theme propagation.
|
||||
|
||||
void ThemeOwner::assign_theme_on_parented(Node *p_for_node) {
|
||||
// We check if there are any themes affecting the parent. If that's the case
|
||||
// its children also need to be affected.
|
||||
// We don't notify here because `NOTIFICATION_THEME_CHANGED` will be handled
|
||||
// a bit later by `NOTIFICATION_ENTER_TREE`.
|
||||
|
||||
Node *parent = p_for_node->get_parent();
|
||||
|
||||
Control *parent_c = Object::cast_to<Control>(parent);
|
||||
if (parent_c && parent_c->has_theme_owner_node()) {
|
||||
propagate_theme_changed(p_for_node, parent_c->get_theme_owner_node(), false, true);
|
||||
} else {
|
||||
Window *parent_w = Object::cast_to<Window>(parent);
|
||||
if (parent_w && parent_w->has_theme_owner_node()) {
|
||||
propagate_theme_changed(p_for_node, parent_w->get_theme_owner_node(), false, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ThemeOwner::clear_theme_on_unparented(Node *p_for_node) {
|
||||
// We check if there were any themes affecting the parent. If that's the case
|
||||
// its children need were also affected and need to be updated.
|
||||
// We don't notify because we're exiting the tree, and it's not important.
|
||||
|
||||
Node *parent = p_for_node->get_parent();
|
||||
|
||||
Control *parent_c = Object::cast_to<Control>(parent);
|
||||
if (parent_c && parent_c->has_theme_owner_node()) {
|
||||
propagate_theme_changed(p_for_node, nullptr, false, true);
|
||||
} else {
|
||||
Window *parent_w = Object::cast_to<Window>(parent);
|
||||
if (parent_w && parent_w->has_theme_owner_node()) {
|
||||
propagate_theme_changed(p_for_node, nullptr, false, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ThemeOwner::propagate_theme_changed(Node *p_to_node, Node *p_owner_node, bool p_notify, bool p_assign) {
|
||||
Control *c = Object::cast_to<Control>(p_to_node);
|
||||
Window *w = c == nullptr ? Object::cast_to<Window>(p_to_node) : nullptr;
|
||||
|
||||
if (!c && !w) {
|
||||
// Theme inheritance chains are broken by nodes that aren't Control or Window.
|
||||
return;
|
||||
}
|
||||
|
||||
bool assign = p_assign;
|
||||
if (c) {
|
||||
if (c != p_owner_node && c->get_theme().is_valid()) {
|
||||
// Has a theme, so we don't want to change the theme owner,
|
||||
// but we still want to propagate in case this child has theme items
|
||||
// it inherits from the theme this node uses.
|
||||
// See https://github.com/godotengine/godot/issues/62844.
|
||||
assign = false;
|
||||
}
|
||||
|
||||
if (assign) {
|
||||
c->set_theme_owner_node(p_owner_node);
|
||||
}
|
||||
|
||||
if (p_notify) {
|
||||
c->notification(Control::NOTIFICATION_THEME_CHANGED);
|
||||
}
|
||||
} else if (w) {
|
||||
if (w != p_owner_node && w->get_theme().is_valid()) {
|
||||
// Same as above.
|
||||
assign = false;
|
||||
}
|
||||
|
||||
if (assign) {
|
||||
w->set_theme_owner_node(p_owner_node);
|
||||
}
|
||||
|
||||
if (p_notify) {
|
||||
w->notification(Window::NOTIFICATION_THEME_CHANGED);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < p_to_node->get_child_count(); i++) {
|
||||
propagate_theme_changed(p_to_node->get_child(i), p_owner_node, p_notify, assign);
|
||||
}
|
||||
}
|
||||
|
||||
// Theme lookup.
|
||||
|
||||
void ThemeOwner::get_theme_type_dependencies(const Node *p_for_node, const StringName &p_theme_type, List<StringName> *r_list) const {
|
||||
const Control *for_c = Object::cast_to<Control>(p_for_node);
|
||||
const Window *for_w = Object::cast_to<Window>(p_for_node);
|
||||
ERR_FAIL_COND_MSG(!for_c && !for_w, "Only Control and Window nodes and derivatives can be polled for theming.");
|
||||
|
||||
Ref<Theme> default_theme = ThemeDB::get_singleton()->get_default_theme();
|
||||
Ref<Theme> project_theme = ThemeDB::get_singleton()->get_project_theme();
|
||||
|
||||
StringName type_variation;
|
||||
if (for_c) {
|
||||
type_variation = for_c->get_theme_type_variation();
|
||||
} else if (for_w) {
|
||||
type_variation = for_w->get_theme_type_variation();
|
||||
}
|
||||
|
||||
if (p_theme_type == StringName() || p_theme_type == p_for_node->get_class_name() || p_theme_type == type_variation) {
|
||||
if (project_theme.is_valid() && project_theme->get_type_variation_base(type_variation) != StringName()) {
|
||||
project_theme->get_type_dependencies(p_for_node->get_class_name(), type_variation, r_list);
|
||||
} else {
|
||||
default_theme->get_type_dependencies(p_for_node->get_class_name(), type_variation, r_list);
|
||||
}
|
||||
} else {
|
||||
default_theme->get_type_dependencies(p_theme_type, StringName(), r_list);
|
||||
}
|
||||
}
|
||||
|
||||
Node *ThemeOwner::_get_next_owner_node(Node *p_from_node) const {
|
||||
Node *parent = p_from_node->get_parent();
|
||||
|
||||
Control *parent_c = Object::cast_to<Control>(parent);
|
||||
if (parent_c) {
|
||||
return parent_c->get_theme_owner_node();
|
||||
} else {
|
||||
Window *parent_w = Object::cast_to<Window>(parent);
|
||||
if (parent_w) {
|
||||
return parent_w->get_theme_owner_node();
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Variant ThemeOwner::get_theme_item_in_types(Theme::DataType p_data_type, const StringName &p_name, List<StringName> p_theme_types) {
|
||||
ERR_FAIL_COND_V_MSG(p_theme_types.size() == 0, Variant(), "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.
|
||||
// Only nodes with a theme resource attached are considered.
|
||||
Node *owner_node = get_owner_node();
|
||||
|
||||
while (owner_node) {
|
||||
// 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) {
|
||||
Ref<Theme> owner_theme;
|
||||
|
||||
Control *owner_c = Object::cast_to<Control>(owner_node);
|
||||
if (owner_c) {
|
||||
owner_theme = owner_c->get_theme();
|
||||
}
|
||||
Window *owner_w = Object::cast_to<Window>(owner_node);
|
||||
if (owner_w) {
|
||||
owner_theme = owner_w->get_theme();
|
||||
}
|
||||
|
||||
if (owner_theme.is_valid() && owner_theme->has_theme_item(p_data_type, p_name, E)) {
|
||||
return owner_theme->get_theme_item(p_data_type, p_name, E);
|
||||
}
|
||||
}
|
||||
|
||||
owner_node = _get_next_owner_node(owner_node);
|
||||
}
|
||||
|
||||
// Secondly, check the project-defined Theme resource.
|
||||
if (ThemeDB::get_singleton()->get_project_theme().is_valid()) {
|
||||
for (const StringName &E : p_theme_types) {
|
||||
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 (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 ThemeDB::get_singleton()->get_default_theme()->get_theme_item(p_data_type, p_name, p_theme_types[0]);
|
||||
}
|
||||
|
||||
bool ThemeOwner::has_theme_item_in_types(Theme::DataType p_data_type, const StringName &p_name, List<StringName> p_theme_types) {
|
||||
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.
|
||||
// Only nodes with a theme resource attached are considered.
|
||||
Node *owner_node = get_owner_node();
|
||||
|
||||
while (owner_node) {
|
||||
// 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) {
|
||||
Ref<Theme> owner_theme;
|
||||
|
||||
Control *owner_c = Object::cast_to<Control>(owner_node);
|
||||
if (owner_c) {
|
||||
owner_theme = owner_c->get_theme();
|
||||
}
|
||||
Window *owner_w = Object::cast_to<Window>(owner_node);
|
||||
if (owner_w) {
|
||||
owner_theme = owner_w->get_theme();
|
||||
}
|
||||
|
||||
if (owner_theme.is_valid() && owner_theme->has_theme_item(p_data_type, p_name, E)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
owner_node = _get_next_owner_node(owner_node);
|
||||
}
|
||||
|
||||
// Secondly, check the project-defined Theme resource.
|
||||
if (ThemeDB::get_singleton()->get_project_theme().is_valid()) {
|
||||
for (const StringName &E : p_theme_types) {
|
||||
if (ThemeDB::get_singleton()->get_project_theme()->has_theme_item(p_data_type, p_name, E)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Lastly, fall back on the items defined in the default Theme, if they exist.
|
||||
for (const StringName &E : p_theme_types) {
|
||||
if (ThemeDB::get_singleton()->get_default_theme()->has_theme_item(p_data_type, p_name, E)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
float ThemeOwner::get_theme_default_base_scale() {
|
||||
// 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.
|
||||
Node *owner_node = get_owner_node();
|
||||
|
||||
while (owner_node) {
|
||||
Ref<Theme> owner_theme;
|
||||
|
||||
Control *owner_c = Object::cast_to<Control>(owner_node);
|
||||
if (owner_c) {
|
||||
owner_theme = owner_c->get_theme();
|
||||
}
|
||||
Window *owner_w = Object::cast_to<Window>(owner_node);
|
||||
if (owner_w) {
|
||||
owner_theme = owner_w->get_theme();
|
||||
}
|
||||
|
||||
if (owner_theme.is_valid() && owner_theme->has_default_base_scale()) {
|
||||
return owner_theme->get_default_base_scale();
|
||||
}
|
||||
|
||||
owner_node = _get_next_owner_node(owner_node);
|
||||
}
|
||||
|
||||
// Secondly, check the project-defined Theme resource.
|
||||
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 (ThemeDB::get_singleton()->get_default_theme()->has_default_base_scale()) {
|
||||
return ThemeDB::get_singleton()->get_default_theme()->get_default_base_scale();
|
||||
}
|
||||
return ThemeDB::get_singleton()->get_fallback_base_scale();
|
||||
}
|
||||
|
||||
Ref<Font> ThemeOwner::get_theme_default_font() {
|
||||
// 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.
|
||||
Node *owner_node = get_owner_node();
|
||||
|
||||
while (owner_node) {
|
||||
Ref<Theme> owner_theme;
|
||||
|
||||
Control *owner_c = Object::cast_to<Control>(owner_node);
|
||||
if (owner_c) {
|
||||
owner_theme = owner_c->get_theme();
|
||||
}
|
||||
Window *owner_w = Object::cast_to<Window>(owner_node);
|
||||
if (owner_w) {
|
||||
owner_theme = owner_w->get_theme();
|
||||
}
|
||||
|
||||
if (owner_theme.is_valid() && owner_theme->has_default_font()) {
|
||||
return owner_theme->get_default_font();
|
||||
}
|
||||
|
||||
owner_node = _get_next_owner_node(owner_node);
|
||||
}
|
||||
|
||||
// Secondly, check the project-defined Theme resource.
|
||||
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 (ThemeDB::get_singleton()->get_default_theme()->has_default_font()) {
|
||||
return ThemeDB::get_singleton()->get_default_theme()->get_default_font();
|
||||
}
|
||||
return ThemeDB::get_singleton()->get_fallback_font();
|
||||
}
|
||||
|
||||
int ThemeOwner::get_theme_default_font_size() {
|
||||
// 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.
|
||||
Node *owner_node = get_owner_node();
|
||||
|
||||
while (owner_node) {
|
||||
Ref<Theme> owner_theme;
|
||||
|
||||
Control *owner_c = Object::cast_to<Control>(owner_node);
|
||||
if (owner_c) {
|
||||
owner_theme = owner_c->get_theme();
|
||||
}
|
||||
Window *owner_w = Object::cast_to<Window>(owner_node);
|
||||
if (owner_w) {
|
||||
owner_theme = owner_w->get_theme();
|
||||
}
|
||||
|
||||
if (owner_theme.is_valid() && owner_theme->has_default_font_size()) {
|
||||
return owner_theme->get_default_font_size();
|
||||
}
|
||||
|
||||
owner_node = _get_next_owner_node(owner_node);
|
||||
}
|
||||
|
||||
// Secondly, check the project-defined Theme resource.
|
||||
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 (ThemeDB::get_singleton()->get_default_theme()->has_default_font_size()) {
|
||||
return ThemeDB::get_singleton()->get_default_theme()->get_default_font_size();
|
||||
}
|
||||
return ThemeDB::get_singleton()->get_fallback_font_size();
|
||||
}
|
75
scene/theme/theme_owner.h
Normal file
75
scene/theme/theme_owner.h
Normal file
@ -0,0 +1,75 @@
|
||||
/*************************************************************************/
|
||||
/* theme_owner.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_OWNER_H
|
||||
#define THEME_OWNER_H
|
||||
|
||||
#include "core/object/object.h"
|
||||
#include "scene/resources/theme.h"
|
||||
|
||||
class Control;
|
||||
class Node;
|
||||
class Window;
|
||||
|
||||
class ThemeOwner : public Object {
|
||||
Control *owner_control = nullptr;
|
||||
Window *owner_window = nullptr;
|
||||
|
||||
Node *_get_next_owner_node(Node *p_from_node) const;
|
||||
|
||||
public:
|
||||
// Theme owner node.
|
||||
|
||||
void set_owner_node(Node *p_node);
|
||||
Node *get_owner_node() const;
|
||||
bool has_owner_node() const;
|
||||
|
||||
// Theme propagation.
|
||||
|
||||
void assign_theme_on_parented(Node *p_for_node);
|
||||
void clear_theme_on_unparented(Node *p_for_node);
|
||||
void propagate_theme_changed(Node *p_to_node, Node *p_owner_node, bool p_notify, bool p_assign);
|
||||
|
||||
// Theme lookup.
|
||||
|
||||
void get_theme_type_dependencies(const Node *p_for_node, const StringName &p_theme_type, List<StringName> *r_list) const;
|
||||
|
||||
Variant get_theme_item_in_types(Theme::DataType p_data_type, const StringName &p_name, List<StringName> p_theme_types);
|
||||
bool has_theme_item_in_types(Theme::DataType p_data_type, const StringName &p_name, List<StringName> p_theme_types);
|
||||
|
||||
float get_theme_default_base_scale();
|
||||
Ref<Font> get_theme_default_font();
|
||||
int get_theme_default_font_size();
|
||||
|
||||
ThemeOwner() {}
|
||||
~ThemeOwner() {}
|
||||
};
|
||||
|
||||
#endif // THEME_OWNER_H
|
Loading…
Reference in New Issue
Block a user