diff --git a/doc/classes/Container.xml b/doc/classes/Container.xml index 6ac02e2d081..f9d1433a60d 100644 --- a/doc/classes/Container.xml +++ b/doc/classes/Container.xml @@ -40,6 +40,9 @@ + + If [code]true[/code], this container is marked as a region for accessibility. Use [member Control.accessibility_name] to give the region a descriptive name. Screen readers can navigate between regions using landmark navigation. + diff --git a/doc/classes/DisplayServer.xml b/doc/classes/DisplayServer.xml index 853a8befeac..11023e8716d 100644 --- a/doc/classes/DisplayServer.xml +++ b/doc/classes/DisplayServer.xml @@ -2785,6 +2785,9 @@ Tooltip element. + + Region/landmark element. Screen readers can navigate between regions using landmark navigation. + Popup menu. diff --git a/drivers/accesskit/accessibility_driver_accesskit.cpp b/drivers/accesskit/accessibility_driver_accesskit.cpp index 093425e761d..c0794462c8f 100644 --- a/drivers/accesskit/accessibility_driver_accesskit.cpp +++ b/drivers/accesskit/accessibility_driver_accesskit.cpp @@ -1657,6 +1657,7 @@ AccessibilityDriverAccessKit::AccessibilityDriverAccessKit() { role_map[DisplayServer::AccessibilityRole::ROLE_TITLE_BAR] = ACCESSKIT_ROLE_TITLE_BAR; role_map[DisplayServer::AccessibilityRole::ROLE_DIALOG] = ACCESSKIT_ROLE_DIALOG; role_map[DisplayServer::AccessibilityRole::ROLE_TOOLTIP] = ACCESSKIT_ROLE_TOOLTIP; + role_map[DisplayServer::AccessibilityRole::ROLE_REGION] = ACCESSKIT_ROLE_REGION; action_map[DisplayServer::AccessibilityAction::ACTION_CLICK] = ACCESSKIT_ACTION_CLICK; action_map[DisplayServer::AccessibilityAction::ACTION_FOCUS] = ACCESSKIT_ACTION_FOCUS; diff --git a/editor/docks/editor_dock.cpp b/editor/docks/editor_dock.cpp index f46b68ed90a..9421de96c6a 100644 --- a/editor/docks/editor_dock.cpp +++ b/editor/docks/editor_dock.cpp @@ -43,6 +43,15 @@ void EditorDock::_emit_changed() { emit_signal(SNAME("_tab_style_changed")); } +void EditorDock::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_READY: { + set_accessibility_region(true); + set_accessibility_name(get_display_title()); + } break; + } +} + void EditorDock::_bind_methods() { ClassDB::bind_method(D_METHOD("open"), &EditorDock::open); ClassDB::bind_method(D_METHOD("make_visible"), &EditorDock::make_visible); @@ -142,6 +151,7 @@ void EditorDock::set_title(const String &p_title) { return; } title = p_title; + set_accessibility_name(get_display_title()); _emit_changed(); } diff --git a/editor/docks/editor_dock.h b/editor/docks/editor_dock.h index 2571af3946b..d771d907260 100644 --- a/editor/docks/editor_dock.h +++ b/editor/docks/editor_dock.h @@ -94,6 +94,7 @@ private: void _emit_changed(); protected: + void _notification(int p_what); static void _bind_methods(); GDVIRTUAL1(_update_layout, int) diff --git a/editor/editor_main_screen.cpp b/editor/editor_main_screen.cpp index d51e8f20a65..7f582a7d95a 100644 --- a/editor/editor_main_screen.cpp +++ b/editor/editor_main_screen.cpp @@ -41,6 +41,7 @@ void EditorMainScreen::_notification(int p_what) { switch (p_what) { case NOTIFICATION_READY: { + set_accessibility_region(true); if (EDITOR_3D < buttons.size() && buttons[EDITOR_3D]->is_visible()) { // If the 3D editor is enabled, use this as the default. select(EDITOR_3D); @@ -194,6 +195,7 @@ void EditorMainScreen::select(int p_index) { selected_plugin = new_editor; selected_plugin->make_visible(true); selected_plugin->selected_notify(); + set_accessibility_name(selected_plugin->get_plugin_name()); EditorData &editor_data = EditorNode::get_editor_data(); int plugin_count = editor_data.get_editor_plugin_count(); diff --git a/editor/gui/editor_bottom_panel.cpp b/editor/gui/editor_bottom_panel.cpp index 3961f646cb5..22e85ad31fd 100644 --- a/editor/gui/editor_bottom_panel.cpp +++ b/editor/gui/editor_bottom_panel.cpp @@ -47,6 +47,7 @@ void EditorBottomPanel::_notification(int p_what) { switch (p_what) { case NOTIFICATION_READY: { + set_accessibility_region(true); layout_popup = get_popup(); } break; @@ -60,6 +61,9 @@ void EditorBottomPanel::_notification(int p_what) { void EditorBottomPanel::_on_tab_changed(int p_idx) { _update_center_split_offset(); _repaint(); + if (p_idx >= 0 && p_idx < get_tab_count()) { + set_accessibility_name(get_tab_title(p_idx)); + } } void EditorBottomPanel::_theme_changed() { diff --git a/scene/gui/container.cpp b/scene/gui/container.cpp index 81c7bb4dd79..b96a0ca346a 100644 --- a/scene/gui/container.cpp +++ b/scene/gui/container.cpp @@ -188,7 +188,11 @@ void Container::_notification(int p_what) { RID ae = get_accessibility_element(); ERR_FAIL_COND(ae.is_null()); - DisplayServer::get_singleton()->accessibility_update_set_role(ae, DisplayServer::AccessibilityRole::ROLE_CONTAINER); + if (accessibility_region) { + DisplayServer::get_singleton()->accessibility_update_set_role(ae, DisplayServer::AccessibilityRole::ROLE_REGION); + } else { + DisplayServer::get_singleton()->accessibility_update_set_role(ae, DisplayServer::AccessibilityRole::ROLE_CONTAINER); + } } break; case NOTIFICATION_RESIZED: @@ -204,6 +208,18 @@ void Container::_notification(int p_what) { } } +void Container::set_accessibility_region(bool p_region) { + ERR_MAIN_THREAD_GUARD; + if (accessibility_region != p_region) { + accessibility_region = p_region; + queue_accessibility_update(); + } +} + +bool Container::is_accessibility_region() const { + return accessibility_region; +} + PackedStringArray Container::get_configuration_warnings() const { PackedStringArray warnings = Control::get_configuration_warnings(); @@ -217,6 +233,8 @@ PackedStringArray Container::get_configuration_warnings() const { void Container::_bind_methods() { ClassDB::bind_method(D_METHOD("queue_sort"), &Container::queue_sort); ClassDB::bind_method(D_METHOD("fit_child_in_rect", "child", "rect"), &Container::fit_child_in_rect); + ClassDB::bind_method(D_METHOD("set_accessibility_region", "region"), &Container::set_accessibility_region); + ClassDB::bind_method(D_METHOD("is_accessibility_region"), &Container::is_accessibility_region); GDVIRTUAL_BIND(_get_allowed_size_flags_horizontal); GDVIRTUAL_BIND(_get_allowed_size_flags_vertical); @@ -226,6 +244,8 @@ void Container::_bind_methods() { ADD_SIGNAL(MethodInfo("pre_sort_children")); ADD_SIGNAL(MethodInfo("sort_children")); + + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "accessibility_region"), "set_accessibility_region", "is_accessibility_region"); } Container::Container() { diff --git a/scene/gui/container.h b/scene/gui/container.h index 50be92d9b9a..af9fbc7fe91 100644 --- a/scene/gui/container.h +++ b/scene/gui/container.h @@ -36,6 +36,7 @@ class Container : public Control { GDCLASS(Container, Control); bool pending_sort = false; + bool accessibility_region = false; void _sort_children(); void _child_minsize_changed(); @@ -72,5 +73,8 @@ public: PackedStringArray get_configuration_warnings() const override; + void set_accessibility_region(bool p_region); + bool is_accessibility_region() const; + Container(); }; diff --git a/scene/gui/scroll_container.cpp b/scene/gui/scroll_container.cpp index 7794443daf6..29dc4b0c762 100644 --- a/scene/gui/scroll_container.cpp +++ b/scene/gui/scroll_container.cpp @@ -434,7 +434,11 @@ void ScrollContainer::_notification(int p_what) { RID ae = get_accessibility_element(); ERR_FAIL_COND(ae.is_null()); - DisplayServer::get_singleton()->accessibility_update_set_role(ae, DisplayServer::AccessibilityRole::ROLE_SCROLL_VIEW); + if (is_accessibility_region()) { + DisplayServer::get_singleton()->accessibility_update_set_role(ae, DisplayServer::AccessibilityRole::ROLE_REGION); + } else { + DisplayServer::get_singleton()->accessibility_update_set_role(ae, DisplayServer::AccessibilityRole::ROLE_SCROLL_VIEW); + } DisplayServer::get_singleton()->accessibility_update_add_action(ae, DisplayServer::AccessibilityAction::ACTION_SCROLL_DOWN, callable_mp(this, &ScrollContainer::_accessibility_action_scroll_down)); DisplayServer::get_singleton()->accessibility_update_add_action(ae, DisplayServer::AccessibilityAction::ACTION_SCROLL_LEFT, callable_mp(this, &ScrollContainer::_accessibility_action_scroll_left)); diff --git a/scene/gui/tab_container.cpp b/scene/gui/tab_container.cpp index e41f0885694..7e4058f066b 100644 --- a/scene/gui/tab_container.cpp +++ b/scene/gui/tab_container.cpp @@ -565,6 +565,7 @@ void TabContainer::_on_tab_hovered(int p_tab) { void TabContainer::_on_tab_changed(int p_tab) { callable_mp(this, &TabContainer::_repaint).call_deferred(); queue_redraw(); + queue_accessibility_update(); emit_signal(SNAME("tab_changed"), p_tab); } diff --git a/servers/display/display_server.cpp b/servers/display/display_server.cpp index 4e929e31d7b..f53aa1ec2f0 100644 --- a/servers/display/display_server.cpp +++ b/servers/display/display_server.cpp @@ -1708,6 +1708,7 @@ void DisplayServer::_bind_methods() { BIND_ENUM_CONSTANT(ROLE_TITLE_BAR); BIND_ENUM_CONSTANT(ROLE_DIALOG); BIND_ENUM_CONSTANT(ROLE_TOOLTIP); + BIND_ENUM_CONSTANT(ROLE_REGION); BIND_ENUM_CONSTANT(POPUP_MENU); BIND_ENUM_CONSTANT(POPUP_LIST); diff --git a/servers/display/display_server.h b/servers/display/display_server.h index 49328806727..0639e8d8538 100644 --- a/servers/display/display_server.h +++ b/servers/display/display_server.h @@ -606,6 +606,7 @@ public: ROLE_TITLE_BAR, ROLE_DIALOG, ROLE_TOOLTIP, + ROLE_REGION, }; enum AccessibilityPopupType {