Add `WidgetType::Tab`
Is your feature request related to a problem? Please describe.
There is no suitable WidgetType for tabs while I was implementing AccessKit support for egui_dock. AccessKit provides accesskit::Role::Tab and other tab-related widgets that will be described by assistive technologies accurately.
Describe the solution you'd like
Add a WidgetType::Tab variant mapping to accesskit::Role::Tab, with WidgetInfo::selected triggering set_selected instead of set_toggled for it. Possibly also some way to mark a container Ui as Role::TabList or Role::TabPanel.
Describe alternatives you've considered
Currently I had to override the role after widget_info using accesskit_node_builder:
response.widget_info(|| WidgetInfo::selected(WidgetType::Button, enabled, selected, title));
ui.ctx().accesskit_node_builder(response.id, |node| {
node.set_role(accesskit::Role::Tab);
node.set_selected(selected);
node.clear_toggled();
});Also tried using other existing WidgetTypes like selectable label, but assistive technologies will interpret it as a selectable label instead of a tab, which can be confusing.
Additional context See https://github.com/anhosh/egui_dock/pull/345.
Edit: the following has been opened to #8557.
During that PR, I also found out that there is no way to describe the direction (horizontal/vertical) on WidgetType::ResizeHandle, and all splitters are interpreted as "horizontal" in VoiceOver, and also window resizing doesn't work using VoiceOver (it always reports the window resizing handle as a horizontal splitter stuck at 0%). The PR works around this by
let ak_steps = ui.input(|input| {
input.num_accesskit_action_requests(response.id, accesskit::Action::Increment) as f32
- input.num_accesskit_action_requests(response.id, accesskit::Action::Decrement) as f32
});
let ak_set_value = ui.input(|input| {
input
.accesskit_action_requests(response.id, accesskit::Action::SetValue)
.find_map(|request| match request.data {
Some(accesskit::ActionData::NumericValue(value)) => Some(value as f32),
_ => None,
})
});
let mut delta = arrow_key_offset.unwrap_or(response.drag_delta());
delta.dim_point += ak_steps * style.separator.arrow_key_step_distance;
if let Some(value) = ak_set_value {
delta.dim_point += (value.clamp(0.0, 1.0) - split.fraction) * rect.dim_size();
}
apply_separator_delta(split, SeparatorAxis::sep_axis, delta, &style.separator);
if response.double_clicked() {
split.fraction = 0.5;
}
// Allow assistive technologies to adjust the separator fraction.
let fraction = split.fraction;
let step = style.separator.arrow_key_step_distance / rect.dim_size().max(1.0);
ui.ctx().accesskit_node_builder(response.id, |node| {
node.set_orientation(accesskit::Orientation::ak_orientation);
node.set_numeric_value(fraction.into());
node.set_min_numeric_value(0.0);
node.set_max_numeric_value(1.0);
node.set_numeric_value_step(step.into());
node.add_action(accesskit::Action::Increment);
node.add_action(accesskit::Action::Decrement);
node.add_action(accesskit::Action::SetValue);
});Source: emilk/egui