zng_view_api/access.rs
1//! Accessibility and automation types.
2
3use std::{num::NonZeroU32, ops};
4
5use bitflags::bitflags;
6use serde::{Deserialize, Serialize};
7
8use zng_txt::Txt;
9use zng_unit::{PxRect, PxSize, PxTransform};
10
11/// Accessibility role of a node in the accessibility tree.
12#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
13#[non_exhaustive]
14pub enum AccessRole {
15 /// Clickable widgets that trigger a response when activated by the user.
16 Button,
17 /// checkable interactive widget.
18 ///
19 /// Must also set [`AccessState::Checked`].
20 ///
21 /// [`AccessState::Checked`]: crate::access::AccessState::Checked
22 CheckBox,
23 /// Identifies a cell in a grid widget.
24 GridCell,
25 /// Interactive reference to a resource
26 Link,
27 /// Indicates the widget is an option in a set of choices contained by a menu or menu-bar.
28 MenuItem,
29 /// Widget is a checkable option in a menu.
30 ///
31 /// Must also set [`AccessState::Checked`].
32 ///
33 /// [`AccessState::Checked`]: crate::access::AccessState::Checked
34 MenuItemCheckBox,
35 /// Widget is a selectable option in a menu where only one option can be selected at a time.
36 MenuItemRadio,
37 /// Selectable items in a list-box.
38 Option,
39 /// Defines a widget that displays the progress status for tasks that take a long time.
40 ///
41 /// The [`AccessState::Value`] and other value states define the progress.
42 ///
43 /// [`AccessState::Value`]: crate::access::AccessState::Value
44 ProgressBar,
45 /// Selectable items in a list where only one item may be selected at a time.
46 Radio,
47 /// Widget controls the scrolling of content within a viewing area.
48 ///
49 /// Must also set [`AccessState::Controls`] and [`AccessState::Value`] to define
50 /// the scroll widget and amount scrolled. By default the value min/max is 0/100.
51 ///
52 /// [`AccessState::Controls`]: crate::access::AccessState::Controls
53 /// [`AccessState::Value`]: crate::access::AccessState::Value
54 ScrollBar,
55 /// Identifies a text-box that is used for searching.
56 SearchBox,
57 /// Defines an input where the user selects a value from within a given range.
58 ///
59 /// The [`AccessState::Value`] and other value states define the range and value.
60 ///
61 /// [`AccessState::Value`]: crate::access::AccessState::Value
62 Slider,
63 /// Defines a type of range that expects the user to select a value from among discrete choices.
64 SpinButton,
65 /// Identifies a check-box with named states.
66 Switch,
67 /// Identifies a widget in a tab-list that selects the active tab in a tab-panel.
68 Tab,
69 /// Identifies a container for the active tab.
70 TabPanel,
71 /// Identifies a widget that allows the input of free-form text.
72 TextInput,
73 /// Identifies an item in a tree widget.
74 TreeItem,
75
76 /// Identifies a widget as an input that controls another widget,
77 /// such as a list-box or grid, that can dynamically pop up to help the user set the value of that input.
78 ComboBox,
79 /// Identifies a container of columns, rows and cells.
80 Grid,
81 /// Identifies a list of selectable items.
82 ListBox,
83 /// Identifies a composite widget that offers a list of choices to the user.
84 Menu,
85 /// Identifies the part of a menu that always stays visible.
86 MenuBar,
87 /// Identifies a group of radio buttons.
88 RadioGroup,
89 /// Identifies the widget that serves as the container for a set of tabs. The selected tab content
90 /// is shown in a [`TabPanel`].
91 ///
92 /// [`TabPanel`]: Self::TabPanel
93 TabList,
94 /// Widget that allows the user to select one or more items from a hierarchically organized collection.
95 Tree,
96 /// Identifies a widget as being grid whose rows can be expanded and collapsed in the same manner as for a tree.
97 TreeGrid,
98
99 /// Indicates to assistive technologies that a widget and all of its children should be treated similar to a desktop application.
100 Application,
101 /// Indicates a section of a page that could easily stand on its own.
102 Article,
103 /// Identifies a widget as being a cell in a tabular container that does not contain column or row header information.
104 Cell,
105 /// Identifies a column of cells within a tabular structure.
106 Column,
107 /// Identifies a widget as being a cell in a row contains header information for a column.
108 ColumnHeader,
109 /// Indicates the widget is a definition of a term or concept.
110 Definition,
111 /// Focusable content within complex composite widgets or applications
112 /// for which assistive technologies can switch reading context back to a reading mode.
113 Document,
114 /// Identifies a dynamic scrollable list of articles in which articles are added to or
115 /// removed from either end of the list as the user scrolls.
116 Feed,
117 /// Identify a figure inside page content where appropriate semantics do not already exist.
118 Figure,
119 /// Identifies a set of user interface objects that is not intended to be included in a page
120 /// summary or table of contents by assistive technologies.
121 Group,
122 /// Defines a heading to a page or section, with [`AccessState::Level`] defining structure.
123 ///
124 /// [`AccessState::Level`]: crate::access::AccessState::Level
125 Heading,
126 /// Identifies a widget container that should be considered as a single image.
127 Image,
128 /// Identifies a list of items.
129 List,
130 /// Identifies an item inside a list of items.
131 ListItem,
132 /// Indicates that the content represents a mathematical expression.
133 Math,
134 /// Identifies a section whose content is parenthetic or ancillary to the main content.
135 Note,
136
137 /// Identifies a row of cells within a tabular structure.
138 Row,
139 /// Identifies a group of rows within a tabular structure.
140 RowGroup,
141 /// Identifies a cell containing header information for a row within a tabular structure.
142 RowHeader,
143 /// Identifies a divider that separates and distinguishes sections of content or groups of menu items.
144 Separator,
145 /// Identifies the widget containing the role as having a non-interactive table structure containing data arranged in rows and columns.
146 Table,
147 /// Identifies a word or phrase with an optional corresponding [`Definition`].
148 ///
149 /// [`Definition`]: Self::Definition
150 Term,
151 /// Defines the containing widget as a collection of commonly used function buttons or controls represented in a compact visual form.
152 ToolBar,
153 /// Identifies a contextual text bubble that displays a description for an element that appears on pointer hover or keyboard focus.
154 ToolTip,
155
156 /// Identifies the global header, which usually includes a logo, company name, search feature, and possibly the global navigation or a slogan.
157 Banner,
158 /// Identifies a supporting section that relates to the main content.
159 Complementary,
160 /// Identifies a footer, containing identifying information such as copyright information, navigation links, and privacy statements.
161 ContentInfo,
162 /// Identify a group of widgets that are a register form.
163 Form,
164 /// Identifies the primary content.
165 Main,
166 /// Identifies major groups of links used for navigating the app.
167 Navigation,
168 /// Identifies significant areas. Usually set with [`AccessState::Label`].
169 ///
170 /// [`AccessState::Label`]: crate::access::AccessState::Label
171 Region,
172 /// Identifies the search area or form.
173 Search,
174
175 /// Identifies important, and usually time-sensitive, information.
176 Alert,
177 /// Identifies a widget that creates a live region where new information is added in a
178 /// meaningful order and old information may disappear.
179 Log,
180 /// Identifies a live region containing non-essential information which changes frequently.
181 Marquee,
182 /// Identifies a live region containing advisory information for the user that is not
183 /// important enough to be an alert.
184 Status,
185 /// Indicates to assistive technologies that a widget is a numerical counter listing the amount
186 /// of elapsed time from a starting point or the remaining time until an end point.
187 /// Assistive technologies will not announce updates to a timer.
188 Timer,
189
190 /// Identifies a modal alert dialogs that interrupt a user's workflow to communicate an important message and require a response.
191 AlertDialog,
192 /// Identifies a widget that has content separate from the normal window and is presented as an overlay.
193 Dialog,
194}
195#[cfg(feature = "var")]
196zng_var::impl_from_and_into_var! {
197 fn from(some: AccessRole) -> Option<AccessRole>;
198}
199
200/// Kind of current item a widget represents.
201#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
202#[non_exhaustive]
203pub enum CurrentKind {
204 /// Represents the current page within a set of pages such as the link to the current document in a breadcrumb.
205 Page,
206 /// Represents the current step within a process such as the current step in an enumerated multi step checkout flow .
207 Step,
208 /// Represents the current location within an environment or context such as the image that is visually
209 /// highlighted as the current component of a flow chart.
210 Location,
211 /// Represents the current date within a collection of dates such as the current date within a calendar.
212 Date,
213 /// Represents the current time within a set of times such as the current time within a timetable.
214 Time,
215 /// Represents the current item within a set.
216 Item,
217}
218
219#[cfg(feature = "var")]
220zng_var::impl_from_and_into_var! {
221 fn from(some: CurrentKind) -> Option<CurrentKind>;
222}
223
224/// Accessibility attribute of a node in the accessibility tree.
225#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
226#[non_exhaustive]
227pub enum AccessState {
228 /// Inputting text triggers display of one or more predictions of the user's intended
229 /// value for a [`ComboBox`], [`SearchBox`], or [`TextInput`].
230 ///
231 /// [`ComboBox`]: AccessRole::ComboBox
232 /// [`SearchBox`]: AccessRole::SearchBox
233 /// [`TextInput`]: AccessRole::TextInput
234 AutoComplete(AutoComplete),
235
236 /// If the widget is checked (`Some(true)`), unchecked (`Some(false)`), or if the checked status is indeterminate (`None`).
237 Checked(Option<bool>),
238
239 /// Indicates that the widget represents a [current](CurrentKind) item.
240 Current(CurrentKind),
241
242 /// Indicates that the widget is perceivable but disabled, so it is not editable or otherwise operable.
243 Disabled,
244
245 /// Indicates that the widget is an error message for the referenced node.
246 ///
247 /// The other widget must be [`Invalid`].
248 ///
249 /// [`Invalid`]: Self::Invalid
250 ErrorMessage(AccessNodeId),
251
252 /// Indicate that the widget toggles the visibility of related widgets.
253 ///
254 /// Use [`Controls`], or [`Owns`] to indicate the widgets that change visibility based on
255 /// this value.
256 ///
257 /// [`Controls`]: Self::Controls
258 /// [`Owns`]: Self::Owns
259 Expanded(bool),
260
261 /// Indicates the availability and type of interactive popup widget.
262 Popup(Popup),
263
264 /// Indicates the entered value does not conform to the format expected by the application.
265 Invalid(Invalid),
266
267 /// Defines a string value that labels the widget.
268 Label(Txt),
269
270 /// Defines the hierarchical level of a widget within a structure.
271 Level(NonZeroU32),
272 /// Indicates whether the widget is modal when displayed.
273 Modal,
274 /// Indicates that the user may select more than one item from the current selectable descendants.
275 MultiSelectable,
276 /// Indicates whether the widget's orientation is horizontal, vertical, or unknown/ambiguous.
277 Orientation(Orientation),
278 /// Short hint (a word or short phrase) intended to help the user with data entry when a form control has no value.
279 Placeholder(Txt),
280 /// Indicates that the widget is not editable, but is otherwise operable.
281 ReadOnly,
282 /// Indicates that user input is required on the widget before a form may be submitted.
283 Required,
284 /// Indicates that the widget is selected.
285 Selected,
286 /// Indicates if items in a table or grid are sorted in ascending or descending order.
287 Sort(SortDirection),
288 /// Defines the maximum value (inclusive).
289 ValueMax(f64),
290 /// Defines the minimum value (inclusive).
291 ValueMin(f64),
292 /// Defines the current value.
293 Value(f64),
294 /// Defines a human readable version of the [`Value`].
295 ///
296 /// [`Value`]: Self::Value
297 ValueText(Txt),
298
299 /// Indicate that the widget can change.
300 Live {
301 /// How the changes must be notified.
302 indicator: LiveIndicator,
303 /// If the live region must be re-read entirely after each update.
304 atomic: bool,
305 /// Indicates the live area being modified and that assistive technologies may want
306 /// to wait until the changes are complete before informing the user about the update.
307 busy: bool,
308 },
309
310 /// Identifies the currently active widget when focus is on a composite widget, [`ComboBox`], [`TextInput`], [`Group`], or [`Application`].
311 ///
312 /// [`ComboBox`]: AccessRole::ComboBox
313 /// [`TextInput`]: AccessRole::TextInput
314 /// [`Group`]: AccessRole::Group
315 /// [`Application`]: AccessRole::Application
316 ActiveDescendant(AccessNodeId),
317
318 /// Defines the total number of columns in a [`Table`], [`Grid`], or [`TreeGrid`] when not all columns are present in tree.
319 ///
320 /// The value `0` indicates that not all columns are in the widget and the application cannot determinate the exact number.
321 ///
322 /// [`Table`]: AccessRole::Table
323 /// [`Grid`]: AccessRole::Grid
324 /// [`TreeGrid`]: AccessRole::TreeGrid
325 ColCount(usize),
326 /// Defines a widget's column index in the parent table or grid.
327 ColIndex(usize),
328 /// Defines the number of columns spanned by the widget in the parent table or grid.
329 ColSpan(usize),
330 /// Identifies the widget(s) whose contents or presence are controlled by this widget.
331 Controls(Vec<AccessNodeId>),
332 /// Identifies the widget(s) that describes this widget.
333 DescribedBy(Vec<AccessNodeId>),
334 /// Identifies the widget(s) that provide additional information related to this widget.
335 Details(Vec<AccessNodeId>),
336 /// Options for next widget to read.
337 FlowTo(Vec<AccessNodeId>),
338 /// Identifies the widget(s) that labels the widget it is applied to.
339 LabelledBy(Vec<AccessNodeId>),
340 /// Uses the widget children as [`LabelledBy`].
341 ///
342 /// [`LabelledBy`]: Self::LabelledBy
343 LabelledByChild,
344 /// Identifies widget(s) in order to define a visual, functional, or contextual relationship between a parent and its child
345 /// widgets when the tree hierarchy cannot be used to represent the relationship.
346 Owns(Vec<AccessNodeId>),
347 /// Defines the widget's number or position in the current set of list items or tree items when not all items are present in the tree.
348 ItemIndex(usize),
349 /// Defines the total number of rows in a [`Table`], [`Grid`], or [`TreeGrid`] when not all rows are present in tree.
350 ///
351 /// The value `0` indicates that not all rows are in the widget and the application cannot determinate the exact number.
352 ///
353 /// [`Table`]: AccessRole::Table
354 /// [`Grid`]: AccessRole::Grid
355 /// [`TreeGrid`]: AccessRole::TreeGrid
356 RowCount(usize),
357 /// Defines a widget's row index in the parent table or grid.
358 RowIndex(usize),
359 /// Defines the number of rows spanned by the widget in the parent table or grid.
360 RowSpan(usize),
361 /// Defines the number of items in the current set of list items or tree items when not all items in the set are present in the tree.
362 ItemCount(usize),
363
364 /// Language of texts inside the widget and descendants.
365 Lang(unic_langid::LanguageIdentifier),
366
367 /// Normalized (0..1) horizontal scroll, 0 is showing the content leftmost edge, 1 is showing the content the rightmost edge.
368 ScrollHorizontal(f32),
369
370 /// Normalized (0..1) vertical scroll, 0 is showing the content topmost edge, 1 is showing the content the bottommost edge.
371 ScrollVertical(f32),
372}
373
374#[cfg(feature = "var")]
375zng_var::impl_from_and_into_var! {
376 fn from(some: AccessState) -> Option<AccessState>;
377}
378
379/// Defines how a live update is communicated to the user.
380///
381/// See [`AccessState::Live`] for more details.
382///
383/// [`AccessState::Live`]: crate::access::AccessState::Live
384#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
385#[non_exhaustive]
386pub enum LiveIndicator {
387 /// Indicates that updates to the region have the highest priority and should be presented to the user immediately.
388 Assertive,
389 /// Indicates that updates to the region should **not** be presented to the user unless the user is currently focused on that region.
390 OnlyFocused,
391 /// Indicates that updates to the region should be presented at the next graceful opportunity, such as at the end of
392 /// speaking the current sentence or when the user pauses typing.
393 Polite,
394}
395
396#[cfg(feature = "var")]
397zng_var::impl_from_and_into_var! {
398 fn from(some: LiveIndicator) -> Option<LiveIndicator>;
399}
400
401/// Sort direction.
402///
403/// See [`AccessState::Sort`] for more details.
404///
405/// [`AccessState::Sort`]: crate::access::AccessState::Sort
406#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
407pub enum SortDirection {
408 /// Items are sorted in ascending order by this column.
409 Ascending,
410 /// Items are sorted in descending order by this column.
411 Descending,
412}
413
414#[cfg(feature = "var")]
415zng_var::impl_from_and_into_var! {
416 fn from(some: SortDirection) -> Option<SortDirection>;
417}
418
419/// Widget orientation.
420///
421/// See [`AccessState::Orientation`] for more details.
422///
423/// [`AccessState::Orientation`]: crate::access::AccessState::Orientation
424#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
425pub enum Orientation {
426 /// Widget is horizontal.
427 Horizontal,
428 /// Widget is vertical.
429 Vertical,
430}
431
432#[cfg(feature = "var")]
433zng_var::impl_from_and_into_var! {
434 fn from(some: Orientation) -> Option<Orientation>;
435}
436
437/// Popup type.
438///
439/// See [`AccessState::Popup`].
440///
441/// [`AccessState::Popup`]: crate::access::AccessState::Popup
442#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
443#[non_exhaustive]
444pub enum Popup {
445 /// The popup is a menu.
446 Menu,
447 /// The popup is a list-box.
448 ListBox,
449 /// The popup is a tree.
450 Tree,
451 /// The popup is a grid.
452 Grid,
453 /// The popup is a dialog.
454 Dialog,
455}
456
457#[cfg(feature = "var")]
458zng_var::impl_from_and_into_var! {
459 fn from(some: Popup) -> Option<Popup>;
460}
461
462bitflags! {
463 /// Defines how inputting text could trigger display of one or more predictions of the user's intended value.
464 ///
465 /// See [`AccessState::AutoComplete`] for more details.
466 ///
467 /// [`AccessState::AutoComplete`]: crate::access::AccessState::AutoComplete
468 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
469 pub struct AutoComplete: u8 {
470 /// Text suggesting one way to complete the provided input may be dynamically inserted after the caret.
471 const INLINE = 0b01;
472
473 /// When a user is providing input, a widget containing a collection of values that
474 /// could complete the provided input may be displayed.
475 const LIST = 0b10;
476
477 /// An input to offer both models at the same time. When a user is providing input,
478 /// a widget containing a collection of values that could complete the provided input
479 /// may be displayed. If displayed, one value in the collection is automatically selected,
480 /// and the text needed to complete the automatically selected value appears after the caret in the input.
481 const BOTH = 0b11;
482 }
483
484 /// Defines the kind of invalid data error of a widget.
485 ///
486 /// See [`AccessState::Invalid`] for more details.
487 ///
488 /// [`AccessState::Invalid`]: crate::access::AccessState::Invalid
489 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
490 pub struct Invalid: u8 {
491 /// Indicates the entered value does not conform to the format expected by the application.
492 const ANY = 0b001;
493 /// Indicates the entered value contains a grammatical error.
494 const GRAMMAR = 0b011;
495 /// Indicates the entered value contains a spelling error.
496 const SPELLING = 0b101;
497 }
498}
499
500/// Identifies an accessibility widget node.
501///
502/// Note IDs are defined by the app-process, usually they are the `WidgetId`.
503#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
504pub struct AccessNodeId(pub u64);
505
506#[cfg(feature = "var")]
507zng_var::impl_from_and_into_var! {
508 fn from(some: AccessNodeId) -> Option<AccessNodeId>;
509}
510
511/// Accessibility command.
512///
513/// The command must run in the context of the target widow and widget, see [`Event::AccessCommand`] for more details.
514///
515/// [`Event::AccessCommand`]: crate::Event::AccessCommand
516#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
517#[non_exhaustive]
518pub enum AccessCmd {
519 /// Run the click action on the widget.
520 ///
521 /// If `true` run the primary (default) action, if `false` run the context action.
522 Click(bool),
523
524 /// Focus or escape focus on the widget.
525 ///
526 /// If `true` the widget is focused, if `false` and the widget is already focused does ESC.
527 Focus(bool),
528
529 /// Sets the focus navigation origin to the widget.
530 ///
531 /// The navigation origin is the widget that logical and directional focus requests moves from. If
532 /// not set the focus moves from the current focus, if set it moves from this origin. The origin widget
533 /// does not need to be focusable and it is not focused by this command.
534 FocusNavOrigin,
535
536 /// Expand or collapse the widget content.
537 SetExpanded(bool),
538
539 /// Increment by steps.
540 ///
541 /// Associated value is usually is -1 or 1.
542 Increment(i32),
543
544 /// Show or hide the widget's tooltip.
545 SetToolTipVis(bool),
546
547 /// Scroll command.
548 Scroll(ScrollCmd),
549
550 /// Insert the text.
551 ReplaceSelectedText(Txt),
552
553 /// Set the text selection.
554 ///
555 /// The two *points* are defined by the widget and string byte char index. The
556 /// start can be before or after (textually). The byte index must be at the start of
557 /// a grapheme and UTF-8 char.
558 SelectText {
559 /// Selection start.
560 start: (AccessNodeId, usize),
561 /// Selection end, where the caret is positioned.
562 caret: (AccessNodeId, usize),
563 },
564
565 /// Replace the value of the control with the specified value and
566 /// reset the selection, if applicable.
567 SetString(Txt),
568
569 /// Replace the value of the control with the specified value and
570 /// reset the selection, if applicable.
571 SetNumber(f64),
572}
573impl AccessCmd {
574 /// Gets the command discriminant without associated data.
575 pub fn name(&self) -> AccessCmdName {
576 match self {
577 AccessCmd::Click(_) => AccessCmdName::Click,
578 AccessCmd::Focus(_) => AccessCmdName::Focus,
579 AccessCmd::FocusNavOrigin => AccessCmdName::FocusNavOrigin,
580 AccessCmd::SetExpanded(_) => AccessCmdName::SetExpanded,
581 AccessCmd::Increment(_) => AccessCmdName::Increment,
582 AccessCmd::SetToolTipVis(_) => AccessCmdName::SetToolTipVis,
583 AccessCmd::Scroll(_) => AccessCmdName::Scroll,
584 AccessCmd::ReplaceSelectedText(_) => AccessCmdName::ReplaceSelectedText,
585 AccessCmd::SelectText { .. } => AccessCmdName::SelectText,
586 AccessCmd::SetString(_) => AccessCmdName::SetString,
587 AccessCmd::SetNumber(_) => AccessCmdName::SetNumber,
588 }
589 }
590}
591
592#[cfg(feature = "var")]
593zng_var::impl_from_and_into_var! {
594 fn from(some: AccessCmd) -> Option<AccessCmd>;
595}
596
597/// Accessibility command without associated data.
598///
599/// See [`AccessCmd::name`] for more details.
600///
601/// [`AccessCmd::name`]: crate::access::AccessCmd::name
602#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
603#[non_exhaustive]
604pub enum AccessCmdName {
605 /// [`AccessCmd::Click`]
606 ///
607 /// [`AccessCmd::Click`]: crate::access::AccessCmd::Click
608 Click,
609
610 /// [`AccessCmd::Focus`]
611 ///
612 /// [`AccessCmd::Focus`]: crate::access::AccessCmd::Focus
613 Focus,
614 /// [`AccessCmd::FocusNavOrigin`]
615 ///
616 /// [`AccessCmd::FocusNavOrigin`]: crate::access::AccessCmd::FocusNavOrigin
617 FocusNavOrigin,
618
619 /// [`AccessCmd::SetExpanded`]
620 ///
621 /// [`AccessCmd::SetExpanded`]: crate::access::AccessCmd::SetExpanded
622 SetExpanded,
623
624 /// [`AccessCmd::Increment`]
625 ///
626 /// [`AccessCmd::Increment`]: crate::access::AccessCmd::Increment
627 Increment,
628
629 /// [`AccessCmd::SetToolTipVis`]
630 ///
631 /// [`AccessCmd::SetToolTipVis`]: crate::access::AccessCmd::SetToolTipVis
632 SetToolTipVis,
633
634 /// [`AccessCmd::Scroll`]
635 ///
636 /// [`AccessCmd::Scroll`]: crate::access::AccessCmd::Scroll
637 Scroll,
638
639 /// [`AccessCmd::ReplaceSelectedText`]
640 ///
641 /// [`AccessCmd::ReplaceSelectedText`]: crate::access::AccessCmd::ReplaceSelectedText
642 ReplaceSelectedText,
643
644 /// [`AccessCmd::SelectText`]
645 ///
646 /// [`AccessCmd::SelectText`]: crate::access::AccessCmd::SelectText
647 SelectText,
648
649 /// [`AccessCmd::SetString`]
650 ///
651 /// [`AccessCmd::SetString`]: crate::access::AccessCmd::SetString
652 SetString,
653
654 /// [`AccessCmd::SetNumber`]
655 ///
656 /// [`AccessCmd::SetNumber`]: crate::access::AccessCmd::SetNumber
657 SetNumber,
658}
659
660#[cfg(feature = "var")]
661zng_var::impl_from_and_into_var! {
662 fn from(some: AccessCmdName) -> Option<AccessCmdName>;
663}
664
665/// Accessibility scroll command.
666///
667/// The command must run in the context of the target widow and widget, see [`AccessCmd::Scroll`] for more details.
668///
669/// [`AccessCmd::Scroll`]: crate::access::AccessCmd::Scroll
670#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
671#[non_exhaustive]
672pub enum ScrollCmd {
673 /// Scroll page up.
674 ///
675 /// If the scroll-box only scrolls horizontally this is the same as `ScrollLeft`.
676 PageUp,
677 /// Scroll page down.
678 ///
679 /// If the scroll-box only scrolls horizontally this is the same as `ScrollRight`.
680 PageDown,
681 /// Scroll page left.
682 PageLeft,
683 /// Scroll page right.
684 PageRight,
685
686 /// Scroll until the widget is fully visible.
687 ScrollTo,
688 /// Scroll until the rectangle (in the widget space) is fully visible.
689 ScrollToRect(PxRect),
690}
691
692#[cfg(feature = "var")]
693zng_var::impl_from_and_into_var! {
694 fn from(some: ScrollCmd) -> Option<ScrollCmd>;
695}
696
697/// Represents a widget in the access info tree.
698#[derive(Debug, Clone, Serialize, Deserialize)]
699#[non_exhaustive]
700pub struct AccessNode {
701 /// Widget ID.
702 pub id: AccessNodeId,
703 /// Accessibility role.
704 pub role: Option<AccessRole>,
705 /// Commands the widget supports.
706 pub commands: Vec<AccessCmdName>,
707 /// Accessibility state.
708 pub state: Vec<AccessState>,
709 /// Widget transform (in the parent space).
710 pub transform: PxTransform,
711 /// Widget bounds size (in the `transform` space).
712 pub size: PxSize,
713 /// Children, including nodes that are not present in the tree because they did not change since last update.
714 ///
715 /// Can be empty if all children are present in the tree. If not empty it must contain all children, omitted and present,
716 /// in the logical order.
717 ///
718 /// See [`AccessTreeBuilder::push`] for more details.
719 pub children: Vec<AccessNodeId>,
720
721 /// Number of children nodes actually present in the tree.
722 ///
723 /// See [`AccessTreeBuilder::push`] for more details.
724 pub children_len: u32,
725 /// Number of descendant nodes actually present in the tree.
726 ///
727 /// See [`AccessTreeBuilder::push`] for more details.
728 pub descendants_len: u32,
729}
730impl AccessNode {
731 /// New leaf node.
732 pub fn new(id: AccessNodeId, role: Option<AccessRole>) -> Self {
733 Self {
734 id,
735 role,
736 commands: vec![],
737 state: vec![],
738 transform: PxTransform::identity(),
739 size: PxSize::zero(),
740 children: vec![],
741 children_len: 0,
742 descendants_len: 0,
743 }
744 }
745
746 /// Total count of children.
747 pub fn children_count(&self) -> usize {
748 (self.children_len as usize).max(self.children.len())
749 }
750}
751
752/// Accessibility info tree builder.
753#[derive(Default)]
754pub struct AccessTreeBuilder {
755 nodes: Vec<AccessNode>,
756 #[cfg(debug_assertions)]
757 ids: rustc_hash::FxHashSet<AccessNodeId>,
758}
759impl AccessTreeBuilder {
760 /// Pushes a node on the tree.
761 ///
762 /// If [`children_len`] is not zero the children must be pushed immediately after, each child
763 /// pushes their children immediately after too. A tree `(a(a.a, a.b, a.c), b)` pushes `[a, a.a, a.b, a.c, b]`.
764 ///
765 /// Note that you can push with [`children_len`] zero, and then use the returned index and [`node`] to set the children
766 /// count after pushing the descendants. Also don't forget to update the [`descendants_len`].
767 ///
768 /// If the tree is being build for an update children that did not change can be omitted, if any child is omitted
769 /// the [`children`] value must be set, it must list IDs for both present and omitted nodes in the same order they
770 /// would have been pushed if not omitted.
771 ///
772 /// Note that changed nodes must be present in full, for example, if only the size changes all the node state
773 /// must also be present, this includes the total count of children, if a child is inserted the parent node must
774 /// also be present, the grand-parent in this case does not need to be present.
775 ///
776 /// [`node`]: Self::node
777 /// [`children_len`]: AccessNode::children_len
778 /// [`descendants_len`]: AccessNode::descendants_len
779 /// [`children`]: AccessNode::children
780 pub fn push(&mut self, node: AccessNode) -> usize {
781 #[cfg(debug_assertions)]
782 if !self.ids.insert(node.id) {
783 panic!("id `{:?}` already in tree", node.id)
784 }
785
786 let i = self.nodes.len();
787 self.nodes.push(node);
788 i
789 }
790
791 /// Mutable reference to an already pushed node.
792 pub fn node(&mut self, i: usize) -> &mut AccessNode {
793 &mut self.nodes[i]
794 }
795
796 /// Build the tree.
797 ///
798 /// # Panics
799 ///
800 /// Panics if no node was pushed, at least one node (root) is required.
801 pub fn build(self) -> AccessTree {
802 assert!(!self.nodes.is_empty(), "missing root node");
803 AccessTree(self.nodes)
804 }
805}
806impl ops::Deref for AccessTreeBuilder {
807 type Target = [AccessNode];
808
809 fn deref(&self) -> &Self::Target {
810 &self.nodes
811 }
812}
813
814/// Accessibility info tree for a window.
815#[derive(Debug, Clone, Serialize, Deserialize)]
816pub struct AccessTree(Vec<AccessNode>);
817impl AccessTree {
818 /// Root node.
819 pub fn root(&self) -> AccessNodeRef<'_> {
820 AccessNodeRef { tree: self, index: 0 }
821 }
822}
823impl ops::Deref for AccessTree {
824 type Target = [AccessNode];
825
826 fn deref(&self) -> &Self::Target {
827 &self.0
828 }
829}
830impl From<AccessTree> for Vec<AccessNode> {
831 fn from(value: AccessTree) -> Self {
832 value.0
833 }
834}
835impl IntoIterator for AccessTree {
836 type Item = AccessNode;
837
838 type IntoIter = std::vec::IntoIter<AccessNode>;
839
840 fn into_iter(self) -> Self::IntoIter {
841 self.0.into_iter()
842 }
843}
844
845/// Reference an access node in a tree.
846pub struct AccessNodeRef<'a> {
847 tree: &'a AccessTree,
848 index: usize,
849}
850impl AccessNodeRef<'_> {
851 /// Iterate over `self` and all descendant nodes.
852 pub fn self_and_descendants(&self) -> impl ExactSizeIterator<Item = AccessNodeRef<'_>> {
853 let range = self.index..(self.index + self.descendants_len as usize);
854 let tree = self.tree;
855 range.map(move |i| AccessNodeRef { tree, index: i })
856 }
857
858 /// Iterate over all descendant nodes.
859 pub fn descendants(&self) -> impl ExactSizeIterator<Item = AccessNodeRef<'_>> {
860 let mut d = self.self_and_descendants();
861 d.next();
862 d
863 }
864
865 /// Iterate over children nodes.
866 pub fn children(&self) -> impl ExactSizeIterator<Item = AccessNodeRef<'_>> {
867 struct ChildrenIter<'a> {
868 tree: &'a AccessTree,
869 count: usize,
870 index: usize,
871 }
872 impl<'a> Iterator for ChildrenIter<'a> {
873 type Item = AccessNodeRef<'a>;
874
875 fn next(&mut self) -> Option<Self::Item> {
876 if self.count > 0 {
877 let item = AccessNodeRef {
878 tree: self.tree,
879 index: self.index,
880 };
881
882 self.count -= 1;
883 self.index += 1 + item.descendants_len as usize;
884
885 Some(item)
886 } else {
887 None
888 }
889 }
890
891 fn size_hint(&self) -> (usize, Option<usize>) {
892 (self.count, Some(self.count))
893 }
894 }
895 impl ExactSizeIterator for ChildrenIter<'_> {}
896 ChildrenIter {
897 tree: self.tree,
898 count: self.children_len as usize,
899 index: self.index + 1,
900 }
901 }
902}
903impl ops::Deref for AccessNodeRef<'_> {
904 type Target = AccessNode;
905
906 fn deref(&self) -> &Self::Target {
907 &self.tree[self.index]
908 }
909}
910
911/// Update for accessibility info tree for a window.
912#[derive(Debug, Clone, Serialize, Deserialize)]
913#[non_exhaustive]
914pub struct AccessTreeUpdate {
915 /// Partial updates or full update.
916 pub updates: Vec<AccessTree>,
917
918 /// Is the root widget if the entire tree is present in `updates`.
919 pub full_root: Option<AccessNodeId>,
920
921 /// Focused widget, or root.
922 pub focused: AccessNodeId,
923}
924impl AccessTreeUpdate {
925 /// New update.
926 pub fn new(updates: Vec<AccessTree>, full_root: Option<AccessNodeId>, focused: AccessNodeId) -> Self {
927 Self {
928 updates,
929 full_root,
930 focused,
931 }
932 }
933}