use super::{EventCx, EventState};
use crate::cast::CastApprox;
use crate::event::{Command, Event, FocusSource, Scroll, ScrollDelta};
use crate::geom::{Rect, Size};
use crate::window::WindowErased;
use crate::{Id, Node, TileExt};
impl EventState {
#[inline]
pub(crate) fn accesskit_is_enabled(&self) -> bool {
self.accesskit_is_enabled
}
pub(crate) fn accesskit_tree_update(
&mut self,
root: &dyn WindowErased,
) -> accesskit::TreeUpdate {
self.accesskit_is_enabled = true;
let (nodes, root_id) = crate::accesskit::window_nodes(root);
let tree = Some(accesskit::Tree::new(root_id));
let focus = self
.nav_focus()
.map(|id| id.into())
.filter(|node_id| nodes.iter().any(|(id, _)| id == node_id))
.unwrap_or(root_id);
accesskit::TreeUpdate { nodes, tree, focus }
}
pub(crate) fn disable_accesskit(&mut self) {
self.accesskit_is_enabled = false;
}
}
impl<'a> EventCx<'a> {
pub(crate) fn handle_accesskit_action(
&mut self,
widget: Node<'_>,
request: accesskit::ActionRequest,
) {
let Some(id) = Id::try_from_u64(request.target.0) else {
return;
};
use crate::messages::{self, Erased, SetValueF64, SetValueText};
use accesskit::{Action as AKA, ActionData};
match request.action {
AKA::Click => {
self.send_event(widget, id, Event::Command(Command::Activate, None));
}
AKA::Focus => self.set_nav_focus(id, FocusSource::Synthetic),
AKA::Blur => (),
AKA::Collapse | AKA::Expand => (), AKA::CustomAction => (),
AKA::Decrement => {
self.send_or_replay(widget, id, Erased::new(messages::DecrementStep));
}
AKA::Increment => {
self.send_or_replay(widget, id, Erased::new(messages::IncrementStep));
}
AKA::HideTooltip | AKA::ShowTooltip => (),
AKA::ReplaceSelectedText => (),
AKA::ScrollDown | AKA::ScrollLeft | AKA::ScrollRight | AKA::ScrollUp => {
let delta = match request.action {
AKA::ScrollDown => ScrollDelta::Lines(0.0, 1.0),
AKA::ScrollLeft => ScrollDelta::Lines(-1.0, 0.0),
AKA::ScrollRight => ScrollDelta::Lines(1.0, 0.0),
AKA::ScrollUp => ScrollDelta::Lines(0.0, -1.0),
_ => unreachable!(),
};
self.send_event(widget, id, Event::Scroll(delta));
}
AKA::ScrollIntoView | AKA::ScrollToPoint => {
let scroll = match request.data {
None => {
debug_assert_eq!(request.action, AKA::ScrollIntoView);
if let Some(tile) = widget.as_tile().find_tile(&id) {
Scroll::Rect(tile.rect())
} else {
return;
}
}
Some(ActionData::ScrollToPoint(point)) => {
debug_assert_eq!(request.action, AKA::ScrollToPoint);
let pos = point.cast_approx();
let size = Size::ZERO;
Scroll::Rect(Rect { pos, size })
}
_ => {
debug_assert!(false);
return;
}
};
self.replay_scroll(widget, id, scroll);
}
AKA::SetScrollOffset => {
if let Some(ActionData::SetScrollOffset(point)) = request.data {
let msg = kas::messages::SetScrollOffset(point.cast_approx());
self.send_or_replay(widget, id, Erased::new(msg));
}
}
AKA::SetTextSelection => (),
AKA::SetSequentialFocusNavigationStartingPoint => (),
AKA::SetValue => {
let msg = match request.data {
Some(ActionData::Value(text)) => Erased::new(SetValueText(text.into())),
Some(ActionData::NumericValue(n)) => Erased::new(SetValueF64(n)),
_ => return,
};
self.send_or_replay(widget, id, msg);
}
AKA::ShowContextMenu => (),
}
}
}