mirror of
https://github.com/emilk/egui.git
synced 2026-09-02 14:50:03 -04:00
Group AccessKit nodes by Ui (#7386)
* closes https://github.com/emilk/egui/issues/5674 This changes egui to create an AccessKit node for each `Ui`. I'm not sure if this alone will directly improve accessibility, but it should make it easier to create the correct parent / child relations (e.g. grouping menus as children of menu buttons). Instead of having a global stack of parent ids, they are now passed via a parent_id field in `UiBuilder`. If having all these `GenericContainer` nodes somehow is bad for accessibility, the PR could also be changed to only create nodes if there is actually some accessibility info with it (the relevant is currently commented-out in the PR). But I think screen readers should just ignore these nodes, so it should be fine? We could also use this as motivation to git red of some unnecessary wrapped `Ui`s, e.g. CentralPanel creates 3 Uis when 2 should be enough (the initial Ui and a Frame, maybe we could even only show the `Frame` if we can give it an UiBuilder and somehow show the Frame with `Ui::new`). Here is a screenshot from the accessibility inspector (https://github.com/emilk/egui/pull/7368) with this PR: <img width="431" height="744" alt="Screenshot 2025-07-24 at 12 09 55" src="https://github.com/user-attachments/assets/6c4e5ff6-5c38-450e-9500-0776c9018d8c" /> Without this PR: https://github.com/user-attachments/assets/270e32fc-9c7a-4dad-8c90-7638c487a602
This commit is contained in:
@@ -18,9 +18,20 @@ fn empty_ui_should_return_tree_with_only_root_window() {
|
||||
|
||||
assert_eq!(
|
||||
output.nodes.len(),
|
||||
1,
|
||||
"Empty ui should produce only the root window."
|
||||
4,
|
||||
"Expected the root node and two Uis and a Frame for the panel"
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
output
|
||||
.nodes
|
||||
.iter()
|
||||
.filter(|(_, n)| n.role() == Role::GenericContainer)
|
||||
.count(),
|
||||
3,
|
||||
"Expected two Uis and one Frame as GenericContainer nodes.",
|
||||
);
|
||||
|
||||
let (id, root) = &output.nodes[0];
|
||||
|
||||
assert_eq!(*id, output.tree.unwrap().root);
|
||||
@@ -35,12 +46,6 @@ fn button_node() {
|
||||
CentralPanel::default().show(ctx, |ui| ui.button(button_text));
|
||||
});
|
||||
|
||||
assert_eq!(
|
||||
output.nodes.len(),
|
||||
2,
|
||||
"Expected only the root node and the button."
|
||||
);
|
||||
|
||||
let (_, button) = output
|
||||
.nodes
|
||||
.iter()
|
||||
@@ -61,12 +66,6 @@ fn disabled_button_node() {
|
||||
});
|
||||
});
|
||||
|
||||
assert_eq!(
|
||||
output.nodes.len(),
|
||||
2,
|
||||
"Expected only the root node and the button."
|
||||
);
|
||||
|
||||
let (_, button) = output
|
||||
.nodes
|
||||
.iter()
|
||||
@@ -86,12 +85,6 @@ fn toggle_button_node() {
|
||||
CentralPanel::default().show(ctx, |ui| ui.toggle_value(&mut selected, button_text));
|
||||
});
|
||||
|
||||
assert_eq!(
|
||||
output.nodes.len(),
|
||||
2,
|
||||
"Expected only the root node and the button."
|
||||
);
|
||||
|
||||
let (_, toggle) = output
|
||||
.nodes
|
||||
.iter()
|
||||
@@ -114,12 +107,6 @@ fn multiple_disabled_widgets() {
|
||||
});
|
||||
});
|
||||
|
||||
assert_eq!(
|
||||
output.nodes.len(),
|
||||
4,
|
||||
"Expected the root node and all the child widgets."
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
output
|
||||
.nodes
|
||||
@@ -194,15 +181,25 @@ fn assert_window_exists(tree: &TreeUpdate, title: &str, parent: NodeId) -> NodeI
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn assert_parent_child(tree: &TreeUpdate, parent: NodeId, child: NodeId) {
|
||||
fn assert_parent_child(tree: &TreeUpdate, parent_id: NodeId, child: NodeId) {
|
||||
assert!(
|
||||
has_child_recursively(tree, parent_id, child),
|
||||
"Node is not a child of the given parent."
|
||||
);
|
||||
}
|
||||
|
||||
fn has_child_recursively(tree: &TreeUpdate, parent: NodeId, child: NodeId) -> bool {
|
||||
let (_, parent) = tree
|
||||
.nodes
|
||||
.iter()
|
||||
.find(|(id, _)| id == &parent)
|
||||
.expect("Parent does not exist.");
|
||||
|
||||
assert!(
|
||||
parent.children().contains(&child),
|
||||
"Node is not a child of the given parent."
|
||||
);
|
||||
for &c in parent.children() {
|
||||
if c == child || has_child_recursively(tree, c, child) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user