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")
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")
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 ScrollBackward,
311 ScrollDown,
312 ScrollForward,
313 ScrollLeft,
314 ScrollRight,
315 ScrollUp,
316
317 ScrollIntoView,
321
322 ScrollToPoint,
326
327 SetScrollOffset,
329
330 SetTextSelection,
332
333 SetSequentialFocusNavigationStartingPoint,
337
338 SetValue,
342
343 ShowContextMenu,
344}
345
346impl Action {
347 fn mask(self) -> u32 {
348 1 << (self as u8)
349 }
350
351 #[cfg(not(feature = "enumn"))]
352 fn n(value: u8) -> Option<Self> {
353 match value {
357 0 => Some(Action::Click),
358 1 => Some(Action::Focus),
359 2 => Some(Action::Blur),
360 3 => Some(Action::Collapse),
361 4 => Some(Action::Expand),
362 5 => Some(Action::CustomAction),
363 6 => Some(Action::Decrement),
364 7 => Some(Action::Increment),
365 8 => Some(Action::HideTooltip),
366 9 => Some(Action::ShowTooltip),
367 10 => Some(Action::ReplaceSelectedText),
368 11 => Some(Action::ScrollBackward),
369 12 => Some(Action::ScrollDown),
370 13 => Some(Action::ScrollForward),
371 14 => Some(Action::ScrollLeft),
372 15 => Some(Action::ScrollRight),
373 16 => Some(Action::ScrollUp),
374 17 => Some(Action::ScrollIntoView),
375 18 => Some(Action::ScrollToPoint),
376 19 => Some(Action::SetScrollOffset),
377 20 => Some(Action::SetTextSelection),
378 21 => Some(Action::SetSequentialFocusNavigationStartingPoint),
379 22 => Some(Action::SetValue),
380 23 => Some(Action::ShowContextMenu),
381 _ => None,
382 }
383 }
384}
385
386fn action_mask_to_action_vec(mask: u32) -> Vec<Action> {
387 let mut actions = Vec::new();
388 let mut i = 0;
389 while let Some(variant) = Action::n(i) {
390 if mask & variant.mask() != 0 {
391 actions.push(variant);
392 }
393 i += 1;
394 }
395 actions
396}
397
398#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
399#[cfg_attr(feature = "enumn", derive(enumn::N))]
400#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
401#[cfg_attr(feature = "schemars", derive(JsonSchema))]
402#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
403#[cfg_attr(
404 feature = "pyo3",
405 pyclass(module = "accesskit", rename_all = "SCREAMING_SNAKE_CASE")
406)]
407#[repr(u8)]
408pub enum Orientation {
409 Horizontal,
411 Vertical,
413}
414
415#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
416#[cfg_attr(feature = "enumn", derive(enumn::N))]
417#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
418#[cfg_attr(feature = "schemars", derive(JsonSchema))]
419#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
420#[cfg_attr(
421 feature = "pyo3",
422 pyclass(module = "accesskit", rename_all = "SCREAMING_SNAKE_CASE")
423)]
424#[repr(u8)]
425pub enum TextDirection {
426 LeftToRight,
427 RightToLeft,
428 TopToBottom,
429 BottomToTop,
430}
431
432#[derive(Clone, Copy, Debug, PartialEq, Eq)]
437#[cfg_attr(feature = "enumn", derive(enumn::N))]
438#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
439#[cfg_attr(feature = "schemars", derive(JsonSchema))]
440#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
441#[cfg_attr(
442 feature = "pyo3",
443 pyclass(module = "accesskit", rename_all = "SCREAMING_SNAKE_CASE")
444)]
445#[repr(u8)]
446pub enum Invalid {
447 True,
448 Grammar,
449 Spelling,
450}
451
452#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
453#[cfg_attr(feature = "enumn", derive(enumn::N))]
454#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
455#[cfg_attr(feature = "schemars", derive(JsonSchema))]
456#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
457#[cfg_attr(
458 feature = "pyo3",
459 pyclass(module = "accesskit", rename_all = "SCREAMING_SNAKE_CASE")
460)]
461#[repr(u8)]
462pub enum Toggled {
463 False,
464 True,
465 Mixed,
466}
467
468#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
469#[cfg_attr(feature = "enumn", derive(enumn::N))]
470#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
471#[cfg_attr(feature = "schemars", derive(JsonSchema))]
472#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
473#[cfg_attr(
474 feature = "pyo3",
475 pyclass(module = "accesskit", rename_all = "SCREAMING_SNAKE_CASE")
476)]
477#[repr(u8)]
478pub enum SortDirection {
479 Ascending,
480 Descending,
481 Other,
482}
483
484#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
485#[cfg_attr(feature = "enumn", derive(enumn::N))]
486#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
487#[cfg_attr(feature = "schemars", derive(JsonSchema))]
488#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
489#[cfg_attr(
490 feature = "pyo3",
491 pyclass(module = "accesskit", rename_all = "SCREAMING_SNAKE_CASE")
492)]
493#[repr(u8)]
494pub enum AriaCurrent {
495 False,
496 True,
497 Page,
498 Step,
499 Location,
500 Date,
501 Time,
502}
503
504#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
505#[cfg_attr(feature = "enumn", derive(enumn::N))]
506#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
507#[cfg_attr(feature = "schemars", derive(JsonSchema))]
508#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
509#[cfg_attr(
510 feature = "pyo3",
511 pyclass(module = "accesskit", rename_all = "SCREAMING_SNAKE_CASE")
512)]
513#[repr(u8)]
514pub enum AutoComplete {
515 Inline,
516 List,
517 Both,
518}
519
520#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
521#[cfg_attr(feature = "enumn", derive(enumn::N))]
522#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
523#[cfg_attr(feature = "schemars", derive(JsonSchema))]
524#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
525#[cfg_attr(
526 feature = "pyo3",
527 pyclass(module = "accesskit", rename_all = "SCREAMING_SNAKE_CASE")
528)]
529#[repr(u8)]
530pub enum Live {
531 Off,
532 Polite,
533 Assertive,
534}
535
536#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
537#[cfg_attr(feature = "enumn", derive(enumn::N))]
538#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
539#[cfg_attr(feature = "schemars", derive(JsonSchema))]
540#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
541#[cfg_attr(
542 feature = "pyo3",
543 pyclass(module = "accesskit", rename_all = "SCREAMING_SNAKE_CASE")
544)]
545#[repr(u8)]
546pub enum HasPopup {
547 True,
548 Menu,
549 Listbox,
550 Tree,
551 Grid,
552 Dialog,
553}
554
555#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
556#[cfg_attr(feature = "enumn", derive(enumn::N))]
557#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
558#[cfg_attr(feature = "schemars", derive(JsonSchema))]
559#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
560#[cfg_attr(
561 feature = "pyo3",
562 pyclass(module = "accesskit", rename_all = "SCREAMING_SNAKE_CASE")
563)]
564#[repr(u8)]
565pub enum ListStyle {
566 Circle,
567 Disc,
568 Image,
569 Numeric,
570 Square,
571 Other,
573}
574
575#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
576#[cfg_attr(feature = "enumn", derive(enumn::N))]
577#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
578#[cfg_attr(feature = "schemars", derive(JsonSchema))]
579#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
580#[cfg_attr(
581 feature = "pyo3",
582 pyclass(module = "accesskit", rename_all = "SCREAMING_SNAKE_CASE")
583)]
584#[repr(u8)]
585pub enum TextAlign {
586 Left,
587 Right,
588 Center,
589 Justify,
590}
591
592#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
593#[cfg_attr(feature = "enumn", derive(enumn::N))]
594#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
595#[cfg_attr(feature = "schemars", derive(JsonSchema))]
596#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
597#[cfg_attr(
598 feature = "pyo3",
599 pyclass(module = "accesskit", rename_all = "SCREAMING_SNAKE_CASE")
600)]
601#[repr(u8)]
602pub enum VerticalOffset {
603 Subscript,
604 Superscript,
605}
606
607#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
608#[cfg_attr(feature = "enumn", derive(enumn::N))]
609#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
610#[cfg_attr(feature = "schemars", derive(JsonSchema))]
611#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
612#[cfg_attr(
613 feature = "pyo3",
614 pyclass(module = "accesskit", rename_all = "SCREAMING_SNAKE_CASE")
615)]
616#[repr(u8)]
617pub enum TextDecoration {
618 Solid,
619 Dotted,
620 Dashed,
621 Double,
622 Wavy,
623}
624
625pub type NodeIdContent = u64;
626
627#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
629#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
630#[cfg_attr(feature = "schemars", derive(JsonSchema))]
631#[repr(transparent)]
632pub struct NodeId(pub NodeIdContent);
633
634impl From<NodeIdContent> for NodeId {
635 #[inline]
636 fn from(inner: NodeIdContent) -> Self {
637 Self(inner)
638 }
639}
640
641impl From<NodeId> for NodeIdContent {
642 #[inline]
643 fn from(outer: NodeId) -> Self {
644 outer.0
645 }
646}
647
648#[derive(Clone, Debug, PartialEq, Eq)]
653#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
654#[cfg_attr(feature = "schemars", derive(JsonSchema))]
655#[cfg_attr(feature = "serde", serde(deny_unknown_fields))]
656#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
657pub struct CustomAction {
658 pub id: i32,
659 pub description: Box<str>,
660}
661
662#[derive(Clone, Copy, Debug, PartialEq, Eq)]
663#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
664#[cfg_attr(feature = "schemars", derive(JsonSchema))]
665#[cfg_attr(feature = "serde", serde(deny_unknown_fields))]
666#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
667pub struct TextPosition {
668 pub node: NodeId,
670 pub character_index: usize,
673}
674
675#[derive(Clone, Copy, Debug, PartialEq, Eq)]
676#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
677#[cfg_attr(feature = "schemars", derive(JsonSchema))]
678#[cfg_attr(feature = "serde", serde(deny_unknown_fields))]
679#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
680pub struct TextSelection {
681 pub anchor: TextPosition,
686 pub focus: TextPosition,
690}
691
692#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
693#[cfg_attr(feature = "serde", derive(Serialize, Deserialize, enumn::N))]
694#[cfg_attr(feature = "schemars", derive(JsonSchema))]
695#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
696#[repr(u8)]
697enum Flag {
698 Hidden,
699 Linked,
700 Multiselectable,
701 Required,
702 Visited,
703 Busy,
704 LiveAtomic,
705 Modal,
706 TouchTransparent,
707 ReadOnly,
708 Disabled,
709 Bold,
710 Italic,
711 ClipsChildren,
712 IsLineBreakingObject,
713 IsPageBreakingObject,
714 IsSpellingError,
715 IsGrammarError,
716 IsSearchMatch,
717 IsSuggestion,
718}
719
720impl Flag {
721 fn mask(self) -> u32 {
722 1 << (self as u8)
723 }
724}
725
726#[derive(Clone, Debug, PartialEq)]
730enum PropertyValue {
731 None,
732 NodeIdVec(Vec<NodeId>),
733 NodeId(NodeId),
734 String(Box<str>),
735 F64(f64),
736 Usize(usize),
737 Color(u32),
738 TextDecoration(TextDecoration),
739 LengthSlice(Box<[u8]>),
740 CoordSlice(Box<[f32]>),
741 Bool(bool),
742 Invalid(Invalid),
743 Toggled(Toggled),
744 Live(Live),
745 TextDirection(TextDirection),
746 Orientation(Orientation),
747 SortDirection(SortDirection),
748 AriaCurrent(AriaCurrent),
749 AutoComplete(AutoComplete),
750 HasPopup(HasPopup),
751 ListStyle(ListStyle),
752 TextAlign(TextAlign),
753 VerticalOffset(VerticalOffset),
754 Affine(Box<Affine>),
755 Rect(Rect),
756 TextSelection(Box<TextSelection>),
757 CustomActionVec(Vec<CustomAction>),
758}
759
760#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
761#[cfg_attr(feature = "serde", derive(Serialize, Deserialize, enumn::N))]
762#[cfg_attr(feature = "schemars", derive(JsonSchema))]
763#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
764#[repr(u8)]
765enum PropertyId {
766 Children,
768 Controls,
769 Details,
770 DescribedBy,
771 FlowTo,
772 LabelledBy,
773 Owns,
774 RadioGroup,
775
776 ActiveDescendant,
778 ErrorMessage,
779 InPageLinkTarget,
780 MemberOf,
781 NextOnLine,
782 PreviousOnLine,
783 PopupFor,
784
785 Label,
787 Description,
788 Value,
789 AccessKey,
790 AuthorId,
791 ClassName,
792 FontFamily,
793 HtmlTag,
794 InnerHtml,
795 KeyboardShortcut,
796 Language,
797 Placeholder,
798 RoleDescription,
799 StateDescription,
800 Tooltip,
801 Url,
802 RowIndexText,
803 ColumnIndexText,
804
805 ScrollX,
807 ScrollXMin,
808 ScrollXMax,
809 ScrollY,
810 ScrollYMin,
811 ScrollYMax,
812 NumericValue,
813 MinNumericValue,
814 MaxNumericValue,
815 NumericValueStep,
816 NumericValueJump,
817 FontSize,
818 FontWeight,
819
820 RowCount,
822 ColumnCount,
823 RowIndex,
824 ColumnIndex,
825 RowSpan,
826 ColumnSpan,
827 Level,
828 SizeOfSet,
829 PositionInSet,
830
831 ColorValue,
833 BackgroundColor,
834 ForegroundColor,
835
836 Overline,
838 Strikethrough,
839 Underline,
840
841 CharacterLengths,
843 WordLengths,
844
845 CharacterPositions,
847 CharacterWidths,
848
849 Expanded,
851 Selected,
852
853 Invalid,
855 Toggled,
856 Live,
857 TextDirection,
858 Orientation,
859 SortDirection,
860 AriaCurrent,
861 AutoComplete,
862 HasPopup,
863 ListStyle,
864 TextAlign,
865 VerticalOffset,
866
867 Transform,
869 Bounds,
870 TextSelection,
871 CustomActions,
872
873 Unset,
875}
876
877#[derive(Clone, Copy, Debug, PartialEq, Eq)]
878#[repr(transparent)]
879struct PropertyIndices([u8; PropertyId::Unset as usize]);
880
881impl Default for PropertyIndices {
882 fn default() -> Self {
883 Self([PropertyId::Unset as u8; PropertyId::Unset as usize])
884 }
885}
886
887#[derive(Clone, Debug, PartialEq)]
888struct FrozenProperties {
889 indices: PropertyIndices,
890 values: Box<[PropertyValue]>,
891}
892
893#[derive(Clone, PartialEq)]
897pub struct FrozenNode {
898 role: Role,
899 actions: u32,
900 flags: u32,
901 properties: FrozenProperties,
902}
903
904#[derive(Clone, Debug, Default, PartialEq)]
905struct Properties {
906 indices: PropertyIndices,
907 values: Vec<PropertyValue>,
908}
909
910#[derive(Clone, Default, PartialEq)]
917#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
918#[cfg_attr(feature = "schemars", derive(JsonSchema))]
919#[cfg_attr(feature = "serde", serde(deny_unknown_fields))]
920#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
921pub struct Node {
922 role: Role,
923 actions: u32,
924 flags: u32,
925 properties: Properties,
926}
927
928impl PropertyIndices {
929 fn get<'a>(&self, values: &'a [PropertyValue], id: PropertyId) -> &'a PropertyValue {
930 let index = self.0[id as usize];
931 if index == PropertyId::Unset as u8 {
932 &PropertyValue::None
933 } else {
934 &values[index as usize]
935 }
936 }
937}
938
939fn unexpected_property_type() -> ! {
940 panic!();
941}
942
943impl Properties {
944 fn get_mut(&mut self, id: PropertyId, default: PropertyValue) -> &mut PropertyValue {
945 let index = self.indices.0[id as usize] as usize;
946 if index == PropertyId::Unset as usize {
947 self.values.push(default);
948 let index = self.values.len() - 1;
949 self.indices.0[id as usize] = index as u8;
950 &mut self.values[index]
951 } else {
952 if matches!(self.values[index], PropertyValue::None) {
953 self.values[index] = default;
954 }
955 &mut self.values[index]
956 }
957 }
958
959 fn set(&mut self, id: PropertyId, value: PropertyValue) {
960 let index = self.indices.0[id as usize];
961 if index == PropertyId::Unset as u8 {
962 self.values.push(value);
963 self.indices.0[id as usize] = (self.values.len() - 1) as u8;
964 } else {
965 self.values[index as usize] = value;
966 }
967 }
968
969 fn clear(&mut self, id: PropertyId) {
970 let index = self.indices.0[id as usize];
971 if index != PropertyId::Unset as u8 {
972 self.values[index as usize] = PropertyValue::None;
973 }
974 }
975}
976
977impl From<Properties> for FrozenProperties {
978 fn from(props: Properties) -> Self {
979 Self {
980 indices: props.indices,
981 values: props.values.into_boxed_slice(),
982 }
983 }
984}
985
986macro_rules! flag_methods {
987 ($($(#[$doc:meta])* ($id:ident, $getter:ident, $setter:ident, $clearer:ident)),+) => {
988 impl FrozenNode {
989 $($(#[$doc])*
990 #[inline]
991 pub fn $getter(&self) -> bool {
992 (self.flags & (Flag::$id).mask()) != 0
993 })*
994 fn debug_flag_properties(&self, fmt: &mut fmt::DebugStruct) {
995 $(
996 if self.$getter() {
997 fmt.field(stringify!($getter), &true);
998 }
999 )*
1000 }
1001 }
1002 impl Node {
1003 $($(#[$doc])*
1004 #[inline]
1005 pub fn $getter(&self) -> bool {
1006 (self.flags & (Flag::$id).mask()) != 0
1007 }
1008 #[inline]
1009 pub fn $setter(&mut self) {
1010 self.flags |= (Flag::$id).mask();
1011 }
1012 #[inline]
1013 pub fn $clearer(&mut self) {
1014 self.flags &= !((Flag::$id).mask());
1015 })*
1016 fn debug_flag_properties(&self, fmt: &mut fmt::DebugStruct) {
1017 $(
1018 if self.$getter() {
1019 fmt.field(stringify!($getter), &true);
1020 }
1021 )*
1022 }
1023 }
1024 }
1025}
1026
1027macro_rules! option_ref_type_getters {
1028 ($(($method:ident, $type:ty, $variant:ident)),+) => {
1029 impl PropertyIndices {
1030 $(fn $method<'a>(&self, values: &'a [PropertyValue], id: PropertyId) -> Option<&'a $type> {
1031 match self.get(values, id) {
1032 PropertyValue::None => None,
1033 PropertyValue::$variant(value) => Some(value),
1034 _ => unexpected_property_type(),
1035 }
1036 })*
1037 }
1038 }
1039}
1040
1041macro_rules! slice_type_getters {
1042 ($(($method:ident, $type:ty, $variant:ident)),+) => {
1043 impl PropertyIndices {
1044 $(fn $method<'a>(&self, values: &'a [PropertyValue], id: PropertyId) -> &'a [$type] {
1045 match self.get(values, id) {
1046 PropertyValue::None => &[],
1047 PropertyValue::$variant(value) => value,
1048 _ => unexpected_property_type(),
1049 }
1050 })*
1051 }
1052 }
1053}
1054
1055macro_rules! copy_type_getters {
1056 ($(($method:ident, $type:ty, $variant:ident)),+) => {
1057 impl PropertyIndices {
1058 $(fn $method(&self, values: &[PropertyValue], id: PropertyId) -> Option<$type> {
1059 match self.get(values, id) {
1060 PropertyValue::None => None,
1061 PropertyValue::$variant(value) => Some(*value),
1062 _ => unexpected_property_type(),
1063 }
1064 })*
1065 }
1066 }
1067}
1068
1069macro_rules! box_type_setters {
1070 ($(($method:ident, $type:ty, $variant:ident)),+) => {
1071 impl Node {
1072 $(fn $method(&mut self, id: PropertyId, value: impl Into<Box<$type>>) {
1073 self.properties.set(id, PropertyValue::$variant(value.into()));
1074 })*
1075 }
1076 }
1077}
1078
1079macro_rules! copy_type_setters {
1080 ($(($method:ident, $type:ty, $variant:ident)),+) => {
1081 impl Node {
1082 $(fn $method(&mut self, id: PropertyId, value: $type) {
1083 self.properties.set(id, PropertyValue::$variant(value));
1084 })*
1085 }
1086 }
1087}
1088
1089macro_rules! vec_type_methods {
1090 ($(($type:ty, $variant:ident, $getter:ident, $setter:ident, $pusher:ident)),+) => {
1091 $(slice_type_getters! {
1092 ($getter, $type, $variant)
1093 })*
1094 impl Node {
1095 $(fn $setter(&mut self, id: PropertyId, value: impl Into<Vec<$type>>) {
1096 self.properties.set(id, PropertyValue::$variant(value.into()));
1097 }
1098 fn $pusher(&mut self, id: PropertyId, item: $type) {
1099 match self.properties.get_mut(id, PropertyValue::$variant(Vec::new())) {
1100 PropertyValue::$variant(v) => {
1101 v.push(item);
1102 }
1103 _ => unexpected_property_type(),
1104 }
1105 })*
1106 }
1107 }
1108}
1109
1110macro_rules! property_methods {
1111 ($($(#[$doc:meta])* ($id:ident, $getter:ident, $type_getter:ident, $getter_result:ty, $setter:ident, $type_setter:ident, $setter_param:ty, $clearer:ident)),+) => {
1112 impl FrozenNode {
1113 $($(#[$doc])*
1114 #[inline]
1115 pub fn $getter(&self) -> $getter_result {
1116 self.properties.indices.$type_getter(&self.properties.values, PropertyId::$id)
1117 })*
1118 }
1119 impl Node {
1120 $($(#[$doc])*
1121 #[inline]
1122 pub fn $getter(&self) -> $getter_result {
1123 self.properties.indices.$type_getter(&self.properties.values, PropertyId::$id)
1124 }
1125 #[inline]
1126 pub fn $setter(&mut self, value: $setter_param) {
1127 self.$type_setter(PropertyId::$id, value);
1128 }
1129 #[inline]
1130 pub fn $clearer(&mut self) {
1131 self.properties.clear(PropertyId::$id);
1132 })*
1133 }
1134 }
1135}
1136
1137macro_rules! vec_property_methods {
1138 ($($(#[$doc:meta])* ($id:ident, $item_type:ty, $getter:ident, $type_getter:ident, $setter:ident, $type_setter:ident, $pusher:ident, $type_pusher:ident, $clearer:ident)),+) => {
1139 $(property_methods! {
1140 $(#[$doc])*
1141 ($id, $getter, $type_getter, &[$item_type], $setter, $type_setter, impl Into<Vec<$item_type>>, $clearer)
1142 }
1143 impl Node {
1144 #[inline]
1145 pub fn $pusher(&mut self, item: $item_type) {
1146 self.$type_pusher(PropertyId::$id, item);
1147 }
1148 })*
1149 }
1150}
1151
1152macro_rules! slice_properties_debug_method {
1153 ($name:ident, [$($getter:ident,)*]) => {
1154 fn $name(&self, fmt: &mut fmt::DebugStruct) {
1155 $(
1156 let value = self.$getter();
1157 if !value.is_empty() {
1158 fmt.field(stringify!($getter), &value);
1159 }
1160 )*
1161 }
1162 }
1163}
1164
1165macro_rules! node_id_vec_property_methods {
1166 ($($(#[$doc:meta])* ($id:ident, $getter:ident, $setter:ident, $pusher:ident, $clearer:ident)),+) => {
1167 $(vec_property_methods! {
1168 $(#[$doc])*
1169 ($id, NodeId, $getter, get_node_id_vec, $setter, set_node_id_vec, $pusher, push_to_node_id_vec, $clearer)
1170 })*
1171 impl FrozenNode {
1172 slice_properties_debug_method! { debug_node_id_vec_properties, [$($getter,)*] }
1173 }
1174 impl Node {
1175 slice_properties_debug_method! { debug_node_id_vec_properties, [$($getter,)*] }
1176 }
1177 }
1178}
1179
1180macro_rules! option_properties_debug_method {
1181 ($name:ident, [$($getter:ident,)*]) => {
1182 fn $name(&self, fmt: &mut fmt::DebugStruct) {
1183 $(
1184 if let Some(value) = self.$getter() {
1185 fmt.field(stringify!($getter), &value);
1186 }
1187 )*
1188 }
1189 }
1190}
1191
1192macro_rules! node_id_property_methods {
1193 ($($(#[$doc:meta])* ($id:ident, $getter:ident, $setter:ident, $clearer:ident)),+) => {
1194 $(property_methods! {
1195 $(#[$doc])*
1196 ($id, $getter, get_node_id_property, Option<NodeId>, $setter, set_node_id_property, NodeId, $clearer)
1197 })*
1198 impl FrozenNode {
1199 option_properties_debug_method! { debug_node_id_properties, [$($getter,)*] }
1200 }
1201 impl Node {
1202 option_properties_debug_method! { debug_node_id_properties, [$($getter,)*] }
1203 }
1204 }
1205}
1206
1207macro_rules! string_property_methods {
1208 ($($(#[$doc:meta])* ($id:ident, $getter:ident, $setter:ident, $clearer:ident)),+) => {
1209 $(property_methods! {
1210 $(#[$doc])*
1211 ($id, $getter, get_string_property, Option<&str>, $setter, set_string_property, impl Into<Box<str>>, $clearer)
1212 })*
1213 impl FrozenNode {
1214 option_properties_debug_method! { debug_string_properties, [$($getter,)*] }
1215 }
1216 impl Node {
1217 option_properties_debug_method! { debug_string_properties, [$($getter,)*] }
1218 }
1219 }
1220}
1221
1222macro_rules! f64_property_methods {
1223 ($($(#[$doc:meta])* ($id:ident, $getter:ident, $setter:ident, $clearer:ident)),+) => {
1224 $(property_methods! {
1225 $(#[$doc])*
1226 ($id, $getter, get_f64_property, Option<f64>, $setter, set_f64_property, f64, $clearer)
1227 })*
1228 impl FrozenNode {
1229 option_properties_debug_method! { debug_f64_properties, [$($getter,)*] }
1230 }
1231 impl Node {
1232 option_properties_debug_method! { debug_f64_properties, [$($getter,)*] }
1233 }
1234 }
1235}
1236
1237macro_rules! usize_property_methods {
1238 ($($(#[$doc:meta])* ($id:ident, $getter:ident, $setter:ident, $clearer:ident)),+) => {
1239 $(property_methods! {
1240 $(#[$doc])*
1241 ($id, $getter, get_usize_property, Option<usize>, $setter, set_usize_property, usize, $clearer)
1242 })*
1243 impl FrozenNode {
1244 option_properties_debug_method! { debug_usize_properties, [$($getter,)*] }
1245 }
1246 impl Node {
1247 option_properties_debug_method! { debug_usize_properties, [$($getter,)*] }
1248 }
1249 }
1250}
1251
1252macro_rules! color_property_methods {
1253 ($($(#[$doc:meta])* ($id:ident, $getter:ident, $setter:ident, $clearer:ident)),+) => {
1254 $(property_methods! {
1255 $(#[$doc])*
1256 ($id, $getter, get_color_property, Option<u32>, $setter, set_color_property, u32, $clearer)
1257 })*
1258 impl FrozenNode {
1259 option_properties_debug_method! { debug_color_properties, [$($getter,)*] }
1260 }
1261 impl Node {
1262 option_properties_debug_method! { debug_color_properties, [$($getter,)*] }
1263 }
1264 }
1265}
1266
1267macro_rules! text_decoration_property_methods {
1268 ($($(#[$doc:meta])* ($id:ident, $getter:ident, $setter:ident, $clearer:ident)),+) => {
1269 $(property_methods! {
1270 $(#[$doc])*
1271 ($id, $getter, get_text_decoration_property, Option<TextDecoration>, $setter, set_text_decoration_property, TextDecoration, $clearer)
1272 })*
1273 impl FrozenNode {
1274 option_properties_debug_method! { debug_text_decoration_properties, [$($getter,)*] }
1275 }
1276 impl Node {
1277 option_properties_debug_method! { debug_text_decoration_properties, [$($getter,)*] }
1278 }
1279 }
1280}
1281
1282macro_rules! length_slice_property_methods {
1283 ($($(#[$doc:meta])* ($id:ident, $getter:ident, $setter:ident, $clearer:ident)),+) => {
1284 $(property_methods! {
1285 $(#[$doc])*
1286 ($id, $getter, get_length_slice_property, &[u8], $setter, set_length_slice_property, impl Into<Box<[u8]>>, $clearer)
1287 })*
1288 impl FrozenNode {
1289 slice_properties_debug_method! { debug_length_slice_properties, [$($getter,)*] }
1290 }
1291 impl Node {
1292 slice_properties_debug_method! { debug_length_slice_properties, [$($getter,)*] }
1293 }
1294 }
1295}
1296
1297macro_rules! coord_slice_property_methods {
1298 ($($(#[$doc:meta])* ($id:ident, $getter:ident, $setter:ident, $clearer:ident)),+) => {
1299 $(property_methods! {
1300 $(#[$doc])*
1301 ($id, $getter, get_coord_slice_property, Option<&[f32]>, $setter, set_coord_slice_property, impl Into<Box<[f32]>>, $clearer)
1302 })*
1303 impl FrozenNode {
1304 option_properties_debug_method! { debug_coord_slice_properties, [$($getter,)*] }
1305 }
1306 impl Node {
1307 option_properties_debug_method! { debug_coord_slice_properties, [$($getter,)*] }
1308 }
1309 }
1310}
1311
1312macro_rules! bool_property_methods {
1313 ($($(#[$doc:meta])* ($id:ident, $getter:ident, $setter:ident, $clearer:ident)),+) => {
1314 $(property_methods! {
1315 $(#[$doc])*
1316 ($id, $getter, get_bool_property, Option<bool>, $setter, set_bool_property, bool, $clearer)
1317 })*
1318 impl FrozenNode {
1319 option_properties_debug_method! { debug_bool_properties, [$($getter,)*] }
1320 }
1321 impl Node {
1322 option_properties_debug_method! { debug_bool_properties, [$($getter,)*] }
1323 }
1324 }
1325}
1326
1327macro_rules! unique_enum_property_methods {
1328 ($($(#[$doc:meta])* ($id:ident, $getter:ident, $setter:ident, $clearer:ident)),+) => {
1329 impl FrozenNode {
1330 $($(#[$doc])*
1331 #[inline]
1332 pub fn $getter(&self) -> Option<$id> {
1333 match self.properties.indices.get(&self.properties.values, PropertyId::$id) {
1334 PropertyValue::None => None,
1335 PropertyValue::$id(value) => Some(*value),
1336 _ => unexpected_property_type(),
1337 }
1338 })*
1339 option_properties_debug_method! { debug_unique_enum_properties, [$($getter,)*] }
1340 }
1341 impl Node {
1342 $($(#[$doc])*
1343 #[inline]
1344 pub fn $getter(&self) -> Option<$id> {
1345 match self.properties.indices.get(&self.properties.values, PropertyId::$id) {
1346 PropertyValue::None => None,
1347 PropertyValue::$id(value) => Some(*value),
1348 _ => unexpected_property_type(),
1349 }
1350 }
1351 #[inline]
1352 pub fn $setter(&mut self, value: $id) {
1353 self.properties.set(PropertyId::$id, PropertyValue::$id(value));
1354 }
1355 #[inline]
1356 pub fn $clearer(&mut self) {
1357 self.properties.clear(PropertyId::$id);
1358 })*
1359 option_properties_debug_method! { debug_unique_enum_properties, [$($getter,)*] }
1360 }
1361 }
1362}
1363
1364impl Node {
1365 #[inline]
1366 pub fn new(role: Role) -> Self {
1367 Self {
1368 role,
1369 ..Default::default()
1370 }
1371 }
1372}
1373
1374impl From<Node> for FrozenNode {
1375 fn from(node: Node) -> Self {
1376 Self {
1377 role: node.role,
1378 actions: node.actions,
1379 flags: node.flags,
1380 properties: node.properties.into(),
1381 }
1382 }
1383}
1384
1385impl FrozenNode {
1386 #[inline]
1387 pub fn role(&self) -> Role {
1388 self.role
1389 }
1390}
1391
1392impl Node {
1393 #[inline]
1394 pub fn role(&self) -> Role {
1395 self.role
1396 }
1397 #[inline]
1398 pub fn set_role(&mut self, value: Role) {
1399 self.role = value;
1400 }
1401}
1402
1403impl FrozenNode {
1404 #[inline]
1405 pub fn supports_action(&self, action: Action) -> bool {
1406 (self.actions & action.mask()) != 0
1407 }
1408}
1409
1410impl Node {
1411 #[inline]
1412 pub fn supports_action(&self, action: Action) -> bool {
1413 (self.actions & action.mask()) != 0
1414 }
1415 #[inline]
1416 pub fn add_action(&mut self, action: Action) {
1417 self.actions |= action.mask();
1418 }
1419 #[inline]
1420 pub fn remove_action(&mut self, action: Action) {
1421 self.actions &= !(action.mask());
1422 }
1423 #[inline]
1424 pub fn clear_actions(&mut self) {
1425 self.actions = 0;
1426 }
1427}
1428
1429flag_methods! {
1430 (Hidden, is_hidden, set_hidden, clear_hidden),
1433 (Linked, is_linked, set_linked, clear_linked),
1434 (Multiselectable, is_multiselectable, set_multiselectable, clear_multiselectable),
1435 (Required, is_required, set_required, clear_required),
1436 (Visited, is_visited, set_visited, clear_visited),
1437 (Busy, is_busy, set_busy, clear_busy),
1438 (LiveAtomic, is_live_atomic, set_live_atomic, clear_live_atomic),
1439 (Modal, is_modal, set_modal, clear_modal),
1441 (TouchTransparent, is_touch_transparent, set_touch_transparent, clear_touch_transparent),
1445 (ReadOnly, is_read_only, set_read_only, clear_read_only),
1447 (Disabled, is_disabled, set_disabled, clear_disabled),
1449 (Bold, is_bold, set_bold, clear_bold),
1450 (Italic, is_italic, set_italic, clear_italic),
1451 (ClipsChildren, clips_children, set_clips_children, clear_clips_children),
1454 (IsLineBreakingObject, is_line_breaking_object, set_is_line_breaking_object, clear_is_line_breaking_object),
1457 (IsPageBreakingObject, is_page_breaking_object, set_is_page_breaking_object, clear_is_page_breaking_object),
1459 (IsSpellingError, is_spelling_error, set_is_spelling_error, clear_is_spelling_error),
1460 (IsGrammarError, is_grammar_error, set_is_grammar_error, clear_is_grammar_error),
1461 (IsSearchMatch, is_search_match, set_is_search_match, clear_is_search_match),
1462 (IsSuggestion, is_suggestion, set_is_suggestion, clear_is_suggestion)
1463}
1464
1465option_ref_type_getters! {
1466 (get_affine_property, Affine, Affine),
1467 (get_string_property, str, String),
1468 (get_coord_slice_property, [f32], CoordSlice),
1469 (get_text_selection_property, TextSelection, TextSelection)
1470}
1471
1472slice_type_getters! {
1473 (get_length_slice_property, u8, LengthSlice)
1474}
1475
1476copy_type_getters! {
1477 (get_rect_property, Rect, Rect),
1478 (get_node_id_property, NodeId, NodeId),
1479 (get_f64_property, f64, F64),
1480 (get_usize_property, usize, Usize),
1481 (get_color_property, u32, Color),
1482 (get_text_decoration_property, TextDecoration, TextDecoration),
1483 (get_bool_property, bool, Bool)
1484}
1485
1486box_type_setters! {
1487 (set_affine_property, Affine, Affine),
1488 (set_string_property, str, String),
1489 (set_length_slice_property, [u8], LengthSlice),
1490 (set_coord_slice_property, [f32], CoordSlice),
1491 (set_text_selection_property, TextSelection, TextSelection)
1492}
1493
1494copy_type_setters! {
1495 (set_rect_property, Rect, Rect),
1496 (set_node_id_property, NodeId, NodeId),
1497 (set_f64_property, f64, F64),
1498 (set_usize_property, usize, Usize),
1499 (set_color_property, u32, Color),
1500 (set_text_decoration_property, TextDecoration, TextDecoration),
1501 (set_bool_property, bool, Bool)
1502}
1503
1504vec_type_methods! {
1505 (NodeId, NodeIdVec, get_node_id_vec, set_node_id_vec, push_to_node_id_vec),
1506 (CustomAction, CustomActionVec, get_custom_action_vec, set_custom_action_vec, push_to_custom_action_vec)
1507}
1508
1509node_id_vec_property_methods! {
1510 (Children, children, set_children, push_child, clear_children),
1511 (Controls, controls, set_controls, push_controlled, clear_controls),
1512 (Details, details, set_details, push_detail, clear_details),
1513 (DescribedBy, described_by, set_described_by, push_described_by, clear_described_by),
1514 (FlowTo, flow_to, set_flow_to, push_flow_to, clear_flow_to),
1515 (LabelledBy, labelled_by, set_labelled_by, push_labelled_by, clear_labelled_by),
1516 (Owns, owns, set_owns, push_owned, clear_owns),
1522 (RadioGroup, radio_group, set_radio_group, push_to_radio_group, clear_radio_group)
1525}
1526
1527node_id_property_methods! {
1528 (ActiveDescendant, active_descendant, set_active_descendant, clear_active_descendant),
1529 (ErrorMessage, error_message, set_error_message, clear_error_message),
1530 (InPageLinkTarget, in_page_link_target, set_in_page_link_target, clear_in_page_link_target),
1531 (MemberOf, member_of, set_member_of, clear_member_of),
1532 (NextOnLine, next_on_line, set_next_on_line, clear_next_on_line),
1533 (PreviousOnLine, previous_on_line, set_previous_on_line, clear_previous_on_line),
1534 (PopupFor, popup_for, set_popup_for, clear_popup_for)
1535}
1536
1537string_property_methods! {
1538 (Label, label, set_label, clear_label),
1543 (Description, description, set_description, clear_description),
1544 (Value, value, set_value, clear_value),
1545 (AccessKey, access_key, set_access_key, clear_access_key),
1553 (AuthorId, author_id, set_author_id, clear_author_id),
1556 (ClassName, class_name, set_class_name, clear_class_name),
1557 (FontFamily, font_family, set_font_family, clear_font_family),
1559 (HtmlTag, html_tag, set_html_tag, clear_html_tag),
1560 (InnerHtml, inner_html, set_inner_html, clear_inner_html),
1563 (KeyboardShortcut, keyboard_shortcut, set_keyboard_shortcut, clear_keyboard_shortcut),
1567 (Language, language, set_language, clear_language),
1569 (Placeholder, placeholder, set_placeholder, clear_placeholder),
1574 (RoleDescription, role_description, set_role_description, clear_role_description),
1578 (StateDescription, state_description, set_state_description, clear_state_description),
1583 (Tooltip, tooltip, set_tooltip, clear_tooltip),
1588 (Url, url, set_url, clear_url),
1589 (RowIndexText, row_index_text, set_row_index_text, clear_row_index_text),
1590 (ColumnIndexText, column_index_text, set_column_index_text, clear_column_index_text)
1591}
1592
1593f64_property_methods! {
1594 (ScrollX, scroll_x, set_scroll_x, clear_scroll_x),
1595 (ScrollXMin, scroll_x_min, set_scroll_x_min, clear_scroll_x_min),
1596 (ScrollXMax, scroll_x_max, set_scroll_x_max, clear_scroll_x_max),
1597 (ScrollY, scroll_y, set_scroll_y, clear_scroll_y),
1598 (ScrollYMin, scroll_y_min, set_scroll_y_min, clear_scroll_y_min),
1599 (ScrollYMax, scroll_y_max, set_scroll_y_max, clear_scroll_y_max),
1600 (NumericValue, numeric_value, set_numeric_value, clear_numeric_value),
1601 (MinNumericValue, min_numeric_value, set_min_numeric_value, clear_min_numeric_value),
1602 (MaxNumericValue, max_numeric_value, set_max_numeric_value, clear_max_numeric_value),
1603 (NumericValueStep, numeric_value_step, set_numeric_value_step, clear_numeric_value_step),
1604 (NumericValueJump, numeric_value_jump, set_numeric_value_jump, clear_numeric_value_jump),
1605 (FontSize, font_size, set_font_size, clear_font_size),
1607 (FontWeight, font_weight, set_font_weight, clear_font_weight)
1610}
1611
1612usize_property_methods! {
1613 (RowCount, row_count, set_row_count, clear_row_count),
1614 (ColumnCount, column_count, set_column_count, clear_column_count),
1615 (RowIndex, row_index, set_row_index, clear_row_index),
1616 (ColumnIndex, column_index, set_column_index, clear_column_index),
1617 (RowSpan, row_span, set_row_span, clear_row_span),
1618 (ColumnSpan, column_span, set_column_span, clear_column_span),
1619 (Level, level, set_level, clear_level),
1620 (SizeOfSet, size_of_set, set_size_of_set, clear_size_of_set),
1621 (PositionInSet, position_in_set, set_position_in_set, clear_position_in_set)
1622}
1623
1624color_property_methods! {
1625 (ColorValue, color_value, set_color_value, clear_color_value),
1627 (BackgroundColor, background_color, set_background_color, clear_background_color),
1629 (ForegroundColor, foreground_color, set_foreground_color, clear_foreground_color)
1631}
1632
1633text_decoration_property_methods! {
1634 (Overline, overline, set_overline, clear_overline),
1635 (Strikethrough, strikethrough, set_strikethrough, clear_strikethrough),
1636 (Underline, underline, set_underline, clear_underline)
1637}
1638
1639length_slice_property_methods! {
1640 (CharacterLengths, character_lengths, set_character_lengths, clear_character_lengths),
1659
1660 (WordLengths, word_lengths, set_word_lengths, clear_word_lengths)
1683}
1684
1685coord_slice_property_methods! {
1686 (CharacterPositions, character_positions, set_character_positions, clear_character_positions),
1703
1704 (CharacterWidths, character_widths, set_character_widths, clear_character_widths)
1723}
1724
1725bool_property_methods! {
1726 (Expanded, is_expanded, set_expanded, clear_expanded),
1731
1732 (Selected, is_selected, set_selected, clear_selected)
1742}
1743
1744unique_enum_property_methods! {
1745 (Invalid, invalid, set_invalid, clear_invalid),
1746 (Toggled, toggled, set_toggled, clear_toggled),
1747 (Live, live, set_live, clear_live),
1748 (TextDirection, text_direction, set_text_direction, clear_text_direction),
1749 (Orientation, orientation, set_orientation, clear_orientation),
1750 (SortDirection, sort_direction, set_sort_direction, clear_sort_direction),
1751 (AriaCurrent, aria_current, set_aria_current, clear_aria_current),
1752 (AutoComplete, auto_complete, set_auto_complete, clear_auto_complete),
1753 (HasPopup, has_popup, set_has_popup, clear_has_popup),
1754 (ListStyle, list_style, set_list_style, clear_list_style),
1756 (TextAlign, text_align, set_text_align, clear_text_align),
1757 (VerticalOffset, vertical_offset, set_vertical_offset, clear_vertical_offset)
1758}
1759
1760property_methods! {
1761 (Transform, transform, get_affine_property, Option<&Affine>, set_transform, set_affine_property, impl Into<Box<Affine>>, clear_transform),
1774
1775 (Bounds, bounds, get_rect_property, Option<Rect>, set_bounds, set_rect_property, Rect, clear_bounds),
1786
1787 (TextSelection, text_selection, get_text_selection_property, Option<&TextSelection>, set_text_selection, set_text_selection_property, impl Into<Box<TextSelection>>, clear_text_selection)
1788}
1789
1790impl FrozenNode {
1791 option_properties_debug_method! { debug_option_properties, [transform, bounds, text_selection,] }
1792}
1793
1794impl Node {
1795 option_properties_debug_method! { debug_option_properties, [transform, bounds, text_selection,] }
1796}
1797
1798vec_property_methods! {
1799 (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)
1800}
1801
1802impl fmt::Debug for FrozenNode {
1803 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1804 let mut fmt = f.debug_struct("FrozenNode");
1805
1806 fmt.field("role", &self.role());
1807
1808 let supported_actions = action_mask_to_action_vec(self.actions);
1809 if !supported_actions.is_empty() {
1810 fmt.field("actions", &supported_actions);
1811 }
1812
1813 self.debug_flag_properties(&mut fmt);
1814 self.debug_node_id_vec_properties(&mut fmt);
1815 self.debug_node_id_properties(&mut fmt);
1816 self.debug_string_properties(&mut fmt);
1817 self.debug_f64_properties(&mut fmt);
1818 self.debug_usize_properties(&mut fmt);
1819 self.debug_color_properties(&mut fmt);
1820 self.debug_text_decoration_properties(&mut fmt);
1821 self.debug_length_slice_properties(&mut fmt);
1822 self.debug_coord_slice_properties(&mut fmt);
1823 self.debug_bool_properties(&mut fmt);
1824 self.debug_unique_enum_properties(&mut fmt);
1825 self.debug_option_properties(&mut fmt);
1826
1827 let custom_actions = self.custom_actions();
1828 if !custom_actions.is_empty() {
1829 fmt.field("custom_actions", &custom_actions);
1830 }
1831
1832 fmt.finish()
1833 }
1834}
1835
1836impl fmt::Debug for Node {
1837 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1838 let mut fmt = f.debug_struct("Node");
1839
1840 fmt.field("role", &self.role());
1841
1842 let supported_actions = action_mask_to_action_vec(self.actions);
1843 if !supported_actions.is_empty() {
1844 fmt.field("actions", &supported_actions);
1845 }
1846
1847 self.debug_flag_properties(&mut fmt);
1848 self.debug_node_id_vec_properties(&mut fmt);
1849 self.debug_node_id_properties(&mut fmt);
1850 self.debug_string_properties(&mut fmt);
1851 self.debug_f64_properties(&mut fmt);
1852 self.debug_usize_properties(&mut fmt);
1853 self.debug_color_properties(&mut fmt);
1854 self.debug_text_decoration_properties(&mut fmt);
1855 self.debug_length_slice_properties(&mut fmt);
1856 self.debug_coord_slice_properties(&mut fmt);
1857 self.debug_bool_properties(&mut fmt);
1858 self.debug_unique_enum_properties(&mut fmt);
1859 self.debug_option_properties(&mut fmt);
1860
1861 let custom_actions = self.custom_actions();
1862 if !custom_actions.is_empty() {
1863 fmt.field("custom_actions", &custom_actions);
1864 }
1865
1866 fmt.finish()
1867 }
1868}
1869
1870#[cfg(feature = "serde")]
1871macro_rules! serialize_property {
1872 ($self:ident, $map:ident, $index:ident, $id:ident, { $($variant:ident),+ }) => {
1873 match &$self.values[$index as usize] {
1874 PropertyValue::None => (),
1875 $(PropertyValue::$variant(value) => {
1876 $map.serialize_entry(&$id, &value)?;
1877 })*
1878 }
1879 }
1880}
1881
1882#[cfg(feature = "serde")]
1883macro_rules! deserialize_property {
1884 ($props:ident, $map:ident, $key:ident, { $($type:ident { $($id:ident),+ }),+ }) => {
1885 match $key {
1886 $($(PropertyId::$id => {
1887 let value = $map.next_value()?;
1888 $props.set(PropertyId::$id, PropertyValue::$type(value));
1889 })*)*
1890 PropertyId::Unset => {
1891 let _ = $map.next_value::<IgnoredAny>()?;
1892 }
1893 }
1894 }
1895}
1896
1897#[cfg(feature = "serde")]
1898impl Serialize for Properties {
1899 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1900 where
1901 S: Serializer,
1902 {
1903 let mut len = 0;
1904 for value in &*self.values {
1905 if !matches!(*value, PropertyValue::None) {
1906 len += 1;
1907 }
1908 }
1909 let mut map = serializer.serialize_map(Some(len))?;
1910 for (id, index) in self.indices.0.iter().copied().enumerate() {
1911 if index == PropertyId::Unset as u8 {
1912 continue;
1913 }
1914 let id = PropertyId::n(id as _).unwrap();
1915 serialize_property!(self, map, index, id, {
1916 NodeIdVec,
1917 NodeId,
1918 String,
1919 F64,
1920 Usize,
1921 Color,
1922 TextDecoration,
1923 LengthSlice,
1924 CoordSlice,
1925 Bool,
1926 Invalid,
1927 Toggled,
1928 Live,
1929 TextDirection,
1930 Orientation,
1931 SortDirection,
1932 AriaCurrent,
1933 AutoComplete,
1934 HasPopup,
1935 ListStyle,
1936 TextAlign,
1937 VerticalOffset,
1938 Affine,
1939 Rect,
1940 TextSelection,
1941 CustomActionVec
1942 });
1943 }
1944 map.end()
1945 }
1946}
1947
1948#[cfg(feature = "serde")]
1949struct PropertiesVisitor;
1950
1951#[cfg(feature = "serde")]
1952impl<'de> Visitor<'de> for PropertiesVisitor {
1953 type Value = Properties;
1954
1955 #[inline]
1956 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
1957 formatter.write_str("property map")
1958 }
1959
1960 fn visit_map<V>(self, mut map: V) -> Result<Self::Value, V::Error>
1961 where
1962 V: MapAccess<'de>,
1963 {
1964 let mut props = Properties::default();
1965 while let Some(id) = map.next_key()? {
1966 deserialize_property!(props, map, id, {
1967 NodeIdVec {
1968 Children,
1969 Controls,
1970 Details,
1971 DescribedBy,
1972 FlowTo,
1973 LabelledBy,
1974 Owns,
1975 RadioGroup
1976 },
1977 NodeId {
1978 ActiveDescendant,
1979 ErrorMessage,
1980 InPageLinkTarget,
1981 MemberOf,
1982 NextOnLine,
1983 PreviousOnLine,
1984 PopupFor
1985 },
1986 String {
1987 Label,
1988 Description,
1989 Value,
1990 AccessKey,
1991 AuthorId,
1992 ClassName,
1993 FontFamily,
1994 HtmlTag,
1995 InnerHtml,
1996 KeyboardShortcut,
1997 Language,
1998 Placeholder,
1999 RoleDescription,
2000 StateDescription,
2001 Tooltip,
2002 Url,
2003 RowIndexText,
2004 ColumnIndexText
2005 },
2006 F64 {
2007 ScrollX,
2008 ScrollXMin,
2009 ScrollXMax,
2010 ScrollY,
2011 ScrollYMin,
2012 ScrollYMax,
2013 NumericValue,
2014 MinNumericValue,
2015 MaxNumericValue,
2016 NumericValueStep,
2017 NumericValueJump,
2018 FontSize,
2019 FontWeight
2020 },
2021 Usize {
2022 RowCount,
2023 ColumnCount,
2024 RowIndex,
2025 ColumnIndex,
2026 RowSpan,
2027 ColumnSpan,
2028 Level,
2029 SizeOfSet,
2030 PositionInSet
2031 },
2032 Color {
2033 ColorValue,
2034 BackgroundColor,
2035 ForegroundColor
2036 },
2037 TextDecoration {
2038 Overline,
2039 Strikethrough,
2040 Underline
2041 },
2042 LengthSlice {
2043 CharacterLengths,
2044 WordLengths
2045 },
2046 CoordSlice {
2047 CharacterPositions,
2048 CharacterWidths
2049 },
2050 Bool {
2051 Expanded,
2052 Selected
2053 },
2054 Invalid { Invalid },
2055 Toggled { Toggled },
2056 Live { Live },
2057 TextDirection { TextDirection },
2058 Orientation { Orientation },
2059 SortDirection { SortDirection },
2060 AriaCurrent { AriaCurrent },
2061 AutoComplete { AutoComplete },
2062 HasPopup { HasPopup },
2063 ListStyle { ListStyle },
2064 TextAlign { TextAlign },
2065 VerticalOffset { VerticalOffset },
2066 Affine { Transform },
2067 Rect { Bounds },
2068 TextSelection { TextSelection },
2069 CustomActionVec { CustomActions }
2070 });
2071 }
2072
2073 Ok(props)
2074 }
2075}
2076
2077#[cfg(feature = "serde")]
2078impl<'de> Deserialize<'de> for Properties {
2079 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
2080 where
2081 D: Deserializer<'de>,
2082 {
2083 deserializer.deserialize_map(PropertiesVisitor)
2084 }
2085}
2086
2087#[cfg(feature = "schemars")]
2088macro_rules! add_schema_property {
2089 ($gen:ident, $properties:ident, $enum_value:expr, $type:ty) => {{
2090 let name = format!("{:?}", $enum_value);
2091 let name = name[..1].to_ascii_lowercase() + &name[1..];
2092 let subschema = $gen.subschema_for::<$type>();
2093 $properties.insert(name, subschema);
2094 }};
2095}
2096
2097#[cfg(feature = "schemars")]
2098macro_rules! add_properties_to_schema {
2099 ($gen:ident, $properties:ident, { $($type:ty { $($id:ident),+ }),+ }) => {
2100 $($(add_schema_property!($gen, $properties, PropertyId::$id, $type);)*)*
2101 }
2102}
2103
2104#[cfg(feature = "schemars")]
2105impl JsonSchema for Properties {
2106 #[inline]
2107 fn schema_name() -> String {
2108 "Properties".into()
2109 }
2110
2111 fn json_schema(gen: &mut SchemaGenerator) -> Schema {
2112 let mut properties = SchemaMap::<String, Schema>::new();
2113 add_properties_to_schema!(gen, properties, {
2114 Vec<NodeId> {
2115 Children,
2116 Controls,
2117 Details,
2118 DescribedBy,
2119 FlowTo,
2120 LabelledBy,
2121 Owns,
2122 RadioGroup
2123 },
2124 NodeId {
2125 ActiveDescendant,
2126 ErrorMessage,
2127 InPageLinkTarget,
2128 MemberOf,
2129 NextOnLine,
2130 PreviousOnLine,
2131 PopupFor
2132 },
2133 Box<str> {
2134 Label,
2135 Description,
2136 Value,
2137 AccessKey,
2138 AuthorId,
2139 ClassName,
2140 FontFamily,
2141 HtmlTag,
2142 InnerHtml,
2143 KeyboardShortcut,
2144 Language,
2145 Placeholder,
2146 RoleDescription,
2147 StateDescription,
2148 Tooltip,
2149 Url,
2150 RowIndexText,
2151 ColumnIndexText
2152 },
2153 f64 {
2154 ScrollX,
2155 ScrollXMin,
2156 ScrollXMax,
2157 ScrollY,
2158 ScrollYMin,
2159 ScrollYMax,
2160 NumericValue,
2161 MinNumericValue,
2162 MaxNumericValue,
2163 NumericValueStep,
2164 NumericValueJump,
2165 FontSize,
2166 FontWeight
2167 },
2168 usize {
2169 RowCount,
2170 ColumnCount,
2171 RowIndex,
2172 ColumnIndex,
2173 RowSpan,
2174 ColumnSpan,
2175 Level,
2176 SizeOfSet,
2177 PositionInSet
2178 },
2179 u32 {
2180 ColorValue,
2181 BackgroundColor,
2182 ForegroundColor
2183 },
2184 TextDecoration {
2185 Overline,
2186 Strikethrough,
2187 Underline
2188 },
2189 Box<[u8]> {
2190 CharacterLengths,
2191 WordLengths
2192 },
2193 Box<[f32]> {
2194 CharacterPositions,
2195 CharacterWidths
2196 },
2197 bool {
2198 Expanded,
2199 Selected
2200 },
2201 Invalid { Invalid },
2202 Toggled { Toggled },
2203 Live { Live },
2204 TextDirection { TextDirection },
2205 Orientation { Orientation },
2206 SortDirection { SortDirection },
2207 AriaCurrent { AriaCurrent },
2208 AutoComplete { AutoComplete },
2209 HasPopup { HasPopup },
2210 ListStyle { ListStyle },
2211 TextAlign { TextAlign },
2212 VerticalOffset { VerticalOffset },
2213 Affine { Transform },
2214 Rect { Bounds },
2215 TextSelection { TextSelection },
2216 Vec<CustomAction> { CustomActions }
2217 });
2218 SchemaObject {
2219 instance_type: Some(InstanceType::Object.into()),
2220 object: Some(
2221 ObjectValidation {
2222 properties,
2223 ..Default::default()
2224 }
2225 .into(),
2226 ),
2227 ..Default::default()
2228 }
2229 .into()
2230 }
2231}
2232
2233#[derive(Clone, Debug, PartialEq, Eq)]
2236#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2237#[cfg_attr(feature = "schemars", derive(JsonSchema))]
2238#[cfg_attr(feature = "serde", serde(deny_unknown_fields))]
2239#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
2240pub struct Tree {
2241 pub root: NodeId,
2243 pub app_name: Option<String>,
2245 pub toolkit_name: Option<String>,
2247 pub toolkit_version: Option<String>,
2249}
2250
2251impl Tree {
2252 #[inline]
2253 pub fn new(root: NodeId) -> Tree {
2254 Tree {
2255 root,
2256 app_name: None,
2257 toolkit_name: None,
2258 toolkit_version: None,
2259 }
2260 }
2261}
2262
2263#[derive(Clone, Debug, PartialEq)]
2275#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2276#[cfg_attr(feature = "schemars", derive(JsonSchema))]
2277#[cfg_attr(feature = "serde", serde(deny_unknown_fields))]
2278#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
2279pub struct TreeUpdate {
2280 pub nodes: Vec<(NodeId, Node)>,
2301
2302 pub tree: Option<Tree>,
2307
2308 pub focus: NodeId,
2314}
2315
2316#[derive(Clone, Debug, PartialEq)]
2317#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2318#[cfg_attr(feature = "schemars", derive(JsonSchema))]
2319#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
2320#[repr(C)]
2321pub enum ActionData {
2322 CustomAction(i32),
2323 Value(Box<str>),
2324 NumericValue(f64),
2325 ScrollTargetRect(Rect),
2328 ScrollToPoint(Point),
2331 SetScrollOffset(Point),
2334 SetTextSelection(TextSelection),
2335}
2336
2337#[derive(Clone, Debug, PartialEq)]
2338#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2339#[cfg_attr(feature = "schemars", derive(JsonSchema))]
2340#[cfg_attr(feature = "serde", serde(deny_unknown_fields))]
2341#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
2342pub struct ActionRequest {
2343 pub action: Action,
2344 pub target: NodeId,
2345 pub data: Option<ActionData>,
2346}
2347
2348pub trait ActivationHandler {
2350 fn request_initial_tree(&mut self) -> Option<TreeUpdate>;
2372}
2373
2374pub trait ActionHandler {
2376 fn do_action(&mut self, request: ActionRequest);
2386}
2387
2388pub trait DeactivationHandler {
2390 fn deactivate_accessibility(&mut self);
2398}
2399
2400#[cfg(test)]
2401mod tests {
2402 use super::*;
2403
2404 #[test]
2405 fn action_n() {
2406 assert_eq!(Action::n(0), Some(Action::Click));
2407 assert_eq!(Action::n(1), Some(Action::Focus));
2408 assert_eq!(Action::n(2), Some(Action::Blur));
2409 assert_eq!(Action::n(3), Some(Action::Collapse));
2410 assert_eq!(Action::n(4), Some(Action::Expand));
2411 assert_eq!(Action::n(5), Some(Action::CustomAction));
2412 assert_eq!(Action::n(6), Some(Action::Decrement));
2413 assert_eq!(Action::n(7), Some(Action::Increment));
2414 assert_eq!(Action::n(8), Some(Action::HideTooltip));
2415 assert_eq!(Action::n(9), Some(Action::ShowTooltip));
2416 assert_eq!(Action::n(10), Some(Action::ReplaceSelectedText));
2417 assert_eq!(Action::n(11), Some(Action::ScrollBackward));
2418 assert_eq!(Action::n(12), Some(Action::ScrollDown));
2419 assert_eq!(Action::n(13), Some(Action::ScrollForward));
2420 assert_eq!(Action::n(14), Some(Action::ScrollLeft));
2421 assert_eq!(Action::n(15), Some(Action::ScrollRight));
2422 assert_eq!(Action::n(16), Some(Action::ScrollUp));
2423 assert_eq!(Action::n(17), Some(Action::ScrollIntoView));
2424 assert_eq!(Action::n(18), Some(Action::ScrollToPoint));
2425 assert_eq!(Action::n(19), Some(Action::SetScrollOffset));
2426 assert_eq!(Action::n(20), Some(Action::SetTextSelection));
2427 assert_eq!(
2428 Action::n(21),
2429 Some(Action::SetSequentialFocusNavigationStartingPoint)
2430 );
2431 assert_eq!(Action::n(22), Some(Action::SetValue));
2432 assert_eq!(Action::n(23), Some(Action::ShowContextMenu));
2433 assert_eq!(Action::n(24), None);
2434 }
2435
2436 #[test]
2437 fn test_action_mask_to_action_vec() {
2438 assert_eq!(
2439 Vec::<Action>::new(),
2440 action_mask_to_action_vec(Node::new(Role::Unknown).actions)
2441 );
2442
2443 let mut node = Node::new(Role::Unknown);
2444 node.add_action(Action::Click);
2445 assert_eq!(
2446 &[Action::Click],
2447 action_mask_to_action_vec(node.actions).as_slice()
2448 );
2449
2450 let mut node = Node::new(Role::Unknown);
2451 node.add_action(Action::ShowContextMenu);
2452 assert_eq!(
2453 &[Action::ShowContextMenu],
2454 action_mask_to_action_vec(node.actions).as_slice()
2455 );
2456
2457 let mut node = Node::new(Role::Unknown);
2458 node.add_action(Action::Click);
2459 node.add_action(Action::ShowContextMenu);
2460 assert_eq!(
2461 &[Action::Click, Action::ShowContextMenu],
2462 action_mask_to_action_vec(node.actions).as_slice()
2463 );
2464
2465 let mut node = Node::new(Role::Unknown);
2466 node.add_action(Action::Focus);
2467 node.add_action(Action::Blur);
2468 node.add_action(Action::Collapse);
2469 assert_eq!(
2470 &[Action::Focus, Action::Blur, Action::Collapse],
2471 action_mask_to_action_vec(node.actions).as_slice()
2472 );
2473 }
2474}