summaryrefslogtreecommitdiff
path: root/scene/gui/control.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'scene/gui/control.cpp')
-rw-r--r--scene/gui/control.cpp875
1 files changed, 348 insertions, 527 deletions
diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp
index 06aa913eb1..b4e603d5ed 100644
--- a/scene/gui/control.cpp
+++ b/scene/gui/control.cpp
@@ -43,6 +43,8 @@
#include "scene/main/canvas_layer.h"
#include "scene/main/window.h"
#include "scene/scene_string_names.h"
+#include "scene/theme/theme_db.h"
+#include "scene/theme/theme_owner.h"
#include "servers/rendering_server.h"
#include "servers/text_server.h"
@@ -193,15 +195,15 @@ void Control::get_argument_options(const StringName &p_function, int p_idx, List
List<StringName> sn;
String pf = p_function;
if (pf == "add_theme_color_override" || pf == "has_theme_color" || pf == "has_theme_color_override" || pf == "get_theme_color") {
- Theme::get_default()->get_color_list(get_class(), &sn);
+ ThemeDB::get_singleton()->get_default_theme()->get_color_list(get_class(), &sn);
} else if (pf == "add_theme_style_override" || pf == "has_theme_style" || pf == "has_theme_style_override" || pf == "get_theme_style") {
- Theme::get_default()->get_stylebox_list(get_class(), &sn);
+ ThemeDB::get_singleton()->get_default_theme()->get_stylebox_list(get_class(), &sn);
} else if (pf == "add_theme_font_override" || pf == "has_theme_font" || pf == "has_theme_font_override" || pf == "get_theme_font") {
- Theme::get_default()->get_font_list(get_class(), &sn);
+ ThemeDB::get_singleton()->get_default_theme()->get_font_list(get_class(), &sn);
} else if (pf == "add_theme_font_size_override" || pf == "has_theme_font_size" || pf == "has_theme_font_size_override" || pf == "get_theme_font_size") {
- Theme::get_default()->get_font_size_list(get_class(), &sn);
+ ThemeDB::get_singleton()->get_default_theme()->get_font_size_list(get_class(), &sn);
} else if (pf == "add_theme_constant_override" || pf == "has_theme_constant" || pf == "has_theme_constant_override" || pf == "get_theme_constant") {
- Theme::get_default()->get_constant_list(get_class(), &sn);
+ ThemeDB::get_singleton()->get_default_theme()->get_constant_list(get_class(), &sn);
}
sn.sort_custom<StringName::AlphCompare>();
@@ -252,36 +254,36 @@ bool Control::_set(const StringName &p_name, const Variant &p_value) {
if (name.begins_with("theme_override_icons/")) {
String dname = name.get_slicec('/', 1);
if (data.icon_override.has(dname)) {
- data.icon_override[dname]->disconnect("changed", callable_mp(this, &Control::_theme_property_override_changed));
+ data.icon_override[dname]->disconnect("changed", callable_mp(this, &Control::_notify_theme_override_changed));
}
data.icon_override.erase(dname);
- notification(NOTIFICATION_THEME_CHANGED);
+ _notify_theme_override_changed();
} else if (name.begins_with("theme_override_styles/")) {
String dname = name.get_slicec('/', 1);
if (data.style_override.has(dname)) {
- data.style_override[dname]->disconnect("changed", callable_mp(this, &Control::_theme_property_override_changed));
+ data.style_override[dname]->disconnect("changed", callable_mp(this, &Control::_notify_theme_override_changed));
}
data.style_override.erase(dname);
- notification(NOTIFICATION_THEME_CHANGED);
+ _notify_theme_override_changed();
} else if (name.begins_with("theme_override_fonts/")) {
String dname = name.get_slicec('/', 1);
if (data.font_override.has(dname)) {
- data.font_override[dname]->disconnect("changed", callable_mp(this, &Control::_theme_property_override_changed));
+ data.font_override[dname]->disconnect("changed", callable_mp(this, &Control::_notify_theme_override_changed));
}
data.font_override.erase(dname);
- notification(NOTIFICATION_THEME_CHANGED);
+ _notify_theme_override_changed();
} else if (name.begins_with("theme_override_font_sizes/")) {
String dname = name.get_slicec('/', 1);
data.font_size_override.erase(dname);
- notification(NOTIFICATION_THEME_CHANGED);
+ _notify_theme_override_changed();
} else if (name.begins_with("theme_override_colors/")) {
String dname = name.get_slicec('/', 1);
data.color_override.erase(dname);
- notification(NOTIFICATION_THEME_CHANGED);
+ _notify_theme_override_changed();
} else if (name.begins_with("theme_override_constants/")) {
String dname = name.get_slicec('/', 1);
data.constant_override.erase(dname);
- notification(NOTIFICATION_THEME_CHANGED);
+ _notify_theme_override_changed();
} else {
return false;
}
@@ -344,7 +346,7 @@ bool Control::_get(const StringName &p_name, Variant &r_ret) const {
}
void Control::_get_property_list(List<PropertyInfo> *p_list) const {
- Ref<Theme> theme = Theme::get_default();
+ Ref<Theme> theme = ThemeDB::get_singleton()->get_default_theme();
p_list->push_back(PropertyInfo(Variant::NIL, TTRC("Theme Overrides"), PROPERTY_HINT_NONE, "theme_override_", PROPERTY_USAGE_GROUP));
@@ -422,16 +424,16 @@ void Control::_get_property_list(List<PropertyInfo> *p_list) const {
}
}
-void Control::_validate_property(PropertyInfo &property) const {
+void Control::_validate_property(PropertyInfo &p_property) const {
// Update theme type variation options.
- if (property.name == "theme_type_variation") {
+ if (p_property.name == "theme_type_variation") {
List<StringName> names;
// Only the default theme and the project theme are used for the list of options.
// This is an imposed limitation to simplify the logic needed to leverage those options.
- Theme::get_default()->get_type_variation_list(get_class_name(), &names);
- if (Theme::get_project_default().is_valid()) {
- Theme::get_project_default()->get_type_variation_list(get_class_name(), &names);
+ ThemeDB::get_singleton()->get_default_theme()->get_type_variation_list(get_class_name(), &names);
+ if (ThemeDB::get_singleton()->get_project_theme().is_valid()) {
+ ThemeDB::get_singleton()->get_project_theme()->get_type_variation_list(get_class_name(), &names);
}
names.sort_custom<StringName::AlphCompare>();
@@ -447,18 +449,18 @@ void Control::_validate_property(PropertyInfo &property) const {
unique_names.append(E);
}
- property.hint_string = hint_string;
+ p_property.hint_string = hint_string;
}
- if (property.name == "mouse_force_pass_scroll_events") {
+ if (p_property.name == "mouse_force_pass_scroll_events") {
// Disable force pass if the control is not stopping the event.
if (data.mouse_filter != MOUSE_FILTER_STOP) {
- property.usage |= PROPERTY_USAGE_READ_ONLY;
+ p_property.usage |= PROPERTY_USAGE_READ_ONLY;
}
}
- if (property.name == "scale") {
- property.hint = PROPERTY_HINT_LINK;
+ if (p_property.name == "scale") {
+ p_property.hint = PROPERTY_HINT_LINK;
}
// Validate which positioning properties should be displayed depending on the parent and the layout mode.
@@ -467,33 +469,33 @@ void Control::_validate_property(PropertyInfo &property) const {
// If there is no parent, display both anchor and container options.
// Set the layout mode to be disabled with the proper value.
- if (property.name == "layout_mode") {
- property.hint_string = "Position,Anchors,Container,Uncontrolled";
- property.usage |= PROPERTY_USAGE_READ_ONLY;
+ if (p_property.name == "layout_mode") {
+ p_property.hint_string = "Position,Anchors,Container,Uncontrolled";
+ p_property.usage |= PROPERTY_USAGE_READ_ONLY;
}
// Use the layout mode to display or hide advanced anchoring properties.
bool use_custom_anchors = _get_anchors_layout_preset() == -1; // Custom "preset".
- if (!use_custom_anchors && (property.name.begins_with("anchor_") || property.name.begins_with("offset_") || property.name.begins_with("grow_"))) {
- property.usage ^= PROPERTY_USAGE_EDITOR;
+ if (!use_custom_anchors && (p_property.name.begins_with("anchor_") || p_property.name.begins_with("offset_") || p_property.name.begins_with("grow_"))) {
+ p_property.usage ^= PROPERTY_USAGE_EDITOR;
}
} else if (Object::cast_to<Container>(parent_node)) {
// If the parent is a container, display only container-related properties.
- if (property.name.begins_with("anchor_") || property.name.begins_with("offset_") || property.name.begins_with("grow_") || property.name == "anchors_preset" ||
- property.name == "position" || property.name == "rotation" || property.name == "scale" || property.name == "size" || property.name == "pivot_offset") {
- property.usage ^= PROPERTY_USAGE_EDITOR;
+ if (p_property.name.begins_with("anchor_") || p_property.name.begins_with("offset_") || p_property.name.begins_with("grow_") || p_property.name == "anchors_preset" ||
+ p_property.name == "position" || p_property.name == "rotation" || p_property.name == "scale" || p_property.name == "size" || p_property.name == "pivot_offset") {
+ p_property.usage ^= PROPERTY_USAGE_EDITOR;
- } else if (property.name == "layout_mode") {
+ } else if (p_property.name == "layout_mode") {
// Set the layout mode to be disabled with the proper value.
- property.hint_string = "Position,Anchors,Container,Uncontrolled";
- property.usage |= PROPERTY_USAGE_READ_ONLY;
- } else if (property.name == "size_flags_horizontal" || property.name == "size_flags_vertical") {
+ p_property.hint_string = "Position,Anchors,Container,Uncontrolled";
+ p_property.usage |= PROPERTY_USAGE_READ_ONLY;
+ } else if (p_property.name == "size_flags_horizontal" || p_property.name == "size_flags_vertical") {
// Filter allowed size flags based on the parent container configuration.
Container *parent_container = Object::cast_to<Container>(parent_node);
Vector<int> size_flags;
- if (property.name == "size_flags_horizontal") {
+ if (p_property.name == "size_flags_horizontal") {
size_flags = parent_container->get_allowed_size_flags_horizontal();
- } else if (property.name == "size_flags_vertical") {
+ } else if (p_property.name == "size_flags_vertical") {
size_flags = parent_container->get_allowed_size_flags_vertical();
}
@@ -522,30 +524,30 @@ void Control::_validate_property(PropertyInfo &property) const {
}
if (hint_string.is_empty()) {
- property.hint_string = "";
- property.usage |= PROPERTY_USAGE_READ_ONLY;
+ p_property.hint_string = "";
+ p_property.usage |= PROPERTY_USAGE_READ_ONLY;
} else {
- property.hint_string = hint_string;
+ p_property.hint_string = hint_string;
}
}
} else {
// If the parent is NOT a container or not a control at all, display only anchoring-related properties.
- if (property.name.begins_with("size_flags_")) {
- property.usage ^= PROPERTY_USAGE_EDITOR;
+ if (p_property.name.begins_with("size_flags_")) {
+ p_property.usage ^= PROPERTY_USAGE_EDITOR;
- } else if (property.name == "layout_mode") {
+ } else if (p_property.name == "layout_mode") {
// Set the layout mode to be enabled with proper options.
- property.hint_string = "Position,Anchors";
+ p_property.hint_string = "Position,Anchors";
}
// Use the layout mode to display or hide advanced anchoring properties.
bool use_anchors = _get_layout_mode() == LayoutMode::LAYOUT_MODE_ANCHORS;
- if (!use_anchors && property.name == "anchors_preset") {
- property.usage ^= PROPERTY_USAGE_EDITOR;
+ if (!use_anchors && p_property.name == "anchors_preset") {
+ p_property.usage ^= PROPERTY_USAGE_EDITOR;
}
bool use_custom_anchors = use_anchors && _get_anchors_layout_preset() == -1; // Custom "preset".
- if (!use_custom_anchors && (property.name.begins_with("anchor_") || property.name.begins_with("offset_") || property.name.begins_with("grow_"))) {
- property.usage ^= PROPERTY_USAGE_EDITOR;
+ if (!use_custom_anchors && (p_property.name.begins_with("anchor_") || p_property.name.begins_with("offset_") || p_property.name.begins_with("grow_"))) {
+ p_property.usage ^= PROPERTY_USAGE_EDITOR;
}
}
@@ -555,14 +557,34 @@ void Control::_validate_property(PropertyInfo &property) const {
}
bool property_is_managed_by_container = false;
for (unsigned i = 0; i < properties_managed_by_container_count; i++) {
- property_is_managed_by_container = properties_managed_by_container[i] == property.name;
+ property_is_managed_by_container = properties_managed_by_container[i] == p_property.name;
if (property_is_managed_by_container) {
break;
}
}
if (property_is_managed_by_container) {
- property.usage |= PROPERTY_USAGE_READ_ONLY;
+ p_property.usage |= PROPERTY_USAGE_READ_ONLY;
+ }
+}
+
+bool Control::_property_can_revert(const StringName &p_name) const {
+ if (p_name == "layout_mode" || p_name == "anchors_preset") {
+ return true;
+ }
+
+ return false;
+}
+
+bool Control::_property_get_revert(const StringName &p_name, Variant &r_property) const {
+ if (p_name == "layout_mode") {
+ r_property = _get_default_layout_mode();
+ return true;
+ } else if (p_name == "anchors_preset") {
+ r_property = LayoutPreset::PRESET_TOP_LEFT;
+ return true;
}
+
+ return false;
}
// Global relations.
@@ -692,7 +714,7 @@ void Control::set_anchor(Side p_side, real_t p_anchor, bool p_keep_offset, bool
_size_changed();
}
- update();
+ queue_redraw();
}
real_t Control::get_anchor(Side p_side) const {
@@ -703,6 +725,9 @@ real_t Control::get_anchor(Side p_side) const {
void Control::set_offset(Side p_side, real_t p_value) {
ERR_FAIL_INDEX((int)p_side, 4);
+ if (data.offset[p_side] == p_value) {
+ return;
+ }
data.offset[p_side] = p_value;
_size_changed();
@@ -720,6 +745,10 @@ void Control::set_anchor_and_offset(Side p_side, real_t p_anchor, real_t p_pos,
}
void Control::set_begin(const Size2 &p_point) {
+ if (data.offset[0] == p_point.x && data.offset[1] == p_point.y) {
+ return;
+ }
+
data.offset[0] = p_point.x;
data.offset[1] = p_point.y;
_size_changed();
@@ -730,6 +759,10 @@ Size2 Control::get_begin() const {
}
void Control::set_end(const Size2 &p_point) {
+ if (data.offset[2] == p_point.x && data.offset[3] == p_point.y) {
+ return;
+ }
+
data.offset[2] = p_point.x;
data.offset[3] = p_point.y;
_size_changed();
@@ -740,6 +773,10 @@ Size2 Control::get_end() const {
}
void Control::set_h_grow_direction(GrowDirection p_direction) {
+ if (data.h_grow == p_direction) {
+ return;
+ }
+
ERR_FAIL_INDEX((int)p_direction, 3);
data.h_grow = p_direction;
@@ -751,6 +788,10 @@ Control::GrowDirection Control::get_h_grow_direction() const {
}
void Control::set_v_grow_direction(GrowDirection p_direction) {
+ if (data.v_grow == p_direction) {
+ return;
+ }
+
ERR_FAIL_INDEX((int)p_direction, 3);
data.v_grow = p_direction;
@@ -794,24 +835,15 @@ void Control::_compute_offsets(Rect2 p_rect, const real_t p_anchors[4], real_t (
void Control::_set_layout_mode(LayoutMode p_mode) {
bool list_changed = false;
- if (p_mode == LayoutMode::LAYOUT_MODE_POSITION || p_mode == LayoutMode::LAYOUT_MODE_ANCHORS) {
- if ((int)get_meta("_edit_layout_mode", p_mode) != (int)p_mode) {
- list_changed = true;
- }
-
- set_meta("_edit_layout_mode", (int)p_mode);
+ if (data.stored_layout_mode != p_mode) {
+ list_changed = true;
+ data.stored_layout_mode = p_mode;
+ }
- if (p_mode == LayoutMode::LAYOUT_MODE_POSITION) {
- remove_meta("_edit_layout_mode");
- remove_meta("_edit_use_custom_anchors");
- set_anchors_and_offsets_preset(LayoutPreset::PRESET_TOP_LEFT, LayoutPresetMode::PRESET_MODE_KEEP_SIZE);
- set_grow_direction_preset(LayoutPreset::PRESET_TOP_LEFT);
- }
- } else {
- if (has_meta("_edit_layout_mode")) {
- remove_meta("_edit_layout_mode");
- list_changed = true;
- }
+ if (data.stored_layout_mode == LayoutMode::LAYOUT_MODE_POSITION) {
+ data.stored_use_custom_anchors = false;
+ set_anchors_and_offsets_preset(LayoutPreset::PRESET_TOP_LEFT, LayoutPresetMode::PRESET_MODE_KEEP_SIZE);
+ set_grow_direction_preset(LayoutPreset::PRESET_TOP_LEFT);
}
if (list_changed) {
@@ -832,33 +864,43 @@ Control::LayoutMode Control::_get_layout_mode() const {
if (_get_anchors_layout_preset() != (int)LayoutPreset::PRESET_TOP_LEFT) {
return LayoutMode::LAYOUT_MODE_ANCHORS;
}
- // Otherwise check what was saved.
- if (has_meta("_edit_layout_mode")) {
- return (LayoutMode)(int)get_meta("_edit_layout_mode");
+
+ // Otherwise fallback on what's stored.
+ return data.stored_layout_mode;
+}
+
+Control::LayoutMode Control::_get_default_layout_mode() const {
+ Node *parent_node = get_parent_control();
+ // In these modes the property is read-only.
+ if (!parent_node) {
+ return LayoutMode::LAYOUT_MODE_UNCONTROLLED;
+ } else if (Object::cast_to<Container>(parent_node)) {
+ return LayoutMode::LAYOUT_MODE_CONTAINER;
}
- // Or fallback on default.
+
+ // Otherwise fallback on the position mode.
return LayoutMode::LAYOUT_MODE_POSITION;
}
void Control::_set_anchors_layout_preset(int p_preset) {
bool list_changed = false;
- if (get_meta("_edit_layout_mode", LayoutMode::LAYOUT_MODE_ANCHORS).operator int() != LayoutMode::LAYOUT_MODE_ANCHORS) {
+ if (data.stored_layout_mode != LayoutMode::LAYOUT_MODE_ANCHORS) {
list_changed = true;
- set_meta("_edit_layout_mode", LayoutMode::LAYOUT_MODE_ANCHORS);
+ data.stored_layout_mode = LayoutMode::LAYOUT_MODE_ANCHORS;
}
if (p_preset == -1) {
- if (!get_meta("_edit_use_custom_anchors", false)) {
- set_meta("_edit_use_custom_anchors", true);
+ if (!data.stored_use_custom_anchors) {
+ data.stored_use_custom_anchors = true;
notify_property_list_changed();
}
return; // Keep settings as is.
}
- if (get_meta("_edit_use_custom_anchors", true)) {
+ if (data.stored_use_custom_anchors) {
list_changed = true;
- remove_meta("_edit_use_custom_anchors");
+ data.stored_use_custom_anchors = false;
}
LayoutPreset preset = (LayoutPreset)p_preset;
@@ -899,7 +941,7 @@ void Control::_set_anchors_layout_preset(int p_preset) {
int Control::_get_anchors_layout_preset() const {
// If the custom preset was selected by user, use it.
- if ((bool)get_meta("_edit_use_custom_anchors", false)) {
+ if (data.stored_use_custom_anchors) {
return -1;
}
@@ -1406,6 +1448,10 @@ Rect2 Control::get_anchorable_rect() const {
}
void Control::set_scale(const Vector2 &p_scale) {
+ if (data.scale == p_scale) {
+ return;
+ }
+
data.scale = p_scale;
// Avoid having 0 scale values, can lead to errors in physics and rendering.
if (data.scale.x == 0) {
@@ -1414,7 +1460,7 @@ void Control::set_scale(const Vector2 &p_scale) {
if (data.scale.y == 0) {
data.scale.y = CMP_EPSILON;
}
- update();
+ queue_redraw();
_notify_transform();
}
@@ -1423,8 +1469,12 @@ Vector2 Control::get_scale() const {
}
void Control::set_rotation(real_t p_radians) {
+ if (data.rotation == p_radians) {
+ return;
+ }
+
data.rotation = p_radians;
- update();
+ queue_redraw();
_notify_transform();
}
@@ -1433,8 +1483,12 @@ real_t Control::get_rotation() const {
}
void Control::set_pivot_offset(const Vector2 &p_pivot) {
+ if (data.pivot_offset == p_pivot) {
+ return;
+ }
+
data.pivot_offset = p_pivot;
- update();
+ queue_redraw();
_notify_transform();
}
@@ -2183,8 +2237,11 @@ Control::CursorShape Control::get_cursor_shape(const Point2 &p_pos) const {
}
void Control::set_disable_visibility_clip(bool p_ignore) {
+ if (data.disable_visibility_clip == p_ignore) {
+ return;
+ }
data.disable_visibility_clip = p_ignore;
- update();
+ queue_redraw();
}
bool Control::is_visibility_clip_disabled() const {
@@ -2192,8 +2249,11 @@ bool Control::is_visibility_clip_disabled() const {
}
void Control::set_clip_contents(bool p_clip) {
+ if (data.clip_contents == p_clip) {
+ return;
+ }
data.clip_contents = p_clip;
- update();
+ queue_redraw();
}
bool Control::is_clipping_contents() {
@@ -2202,64 +2262,40 @@ bool Control::is_clipping_contents() {
// Theming.
-void Control::_propagate_theme_changed(Node *p_at, Control *p_owner, Window *p_owner_window, bool p_assign) {
- Control *c = Object::cast_to<Control>(p_at);
-
- if (c && c != p_owner && c->data.theme.is_valid()) { // has a theme, this can't be propagated
- return;
- }
-
- Window *w = c == nullptr ? Object::cast_to<Window>(p_at) : nullptr;
-
- if (w && w != p_owner_window && w->theme.is_valid()) { // has a theme, this can't be propagated
- return;
+void Control::_theme_changed() {
+ if (is_inside_tree()) {
+ data.theme_owner->propagate_theme_changed(this, this, true, false);
}
+}
- for (int i = 0; i < p_at->get_child_count(); i++) {
- CanvasItem *child = Object::cast_to<CanvasItem>(p_at->get_child(i));
- if (child) {
- _propagate_theme_changed(child, p_owner, p_owner_window, p_assign);
- } else {
- Window *window = Object::cast_to<Window>(p_at->get_child(i));
- if (window) {
- _propagate_theme_changed(window, p_owner, p_owner_window, p_assign);
- }
- }
+void Control::_notify_theme_override_changed() {
+ if (!data.bulk_theme_override && is_inside_tree()) {
+ notification(NOTIFICATION_THEME_CHANGED);
}
+}
- if (c) {
- if (p_assign) {
- c->data.theme_owner = p_owner;
- c->data.theme_owner_window = p_owner_window;
- }
- c->notification(Control::NOTIFICATION_THEME_CHANGED);
- c->emit_signal(SceneStringNames::get_singleton()->theme_changed);
- }
+void Control::_invalidate_theme_cache() {
+ data.theme_icon_cache.clear();
+ data.theme_style_cache.clear();
+ data.theme_font_cache.clear();
+ data.theme_font_size_cache.clear();
+ data.theme_color_cache.clear();
+ data.theme_constant_cache.clear();
+}
- if (w) {
- if (p_assign) {
- w->theme_owner = p_owner;
- w->theme_owner_window = p_owner_window;
- }
- w->notification(Window::NOTIFICATION_THEME_CHANGED);
- w->emit_signal(SceneStringNames::get_singleton()->theme_changed);
- }
+void Control::_update_theme_item_cache() {
}
-void Control::_theme_changed() {
- _propagate_theme_changed(this, this, nullptr, false);
+void Control::set_theme_owner_node(Node *p_node) {
+ data.theme_owner->set_owner_node(p_node);
}
-void Control::_theme_property_override_changed() {
- notification(NOTIFICATION_THEME_CHANGED);
- emit_signal(SceneStringNames::get_singleton()->theme_changed);
- update_minimum_size(); // Overrides are likely to affect minimum size.
+Node *Control::get_theme_owner_node() const {
+ return data.theme_owner->get_owner_node();
}
-void Control::_notify_theme_changed() {
- if (!data.bulk_theme_override) {
- notification(NOTIFICATION_THEME_CHANGED);
- }
+bool Control::has_theme_owner_node() const {
+ return data.theme_owner->has_owner_node();
}
void Control::set_theme(const Ref<Theme> &p_theme) {
@@ -2272,28 +2308,25 @@ void Control::set_theme(const Ref<Theme> &p_theme) {
}
data.theme = p_theme;
- if (!p_theme.is_null()) {
- data.theme_owner = this;
- data.theme_owner_window = nullptr;
- _propagate_theme_changed(this, this, nullptr);
- } else {
- Control *parent_c = Object::cast_to<Control>(get_parent());
+ if (data.theme.is_valid()) {
+ data.theme_owner->propagate_theme_changed(this, this, is_inside_tree(), true);
+ data.theme->connect("changed", callable_mp(this, &Control::_theme_changed), CONNECT_DEFERRED);
+ return;
+ }
- if (parent_c && (parent_c->data.theme_owner || parent_c->data.theme_owner_window)) {
- Control::_propagate_theme_changed(this, parent_c->data.theme_owner, parent_c->data.theme_owner_window);
- } else {
- Window *parent_w = cast_to<Window>(get_parent());
- if (parent_w && (parent_w->theme_owner || parent_w->theme_owner_window)) {
- Control::_propagate_theme_changed(this, parent_w->theme_owner, parent_w->theme_owner_window);
- } else {
- Control::_propagate_theme_changed(this, nullptr, nullptr);
- }
- }
+ Control *parent_c = Object::cast_to<Control>(get_parent());
+ if (parent_c && parent_c->has_theme_owner_node()) {
+ data.theme_owner->propagate_theme_changed(this, parent_c->get_theme_owner_node(), is_inside_tree(), true);
+ return;
}
- if (data.theme.is_valid()) {
- data.theme->connect("changed", callable_mp(this, &Control::_theme_changed), CONNECT_DEFERRED);
+ Window *parent_w = cast_to<Window>(get_parent());
+ if (parent_w && parent_w->has_theme_owner_node()) {
+ data.theme_owner->propagate_theme_changed(this, parent_w->get_theme_owner_node(), is_inside_tree(), true);
+ return;
}
+
+ data.theme_owner->propagate_theme_changed(this, nullptr, is_inside_tree(), true);
}
Ref<Theme> Control::get_theme() const {
@@ -2301,8 +2334,13 @@ Ref<Theme> Control::get_theme() const {
}
void Control::set_theme_type_variation(const StringName &p_theme_type) {
+ if (data.theme_type_variation == p_theme_type) {
+ return;
+ }
data.theme_type_variation = p_theme_type;
- _propagate_theme_changed(this, data.theme_owner, data.theme_owner_window);
+ if (is_inside_tree()) {
+ notification(NOTIFICATION_THEME_CHANGED);
+ }
}
StringName Control::get_theme_type_variation() const {
@@ -2311,130 +2349,6 @@ StringName Control::get_theme_type_variation() const {
/// Theme property lookup.
-template <class T>
-T Control::get_theme_item_in_types(Control *p_theme_owner, Window *p_theme_owner_window, Theme::DataType p_data_type, const StringName &p_name, List<StringName> p_theme_types) {
- ERR_FAIL_COND_V_MSG(p_theme_types.size() == 0, T(), "At least one theme type must be specified.");
-
- // First, look through each control or window node in the branch, until no valid parent can be found.
- // Only nodes with a theme resource attached are considered.
- Control *theme_owner = p_theme_owner;
- Window *theme_owner_window = p_theme_owner_window;
-
- while (theme_owner || theme_owner_window) {
- // For each theme resource check the theme types provided and see if p_name exists with any of them.
- for (const StringName &E : p_theme_types) {
- if (theme_owner && theme_owner->data.theme->has_theme_item(p_data_type, p_name, E)) {
- return theme_owner->data.theme->get_theme_item(p_data_type, p_name, E);
- }
-
- if (theme_owner_window && theme_owner_window->theme->has_theme_item(p_data_type, p_name, E)) {
- return theme_owner_window->theme->get_theme_item(p_data_type, p_name, E);
- }
- }
-
- Node *parent = theme_owner ? theme_owner->get_parent() : theme_owner_window->get_parent();
- Control *parent_c = Object::cast_to<Control>(parent);
- if (parent_c) {
- theme_owner = parent_c->data.theme_owner;
- theme_owner_window = parent_c->data.theme_owner_window;
- } else {
- Window *parent_w = Object::cast_to<Window>(parent);
- if (parent_w) {
- theme_owner = parent_w->theme_owner;
- theme_owner_window = parent_w->theme_owner_window;
- } else {
- theme_owner = nullptr;
- theme_owner_window = nullptr;
- }
- }
- }
-
- // Secondly, check the project-defined Theme resource.
- if (Theme::get_project_default().is_valid()) {
- for (const StringName &E : p_theme_types) {
- if (Theme::get_project_default()->has_theme_item(p_data_type, p_name, E)) {
- return Theme::get_project_default()->get_theme_item(p_data_type, p_name, E);
- }
- }
- }
-
- // Lastly, fall back on the items defined in the default Theme, if they exist.
- for (const StringName &E : p_theme_types) {
- if (Theme::get_default()->has_theme_item(p_data_type, p_name, E)) {
- return Theme::get_default()->get_theme_item(p_data_type, p_name, E);
- }
- }
- // If they don't exist, use any type to return the default/empty value.
- return Theme::get_default()->get_theme_item(p_data_type, p_name, p_theme_types[0]);
-}
-
-bool Control::has_theme_item_in_types(Control *p_theme_owner, Window *p_theme_owner_window, Theme::DataType p_data_type, const StringName &p_name, List<StringName> p_theme_types) {
- ERR_FAIL_COND_V_MSG(p_theme_types.size() == 0, false, "At least one theme type must be specified.");
-
- // First, look through each control or window node in the branch, until no valid parent can be found.
- // Only nodes with a theme resource attached are considered.
- Control *theme_owner = p_theme_owner;
- Window *theme_owner_window = p_theme_owner_window;
-
- while (theme_owner || theme_owner_window) {
- // For each theme resource check the theme types provided and see if p_name exists with any of them.
- for (const StringName &E : p_theme_types) {
- if (theme_owner && theme_owner->data.theme->has_theme_item(p_data_type, p_name, E)) {
- return true;
- }
-
- if (theme_owner_window && theme_owner_window->theme->has_theme_item(p_data_type, p_name, E)) {
- return true;
- }
- }
-
- Node *parent = theme_owner ? theme_owner->get_parent() : theme_owner_window->get_parent();
- Control *parent_c = Object::cast_to<Control>(parent);
- if (parent_c) {
- theme_owner = parent_c->data.theme_owner;
- theme_owner_window = parent_c->data.theme_owner_window;
- } else {
- Window *parent_w = Object::cast_to<Window>(parent);
- if (parent_w) {
- theme_owner = parent_w->theme_owner;
- theme_owner_window = parent_w->theme_owner_window;
- } else {
- theme_owner = nullptr;
- theme_owner_window = nullptr;
- }
- }
- }
-
- // Secondly, check the project-defined Theme resource.
- if (Theme::get_project_default().is_valid()) {
- for (const StringName &E : p_theme_types) {
- if (Theme::get_project_default()->has_theme_item(p_data_type, p_name, E)) {
- return true;
- }
- }
- }
-
- // Lastly, fall back on the items defined in the default Theme, if they exist.
- for (const StringName &E : p_theme_types) {
- if (Theme::get_default()->has_theme_item(p_data_type, p_name, E)) {
- return true;
- }
- }
- return false;
-}
-
-void Control::_get_theme_type_dependencies(const StringName &p_theme_type, List<StringName> *p_list) const {
- if (p_theme_type == StringName() || p_theme_type == get_class_name() || p_theme_type == data.theme_type_variation) {
- if (Theme::get_project_default().is_valid() && Theme::get_project_default()->get_type_variation_base(data.theme_type_variation) != StringName()) {
- Theme::get_project_default()->get_type_dependencies(get_class_name(), data.theme_type_variation, p_list);
- } else {
- Theme::get_default()->get_type_dependencies(get_class_name(), data.theme_type_variation, p_list);
- }
- } else {
- Theme::get_default()->get_type_dependencies(p_theme_type, StringName(), p_list);
- }
-}
-
Ref<Texture2D> Control::get_theme_icon(const StringName &p_name, const StringName &p_theme_type) const {
if (p_theme_type == StringName() || p_theme_type == get_class_name() || p_theme_type == data.theme_type_variation) {
const Ref<Texture2D> *tex = data.icon_override.getptr(p_name);
@@ -2443,9 +2357,15 @@ Ref<Texture2D> Control::get_theme_icon(const StringName &p_name, const StringNam
}
}
+ if (data.theme_icon_cache.has(p_theme_type) && data.theme_icon_cache[p_theme_type].has(p_name)) {
+ return data.theme_icon_cache[p_theme_type][p_name];
+ }
+
List<StringName> theme_types;
- _get_theme_type_dependencies(p_theme_type, &theme_types);
- return get_theme_item_in_types<Ref<Texture2D>>(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_ICON, p_name, theme_types);
+ data.theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types);
+ Ref<Texture2D> icon = data.theme_owner->get_theme_item_in_types(Theme::DATA_TYPE_ICON, p_name, theme_types);
+ data.theme_icon_cache[p_theme_type][p_name] = icon;
+ return icon;
}
Ref<StyleBox> Control::get_theme_stylebox(const StringName &p_name, const StringName &p_theme_type) const {
@@ -2456,9 +2376,15 @@ Ref<StyleBox> Control::get_theme_stylebox(const StringName &p_name, const String
}
}
+ if (data.theme_style_cache.has(p_theme_type) && data.theme_style_cache[p_theme_type].has(p_name)) {
+ return data.theme_style_cache[p_theme_type][p_name];
+ }
+
List<StringName> theme_types;
- _get_theme_type_dependencies(p_theme_type, &theme_types);
- return get_theme_item_in_types<Ref<StyleBox>>(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_STYLEBOX, p_name, theme_types);
+ data.theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types);
+ Ref<StyleBox> style = data.theme_owner->get_theme_item_in_types(Theme::DATA_TYPE_STYLEBOX, p_name, theme_types);
+ data.theme_style_cache[p_theme_type][p_name] = style;
+ return style;
}
Ref<Font> Control::get_theme_font(const StringName &p_name, const StringName &p_theme_type) const {
@@ -2469,9 +2395,15 @@ Ref<Font> Control::get_theme_font(const StringName &p_name, const StringName &p_
}
}
+ if (data.theme_font_cache.has(p_theme_type) && data.theme_font_cache[p_theme_type].has(p_name)) {
+ return data.theme_font_cache[p_theme_type][p_name];
+ }
+
List<StringName> theme_types;
- _get_theme_type_dependencies(p_theme_type, &theme_types);
- return get_theme_item_in_types<Ref<Font>>(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_FONT, p_name, theme_types);
+ data.theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types);
+ Ref<Font> font = data.theme_owner->get_theme_item_in_types(Theme::DATA_TYPE_FONT, p_name, theme_types);
+ data.theme_font_cache[p_theme_type][p_name] = font;
+ return font;
}
int Control::get_theme_font_size(const StringName &p_name, const StringName &p_theme_type) const {
@@ -2482,9 +2414,15 @@ int Control::get_theme_font_size(const StringName &p_name, const StringName &p_t
}
}
+ if (data.theme_font_size_cache.has(p_theme_type) && data.theme_font_size_cache[p_theme_type].has(p_name)) {
+ return data.theme_font_size_cache[p_theme_type][p_name];
+ }
+
List<StringName> theme_types;
- _get_theme_type_dependencies(p_theme_type, &theme_types);
- return get_theme_item_in_types<int>(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_FONT_SIZE, p_name, theme_types);
+ data.theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types);
+ int font_size = data.theme_owner->get_theme_item_in_types(Theme::DATA_TYPE_FONT_SIZE, p_name, theme_types);
+ data.theme_font_size_cache[p_theme_type][p_name] = font_size;
+ return font_size;
}
Color Control::get_theme_color(const StringName &p_name, const StringName &p_theme_type) const {
@@ -2495,9 +2433,15 @@ Color Control::get_theme_color(const StringName &p_name, const StringName &p_the
}
}
+ if (data.theme_color_cache.has(p_theme_type) && data.theme_color_cache[p_theme_type].has(p_name)) {
+ return data.theme_color_cache[p_theme_type][p_name];
+ }
+
List<StringName> theme_types;
- _get_theme_type_dependencies(p_theme_type, &theme_types);
- return get_theme_item_in_types<Color>(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_COLOR, p_name, theme_types);
+ data.theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types);
+ Color color = data.theme_owner->get_theme_item_in_types(Theme::DATA_TYPE_COLOR, p_name, theme_types);
+ data.theme_color_cache[p_theme_type][p_name] = color;
+ return color;
}
int Control::get_theme_constant(const StringName &p_name, const StringName &p_theme_type) const {
@@ -2508,9 +2452,15 @@ int Control::get_theme_constant(const StringName &p_name, const StringName &p_th
}
}
+ if (data.theme_constant_cache.has(p_theme_type) && data.theme_constant_cache[p_theme_type].has(p_name)) {
+ return data.theme_constant_cache[p_theme_type][p_name];
+ }
+
List<StringName> theme_types;
- _get_theme_type_dependencies(p_theme_type, &theme_types);
- return get_theme_item_in_types<int>(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_CONSTANT, p_name, theme_types);
+ data.theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types);
+ int constant = data.theme_owner->get_theme_item_in_types(Theme::DATA_TYPE_CONSTANT, p_name, theme_types);
+ data.theme_constant_cache[p_theme_type][p_name] = constant;
+ return constant;
}
bool Control::has_theme_icon(const StringName &p_name, const StringName &p_theme_type) const {
@@ -2521,8 +2471,8 @@ bool Control::has_theme_icon(const StringName &p_name, const StringName &p_theme
}
List<StringName> theme_types;
- _get_theme_type_dependencies(p_theme_type, &theme_types);
- return has_theme_item_in_types(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_ICON, p_name, theme_types);
+ data.theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types);
+ return data.theme_owner->has_theme_item_in_types(Theme::DATA_TYPE_ICON, p_name, theme_types);
}
bool Control::has_theme_stylebox(const StringName &p_name, const StringName &p_theme_type) const {
@@ -2533,8 +2483,8 @@ bool Control::has_theme_stylebox(const StringName &p_name, const StringName &p_t
}
List<StringName> theme_types;
- _get_theme_type_dependencies(p_theme_type, &theme_types);
- return has_theme_item_in_types(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_STYLEBOX, p_name, theme_types);
+ data.theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types);
+ return data.theme_owner->has_theme_item_in_types(Theme::DATA_TYPE_STYLEBOX, p_name, theme_types);
}
bool Control::has_theme_font(const StringName &p_name, const StringName &p_theme_type) const {
@@ -2545,8 +2495,8 @@ bool Control::has_theme_font(const StringName &p_name, const StringName &p_theme
}
List<StringName> theme_types;
- _get_theme_type_dependencies(p_theme_type, &theme_types);
- return has_theme_item_in_types(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_FONT, p_name, theme_types);
+ data.theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types);
+ return data.theme_owner->has_theme_item_in_types(Theme::DATA_TYPE_FONT, p_name, theme_types);
}
bool Control::has_theme_font_size(const StringName &p_name, const StringName &p_theme_type) const {
@@ -2557,8 +2507,8 @@ bool Control::has_theme_font_size(const StringName &p_name, const StringName &p_
}
List<StringName> theme_types;
- _get_theme_type_dependencies(p_theme_type, &theme_types);
- return has_theme_item_in_types(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_FONT_SIZE, p_name, theme_types);
+ data.theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types);
+ return data.theme_owner->has_theme_item_in_types(Theme::DATA_TYPE_FONT_SIZE, p_name, theme_types);
}
bool Control::has_theme_color(const StringName &p_name, const StringName &p_theme_type) const {
@@ -2569,8 +2519,8 @@ bool Control::has_theme_color(const StringName &p_name, const StringName &p_them
}
List<StringName> theme_types;
- _get_theme_type_dependencies(p_theme_type, &theme_types);
- return has_theme_item_in_types(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_COLOR, p_name, theme_types);
+ data.theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types);
+ return data.theme_owner->has_theme_item_in_types(Theme::DATA_TYPE_COLOR, p_name, theme_types);
}
bool Control::has_theme_constant(const StringName &p_name, const StringName &p_theme_type) const {
@@ -2581,8 +2531,8 @@ bool Control::has_theme_constant(const StringName &p_name, const StringName &p_t
}
List<StringName> theme_types;
- _get_theme_type_dependencies(p_theme_type, &theme_types);
- return has_theme_item_in_types(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_CONSTANT, p_name, theme_types);
+ data.theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types);
+ return data.theme_owner->has_theme_item_in_types(Theme::DATA_TYPE_CONSTANT, p_name, theme_types);
}
/// Local property overrides.
@@ -2591,93 +2541,93 @@ void Control::add_theme_icon_override(const StringName &p_name, const Ref<Textur
ERR_FAIL_COND(!p_icon.is_valid());
if (data.icon_override.has(p_name)) {
- data.icon_override[p_name]->disconnect("changed", callable_mp(this, &Control::_theme_property_override_changed));
+ data.icon_override[p_name]->disconnect("changed", callable_mp(this, &Control::_notify_theme_override_changed));
}
data.icon_override[p_name] = p_icon;
- data.icon_override[p_name]->connect("changed", callable_mp(this, &Control::_theme_property_override_changed), CONNECT_REFERENCE_COUNTED);
- _notify_theme_changed();
+ data.icon_override[p_name]->connect("changed", callable_mp(this, &Control::_notify_theme_override_changed), CONNECT_REFERENCE_COUNTED);
+ _notify_theme_override_changed();
}
void Control::add_theme_style_override(const StringName &p_name, const Ref<StyleBox> &p_style) {
ERR_FAIL_COND(!p_style.is_valid());
if (data.style_override.has(p_name)) {
- data.style_override[p_name]->disconnect("changed", callable_mp(this, &Control::_theme_property_override_changed));
+ data.style_override[p_name]->disconnect("changed", callable_mp(this, &Control::_notify_theme_override_changed));
}
data.style_override[p_name] = p_style;
- data.style_override[p_name]->connect("changed", callable_mp(this, &Control::_theme_property_override_changed), CONNECT_REFERENCE_COUNTED);
- _notify_theme_changed();
+ data.style_override[p_name]->connect("changed", callable_mp(this, &Control::_notify_theme_override_changed), CONNECT_REFERENCE_COUNTED);
+ _notify_theme_override_changed();
}
void Control::add_theme_font_override(const StringName &p_name, const Ref<Font> &p_font) {
ERR_FAIL_COND(!p_font.is_valid());
if (data.font_override.has(p_name)) {
- data.font_override[p_name]->disconnect("changed", callable_mp(this, &Control::_theme_property_override_changed));
+ data.font_override[p_name]->disconnect("changed", callable_mp(this, &Control::_notify_theme_override_changed));
}
data.font_override[p_name] = p_font;
- data.font_override[p_name]->connect("changed", callable_mp(this, &Control::_theme_property_override_changed), CONNECT_REFERENCE_COUNTED);
- _notify_theme_changed();
+ data.font_override[p_name]->connect("changed", callable_mp(this, &Control::_notify_theme_override_changed), CONNECT_REFERENCE_COUNTED);
+ _notify_theme_override_changed();
}
void Control::add_theme_font_size_override(const StringName &p_name, int p_font_size) {
data.font_size_override[p_name] = p_font_size;
- _notify_theme_changed();
+ _notify_theme_override_changed();
}
void Control::add_theme_color_override(const StringName &p_name, const Color &p_color) {
data.color_override[p_name] = p_color;
- _notify_theme_changed();
+ _notify_theme_override_changed();
}
void Control::add_theme_constant_override(const StringName &p_name, int p_constant) {
data.constant_override[p_name] = p_constant;
- _notify_theme_changed();
+ _notify_theme_override_changed();
}
void Control::remove_theme_icon_override(const StringName &p_name) {
if (data.icon_override.has(p_name)) {
- data.icon_override[p_name]->disconnect("changed", callable_mp(this, &Control::_theme_property_override_changed));
+ data.icon_override[p_name]->disconnect("changed", callable_mp(this, &Control::_notify_theme_override_changed));
}
data.icon_override.erase(p_name);
- _notify_theme_changed();
+ _notify_theme_override_changed();
}
void Control::remove_theme_style_override(const StringName &p_name) {
if (data.style_override.has(p_name)) {
- data.style_override[p_name]->disconnect("changed", callable_mp(this, &Control::_theme_property_override_changed));
+ data.style_override[p_name]->disconnect("changed", callable_mp(this, &Control::_notify_theme_override_changed));
}
data.style_override.erase(p_name);
- _notify_theme_changed();
+ _notify_theme_override_changed();
}
void Control::remove_theme_font_override(const StringName &p_name) {
if (data.font_override.has(p_name)) {
- data.font_override[p_name]->disconnect("changed", callable_mp(this, &Control::_theme_property_override_changed));
+ data.font_override[p_name]->disconnect("changed", callable_mp(this, &Control::_notify_theme_override_changed));
}
data.font_override.erase(p_name);
- _notify_theme_changed();
+ _notify_theme_override_changed();
}
void Control::remove_theme_font_size_override(const StringName &p_name) {
data.font_size_override.erase(p_name);
- _notify_theme_changed();
+ _notify_theme_override_changed();
}
void Control::remove_theme_color_override(const StringName &p_name) {
data.color_override.erase(p_name);
- _notify_theme_changed();
+ _notify_theme_override_changed();
}
void Control::remove_theme_constant_override(const StringName &p_name) {
data.constant_override.erase(p_name);
- _notify_theme_changed();
+ _notify_theme_override_changed();
}
bool Control::has_theme_icon_override(const StringName &p_name) const {
@@ -2712,157 +2662,16 @@ bool Control::has_theme_constant_override(const StringName &p_name) const {
/// Default theme properties.
-float Control::fetch_theme_default_base_scale(Control *p_theme_owner, Window *p_theme_owner_window) {
- // First, look through each control or window node in the branch, until no valid parent can be found.
- // Only nodes with a theme resource attached are considered.
- // For each theme resource see if their assigned theme has the default value defined and valid.
- Control *theme_owner = p_theme_owner;
- Window *theme_owner_window = p_theme_owner_window;
-
- while (theme_owner || theme_owner_window) {
- if (theme_owner && theme_owner->data.theme->has_default_base_scale()) {
- return theme_owner->data.theme->get_default_base_scale();
- }
-
- if (theme_owner_window && theme_owner_window->theme->has_default_base_scale()) {
- return theme_owner_window->theme->get_default_base_scale();
- }
-
- Node *parent = theme_owner ? theme_owner->get_parent() : theme_owner_window->get_parent();
- Control *parent_c = Object::cast_to<Control>(parent);
- if (parent_c) {
- theme_owner = parent_c->data.theme_owner;
- theme_owner_window = parent_c->data.theme_owner_window;
- } else {
- Window *parent_w = Object::cast_to<Window>(parent);
- if (parent_w) {
- theme_owner = parent_w->theme_owner;
- theme_owner_window = parent_w->theme_owner_window;
- } else {
- theme_owner = nullptr;
- theme_owner_window = nullptr;
- }
- }
- }
-
- // Secondly, check the project-defined Theme resource.
- if (Theme::get_project_default().is_valid()) {
- if (Theme::get_project_default()->has_default_base_scale()) {
- return Theme::get_project_default()->get_default_base_scale();
- }
- }
-
- // Lastly, fall back on the default Theme.
- if (Theme::get_default()->has_default_base_scale()) {
- return Theme::get_default()->get_default_base_scale();
- }
- return Theme::get_fallback_base_scale();
-}
-
float Control::get_theme_default_base_scale() const {
- return fetch_theme_default_base_scale(data.theme_owner, data.theme_owner_window);
-}
-
-Ref<Font> Control::fetch_theme_default_font(Control *p_theme_owner, Window *p_theme_owner_window) {
- // First, look through each control or window node in the branch, until no valid parent can be found.
- // Only nodes with a theme resource attached are considered.
- // For each theme resource see if their assigned theme has the default value defined and valid.
- Control *theme_owner = p_theme_owner;
- Window *theme_owner_window = p_theme_owner_window;
-
- while (theme_owner || theme_owner_window) {
- if (theme_owner && theme_owner->data.theme->has_default_font()) {
- return theme_owner->data.theme->get_default_font();
- }
-
- if (theme_owner_window && theme_owner_window->theme->has_default_font()) {
- return theme_owner_window->theme->get_default_font();
- }
-
- Node *parent = theme_owner ? theme_owner->get_parent() : theme_owner_window->get_parent();
- Control *parent_c = Object::cast_to<Control>(parent);
- if (parent_c) {
- theme_owner = parent_c->data.theme_owner;
- theme_owner_window = parent_c->data.theme_owner_window;
- } else {
- Window *parent_w = Object::cast_to<Window>(parent);
- if (parent_w) {
- theme_owner = parent_w->theme_owner;
- theme_owner_window = parent_w->theme_owner_window;
- } else {
- theme_owner = nullptr;
- theme_owner_window = nullptr;
- }
- }
- }
-
- // Secondly, check the project-defined Theme resource.
- if (Theme::get_project_default().is_valid()) {
- if (Theme::get_project_default()->has_default_font()) {
- return Theme::get_project_default()->get_default_font();
- }
- }
-
- // Lastly, fall back on the default Theme.
- if (Theme::get_default()->has_default_font()) {
- return Theme::get_default()->get_default_font();
- }
- return Theme::get_fallback_font();
+ return data.theme_owner->get_theme_default_base_scale();
}
Ref<Font> Control::get_theme_default_font() const {
- return fetch_theme_default_font(data.theme_owner, data.theme_owner_window);
-}
-
-int Control::fetch_theme_default_font_size(Control *p_theme_owner, Window *p_theme_owner_window) {
- // First, look through each control or window node in the branch, until no valid parent can be found.
- // Only nodes with a theme resource attached are considered.
- // For each theme resource see if their assigned theme has the default value defined and valid.
- Control *theme_owner = p_theme_owner;
- Window *theme_owner_window = p_theme_owner_window;
-
- while (theme_owner || theme_owner_window) {
- if (theme_owner && theme_owner->data.theme->has_default_font_size()) {
- return theme_owner->data.theme->get_default_font_size();
- }
-
- if (theme_owner_window && theme_owner_window->theme->has_default_font_size()) {
- return theme_owner_window->theme->get_default_font_size();
- }
-
- Node *parent = theme_owner ? theme_owner->get_parent() : theme_owner_window->get_parent();
- Control *parent_c = Object::cast_to<Control>(parent);
- if (parent_c) {
- theme_owner = parent_c->data.theme_owner;
- theme_owner_window = parent_c->data.theme_owner_window;
- } else {
- Window *parent_w = Object::cast_to<Window>(parent);
- if (parent_w) {
- theme_owner = parent_w->theme_owner;
- theme_owner_window = parent_w->theme_owner_window;
- } else {
- theme_owner = nullptr;
- theme_owner_window = nullptr;
- }
- }
- }
-
- // Secondly, check the project-defined Theme resource.
- if (Theme::get_project_default().is_valid()) {
- if (Theme::get_project_default()->has_default_font_size()) {
- return Theme::get_project_default()->get_default_font_size();
- }
- }
-
- // Lastly, fall back on the default Theme.
- if (Theme::get_default()->has_default_font_size()) {
- return Theme::get_default()->get_default_font_size();
- }
- return Theme::get_fallback_font_size();
+ return data.theme_owner->get_theme_default_font();
}
int Control::get_theme_default_font_size() const {
- return fetch_theme_default_font_size(data.theme_owner, data.theme_owner_window);
+ return data.theme_owner->get_theme_default_font_size();
}
/// Bulk actions.
@@ -2875,18 +2684,18 @@ void Control::end_bulk_theme_override() {
ERR_FAIL_COND(!data.bulk_theme_override);
data.bulk_theme_override = false;
- _notify_theme_changed();
+ _notify_theme_override_changed();
}
// Internationalization.
-Array Control::structured_text_parser(TextServer::StructuredTextParser p_parser_type, const Array &p_args, const String &p_text) const {
+TypedArray<Vector2i> Control::structured_text_parser(TextServer::StructuredTextParser p_parser_type, const Array &p_args, const String &p_text) const {
if (p_parser_type == TextServer::STRUCTURED_TEXT_CUSTOM) {
- Array ret;
+ TypedArray<Vector2i> ret;
if (GDVIRTUAL_CALL(_structured_text_parser, p_args, p_text, ret)) {
return ret;
} else {
- return Array();
+ return TypedArray<Vector2i>();
}
} else {
return TS->parse_structured_text(p_parser_type, p_args, p_text);
@@ -2894,6 +2703,9 @@ Array Control::structured_text_parser(TextServer::StructuredTextParser p_parser_
}
void Control::set_layout_direction(Control::LayoutDirection p_direction) {
+ if (data.layout_dir == p_direction) {
+ return;
+ }
ERR_FAIL_INDEX((int)p_direction, 4);
data.layout_dir = p_direction;
@@ -2954,12 +2766,12 @@ bool Control::is_auto_translating() const {
// Extra properties.
-void Control::set_tooltip(const String &p_tooltip) {
- data.tooltip = p_tooltip;
+void Control::set_tooltip_text(const String &p_hint) {
+ data.tooltip = p_hint;
update_configuration_warnings();
}
-String Control::_get_tooltip() const {
+String Control::get_tooltip_text() const {
return data.tooltip;
}
@@ -2977,36 +2789,25 @@ Control *Control::make_custom_tooltip(const String &p_text) const {
// Base object overrides.
-void Control::add_child_notify(Node *p_child) {
- Control *child_c = Object::cast_to<Control>(p_child);
-
- if (child_c && child_c->data.theme.is_null() && (data.theme_owner || data.theme_owner_window)) {
- _propagate_theme_changed(child_c, data.theme_owner, data.theme_owner_window); //need to propagate here, since many controls may require setting up stuff
- }
-
- Window *child_w = Object::cast_to<Window>(p_child);
-
- if (child_w && child_w->theme.is_null() && (data.theme_owner || data.theme_owner_window)) {
- _propagate_theme_changed(child_w, data.theme_owner, data.theme_owner_window); //need to propagate here, since many controls may require setting up stuff
- }
-}
-
-void Control::remove_child_notify(Node *p_child) {
- Control *child_c = Object::cast_to<Control>(p_child);
+void Control::_notification(int p_notification) {
+ switch (p_notification) {
+ case NOTIFICATION_POSTINITIALIZE: {
+ _invalidate_theme_cache();
+ _update_theme_item_cache();
+ } break;
- if (child_c && (child_c->data.theme_owner || child_c->data.theme_owner_window) && child_c->data.theme.is_null()) {
- _propagate_theme_changed(child_c, nullptr, nullptr);
- }
+ case NOTIFICATION_PARENTED: {
+ data.theme_owner->assign_theme_on_parented(this);
+ } break;
- Window *child_w = Object::cast_to<Window>(p_child);
+ case NOTIFICATION_UNPARENTED: {
+ data.theme_owner->clear_theme_on_unparented(this);
+ } break;
- if (child_w && (child_w->theme_owner || child_w->theme_owner_window) && child_w->theme.is_null()) {
- _propagate_theme_changed(child_w, nullptr, nullptr);
- }
-}
+ case NOTIFICATION_ENTER_TREE: {
+ notification(NOTIFICATION_THEME_CHANGED);
+ } break;
-void Control::_notification(int p_notification) {
- switch (p_notification) {
case NOTIFICATION_POST_ENTER_TREE: {
data.minimum_size_valid = false;
data.is_rtl_dirty = true;
@@ -3020,7 +2821,7 @@ void Control::_notification(int p_notification) {
case NOTIFICATION_READY: {
#ifdef DEBUG_ENABLED
- connect("ready", callable_mp(this, &Control::_clear_size_warning), CONNECT_DEFERRED | CONNECT_ONESHOT);
+ connect("ready", callable_mp(this, &Control::_clear_size_warning), CONNECT_DEFERRED | CONNECT_ONE_SHOT);
#endif
} break;
@@ -3029,18 +2830,6 @@ void Control::_notification(int p_notification) {
data.parent_window = Object::cast_to<Window>(get_parent());
data.is_rtl_dirty = true;
- if (data.theme.is_null()) {
- if (data.parent && (data.parent->data.theme_owner || data.parent->data.theme_owner_window)) {
- data.theme_owner = data.parent->data.theme_owner;
- data.theme_owner_window = data.parent->data.theme_owner_window;
- notification(NOTIFICATION_THEME_CHANGED);
- } else if (data.parent_window && (data.parent_window->theme_owner || data.parent_window->theme_owner_window)) {
- data.theme_owner = data.parent_window->theme_owner;
- data.theme_owner_window = data.parent_window->theme_owner_window;
- notification(NOTIFICATION_THEME_CHANGED);
- }
- }
-
CanvasItem *node = this;
bool has_parent_control = false;
@@ -3106,9 +2895,9 @@ void Control::_notification(int p_notification) {
// some parents need to know the order of the children to draw (like TabContainer)
// update if necessary
if (data.parent) {
- data.parent->update();
+ data.parent->queue_redraw();
}
- update();
+ queue_redraw();
if (data.RI) {
get_viewport()->_gui_set_root_order_dirty();
@@ -3135,17 +2924,20 @@ void Control::_notification(int p_notification) {
case NOTIFICATION_FOCUS_ENTER: {
emit_signal(SceneStringNames::get_singleton()->focus_entered);
- update();
+ queue_redraw();
} break;
case NOTIFICATION_FOCUS_EXIT: {
emit_signal(SceneStringNames::get_singleton()->focus_exited);
- update();
+ queue_redraw();
} break;
case NOTIFICATION_THEME_CHANGED: {
+ emit_signal(SceneStringNames::get_singleton()->theme_changed);
+ _invalidate_theme_cache();
+ _update_theme_item_cache();
update_minimum_size();
- update();
+ queue_redraw();
} break;
case NOTIFICATION_VISIBILITY_CHANGED: {
@@ -3164,6 +2956,8 @@ void Control::_notification(int p_notification) {
case NOTIFICATION_LAYOUT_DIRECTION_CHANGED: {
if (is_inside_tree()) {
data.is_rtl_dirty = true;
+ _invalidate_theme_cache();
+ _update_theme_item_cache();
_size_changed();
}
} break;
@@ -3291,9 +3085,9 @@ void Control::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_v_grow_direction", "direction"), &Control::set_v_grow_direction);
ClassDB::bind_method(D_METHOD("get_v_grow_direction"), &Control::get_v_grow_direction);
- ClassDB::bind_method(D_METHOD("set_tooltip", "tooltip"), &Control::set_tooltip);
+ ClassDB::bind_method(D_METHOD("set_tooltip_text", "hint"), &Control::set_tooltip_text);
+ ClassDB::bind_method(D_METHOD("get_tooltip_text"), &Control::get_tooltip_text);
ClassDB::bind_method(D_METHOD("get_tooltip", "at_position"), &Control::get_tooltip, DEFVAL(Point2()));
- ClassDB::bind_method(D_METHOD("_get_tooltip"), &Control::_get_tooltip);
ClassDB::bind_method(D_METHOD("set_default_cursor_shape", "shape"), &Control::set_default_cursor_shape);
ClassDB::bind_method(D_METHOD("get_default_cursor_shape"), &Control::get_default_cursor_shape);
@@ -3340,7 +3134,7 @@ void Control::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "clip_contents"), "set_clip_contents", "is_clipping_contents");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "custom_minimum_size", PROPERTY_HINT_NONE, "suffix:px"), "set_custom_minimum_size", "get_custom_minimum_size");
ADD_PROPERTY(PropertyInfo(Variant::INT, "layout_direction", PROPERTY_HINT_ENUM, "Inherited,Locale,Left-to-Right,Right-to-Left"), "set_layout_direction", "get_layout_direction");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "layout_mode", PROPERTY_HINT_ENUM, "Position,Anchors,Container,Uncontrolled", PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_layout_mode", "_get_layout_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "layout_mode", PROPERTY_HINT_ENUM, "Position,Anchors,Container,Uncontrolled", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_INTERNAL), "_set_layout_mode", "_get_layout_mode");
ADD_PROPERTY_DEFAULT("layout_mode", LayoutMode::LAYOUT_MODE_POSITION);
const String anchors_presets_options = "Custom:-1,PresetFullRect:15,"
@@ -3348,14 +3142,14 @@ void Control::_bind_methods() {
"PresetCenterLeft:4,PresetCenterTop:5,PresetCenterRight:6,PresetCenterBottom:7,PresetCenter:8,"
"PresetLeftWide:9,PresetTopWide:10,PresetRightWide:11,PresetBottomWide:12,PresetVCenterWide:13,PresetHCenterWide:14";
- ADD_PROPERTY(PropertyInfo(Variant::INT, "anchors_preset", PROPERTY_HINT_ENUM, anchors_presets_options, PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_anchors_layout_preset", "_get_anchors_layout_preset");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "anchors_preset", PROPERTY_HINT_ENUM, anchors_presets_options, PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_INTERNAL), "_set_anchors_layout_preset", "_get_anchors_layout_preset");
ADD_PROPERTY_DEFAULT("anchors_preset", -1);
ADD_SUBGROUP_INDENT("Anchor Points", "anchor_", 1);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anchor_left", PROPERTY_HINT_RANGE, "0,1,0.001,or_lesser,or_greater"), "_set_anchor", "get_anchor", SIDE_LEFT);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anchor_top", PROPERTY_HINT_RANGE, "0,1,0.001,or_lesser,or_greater"), "_set_anchor", "get_anchor", SIDE_TOP);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anchor_right", PROPERTY_HINT_RANGE, "0,1,0.001,or_lesser,or_greater"), "_set_anchor", "get_anchor", SIDE_RIGHT);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anchor_bottom", PROPERTY_HINT_RANGE, "0,1,0.001,or_lesser,or_greater"), "_set_anchor", "get_anchor", SIDE_BOTTOM);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anchor_left", PROPERTY_HINT_RANGE, "0,1,0.001,or_less,or_greater"), "_set_anchor", "get_anchor", SIDE_LEFT);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anchor_top", PROPERTY_HINT_RANGE, "0,1,0.001,or_less,or_greater"), "_set_anchor", "get_anchor", SIDE_TOP);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anchor_right", PROPERTY_HINT_RANGE, "0,1,0.001,or_less,or_greater"), "_set_anchor", "get_anchor", SIDE_RIGHT);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anchor_bottom", PROPERTY_HINT_RANGE, "0,1,0.001,or_less,or_greater"), "_set_anchor", "get_anchor", SIDE_BOTTOM);
ADD_SUBGROUP_INDENT("Anchor Offsets", "offset_", 1);
ADD_PROPERTYI(PropertyInfo(Variant::INT, "offset_left", PROPERTY_HINT_RANGE, "-4096,4096,suffix:px"), "set_offset", "get_offset", SIDE_LEFT);
@@ -3371,7 +3165,7 @@ void Control::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "size", PROPERTY_HINT_NONE, "suffix:px", PROPERTY_USAGE_EDITOR), "_set_size", "get_size");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "position", PROPERTY_HINT_NONE, "suffix:px", PROPERTY_USAGE_EDITOR), "_set_position", "get_position");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "global_position", PROPERTY_HINT_NONE, "suffix:px", PROPERTY_USAGE_NONE), "_set_global_position", "get_global_position");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "rotation", PROPERTY_HINT_RANGE, "-360,360,0.1,or_lesser,or_greater,radians"), "set_rotation", "get_rotation");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "rotation", PROPERTY_HINT_RANGE, "-360,360,0.1,or_less,or_greater,radians"), "set_rotation", "get_rotation");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "scale"), "set_scale", "get_scale");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "pivot_offset", PROPERTY_HINT_NONE, "suffix:px"), "set_pivot_offset", "get_pivot_offset");
@@ -3383,8 +3177,8 @@ void Control::_bind_methods() {
ADD_GROUP("Auto Translate", "");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "auto_translate"), "set_auto_translate", "is_auto_translating");
- ADD_GROUP("Hint", "hint_");
- ADD_PROPERTY(PropertyInfo(Variant::STRING, "hint_tooltip", PROPERTY_HINT_MULTILINE_TEXT), "set_tooltip", "_get_tooltip");
+ ADD_GROUP("Tooltip", "tooltip_");
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "tooltip_text", PROPERTY_HINT_MULTILINE_TEXT), "set_tooltip_text", "get_tooltip_text");
ADD_GROUP("Focus", "focus_");
ADD_PROPERTYI(PropertyInfo(Variant::NODE_PATH, "focus_neighbor_left", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Control"), "set_focus_neighbor", "get_focus_neighbor", SIDE_LEFT);
@@ -3507,3 +3301,30 @@ void Control::_bind_methods() {
GDVIRTUAL_BIND(_gui_input, "event");
}
+
+Control::Control() {
+ data.theme_owner = memnew(ThemeOwner);
+}
+
+Control::~Control() {
+ memdelete(data.theme_owner);
+
+ // Resources need to be disconnected.
+ for (KeyValue<StringName, Ref<Texture2D>> &E : data.icon_override) {
+ E.value->disconnect("changed", callable_mp(this, &Control::_notify_theme_override_changed));
+ }
+ for (KeyValue<StringName, Ref<StyleBox>> &E : data.style_override) {
+ E.value->disconnect("changed", callable_mp(this, &Control::_notify_theme_override_changed));
+ }
+ for (KeyValue<StringName, Ref<Font>> &E : data.font_override) {
+ E.value->disconnect("changed", callable_mp(this, &Control::_notify_theme_override_changed));
+ }
+
+ // Then override maps can be simply cleared.
+ data.icon_override.clear();
+ data.style_override.clear();
+ data.font_override.clear();
+ data.font_size_override.clear();
+ data.color_override.clear();
+ data.constant_override.clear();
+}