From 76411b5d74aa980395fd8c24e072fa300879d539 Mon Sep 17 00:00:00 2001 From: Arnold Loubriat Date: Fri, 8 Mar 2024 09:54:21 +0100 Subject: [PATCH] Add accessibility to `ProgressBar` and `Spinner` (#4139) - Introduces `WidgetType::ProgressIndicator` and maps it to the corresponding AccessKit role. - A `Spinner` is now exposed as a widget indicating a progress for which a completion state is not known. - On the other hand, a `ProgressBar` reports a completion state and can possibly be labeled. Note that a label is not used if not explicitly asked by the user, as it would be redundant information. Assistive technologies prefer the numerical value so they can, for instance, emit beeps of which the frequency rise as the completion state increase. I had to call `floor` on the progression as it seems all the ATs I tested would round the value, hence reporting something different than what is displayed on the label. --- crates/egui/src/data/output.rs | 1 + crates/egui/src/lib.rs | 2 ++ crates/egui/src/response.rs | 1 + crates/egui/src/widgets/progress_bar.rs | 11 +++++++++++ crates/egui/src/widgets/spinner.rs | 3 ++- 5 files changed, 17 insertions(+), 1 deletion(-) diff --git a/crates/egui/src/data/output.rs b/crates/egui/src/data/output.rs index 9960d515..d1db5fc2 100644 --- a/crates/egui/src/data/output.rs +++ b/crates/egui/src/data/output.rs @@ -633,6 +633,7 @@ impl WidgetInfo { WidgetType::ColorButton => "color button", WidgetType::ImageButton => "image button", WidgetType::CollapsingHeader => "collapsing header", + WidgetType::ProgressIndicator => "progress indicator", WidgetType::Label | WidgetType::Other => "", }; diff --git a/crates/egui/src/lib.rs b/crates/egui/src/lib.rs index 9c065811..69328045 100644 --- a/crates/egui/src/lib.rs +++ b/crates/egui/src/lib.rs @@ -643,6 +643,8 @@ pub enum WidgetType { CollapsingHeader, + ProgressIndicator, + /// If you cannot fit any of the above slots. /// /// If this is something you think should be added, file an issue. diff --git a/crates/egui/src/response.rs b/crates/egui/src/response.rs index 70c82ac3..a34ed8fa 100644 --- a/crates/egui/src/response.rs +++ b/crates/egui/src/response.rs @@ -783,6 +783,7 @@ impl Response { WidgetType::Slider => Role::Slider, WidgetType::DragValue => Role::SpinButton, WidgetType::ColorButton => Role::ColorWell, + WidgetType::ProgressIndicator => Role::ProgressIndicator, WidgetType::Other => Role::Unknown, }); if let Some(label) = info.label { diff --git a/crates/egui/src/widgets/progress_bar.rs b/crates/egui/src/widgets/progress_bar.rs index cd00bd74..99c768bf 100644 --- a/crates/egui/src/widgets/progress_bar.rs +++ b/crates/egui/src/widgets/progress_bar.rs @@ -113,6 +113,17 @@ impl Widget for ProgressBar { let (outer_rect, response) = ui.allocate_exact_size(vec2(desired_width, height), Sense::hover()); + response.widget_info(|| { + let mut info = if let Some(ProgressBarText::Custom(text)) = &text { + WidgetInfo::labeled(WidgetType::ProgressIndicator, text.text()) + } else { + WidgetInfo::new(WidgetType::ProgressIndicator) + }; + info.value = Some((progress as f64 * 100.0).floor()); + + info + }); + if ui.is_rect_visible(response.rect) { if animate { ui.ctx().request_repaint(); diff --git a/crates/egui/src/widgets/spinner.rs b/crates/egui/src/widgets/spinner.rs index 0327bfab..f1884284 100644 --- a/crates/egui/src/widgets/spinner.rs +++ b/crates/egui/src/widgets/spinner.rs @@ -1,6 +1,6 @@ use epaint::{emath::lerp, vec2, Color32, Pos2, Rect, Shape, Stroke}; -use crate::{Response, Sense, Ui, Widget}; +use crate::{Response, Sense, Ui, Widget, WidgetInfo, WidgetType}; /// A spinner widget used to indicate loading. /// @@ -66,6 +66,7 @@ impl Widget for Spinner { .size .unwrap_or_else(|| ui.style().spacing.interact_size.y); let (rect, response) = ui.allocate_exact_size(vec2(size, size), Sense::hover()); + response.widget_info(|| WidgetInfo::new(WidgetType::ProgressIndicator)); self.paint_at(ui, rect); response