Skip to main content

ansiq_runtime/
focus.rs

1use ansiq_core::Node;
2
3#[derive(Debug, Default)]
4pub struct FocusState {
5    order: Vec<usize>,
6    current: Option<usize>,
7    scope_key: Option<String>,
8}
9
10impl FocusState {
11    pub fn sync_from_tree<Message>(&mut self, tree: &Node<Message>) {
12        let mut next_order = Vec::new();
13        if let Some(scope_key) = self.scope_key.as_deref() {
14            if let Some(scope_root) = find_scope_root(tree, scope_key) {
15                collect_focusable_ids(scope_root, &mut next_order);
16            } else {
17                collect_focusable_ids(tree, &mut next_order);
18            }
19        } else {
20            collect_focusable_ids(tree, &mut next_order);
21        }
22
23        self.current = if next_order.is_empty() {
24            None
25        } else if self
26            .current
27            .is_some_and(|current| next_order.contains(&current))
28        {
29            self.current
30        } else {
31            next_order.first().copied()
32        };
33        self.order = next_order;
34    }
35
36    pub fn current(&self) -> Option<usize> {
37        self.current
38    }
39
40    pub fn set_current(&mut self, current: Option<usize>) {
41        self.current = current;
42    }
43
44    pub fn set_scope_key(&mut self, scope_key: Option<String>) {
45        self.scope_key = scope_key;
46    }
47
48    pub fn scope_key(&self) -> Option<&str> {
49        self.scope_key.as_deref()
50    }
51
52    pub fn next(&mut self) {
53        self.step(1);
54    }
55
56    pub fn prev(&mut self) {
57        self.step_back();
58    }
59
60    fn step(&mut self, amount: usize) {
61        if self.order.is_empty() {
62            self.current = None;
63            return;
64        }
65
66        let index = self
67            .current
68            .and_then(|current| self.order.iter().position(|id| *id == current))
69            .unwrap_or(0);
70        let next = (index + amount) % self.order.len();
71        self.current = Some(self.order[next]);
72    }
73
74    fn step_back(&mut self) {
75        if self.order.is_empty() {
76            self.current = None;
77            return;
78        }
79
80        let index = self
81            .current
82            .and_then(|current| self.order.iter().position(|id| *id == current))
83            .unwrap_or(0);
84        let next = if index == 0 {
85            self.order.len() - 1
86        } else {
87            index - 1
88        };
89        self.current = Some(self.order[next]);
90    }
91}
92
93fn collect_focusable_ids<Message>(node: &Node<Message>, output: &mut Vec<usize>) {
94    if node.element.focusable {
95        output.push(node.id);
96    }
97
98    for child in &node.children {
99        collect_focusable_ids(child, output);
100    }
101}
102
103fn find_scope_root<'a, Message>(
104    node: &'a Node<Message>,
105    scope_key: &str,
106) -> Option<&'a Node<Message>> {
107    if node.element.continuity_key() == Some(scope_key) {
108        return Some(node);
109    }
110
111    for child in &node.children {
112        if let Some(found) = find_scope_root(child, scope_key) {
113            return Some(found);
114        }
115    }
116
117    None
118}