1#![cfg_attr(not(any(feature = "pyo3", feature = "schemars")), no_std)]
12
13extern crate alloc;
14
15#[cfg(feature = "schemars")]
16use alloc::borrow::Cow;
17use alloc::{borrow::ToOwned, boxed::Box, string::String, vec::Vec};
18use core::fmt;
19#[cfg(feature = "pyo3")]
20use pyo3::pyclass;
21#[cfg(feature = "schemars")]
22use schemars::{JsonSchema, Schema, SchemaGenerator, json_schema};
23#[cfg(feature = "serde")]
24use serde::{
25 Deserialize, Serialize,
26 de::{Deserializer, IgnoredAny, MapAccess, Visitor},
27 ser::{SerializeMap, Serializer},
28};
29#[cfg(feature = "schemars")]
30use serde_json::{Map as SchemaMap, Value as SchemaValue};
31
32pub use uuid::Uuid;
33
34mod geometry;
35pub use geometry::{Affine, Point, Rect, Size, Vec2};
36
37#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
48#[cfg_attr(feature = "enumn", derive(enumn::N))]
49#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
50#[cfg_attr(feature = "schemars", derive(JsonSchema))]
51#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
52#[cfg_attr(
53 feature = "pyo3",
54 pyclass(
55 module = "accesskit",
56 rename_all = "SCREAMING_SNAKE_CASE",
57 eq,
58 from_py_object
59 )
60)]
61#[repr(u8)]
62pub enum Role {
63 #[default]
64 Unknown,
65 TextRun,
66 Cell,
67 Label,
68 Image,
69 Link,
70 Row,
71 ListItem,
72
73 ListMarker,
75
76 TreeItem,
77 ListBoxOption,
78 MenuItem,
79 MenuListOption,
80 Paragraph,
81
82 GenericContainer,
86
87 CheckBox,
88 RadioButton,
89 TextInput,
90 Button,
91 DefaultButton,
92 Pane,
93 RowHeader,
94 ColumnHeader,
95 RowGroup,
96 List,
97 Table,
98 LayoutTableCell,
99 LayoutTableRow,
100 LayoutTable,
101 Switch,
102 Menu,
103
104 MultilineTextInput,
105 SearchInput,
106 DateInput,
107 DateTimeInput,
108 WeekInput,
109 MonthInput,
110 TimeInput,
111 EmailInput,
112 NumberInput,
113 PasswordInput,
114 PhoneNumberInput,
115 UrlInput,
116
117 Abbr,
118 Alert,
119 AlertDialog,
120 Application,
121 Article,
122 Audio,
123 Banner,
124 Blockquote,
125 Canvas,
126 Caption,
127 Caret,
128 Code,
129 ColorWell,
130 ComboBox,
131 EditableComboBox,
132 Complementary,
133 Comment,
134 ContentDeletion,
135 ContentInsertion,
136 ContentInfo,
137 Definition,
138 DescriptionList,
139 Details,
140 Dialog,
141 DisclosureTriangle,
142 Document,
143 EmbeddedObject,
144 Emphasis,
145 Feed,
146 FigureCaption,
147 Figure,
148 Footer,
149 Form,
150 Grid,
151 GridCell,
152 Group,
153 Header,
154 Heading,
155 Iframe,
156 IframePresentational,
157 ImeCandidate,
158 Keyboard,
159 Legend,
160 LineBreak,
161 ListBox,
162 Log,
163 Main,
164 Mark,
165 Marquee,
166 Math,
167 MenuBar,
168 MenuItemCheckBox,
169 MenuItemRadio,
170 MenuListPopup,
171 Meter,
172 Navigation,
173 Note,
174 PluginObject,
175 ProgressIndicator,
176 RadioGroup,
177 Region,
178 RootWebArea,
179 Ruby,
180 RubyAnnotation,
181 ScrollBar,
182 ScrollView,
183 Search,
184 Section,
185 SectionFooter,
186 SectionHeader,
187 Slider,
188 SpinButton,
189 Splitter,
190 Status,
191 Strong,
192 Suggestion,
193 SvgRoot,
194 Tab,
195 TabList,
196 TabPanel,
197 Term,
198 Time,
199 Timer,
200 TitleBar,
201 Toolbar,
202 Tooltip,
203 Tree,
204 TreeGrid,
205 Video,
206 WebView,
207 Window,
208
209 PdfActionableHighlight,
210 PdfRoot,
211
212 GraphicsDocument,
215 GraphicsObject,
216 GraphicsSymbol,
217
218 DocAbstract,
221 DocAcknowledgements,
222 DocAfterword,
223 DocAppendix,
224 DocBackLink,
225 DocBiblioEntry,
226 DocBibliography,
227 DocBiblioRef,
228 DocChapter,
229 DocColophon,
230 DocConclusion,
231 DocCover,
232 DocCredit,
233 DocCredits,
234 DocDedication,
235 DocEndnote,
236 DocEndnotes,
237 DocEpigraph,
238 DocEpilogue,
239 DocErrata,
240 DocExample,
241 DocFootnote,
242 DocForeword,
243 DocGlossary,
244 DocGlossRef,
245 DocIndex,
246 DocIntroduction,
247 DocNoteRef,
248 DocNotice,
249 DocPageBreak,
250 DocPageFooter,
251 DocPageHeader,
252 DocPageList,
253 DocPart,
254 DocPreface,
255 DocPrologue,
256 DocPullquote,
257 DocQna,
258 DocSubtitle,
259 DocTip,
260 DocToc,
261
262 ListGrid,
266
267 Terminal,
271}
272
273#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
275#[cfg_attr(feature = "enumn", derive(enumn::N))]
276#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
277#[cfg_attr(feature = "schemars", derive(JsonSchema))]
278#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
279#[cfg_attr(
280 feature = "pyo3",
281 pyclass(
282 module = "accesskit",
283 rename_all = "SCREAMING_SNAKE_CASE",
284 eq,
285 from_py_object
286 )
287)]
288#[repr(u8)]
289pub enum Action {
290 Click,
292
293 Focus,
294 Blur,
295
296 Collapse,
297 Expand,
298
299 CustomAction,
301
302 Decrement,
304 Increment,
306
307 HideTooltip,
308 ShowTooltip,
309
310 ReplaceSelectedText,
314
315 ScrollDown,
317 ScrollLeft,
319 ScrollRight,
321 ScrollUp,
323
324 ScrollIntoView,
327
328 ScrollToPoint,
332
333 SetScrollOffset,
335
336 SetTextSelection,
338
339 SetSequentialFocusNavigationStartingPoint,
343
344 SetValue,
348
349 ShowContextMenu,
350}
351
352impl Action {
353 fn mask(self) -> u32 {
354 1 << (self as u8)
355 }
356
357 #[cfg(not(feature = "enumn"))]
358 fn n(value: u8) -> Option<Self> {
359 match value {
363 0 => Some(Action::Click),
364 1 => Some(Action::Focus),
365 2 => Some(Action::Blur),
366 3 => Some(Action::Collapse),
367 4 => Some(Action::Expand),
368 5 => Some(Action::CustomAction),
369 6 => Some(Action::Decrement),
370 7 => Some(Action::Increment),
371 8 => Some(Action::HideTooltip),
372 9 => Some(Action::ShowTooltip),
373 10 => Some(Action::ReplaceSelectedText),
374 11 => Some(Action::ScrollDown),
375 12 => Some(Action::ScrollLeft),
376 13 => Some(Action::ScrollRight),
377 14 => Some(Action::ScrollUp),
378 15 => Some(Action::ScrollIntoView),
379 16 => Some(Action::ScrollToPoint),
380 17 => Some(Action::SetScrollOffset),
381 18 => Some(Action::SetTextSelection),
382 19 => Some(Action::SetSequentialFocusNavigationStartingPoint),
383 20 => Some(Action::SetValue),
384 21 => Some(Action::ShowContextMenu),
385 _ => None,
386 }
387 }
388}
389
390fn action_mask_to_action_vec(mask: u32) -> Vec<Action> {
391 let mut actions = Vec::new();
392 let mut i = 0;
393 while let Some(variant) = Action::n(i) {
394 if mask & variant.mask() != 0 {
395 actions.push(variant);
396 }
397 i += 1;
398 }
399 actions
400}
401
402#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
403#[cfg_attr(feature = "enumn", derive(enumn::N))]
404#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
405#[cfg_attr(feature = "schemars", derive(JsonSchema))]
406#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
407#[cfg_attr(
408 feature = "pyo3",
409 pyclass(
410 module = "accesskit",
411 rename_all = "SCREAMING_SNAKE_CASE",
412 eq,
413 from_py_object
414 )
415)]
416#[repr(u8)]
417pub enum Orientation {
418 Horizontal,
420 Vertical,
422}
423
424#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
425#[cfg_attr(feature = "enumn", derive(enumn::N))]
426#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
427#[cfg_attr(feature = "schemars", derive(JsonSchema))]
428#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
429#[cfg_attr(
430 feature = "pyo3",
431 pyclass(
432 module = "accesskit",
433 rename_all = "SCREAMING_SNAKE_CASE",
434 eq,
435 from_py_object
436 )
437)]
438#[repr(u8)]
439pub enum TextDirection {
440 LeftToRight,
441 RightToLeft,
442 TopToBottom,
443 BottomToTop,
444}
445
446#[derive(Clone, Copy, Debug, PartialEq, Eq)]
451#[cfg_attr(feature = "enumn", derive(enumn::N))]
452#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
453#[cfg_attr(feature = "schemars", derive(JsonSchema))]
454#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
455#[cfg_attr(
456 feature = "pyo3",
457 pyclass(
458 module = "accesskit",
459 rename_all = "SCREAMING_SNAKE_CASE",
460 eq,
461 from_py_object
462 )
463)]
464#[repr(u8)]
465pub enum Invalid {
466 True,
467 Grammar,
468 Spelling,
469}
470
471#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
472#[cfg_attr(feature = "enumn", derive(enumn::N))]
473#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
474#[cfg_attr(feature = "schemars", derive(JsonSchema))]
475#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
476#[cfg_attr(
477 feature = "pyo3",
478 pyclass(
479 module = "accesskit",
480 rename_all = "SCREAMING_SNAKE_CASE",
481 eq,
482 from_py_object
483 )
484)]
485#[repr(u8)]
486pub enum Toggled {
487 False,
488 True,
489 Mixed,
490}
491
492impl From<bool> for Toggled {
493 #[inline]
494 fn from(b: bool) -> Self {
495 match b {
496 false => Self::False,
497 true => Self::True,
498 }
499 }
500}
501
502#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
503#[cfg_attr(feature = "enumn", derive(enumn::N))]
504#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
505#[cfg_attr(feature = "schemars", derive(JsonSchema))]
506#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
507#[cfg_attr(
508 feature = "pyo3",
509 pyclass(
510 module = "accesskit",
511 rename_all = "SCREAMING_SNAKE_CASE",
512 eq,
513 from_py_object
514 )
515)]
516#[repr(u8)]
517pub enum SortDirection {
518 Ascending,
519 Descending,
520 Other,
521}
522
523#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
524#[cfg_attr(feature = "enumn", derive(enumn::N))]
525#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
526#[cfg_attr(feature = "schemars", derive(JsonSchema))]
527#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
528#[cfg_attr(
529 feature = "pyo3",
530 pyclass(
531 module = "accesskit",
532 rename_all = "SCREAMING_SNAKE_CASE",
533 eq,
534 from_py_object
535 )
536)]
537#[repr(u8)]
538pub enum AriaCurrent {
539 False,
540 True,
541 Page,
542 Step,
543 Location,
544 Date,
545 Time,
546}
547
548#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
549#[cfg_attr(feature = "enumn", derive(enumn::N))]
550#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
551#[cfg_attr(feature = "schemars", derive(JsonSchema))]
552#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
553#[cfg_attr(
554 feature = "pyo3",
555 pyclass(
556 module = "accesskit",
557 rename_all = "SCREAMING_SNAKE_CASE",
558 eq,
559 from_py_object
560 )
561)]
562#[repr(u8)]
563pub enum AutoComplete {
564 Inline,
565 List,
566 Both,
567}
568
569#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
570#[cfg_attr(feature = "enumn", derive(enumn::N))]
571#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
572#[cfg_attr(feature = "schemars", derive(JsonSchema))]
573#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
574#[cfg_attr(
575 feature = "pyo3",
576 pyclass(
577 module = "accesskit",
578 rename_all = "SCREAMING_SNAKE_CASE",
579 eq,
580 from_py_object
581 )
582)]
583#[repr(u8)]
584pub enum Live {
585 Off,
586 Polite,
587 Assertive,
588}
589
590#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
591#[cfg_attr(feature = "enumn", derive(enumn::N))]
592#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
593#[cfg_attr(feature = "schemars", derive(JsonSchema))]
594#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
595#[cfg_attr(
596 feature = "pyo3",
597 pyclass(
598 module = "accesskit",
599 rename_all = "SCREAMING_SNAKE_CASE",
600 eq,
601 from_py_object
602 )
603)]
604#[repr(u8)]
605pub enum HasPopup {
606 Menu,
607 Listbox,
608 Tree,
609 Grid,
610 Dialog,
611}
612
613#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
614#[cfg_attr(feature = "enumn", derive(enumn::N))]
615#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
616#[cfg_attr(feature = "schemars", derive(JsonSchema))]
617#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
618#[cfg_attr(
619 feature = "pyo3",
620 pyclass(
621 module = "accesskit",
622 rename_all = "SCREAMING_SNAKE_CASE",
623 eq,
624 from_py_object
625 )
626)]
627#[repr(u8)]
628pub enum ListStyle {
629 Circle,
630 Disc,
631 Image,
632 Numeric,
633 Square,
634 Other,
636}
637
638#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
639#[cfg_attr(feature = "enumn", derive(enumn::N))]
640#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
641#[cfg_attr(feature = "schemars", derive(JsonSchema))]
642#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
643#[cfg_attr(
644 feature = "pyo3",
645 pyclass(
646 module = "accesskit",
647 rename_all = "SCREAMING_SNAKE_CASE",
648 eq,
649 from_py_object
650 )
651)]
652#[repr(u8)]
653pub enum TextAlign {
654 Left,
655 Right,
656 Center,
657 Justify,
658}
659
660#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
661#[cfg_attr(feature = "enumn", derive(enumn::N))]
662#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
663#[cfg_attr(feature = "schemars", derive(JsonSchema))]
664#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
665#[cfg_attr(
666 feature = "pyo3",
667 pyclass(
668 module = "accesskit",
669 rename_all = "SCREAMING_SNAKE_CASE",
670 eq,
671 from_py_object
672 )
673)]
674#[repr(u8)]
675pub enum VerticalOffset {
676 Subscript,
677 Superscript,
678}
679
680#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
681#[cfg_attr(feature = "enumn", derive(enumn::N))]
682#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
683#[cfg_attr(feature = "schemars", derive(JsonSchema))]
684#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
685#[cfg_attr(
686 feature = "pyo3",
687 pyclass(
688 module = "accesskit",
689 rename_all = "SCREAMING_SNAKE_CASE",
690 eq,
691 from_py_object
692 )
693)]
694#[repr(u8)]
695pub enum TextDecorationStyle {
696 Solid,
697 Dotted,
698 Dashed,
699 Double,
700 Wavy,
701}
702
703pub type NodeIdContent = u64;
704
705#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
712#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
713#[cfg_attr(feature = "schemars", derive(JsonSchema))]
714#[repr(transparent)]
715pub struct NodeId(pub NodeIdContent);
716
717impl From<NodeIdContent> for NodeId {
718 #[inline]
719 fn from(inner: NodeIdContent) -> Self {
720 Self(inner)
721 }
722}
723
724impl From<NodeId> for NodeIdContent {
725 #[inline]
726 fn from(outer: NodeId) -> Self {
727 outer.0
728 }
729}
730
731impl fmt::Debug for NodeId {
732 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
733 write!(f, "#{}", self.0)
734 }
735}
736
737#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
742#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
743#[cfg_attr(feature = "schemars", derive(JsonSchema))]
744#[repr(transparent)]
745pub struct TreeId(pub Uuid);
746
747impl TreeId {
748 pub const ROOT: Self = Self(Uuid::nil());
750}
751
752#[derive(Clone, Debug, PartialEq, Eq)]
757#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
758#[cfg_attr(feature = "schemars", derive(JsonSchema))]
759#[cfg_attr(feature = "serde", serde(deny_unknown_fields))]
760#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
761pub struct CustomAction {
762 pub id: i32,
763 pub description: String,
764}
765
766#[derive(Clone, Copy, Debug, PartialEq, Eq)]
767#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
768#[cfg_attr(feature = "schemars", derive(JsonSchema))]
769#[cfg_attr(feature = "serde", serde(deny_unknown_fields))]
770#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
771pub struct TextPosition {
772 pub node: NodeId,
774 pub character_index: usize,
777}
778
779#[derive(Clone, Copy, Debug, PartialEq, Eq)]
780#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
781#[cfg_attr(feature = "schemars", derive(JsonSchema))]
782#[cfg_attr(feature = "serde", serde(deny_unknown_fields))]
783#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
784pub struct TextSelection {
785 pub anchor: TextPosition,
790 pub focus: TextPosition,
794}
795
796#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
797#[cfg_attr(feature = "serde", derive(Serialize, Deserialize, enumn::N))]
798#[cfg_attr(feature = "schemars", derive(JsonSchema))]
799#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
800#[repr(u8)]
801enum Flag {
802 Hidden,
803 Multiselectable,
804 Required,
805 Visited,
806 Busy,
807 LiveAtomic,
808 Modal,
809 TouchTransparent,
810 ReadOnly,
811 Disabled,
812 Italic,
813 ClipsChildren,
814 IsLineBreakingObject,
815 IsPageBreakingObject,
816 IsSpellingError,
817 IsGrammarError,
818 IsSearchMatch,
819 IsSuggestion,
820}
821
822impl Flag {
823 fn mask(self) -> u32 {
824 1 << (self as u8)
825 }
826}
827
828#[derive(Clone, Copy, Debug, PartialEq, Eq)]
830#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
831#[cfg_attr(feature = "schemars", derive(JsonSchema))]
832#[cfg_attr(feature = "serde", serde(deny_unknown_fields))]
833#[repr(C)]
834pub struct Color {
835 pub red: u8,
836 pub green: u8,
837 pub blue: u8,
838 pub alpha: u8,
839}
840
841#[derive(Clone, Copy, Debug, PartialEq, Eq)]
843#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
844#[cfg_attr(feature = "schemars", derive(JsonSchema))]
845#[cfg_attr(feature = "serde", serde(deny_unknown_fields))]
846#[repr(C)]
847pub struct TextDecoration {
848 pub style: TextDecorationStyle,
849 pub color: Color,
850}
851
852#[derive(Debug, PartialEq)]
856enum PropertyValue {
857 None,
858 NodeIdVec(Vec<NodeId>),
859 NodeId(NodeId),
860 String(String),
861 F64(f64),
862 F32(f32),
863 Usize(usize),
864 Color(Color),
865 TextDecoration(TextDecoration),
866 LengthVec(Vec<u8>),
867 CoordVec(Vec<f32>),
868 Bool(bool),
869 Invalid(Invalid),
870 Toggled(Toggled),
871 Live(Live),
872 TextDirection(TextDirection),
873 Orientation(Orientation),
874 SortDirection(SortDirection),
875 AriaCurrent(AriaCurrent),
876 AutoComplete(AutoComplete),
877 HasPopup(HasPopup),
878 ListStyle(ListStyle),
879 TextAlign(TextAlign),
880 VerticalOffset(VerticalOffset),
881 Affine(Box<Affine>),
882 Rect(Rect),
883 TextSelection(Box<TextSelection>),
884 CustomActionVec(Vec<CustomAction>),
885 TreeId(TreeId),
886}
887
888#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
889#[cfg_attr(feature = "serde", derive(Serialize, Deserialize, enumn::N))]
890#[cfg_attr(feature = "schemars", derive(JsonSchema))]
891#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
892#[repr(u8)]
893enum PropertyId {
894 Children,
896 Controls,
897 Details,
898 DescribedBy,
899 FlowTo,
900 LabelledBy,
901 Owns,
902 RadioGroup,
903
904 ActiveDescendant,
906 ErrorMessage,
907 InPageLinkTarget,
908 MemberOf,
909 NextOnLine,
910 PreviousOnLine,
911 PopupFor,
912
913 Label,
915 Description,
916 Value,
917 AccessKey,
918 AuthorId,
919 ClassName,
920 FontFamily,
921 HtmlId,
922 HtmlTag,
923 InnerHtml,
924 KeyboardShortcut,
925 Language,
926 Placeholder,
927 RoleDescription,
928 StateDescription,
929 Tooltip,
930 Url,
931 RowIndexText,
932 ColumnIndexText,
933 BrailleLabel,
934 BrailleRoleDescription,
935
936 ScrollX,
938 ScrollXMin,
939 ScrollXMax,
940 ScrollY,
941 ScrollYMin,
942 ScrollYMax,
943 NumericValue,
944 MinNumericValue,
945 MaxNumericValue,
946 NumericValueStep,
947 NumericValueJump,
948
949 FontSize,
951 FontWeight,
952
953 RowCount,
955 ColumnCount,
956 RowIndex,
957 ColumnIndex,
958 RowSpan,
959 ColumnSpan,
960 Level,
961 SizeOfSet,
962 PositionInSet,
963
964 ColorValue,
966 BackgroundColor,
967 ForegroundColor,
968
969 Overline,
971 Strikethrough,
972 Underline,
973
974 CharacterLengths,
976 WordStarts,
977
978 CharacterPositions,
980 CharacterWidths,
981
982 Expanded,
984 Selected,
985
986 Invalid,
988 Toggled,
989 Live,
990 TextDirection,
991 Orientation,
992 SortDirection,
993 AriaCurrent,
994 AutoComplete,
995 HasPopup,
996 ListStyle,
997 TextAlign,
998 VerticalOffset,
999
1000 Transform,
1002 Bounds,
1003 TextSelection,
1004 CustomActions,
1005 TreeId,
1006
1007 Unset,
1009}
1010
1011impl Clone for PropertyValue {
1012 fn clone(&self) -> Self {
1013 match self {
1014 Self::None => Self::None,
1015 Self::NodeIdVec(v) => Self::NodeIdVec(v.clone()),
1016 Self::NodeId(v) => Self::NodeId(*v),
1017 Self::String(v) => Self::String(v.clone()),
1018 Self::F64(v) => Self::F64(*v),
1019 Self::F32(v) => Self::F32(*v),
1020 Self::Usize(v) => Self::Usize(*v),
1021 Self::Color(v) => Self::Color(*v),
1022 Self::TextDecoration(v) => Self::TextDecoration(*v),
1023 Self::LengthVec(v) => Self::LengthVec(v.clone()),
1024 Self::CoordVec(v) => Self::CoordVec(v.clone()),
1025 Self::Bool(v) => Self::Bool(*v),
1026 Self::Invalid(v) => Self::Invalid(*v),
1027 Self::Toggled(v) => Self::Toggled(*v),
1028 Self::Live(v) => Self::Live(*v),
1029 Self::TextDirection(v) => Self::TextDirection(*v),
1030 Self::Orientation(v) => Self::Orientation(*v),
1031 Self::SortDirection(v) => Self::SortDirection(*v),
1032 Self::AriaCurrent(v) => Self::AriaCurrent(*v),
1033 Self::AutoComplete(v) => Self::AutoComplete(*v),
1034 Self::HasPopup(v) => Self::HasPopup(*v),
1035 Self::ListStyle(v) => Self::ListStyle(*v),
1036 Self::TextAlign(v) => Self::TextAlign(*v),
1037 Self::VerticalOffset(v) => Self::VerticalOffset(*v),
1038 Self::Affine(v) => Self::Affine(v.clone()),
1039 Self::Rect(v) => Self::Rect(*v),
1040 Self::TextSelection(v) => Self::TextSelection(v.clone()),
1041 Self::CustomActionVec(v) => Self::CustomActionVec(v.clone()),
1042 Self::TreeId(v) => Self::TreeId(*v),
1043 }
1044 }
1045
1046 fn clone_from(&mut self, source: &Self) {
1047 match (self, source) {
1048 (Self::NodeIdVec(dest), Self::NodeIdVec(source)) => dest.clone_from(source),
1049 (Self::String(dest), Self::String(source)) => dest.clone_from(source),
1050 (Self::LengthVec(dest), Self::LengthVec(source)) => dest.clone_from(source),
1051 (Self::CoordVec(dest), Self::CoordVec(source)) => dest.clone_from(source),
1052 (Self::CustomActionVec(dest), Self::CustomActionVec(source)) => dest.clone_from(source),
1053 (Self::Affine(dest), Self::Affine(source)) => dest.clone_from(source),
1054 (Self::TextSelection(dest), Self::TextSelection(source)) => dest.clone_from(source),
1055 (dest, source) => *dest = source.clone(),
1056 }
1057 }
1058}
1059
1060#[derive(Clone, Copy, Debug, PartialEq, Eq)]
1061#[repr(transparent)]
1062struct PropertyIndices([u8; PropertyId::Unset as usize]);
1063
1064impl Default for PropertyIndices {
1065 fn default() -> Self {
1066 Self([PropertyId::Unset as u8; PropertyId::Unset as usize])
1067 }
1068}
1069
1070#[derive(Debug, Default)]
1071struct Properties {
1072 indices: PropertyIndices,
1073 values: Vec<PropertyValue>,
1074}
1075
1076fn value_at(values: &[PropertyValue], index: u8) -> &PropertyValue {
1077 if index == PropertyId::Unset as u8 {
1078 &PropertyValue::None
1079 } else {
1080 &values[index as usize]
1081 }
1082}
1083
1084impl PartialEq for Properties {
1085 fn eq(&self, other: &Self) -> bool {
1086 self.indices
1087 .0
1088 .iter()
1089 .zip(other.indices.0.iter())
1090 .all(|(&own, &other_index)| {
1091 value_at(&self.values, own) == value_at(&other.values, other_index)
1092 })
1093 }
1094}
1095
1096#[derive(Default, PartialEq)]
1103#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1104#[cfg_attr(feature = "schemars", derive(JsonSchema))]
1105#[cfg_attr(feature = "serde", serde(deny_unknown_fields))]
1106#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
1107pub struct Node {
1108 role: Role,
1109 actions: u32,
1110 child_actions: u32,
1111 flags: u32,
1112 properties: Properties,
1113}
1114
1115impl PropertyIndices {
1116 fn get<'a>(&self, values: &'a [PropertyValue], id: PropertyId) -> &'a PropertyValue {
1117 value_at(values, self.0[id as usize])
1118 }
1119}
1120
1121impl Properties {
1122 fn get_mut(&mut self, id: PropertyId, default: PropertyValue) -> &mut PropertyValue {
1123 let index = self.indices.0[id as usize] as usize;
1124 if index == PropertyId::Unset as usize {
1125 self.values.push(default);
1126 let index = self.values.len() - 1;
1127 self.indices.0[id as usize] = index as u8;
1128 &mut self.values[index]
1129 } else {
1130 let value = &mut self.values[index];
1131 if matches!(value, PropertyValue::None) {
1132 *value = default;
1133 }
1134 value
1135 }
1136 }
1137
1138 fn set(&mut self, id: PropertyId, value: PropertyValue) {
1139 let index = self.indices.0[id as usize];
1140 if index == PropertyId::Unset as u8 {
1141 self.values.push(value);
1142 self.indices.0[id as usize] = (self.values.len() - 1) as u8;
1143 } else {
1144 self.values[index as usize] = value;
1145 }
1146 }
1147
1148 fn clear(&mut self, id: PropertyId) {
1149 let index = self.indices.0[id as usize];
1150 if index != PropertyId::Unset as u8 {
1151 self.values[index as usize] = PropertyValue::None;
1152 }
1153 }
1154}
1155
1156impl Clone for Properties {
1157 fn clone(&self) -> Self {
1158 Self {
1159 indices: self.indices,
1160 values: self.values.clone(),
1161 }
1162 }
1163
1164 fn clone_from(&mut self, source: &Self) {
1165 self.indices = source.indices;
1166 source.values.clone_into(&mut self.values);
1167 }
1168}
1169
1170macro_rules! flag_methods {
1171 ($($(#[$doc:meta])* ($id:ident, $getter:ident, $setter:ident, $clearer:ident)),+) => {
1172 impl Node {
1173 $($(#[$doc])*
1174 #[inline]
1175 pub fn $getter(&self) -> bool {
1176 (self.flags & (Flag::$id).mask()) != 0
1177 }
1178 #[inline]
1179 pub fn $setter(&mut self) {
1180 self.flags |= (Flag::$id).mask();
1181 }
1182 #[inline]
1183 pub fn $clearer(&mut self) {
1184 self.flags &= !((Flag::$id).mask());
1185 })*
1186 fn debug_flag_properties(&self, fmt: &mut fmt::DebugStruct) {
1187 $(
1188 if self.$getter() {
1189 fmt.field(stringify!($getter), &true);
1190 }
1191 )*
1192 }
1193 }
1194 $(#[cfg(test)]
1195 mod $getter {
1196 use super::{Node, Role};
1197
1198 #[test]
1199 fn getter_should_return_default_value() {
1200 let node = Node::new(Role::Unknown);
1201 assert!(!node.$getter());
1202 }
1203
1204 #[test]
1205 fn setter_should_update_the_property() {
1206 let mut node = Node::new(Role::Unknown);
1207 node.$setter();
1208 assert!(node.$getter());
1209 }
1210
1211 #[test]
1212 fn clearer_should_reset_the_property() {
1213 let mut node = Node::new(Role::Unknown);
1214 node.$setter();
1215 node.$clearer();
1216 assert!(!node.$getter());
1217 }
1218 })*
1219 }
1220}
1221
1222macro_rules! option_ref_type_getters {
1223 ($(($method:ident, $type:ty, $variant:ident)),+) => {
1224 impl PropertyIndices {
1225 $(fn $method<'a>(&self, values: &'a [PropertyValue], id: PropertyId) -> Option<&'a $type> {
1226 match self.get(values, id) {
1227 PropertyValue::$variant(value) => Some(value),
1228 _ => None,
1229 }
1230 })*
1231 }
1232 }
1233}
1234
1235macro_rules! slice_type_getters {
1236 ($(($method:ident, $type:ty, $variant:ident)),+) => {
1237 impl PropertyIndices {
1238 $(fn $method<'a>(&self, values: &'a [PropertyValue], id: PropertyId) -> &'a [$type] {
1239 match self.get(values, id) {
1240 PropertyValue::$variant(value) => value,
1241 _ => &[],
1242 }
1243 })*
1244 }
1245 }
1246}
1247
1248macro_rules! copy_type_getters {
1249 ($(($method:ident, $type:ty, $variant:ident)),+) => {
1250 impl PropertyIndices {
1251 $(fn $method(&self, values: &[PropertyValue], id: PropertyId) -> Option<$type> {
1252 match self.get(values, id) {
1253 PropertyValue::$variant(value) => Some(*value),
1254 _ => None,
1255 }
1256 })*
1257 }
1258 }
1259}
1260
1261macro_rules! owned_type_setters {
1262 ($(($method:ident, $type:ty, $variant:ident)),+) => {
1263 impl Node {
1264 $(fn $method(&mut self, id: PropertyId, value: impl Into<$type>) {
1265 self.properties.set(id, PropertyValue::$variant(value.into()));
1266 })*
1267 }
1268 }
1269}
1270
1271macro_rules! copy_type_setters {
1272 ($(($method:ident, $type:ty, $variant:ident)),+) => {
1273 impl Node {
1274 $(fn $method(&mut self, id: PropertyId, value: $type) {
1275 self.properties.set(id, PropertyValue::$variant(value));
1276 })*
1277 }
1278 }
1279}
1280
1281macro_rules! vec_type_methods {
1282 ($(($type:ty, $variant:ident, $getter:ident, $setter:ident, $pusher:ident)),+) => {
1283 $(slice_type_getters! {
1284 ($getter, $type, $variant)
1285 })*
1286 impl Node {
1287 $(fn $setter(&mut self, id: PropertyId, value: impl Into<Vec<$type>>) {
1288 self.properties.set(id, PropertyValue::$variant(value.into()));
1289 }
1290 fn $pusher(&mut self, id: PropertyId, item: $type) {
1291 if let PropertyValue::$variant(v) = self.properties.get_mut(id, PropertyValue::$variant(Vec::new())) {
1292 v.push(item);
1293 }
1294 })*
1295 }
1296 }
1297}
1298
1299macro_rules! property_methods {
1300 ($($(#[$doc:meta])* ($id:ident, $getter:ident, $type_getter:ident, $getter_result:ty, $setter:ident, $type_setter:ident, $setter_param:ty, $clearer:ident)),+) => {
1301 impl Node {
1302 $($(#[$doc])*
1303 #[inline]
1304 pub fn $getter(&self) -> $getter_result {
1305 self.properties.indices.$type_getter(&self.properties.values, PropertyId::$id)
1306 }
1307 #[inline]
1308 pub fn $setter(&mut self, value: $setter_param) {
1309 self.$type_setter(PropertyId::$id, value);
1310 }
1311 #[inline]
1312 pub fn $clearer(&mut self) {
1313 self.properties.clear(PropertyId::$id);
1314 })*
1315 }
1316 }
1317}
1318
1319macro_rules! vec_property_methods {
1320 ($($(#[$doc:meta])* ($id:ident, $item_type:ty, $getter:ident, $type_getter:ident, $setter:ident, $type_setter:ident, $pusher:ident, $type_pusher:ident, $clearer:ident)),+) => {
1321 $(property_methods! {
1322 $(#[$doc])*
1323 ($id, $getter, $type_getter, &[$item_type], $setter, $type_setter, impl Into<Vec<$item_type>>, $clearer)
1324 }
1325 impl Node {
1326 #[inline]
1327 pub fn $pusher(&mut self, item: $item_type) {
1328 self.$type_pusher(PropertyId::$id, item);
1329 }
1330 })*
1331 }
1332}
1333
1334macro_rules! vec_properties_debug_method {
1335 ($name:ident, [$($getter:ident,)*]) => {
1336 fn $name(&self, fmt: &mut fmt::DebugStruct) {
1337 $(
1338 let value = self.$getter();
1339 if !value.is_empty() {
1340 fmt.field(stringify!($getter), &value);
1341 }
1342 )*
1343 }
1344 }
1345}
1346
1347macro_rules! node_id_vec_property_methods {
1348 ($($(#[$doc:meta])* ($id:ident, $getter:ident, $setter:ident, $pusher:ident, $clearer:ident)),+) => {
1349 $(vec_property_methods! {
1350 $(#[$doc])*
1351 ($id, NodeId, $getter, get_node_id_vec, $setter, set_node_id_vec, $pusher, push_to_node_id_vec, $clearer)
1352 })*
1353 impl Node {
1354 vec_properties_debug_method! { debug_node_id_vec_properties, [$($getter,)*] }
1355 }
1356 $(#[cfg(test)]
1357 mod $getter {
1358 use super::{Node, NodeId, Role};
1359
1360 #[test]
1361 fn getter_should_return_default_value() {
1362 let node = Node::new(Role::Unknown);
1363 assert!(node.$getter().is_empty());
1364 }
1365 #[test]
1366 fn setter_should_update_the_property() {
1367 let mut node = Node::new(Role::Unknown);
1368 node.$setter([]);
1369 assert!(node.$getter().is_empty());
1370 node.$setter([NodeId(0), NodeId(1)]);
1371 assert_eq!(node.$getter(), &[NodeId(0), NodeId(1)]);
1372 }
1373 #[test]
1374 fn pusher_should_update_the_property() {
1375 let mut node = Node::new(Role::Unknown);
1376 node.$pusher(NodeId(0));
1377 assert_eq!(node.$getter(), &[NodeId(0)]);
1378 node.$pusher(NodeId(1));
1379 assert_eq!(node.$getter(), &[NodeId(0), NodeId(1)]);
1380 }
1381 #[test]
1382 fn pusher_should_start_a_new_list_after_the_clearer() {
1383 let mut node = Node::new(Role::Unknown);
1384 node.$setter([NodeId(0)]);
1385 node.$clearer();
1386 node.$pusher(NodeId(1));
1387 assert_eq!(node.$getter(), &[NodeId(1)]);
1388 }
1389 #[test]
1390 fn clearer_should_reset_the_property() {
1391 let mut node = Node::new(Role::Unknown);
1392 node.$setter([NodeId(0)]);
1393 node.$clearer();
1394 assert!(node.$getter().is_empty());
1395 }
1396 })*
1397 }
1398}
1399
1400macro_rules! option_properties_debug_method {
1401 ($name:ident, [$($getter:ident,)*]) => {
1402 fn $name(&self, fmt: &mut fmt::DebugStruct) {
1403 $(
1404 if let Some(value) = self.$getter() {
1405 fmt.field(stringify!($getter), &value);
1406 }
1407 )*
1408 }
1409 }
1410}
1411
1412macro_rules! node_id_property_methods {
1413 ($($(#[$doc:meta])* ($id:ident, $getter:ident, $setter:ident, $clearer:ident)),+) => {
1414 $(property_methods! {
1415 $(#[$doc])*
1416 ($id, $getter, get_node_id_property, Option<NodeId>, $setter, set_node_id_property, NodeId, $clearer)
1417 })*
1418 impl Node {
1419 option_properties_debug_method! { debug_node_id_properties, [$($getter,)*] }
1420 }
1421 $(#[cfg(test)]
1422 mod $getter {
1423 use super::{Node, NodeId, Role};
1424
1425 #[test]
1426 fn getter_should_return_default_value() {
1427 let node = Node::new(Role::Unknown);
1428 assert!(node.$getter().is_none());
1429 }
1430 #[test]
1431 fn setter_should_update_the_property() {
1432 let mut node = Node::new(Role::Unknown);
1433 node.$setter(NodeId(1));
1434 assert_eq!(node.$getter(), Some(NodeId(1)));
1435 }
1436 #[test]
1437 fn clearer_should_reset_the_property() {
1438 let mut node = Node::new(Role::Unknown);
1439 node.$setter(NodeId(1));
1440 node.$clearer();
1441 assert!(node.$getter().is_none());
1442 }
1443 })*
1444 }
1445}
1446
1447macro_rules! string_property_methods {
1448 ($($(#[$doc:meta])* ($id:ident, $getter:ident, $setter:ident, $clearer:ident)),+) => {
1449 $(property_methods! {
1450 $(#[$doc])*
1451 ($id, $getter, get_string_property, Option<&str>, $setter, set_string_property, impl Into<String>, $clearer)
1452 })*
1453 impl Node {
1454 option_properties_debug_method! { debug_string_properties, [$($getter,)*] }
1455 }
1456 $(#[cfg(test)]
1457 mod $getter {
1458 use super::{Node, Role};
1459
1460 #[test]
1461 fn getter_should_return_default_value() {
1462 let node = Node::new(Role::Unknown);
1463 assert!(node.$getter().is_none());
1464 }
1465 #[test]
1466 fn setter_should_update_the_property() {
1467 let mut node = Node::new(Role::Unknown);
1468 node.$setter("test");
1469 assert_eq!(node.$getter(), Some("test"));
1470 }
1471 #[test]
1472 fn clearer_should_reset_the_property() {
1473 let mut node = Node::new(Role::Unknown);
1474 node.$setter("test");
1475 node.$clearer();
1476 assert!(node.$getter().is_none());
1477 }
1478 })*
1479 }
1480}
1481
1482macro_rules! f64_property_methods {
1483 ($($(#[$doc:meta])* ($id:ident, $getter:ident, $setter:ident, $clearer:ident)),+) => {
1484 $(property_methods! {
1485 $(#[$doc])*
1486 ($id, $getter, get_f64_property, Option<f64>, $setter, set_f64_property, f64, $clearer)
1487 })*
1488 impl Node {
1489 option_properties_debug_method! { debug_f64_properties, [$($getter,)*] }
1490 }
1491 $(#[cfg(test)]
1492 mod $getter {
1493 use super::{Node, Role};
1494
1495 #[test]
1496 fn getter_should_return_default_value() {
1497 let node = Node::new(Role::Unknown);
1498 assert!(node.$getter().is_none());
1499 }
1500 #[test]
1501 fn setter_should_update_the_property() {
1502 let mut node = Node::new(Role::Unknown);
1503 node.$setter(1.0);
1504 assert_eq!(node.$getter(), Some(1.0));
1505 }
1506 #[test]
1507 fn clearer_should_reset_the_property() {
1508 let mut node = Node::new(Role::Unknown);
1509 node.$setter(1.0);
1510 node.$clearer();
1511 assert!(node.$getter().is_none());
1512 }
1513 })*
1514 }
1515}
1516
1517macro_rules! f32_property_methods {
1518 ($($(#[$doc:meta])* ($id:ident, $getter:ident, $setter:ident, $clearer:ident)),+) => {
1519 $(property_methods! {
1520 $(#[$doc])*
1521 ($id, $getter, get_f32_property, Option<f32>, $setter, set_f32_property, f32, $clearer)
1522 })*
1523 impl Node {
1524 option_properties_debug_method! { debug_f32_properties, [$($getter,)*] }
1525 }
1526 $(#[cfg(test)]
1527 mod $getter {
1528 use super::{Node, Role};
1529
1530 #[test]
1531 fn getter_should_return_default_value() {
1532 let node = Node::new(Role::Unknown);
1533 assert!(node.$getter().is_none());
1534 }
1535 #[test]
1536 fn setter_should_update_the_property() {
1537 let mut node = Node::new(Role::Unknown);
1538 node.$setter(1.0);
1539 assert_eq!(node.$getter(), Some(1.0));
1540 }
1541 #[test]
1542 fn clearer_should_reset_the_property() {
1543 let mut node = Node::new(Role::Unknown);
1544 node.$setter(1.0);
1545 node.$clearer();
1546 assert!(node.$getter().is_none());
1547 }
1548 })*
1549 }
1550}
1551
1552macro_rules! usize_property_methods {
1553 ($($(#[$doc:meta])* ($id:ident, $getter:ident, $setter:ident, $clearer:ident)),+) => {
1554 $(property_methods! {
1555 $(#[$doc])*
1556 ($id, $getter, get_usize_property, Option<usize>, $setter, set_usize_property, usize, $clearer)
1557 })*
1558 impl Node {
1559 option_properties_debug_method! { debug_usize_properties, [$($getter,)*] }
1560 }
1561 $(#[cfg(test)]
1562 mod $getter {
1563 use super::{Node, Role};
1564
1565 #[test]
1566 fn getter_should_return_default_value() {
1567 let node = Node::new(Role::Unknown);
1568 assert!(node.$getter().is_none());
1569 }
1570 #[test]
1571 fn setter_should_update_the_property() {
1572 let mut node = Node::new(Role::Unknown);
1573 node.$setter(1);
1574 assert_eq!(node.$getter(), Some(1));
1575 }
1576 #[test]
1577 fn clearer_should_reset_the_property() {
1578 let mut node = Node::new(Role::Unknown);
1579 node.$setter(1);
1580 node.$clearer();
1581 assert!(node.$getter().is_none());
1582 }
1583 })*
1584 }
1585}
1586
1587macro_rules! color_property_methods {
1588 ($($(#[$doc:meta])* ($id:ident, $getter:ident, $setter:ident, $clearer:ident)),+) => {
1589 $(property_methods! {
1590 $(#[$doc])*
1591 ($id, $getter, get_color_property, Option<Color>, $setter, set_color_property, Color, $clearer)
1592 })*
1593 impl Node {
1594 option_properties_debug_method! { debug_color_properties, [$($getter,)*] }
1595 }
1596 $(#[cfg(test)]
1597 mod $getter {
1598 use super::{Color, Node, Role};
1599
1600 #[test]
1601 fn getter_should_return_default_value() {
1602 let node = Node::new(Role::Unknown);
1603 assert!(node.$getter().is_none());
1604 }
1605 #[test]
1606 fn setter_should_update_the_property() {
1607 let mut node = Node::new(Role::Unknown);
1608 node.$setter(Color { red: 255, green: 255, blue: 255, alpha: 255 });
1609 assert_eq!(node.$getter(), Some(Color { red: 255, green: 255, blue: 255, alpha: 255 }));
1610 }
1611 #[test]
1612 fn clearer_should_reset_the_property() {
1613 let mut node = Node::new(Role::Unknown);
1614 node.$setter(Color { red: 255, green: 255, blue: 255, alpha: 255 });
1615 node.$clearer();
1616 assert!(node.$getter().is_none());
1617 }
1618 })*
1619 }
1620}
1621
1622macro_rules! text_decoration_property_methods {
1623 ($($(#[$doc:meta])* ($id:ident, $getter:ident, $setter:ident, $clearer:ident)),+) => {
1624 $(property_methods! {
1625 $(#[$doc])*
1626 ($id, $getter, get_text_decoration_property, Option<TextDecoration>, $setter, set_text_decoration_property, TextDecoration, $clearer)
1627 })*
1628 impl Node {
1629 option_properties_debug_method! { debug_text_decoration_properties, [$($getter,)*] }
1630 }
1631 $(#[cfg(test)]
1632 mod $getter {
1633 use super::{Color, Node, Role, TextDecoration, TextDecorationStyle};
1634
1635 const TEST_TEXT_DECORATION: TextDecoration = TextDecoration {
1636 style: TextDecorationStyle::Dotted,
1637 color: Color {
1638 red: 0,
1639 green: 0,
1640 blue: 0,
1641 alpha: 255,
1642 },
1643 };
1644
1645 #[test]
1646 fn getter_should_return_default_value() {
1647 let node = Node::new(Role::Unknown);
1648 assert!(node.$getter().is_none());
1649 }
1650 #[test]
1651 fn setter_should_update_the_property() {
1652 let mut node = Node::new(Role::Unknown);
1653 node.$setter(TEST_TEXT_DECORATION);
1654 assert_eq!(node.$getter(), Some(TEST_TEXT_DECORATION));
1655 }
1656 #[test]
1657 fn clearer_should_reset_the_property() {
1658 let mut node = Node::new(Role::Unknown);
1659 node.$setter(TEST_TEXT_DECORATION);
1660 node.$clearer();
1661 assert!(node.$getter().is_none());
1662 }
1663 })*
1664 }
1665}
1666
1667macro_rules! length_vec_property_methods {
1668 ($($(#[$doc:meta])* ($id:ident, $getter:ident, $setter:ident, $clearer:ident)),+) => {
1669 $(property_methods! {
1670 $(#[$doc])*
1671 ($id, $getter, get_length_vec_property, &[u8], $setter, set_length_vec_property, impl Into<Vec<u8>>, $clearer)
1672 })*
1673 impl Node {
1674 vec_properties_debug_method! { debug_length_vec_properties, [$($getter,)*] }
1675 }
1676 $(#[cfg(test)]
1677 mod $getter {
1678 use super::{Node, Role};
1679
1680 #[test]
1681 fn getter_should_return_default_value() {
1682 let node = Node::new(Role::Unknown);
1683 assert!(node.$getter().is_empty());
1684 }
1685 #[test]
1686 fn setter_should_update_the_property() {
1687 let mut node = Node::new(Role::Unknown);
1688 node.$setter([]);
1689 assert!(node.$getter().is_empty());
1690 node.$setter([1, 2]);
1691 assert_eq!(node.$getter(), &[1, 2]);
1692 }
1693 #[test]
1694 fn clearer_should_reset_the_property() {
1695 let mut node = Node::new(Role::Unknown);
1696 node.$setter([1, 2]);
1697 node.$clearer();
1698 assert!(node.$getter().is_empty());
1699 }
1700 })*
1701 }
1702}
1703
1704macro_rules! coord_vec_property_methods {
1705 ($($(#[$doc:meta])* ($id:ident, $getter:ident, $setter:ident, $clearer:ident)),+) => {
1706 $(property_methods! {
1707 $(#[$doc])*
1708 ($id, $getter, get_coord_vec_property, Option<&[f32]>, $setter, set_coord_vec_property, impl Into<Vec<f32>>, $clearer)
1709 })*
1710 impl Node {
1711 option_properties_debug_method! { debug_coord_vec_properties, [$($getter,)*] }
1712 }
1713 $(#[cfg(test)]
1714 mod $getter {
1715 use super::{Node, Role};
1716
1717 #[test]
1718 fn getter_should_return_default_value() {
1719 let node = Node::new(Role::Unknown);
1720 assert!(node.$getter().is_none());
1721 }
1722 #[test]
1723 fn setter_should_update_the_property() {
1724 let mut node = Node::new(Role::Unknown);
1725 node.$setter([]);
1726 let expected: Option<&[f32]> = Some(&[]);
1727 assert_eq!(node.$getter(), expected);
1728 node.$setter([1.0, 2.0]);
1729 let expected: Option<&[f32]> = Some(&[1.0, 2.0]);
1730 assert_eq!(node.$getter(), expected);
1731 }
1732 #[test]
1733 fn clearer_should_reset_the_property() {
1734 let mut node = Node::new(Role::Unknown);
1735 node.$setter([1.0, 2.0]);
1736 node.$clearer();
1737 assert!(node.$getter().is_none());
1738 }
1739 })*
1740 }
1741}
1742
1743macro_rules! bool_property_methods {
1744 ($($(#[$doc:meta])* ($id:ident, $getter:ident, $setter:ident, $clearer:ident)),+) => {
1745 $(property_methods! {
1746 $(#[$doc])*
1747 ($id, $getter, get_bool_property, Option<bool>, $setter, set_bool_property, bool, $clearer)
1748 })*
1749 impl Node {
1750 option_properties_debug_method! { debug_bool_properties, [$($getter,)*] }
1751 }
1752 $(#[cfg(test)]
1753 mod $getter {
1754 use super::{Node, Role};
1755
1756 #[test]
1757 fn getter_should_return_default_value() {
1758 let node = Node::new(Role::Unknown);
1759 assert!(node.$getter().is_none());
1760 }
1761 #[test]
1762 fn setter_should_update_the_property() {
1763 let mut node = Node::new(Role::Unknown);
1764 node.$setter(true);
1765 assert_eq!(node.$getter(), Some(true));
1766 }
1767 #[test]
1768 fn clearer_should_reset_the_property() {
1769 let mut node = Node::new(Role::Unknown);
1770 node.$setter(true);
1771 node.$clearer();
1772 assert!(node.$getter().is_none());
1773 }
1774 })*
1775 }
1776}
1777
1778macro_rules! unique_enum_property_methods {
1779 ($($(#[$doc:meta])* ($id:ident, $getter:ident, $setter:ident, $clearer:ident, $variant:ident)),+) => {
1780 impl Node {
1781 $($(#[$doc])*
1782 #[inline]
1783 pub fn $getter(&self) -> Option<$id> {
1784 match self.properties.indices.get(&self.properties.values, PropertyId::$id) {
1785 PropertyValue::$id(value) => Some(*value),
1786 _ => None,
1787 }
1788 }
1789 #[inline]
1790 pub fn $setter(&mut self, value: $id) {
1791 self.properties.set(PropertyId::$id, PropertyValue::$id(value));
1792 }
1793 #[inline]
1794 pub fn $clearer(&mut self) {
1795 self.properties.clear(PropertyId::$id);
1796 })*
1797 option_properties_debug_method! { debug_unique_enum_properties, [$($getter,)*] }
1798 }
1799 $(#[cfg(test)]
1800 mod $getter {
1801 use super::{Node, Role};
1802
1803 #[test]
1804 fn getter_should_return_default_value() {
1805 let node = Node::new(Role::Unknown);
1806 assert!(node.$getter().is_none());
1807 }
1808 #[test]
1809 fn setter_should_update_the_property() {
1810 let mut node = Node::new(Role::Unknown);
1811 let variant = super::$id::$variant;
1812 node.$setter(variant);
1813 assert_eq!(node.$getter(), Some(variant));
1814 }
1815 #[test]
1816 fn clearer_should_reset_the_property() {
1817 let mut node = Node::new(Role::Unknown);
1818 node.$setter(super::$id::$variant);
1819 node.$clearer();
1820 assert!(node.$getter().is_none());
1821 }
1822 })*
1823 }
1824}
1825
1826impl Node {
1827 #[inline]
1828 pub fn new(role: Role) -> Self {
1829 Self {
1830 role,
1831 ..Default::default()
1832 }
1833 }
1834}
1835
1836impl Clone for Node {
1837 fn clone(&self) -> Self {
1838 Self {
1839 role: self.role,
1840 actions: self.actions,
1841 child_actions: self.child_actions,
1842 flags: self.flags,
1843 properties: self.properties.clone(),
1844 }
1845 }
1846
1847 fn clone_from(&mut self, source: &Self) {
1848 self.role = source.role;
1849 self.actions = source.actions;
1850 self.child_actions = source.child_actions;
1851 self.flags = source.flags;
1852 self.properties.clone_from(&source.properties);
1853 }
1854}
1855
1856impl Node {
1857 #[inline]
1858 pub fn role(&self) -> Role {
1859 self.role
1860 }
1861 #[inline]
1862 pub fn set_role(&mut self, value: Role) {
1863 self.role = value;
1864 }
1865
1866 #[inline]
1867 pub fn supports_action(&self, action: Action) -> bool {
1868 (self.actions & action.mask()) != 0
1869 }
1870 #[inline]
1871 pub fn add_action(&mut self, action: Action) {
1872 self.actions |= action.mask();
1873 }
1874 #[inline]
1875 pub fn remove_action(&mut self, action: Action) {
1876 self.actions &= !(action.mask());
1877 }
1878 #[inline]
1879 pub fn clear_actions(&mut self) {
1880 self.actions = 0;
1881 }
1882
1883 #[inline]
1886 pub fn child_supports_action(&self, action: Action) -> bool {
1887 (self.child_actions & action.mask()) != 0
1888 }
1889 #[inline]
1892 pub fn add_child_action(&mut self, action: Action) {
1893 self.child_actions |= action.mask();
1894 }
1895 #[inline]
1898 pub fn remove_child_action(&mut self, action: Action) {
1899 self.child_actions &= !(action.mask());
1900 }
1901 #[inline]
1904 pub fn clear_child_actions(&mut self) {
1905 self.child_actions = 0;
1906 }
1907}
1908
1909flag_methods! {
1910 (Hidden, is_hidden, set_hidden, clear_hidden),
1920 (Multiselectable, is_multiselectable, set_multiselectable, clear_multiselectable),
1925 (Required, is_required, set_required, clear_required),
1930 (Visited, is_visited, set_visited, clear_visited),
1932 (Busy, is_busy, set_busy, clear_busy),
1937 (LiveAtomic, is_live_atomic, set_live_atomic, clear_live_atomic),
1942 (Modal, is_modal, set_modal, clear_modal),
1946 (TouchTransparent, is_touch_transparent, set_touch_transparent, clear_touch_transparent),
1949 (ReadOnly, is_read_only, set_read_only, clear_read_only),
1954 (Disabled, is_disabled, set_disabled, clear_disabled),
1959 (Italic, is_italic, set_italic, clear_italic),
1961 (ClipsChildren, clips_children, set_clips_children, clear_clips_children),
1963 (IsLineBreakingObject, is_line_breaking_object, set_is_line_breaking_object, clear_is_line_breaking_object),
1965 (IsPageBreakingObject, is_page_breaking_object, set_is_page_breaking_object, clear_is_page_breaking_object),
1967 (IsSpellingError, is_spelling_error, set_is_spelling_error, clear_is_spelling_error),
1969 (IsGrammarError, is_grammar_error, set_is_grammar_error, clear_is_grammar_error),
1971 (IsSearchMatch, is_search_match, set_is_search_match, clear_is_search_match),
1973 (IsSuggestion, is_suggestion, set_is_suggestion, clear_is_suggestion)
1975}
1976
1977option_ref_type_getters! {
1978 (get_affine_property, Affine, Affine),
1979 (get_string_property, str, String),
1980 (get_coord_vec_property, [f32], CoordVec),
1981 (get_text_selection_property, TextSelection, TextSelection)
1982}
1983
1984slice_type_getters! {
1985 (get_length_vec_property, u8, LengthVec)
1986}
1987
1988copy_type_getters! {
1989 (get_rect_property, Rect, Rect),
1990 (get_node_id_property, NodeId, NodeId),
1991 (get_f64_property, f64, F64),
1992 (get_f32_property, f32, F32),
1993 (get_usize_property, usize, Usize),
1994 (get_color_property, Color, Color),
1995 (get_text_decoration_property, TextDecoration, TextDecoration),
1996 (get_bool_property, bool, Bool),
1997 (get_tree_id_property, TreeId, TreeId)
1998}
1999
2000owned_type_setters! {
2001 (set_affine_property, Box<Affine>, Affine),
2002 (set_string_property, String, String),
2003 (set_length_vec_property, Vec<u8>, LengthVec),
2004 (set_coord_vec_property, Vec<f32>, CoordVec),
2005 (set_text_selection_property, Box<TextSelection>, TextSelection)
2006}
2007
2008copy_type_setters! {
2009 (set_rect_property, Rect, Rect),
2010 (set_node_id_property, NodeId, NodeId),
2011 (set_f64_property, f64, F64),
2012 (set_f32_property, f32, F32),
2013 (set_usize_property, usize, Usize),
2014 (set_color_property, Color, Color),
2015 (set_text_decoration_property, TextDecoration, TextDecoration),
2016 (set_bool_property, bool, Bool),
2017 (set_tree_id_property, TreeId, TreeId)
2018}
2019
2020vec_type_methods! {
2021 (NodeId, NodeIdVec, get_node_id_vec, set_node_id_vec, push_to_node_id_vec),
2022 (CustomAction, CustomActionVec, get_custom_action_vec, set_custom_action_vec, push_to_custom_action_vec)
2023}
2024
2025node_id_vec_property_methods! {
2026 (Children, children, set_children, push_child, clear_children),
2029 (Controls, controls, set_controls, push_controlled, clear_controls),
2034 (Details, details, set_details, push_detail, clear_details),
2043 (DescribedBy, described_by, set_described_by, push_described_by, clear_described_by),
2049 (FlowTo, flow_to, set_flow_to, push_flow_to, clear_flow_to),
2054 (LabelledBy, labelled_by, set_labelled_by, push_labelled_by, clear_labelled_by),
2058 (Owns, owns, set_owns, push_owned, clear_owns),
2064 (RadioGroup, radio_group, set_radio_group, push_to_radio_group, clear_radio_group)
2067}
2068
2069node_id_property_methods! {
2070 (ActiveDescendant, active_descendant, set_active_descendant, clear_active_descendant),
2076 (ErrorMessage, error_message, set_error_message, clear_error_message),
2082 (InPageLinkTarget, in_page_link_target, set_in_page_link_target, clear_in_page_link_target),
2085 (MemberOf, member_of, set_member_of, clear_member_of),
2087 (NextOnLine, next_on_line, set_next_on_line, clear_next_on_line),
2090 (PreviousOnLine, previous_on_line, set_previous_on_line, clear_previous_on_line),
2093 (PopupFor, popup_for, set_popup_for, clear_popup_for)
2095}
2096
2097string_property_methods! {
2098 (Label, label, set_label, clear_label),
2105 (Description, description, set_description, clear_description),
2110 (Value, value, set_value, clear_value),
2119 (AccessKey, access_key, set_access_key, clear_access_key),
2127 (AuthorId, author_id, set_author_id, clear_author_id),
2130 (ClassName, class_name, set_class_name, clear_class_name),
2132 (FontFamily, font_family, set_font_family, clear_font_family),
2135 (HtmlId, html_id, set_html_id, clear_html_id),
2141 (HtmlTag, html_tag, set_html_tag, clear_html_tag),
2143 (InnerHtml, inner_html, set_inner_html, clear_inner_html),
2146 (KeyboardShortcut, keyboard_shortcut, set_keyboard_shortcut, clear_keyboard_shortcut),
2153 (Language, language, set_language, clear_language),
2156 (Placeholder, placeholder, set_placeholder, clear_placeholder),
2162 (RoleDescription, role_description, set_role_description, clear_role_description),
2169 (StateDescription, state_description, set_state_description, clear_state_description),
2174 (Tooltip, tooltip, set_tooltip, clear_tooltip),
2179 (Url, url, set_url, clear_url),
2181 (RowIndexText, row_index_text, set_row_index_text, clear_row_index_text),
2186 (ColumnIndexText, column_index_text, set_column_index_text, clear_column_index_text),
2191 (BrailleLabel, braille_label, set_braille_label, clear_braille_label),
2198 (BrailleRoleDescription, braille_role_description, set_braille_role_description, clear_braille_role_description)
2205}
2206
2207f64_property_methods! {
2208 (ScrollX, scroll_x, set_scroll_x, clear_scroll_x),
2210 (ScrollXMin, scroll_x_min, set_scroll_x_min, clear_scroll_x_min),
2212 (ScrollXMax, scroll_x_max, set_scroll_x_max, clear_scroll_x_max),
2214 (ScrollY, scroll_y, set_scroll_y, clear_scroll_y),
2216 (ScrollYMin, scroll_y_min, set_scroll_y_min, clear_scroll_y_min),
2218 (ScrollYMax, scroll_y_max, set_scroll_y_max, clear_scroll_y_max),
2220 (NumericValue, numeric_value, set_numeric_value, clear_numeric_value),
2225 (MinNumericValue, min_numeric_value, set_min_numeric_value, clear_min_numeric_value),
2230 (MaxNumericValue, max_numeric_value, set_max_numeric_value, clear_max_numeric_value),
2235 (NumericValueStep, numeric_value_step, set_numeric_value_step, clear_numeric_value_step),
2238 (NumericValueJump, numeric_value_jump, set_numeric_value_jump, clear_numeric_value_jump)
2241}
2242
2243f32_property_methods! {
2244 (FontSize, font_size, set_font_size, clear_font_size),
2246 (FontWeight, font_weight, set_font_weight, clear_font_weight)
2249}
2250
2251usize_property_methods! {
2252 (RowCount, row_count, set_row_count, clear_row_count),
2257 (ColumnCount, column_count, set_column_count, clear_column_count),
2262 (RowIndex, row_index, set_row_index, clear_row_index),
2270 (ColumnIndex, column_index, set_column_index, clear_column_index),
2278 (RowSpan, row_span, set_row_span, clear_row_span),
2283 (ColumnSpan, column_span, set_column_span, clear_column_span),
2288 (Level, level, set_level, clear_level),
2296 (SizeOfSet, size_of_set, set_size_of_set, clear_size_of_set),
2304 (PositionInSet, position_in_set, set_position_in_set, clear_position_in_set)
2314}
2315
2316color_property_methods! {
2317 (ColorValue, color_value, set_color_value, clear_color_value),
2319 (BackgroundColor, background_color, set_background_color, clear_background_color),
2321 (ForegroundColor, foreground_color, set_foreground_color, clear_foreground_color)
2323}
2324
2325text_decoration_property_methods! {
2326 (Overline, overline, set_overline, clear_overline),
2328 (Strikethrough, strikethrough, set_strikethrough, clear_strikethrough),
2330 (Underline, underline, set_underline, clear_underline)
2332}
2333
2334length_vec_property_methods! {
2335 (CharacterLengths, character_lengths, set_character_lengths, clear_character_lengths),
2354
2355 (WordStarts, word_starts, set_word_starts, clear_word_starts)
2385}
2386
2387coord_vec_property_methods! {
2388 (CharacterPositions, character_positions, set_character_positions, clear_character_positions),
2405
2406 (CharacterWidths, character_widths, set_character_widths, clear_character_widths)
2425}
2426
2427bool_property_methods! {
2428 (Expanded, is_expanded, set_expanded, clear_expanded),
2436
2437 (Selected, is_selected, set_selected, clear_selected)
2450}
2451
2452unique_enum_property_methods! {
2453 (Invalid, invalid, set_invalid, clear_invalid, Grammar),
2458 (Toggled, toggled, set_toggled, clear_toggled, True),
2468 (Live, live, set_live, clear_live, Polite),
2473 (TextDirection, text_direction, set_text_direction, clear_text_direction, RightToLeft),
2475 (Orientation, orientation, set_orientation, clear_orientation, Vertical),
2480 (SortDirection, sort_direction, set_sort_direction, clear_sort_direction, Descending),
2485 (AriaCurrent, aria_current, set_aria_current, clear_aria_current, True),
2490 (AutoComplete, auto_complete, set_auto_complete, clear_auto_complete, List),
2495 (HasPopup, has_popup, set_has_popup, clear_has_popup, Menu),
2500 (ListStyle, list_style, set_list_style, clear_list_style, Disc),
2502 (TextAlign, text_align, set_text_align, clear_text_align, Right),
2504 (VerticalOffset, vertical_offset, set_vertical_offset, clear_vertical_offset, Superscript)
2506}
2507
2508property_methods! {
2509 (Transform, transform, get_affine_property, Option<&Affine>, set_transform, set_affine_property, impl Into<Box<Affine>>, clear_transform),
2522
2523 (Bounds, bounds, get_rect_property, Option<Rect>, set_bounds, set_rect_property, Rect, clear_bounds),
2534
2535 (TextSelection, text_selection, get_text_selection_property, Option<&TextSelection>, set_text_selection, set_text_selection_property, impl Into<Box<TextSelection>>, clear_text_selection),
2537
2538 (TreeId, tree_id, get_tree_id_property, Option<TreeId>, set_tree_id, set_tree_id_property, TreeId, clear_tree_id)
2546}
2547
2548impl Node {
2549 option_properties_debug_method! { debug_option_properties, [transform, bounds, text_selection, tree_id,] }
2550}
2551
2552#[cfg(test)]
2553mod transform {
2554 use super::{Affine, Node, Role};
2555
2556 #[test]
2557 fn getter_should_return_default_value() {
2558 let node = Node::new(Role::Unknown);
2559 assert!(node.transform().is_none());
2560 }
2561 #[test]
2562 fn setter_should_update_the_property() {
2563 let mut node = Node::new(Role::Unknown);
2564 node.set_transform(Affine::IDENTITY);
2565 assert_eq!(node.transform(), Some(&Affine::IDENTITY));
2566 }
2567 #[test]
2568 fn clearer_should_reset_the_property() {
2569 let mut node = Node::new(Role::Unknown);
2570 node.set_transform(Affine::IDENTITY);
2571 node.clear_transform();
2572 assert!(node.transform().is_none());
2573 }
2574}
2575
2576#[cfg(test)]
2577mod bounds {
2578 use super::{Node, Rect, Role};
2579
2580 #[test]
2581 fn getter_should_return_default_value() {
2582 let node = Node::new(Role::Unknown);
2583 assert!(node.bounds().is_none());
2584 }
2585 #[test]
2586 fn setter_should_update_the_property() {
2587 let mut node = Node::new(Role::Unknown);
2588 let value = Rect {
2589 x0: 0.0,
2590 y0: 1.0,
2591 x1: 2.0,
2592 y1: 3.0,
2593 };
2594 node.set_bounds(value);
2595 assert_eq!(node.bounds(), Some(value));
2596 }
2597 #[test]
2598 fn clearer_should_reset_the_property() {
2599 let mut node = Node::new(Role::Unknown);
2600 node.set_bounds(Rect {
2601 x0: 0.0,
2602 y0: 1.0,
2603 x1: 2.0,
2604 y1: 3.0,
2605 });
2606 node.clear_bounds();
2607 assert!(node.bounds().is_none());
2608 }
2609}
2610
2611#[cfg(test)]
2612mod text_selection {
2613 use super::{Node, NodeId, Role, TextPosition, TextSelection};
2614
2615 #[test]
2616 fn getter_should_return_default_value() {
2617 let node = Node::new(Role::Unknown);
2618 assert!(node.text_selection().is_none());
2619 }
2620 #[test]
2621 fn setter_should_update_the_property() {
2622 let mut node = Node::new(Role::Unknown);
2623 let value = TextSelection {
2624 anchor: TextPosition {
2625 node: NodeId(0),
2626 character_index: 0,
2627 },
2628 focus: TextPosition {
2629 node: NodeId(0),
2630 character_index: 2,
2631 },
2632 };
2633 node.set_text_selection(value);
2634 assert_eq!(node.text_selection(), Some(&value));
2635 }
2636 #[test]
2637 fn clearer_should_reset_the_property() {
2638 let mut node = Node::new(Role::Unknown);
2639 node.set_text_selection(TextSelection {
2640 anchor: TextPosition {
2641 node: NodeId(0),
2642 character_index: 0,
2643 },
2644 focus: TextPosition {
2645 node: NodeId(0),
2646 character_index: 2,
2647 },
2648 });
2649 node.clear_text_selection();
2650 assert!(node.text_selection().is_none());
2651 }
2652}
2653
2654#[cfg(test)]
2655mod tree_id {
2656 use super::{Node, Role, TreeId, Uuid};
2657
2658 #[test]
2659 fn getter_should_return_default_value() {
2660 let node = Node::new(Role::GenericContainer);
2661 assert!(node.tree_id().is_none());
2662 }
2663 #[test]
2664 fn setter_should_update_the_property() {
2665 let mut node = Node::new(Role::GenericContainer);
2666 let value = TreeId(Uuid::nil());
2667 node.set_tree_id(value);
2668 assert_eq!(node.tree_id(), Some(value));
2669 }
2670 #[test]
2671 fn clearer_should_reset_the_property() {
2672 let mut node = Node::new(Role::GenericContainer);
2673 node.set_tree_id(TreeId(Uuid::nil()));
2674 node.clear_tree_id();
2675 assert!(node.tree_id().is_none());
2676 }
2677}
2678
2679vec_property_methods! {
2680 (CustomActions, CustomAction, custom_actions, get_custom_action_vec, set_custom_actions, set_custom_action_vec, push_custom_action, push_to_custom_action_vec, clear_custom_actions)
2682}
2683
2684#[cfg(test)]
2685mod custom_actions {
2686 use super::{CustomAction, Node, Role};
2687 use core::slice;
2688
2689 #[test]
2690 fn getter_should_return_default_value() {
2691 let node = Node::new(Role::Unknown);
2692 assert!(node.custom_actions().is_empty());
2693 }
2694 #[test]
2695 fn setter_should_update_the_property() {
2696 let mut node = Node::new(Role::Unknown);
2697 let value = alloc::vec![
2698 CustomAction {
2699 id: 0,
2700 description: "first test action".into(),
2701 },
2702 CustomAction {
2703 id: 1,
2704 description: "second test action".into(),
2705 },
2706 ];
2707 node.set_custom_actions(value.clone());
2708 assert_eq!(node.custom_actions(), value);
2709 }
2710 #[test]
2711 fn pusher_should_update_the_property() {
2712 let mut node = Node::new(Role::Unknown);
2713 let first_action = CustomAction {
2714 id: 0,
2715 description: "first test action".into(),
2716 };
2717 let second_action = CustomAction {
2718 id: 1,
2719 description: "second test action".into(),
2720 };
2721 node.push_custom_action(first_action.clone());
2722 assert_eq!(node.custom_actions(), slice::from_ref(&first_action));
2723 node.push_custom_action(second_action.clone());
2724 assert_eq!(node.custom_actions(), &[first_action, second_action]);
2725 }
2726 #[test]
2727 fn pusher_should_start_a_new_list_after_the_clearer() {
2728 let mut node = Node::new(Role::Unknown);
2729 node.set_custom_actions([CustomAction {
2730 id: 0,
2731 description: "first test action".into(),
2732 }]);
2733 node.clear_custom_actions();
2734 let second_action = CustomAction {
2735 id: 1,
2736 description: "second test action".into(),
2737 };
2738 node.push_custom_action(second_action.clone());
2739 assert_eq!(node.custom_actions(), slice::from_ref(&second_action));
2740 }
2741 #[test]
2742 fn clearer_should_reset_the_property() {
2743 let mut node = Node::new(Role::Unknown);
2744 node.set_custom_actions([CustomAction {
2745 id: 0,
2746 description: "test action".into(),
2747 }]);
2748 node.clear_custom_actions();
2749 assert!(node.custom_actions().is_empty());
2750 }
2751}
2752
2753impl fmt::Debug for Node {
2754 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2755 let mut fmt = f.debug_struct("Node");
2756
2757 fmt.field("role", &self.role());
2758
2759 let supported_actions = action_mask_to_action_vec(self.actions);
2760 if !supported_actions.is_empty() {
2761 fmt.field("actions", &supported_actions);
2762 }
2763
2764 let child_supported_actions = action_mask_to_action_vec(self.child_actions);
2765 if !child_supported_actions.is_empty() {
2766 fmt.field("child_actions", &child_supported_actions);
2767 }
2768
2769 self.debug_flag_properties(&mut fmt);
2770 self.debug_node_id_vec_properties(&mut fmt);
2771 self.debug_node_id_properties(&mut fmt);
2772 self.debug_string_properties(&mut fmt);
2773 self.debug_f64_properties(&mut fmt);
2774 self.debug_f32_properties(&mut fmt);
2775 self.debug_usize_properties(&mut fmt);
2776 self.debug_color_properties(&mut fmt);
2777 self.debug_text_decoration_properties(&mut fmt);
2778 self.debug_length_vec_properties(&mut fmt);
2779 self.debug_coord_vec_properties(&mut fmt);
2780 self.debug_bool_properties(&mut fmt);
2781 self.debug_unique_enum_properties(&mut fmt);
2782 self.debug_option_properties(&mut fmt);
2783
2784 let custom_actions = self.custom_actions();
2785 if !custom_actions.is_empty() {
2786 fmt.field("custom_actions", &custom_actions);
2787 }
2788
2789 fmt.finish()
2790 }
2791}
2792
2793#[cfg(feature = "serde")]
2794macro_rules! serialize_property {
2795 ($self:ident, $map:ident, $index:ident, $id:ident, { $($variant:ident),+ }) => {
2796 match &$self.values[$index as usize] {
2797 PropertyValue::None => (),
2798 $(PropertyValue::$variant(value) => {
2799 $map.serialize_entry(&$id, &value)?;
2800 })*
2801 }
2802 }
2803}
2804
2805#[cfg(feature = "serde")]
2806macro_rules! deserialize_property {
2807 ($props:ident, $map:ident, $key:ident, { $($type:ident { $($id:ident),+ }),+ }) => {
2808 match $key {
2809 $($(PropertyId::$id => {
2810 let value = $map.next_value()?;
2811 $props.set(PropertyId::$id, PropertyValue::$type(value));
2812 })*)*
2813 PropertyId::Unset => {
2814 let _ = $map.next_value::<IgnoredAny>()?;
2815 }
2816 }
2817 }
2818}
2819
2820#[cfg(feature = "serde")]
2821impl Serialize for Properties {
2822 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
2823 where
2824 S: Serializer,
2825 {
2826 let mut len = 0;
2827 for value in &*self.values {
2828 if !matches!(*value, PropertyValue::None) {
2829 len += 1;
2830 }
2831 }
2832 let mut map = serializer.serialize_map(Some(len))?;
2833 for (id, index) in self.indices.0.iter().copied().enumerate() {
2834 if index == PropertyId::Unset as u8 {
2835 continue;
2836 }
2837 let id = PropertyId::n(id as _).unwrap();
2838 serialize_property!(self, map, index, id, {
2839 NodeIdVec,
2840 NodeId,
2841 String,
2842 F64,
2843 F32,
2844 Usize,
2845 Color,
2846 TextDecoration,
2847 LengthVec,
2848 CoordVec,
2849 Bool,
2850 Invalid,
2851 Toggled,
2852 Live,
2853 TextDirection,
2854 Orientation,
2855 SortDirection,
2856 AriaCurrent,
2857 AutoComplete,
2858 HasPopup,
2859 ListStyle,
2860 TextAlign,
2861 VerticalOffset,
2862 Affine,
2863 Rect,
2864 TextSelection,
2865 CustomActionVec,
2866 TreeId
2867 });
2868 }
2869 map.end()
2870 }
2871}
2872
2873#[cfg(feature = "serde")]
2874struct PropertiesVisitor;
2875
2876#[cfg(feature = "serde")]
2877impl<'de> Visitor<'de> for PropertiesVisitor {
2878 type Value = Properties;
2879
2880 #[inline]
2881 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
2882 formatter.write_str("property map")
2883 }
2884
2885 fn visit_map<V>(self, mut map: V) -> Result<Self::Value, V::Error>
2886 where
2887 V: MapAccess<'de>,
2888 {
2889 let mut props = Properties::default();
2890 while let Some(id) = map.next_key()? {
2891 deserialize_property!(props, map, id, {
2892 NodeIdVec {
2893 Children,
2894 Controls,
2895 Details,
2896 DescribedBy,
2897 FlowTo,
2898 LabelledBy,
2899 Owns,
2900 RadioGroup
2901 },
2902 NodeId {
2903 ActiveDescendant,
2904 ErrorMessage,
2905 InPageLinkTarget,
2906 MemberOf,
2907 NextOnLine,
2908 PreviousOnLine,
2909 PopupFor
2910 },
2911 String {
2912 Label,
2913 Description,
2914 Value,
2915 AccessKey,
2916 AuthorId,
2917 ClassName,
2918 FontFamily,
2919 HtmlId,
2920 HtmlTag,
2921 InnerHtml,
2922 KeyboardShortcut,
2923 Language,
2924 Placeholder,
2925 RoleDescription,
2926 StateDescription,
2927 Tooltip,
2928 Url,
2929 RowIndexText,
2930 ColumnIndexText,
2931 BrailleLabel,
2932 BrailleRoleDescription
2933 },
2934 F64 {
2935 ScrollX,
2936 ScrollXMin,
2937 ScrollXMax,
2938 ScrollY,
2939 ScrollYMin,
2940 ScrollYMax,
2941 NumericValue,
2942 MinNumericValue,
2943 MaxNumericValue,
2944 NumericValueStep,
2945 NumericValueJump
2946 },
2947 F32 {
2948 FontSize,
2949 FontWeight
2950 },
2951 Usize {
2952 RowCount,
2953 ColumnCount,
2954 RowIndex,
2955 ColumnIndex,
2956 RowSpan,
2957 ColumnSpan,
2958 Level,
2959 SizeOfSet,
2960 PositionInSet
2961 },
2962 Color {
2963 ColorValue,
2964 BackgroundColor,
2965 ForegroundColor
2966 },
2967 TextDecoration {
2968 Overline,
2969 Strikethrough,
2970 Underline
2971 },
2972 LengthVec {
2973 CharacterLengths,
2974 WordStarts
2975 },
2976 CoordVec {
2977 CharacterPositions,
2978 CharacterWidths
2979 },
2980 Bool {
2981 Expanded,
2982 Selected
2983 },
2984 Invalid { Invalid },
2985 Toggled { Toggled },
2986 Live { Live },
2987 TextDirection { TextDirection },
2988 Orientation { Orientation },
2989 SortDirection { SortDirection },
2990 AriaCurrent { AriaCurrent },
2991 AutoComplete { AutoComplete },
2992 HasPopup { HasPopup },
2993 ListStyle { ListStyle },
2994 TextAlign { TextAlign },
2995 VerticalOffset { VerticalOffset },
2996 Affine { Transform },
2997 Rect { Bounds },
2998 TextSelection { TextSelection },
2999 CustomActionVec { CustomActions },
3000 TreeId { TreeId }
3001 });
3002 }
3003
3004 Ok(props)
3005 }
3006}
3007
3008#[cfg(feature = "serde")]
3009impl<'de> Deserialize<'de> for Properties {
3010 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
3011 where
3012 D: Deserializer<'de>,
3013 {
3014 deserializer.deserialize_map(PropertiesVisitor)
3015 }
3016}
3017
3018#[cfg(feature = "schemars")]
3019macro_rules! add_schema_property {
3020 ($gen:ident, $properties:ident, $enum_value:expr, $type:ty) => {{
3021 let name = format!("{:?}", $enum_value);
3022 let name = name[..1].to_ascii_lowercase() + &name[1..];
3023 let subschema = $gen.subschema_for::<$type>();
3024 $properties.insert(name, SchemaValue::from(subschema));
3025 }};
3026}
3027
3028#[cfg(feature = "schemars")]
3029macro_rules! add_properties_to_schema {
3030 ($gen:ident, $properties:ident, { $($type:ty { $($id:ident),+ }),+ }) => {
3031 $($(add_schema_property!($gen, $properties, PropertyId::$id, $type);)*)*
3032 }
3033}
3034
3035#[cfg(feature = "schemars")]
3036impl JsonSchema for Properties {
3037 #[inline]
3038 fn schema_name() -> Cow<'static, str> {
3039 "Properties".into()
3040 }
3041
3042 fn json_schema(generator: &mut SchemaGenerator) -> Schema {
3043 let mut properties = SchemaMap::<String, SchemaValue>::new();
3044 add_properties_to_schema!(generator, properties, {
3045 Vec<NodeId> {
3046 Children,
3047 Controls,
3048 Details,
3049 DescribedBy,
3050 FlowTo,
3051 LabelledBy,
3052 Owns,
3053 RadioGroup
3054 },
3055 NodeId {
3056 ActiveDescendant,
3057 ErrorMessage,
3058 InPageLinkTarget,
3059 MemberOf,
3060 NextOnLine,
3061 PreviousOnLine,
3062 PopupFor
3063 },
3064 String {
3065 Label,
3066 Description,
3067 Value,
3068 AccessKey,
3069 AuthorId,
3070 ClassName,
3071 FontFamily,
3072 HtmlId,
3073 HtmlTag,
3074 InnerHtml,
3075 KeyboardShortcut,
3076 Language,
3077 Placeholder,
3078 RoleDescription,
3079 StateDescription,
3080 Tooltip,
3081 Url,
3082 RowIndexText,
3083 ColumnIndexText,
3084 BrailleLabel,
3085 BrailleRoleDescription
3086 },
3087 f64 {
3088 ScrollX,
3089 ScrollXMin,
3090 ScrollXMax,
3091 ScrollY,
3092 ScrollYMin,
3093 ScrollYMax,
3094 NumericValue,
3095 MinNumericValue,
3096 MaxNumericValue,
3097 NumericValueStep,
3098 NumericValueJump
3099 },
3100 f32 {
3101 FontSize,
3102 FontWeight
3103 },
3104 usize {
3105 RowCount,
3106 ColumnCount,
3107 RowIndex,
3108 ColumnIndex,
3109 RowSpan,
3110 ColumnSpan,
3111 Level,
3112 SizeOfSet,
3113 PositionInSet
3114 },
3115 Color {
3116 ColorValue,
3117 BackgroundColor,
3118 ForegroundColor
3119 },
3120 TextDecoration {
3121 Overline,
3122 Strikethrough,
3123 Underline
3124 },
3125 Vec<u8> {
3126 CharacterLengths,
3127 WordStarts
3128 },
3129 Vec<f32> {
3130 CharacterPositions,
3131 CharacterWidths
3132 },
3133 bool {
3134 Expanded,
3135 Selected
3136 },
3137 Invalid { Invalid },
3138 Toggled { Toggled },
3139 Live { Live },
3140 TextDirection { TextDirection },
3141 Orientation { Orientation },
3142 SortDirection { SortDirection },
3143 AriaCurrent { AriaCurrent },
3144 AutoComplete { AutoComplete },
3145 HasPopup { HasPopup },
3146 ListStyle { ListStyle },
3147 TextAlign { TextAlign },
3148 VerticalOffset { VerticalOffset },
3149 Affine { Transform },
3150 Rect { Bounds },
3151 TextSelection { TextSelection },
3152 Vec<CustomAction> { CustomActions }
3153 });
3154 json_schema!({
3155 "type": "object",
3156 "properties": properties
3157 })
3158 }
3159}
3160
3161#[derive(Clone, Debug, PartialEq, Eq)]
3164#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3165#[cfg_attr(feature = "schemars", derive(JsonSchema))]
3166#[cfg_attr(feature = "serde", serde(deny_unknown_fields))]
3167#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
3168pub struct TreeInfo {
3169 pub root: NodeId,
3171 pub toolkit_name: Option<String>,
3173 pub toolkit_version: Option<String>,
3175}
3176
3177#[deprecated(note = "Use TreeInfo instead")]
3178pub type Tree = TreeInfo;
3179
3180impl TreeInfo {
3181 #[inline]
3182 pub fn new(root: NodeId) -> TreeInfo {
3183 TreeInfo {
3184 root,
3185 toolkit_name: None,
3186 toolkit_version: None,
3187 }
3188 }
3189}
3190
3191#[derive(Clone, Debug, PartialEq)]
3203#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3204#[cfg_attr(feature = "schemars", derive(JsonSchema))]
3205#[cfg_attr(feature = "serde", serde(deny_unknown_fields))]
3206#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
3207pub struct TreeUpdate {
3208 pub nodes: Vec<(NodeId, Node)>,
3229
3230 pub tree: Option<TreeInfo>,
3235
3236 pub tree_id: TreeId,
3246
3247 pub focus: NodeId,
3257}
3258
3259#[derive(Clone, Copy, Debug, PartialEq, Eq)]
3262#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3263#[cfg_attr(feature = "schemars", derive(JsonSchema))]
3264#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
3265#[cfg_attr(
3266 feature = "pyo3",
3267 pyclass(module = "accesskit", rename_all = "SCREAMING_SNAKE_CASE", eq)
3268)]
3269#[repr(u8)]
3270pub enum ScrollUnit {
3271 Item,
3275 Page,
3277}
3278
3279#[derive(Clone, Copy, Debug, PartialEq, Eq)]
3282#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3283#[cfg_attr(feature = "schemars", derive(JsonSchema))]
3284#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
3285#[cfg_attr(
3286 feature = "pyo3",
3287 pyclass(module = "accesskit", rename_all = "SCREAMING_SNAKE_CASE", eq)
3288)]
3289#[repr(u8)]
3290pub enum ScrollHint {
3291 TopLeft,
3292 BottomRight,
3293 TopEdge,
3294 BottomEdge,
3295 LeftEdge,
3296 RightEdge,
3297}
3298
3299#[derive(Clone, Debug, PartialEq)]
3300#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3301#[cfg_attr(feature = "schemars", derive(JsonSchema))]
3302#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
3303#[repr(C)]
3304pub enum ActionData {
3305 CustomAction(i32),
3306 Value(Box<str>),
3307 NumericValue(f64),
3308 ScrollUnit(ScrollUnit),
3309 ScrollHint(ScrollHint),
3313 ScrollToPoint(Point),
3316 SetScrollOffset(Point),
3319 SetTextSelection(TextSelection),
3320}
3321
3322#[derive(Clone, Debug, PartialEq)]
3323#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3324#[cfg_attr(feature = "schemars", derive(JsonSchema))]
3325#[cfg_attr(feature = "serde", serde(deny_unknown_fields))]
3326#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
3327pub struct ActionRequest {
3328 pub action: Action,
3329 pub target_tree: TreeId,
3330 pub target_node: NodeId,
3331 pub data: Option<ActionData>,
3332}
3333
3334pub trait ActivationHandler {
3336 fn request_initial_tree(&mut self) -> Option<TreeUpdate>;
3358}
3359
3360pub trait ActionHandler {
3362 fn do_action(&mut self, request: ActionRequest);
3372}
3373
3374pub trait DeactivationHandler {
3376 fn deactivate_accessibility(&mut self);
3384}
3385
3386#[cfg(test)]
3387mod tests {
3388 use super::*;
3389 use alloc::format;
3390
3391 #[test]
3392 fn nodes_should_be_equal_regardless_of_the_order_properties_were_set() {
3393 let mut node = Node::new(Role::Button);
3394 node.set_label("a label");
3395 node.set_children([NodeId(1)]);
3396 node.set_description("a description");
3397
3398 let mut reordered = Node::new(Role::Button);
3399 reordered.set_description("a description");
3400 reordered.set_children([NodeId(1)]);
3401 reordered.set_label("a label");
3402
3403 assert_eq!(node, reordered);
3404 }
3405
3406 #[test]
3407 fn cleared_property_should_be_equal_to_one_that_was_never_set() {
3408 let mut node = Node::new(Role::Button);
3409 node.set_label("a label");
3410 node.clear_label();
3411
3412 assert_eq!(node, Node::new(Role::Button));
3413 }
3414
3415 #[test]
3416 fn clone_from_should_be_equivalent_to_clone() {
3417 let mut source = Node::new(Role::Button);
3418 source.add_action(Action::Click);
3419 source.add_child_action(Action::Focus);
3420 source.set_hidden();
3421 source.set_label("source");
3422 source.set_children([NodeId(1)]);
3423
3424 let mut dest = Node::new(Role::CheckBox);
3425 dest.add_action(Action::Focus);
3426 dest.set_multiselectable();
3427 dest.set_description("dest");
3428 dest.set_children([NodeId(7), NodeId(8)]);
3429 dest.clone_from(&source);
3430
3431 assert_eq!(dest, source.clone());
3432 }
3433
3434 #[test]
3435 fn clone_from_should_reuse_the_destination_string_buffer() {
3436 let mut source = Node::new(Role::Button);
3437 source.set_label("new label");
3438 let mut dest = Node::new(Role::Button);
3439 dest.set_label("old label with room to spare");
3440 let buffer = dest.label().unwrap().as_ptr();
3441
3442 dest.clone_from(&source);
3443
3444 assert_eq!(dest.label(), Some("new label"));
3445 assert_eq!(dest.label().unwrap().as_ptr(), buffer);
3446 }
3447
3448 #[test]
3449 fn clone_from_should_reuse_the_destination_slice_buffer() {
3450 let mut source = Node::new(Role::TextRun);
3451 source.set_character_lengths([1u8, 2, 3]);
3452 let mut dest = Node::new(Role::TextRun);
3453 dest.set_character_lengths([9u8; 16]);
3454 let buffer = dest.character_lengths().as_ptr();
3455
3456 dest.clone_from(&source);
3457
3458 assert_eq!(dest.character_lengths(), &[1, 2, 3]);
3459 assert_eq!(dest.character_lengths().as_ptr(), buffer);
3460 }
3461
3462 #[test]
3463 fn u64_should_be_convertible_to_node_id() {
3464 assert_eq!(NodeId::from(0u64), NodeId(0));
3465 assert_eq!(NodeId::from(1u64), NodeId(1));
3466 }
3467
3468 #[test]
3469 fn node_id_should_be_convertible_to_u64() {
3470 assert_eq!(u64::from(NodeId(0)), 0u64);
3471 assert_eq!(u64::from(NodeId(1)), 1u64);
3472 }
3473
3474 #[test]
3475 fn node_id_should_have_debug_repr() {
3476 assert_eq!(&format!("{:?}", NodeId(0)), "#0");
3477 assert_eq!(&format!("{:?}", NodeId(1)), "#1");
3478 }
3479
3480 #[test]
3481 fn action_n_should_return_the_corresponding_variant() {
3482 assert_eq!(Action::n(0), Some(Action::Click));
3483 assert_eq!(Action::n(1), Some(Action::Focus));
3484 assert_eq!(Action::n(2), Some(Action::Blur));
3485 assert_eq!(Action::n(3), Some(Action::Collapse));
3486 assert_eq!(Action::n(4), Some(Action::Expand));
3487 assert_eq!(Action::n(5), Some(Action::CustomAction));
3488 assert_eq!(Action::n(6), Some(Action::Decrement));
3489 assert_eq!(Action::n(7), Some(Action::Increment));
3490 assert_eq!(Action::n(8), Some(Action::HideTooltip));
3491 assert_eq!(Action::n(9), Some(Action::ShowTooltip));
3492 assert_eq!(Action::n(10), Some(Action::ReplaceSelectedText));
3493 assert_eq!(Action::n(11), Some(Action::ScrollDown));
3494 assert_eq!(Action::n(12), Some(Action::ScrollLeft));
3495 assert_eq!(Action::n(13), Some(Action::ScrollRight));
3496 assert_eq!(Action::n(14), Some(Action::ScrollUp));
3497 assert_eq!(Action::n(15), Some(Action::ScrollIntoView));
3498 assert_eq!(Action::n(16), Some(Action::ScrollToPoint));
3499 assert_eq!(Action::n(17), Some(Action::SetScrollOffset));
3500 assert_eq!(Action::n(18), Some(Action::SetTextSelection));
3501 assert_eq!(
3502 Action::n(19),
3503 Some(Action::SetSequentialFocusNavigationStartingPoint)
3504 );
3505 assert_eq!(Action::n(20), Some(Action::SetValue));
3506 assert_eq!(Action::n(21), Some(Action::ShowContextMenu));
3507 assert_eq!(Action::n(22), None);
3508 }
3509
3510 #[test]
3511 fn empty_action_mask_should_be_converted_to_empty_vec() {
3512 assert_eq!(
3513 Vec::<Action>::new(),
3514 action_mask_to_action_vec(Node::new(Role::Unknown).actions)
3515 );
3516 }
3517
3518 #[test]
3519 fn action_mask_should_be_convertible_to_vec() {
3520 let mut node = Node::new(Role::Unknown);
3521 node.add_action(Action::Click);
3522 assert_eq!(
3523 &[Action::Click],
3524 action_mask_to_action_vec(node.actions).as_slice()
3525 );
3526
3527 let mut node = Node::new(Role::Unknown);
3528 node.add_action(Action::ShowContextMenu);
3529 assert_eq!(
3530 &[Action::ShowContextMenu],
3531 action_mask_to_action_vec(node.actions).as_slice()
3532 );
3533
3534 let mut node = Node::new(Role::Unknown);
3535 node.add_action(Action::Click);
3536 node.add_action(Action::ShowContextMenu);
3537 assert_eq!(
3538 &[Action::Click, Action::ShowContextMenu],
3539 action_mask_to_action_vec(node.actions).as_slice()
3540 );
3541
3542 let mut node = Node::new(Role::Unknown);
3543 node.add_action(Action::Focus);
3544 node.add_action(Action::Blur);
3545 node.add_action(Action::Collapse);
3546 assert_eq!(
3547 &[Action::Focus, Action::Blur, Action::Collapse],
3548 action_mask_to_action_vec(node.actions).as_slice()
3549 );
3550 }
3551
3552 #[test]
3553 fn new_node_should_have_user_provided_role() {
3554 let node = Node::new(Role::Button);
3555 assert_eq!(node.role(), Role::Button);
3556 }
3557
3558 #[test]
3559 fn node_role_setter_should_update_the_role() {
3560 let mut node = Node::new(Role::Button);
3561 node.set_role(Role::CheckBox);
3562 assert_eq!(node.role(), Role::CheckBox);
3563 }
3564
3565 macro_rules! assert_absent_action {
3566 ($node:ident, $action:ident) => {
3567 assert!(!$node.supports_action(Action::$action));
3568 assert!(!$node.child_supports_action(Action::$action));
3569 };
3570 }
3571
3572 #[test]
3573 fn new_node_should_not_support_anyaction() {
3574 let node = Node::new(Role::Unknown);
3575 assert_absent_action!(node, Click);
3576 assert_absent_action!(node, Focus);
3577 assert_absent_action!(node, Blur);
3578 assert_absent_action!(node, Collapse);
3579 assert_absent_action!(node, Expand);
3580 assert_absent_action!(node, CustomAction);
3581 assert_absent_action!(node, Decrement);
3582 assert_absent_action!(node, Increment);
3583 assert_absent_action!(node, HideTooltip);
3584 assert_absent_action!(node, ShowTooltip);
3585 assert_absent_action!(node, ReplaceSelectedText);
3586 assert_absent_action!(node, ScrollDown);
3587 assert_absent_action!(node, ScrollLeft);
3588 assert_absent_action!(node, ScrollRight);
3589 assert_absent_action!(node, ScrollUp);
3590 assert_absent_action!(node, ScrollIntoView);
3591 assert_absent_action!(node, ScrollToPoint);
3592 assert_absent_action!(node, SetScrollOffset);
3593 assert_absent_action!(node, SetTextSelection);
3594 assert_absent_action!(node, SetSequentialFocusNavigationStartingPoint);
3595 assert_absent_action!(node, SetValue);
3596 assert_absent_action!(node, ShowContextMenu);
3597 }
3598
3599 #[test]
3600 fn node_add_action_should_add_the_action() {
3601 let mut node = Node::new(Role::Unknown);
3602 node.add_action(Action::Focus);
3603 assert!(node.supports_action(Action::Focus));
3604 node.add_action(Action::Blur);
3605 assert!(node.supports_action(Action::Blur));
3606 }
3607
3608 #[test]
3609 fn node_add_child_action_should_add_the_action() {
3610 let mut node = Node::new(Role::Unknown);
3611 node.add_child_action(Action::Focus);
3612 assert!(node.child_supports_action(Action::Focus));
3613 node.add_child_action(Action::Blur);
3614 assert!(node.child_supports_action(Action::Blur));
3615 }
3616
3617 #[test]
3618 fn node_add_action_should_do_nothing_if_the_action_is_already_supported() {
3619 let mut node = Node::new(Role::Unknown);
3620 node.add_action(Action::Focus);
3621 node.add_action(Action::Focus);
3622 assert!(node.supports_action(Action::Focus));
3623 }
3624
3625 #[test]
3626 fn node_add_child_action_should_do_nothing_if_the_action_is_already_supported() {
3627 let mut node = Node::new(Role::Unknown);
3628 node.add_child_action(Action::Focus);
3629 node.add_child_action(Action::Focus);
3630 assert!(node.child_supports_action(Action::Focus));
3631 }
3632
3633 #[test]
3634 fn node_remove_action_should_remove_the_action() {
3635 let mut node = Node::new(Role::Unknown);
3636 node.add_action(Action::Blur);
3637 node.remove_action(Action::Blur);
3638 assert!(!node.supports_action(Action::Blur));
3639 }
3640
3641 #[test]
3642 fn node_remove_child_action_should_remove_the_action() {
3643 let mut node = Node::new(Role::Unknown);
3644 node.add_child_action(Action::Blur);
3645 node.remove_child_action(Action::Blur);
3646 assert!(!node.child_supports_action(Action::Blur));
3647 }
3648
3649 #[test]
3650 fn node_clear_actions_should_remove_all_actions() {
3651 let mut node = Node::new(Role::Unknown);
3652 node.add_action(Action::Focus);
3653 node.add_action(Action::Blur);
3654 node.clear_actions();
3655 assert!(!node.supports_action(Action::Focus));
3656 assert!(!node.supports_action(Action::Blur));
3657 }
3658
3659 #[test]
3660 fn node_clear_child_actions_should_remove_all_actions() {
3661 let mut node = Node::new(Role::Unknown);
3662 node.add_child_action(Action::Focus);
3663 node.add_child_action(Action::Blur);
3664 node.clear_child_actions();
3665 assert!(!node.child_supports_action(Action::Focus));
3666 assert!(!node.child_supports_action(Action::Blur));
3667 }
3668
3669 #[test]
3670 fn node_should_have_debug_repr() {
3671 let mut node = Node::new(Role::Unknown);
3672 node.add_action(Action::Click);
3673 node.add_action(Action::Focus);
3674 node.add_child_action(Action::ScrollIntoView);
3675 node.set_hidden();
3676 node.set_multiselectable();
3677 node.set_children([NodeId(0), NodeId(1)]);
3678 node.set_active_descendant(NodeId(2));
3679 node.push_custom_action(CustomAction {
3680 id: 0,
3681 description: "test action".into(),
3682 });
3683
3684 assert_eq!(
3685 &format!("{node:?}"),
3686 r#"Node { role: Unknown, actions: [Click, Focus], child_actions: [ScrollIntoView], is_hidden: true, is_multiselectable: true, children: [#0, #1], active_descendant: #2, custom_actions: [CustomAction { id: 0, description: "test action" }] }"#
3687 );
3688 }
3689
3690 #[test]
3691 fn new_tree_should_have_root_id() {
3692 let tree = TreeInfo::new(NodeId(1));
3693 assert_eq!(tree.root, NodeId(1));
3694 assert_eq!(tree.toolkit_name, None);
3695 assert_eq!(tree.toolkit_version, None);
3696 }
3697}