i_slint_core/
accessibility.rs1use crate::{
7 item_tree::ItemTreeVTable,
8 items::{ItemRc, TextInput},
9 SharedString,
10};
11use alloc::{vec, vec::Vec};
12use bitflags::bitflags;
13use vtable::VRcMapped;
14
15#[repr(u32)]
17#[derive(PartialEq, Eq, Copy, Clone, strum::Display)]
18#[strum(serialize_all = "kebab-case")]
19pub enum AccessibleStringProperty {
20 Checkable,
21 Checked,
22 DelegateFocus,
23 Description,
24 Enabled,
25 Expandable,
26 Expanded,
27 ItemCount,
28 ItemIndex,
29 ItemSelectable,
30 ItemSelected,
31 Label,
32 PlaceholderText,
33 ReadOnly,
34 Value,
35 ValueMaximum,
36 ValueMinimum,
37 ValueStep,
38}
39
40#[repr(u32)]
42#[derive(PartialEq, Clone)]
43pub enum AccessibilityAction {
44 Default,
45 Decrement,
46 Increment,
47 Expand,
48 ReplaceSelectedText(SharedString),
50 SetValue(SharedString),
51}
52
53bitflags! {
54 #[repr(transparent)]
56 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
57 pub struct SupportedAccessibilityAction: u32 {
58 const Default = 1;
59 const Decrement = 1 << 1;
60 const Increment = 1 << 2;
61 const Expand = 1 << 3;
62 const ReplaceSelectedText = 1 << 4;
63 const SetValue = 1 << 5;
64 }
65}
66
67pub fn accessible_descendents(root_item: &ItemRc) -> impl Iterator<Item = ItemRc> {
72 fn try_candidate_or_find_next_accessible_descendent(
73 candidate: ItemRc,
74 descendent_candidates: &mut Vec<ItemRc>,
75 ) -> Option<ItemRc> {
76 if candidate.is_accessible() {
77 return Some(candidate);
78 }
79
80 candidate.first_child().and_then(|child| {
81 if let Some(next) = child.next_sibling() {
82 descendent_candidates.push(next);
83 }
84 try_candidate_or_find_next_accessible_descendent(child, descendent_candidates)
85 })
86 }
87
88 let mut descendent_candidates = Vec::new();
91 if let Some(child) = root_item.first_child() {
92 descendent_candidates.push(child);
93 }
94
95 core::iter::from_fn(move || loop {
96 let candidate = descendent_candidates.pop()?;
97
98 if let Some(next_candidate) = candidate.next_sibling() {
99 descendent_candidates.push(next_candidate);
100 }
101
102 if let Some(descendent) =
103 try_candidate_or_find_next_accessible_descendent(candidate, &mut descendent_candidates)
104 {
105 return Some(descendent);
106 }
107 })
108}
109
110pub fn find_text_input(item: &ItemRc) -> Option<VRcMapped<ItemTreeVTable, TextInput>> {
112 fn try_candidate_or_find_next_descendent(
113 candidate: ItemRc,
114 descendent_candidates: &mut Vec<ItemRc>,
115 ) -> Option<VRcMapped<ItemTreeVTable, TextInput>> {
116 if let Some(input) = candidate.downcast::<TextInput>() {
117 return Some(input);
118 }
119
120 candidate.first_child().and_then(|child| {
121 if let Some(next) = child.next_sibling() {
122 descendent_candidates.push(next);
123 }
124 try_candidate_or_find_next_descendent(child, descendent_candidates)
125 })
126 }
127
128 let mut descendent_candidates = vec![item.clone()];
129
130 loop {
131 let candidate = descendent_candidates.pop()?;
132
133 if let Some(next_candidate) = candidate.next_sibling() {
134 descendent_candidates.push(next_candidate);
135 }
136
137 if let Some(input) =
138 try_candidate_or_find_next_descendent(candidate, &mut descendent_candidates)
139 {
140 return Some(input);
141 }
142 }
143}