From cdb35db426a52fe1be7bbfccba4cff5ee40ddd4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pa=CC=84vels=20Nadtoc=CC=8Cajevs?= <7645683+bruvzg@users.noreply.github.com> Date: Mon, 9 Mar 2026 15:12:48 +0200 Subject: [PATCH] Do not show accessibility configuration warnings for non-focusable controls, account for name fallback. --- scene/gui/button.cpp | 23 ++++--- scene/gui/button.h | 2 + scene/gui/control.cpp | 40 ++++++----- scene/gui/control.h | 2 + scene/gui/graph_node.cpp | 125 +++++++++++++++++----------------- scene/gui/graph_node.h | 2 + scene/gui/line_edit.cpp | 13 +++- scene/gui/line_edit.h | 2 + scene/gui/link_button.cpp | 24 ++++--- scene/gui/link_button.h | 2 + scene/gui/menu_bar.cpp | 2 + scene/gui/popup_menu.cpp | 11 ++- scene/gui/popup_menu.h | 2 + scene/gui/spin_box.cpp | 10 ++- scene/gui/spin_box.h | 2 + scene/gui/split_container.cpp | 5 +- scene/gui/split_container.h | 2 + scene/gui/text_edit.cpp | 13 +++- scene/gui/text_edit.h | 2 + scene/main/window.cpp | 36 ++++++++-- scene/main/window.h | 4 ++ 21 files changed, 214 insertions(+), 110 deletions(-) diff --git a/scene/gui/button.cpp b/scene/gui/button.cpp index 6f805b319c..7fad8abd12 100644 --- a/scene/gui/button.cpp +++ b/scene/gui/button.cpp @@ -153,20 +153,25 @@ Ref Button::_get_current_stylebox() const { return stylebox; } +String Button::_get_accessibility_name() const { + const String &ac_name = Control::_get_accessibility_name(); + if (!xl_text.is_empty() && ac_name.is_empty()) { + return xl_text; + } else if (!xl_text.is_empty() && !ac_name.is_empty() && ac_name != xl_text) { + return ac_name + ": " + xl_text; + } else if (xl_text.is_empty() && ac_name.is_empty() && !get_tooltip_text().is_empty()) { + return get_tooltip_text(); // Fall back to tooltip. + } else { + return ac_name; + } +} + void Button::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ACCESSIBILITY_UPDATE: { RID ae = get_accessibility_element(); ERR_FAIL_COND(ae.is_null()); - const String &ac_name = get_accessibility_name(); - if (!xl_text.is_empty() && ac_name.is_empty()) { - AccessibilityServer::get_singleton()->update_set_name(ae, xl_text); - } else if (!xl_text.is_empty() && !ac_name.is_empty() && ac_name != xl_text) { - AccessibilityServer::get_singleton()->update_set_name(ae, ac_name + ": " + xl_text); - } else if (xl_text.is_empty() && ac_name.is_empty() && !get_tooltip_text().is_empty()) { - AccessibilityServer::get_singleton()->update_set_name(ae, get_tooltip_text()); // Fall back to tooltip. - } AcceptDialog *dlg = Object::cast_to(get_parent()); if (dlg && dlg->get_ok_button() == this) { AccessibilityServer::get_singleton()->update_set_role(ae, AccessibilityServerEnums::AccessibilityRole::ROLE_DEFAULT_BUTTON); @@ -182,6 +187,7 @@ void Button::_notification(int p_what) { _shape(); update_minimum_size(); + update_configuration_warnings(); queue_accessibility_update(); queue_redraw(); } break; @@ -600,6 +606,7 @@ void Button::set_text(const String &p_text) { xl_text = translated_text; _shape(); + update_configuration_warnings(); queue_accessibility_update(); queue_redraw(); update_minimum_size(); diff --git a/scene/gui/button.h b/scene/gui/button.h index 1f7711ec85..37e7da8def 100644 --- a/scene/gui/button.h +++ b/scene/gui/button.h @@ -120,6 +120,8 @@ protected: void _notification(int p_what); static void _bind_methods(); + virtual String _get_accessibility_name() const override; + public: virtual Size2 get_minimum_size() const override; diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp index 2425642a98..de1dc5ce7f 100644 --- a/scene/gui/control.cpp +++ b/scene/gui/control.cpp @@ -263,21 +263,32 @@ PackedStringArray Control::get_configuration_warnings() const { return warnings; } +String Control::_get_accessibility_name() const { + if (get_parent_control()) { + String container_info = get_parent_control()->get_accessibility_container_name(this); + return container_info.is_empty() ? get_accessibility_name() : get_accessibility_name() + " " + container_info; + } else { + return get_accessibility_name(); + } +} + PackedStringArray Control::get_accessibility_configuration_warnings() const { ERR_READ_THREAD_GUARD_V(PackedStringArray()); PackedStringArray warnings = Node::get_accessibility_configuration_warnings(); - String ac_name = get_accessibility_name().strip_edges(); - if (ac_name.is_empty()) { - warnings.push_back(RTR("Accessibility Name must not be empty, or contain only spaces.")); - } - if (ac_name.contains(get_class_name())) { - warnings.push_back(RTR("Accessibility Name must not include Node class name.")); - } - for (int i = 0; i < ac_name.length(); i++) { - if (is_control(ac_name[i])) { - warnings.push_back(RTR("Accessibility Name must not include control character.")); - break; + if (get_focus_mode_with_override() != FOCUS_NONE) { + String ac_name = _get_accessibility_name().strip_edges(); + if (ac_name.is_empty()) { + warnings.push_back(RTR("Accessibility Name must not be empty, or contain only spaces.")); + } + if (ac_name.contains(get_class_name())) { + warnings.push_back(RTR("Accessibility Name must not include Node class name.")); + } + for (int i = 0; i < ac_name.length(); i++) { + if (is_control(ac_name[i])) { + warnings.push_back(RTR("Accessibility Name must not include control character.")); + break; + } } } @@ -4040,12 +4051,7 @@ void Control::_notification(int p_notification) { ERR_FAIL_COND(ae.is_null()); // Base info. - if (get_parent_control()) { - String container_info = get_parent_control()->get_accessibility_container_name(this); - AccessibilityServer::get_singleton()->update_set_name(ae, container_info.is_empty() ? get_accessibility_name() : get_accessibility_name() + " " + container_info); - } else { - AccessibilityServer::get_singleton()->update_set_name(ae, get_accessibility_name()); - } + AccessibilityServer::get_singleton()->update_set_name(ae, _get_accessibility_name()); AccessibilityServer::get_singleton()->update_set_description(ae, get_accessibility_description()); AccessibilityServer::get_singleton()->update_set_live(ae, get_accessibility_live()); diff --git a/scene/gui/control.h b/scene/gui/control.h index 6f30063664..4a85c7ed8b 100644 --- a/scene/gui/control.h +++ b/scene/gui/control.h @@ -681,6 +681,8 @@ public: void set_accessibility_name(const String &p_name); String get_accessibility_name() const; + virtual String _get_accessibility_name() const; + void set_accessibility_description(const String &p_description); String get_accessibility_description() const; diff --git a/scene/gui/graph_node.cpp b/scene/gui/graph_node.cpp index 0e07326fbc..4f52ec4f07 100644 --- a/scene/gui/graph_node.cpp +++ b/scene/gui/graph_node.cpp @@ -544,74 +544,77 @@ void GraphNode::gui_input(const Ref &p_event) { GraphElement::gui_input(p_event); } +String GraphNode::_get_accessibility_name() const { + String name = Control::_get_accessibility_name(); + if (name.is_empty()) { + name = get_name(); + } + name = vformat(ETR("graph node %s (%s)"), name, get_title()); + + if (slot_table.has(selected_slot)) { + GraphEdit *graph = Object::cast_to(get_parent()); + Dictionary type_info; + if (graph) { + type_info = graph->get_type_names(); + } + const Slot &slot = slot_table[selected_slot]; + name += ", " + vformat(ETR("slot %d of %d"), selected_slot + 1, slot_count); + if (slot.enable_left) { + if (type_info.has(slot.type_left)) { + name += "," + vformat(ETR("input port, type: %s"), type_info[slot.type_left]); + } else { + name += "," + vformat(ETR("input port, type: %d"), slot.type_left); + } + if (graph) { + for (int i = 0; i < left_port_cache.size(); i++) { + if (left_port_cache[i].slot_index == selected_slot) { + String cd = graph->get_connections_description(get_name(), i); + if (cd.is_empty()) { + name += " " + ETR("no connections"); + } else { + name += " " + cd; + } + break; + } + } + } + } + if (slot.enable_right) { + if (type_info.has(slot.type_right)) { + name += "," + vformat(ETR("output port, type: %s"), type_info[slot.type_right]); + } else { + name += "," + vformat(ETR("output port, type: %d"), slot.type_right); + } + if (graph) { + for (int i = 0; i < right_port_cache.size(); i++) { + if (right_port_cache[i].slot_index == selected_slot) { + String cd = graph->get_connections_description(get_name(), i); + if (cd.is_empty()) { + name += " " + ETR("no connections"); + } else { + name += " " + cd; + } + break; + } + } + } + } + if (graph && graph->is_keyboard_connecting()) { + name += ", " + ETR("currently selecting target port"); + } + } else { + name += ", " + vformat(ETR("has %d slots"), slot_count); + } + return name; +} + void GraphNode::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ACCESSIBILITY_UPDATE: { RID ae = get_accessibility_element(); ERR_FAIL_COND(ae.is_null()); - String name = get_accessibility_name(); - if (name.is_empty()) { - name = get_name(); - } - name = vformat(ETR("graph node %s (%s)"), name, get_title()); - - if (slot_table.has(selected_slot)) { - GraphEdit *graph = Object::cast_to(get_parent()); - Dictionary type_info; - if (graph) { - type_info = graph->get_type_names(); - } - const Slot &slot = slot_table[selected_slot]; - name += ", " + vformat(ETR("slot %d of %d"), selected_slot + 1, slot_count); - if (slot.enable_left) { - if (type_info.has(slot.type_left)) { - name += "," + vformat(ETR("input port, type: %s"), type_info[slot.type_left]); - } else { - name += "," + vformat(ETR("input port, type: %d"), slot.type_left); - } - if (graph) { - for (int i = 0; i < left_port_cache.size(); i++) { - if (left_port_cache[i].slot_index == selected_slot) { - String cd = graph->get_connections_description(get_name(), i); - if (cd.is_empty()) { - name += " " + ETR("no connections"); - } else { - name += " " + cd; - } - break; - } - } - } - } - if (slot.enable_right) { - if (type_info.has(slot.type_right)) { - name += "," + vformat(ETR("output port, type: %s"), type_info[slot.type_right]); - } else { - name += "," + vformat(ETR("output port, type: %d"), slot.type_right); - } - if (graph) { - for (int i = 0; i < right_port_cache.size(); i++) { - if (right_port_cache[i].slot_index == selected_slot) { - String cd = graph->get_connections_description(get_name(), i); - if (cd.is_empty()) { - name += " " + ETR("no connections"); - } else { - name += " " + cd; - } - break; - } - } - } - } - if (graph && graph->is_keyboard_connecting()) { - name += ", " + ETR("currently selecting target port"); - } - } else { - name += ", " + vformat(ETR("has %d slots"), slot_count); - } AccessibilityServer::get_singleton()->update_set_role(ae, AccessibilityServerEnums::AccessibilityRole::ROLE_LIST); - AccessibilityServer::get_singleton()->update_set_name(ae, name); AccessibilityServer::get_singleton()->update_add_custom_action(ae, CustomAccessibilityAction::ACTION_CONNECT_INPUT, ETR("Edit Input Port Connection")); AccessibilityServer::get_singleton()->update_add_custom_action(ae, CustomAccessibilityAction::ACTION_CONNECT_OUTPUT, ETR("Edit Output Port Connection")); AccessibilityServer::get_singleton()->update_add_custom_action(ae, CustomAccessibilityAction::ACTION_FOLLOW_INPUT, ETR("Follow Input Port Connection")); diff --git a/scene/gui/graph_node.h b/scene/gui/graph_node.h index bdbc11926c..43fec13494 100644 --- a/scene/gui/graph_node.h +++ b/scene/gui/graph_node.h @@ -127,6 +127,8 @@ protected: bool _get(const StringName &p_name, Variant &r_ret) const; void _get_property_list(List *p_list) const; + virtual String _get_accessibility_name() const override; + public: virtual String get_accessibility_container_name(const Node *p_node) const override; virtual void gui_input(const Ref &p_event) override; diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp index 6f16c0d761..45a35f151e 100644 --- a/scene/gui/line_edit.cpp +++ b/scene/gui/line_edit.cpp @@ -1214,6 +1214,15 @@ void LineEdit::_accessibility_action_menu(const Variant &p_data) { menu->grab_focus(); } +String LineEdit::_get_accessibility_name() const { + const String &ac_name = Control::_get_accessibility_name(); + if (!placeholder.is_empty() && ac_name.is_empty()) { + return atr(placeholder); + } else { + return ac_name; + } +} + void LineEdit::_notification(int p_what) { switch (p_what) { #ifdef TOOLS_ENABLED @@ -1242,9 +1251,6 @@ void LineEdit::_notification(int p_what) { if (using_placeholder && !placeholder.is_empty()) { AccessibilityServer::get_singleton()->update_set_placeholder(ae, atr(placeholder)); } - if (!placeholder.is_empty() && get_accessibility_name().is_empty()) { - AccessibilityServer::get_singleton()->update_set_name(ae, atr(placeholder)); - } AccessibilityServer::get_singleton()->update_set_flag(ae, AccessibilityServerEnums::AccessibilityFlags::FLAG_READONLY, !editable); AccessibilityServer::get_singleton()->update_add_action(ae, AccessibilityServerEnums::AccessibilityAction::ACTION_SET_TEXT_SELECTION, callable_mp(this, &LineEdit::_accessibility_action_set_selection)); @@ -2269,6 +2275,7 @@ void LineEdit::set_placeholder(String p_text) { placeholder_translated = atr(placeholder); _shape(); queue_redraw(); + update_configuration_warnings(); } String LineEdit::get_placeholder() const { diff --git a/scene/gui/line_edit.h b/scene/gui/line_edit.h index a4749b4c11..f1e8477eed 100644 --- a/scene/gui/line_edit.h +++ b/scene/gui/line_edit.h @@ -297,6 +297,8 @@ protected: void _accessibility_action_set_value(const Variant &p_data); void _accessibility_action_menu(const Variant &p_data); + virtual String _get_accessibility_name() const override; + public: void edit(bool p_hide_focus = false); void unedit(); diff --git a/scene/gui/link_button.cpp b/scene/gui/link_button.cpp index 77ccded0e5..ebc8882bc1 100644 --- a/scene/gui/link_button.cpp +++ b/scene/gui/link_button.cpp @@ -62,6 +62,7 @@ void LinkButton::set_text(const String &p_text) { text = p_text; xl_text = atr(text); _shape(); + update_configuration_warnings(); update_minimum_size(); queue_redraw(); } @@ -206,6 +207,19 @@ Control::CursorShape LinkButton::get_cursor_shape(const Point2 &p_pos) const { return is_disabled() ? CURSOR_ARROW : get_default_cursor_shape(); } +String LinkButton::_get_accessibility_name() const { + const String &ac_name = Control::_get_accessibility_name(); + if (!xl_text.is_empty() && ac_name.is_empty()) { + return xl_text; + } else if (!xl_text.is_empty() && !ac_name.is_empty() && ac_name != xl_text) { + return ac_name + ": " + xl_text; + } else if (xl_text.is_empty() && ac_name.is_empty() && !get_tooltip_text().is_empty()) { + return get_tooltip_text(); // Fall back to tooltip. + } else { + return ac_name; + } +} + void LinkButton::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ACCESSIBILITY_UPDATE: { @@ -213,20 +227,14 @@ void LinkButton::_notification(int p_what) { ERR_FAIL_COND(ae.is_null()); AccessibilityServer::get_singleton()->update_set_role(ae, AccessibilityServerEnums::AccessibilityRole::ROLE_LINK); - const String &ac_name = get_accessibility_name(); - if (!xl_text.is_empty() && ac_name.is_empty()) { - AccessibilityServer::get_singleton()->update_set_name(ae, xl_text); - } else if (!xl_text.is_empty() && !ac_name.is_empty() && ac_name != xl_text) { - AccessibilityServer::get_singleton()->update_set_name(ae, ac_name + ": " + xl_text); - } else if (xl_text.is_empty() && ac_name.is_empty() && !get_tooltip_text().is_empty()) { - AccessibilityServer::get_singleton()->update_set_name(ae, get_tooltip_text()); // Fall back to tooltip. - } + AccessibilityServer::get_singleton()->update_set_url(ae, uri); } break; case NOTIFICATION_TRANSLATION_CHANGED: { xl_text = atr(text); _shape(); + update_configuration_warnings(); update_minimum_size(); queue_redraw(); } break; diff --git a/scene/gui/link_button.h b/scene/gui/link_button.h index 3591a6af1d..7c0a16a800 100644 --- a/scene/gui/link_button.h +++ b/scene/gui/link_button.h @@ -84,6 +84,8 @@ protected: void _notification(int p_what); static void _bind_methods(); + virtual String _get_accessibility_name() const override; + public: void set_text(const String &p_text); String get_text() const; diff --git a/scene/gui/menu_bar.cpp b/scene/gui/menu_bar.cpp index f524e1a007..d882d30d0f 100644 --- a/scene/gui/menu_bar.cpp +++ b/scene/gui/menu_bar.cpp @@ -708,6 +708,7 @@ void MenuBar::remove_child_notify(Node *p_child) { menu_cache.remove_at(idx); p_child->remove_meta("_menu_name"); + p_child->update_configuration_warnings(); p_child->remove_meta("_menu_tooltip"); p_child->disconnect("renamed", callable_mp(this, &MenuBar::_refresh_menu_names)); @@ -900,6 +901,7 @@ void MenuBar::set_menu_title(int p_menu, const String &p_title) { } else { pm->set_meta("_menu_name", p_title); } + pm->update_configuration_warnings(); menu_cache.write[p_menu].name = p_title; shape(menu_cache.write[p_menu]); if (!global_menu_tag.is_empty() && menu_cache[p_menu].submenu_rid.is_valid()) { diff --git a/scene/gui/popup_menu.cpp b/scene/gui/popup_menu.cpp index 67c1acd441..55899b017b 100644 --- a/scene/gui/popup_menu.cpp +++ b/scene/gui/popup_menu.cpp @@ -1295,6 +1295,14 @@ RID PopupMenu::get_focused_accessibility_element() const { } } +String PopupMenu::_get_accessibility_name() const { + if (has_meta("_menu_name")) { + return get_meta("_menu_name", get_name()); + } else { + return Window::_get_accessibility_name(); + } +} + void PopupMenu::_notification(int p_what) { switch (p_what) { case NOTIFICATION_EXIT_TREE: { @@ -1315,9 +1323,6 @@ void PopupMenu::_notification(int p_what) { RID ae = get_accessibility_element(); ERR_FAIL_COND(ae.is_null()); - if (has_meta("_menu_name")) { - AccessibilityServer::get_singleton()->update_set_name(ae, get_meta("_menu_name", get_name())); - } AccessibilityServer::get_singleton()->update_set_role(ae, AccessibilityServerEnums::AccessibilityRole::ROLE_MENU); AccessibilityServer::get_singleton()->update_set_list_item_count(ae, items.size()); diff --git a/scene/gui/popup_menu.h b/scene/gui/popup_menu.h index bd6a02c1b9..8a600d7457 100644 --- a/scene/gui/popup_menu.h +++ b/scene/gui/popup_menu.h @@ -272,6 +272,8 @@ protected: bool _property_get_revert(const StringName &p_name, Variant &r_property) const { return property_helper.property_get_revert(p_name, r_property); } static void _bind_methods(); + virtual String _get_accessibility_name() const override; + #ifndef DISABLE_DEPRECATED void _add_shortcut_bind_compat_36493(const Ref &p_shortcut, int p_id = -1, bool p_global = false); void _add_icon_shortcut_bind_compat_36493(const Ref &p_icon, const Ref &p_shortcut, int p_id = -1, bool p_global = false); diff --git a/scene/gui/spin_box.cpp b/scene/gui/spin_box.cpp index 56d0a95844..8d54fadbb6 100644 --- a/scene/gui/spin_box.cpp +++ b/scene/gui/spin_box.cpp @@ -54,6 +54,15 @@ void SpinBoxLineEdit::_accessibility_action_dec(const Variant &p_data) { } } +String SpinBoxLineEdit::_get_accessibility_name() const { + SpinBox *parent_sb = Object::cast_to(get_parent()); + if (parent_sb) { + return parent_sb->_get_accessibility_name(); + } else { + return Control::_get_accessibility_name(); + } +} + void SpinBoxLineEdit::_notification(int p_what) { ERR_MAIN_THREAD_GUARD; switch (p_what) { @@ -64,7 +73,6 @@ void SpinBoxLineEdit::_notification(int p_what) { SpinBox *parent_sb = Object::cast_to(get_parent()); if (parent_sb) { AccessibilityServer::get_singleton()->update_set_role(ae, AccessibilityServerEnums::AccessibilityRole::ROLE_SPIN_BUTTON); - AccessibilityServer::get_singleton()->update_set_name(ae, parent_sb->get_accessibility_name()); AccessibilityServer::get_singleton()->update_set_description(ae, parent_sb->get_accessibility_description()); AccessibilityServer::get_singleton()->update_set_live(ae, parent_sb->get_accessibility_live()); AccessibilityServer::get_singleton()->update_set_num_value(ae, parent_sb->get_value()); diff --git a/scene/gui/spin_box.h b/scene/gui/spin_box.h index 032349db5b..8a4f7a5cc5 100644 --- a/scene/gui/spin_box.h +++ b/scene/gui/spin_box.h @@ -42,6 +42,8 @@ protected: void _accessibility_action_inc(const Variant &p_data); void _accessibility_action_dec(const Variant &p_data); + + virtual String _get_accessibility_name() const override; }; class SpinBox : public Range { diff --git a/scene/gui/split_container.cpp b/scene/gui/split_container.cpp index 6feee52efc..995f0bd452 100644 --- a/scene/gui/split_container.cpp +++ b/scene/gui/split_container.cpp @@ -322,6 +322,10 @@ void SplitContainerDragger::stop_dragging() { } } +String SplitContainerDragger::_get_accessibility_name() const { + return RTR("Drag to resize"); +} + void SplitContainerDragger::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ACCESSIBILITY_UPDATE: { @@ -332,7 +336,6 @@ void SplitContainerDragger::_notification(int p_what) { ERR_FAIL_COND(ae.is_null()); AccessibilityServer::get_singleton()->update_set_role(ae, AccessibilityServerEnums::AccessibilityRole::ROLE_SPLITTER); - AccessibilityServer::get_singleton()->update_set_name(ae, RTR("Drag to resize")); SplitContainer *sc = Object::cast_to(get_parent()); if (sc->collapsed || sc->valid_children.size() < 2u || !sc->dragging_enabled) { diff --git a/scene/gui/split_container.h b/scene/gui/split_container.h index 7f774dda7b..7acc752ed0 100644 --- a/scene/gui/split_container.h +++ b/scene/gui/split_container.h @@ -81,6 +81,8 @@ protected: void _accessibility_action_dec(const Variant &p_data); void _accessibility_action_set_value(const Variant &p_data); + virtual String _get_accessibility_name() const override; + public: int dragger_index = -1; diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index 76b4c232b3..1a062661c8 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -742,6 +742,14 @@ Ref TextEdit::_get_current_stylebox() const { return editable ? theme_cache.style_normal : theme_cache.style_readonly; } +String TextEdit::_get_accessibility_name() const { + if (!placeholder_text.is_empty() && get_accessibility_name().is_empty()) { + return atr(placeholder_text); + } else { + return Control::_get_accessibility_name(); + } +} + void TextEdit::_notification(int p_what) { switch (p_what) { case NOTIFICATION_EXIT_TREE: @@ -757,9 +765,7 @@ void TextEdit::_notification(int p_what) { if (text.size() == 1 && text[0].is_empty()) { AccessibilityServer::get_singleton()->update_set_placeholder(ae, atr(placeholder_text)); } - if (!placeholder_text.is_empty() && get_accessibility_name().is_empty()) { - AccessibilityServer::get_singleton()->update_set_name(ae, atr(placeholder_text)); - } + AccessibilityServer::get_singleton()->update_set_flag(ae, AccessibilityServerEnums::AccessibilityFlags::FLAG_READONLY, !editable); AccessibilityServer::get_singleton()->update_add_action(ae, AccessibilityServerEnums::AccessibilityAction::ACTION_SET_TEXT_SELECTION, callable_mp(this, &TextEdit::_accessibility_action_set_selection)); AccessibilityServer::get_singleton()->update_add_action(ae, AccessibilityServerEnums::AccessibilityAction::ACTION_REPLACE_SELECTED_TEXT, callable_mp(this, &TextEdit::_accessibility_action_replace_selected)); @@ -4046,6 +4052,7 @@ void TextEdit::set_placeholder(const String &p_text) { placeholder_text = p_text; _update_placeholder(); + update_configuration_warnings(); queue_accessibility_update(); queue_redraw(); } diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h index 4a990a0eb4..182f7d77fb 100644 --- a/scene/gui/text_edit.h +++ b/scene/gui/text_edit.h @@ -708,6 +708,8 @@ protected: virtual void _draw_guidelines() {} virtual void _update_theme_item_cache() override; + virtual String _get_accessibility_name() const override; + /* Internal API for CodeEdit, pending public API. */ // Brace matching. struct BraceMatchingData { diff --git a/scene/main/window.cpp b/scene/main/window.cpp index e08204d9ac..de703e7fbc 100644 --- a/scene/main/window.cpp +++ b/scene/main/window.cpp @@ -1514,6 +1514,35 @@ RID Window::get_focused_accessibility_element() const { return Node::get_focused_accessibility_element(); } +String Window::_get_accessibility_name() const { + if (accessibility_name.is_empty()) { + return displayed_title; + } else { + return accessibility_name; + } +} + +PackedStringArray Window::get_accessibility_configuration_warnings() const { + ERR_READ_THREAD_GUARD_V(PackedStringArray()); + PackedStringArray warnings = Node::get_accessibility_configuration_warnings(); + + String ac_name = _get_accessibility_name().strip_edges(); + if (ac_name.is_empty()) { + warnings.push_back(RTR("Accessibility Name must not be empty, or contain only spaces.")); + } + if (ac_name.contains(get_class_name())) { + warnings.push_back(RTR("Accessibility Name must not include Node class name.")); + } + for (int i = 0; i < ac_name.length(); i++) { + if (is_control(ac_name[i])) { + warnings.push_back(RTR("Accessibility Name must not include control character.")); + break; + } + } + + return warnings; +} + void Window::_notification(int p_what) { ERR_MAIN_THREAD_GUARD; switch (p_what) { @@ -1533,11 +1562,7 @@ void Window::_notification(int p_what) { ERR_FAIL_COND(ae.is_null()); AccessibilityServer::get_singleton()->update_set_role(ae, AccessibilityServerEnums::AccessibilityRole::ROLE_WINDOW); - if (accessibility_name.is_empty()) { - AccessibilityServer::get_singleton()->update_set_name(ae, displayed_title); - } else { - AccessibilityServer::get_singleton()->update_set_name(ae, accessibility_name); - } + AccessibilityServer::get_singleton()->update_set_name(ae, _get_accessibility_name()); AccessibilityServer::get_singleton()->update_set_description(ae, accessibility_description); AccessibilityServer::get_singleton()->update_set_flag(ae, AccessibilityServerEnums::AccessibilityFlags::FLAG_MODAL, exclusive); AccessibilityServer::get_singleton()->update_add_action(ae, AccessibilityServerEnums::AccessibilityAction::ACTION_FOCUS, callable_mp(this, &Window::_accessibility_action_grab_focus)); @@ -3319,6 +3344,7 @@ void Window::_update_displayed_title() { } #endif + update_configuration_warnings(); queue_accessibility_update(); } diff --git a/scene/main/window.h b/scene/main/window.h index c00a038d12..34a4ebe77e 100644 --- a/scene/main/window.h +++ b/scene/main/window.h @@ -288,6 +288,8 @@ protected: virtual void add_child_notify(Node *p_child) override; virtual void remove_child_notify(Node *p_child) override; + virtual String _get_accessibility_name() const; + GDVIRTUAL0RC(Vector2, _get_contents_minimum_size) public: @@ -297,6 +299,8 @@ public: NOTIFICATION_THEME_CHANGED = 32 }; + PackedStringArray get_accessibility_configuration_warnings() const override; + static void set_root_layout_direction(int p_root_dir); static Window *get_from_id(DisplayServerEnums::WindowID p_window_id);