fret_ui/tree/ui_tree_mutation/
focus.rs1use super::super::*;
2
3impl<H: UiHost> UiTree<H> {
4 pub fn children(&self, parent: NodeId) -> Vec<NodeId> {
5 self.nodes
6 .get(parent)
7 .map(|n| n.children.clone())
8 .unwrap_or_default()
9 }
10
11 pub(crate) fn children_ref(&self, parent: NodeId) -> &[NodeId] {
12 self.nodes
13 .get(parent)
14 .map(|n| n.children.as_slice())
15 .unwrap_or(&[])
16 }
17
18 pub(crate) fn repair_parent_pointers_from_layer_roots(&mut self) -> u32 {
28 let roots = self.all_layer_roots();
29 if roots.is_empty() {
30 return 0;
31 }
32
33 let mut repaired: u32 = 0;
34 let mut visited: HashSet<NodeId> = HashSet::new();
35 let mut stack: Vec<(Option<NodeId>, NodeId)> = Vec::with_capacity(roots.len());
36 for root in roots {
37 stack.push((None, root));
38 }
39
40 while let Some((expected_parent, node)) = stack.pop() {
41 if !visited.insert(node) {
42 continue;
43 }
44
45 let (current_parent, children) = match self.nodes.get(node) {
46 Some(n) => (n.parent, n.children.clone()),
47 None => continue,
48 };
49
50 if current_parent != expected_parent
51 && let Some(n) = self.nodes.get_mut(node)
52 {
53 n.parent = expected_parent;
54 repaired = repaired.saturating_add(1);
55 }
56
57 for child in children {
58 stack.push((Some(node), child));
59 }
60 }
61
62 repaired
63 }
64
65 pub fn node_parent(&self, node: NodeId) -> Option<NodeId> {
66 self.nodes.get(node).and_then(|n| n.parent)
67 }
68
69 pub fn debug_node_measured_size(&self, node: NodeId) -> Option<Size> {
70 self.nodes.get(node).map(|n| n.measured_size)
71 }
72
73 pub fn debug_declarative_instance_kind(
76 &self,
77 app: &mut H,
78 window: AppWindowId,
79 node: NodeId,
80 ) -> Option<&'static str> {
81 crate::declarative::element_record_for_node(app, window, node)
82 .map(|record| record.instance.kind_name())
83 }
84
85 pub fn first_focusable_ancestor_including_declarative(
86 &self,
87 app: &mut H,
88 window: AppWindowId,
89 start: NodeId,
90 ) -> Option<NodeId> {
91 let mut node = Some(start);
92 while let Some(id) = node {
93 let focusable = if let Some(record) =
94 crate::declarative::element_record_for_node(app, window, id)
95 {
96 match &record.instance {
97 crate::declarative::ElementInstance::TextInput(_) => true,
98 crate::declarative::ElementInstance::TextArea(_) => true,
99 crate::declarative::ElementInstance::TextInputRegion(_) => true,
100 crate::declarative::ElementInstance::Pressable(p) => p.enabled && p.focusable,
101 _ => false,
102 }
103 } else {
104 self.nodes
105 .get(id)
106 .and_then(|n| n.widget.as_ref())
107 .is_some_and(|w| w.is_focusable())
108 };
109
110 if focusable {
111 return Some(id);
112 }
113
114 node = self.nodes.get(id).and_then(|n| n.parent);
115 }
116 None
117 }
118
119 pub fn first_focusable_descendant(&self, root: NodeId) -> Option<NodeId> {
120 let mut stack = vec![root];
121 while let Some(id) = stack.pop() {
122 let focusable = self
123 .nodes
124 .get(id)
125 .and_then(|n| n.widget.as_ref())
126 .is_some_and(|w| w.is_focusable());
127 if focusable {
128 return Some(id);
129 }
130
131 if let Some(node) = self.nodes.get(id) {
132 let traverse_children = node
133 .widget
134 .as_ref()
135 .map(|w| w.focus_traversal_children())
136 .unwrap_or(true);
137 if traverse_children {
138 for &child in node.children.iter().rev() {
139 stack.push(child);
140 }
141 }
142 }
143 }
144 None
145 }
146
147 pub fn first_focusable_descendant_including_declarative(
155 &self,
156 app: &mut H,
157 window: AppWindowId,
158 root: NodeId,
159 ) -> Option<NodeId> {
160 let mut stack = vec![root];
161 while let Some(id) = stack.pop() {
162 let (focusable, traverse_children) = if let Some(record) =
163 crate::declarative::element_record_for_node(app, window, id)
164 {
165 let focusable = match &record.instance {
166 crate::declarative::ElementInstance::TextInput(_) => true,
167 crate::declarative::ElementInstance::TextArea(_) => true,
168 crate::declarative::ElementInstance::TextInputRegion(_) => true,
169 crate::declarative::ElementInstance::Pressable(p) => p.enabled && p.focusable,
170 crate::declarative::ElementInstance::Semantics(p) => {
171 p.focusable && !p.disabled && !p.hidden
172 }
173 _ => false,
174 };
175 let traverse_children = match &record.instance {
176 crate::declarative::ElementInstance::Pressable(p) => p.enabled,
177 crate::declarative::ElementInstance::InteractivityGate(p) => {
178 p.present && p.interactive
179 }
180 crate::declarative::ElementInstance::Spinner(_) => false,
181 _ => true,
182 };
183 (focusable, traverse_children)
184 } else {
185 let traverse_children = self
186 .nodes
187 .get(id)
188 .and_then(|n| n.widget.as_ref())
189 .map(|w| w.focus_traversal_children())
190 .unwrap_or(true);
191 let focusable = self
192 .nodes
193 .get(id)
194 .and_then(|n| n.widget.as_ref())
195 .is_some_and(|w| w.is_focusable());
196 (focusable, traverse_children)
197 };
198
199 if focusable {
200 return Some(id);
201 }
202
203 if traverse_children && let Some(node) = self.nodes.get(id) {
204 for &child in node.children.iter().rev() {
205 stack.push(child);
206 }
207 }
208 }
209 None
210 }
211
212 pub fn first_focusable_descendant_including_declarative_present_only(
218 &self,
219 app: &mut H,
220 window: AppWindowId,
221 root: NodeId,
222 ) -> Option<NodeId> {
223 let mut stack = vec![root];
224 while let Some(id) = stack.pop() {
225 let (focusable, traverse_children) = if let Some(record) =
226 crate::declarative::element_record_for_node(app, window, id)
227 {
228 let focusable = match &record.instance {
229 crate::declarative::ElementInstance::TextInput(_) => true,
230 crate::declarative::ElementInstance::TextArea(_) => true,
231 crate::declarative::ElementInstance::TextInputRegion(_) => true,
232 crate::declarative::ElementInstance::Pressable(p) => p.enabled && p.focusable,
233 crate::declarative::ElementInstance::Semantics(p) => {
234 p.focusable && !p.disabled && !p.hidden
235 }
236 _ => false,
237 };
238 let traverse_children = match &record.instance {
239 crate::declarative::ElementInstance::Pressable(p) => p.enabled,
240 crate::declarative::ElementInstance::InteractivityGate(p) => p.present,
241 crate::declarative::ElementInstance::Spinner(_) => false,
242 _ => true,
243 };
244 (focusable, traverse_children)
245 } else {
246 let traverse_children = self
247 .nodes
248 .get(id)
249 .and_then(|n| n.widget.as_ref())
250 .map(|w| w.focus_traversal_children())
251 .unwrap_or(true);
252 let focusable = self
253 .nodes
254 .get(id)
255 .and_then(|n| n.widget.as_ref())
256 .is_some_and(|w| w.is_focusable());
257 (focusable, traverse_children)
258 };
259
260 if focusable {
261 return Some(id);
262 }
263
264 if traverse_children && let Some(node) = self.nodes.get(id) {
265 for &child in node.children.iter().rev() {
266 stack.push(child);
267 }
268 }
269 }
270 None
271 }
272}