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 9960d5159..d1db5fc2a 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 9c065811d..693280453 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 70c82ac31..a34ed8fa7 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 cd00bd740..99c768bf9 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 0327bfab1..f18842844 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