use std::cell::RefCell;
use std::ffi::c_void;
use std::rc::Rc;
use accesskit::{ActionHandler, ActionRequest, ActivationHandler, TreeUpdate};
use accesskit_macos::SubclassingAdapter;
use super::window::MuriView;
use super::{UiEvent, WindowKind};
use crate::keynav::MenuFocus;
use crate::menu::Menu;
pub(super) struct A11ySnapshot {
pub menu: Menu,
pub focus: MenuFocus,
}
pub(super) fn build_update(snap: &A11ySnapshot) -> TreeUpdate {
let mut tree = crate::a11y::build_tree(&snap.menu);
let mut path = Vec::with_capacity(snap.focus.flyout.len());
for frame in &snap.focus.flyout {
path.push(frame.parent);
crate::a11y::set_expanded(&mut tree, &path, true);
}
let focus = crate::a11y::focused_id(&tree, &snap.focus);
crate::a11y::accesskit::tree_update(&tree, focus)
}
struct Activation {
snapshot: Rc<RefCell<A11ySnapshot>>,
}
impl ActivationHandler for Activation {
fn request_initial_tree(&mut self) -> Option<TreeUpdate> {
Some(build_update(&self.snapshot.borrow()))
}
}
struct Actions {
kind: WindowKind,
}
impl ActionHandler for Actions {
fn do_action(&mut self, request: ActionRequest) {
super::push_event(UiEvent::A11yAction {
kind: self.kind,
request,
});
}
}
pub(super) fn make_adapter(
view: &MuriView,
snapshot: Rc<RefCell<A11ySnapshot>>,
kind: WindowKind,
) -> SubclassingAdapter {
let ptr = (view as *const MuriView) as *mut c_void;
unsafe { SubclassingAdapter::new(ptr, Activation { snapshot }, Actions { kind }) }
}
pub(super) fn sync(
adapter: &mut SubclassingAdapter,
snapshot: &Rc<RefCell<A11ySnapshot>>,
menu: impl FnOnce() -> Menu,
focus: MenuFocus,
) {
let snap = Rc::clone(snapshot);
if let Some(events) = adapter.update_if_active(move || {
{
let mut s = snap.borrow_mut();
s.menu = menu();
s.focus = focus;
}
build_update(&snap.borrow())
}) {
events.raise();
}
}