tessera_foundation/modifier/
semantics.rs1use tessera_ui::{
9 AccessibilityActionHandler, AccessibilityNode, SemanticsModifierNode,
10 accesskit::{Action, Live, Role, Toggled},
11 modifier::ModifierCapabilityExt as _,
12};
13
14use super::layout::Padding;
15
16#[derive(Clone, Default)]
18pub struct SemanticsArgs {
19 pub role: Option<Role>,
21 pub label: Option<String>,
23 pub description: Option<String>,
25 pub value: Option<String>,
27 pub numeric_value: Option<f64>,
29 pub numeric_range: Option<(f64, f64)>,
31 pub focusable: bool,
33 pub focused: bool,
35 pub toggled: Option<Toggled>,
37 pub invalid: Option<tessera_ui::accesskit::Invalid>,
39 pub selected: Option<bool>,
41 pub expanded: Option<bool>,
43 pub has_popup: Option<tessera_ui::accesskit::HasPopup>,
45 pub disabled: bool,
47 pub hidden: bool,
49 pub modal: bool,
51 pub actions: Vec<Action>,
53 pub test_tag: Option<String>,
55 pub bounds_padding: Option<Padding>,
57 pub merge_descendants: bool,
59 pub state_description: Option<String>,
61 pub role_description: Option<String>,
63 pub tooltip: Option<String>,
65 pub live: Option<Live>,
67 pub heading_level: Option<u32>,
69 pub scroll_x: Option<(f64, f64, f64)>,
71 pub scroll_y: Option<(f64, f64, f64)>,
73 pub numeric_value_step: Option<f64>,
75 pub numeric_value_jump: Option<f64>,
77 pub collection_info: Option<(usize, usize, bool)>,
79 pub collection_item_info: Option<(usize, usize, usize, usize, bool)>,
82}
83
84impl SemanticsArgs {
85 pub fn clear() -> Self {
87 Self {
88 merge_descendants: false,
89 ..Default::default()
90 }
91 }
92}
93
94struct SemanticsModifierNodeImpl {
95 args: SemanticsArgs,
96}
97
98impl SemanticsModifierNode for SemanticsModifierNodeImpl {
99 fn apply(
100 &self,
101 accessibility: &mut AccessibilityNode,
102 _action_handler: &mut Option<AccessibilityActionHandler>,
103 ) {
104 let SemanticsArgs {
105 role,
106 label,
107 description,
108 value,
109 numeric_value,
110 numeric_range,
111 focusable,
112 focused,
113 toggled,
114 invalid,
115 selected,
116 expanded,
117 has_popup,
118 disabled,
119 hidden,
120 modal,
121 actions,
122 test_tag,
123 bounds_padding,
124 merge_descendants,
125 state_description,
126 role_description,
127 tooltip,
128 live,
129 heading_level,
130 scroll_x,
131 scroll_y,
132 numeric_value_step,
133 numeric_value_jump,
134 collection_info,
135 collection_item_info,
136 } = &self.args;
137
138 accessibility.role = *role;
139 accessibility.label = label.clone();
140 accessibility.description = description.clone();
141 accessibility.value = value.clone();
142 accessibility.numeric_value = *numeric_value;
143 accessibility.min_numeric_value = numeric_range.map(|(min, _)| min);
144 accessibility.max_numeric_value = numeric_range.map(|(_, max)| max);
145 accessibility.focusable = *focusable;
146 accessibility.focused = *focused;
147 accessibility.toggled = *toggled;
148 accessibility.invalid = *invalid;
149 accessibility.selected = *selected;
150 accessibility.expanded = *expanded;
151 accessibility.has_popup = *has_popup;
152 accessibility.disabled = *disabled;
153 accessibility.hidden = *hidden;
154 accessibility.modal = *modal;
155 accessibility.actions = actions.clone();
156 accessibility.key = test_tag.clone();
157 accessibility.merge_descendants = *merge_descendants;
158 accessibility.state_description = state_description.clone();
159 accessibility.role_description = role_description.clone();
160 accessibility.tooltip = tooltip.clone();
161 accessibility.live = *live;
162 accessibility.heading_level = *heading_level;
163 accessibility.scroll_x = *scroll_x;
164 accessibility.scroll_y = *scroll_y;
165 accessibility.numeric_value_step = *numeric_value_step;
166 accessibility.numeric_value_jump = *numeric_value_jump;
167 accessibility.collection_info = *collection_info;
168 accessibility.collection_item_info = *collection_item_info;
169 accessibility.bounds_padding =
170 bounds_padding.map(|padding| tessera_ui::accessibility::AccessibilityPadding {
171 left: padding.left.into(),
172 top: padding.top.into(),
173 right: padding.right.into(),
174 bottom: padding.bottom.into(),
175 });
176 }
177}
178
179pub(crate) fn apply_semantics_modifier(
180 base: tessera_ui::Modifier,
181 args: SemanticsArgs,
182) -> tessera_ui::Modifier {
183 base.push_semantics(SemanticsModifierNodeImpl { args })
184}