i_slint_core/
accessibility.rs1use crate::{
7 SharedString,
8 item_tree::ItemTreeVTable,
9 items::{ItemRc, TextInput},
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 Id,
28 ItemCount,
29 ItemIndex,
30 ItemSelectable,
31 ItemSelected,
32 Label,
33 PlaceholderText,
34 ReadOnly,
35 Value,
36 ValueMaximum,
37 ValueMinimum,
38 ValueStep,
39}
40
41#[repr(u32)]
43#[derive(PartialEq, Clone)]
44pub enum AccessibilityAction {
45 Default,
46 Decrement,
47 Increment,
48 Expand,
49 ReplaceSelectedText(SharedString),
51 SetValue(SharedString),
52}
53
54bitflags! {
55 #[repr(transparent)]
57 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
58 pub struct SupportedAccessibilityAction: u32 {
59 const Default = 1;
60 const Decrement = 1 << 1;
61 const Increment = 1 << 2;
62 const Expand = 1 << 3;
63 const ReplaceSelectedText = 1 << 4;
64 const SetValue = 1 << 5;
65 }
66}
67
68pub fn accessible_descendents(root_item: &ItemRc) -> impl Iterator<Item = ItemRc> {
73 fn try_candidate_or_find_next_accessible_descendent(
74 candidate: ItemRc,
75 descendent_candidates: &mut Vec<ItemRc>,
76 ) -> Option<ItemRc> {
77 if candidate.is_accessible() {
78 return Some(candidate);
79 }
80
81 candidate.first_child().and_then(|child| {
82 if let Some(next) = child.next_sibling() {
83 descendent_candidates.push(next);
84 }
85 try_candidate_or_find_next_accessible_descendent(child, descendent_candidates)
86 })
87 }
88
89 let mut descendent_candidates = Vec::new();
92 if let Some(child) = root_item.first_child() {
93 descendent_candidates.push(child);
94 }
95
96 core::iter::from_fn(move || {
97 loop {
98 let candidate = descendent_candidates.pop()?;
99
100 if let Some(next_candidate) = candidate.next_sibling() {
101 descendent_candidates.push(next_candidate);
102 }
103
104 if let Some(descendent) = try_candidate_or_find_next_accessible_descendent(
105 candidate,
106 &mut descendent_candidates,
107 ) {
108 return Some(descendent);
109 }
110 }
111 })
112}
113
114pub fn find_text_input(item: &ItemRc) -> Option<VRcMapped<ItemTreeVTable, TextInput>> {
116 fn try_candidate_or_find_next_descendent(
117 candidate: ItemRc,
118 descendent_candidates: &mut Vec<ItemRc>,
119 ) -> Option<VRcMapped<ItemTreeVTable, TextInput>> {
120 if let Some(input) = candidate.downcast::<TextInput>() {
121 return Some(input);
122 }
123
124 candidate.first_child().and_then(|child| {
125 if let Some(next) = child.next_sibling() {
126 descendent_candidates.push(next);
127 }
128 try_candidate_or_find_next_descendent(child, descendent_candidates)
129 })
130 }
131
132 let mut descendent_candidates = vec![item.clone()];
133
134 loop {
135 let candidate = descendent_candidates.pop()?;
136
137 if let Some(next_candidate) = candidate.next_sibling() {
138 descendent_candidates.push(next_candidate);
139 }
140
141 if let Some(input) =
142 try_candidate_or_find_next_descendent(candidate, &mut descendent_candidates)
143 {
144 return Some(input);
145 }
146 }
147}