diff options
Diffstat (limited to 'scene/resources/theme.cpp')
-rw-r--r-- | scene/resources/theme.cpp | 948 |
1 files changed, 507 insertions, 441 deletions
diff --git a/scene/resources/theme.cpp b/scene/resources/theme.cpp index e49d883ba4..99977a20f2 100644 --- a/scene/resources/theme.cpp +++ b/scene/resources/theme.cpp @@ -29,270 +29,20 @@ /*************************************************************************/ #include "theme.h" -#include "core/io/file_access.h" #include "core/string/print_string.h" -void Theme::_emit_theme_changed() { - if (no_change_propagation) { - return; - } - - notify_property_list_changed(); - emit_changed(); -} - -Vector<String> Theme::_get_icon_list(const String &p_theme_type) const { - Vector<String> ilret; - List<StringName> il; - - get_icon_list(p_theme_type, &il); - ilret.resize(il.size()); - - int i = 0; - String *w = ilret.ptrw(); - for (List<StringName>::Element *E = il.front(); E; E = E->next(), i++) { - w[i] = E->get(); - } - return ilret; -} - -Vector<String> Theme::_get_icon_type_list() const { - Vector<String> ilret; - List<StringName> il; - - get_icon_type_list(&il); - ilret.resize(il.size()); - - int i = 0; - String *w = ilret.ptrw(); - for (List<StringName>::Element *E = il.front(); E; E = E->next(), i++) { - w[i] = E->get(); - } - return ilret; -} - -Vector<String> Theme::_get_stylebox_list(const String &p_theme_type) const { - Vector<String> ilret; - List<StringName> il; - - get_stylebox_list(p_theme_type, &il); - ilret.resize(il.size()); - - int i = 0; - String *w = ilret.ptrw(); - for (List<StringName>::Element *E = il.front(); E; E = E->next(), i++) { - w[i] = E->get(); - } - return ilret; -} - -Vector<String> Theme::_get_stylebox_type_list() const { - Vector<String> ilret; - List<StringName> il; - - get_stylebox_type_list(&il); - ilret.resize(il.size()); - - int i = 0; - String *w = ilret.ptrw(); - for (List<StringName>::Element *E = il.front(); E; E = E->next(), i++) { - w[i] = E->get(); - } - return ilret; -} - -Vector<String> Theme::_get_font_list(const String &p_theme_type) const { - Vector<String> ilret; - List<StringName> il; - - get_font_list(p_theme_type, &il); - ilret.resize(il.size()); - - int i = 0; - String *w = ilret.ptrw(); - for (List<StringName>::Element *E = il.front(); E; E = E->next(), i++) { - w[i] = E->get(); - } - return ilret; -} - -Vector<String> Theme::_get_font_type_list() const { - Vector<String> ilret; - List<StringName> il; - - get_font_type_list(&il); - ilret.resize(il.size()); - - int i = 0; - String *w = ilret.ptrw(); - for (List<StringName>::Element *E = il.front(); E; E = E->next(), i++) { - w[i] = E->get(); - } - return ilret; -} - -Vector<String> Theme::_get_font_size_list(const String &p_theme_type) const { - Vector<String> ilret; - List<StringName> il; - - get_font_size_list(p_theme_type, &il); - ilret.resize(il.size()); - - int i = 0; - String *w = ilret.ptrw(); - for (List<StringName>::Element *E = il.front(); E; E = E->next(), i++) { - w[i] = E->get(); - } - return ilret; -} - -Vector<String> Theme::_get_font_size_type_list() const { - Vector<String> ilret; - List<StringName> il; - - get_font_size_type_list(&il); - ilret.resize(il.size()); - - int i = 0; - String *w = ilret.ptrw(); - for (List<StringName>::Element *E = il.front(); E; E = E->next(), i++) { - w[i] = E->get(); - } - return ilret; -} - -Vector<String> Theme::_get_color_list(const String &p_theme_type) const { - Vector<String> ilret; - List<StringName> il; - - get_color_list(p_theme_type, &il); - ilret.resize(il.size()); - - int i = 0; - String *w = ilret.ptrw(); - for (List<StringName>::Element *E = il.front(); E; E = E->next(), i++) { - w[i] = E->get(); - } - return ilret; -} - -Vector<String> Theme::_get_color_type_list() const { - Vector<String> ilret; - List<StringName> il; - - get_color_type_list(&il); - ilret.resize(il.size()); - - int i = 0; - String *w = ilret.ptrw(); - for (List<StringName>::Element *E = il.front(); E; E = E->next(), i++) { - w[i] = E->get(); - } - return ilret; -} - -Vector<String> Theme::_get_constant_list(const String &p_theme_type) const { - Vector<String> ilret; - List<StringName> il; - - get_constant_list(p_theme_type, &il); - ilret.resize(il.size()); - - int i = 0; - String *w = ilret.ptrw(); - for (List<StringName>::Element *E = il.front(); E; E = E->next(), i++) { - w[i] = E->get(); - } - return ilret; -} - -Vector<String> Theme::_get_constant_type_list() const { - Vector<String> ilret; - List<StringName> il; - - get_constant_type_list(&il); - ilret.resize(il.size()); - - int i = 0; - String *w = ilret.ptrw(); - for (List<StringName>::Element *E = il.front(); E; E = E->next(), i++) { - w[i] = E->get(); - } - return ilret; -} - -Vector<String> Theme::_get_theme_item_list(DataType p_data_type, const String &p_theme_type) const { - switch (p_data_type) { - case DATA_TYPE_COLOR: - return _get_color_list(p_theme_type); - case DATA_TYPE_CONSTANT: - return _get_constant_list(p_theme_type); - case DATA_TYPE_FONT: - return _get_font_list(p_theme_type); - case DATA_TYPE_FONT_SIZE: - return _get_font_size_list(p_theme_type); - case DATA_TYPE_ICON: - return _get_icon_list(p_theme_type); - case DATA_TYPE_STYLEBOX: - return _get_stylebox_list(p_theme_type); - case DATA_TYPE_MAX: - break; // Can't happen, but silences warning. - } - - return Vector<String>(); -} - -Vector<String> Theme::_get_theme_item_type_list(DataType p_data_type) const { - switch (p_data_type) { - case DATA_TYPE_COLOR: - return _get_color_type_list(); - case DATA_TYPE_CONSTANT: - return _get_constant_type_list(); - case DATA_TYPE_FONT: - return _get_font_type_list(); - case DATA_TYPE_FONT_SIZE: - return _get_font_size_type_list(); - case DATA_TYPE_ICON: - return _get_icon_type_list(); - case DATA_TYPE_STYLEBOX: - return _get_stylebox_type_list(); - case DATA_TYPE_MAX: - break; // Can't happen, but silences warning. - } - - return Vector<String>(); -} - -Vector<String> Theme::_get_type_variation_list(const StringName &p_theme_type) const { - Vector<String> ilret; - List<StringName> il; - - get_type_variation_list(p_theme_type, &il); - ilret.resize(il.size()); - - int i = 0; - String *w = ilret.ptrw(); - for (List<StringName>::Element *E = il.front(); E; E = E->next(), i++) { - w[i] = E->get(); - } - return ilret; -} - -Vector<String> Theme::_get_type_list() const { - Vector<String> ilret; - List<StringName> il; - - get_type_list(&il); - ilret.resize(il.size()); +// Universal Theme resources used when no other theme has the item. +Ref<Theme> Theme::default_theme; +Ref<Theme> Theme::project_default_theme; - int i = 0; - String *w = ilret.ptrw(); - for (List<StringName>::Element *E = il.front(); E; E = E->next(), i++) { - w[i] = E->get(); - } - return ilret; -} +// Universal default values, final fallback for every theme. +float Theme::default_base_scale = 1.0; +Ref<Texture2D> Theme::default_icon; +Ref<StyleBox> Theme::default_style; +Ref<Font> Theme::default_font; +int Theme::default_font_size = 16; +// Dynamic properties. bool Theme::_set(const StringName &p_name, const Variant &p_value) { String sname = p_name; @@ -419,7 +169,7 @@ void Theme::_get_property_list(List<PropertyInfo> *p_list) const { const StringName *key2 = nullptr; while ((key2 = font_size_map[*key].next(key2))) { - list.push_back(PropertyInfo(Variant::INT, String() + *key + "/font_sizes/" + *key2)); + list.push_back(PropertyInfo(Variant::INT, String() + *key + "/font_sizes/" + *key2, PROPERTY_HINT_RANGE, "0,256,1,or_greater")); } } @@ -452,6 +202,63 @@ void Theme::_get_property_list(List<PropertyInfo> *p_list) const { } } +// Universal fallback Theme resources. +Ref<Theme> Theme::get_default() { + return default_theme; +} + +void Theme::set_default(const Ref<Theme> &p_default) { + default_theme = p_default; +} + +Ref<Theme> Theme::get_project_default() { + return project_default_theme; +} + +void Theme::set_project_default(const Ref<Theme> &p_project_default) { + project_default_theme = 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<Texture2D> &p_icon) { + default_icon = p_icon; +} + +void Theme::set_default_style(const Ref<StyleBox> &p_style) { + default_style = p_style; +} + +void Theme::set_default_font(const Ref<Font> &p_font) { + default_font = p_font; +} + +void Theme::set_default_font_size(int p_font_size) { + default_font_size = 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<Font> &p_default_font) { if (default_theme_font == p_default_font) { return; @@ -464,7 +271,7 @@ void Theme::set_default_theme_font(const Ref<Font> &p_default_font) { default_theme_font = p_default_font; if (default_theme_font.is_valid()) { - default_theme_font->connect("changed", callable_mp(this, &Theme::_emit_theme_changed), varray(), CONNECT_REFERENCE_COUNTED); + default_theme_font->connect("changed", callable_mp(this, &Theme::_emit_theme_changed), varray(false), CONNECT_REFERENCE_COUNTED); } _emit_theme_changed(); @@ -474,6 +281,10 @@ Ref<Font> 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; @@ -488,57 +299,25 @@ int Theme::get_default_theme_font_size() const { return default_theme_font_size; } -Ref<Theme> Theme::project_default_theme; -Ref<Theme> Theme::default_theme; -Ref<Texture2D> Theme::default_icon; -Ref<StyleBox> Theme::default_style; -Ref<Font> Theme::default_font; -int Theme::default_font_size = 16; - -Ref<Theme> Theme::get_default() { - return default_theme; -} - -void Theme::set_default(const Ref<Theme> &p_default) { - default_theme = p_default; -} - -Ref<Theme> Theme::get_project_default() { - return project_default_theme; -} - -void Theme::set_project_default(const Ref<Theme> &p_project_default) { - project_default_theme = p_project_default; -} - -void Theme::set_default_icon(const Ref<Texture2D> &p_icon) { - default_icon = p_icon; -} - -void Theme::set_default_style(const Ref<StyleBox> &p_style) { - default_style = p_style; -} - -void Theme::set_default_font(const Ref<Font> &p_font) { - default_font = p_font; -} - -void Theme::set_default_font_size(int p_font_size) { - default_font_size = p_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<Texture2D> &p_icon) { + bool existing = false; if (icon_map[p_theme_type].has(p_name) && icon_map[p_theme_type][p_name].is_valid()) { + existing = true; icon_map[p_theme_type][p_name]->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed)); } icon_map[p_theme_type][p_name] = p_icon; if (p_icon.is_valid()) { - icon_map[p_theme_type][p_name]->connect("changed", callable_mp(this, &Theme::_emit_theme_changed), varray(), CONNECT_REFERENCE_COUNTED); + icon_map[p_theme_type][p_name]->connect("changed", callable_mp(this, &Theme::_emit_theme_changed), varray(false), CONNECT_REFERENCE_COUNTED); } - _emit_theme_changed(); + _emit_theme_changed(!existing); } Ref<Texture2D> Theme::get_icon(const StringName &p_name, const StringName &p_theme_type) const { @@ -565,7 +344,7 @@ void Theme::rename_icon(const StringName &p_old_name, const StringName &p_name, icon_map[p_theme_type][p_name] = icon_map[p_theme_type][p_old_name]; icon_map[p_theme_type].erase(p_old_name); - _emit_theme_changed(); + _emit_theme_changed(true); } void Theme::clear_icon(const StringName &p_name, const StringName &p_theme_type) { @@ -578,7 +357,7 @@ void Theme::clear_icon(const StringName &p_name, const StringName &p_theme_type) icon_map[p_theme_type].erase(p_name); - _emit_theme_changed(); + _emit_theme_changed(true); } void Theme::get_icon_list(StringName p_theme_type, List<StringName> *p_list) const { @@ -611,18 +390,21 @@ void Theme::get_icon_type_list(List<StringName> *p_list) const { } } +// Styleboxes. void Theme::set_stylebox(const StringName &p_name, const StringName &p_theme_type, const Ref<StyleBox> &p_style) { + bool existing = false; if (style_map[p_theme_type].has(p_name) && style_map[p_theme_type][p_name].is_valid()) { + existing = true; style_map[p_theme_type][p_name]->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed)); } style_map[p_theme_type][p_name] = p_style; if (p_style.is_valid()) { - style_map[p_theme_type][p_name]->connect("changed", callable_mp(this, &Theme::_emit_theme_changed), varray(), CONNECT_REFERENCE_COUNTED); + style_map[p_theme_type][p_name]->connect("changed", callable_mp(this, &Theme::_emit_theme_changed), varray(false), CONNECT_REFERENCE_COUNTED); } - _emit_theme_changed(); + _emit_theme_changed(!existing); } Ref<StyleBox> Theme::get_stylebox(const StringName &p_name, const StringName &p_theme_type) const { @@ -649,7 +431,7 @@ void Theme::rename_stylebox(const StringName &p_old_name, const StringName &p_na style_map[p_theme_type][p_name] = style_map[p_theme_type][p_old_name]; style_map[p_theme_type].erase(p_old_name); - _emit_theme_changed(); + _emit_theme_changed(true); } void Theme::clear_stylebox(const StringName &p_name, const StringName &p_theme_type) { @@ -662,7 +444,7 @@ void Theme::clear_stylebox(const StringName &p_name, const StringName &p_theme_t style_map[p_theme_type].erase(p_name); - _emit_theme_changed(); + _emit_theme_changed(true); } void Theme::get_stylebox_list(StringName p_theme_type, List<StringName> *p_list) const { @@ -695,24 +477,27 @@ void Theme::get_stylebox_type_list(List<StringName> *p_list) const { } } +// Fonts. void Theme::set_font(const StringName &p_name, const StringName &p_theme_type, const Ref<Font> &p_font) { + bool existing = false; if (font_map[p_theme_type][p_name].is_valid()) { + existing = true; font_map[p_theme_type][p_name]->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed)); } font_map[p_theme_type][p_name] = p_font; if (p_font.is_valid()) { - font_map[p_theme_type][p_name]->connect("changed", callable_mp(this, &Theme::_emit_theme_changed), varray(), CONNECT_REFERENCE_COUNTED); + font_map[p_theme_type][p_name]->connect("changed", callable_mp(this, &Theme::_emit_theme_changed), varray(false), CONNECT_REFERENCE_COUNTED); } - _emit_theme_changed(); + _emit_theme_changed(!existing); } Ref<Font> 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; @@ -720,7 +505,7 @@ Ref<Font> 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 { @@ -735,7 +520,7 @@ void Theme::rename_font(const StringName &p_old_name, const StringName &p_name, font_map[p_theme_type][p_name] = font_map[p_theme_type][p_old_name]; font_map[p_theme_type].erase(p_old_name); - _emit_theme_changed(); + _emit_theme_changed(true); } void Theme::clear_font(const StringName &p_name, const StringName &p_theme_type) { @@ -748,7 +533,7 @@ void Theme::clear_font(const StringName &p_name, const StringName &p_theme_type) font_map[p_theme_type].erase(p_name); - _emit_theme_changed(); + _emit_theme_changed(true); } void Theme::get_font_list(StringName p_theme_type, List<StringName> *p_list) const { @@ -781,16 +566,18 @@ void Theme::get_font_type_list(List<StringName> *p_list) const { } } +// Font sizes. void Theme::set_font_size(const StringName &p_name, const StringName &p_theme_type, int p_font_size) { + bool existing = has_font_size_nocheck(p_name, p_theme_type); font_size_map[p_theme_type][p_name] = p_font_size; - _emit_theme_changed(); + _emit_theme_changed(!existing); } 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; @@ -798,7 +585,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 { @@ -813,7 +600,7 @@ void Theme::rename_font_size(const StringName &p_old_name, const StringName &p_n font_size_map[p_theme_type][p_name] = font_size_map[p_theme_type][p_old_name]; font_size_map[p_theme_type].erase(p_old_name); - _emit_theme_changed(); + _emit_theme_changed(true); } void Theme::clear_font_size(const StringName &p_name, const StringName &p_theme_type) { @@ -822,7 +609,7 @@ void Theme::clear_font_size(const StringName &p_name, const StringName &p_theme_ font_size_map[p_theme_type].erase(p_name); - _emit_theme_changed(); + _emit_theme_changed(true); } void Theme::get_font_size_list(StringName p_theme_type, List<StringName> *p_list) const { @@ -855,10 +642,12 @@ void Theme::get_font_size_type_list(List<StringName> *p_list) const { } } +// Colors. void Theme::set_color(const StringName &p_name, const StringName &p_theme_type, const Color &p_color) { + bool existing = has_color_nocheck(p_name, p_theme_type); color_map[p_theme_type][p_name] = p_color; - _emit_theme_changed(); + _emit_theme_changed(!existing); } Color Theme::get_color(const StringName &p_name, const StringName &p_theme_type) const { @@ -885,7 +674,7 @@ void Theme::rename_color(const StringName &p_old_name, const StringName &p_name, color_map[p_theme_type][p_name] = color_map[p_theme_type][p_old_name]; color_map[p_theme_type].erase(p_old_name); - _emit_theme_changed(); + _emit_theme_changed(true); } void Theme::clear_color(const StringName &p_name, const StringName &p_theme_type) { @@ -894,7 +683,7 @@ void Theme::clear_color(const StringName &p_name, const StringName &p_theme_type color_map[p_theme_type].erase(p_name); - _emit_theme_changed(); + _emit_theme_changed(true); } void Theme::get_color_list(StringName p_theme_type, List<StringName> *p_list) const { @@ -927,10 +716,12 @@ void Theme::get_color_type_list(List<StringName> *p_list) const { } } +// Theme constants. void Theme::set_constant(const StringName &p_name, const StringName &p_theme_type, int p_constant) { + bool existing = has_constant_nocheck(p_name, p_theme_type); constant_map[p_theme_type][p_name] = p_constant; - _emit_theme_changed(); + _emit_theme_changed(!existing); } int Theme::get_constant(const StringName &p_name, const StringName &p_theme_type) const { @@ -957,7 +748,7 @@ void Theme::rename_constant(const StringName &p_old_name, const StringName &p_na constant_map[p_theme_type][p_name] = constant_map[p_theme_type][p_old_name]; constant_map[p_theme_type].erase(p_old_name); - _emit_theme_changed(); + _emit_theme_changed(true); } void Theme::clear_constant(const StringName &p_name, const StringName &p_theme_type) { @@ -966,7 +757,7 @@ void Theme::clear_constant(const StringName &p_name, const StringName &p_theme_t constant_map[p_theme_type].erase(p_name); - _emit_theme_changed(); + _emit_theme_changed(true); } void Theme::get_constant_list(StringName p_theme_type, List<StringName> *p_list) const { @@ -999,6 +790,7 @@ void Theme::get_constant_type_list(List<StringName> *p_list) const { } } +// Generic methods for managing theme items. void Theme::set_theme_item(DataType p_data_type, const StringName &p_name, const StringName &p_theme_type, const Variant &p_value) { switch (p_data_type) { case DATA_TYPE_COLOR: { @@ -1230,6 +1022,7 @@ void Theme::get_theme_item_type_list(DataType p_data_type, List<StringName> *p_l } } +// Theme type variations. void Theme::set_type_variation(const StringName &p_theme_type, const StringName &p_base_type) { ERR_FAIL_COND_MSG(p_theme_type == StringName(), "An empty theme type cannot be marked as a variation of another type."); ERR_FAIL_COND_MSG(ClassDB::class_exists(p_theme_type), "A type associated with a built-in class cannot be marked as a variation of another type."); @@ -1243,7 +1036,7 @@ void Theme::set_type_variation(const StringName &p_theme_type, const StringName variation_map[p_theme_type] = p_base_type; variation_base_map[p_base_type].push_back(p_theme_type); - _emit_theme_changed(); + _emit_theme_changed(true); } bool Theme::is_type_variation(const StringName &p_theme_type, const StringName &p_base_type) const { @@ -1257,7 +1050,7 @@ void Theme::clear_type_variation(const StringName &p_theme_type) { variation_base_map[base_type].erase(p_theme_type); variation_map.erase(p_theme_type); - _emit_theme_changed(); + _emit_theme_changed(true); } StringName Theme::get_type_variation_base(const StringName &p_theme_type) const { @@ -1287,67 +1080,355 @@ void Theme::get_type_variation_list(const StringName &p_base_type, List<StringNa } } -void Theme::_freeze_change_propagation() { - no_change_propagation = true; -} +// Theme types. +void Theme::get_type_list(List<StringName> *p_list) const { + ERR_FAIL_NULL(p_list); -void Theme::_unfreeze_and_propagate_changes() { - no_change_propagation = false; - _emit_theme_changed(); + Set<StringName> types; + const StringName *key = nullptr; + + // Icons. + while ((key = icon_map.next(key))) { + types.insert(*key); + } + + key = nullptr; + + // StyleBoxes. + while ((key = style_map.next(key))) { + types.insert(*key); + } + + key = nullptr; + + // Fonts. + while ((key = font_map.next(key))) { + types.insert(*key); + } + + key = nullptr; + + // Font sizes. + while ((key = font_size_map.next(key))) { + types.insert(*key); + } + + key = nullptr; + + // Colors. + while ((key = color_map.next(key))) { + types.insert(*key); + } + + key = nullptr; + + // Constants. + while ((key = constant_map.next(key))) { + types.insert(*key); + } + + for (Set<StringName>::Element *E = types.front(); E; E = E->next()) { + p_list->push_back(E->get()); + } } -void Theme::clear() { - // These items need disconnecting. - { - const StringName *K = nullptr; - while ((K = icon_map.next(K))) { - const StringName *L = nullptr; - while ((L = icon_map[*K].next(L))) { - Ref<Texture2D> icon = icon_map[*K][*L]; - if (icon.is_valid()) { - icon->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed)); - } +void Theme::get_type_dependencies(const StringName &p_base_type, const StringName &p_type_variation, List<StringName> *p_list) { + ERR_FAIL_NULL(p_list); + + // Build the dependency chain for type variations. + if (p_type_variation != StringName()) { + StringName variation_name = p_type_variation; + while (variation_name != StringName()) { + p_list->push_back(variation_name); + variation_name = get_type_variation_base(variation_name); + + // If we have reached the base type dependency, it's safe to stop (assuming no funny business was done to the Theme). + if (variation_name == p_base_type) { + break; } } } - { - const StringName *K = nullptr; - while ((K = style_map.next(K))) { - const StringName *L = nullptr; - while ((L = style_map[*K].next(L))) { - Ref<StyleBox> style = style_map[*K][*L]; - if (style.is_valid()) { - style->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed)); - } - } - } + // Continue building the chain using native class hierarchy. + StringName class_name = p_base_type; + while (class_name != StringName()) { + p_list->push_back(class_name); + class_name = ClassDB::get_parent_class_nocheck(class_name); } +} - { - const StringName *K = nullptr; - while ((K = font_map.next(K))) { - const StringName *L = nullptr; - while ((L = font_map[*K].next(L))) { - Ref<Font> font = font_map[*K][*L]; - if (font.is_valid()) { - font->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed)); - } - } - } +// Internal methods for getting lists as a Vector of String (compatible with public API). +Vector<String> Theme::_get_icon_list(const String &p_theme_type) const { + Vector<String> ilret; + List<StringName> il; + + get_icon_list(p_theme_type, &il); + ilret.resize(il.size()); + + int i = 0; + String *w = ilret.ptrw(); + for (List<StringName>::Element *E = il.front(); E; E = E->next(), i++) { + w[i] = E->get(); } + return ilret; +} - icon_map.clear(); - style_map.clear(); - font_map.clear(); - font_size_map.clear(); - color_map.clear(); - constant_map.clear(); +Vector<String> Theme::_get_icon_type_list() const { + Vector<String> ilret; + List<StringName> il; - variation_map.clear(); - variation_base_map.clear(); + get_icon_type_list(&il); + ilret.resize(il.size()); - _emit_theme_changed(); + int i = 0; + String *w = ilret.ptrw(); + for (List<StringName>::Element *E = il.front(); E; E = E->next(), i++) { + w[i] = E->get(); + } + return ilret; +} + +Vector<String> Theme::_get_stylebox_list(const String &p_theme_type) const { + Vector<String> ilret; + List<StringName> il; + + get_stylebox_list(p_theme_type, &il); + ilret.resize(il.size()); + + int i = 0; + String *w = ilret.ptrw(); + for (List<StringName>::Element *E = il.front(); E; E = E->next(), i++) { + w[i] = E->get(); + } + return ilret; +} + +Vector<String> Theme::_get_stylebox_type_list() const { + Vector<String> ilret; + List<StringName> il; + + get_stylebox_type_list(&il); + ilret.resize(il.size()); + + int i = 0; + String *w = ilret.ptrw(); + for (List<StringName>::Element *E = il.front(); E; E = E->next(), i++) { + w[i] = E->get(); + } + return ilret; +} + +Vector<String> Theme::_get_font_list(const String &p_theme_type) const { + Vector<String> ilret; + List<StringName> il; + + get_font_list(p_theme_type, &il); + ilret.resize(il.size()); + + int i = 0; + String *w = ilret.ptrw(); + for (List<StringName>::Element *E = il.front(); E; E = E->next(), i++) { + w[i] = E->get(); + } + return ilret; +} + +Vector<String> Theme::_get_font_type_list() const { + Vector<String> ilret; + List<StringName> il; + + get_font_type_list(&il); + ilret.resize(il.size()); + + int i = 0; + String *w = ilret.ptrw(); + for (List<StringName>::Element *E = il.front(); E; E = E->next(), i++) { + w[i] = E->get(); + } + return ilret; +} + +Vector<String> Theme::_get_font_size_list(const String &p_theme_type) const { + Vector<String> ilret; + List<StringName> il; + + get_font_size_list(p_theme_type, &il); + ilret.resize(il.size()); + + int i = 0; + String *w = ilret.ptrw(); + for (List<StringName>::Element *E = il.front(); E; E = E->next(), i++) { + w[i] = E->get(); + } + return ilret; +} + +Vector<String> Theme::_get_font_size_type_list() const { + Vector<String> ilret; + List<StringName> il; + + get_font_size_type_list(&il); + ilret.resize(il.size()); + + int i = 0; + String *w = ilret.ptrw(); + for (List<StringName>::Element *E = il.front(); E; E = E->next(), i++) { + w[i] = E->get(); + } + return ilret; +} + +Vector<String> Theme::_get_color_list(const String &p_theme_type) const { + Vector<String> ilret; + List<StringName> il; + + get_color_list(p_theme_type, &il); + ilret.resize(il.size()); + + int i = 0; + String *w = ilret.ptrw(); + for (List<StringName>::Element *E = il.front(); E; E = E->next(), i++) { + w[i] = E->get(); + } + return ilret; +} + +Vector<String> Theme::_get_color_type_list() const { + Vector<String> ilret; + List<StringName> il; + + get_color_type_list(&il); + ilret.resize(il.size()); + + int i = 0; + String *w = ilret.ptrw(); + for (List<StringName>::Element *E = il.front(); E; E = E->next(), i++) { + w[i] = E->get(); + } + return ilret; +} + +Vector<String> Theme::_get_constant_list(const String &p_theme_type) const { + Vector<String> ilret; + List<StringName> il; + + get_constant_list(p_theme_type, &il); + ilret.resize(il.size()); + + int i = 0; + String *w = ilret.ptrw(); + for (List<StringName>::Element *E = il.front(); E; E = E->next(), i++) { + w[i] = E->get(); + } + return ilret; +} + +Vector<String> Theme::_get_constant_type_list() const { + Vector<String> ilret; + List<StringName> il; + + get_constant_type_list(&il); + ilret.resize(il.size()); + + int i = 0; + String *w = ilret.ptrw(); + for (List<StringName>::Element *E = il.front(); E; E = E->next(), i++) { + w[i] = E->get(); + } + return ilret; +} + +Vector<String> Theme::_get_theme_item_list(DataType p_data_type, const String &p_theme_type) const { + switch (p_data_type) { + case DATA_TYPE_COLOR: + return _get_color_list(p_theme_type); + case DATA_TYPE_CONSTANT: + return _get_constant_list(p_theme_type); + case DATA_TYPE_FONT: + return _get_font_list(p_theme_type); + case DATA_TYPE_FONT_SIZE: + return _get_font_size_list(p_theme_type); + case DATA_TYPE_ICON: + return _get_icon_list(p_theme_type); + case DATA_TYPE_STYLEBOX: + return _get_stylebox_list(p_theme_type); + case DATA_TYPE_MAX: + break; // Can't happen, but silences warning. + } + + return Vector<String>(); +} + +Vector<String> Theme::_get_theme_item_type_list(DataType p_data_type) const { + switch (p_data_type) { + case DATA_TYPE_COLOR: + return _get_color_type_list(); + case DATA_TYPE_CONSTANT: + return _get_constant_type_list(); + case DATA_TYPE_FONT: + return _get_font_type_list(); + case DATA_TYPE_FONT_SIZE: + return _get_font_size_type_list(); + case DATA_TYPE_ICON: + return _get_icon_type_list(); + case DATA_TYPE_STYLEBOX: + return _get_stylebox_type_list(); + case DATA_TYPE_MAX: + break; // Can't happen, but silences warning. + } + + return Vector<String>(); +} + +Vector<String> Theme::_get_type_variation_list(const StringName &p_theme_type) const { + Vector<String> ilret; + List<StringName> il; + + get_type_variation_list(p_theme_type, &il); + ilret.resize(il.size()); + + int i = 0; + String *w = ilret.ptrw(); + for (List<StringName>::Element *E = il.front(); E; E = E->next(), i++) { + w[i] = E->get(); + } + return ilret; +} + +Vector<String> Theme::_get_type_list() const { + Vector<String> ilret; + List<StringName> il; + + get_type_list(&il); + ilret.resize(il.size()); + + int i = 0; + String *w = ilret.ptrw(); + for (List<StringName>::Element *E = il.front(); E; E = E->next(), i++) { + w[i] = E->get(); + } + return ilret; +} + +// Theme bulk manipulations. +void Theme::_emit_theme_changed(bool p_notify_list_changed) { + if (no_change_propagation) { + return; + } + + if (p_notify_list_changed) { + notify_property_list_changed(); + } + emit_changed(); +} + +void Theme::_freeze_change_propagation() { + no_change_propagation = true; +} + +void Theme::_unfreeze_and_propagate_changes() { + no_change_propagation = false; + _emit_theme_changed(true); } void Theme::merge_with(const Ref<Theme> &p_other) { @@ -1434,80 +1515,58 @@ void Theme::merge_with(const Ref<Theme> &p_other) { _unfreeze_and_propagate_changes(); } -void Theme::get_type_list(List<StringName> *p_list) const { - ERR_FAIL_NULL(p_list); - - Set<StringName> types; - const StringName *key = nullptr; - - // Icons. - while ((key = icon_map.next(key))) { - types.insert(*key); - } - - key = nullptr; - - // StyleBoxes. - while ((key = style_map.next(key))) { - types.insert(*key); - } - - key = nullptr; - - // Fonts. - while ((key = font_map.next(key))) { - types.insert(*key); - } - - key = nullptr; - - // Font sizes. - while ((key = font_size_map.next(key))) { - types.insert(*key); - } - - key = nullptr; - - // Colors. - while ((key = color_map.next(key))) { - types.insert(*key); - } - - key = nullptr; - - // Constants. - while ((key = constant_map.next(key))) { - types.insert(*key); +void Theme::clear() { + // These items need disconnecting. + { + const StringName *K = nullptr; + while ((K = icon_map.next(K))) { + const StringName *L = nullptr; + while ((L = icon_map[*K].next(L))) { + Ref<Texture2D> icon = icon_map[*K][*L]; + if (icon.is_valid()) { + icon->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed)); + } + } + } } - for (Set<StringName>::Element *E = types.front(); E; E = E->next()) { - p_list->push_back(E->get()); + { + const StringName *K = nullptr; + while ((K = style_map.next(K))) { + const StringName *L = nullptr; + while ((L = style_map[*K].next(L))) { + Ref<StyleBox> style = style_map[*K][*L]; + if (style.is_valid()) { + style->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed)); + } + } + } } -} -void Theme::get_type_dependencies(const StringName &p_base_type, const StringName &p_type_variation, List<StringName> *p_list) { - ERR_FAIL_NULL(p_list); - - // Build the dependency chain for type variations. - if (p_type_variation != StringName()) { - StringName variation_name = p_type_variation; - while (variation_name != StringName()) { - p_list->push_back(variation_name); - variation_name = get_type_variation_base(variation_name); - - // If we have reached the base type dependency, it's safe to stop (assuming no funny business was done to the Theme). - if (variation_name == p_base_type) { - break; + { + const StringName *K = nullptr; + while ((K = font_map.next(K))) { + const StringName *L = nullptr; + while ((L = font_map[*K].next(L))) { + Ref<Font> font = font_map[*K][*L]; + if (font.is_valid()) { + font->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed)); + } } } } - // Continue building the chain using native class hierarchy. - StringName class_name = p_base_type; - while (class_name != StringName()) { - p_list->push_back(class_name); - class_name = ClassDB::get_parent_class_nocheck(class_name); - } + icon_map.clear(); + style_map.clear(); + font_map.clear(); + font_size_map.clear(); + color_map.clear(); + constant_map.clear(); + + variation_map.clear(); + variation_base_map.clear(); + + _emit_theme_changed(true); } void Theme::reset_state() { @@ -1563,11 +1622,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); @@ -1588,8 +1653,9 @@ 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"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "default_font_size", PROPERTY_HINT_RANGE, "0,256,1,or_greater"), "set_default_font_size", "get_default_font_size"); BIND_ENUM_CONSTANT(DATA_TYPE_COLOR); BIND_ENUM_CONSTANT(DATA_TYPE_CONSTANT); |