fltk_accesskit/
lib.rs

1#![doc = include_str!("../README.md")]
2
3use accesskit::{NodeClassSet, NodeId, Tree, TreeUpdate};
4use fltk::{enums::*, prelude::*, *};
5use std::num::NonZeroU128;
6
7pub mod accessible;
8mod fltk_adapter;
9mod platform_adapter;
10
11pub use accessible::Accessible;
12pub use fltk_adapter::{ActionRequestEvent, Adapter};
13
14pub struct AccessibilityContext {
15    adapter: Adapter,
16    root: window::Window,
17    widgets: Vec<Box<dyn Accessible>>,
18    nc: NodeClassSet,
19}
20
21impl AccessibilityContext {
22    pub fn new(root: window::Window, mut widgets: Vec<Box<dyn Accessible>>) -> Self {
23        let mut nc = NodeClassSet::new();
24        let mut wids = vec![];
25        for w in &widgets {
26            let n = w.make_node(&mut nc, &[]);
27            wids.push(n);
28        }
29        let (win_id, win_node) =
30            root.make_node(&mut nc, &wids.iter().map(|x| x.0).collect::<Vec<_>>());
31        wids.push((win_id, win_node));
32        let adapter = {
33            Adapter::new(&root, move || TreeUpdate {
34                nodes: wids,
35                tree: Some(Tree::new(win_id)),
36                focus: if let Some(focused) = app::focus() {
37                    let focused = focused.as_widget_ptr() as usize as u128;
38                    Some(NodeId(unsafe { NonZeroU128::new_unchecked(focused) }))
39                } else {
40                    None
41                },
42            })
43        };
44        widgets.push(Box::new(root.clone()));
45        Self {
46            adapter,
47            root,
48            widgets,
49            nc,
50        }
51    }
52}
53
54pub trait AccessibleApp {
55    fn run_with_accessibility(&self, ac: AccessibilityContext) -> Result<(), FltkError>;
56}
57
58impl AccessibleApp for app::App {
59    fn run_with_accessibility(&self, mut ac: AccessibilityContext) -> Result<(), FltkError> {
60        ac.root.handle({
61            let adapter = ac.adapter.clone();
62            move |w, ev| {
63                let adapter = adapter.clone();
64                match ev {
65                    Event::KeyUp => {
66                        // if app::event_key() == Key::Tab {
67                        let mut wids = vec![];
68                        for w in &ac.widgets {
69                            let n = w.make_node(&mut ac.nc, &[]);
70                            wids.push(n);
71                        }
72                        let (win_id, win_node) =
73                            w.make_node(&mut ac.nc, &wids.iter().map(|x| x.0).collect::<Vec<_>>());
74                        wids.push((win_id, win_node));
75                        if let Some(focused) = app::focus() {
76                            let focused = focused.as_widget_ptr() as usize as u128;
77                            let node_id = NodeId(unsafe { NonZeroU128::new_unchecked(focused) });
78                            adapter.update_if_active(|| TreeUpdate {
79                                nodes: wids,
80                                tree: None,
81                                focus: Some(node_id),
82                            });
83                        }
84                        // }
85                        false
86                    }
87                    _ => false,
88                }
89            }
90        });
91        self.run()
92    }
93}