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)]
202pub enum CurrentKind {
203    /// Represents the current page within a set of pages such as the link to the current document in a breadcrumb.
204    Page,
205    /// Represents the current step within a process such as the current step in an enumerated multi step checkout flow .
206    Step,
207    /// Represents the current location within an environment or context such as the image that is visually
208    /// highlighted as the current component of a flow chart.
209    Location,
210    /// Represents the current date within a collection of dates such as the current date within a calendar.
211    Date,
212    /// Represents the current time within a set of times such as the current time within a timetable.
213    Time,
214    /// Represents the current item within a set.
215    Item,
216}
217
218#[cfg(feature = "var")]
219zng_var::impl_from_and_into_var! {
220    fn from(some: CurrentKind) -> Option<CurrentKind>;
221}
222
223/// Accessibility attribute of a node in the accessibility tree.
224#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
225#[non_exhaustive]
226pub enum AccessState {
227    /// Inputting text triggers display of one or more predictions of the user's intended
228    /// value for a [`ComboBox`], [`SearchBox`], or [`TextInput`].
229    ///
230    /// [`ComboBox`]: AccessRole::ComboBox
231    /// [`SearchBox`]: AccessRole::SearchBox
232    /// [`TextInput`]: AccessRole::TextInput
233    AutoComplete(AutoComplete),
234
235    /// If the widget is checked (`Some(true)`), unchecked (`Some(false)`), or if the checked status is indeterminate (`None`).
236    Checked(Option<bool>),
237
238    /// Indicates that the widget represents a [current](CurrentKind) item.
239    Current(CurrentKind),
240
241    /// Indicates that the widget is perceivable but disabled, so it is not editable or otherwise operable.
242    Disabled,
243
244    /// Indicates that the widget is an error message for the referenced node.
245    ///
246    /// The other widget must be [`Invalid`].
247    ///
248    /// [`Invalid`]: Self::Invalid
249    ErrorMessage(AccessNodeId),
250
251    /// Indicate that the widget toggles the visibility of related widgets.
252    ///
253    /// Use [`Controls`], or [`Owns`] to indicate the widgets that change visibility based on
254    /// this value.
255    ///
256    /// [`Controls`]: Self::Controls
257    /// [`Owns`]: Self::Owns
258    Expanded(bool),
259
260    /// Indicates the availability and type of interactive popup widget.
261    Popup(Popup),
262
263    /// Indicates the entered value does not conform to the format expected by the application.
264    Invalid(Invalid),
265
266    /// Defines a string value that labels the widget.
267    Label(Txt),
268
269    /// Defines the hierarchical level of a widget within a structure.
270    Level(NonZeroU32),
271    /// Indicates whether the widget is modal when displayed.
272    Modal,
273    /// Indicates that the user may select more than one item from the current selectable descendants.
274    MultiSelectable,
275    /// Indicates whether the widget's orientation is horizontal, vertical, or unknown/ambiguous.
276    Orientation(Orientation),
277    /// Short hint (a word or short phrase) intended to help the user with data entry when a form control has no value.
278    Placeholder(Txt),
279    /// Indicates that the widget is not editable, but is otherwise operable.
280    ReadOnly,
281    /// Indicates that user input is required on the widget before a form may be submitted.
282    Required,
283    /// Indicates that the widget is selected.
284    Selected,
285    /// Indicates if items in a table or grid are sorted in ascending or descending order.
286    Sort(SortDirection),
287    /// Defines the maximum value (inclusive).
288    ValueMax(f64),
289    /// Defines the minimum value (inclusive).
290    ValueMin(f64),
291    /// Defines the current value.
292    Value(f64),
293    /// Defines a human readable version of the [`Value`].
294    ///
295    /// [`Value`]: Self::Value
296    ValueText(Txt),
297
298    /// Indicate that the widget can change.
299    Live {
300        /// How the changes must be notified.
301        indicator: LiveIndicator,
302        /// If the live region must be re-read entirely after each update.
303        atomic: bool,
304        /// Indicates the live area being modified and that assistive technologies may want
305        /// to wait until the changes are complete before informing the user about the update.
306        busy: bool,
307    },
308
309    /// Identifies the currently active widget when focus is on a composite widget, [`ComboBox`], [`TextInput`], [`Group`], or [`Application`].
310    ///
311    /// [`ComboBox`]: AccessRole::ComboBox
312    /// [`TextInput`]: AccessRole::TextInput
313    /// [`Group`]: AccessRole::Group
314    /// [`Application`]: AccessRole::Application
315    ActiveDescendant(AccessNodeId),
316
317    /// Defines the total number of columns in a [`Table`], [`Grid`], or [`TreeGrid`] when not all columns are present in tree.
318    ///
319    /// The value `0` indicates that not all columns are in the widget and the application cannot determinate the exact number.
320    ///
321    /// [`Table`]: AccessRole::Table
322    /// [`Grid`]: AccessRole::Grid
323    /// [`TreeGrid`]: AccessRole::TreeGrid
324    ColCount(usize),
325    /// Defines a widget's column index in the parent table or grid.
326    ColIndex(usize),
327    /// Defines the number of columns spanned by the widget in the parent table or grid.
328    ColSpan(usize),
329    /// Identifies the widget(s) whose contents or presence are controlled by this widget.
330    Controls(Vec<AccessNodeId>),
331    /// Identifies the widget(s) that describes this widget.
332    DescribedBy(Vec<AccessNodeId>),
333    /// Identifies the widget(s) that provide additional information related to this widget.
334    Details(Vec<AccessNodeId>),
335    /// Options for next widget to read.
336    FlowTo(Vec<AccessNodeId>),
337    /// Identifies the widget(s) that labels the widget it is applied to.
338    LabelledBy(Vec<AccessNodeId>),
339    /// Uses the widget children as [`LabelledBy`].
340    ///
341    /// [`LabelledBy`]: Self::LabelledBy
342    LabelledByChild,
343    /// Identifies widget(s) in order to define a visual, functional, or contextual relationship between a parent and its child
344    /// widgets when the tree hierarchy cannot be used to represent the relationship.
345    Owns(Vec<AccessNodeId>),
346    /// 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.
347    ItemIndex(usize),
348    /// Defines the total number of rows in a [`Table`], [`Grid`], or [`TreeGrid`] when not all rows are present in tree.
349    ///
350    /// The value `0` indicates that not all rows are in the widget and the application cannot determinate the exact number.
351    ///
352    /// [`Table`]: AccessRole::Table
353    /// [`Grid`]: AccessRole::Grid
354    /// [`TreeGrid`]: AccessRole::TreeGrid
355    RowCount(usize),
356    /// Defines a widget's row index in the parent table or grid.
357    RowIndex(usize),
358    /// Defines the number of rows spanned by the widget in the parent table or grid.
359    RowSpan(usize),
360    /// 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.
361    ItemCount(usize),
362
363    /// Language of texts inside the widget and descendants.
364    Lang(unic_langid::LanguageIdentifier),
365
366    /// Normalized (0..1) horizontal scroll, 0 is showing the content leftmost edge, 1 is showing the content the rightmost edge.
367    ScrollHorizontal(f32),
368
369    /// Normalized (0..1) vertical scroll, 0 is showing the content topmost edge, 1 is showing the content the bottommost edge.
370    ScrollVertical(f32),
371}
372
373#[cfg(feature = "var")]
374zng_var::impl_from_and_into_var! {
375    fn from(some: AccessState) -> Option<AccessState>;
376}
377
378/// Defines how a live update is communicated to the user.
379///
380/// See [`AccessState::Live`] for more details.
381///
382/// [`AccessState::Live`]: crate::access::AccessState::Live
383#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
384pub enum LiveIndicator {
385    /// Indicates that updates to the region have the highest priority and should be presented to the user immediately.
386    Assertive,
387    /// Indicates that updates to the region should **not** be presented to the user unless the user is currently focused on that region.
388    OnlyFocused,
389    /// Indicates that updates to the region should be presented at the next graceful opportunity, such as at the end of
390    /// speaking the current sentence or when the user pauses typing.
391    Polite,
392}
393
394#[cfg(feature = "var")]
395zng_var::impl_from_and_into_var! {
396    fn from(some: LiveIndicator) -> Option<LiveIndicator>;
397}
398
399/// Sort direction.
400///
401/// See [`AccessState::Sort`] for more details.
402///
403/// [`AccessState::Sort`]: crate::access::AccessState::Sort
404#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
405pub enum SortDirection {
406    /// Items are sorted in ascending order by this column.
407    Ascending,
408    /// Items are sorted in descending order by this column.
409    Descending,
410}
411
412#[cfg(feature = "var")]
413zng_var::impl_from_and_into_var! {
414    fn from(some: SortDirection) -> Option<SortDirection>;
415}
416
417/// Widget orientation.
418///
419/// See [`AccessState::Orientation`] for more details.
420///
421/// [`AccessState::Orientation`]: crate::access::AccessState::Orientation
422#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
423pub enum Orientation {
424    /// Widget is horizontal.
425    Horizontal,
426    /// Widget is vertical.
427    Vertical,
428}
429
430#[cfg(feature = "var")]
431zng_var::impl_from_and_into_var! {
432    fn from(some: Orientation) -> Option<Orientation>;
433}
434
435/// Popup type.
436///
437/// See [`AccessState::Popup`].
438///
439/// [`AccessState::Popup`]: crate::access::AccessState::Popup
440#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
441pub enum Popup {
442    /// The popup is a menu.
443    Menu,
444    /// The popup is a list-box.
445    ListBox,
446    /// The popup is a tree.
447    Tree,
448    /// The popup is a grid.
449    Grid,
450    /// The popup is a dialog.
451    Dialog,
452}
453
454#[cfg(feature = "var")]
455zng_var::impl_from_and_into_var! {
456    fn from(some: Popup) -> Option<Popup>;
457}
458
459bitflags! {
460    /// Defines how inputting text could trigger display of one or more predictions of the user's intended value.
461    ///
462    /// See [`AccessState::AutoComplete`] for more details.
463    ///
464    /// [`AccessState::AutoComplete`]: crate::access::AccessState::AutoComplete
465    #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
466    pub struct AutoComplete: u8 {
467
468        /// Text suggesting one way to complete the provided input may be dynamically inserted after the caret.
469        const INLINE = 0b01;
470
471        /// When a user is providing input, a widget containing a collection of values that
472        /// could complete the provided input may be displayed.
473        const LIST = 0b10;
474
475        /// An input to offer both models at the same time. When a user is providing input,
476        /// a widget containing a collection of values that could complete the provided input
477        /// may be displayed. If displayed, one value in the collection is automatically selected,
478        /// and the text needed to complete the automatically selected value appears after the caret in the input.
479        const BOTH = 0b11;
480    }
481
482    /// Defines the kind of invalid data error of a widget.
483    ///
484    /// See [`AccessState::Invalid`] for more details.
485    ///
486    /// [`AccessState::Invalid`]: crate::access::AccessState::Invalid
487    #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
488    pub struct Invalid: u8 {
489        /// Indicates the entered value does not conform to the format expected by the application.
490        const ANY      = 0b001;
491        /// Indicates the entered value contains a grammatical error.
492        const GRAMMAR  = 0b011;
493         /// Indicates the entered value contains a spelling error.
494        const SPELLING = 0b101;
495    }
496}
497
498/// Identifies an accessibility widget node.
499///
500/// Note IDs are defined by the app-process, usually they are the `WidgetId`.
501#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
502pub struct AccessNodeId(pub u64);
503
504#[cfg(feature = "var")]
505zng_var::impl_from_and_into_var! {
506    fn from(some: AccessNodeId) -> Option<AccessNodeId>;
507}
508
509/// Accessibility command.
510///
511/// The command must run in the context of the target widow and widget, see [`Event::AccessCommand`] for more details.
512///
513/// [`Event::AccessCommand`]: crate::Event::AccessCommand
514#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
515#[non_exhaustive]
516pub enum AccessCmd {
517    /// Run the click action on the widget.
518    ///
519    /// If `true` run the primary (default) action, if `false` run the context action.
520    Click(bool),
521
522    /// Focus or escape focus on the widget.
523    ///
524    /// If `true` the widget is focused, if `false` and the widget is already focused does ESC.
525    Focus(bool),
526
527    /// Sets the focus navigation origin to the widget.
528    ///
529    /// The navigation origin is the widget that logical and directional focus requests moves from. If
530    /// not set the focus moves from the current focus, if set it moves from this origin. The origin widget
531    /// does not need to be focusable and it is not focused by this command.
532    FocusNavOrigin,
533
534    /// Expand or collapse the widget content.
535    SetExpanded(bool),
536
537    /// Increment by steps.
538    ///
539    /// Associated value is usually is -1 or 1.
540    Increment(i32),
541
542    /// Show or hide the widget's tooltip.
543    SetToolTipVis(bool),
544
545    /// Scroll command.
546    Scroll(ScrollCmd),
547
548    /// Insert the text.
549    ReplaceSelectedText(Txt),
550
551    /// Set the text selection.
552    ///
553    /// The two *points* are defined by the widget and string byte char index. The
554    /// start can be before or after (textually). The byte index must be at the start of
555    /// a grapheme and UTF-8 char.
556    SelectText {
557        /// Selection start.
558        start: (AccessNodeId, usize),
559        /// Selection end, where the caret is positioned.
560        caret: (AccessNodeId, usize),
561    },
562
563    /// Replace the value of the control with the specified value and
564    /// reset the selection, if applicable.
565    SetString(Txt),
566
567    /// Replace the value of the control with the specified value and
568    /// reset the selection, if applicable.
569    SetNumber(f64),
570}
571impl AccessCmd {
572    /// Gets the command discriminant without associated data.
573    pub fn name(&self) -> AccessCmdName {
574        match self {
575            AccessCmd::Click(_) => AccessCmdName::Click,
576            AccessCmd::Focus(_) => AccessCmdName::Focus,
577            AccessCmd::FocusNavOrigin => AccessCmdName::FocusNavOrigin,
578            AccessCmd::SetExpanded(_) => AccessCmdName::SetExpanded,
579            AccessCmd::Increment(_) => AccessCmdName::Increment,
580            AccessCmd::SetToolTipVis(_) => AccessCmdName::SetToolTipVis,
581            AccessCmd::Scroll(_) => AccessCmdName::Scroll,
582            AccessCmd::ReplaceSelectedText(_) => AccessCmdName::ReplaceSelectedText,
583            AccessCmd::SelectText { .. } => AccessCmdName::SelectText,
584            AccessCmd::SetString(_) => AccessCmdName::SetString,
585            AccessCmd::SetNumber(_) => AccessCmdName::SetNumber,
586        }
587    }
588}
589
590#[cfg(feature = "var")]
591zng_var::impl_from_and_into_var! {
592    fn from(some: AccessCmd) -> Option<AccessCmd>;
593}
594
595/// Accessibility command without associated data.
596///
597/// See [`AccessCmd::name`] for more details.
598///
599/// [`AccessCmd::name`]: crate::access::AccessCmd::name
600#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
601#[non_exhaustive]
602pub enum AccessCmdName {
603    /// [`AccessCmd::Click`]
604    ///
605    /// [`AccessCmd::Click`]: crate::access::AccessCmd::Click
606    Click,
607
608    /// [`AccessCmd::Focus`]
609    ///
610    /// [`AccessCmd::Focus`]: crate::access::AccessCmd::Focus
611    Focus,
612    /// [`AccessCmd::FocusNavOrigin`]
613    ///
614    /// [`AccessCmd::FocusNavOrigin`]: crate::access::AccessCmd::FocusNavOrigin
615    FocusNavOrigin,
616
617    /// [`AccessCmd::SetExpanded`]
618    ///
619    /// [`AccessCmd::SetExpanded`]: crate::access::AccessCmd::SetExpanded
620    SetExpanded,
621
622    /// [`AccessCmd::Increment`]
623    ///
624    /// [`AccessCmd::Increment`]: crate::access::AccessCmd::Increment
625    Increment,
626
627    /// [`AccessCmd::SetToolTipVis`]
628    ///
629    /// [`AccessCmd::SetToolTipVis`]: crate::access::AccessCmd::SetToolTipVis
630    SetToolTipVis,
631
632    /// [`AccessCmd::Scroll`]
633    ///
634    /// [`AccessCmd::Scroll`]: crate::access::AccessCmd::Scroll
635    Scroll,
636
637    /// [`AccessCmd::ReplaceSelectedText`]
638    ///
639    /// [`AccessCmd::ReplaceSelectedText`]: crate::access::AccessCmd::ReplaceSelectedText
640    ReplaceSelectedText,
641
642    /// [`AccessCmd::SelectText`]
643    ///
644    /// [`AccessCmd::SelectText`]: crate::access::AccessCmd::SelectText
645    SelectText,
646
647    /// [`AccessCmd::SetString`]
648    ///
649    /// [`AccessCmd::SetString`]: crate::access::AccessCmd::SetString
650    SetString,
651
652    /// [`AccessCmd::SetNumber`]
653    ///
654    /// [`AccessCmd::SetNumber`]: crate::access::AccessCmd::SetNumber
655    SetNumber,
656}
657
658#[cfg(feature = "var")]
659zng_var::impl_from_and_into_var! {
660    fn from(some: AccessCmdName) -> Option<AccessCmdName>;
661}
662
663/// Accessibility scroll command.
664///
665/// The command must run in the context of the target widow and widget, see [`AccessCmd::Scroll`] for more details.
666///
667/// [`AccessCmd::Scroll`]: crate::access::AccessCmd::Scroll
668#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
669pub enum ScrollCmd {
670    /// Scroll page up.
671    ///
672    /// If the scroll-box only scrolls horizontally this is the same as `ScrollLeft`.
673    PageUp,
674    /// Scroll page down.
675    ///
676    /// If the scroll-box only scrolls horizontally this is the same as `ScrollRight`.
677    PageDown,
678    /// Scroll page left.
679    PageLeft,
680    /// Scroll page right.
681    PageRight,
682
683    /// Scroll until the widget is fully visible.
684    ScrollTo,
685    /// Scroll until the rectangle (in the widget space) is fully visible.
686    ScrollToRect(PxRect),
687}
688
689#[cfg(feature = "var")]
690zng_var::impl_from_and_into_var! {
691    fn from(some: ScrollCmd) -> Option<ScrollCmd>;
692}
693
694/// Represents a widget in the access info tree.
695#[derive(Debug, Clone, Serialize, Deserialize)]
696pub struct AccessNode {
697    /// Widget ID.
698    pub id: AccessNodeId,
699    /// Accessibility role.
700    pub role: Option<AccessRole>,
701    /// Commands the widget supports.
702    pub commands: Vec<AccessCmdName>,
703    /// Accessibility state.
704    pub state: Vec<AccessState>,
705    /// Widget transform (in the parent space).
706    pub transform: PxTransform,
707    /// Widget bounds size (in the `transform` space).
708    pub size: PxSize,
709    /// Children, including nodes that are not present in the tree because they did not change since last update.
710    ///
711    /// Can be empty if all children are present in the tree. If not empty it must contain all children, omitted and present,
712    /// in the logical order.
713    ///
714    /// See [`AccessTreeBuilder::push`] for more details.
715    pub children: Vec<AccessNodeId>,
716
717    /// Number of children nodes actually present in the tree.
718    ///
719    /// See [`AccessTreeBuilder::push`] for more details.
720    pub children_len: u32,
721    /// Number of descendant nodes actually present in the tree.
722    ///
723    /// See [`AccessTreeBuilder::push`] for more details.
724    pub descendants_len: u32,
725}
726impl AccessNode {
727    /// New leaf node.
728    pub fn new(id: AccessNodeId, role: Option<AccessRole>) -> Self {
729        Self {
730            id,
731            role,
732            commands: vec![],
733            state: vec![],
734            transform: PxTransform::identity(),
735            size: PxSize::zero(),
736            children: vec![],
737            children_len: 0,
738            descendants_len: 0,
739        }
740    }
741
742    /// Total count of children.
743    pub fn children_count(&self) -> usize {
744        (self.children_len as usize).max(self.children.len())
745    }
746}
747
748/// Accessibility info tree builder.
749#[derive(Default)]
750pub struct AccessTreeBuilder {
751    nodes: Vec<AccessNode>,
752    #[cfg(debug_assertions)]
753    ids: rustc_hash::FxHashSet<AccessNodeId>,
754}
755impl AccessTreeBuilder {
756    /// Pushes a node on the tree.
757    ///
758    /// If [`children_len`] is not zero the children must be pushed immediately after, each child
759    /// 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]`.
760    ///
761    /// Note that you can push with [`children_len`] zero, and then use the returned index and [`node`] to set the children
762    /// count after pushing the descendants. Also don't forget to update the [`descendants_len`].
763    ///
764    /// If the tree is being build for an update children that did not change can be omitted, if any child is omitted
765    /// the [`children`] value must be set, it must list IDs for both present and omitted nodes in the same order they
766    /// would have been pushed if not omitted.
767    ///
768    /// Note that changed nodes must be present in full, for example, if only the size changes all the node state
769    /// must also be present, this includes the total count of children, if a child is inserted the parent node must
770    /// also be present, the grand-parent in this case does not need to be present.
771    ///
772    /// [`node`]: Self::node
773    /// [`children_len`]: AccessNode::children_len
774    /// [`descendants_len`]: AccessNode::descendants_len
775    /// [`children`]: AccessNode::children
776    pub fn push(&mut self, node: AccessNode) -> usize {
777        #[cfg(debug_assertions)]
778        if !self.ids.insert(node.id) {
779            panic!("id `{:?}` already in tree", node.id)
780        }
781
782        let i = self.nodes.len();
783        self.nodes.push(node);
784        i
785    }
786
787    /// Mutable reference to an already pushed node.
788    pub fn node(&mut self, i: usize) -> &mut AccessNode {
789        &mut self.nodes[i]
790    }
791
792    /// Build the tree.
793    ///
794    /// # Panics
795    ///
796    /// Panics if no node was pushed, at least one node (root) is required.
797    pub fn build(self) -> AccessTree {
798        assert!(!self.nodes.is_empty(), "missing root node");
799        AccessTree(self.nodes)
800    }
801}
802impl ops::Deref for AccessTreeBuilder {
803    type Target = [AccessNode];
804
805    fn deref(&self) -> &Self::Target {
806        &self.nodes
807    }
808}
809
810/// Accessibility info tree for a window.
811#[derive(Debug, Clone, Serialize, Deserialize)]
812pub struct AccessTree(Vec<AccessNode>);
813impl AccessTree {
814    /// Root node.
815    pub fn root(&self) -> AccessNodeRef {
816        AccessNodeRef { tree: self, index: 0 }
817    }
818}
819impl ops::Deref for AccessTree {
820    type Target = [AccessNode];
821
822    fn deref(&self) -> &Self::Target {
823        &self.0
824    }
825}
826impl From<AccessTree> for Vec<AccessNode> {
827    fn from(value: AccessTree) -> Self {
828        value.0
829    }
830}
831impl IntoIterator for AccessTree {
832    type Item = AccessNode;
833
834    type IntoIter = std::vec::IntoIter<AccessNode>;
835
836    fn into_iter(self) -> Self::IntoIter {
837        self.0.into_iter()
838    }
839}
840
841/// Reference an access node in a tree.
842pub struct AccessNodeRef<'a> {
843    tree: &'a AccessTree,
844    index: usize,
845}
846impl AccessNodeRef<'_> {
847    /// Iterate over `self` and all descendant nodes.
848    pub fn self_and_descendants(&self) -> impl ExactSizeIterator<Item = AccessNodeRef> {
849        let range = self.index..(self.index + self.descendants_len as usize);
850        let tree = self.tree;
851        range.map(move |i| AccessNodeRef { tree, index: i })
852    }
853
854    /// Iterate over all descendant nodes.
855    pub fn descendants(&self) -> impl ExactSizeIterator<Item = AccessNodeRef> {
856        let mut d = self.self_and_descendants();
857        d.next();
858        d
859    }
860
861    /// Iterate over children nodes.
862    pub fn children(&self) -> impl ExactSizeIterator<Item = AccessNodeRef> {
863        struct ChildrenIter<'a> {
864            tree: &'a AccessTree,
865            count: usize,
866            index: usize,
867        }
868        impl<'a> Iterator for ChildrenIter<'a> {
869            type Item = AccessNodeRef<'a>;
870
871            fn next(&mut self) -> Option<Self::Item> {
872                if self.count > 0 {
873                    let item = AccessNodeRef {
874                        tree: self.tree,
875                        index: self.index,
876                    };
877
878                    self.count -= 1;
879                    self.index += 1 + item.descendants_len as usize;
880
881                    Some(item)
882                } else {
883                    None
884                }
885            }
886
887            fn size_hint(&self) -> (usize, Option<usize>) {
888                (self.count, Some(self.count))
889            }
890        }
891        impl ExactSizeIterator for ChildrenIter<'_> {}
892        ChildrenIter {
893            tree: self.tree,
894            count: self.children_len as usize,
895            index: self.index + 1,
896        }
897    }
898}
899impl ops::Deref for AccessNodeRef<'_> {
900    type Target = AccessNode;
901
902    fn deref(&self) -> &Self::Target {
903        &self.tree[self.index]
904    }
905}
906
907/// Update for accessibility info tree for a window.
908#[derive(Debug, Clone, Serialize, Deserialize)]
909pub struct AccessTreeUpdate {
910    /// Partial updates or full update.
911    pub updates: Vec<AccessTree>,
912
913    /// Is the root widget if the entire tree is present in `updates`.
914    pub full_root: Option<AccessNodeId>,
915
916    /// Focused widget, or root.
917    pub focused: AccessNodeId,
918}