1use crate::instance::Instance;
11use i_slint_core::SharedString;
12use i_slint_core::accessibility::{
13 AccessibilityAction, AccessibleStringProperty, SupportedAccessibilityAction,
14};
15use i_slint_core::item_tree::{
16 IndexRange, ItemTree, ItemTreeNode, ItemTreeVTable, ItemVisitorVTable, ItemWeak,
17 TraversalOrder, VisitChildrenResult,
18};
19use i_slint_core::items::{AccessibleRole, ItemVTable};
20use i_slint_core::layout::{LayoutInfo, Orientation};
21use i_slint_core::lengths::LogicalRect;
22use i_slint_core::slice::Slice;
23use i_slint_core::window::WindowAdapterRc;
24use std::pin::Pin;
25use vtable::{VRef, VRefMut, VWeak};
26
27i_slint_core::ItemTreeVTable_static!(static INTERPRETER_INSTANCE_VT for Instance);
28
29pub(crate) fn sub_component_path_of(
33 target: &crate::instance::SubComponentInstance,
34 parent_root: &Instance,
35) -> Vec<i_slint_compiler::llr::SubComponentInstanceIdx> {
36 fn walk(
37 current: &crate::instance::SubComponentInstance,
38 target_ptr: *const crate::instance::SubComponentInstance,
39 path: &mut Vec<i_slint_compiler::llr::SubComponentInstanceIdx>,
40 ) -> bool {
41 if std::ptr::eq(current as *const _, target_ptr) {
42 return true;
43 }
44 for (idx, nested) in current.sub_components.iter().enumerate() {
45 path.push(idx.into());
46 if walk(nested, target_ptr, path) {
47 return true;
48 }
49 path.pop();
50 }
51 false
52 }
53 let mut path = Vec::new();
54 walk(&parent_root.root_sub_component, target as *const _, &mut path);
55 path
56}
57
58impl i_slint_core::item_tree::ItemTree for Instance {
59 fn visit_children_item(
60 self: Pin<&Self>,
61 index: isize,
62 order: TraversalOrder,
63 visitor: VRefMut<'_, ItemVisitorVTable>,
64 ) -> VisitChildrenResult {
65 let this = self.get_ref();
66 let weak = this.self_weak.get().unwrap().clone();
67 if index >= 0 && this.z_sort_table.get(index as usize).is_some_and(|e| e.is_some()) {
68 i_slint_core::item_tree::visit_item_tree_z_sorted(
69 &vtable::VRc::into_dyn(weak.upgrade().unwrap()),
70 &this.tree_nodes[..],
71 index,
72 order,
73 visitor,
74 &mut |order, visitor, dyn_index| {
75 self.visit_dynamic_children(dyn_index, order, visitor)
76 },
77 &mut |push| self.collect_z_sorted_children(index, push),
78 )
79 } else {
80 i_slint_core::item_tree::visit_item_tree(
81 &vtable::VRc::into_dyn(weak.upgrade().unwrap()),
82 &this.tree_nodes[..],
83 index,
84 order,
85 visitor,
86 &mut |order, visitor, dyn_index| {
87 self.visit_dynamic_children(dyn_index, order, visitor)
88 },
89 )
90 }
91 }
92
93 fn get_item_ref(self: Pin<&Self>, index: u32) -> Pin<VRef<'_, ItemVTable>> {
94 let this = self.get_ref();
98 let entry = this
99 .item_table
100 .get(index as usize)
101 .and_then(Option::as_ref)
102 .expect("get_item_ref: tree index is not a static item");
103 let mut current: &crate::instance::SubComponentInstance = &this.root_sub_component;
107 for &sub_idx in entry.0.iter() {
108 current = ¤t.sub_components[sub_idx];
109 }
110 Pin::as_ref(¤t.items[entry.1]).as_item_ref()
111 }
112
113 fn ensure_instantiated(self: Pin<&Self>) -> bool {
114 self.get_ref().ensure_instantiated()
115 }
116
117 fn get_subtree_range(self: Pin<&Self>, index: u32) -> IndexRange {
118 let Some((sub, rep_idx)) = self.get_ref().dynamic_at(index) else {
119 return IndexRange { start: 0, end: 0 };
120 };
121 if let Some(cc) = crate::instance::component_container_item(&sub, rep_idx) {
122 return cc.subtree_range();
123 }
124 let repeater = &sub.repeaters[rep_idx];
125 repeater.track_instance_changes();
126 let range = repeater.range();
127 IndexRange { start: range.start, end: range.end }
128 }
129
130 fn get_subtree(
131 self: Pin<&Self>,
132 index: u32,
133 subindex: usize,
134 result: &mut VWeak<ItemTreeVTable, vtable::Dyn>,
135 ) {
136 let Some((sub, rep_idx)) = self.get_ref().dynamic_at(index) else {
137 return;
138 };
139 if let Some(cc) = crate::instance::component_container_item(&sub, rep_idx) {
140 if subindex == 0 {
141 *result = cc.subtree_component();
142 }
143 return;
144 }
145 let repeater = &sub.repeaters[rep_idx];
146 if let Some(instance) = repeater.instance_at(subindex) {
147 *result = vtable::VRc::downgrade(&vtable::VRc::into_dyn(instance));
148 }
149 }
150
151 fn get_item_tree(self: Pin<&Self>) -> Slice<'_, ItemTreeNode> {
152 Slice::from(&*self.get_ref().tree_nodes)
153 }
154
155 fn parent_node(self: Pin<&Self>, result: &mut ItemWeak) {
156 let this = self.get_ref();
160 if let Some((outer_weak, outer_index)) = this.embedded_in.get()
164 && let Some(outer) = outer_weak.upgrade()
165 {
166 *result = i_slint_core::items::ItemRc::new(outer, *outer_index).downgrade();
167 return;
168 }
169 let Some(parent_sub) = this.parent_instance.upgrade() else { return };
170 let Some(parent_root_vrc) = parent_sub.root.get().and_then(|w| w.upgrade()) else {
171 return;
172 };
173 let parent_dyn = vtable::VRc::into_dyn(parent_root_vrc.clone());
174 if let Some((_, repeater_idx)) = this.root_sub_component.repeated_in.get() {
175 let rep_idx = *repeater_idx;
181 let parent_path = sub_component_path_of(&parent_sub, &parent_root_vrc);
182 for (flat, entry) in parent_root_vrc.dynamic_table.iter().enumerate() {
183 if let Some((path, idx)) = entry.as_ref()
184 && path.as_ref() == parent_path.as_slice()
185 && *idx == rep_idx
186 {
187 *result = i_slint_core::items::ItemRc::new(parent_dyn, flat as u32).downgrade();
188 return;
189 }
190 }
191 } else {
192 *result = i_slint_core::items::ItemRc::new(parent_dyn, 0).downgrade();
195 }
196 }
197
198 fn embed_component(
199 self: Pin<&Self>,
200 parent: &VWeak<ItemTreeVTable>,
201 parent_item_tree_index: u32,
202 ) -> bool {
203 let this = self.get_ref();
206 this.embedded_in.set((parent.clone(), parent_item_tree_index)).is_ok()
207 }
208
209 fn subtree_index(self: Pin<&Self>) -> usize {
210 let this = self.get_ref();
213 let sc = &this.root_sub_component.compilation_unit.sub_components
214 [this.root_sub_component.sub_component_idx];
215 for (idx, prop) in sc.properties.iter_enumerated() {
216 if prop.name == "model_index"
217 && let crate::Value::Number(n) =
218 Pin::as_ref(&this.root_sub_component.properties[idx]).get()
219 {
220 return n as usize;
221 }
222 }
223 0
225 }
226
227 fn layout_info(self: Pin<&Self>, orientation: Orientation) -> LayoutInfo {
228 let this = self.get_ref();
229 let sc_idx = this.root_sub_component.sub_component_idx;
230 let cu = &this.root_sub_component.compilation_unit;
231 let sc = &cu.sub_components[sc_idx];
232 let expr = match orientation {
233 Orientation::Horizontal => sc.layout_info_h.borrow(),
234 Orientation::Vertical => sc.layout_info_v.borrow(),
235 };
236 let mut ctx = crate::eval::EvalContext::new(this.root_sub_component.clone());
237 crate::eval::eval_expression(&mut ctx, &expr).try_into().unwrap_or_default()
238 }
239
240 fn item_geometry(self: Pin<&Self>, item_index: u32) -> LogicalRect {
241 let this = self.get_ref();
247 let Some(entry) = this.item_table.get(item_index as usize).and_then(Option::as_ref) else {
248 return LogicalRect::default();
249 };
250 let mut owner_rc = this.root_sub_component.clone();
251 for &sub_idx in entry.0.iter() {
252 owner_rc = owner_rc.sub_components[sub_idx].clone();
253 }
254 let cu = owner_rc.compilation_unit.clone();
255 let sc = &cu.sub_components[owner_rc.sub_component_idx];
256 let item = &sc.items[entry.1];
257 let parent_placement = if !entry.0.is_empty() && item.index_in_tree == 0 {
270 let mut parent_rc = this.root_sub_component.clone();
271 for &sub_idx in &entry.0[..entry.0.len() - 1] {
272 parent_rc = parent_rc.sub_components[sub_idx].clone();
273 }
274 let placement = entry.0[entry.0.len() - 1];
275 let parent_sc = &cu.sub_components[parent_rc.sub_component_idx];
276 let placement_idx = parent_sc.sub_components[placement].index_in_tree as usize;
277 parent_sc
278 .geometries
279 .get(placement_idx)
280 .and_then(|g| g.clone())
281 .map(|expr| (expr, parent_rc))
282 } else {
283 None
284 };
285 let (expr_cell, ctx_owner) = if let Some(pair) = parent_placement {
286 pair
287 } else {
288 let tree_local_idx = item.index_in_tree as usize;
289 match sc.geometries.get(tree_local_idx) {
290 Some(Some(expr)) => (expr.clone(), owner_rc),
291 _ => return LogicalRect::default(),
292 }
293 };
294 let expr = expr_cell.borrow();
295 let mut ctx = crate::eval::EvalContext::new(ctx_owner);
296 let crate::Value::Struct(s) = crate::eval::eval_expression(&mut ctx, &expr) else {
297 return LogicalRect::default();
298 };
299 let as_f32 = |name: &str| -> f32 {
300 match s.get_field(name) {
301 Some(crate::Value::Number(n)) => *n as f32,
302 _ => 0.0,
303 }
304 };
305 LogicalRect::new(
306 i_slint_core::lengths::LogicalPoint::new(as_f32("x"), as_f32("y")),
307 i_slint_core::lengths::LogicalSize::new(as_f32("width"), as_f32("height")),
308 )
309 }
310
311 fn accessible_role(self: Pin<&Self>, item_index: u32) -> AccessibleRole {
312 let Some((owner, local_idx)) = resolve_accessible_item(self.get_ref(), item_index) else {
313 return AccessibleRole::default();
314 };
315 let cu = owner.compilation_unit.clone();
316 let sc = &cu.sub_components[owner.sub_component_idx];
317 let Some(expr) = sc.accessible_prop.get(&(local_idx, "Role".to_string())) else {
318 return AccessibleRole::default();
319 };
320 let mut ctx = crate::eval::EvalContext::new(owner);
321 crate::eval::eval_expression(&mut ctx, &expr.borrow()).try_into().unwrap_or_default()
322 }
323
324 fn accessible_string_property(
325 self: Pin<&Self>,
326 item_index: u32,
327 what: AccessibleStringProperty,
328 result: &mut SharedString,
329 ) -> bool {
330 let what_str = accessible_string_property_name(what);
331 for (owner, local_idx) in resolve_accessible_candidates(self.get_ref(), item_index) {
332 let cu = owner.compilation_unit.clone();
333 let sc = &cu.sub_components[owner.sub_component_idx];
334 if let Some(expr) = sc.accessible_prop.get(&(local_idx, what_str.clone())) {
335 let mut ctx = crate::eval::EvalContext::new(owner);
336 if let crate::Value::String(s) =
337 crate::eval::eval_expression(&mut ctx, &expr.borrow())
338 {
339 *result = s;
340 return true;
341 }
342 }
343 }
344 false
345 }
346
347 fn accessibility_action(self: Pin<&Self>, item_index: u32, action: &AccessibilityAction) {
348 let what = format!("Action{}", accessibility_action_name(action));
349 for (owner, local_idx) in resolve_accessible_candidates(self.get_ref(), item_index) {
350 let cu = owner.compilation_unit.clone();
351 let sc = &cu.sub_components[owner.sub_component_idx];
352 if let Some(expr) = sc.accessible_prop.get(&(local_idx, what.clone())) {
353 let args = accessibility_action_args(action);
354 let mut ctx = crate::eval::EvalContext::with_arguments(owner, args);
355 crate::eval::eval_expression(&mut ctx, &expr.borrow());
356 return;
357 }
358 }
359 }
360
361 fn supported_accessibility_actions(
362 self: Pin<&Self>,
363 item_index: u32,
364 ) -> SupportedAccessibilityAction {
365 let mut actions = SupportedAccessibilityAction::default();
366 for (owner, local_idx) in resolve_accessible_candidates(self.get_ref(), item_index) {
367 let cu = owner.compilation_unit.clone();
368 let sc = &cu.sub_components[owner.sub_component_idx];
369 for (idx, key) in sc.accessible_prop.keys() {
370 if *idx == local_idx
371 && let Some(action_name) = key.strip_prefix("Action")
372 {
373 actions |= SupportedAccessibilityAction::from_name(action_name)
374 .unwrap_or_else(|| panic!("Not an accessible action: {action_name:?}"));
375 }
376 }
377 }
378 actions
379 }
380
381 fn item_element_infos(self: Pin<&Self>, item_index: u32, result: &mut SharedString) -> bool {
382 let this = self.get_ref();
383 let Some(entry) = this.item_table.get(item_index as usize).and_then(Option::as_ref) else {
384 return false;
385 };
386 let cu = &this.root_sub_component.compilation_unit;
387 let mut owner_sc_idx = this.root_sub_component.sub_component_idx;
397 let mut local_idx = item_index;
398 for &sub_step in entry.0.iter() {
399 let owner_sc = &cu.sub_components[owner_sc_idx];
400 if let Some(info) = owner_sc.element_infos.get(&local_idx) {
401 *result = info.as_str().into();
402 return true;
403 }
404 let nested = &owner_sc.sub_components[sub_step];
405 if local_idx == nested.index_in_tree {
407 local_idx = 0;
408 } else if nested.index_of_first_child_in_tree > 0 {
409 local_idx = local_idx + 1 - nested.index_of_first_child_in_tree;
410 }
411 owner_sc_idx = nested.ty;
412 }
413 let owner_sc = &cu.sub_components[owner_sc_idx];
414 let item_local_idx = owner_sc.items[entry.1].index_in_tree;
415 if let Some(infos) = owner_sc.element_infos.get(&item_local_idx) {
416 *result = infos.as_str().into();
417 true
418 } else {
419 false
420 }
421 }
422
423 fn window_adapter(self: Pin<&Self>, do_create: bool, result: &mut Option<WindowAdapterRc>) {
424 let this = self.get_ref();
427 if let Some(adapter) = this.window_adapter.get() {
428 *result = Some(adapter.clone());
429 return;
430 }
431 let mut parent_sub = this.parent_instance.upgrade();
432 while let Some(sub) = parent_sub {
433 let Some(root_vrc) = sub.root.get().and_then(|w| w.upgrade()) else { break };
434 if let Some(adapter) = root_vrc.window_adapter.get() {
435 *result = Some(adapter.clone());
436 return;
437 }
438 parent_sub = root_vrc.parent_instance.upgrade();
439 }
440 if do_create {
441 *result = this.window_adapter_or_default();
442 }
443 }
444}
445
446fn resolve_accessible_item(
449 instance: &Instance,
450 item_index: u32,
451) -> Option<(Pin<std::rc::Rc<crate::instance::SubComponentInstance>>, u32)> {
452 let entry = instance.item_table.get(item_index as usize).and_then(Option::as_ref)?;
453 let mut owner = instance.root_sub_component.clone();
454 for &sub_idx in entry.0.iter() {
455 let next = owner.sub_components[sub_idx].clone();
456 owner = next;
457 }
458 let cu = &owner.compilation_unit;
459 let sc = &cu.sub_components[owner.sub_component_idx];
460 let local_idx = sc.items[entry.1].index_in_tree;
461 Some((owner, local_idx))
462}
463
464fn resolve_accessible_candidates(
470 instance: &Instance,
471 item_index: u32,
472) -> Vec<(Pin<std::rc::Rc<crate::instance::SubComponentInstance>>, u32)> {
473 let mut out = Vec::new();
474 let Some(entry) = instance.item_table.get(item_index as usize).and_then(Option::as_ref) else {
475 return out;
476 };
477 if !entry.0.is_empty() {
480 out.push((instance.root_sub_component.clone(), item_index));
481 }
482 let mut owner = instance.root_sub_component.clone();
484 for &sub_idx in entry.0.iter() {
485 let next = owner.sub_components[sub_idx].clone();
486 owner = next;
487 }
488 let cu = &owner.compilation_unit;
489 let sc = &cu.sub_components[owner.sub_component_idx];
490 let local_idx = sc.items[entry.1].index_in_tree;
491 out.push((owner, local_idx));
492 out
493}
494
495fn accessible_string_property_name(what: AccessibleStringProperty) -> String {
499 i_slint_compiler::generator::to_pascal_case(&what.to_string())
500}
501
502fn accessibility_action_name(action: &AccessibilityAction) -> &'static str {
503 match action {
504 AccessibilityAction::Default => "Default",
505 AccessibilityAction::Decrement => "Decrement",
506 AccessibilityAction::Increment => "Increment",
507 AccessibilityAction::Expand => "Expand",
508 AccessibilityAction::ReplaceSelectedText(_) => "ReplaceSelectedText",
509 AccessibilityAction::SetValue(_) => "SetValue",
510 AccessibilityAction::SetSelectionOffsets(..) => "SetSelectionOffsets",
511 }
512}
513
514fn accessibility_action_args(action: &AccessibilityAction) -> Vec<crate::Value> {
515 match action {
516 AccessibilityAction::ReplaceSelectedText(s) | AccessibilityAction::SetValue(s) => {
517 vec![crate::Value::String(s.clone())]
518 }
519 AccessibilityAction::SetSelectionOffsets(anchor, focus) => {
520 vec![crate::Value::Number(*anchor as f64), crate::Value::Number(*focus as f64)]
521 }
522 _ => Vec::new(),
523 }
524}