1#![cfg_attr(not(any(feature = "pyo3", feature = "schemars")), no_std)]
12
13extern crate alloc;
14
15use alloc::{boxed::Box, string::String, vec::Vec};
16use core::fmt;
17#[cfg(feature = "pyo3")]
18use pyo3::pyclass;
19#[cfg(feature = "schemars")]
20use schemars::{
21 gen::SchemaGenerator,
22 schema::{InstanceType, ObjectValidation, Schema, SchemaObject},
23 JsonSchema, Map as SchemaMap,
24};
25#[cfg(feature = "serde")]
26use serde::{
27 de::{Deserializer, IgnoredAny, MapAccess, Visitor},
28 ser::{SerializeMap, Serializer},
29 Deserialize, Serialize,
30};
31
32mod geometry;
33pub use geometry::{Affine, Point, Rect, Size, Vec2};
34
35#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
46#[cfg_attr(feature = "enumn", derive(enumn::N))]
47#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
48#[cfg_attr(feature = "schemars", derive(JsonSchema))]
49#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
50#[cfg_attr(
51 feature = "pyo3",
52 pyclass(module = "accesskit", rename_all = "SCREAMING_SNAKE_CASE", eq)
53)]
54#[repr(u8)]
55pub enum Role {
56 #[default]
57 Unknown,
58 TextRun,
59 Cell,
60 Label,
61 Image,
62 Link,
63 Row,
64 ListItem,
65
66 ListMarker,
68
69 TreeItem,
70 ListBoxOption,
71 MenuItem,
72 MenuListOption,
73 Paragraph,
74
75 GenericContainer,
79
80 CheckBox,
81 RadioButton,
82 TextInput,
83 Button,
84 DefaultButton,
85 Pane,
86 RowHeader,
87 ColumnHeader,
88 RowGroup,
89 List,
90 Table,
91 LayoutTableCell,
92 LayoutTableRow,
93 LayoutTable,
94 Switch,
95 Menu,
96
97 MultilineTextInput,
98 SearchInput,
99 DateInput,
100 DateTimeInput,
101 WeekInput,
102 MonthInput,
103 TimeInput,
104 EmailInput,
105 NumberInput,
106 PasswordInput,
107 PhoneNumberInput,
108 UrlInput,
109
110 Abbr,
111 Alert,
112 AlertDialog,
113 Application,
114 Article,
115 Audio,
116 Banner,
117 Blockquote,
118 Canvas,
119 Caption,
120 Caret,
121 Code,
122 ColorWell,
123 ComboBox,
124 EditableComboBox,
125 Complementary,
126 Comment,
127 ContentDeletion,
128 ContentInsertion,
129 ContentInfo,
130 Definition,
131 DescriptionList,
132 DescriptionListDetail,
133 DescriptionListTerm,
134 Details,
135 Dialog,
136 Directory,
137 DisclosureTriangle,
138 Document,
139 EmbeddedObject,
140 Emphasis,
141 Feed,
142 FigureCaption,
143 Figure,
144 Footer,
145 FooterAsNonLandmark,
146 Form,
147 Grid,
148 Group,
149 Header,
150 HeaderAsNonLandmark,
151 Heading,
152 Iframe,
153 IframePresentational,
154 ImeCandidate,
155 Keyboard,
156 Legend,
157 LineBreak,
158 ListBox,
159 Log,
160 Main,
161 Mark,
162 Marquee,
163 Math,
164 MenuBar,
165 MenuItemCheckBox,
166 MenuItemRadio,
167 MenuListPopup,
168 Meter,
169 Navigation,
170 Note,
171 PluginObject,
172 Portal,
173 Pre,
174 ProgressIndicator,
175 RadioGroup,
176 Region,
177 RootWebArea,
178 Ruby,
179 RubyAnnotation,
180 ScrollBar,
181 ScrollView,
182 Search,
183 Section,
184 Slider,
185 SpinButton,
186 Splitter,
187 Status,
188 Strong,
189 Suggestion,
190 SvgRoot,
191 Tab,
192 TabList,
193 TabPanel,
194 Term,
195 Time,
196 Timer,
197 TitleBar,
198 Toolbar,
199 Tooltip,
200 Tree,
201 TreeGrid,
202 Video,
203 WebView,
204 Window,
205
206 PdfActionableHighlight,
207 PdfRoot,
208
209 GraphicsDocument,
212 GraphicsObject,
213 GraphicsSymbol,
214
215 DocAbstract,
218 DocAcknowledgements,
219 DocAfterword,
220 DocAppendix,
221 DocBackLink,
222 DocBiblioEntry,
223 DocBibliography,
224 DocBiblioRef,
225 DocChapter,
226 DocColophon,
227 DocConclusion,
228 DocCover,
229 DocCredit,
230 DocCredits,
231 DocDedication,
232 DocEndnote,
233 DocEndnotes,
234 DocEpigraph,
235 DocEpilogue,
236 DocErrata,
237 DocExample,
238 DocFootnote,
239 DocForeword,
240 DocGlossary,
241 DocGlossRef,
242 DocIndex,
243 DocIntroduction,
244 DocNoteRef,
245 DocNotice,
246 DocPageBreak,
247 DocPageFooter,
248 DocPageHeader,
249 DocPageList,
250 DocPart,
251 DocPreface,
252 DocPrologue,
253 DocPullquote,
254 DocQna,
255 DocSubtitle,
256 DocTip,
257 DocToc,
258
259 ListGrid,
263
264 Terminal,
268}
269
270#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
272#[cfg_attr(feature = "enumn", derive(enumn::N))]
273#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
274#[cfg_attr(feature = "schemars", derive(JsonSchema))]
275#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
276#[cfg_attr(
277 feature = "pyo3",
278 pyclass(module = "accesskit", rename_all = "SCREAMING_SNAKE_CASE", eq)
279)]
280#[repr(u8)]
281pub enum Action {
282 Click,
284
285 Focus,
286 Blur,
287
288 Collapse,
289 Expand,
290
291 CustomAction,
293
294 Decrement,
296 Increment,
298
299 HideTooltip,
300 ShowTooltip,
301
302 ReplaceSelectedText,
306
307 ScrollDown,
309 ScrollLeft,
311 ScrollRight,
313 ScrollUp,
315
316 ScrollIntoView,
320
321 ScrollToPoint,
325
326 SetScrollOffset,
328
329 SetTextSelection,
331
332 SetSequentialFocusNavigationStartingPoint,
336
337 SetValue,
341
342 ShowContextMenu,
343}
344
345impl Action {
346 fn mask(self) -> u32 {
347 1 << (self as u8)
348 }
349
350 #[cfg(not(feature = "enumn"))]
351 fn n(value: u8) -> Option<Self> {
352 match value {
356 0 => Some(Action::Click),
357 1 => Some(Action::Focus),
358 2 => Some(Action::Blur),
359 3 => Some(Action::Collapse),
360 4 => Some(Action::Expand),
361 5 => Some(Action::CustomAction),
362 6 => Some(Action::Decrement),
363 7 => Some(Action::Increment),
364 8 => Some(Action::HideTooltip),
365 9 => Some(Action::ShowTooltip),
366 10 => Some(Action::ReplaceSelectedText),
367 11 => Some(Action::ScrollDown),
368 12 => Some(Action::ScrollLeft),
369 13 => Some(Action::ScrollRight),
370 14 => Some(Action::ScrollUp),
371 15 => Some(Action::ScrollIntoView),
372 16 => Some(Action::ScrollToPoint),
373 17 => Some(Action::SetScrollOffset),
374 18 => Some(Action::SetTextSelection),
375 19 => Some(Action::SetSequentialFocusNavigationStartingPoint),
376 20 => Some(Action::SetValue),
377 21 => Some(Action::ShowContextMenu),
378 _ => None,
379 }
380 }
381}
382
383fn action_mask_to_action_vec(mask: u32) -> Vec<Action> {
384 let mut actions = Vec::new();
385 let mut i = 0;
386 while let Some(variant) = Action::n(i) {
387 if mask & variant.mask() != 0 {
388 actions.push(variant);
389 }
390 i += 1;
391 }
392 actions
393}
394
395#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
396#[cfg_attr(feature = "enumn", derive(enumn::N))]
397#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
398#[cfg_attr(feature = "schemars", derive(JsonSchema))]
399#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
400#[cfg_attr(
401 feature = "pyo3",
402 pyclass(module = "accesskit", rename_all = "SCREAMING_SNAKE_CASE", eq)
403)]
404#[repr(u8)]
405pub enum Orientation {
406 Horizontal,
408 Vertical,
410}
411
412#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
413#[cfg_attr(feature = "enumn", derive(enumn::N))]
414#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
415#[cfg_attr(feature = "schemars", derive(JsonSchema))]
416#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
417#[cfg_attr(
418 feature = "pyo3",
419 pyclass(module = "accesskit", rename_all = "SCREAMING_SNAKE_CASE", eq)
420)]
421#[repr(u8)]
422pub enum TextDirection {
423 LeftToRight,
424 RightToLeft,
425 TopToBottom,
426 BottomToTop,
427}
428
429#[derive(Clone, Copy, Debug, PartialEq, Eq)]
434#[cfg_attr(feature = "enumn", derive(enumn::N))]
435#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
436#[cfg_attr(feature = "schemars", derive(JsonSchema))]
437#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
438#[cfg_attr(
439 feature = "pyo3",
440 pyclass(module = "accesskit", rename_all = "SCREAMING_SNAKE_CASE", eq)
441)]
442#[repr(u8)]
443pub enum Invalid {
444 True,
445 Grammar,
446 Spelling,
447}
448
449#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
450#[cfg_attr(feature = "enumn", derive(enumn::N))]
451#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
452#[cfg_attr(feature = "schemars", derive(JsonSchema))]
453#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
454#[cfg_attr(
455 feature = "pyo3",
456 pyclass(module = "accesskit", rename_all = "SCREAMING_SNAKE_CASE", eq)
457)]
458#[repr(u8)]
459pub enum Toggled {
460 False,
461 True,
462 Mixed,
463}
464
465impl From<bool> for Toggled {
466 #[inline]
467 fn from(b: bool) -> Self {
468 match b {
469 false => Self::False,
470 true => Self::True,
471 }
472 }
473}
474
475#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
476#[cfg_attr(feature = "enumn", derive(enumn::N))]
477#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
478#[cfg_attr(feature = "schemars", derive(JsonSchema))]
479#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
480#[cfg_attr(
481 feature = "pyo3",
482 pyclass(module = "accesskit", rename_all = "SCREAMING_SNAKE_CASE", eq)
483)]
484#[repr(u8)]
485pub enum SortDirection {
486 Ascending,
487 Descending,
488 Other,
489}
490
491#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
492#[cfg_attr(feature = "enumn", derive(enumn::N))]
493#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
494#[cfg_attr(feature = "schemars", derive(JsonSchema))]
495#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
496#[cfg_attr(
497 feature = "pyo3",
498 pyclass(module = "accesskit", rename_all = "SCREAMING_SNAKE_CASE", eq)
499)]
500#[repr(u8)]
501pub enum AriaCurrent {
502 False,
503 True,
504 Page,
505 Step,
506 Location,
507 Date,
508 Time,
509}
510
511#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
512#[cfg_attr(feature = "enumn", derive(enumn::N))]
513#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
514#[cfg_attr(feature = "schemars", derive(JsonSchema))]
515#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
516#[cfg_attr(
517 feature = "pyo3",
518 pyclass(module = "accesskit", rename_all = "SCREAMING_SNAKE_CASE", eq)
519)]
520#[repr(u8)]
521pub enum AutoComplete {
522 Inline,
523 List,
524 Both,
525}
526
527#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
528#[cfg_attr(feature = "enumn", derive(enumn::N))]
529#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
530#[cfg_attr(feature = "schemars", derive(JsonSchema))]
531#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
532#[cfg_attr(
533 feature = "pyo3",
534 pyclass(module = "accesskit", rename_all = "SCREAMING_SNAKE_CASE", eq)
535)]
536#[repr(u8)]
537pub enum Live {
538 Off,
539 Polite,
540 Assertive,
541}
542
543#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
544#[cfg_attr(feature = "enumn", derive(enumn::N))]
545#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
546#[cfg_attr(feature = "schemars", derive(JsonSchema))]
547#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
548#[cfg_attr(
549 feature = "pyo3",
550 pyclass(module = "accesskit", rename_all = "SCREAMING_SNAKE_CASE", eq)
551)]
552#[repr(u8)]
553pub enum HasPopup {
554 Menu,
555 Listbox,
556 Tree,
557 Grid,
558 Dialog,
559}
560
561#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
562#[cfg_attr(feature = "enumn", derive(enumn::N))]
563#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
564#[cfg_attr(feature = "schemars", derive(JsonSchema))]
565#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
566#[cfg_attr(
567 feature = "pyo3",
568 pyclass(module = "accesskit", rename_all = "SCREAMING_SNAKE_CASE", eq)
569)]
570#[repr(u8)]
571pub enum ListStyle {
572 Circle,
573 Disc,
574 Image,
575 Numeric,
576 Square,
577 Other,
579}
580
581#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
582#[cfg_attr(feature = "enumn", derive(enumn::N))]
583#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
584#[cfg_attr(feature = "schemars", derive(JsonSchema))]
585#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
586#[cfg_attr(
587 feature = "pyo3",
588 pyclass(module = "accesskit", rename_all = "SCREAMING_SNAKE_CASE", eq)
589)]
590#[repr(u8)]
591pub enum TextAlign {
592 Left,
593 Right,
594 Center,
595 Justify,
596}
597
598#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
599#[cfg_attr(feature = "enumn", derive(enumn::N))]
600#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
601#[cfg_attr(feature = "schemars", derive(JsonSchema))]
602#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
603#[cfg_attr(
604 feature = "pyo3",
605 pyclass(module = "accesskit", rename_all = "SCREAMING_SNAKE_CASE", eq)
606)]
607#[repr(u8)]
608pub enum VerticalOffset {
609 Subscript,
610 Superscript,
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(module = "accesskit", rename_all = "SCREAMING_SNAKE_CASE", eq)
621)]
622#[repr(u8)]
623pub enum TextDecoration {
624 Solid,
625 Dotted,
626 Dashed,
627 Double,
628 Wavy,
629}
630
631pub type NodeIdContent = u64;
632
633#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
635#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
636#[cfg_attr(feature = "schemars", derive(JsonSchema))]
637#[repr(transparent)]
638pub struct NodeId(pub NodeIdContent);
639
640impl From<NodeIdContent> for NodeId {
641 #[inline]
642 fn from(inner: NodeIdContent) -> Self {
643 Self(inner)
644 }
645}
646
647impl From<NodeId> for NodeIdContent {
648 #[inline]
649 fn from(outer: NodeId) -> Self {
650 outer.0
651 }
652}
653
654impl fmt::Debug for NodeId {
655 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
656 write!(f, "#{}", self.0)
657 }
658}
659
660#[derive(Clone, Debug, PartialEq, Eq)]
665#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
666#[cfg_attr(feature = "schemars", derive(JsonSchema))]
667#[cfg_attr(feature = "serde", serde(deny_unknown_fields))]
668#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
669pub struct CustomAction {
670 pub id: i32,
671 pub description: Box<str>,
672}
673
674#[derive(Clone, Copy, Debug, PartialEq, Eq)]
675#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
676#[cfg_attr(feature = "schemars", derive(JsonSchema))]
677#[cfg_attr(feature = "serde", serde(deny_unknown_fields))]
678#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
679pub struct TextPosition {
680 pub node: NodeId,
682 pub character_index: usize,
685}
686
687#[derive(Clone, Copy, Debug, PartialEq, Eq)]
688#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
689#[cfg_attr(feature = "schemars", derive(JsonSchema))]
690#[cfg_attr(feature = "serde", serde(deny_unknown_fields))]
691#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
692pub struct TextSelection {
693 pub anchor: TextPosition,
698 pub focus: TextPosition,
702}
703
704#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
705#[cfg_attr(feature = "serde", derive(Serialize, Deserialize, enumn::N))]
706#[cfg_attr(feature = "schemars", derive(JsonSchema))]
707#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
708#[repr(u8)]
709enum Flag {
710 Hidden,
711 Multiselectable,
712 Required,
713 Visited,
714 Busy,
715 LiveAtomic,
716 Modal,
717 TouchTransparent,
718 ReadOnly,
719 Disabled,
720 Bold,
721 Italic,
722 ClipsChildren,
723 IsLineBreakingObject,
724 IsPageBreakingObject,
725 IsSpellingError,
726 IsGrammarError,
727 IsSearchMatch,
728 IsSuggestion,
729}
730
731impl Flag {
732 fn mask(self) -> u32 {
733 1 << (self as u8)
734 }
735}
736
737#[derive(Clone, Debug, PartialEq)]
741enum PropertyValue {
742 None,
743 NodeIdVec(Vec<NodeId>),
744 NodeId(NodeId),
745 String(Box<str>),
746 F64(f64),
747 Usize(usize),
748 Color(u32),
749 TextDecoration(TextDecoration),
750 LengthSlice(Box<[u8]>),
751 CoordSlice(Box<[f32]>),
752 Bool(bool),
753 Invalid(Invalid),
754 Toggled(Toggled),
755 Live(Live),
756 TextDirection(TextDirection),
757 Orientation(Orientation),
758 SortDirection(SortDirection),
759 AriaCurrent(AriaCurrent),
760 AutoComplete(AutoComplete),
761 HasPopup(HasPopup),
762 ListStyle(ListStyle),
763 TextAlign(TextAlign),
764 VerticalOffset(VerticalOffset),
765 Affine(Box<Affine>),
766 Rect(Rect),
767 TextSelection(Box<TextSelection>),
768 CustomActionVec(Vec<CustomAction>),
769}
770
771#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
772#[cfg_attr(feature = "serde", derive(Serialize, Deserialize, enumn::N))]
773#[cfg_attr(feature = "schemars", derive(JsonSchema))]
774#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
775#[repr(u8)]
776enum PropertyId {
777 Children,
779 Controls,
780 Details,
781 DescribedBy,
782 FlowTo,
783 LabelledBy,
784 Owns,
785 RadioGroup,
786
787 ActiveDescendant,
789 ErrorMessage,
790 InPageLinkTarget,
791 MemberOf,
792 NextOnLine,
793 PreviousOnLine,
794 PopupFor,
795
796 Label,
798 Description,
799 Value,
800 AccessKey,
801 AuthorId,
802 ClassName,
803 FontFamily,
804 HtmlTag,
805 InnerHtml,
806 KeyboardShortcut,
807 Language,
808 Placeholder,
809 RoleDescription,
810 StateDescription,
811 Tooltip,
812 Url,
813 RowIndexText,
814 ColumnIndexText,
815
816 ScrollX,
818 ScrollXMin,
819 ScrollXMax,
820 ScrollY,
821 ScrollYMin,
822 ScrollYMax,
823 NumericValue,
824 MinNumericValue,
825 MaxNumericValue,
826 NumericValueStep,
827 NumericValueJump,
828 FontSize,
829 FontWeight,
830
831 RowCount,
833 ColumnCount,
834 RowIndex,
835 ColumnIndex,
836 RowSpan,
837 ColumnSpan,
838 Level,
839 SizeOfSet,
840 PositionInSet,
841
842 ColorValue,
844 BackgroundColor,
845 ForegroundColor,
846
847 Overline,
849 Strikethrough,
850 Underline,
851
852 CharacterLengths,
854 WordLengths,
855
856 CharacterPositions,
858 CharacterWidths,
859
860 Expanded,
862 Selected,
863
864 Invalid,
866 Toggled,
867 Live,
868 TextDirection,
869 Orientation,
870 SortDirection,
871 AriaCurrent,
872 AutoComplete,
873 HasPopup,
874 ListStyle,
875 TextAlign,
876 VerticalOffset,
877
878 Transform,
880 Bounds,
881 TextSelection,
882 CustomActions,
883
884 Unset,
886}
887
888#[derive(Clone, Copy, Debug, PartialEq, Eq)]
889#[repr(transparent)]
890struct PropertyIndices([u8; PropertyId::Unset as usize]);
891
892impl Default for PropertyIndices {
893 fn default() -> Self {
894 Self([PropertyId::Unset as u8; PropertyId::Unset as usize])
895 }
896}
897
898#[derive(Clone, Debug, Default, PartialEq)]
899struct Properties {
900 indices: PropertyIndices,
901 values: Vec<PropertyValue>,
902}
903
904#[derive(Clone, Default, PartialEq)]
911#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
912#[cfg_attr(feature = "schemars", derive(JsonSchema))]
913#[cfg_attr(feature = "serde", serde(deny_unknown_fields))]
914#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
915pub struct Node {
916 role: Role,
917 actions: u32,
918 flags: u32,
919 properties: Properties,
920}
921
922impl PropertyIndices {
923 fn get<'a>(&self, values: &'a [PropertyValue], id: PropertyId) -> &'a PropertyValue {
924 let index = self.0[id as usize];
925 if index == PropertyId::Unset as u8 {
926 &PropertyValue::None
927 } else {
928 &values[index as usize]
929 }
930 }
931}
932
933impl Properties {
934 fn get_mut(&mut self, id: PropertyId, default: PropertyValue) -> &mut PropertyValue {
935 let index = self.indices.0[id as usize] as usize;
936 if index == PropertyId::Unset as usize {
937 self.values.push(default);
938 let index = self.values.len() - 1;
939 self.indices.0[id as usize] = index as u8;
940 &mut self.values[index]
941 } else {
942 &mut self.values[index]
943 }
944 }
945
946 fn set(&mut self, id: PropertyId, value: PropertyValue) {
947 let index = self.indices.0[id as usize];
948 if index == PropertyId::Unset as u8 {
949 self.values.push(value);
950 self.indices.0[id as usize] = (self.values.len() - 1) as u8;
951 } else {
952 self.values[index as usize] = value;
953 }
954 }
955
956 fn clear(&mut self, id: PropertyId) {
957 let index = self.indices.0[id as usize];
958 if index != PropertyId::Unset as u8 {
959 self.values[index as usize] = PropertyValue::None;
960 }
961 }
962}
963
964macro_rules! flag_methods {
965 ($($(#[$doc:meta])* ($id:ident, $getter:ident, $setter:ident, $clearer:ident)),+) => {
966 impl Node {
967 $($(#[$doc])*
968 #[inline]
969 pub fn $getter(&self) -> bool {
970 (self.flags & (Flag::$id).mask()) != 0
971 }
972 #[inline]
973 pub fn $setter(&mut self) {
974 self.flags |= (Flag::$id).mask();
975 }
976 #[inline]
977 pub fn $clearer(&mut self) {
978 self.flags &= !((Flag::$id).mask());
979 })*
980 fn debug_flag_properties(&self, fmt: &mut fmt::DebugStruct) {
981 $(
982 if self.$getter() {
983 fmt.field(stringify!($getter), &true);
984 }
985 )*
986 }
987 }
988 $(#[cfg(test)]
989 mod $getter {
990 use super::{Node, Role};
991
992 #[test]
993 fn getter_should_return_default_value() {
994 let node = Node::new(Role::Unknown);
995 assert!(!node.$getter());
996 }
997
998 #[test]
999 fn setter_should_update_the_property() {
1000 let mut node = Node::new(Role::Unknown);
1001 node.$setter();
1002 assert!(node.$getter());
1003 }
1004
1005 #[test]
1006 fn clearer_should_reset_the_property() {
1007 let mut node = Node::new(Role::Unknown);
1008 node.$setter();
1009 node.$clearer();
1010 assert!(!node.$getter());
1011 }
1012 })*
1013 }
1014}
1015
1016macro_rules! option_ref_type_getters {
1017 ($(($method:ident, $type:ty, $variant:ident)),+) => {
1018 impl PropertyIndices {
1019 $(fn $method<'a>(&self, values: &'a [PropertyValue], id: PropertyId) -> Option<&'a $type> {
1020 match self.get(values, id) {
1021 PropertyValue::$variant(value) => Some(value),
1022 _ => None,
1023 }
1024 })*
1025 }
1026 }
1027}
1028
1029macro_rules! slice_type_getters {
1030 ($(($method:ident, $type:ty, $variant:ident)),+) => {
1031 impl PropertyIndices {
1032 $(fn $method<'a>(&self, values: &'a [PropertyValue], id: PropertyId) -> &'a [$type] {
1033 match self.get(values, id) {
1034 PropertyValue::$variant(value) => value,
1035 _ => &[],
1036 }
1037 })*
1038 }
1039 }
1040}
1041
1042macro_rules! copy_type_getters {
1043 ($(($method:ident, $type:ty, $variant:ident)),+) => {
1044 impl PropertyIndices {
1045 $(fn $method(&self, values: &[PropertyValue], id: PropertyId) -> Option<$type> {
1046 match self.get(values, id) {
1047 PropertyValue::$variant(value) => Some(*value),
1048 _ => None,
1049 }
1050 })*
1051 }
1052 }
1053}
1054
1055macro_rules! box_type_setters {
1056 ($(($method:ident, $type:ty, $variant:ident)),+) => {
1057 impl Node {
1058 $(fn $method(&mut self, id: PropertyId, value: impl Into<Box<$type>>) {
1059 self.properties.set(id, PropertyValue::$variant(value.into()));
1060 })*
1061 }
1062 }
1063}
1064
1065macro_rules! copy_type_setters {
1066 ($(($method:ident, $type:ty, $variant:ident)),+) => {
1067 impl Node {
1068 $(fn $method(&mut self, id: PropertyId, value: $type) {
1069 self.properties.set(id, PropertyValue::$variant(value));
1070 })*
1071 }
1072 }
1073}
1074
1075macro_rules! vec_type_methods {
1076 ($(($type:ty, $variant:ident, $getter:ident, $setter:ident, $pusher:ident)),+) => {
1077 $(slice_type_getters! {
1078 ($getter, $type, $variant)
1079 })*
1080 impl Node {
1081 $(fn $setter(&mut self, id: PropertyId, value: impl Into<Vec<$type>>) {
1082 self.properties.set(id, PropertyValue::$variant(value.into()));
1083 }
1084 fn $pusher(&mut self, id: PropertyId, item: $type) {
1085 if let PropertyValue::$variant(v) = self.properties.get_mut(id, PropertyValue::$variant(Vec::new())) {
1086 v.push(item);
1087 }
1088 })*
1089 }
1090 }
1091}
1092
1093macro_rules! property_methods {
1094 ($($(#[$doc:meta])* ($id:ident, $getter:ident, $type_getter:ident, $getter_result:ty, $setter:ident, $type_setter:ident, $setter_param:ty, $clearer:ident)),+) => {
1095 impl Node {
1096 $($(#[$doc])*
1097 #[inline]
1098 pub fn $getter(&self) -> $getter_result {
1099 self.properties.indices.$type_getter(&self.properties.values, PropertyId::$id)
1100 }
1101 #[inline]
1102 pub fn $setter(&mut self, value: $setter_param) {
1103 self.$type_setter(PropertyId::$id, value);
1104 }
1105 #[inline]
1106 pub fn $clearer(&mut self) {
1107 self.properties.clear(PropertyId::$id);
1108 })*
1109 }
1110 }
1111}
1112
1113macro_rules! vec_property_methods {
1114 ($($(#[$doc:meta])* ($id:ident, $item_type:ty, $getter:ident, $type_getter:ident, $setter:ident, $type_setter:ident, $pusher:ident, $type_pusher:ident, $clearer:ident)),+) => {
1115 $(property_methods! {
1116 $(#[$doc])*
1117 ($id, $getter, $type_getter, &[$item_type], $setter, $type_setter, impl Into<Vec<$item_type>>, $clearer)
1118 }
1119 impl Node {
1120 #[inline]
1121 pub fn $pusher(&mut self, item: $item_type) {
1122 self.$type_pusher(PropertyId::$id, item);
1123 }
1124 })*
1125 }
1126}
1127
1128macro_rules! slice_properties_debug_method {
1129 ($name:ident, [$($getter:ident,)*]) => {
1130 fn $name(&self, fmt: &mut fmt::DebugStruct) {
1131 $(
1132 let value = self.$getter();
1133 if !value.is_empty() {
1134 fmt.field(stringify!($getter), &value);
1135 }
1136 )*
1137 }
1138 }
1139}
1140
1141macro_rules! node_id_vec_property_methods {
1142 ($($(#[$doc:meta])* ($id:ident, $getter:ident, $setter:ident, $pusher:ident, $clearer:ident)),+) => {
1143 $(vec_property_methods! {
1144 $(#[$doc])*
1145 ($id, NodeId, $getter, get_node_id_vec, $setter, set_node_id_vec, $pusher, push_to_node_id_vec, $clearer)
1146 })*
1147 impl Node {
1148 slice_properties_debug_method! { debug_node_id_vec_properties, [$($getter,)*] }
1149 }
1150 $(#[cfg(test)]
1151 mod $getter {
1152 use super::{Node, NodeId, Role};
1153
1154 #[test]
1155 fn getter_should_return_default_value() {
1156 let node = Node::new(Role::Unknown);
1157 assert!(node.$getter().is_empty());
1158 }
1159 #[test]
1160 fn setter_should_update_the_property() {
1161 let mut node = Node::new(Role::Unknown);
1162 node.$setter([]);
1163 assert!(node.$getter().is_empty());
1164 node.$setter([NodeId(0), NodeId(1)]);
1165 assert_eq!(node.$getter(), &[NodeId(0), NodeId(1)]);
1166 }
1167 #[test]
1168 fn pusher_should_update_the_property() {
1169 let mut node = Node::new(Role::Unknown);
1170 node.$pusher(NodeId(0));
1171 assert_eq!(node.$getter(), &[NodeId(0)]);
1172 node.$pusher(NodeId(1));
1173 assert_eq!(node.$getter(), &[NodeId(0), NodeId(1)]);
1174 }
1175 #[test]
1176 fn clearer_should_reset_the_property() {
1177 let mut node = Node::new(Role::Unknown);
1178 node.$setter([NodeId(0)]);
1179 node.$clearer();
1180 assert!(node.$getter().is_empty());
1181 }
1182 })*
1183 }
1184}
1185
1186macro_rules! option_properties_debug_method {
1187 ($name:ident, [$($getter:ident,)*]) => {
1188 fn $name(&self, fmt: &mut fmt::DebugStruct) {
1189 $(
1190 if let Some(value) = self.$getter() {
1191 fmt.field(stringify!($getter), &value);
1192 }
1193 )*
1194 }
1195 }
1196}
1197
1198macro_rules! node_id_property_methods {
1199 ($($(#[$doc:meta])* ($id:ident, $getter:ident, $setter:ident, $clearer:ident)),+) => {
1200 $(property_methods! {
1201 $(#[$doc])*
1202 ($id, $getter, get_node_id_property, Option<NodeId>, $setter, set_node_id_property, NodeId, $clearer)
1203 })*
1204 impl Node {
1205 option_properties_debug_method! { debug_node_id_properties, [$($getter,)*] }
1206 }
1207 $(#[cfg(test)]
1208 mod $getter {
1209 use super::{Node, NodeId, Role};
1210
1211 #[test]
1212 fn getter_should_return_default_value() {
1213 let node = Node::new(Role::Unknown);
1214 assert!(node.$getter().is_none());
1215 }
1216 #[test]
1217 fn setter_should_update_the_property() {
1218 let mut node = Node::new(Role::Unknown);
1219 node.$setter(NodeId(1));
1220 assert_eq!(node.$getter(), Some(NodeId(1)));
1221 }
1222 #[test]
1223 fn clearer_should_reset_the_property() {
1224 let mut node = Node::new(Role::Unknown);
1225 node.$setter(NodeId(1));
1226 node.$clearer();
1227 assert!(node.$getter().is_none());
1228 }
1229 })*
1230 }
1231}
1232
1233macro_rules! string_property_methods {
1234 ($($(#[$doc:meta])* ($id:ident, $getter:ident, $setter:ident, $clearer:ident)),+) => {
1235 $(property_methods! {
1236 $(#[$doc])*
1237 ($id, $getter, get_string_property, Option<&str>, $setter, set_string_property, impl Into<Box<str>>, $clearer)
1238 })*
1239 impl Node {
1240 option_properties_debug_method! { debug_string_properties, [$($getter,)*] }
1241 }
1242 $(#[cfg(test)]
1243 mod $getter {
1244 use super::{Node, Role};
1245
1246 #[test]
1247 fn getter_should_return_default_value() {
1248 let node = Node::new(Role::Unknown);
1249 assert!(node.$getter().is_none());
1250 }
1251 #[test]
1252 fn setter_should_update_the_property() {
1253 let mut node = Node::new(Role::Unknown);
1254 node.$setter("test");
1255 assert_eq!(node.$getter(), Some("test"));
1256 }
1257 #[test]
1258 fn clearer_should_reset_the_property() {
1259 let mut node = Node::new(Role::Unknown);
1260 node.$setter("test");
1261 node.$clearer();
1262 assert!(node.$getter().is_none());
1263 }
1264 })*
1265 }
1266}
1267
1268macro_rules! f64_property_methods {
1269 ($($(#[$doc:meta])* ($id:ident, $getter:ident, $setter:ident, $clearer:ident)),+) => {
1270 $(property_methods! {
1271 $(#[$doc])*
1272 ($id, $getter, get_f64_property, Option<f64>, $setter, set_f64_property, f64, $clearer)
1273 })*
1274 impl Node {
1275 option_properties_debug_method! { debug_f64_properties, [$($getter,)*] }
1276 }
1277 $(#[cfg(test)]
1278 mod $getter {
1279 use super::{Node, Role};
1280
1281 #[test]
1282 fn getter_should_return_default_value() {
1283 let node = Node::new(Role::Unknown);
1284 assert!(node.$getter().is_none());
1285 }
1286 #[test]
1287 fn setter_should_update_the_property() {
1288 let mut node = Node::new(Role::Unknown);
1289 node.$setter(1.0);
1290 assert_eq!(node.$getter(), Some(1.0));
1291 }
1292 #[test]
1293 fn clearer_should_reset_the_property() {
1294 let mut node = Node::new(Role::Unknown);
1295 node.$setter(1.0);
1296 node.$clearer();
1297 assert!(node.$getter().is_none());
1298 }
1299 })*
1300 }
1301}
1302
1303macro_rules! usize_property_methods {
1304 ($($(#[$doc:meta])* ($id:ident, $getter:ident, $setter:ident, $clearer:ident)),+) => {
1305 $(property_methods! {
1306 $(#[$doc])*
1307 ($id, $getter, get_usize_property, Option<usize>, $setter, set_usize_property, usize, $clearer)
1308 })*
1309 impl Node {
1310 option_properties_debug_method! { debug_usize_properties, [$($getter,)*] }
1311 }
1312 $(#[cfg(test)]
1313 mod $getter {
1314 use super::{Node, Role};
1315
1316 #[test]
1317 fn getter_should_return_default_value() {
1318 let node = Node::new(Role::Unknown);
1319 assert!(node.$getter().is_none());
1320 }
1321 #[test]
1322 fn setter_should_update_the_property() {
1323 let mut node = Node::new(Role::Unknown);
1324 node.$setter(1);
1325 assert_eq!(node.$getter(), Some(1));
1326 }
1327 #[test]
1328 fn clearer_should_reset_the_property() {
1329 let mut node = Node::new(Role::Unknown);
1330 node.$setter(1);
1331 node.$clearer();
1332 assert!(node.$getter().is_none());
1333 }
1334 })*
1335 }
1336}
1337
1338macro_rules! color_property_methods {
1339 ($($(#[$doc:meta])* ($id:ident, $getter:ident, $setter:ident, $clearer:ident)),+) => {
1340 $(property_methods! {
1341 $(#[$doc])*
1342 ($id, $getter, get_color_property, Option<u32>, $setter, set_color_property, u32, $clearer)
1343 })*
1344 impl Node {
1345 option_properties_debug_method! { debug_color_properties, [$($getter,)*] }
1346 }
1347 $(#[cfg(test)]
1348 mod $getter {
1349 use super::{Node, Role};
1350
1351 #[test]
1352 fn getter_should_return_default_value() {
1353 let node = Node::new(Role::Unknown);
1354 assert!(node.$getter().is_none());
1355 }
1356 #[test]
1357 fn setter_should_update_the_property() {
1358 let mut node = Node::new(Role::Unknown);
1359 node.$setter(1);
1360 assert_eq!(node.$getter(), Some(1));
1361 }
1362 #[test]
1363 fn clearer_should_reset_the_property() {
1364 let mut node = Node::new(Role::Unknown);
1365 node.$setter(1);
1366 node.$clearer();
1367 assert!(node.$getter().is_none());
1368 }
1369 })*
1370 }
1371}
1372
1373macro_rules! text_decoration_property_methods {
1374 ($($(#[$doc:meta])* ($id:ident, $getter:ident, $setter:ident, $clearer:ident)),+) => {
1375 $(property_methods! {
1376 $(#[$doc])*
1377 ($id, $getter, get_text_decoration_property, Option<TextDecoration>, $setter, set_text_decoration_property, TextDecoration, $clearer)
1378 })*
1379 impl Node {
1380 option_properties_debug_method! { debug_text_decoration_properties, [$($getter,)*] }
1381 }
1382 $(#[cfg(test)]
1383 mod $getter {
1384 use super::{Node, Role, TextDecoration};
1385
1386 #[test]
1387 fn getter_should_return_default_value() {
1388 let node = Node::new(Role::Unknown);
1389 assert!(node.$getter().is_none());
1390 }
1391 #[test]
1392 fn setter_should_update_the_property() {
1393 let mut node = Node::new(Role::Unknown);
1394 node.$setter(TextDecoration::Dotted);
1395 assert_eq!(node.$getter(), Some(TextDecoration::Dotted));
1396 }
1397 #[test]
1398 fn clearer_should_reset_the_property() {
1399 let mut node = Node::new(Role::Unknown);
1400 node.$setter(TextDecoration::Dotted);
1401 node.$clearer();
1402 assert!(node.$getter().is_none());
1403 }
1404 })*
1405 }
1406}
1407
1408macro_rules! length_slice_property_methods {
1409 ($($(#[$doc:meta])* ($id:ident, $getter:ident, $setter:ident, $clearer:ident)),+) => {
1410 $(property_methods! {
1411 $(#[$doc])*
1412 ($id, $getter, get_length_slice_property, &[u8], $setter, set_length_slice_property, impl Into<Box<[u8]>>, $clearer)
1413 })*
1414 impl Node {
1415 slice_properties_debug_method! { debug_length_slice_properties, [$($getter,)*] }
1416 }
1417 $(#[cfg(test)]
1418 mod $getter {
1419 use super::{Node, Role};
1420
1421 #[test]
1422 fn getter_should_return_default_value() {
1423 let node = Node::new(Role::Unknown);
1424 assert!(node.$getter().is_empty());
1425 }
1426 #[test]
1427 fn setter_should_update_the_property() {
1428 let mut node = Node::new(Role::Unknown);
1429 node.$setter([]);
1430 assert!(node.$getter().is_empty());
1431 node.$setter([1, 2]);
1432 assert_eq!(node.$getter(), &[1, 2]);
1433 }
1434 #[test]
1435 fn clearer_should_reset_the_property() {
1436 let mut node = Node::new(Role::Unknown);
1437 node.$setter([1, 2]);
1438 node.$clearer();
1439 assert!(node.$getter().is_empty());
1440 }
1441 })*
1442 }
1443}
1444
1445macro_rules! coord_slice_property_methods {
1446 ($($(#[$doc:meta])* ($id:ident, $getter:ident, $setter:ident, $clearer:ident)),+) => {
1447 $(property_methods! {
1448 $(#[$doc])*
1449 ($id, $getter, get_coord_slice_property, Option<&[f32]>, $setter, set_coord_slice_property, impl Into<Box<[f32]>>, $clearer)
1450 })*
1451 impl Node {
1452 option_properties_debug_method! { debug_coord_slice_properties, [$($getter,)*] }
1453 }
1454 $(#[cfg(test)]
1455 mod $getter {
1456 use super::{Node, Role};
1457
1458 #[test]
1459 fn getter_should_return_default_value() {
1460 let node = Node::new(Role::Unknown);
1461 assert!(node.$getter().is_none());
1462 }
1463 #[test]
1464 fn setter_should_update_the_property() {
1465 let mut node = Node::new(Role::Unknown);
1466 node.$setter([]);
1467 let expected: Option<&[f32]> = Some(&[]);
1468 assert_eq!(node.$getter(), expected);
1469 node.$setter([1.0, 2.0]);
1470 let expected: Option<&[f32]> = Some(&[1.0, 2.0]);
1471 assert_eq!(node.$getter(), expected);
1472 }
1473 #[test]
1474 fn clearer_should_reset_the_property() {
1475 let mut node = Node::new(Role::Unknown);
1476 node.$setter([1.0, 2.0]);
1477 node.$clearer();
1478 assert!(node.$getter().is_none());
1479 }
1480 })*
1481 }
1482}
1483
1484macro_rules! bool_property_methods {
1485 ($($(#[$doc:meta])* ($id:ident, $getter:ident, $setter:ident, $clearer:ident)),+) => {
1486 $(property_methods! {
1487 $(#[$doc])*
1488 ($id, $getter, get_bool_property, Option<bool>, $setter, set_bool_property, bool, $clearer)
1489 })*
1490 impl Node {
1491 option_properties_debug_method! { debug_bool_properties, [$($getter,)*] }
1492 }
1493 $(#[cfg(test)]
1494 mod $getter {
1495 use super::{Node, Role};
1496
1497 #[test]
1498 fn getter_should_return_default_value() {
1499 let node = Node::new(Role::Unknown);
1500 assert!(node.$getter().is_none());
1501 }
1502 #[test]
1503 fn setter_should_update_the_property() {
1504 let mut node = Node::new(Role::Unknown);
1505 node.$setter(true);
1506 assert_eq!(node.$getter(), Some(true));
1507 }
1508 #[test]
1509 fn clearer_should_reset_the_property() {
1510 let mut node = Node::new(Role::Unknown);
1511 node.$setter(true);
1512 node.$clearer();
1513 assert!(node.$getter().is_none());
1514 }
1515 })*
1516 }
1517}
1518
1519macro_rules! unique_enum_property_methods {
1520 ($($(#[$doc:meta])* ($id:ident, $getter:ident, $setter:ident, $clearer:ident, $variant:ident)),+) => {
1521 impl Node {
1522 $($(#[$doc])*
1523 #[inline]
1524 pub fn $getter(&self) -> Option<$id> {
1525 match self.properties.indices.get(&self.properties.values, PropertyId::$id) {
1526 PropertyValue::$id(value) => Some(*value),
1527 _ => None,
1528 }
1529 }
1530 #[inline]
1531 pub fn $setter(&mut self, value: $id) {
1532 self.properties.set(PropertyId::$id, PropertyValue::$id(value));
1533 }
1534 #[inline]
1535 pub fn $clearer(&mut self) {
1536 self.properties.clear(PropertyId::$id);
1537 })*
1538 option_properties_debug_method! { debug_unique_enum_properties, [$($getter,)*] }
1539 }
1540 $(#[cfg(test)]
1541 mod $getter {
1542 use super::{Node, Role};
1543
1544 #[test]
1545 fn getter_should_return_default_value() {
1546 let node = Node::new(Role::Unknown);
1547 assert!(node.$getter().is_none());
1548 }
1549 #[test]
1550 fn setter_should_update_the_property() {
1551 let mut node = Node::new(Role::Unknown);
1552 let variant = super::$id::$variant;
1553 node.$setter(variant);
1554 assert_eq!(node.$getter(), Some(variant));
1555 }
1556 #[test]
1557 fn clearer_should_reset_the_property() {
1558 let mut node = Node::new(Role::Unknown);
1559 node.$setter(super::$id::$variant);
1560 node.$clearer();
1561 assert!(node.$getter().is_none());
1562 }
1563 })*
1564 }
1565}
1566
1567impl Node {
1568 #[inline]
1569 pub fn new(role: Role) -> Self {
1570 Self {
1571 role,
1572 ..Default::default()
1573 }
1574 }
1575}
1576
1577impl Node {
1578 #[inline]
1579 pub fn role(&self) -> Role {
1580 self.role
1581 }
1582 #[inline]
1583 pub fn set_role(&mut self, value: Role) {
1584 self.role = value;
1585 }
1586
1587 #[inline]
1588 pub fn supports_action(&self, action: Action) -> bool {
1589 (self.actions & action.mask()) != 0
1590 }
1591 #[inline]
1592 pub fn add_action(&mut self, action: Action) {
1593 self.actions |= action.mask();
1594 }
1595 #[inline]
1596 pub fn remove_action(&mut self, action: Action) {
1597 self.actions &= !(action.mask());
1598 }
1599 #[inline]
1600 pub fn clear_actions(&mut self) {
1601 self.actions = 0;
1602 }
1603}
1604
1605flag_methods! {
1606 (Hidden, is_hidden, set_hidden, clear_hidden),
1609 (Multiselectable, is_multiselectable, set_multiselectable, clear_multiselectable),
1610 (Required, is_required, set_required, clear_required),
1611 (Visited, is_visited, set_visited, clear_visited),
1612 (Busy, is_busy, set_busy, clear_busy),
1613 (LiveAtomic, is_live_atomic, set_live_atomic, clear_live_atomic),
1614 (Modal, is_modal, set_modal, clear_modal),
1616 (TouchTransparent, is_touch_transparent, set_touch_transparent, clear_touch_transparent),
1620 (ReadOnly, is_read_only, set_read_only, clear_read_only),
1622 (Disabled, is_disabled, set_disabled, clear_disabled),
1624 (Bold, is_bold, set_bold, clear_bold),
1625 (Italic, is_italic, set_italic, clear_italic),
1626 (ClipsChildren, clips_children, set_clips_children, clear_clips_children),
1629 (IsLineBreakingObject, is_line_breaking_object, set_is_line_breaking_object, clear_is_line_breaking_object),
1632 (IsPageBreakingObject, is_page_breaking_object, set_is_page_breaking_object, clear_is_page_breaking_object),
1634 (IsSpellingError, is_spelling_error, set_is_spelling_error, clear_is_spelling_error),
1635 (IsGrammarError, is_grammar_error, set_is_grammar_error, clear_is_grammar_error),
1636 (IsSearchMatch, is_search_match, set_is_search_match, clear_is_search_match),
1637 (IsSuggestion, is_suggestion, set_is_suggestion, clear_is_suggestion)
1638}
1639
1640option_ref_type_getters! {
1641 (get_affine_property, Affine, Affine),
1642 (get_string_property, str, String),
1643 (get_coord_slice_property, [f32], CoordSlice),
1644 (get_text_selection_property, TextSelection, TextSelection)
1645}
1646
1647slice_type_getters! {
1648 (get_length_slice_property, u8, LengthSlice)
1649}
1650
1651copy_type_getters! {
1652 (get_rect_property, Rect, Rect),
1653 (get_node_id_property, NodeId, NodeId),
1654 (get_f64_property, f64, F64),
1655 (get_usize_property, usize, Usize),
1656 (get_color_property, u32, Color),
1657 (get_text_decoration_property, TextDecoration, TextDecoration),
1658 (get_bool_property, bool, Bool)
1659}
1660
1661box_type_setters! {
1662 (set_affine_property, Affine, Affine),
1663 (set_string_property, str, String),
1664 (set_length_slice_property, [u8], LengthSlice),
1665 (set_coord_slice_property, [f32], CoordSlice),
1666 (set_text_selection_property, TextSelection, TextSelection)
1667}
1668
1669copy_type_setters! {
1670 (set_rect_property, Rect, Rect),
1671 (set_node_id_property, NodeId, NodeId),
1672 (set_f64_property, f64, F64),
1673 (set_usize_property, usize, Usize),
1674 (set_color_property, u32, Color),
1675 (set_text_decoration_property, TextDecoration, TextDecoration),
1676 (set_bool_property, bool, Bool)
1677}
1678
1679vec_type_methods! {
1680 (NodeId, NodeIdVec, get_node_id_vec, set_node_id_vec, push_to_node_id_vec),
1681 (CustomAction, CustomActionVec, get_custom_action_vec, set_custom_action_vec, push_to_custom_action_vec)
1682}
1683
1684node_id_vec_property_methods! {
1685 (Children, children, set_children, push_child, clear_children),
1686 (Controls, controls, set_controls, push_controlled, clear_controls),
1687 (Details, details, set_details, push_detail, clear_details),
1688 (DescribedBy, described_by, set_described_by, push_described_by, clear_described_by),
1689 (FlowTo, flow_to, set_flow_to, push_flow_to, clear_flow_to),
1690 (LabelledBy, labelled_by, set_labelled_by, push_labelled_by, clear_labelled_by),
1691 (Owns, owns, set_owns, push_owned, clear_owns),
1697 (RadioGroup, radio_group, set_radio_group, push_to_radio_group, clear_radio_group)
1700}
1701
1702node_id_property_methods! {
1703 (ActiveDescendant, active_descendant, set_active_descendant, clear_active_descendant),
1704 (ErrorMessage, error_message, set_error_message, clear_error_message),
1705 (InPageLinkTarget, in_page_link_target, set_in_page_link_target, clear_in_page_link_target),
1706 (MemberOf, member_of, set_member_of, clear_member_of),
1707 (NextOnLine, next_on_line, set_next_on_line, clear_next_on_line),
1708 (PreviousOnLine, previous_on_line, set_previous_on_line, clear_previous_on_line),
1709 (PopupFor, popup_for, set_popup_for, clear_popup_for)
1710}
1711
1712string_property_methods! {
1713 (Label, label, set_label, clear_label),
1718 (Description, description, set_description, clear_description),
1719 (Value, value, set_value, clear_value),
1720 (AccessKey, access_key, set_access_key, clear_access_key),
1728 (AuthorId, author_id, set_author_id, clear_author_id),
1731 (ClassName, class_name, set_class_name, clear_class_name),
1732 (FontFamily, font_family, set_font_family, clear_font_family),
1734 (HtmlTag, html_tag, set_html_tag, clear_html_tag),
1735 (InnerHtml, inner_html, set_inner_html, clear_inner_html),
1738 (KeyboardShortcut, keyboard_shortcut, set_keyboard_shortcut, clear_keyboard_shortcut),
1742 (Language, language, set_language, clear_language),
1744 (Placeholder, placeholder, set_placeholder, clear_placeholder),
1749 (RoleDescription, role_description, set_role_description, clear_role_description),
1753 (StateDescription, state_description, set_state_description, clear_state_description),
1758 (Tooltip, tooltip, set_tooltip, clear_tooltip),
1763 (Url, url, set_url, clear_url),
1764 (RowIndexText, row_index_text, set_row_index_text, clear_row_index_text),
1765 (ColumnIndexText, column_index_text, set_column_index_text, clear_column_index_text)
1766}
1767
1768f64_property_methods! {
1769 (ScrollX, scroll_x, set_scroll_x, clear_scroll_x),
1770 (ScrollXMin, scroll_x_min, set_scroll_x_min, clear_scroll_x_min),
1771 (ScrollXMax, scroll_x_max, set_scroll_x_max, clear_scroll_x_max),
1772 (ScrollY, scroll_y, set_scroll_y, clear_scroll_y),
1773 (ScrollYMin, scroll_y_min, set_scroll_y_min, clear_scroll_y_min),
1774 (ScrollYMax, scroll_y_max, set_scroll_y_max, clear_scroll_y_max),
1775 (NumericValue, numeric_value, set_numeric_value, clear_numeric_value),
1776 (MinNumericValue, min_numeric_value, set_min_numeric_value, clear_min_numeric_value),
1777 (MaxNumericValue, max_numeric_value, set_max_numeric_value, clear_max_numeric_value),
1778 (NumericValueStep, numeric_value_step, set_numeric_value_step, clear_numeric_value_step),
1779 (NumericValueJump, numeric_value_jump, set_numeric_value_jump, clear_numeric_value_jump),
1780 (FontSize, font_size, set_font_size, clear_font_size),
1782 (FontWeight, font_weight, set_font_weight, clear_font_weight)
1785}
1786
1787usize_property_methods! {
1788 (RowCount, row_count, set_row_count, clear_row_count),
1789 (ColumnCount, column_count, set_column_count, clear_column_count),
1790 (RowIndex, row_index, set_row_index, clear_row_index),
1791 (ColumnIndex, column_index, set_column_index, clear_column_index),
1792 (RowSpan, row_span, set_row_span, clear_row_span),
1793 (ColumnSpan, column_span, set_column_span, clear_column_span),
1794 (Level, level, set_level, clear_level),
1795 (SizeOfSet, size_of_set, set_size_of_set, clear_size_of_set),
1797 (PositionInSet, position_in_set, set_position_in_set, clear_position_in_set)
1802}
1803
1804color_property_methods! {
1805 (ColorValue, color_value, set_color_value, clear_color_value),
1807 (BackgroundColor, background_color, set_background_color, clear_background_color),
1809 (ForegroundColor, foreground_color, set_foreground_color, clear_foreground_color)
1811}
1812
1813text_decoration_property_methods! {
1814 (Overline, overline, set_overline, clear_overline),
1815 (Strikethrough, strikethrough, set_strikethrough, clear_strikethrough),
1816 (Underline, underline, set_underline, clear_underline)
1817}
1818
1819length_slice_property_methods! {
1820 (CharacterLengths, character_lengths, set_character_lengths, clear_character_lengths),
1839
1840 (WordLengths, word_lengths, set_word_lengths, clear_word_lengths)
1863}
1864
1865coord_slice_property_methods! {
1866 (CharacterPositions, character_positions, set_character_positions, clear_character_positions),
1883
1884 (CharacterWidths, character_widths, set_character_widths, clear_character_widths)
1903}
1904
1905bool_property_methods! {
1906 (Expanded, is_expanded, set_expanded, clear_expanded),
1911
1912 (Selected, is_selected, set_selected, clear_selected)
1922}
1923
1924unique_enum_property_methods! {
1925 (Invalid, invalid, set_invalid, clear_invalid, Grammar),
1926 (Toggled, toggled, set_toggled, clear_toggled, True),
1927 (Live, live, set_live, clear_live, Polite),
1928 (TextDirection, text_direction, set_text_direction, clear_text_direction, RightToLeft),
1929 (Orientation, orientation, set_orientation, clear_orientation, Vertical),
1930 (SortDirection, sort_direction, set_sort_direction, clear_sort_direction, Descending),
1931 (AriaCurrent, aria_current, set_aria_current, clear_aria_current, True),
1932 (AutoComplete, auto_complete, set_auto_complete, clear_auto_complete, List),
1933 (HasPopup, has_popup, set_has_popup, clear_has_popup, Menu),
1934 (ListStyle, list_style, set_list_style, clear_list_style, Disc),
1936 (TextAlign, text_align, set_text_align, clear_text_align, Right),
1937 (VerticalOffset, vertical_offset, set_vertical_offset, clear_vertical_offset, Superscript)
1938}
1939
1940property_methods! {
1941 (Transform, transform, get_affine_property, Option<&Affine>, set_transform, set_affine_property, impl Into<Box<Affine>>, clear_transform),
1954
1955 (Bounds, bounds, get_rect_property, Option<Rect>, set_bounds, set_rect_property, Rect, clear_bounds),
1966
1967 (TextSelection, text_selection, get_text_selection_property, Option<&TextSelection>, set_text_selection, set_text_selection_property, impl Into<Box<TextSelection>>, clear_text_selection)
1968}
1969
1970impl Node {
1971 option_properties_debug_method! { debug_option_properties, [transform, bounds, text_selection,] }
1972}
1973
1974#[cfg(test)]
1975mod transform {
1976 use super::{Affine, Node, Role};
1977
1978 #[test]
1979 fn getter_should_return_default_value() {
1980 let node = Node::new(Role::Unknown);
1981 assert!(node.transform().is_none());
1982 }
1983 #[test]
1984 fn setter_should_update_the_property() {
1985 let mut node = Node::new(Role::Unknown);
1986 node.set_transform(Affine::IDENTITY);
1987 assert_eq!(node.transform(), Some(&Affine::IDENTITY));
1988 }
1989 #[test]
1990 fn clearer_should_reset_the_property() {
1991 let mut node = Node::new(Role::Unknown);
1992 node.set_transform(Affine::IDENTITY);
1993 node.clear_transform();
1994 assert!(node.transform().is_none());
1995 }
1996}
1997
1998#[cfg(test)]
1999mod bounds {
2000 use super::{Node, Rect, Role};
2001
2002 #[test]
2003 fn getter_should_return_default_value() {
2004 let node = Node::new(Role::Unknown);
2005 assert!(node.bounds().is_none());
2006 }
2007 #[test]
2008 fn setter_should_update_the_property() {
2009 let mut node = Node::new(Role::Unknown);
2010 let value = Rect {
2011 x0: 0.0,
2012 y0: 1.0,
2013 x1: 2.0,
2014 y1: 3.0,
2015 };
2016 node.set_bounds(value);
2017 assert_eq!(node.bounds(), Some(value));
2018 }
2019 #[test]
2020 fn clearer_should_reset_the_property() {
2021 let mut node = Node::new(Role::Unknown);
2022 node.set_bounds(Rect {
2023 x0: 0.0,
2024 y0: 1.0,
2025 x1: 2.0,
2026 y1: 3.0,
2027 });
2028 node.clear_bounds();
2029 assert!(node.bounds().is_none());
2030 }
2031}
2032
2033#[cfg(test)]
2034mod text_selection {
2035 use super::{Node, NodeId, Role, TextPosition, TextSelection};
2036
2037 #[test]
2038 fn getter_should_return_default_value() {
2039 let node = Node::new(Role::Unknown);
2040 assert!(node.text_selection().is_none());
2041 }
2042 #[test]
2043 fn setter_should_update_the_property() {
2044 let mut node = Node::new(Role::Unknown);
2045 let value = TextSelection {
2046 anchor: TextPosition {
2047 node: NodeId(0),
2048 character_index: 0,
2049 },
2050 focus: TextPosition {
2051 node: NodeId(0),
2052 character_index: 2,
2053 },
2054 };
2055 node.set_text_selection(value);
2056 assert_eq!(node.text_selection(), Some(&value));
2057 }
2058 #[test]
2059 fn clearer_should_reset_the_property() {
2060 let mut node = Node::new(Role::Unknown);
2061 node.set_text_selection(TextSelection {
2062 anchor: TextPosition {
2063 node: NodeId(0),
2064 character_index: 0,
2065 },
2066 focus: TextPosition {
2067 node: NodeId(0),
2068 character_index: 2,
2069 },
2070 });
2071 node.clear_text_selection();
2072 assert!(node.text_selection().is_none());
2073 }
2074}
2075
2076vec_property_methods! {
2077 (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)
2078}
2079
2080#[cfg(test)]
2081mod custom_actions {
2082 use super::{CustomAction, Node, Role};
2083
2084 #[test]
2085 fn getter_should_return_default_value() {
2086 let node = Node::new(Role::Unknown);
2087 assert!(node.custom_actions().is_empty());
2088 }
2089 #[test]
2090 fn setter_should_update_the_property() {
2091 let mut node = Node::new(Role::Unknown);
2092 let value = alloc::vec![
2093 CustomAction {
2094 id: 0,
2095 description: "first test action".into(),
2096 },
2097 CustomAction {
2098 id: 1,
2099 description: "second test action".into(),
2100 },
2101 ];
2102 node.set_custom_actions(value.clone());
2103 assert_eq!(node.custom_actions(), value);
2104 }
2105 #[test]
2106 fn pusher_should_update_the_property() {
2107 let mut node = Node::new(Role::Unknown);
2108 let first_action = CustomAction {
2109 id: 0,
2110 description: "first test action".into(),
2111 };
2112 let second_action = CustomAction {
2113 id: 1,
2114 description: "second test action".into(),
2115 };
2116 node.push_custom_action(first_action.clone());
2117 assert_eq!(node.custom_actions(), &[first_action.clone()]);
2118 node.push_custom_action(second_action.clone());
2119 assert_eq!(node.custom_actions(), &[first_action, second_action]);
2120 }
2121 #[test]
2122 fn clearer_should_reset_the_property() {
2123 let mut node = Node::new(Role::Unknown);
2124 node.set_custom_actions([CustomAction {
2125 id: 0,
2126 description: "test action".into(),
2127 }]);
2128 node.clear_custom_actions();
2129 assert!(node.custom_actions().is_empty());
2130 }
2131}
2132
2133impl fmt::Debug for Node {
2134 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2135 let mut fmt = f.debug_struct("Node");
2136
2137 fmt.field("role", &self.role());
2138
2139 let supported_actions = action_mask_to_action_vec(self.actions);
2140 if !supported_actions.is_empty() {
2141 fmt.field("actions", &supported_actions);
2142 }
2143
2144 self.debug_flag_properties(&mut fmt);
2145 self.debug_node_id_vec_properties(&mut fmt);
2146 self.debug_node_id_properties(&mut fmt);
2147 self.debug_string_properties(&mut fmt);
2148 self.debug_f64_properties(&mut fmt);
2149 self.debug_usize_properties(&mut fmt);
2150 self.debug_color_properties(&mut fmt);
2151 self.debug_text_decoration_properties(&mut fmt);
2152 self.debug_length_slice_properties(&mut fmt);
2153 self.debug_coord_slice_properties(&mut fmt);
2154 self.debug_bool_properties(&mut fmt);
2155 self.debug_unique_enum_properties(&mut fmt);
2156 self.debug_option_properties(&mut fmt);
2157
2158 let custom_actions = self.custom_actions();
2159 if !custom_actions.is_empty() {
2160 fmt.field("custom_actions", &custom_actions);
2161 }
2162
2163 fmt.finish()
2164 }
2165}
2166
2167#[cfg(feature = "serde")]
2168macro_rules! serialize_property {
2169 ($self:ident, $map:ident, $index:ident, $id:ident, { $($variant:ident),+ }) => {
2170 match &$self.values[$index as usize] {
2171 PropertyValue::None => (),
2172 $(PropertyValue::$variant(value) => {
2173 $map.serialize_entry(&$id, &value)?;
2174 })*
2175 }
2176 }
2177}
2178
2179#[cfg(feature = "serde")]
2180macro_rules! deserialize_property {
2181 ($props:ident, $map:ident, $key:ident, { $($type:ident { $($id:ident),+ }),+ }) => {
2182 match $key {
2183 $($(PropertyId::$id => {
2184 let value = $map.next_value()?;
2185 $props.set(PropertyId::$id, PropertyValue::$type(value));
2186 })*)*
2187 PropertyId::Unset => {
2188 let _ = $map.next_value::<IgnoredAny>()?;
2189 }
2190 }
2191 }
2192}
2193
2194#[cfg(feature = "serde")]
2195impl Serialize for Properties {
2196 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
2197 where
2198 S: Serializer,
2199 {
2200 let mut len = 0;
2201 for value in &*self.values {
2202 if !matches!(*value, PropertyValue::None) {
2203 len += 1;
2204 }
2205 }
2206 let mut map = serializer.serialize_map(Some(len))?;
2207 for (id, index) in self.indices.0.iter().copied().enumerate() {
2208 if index == PropertyId::Unset as u8 {
2209 continue;
2210 }
2211 let id = PropertyId::n(id as _).unwrap();
2212 serialize_property!(self, map, index, id, {
2213 NodeIdVec,
2214 NodeId,
2215 String,
2216 F64,
2217 Usize,
2218 Color,
2219 TextDecoration,
2220 LengthSlice,
2221 CoordSlice,
2222 Bool,
2223 Invalid,
2224 Toggled,
2225 Live,
2226 TextDirection,
2227 Orientation,
2228 SortDirection,
2229 AriaCurrent,
2230 AutoComplete,
2231 HasPopup,
2232 ListStyle,
2233 TextAlign,
2234 VerticalOffset,
2235 Affine,
2236 Rect,
2237 TextSelection,
2238 CustomActionVec
2239 });
2240 }
2241 map.end()
2242 }
2243}
2244
2245#[cfg(feature = "serde")]
2246struct PropertiesVisitor;
2247
2248#[cfg(feature = "serde")]
2249impl<'de> Visitor<'de> for PropertiesVisitor {
2250 type Value = Properties;
2251
2252 #[inline]
2253 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
2254 formatter.write_str("property map")
2255 }
2256
2257 fn visit_map<V>(self, mut map: V) -> Result<Self::Value, V::Error>
2258 where
2259 V: MapAccess<'de>,
2260 {
2261 let mut props = Properties::default();
2262 while let Some(id) = map.next_key()? {
2263 deserialize_property!(props, map, id, {
2264 NodeIdVec {
2265 Children,
2266 Controls,
2267 Details,
2268 DescribedBy,
2269 FlowTo,
2270 LabelledBy,
2271 Owns,
2272 RadioGroup
2273 },
2274 NodeId {
2275 ActiveDescendant,
2276 ErrorMessage,
2277 InPageLinkTarget,
2278 MemberOf,
2279 NextOnLine,
2280 PreviousOnLine,
2281 PopupFor
2282 },
2283 String {
2284 Label,
2285 Description,
2286 Value,
2287 AccessKey,
2288 AuthorId,
2289 ClassName,
2290 FontFamily,
2291 HtmlTag,
2292 InnerHtml,
2293 KeyboardShortcut,
2294 Language,
2295 Placeholder,
2296 RoleDescription,
2297 StateDescription,
2298 Tooltip,
2299 Url,
2300 RowIndexText,
2301 ColumnIndexText
2302 },
2303 F64 {
2304 ScrollX,
2305 ScrollXMin,
2306 ScrollXMax,
2307 ScrollY,
2308 ScrollYMin,
2309 ScrollYMax,
2310 NumericValue,
2311 MinNumericValue,
2312 MaxNumericValue,
2313 NumericValueStep,
2314 NumericValueJump,
2315 FontSize,
2316 FontWeight
2317 },
2318 Usize {
2319 RowCount,
2320 ColumnCount,
2321 RowIndex,
2322 ColumnIndex,
2323 RowSpan,
2324 ColumnSpan,
2325 Level,
2326 SizeOfSet,
2327 PositionInSet
2328 },
2329 Color {
2330 ColorValue,
2331 BackgroundColor,
2332 ForegroundColor
2333 },
2334 TextDecoration {
2335 Overline,
2336 Strikethrough,
2337 Underline
2338 },
2339 LengthSlice {
2340 CharacterLengths,
2341 WordLengths
2342 },
2343 CoordSlice {
2344 CharacterPositions,
2345 CharacterWidths
2346 },
2347 Bool {
2348 Expanded,
2349 Selected
2350 },
2351 Invalid { Invalid },
2352 Toggled { Toggled },
2353 Live { Live },
2354 TextDirection { TextDirection },
2355 Orientation { Orientation },
2356 SortDirection { SortDirection },
2357 AriaCurrent { AriaCurrent },
2358 AutoComplete { AutoComplete },
2359 HasPopup { HasPopup },
2360 ListStyle { ListStyle },
2361 TextAlign { TextAlign },
2362 VerticalOffset { VerticalOffset },
2363 Affine { Transform },
2364 Rect { Bounds },
2365 TextSelection { TextSelection },
2366 CustomActionVec { CustomActions }
2367 });
2368 }
2369
2370 Ok(props)
2371 }
2372}
2373
2374#[cfg(feature = "serde")]
2375impl<'de> Deserialize<'de> for Properties {
2376 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
2377 where
2378 D: Deserializer<'de>,
2379 {
2380 deserializer.deserialize_map(PropertiesVisitor)
2381 }
2382}
2383
2384#[cfg(feature = "schemars")]
2385macro_rules! add_schema_property {
2386 ($gen:ident, $properties:ident, $enum_value:expr, $type:ty) => {{
2387 let name = format!("{:?}", $enum_value);
2388 let name = name[..1].to_ascii_lowercase() + &name[1..];
2389 let subschema = $gen.subschema_for::<$type>();
2390 $properties.insert(name, subschema);
2391 }};
2392}
2393
2394#[cfg(feature = "schemars")]
2395macro_rules! add_properties_to_schema {
2396 ($gen:ident, $properties:ident, { $($type:ty { $($id:ident),+ }),+ }) => {
2397 $($(add_schema_property!($gen, $properties, PropertyId::$id, $type);)*)*
2398 }
2399}
2400
2401#[cfg(feature = "schemars")]
2402impl JsonSchema for Properties {
2403 #[inline]
2404 fn schema_name() -> String {
2405 "Properties".into()
2406 }
2407
2408 fn json_schema(gen: &mut SchemaGenerator) -> Schema {
2409 let mut properties = SchemaMap::<String, Schema>::new();
2410 add_properties_to_schema!(gen, properties, {
2411 Vec<NodeId> {
2412 Children,
2413 Controls,
2414 Details,
2415 DescribedBy,
2416 FlowTo,
2417 LabelledBy,
2418 Owns,
2419 RadioGroup
2420 },
2421 NodeId {
2422 ActiveDescendant,
2423 ErrorMessage,
2424 InPageLinkTarget,
2425 MemberOf,
2426 NextOnLine,
2427 PreviousOnLine,
2428 PopupFor
2429 },
2430 Box<str> {
2431 Label,
2432 Description,
2433 Value,
2434 AccessKey,
2435 AuthorId,
2436 ClassName,
2437 FontFamily,
2438 HtmlTag,
2439 InnerHtml,
2440 KeyboardShortcut,
2441 Language,
2442 Placeholder,
2443 RoleDescription,
2444 StateDescription,
2445 Tooltip,
2446 Url,
2447 RowIndexText,
2448 ColumnIndexText
2449 },
2450 f64 {
2451 ScrollX,
2452 ScrollXMin,
2453 ScrollXMax,
2454 ScrollY,
2455 ScrollYMin,
2456 ScrollYMax,
2457 NumericValue,
2458 MinNumericValue,
2459 MaxNumericValue,
2460 NumericValueStep,
2461 NumericValueJump,
2462 FontSize,
2463 FontWeight
2464 },
2465 usize {
2466 RowCount,
2467 ColumnCount,
2468 RowIndex,
2469 ColumnIndex,
2470 RowSpan,
2471 ColumnSpan,
2472 Level,
2473 SizeOfSet,
2474 PositionInSet
2475 },
2476 u32 {
2477 ColorValue,
2478 BackgroundColor,
2479 ForegroundColor
2480 },
2481 TextDecoration {
2482 Overline,
2483 Strikethrough,
2484 Underline
2485 },
2486 Box<[u8]> {
2487 CharacterLengths,
2488 WordLengths
2489 },
2490 Box<[f32]> {
2491 CharacterPositions,
2492 CharacterWidths
2493 },
2494 bool {
2495 Expanded,
2496 Selected
2497 },
2498 Invalid { Invalid },
2499 Toggled { Toggled },
2500 Live { Live },
2501 TextDirection { TextDirection },
2502 Orientation { Orientation },
2503 SortDirection { SortDirection },
2504 AriaCurrent { AriaCurrent },
2505 AutoComplete { AutoComplete },
2506 HasPopup { HasPopup },
2507 ListStyle { ListStyle },
2508 TextAlign { TextAlign },
2509 VerticalOffset { VerticalOffset },
2510 Affine { Transform },
2511 Rect { Bounds },
2512 TextSelection { TextSelection },
2513 Vec<CustomAction> { CustomActions }
2514 });
2515 SchemaObject {
2516 instance_type: Some(InstanceType::Object.into()),
2517 object: Some(
2518 ObjectValidation {
2519 properties,
2520 ..Default::default()
2521 }
2522 .into(),
2523 ),
2524 ..Default::default()
2525 }
2526 .into()
2527 }
2528}
2529
2530#[derive(Clone, Debug, PartialEq, Eq)]
2533#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2534#[cfg_attr(feature = "schemars", derive(JsonSchema))]
2535#[cfg_attr(feature = "serde", serde(deny_unknown_fields))]
2536#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
2537pub struct Tree {
2538 pub root: NodeId,
2540 pub toolkit_name: Option<String>,
2542 pub toolkit_version: Option<String>,
2544}
2545
2546impl Tree {
2547 #[inline]
2548 pub fn new(root: NodeId) -> Tree {
2549 Tree {
2550 root,
2551 toolkit_name: None,
2552 toolkit_version: None,
2553 }
2554 }
2555}
2556
2557#[derive(Clone, Debug, PartialEq)]
2569#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2570#[cfg_attr(feature = "schemars", derive(JsonSchema))]
2571#[cfg_attr(feature = "serde", serde(deny_unknown_fields))]
2572#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
2573pub struct TreeUpdate {
2574 pub nodes: Vec<(NodeId, Node)>,
2595
2596 pub tree: Option<Tree>,
2601
2602 pub focus: NodeId,
2608}
2609
2610#[derive(Clone, Copy, Debug, PartialEq, Eq)]
2613#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2614#[cfg_attr(feature = "schemars", derive(JsonSchema))]
2615#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
2616#[cfg_attr(
2617 feature = "pyo3",
2618 pyclass(module = "accesskit", rename_all = "SCREAMING_SNAKE_CASE", eq)
2619)]
2620#[repr(u8)]
2621pub enum ScrollUnit {
2622 Item,
2626 Page,
2628}
2629
2630#[derive(Clone, Debug, PartialEq)]
2631#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2632#[cfg_attr(feature = "schemars", derive(JsonSchema))]
2633#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
2634#[repr(C)]
2635pub enum ActionData {
2636 CustomAction(i32),
2637 Value(Box<str>),
2638 NumericValue(f64),
2639 ScrollUnit(ScrollUnit),
2640 ScrollTargetRect(Rect),
2643 ScrollToPoint(Point),
2646 SetScrollOffset(Point),
2649 SetTextSelection(TextSelection),
2650}
2651
2652#[derive(Clone, Debug, PartialEq)]
2653#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2654#[cfg_attr(feature = "schemars", derive(JsonSchema))]
2655#[cfg_attr(feature = "serde", serde(deny_unknown_fields))]
2656#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
2657pub struct ActionRequest {
2658 pub action: Action,
2659 pub target: NodeId,
2660 pub data: Option<ActionData>,
2661}
2662
2663pub trait ActivationHandler {
2665 fn request_initial_tree(&mut self) -> Option<TreeUpdate>;
2687}
2688
2689pub trait ActionHandler {
2691 fn do_action(&mut self, request: ActionRequest);
2701}
2702
2703pub trait DeactivationHandler {
2705 fn deactivate_accessibility(&mut self);
2713}
2714
2715#[cfg(test)]
2716mod tests {
2717 use super::*;
2718 use alloc::format;
2719
2720 #[test]
2721 fn u64_should_be_convertible_to_node_id() {
2722 assert_eq!(NodeId::from(0u64), NodeId(0));
2723 assert_eq!(NodeId::from(1u64), NodeId(1));
2724 }
2725
2726 #[test]
2727 fn node_id_should_be_convertible_to_u64() {
2728 assert_eq!(u64::from(NodeId(0)), 0u64);
2729 assert_eq!(u64::from(NodeId(1)), 1u64);
2730 }
2731
2732 #[test]
2733 fn node_id_should_have_debug_repr() {
2734 assert_eq!(&format!("{:?}", NodeId(0)), "#0");
2735 assert_eq!(&format!("{:?}", NodeId(1)), "#1");
2736 }
2737
2738 #[test]
2739 fn action_n_should_return_the_corresponding_variant() {
2740 assert_eq!(Action::n(0), Some(Action::Click));
2741 assert_eq!(Action::n(1), Some(Action::Focus));
2742 assert_eq!(Action::n(2), Some(Action::Blur));
2743 assert_eq!(Action::n(3), Some(Action::Collapse));
2744 assert_eq!(Action::n(4), Some(Action::Expand));
2745 assert_eq!(Action::n(5), Some(Action::CustomAction));
2746 assert_eq!(Action::n(6), Some(Action::Decrement));
2747 assert_eq!(Action::n(7), Some(Action::Increment));
2748 assert_eq!(Action::n(8), Some(Action::HideTooltip));
2749 assert_eq!(Action::n(9), Some(Action::ShowTooltip));
2750 assert_eq!(Action::n(10), Some(Action::ReplaceSelectedText));
2751 assert_eq!(Action::n(11), Some(Action::ScrollDown));
2752 assert_eq!(Action::n(12), Some(Action::ScrollLeft));
2753 assert_eq!(Action::n(13), Some(Action::ScrollRight));
2754 assert_eq!(Action::n(14), Some(Action::ScrollUp));
2755 assert_eq!(Action::n(15), Some(Action::ScrollIntoView));
2756 assert_eq!(Action::n(16), Some(Action::ScrollToPoint));
2757 assert_eq!(Action::n(17), Some(Action::SetScrollOffset));
2758 assert_eq!(Action::n(18), Some(Action::SetTextSelection));
2759 assert_eq!(
2760 Action::n(19),
2761 Some(Action::SetSequentialFocusNavigationStartingPoint)
2762 );
2763 assert_eq!(Action::n(20), Some(Action::SetValue));
2764 assert_eq!(Action::n(21), Some(Action::ShowContextMenu));
2765 assert_eq!(Action::n(22), None);
2766 }
2767
2768 #[test]
2769 fn empty_action_mask_should_be_converted_to_empty_vec() {
2770 assert_eq!(
2771 Vec::<Action>::new(),
2772 action_mask_to_action_vec(Node::new(Role::Unknown).actions)
2773 );
2774 }
2775
2776 #[test]
2777 fn action_mask_should_be_convertible_to_vec() {
2778 let mut node = Node::new(Role::Unknown);
2779 node.add_action(Action::Click);
2780 assert_eq!(
2781 &[Action::Click],
2782 action_mask_to_action_vec(node.actions).as_slice()
2783 );
2784
2785 let mut node = Node::new(Role::Unknown);
2786 node.add_action(Action::ShowContextMenu);
2787 assert_eq!(
2788 &[Action::ShowContextMenu],
2789 action_mask_to_action_vec(node.actions).as_slice()
2790 );
2791
2792 let mut node = Node::new(Role::Unknown);
2793 node.add_action(Action::Click);
2794 node.add_action(Action::ShowContextMenu);
2795 assert_eq!(
2796 &[Action::Click, Action::ShowContextMenu],
2797 action_mask_to_action_vec(node.actions).as_slice()
2798 );
2799
2800 let mut node = Node::new(Role::Unknown);
2801 node.add_action(Action::Focus);
2802 node.add_action(Action::Blur);
2803 node.add_action(Action::Collapse);
2804 assert_eq!(
2805 &[Action::Focus, Action::Blur, Action::Collapse],
2806 action_mask_to_action_vec(node.actions).as_slice()
2807 );
2808 }
2809
2810 #[test]
2811 fn new_node_should_have_user_provided_role() {
2812 let node = Node::new(Role::Button);
2813 assert_eq!(node.role(), Role::Button);
2814 }
2815
2816 #[test]
2817 fn node_role_setter_should_update_the_role() {
2818 let mut node = Node::new(Role::Button);
2819 node.set_role(Role::CheckBox);
2820 assert_eq!(node.role(), Role::CheckBox);
2821 }
2822
2823 #[test]
2824 fn new_node_should_not_support_anyaction() {
2825 let node = Node::new(Role::Unknown);
2826 assert!(!node.supports_action(Action::Click));
2827 assert!(!node.supports_action(Action::Focus));
2828 assert!(!node.supports_action(Action::Blur));
2829 assert!(!node.supports_action(Action::Collapse));
2830 assert!(!node.supports_action(Action::Expand));
2831 assert!(!node.supports_action(Action::CustomAction));
2832 assert!(!node.supports_action(Action::Decrement));
2833 assert!(!node.supports_action(Action::Increment));
2834 assert!(!node.supports_action(Action::HideTooltip));
2835 assert!(!node.supports_action(Action::ShowTooltip));
2836 assert!(!node.supports_action(Action::ReplaceSelectedText));
2837 assert!(!node.supports_action(Action::ScrollDown));
2838 assert!(!node.supports_action(Action::ScrollLeft));
2839 assert!(!node.supports_action(Action::ScrollRight));
2840 assert!(!node.supports_action(Action::ScrollUp));
2841 assert!(!node.supports_action(Action::ScrollIntoView));
2842 assert!(!node.supports_action(Action::ScrollToPoint));
2843 assert!(!node.supports_action(Action::SetScrollOffset));
2844 assert!(!node.supports_action(Action::SetTextSelection));
2845 assert!(!node.supports_action(Action::SetSequentialFocusNavigationStartingPoint));
2846 assert!(!node.supports_action(Action::SetValue));
2847 assert!(!node.supports_action(Action::ShowContextMenu));
2848 }
2849
2850 #[test]
2851 fn node_add_action_should_add_the_action() {
2852 let mut node = Node::new(Role::Unknown);
2853 node.add_action(Action::Focus);
2854 assert!(node.supports_action(Action::Focus));
2855 node.add_action(Action::Blur);
2856 assert!(node.supports_action(Action::Blur));
2857 }
2858
2859 #[test]
2860 fn node_add_action_should_do_nothing_if_the_action_is_already_supported() {
2861 let mut node = Node::new(Role::Unknown);
2862 node.add_action(Action::Focus);
2863 node.add_action(Action::Focus);
2864 assert!(node.supports_action(Action::Focus));
2865 }
2866
2867 #[test]
2868 fn node_remove_action_should_remove_the_action() {
2869 let mut node = Node::new(Role::Unknown);
2870 node.add_action(Action::Blur);
2871 node.remove_action(Action::Blur);
2872 assert!(!node.supports_action(Action::Blur));
2873 }
2874
2875 #[test]
2876 fn node_clear_actions_should_remove_all_actions() {
2877 let mut node = Node::new(Role::Unknown);
2878 node.add_action(Action::Focus);
2879 node.add_action(Action::Blur);
2880 node.clear_actions();
2881 assert!(!node.supports_action(Action::Focus));
2882 assert!(!node.supports_action(Action::Blur));
2883 }
2884
2885 #[test]
2886 fn node_should_have_debug_repr() {
2887 let mut node = Node::new(Role::Unknown);
2888 node.add_action(Action::Click);
2889 node.add_action(Action::Focus);
2890 node.set_hidden();
2891 node.set_multiselectable();
2892 node.set_children([NodeId(0), NodeId(1)]);
2893 node.set_active_descendant(NodeId(2));
2894 node.push_custom_action(CustomAction {
2895 id: 0,
2896 description: "test action".into(),
2897 });
2898
2899 assert_eq!(
2900 &format!("{node:?}"),
2901 r#"Node { role: Unknown, actions: [Click, Focus], is_hidden: true, is_multiselectable: true, children: [#0, #1], active_descendant: #2, custom_actions: [CustomAction { id: 0, description: "test action" }] }"#
2902 );
2903 }
2904
2905 #[test]
2906 fn new_tree_should_have_root_id() {
2907 let tree = Tree::new(NodeId(1));
2908 assert_eq!(tree.root, NodeId(1));
2909 assert_eq!(tree.toolkit_name, None);
2910 assert_eq!(tree.toolkit_version, None);
2911 }
2912}