Base accessibility API.

This commit is contained in:
Pāvels Nadtočajevs 2025-03-21 16:42:23 +02:00
parent af2c713971
commit b106dfd4f9
No known key found for this signature in database
GPG key ID: 8413210218EF35D2
124 changed files with 7631 additions and 181 deletions

View file

@ -351,6 +351,35 @@ void TabBar::_shape(int p_tab) {
tabs.write[p_tab].text_buf->add_string(atr(tabs[p_tab].text), theme_cache.font, theme_cache.font_size, tabs[p_tab].language);
}
RID TabBar::get_tab_accessibility_element(int p_tab) const {
RID ae = get_accessibility_element();
ERR_FAIL_COND_V(ae.is_null(), RID());
const Tab &item = tabs[p_tab];
if (item.accessibility_item_element.is_null()) {
item.accessibility_item_element = DisplayServer::get_singleton()->accessibility_create_sub_element(ae, DisplayServer::AccessibilityRole::ROLE_TAB);
item.accessibility_item_dirty = true;
}
return item.accessibility_item_element;
}
RID TabBar::get_focused_accessibility_element() const {
if (current == -1) {
return get_accessibility_element();
} else {
const Tab &item = tabs[current];
return item.accessibility_item_element;
}
}
void TabBar::_accessibility_action_scroll_into_view(const Variant &p_data, int p_index) {
ensure_tab_visible(p_index);
}
void TabBar::_accessibility_action_focus(const Variant &p_data, int p_index) {
set_current_tab(p_index);
}
void TabBar::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
@ -383,6 +412,46 @@ void TabBar::_notification(int p_what) {
}
} break;
case NOTIFICATION_EXIT_TREE:
case NOTIFICATION_ACCESSIBILITY_INVALIDATE: {
for (int i = 0; i < tabs.size(); i++) {
tabs.write[i].accessibility_item_element = RID();
}
} break;
case NOTIFICATION_ACCESSIBILITY_UPDATE: {
RID ae = get_accessibility_element();
ERR_FAIL_COND(ae.is_null());
DisplayServer::get_singleton()->accessibility_update_set_role(ae, DisplayServer::AccessibilityRole::ROLE_TAB_BAR);
DisplayServer::get_singleton()->accessibility_update_set_list_item_count(ae, tabs.size());
for (int i = 0; i < tabs.size(); i++) {
const Tab &item = tabs[i];
if (item.accessibility_item_element.is_null()) {
item.accessibility_item_element = DisplayServer::get_singleton()->accessibility_create_sub_element(ae, DisplayServer::AccessibilityRole::ROLE_TAB);
item.accessibility_item_dirty = true;
}
if (item.accessibility_item_dirty) {
DisplayServer::get_singleton()->accessibility_update_add_action(item.accessibility_item_element, DisplayServer::AccessibilityAction::ACTION_SCROLL_INTO_VIEW, callable_mp(this, &TabBar::_accessibility_action_scroll_into_view).bind(i));
DisplayServer::get_singleton()->accessibility_update_add_action(item.accessibility_item_element, DisplayServer::AccessibilityAction::ACTION_FOCUS, callable_mp(this, &TabBar::_accessibility_action_focus).bind(i));
DisplayServer::get_singleton()->accessibility_update_set_list_item_index(item.accessibility_item_element, i);
DisplayServer::get_singleton()->accessibility_update_set_name(item.accessibility_item_element, atr(item.text));
DisplayServer::get_singleton()->accessibility_update_set_list_item_selected(item.accessibility_item_element, i == current);
DisplayServer::get_singleton()->accessibility_update_set_flag(item.accessibility_item_element, DisplayServer::AccessibilityFlags::FLAG_DISABLED, item.disabled);
DisplayServer::get_singleton()->accessibility_update_set_flag(item.accessibility_item_element, DisplayServer::AccessibilityFlags::FLAG_HIDDEN, item.hidden);
DisplayServer::get_singleton()->accessibility_update_set_tooltip(item.accessibility_item_element, item.tooltip);
DisplayServer::get_singleton()->accessibility_update_set_bounds(item.accessibility_item_element, Rect2(Point2(item.ofs_cache, 0), Size2(item.size_cache, get_size().height)));
item.accessibility_item_dirty = false;
}
}
} break;
case NOTIFICATION_LAYOUT_DIRECTION_CHANGED: {
queue_redraw();
} break;
@ -393,6 +462,7 @@ void TabBar::_notification(int p_what) {
_shape(i);
}
queue_accessibility_update();
queue_redraw();
update_minimum_size();
@ -672,6 +742,15 @@ void TabBar::set_tab_count(int p_count) {
}
ERR_FAIL_COND(p_count < 0);
if (tabs.size() > p_count) {
for (int i = p_count; i < tabs.size(); i++) {
if (tabs[i].accessibility_item_element.is_valid()) {
DisplayServer::get_singleton()->accessibility_free_element(tabs.write[i].accessibility_item_element);
tabs.write[i].accessibility_item_element = RID();
}
}
}
tabs.resize(p_count);
if (p_count == 0) {
@ -702,6 +781,7 @@ void TabBar::set_tab_count(int p_count) {
}
}
queue_accessibility_update();
queue_redraw();
update_minimum_size();
notify_property_list_changed();
@ -737,6 +817,7 @@ void TabBar::set_current_tab(int p_current) {
if (scroll_to_selected) {
ensure_tab_visible(current);
}
queue_accessibility_update();
queue_redraw();
emit_signal(SNAME("tab_changed"), p_current);
@ -785,6 +866,7 @@ void TabBar::set_tab_offset(int p_offset) {
ERR_FAIL_INDEX(p_offset, tabs.size());
offset = p_offset;
_update_cache();
queue_accessibility_update();
queue_redraw();
}
@ -811,6 +893,7 @@ void TabBar::set_tab_title(int p_tab, const String &p_title) {
if (scroll_to_selected) {
ensure_tab_visible(current);
}
queue_accessibility_update();
queue_redraw();
update_minimum_size();
}
@ -823,6 +906,7 @@ String TabBar::get_tab_title(int p_tab) const {
void TabBar::set_tab_tooltip(int p_tab, const String &p_tooltip) {
ERR_FAIL_INDEX(p_tab, tabs.size());
tabs.write[p_tab].tooltip = p_tooltip;
queue_accessibility_update();
}
String TabBar::get_tab_tooltip(int p_tab) const {
@ -836,7 +920,9 @@ void TabBar::set_tab_text_direction(int p_tab, Control::TextDirection p_text_dir
if (tabs[p_tab].text_direction != p_text_direction) {
tabs.write[p_tab].text_direction = p_text_direction;
_shape(p_tab);
queue_accessibility_update();
queue_redraw();
}
}
@ -851,12 +937,14 @@ void TabBar::set_tab_language(int p_tab, const String &p_language) {
if (tabs[p_tab].language != p_language) {
tabs.write[p_tab].language = p_language;
_shape(p_tab);
_update_cache();
_ensure_no_over_offset();
if (scroll_to_selected) {
ensure_tab_visible(current);
}
queue_accessibility_update();
queue_redraw();
update_minimum_size();
}
@ -927,6 +1015,7 @@ void TabBar::set_tab_disabled(int p_tab, bool p_disabled) {
if (scroll_to_selected) {
ensure_tab_visible(current);
}
queue_accessibility_update();
queue_redraw();
update_minimum_size();
}
@ -950,6 +1039,7 @@ void TabBar::set_tab_hidden(int p_tab, bool p_hidden) {
if (scroll_to_selected) {
ensure_tab_visible(current);
}
queue_accessibility_update();
queue_redraw();
update_minimum_size();
}
@ -1117,6 +1207,8 @@ void TabBar::_update_cache(bool p_update_hover) {
max_drawn_tab--;
}
}
tabs.write[i].accessibility_item_dirty = true;
}
missing_right = max_drawn_tab < tabs.size() - 1;
@ -1171,6 +1263,7 @@ void TabBar::add_tab(const String &p_str, const Ref<Texture2D> &p_icon) {
if (scroll_to_selected) {
ensure_tab_visible(current);
}
queue_accessibility_update();
queue_redraw();
update_minimum_size();
@ -1189,12 +1282,19 @@ void TabBar::clear_tabs() {
return;
}
for (int i = 0; i < tabs.size(); i++) {
if (tabs[i].accessibility_item_element.is_valid()) {
DisplayServer::get_singleton()->accessibility_free_element(tabs.write[i].accessibility_item_element);
tabs.write[i].accessibility_item_element = RID();
}
}
tabs.clear();
offset = 0;
max_drawn_tab = 0;
current = -1;
previous = -1;
queue_accessibility_update();
queue_redraw();
update_minimum_size();
notify_property_list_changed();
@ -1202,6 +1302,11 @@ void TabBar::clear_tabs() {
void TabBar::remove_tab(int p_idx) {
ERR_FAIL_INDEX(p_idx, tabs.size());
if (tabs[p_idx].accessibility_item_element.is_valid()) {
DisplayServer::get_singleton()->accessibility_free_element(tabs.write[p_idx].accessibility_item_element);
tabs.write[p_idx].accessibility_item_element = RID();
}
tabs.remove_at(p_idx);
bool is_tab_changing = current == p_idx;
@ -1251,6 +1356,7 @@ void TabBar::remove_tab(int p_idx) {
}
}
queue_accessibility_update();
queue_redraw();
update_minimum_size();
notify_property_list_changed();
@ -1284,7 +1390,7 @@ void TabBar::drop_data(const Point2 &p_point, const Variant &p_data) {
}
Variant TabBar::_handle_get_drag_data(const String &p_type, const Point2 &p_point) {
int tab_over = get_tab_idx_at_point(p_point);
int tab_over = (p_point == Vector2(INFINITY, INFINITY)) ? current : get_tab_idx_at_point(p_point);
if (tab_over < 0) {
return Variant();
}
@ -1349,7 +1455,7 @@ void TabBar::_handle_drop_data(const String &p_type, const Point2 &p_point, cons
if (String(d["type"]) == p_type) {
int tab_from_id = d["tab_index"];
int hover_now = get_closest_tab_idx_to_point(p_point);
int hover_now = (p_point == Vector2(INFINITY, INFINITY)) ? current : get_closest_tab_idx_to_point(p_point);
NodePath from_path = d["from_path"];
NodePath to_path = get_path();
@ -1407,6 +1513,8 @@ void TabBar::_handle_drop_data(const String &p_type, const Point2 &p_point, cons
void TabBar::_move_tab_from(TabBar *p_from_tabbar, int p_from_index, int p_to_index) {
Tab moving_tab = p_from_tabbar->tabs[p_from_index];
moving_tab.accessibility_item_element = RID();
moving_tab.accessibility_item_dirty = true;
p_from_tabbar->remove_tab(p_from_index);
tabs.insert(p_to_index, moving_tab);
@ -1426,6 +1534,7 @@ void TabBar::_move_tab_from(TabBar *p_from_tabbar, int p_from_index, int p_to_in
queue_redraw();
}
queue_accessibility_update();
update_minimum_size();
}
@ -1515,6 +1624,8 @@ void TabBar::move_tab(int p_from, int p_to) {
ERR_FAIL_INDEX(p_to, tabs.size());
Tab tab_from = tabs[p_from];
tab_from.accessibility_item_dirty = true;
tabs.remove_at(p_from);
tabs.insert(p_to, tab_from);
@ -1539,6 +1650,7 @@ void TabBar::move_tab(int p_from, int p_to) {
if (scroll_to_selected) {
ensure_tab_visible(current);
}
queue_accessibility_update();
queue_redraw();
notify_property_list_changed();
}
@ -1957,6 +2069,7 @@ void TabBar::_bind_methods() {
}
TabBar::TabBar() {
set_focus_mode(FOCUS_ACCESSIBILITY);
set_size(Size2(get_size().width, get_minimum_size().height));
set_focus_mode(FOCUS_ALL);
connect(SceneStringName(mouse_exited), callable_mp(this, &TabBar::_on_mouse_exited));