From 8aa78bc0501a37d7c1e81f0954ac5bd9b49f890f Mon Sep 17 00:00:00 2001 From: Yuri Sizov Date: Sat, 2 Oct 2021 19:26:20 +0300 Subject: [PATCH 1/3] Reorganize Theme resource code for better maintainability --- scene/resources/theme.cpp | 2251 +++++++++++++++++++------------------ scene/resources/theme.h | 6 +- 2 files changed, 1139 insertions(+), 1118 deletions(-) diff --git a/scene/resources/theme.cpp b/scene/resources/theme.cpp index e49d883ba4e..dab08d48c2a 100644 --- a/scene/resources/theme.cpp +++ b/scene/resources/theme.cpp @@ -29,18 +29,1095 @@ /*************************************************************************/ #include "theme.h" -#include "core/io/file_access.h" #include "core/string/print_string.h" -void Theme::_emit_theme_changed() { - if (no_change_propagation) { +// Universal Theme resources used when no other theme has the item. +Ref Theme::default_theme; +Ref Theme::project_default_theme; + +// Universal default values, final fallback for every theme. +Ref Theme::default_icon; +Ref Theme::default_style; +Ref 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; + + if (sname.find("/") != -1) { + String type = sname.get_slicec('/', 1); + String theme_type = sname.get_slicec('/', 0); + String name = sname.get_slicec('/', 2); + + if (type == "icons") { + set_icon(name, theme_type, p_value); + } else if (type == "styles") { + set_stylebox(name, theme_type, p_value); + } else if (type == "fonts") { + set_font(name, theme_type, p_value); + } else if (type == "font_sizes") { + set_font_size(name, theme_type, p_value); + } else if (type == "colors") { + set_color(name, theme_type, p_value); + } else if (type == "constants") { + set_constant(name, theme_type, p_value); + } else if (type == "base_type") { + set_type_variation(theme_type, p_value); + } else { + return false; + } + + return true; + } + + return false; +} + +bool Theme::_get(const StringName &p_name, Variant &r_ret) const { + String sname = p_name; + + if (sname.find("/") != -1) { + String type = sname.get_slicec('/', 1); + String theme_type = sname.get_slicec('/', 0); + String name = sname.get_slicec('/', 2); + + if (type == "icons") { + if (!has_icon(name, theme_type)) { + r_ret = Ref(); + } else { + r_ret = get_icon(name, theme_type); + } + } else if (type == "styles") { + if (!has_stylebox(name, theme_type)) { + r_ret = Ref(); + } else { + r_ret = get_stylebox(name, theme_type); + } + } else if (type == "fonts") { + if (!has_font(name, theme_type)) { + r_ret = Ref(); + } else { + r_ret = get_font(name, theme_type); + } + } else if (type == "font_sizes") { + r_ret = get_font_size(name, theme_type); + } else if (type == "colors") { + r_ret = get_color(name, theme_type); + } else if (type == "constants") { + r_ret = get_constant(name, theme_type); + } else if (type == "base_type") { + r_ret = get_type_variation_base(theme_type); + } else { + return false; + } + + return true; + } + + return false; +} + +void Theme::_get_property_list(List *p_list) const { + List list; + + const StringName *key = nullptr; + + // Type variations. + while ((key = variation_map.next(key))) { + list.push_back(PropertyInfo(Variant::STRING_NAME, String() + *key + "/base_type")); + } + + key = nullptr; + + // Icons. + while ((key = icon_map.next(key))) { + const StringName *key2 = nullptr; + + while ((key2 = icon_map[*key].next(key2))) { + list.push_back(PropertyInfo(Variant::OBJECT, String() + *key + "/icons/" + *key2, PROPERTY_HINT_RESOURCE_TYPE, "Texture2D", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_STORE_IF_NULL)); + } + } + + key = nullptr; + + // Styles. + while ((key = style_map.next(key))) { + const StringName *key2 = nullptr; + + while ((key2 = style_map[*key].next(key2))) { + list.push_back(PropertyInfo(Variant::OBJECT, String() + *key + "/styles/" + *key2, PROPERTY_HINT_RESOURCE_TYPE, "StyleBox", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_STORE_IF_NULL)); + } + } + + key = nullptr; + + // Fonts. + while ((key = font_map.next(key))) { + const StringName *key2 = nullptr; + + while ((key2 = font_map[*key].next(key2))) { + list.push_back(PropertyInfo(Variant::OBJECT, String() + *key + "/fonts/" + *key2, PROPERTY_HINT_RESOURCE_TYPE, "Font", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_STORE_IF_NULL)); + } + } + + key = nullptr; + + // Font sizes. + while ((key = font_size_map.next(key))) { + const StringName *key2 = nullptr; + + while ((key2 = font_size_map[*key].next(key2))) { + list.push_back(PropertyInfo(Variant::INT, String() + *key + "/font_sizes/" + *key2)); + } + } + + key = nullptr; + + // Colors. + while ((key = color_map.next(key))) { + const StringName *key2 = nullptr; + + while ((key2 = color_map[*key].next(key2))) { + list.push_back(PropertyInfo(Variant::COLOR, String() + *key + "/colors/" + *key2)); + } + } + + key = nullptr; + + // Constants. + while ((key = constant_map.next(key))) { + const StringName *key2 = nullptr; + + while ((key2 = constant_map[*key].next(key2))) { + list.push_back(PropertyInfo(Variant::INT, String() + *key + "/constants/" + *key2)); + } + } + + // Sort and store properties. + list.sort(); + for (const PropertyInfo &E : list) { + p_list->push_back(E); + } +} + +// Universal fallback Theme resources. +Ref Theme::get_default() { + return default_theme; +} + +void Theme::set_default(const Ref &p_default) { + default_theme = p_default; +} + +Ref Theme::get_project_default() { + return project_default_theme; +} + +void Theme::set_project_default(const Ref &p_project_default) { + project_default_theme = p_project_default; +} + +// Universal fallback values for theme item types. +void Theme::set_default_icon(const Ref &p_icon) { + default_icon = p_icon; +} + +void Theme::set_default_style(const Ref &p_style) { + default_style = p_style; +} + +void Theme::set_default_font(const Ref &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_font(const Ref &p_default_font) { + if (default_theme_font == p_default_font) { return; } - notify_property_list_changed(); - emit_changed(); + if (default_theme_font.is_valid()) { + default_theme_font->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed)); + } + + 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); + } + + _emit_theme_changed(); } +Ref Theme::get_default_theme_font() const { + return default_theme_font; +} + +void Theme::set_default_theme_font_size(int p_font_size) { + if (default_theme_font_size == p_font_size) { + return; + } + + default_theme_font_size = p_font_size; + + _emit_theme_changed(); +} + +int Theme::get_default_theme_font_size() const { + return default_theme_font_size; +} + +// Icons. +void Theme::set_icon(const StringName &p_name, const StringName &p_theme_type, const Ref &p_icon) { + if (icon_map[p_theme_type].has(p_name) && icon_map[p_theme_type][p_name].is_valid()) { + 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); + } + + _emit_theme_changed(); +} + +Ref Theme::get_icon(const StringName &p_name, const StringName &p_theme_type) const { + if (icon_map.has(p_theme_type) && icon_map[p_theme_type].has(p_name) && icon_map[p_theme_type][p_name].is_valid()) { + return icon_map[p_theme_type][p_name]; + } else { + return default_icon; + } +} + +bool Theme::has_icon(const StringName &p_name, const StringName &p_theme_type) const { + return (icon_map.has(p_theme_type) && icon_map[p_theme_type].has(p_name) && icon_map[p_theme_type][p_name].is_valid()); +} + +bool Theme::has_icon_nocheck(const StringName &p_name, const StringName &p_theme_type) const { + return (icon_map.has(p_theme_type) && icon_map[p_theme_type].has(p_name)); +} + +void Theme::rename_icon(const StringName &p_old_name, const StringName &p_name, const StringName &p_theme_type) { + ERR_FAIL_COND_MSG(!icon_map.has(p_theme_type), "Cannot rename the icon '" + String(p_old_name) + "' because the node type '" + String(p_theme_type) + "' does not exist."); + ERR_FAIL_COND_MSG(icon_map[p_theme_type].has(p_name), "Cannot rename the icon '" + String(p_old_name) + "' because the new name '" + String(p_name) + "' already exists."); + ERR_FAIL_COND_MSG(!icon_map[p_theme_type].has(p_old_name), "Cannot rename the icon '" + String(p_old_name) + "' because it does not exist."); + + 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(); +} + +void Theme::clear_icon(const StringName &p_name, const StringName &p_theme_type) { + ERR_FAIL_COND_MSG(!icon_map.has(p_theme_type), "Cannot clear the icon '" + String(p_name) + "' because the node type '" + String(p_theme_type) + "' does not exist."); + ERR_FAIL_COND_MSG(!icon_map[p_theme_type].has(p_name), "Cannot clear the icon '" + String(p_name) + "' because it does not exist."); + + if (icon_map[p_theme_type][p_name].is_valid()) { + icon_map[p_theme_type][p_name]->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed)); + } + + icon_map[p_theme_type].erase(p_name); + + _emit_theme_changed(); +} + +void Theme::get_icon_list(StringName p_theme_type, List *p_list) const { + ERR_FAIL_NULL(p_list); + + if (!icon_map.has(p_theme_type)) { + return; + } + + const StringName *key = nullptr; + + while ((key = icon_map[p_theme_type].next(key))) { + p_list->push_back(*key); + } +} + +void Theme::add_icon_type(const StringName &p_theme_type) { + if (icon_map.has(p_theme_type)) { + return; + } + icon_map[p_theme_type] = HashMap>(); +} + +void Theme::get_icon_type_list(List *p_list) const { + ERR_FAIL_NULL(p_list); + + const StringName *key = nullptr; + while ((key = icon_map.next(key))) { + p_list->push_back(*key); + } +} + +// Styleboxes. +void Theme::set_stylebox(const StringName &p_name, const StringName &p_theme_type, const Ref &p_style) { + if (style_map[p_theme_type].has(p_name) && style_map[p_theme_type][p_name].is_valid()) { + 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); + } + + _emit_theme_changed(); +} + +Ref Theme::get_stylebox(const StringName &p_name, const StringName &p_theme_type) const { + if (style_map.has(p_theme_type) && style_map[p_theme_type].has(p_name) && style_map[p_theme_type][p_name].is_valid()) { + return style_map[p_theme_type][p_name]; + } else { + return default_style; + } +} + +bool Theme::has_stylebox(const StringName &p_name, const StringName &p_theme_type) const { + return (style_map.has(p_theme_type) && style_map[p_theme_type].has(p_name) && style_map[p_theme_type][p_name].is_valid()); +} + +bool Theme::has_stylebox_nocheck(const StringName &p_name, const StringName &p_theme_type) const { + return (style_map.has(p_theme_type) && style_map[p_theme_type].has(p_name)); +} + +void Theme::rename_stylebox(const StringName &p_old_name, const StringName &p_name, const StringName &p_theme_type) { + ERR_FAIL_COND_MSG(!style_map.has(p_theme_type), "Cannot rename the stylebox '" + String(p_old_name) + "' because the node type '" + String(p_theme_type) + "' does not exist."); + ERR_FAIL_COND_MSG(style_map[p_theme_type].has(p_name), "Cannot rename the stylebox '" + String(p_old_name) + "' because the new name '" + String(p_name) + "' already exists."); + ERR_FAIL_COND_MSG(!style_map[p_theme_type].has(p_old_name), "Cannot rename the stylebox '" + String(p_old_name) + "' because it does not exist."); + + 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(); +} + +void Theme::clear_stylebox(const StringName &p_name, const StringName &p_theme_type) { + ERR_FAIL_COND_MSG(!style_map.has(p_theme_type), "Cannot clear the stylebox '" + String(p_name) + "' because the node type '" + String(p_theme_type) + "' does not exist."); + ERR_FAIL_COND_MSG(!style_map[p_theme_type].has(p_name), "Cannot clear the stylebox '" + String(p_name) + "' because it does not exist."); + + if (style_map[p_theme_type][p_name].is_valid()) { + style_map[p_theme_type][p_name]->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed)); + } + + style_map[p_theme_type].erase(p_name); + + _emit_theme_changed(); +} + +void Theme::get_stylebox_list(StringName p_theme_type, List *p_list) const { + ERR_FAIL_NULL(p_list); + + if (!style_map.has(p_theme_type)) { + return; + } + + const StringName *key = nullptr; + + while ((key = style_map[p_theme_type].next(key))) { + p_list->push_back(*key); + } +} + +void Theme::add_stylebox_type(const StringName &p_theme_type) { + if (style_map.has(p_theme_type)) { + return; + } + style_map[p_theme_type] = HashMap>(); +} + +void Theme::get_stylebox_type_list(List *p_list) const { + ERR_FAIL_NULL(p_list); + + const StringName *key = nullptr; + while ((key = style_map.next(key))) { + p_list->push_back(*key); + } +} + +// Fonts. +void Theme::set_font(const StringName &p_name, const StringName &p_theme_type, const Ref &p_font) { + if (font_map[p_theme_type][p_name].is_valid()) { + 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); + } + + _emit_theme_changed(); +} + +Ref Theme::get_font(const StringName &p_name, const StringName &p_theme_type) const { + if (font_map.has(p_theme_type) && font_map[p_theme_type].has(p_name) && font_map[p_theme_type][p_name].is_valid()) { + return font_map[p_theme_type][p_name]; + } else if (default_theme_font.is_valid()) { + return default_theme_font; + } else { + return default_font; + } +} + +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()); +} + +bool Theme::has_font_nocheck(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)); +} + +void Theme::rename_font(const StringName &p_old_name, const StringName &p_name, const StringName &p_theme_type) { + ERR_FAIL_COND_MSG(!font_map.has(p_theme_type), "Cannot rename the font '" + String(p_old_name) + "' because the node type '" + String(p_theme_type) + "' does not exist."); + ERR_FAIL_COND_MSG(font_map[p_theme_type].has(p_name), "Cannot rename the font '" + String(p_old_name) + "' because the new name '" + String(p_name) + "' already exists."); + ERR_FAIL_COND_MSG(!font_map[p_theme_type].has(p_old_name), "Cannot rename the font '" + String(p_old_name) + "' because it does not exist."); + + 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(); +} + +void Theme::clear_font(const StringName &p_name, const StringName &p_theme_type) { + ERR_FAIL_COND_MSG(!font_map.has(p_theme_type), "Cannot clear the font '" + String(p_name) + "' because the node type '" + String(p_theme_type) + "' does not exist."); + ERR_FAIL_COND_MSG(!font_map[p_theme_type].has(p_name), "Cannot clear the font '" + String(p_name) + "' because it does not exist."); + + if (font_map[p_theme_type][p_name].is_valid()) { + font_map[p_theme_type][p_name]->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed)); + } + + font_map[p_theme_type].erase(p_name); + + _emit_theme_changed(); +} + +void Theme::get_font_list(StringName p_theme_type, List *p_list) const { + ERR_FAIL_NULL(p_list); + + if (!font_map.has(p_theme_type)) { + return; + } + + const StringName *key = nullptr; + + while ((key = font_map[p_theme_type].next(key))) { + p_list->push_back(*key); + } +} + +void Theme::add_font_type(const StringName &p_theme_type) { + if (font_map.has(p_theme_type)) { + return; + } + font_map[p_theme_type] = HashMap>(); +} + +void Theme::get_font_type_list(List *p_list) const { + ERR_FAIL_NULL(p_list); + + const StringName *key = nullptr; + while ((key = font_map.next(key))) { + p_list->push_back(*key); + } +} + +// Font sizes. +void Theme::set_font_size(const StringName &p_name, const StringName &p_theme_type, int p_font_size) { + font_size_map[p_theme_type][p_name] = p_font_size; + + _emit_theme_changed(); +} + +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) { + return default_theme_font_size; + } else { + return default_font_size; + } +} + +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)); +} + +bool Theme::has_font_size_nocheck(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)); +} + +void Theme::rename_font_size(const StringName &p_old_name, const StringName &p_name, const StringName &p_theme_type) { + ERR_FAIL_COND_MSG(!font_size_map.has(p_theme_type), "Cannot rename the font size '" + String(p_old_name) + "' because the node type '" + String(p_theme_type) + "' does not exist."); + ERR_FAIL_COND_MSG(font_size_map[p_theme_type].has(p_name), "Cannot rename the font size '" + String(p_old_name) + "' because the new name '" + String(p_name) + "' already exists."); + ERR_FAIL_COND_MSG(!font_size_map[p_theme_type].has(p_old_name), "Cannot rename the font size '" + String(p_old_name) + "' because it does not exist."); + + 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(); +} + +void Theme::clear_font_size(const StringName &p_name, const StringName &p_theme_type) { + ERR_FAIL_COND_MSG(!font_size_map.has(p_theme_type), "Cannot clear the font size '" + String(p_name) + "' because the node type '" + String(p_theme_type) + "' does not exist."); + ERR_FAIL_COND_MSG(!font_size_map[p_theme_type].has(p_name), "Cannot clear the font size '" + String(p_name) + "' because it does not exist."); + + font_size_map[p_theme_type].erase(p_name); + + _emit_theme_changed(); +} + +void Theme::get_font_size_list(StringName p_theme_type, List *p_list) const { + ERR_FAIL_NULL(p_list); + + if (!font_size_map.has(p_theme_type)) { + return; + } + + const StringName *key = nullptr; + + while ((key = font_size_map[p_theme_type].next(key))) { + p_list->push_back(*key); + } +} + +void Theme::add_font_size_type(const StringName &p_theme_type) { + if (font_size_map.has(p_theme_type)) { + return; + } + font_size_map[p_theme_type] = HashMap(); +} + +void Theme::get_font_size_type_list(List *p_list) const { + ERR_FAIL_NULL(p_list); + + const StringName *key = nullptr; + while ((key = font_size_map.next(key))) { + p_list->push_back(*key); + } +} + +// Colors. +void Theme::set_color(const StringName &p_name, const StringName &p_theme_type, const Color &p_color) { + color_map[p_theme_type][p_name] = p_color; + + _emit_theme_changed(); +} + +Color Theme::get_color(const StringName &p_name, const StringName &p_theme_type) const { + if (color_map.has(p_theme_type) && color_map[p_theme_type].has(p_name)) { + return color_map[p_theme_type][p_name]; + } else { + return Color(); + } +} + +bool Theme::has_color(const StringName &p_name, const StringName &p_theme_type) const { + return (color_map.has(p_theme_type) && color_map[p_theme_type].has(p_name)); +} + +bool Theme::has_color_nocheck(const StringName &p_name, const StringName &p_theme_type) const { + return (color_map.has(p_theme_type) && color_map[p_theme_type].has(p_name)); +} + +void Theme::rename_color(const StringName &p_old_name, const StringName &p_name, const StringName &p_theme_type) { + ERR_FAIL_COND_MSG(!color_map.has(p_theme_type), "Cannot rename the color '" + String(p_old_name) + "' because the node type '" + String(p_theme_type) + "' does not exist."); + ERR_FAIL_COND_MSG(color_map[p_theme_type].has(p_name), "Cannot rename the color '" + String(p_old_name) + "' because the new name '" + String(p_name) + "' already exists."); + ERR_FAIL_COND_MSG(!color_map[p_theme_type].has(p_old_name), "Cannot rename the color '" + String(p_old_name) + "' because it does not exist."); + + 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(); +} + +void Theme::clear_color(const StringName &p_name, const StringName &p_theme_type) { + ERR_FAIL_COND_MSG(!color_map.has(p_theme_type), "Cannot clear the color '" + String(p_name) + "' because the node type '" + String(p_theme_type) + "' does not exist."); + ERR_FAIL_COND_MSG(!color_map[p_theme_type].has(p_name), "Cannot clear the color '" + String(p_name) + "' because it does not exist."); + + color_map[p_theme_type].erase(p_name); + + _emit_theme_changed(); +} + +void Theme::get_color_list(StringName p_theme_type, List *p_list) const { + ERR_FAIL_NULL(p_list); + + if (!color_map.has(p_theme_type)) { + return; + } + + const StringName *key = nullptr; + + while ((key = color_map[p_theme_type].next(key))) { + p_list->push_back(*key); + } +} + +void Theme::add_color_type(const StringName &p_theme_type) { + if (color_map.has(p_theme_type)) { + return; + } + color_map[p_theme_type] = HashMap(); +} + +void Theme::get_color_type_list(List *p_list) const { + ERR_FAIL_NULL(p_list); + + const StringName *key = nullptr; + while ((key = color_map.next(key))) { + p_list->push_back(*key); + } +} + +// Theme constants. +void Theme::set_constant(const StringName &p_name, const StringName &p_theme_type, int p_constant) { + constant_map[p_theme_type][p_name] = p_constant; + + _emit_theme_changed(); +} + +int Theme::get_constant(const StringName &p_name, const StringName &p_theme_type) const { + if (constant_map.has(p_theme_type) && constant_map[p_theme_type].has(p_name)) { + return constant_map[p_theme_type][p_name]; + } else { + return 0; + } +} + +bool Theme::has_constant(const StringName &p_name, const StringName &p_theme_type) const { + return (constant_map.has(p_theme_type) && constant_map[p_theme_type].has(p_name)); +} + +bool Theme::has_constant_nocheck(const StringName &p_name, const StringName &p_theme_type) const { + return (constant_map.has(p_theme_type) && constant_map[p_theme_type].has(p_name)); +} + +void Theme::rename_constant(const StringName &p_old_name, const StringName &p_name, const StringName &p_theme_type) { + ERR_FAIL_COND_MSG(!constant_map.has(p_theme_type), "Cannot rename the constant '" + String(p_old_name) + "' because the node type '" + String(p_theme_type) + "' does not exist."); + ERR_FAIL_COND_MSG(constant_map[p_theme_type].has(p_name), "Cannot rename the constant '" + String(p_old_name) + "' because the new name '" + String(p_name) + "' already exists."); + ERR_FAIL_COND_MSG(!constant_map[p_theme_type].has(p_old_name), "Cannot rename the constant '" + String(p_old_name) + "' because it does not exist."); + + 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(); +} + +void Theme::clear_constant(const StringName &p_name, const StringName &p_theme_type) { + ERR_FAIL_COND_MSG(!constant_map.has(p_theme_type), "Cannot clear the constant '" + String(p_name) + "' because the node type '" + String(p_theme_type) + "' does not exist."); + ERR_FAIL_COND_MSG(!constant_map[p_theme_type].has(p_name), "Cannot clear the constant '" + String(p_name) + "' because it does not exist."); + + constant_map[p_theme_type].erase(p_name); + + _emit_theme_changed(); +} + +void Theme::get_constant_list(StringName p_theme_type, List *p_list) const { + ERR_FAIL_NULL(p_list); + + if (!constant_map.has(p_theme_type)) { + return; + } + + const StringName *key = nullptr; + + while ((key = constant_map[p_theme_type].next(key))) { + p_list->push_back(*key); + } +} + +void Theme::add_constant_type(const StringName &p_theme_type) { + if (constant_map.has(p_theme_type)) { + return; + } + constant_map[p_theme_type] = HashMap(); +} + +void Theme::get_constant_type_list(List *p_list) const { + ERR_FAIL_NULL(p_list); + + const StringName *key = nullptr; + while ((key = constant_map.next(key))) { + p_list->push_back(*key); + } +} + +// 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: { + ERR_FAIL_COND_MSG(p_value.get_type() != Variant::COLOR, "Theme item's data type (Color) does not match Variant's type (" + Variant::get_type_name(p_value.get_type()) + ")."); + + Color color_value = p_value; + set_color(p_name, p_theme_type, color_value); + } break; + case DATA_TYPE_CONSTANT: { + ERR_FAIL_COND_MSG(p_value.get_type() != Variant::INT, "Theme item's data type (int) does not match Variant's type (" + Variant::get_type_name(p_value.get_type()) + ")."); + + int constant_value = p_value; + set_constant(p_name, p_theme_type, constant_value); + } break; + case DATA_TYPE_FONT: { + ERR_FAIL_COND_MSG(p_value.get_type() != Variant::OBJECT, "Theme item's data type (Object) does not match Variant's type (" + Variant::get_type_name(p_value.get_type()) + ")."); + + Ref font_value = Object::cast_to(p_value.get_validated_object()); + set_font(p_name, p_theme_type, font_value); + } break; + case DATA_TYPE_FONT_SIZE: { + ERR_FAIL_COND_MSG(p_value.get_type() != Variant::INT, "Theme item's data type (int) does not match Variant's type (" + Variant::get_type_name(p_value.get_type()) + ")."); + + int font_size_value = p_value; + set_font_size(p_name, p_theme_type, font_size_value); + } break; + case DATA_TYPE_ICON: { + ERR_FAIL_COND_MSG(p_value.get_type() != Variant::OBJECT, "Theme item's data type (Object) does not match Variant's type (" + Variant::get_type_name(p_value.get_type()) + ")."); + + Ref icon_value = Object::cast_to(p_value.get_validated_object()); + set_icon(p_name, p_theme_type, icon_value); + } break; + case DATA_TYPE_STYLEBOX: { + ERR_FAIL_COND_MSG(p_value.get_type() != Variant::OBJECT, "Theme item's data type (Object) does not match Variant's type (" + Variant::get_type_name(p_value.get_type()) + ")."); + + Ref stylebox_value = Object::cast_to(p_value.get_validated_object()); + set_stylebox(p_name, p_theme_type, stylebox_value); + } break; + case DATA_TYPE_MAX: + break; // Can't happen, but silences warning. + } +} + +Variant Theme::get_theme_item(DataType p_data_type, const StringName &p_name, const StringName &p_theme_type) const { + switch (p_data_type) { + case DATA_TYPE_COLOR: + return get_color(p_name, p_theme_type); + case DATA_TYPE_CONSTANT: + return get_constant(p_name, p_theme_type); + case DATA_TYPE_FONT: + return get_font(p_name, p_theme_type); + case DATA_TYPE_FONT_SIZE: + return get_font_size(p_name, p_theme_type); + case DATA_TYPE_ICON: + return get_icon(p_name, p_theme_type); + case DATA_TYPE_STYLEBOX: + return get_stylebox(p_name, p_theme_type); + case DATA_TYPE_MAX: + break; // Can't happen, but silences warning. + } + + return Variant(); +} + +bool Theme::has_theme_item(DataType p_data_type, const StringName &p_name, const StringName &p_theme_type) const { + switch (p_data_type) { + case DATA_TYPE_COLOR: + return has_color(p_name, p_theme_type); + case DATA_TYPE_CONSTANT: + return has_constant(p_name, p_theme_type); + case DATA_TYPE_FONT: + return has_font(p_name, p_theme_type); + case DATA_TYPE_FONT_SIZE: + return has_font_size(p_name, p_theme_type); + case DATA_TYPE_ICON: + return has_icon(p_name, p_theme_type); + case DATA_TYPE_STYLEBOX: + return has_stylebox(p_name, p_theme_type); + case DATA_TYPE_MAX: + break; // Can't happen, but silences warning. + } + + return false; +} + +bool Theme::has_theme_item_nocheck(DataType p_data_type, const StringName &p_name, const StringName &p_theme_type) const { + switch (p_data_type) { + case DATA_TYPE_COLOR: + return has_color_nocheck(p_name, p_theme_type); + case DATA_TYPE_CONSTANT: + return has_constant_nocheck(p_name, p_theme_type); + case DATA_TYPE_FONT: + return has_font_nocheck(p_name, p_theme_type); + case DATA_TYPE_FONT_SIZE: + return has_font_size_nocheck(p_name, p_theme_type); + case DATA_TYPE_ICON: + return has_icon_nocheck(p_name, p_theme_type); + case DATA_TYPE_STYLEBOX: + return has_stylebox_nocheck(p_name, p_theme_type); + case DATA_TYPE_MAX: + break; // Can't happen, but silences warning. + } + + return false; +} + +void Theme::rename_theme_item(DataType p_data_type, const StringName &p_old_name, const StringName &p_name, const StringName &p_theme_type) { + switch (p_data_type) { + case DATA_TYPE_COLOR: + rename_color(p_old_name, p_name, p_theme_type); + break; + case DATA_TYPE_CONSTANT: + rename_constant(p_old_name, p_name, p_theme_type); + break; + case DATA_TYPE_FONT: + rename_font(p_old_name, p_name, p_theme_type); + break; + case DATA_TYPE_FONT_SIZE: + rename_font_size(p_old_name, p_name, p_theme_type); + break; + case DATA_TYPE_ICON: + rename_icon(p_old_name, p_name, p_theme_type); + break; + case DATA_TYPE_STYLEBOX: + rename_stylebox(p_old_name, p_name, p_theme_type); + break; + case DATA_TYPE_MAX: + break; // Can't happen, but silences warning. + } +} + +void Theme::clear_theme_item(DataType p_data_type, const StringName &p_name, const StringName &p_theme_type) { + switch (p_data_type) { + case DATA_TYPE_COLOR: + clear_color(p_name, p_theme_type); + break; + case DATA_TYPE_CONSTANT: + clear_constant(p_name, p_theme_type); + break; + case DATA_TYPE_FONT: + clear_font(p_name, p_theme_type); + break; + case DATA_TYPE_FONT_SIZE: + clear_font_size(p_name, p_theme_type); + break; + case DATA_TYPE_ICON: + clear_icon(p_name, p_theme_type); + break; + case DATA_TYPE_STYLEBOX: + clear_stylebox(p_name, p_theme_type); + break; + case DATA_TYPE_MAX: + break; // Can't happen, but silences warning. + } +} + +void Theme::get_theme_item_list(DataType p_data_type, StringName p_theme_type, List *p_list) const { + switch (p_data_type) { + case DATA_TYPE_COLOR: + get_color_list(p_theme_type, p_list); + break; + case DATA_TYPE_CONSTANT: + get_constant_list(p_theme_type, p_list); + break; + case DATA_TYPE_FONT: + get_font_list(p_theme_type, p_list); + break; + case DATA_TYPE_FONT_SIZE: + get_font_size_list(p_theme_type, p_list); + break; + case DATA_TYPE_ICON: + get_icon_list(p_theme_type, p_list); + break; + case DATA_TYPE_STYLEBOX: + get_stylebox_list(p_theme_type, p_list); + break; + case DATA_TYPE_MAX: + break; // Can't happen, but silences warning. + } +} + +void Theme::add_theme_item_type(DataType p_data_type, const StringName &p_theme_type) { + switch (p_data_type) { + case DATA_TYPE_COLOR: + add_color_type(p_theme_type); + break; + case DATA_TYPE_CONSTANT: + add_constant_type(p_theme_type); + break; + case DATA_TYPE_FONT: + add_font_type(p_theme_type); + break; + case DATA_TYPE_FONT_SIZE: + add_font_size_type(p_theme_type); + break; + case DATA_TYPE_ICON: + add_icon_type(p_theme_type); + break; + case DATA_TYPE_STYLEBOX: + add_stylebox_type(p_theme_type); + break; + case DATA_TYPE_MAX: + break; // Can't happen, but silences warning. + } +} + +void Theme::get_theme_item_type_list(DataType p_data_type, List *p_list) const { + switch (p_data_type) { + case DATA_TYPE_COLOR: + get_color_type_list(p_list); + break; + case DATA_TYPE_CONSTANT: + get_constant_type_list(p_list); + break; + case DATA_TYPE_FONT: + get_font_type_list(p_list); + break; + case DATA_TYPE_FONT_SIZE: + get_font_size_type_list(p_list); + break; + case DATA_TYPE_ICON: + get_icon_type_list(p_list); + break; + case DATA_TYPE_STYLEBOX: + get_stylebox_type_list(p_list); + break; + case DATA_TYPE_MAX: + break; // Can't happen, but silences warning. + } +} + +// 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."); + ERR_FAIL_COND_MSG(p_base_type == StringName(), "An empty theme type cannot be the base type of a variation. Use clear_type_variation() instead if you want to unmark '" + String(p_theme_type) + "' as a variation."); + + if (variation_map.has(p_theme_type)) { + StringName old_base = variation_map[p_theme_type]; + variation_base_map[old_base].erase(p_theme_type); + } + + variation_map[p_theme_type] = p_base_type; + variation_base_map[p_base_type].push_back(p_theme_type); + + _emit_theme_changed(); +} + +bool Theme::is_type_variation(const StringName &p_theme_type, const StringName &p_base_type) const { + return (variation_map.has(p_theme_type) && variation_map[p_theme_type] == p_base_type); +} + +void Theme::clear_type_variation(const StringName &p_theme_type) { + ERR_FAIL_COND_MSG(!variation_map.has(p_theme_type), "Cannot clear the type variation '" + String(p_theme_type) + "' because it does not exist."); + + StringName base_type = variation_map[p_theme_type]; + variation_base_map[base_type].erase(p_theme_type); + variation_map.erase(p_theme_type); + + _emit_theme_changed(); +} + +StringName Theme::get_type_variation_base(const StringName &p_theme_type) const { + if (!variation_map.has(p_theme_type)) { + return StringName(); + } + + return variation_map[p_theme_type]; +} + +void Theme::get_type_variation_list(const StringName &p_base_type, List *p_list) const { + ERR_FAIL_NULL(p_list); + + if (!variation_base_map.has(p_base_type)) { + return; + } + + for (const StringName &E : variation_base_map[p_base_type]) { + // Prevent infinite loops if variants were set to be cross-dependent (that's still invalid usage, but handling for stability sake). + if (p_list->find(E)) { + continue; + } + + p_list->push_back(E); + // Continue looking for sub-variations. + get_type_variation_list(E, p_list); + } +} + +// Theme types. +void Theme::get_type_list(List *p_list) const { + ERR_FAIL_NULL(p_list); + + Set 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::Element *E = types.front(); E; E = E->next()) { + p_list->push_back(E->get()); + } +} + +void Theme::get_type_dependencies(const StringName &p_base_type, const StringName &p_type_variation, List *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; + } + } + } + + // 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); + } +} + +// Internal methods for getting lists as a Vector of String (compatible with public API). Vector Theme::_get_icon_list(const String &p_theme_type) const { Vector ilret; List il; @@ -293,998 +1370,14 @@ Vector Theme::_get_type_list() const { return ilret; } -bool Theme::_set(const StringName &p_name, const Variant &p_value) { - String sname = p_name; - - if (sname.find("/") != -1) { - String type = sname.get_slicec('/', 1); - String theme_type = sname.get_slicec('/', 0); - String name = sname.get_slicec('/', 2); - - if (type == "icons") { - set_icon(name, theme_type, p_value); - } else if (type == "styles") { - set_stylebox(name, theme_type, p_value); - } else if (type == "fonts") { - set_font(name, theme_type, p_value); - } else if (type == "font_sizes") { - set_font_size(name, theme_type, p_value); - } else if (type == "colors") { - set_color(name, theme_type, p_value); - } else if (type == "constants") { - set_constant(name, theme_type, p_value); - } else if (type == "base_type") { - set_type_variation(theme_type, p_value); - } else { - return false; - } - - return true; - } - - return false; -} - -bool Theme::_get(const StringName &p_name, Variant &r_ret) const { - String sname = p_name; - - if (sname.find("/") != -1) { - String type = sname.get_slicec('/', 1); - String theme_type = sname.get_slicec('/', 0); - String name = sname.get_slicec('/', 2); - - if (type == "icons") { - if (!has_icon(name, theme_type)) { - r_ret = Ref(); - } else { - r_ret = get_icon(name, theme_type); - } - } else if (type == "styles") { - if (!has_stylebox(name, theme_type)) { - r_ret = Ref(); - } else { - r_ret = get_stylebox(name, theme_type); - } - } else if (type == "fonts") { - if (!has_font(name, theme_type)) { - r_ret = Ref(); - } else { - r_ret = get_font(name, theme_type); - } - } else if (type == "font_sizes") { - r_ret = get_font_size(name, theme_type); - } else if (type == "colors") { - r_ret = get_color(name, theme_type); - } else if (type == "constants") { - r_ret = get_constant(name, theme_type); - } else if (type == "base_type") { - r_ret = get_type_variation_base(theme_type); - } else { - return false; - } - - return true; - } - - return false; -} - -void Theme::_get_property_list(List *p_list) const { - List list; - - const StringName *key = nullptr; - - // Type variations. - while ((key = variation_map.next(key))) { - list.push_back(PropertyInfo(Variant::STRING_NAME, String() + *key + "/base_type")); - } - - key = nullptr; - - // Icons. - while ((key = icon_map.next(key))) { - const StringName *key2 = nullptr; - - while ((key2 = icon_map[*key].next(key2))) { - list.push_back(PropertyInfo(Variant::OBJECT, String() + *key + "/icons/" + *key2, PROPERTY_HINT_RESOURCE_TYPE, "Texture2D", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_STORE_IF_NULL)); - } - } - - key = nullptr; - - // Styles. - while ((key = style_map.next(key))) { - const StringName *key2 = nullptr; - - while ((key2 = style_map[*key].next(key2))) { - list.push_back(PropertyInfo(Variant::OBJECT, String() + *key + "/styles/" + *key2, PROPERTY_HINT_RESOURCE_TYPE, "StyleBox", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_STORE_IF_NULL)); - } - } - - key = nullptr; - - // Fonts. - while ((key = font_map.next(key))) { - const StringName *key2 = nullptr; - - while ((key2 = font_map[*key].next(key2))) { - list.push_back(PropertyInfo(Variant::OBJECT, String() + *key + "/fonts/" + *key2, PROPERTY_HINT_RESOURCE_TYPE, "Font", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_STORE_IF_NULL)); - } - } - - key = nullptr; - - // Font sizes. - while ((key = font_size_map.next(key))) { - const StringName *key2 = nullptr; - - while ((key2 = font_size_map[*key].next(key2))) { - list.push_back(PropertyInfo(Variant::INT, String() + *key + "/font_sizes/" + *key2)); - } - } - - key = nullptr; - - // Colors. - while ((key = color_map.next(key))) { - const StringName *key2 = nullptr; - - while ((key2 = color_map[*key].next(key2))) { - list.push_back(PropertyInfo(Variant::COLOR, String() + *key + "/colors/" + *key2)); - } - } - - key = nullptr; - - // Constants. - while ((key = constant_map.next(key))) { - const StringName *key2 = nullptr; - - while ((key2 = constant_map[*key].next(key2))) { - list.push_back(PropertyInfo(Variant::INT, String() + *key + "/constants/" + *key2)); - } - } - - // Sort and store properties. - list.sort(); - for (const PropertyInfo &E : list) { - p_list->push_back(E); - } -} - -void Theme::set_default_theme_font(const Ref &p_default_font) { - if (default_theme_font == p_default_font) { +// Theme bulk manipulations. +void Theme::_emit_theme_changed() { + if (no_change_propagation) { return; } - if (default_theme_font.is_valid()) { - default_theme_font->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed)); - } - - 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); - } - - _emit_theme_changed(); -} - -Ref Theme::get_default_theme_font() const { - return default_theme_font; -} - -void Theme::set_default_theme_font_size(int p_font_size) { - if (default_theme_font_size == p_font_size) { - return; - } - - default_theme_font_size = p_font_size; - - _emit_theme_changed(); -} - -int Theme::get_default_theme_font_size() const { - return default_theme_font_size; -} - -Ref Theme::project_default_theme; -Ref Theme::default_theme; -Ref Theme::default_icon; -Ref Theme::default_style; -Ref Theme::default_font; -int Theme::default_font_size = 16; - -Ref Theme::get_default() { - return default_theme; -} - -void Theme::set_default(const Ref &p_default) { - default_theme = p_default; -} - -Ref Theme::get_project_default() { - return project_default_theme; -} - -void Theme::set_project_default(const Ref &p_project_default) { - project_default_theme = p_project_default; -} - -void Theme::set_default_icon(const Ref &p_icon) { - default_icon = p_icon; -} - -void Theme::set_default_style(const Ref &p_style) { - default_style = p_style; -} - -void Theme::set_default_font(const Ref &p_font) { - default_font = p_font; -} - -void Theme::set_default_font_size(int p_font_size) { - default_font_size = p_font_size; -} - -void Theme::set_icon(const StringName &p_name, const StringName &p_theme_type, const Ref &p_icon) { - if (icon_map[p_theme_type].has(p_name) && icon_map[p_theme_type][p_name].is_valid()) { - 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); - } - - _emit_theme_changed(); -} - -Ref Theme::get_icon(const StringName &p_name, const StringName &p_theme_type) const { - if (icon_map.has(p_theme_type) && icon_map[p_theme_type].has(p_name) && icon_map[p_theme_type][p_name].is_valid()) { - return icon_map[p_theme_type][p_name]; - } else { - return default_icon; - } -} - -bool Theme::has_icon(const StringName &p_name, const StringName &p_theme_type) const { - return (icon_map.has(p_theme_type) && icon_map[p_theme_type].has(p_name) && icon_map[p_theme_type][p_name].is_valid()); -} - -bool Theme::has_icon_nocheck(const StringName &p_name, const StringName &p_theme_type) const { - return (icon_map.has(p_theme_type) && icon_map[p_theme_type].has(p_name)); -} - -void Theme::rename_icon(const StringName &p_old_name, const StringName &p_name, const StringName &p_theme_type) { - ERR_FAIL_COND_MSG(!icon_map.has(p_theme_type), "Cannot rename the icon '" + String(p_old_name) + "' because the node type '" + String(p_theme_type) + "' does not exist."); - ERR_FAIL_COND_MSG(icon_map[p_theme_type].has(p_name), "Cannot rename the icon '" + String(p_old_name) + "' because the new name '" + String(p_name) + "' already exists."); - ERR_FAIL_COND_MSG(!icon_map[p_theme_type].has(p_old_name), "Cannot rename the icon '" + String(p_old_name) + "' because it does not exist."); - - 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(); -} - -void Theme::clear_icon(const StringName &p_name, const StringName &p_theme_type) { - ERR_FAIL_COND_MSG(!icon_map.has(p_theme_type), "Cannot clear the icon '" + String(p_name) + "' because the node type '" + String(p_theme_type) + "' does not exist."); - ERR_FAIL_COND_MSG(!icon_map[p_theme_type].has(p_name), "Cannot clear the icon '" + String(p_name) + "' because it does not exist."); - - if (icon_map[p_theme_type][p_name].is_valid()) { - icon_map[p_theme_type][p_name]->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed)); - } - - icon_map[p_theme_type].erase(p_name); - - _emit_theme_changed(); -} - -void Theme::get_icon_list(StringName p_theme_type, List *p_list) const { - ERR_FAIL_NULL(p_list); - - if (!icon_map.has(p_theme_type)) { - return; - } - - const StringName *key = nullptr; - - while ((key = icon_map[p_theme_type].next(key))) { - p_list->push_back(*key); - } -} - -void Theme::add_icon_type(const StringName &p_theme_type) { - if (icon_map.has(p_theme_type)) { - return; - } - icon_map[p_theme_type] = HashMap>(); -} - -void Theme::get_icon_type_list(List *p_list) const { - ERR_FAIL_NULL(p_list); - - const StringName *key = nullptr; - while ((key = icon_map.next(key))) { - p_list->push_back(*key); - } -} - -void Theme::set_stylebox(const StringName &p_name, const StringName &p_theme_type, const Ref &p_style) { - if (style_map[p_theme_type].has(p_name) && style_map[p_theme_type][p_name].is_valid()) { - 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); - } - - _emit_theme_changed(); -} - -Ref Theme::get_stylebox(const StringName &p_name, const StringName &p_theme_type) const { - if (style_map.has(p_theme_type) && style_map[p_theme_type].has(p_name) && style_map[p_theme_type][p_name].is_valid()) { - return style_map[p_theme_type][p_name]; - } else { - return default_style; - } -} - -bool Theme::has_stylebox(const StringName &p_name, const StringName &p_theme_type) const { - return (style_map.has(p_theme_type) && style_map[p_theme_type].has(p_name) && style_map[p_theme_type][p_name].is_valid()); -} - -bool Theme::has_stylebox_nocheck(const StringName &p_name, const StringName &p_theme_type) const { - return (style_map.has(p_theme_type) && style_map[p_theme_type].has(p_name)); -} - -void Theme::rename_stylebox(const StringName &p_old_name, const StringName &p_name, const StringName &p_theme_type) { - ERR_FAIL_COND_MSG(!style_map.has(p_theme_type), "Cannot rename the stylebox '" + String(p_old_name) + "' because the node type '" + String(p_theme_type) + "' does not exist."); - ERR_FAIL_COND_MSG(style_map[p_theme_type].has(p_name), "Cannot rename the stylebox '" + String(p_old_name) + "' because the new name '" + String(p_name) + "' already exists."); - ERR_FAIL_COND_MSG(!style_map[p_theme_type].has(p_old_name), "Cannot rename the stylebox '" + String(p_old_name) + "' because it does not exist."); - - 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(); -} - -void Theme::clear_stylebox(const StringName &p_name, const StringName &p_theme_type) { - ERR_FAIL_COND_MSG(!style_map.has(p_theme_type), "Cannot clear the stylebox '" + String(p_name) + "' because the node type '" + String(p_theme_type) + "' does not exist."); - ERR_FAIL_COND_MSG(!style_map[p_theme_type].has(p_name), "Cannot clear the stylebox '" + String(p_name) + "' because it does not exist."); - - if (style_map[p_theme_type][p_name].is_valid()) { - style_map[p_theme_type][p_name]->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed)); - } - - style_map[p_theme_type].erase(p_name); - - _emit_theme_changed(); -} - -void Theme::get_stylebox_list(StringName p_theme_type, List *p_list) const { - ERR_FAIL_NULL(p_list); - - if (!style_map.has(p_theme_type)) { - return; - } - - const StringName *key = nullptr; - - while ((key = style_map[p_theme_type].next(key))) { - p_list->push_back(*key); - } -} - -void Theme::add_stylebox_type(const StringName &p_theme_type) { - if (style_map.has(p_theme_type)) { - return; - } - style_map[p_theme_type] = HashMap>(); -} - -void Theme::get_stylebox_type_list(List *p_list) const { - ERR_FAIL_NULL(p_list); - - const StringName *key = nullptr; - while ((key = style_map.next(key))) { - p_list->push_back(*key); - } -} - -void Theme::set_font(const StringName &p_name, const StringName &p_theme_type, const Ref &p_font) { - if (font_map[p_theme_type][p_name].is_valid()) { - 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); - } - - _emit_theme_changed(); -} - -Ref Theme::get_font(const StringName &p_name, const StringName &p_theme_type) const { - if (font_map.has(p_theme_type) && font_map[p_theme_type].has(p_name) && font_map[p_theme_type][p_name].is_valid()) { - return font_map[p_theme_type][p_name]; - } else if (default_theme_font.is_valid()) { - return default_theme_font; - } else { - return default_font; - } -} - -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()); -} - -bool Theme::has_font_nocheck(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)); -} - -void Theme::rename_font(const StringName &p_old_name, const StringName &p_name, const StringName &p_theme_type) { - ERR_FAIL_COND_MSG(!font_map.has(p_theme_type), "Cannot rename the font '" + String(p_old_name) + "' because the node type '" + String(p_theme_type) + "' does not exist."); - ERR_FAIL_COND_MSG(font_map[p_theme_type].has(p_name), "Cannot rename the font '" + String(p_old_name) + "' because the new name '" + String(p_name) + "' already exists."); - ERR_FAIL_COND_MSG(!font_map[p_theme_type].has(p_old_name), "Cannot rename the font '" + String(p_old_name) + "' because it does not exist."); - - 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(); -} - -void Theme::clear_font(const StringName &p_name, const StringName &p_theme_type) { - ERR_FAIL_COND_MSG(!font_map.has(p_theme_type), "Cannot clear the font '" + String(p_name) + "' because the node type '" + String(p_theme_type) + "' does not exist."); - ERR_FAIL_COND_MSG(!font_map[p_theme_type].has(p_name), "Cannot clear the font '" + String(p_name) + "' because it does not exist."); - - if (font_map[p_theme_type][p_name].is_valid()) { - font_map[p_theme_type][p_name]->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed)); - } - - font_map[p_theme_type].erase(p_name); - - _emit_theme_changed(); -} - -void Theme::get_font_list(StringName p_theme_type, List *p_list) const { - ERR_FAIL_NULL(p_list); - - if (!font_map.has(p_theme_type)) { - return; - } - - const StringName *key = nullptr; - - while ((key = font_map[p_theme_type].next(key))) { - p_list->push_back(*key); - } -} - -void Theme::add_font_type(const StringName &p_theme_type) { - if (font_map.has(p_theme_type)) { - return; - } - font_map[p_theme_type] = HashMap>(); -} - -void Theme::get_font_type_list(List *p_list) const { - ERR_FAIL_NULL(p_list); - - const StringName *key = nullptr; - while ((key = font_map.next(key))) { - p_list->push_back(*key); - } -} - -void Theme::set_font_size(const StringName &p_name, const StringName &p_theme_type, int p_font_size) { - font_size_map[p_theme_type][p_name] = p_font_size; - - _emit_theme_changed(); -} - -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) { - return default_theme_font_size; - } else { - return default_font_size; - } -} - -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)); -} - -bool Theme::has_font_size_nocheck(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)); -} - -void Theme::rename_font_size(const StringName &p_old_name, const StringName &p_name, const StringName &p_theme_type) { - ERR_FAIL_COND_MSG(!font_size_map.has(p_theme_type), "Cannot rename the font size '" + String(p_old_name) + "' because the node type '" + String(p_theme_type) + "' does not exist."); - ERR_FAIL_COND_MSG(font_size_map[p_theme_type].has(p_name), "Cannot rename the font size '" + String(p_old_name) + "' because the new name '" + String(p_name) + "' already exists."); - ERR_FAIL_COND_MSG(!font_size_map[p_theme_type].has(p_old_name), "Cannot rename the font size '" + String(p_old_name) + "' because it does not exist."); - - 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(); -} - -void Theme::clear_font_size(const StringName &p_name, const StringName &p_theme_type) { - ERR_FAIL_COND_MSG(!font_size_map.has(p_theme_type), "Cannot clear the font size '" + String(p_name) + "' because the node type '" + String(p_theme_type) + "' does not exist."); - ERR_FAIL_COND_MSG(!font_size_map[p_theme_type].has(p_name), "Cannot clear the font size '" + String(p_name) + "' because it does not exist."); - - font_size_map[p_theme_type].erase(p_name); - - _emit_theme_changed(); -} - -void Theme::get_font_size_list(StringName p_theme_type, List *p_list) const { - ERR_FAIL_NULL(p_list); - - if (!font_size_map.has(p_theme_type)) { - return; - } - - const StringName *key = nullptr; - - while ((key = font_size_map[p_theme_type].next(key))) { - p_list->push_back(*key); - } -} - -void Theme::add_font_size_type(const StringName &p_theme_type) { - if (font_size_map.has(p_theme_type)) { - return; - } - font_size_map[p_theme_type] = HashMap(); -} - -void Theme::get_font_size_type_list(List *p_list) const { - ERR_FAIL_NULL(p_list); - - const StringName *key = nullptr; - while ((key = font_size_map.next(key))) { - p_list->push_back(*key); - } -} - -void Theme::set_color(const StringName &p_name, const StringName &p_theme_type, const Color &p_color) { - color_map[p_theme_type][p_name] = p_color; - - _emit_theme_changed(); -} - -Color Theme::get_color(const StringName &p_name, const StringName &p_theme_type) const { - if (color_map.has(p_theme_type) && color_map[p_theme_type].has(p_name)) { - return color_map[p_theme_type][p_name]; - } else { - return Color(); - } -} - -bool Theme::has_color(const StringName &p_name, const StringName &p_theme_type) const { - return (color_map.has(p_theme_type) && color_map[p_theme_type].has(p_name)); -} - -bool Theme::has_color_nocheck(const StringName &p_name, const StringName &p_theme_type) const { - return (color_map.has(p_theme_type) && color_map[p_theme_type].has(p_name)); -} - -void Theme::rename_color(const StringName &p_old_name, const StringName &p_name, const StringName &p_theme_type) { - ERR_FAIL_COND_MSG(!color_map.has(p_theme_type), "Cannot rename the color '" + String(p_old_name) + "' because the node type '" + String(p_theme_type) + "' does not exist."); - ERR_FAIL_COND_MSG(color_map[p_theme_type].has(p_name), "Cannot rename the color '" + String(p_old_name) + "' because the new name '" + String(p_name) + "' already exists."); - ERR_FAIL_COND_MSG(!color_map[p_theme_type].has(p_old_name), "Cannot rename the color '" + String(p_old_name) + "' because it does not exist."); - - 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(); -} - -void Theme::clear_color(const StringName &p_name, const StringName &p_theme_type) { - ERR_FAIL_COND_MSG(!color_map.has(p_theme_type), "Cannot clear the color '" + String(p_name) + "' because the node type '" + String(p_theme_type) + "' does not exist."); - ERR_FAIL_COND_MSG(!color_map[p_theme_type].has(p_name), "Cannot clear the color '" + String(p_name) + "' because it does not exist."); - - color_map[p_theme_type].erase(p_name); - - _emit_theme_changed(); -} - -void Theme::get_color_list(StringName p_theme_type, List *p_list) const { - ERR_FAIL_NULL(p_list); - - if (!color_map.has(p_theme_type)) { - return; - } - - const StringName *key = nullptr; - - while ((key = color_map[p_theme_type].next(key))) { - p_list->push_back(*key); - } -} - -void Theme::add_color_type(const StringName &p_theme_type) { - if (color_map.has(p_theme_type)) { - return; - } - color_map[p_theme_type] = HashMap(); -} - -void Theme::get_color_type_list(List *p_list) const { - ERR_FAIL_NULL(p_list); - - const StringName *key = nullptr; - while ((key = color_map.next(key))) { - p_list->push_back(*key); - } -} - -void Theme::set_constant(const StringName &p_name, const StringName &p_theme_type, int p_constant) { - constant_map[p_theme_type][p_name] = p_constant; - - _emit_theme_changed(); -} - -int Theme::get_constant(const StringName &p_name, const StringName &p_theme_type) const { - if (constant_map.has(p_theme_type) && constant_map[p_theme_type].has(p_name)) { - return constant_map[p_theme_type][p_name]; - } else { - return 0; - } -} - -bool Theme::has_constant(const StringName &p_name, const StringName &p_theme_type) const { - return (constant_map.has(p_theme_type) && constant_map[p_theme_type].has(p_name)); -} - -bool Theme::has_constant_nocheck(const StringName &p_name, const StringName &p_theme_type) const { - return (constant_map.has(p_theme_type) && constant_map[p_theme_type].has(p_name)); -} - -void Theme::rename_constant(const StringName &p_old_name, const StringName &p_name, const StringName &p_theme_type) { - ERR_FAIL_COND_MSG(!constant_map.has(p_theme_type), "Cannot rename the constant '" + String(p_old_name) + "' because the node type '" + String(p_theme_type) + "' does not exist."); - ERR_FAIL_COND_MSG(constant_map[p_theme_type].has(p_name), "Cannot rename the constant '" + String(p_old_name) + "' because the new name '" + String(p_name) + "' already exists."); - ERR_FAIL_COND_MSG(!constant_map[p_theme_type].has(p_old_name), "Cannot rename the constant '" + String(p_old_name) + "' because it does not exist."); - - 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(); -} - -void Theme::clear_constant(const StringName &p_name, const StringName &p_theme_type) { - ERR_FAIL_COND_MSG(!constant_map.has(p_theme_type), "Cannot clear the constant '" + String(p_name) + "' because the node type '" + String(p_theme_type) + "' does not exist."); - ERR_FAIL_COND_MSG(!constant_map[p_theme_type].has(p_name), "Cannot clear the constant '" + String(p_name) + "' because it does not exist."); - - constant_map[p_theme_type].erase(p_name); - - _emit_theme_changed(); -} - -void Theme::get_constant_list(StringName p_theme_type, List *p_list) const { - ERR_FAIL_NULL(p_list); - - if (!constant_map.has(p_theme_type)) { - return; - } - - const StringName *key = nullptr; - - while ((key = constant_map[p_theme_type].next(key))) { - p_list->push_back(*key); - } -} - -void Theme::add_constant_type(const StringName &p_theme_type) { - if (constant_map.has(p_theme_type)) { - return; - } - constant_map[p_theme_type] = HashMap(); -} - -void Theme::get_constant_type_list(List *p_list) const { - ERR_FAIL_NULL(p_list); - - const StringName *key = nullptr; - while ((key = constant_map.next(key))) { - p_list->push_back(*key); - } -} - -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: { - ERR_FAIL_COND_MSG(p_value.get_type() != Variant::COLOR, "Theme item's data type (Color) does not match Variant's type (" + Variant::get_type_name(p_value.get_type()) + ")."); - - Color color_value = p_value; - set_color(p_name, p_theme_type, color_value); - } break; - case DATA_TYPE_CONSTANT: { - ERR_FAIL_COND_MSG(p_value.get_type() != Variant::INT, "Theme item's data type (int) does not match Variant's type (" + Variant::get_type_name(p_value.get_type()) + ")."); - - int constant_value = p_value; - set_constant(p_name, p_theme_type, constant_value); - } break; - case DATA_TYPE_FONT: { - ERR_FAIL_COND_MSG(p_value.get_type() != Variant::OBJECT, "Theme item's data type (Object) does not match Variant's type (" + Variant::get_type_name(p_value.get_type()) + ")."); - - Ref font_value = Object::cast_to(p_value.get_validated_object()); - set_font(p_name, p_theme_type, font_value); - } break; - case DATA_TYPE_FONT_SIZE: { - ERR_FAIL_COND_MSG(p_value.get_type() != Variant::INT, "Theme item's data type (int) does not match Variant's type (" + Variant::get_type_name(p_value.get_type()) + ")."); - - int font_size_value = p_value; - set_font_size(p_name, p_theme_type, font_size_value); - } break; - case DATA_TYPE_ICON: { - ERR_FAIL_COND_MSG(p_value.get_type() != Variant::OBJECT, "Theme item's data type (Object) does not match Variant's type (" + Variant::get_type_name(p_value.get_type()) + ")."); - - Ref icon_value = Object::cast_to(p_value.get_validated_object()); - set_icon(p_name, p_theme_type, icon_value); - } break; - case DATA_TYPE_STYLEBOX: { - ERR_FAIL_COND_MSG(p_value.get_type() != Variant::OBJECT, "Theme item's data type (Object) does not match Variant's type (" + Variant::get_type_name(p_value.get_type()) + ")."); - - Ref stylebox_value = Object::cast_to(p_value.get_validated_object()); - set_stylebox(p_name, p_theme_type, stylebox_value); - } break; - case DATA_TYPE_MAX: - break; // Can't happen, but silences warning. - } -} - -Variant Theme::get_theme_item(DataType p_data_type, const StringName &p_name, const StringName &p_theme_type) const { - switch (p_data_type) { - case DATA_TYPE_COLOR: - return get_color(p_name, p_theme_type); - case DATA_TYPE_CONSTANT: - return get_constant(p_name, p_theme_type); - case DATA_TYPE_FONT: - return get_font(p_name, p_theme_type); - case DATA_TYPE_FONT_SIZE: - return get_font_size(p_name, p_theme_type); - case DATA_TYPE_ICON: - return get_icon(p_name, p_theme_type); - case DATA_TYPE_STYLEBOX: - return get_stylebox(p_name, p_theme_type); - case DATA_TYPE_MAX: - break; // Can't happen, but silences warning. - } - - return Variant(); -} - -bool Theme::has_theme_item(DataType p_data_type, const StringName &p_name, const StringName &p_theme_type) const { - switch (p_data_type) { - case DATA_TYPE_COLOR: - return has_color(p_name, p_theme_type); - case DATA_TYPE_CONSTANT: - return has_constant(p_name, p_theme_type); - case DATA_TYPE_FONT: - return has_font(p_name, p_theme_type); - case DATA_TYPE_FONT_SIZE: - return has_font_size(p_name, p_theme_type); - case DATA_TYPE_ICON: - return has_icon(p_name, p_theme_type); - case DATA_TYPE_STYLEBOX: - return has_stylebox(p_name, p_theme_type); - case DATA_TYPE_MAX: - break; // Can't happen, but silences warning. - } - - return false; -} - -bool Theme::has_theme_item_nocheck(DataType p_data_type, const StringName &p_name, const StringName &p_theme_type) const { - switch (p_data_type) { - case DATA_TYPE_COLOR: - return has_color_nocheck(p_name, p_theme_type); - case DATA_TYPE_CONSTANT: - return has_constant_nocheck(p_name, p_theme_type); - case DATA_TYPE_FONT: - return has_font_nocheck(p_name, p_theme_type); - case DATA_TYPE_FONT_SIZE: - return has_font_size_nocheck(p_name, p_theme_type); - case DATA_TYPE_ICON: - return has_icon_nocheck(p_name, p_theme_type); - case DATA_TYPE_STYLEBOX: - return has_stylebox_nocheck(p_name, p_theme_type); - case DATA_TYPE_MAX: - break; // Can't happen, but silences warning. - } - - return false; -} - -void Theme::rename_theme_item(DataType p_data_type, const StringName &p_old_name, const StringName &p_name, const StringName &p_theme_type) { - switch (p_data_type) { - case DATA_TYPE_COLOR: - rename_color(p_old_name, p_name, p_theme_type); - break; - case DATA_TYPE_CONSTANT: - rename_constant(p_old_name, p_name, p_theme_type); - break; - case DATA_TYPE_FONT: - rename_font(p_old_name, p_name, p_theme_type); - break; - case DATA_TYPE_FONT_SIZE: - rename_font_size(p_old_name, p_name, p_theme_type); - break; - case DATA_TYPE_ICON: - rename_icon(p_old_name, p_name, p_theme_type); - break; - case DATA_TYPE_STYLEBOX: - rename_stylebox(p_old_name, p_name, p_theme_type); - break; - case DATA_TYPE_MAX: - break; // Can't happen, but silences warning. - } -} - -void Theme::clear_theme_item(DataType p_data_type, const StringName &p_name, const StringName &p_theme_type) { - switch (p_data_type) { - case DATA_TYPE_COLOR: - clear_color(p_name, p_theme_type); - break; - case DATA_TYPE_CONSTANT: - clear_constant(p_name, p_theme_type); - break; - case DATA_TYPE_FONT: - clear_font(p_name, p_theme_type); - break; - case DATA_TYPE_FONT_SIZE: - clear_font_size(p_name, p_theme_type); - break; - case DATA_TYPE_ICON: - clear_icon(p_name, p_theme_type); - break; - case DATA_TYPE_STYLEBOX: - clear_stylebox(p_name, p_theme_type); - break; - case DATA_TYPE_MAX: - break; // Can't happen, but silences warning. - } -} - -void Theme::get_theme_item_list(DataType p_data_type, StringName p_theme_type, List *p_list) const { - switch (p_data_type) { - case DATA_TYPE_COLOR: - get_color_list(p_theme_type, p_list); - break; - case DATA_TYPE_CONSTANT: - get_constant_list(p_theme_type, p_list); - break; - case DATA_TYPE_FONT: - get_font_list(p_theme_type, p_list); - break; - case DATA_TYPE_FONT_SIZE: - get_font_size_list(p_theme_type, p_list); - break; - case DATA_TYPE_ICON: - get_icon_list(p_theme_type, p_list); - break; - case DATA_TYPE_STYLEBOX: - get_stylebox_list(p_theme_type, p_list); - break; - case DATA_TYPE_MAX: - break; // Can't happen, but silences warning. - } -} - -void Theme::add_theme_item_type(DataType p_data_type, const StringName &p_theme_type) { - switch (p_data_type) { - case DATA_TYPE_COLOR: - add_color_type(p_theme_type); - break; - case DATA_TYPE_CONSTANT: - add_constant_type(p_theme_type); - break; - case DATA_TYPE_FONT: - add_font_type(p_theme_type); - break; - case DATA_TYPE_FONT_SIZE: - add_font_size_type(p_theme_type); - break; - case DATA_TYPE_ICON: - add_icon_type(p_theme_type); - break; - case DATA_TYPE_STYLEBOX: - add_stylebox_type(p_theme_type); - break; - case DATA_TYPE_MAX: - break; // Can't happen, but silences warning. - } -} - -void Theme::get_theme_item_type_list(DataType p_data_type, List *p_list) const { - switch (p_data_type) { - case DATA_TYPE_COLOR: - get_color_type_list(p_list); - break; - case DATA_TYPE_CONSTANT: - get_constant_type_list(p_list); - break; - case DATA_TYPE_FONT: - get_font_type_list(p_list); - break; - case DATA_TYPE_FONT_SIZE: - get_font_size_type_list(p_list); - break; - case DATA_TYPE_ICON: - get_icon_type_list(p_list); - break; - case DATA_TYPE_STYLEBOX: - get_stylebox_type_list(p_list); - break; - case DATA_TYPE_MAX: - break; // Can't happen, but silences warning. - } -} - -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."); - ERR_FAIL_COND_MSG(p_base_type == StringName(), "An empty theme type cannot be the base type of a variation. Use clear_type_variation() instead if you want to unmark '" + String(p_theme_type) + "' as a variation."); - - if (variation_map.has(p_theme_type)) { - StringName old_base = variation_map[p_theme_type]; - variation_base_map[old_base].erase(p_theme_type); - } - - variation_map[p_theme_type] = p_base_type; - variation_base_map[p_base_type].push_back(p_theme_type); - - _emit_theme_changed(); -} - -bool Theme::is_type_variation(const StringName &p_theme_type, const StringName &p_base_type) const { - return (variation_map.has(p_theme_type) && variation_map[p_theme_type] == p_base_type); -} - -void Theme::clear_type_variation(const StringName &p_theme_type) { - ERR_FAIL_COND_MSG(!variation_map.has(p_theme_type), "Cannot clear the type variation '" + String(p_theme_type) + "' because it does not exist."); - - StringName base_type = variation_map[p_theme_type]; - variation_base_map[base_type].erase(p_theme_type); - variation_map.erase(p_theme_type); - - _emit_theme_changed(); -} - -StringName Theme::get_type_variation_base(const StringName &p_theme_type) const { - if (!variation_map.has(p_theme_type)) { - return StringName(); - } - - return variation_map[p_theme_type]; -} - -void Theme::get_type_variation_list(const StringName &p_base_type, List *p_list) const { - ERR_FAIL_NULL(p_list); - - if (!variation_base_map.has(p_base_type)) { - return; - } - - for (const StringName &E : variation_base_map[p_base_type]) { - // Prevent infinite loops if variants were set to be cross-dependent (that's still invalid usage, but handling for stability sake). - if (p_list->find(E)) { - continue; - } - - p_list->push_back(E); - // Continue looking for sub-variations. - get_type_variation_list(E, p_list); - } + notify_property_list_changed(); + emit_changed(); } void Theme::_freeze_change_propagation() { @@ -1296,60 +1389,6 @@ void Theme::_unfreeze_and_propagate_changes() { _emit_theme_changed(); } -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 icon = icon_map[*K][*L]; - if (icon.is_valid()) { - icon->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed)); - } - } - } - } - - { - const StringName *K = nullptr; - while ((K = style_map.next(K))) { - const StringName *L = nullptr; - while ((L = style_map[*K].next(L))) { - Ref style = style_map[*K][*L]; - if (style.is_valid()) { - style->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed)); - } - } - } - } - - { - const StringName *K = nullptr; - while ((K = font_map.next(K))) { - const StringName *L = nullptr; - while ((L = font_map[*K].next(L))) { - Ref font = font_map[*K][*L]; - if (font.is_valid()) { - font->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed)); - } - } - } - } - - 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(); -} - void Theme::merge_with(const Ref &p_other) { if (p_other.is_null()) { return; @@ -1434,80 +1473,58 @@ void Theme::merge_with(const Ref &p_other) { _unfreeze_and_propagate_changes(); } -void Theme::get_type_list(List *p_list) const { - ERR_FAIL_NULL(p_list); - - Set 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::Element *E = types.front(); E; E = E->next()) { - p_list->push_back(E->get()); - } -} - -void Theme::get_type_dependencies(const StringName &p_base_type, const StringName &p_type_variation, List *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; +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 icon = icon_map[*K][*L]; + if (icon.is_valid()) { + icon->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 = style_map.next(K))) { + const StringName *L = nullptr; + while ((L = style_map[*K].next(L))) { + Ref style = style_map[*K][*L]; + if (style.is_valid()) { + style->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed)); + } + } + } } + + { + const StringName *K = nullptr; + while ((K = font_map.next(K))) { + const StringName *L = nullptr; + while ((L = font_map[*K].next(L))) { + Ref font = font_map[*K][*L]; + if (font.is_valid()) { + font->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed)); + } + } + } + } + + 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(); } void Theme::reset_state() { diff --git a/scene/resources/theme.h b/scene/resources/theme.h index 15f21b91b8d..35e466f899c 100644 --- a/scene/resources/theme.h +++ b/scene/resources/theme.h @@ -96,13 +96,17 @@ protected: bool _get(const StringName &p_name, Variant &r_ret) const; void _get_property_list(List *p_list) const; - static Ref project_default_theme; + // Universal Theme resources used when no other theme has the item. static Ref default_theme; + static Ref project_default_theme; + + // Universal default values, final fallback for every theme. static Ref default_icon; static Ref default_style; static Ref default_font; static int default_font_size; + // Default values configurable for each individual theme. Ref default_theme_font; int default_theme_font_size = -1; From 4a42a66cd92cbadac02bd1846ac4022dc8aaa44b Mon Sep 17 00:00:00 2001 From: Yuri Sizov Date: Sat, 2 Oct 2021 23:06:14 +0300 Subject: [PATCH 2/3] Add the base scale factor to the Theme resource --- doc/classes/Control.xml | 21 +++ doc/classes/Theme.xml | 28 +++- doc/classes/Window.xml | 15 ++ editor/editor_themes.cpp | 5 +- scene/gui/control.cpp | 154 +++++++++++++++++- scene/gui/control.h | 8 + scene/main/window.cpp | 16 ++ scene/main/window.h | 4 + .../resources/default_theme/default_theme.cpp | 9 +- scene/resources/theme.cpp | 46 +++++- scene/resources/theme.h | 9 + 11 files changed, 305 insertions(+), 10 deletions(-) diff --git a/doc/classes/Control.xml b/doc/classes/Control.xml index b00bf1c2508..6fa59a15ac1 100644 --- a/doc/classes/Control.xml +++ b/doc/classes/Control.xml @@ -458,6 +458,27 @@ See [method get_theme_color] for details. + + + + Returns the default base scale value from the first matching [Theme] in the tree if that [Theme] has a valid [member Theme.default_base_scale] value. + See [method get_theme_color] for details. + + + + + + Returns the default font from the first matching [Theme] in the tree if that [Theme] has a valid [member Theme.default_font] value. + See [method get_theme_color] for details. + + + + + + Returns the default font size value from the first matching [Theme] in the tree if that [Theme] has a valid [member Theme.default_font_size] value. + See [method get_theme_color] for details. + + diff --git a/doc/classes/Theme.xml b/doc/classes/Theme.xml index edf58744329..2f5648dda9e 100644 --- a/doc/classes/Theme.xml +++ b/doc/classes/Theme.xml @@ -273,6 +273,24 @@ Returns [code]false[/code] if the theme does not have [code]theme_type[/code]. + + + + Returns [code]true[/code] if this theme has a valid [member default_base_scale] value. + + + + + + Returns [code]true[/code] if this theme has a valid [member default_font] value. + + + + + + Returns [code]true[/code] if this theme has a valid [member default_font_size] value. + + @@ -484,11 +502,17 @@ + + The default base scale factor of this [Theme] resource. Used by some controls to scale their visual properties based on a global scale factor. If this value is set to [code]0.0[/code], the global scale factor is used. + Use [method has_default_base_scale] to check if this value is valid. + - The theme's default font. + The default font of this [Theme] resource. Used as a fallback value for font items defined in this theme, but having invalid values. If this value is also invalid, the global default value is used. + Use [method has_default_font] to check if this value is valid. - The theme's default font size. Set to [code]-1[/code] to ignore and use global default. + The default font size of this [Theme] resource. Used as a fallback value for font size items defined in this theme, but having invalid values. If this value is set to [code]-1[/code], the global default value is used. + Use [method has_default_font_size] to check if this value is valid. diff --git a/doc/classes/Window.xml b/doc/classes/Window.xml index 15d844aacb6..0653c8b4535 100644 --- a/doc/classes/Window.xml +++ b/doc/classes/Window.xml @@ -59,6 +59,21 @@ + + + + + + + + + + + + + + + diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp index 0579fb4cbd2..6efbcbc61ee 100644 --- a/editor/editor_themes.cpp +++ b/editor/editor_themes.cpp @@ -292,7 +292,8 @@ void editor_register_and_generate_icons(Ref p_theme, bool p_dark_theme = Ref create_editor_theme(const Ref p_theme) { Ref theme = Ref(memnew(Theme)); - const float default_contrast = 0.3; + // Controls may rely on the scale for their internal drawing logic. + theme->set_default_theme_base_scale(EDSCALE); // Theme settings Color accent_color = EDITOR_GET("interface/theme/accent_color"); @@ -310,6 +311,8 @@ Ref create_editor_theme(const Ref p_theme) { Color preset_base_color; float preset_contrast = 0; + const float default_contrast = 0.3; + // Please use alphabetical order if you're adding a new theme here // (after "Custom") diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp index 1b8b5e17eda..e2d3807b404 100644 --- a/scene/gui/control.cpp +++ b/scene/gui/control.cpp @@ -833,11 +833,12 @@ T Control::get_theme_item_in_types(Control *p_theme_owner, Window *p_theme_owner ERR_FAIL_COND_V_MSG(p_theme_types.size() == 0, T(), "At least one theme type must be specified."); // First, look through each control or window node in the branch, until no valid parent can be found. - // For each control iterate through its inheritance chain and see if p_name exists in any of them. + // Only nodes with a theme resource attached are considered. Control *theme_owner = p_theme_owner; Window *theme_owner_window = p_theme_owner_window; while (theme_owner || theme_owner_window) { + // For each theme resource check the theme types provided and see if p_name exists with any of them. for (const StringName &E : p_theme_types) { if (theme_owner && theme_owner->data.theme->has_theme_item(p_data_type, p_name, E)) { return theme_owner->data.theme->get_theme_item(p_data_type, p_name, E); @@ -888,11 +889,12 @@ bool Control::has_theme_item_in_types(Control *p_theme_owner, Window *p_theme_ow ERR_FAIL_COND_V_MSG(p_theme_types.size() == 0, false, "At least one theme type must be specified."); // First, look through each control or window node in the branch, until no valid parent can be found. - // For each control iterate through its inheritance chain and see if p_name exists in any of them. + // Only nodes with a theme resource attached are considered. Control *theme_owner = p_theme_owner; Window *theme_owner_window = p_theme_owner_window; while (theme_owner || theme_owner_window) { + // For each theme resource check the theme types provided and see if p_name exists with any of them. for (const StringName &E : p_theme_types) { if (theme_owner && theme_owner->data.theme->has_theme_item(p_data_type, p_name, E)) { return true; @@ -1130,6 +1132,150 @@ bool Control::has_theme_constant(const StringName &p_name, const StringName &p_t return has_theme_item_in_types(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_CONSTANT, p_name, theme_types); } +float Control::fetch_theme_default_base_scale(Control *p_theme_owner, Window *p_theme_owner_window) { + // First, look through each control or window node in the branch, until no valid parent can be found. + // Only nodes with a theme resource attached are considered. + // For each theme resource see if their assigned theme has the default value defined and valid. + Control *theme_owner = p_theme_owner; + Window *theme_owner_window = p_theme_owner_window; + + while (theme_owner || theme_owner_window) { + if (theme_owner && theme_owner->data.theme->has_default_theme_base_scale()) { + return theme_owner->data.theme->get_default_theme_base_scale(); + } + + if (theme_owner_window && theme_owner_window->theme->has_default_theme_base_scale()) { + return theme_owner_window->theme->get_default_theme_base_scale(); + } + + Node *parent = theme_owner ? theme_owner->get_parent() : theme_owner_window->get_parent(); + Control *parent_c = Object::cast_to(parent); + if (parent_c) { + theme_owner = parent_c->data.theme_owner; + theme_owner_window = parent_c->data.theme_owner_window; + } else { + Window *parent_w = Object::cast_to(parent); + if (parent_w) { + theme_owner = parent_w->theme_owner; + theme_owner_window = parent_w->theme_owner_window; + } else { + theme_owner = nullptr; + theme_owner_window = nullptr; + } + } + } + + // Secondly, check the project-defined Theme resource. + if (Theme::get_project_default().is_valid()) { + if (Theme::get_project_default()->has_default_theme_base_scale()) { + return Theme::get_project_default()->get_default_theme_base_scale(); + } + } + + // Lastly, fall back on the default Theme. + return Theme::get_default()->get_default_theme_base_scale(); +} + +float Control::get_theme_default_base_scale() const { + return fetch_theme_default_base_scale(data.theme_owner, data.theme_owner_window); +} + +Ref Control::fetch_theme_default_font(Control *p_theme_owner, Window *p_theme_owner_window) { + // First, look through each control or window node in the branch, until no valid parent can be found. + // Only nodes with a theme resource attached are considered. + // For each theme resource see if their assigned theme has the default value defined and valid. + Control *theme_owner = p_theme_owner; + Window *theme_owner_window = p_theme_owner_window; + + while (theme_owner || theme_owner_window) { + if (theme_owner && theme_owner->data.theme->has_default_theme_font()) { + return theme_owner->data.theme->get_default_theme_font(); + } + + if (theme_owner_window && theme_owner_window->theme->has_default_theme_font()) { + return theme_owner_window->theme->get_default_theme_font(); + } + + Node *parent = theme_owner ? theme_owner->get_parent() : theme_owner_window->get_parent(); + Control *parent_c = Object::cast_to(parent); + if (parent_c) { + theme_owner = parent_c->data.theme_owner; + theme_owner_window = parent_c->data.theme_owner_window; + } else { + Window *parent_w = Object::cast_to(parent); + if (parent_w) { + theme_owner = parent_w->theme_owner; + theme_owner_window = parent_w->theme_owner_window; + } else { + theme_owner = nullptr; + theme_owner_window = nullptr; + } + } + } + + // Secondly, check the project-defined Theme resource. + if (Theme::get_project_default().is_valid()) { + if (Theme::get_project_default()->has_default_theme_font()) { + return Theme::get_project_default()->get_default_theme_font(); + } + } + + // Lastly, fall back on the default Theme. + return Theme::get_default()->get_default_theme_font(); +} + +Ref Control::get_theme_default_font() const { + return fetch_theme_default_font(data.theme_owner, data.theme_owner_window); +} + +int Control::fetch_theme_default_font_size(Control *p_theme_owner, Window *p_theme_owner_window) { + // First, look through each control or window node in the branch, until no valid parent can be found. + // Only nodes with a theme resource attached are considered. + // For each theme resource see if their assigned theme has the default value defined and valid. + Control *theme_owner = p_theme_owner; + Window *theme_owner_window = p_theme_owner_window; + + while (theme_owner || theme_owner_window) { + if (theme_owner && theme_owner->data.theme->has_default_theme_font_size()) { + return theme_owner->data.theme->get_default_theme_font_size(); + } + + if (theme_owner_window && theme_owner_window->theme->has_default_theme_font_size()) { + return theme_owner_window->theme->get_default_theme_font_size(); + } + + Node *parent = theme_owner ? theme_owner->get_parent() : theme_owner_window->get_parent(); + Control *parent_c = Object::cast_to(parent); + if (parent_c) { + theme_owner = parent_c->data.theme_owner; + theme_owner_window = parent_c->data.theme_owner_window; + } else { + Window *parent_w = Object::cast_to(parent); + if (parent_w) { + theme_owner = parent_w->theme_owner; + theme_owner_window = parent_w->theme_owner_window; + } else { + theme_owner = nullptr; + theme_owner_window = nullptr; + } + } + } + + // Secondly, check the project-defined Theme resource. + if (Theme::get_project_default().is_valid()) { + if (Theme::get_project_default()->has_default_theme_font_size()) { + return Theme::get_project_default()->get_default_theme_font_size(); + } + } + + // Lastly, fall back on the default Theme. + return Theme::get_default()->get_default_theme_font_size(); +} + +int Control::get_theme_default_font_size() const { + return fetch_theme_default_font_size(data.theme_owner, data.theme_owner_window); +} + Rect2 Control::get_parent_anchorable_rect() const { if (!is_inside_tree()) { return Rect2(); @@ -2789,6 +2935,10 @@ void Control::_bind_methods() { ClassDB::bind_method(D_METHOD("has_theme_color", "name", "theme_type"), &Control::has_theme_color, DEFVAL("")); ClassDB::bind_method(D_METHOD("has_theme_constant", "name", "theme_type"), &Control::has_theme_constant, DEFVAL("")); + ClassDB::bind_method(D_METHOD("get_theme_default_base_scale"), &Control::get_theme_default_base_scale); + ClassDB::bind_method(D_METHOD("get_theme_default_font"), &Control::get_theme_default_font); + ClassDB::bind_method(D_METHOD("get_theme_default_font_size"), &Control::get_theme_default_font_size); + ClassDB::bind_method(D_METHOD("get_parent_control"), &Control::get_parent_control); ClassDB::bind_method(D_METHOD("set_h_grow_direction", "direction"), &Control::set_h_grow_direction); diff --git a/scene/gui/control.h b/scene/gui/control.h index 87ff3918cb8..bdc06319ea6 100644 --- a/scene/gui/control.h +++ b/scene/gui/control.h @@ -509,6 +509,14 @@ public: bool has_theme_color(const StringName &p_name, const StringName &p_theme_type = StringName()) const; bool has_theme_constant(const StringName &p_name, const StringName &p_theme_type = StringName()) const; + static float fetch_theme_default_base_scale(Control *p_theme_owner, Window *p_theme_owner_window); + static Ref fetch_theme_default_font(Control *p_theme_owner, Window *p_theme_owner_window); + static int fetch_theme_default_font_size(Control *p_theme_owner, Window *p_theme_owner_window); + + float get_theme_default_base_scale() const; + Ref get_theme_default_font() const; + int get_theme_default_font_size() const; + /* TOOLTIP */ void set_tooltip(const String &p_tooltip); diff --git a/scene/main/window.cpp b/scene/main/window.cpp index ca5a3915d0a..a0f62c853f1 100644 --- a/scene/main/window.cpp +++ b/scene/main/window.cpp @@ -1266,6 +1266,18 @@ bool Window::has_theme_constant(const StringName &p_name, const StringName &p_th return Control::has_theme_item_in_types(theme_owner, theme_owner_window, Theme::DATA_TYPE_CONSTANT, p_name, theme_types); } +float Window::get_theme_default_base_scale() const { + return Control::fetch_theme_default_base_scale(theme_owner, theme_owner_window); +} + +Ref Window::get_theme_default_font() const { + return Control::fetch_theme_default_font(theme_owner, theme_owner_window); +} + +int Window::get_theme_default_font_size() const { + return Control::fetch_theme_default_font_size(theme_owner, theme_owner_window); +} + Rect2i Window::get_parent_rect() const { ERR_FAIL_COND_V(!is_inside_tree(), Rect2i()); if (is_embedded()) { @@ -1480,6 +1492,10 @@ void Window::_bind_methods() { ClassDB::bind_method(D_METHOD("has_theme_color", "name", "theme_type"), &Window::has_theme_color, DEFVAL("")); ClassDB::bind_method(D_METHOD("has_theme_constant", "name", "theme_type"), &Window::has_theme_constant, DEFVAL("")); + ClassDB::bind_method(D_METHOD("get_theme_default_base_scale"), &Window::get_theme_default_base_scale); + ClassDB::bind_method(D_METHOD("get_theme_default_font"), &Window::get_theme_default_font); + ClassDB::bind_method(D_METHOD("get_theme_default_font_size"), &Window::get_theme_default_font_size); + ClassDB::bind_method(D_METHOD("set_layout_direction", "direction"), &Window::set_layout_direction); ClassDB::bind_method(D_METHOD("get_layout_direction"), &Window::get_layout_direction); ClassDB::bind_method(D_METHOD("is_layout_rtl"), &Window::is_layout_rtl); diff --git a/scene/main/window.h b/scene/main/window.h index 4f31d9cd1f3..def6eab7b8b 100644 --- a/scene/main/window.h +++ b/scene/main/window.h @@ -280,6 +280,10 @@ public: bool has_theme_color(const StringName &p_name, const StringName &p_theme_type = StringName()) const; bool has_theme_constant(const StringName &p_name, const StringName &p_theme_type = StringName()) const; + float get_theme_default_base_scale() const; + Ref get_theme_default_font() const; + int get_theme_default_font_size() const; + Rect2i get_parent_rect() const; virtual DisplayServer::WindowID get_window_id() const override; diff --git a/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp index 94cf8264775..54bb7a82cfd 100644 --- a/scene/resources/default_theme/default_theme.cpp +++ b/scene/resources/default_theme/default_theme.cpp @@ -1036,9 +1036,16 @@ void make_default_theme(bool p_hidpi, Ref p_font) { } Ref large_font = default_font; - fill_default_theme(t, default_font, large_font, default_icon, default_style, p_hidpi ? 2.0 : 1.0); + + float default_scale = 1.0; + if (p_hidpi) { + default_scale = 2.0; + } + + fill_default_theme(t, default_font, large_font, default_icon, default_style, default_scale); Theme::set_default(t); + Theme::set_default_base_scale(default_scale); Theme::set_default_icon(default_icon); Theme::set_default_style(default_style); Theme::set_default_font(default_font); diff --git a/scene/resources/theme.cpp b/scene/resources/theme.cpp index dab08d48c2a..dd5f0b9c6c0 100644 --- a/scene/resources/theme.cpp +++ b/scene/resources/theme.cpp @@ -36,6 +36,7 @@ Ref Theme::default_theme; Ref Theme::project_default_theme; // Universal default values, final fallback for every theme. +float Theme::default_base_scale = 1.0; Ref Theme::default_icon; Ref Theme::default_style; Ref Theme::default_font; @@ -219,6 +220,10 @@ void Theme::set_project_default(const Ref &p_project_default) { } // Universal fallback values for theme item types. +void Theme::set_default_base_scale(float p_base_scale) { + default_base_scale = p_base_scale; +} + void Theme::set_default_icon(const Ref &p_icon) { default_icon = p_icon; } @@ -236,6 +241,24 @@ void Theme::set_default_font_size(int p_font_size) { } // Fallback values for theme item types, configurable per theme. +void Theme::set_default_theme_base_scale(float p_base_scale) { + if (default_theme_base_scale == p_base_scale) { + return; + } + + default_theme_base_scale = p_base_scale; + + _emit_theme_changed(); +} + +float Theme::get_default_theme_base_scale() const { + return default_theme_base_scale; +} + +bool Theme::has_default_theme_base_scale() const { + return default_theme_base_scale > 0.0; +} + void Theme::set_default_theme_font(const Ref &p_default_font) { if (default_theme_font == p_default_font) { return; @@ -258,6 +281,10 @@ Ref Theme::get_default_theme_font() const { return default_theme_font; } +bool Theme::has_default_theme_font() const { + return default_theme_font.is_valid(); +} + void Theme::set_default_theme_font_size(int p_font_size) { if (default_theme_font_size == p_font_size) { return; @@ -272,6 +299,10 @@ int Theme::get_default_theme_font_size() const { return default_theme_font_size; } +bool Theme::has_default_theme_font_size() const { + return default_theme_font_size > 0; +} + // Icons. void Theme::set_icon(const StringName &p_name, const StringName &p_theme_type, const Ref &p_icon) { if (icon_map[p_theme_type].has(p_name) && icon_map[p_theme_type][p_name].is_valid()) { @@ -460,7 +491,7 @@ void Theme::set_font(const StringName &p_name, const StringName &p_theme_type, c Ref Theme::get_font(const StringName &p_name, const StringName &p_theme_type) const { if (font_map.has(p_theme_type) && font_map[p_theme_type].has(p_name) && font_map[p_theme_type][p_name].is_valid()) { return font_map[p_theme_type][p_name]; - } else if (default_theme_font.is_valid()) { + } else if (has_default_theme_font()) { return default_theme_font; } else { return default_font; @@ -468,7 +499,7 @@ Ref Theme::get_font(const StringName &p_name, const StringName &p_theme_ty } bool Theme::has_font(const StringName &p_name, const StringName &p_theme_type) const { - return ((font_map.has(p_theme_type) && font_map[p_theme_type].has(p_name) && font_map[p_theme_type][p_name].is_valid()) || default_theme_font.is_valid()); + return ((font_map.has(p_theme_type) && font_map[p_theme_type].has(p_name) && font_map[p_theme_type][p_name].is_valid()) || has_default_theme_font()); } bool Theme::has_font_nocheck(const StringName &p_name, const StringName &p_theme_type) const { @@ -539,7 +570,7 @@ void Theme::set_font_size(const StringName &p_name, const StringName &p_theme_ty int Theme::get_font_size(const StringName &p_name, const StringName &p_theme_type) const { if (font_size_map.has(p_theme_type) && font_size_map[p_theme_type].has(p_name) && (font_size_map[p_theme_type][p_name] > 0)) { return font_size_map[p_theme_type][p_name]; - } else if (default_theme_font_size > 0) { + } else if (has_default_theme_font_size()) { return default_theme_font_size; } else { return default_font_size; @@ -547,7 +578,7 @@ int Theme::get_font_size(const StringName &p_name, const StringName &p_theme_typ } bool Theme::has_font_size(const StringName &p_name, const StringName &p_theme_type) const { - return ((font_size_map.has(p_theme_type) && font_size_map[p_theme_type].has(p_name) && (font_size_map[p_theme_type][p_name] > 0)) || (default_theme_font_size > 0)); + return ((font_size_map.has(p_theme_type) && font_size_map[p_theme_type].has(p_name) && (font_size_map[p_theme_type][p_name] > 0)) || has_default_theme_font_size()); } bool Theme::has_font_size_nocheck(const StringName &p_name, const StringName &p_theme_type) const { @@ -1580,11 +1611,17 @@ void Theme::_bind_methods() { ClassDB::bind_method(D_METHOD("get_constant_list", "theme_type"), &Theme::_get_constant_list); ClassDB::bind_method(D_METHOD("get_constant_type_list"), &Theme::_get_constant_type_list); + ClassDB::bind_method(D_METHOD("set_default_base_scale", "font_size"), &Theme::set_default_theme_base_scale); + ClassDB::bind_method(D_METHOD("get_default_base_scale"), &Theme::get_default_theme_base_scale); + ClassDB::bind_method(D_METHOD("has_default_base_scale"), &Theme::has_default_theme_base_scale); + ClassDB::bind_method(D_METHOD("set_default_font", "font"), &Theme::set_default_theme_font); ClassDB::bind_method(D_METHOD("get_default_font"), &Theme::get_default_theme_font); + ClassDB::bind_method(D_METHOD("has_default_font"), &Theme::has_default_theme_font); ClassDB::bind_method(D_METHOD("set_default_font_size", "font_size"), &Theme::set_default_theme_font_size); ClassDB::bind_method(D_METHOD("get_default_font_size"), &Theme::get_default_theme_font_size); + ClassDB::bind_method(D_METHOD("has_default_font_size"), &Theme::has_default_theme_font_size); ClassDB::bind_method(D_METHOD("set_theme_item", "data_type", "name", "theme_type", "value"), &Theme::set_theme_item); ClassDB::bind_method(D_METHOD("get_theme_item", "data_type", "name", "theme_type"), &Theme::get_theme_item); @@ -1605,6 +1642,7 @@ void Theme::_bind_methods() { ClassDB::bind_method(D_METHOD("merge_with", "other"), &Theme::merge_with); ClassDB::bind_method(D_METHOD("clear"), &Theme::clear); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "default_base_scale", PROPERTY_HINT_RANGE, "0.0,2.0,0.01,or_greater"), "set_default_base_scale", "get_default_base_scale"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "default_font", PROPERTY_HINT_RESOURCE_TYPE, "Font"), "set_default_font", "get_default_font"); ADD_PROPERTY(PropertyInfo(Variant::INT, "default_font_size"), "set_default_font_size", "get_default_font_size"); diff --git a/scene/resources/theme.h b/scene/resources/theme.h index 35e466f899c..50466d99c23 100644 --- a/scene/resources/theme.h +++ b/scene/resources/theme.h @@ -101,12 +101,14 @@ protected: static Ref project_default_theme; // Universal default values, final fallback for every theme. + static float default_base_scale; static Ref default_icon; static Ref default_style; static Ref default_font; static int default_font_size; // Default values configurable for each individual theme. + float default_theme_base_scale = 0.0; Ref default_theme_font; int default_theme_font_size = -1; @@ -124,16 +126,23 @@ public: static Ref get_project_default(); static void set_project_default(const Ref &p_project_default); + static void set_default_base_scale(float p_base_scale); static void set_default_icon(const Ref &p_icon); static void set_default_style(const Ref &p_style); static void set_default_font(const Ref &p_font); static void set_default_font_size(int p_font_size); + void set_default_theme_base_scale(float p_base_scale); + float get_default_theme_base_scale() const; + bool has_default_theme_base_scale() const; + void set_default_theme_font(const Ref &p_default_font); Ref get_default_theme_font() const; + bool has_default_theme_font() const; void set_default_theme_font_size(int p_font_size); int get_default_theme_font_size() const; + bool has_default_theme_font_size() const; void set_icon(const StringName &p_name, const StringName &p_theme_type, const Ref &p_icon); Ref get_icon(const StringName &p_name, const StringName &p_theme_type) const; From bdbb7b3999cddc821489d11350ad21bf89af5a42 Mon Sep 17 00:00:00 2001 From: Yuri Sizov Date: Sat, 2 Oct 2021 23:07:42 +0300 Subject: [PATCH 3/3] Remove EDSCALE dependency from /scene/gui --- scene/gui/color_picker.cpp | 53 ++++++++++++++++------------------- scene/gui/color_picker.h | 1 + scene/gui/dialogs.cpp | 6 ++-- scene/gui/gradient_edit.cpp | 41 +++++++++++++-------------- scene/gui/gradient_edit.h | 7 +++++ scene/gui/graph_edit.cpp | 16 ++--------- scene/gui/line_edit.cpp | 7 +---- scene/gui/rich_text_label.cpp | 14 ++------- scene/gui/text_edit.cpp | 12 ++------ scene/gui/tree.cpp | 18 ++++-------- scene/gui/tree.h | 2 ++ 11 files changed, 68 insertions(+), 109 deletions(-) diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp index 611035fff90..54548e19416 100644 --- a/scene/gui/color_picker.cpp +++ b/scene/gui/color_picker.cpp @@ -35,7 +35,6 @@ #include "core/os/os.h" #ifdef TOOLS_ENABLED -#include "editor/editor_scale.h" #include "editor/editor_settings.h" #endif #include "scene/main/window.h" @@ -44,17 +43,7 @@ List ColorPicker::preset_cache; void ColorPicker::_notification(int p_what) { switch (p_what) { - case NOTIFICATION_THEME_CHANGED: { - btn_pick->set_icon(get_theme_icon(SNAME("screen_picker"), SNAME("ColorPicker"))); - btn_add_preset->set_icon(get_theme_icon(SNAME("add_preset"))); - _update_presets(); - _update_controls(); - } break; case NOTIFICATION_ENTER_TREE: { - btn_pick->set_icon(get_theme_icon(SNAME("screen_picker"), SNAME("ColorPicker"))); - btn_add_preset->set_icon(get_theme_icon(SNAME("add_preset"))); - - _update_controls(); _update_color(); #ifdef TOOLS_ENABLED @@ -71,18 +60,39 @@ void ColorPicker::_notification(int p_what) { } } #endif - } break; - case NOTIFICATION_PARENTED: { + [[fallthrough]]; + } + case NOTIFICATION_THEME_CHANGED: { + btn_pick->set_icon(get_theme_icon(SNAME("screen_picker"), SNAME("ColorPicker"))); + btn_add_preset->set_icon(get_theme_icon(SNAME("add_preset"))); + + uv_edit->set_custom_minimum_size(Size2(get_theme_constant(SNAME("sv_width")), get_theme_constant(SNAME("sv_height")))); + w_edit->set_custom_minimum_size(Size2(get_theme_constant(SNAME("h_width")), 0)); + + wheel_edit->set_custom_minimum_size(Size2(get_theme_constant(SNAME("sv_width")), get_theme_constant(SNAME("sv_height")))); + wheel_margin->add_theme_constant_override("margin_bottom", 8 * get_theme_default_base_scale()); + for (int i = 0; i < 4; i++) { + labels[i]->set_custom_minimum_size(Size2(get_theme_constant(SNAME("label_width")), 0)); set_offset((Side)i, get_offset((Side)i) + get_theme_constant(SNAME("margin"))); } + + if (Engine::get_singleton()->is_editor_hint()) { + // Adjust for the width of the "Script" icon. + text_type->set_custom_minimum_size(Size2(28 * get_theme_default_base_scale(), 0)); + } + + _update_presets(); + _update_controls(); } break; + case NOTIFICATION_VISIBILITY_CHANGED: { Popup *p = Object::cast_to(get_parent()); if (p) { p->set_size(Size2(get_combined_minimum_size().width + get_theme_constant(SNAME("margin")) * 2, get_combined_minimum_size().height + get_theme_constant(SNAME("margin")) * 2)); } } break; + case NOTIFICATION_WM_CLOSE_REQUEST: { if (screen != nullptr && screen->is_visible()) { screen->hide(); @@ -762,11 +772,7 @@ void ColorPicker::_slider_draw(int p_which) { Size2 size = scroll[p_which]->get_size(); Color left_color; Color right_color; -#ifdef TOOLS_ENABLED - const real_t margin = 4 * EDSCALE; -#else - const real_t margin = 4; -#endif + const real_t margin = 4 * get_theme_default_base_scale(); if (p_which == 3) { scroll[p_which]->draw_texture_rect(get_theme_icon(SNAME("sample_bg"), SNAME("ColorPicker")), Rect2(Point2(0, margin), Size2(size.x, margin)), true); @@ -1147,7 +1153,6 @@ ColorPicker::ColorPicker() : uv_edit->set_mouse_filter(MOUSE_FILTER_PASS); uv_edit->set_h_size_flags(SIZE_EXPAND_FILL); uv_edit->set_v_size_flags(SIZE_EXPAND_FILL); - uv_edit->set_custom_minimum_size(Size2(get_theme_constant(SNAME("sv_width")), get_theme_constant(SNAME("sv_height")))); uv_edit->connect("draw", callable_mp(this, &ColorPicker::_hsv_draw), make_binds(0, uv_edit)); HBoxContainer *hb_smpl = memnew(HBoxContainer); @@ -1219,9 +1224,6 @@ ColorPicker::ColorPicker() : text_type->set_text("#"); text_type->set_tooltip(TTR("Switch between hexadecimal and code values.")); if (Engine::get_singleton()->is_editor_hint()) { -#ifdef TOOLS_ENABLED - text_type->set_custom_minimum_size(Size2(28 * EDSCALE, 0)); // Adjust for the width of the "Script" icon. -#endif text_type->connect("pressed", callable_mp(this, &ColorPicker::_text_type_toggled)); } else { text_type->set_flat(true); @@ -1236,7 +1238,6 @@ ColorPicker::ColorPicker() : wheel_edit->set_h_size_flags(SIZE_EXPAND_FILL); wheel_edit->set_v_size_flags(SIZE_EXPAND_FILL); - wheel_edit->set_custom_minimum_size(Size2(get_theme_constant(SNAME("sv_width")), get_theme_constant(SNAME("sv_height")))); hb_edit->add_child(wheel_edit); wheel_mat.instantiate(); @@ -1244,12 +1245,7 @@ ColorPicker::ColorPicker() : circle_mat.instantiate(); circle_mat->set_shader(circle_shader); - MarginContainer *wheel_margin(memnew(MarginContainer)); -#ifdef TOOLS_ENABLED - wheel_margin->add_theme_constant_override("margin_bottom", 8 * EDSCALE); -#else wheel_margin->add_theme_constant_override("margin_bottom", 8); -#endif wheel_edit->add_child(wheel_margin); wheel_margin->add_child(wheel); @@ -1261,7 +1257,6 @@ ColorPicker::ColorPicker() : wheel_uv->connect("draw", callable_mp(this, &ColorPicker::_hsv_draw), make_binds(0, wheel_uv)); hb_edit->add_child(w_edit); - w_edit->set_custom_minimum_size(Size2(get_theme_constant(SNAME("h_width")), 0)); w_edit->set_h_size_flags(SIZE_FILL); w_edit->set_v_size_flags(SIZE_EXPAND_FILL); w_edit->connect("gui_input", callable_mp(this, &ColorPicker::_w_input)); diff --git a/scene/gui/color_picker.h b/scene/gui/color_picker.h index 67ca007eb51..ad4f5ad5b1b 100644 --- a/scene/gui/color_picker.h +++ b/scene/gui/color_picker.h @@ -81,6 +81,7 @@ private: Control *uv_edit = memnew(Control); Control *w_edit = memnew(Control); AspectRatioContainer *wheel_edit = memnew(AspectRatioContainer); + MarginContainer *wheel_margin = memnew(MarginContainer); Ref wheel_mat; Ref circle_mat; Control *wheel = memnew(Control); diff --git a/scene/gui/dialogs.cpp b/scene/gui/dialogs.cpp index 5d98aaa6982..71d2778cc30 100644 --- a/scene/gui/dialogs.cpp +++ b/scene/gui/dialogs.cpp @@ -37,7 +37,6 @@ #ifdef TOOLS_ENABLED #include "editor/editor_node.h" -#include "editor/editor_scale.h" #include "scene/main/window.h" // Only used to check for more modals when dimming the editor. #endif @@ -363,8 +362,7 @@ Button *ConfirmationDialog::get_cancel_button() { ConfirmationDialog::ConfirmationDialog() { set_title(TTRC("Please Confirm...")); -#ifdef TOOLS_ENABLED - set_min_size(Size2(200, 70) * EDSCALE); -#endif + set_min_size(Size2(200, 70)); + cancel = add_cancel_button(); } diff --git a/scene/gui/gradient_edit.cpp b/scene/gui/gradient_edit.cpp index 56b8a936e1b..5d024d3be73 100644 --- a/scene/gui/gradient_edit.cpp +++ b/scene/gui/gradient_edit.cpp @@ -32,15 +32,6 @@ #include "core/os/keyboard.h" -#ifdef TOOLS_ENABLED -#include "editor/editor_scale.h" -#define SPACING (3 * EDSCALE) -#define POINT_WIDTH (8 * EDSCALE) -#else -#define SPACING 3 -#define POINT_WIDTH 8 -#endif - GradientEdit::GradientEdit() { set_focus_mode(FOCUS_ALL); @@ -53,12 +44,12 @@ GradientEdit::GradientEdit() { int GradientEdit::_get_point_from_pos(int x) { int result = -1; - int total_w = get_size().width - get_size().height - SPACING; + int total_w = get_size().width - get_size().height - draw_spacing; float min_distance = 1e20; for (int i = 0; i < points.size(); i++) { //Check if we clicked at point float distance = ABS(x - points[i].offset * total_w); - float min = (POINT_WIDTH / 2 * 1.7); //make it easier to grab + float min = (draw_point_width / 2 * 1.7); //make it easier to grab if (distance <= min && distance < min_distance) { result = i; min_distance = distance; @@ -129,7 +120,7 @@ void GradientEdit::gui_input(const Ref &p_event) { grabbed = _get_point_from_pos(x); if (grabbed != -1) { - int total_w = get_size().width - get_size().height - SPACING; + int total_w = get_size().width - get_size().height - draw_spacing; Gradient::Point newPoint = points[grabbed]; newPoint.offset = CLAMP(x / float(total_w), 0, 1); @@ -151,10 +142,10 @@ void GradientEdit::gui_input(const Ref &p_event) { if (mb.is_valid() && mb->get_button_index() == 1 && mb->is_pressed()) { update(); int x = mb->get_position().x; - int total_w = get_size().width - get_size().height - SPACING; + int total_w = get_size().width - get_size().height - draw_spacing; //Check if color selector was clicked. - if (x > total_w + SPACING) { + if (x > total_w + draw_spacing) { _show_color_picker(); return; } @@ -225,7 +216,7 @@ void GradientEdit::gui_input(const Ref &p_event) { Ref mm = p_event; if (mm.is_valid() && grabbing) { - int total_w = get_size().width - get_size().height - SPACING; + int total_w = get_size().width - get_size().height - draw_spacing; int x = mm->get_position().x; @@ -297,6 +288,12 @@ void GradientEdit::_notification(int p_what) { picker->connect("color_changed", callable_mp(this, &GradientEdit::_color_changed)); } } + + if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) { + draw_spacing = BASE_SPACING * get_theme_default_base_scale(); + draw_point_width = BASE_POINT_WIDTH * get_theme_default_base_scale(); + } + if (p_what == NOTIFICATION_DRAW) { int w = get_size().x; int h = get_size().y; @@ -305,7 +302,7 @@ void GradientEdit::_notification(int p_what) { return; //Safety check. We have division by 'h'. And in any case there is nothing to draw with such size } - int total_w = get_size().width - get_size().height - SPACING; + int total_w = get_size().width - get_size().height - draw_spacing; //Draw checker pattern for ramp draw_texture_rect(get_theme_icon(SNAME("GuiMiniCheckerboard"), SNAME("EditorIcons")), Rect2(0, 0, total_w, h), true); @@ -358,7 +355,7 @@ void GradientEdit::_notification(int p_what) { col.a = 0.9; draw_line(Vector2(points[i].offset * total_w, 0), Vector2(points[i].offset * total_w, h / 2), col); - Rect2 rect = Rect2(points[i].offset * total_w - POINT_WIDTH / 2, h / 2, POINT_WIDTH, h / 2); + Rect2 rect = Rect2(points[i].offset * total_w - draw_point_width / 2, h / 2, draw_point_width, h / 2); draw_rect(rect, points[i].color, true); draw_rect(rect, col, false); if (grabbed == i) { @@ -375,15 +372,15 @@ void GradientEdit::_notification(int p_what) { } //Draw "button" for color selector - draw_texture_rect(get_theme_icon(SNAME("GuiMiniCheckerboard"), SNAME("EditorIcons")), Rect2(total_w + SPACING, 0, h, h), true); + draw_texture_rect(get_theme_icon(SNAME("GuiMiniCheckerboard"), SNAME("EditorIcons")), Rect2(total_w + draw_spacing, 0, h, h), true); if (grabbed != -1) { //Draw with selection color - draw_rect(Rect2(total_w + SPACING, 0, h, h), points[grabbed].color); + draw_rect(Rect2(total_w + draw_spacing, 0, h, h), points[grabbed].color); } else { //if no color selected draw grey color with 'X' on top. - draw_rect(Rect2(total_w + SPACING, 0, h, h), Color(0.5, 0.5, 0.5, 1)); - draw_line(Vector2(total_w + SPACING, 0), Vector2(total_w + SPACING + h, h), Color(1, 1, 1, 0.6)); - draw_line(Vector2(total_w + SPACING, h), Vector2(total_w + SPACING + h, 0), Color(1, 1, 1, 0.6)); + draw_rect(Rect2(total_w + draw_spacing, 0, h, h), Color(0.5, 0.5, 0.5, 1)); + draw_line(Vector2(total_w + draw_spacing, 0), Vector2(total_w + draw_spacing + h, h), Color(1, 1, 1, 0.6)); + draw_line(Vector2(total_w + draw_spacing, h), Vector2(total_w + draw_spacing + h, 0), Color(1, 1, 1, 0.6)); } //Draw borders around color ramp if in focus diff --git a/scene/gui/gradient_edit.h b/scene/gui/gradient_edit.h index a1736319639..f3a39daaf68 100644 --- a/scene/gui/gradient_edit.h +++ b/scene/gui/gradient_edit.h @@ -46,6 +46,13 @@ class GradientEdit : public Control { int grabbed = -1; Vector points; + // Make sure to use the scaled value below. + const int BASE_SPACING = 3; + const int BASE_POINT_WIDTH = 8; + + int draw_spacing = BASE_SPACING; + int draw_point_width = BASE_POINT_WIDTH; + void _draw_checker(int x, int y, int w, int h); void _color_changed(const Color &p_color); int _get_point_from_pos(int x); diff --git a/scene/gui/graph_edit.cpp b/scene/gui/graph_edit.cpp index d9c08ec272a..35e31be9af4 100644 --- a/scene/gui/graph_edit.cpp +++ b/scene/gui/graph_edit.cpp @@ -36,10 +36,6 @@ #include "scene/gui/box_container.h" #include "scene/gui/button.h" -#ifdef TOOLS_ENABLED -#include "editor/editor_scale.h" -#endif - constexpr int MINIMAP_OFFSET = 12; constexpr int MINIMAP_PADDING = 5; @@ -436,6 +432,8 @@ void GraphEdit::_notification(int p_what) { snap_button->set_icon(get_theme_icon(SNAME("snap"))); minimap_button->set_icon(get_theme_icon(SNAME("minimap"))); layout_button->set_icon(get_theme_icon(SNAME("layout"))); + + zoom_label->set_custom_minimum_size(Size2(48, 0) * get_theme_default_base_scale()); } if (p_what == NOTIFICATION_READY) { Size2 hmin = h_scroll->get_combined_minimum_size(); @@ -816,11 +814,7 @@ void GraphEdit::_draw_connection_line(CanvasItem *p_where, const Vector2 &p_from scaled_points.push_back(points[i] * p_zoom); } -#ifdef TOOLS_ENABLED - p_where->draw_polyline_colors(scaled_points, colors, Math::floor(p_width * EDSCALE), lines_antialiased); -#else - p_where->draw_polyline_colors(scaled_points, colors, p_width, lines_antialiased); -#endif + p_where->draw_polyline_colors(scaled_points, colors, Math::floor(p_width * get_theme_default_base_scale()), lines_antialiased); } void GraphEdit::_connections_layer_draw() { @@ -2272,11 +2266,7 @@ GraphEdit::GraphEdit() { zoom_label->set_visible(false); zoom_label->set_v_size_flags(Control::SIZE_SHRINK_CENTER); zoom_label->set_align(Label::ALIGN_CENTER); -#ifdef TOOLS_ENABLED - zoom_label->set_custom_minimum_size(Size2(48, 0) * EDSCALE); -#else zoom_label->set_custom_minimum_size(Size2(48, 0)); -#endif _update_zoom_label(); zoom_minus = memnew(Button); diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp index 2c1092d8f95..653885aa081 100644 --- a/scene/gui/line_edit.cpp +++ b/scene/gui/line_edit.cpp @@ -40,7 +40,6 @@ #include "servers/display_server.h" #include "servers/text_server.h" #ifdef TOOLS_ENABLED -#include "editor/editor_scale.h" #include "editor/editor_settings.h" #endif #include "scene/main/window.h" @@ -713,11 +712,7 @@ void LineEdit::_notification(int p_what) { ofs_max -= r_icon->get_width(); } -#ifdef TOOLS_ENABLED - int caret_width = Math::round(EDSCALE); -#else - int caret_width = 1; -#endif + int caret_width = Math::round(1 * get_theme_default_base_scale()); // Draw selections rects. Vector2 ofs = Point2(x_ofs + scroll_offset, y_ofs); diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp index bc25177275c..4588966d884 100644 --- a/scene/gui/rich_text_label.cpp +++ b/scene/gui/rich_text_label.cpp @@ -41,10 +41,6 @@ #include "modules/regex/regex.h" #endif -#ifdef TOOLS_ENABLED -#include "editor/editor_scale.h" -#endif - RichTextLabel::Item *RichTextLabel::_get_next_item(Item *p_item, bool p_free) const { if (p_free) { if (p_item->subitems.size()) { @@ -995,19 +991,13 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o Color uc = font_color; uc.a *= 0.5; float y_off = TS->shaped_text_get_underline_position(rid); - float underline_width = TS->shaped_text_get_underline_thickness(rid); -#ifdef TOOLS_ENABLED - underline_width *= EDSCALE; -#endif + float underline_width = TS->shaped_text_get_underline_thickness(rid) * get_theme_default_base_scale(); draw_line(p_ofs + Vector2(off.x, off.y + y_off), p_ofs + Vector2(off.x + glyphs[i].advance * glyphs[i].repeat, off.y + y_off), uc, underline_width); } else if (_find_strikethrough(it)) { Color uc = font_color; uc.a *= 0.5; float y_off = -TS->shaped_text_get_ascent(rid) + TS->shaped_text_get_size(rid).y / 2; - float underline_width = TS->shaped_text_get_underline_thickness(rid); -#ifdef TOOLS_ENABLED - underline_width *= EDSCALE; -#endif + float underline_width = TS->shaped_text_get_underline_thickness(rid) * get_theme_default_base_scale(); draw_line(p_ofs + Vector2(off.x, off.y + y_off), p_ofs + Vector2(off.x + glyphs[i].advance * glyphs[i].repeat, off.y + y_off), uc, underline_width); } diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index e2ddc761b8e..875049ab4e7 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -42,10 +42,6 @@ #include "scene/main/window.h" -#ifdef TOOLS_ENABLED -#include "editor/editor_scale.h" -#endif - static bool _is_text_char(char32_t c) { return !is_symbol(c); } @@ -1173,12 +1169,8 @@ void TextEdit::_notification(int p_what) { } } - // Carets -#ifdef TOOLS_ENABLED - int caret_width = Math::round(EDSCALE); -#else - int caret_width = 1; -#endif + // Carets. + int caret_width = Math::round(1 * get_theme_default_base_scale()); if (!clipped && caret.line == line && line_wrap_index == caret_wrap_index) { caret.draw_pos.y = ofs_y + ldata->get_line_descent(line_wrap_index); diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp index 7d7596635cc..3f041bf65a5 100644 --- a/scene/gui/tree.cpp +++ b/scene/gui/tree.cpp @@ -41,10 +41,6 @@ #include "box_container.h" -#ifdef TOOLS_ENABLED -#include "editor/editor_scale.h" -#endif - #include Size2 TreeItem::Cell::get_icon_size() const { @@ -1377,6 +1373,8 @@ void Tree::update_cache() { cache.title_button_hover = get_theme_stylebox(SNAME("title_button_hover")); cache.title_button_color = get_theme_color(SNAME("title_button_color")); + cache.base_scale = get_theme_default_base_scale(); + v_scroll->set_custom_step(cache.font->get_height(cache.font_size)); } @@ -2046,15 +2044,9 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 root_pos -= Point2i(cache.arrow->get_width(), 0); } - float line_width = cache.relationship_line_width; - float parent_line_width = cache.parent_hl_line_width; - float children_line_width = cache.children_hl_line_width; - -#ifdef TOOLS_ENABLED - line_width *= Math::round(EDSCALE); - parent_line_width *= Math::round(EDSCALE); - children_line_width *= Math::round(EDSCALE); -#endif + float line_width = cache.relationship_line_width * Math::round(cache.base_scale); + float parent_line_width = cache.parent_hl_line_width * Math::round(cache.base_scale); + float children_line_width = cache.children_hl_line_width * Math::round(cache.base_scale); Point2i parent_pos = Point2i(parent_ofs - cache.arrow->get_width() / 2, p_pos.y + label_h / 2 + cache.arrow->get_height() / 2) - cache.offset + p_draw_ofs; diff --git a/scene/gui/tree.h b/scene/gui/tree.h index c4a6b6b058f..6ca9458e9bb 100644 --- a/scene/gui/tree.h +++ b/scene/gui/tree.h @@ -516,6 +516,8 @@ private: Color custom_button_font_highlight; Color font_outline_color; + float base_scale = 1.0; + int hseparation = 0; int vseparation = 0; int item_margin = 0;