From 7ddf1fccdd41b3b71b4a02c1cbcec41e3d14c9de Mon Sep 17 00:00:00 2001 From: Haoyu Qiu Date: Tue, 8 Oct 2024 19:38:27 +0800 Subject: [PATCH] Cache layout direction for `Control` Adds `get_resolved_layout_direction()` for `Control` and `Window` to get potentially cached layout direction. --- scene/gui/control.cpp | 168 +++++++++++++++++++++++++----------------- scene/gui/control.h | 9 ++- scene/main/window.cpp | 139 +++++++++++++++++++--------------- scene/main/window.h | 6 +- 4 files changed, 190 insertions(+), 132 deletions(-) diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp index 4010d57b1d27..efca5d55a6ba 100644 --- a/scene/gui/control.cpp +++ b/scene/gui/control.cpp @@ -195,10 +195,18 @@ void Control::reparent(Node *p_parent, bool p_keep_global_transform) { // Editor integration. -int Control::root_layout_direction = 0; +Control::LayoutDirection Control::root_layout_direction = Control::LAYOUT_DIRECTION_APPLICATION_LOCALE; + +static Control::LayoutDirection _to_layout_direction(int p_root_dir) { + // Root node layout direction skips LAYOUT_DIRECTION_INHERIT. + int shifted = p_root_dir + 1; + ERR_FAIL_INDEX_V(shifted, Control::LAYOUT_DIRECTION_MAX, Control::LAYOUT_DIRECTION_APPLICATION_LOCALE); + ERR_FAIL_COND_V(shifted == Control::LAYOUT_DIRECTION_INHERITED, Control::LAYOUT_DIRECTION_APPLICATION_LOCALE); + return (Control::LayoutDirection)shifted; +} void Control::set_root_layout_direction(int p_root_dir) { - root_layout_direction = p_root_dir; + root_layout_direction = _to_layout_direction(p_root_dir); } #ifdef TOOLS_ENABLED @@ -3056,84 +3064,100 @@ Control::LayoutDirection Control::get_layout_direction() const { return data.layout_dir; } -bool Control::is_layout_rtl() const { - ERR_READ_THREAD_GUARD_V(false); - if (data.is_rtl_dirty) { - data.is_rtl_dirty = false; - if (data.layout_dir == LAYOUT_DIRECTION_INHERITED) { +Control::LayoutDirection Control::get_resolved_layout_direction() const { + if (data.is_resolved_layout_dir_dirty) { + data.is_resolved_layout_dir_dirty = false; + + switch (data.layout_dir) { + case LAYOUT_DIRECTION_APPLICATION_LOCALE: { + if (GLOBAL_GET(SNAME("internationalization/rendering/force_right_to_left_layout_direction"))) { + data.resolved_layout_dir = LAYOUT_DIRECTION_RTL; + } else { + data.resolved_layout_dir = LAYOUT_DIRECTION_APPLICATION_LOCALE; + } + } break; + + case LAYOUT_DIRECTION_SYSTEM_LOCALE: { + if (GLOBAL_GET(SNAME("internationalization/rendering/force_right_to_left_layout_direction"))) { + data.resolved_layout_dir = LAYOUT_DIRECTION_RTL; + } else { + data.resolved_layout_dir = LAYOUT_DIRECTION_SYSTEM_LOCALE; + } + } break; + + case LAYOUT_DIRECTION_INHERITED: { #ifdef TOOLS_ENABLED - if (is_part_of_edited_scene() && GLOBAL_GET(SNAME("internationalization/rendering/force_right_to_left_layout_direction"))) { - data.is_rtl = true; - return data.is_rtl; - } - if (is_inside_tree()) { - Node *edited_scene_root = get_tree()->get_edited_scene_root(); - if (edited_scene_root == this) { - int proj_root_layout_direction = GLOBAL_GET(SNAME("internationalization/rendering/root_node_layout_direction")); - if (proj_root_layout_direction == 1) { - data.is_rtl = false; - } else if (proj_root_layout_direction == 2) { - data.is_rtl = true; - } else if (proj_root_layout_direction == 3) { - String locale = OS::get_singleton()->get_locale(); - data.is_rtl = TS->is_locale_right_to_left(locale); - } else { - String locale = TranslationServer::get_singleton()->get_tool_locale(); - data.is_rtl = TS->is_locale_right_to_left(locale); + if (is_part_of_edited_scene() && GLOBAL_GET(SNAME("internationalization/rendering/force_right_to_left_layout_direction"))) { + data.resolved_layout_dir = LAYOUT_DIRECTION_RTL; + return data.resolved_layout_dir; + } + if (is_inside_tree()) { + Node *edited_scene_root = get_tree()->get_edited_scene_root(); + if (edited_scene_root == this) { + data.resolved_layout_dir = _to_layout_direction(GLOBAL_GET(SNAME("internationalization/rendering/root_node_layout_direction"))); + return data.resolved_layout_dir; } - return data.is_rtl; } - } #else - if (GLOBAL_GET(SNAME("internationalization/rendering/force_right_to_left_layout_direction"))) { - data.is_rtl = true; - return data.is_rtl; - } -#endif // TOOLS_ENABLED - Node *parent_node = get_parent(); - while (parent_node) { - Control *parent_control = Object::cast_to(parent_node); - if (parent_control) { - data.is_rtl = parent_control->is_layout_rtl(); - return data.is_rtl; + if (GLOBAL_GET(SNAME("internationalization/rendering/force_right_to_left_layout_direction"))) { + data.resolved_layout_dir = LAYOUT_DIRECTION_RTL; + return data.resolved_layout_dir; } +#endif // TOOLS_ENABLED + Node *parent_node = get_parent(); + while (parent_node) { + Control *parent_control = Object::cast_to(parent_node); + if (parent_control) { + data.resolved_layout_dir = parent_control->get_resolved_layout_direction(); + return data.resolved_layout_dir; + } - Window *parent_window = Object::cast_to(parent_node); - if (parent_window) { - data.is_rtl = parent_window->is_layout_rtl(); - return data.is_rtl; + Window *parent_window = Object::cast_to(parent_node); + if (parent_window) { + data.resolved_layout_dir = (LayoutDirection)parent_window->get_resolved_layout_direction(); + return data.resolved_layout_dir; + } + parent_node = parent_node->get_parent(); } - parent_node = parent_node->get_parent(); - } - if (root_layout_direction == 1) { - data.is_rtl = false; - } else if (root_layout_direction == 2) { - data.is_rtl = true; - } else if (root_layout_direction == 3) { - String locale = OS::get_singleton()->get_locale(); - data.is_rtl = TS->is_locale_right_to_left(locale); - } else { - String locale = TranslationServer::get_singleton()->get_tool_locale(); + data.resolved_layout_dir = root_layout_direction; + } break; + + default: { + data.resolved_layout_dir = data.layout_dir; + } break; + } + } + return data.resolved_layout_dir; +} + +bool Control::is_layout_rtl() const { + ERR_READ_THREAD_GUARD_V(false); + if (data.is_rtl_dirty) { + switch (get_resolved_layout_direction()) { + case LAYOUT_DIRECTION_APPLICATION_LOCALE: { + const String &locale = TranslationServer::get_singleton()->get_tool_locale(); data.is_rtl = TS->is_locale_right_to_left(locale); - } - } else if (data.layout_dir == LAYOUT_DIRECTION_APPLICATION_LOCALE) { - if (GLOBAL_GET(SNAME("internationalization/rendering/force_right_to_left_layout_direction"))) { + } break; + + case LAYOUT_DIRECTION_LTR: { + data.is_rtl = false; + } break; + + case LAYOUT_DIRECTION_RTL: { data.is_rtl = true; - } else { - String locale = TranslationServer::get_singleton()->get_tool_locale(); + } break; + + case LAYOUT_DIRECTION_SYSTEM_LOCALE: { + const String &locale = OS::get_singleton()->get_locale(); data.is_rtl = TS->is_locale_right_to_left(locale); - } - } else if (data.layout_dir == LAYOUT_DIRECTION_SYSTEM_LOCALE) { - if (GLOBAL_GET(SNAME("internationalization/rendering/force_right_to_left_layout_direction"))) { - const_cast(this)->data.is_rtl = true; - } else { - String locale = OS::get_singleton()->get_locale(); - const_cast(this)->data.is_rtl = TS->is_locale_right_to_left(locale); - } - } else { - data.is_rtl = (data.layout_dir == LAYOUT_DIRECTION_RTL); + } break; + + default: { + ERR_PRINT("Unexpected layout direction"); + } break; } + data.is_rtl_dirty = false; } return data.is_rtl; } @@ -3249,6 +3273,7 @@ void Control::_notification(int p_notification) { case NOTIFICATION_POST_ENTER_TREE: { data.is_rtl_dirty = true; + data.is_resolved_layout_dir_dirty = true; update_minimum_size(); _size_changed(); } break; @@ -3268,6 +3293,7 @@ void Control::_notification(int p_notification) { case NOTIFICATION_ENTER_CANVAS: { data.is_rtl_dirty = true; + data.is_resolved_layout_dir_dirty = true; CanvasItem *node = this; bool has_parent_control = false; @@ -3329,6 +3355,7 @@ void Control::_notification(int p_notification) { data.parent_canvas_item = nullptr; data.is_rtl_dirty = true; + data.is_resolved_layout_dir_dirty = true; } break; case NOTIFICATION_CHILD_ORDER_CHANGED: { @@ -3387,8 +3414,11 @@ void Control::_notification(int p_notification) { } } break; - case NOTIFICATION_TRANSLATION_CHANGED: case NOTIFICATION_LAYOUT_DIRECTION_CHANGED: { + data.is_resolved_layout_dir_dirty = true; + [[fallthrough]]; + } + case NOTIFICATION_TRANSLATION_CHANGED: { if (is_inside_tree()) { data.is_rtl_dirty = true; diff --git a/scene/gui/control.h b/scene/gui/control.h index 23190381f3f4..74413141940d 100644 --- a/scene/gui/control.h +++ b/scene/gui/control.h @@ -258,6 +258,9 @@ class Control : public CanvasItem { // Internationalization. LayoutDirection layout_dir = LAYOUT_DIRECTION_INHERITED; + mutable LayoutDirection resolved_layout_dir = LAYOUT_DIRECTION_APPLICATION_LOCALE; + mutable bool is_resolved_layout_dir_dirty = true; + mutable bool is_rtl_dirty = true; mutable bool is_rtl = false; @@ -325,7 +328,8 @@ class Control : public CanvasItem { // Extra properties. - static int root_layout_direction; + // Root layout direction is never LAYOUT_DIRECTION_INHERITED. + static LayoutDirection root_layout_direction; String get_tooltip_text() const; @@ -635,6 +639,9 @@ class Control : public CanvasItem { LayoutDirection get_layout_direction() const; virtual bool is_layout_rtl() const; + // LAYOUT_DIRECTION_INHERITED is resolved into other enumerators. + LayoutDirection get_resolved_layout_direction() const; + void set_localize_numeral_system(bool p_enable); bool is_localizing_numeral_system() const; diff --git a/scene/main/window.cpp b/scene/main/window.cpp index 33e8b81991e2..969a5587bede 100644 --- a/scene/main/window.cpp +++ b/scene/main/window.cpp @@ -39,10 +39,18 @@ // Editor integration. -int Window::root_layout_direction = 0; +Window::LayoutDirection Window::root_layout_direction = Window::LAYOUT_DIRECTION_APPLICATION_LOCALE; + +static Window::LayoutDirection _to_layout_direction(int p_root_dir) { + // Root node layout direction skips LAYOUT_DIRECTION_INHERIT. + int shifted = p_root_dir + 1; + ERR_FAIL_INDEX_V(shifted, Window::LAYOUT_DIRECTION_MAX, Window::LAYOUT_DIRECTION_APPLICATION_LOCALE); + ERR_FAIL_COND_V(shifted == Window::LAYOUT_DIRECTION_INHERITED, Window::LAYOUT_DIRECTION_APPLICATION_LOCALE); + return (Window::LayoutDirection)shifted; +} void Window::set_root_layout_direction(int p_root_dir) { - root_layout_direction = p_root_dir; + root_layout_direction = _to_layout_direction(p_root_dir); } // Dynamic properties. @@ -2645,76 +2653,85 @@ Window::LayoutDirection Window::get_layout_direction() const { return layout_dir; } -bool Window::is_layout_rtl() const { - ERR_READ_THREAD_GUARD_V(false); - if (layout_dir == LAYOUT_DIRECTION_INHERITED) { +Window::LayoutDirection Window::get_resolved_layout_direction() const { + switch (layout_dir) { + case LAYOUT_DIRECTION_APPLICATION_LOCALE: { + if (GLOBAL_GET(SNAME("internationalization/rendering/force_right_to_left_layout_direction"))) { + return LAYOUT_DIRECTION_RTL; + } + return LAYOUT_DIRECTION_APPLICATION_LOCALE; + } break; + + case LAYOUT_DIRECTION_SYSTEM_LOCALE: { + if (GLOBAL_GET(SNAME("internationalization/rendering/force_right_to_left_layout_direction"))) { + return LAYOUT_DIRECTION_RTL; + } + return LAYOUT_DIRECTION_SYSTEM_LOCALE; + } break; + + case LAYOUT_DIRECTION_INHERITED: { #ifdef TOOLS_ENABLED - if (is_part_of_edited_scene() && GLOBAL_GET(SNAME("internationalization/rendering/force_right_to_left_layout_direction"))) { - return true; - } - if (is_inside_tree()) { - Node *edited_scene_root = get_tree()->get_edited_scene_root(); - if (edited_scene_root == this) { - int proj_root_layout_direction = GLOBAL_GET(SNAME("internationalization/rendering/root_node_layout_direction")); - if (proj_root_layout_direction == 1) { - return false; - } else if (proj_root_layout_direction == 2) { - return true; - } else if (proj_root_layout_direction == 3) { - String locale = OS::get_singleton()->get_locale(); - return TS->is_locale_right_to_left(locale); - } else { - String locale = TranslationServer::get_singleton()->get_tool_locale(); - return TS->is_locale_right_to_left(locale); + if (is_part_of_edited_scene() && GLOBAL_GET(SNAME("internationalization/rendering/force_right_to_left_layout_direction"))) { + return LAYOUT_DIRECTION_RTL; + } + if (is_inside_tree()) { + Node *edited_scene_root = get_tree()->get_edited_scene_root(); + if (edited_scene_root == this) { + return _to_layout_direction(GLOBAL_GET(SNAME("internationalization/rendering/root_node_layout_direction"))); } } - } #else - if (GLOBAL_GET(SNAME("internationalization/rendering/force_right_to_left_layout_direction"))) { - return true; - } -#endif - Node *parent_node = get_parent(); - while (parent_node) { - Control *parent_control = Object::cast_to(parent_node); - if (parent_control) { - return parent_control->is_layout_rtl(); + if (GLOBAL_GET(SNAME("internationalization/rendering/force_right_to_left_layout_direction"))) { + return LAYOUT_DIRECTION_RTL; } +#endif + Node *parent_node = get_parent(); + while (parent_node) { + Control *parent_control = Object::cast_to(parent_node); + if (parent_control) { + return (LayoutDirection)parent_control->get_resolved_layout_direction(); + } - Window *parent_window = Object::cast_to(parent_node); - if (parent_window) { - return parent_window->is_layout_rtl(); + Window *parent_window = Object::cast_to(parent_node); + if (parent_window) { + return parent_window->get_resolved_layout_direction(); + } + parent_node = parent_node->get_parent(); } - parent_node = parent_node->get_parent(); - } - if (root_layout_direction == 1) { - return false; - } else if (root_layout_direction == 2) { - return true; - } else if (root_layout_direction == 3) { - String locale = OS::get_singleton()->get_locale(); - return TS->is_locale_right_to_left(locale); - } else { - String locale = TranslationServer::get_singleton()->get_tool_locale(); - return TS->is_locale_right_to_left(locale); - } - } else if (layout_dir == LAYOUT_DIRECTION_APPLICATION_LOCALE) { - if (GLOBAL_GET(SNAME("internationalization/rendering/force_right_to_left_layout_direction"))) { - return true; - } else { - String locale = TranslationServer::get_singleton()->get_tool_locale(); + return root_layout_direction; + } break; + + default: { + return layout_dir; + } break; + } +} + +bool Window::is_layout_rtl() const { + ERR_READ_THREAD_GUARD_V(false); + switch (get_resolved_layout_direction()) { + case LAYOUT_DIRECTION_APPLICATION_LOCALE: { + const String &locale = TranslationServer::get_singleton()->get_tool_locale(); return TS->is_locale_right_to_left(locale); - } - } else if (layout_dir == LAYOUT_DIRECTION_SYSTEM_LOCALE) { - if (GLOBAL_GET(SNAME("internationalization/rendering/force_right_to_left_layout_direction"))) { + } break; + + case LAYOUT_DIRECTION_LTR: { + return false; + } break; + + case LAYOUT_DIRECTION_RTL: { return true; - } else { - String locale = OS::get_singleton()->get_locale(); + } break; + + case LAYOUT_DIRECTION_SYSTEM_LOCALE: { + const String &locale = OS::get_singleton()->get_locale(); return TS->is_locale_right_to_left(locale); - } - } else { - return (layout_dir == LAYOUT_DIRECTION_RTL); + } break; + + default: { + ERR_FAIL_V_MSG(false, "Unexpected layout direction"); + } break; } } diff --git a/scene/main/window.h b/scene/main/window.h index 6c82efcc3f9b..bed3863e9f7f 100644 --- a/scene/main/window.h +++ b/scene/main/window.h @@ -241,7 +241,8 @@ class Window : public Viewport { Ref debugger_stop_shortcut; - static int root_layout_direction; + // Root layout direction is never LAYOUT_DIRECTION_INHERITED. + static LayoutDirection root_layout_direction; protected: virtual Rect2i _popup_adjust_rect() const { return Rect2i(); } @@ -407,6 +408,9 @@ class Window : public Viewport { LayoutDirection get_layout_direction() const; bool is_layout_rtl() const; + // LAYOUT_DIRECTION_INHERITED is resolved into other enumerators. + LayoutDirection get_resolved_layout_direction() const; + #ifndef DISABLE_DEPRECATED void set_auto_translate(bool p_enable); bool is_auto_translating() const;