1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
//! Accessibility and automation types.

use std::{num::NonZeroU32, ops};

use bitflags::bitflags;
use serde::{Deserialize, Serialize};

use zng_txt::Txt;
use zng_unit::{PxRect, PxSize, PxTransform};

/// Accessibility role of a node in the accessibility tree.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[non_exhaustive]
pub enum AccessRole {
    /// Clickable widgets that trigger a response when activated by the user.
    Button,
    /// checkable interactive widget.
    ///
    /// Must also set [`AccessState::Checked`].
    ///
    /// [`AccessState::Checked`]: crate::access::AccessState::Checked
    CheckBox,
    /// Identifies a cell in a grid widget.
    GridCell,
    /// Interactive reference to a resource
    Link,
    /// Indicates the widget is an option in a set of choices contained by a menu or menu-bar.
    MenuItem,
    /// Widget is a checkable option in a menu.
    ///
    /// Must also set [`AccessState::Checked`].
    ///
    /// [`AccessState::Checked`]: crate::access::AccessState::Checked
    MenuItemCheckBox,
    /// Widget is a selectable option in a menu where only one option can be selected at a time.
    MenuItemRadio,
    /// Selectable items in a list-box.
    Option,
    /// Defines a widget that displays the progress status for tasks that take a long time.
    ///
    /// The [`AccessState::Value`] and other value states define the progress.
    ///
    /// [`AccessState::Value`]: crate::access::AccessState::Value
    ProgressBar,
    /// Selectable items in a list where only one item may be selected at a time.
    Radio,
    /// Widget controls the scrolling of content within a viewing area.
    ///
    /// Must also set [`AccessState::Controls`] and [`AccessState::Value`] to define
    /// the scroll widget and amount scrolled. By default the value min/max is 0/100.
    ///
    /// [`AccessState::Controls`]: crate::access::AccessState::Controls
    /// [`AccessState::Value`]: crate::access::AccessState::Value
    ScrollBar,
    /// Identifies a text-box that is used for searching.
    SearchBox,
    /// Defines an input where the user selects a value from within a given range.
    ///
    /// The [`AccessState::Value`] and other value states define the range and value.
    ///
    /// [`AccessState::Value`]: crate::access::AccessState::Value
    Slider,
    /// Defines a type of range that expects the user to select a value from among discrete choices.
    SpinButton,
    /// Identifies a check-box with named states.
    Switch,
    /// Identifies a widget in a tab-list that selects the active tab in a tab-panel.
    Tab,
    /// Identifies a container for the active tab.
    TabPanel,
    /// Identifies a widget that allows the input of free-form text.
    TextInput,
    /// Identifies an item in a tree widget.
    TreeItem,

    /// Identifies a widget as an input that controls another widget,
    /// such as a list-box or grid, that can dynamically pop up to help the user set the value of that input.
    ComboBox,
    /// Identifies a container of columns, rows and cells.
    Grid,
    /// Identifies a list of selectable items.
    ListBox,
    /// Identifies a composite widget that offers a list of choices to the user.
    Menu,
    /// Identifies the part of a menu that always stays visible.
    MenuBar,
    /// Identifies a group of radio buttons.
    RadioGroup,
    /// Identifies the widget that serves as the container for a set of tabs. The selected tab content
    /// is shown in a [`TabPanel`].
    ///
    /// [`TabPanel`]: Self::TabPanel
    TabList,
    /// Widget that allows the user to select one or more items from a hierarchically organized collection.
    Tree,
    /// Identifies a widget as being grid whose rows can be expanded and collapsed in the same manner as for a tree.
    TreeGrid,

    /// Indicates to assistive technologies that a widget and all of its children should be treated similar to a desktop application.
    Application,
    /// Indicates a section of a page that could easily stand on its own.
    Article,
    /// Identifies a widget as being a cell in a tabular container that does not contain column or row header information.
    Cell,
    /// Identifies a column of cells within a tabular structure.
    Column,
    /// Identifies a widget as being a cell in a row contains header information for a column.
    ColumnHeader,
    /// Indicates the widget is a definition of a term or concept.
    Definition,
    /// Focusable content within complex composite widgets or applications
    /// for which assistive technologies can switch reading context back to a reading mode.
    Document,
    /// Identifies a dynamic scrollable list of articles in which articles are added to or
    /// removed from either end of the list as the user scrolls.
    Feed,
    /// Identify a figure inside page content where appropriate semantics do not already exist.
    Figure,
    /// Identifies a set of user interface objects that is not intended to be included in a page
    /// summary or table of contents by assistive technologies.
    Group,
    /// Defines a heading to a page or section, with [`AccessState::Level`] defining structure.
    ///
    /// [`AccessState::Level`]: crate::access::AccessState::Level
    Heading,
    /// Identifies a widget container that should be considered as a single image.
    Image,
    /// Identifies a list of items.
    List,
    /// Identifies an item inside a list of items.
    ListItem,
    /// Indicates that the content represents a mathematical expression.
    Math,
    /// Identifies a section whose content is parenthetic or ancillary to the main content.
    Note,

    /// Identifies a row of cells within a tabular structure.
    Row,
    /// Identifies a group of rows within a tabular structure.
    RowGroup,
    /// Identifies a cell containing header information for a row within a tabular structure.
    RowHeader,
    /// Identifies a divider that separates and distinguishes sections of content or groups of menu items.
    Separator,
    /// Identifies the widget containing the role as having a non-interactive table structure containing data arranged in rows and columns.
    Table,
    /// Identifies a word or phrase with an optional corresponding [`Definition`].
    ///
    /// [`Definition`]: Self::Definition
    Term,
    /// Defines the containing widget as a collection of commonly used function buttons or controls represented in a compact visual form.
    ToolBar,
    /// Identifies a contextual text bubble that displays a description for an element that appears on pointer hover or keyboard focus.
    ToolTip,

    /// Identifies the global header, which usually includes a logo, company name, search feature, and possibly the global navigation or a slogan.
    Banner,
    /// Identifies a supporting section that relates to the main content.
    Complementary,
    /// Identifies a footer, containing identifying information such as copyright information, navigation links, and privacy statements.
    ContentInfo,
    /// Identify a group of widgets that are a register form.
    Form,
    /// Identifies the primary content.
    Main,
    /// Identifies major groups of links used for navigating the app.
    Navigation,
    /// Identifies significant areas. Usually set with [`AccessState::Label`].
    ///
    /// [`AccessState::Label`]: crate::access::AccessState::Label
    Region,
    /// Identifies the search area or form.
    Search,

    /// Identifies important, and usually time-sensitive, information.
    Alert,
    /// Identifies a widget that creates a live region where new information is added in a
    /// meaningful order and old information may disappear.
    Log,
    /// Identifies a live region containing non-essential information which changes frequently.
    Marquee,
    /// Identifies a live region containing advisory information for the user that is not
    /// important enough to be an alert.
    Status,
    /// Indicates to assistive technologies that a widget is a numerical counter listing the amount
    /// of elapsed time from a starting point or the remaining time until an end point.
    /// Assistive technologies will not announce updates to a timer.
    Timer,

    /// Identifies a modal alert dialogs that interrupt a user's workflow to communicate an important message and require a response.
    AlertDialog,
    /// Identifies a widget that has content separate from the normal window and is presented as an overlay.
    Dialog,
}
#[cfg(feature = "var")]
zng_var::impl_from_and_into_var! {
    fn from(some: AccessRole) -> Option<AccessRole>;
}

/// Kind of current item a widget represents.
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
pub enum CurrentKind {
    /// Represents the current page within a set of pages such as the link to the current document in a breadcrumb.
    Page,
    /// Represents the current step within a process such as the current step in an enumerated multi step checkout flow .
    Step,
    /// Represents the current location within an environment or context such as the image that is visually
    /// highlighted as the current component of a flow chart.
    Location,
    /// Represents the current date within a collection of dates such as the current date within a calendar.
    Date,
    /// Represents the current time within a set of times such as the current time within a timetable.
    Time,
    /// Represents the current item within a set.
    Item,
}

#[cfg(feature = "var")]
zng_var::impl_from_and_into_var! {
    fn from(some: CurrentKind) -> Option<CurrentKind>;
}

/// Accessibility attribute of a node in the accessibility tree.
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[non_exhaustive]
pub enum AccessState {
    /// Inputting text triggers display of one or more predictions of the user's intended
    /// value for a [`ComboBox`], [`SearchBox`], or [`TextInput`].
    ///
    /// [`ComboBox`]: AccessRole::ComboBox
    /// [`SearchBox`]: AccessRole::SearchBox
    /// [`TextInput`]: AccessRole::TextInput
    AutoComplete(AutoComplete),

    /// If the widget is checked (`Some(true)`), unchecked (`Some(false)`), or if the checked status is indeterminate (`None`).
    Checked(Option<bool>),

    /// Indicates that the widget represents a [current](CurrentKind) item.
    Current(CurrentKind),

    /// Indicates that the widget is perceivable but disabled, so it is not editable or otherwise operable.
    Disabled,

    /// Indicates that the widget is an error message for the referenced node.
    ///
    /// The other widget must be [`Invalid`].
    ///
    /// [`Invalid`]: Self::Invalid
    ErrorMessage(AccessNodeId),

    /// Indicate that the widget toggles the visibility of related widgets.
    ///
    /// Use [`Controls`], or [`Owns`] to indicate the widgets that change visibility based on
    /// this value.
    ///
    /// [`Controls`]: Self::Controls
    /// [`Owns`]: Self::Owns
    Expanded(bool),

    /// Indicates the availability and type of interactive popup widget.
    Popup(Popup),

    /// Indicates the entered value does not conform to the format expected by the application.
    Invalid(Invalid),

    /// Defines a string value that labels the widget.
    Label(Txt),

    /// Defines the hierarchical level of a widget within a structure.
    Level(NonZeroU32),
    /// Indicates whether the widget is modal when displayed.
    Modal,
    /// Indicates that the user may select more than one item from the current selectable descendants.
    MultiSelectable,
    /// Indicates whether the widget's orientation is horizontal, vertical, or unknown/ambiguous.
    Orientation(Orientation),
    /// Short hint (a word or short phrase) intended to help the user with data entry when a form control has no value.
    Placeholder(Txt),
    /// Indicates that the widget is not editable, but is otherwise operable.
    ReadOnly,
    /// Indicates that user input is required on the widget before a form may be submitted.
    Required,
    /// Indicates that the widget is selected.
    Selected,
    /// Indicates if items in a table or grid are sorted in ascending or descending order.
    Sort(SortDirection),
    /// Defines the maximum value (inclusive).
    ValueMax(f64),
    /// Defines the minimum value (inclusive).
    ValueMin(f64),
    /// Defines the current value.
    Value(f64),
    /// Defines a human readable version of the [`Value`].
    ///
    /// [`Value`]: Self::Value
    ValueText(Txt),

    /// Indicate that the widget can change.
    Live {
        /// How the changes must be notified.
        indicator: LiveIndicator,
        /// If the live region must be re-read entirely after each update.
        atomic: bool,
        /// Indicates the live area being modified and that assistive technologies may want
        /// to wait until the changes are complete before informing the user about the update.
        busy: bool,
    },

    /// Identifies the currently active widget when focus is on a composite widget, [`ComboBox`], [`TextInput`], [`Group`], or [`Application`].
    ///
    /// [`ComboBox`]: AccessRole::ComboBox
    /// [`TextInput`]: AccessRole::TextInput
    /// [`Group`]: AccessRole::Group
    /// [`Application`]: AccessRole::Application
    ActiveDescendant(AccessNodeId),

    /// Defines the total number of columns in a [`Table`], [`Grid`], or [`TreeGrid`] when not all columns are present in tree.
    ///
    /// The value `0` indicates that not all columns are in the widget and the application cannot determinate the exact number.
    ///
    /// [`Table`]: AccessRole::Table
    /// [`Grid`]: AccessRole::Grid
    /// [`TreeGrid`]: AccessRole::TreeGrid
    ColCount(usize),
    /// Defines a widget's column index in the parent table or grid.
    ColIndex(usize),
    /// Defines the number of columns spanned by the widget in the parent table or grid.
    ColSpan(usize),
    /// Identifies the widget(s) whose contents or presence are controlled by this widget.
    Controls(Vec<AccessNodeId>),
    /// Identifies the widget(s) that describes this widget.
    DescribedBy(Vec<AccessNodeId>),
    /// Identifies the widget(s) that provide additional information related to this widget.
    Details(Vec<AccessNodeId>),
    /// Options for next widget to read.
    FlowTo(Vec<AccessNodeId>),
    /// Identifies the widget(s) that labels the widget it is applied to.
    LabelledBy(Vec<AccessNodeId>),
    /// Uses the widget children as [`LabelledBy`].
    ///
    /// [`LabelledBy`]: Self::LabelledBy
    LabelledByChild,
    /// Identifies widget(s) in order to define a visual, functional, or contextual relationship between a parent and its child
    /// widgets when the tree hierarchy cannot be used to represent the relationship.
    Owns(Vec<AccessNodeId>),
    /// 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.
    ItemIndex(usize),
    /// Defines the total number of rows in a [`Table`], [`Grid`], or [`TreeGrid`] when not all rows are present in tree.
    ///
    /// The value `0` indicates that not all rows are in the widget and the application cannot determinate the exact number.
    ///
    /// [`Table`]: AccessRole::Table
    /// [`Grid`]: AccessRole::Grid
    /// [`TreeGrid`]: AccessRole::TreeGrid
    RowCount(usize),
    /// Defines a widget's row index in the parent table or grid.
    RowIndex(usize),
    /// Defines the number of rows spanned by the widget in the parent table or grid.
    RowSpan(usize),
    /// 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.
    ItemCount(usize),

    /// Language of texts inside the widget and descendants.
    Lang(unic_langid::LanguageIdentifier),

    /// Normalized (0..1) horizontal scroll, 0 is showing the content leftmost edge, 1 is showing the content the rightmost edge.
    ScrollHorizontal(f32),

    /// Normalized (0..1) vertical scroll, 0 is showing the content topmost edge, 1 is showing the content the bottommost edge.
    ScrollVertical(f32),
}

#[cfg(feature = "var")]
zng_var::impl_from_and_into_var! {
    fn from(some: AccessState) -> Option<AccessState>;
}

/// Defines how a live update is communicated to the user.
///
/// See [`AccessState::Live`] for more details.
///
/// [`AccessState::Live`]: crate::access::AccessState::Live
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum LiveIndicator {
    /// Indicates that updates to the region have the highest priority and should be presented to the user immediately.
    Assertive,
    /// Indicates that updates to the region should **not** be presented to the user unless the user is currently focused on that region.
    OnlyFocused,
    /// Indicates that updates to the region should be presented at the next graceful opportunity, such as at the end of
    /// speaking the current sentence or when the user pauses typing.
    Polite,
}

#[cfg(feature = "var")]
zng_var::impl_from_and_into_var! {
    fn from(some: LiveIndicator) -> Option<LiveIndicator>;
}

/// Sort direction.
///
/// See [`AccessState::Sort`] for more details.
///
/// [`AccessState::Sort`]: crate::access::AccessState::Sort
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum SortDirection {
    /// Items are sorted in ascending order by this column.
    Ascending,
    /// Items are sorted in descending order by this column.
    Descending,
}

#[cfg(feature = "var")]
zng_var::impl_from_and_into_var! {
    fn from(some: SortDirection) -> Option<SortDirection>;
}

/// Widget orientation.
///
/// See [`AccessState::Orientation`] for more details.
///
/// [`AccessState::Orientation`]: crate::access::AccessState::Orientation
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum Orientation {
    /// Widget is horizontal.
    Horizontal,
    /// Widget is vertical.
    Vertical,
}

#[cfg(feature = "var")]
zng_var::impl_from_and_into_var! {
    fn from(some: Orientation) -> Option<Orientation>;
}

/// Popup type.
///
/// See [`AccessState::Popup`].
///
/// [`AccessState::Popup`]: crate::access::AccessState::Popup
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum Popup {
    /// The popup is a menu.
    Menu,
    /// The popup is a list-box.
    ListBox,
    /// The popup is a tree.
    Tree,
    /// The popup is a grid.
    Grid,
    /// The popup is a dialog.
    Dialog,
}

#[cfg(feature = "var")]
zng_var::impl_from_and_into_var! {
    fn from(some: Popup) -> Option<Popup>;
}

bitflags! {
    /// Defines how inputting text could trigger display of one or more predictions of the user's intended value.
    ///
    /// See [`AccessState::AutoComplete`] for more details.
    ///
    /// [`AccessState::AutoComplete`]: crate::access::AccessState::AutoComplete
    #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
    pub struct AutoComplete: u8 {

        /// Text suggesting one way to complete the provided input may be dynamically inserted after the caret.
        const INLINE = 0b01;

        /// When a user is providing input, a widget containing a collection of values that
        /// could complete the provided input may be displayed.
        const LIST = 0b10;

        /// An input to offer both models at the same time. When a user is providing input,
        /// a widget containing a collection of values that could complete the provided input
        /// may be displayed. If displayed, one value in the collection is automatically selected,
        /// and the text needed to complete the automatically selected value appears after the caret in the input.
        const BOTH = 0b11;
    }

    /// Defines the kind of invalid data error of a widget.
    ///
    /// See [`AccessState::Invalid`] for more details.
    ///
    /// [`AccessState::Invalid`]: crate::access::AccessState::Invalid
    #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
    pub struct Invalid: u8 {
        /// Indicates the entered value does not conform to the format expected by the application.
        const ANY      = 0b001;
        /// Indicates the entered value contains a grammatical error.
        const GRAMMAR  = 0b011;
         /// Indicates the entered value contains a spelling error.
        const SPELLING = 0b101;
    }
}

/// Identifies an accessibility widget node.
///
/// Note IDs are defined by the app-process, usually they are the `WidgetId`.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct AccessNodeId(pub u64);

#[cfg(feature = "var")]
zng_var::impl_from_and_into_var! {
    fn from(some: AccessNodeId) -> Option<AccessNodeId>;
}

/// Accessibility command.
///
/// The command must run in the context of the target widow and widget, see [`Event::AccessCommand`] for more details.
///
/// [`Event::AccessCommand`]: crate::Event::AccessCommand
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[non_exhaustive]
pub enum AccessCmd {
    /// Run the click action on the widget.
    ///
    /// If `true` run the primary (default) action, if `false` run the context action.
    Click(bool),

    /// Focus or escape focus on the widget.
    ///
    /// If `true` the widget is focused, if `false` and the widget is already focused does ESC.
    Focus(bool),

    /// Sets the focus navigation origin to the widget.
    ///
    /// The navigation origin is the widget that logical and directional focus requests moves from. If
    /// not set the focus moves from the current focus, if set it moves from this origin. The origin widget
    /// does not need to be focusable and it is not focused by this command.
    FocusNavOrigin,

    /// Expand or collapse the widget content.
    SetExpanded(bool),

    /// Increment by steps.
    ///
    /// Associated value is usually is -1 or 1.
    Increment(i32),

    /// Show or hide the widget's tooltip.
    SetToolTipVis(bool),

    /// Scroll command.
    Scroll(ScrollCmd),

    /// Insert the text.
    ReplaceSelectedText(Txt),

    /// Set the text selection.
    ///
    /// The two *points* are defined by the widget and string byte char index. The
    /// start can be before or after (textually). The byte index must be at the start of
    /// a grapheme and UTF-8 char.
    SelectText {
        /// Selection start.
        start: (AccessNodeId, usize),
        /// Selection end, where the caret is positioned.
        caret: (AccessNodeId, usize),
    },

    /// Replace the value of the control with the specified value and
    /// reset the selection, if applicable.
    SetString(Txt),

    /// Replace the value of the control with the specified value and
    /// reset the selection, if applicable.
    SetNumber(f64),
}
impl AccessCmd {
    /// Gets the command discriminant without associated data.
    pub fn name(&self) -> AccessCmdName {
        match self {
            AccessCmd::Click(_) => AccessCmdName::Click,
            AccessCmd::Focus(_) => AccessCmdName::Focus,
            AccessCmd::FocusNavOrigin => AccessCmdName::FocusNavOrigin,
            AccessCmd::SetExpanded(_) => AccessCmdName::SetExpanded,
            AccessCmd::Increment(_) => AccessCmdName::Increment,
            AccessCmd::SetToolTipVis(_) => AccessCmdName::SetToolTipVis,
            AccessCmd::Scroll(_) => AccessCmdName::Scroll,
            AccessCmd::ReplaceSelectedText(_) => AccessCmdName::ReplaceSelectedText,
            AccessCmd::SelectText { .. } => AccessCmdName::SelectText,
            AccessCmd::SetString(_) => AccessCmdName::SetString,
            AccessCmd::SetNumber(_) => AccessCmdName::SetNumber,
        }
    }
}

#[cfg(feature = "var")]
zng_var::impl_from_and_into_var! {
    fn from(some: AccessCmd) -> Option<AccessCmd>;
}

/// Accessibility command without associated data.
///
/// See [`AccessCmd::name`] for more details.
///
/// [`AccessCmd::name`]: crate::access::AccessCmd::name
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
#[non_exhaustive]
pub enum AccessCmdName {
    /// [`AccessCmd::Click`]
    ///
    /// [`AccessCmd::Click`]: crate::access::AccessCmd::Click
    Click,

    /// [`AccessCmd::Focus`]
    ///
    /// [`AccessCmd::Focus`]: crate::access::AccessCmd::Focus
    Focus,
    /// [`AccessCmd::FocusNavOrigin`]
    ///
    /// [`AccessCmd::FocusNavOrigin`]: crate::access::AccessCmd::FocusNavOrigin
    FocusNavOrigin,

    /// [`AccessCmd::SetExpanded`]
    ///
    /// [`AccessCmd::SetExpanded`]: crate::access::AccessCmd::SetExpanded
    SetExpanded,

    /// [`AccessCmd::Increment`]
    ///
    /// [`AccessCmd::Increment`]: crate::access::AccessCmd::Increment
    Increment,

    /// [`AccessCmd::SetToolTipVis`]
    ///
    /// [`AccessCmd::SetToolTipVis`]: crate::access::AccessCmd::SetToolTipVis
    SetToolTipVis,

    /// [`AccessCmd::Scroll`]
    ///
    /// [`AccessCmd::Scroll`]: crate::access::AccessCmd::Scroll
    Scroll,

    /// [`AccessCmd::ReplaceSelectedText`]
    ///
    /// [`AccessCmd::ReplaceSelectedText`]: crate::access::AccessCmd::ReplaceSelectedText
    ReplaceSelectedText,

    /// [`AccessCmd::SelectText`]
    ///
    /// [`AccessCmd::SelectText`]: crate::access::AccessCmd::SelectText
    SelectText,

    /// [`AccessCmd::SetString`]
    ///
    /// [`AccessCmd::SetString`]: crate::access::AccessCmd::SetString
    SetString,

    /// [`AccessCmd::SetNumber`]
    ///
    /// [`AccessCmd::SetNumber`]: crate::access::AccessCmd::SetNumber
    SetNumber,
}

#[cfg(feature = "var")]
zng_var::impl_from_and_into_var! {
    fn from(some: AccessCmdName) -> Option<AccessCmdName>;
}

/// Accessibility scroll command.
///
/// The command must run in the context of the target widow and widget, see [`AccessCmd::Scroll`] for more details.
///
/// [`AccessCmd::Scroll`]: crate::access::AccessCmd::Scroll
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub enum ScrollCmd {
    /// Scroll page up.
    ///
    /// If the scroll-box only scrolls horizontally this is the same as `ScrollLeft`.
    PageUp,
    /// Scroll page down.
    ///
    /// If the scroll-box only scrolls horizontally this is the same as `ScrollRight`.
    PageDown,
    /// Scroll page left.
    PageLeft,
    /// Scroll page right.
    PageRight,

    /// Scroll until the widget is fully visible.
    ScrollTo,
    /// Scroll until the rectangle (in the widget space) is fully visible.
    ScrollToRect(PxRect),
}

#[cfg(feature = "var")]
zng_var::impl_from_and_into_var! {
    fn from(some: ScrollCmd) -> Option<ScrollCmd>;
}

/// Represents a widget in the access info tree.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AccessNode {
    /// Widget ID.
    pub id: AccessNodeId,
    /// Accessibility role.
    pub role: Option<AccessRole>,
    /// Commands the widget supports.
    pub commands: Vec<AccessCmdName>,
    /// Accessibility state.
    pub state: Vec<AccessState>,
    /// Widget transform (in the parent space).
    pub transform: PxTransform,
    /// Widget bounds size (in the `transform` space).
    pub size: PxSize,
    /// Children, including nodes that are not present in the tree because they did not change since last update.
    ///
    /// Can be empty if all children are present in the tree. If not empty it must contain all children, omitted and present,
    /// in the logical order.
    ///
    /// See [`AccessTreeBuilder::push`] for more details.
    pub children: Vec<AccessNodeId>,

    /// Number of children nodes actually present in the tree.
    ///
    /// See [`AccessTreeBuilder::push`] for more details.
    pub children_len: u32,
    /// Number of descendant nodes actually present in the tree.
    ///
    /// See [`AccessTreeBuilder::push`] for more details.
    pub descendants_len: u32,
}
impl AccessNode {
    /// New leaf node.
    pub fn new(id: AccessNodeId, role: Option<AccessRole>) -> Self {
        Self {
            id,
            role,
            commands: vec![],
            state: vec![],
            transform: PxTransform::identity(),
            size: PxSize::zero(),
            children: vec![],
            children_len: 0,
            descendants_len: 0,
        }
    }

    /// Total count of children.
    pub fn children_count(&self) -> usize {
        (self.children_len as usize).max(self.children.len())
    }
}

/// Accessibility info tree builder.
#[derive(Default)]
pub struct AccessTreeBuilder {
    nodes: Vec<AccessNode>,
    #[cfg(debug_assertions)]
    ids: rustc_hash::FxHashSet<AccessNodeId>,
}
impl AccessTreeBuilder {
    /// Pushes a node on the tree.
    ///
    /// If [`children_len`] is not zero the children must be pushed immediately after, each child
    /// 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]`.
    ///
    /// Note that you can push with [`children_len`] zero, and then use the returned index and [`node`] to set the children
    /// count after pushing the descendants. Also don't forget to update the [`descendants_len`].
    ///
    /// If the tree is being build for an update children that did not change can be omitted, if any child is omitted
    /// the [`children`] value must be set, it must list IDs for both present and omitted nodes in the same order they
    /// would have been pushed if not omitted.
    ///
    /// Note that changed nodes must be present in full, for example, if only the size changes all the node state
    /// must also be present, this includes the total count of children, if a child is inserted the parent node must
    /// also be present, the grand-parent in this case does not need to be present.
    ///
    /// [`node`]: Self::node
    /// [`children_len`]: AccessNode::children_len
    /// [`descendants_len`]: AccessNode::descendants_len
    /// [`children`]: AccessNode::children
    pub fn push(&mut self, node: AccessNode) -> usize {
        #[cfg(debug_assertions)]
        if !self.ids.insert(node.id) {
            panic!("id `{:?}` already in tree", node.id)
        }

        let i = self.nodes.len();
        self.nodes.push(node);
        i
    }

    /// Mutable reference to an already pushed node.
    pub fn node(&mut self, i: usize) -> &mut AccessNode {
        &mut self.nodes[i]
    }

    /// Build the tree.
    ///
    /// # Panics
    ///
    /// Panics if no node was pushed, at least one node (root) is required.
    pub fn build(self) -> AccessTree {
        assert!(!self.nodes.is_empty(), "missing root node");
        AccessTree(self.nodes)
    }
}
impl ops::Deref for AccessTreeBuilder {
    type Target = [AccessNode];

    fn deref(&self) -> &Self::Target {
        &self.nodes
    }
}

/// Accessibility info tree for a window.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AccessTree(Vec<AccessNode>);
impl AccessTree {
    /// Root node.
    pub fn root(&self) -> AccessNodeRef {
        AccessNodeRef { tree: self, index: 0 }
    }
}
impl ops::Deref for AccessTree {
    type Target = [AccessNode];

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}
impl From<AccessTree> for Vec<AccessNode> {
    fn from(value: AccessTree) -> Self {
        value.0
    }
}
impl IntoIterator for AccessTree {
    type Item = AccessNode;

    type IntoIter = std::vec::IntoIter<AccessNode>;

    fn into_iter(self) -> Self::IntoIter {
        self.0.into_iter()
    }
}

/// Reference an access node in a tree.
pub struct AccessNodeRef<'a> {
    tree: &'a AccessTree,
    index: usize,
}
impl<'a> AccessNodeRef<'a> {
    /// Iterate over `self` and all descendant nodes.
    pub fn self_and_descendants(&self) -> impl ExactSizeIterator<Item = AccessNodeRef> {
        let range = self.index..(self.index + self.descendants_len as usize);
        let tree = self.tree;
        range.map(move |i| AccessNodeRef { tree, index: i })
    }

    /// Iterate over all descendant nodes.
    pub fn descendants(&self) -> impl ExactSizeIterator<Item = AccessNodeRef> {
        let mut d = self.self_and_descendants();
        d.next();
        d
    }

    /// Iterate over children nodes.
    pub fn children(&self) -> impl ExactSizeIterator<Item = AccessNodeRef> {
        struct ChildrenIter<'a> {
            tree: &'a AccessTree,
            count: usize,
            index: usize,
        }
        impl<'a> Iterator for ChildrenIter<'a> {
            type Item = AccessNodeRef<'a>;

            fn next(&mut self) -> Option<Self::Item> {
                if self.count > 0 {
                    let item = AccessNodeRef {
                        tree: self.tree,
                        index: self.index,
                    };

                    self.count -= 1;
                    self.index += 1 + item.descendants_len as usize;

                    Some(item)
                } else {
                    None
                }
            }

            fn size_hint(&self) -> (usize, Option<usize>) {
                (self.count, Some(self.count))
            }
        }
        impl<'a> ExactSizeIterator for ChildrenIter<'a> {}
        ChildrenIter {
            tree: self.tree,
            count: self.children_len as usize,
            index: self.index + 1,
        }
    }
}
impl<'a> ops::Deref for AccessNodeRef<'a> {
    type Target = AccessNode;

    fn deref(&self) -> &Self::Target {
        &self.tree[self.index]
    }
}

/// Update for accessibility info tree for a window.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AccessTreeUpdate {
    /// Partial updates or full update.
    pub updates: Vec<AccessTree>,

    /// Is the root widget if the entire tree is present in `updates`.
    pub full_root: Option<AccessNodeId>,

    /// Focused widget, or root.
    pub focused: AccessNodeId,
}