use std::sync::{
Arc,
Mutex,
};
use accesskit_winit::Adapter;
use freya_common::AccessibilityDirtyNodes;
use freya_core::{
dom::DioxusDOM,
prelude::{
AccessibilityFocusStrategy,
AccessibilityTree,
EventMessage,
SharedAccessibilityTree,
ACCESSIBILITY_ROOT_ID,
},
types::{
AccessibilityId,
NativePlatformSender,
},
};
use freya_native_core::NodeId;
use torin::torin::Torin;
use winit::{
dpi::{
LogicalPosition,
LogicalSize,
},
event::WindowEvent,
event_loop::EventLoopProxy,
window::Window,
};
pub struct AccessKitManager {
accessibility_tree: SharedAccessibilityTree,
accessibility_adapter: Adapter,
adapter_initialized: bool,
}
impl AccessKitManager {
pub fn new(window: &Window, proxy: EventLoopProxy<EventMessage>) -> Self {
let accessibility_tree =
Arc::new(Mutex::new(AccessibilityTree::new(ACCESSIBILITY_ROOT_ID)));
let accessibility_adapter = Adapter::with_event_loop_proxy(window, proxy);
Self {
accessibility_tree,
accessibility_adapter,
adapter_initialized: false,
}
}
pub fn focused_node_id(&self) -> Option<NodeId> {
self.accessibility_tree.lock().unwrap().focused_node_id()
}
pub fn process_accessibility_event(&mut self, event: &WindowEvent, window: &Window) {
self.accessibility_adapter.process_event(window, event)
}
pub fn init_accessibility(
&mut self,
rdom: &DioxusDOM,
layout: &Torin<NodeId>,
dirty_nodes: &mut AccessibilityDirtyNodes,
) {
let tree = self
.accessibility_tree
.lock()
.unwrap()
.init(rdom, layout, dirty_nodes);
self.accessibility_adapter.update_if_active(|| {
self.adapter_initialized = true;
tree
});
}
pub fn process_updates(
&mut self,
rdom: &DioxusDOM,
layout: &Torin<NodeId>,
platform_sender: &NativePlatformSender,
window: &Window,
dirty_nodes: &mut AccessibilityDirtyNodes,
) {
let (tree, node_id) =
self.accessibility_tree
.lock()
.unwrap()
.process_updates(rdom, layout, dirty_nodes);
platform_sender.send_modify(|state| {
state.focused_id = tree.focus;
});
self.update_ime_position(node_id, window, layout);
if self.adapter_initialized {
self.accessibility_adapter.update_if_active(|| tree);
}
}
pub fn focus_next_node(
&mut self,
rdom: &DioxusDOM,
direction: AccessibilityFocusStrategy,
platform_sender: &NativePlatformSender,
window: &Window,
layout: &Torin<NodeId>,
) {
let (tree, node_id) = self
.accessibility_tree
.lock()
.unwrap()
.set_focus_on_next_node(direction, rdom);
platform_sender.send_modify(|state| {
state.focused_id = tree.focus;
});
self.update_ime_position(node_id, window, layout);
if self.adapter_initialized {
self.accessibility_adapter.update_if_active(|| tree);
}
}
pub fn focus_node(
&mut self,
id: AccessibilityId,
platform_sender: &NativePlatformSender,
window: &Window,
layout: &Torin<NodeId>,
) {
let res = self
.accessibility_tree
.lock()
.unwrap()
.set_focus_with_update(id);
if let Some((tree, node_id)) = res {
platform_sender.send_modify(|state| {
state.focused_id = tree.focus;
});
self.update_ime_position(node_id, window, layout);
if self.adapter_initialized {
self.accessibility_adapter.update_if_active(|| tree);
}
}
}
fn update_ime_position(&self, node_id: NodeId, window: &Window, layout: &Torin<NodeId>) {
let layout_node = layout.get(node_id);
if let Some(layout_node) = layout_node {
let area = layout_node.visible_area();
return window.set_ime_cursor_area(
LogicalPosition::new(area.min_x(), area.min_y()),
LogicalSize::new(area.width(), area.height()),
);
}
window.set_ime_cursor_area(
window.inner_position().unwrap_or_default(),
LogicalSize::<u32>::default(),
);
}
}