Refactor and remove excessive calls of NOTIFICATION_THEME_CHANGED

This commit is contained in:
Aaron Record 2022-07-08 13:29:36 -06:00
parent 6d196c1ce3
commit 74eb2a70bd
7 changed files with 170 additions and 182 deletions

View file

@ -252,36 +252,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;
}
@ -2260,62 +2260,62 @@ bool Control::is_clipping_contents() {
// Theming.
void Control::_propagate_theme_changed(Node *p_at, Control *p_owner, Window *p_owner_window, bool p_assign) {
void Control::_propagate_theme_changed(Node *p_at, Control *p_owner, Window *p_owner_window, bool p_notify, bool p_assign) {
Control *c = Object::cast_to<Control>(p_at);
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
if (!c && !w) {
// Theme inheritance chains are broken by nodes that aren't Control or Window.
return;
}
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);
}
}
}
bool assign = p_assign;
if (c) {
if (p_assign) {
if (c != p_owner && c->data.theme.is_valid()) {
// Has a theme, so we don't want to change the theme owner,
// but we still want to propagate in case this child has theme items
// it inherits from the theme this node uses.
// See https://github.com/godotengine/godot/issues/62844.
assign = false;
}
if (assign) {
c->data.theme_owner = p_owner;
c->data.theme_owner_window = p_owner_window;
}
c->notification(Control::NOTIFICATION_THEME_CHANGED);
c->emit_signal(SceneStringNames::get_singleton()->theme_changed);
}
if (w) {
if (p_assign) {
if (p_notify) {
c->notification(Control::NOTIFICATION_THEME_CHANGED);
}
} else if (w) {
if (w != p_owner_window && w->theme.is_valid()) {
// Same as above.
assign = false;
}
if (assign) {
w->theme_owner = p_owner;
w->theme_owner_window = p_owner_window;
}
w->notification(Window::NOTIFICATION_THEME_CHANGED);
w->emit_signal(SceneStringNames::get_singleton()->theme_changed);
if (p_notify) {
w->notification(Window::NOTIFICATION_THEME_CHANGED);
}
}
for (int i = 0; i < p_at->get_child_count(); i++) {
_propagate_theme_changed(p_at->get_child(i), p_owner, p_owner_window, p_notify, assign);
}
}
void Control::_theme_changed() {
_propagate_theme_changed(this, this, nullptr, false);
if (is_inside_tree()) {
_propagate_theme_changed(this, this, nullptr, true, false);
}
}
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.
}
void Control::_notify_theme_changed() {
if (!data.bulk_theme_override) {
void Control::_notify_theme_override_changed() {
if (!data.bulk_theme_override && is_inside_tree()) {
notification(NOTIFICATION_THEME_CHANGED);
}
}
@ -2339,28 +2339,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 (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);
}
}
}
if (data.theme.is_valid()) {
_propagate_theme_changed(this, this, nullptr, is_inside_tree(), true);
data.theme->connect("changed", callable_mp(this, &Control::_theme_changed), CONNECT_DEFERRED);
return;
}
Control *parent_c = Object::cast_to<Control>(get_parent());
if (parent_c && (parent_c->data.theme_owner || parent_c->data.theme_owner_window)) {
_propagate_theme_changed(this, parent_c->data.theme_owner, parent_c->data.theme_owner_window, is_inside_tree(), true);
return;
}
Window *parent_w = cast_to<Window>(get_parent());
if (parent_w && (parent_w->theme_owner || parent_w->theme_owner_window)) {
_propagate_theme_changed(this, parent_w->theme_owner, parent_w->theme_owner_window, is_inside_tree(), true);
return;
}
_propagate_theme_changed(this, nullptr, nullptr, is_inside_tree(), true);
}
Ref<Theme> Control::get_theme() const {
@ -2372,7 +2369,9 @@ void Control::set_theme_type_variation(const StringName &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 {
@ -2697,93 +2696,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 {
@ -2981,7 +2980,7 @@ 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.
@ -3087,37 +3086,26 @@ 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
// We propagate when this node uses a custom theme, so it can pass it on to its children.
if (data.theme_owner || data.theme_owner_window) {
// `p_notify` is false here as `NOTIFICATION_THEME_CHANGED` will be handled by `NOTIFICATION_ENTER_TREE`.
_propagate_theme_changed(p_child, data.theme_owner, data.theme_owner_window, false, true);
}
}
void Control::remove_child_notify(Node *p_child) {
Control *child_c = Object::cast_to<Control>(p_child);
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);
}
Window *child_w = Object::cast_to<Window>(p_child);
if (child_w && (child_w->theme_owner || child_w->theme_owner_window) && child_w->theme.is_null()) {
_propagate_theme_changed(child_w, nullptr, nullptr);
// If the removed child isn't inheriting any theme items through this node, then there's no need to propagate.
if (data.theme_owner || data.theme_owner_window) {
_propagate_theme_changed(p_child, nullptr, nullptr, false, true);
}
}
void Control::_notification(int p_notification) {
switch (p_notification) {
case NOTIFICATION_ENTER_TREE: {
_invalidate_theme_cache();
// Need to defer here, because theme owner information might be set in
// add_child_notify, which doesn't get called until right after this.
call_deferred(SNAME("notification"), NOTIFICATION_THEME_CHANGED);
} break;
case NOTIFICATION_POST_ENTER_TREE: {
@ -3142,18 +3130,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;
@ -3257,6 +3233,7 @@ void Control::_notification(int p_notification) {
} break;
case NOTIFICATION_THEME_CHANGED: {
emit_signal(SceneStringNames::get_singleton()->theme_changed);
_invalidate_theme_cache();
update_minimum_size();
update();
@ -3626,13 +3603,13 @@ void Control::_bind_methods() {
Control::~Control() {
// Resources need to be disconnected.
for (KeyValue<StringName, Ref<Texture2D>> &E : data.icon_override) {
E.value->disconnect("changed", callable_mp(this, &Control::_theme_property_override_changed));
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::_theme_property_override_changed));
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::_theme_property_override_changed));
E.value->disconnect("changed", callable_mp(this, &Control::_notify_theme_override_changed));
}
// Then override maps can be simply cleared.

View file

@ -300,11 +300,10 @@ private:
// Theming.
void _theme_changed();
void _theme_property_override_changed();
void _notify_theme_changed();
void _notify_theme_override_changed();
void _invalidate_theme_cache();
static void _propagate_theme_changed(Node *p_at, Control *p_owner, Window *p_owner_window, bool p_assign = true);
static void _propagate_theme_changed(Node *p_at, Control *p_owner, Window *p_owner_window, bool p_notify, bool p_assign);
template <class T>
static T get_theme_item_in_types(Control *p_theme_owner, Window *p_theme_owner_window, Theme::DataType p_data_type, const StringName &p_name, List<StringName> p_theme_types);