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 {