mirror of
https://github.com/emilk/egui.git
synced 2026-06-26 22:53:14 -04:00
Revert "Remove accesskit feature and always depend on accesskit (#7701)"
This reverts commit 1af5d1d37e.
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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 }
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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<Loaders>,
|
||||
@@ -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<R>(
|
||||
&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);
|
||||
}
|
||||
|
||||
@@ -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`].
|
||||
|
||||
@@ -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<accesskit::TreeUpdate>,
|
||||
|
||||
/// 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)
|
||||
|
||||
@@ -79,6 +79,7 @@ impl Id {
|
||||
self.0.get()
|
||||
}
|
||||
|
||||
#[cfg(feature = "accesskit")]
|
||||
pub(crate) fn accesskit_id(&self) -> accesskit::NodeId {
|
||||
self.value().into()
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
|
||||
@@ -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<Id>,
|
||||
|
||||
#[cfg(feature = "accesskit")]
|
||||
id_requested_by_accesskit: Option<accesskit::NodeId>,
|
||||
|
||||
/// 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.
|
||||
|
||||
@@ -67,6 +67,7 @@ impl ScrollTarget {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "accesskit")]
|
||||
#[derive(Clone)]
|
||||
pub struct AccessKitPassState {
|
||||
pub nodes: IdMap<accesskit::Node>,
|
||||
@@ -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<AccessKitPassState>,
|
||||
|
||||
/// 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();
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -624,6 +624,7 @@ impl LabelSelectionState {
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(feature = "accesskit")]
|
||||
super::accesskit_text::update_accesskit_for_text_widget(
|
||||
ui.ctx(),
|
||||
response.id,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
//! Helpers regarding text selection for labels and text edit.
|
||||
|
||||
#[cfg(feature = "accesskit")]
|
||||
pub mod accesskit_text;
|
||||
|
||||
mod cursor_range;
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -24,6 +24,7 @@ pub struct UiBuilder {
|
||||
pub sizing_pass: bool,
|
||||
pub style: Option<Arc<Style>>,
|
||||
pub sense: Option<Sense>,
|
||||
#[cfg(feature = "accesskit")]
|
||||
pub accessibility_parent: Option<Id>,
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -844,6 +844,7 @@ impl TextEdit<'_> {
|
||||
});
|
||||
}
|
||||
|
||||
#[cfg(feature = "accesskit")]
|
||||
{
|
||||
let role = if password {
|
||||
accesskit::Role::PasswordInput
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user