1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
use accesskit_winit::Adapter;
use freya_core::{
    accessibility::{
        AccessibilityDirtyNodes,
        AccessibilityTree,
        ACCESSIBILITY_ROOT_ID,
    },
    dom::DioxusDOM,
    event_loop_messages::EventLoopMessage,
    states::AccessibilityNodeState,
    types::NativePlatformSender,
};
use freya_native_core::{
    prelude::NodeImmutable,
    NodeId,
};
use torin::torin::Torin;
use winit::{
    dpi::{
        LogicalPosition,
        LogicalSize,
    },
    event::WindowEvent,
    event_loop::EventLoopProxy,
    window::Window,
};

/// Manages the accessibility integration of Accesskit and Winit.
pub struct WinitAcessibilityTree {
    accessibility_tree: AccessibilityTree,
    accessibility_adapter: Adapter,
    adapter_initialized: bool,
}

impl WinitAcessibilityTree {
    pub fn new(window: &Window, proxy: EventLoopProxy<EventLoopMessage>) -> Self {
        let accessibility_tree = 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.focused_node_id()
    }

    /// Process an accessibility window event
    pub fn process_accessibility_event(&mut self, event: &WindowEvent, window: &Window) {
        self.accessibility_adapter.process_event(window, event)
    }

    /// Initialize the Accessibility Tree and update the adapter
    pub fn init_accessibility(
        &mut self,
        rdom: &DioxusDOM,
        layout: &Torin<NodeId>,
        dirty_nodes: &mut AccessibilityDirtyNodes,
    ) {
        let tree = self.accessibility_tree.init(rdom, layout, dirty_nodes);
        self.accessibility_adapter.update_if_active(|| {
            self.adapter_initialized = true;
            tree
        });
    }

    /// Process any pending accessibility tree update and update the adapter
    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
            .process_updates(rdom, layout, dirty_nodes);

        // Notify the components
        platform_sender.send_modify(|state| {
            state.focused_accessibility_id = tree.focus;
            let node_ref = rdom.get(node_id).unwrap();
            let node_accessibility = node_ref.get::<AccessibilityNodeState>().unwrap();
            let layout_node = layout.get(node_id).unwrap();
            state.focused_accessibility_node =
                AccessibilityTree::create_node(&node_ref, layout_node, &node_accessibility)
        });

        // Update the Window IME Position
        let layout_node = layout.get(node_id);
        if let Some(layout_node) = layout_node {
            let area = layout_node.visible_area();
            window.set_ime_cursor_area(
                LogicalPosition::new(area.min_x(), area.min_y()),
                LogicalSize::new(area.width(), area.height()),
            );
        } else {
            window.set_ime_cursor_area(
                window.inner_position().unwrap_or_default(),
                LogicalSize::<u32>::default(),
            );
        }

        if self.adapter_initialized {
            // Update the Adapter
            self.accessibility_adapter.update_if_active(|| tree);
        }
    }
}