diff --git a/crates/eframe/Cargo.toml b/crates/eframe/Cargo.toml index 6924633f1..ed9af012c 100644 --- a/crates/eframe/Cargo.toml +++ b/crates/eframe/Cargo.toml @@ -36,7 +36,7 @@ default = [ ] ## Enable platform accessibility API implementations through [AccessKit](https://accesskit.dev/). -accesskit = ["egui-winit/accesskit"] +accesskit = ["egui/accesskit", "egui-winit/accesskit"] # Allow crates to choose an android-activity backend via Winit # - It's important that most applications should not have to depend on android-activity directly, and can diff --git a/crates/eframe/src/web/app_runner.rs b/crates/eframe/src/web/app_runner.rs index 8a10a90ef..41bb81ae7 100644 --- a/crates/eframe/src/web/app_runner.rs +++ b/crates/eframe/src/web/app_runner.rs @@ -358,7 +358,8 @@ impl AppRunner { events: _, // already handled mutable_text_under_cursor: _, // TODO(#4569): https://github.com/emilk/egui/issues/4569 ime, - accesskit_update: _, // not currently implemented + #[cfg(feature = "accesskit")] + accesskit_update: _, // not currently implemented num_completed_passes: _, // handled by `Context::run` request_discard_reasons: _, // handled by `Context::run` } = platform_output; diff --git a/crates/egui-winit/Cargo.toml b/crates/egui-winit/Cargo.toml index d1b2ab220..a4c84b05f 100644 --- a/crates/egui-winit/Cargo.toml +++ b/crates/egui-winit/Cargo.toml @@ -24,7 +24,7 @@ rustdoc-args = ["--generate-link-to-definition"] default = ["clipboard", "links", "wayland", "winit/default", "x11"] ## Enable platform accessibility API implementations through [AccessKit](https://accesskit.dev/). -accesskit = ["dep:accesskit_winit"] +accesskit = ["dep:accesskit_winit", "egui/accesskit"] # Allow crates to choose an android-activity backend via Winit # - It's important that most applications should not have to depend on android-activity directly, and can diff --git a/crates/egui-winit/src/lib.rs b/crates/egui-winit/src/lib.rs index 7660e3cef..d72c44245 100644 --- a/crates/egui-winit/src/lib.rs +++ b/crates/egui-winit/src/lib.rs @@ -888,6 +888,7 @@ impl State { events: _, // handled elsewhere mutable_text_under_cursor: _, // only used in eframe web ime, + #[cfg(feature = "accesskit")] accesskit_update, num_completed_passes: _, // `egui::Context::run` handles this request_discard_reasons: _, // `egui::Context::run` handles this @@ -946,9 +947,6 @@ impl State { profiling::scope!("accesskit"); accesskit.update_if_active(|| update); } - - #[cfg(not(feature = "accesskit"))] - let _ = accesskit_update; } fn set_cursor_icon(&mut self, window: &Window, cursor_icon: egui::CursorIcon) { diff --git a/crates/egui/Cargo.toml b/crates/egui/Cargo.toml index 764d2401e..c82ae5618 100644 --- a/crates/egui/Cargo.toml +++ b/crates/egui/Cargo.toml @@ -26,6 +26,10 @@ rustdoc-args = ["--generate-link-to-definition"] [features] default = ["default_fonts"] +## Exposes detailed accessibility implementation required by platform +## accessibility APIs. Also requires support in the egui integration. +accesskit = ["dep:accesskit"] + ## [`bytemuck`](https://docs.rs/bytemuck) enables you to cast [`epaint::Vertex`], [`emath::Vec2`] etc to `&[u8]`. bytemuck = ["epaint/bytemuck"] @@ -57,7 +61,7 @@ persistence = ["serde", "epaint/serde", "ron"] rayon = ["epaint/rayon"] ## Allow serialization using [`serde`](https://docs.rs/serde). -serde = ["dep:serde", "epaint/serde", "accesskit/serde"] +serde = ["dep:serde", "epaint/serde", "accesskit?/serde"] ## Change Vertex layout to be compatible with unity unity = ["epaint/unity"] @@ -71,7 +75,6 @@ _override_unity = ["epaint/_override_unity"] emath = { workspace = true, default-features = false } epaint = { workspace = true, default-features = false } -accesskit.workspace = true ahash.workspace = true bitflags.workspace = true log.workspace = true @@ -81,6 +84,7 @@ smallvec.workspace = true unicode-segmentation.workspace = true #! ### Optional dependencies +accesskit = { workspace = true, optional = true } backtrace = { workspace = true, optional = true } diff --git a/crates/egui/src/containers/window.rs b/crates/egui/src/containers/window.rs index 8d7a95be7..7f4bdaa08 100644 --- a/crates/egui/src/containers/window.rs +++ b/crates/egui/src/containers/window.rs @@ -910,6 +910,7 @@ fn resize_interaction( let rect = outer_rect.shrink(window_frame.stroke.width / 2.0); let side_response = |rect, id| { + #[cfg(feature = "accesskit")] ctx.register_accesskit_parent(id, _accessibility_parent); let response = ctx.create_widget( WidgetRect { diff --git a/crates/egui/src/context.rs b/crates/egui/src/context.rs index 2ca7af4fc..d8ff0a856 100644 --- a/crates/egui/src/context.rs +++ b/crates/egui/src/context.rs @@ -41,6 +41,7 @@ use crate::{ viewport::ViewportClass, }; +#[cfg(feature = "accesskit")] use crate::IdMap; /// Information given to the backend about when it is time to repaint the ui. @@ -403,6 +404,7 @@ struct ContextImpl { embed_viewports: bool, + #[cfg(feature = "accesskit")] is_accesskit_enabled: bool, loaders: Arc, @@ -505,6 +507,7 @@ impl ContextImpl { }, ); + #[cfg(feature = "accesskit")] if self.is_accesskit_enabled { profiling::scope!("accesskit"); use crate::pass_state::AccessKitPassState; @@ -586,10 +589,10 @@ impl ContextImpl { } } + #[cfg(feature = "accesskit")] fn accesskit_node_builder(&mut self, id: Id) -> &mut accesskit::Node { let state = self.viewport().this_pass.accesskit_state.as_mut().unwrap(); let builders = &mut state.nodes; - if let std::collections::hash_map::Entry::Vacant(entry) = builders.entry(id) { entry.insert(Default::default()); @@ -616,7 +619,6 @@ impl ContextImpl { let parent_builder = builders.get_mut(&parent_id).unwrap(); parent_builder.push_child(id.accesskit_id()); } - builders.get_mut(&id).unwrap() } @@ -1202,6 +1204,7 @@ impl Context { plugins.on_widget_under_pointer(self, &w); } + #[cfg(feature = "accesskit")] if allow_focus && w.sense.is_focusable() { // Make sure anything that can receive focus has an AccessKit node. // TODO(mwcampbell): For nodes that are filled from widget info, @@ -1209,6 +1212,7 @@ impl Context { self.accesskit_node_builder(w.id, |builder| res.fill_accesskit_node_common(builder)); } + #[cfg(feature = "accesskit")] self.write(|ctx| { use crate::{Align, pass_state::ScrollTarget, style::ScrollAnimation}; let viewport = ctx.viewport_for(ctx.viewport_id()); @@ -1216,14 +1220,12 @@ impl Context { viewport .input .consume_accesskit_action_requests(res.id, |request| { - use accesskit::Action; - // TODO(lucasmerlin): Correctly handle the scroll unit: // https://github.com/AccessKit/accesskit/blob/e639c0e0d8ccbfd9dff302d972fa06f9766d608e/common/src/lib.rs#L2621 const DISTANCE: f32 = 100.0; match &request.action { - Action::ScrollIntoView => { + accesskit::Action::ScrollIntoView => { viewport.this_pass.scroll_target = [ Some(ScrollTarget::new( res.rect.x_range(), @@ -1237,16 +1239,16 @@ impl Context { )), ]; } - Action::ScrollDown => { + accesskit::Action::ScrollDown => { viewport.this_pass.scroll_delta.0 += DISTANCE * Vec2::UP; } - Action::ScrollUp => { + accesskit::Action::ScrollUp => { viewport.this_pass.scroll_delta.0 += DISTANCE * Vec2::DOWN; } - Action::ScrollLeft => { + accesskit::Action::ScrollLeft => { viewport.this_pass.scroll_delta.0 += DISTANCE * Vec2::LEFT; } - Action::ScrollRight => { + accesskit::Action::ScrollRight => { viewport.this_pass.scroll_delta.0 += DISTANCE * Vec2::RIGHT; } _ => return false, @@ -1339,6 +1341,7 @@ impl Context { res.flags.set(Flags::FAKE_PRIMARY_CLICKED, true); } + #[cfg(feature = "accesskit")] if enabled && sense.senses_click() && input.has_accesskit_action_request(id, accesskit::Action::Click) @@ -2495,6 +2498,7 @@ impl ContextImpl { let mut platform_output: PlatformOutput = std::mem::take(&mut viewport.output); + #[cfg(feature = "accesskit")] { profiling::scope!("accesskit"); let state = viewport.this_pass.accesskit_state.take(); @@ -3493,8 +3497,9 @@ impl Context { /// /// The `Context` lock is held while the given closure is called! /// - /// Returns `None` if accesskit is off. + /// Returns `None` if acesskit is off. // TODO(emilk): consider making both read-only and read-write versions + #[cfg(feature = "accesskit")] pub fn accesskit_node_builder( &self, id: Id, @@ -3510,6 +3515,7 @@ impl Context { }) } + #[cfg(feature = "accesskit")] pub(crate) fn register_accesskit_parent(&self, id: Id, parent_id: Id) { self.write(|ctx| { if let Some(state) = ctx.viewport().this_pass.accesskit_state.as_mut() { @@ -3519,11 +3525,13 @@ impl Context { } /// Enable generation of AccessKit tree updates in all future frames. + #[cfg(feature = "accesskit")] pub fn enable_accesskit(&self) { self.write(|ctx| ctx.is_accesskit_enabled = true); } /// Disable generation of AccessKit tree updates in all future frames. + #[cfg(feature = "accesskit")] pub fn disable_accesskit(&self) { self.write(|ctx| ctx.is_accesskit_enabled = false); } diff --git a/crates/egui/src/data/input.rs b/crates/egui/src/data/input.rs index 61f6ae00c..869945ece 100644 --- a/crates/egui/src/data/input.rs +++ b/crates/egui/src/data/input.rs @@ -548,6 +548,7 @@ pub enum Event { WindowFocused(bool), /// An assistive technology (e.g. screen reader) requested an action. + #[cfg(feature = "accesskit")] AccessKitActionRequest(accesskit::ActionRequest), /// The reply of a screenshot requested with [`crate::ViewportCommand::Screenshot`]. diff --git a/crates/egui/src/data/output.rs b/crates/egui/src/data/output.rs index 2c6edba84..deec5162d 100644 --- a/crates/egui/src/data/output.rs +++ b/crates/egui/src/data/output.rs @@ -128,6 +128,7 @@ pub struct PlatformOutput { /// The difference in the widget tree since last frame. /// /// NOTE: this needs to be per-viewport. + #[cfg(feature = "accesskit")] pub accesskit_update: Option, /// How many ui passes is this the sum of? @@ -174,6 +175,7 @@ impl PlatformOutput { mut events, mutable_text_under_cursor, ime, + #[cfg(feature = "accesskit")] accesskit_update, num_completed_passes, mut request_discard_reasons, @@ -188,8 +190,12 @@ impl PlatformOutput { self.request_discard_reasons .append(&mut request_discard_reasons); - // egui produces a complete AccessKit tree for each frame, so overwrite rather than append: - self.accesskit_update = accesskit_update; + #[cfg(feature = "accesskit")] + { + // egui produces a complete AccessKit tree for each frame, + // so overwrite rather than appending. + self.accesskit_update = accesskit_update; + } } /// Take everything ephemeral (everything except `cursor_icon` currently) diff --git a/crates/egui/src/id.rs b/crates/egui/src/id.rs index 7484930c8..0565dc567 100644 --- a/crates/egui/src/id.rs +++ b/crates/egui/src/id.rs @@ -79,6 +79,7 @@ impl Id { self.0.get() } + #[cfg(feature = "accesskit")] pub(crate) fn accesskit_id(&self) -> accesskit::NodeId { self.value().into() } diff --git a/crates/egui/src/input_state/mod.rs b/crates/egui/src/input_state/mod.rs index 0c99b6ac3..e0628809e 100644 --- a/crates/egui/src/input_state/mod.rs +++ b/crates/egui/src/input_state/mod.rs @@ -855,6 +855,7 @@ impl InputState { } } + #[cfg(feature = "accesskit")] pub fn accesskit_action_requests( &self, id: crate::Id, @@ -872,6 +873,7 @@ impl InputState { }) } + #[cfg(feature = "accesskit")] pub fn consume_accesskit_action_requests( &mut self, id: crate::Id, @@ -888,10 +890,12 @@ impl InputState { }); } + #[cfg(feature = "accesskit")] pub fn has_accesskit_action_request(&self, id: crate::Id, action: accesskit::Action) -> bool { self.accesskit_action_requests(id, action).next().is_some() } + #[cfg(feature = "accesskit")] pub fn num_accesskit_action_requests(&self, id: crate::Id, action: accesskit::Action) -> usize { self.accesskit_action_requests(id, action).count() } diff --git a/crates/egui/src/lib.rs b/crates/egui/src/lib.rs index bd4319f0b..2652734cb 100644 --- a/crates/egui/src/lib.rs +++ b/crates/egui/src/lib.rs @@ -448,6 +448,7 @@ pub mod widgets; #[cfg(debug_assertions)] mod callstack; +#[cfg(feature = "accesskit")] pub use accesskit; #[deprecated = "Use the ahash crate directly."] @@ -707,6 +708,7 @@ pub fn __run_test_ui(add_contents: impl Fn(&mut Ui)) { }); } +#[cfg(feature = "accesskit")] pub fn accesskit_root_id() -> Id { Id::new("accesskit_root") } diff --git a/crates/egui/src/memory/mod.rs b/crates/egui/src/memory/mod.rs index d215a3bec..c7bcc6fdc 100644 --- a/crates/egui/src/memory/mod.rs +++ b/crates/egui/src/memory/mod.rs @@ -470,6 +470,7 @@ pub(crate) struct Focus { /// The ID of a widget to give the focus to in the next frame. id_next_frame: Option, + #[cfg(feature = "accesskit")] id_requested_by_accesskit: Option, /// If set, the next widget that is interested in focus will automatically get it. @@ -528,7 +529,10 @@ impl Focus { } let event_filter = self.focused_widget.map(|w| w.filter).unwrap_or_default(); - self.id_requested_by_accesskit = None; + #[cfg(feature = "accesskit")] + { + self.id_requested_by_accesskit = None; + } self.focus_direction = FocusDirection::None; @@ -563,13 +567,16 @@ impl Focus { self.focus_direction = cardinality; } - if let crate::Event::AccessKitActionRequest(accesskit::ActionRequest { - action: accesskit::Action::Focus, - target, - data: None, - }) = event + #[cfg(feature = "accesskit")] { - self.id_requested_by_accesskit = Some(*target); + if let crate::Event::AccessKitActionRequest(accesskit::ActionRequest { + action: accesskit::Action::Focus, + target, + data: None, + }) = event + { + self.id_requested_by_accesskit = Some(*target); + } } } } @@ -599,11 +606,14 @@ impl Focus { } fn interested_in_focus(&mut self, id: Id) { - if self.id_requested_by_accesskit == Some(id.accesskit_id()) { - self.focused_widget = Some(FocusWidget::new(id)); - self.id_requested_by_accesskit = None; - self.give_to_next = false; - self.reset_focus(); + #[cfg(feature = "accesskit")] + { + if self.id_requested_by_accesskit == Some(id.accesskit_id()) { + self.focused_widget = Some(FocusWidget::new(id)); + self.id_requested_by_accesskit = None; + self.give_to_next = false; + self.reset_focus(); + } } // The rect is updated at the end of the frame. diff --git a/crates/egui/src/pass_state.rs b/crates/egui/src/pass_state.rs index 9b323bfa0..2be7e5098 100644 --- a/crates/egui/src/pass_state.rs +++ b/crates/egui/src/pass_state.rs @@ -67,6 +67,7 @@ impl ScrollTarget { } } +#[cfg(feature = "accesskit")] #[derive(Clone)] pub struct AccessKitPassState { pub nodes: IdMap, @@ -224,6 +225,7 @@ pub struct PassState { /// as when swiping down on a touch-screen or track-pad with natural scrolling. pub scroll_delta: (Vec2, style::ScrollAnimation), + #[cfg(feature = "accesskit")] pub accesskit_state: Option, /// Highlight these widgets the next pass. @@ -245,6 +247,7 @@ impl Default for PassState { used_by_panels: Rect::NAN, scroll_target: [None, None], scroll_delta: (Vec2::default(), style::ScrollAnimation::none()), + #[cfg(feature = "accesskit")] accesskit_state: None, highlight_next_pass: Default::default(), @@ -267,6 +270,7 @@ impl PassState { used_by_panels, scroll_target, scroll_delta, + #[cfg(feature = "accesskit")] accesskit_state, highlight_next_pass, @@ -289,7 +293,10 @@ impl PassState { *debug_rect = None; } - *accesskit_state = None; + #[cfg(feature = "accesskit")] + { + *accesskit_state = None; + } highlight_next_pass.clear(); } diff --git a/crates/egui/src/response.rs b/crates/egui/src/response.rs index e89cb5252..4e75142cd 100644 --- a/crates/egui/src/response.rs +++ b/crates/egui/src/response.rs @@ -807,6 +807,7 @@ impl Response { if let Some(event) = event { self.output_event(event); } else { + #[cfg(feature = "accesskit")] self.ctx.accesskit_node_builder(self.id, |builder| { self.fill_accesskit_node_from_widget_info(builder, make_info()); }); @@ -816,6 +817,7 @@ impl Response { } pub fn output_event(&self, event: crate::output::OutputEvent) { + #[cfg(feature = "accesskit")] self.ctx.accesskit_node_builder(self.id, |builder| { self.fill_accesskit_node_from_widget_info(builder, event.widget_info().clone()); }); @@ -826,6 +828,7 @@ impl Response { self.ctx.output_mut(|o| o.events.push(event)); } + #[cfg(feature = "accesskit")] pub(crate) fn fill_accesskit_node_common(&self, builder: &mut accesskit::Node) { if !self.enabled() { builder.set_disabled(); @@ -844,6 +847,7 @@ impl Response { } } + #[cfg(feature = "accesskit")] fn fill_accesskit_node_from_widget_info( &self, builder: &mut accesskit::Node, @@ -918,9 +922,14 @@ impl Response { /// # }); /// ``` pub fn labelled_by(self, id: Id) -> Self { + #[cfg(feature = "accesskit")] self.ctx.accesskit_node_builder(self.id, |builder| { builder.push_labelled_by(id.accesskit_id()); }); + #[cfg(not(feature = "accesskit"))] + { + let _ = id; + } self } diff --git a/crates/egui/src/text_selection/accesskit_text.rs b/crates/egui/src/text_selection/accesskit_text.rs index 974a334d0..4d64229c5 100644 --- a/crates/egui/src/text_selection/accesskit_text.rs +++ b/crates/egui/src/text_selection/accesskit_text.rs @@ -42,9 +42,8 @@ pub fn update_accesskit_for_text_widget( for (row_index, row) in galley.rows.iter().enumerate() { let row_id = parent_id.with(row_index); - + #[cfg(feature = "accesskit")] ctx.register_accesskit_parent(row_id, parent_id); - ctx.accesskit_node_builder(row_id, |builder| { builder.set_role(accesskit::Role::TextRun); let rect = global_from_galley * row.rect_without_leading_space(); diff --git a/crates/egui/src/text_selection/cursor_range.rs b/crates/egui/src/text_selection/cursor_range.rs index a816f5f26..10980c581 100644 --- a/crates/egui/src/text_selection/cursor_range.rs +++ b/crates/egui/src/text_selection/cursor_range.rs @@ -190,6 +190,7 @@ impl CCursorRange { .. } => self.on_key_press(os, galley, modifiers, *key), + #[cfg(feature = "accesskit")] Event::AccessKitActionRequest(accesskit::ActionRequest { action: accesskit::Action::SetTextSelection, target, @@ -219,6 +220,7 @@ impl CCursorRange { // ---------------------------------------------------------------------------- +#[cfg(feature = "accesskit")] fn ccursor_from_accesskit_text_position( id: Id, galley: &Galley, diff --git a/crates/egui/src/text_selection/label_text_selection.rs b/crates/egui/src/text_selection/label_text_selection.rs index bc2884441..0405ca5da 100644 --- a/crates/egui/src/text_selection/label_text_selection.rs +++ b/crates/egui/src/text_selection/label_text_selection.rs @@ -624,6 +624,7 @@ impl LabelSelectionState { ); } + #[cfg(feature = "accesskit")] super::accesskit_text::update_accesskit_for_text_widget( ui.ctx(), response.id, diff --git a/crates/egui/src/text_selection/mod.rs b/crates/egui/src/text_selection/mod.rs index cbd51c31a..8d0943d60 100644 --- a/crates/egui/src/text_selection/mod.rs +++ b/crates/egui/src/text_selection/mod.rs @@ -1,5 +1,6 @@ //! Helpers regarding text selection for labels and text edit. +#[cfg(feature = "accesskit")] pub mod accesskit_text; mod cursor_range; diff --git a/crates/egui/src/ui.rs b/crates/egui/src/ui.rs index 3c7fca2f3..3097ad9bd 100644 --- a/crates/egui/src/ui.rs +++ b/crates/egui/src/ui.rs @@ -133,6 +133,7 @@ impl Ui { sizing_pass, style, sense, + #[cfg(feature = "accesskit")] accessibility_parent, } = ui_builder; @@ -174,6 +175,7 @@ impl Ui { min_rect_already_remembered: false, }; + #[cfg(feature = "accesskit")] if let Some(accessibility_parent) = accessibility_parent { ui.ctx() .register_accesskit_parent(ui.unique_id, accessibility_parent); @@ -200,6 +202,7 @@ impl Ui { ui.set_invisible(); } + #[cfg(feature = "accesskit")] ui.ctx().accesskit_node_builder(ui.unique_id, |node| { node.set_role(accesskit::Role::GenericContainer); }); @@ -270,6 +273,7 @@ impl Ui { sizing_pass, style, sense, + #[cfg(feature = "accesskit")] accessibility_parent, } = ui_builder; @@ -339,6 +343,7 @@ impl Ui { child_ui.disable(); } + #[cfg(feature = "accesskit")] child_ui.ctx().register_accesskit_parent( child_ui.unique_id, accessibility_parent.unwrap_or(self.unique_id), @@ -358,6 +363,7 @@ impl Ui { true, ); + #[cfg(feature = "accesskit")] child_ui .ctx() .accesskit_node_builder(child_ui.unique_id, |node| { @@ -1123,6 +1129,7 @@ impl Ui { impl Ui { /// Check for clicks, drags and/or hover on a specific region of this [`Ui`]. pub fn interact(&self, rect: Rect, id: Id, sense: Sense) -> Response { + #[cfg(feature = "accesskit")] self.ctx().register_accesskit_parent(id, self.unique_id); self.ctx().create_widget( diff --git a/crates/egui/src/ui_builder.rs b/crates/egui/src/ui_builder.rs index 686fdcb47..51b8ec8a5 100644 --- a/crates/egui/src/ui_builder.rs +++ b/crates/egui/src/ui_builder.rs @@ -24,6 +24,7 @@ pub struct UiBuilder { pub sizing_pass: bool, pub style: Option>, pub sense: Option, + #[cfg(feature = "accesskit")] pub accessibility_parent: Option, } @@ -186,9 +187,15 @@ impl UiBuilder { /// /// This will override the automatic parent assignment for accessibility purposes. /// If not set, the parent [`Ui`]'s ID will be used as the accessibility parent. + /// + /// This does nothing if the `accesskit` feature is not enabled. + #[cfg_attr(not(feature = "accesskit"), expect(unused_mut, unused_variables))] #[inline] pub fn accessibility_parent(mut self, parent_id: Id) -> Self { - self.accessibility_parent = Some(parent_id); + #[cfg(feature = "accesskit")] + { + self.accessibility_parent = Some(parent_id); + } self } } diff --git a/crates/egui/src/widgets/drag_value.rs b/crates/egui/src/widgets/drag_value.rs index 29d596201..9515726c2 100644 --- a/crates/egui/src/widgets/drag_value.rs +++ b/crates/egui/src/widgets/drag_value.rs @@ -489,21 +489,27 @@ impl Widget for DragValue<'_> { - input.count_and_consume_key(Modifiers::NONE, Key::ArrowDown) as f64; } - use accesskit::Action; - change += input.num_accesskit_action_requests(id, Action::Increment) as f64 - - input.num_accesskit_action_requests(id, Action::Decrement) as f64; + #[cfg(feature = "accesskit")] + { + use accesskit::Action; + change += input.num_accesskit_action_requests(id, Action::Increment) as f64 + - input.num_accesskit_action_requests(id, Action::Decrement) as f64; + } change }); - ui.input(|input| { + #[cfg(feature = "accesskit")] + { use accesskit::{Action, ActionData}; - for request in input.accesskit_action_requests(id, Action::SetValue) { - if let Some(ActionData::NumericValue(new_value)) = request.data { - value = new_value; + ui.input(|input| { + for request in input.accesskit_action_requests(id, Action::SetValue) { + if let Some(ActionData::NumericValue(new_value)) = request.data { + value = new_value; + } } - } - }); + }); + } if clamp_existing_to_range { value = clamp_value_to_range(value, range.clone()); @@ -663,6 +669,7 @@ impl Widget for DragValue<'_> { response.widget_info(|| WidgetInfo::drag_value(ui.is_enabled(), value)); + #[cfg(feature = "accesskit")] ui.ctx().accesskit_node_builder(response.id, |builder| { use accesskit::Action; // If either end of the range is unbounded, it's better diff --git a/crates/egui/src/widgets/slider.rs b/crates/egui/src/widgets/slider.rs index 129c41c3b..7937e5897 100644 --- a/crates/egui/src/widgets/slider.rs +++ b/crates/egui/src/widgets/slider.rs @@ -716,11 +716,14 @@ impl Slider<'_> { }); } - ui.input(|input| { + #[cfg(feature = "accesskit")] + { use accesskit::Action; - decrement += input.num_accesskit_action_requests(response.id, Action::Decrement); - increment += input.num_accesskit_action_requests(response.id, Action::Increment); - }); + ui.input(|input| { + decrement += input.num_accesskit_action_requests(response.id, Action::Decrement); + increment += input.num_accesskit_action_requests(response.id, Action::Increment); + }); + } let kb_step = increment as f32 - decrement as f32; @@ -756,14 +759,17 @@ impl Slider<'_> { self.set_value(new_value); } - ui.input(|input| { + #[cfg(feature = "accesskit")] + { use accesskit::{Action, ActionData}; - for request in input.accesskit_action_requests(response.id, Action::SetValue) { - if let Some(ActionData::NumericValue(new_value)) = request.data { - self.set_value(new_value); + ui.input(|input| { + for request in input.accesskit_action_requests(response.id, Action::SetValue) { + if let Some(ActionData::NumericValue(new_value)) = request.data { + self.set_value(new_value); + } } - } - }); + }); + } // Paint it: if ui.is_rect_visible(response.rect) { @@ -972,6 +978,7 @@ impl Slider<'_> { } response.widget_info(|| WidgetInfo::slider(ui.is_enabled(), value, self.text.text())); + #[cfg(feature = "accesskit")] ui.ctx().accesskit_node_builder(response.id, |builder| { use accesskit::Action; builder.set_min_numeric_value(*self.range.start()); diff --git a/crates/egui/src/widgets/text_edit/builder.rs b/crates/egui/src/widgets/text_edit/builder.rs index 6f2da1baa..c0364e7ee 100644 --- a/crates/egui/src/widgets/text_edit/builder.rs +++ b/crates/egui/src/widgets/text_edit/builder.rs @@ -844,6 +844,7 @@ impl TextEdit<'_> { }); } + #[cfg(feature = "accesskit")] { let role = if password { accesskit::Role::PasswordInput diff --git a/crates/egui_kittest/Cargo.toml b/crates/egui_kittest/Cargo.toml index 1de8ce7ac..c283d0734 100644 --- a/crates/egui_kittest/Cargo.toml +++ b/crates/egui_kittest/Cargo.toml @@ -35,7 +35,7 @@ x11 = ["eframe?/x11"] [dependencies] kittest.workspace = true -egui.workspace = true +egui = { workspace = true, features = ["accesskit"] } eframe = { workspace = true, optional = true } # wgpu dependencies