Skip to main content

vizia_core/modifiers/
accessibility.rs

1use super::internal;
2use crate::prelude::*;
3use accesskit::SortDirection;
4
5/// Modifiers for changing the accessibility properties of a view.
6pub trait AccessibilityModifiers: internal::Modifiable {
7    /// Sets the accessibility role of the view.
8    fn role(mut self, role: Role) -> Self {
9        let id = self.entity();
10
11        self.context().style.role.insert(id, role);
12
13        self.context().style.needs_access_update(id);
14
15        self
16    }
17
18    /// Sets the accessibility name of the view.
19    fn name<U: ToStringLocalized>(mut self, name: impl Res<U>) -> Self {
20        let entity = self.entity();
21        let current = self.current();
22        self.context().with_current(current, move |cx| {
23            name.set_or_bind(cx, move |cx, name| {
24                cx.style.name.insert(entity, name.get_value(cx).to_string_local(cx));
25                cx.style.needs_access_update(entity);
26            });
27        });
28
29        self
30    }
31
32    /// Sets the accessibility label relationship for the view using the ID of another view.
33    fn labeled_by(mut self, id: impl Into<String>) -> Self {
34        let entity = self.entity();
35        let id = id.into();
36
37        self.context().style.labelled_by.insert(entity, id);
38        self.context().style.needs_access_update(entity);
39
40        self
41    }
42
43    /// Sets the accessibility description relationship for the view using the ID of another view.
44    fn described_by(mut self, id: impl Into<String>) -> Self {
45        let entity = self.entity();
46        let id = id.into();
47
48        self.context().style.described_by.insert(entity, id);
49        self.context().style.needs_access_update(entity);
50
51        self
52    }
53
54    /// Sets the accessibility controls relationship for the view using the ID of another view.
55    fn controls(mut self, id: impl Into<String>) -> Self {
56        let entity = self.entity();
57        let id = id.into();
58
59        self.context().style.controls.insert(entity, id);
60        self.context().style.needs_access_update(entity);
61
62        self
63    }
64
65    /// Sets the accessibility active descendant relationship for the view.
66    fn active_descendant<U: Into<String> + Clone + 'static>(
67        mut self,
68        id: impl Res<U> + 'static,
69    ) -> Self {
70        let entity = self.entity();
71        let current = self.current();
72        self.context().with_current(current, |cx| {
73            id.set_or_bind(cx, move |cx, id| {
74                cx.style.active_descendant.insert(entity, id.get_value(cx).into());
75                cx.style.needs_access_update(entity);
76            });
77        });
78
79        self
80    }
81
82    // /// Sets the accessibility default action for the view.
83    // fn default_action_verb(mut self, action_verb: DefaultActionVerb) -> Self {
84    //     let id = self.entity();
85
86    //     self.context().style.default_action_verb.insert(id, action_verb);
87    //     self.context().style.needs_access_update(id);
88
89    //     self
90    // }
91
92    /// Sets whether the view should act as an accessibility live region.
93    fn live(mut self, live: Live) -> Self {
94        let id = self.entity();
95
96        self.context().style.live.insert(id, live);
97        self.context().style.needs_access_update(id);
98
99        self
100    }
101
102    /// Sets whether the view should be hidden from accessibility.
103    fn hidden<U: Into<bool>>(mut self, hidden: impl Res<U>) -> Self {
104        let entity = self.entity();
105        let current = self.current();
106        self.context().with_current(current, |cx| {
107            hidden.set_or_bind(cx, move |cx, hidden| {
108                cx.style.hidden.insert(entity, hidden.get_value(cx).into());
109                cx.style.needs_access_update(entity);
110            });
111        });
112
113        self
114    }
115
116    /// Sets whether the view should be announced as expanded (`true`) or collapsed (`false`).
117    fn expanded<U: Into<bool>>(mut self, expanded: impl Res<U>) -> Self {
118        let entity = self.entity();
119        let current = self.current();
120        self.context().with_current(current, |cx| {
121            expanded.set_or_bind(cx, move |cx, expanded| {
122                cx.style.expanded.insert(entity, expanded.get_value(cx).into());
123                cx.style.needs_access_update(entity);
124            });
125        });
126
127        self
128    }
129
130    /// Sets whether the view should be announced as selected (`true`) or not selected (`false`).
131    fn accessibility_selected<U: Into<bool>>(mut self, selected: impl Res<U>) -> Self {
132        let entity = self.entity();
133        let current = self.current();
134        self.context().with_current(current, |cx| {
135            selected.set_or_bind(cx, move |cx, selected| {
136                cx.style.selected.insert(entity, selected.get_value(cx).into());
137                cx.style.needs_access_update(entity);
138            });
139        });
140
141        self
142    }
143
144    /// Sets whether the view should be announced as selected (`true`) or not selected (`false`).
145    ///
146    /// This is an alias of [`AccessibilityModifiers::accessibility_selected`].
147    fn selected<U: Into<bool>>(self, selected: impl Res<U>) -> Self {
148        self.accessibility_selected(selected)
149    }
150
151    /// Sets whether the view allows multiple selected descendants.
152    fn multiselectable<U: Into<bool>>(mut self, multiselectable: impl Res<U>) -> Self {
153        let entity = self.entity();
154        let current = self.current();
155        self.context().with_current(current, |cx| {
156            multiselectable.set_or_bind(cx, move |cx, multiselectable| {
157                cx.style.multiselectable.insert(entity, multiselectable.get_value(cx).into());
158                cx.style.needs_access_update(entity);
159            });
160        });
161
162        self
163    }
164
165    /// Sets the accessibility sort direction for sortable headers.
166    ///
167    /// Use `None` when a header is not currently sorted.
168    fn sort_direction(mut self, sort_direction: impl Res<Option<SortDirection>>) -> Self {
169        let entity = self.entity();
170        let current = self.current();
171        self.context().with_current(current, |cx| {
172            sort_direction.set_or_bind(cx, move |cx, sort_direction| {
173                if let Some(value) = sort_direction.get_value(cx) {
174                    cx.style.sort_direction.insert(entity, value);
175                } else {
176                    cx.style.sort_direction.remove(entity);
177                }
178                cx.style.needs_access_update(entity);
179            });
180        });
181
182        self
183    }
184
185    /// Sets the accessibility level for hierarchical items.
186    fn level<U: Into<usize>>(mut self, level: impl Res<U>) -> Self {
187        let entity = self.entity();
188        let current = self.current();
189        self.context().with_current(current, |cx| {
190            level.set_or_bind(cx, move |cx, level| {
191                cx.style.level.insert(entity, level.get_value(cx).into());
192                cx.style.needs_access_update(entity);
193            });
194        });
195
196        self
197    }
198
199    /// Sets the total number of sibling items in a set for this item.
200    fn size_of_set<U: Into<usize>>(mut self, size_of_set: impl Res<U>) -> Self {
201        let entity = self.entity();
202        let current = self.current();
203        self.context().with_current(current, |cx| {
204            size_of_set.set_or_bind(cx, move |cx, size_of_set| {
205                cx.style.size_of_set.insert(entity, size_of_set.get_value(cx).into());
206                cx.style.needs_access_update(entity);
207            });
208        });
209
210        self
211    }
212
213    /// Sets the 1-based position of this item within its sibling set.
214    fn position_in_set<U: Into<usize>>(mut self, position_in_set: impl Res<U>) -> Self {
215        let entity = self.entity();
216        let current = self.current();
217        self.context().with_current(current, |cx| {
218            position_in_set.set_or_bind(cx, move |cx, position_in_set| {
219                cx.style.position_in_set.insert(entity, position_in_set.get_value(cx).into());
220                cx.style.needs_access_update(entity);
221            });
222        });
223
224        self
225    }
226
227    /// Sets the accessibility orientation of the view.
228    /// This does not affect the layout of the view, but is used to inform
229    /// assistive technologies of the orientation of the view.
230    fn orientation<U: Into<Orientation>>(mut self, orientation: impl Res<U>) -> Self {
231        let entity = self.entity();
232        let current = self.current();
233        self.context().with_current(current, |cx| {
234            orientation.set_or_bind(cx, move |cx, orientation| {
235                let orientation_value = orientation.get_value(cx).into();
236
237                if orientation_value == Orientation::Horizontal {
238                    cx.with_current(entity, |cx| {
239                        cx.toggle_class("horizontal", true);
240                        cx.toggle_class("vertical", false);
241                    });
242                } else {
243                    cx.with_current(entity, |cx| {
244                        cx.toggle_class("horizontal", false);
245                        cx.toggle_class("vertical", true);
246                    });
247                }
248                cx.style.orientation.insert(entity, orientation_value);
249                cx.style.needs_access_update(entity);
250            });
251        });
252
253        self
254    }
255
256    /// Sets the accessibility numeric value for the view.
257    fn numeric_value<U: Into<f64>>(mut self, value: impl Res<U>) -> Self {
258        let entity = self.entity();
259        let current = self.current();
260        self.context().with_current(current, |cx| {
261            value.set_or_bind(cx, move |cx, val| {
262                let v = val.get_value(cx).into();
263
264                cx.style.numeric_value.insert(entity, v);
265                cx.style.needs_access_update(entity);
266            });
267        });
268
269        self
270    }
271
272    /// Sets the accessibility text value for the view.
273    fn text_value<U: ToStringLocalized>(mut self, value: impl Res<U>) -> Self {
274        let entity = self.entity();
275        let current = self.current();
276        self.context().with_current(current, move |cx| {
277            value.set_or_bind(cx, move |cx, val| {
278                cx.style.text_value.insert(entity, val.get_value(cx).to_string_local(cx));
279                cx.style.needs_access_update(entity);
280            });
281        });
282
283        self
284    }
285}
286
287impl<V: View> AccessibilityModifiers for Handle<'_, V> {}