Skip to content

Commit 0493d75

Browse files
committed
Editor: Improve accessibility for Editor and Project Settings
- Add accessibility names to EditorSpinSlider, inspector scrollbar, and settings categories tree - Propagate property labels to focusable controls in EditorProperty::set_label - Eliminate duplicate tab stops by setting EditorProperty to FOCUS_NONE when it has focusable children - Fix EditorSettingsPropertyWrapper to pass label and set proper focus mode - Skip setting empty 'Property:' accessibility names
1 parent 5f9a510 commit 0493d75

File tree

4 files changed

+66
-3
lines changed

4 files changed

+66
-3
lines changed

editor/gui/editor_spin_slider.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -464,6 +464,32 @@ void EditorSpinSlider::_draw_spin_slider() {
464464

465465
void EditorSpinSlider::_notification(int p_what) {
466466
switch (p_what) {
467+
case NOTIFICATION_ACCESSIBILITY_UPDATE: {
468+
RID ae = get_accessibility_element();
469+
ERR_FAIL_COND(ae.is_null());
470+
471+
DisplayServer::get_singleton()->accessibility_update_set_role(ae, DisplayServer::AccessibilityRole::ROLE_SPIN_BUTTON);
472+
// Use accessibility_name if set, otherwise fall back to label property.
473+
String name = get_accessibility_name();
474+
if (name.is_empty()) {
475+
name = label;
476+
}
477+
DisplayServer::get_singleton()->accessibility_update_set_name(ae, name);
478+
DisplayServer::get_singleton()->accessibility_update_set_description(ae, get_accessibility_description());
479+
DisplayServer::get_singleton()->accessibility_update_set_num_value(ae, get_value());
480+
DisplayServer::get_singleton()->accessibility_update_set_num_range(ae, get_min(), get_max());
481+
if (get_step() > 0) {
482+
DisplayServer::get_singleton()->accessibility_update_set_num_step(ae, get_step());
483+
} else {
484+
DisplayServer::get_singleton()->accessibility_update_set_num_step(ae, 1);
485+
}
486+
487+
// Propagate accessibility name to internal LineEdit if it doesn't have its own.
488+
if (value_input && !name.is_empty() && value_input->get_accessibility_name().is_empty()) {
489+
value_input->set_accessibility_name(name);
490+
}
491+
} break;
492+
467493
case NOTIFICATION_ENTER_TREE: {
468494
grabbing_spinner_speed = editing_integer ? EDITOR_GET("interface/inspector/integer_drag_speed") : EDITOR_GET("interface/inspector/float_drag_speed");
469495
_update_value_input_stylebox();

editor/inspector/editor_inspector.cpp

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -290,8 +290,10 @@ void EditorProperty::_notification(int p_what) {
290290

291291
DisplayServer::get_singleton()->accessibility_update_set_role(ae, DisplayServer::AccessibilityRole::ROLE_BUTTON);
292292

293-
DisplayServer::get_singleton()->accessibility_update_set_name(ae, vformat(TTR("Property: %s"), label));
294-
DisplayServer::get_singleton()->accessibility_update_set_value(ae, vformat(TTR("Property: %s"), label));
293+
if (!label.is_empty()) {
294+
DisplayServer::get_singleton()->accessibility_update_set_name(ae, vformat(TTR("Property: %s"), label));
295+
DisplayServer::get_singleton()->accessibility_update_set_value(ae, vformat(TTR("Property: %s"), label));
296+
}
295297

296298
DisplayServer::get_singleton()->accessibility_update_set_popup_type(ae, DisplayServer::AccessibilityPopupType::POPUP_MENU);
297299
DisplayServer::get_singleton()->accessibility_update_add_action(ae, DisplayServer::AccessibilityAction::ACTION_SHOW_CONTEXT_MENU, callable_mp(this, &EditorProperty::_accessibility_action_menu));
@@ -716,6 +718,28 @@ void EditorProperty::_notification(int p_what) {
716718
void EditorProperty::set_label(const String &p_label) {
717719
label = p_label;
718720
queue_redraw();
721+
722+
// Propagate label to focusable child controls for accessibility.
723+
// Only set if the child doesn't already have its own accessibility name.
724+
// Also propagate to child EditorProperty nodes (e.g., wrapper -> inner property).
725+
if (!label.is_empty()) {
726+
for (Control *focusable : focusables) {
727+
if (focusable->get_accessibility_name().is_empty()) {
728+
focusable->set_accessibility_name(label);
729+
}
730+
}
731+
// Propagate to child EditorProperty focusables.
732+
for (int i = 0; i < get_child_count(); i++) {
733+
EditorProperty *child_ep = Object::cast_to<EditorProperty>(get_child(i));
734+
if (child_ep && child_ep->get_label().is_empty()) {
735+
for (Control *focusable : child_ep->focusables) {
736+
if (focusable->get_accessibility_name().is_empty()) {
737+
focusable->set_accessibility_name(label);
738+
}
739+
}
740+
}
741+
}
742+
}
719743
}
720744

721745
String EditorProperty::get_label() const {
@@ -979,6 +1003,12 @@ void EditorProperty::_focusable_focused(int p_index) {
9791003
void EditorProperty::add_focusable(Control *p_control) {
9801004
p_control->connect(SceneStringName(focus_entered), callable_mp(this, &EditorProperty::_focusable_focused).bind(focusables.size()));
9811005
focusables.push_back(p_control);
1006+
1007+
// If property has focusable children, make the property itself not focusable
1008+
// to avoid duplicate tab stops.
1009+
if (get_focus_mode() != FOCUS_NONE) {
1010+
set_focus_mode(FOCUS_NONE);
1011+
}
9821012
}
9831013

9841014
void EditorProperty::grab_focus(int p_focusable) {
@@ -5963,6 +5993,7 @@ EditorInspector::EditorInspector() {
59635993
property_focusable = -1;
59645994

59655995
get_v_scroll_bar()->connect(SceneStringName(value_changed), callable_mp(this, &EditorInspector::_vscroll_changed));
5996+
get_v_scroll_bar()->set_accessibility_name(TTRC("Properties"));
59665997
update_scroll_request = -1;
59675998
if (EditorSettings::get_singleton()) {
59685999
refresh_countdown = float(EDITOR_GET("docks/property_editor/auto_refresh_interval"));

editor/inspector/editor_sectioned_inspector.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -367,6 +367,7 @@ SectionedInspector::SectionedInspector() :
367367
sections->set_v_size_flags(SIZE_EXPAND_FILL);
368368
sections->set_hide_root(true);
369369
sections->set_theme_type_variation("TreeSecondary");
370+
sections->set_accessibility_name(TTRC("Categories"));
370371

371372
left_vb->add_child(sections, true);
372373

editor/settings/editor_settings_dialog.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1146,6 +1146,9 @@ void EditorSettingsPropertyWrapper::setup(const String &p_property, EditorProper
11461146
editor_property = p_editor_property;
11471147
add_child(editor_property);
11481148

1149+
// Wrapper is not focusable - focus goes directly to the actual control.
1150+
set_focus_mode(FOCUS_NONE);
1151+
11491152
_update_override();
11501153

11511154
connect(SNAME("property_overridden"), callable_mp(this, &EditorSettingsPropertyWrapper::_create_override));
@@ -1174,7 +1177,9 @@ bool EditorSettingsInspectorPlugin::parse_property(Object *p_object, const Varia
11741177
real_property->set_name_split_ratio(0.0);
11751178
editor->setup(property, real_property, p_hint, p_hint_text, p_usage);
11761179

1177-
add_property_editor(p_path, editor);
1180+
// Generate label from property path for accessibility.
1181+
String label = EditorPropertyNameProcessor::get_singleton()->process_name(p_path, EditorPropertyNameProcessor::STYLE_CAPITALIZED, property, "");
1182+
add_property_editor(p_path, editor, false, label);
11781183
current_object = nullptr;
11791184
return true;
11801185
}

0 commit comments

Comments
 (0)