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 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", eq)
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", eq)
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", eq)
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", eq)
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", eq)
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", eq)
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", eq)
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", eq)
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", eq)
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", eq)
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", eq)
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", eq)
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", eq)
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 From<&FrozenNode> for Node {
1386 fn from(node: &FrozenNode) -> Self {
1387 Self {
1388 role: node.role,
1389 actions: node.actions,
1390 flags: node.flags,
1391 properties: Properties {
1392 indices: node.properties.indices,
1393 values: node.properties.values.to_vec(),
1394 },
1395 }
1396 }
1397}
1398
1399impl FrozenNode {
1400 #[inline]
1401 pub fn role(&self) -> Role {
1402 self.role
1403 }
1404}
1405
1406impl Node {
1407 #[inline]
1408 pub fn role(&self) -> Role {
1409 self.role
1410 }
1411 #[inline]
1412 pub fn set_role(&mut self, value: Role) {
1413 self.role = value;
1414 }
1415}
1416
1417impl FrozenNode {
1418 #[inline]
1419 pub fn supports_action(&self, action: Action) -> bool {
1420 (self.actions & action.mask()) != 0
1421 }
1422}
1423
1424impl Node {
1425 #[inline]
1426 pub fn supports_action(&self, action: Action) -> bool {
1427 (self.actions & action.mask()) != 0
1428 }
1429 #[inline]
1430 pub fn add_action(&mut self, action: Action) {
1431 self.actions |= action.mask();
1432 }
1433 #[inline]
1434 pub fn remove_action(&mut self, action: Action) {
1435 self.actions &= !(action.mask());
1436 }
1437 #[inline]
1438 pub fn clear_actions(&mut self) {
1439 self.actions = 0;
1440 }
1441}
1442
1443flag_methods! {
1444 (Hidden, is_hidden, set_hidden, clear_hidden),
1447 (Linked, is_linked, set_linked, clear_linked),
1448 (Multiselectable, is_multiselectable, set_multiselectable, clear_multiselectable),
1449 (Required, is_required, set_required, clear_required),
1450 (Visited, is_visited, set_visited, clear_visited),
1451 (Busy, is_busy, set_busy, clear_busy),
1452 (LiveAtomic, is_live_atomic, set_live_atomic, clear_live_atomic),
1453 (Modal, is_modal, set_modal, clear_modal),
1455 (TouchTransparent, is_touch_transparent, set_touch_transparent, clear_touch_transparent),
1459 (ReadOnly, is_read_only, set_read_only, clear_read_only),
1461 (Disabled, is_disabled, set_disabled, clear_disabled),
1463 (Bold, is_bold, set_bold, clear_bold),
1464 (Italic, is_italic, set_italic, clear_italic),
1465 (ClipsChildren, clips_children, set_clips_children, clear_clips_children),
1468 (IsLineBreakingObject, is_line_breaking_object, set_is_line_breaking_object, clear_is_line_breaking_object),
1471 (IsPageBreakingObject, is_page_breaking_object, set_is_page_breaking_object, clear_is_page_breaking_object),
1473 (IsSpellingError, is_spelling_error, set_is_spelling_error, clear_is_spelling_error),
1474 (IsGrammarError, is_grammar_error, set_is_grammar_error, clear_is_grammar_error),
1475 (IsSearchMatch, is_search_match, set_is_search_match, clear_is_search_match),
1476 (IsSuggestion, is_suggestion, set_is_suggestion, clear_is_suggestion)
1477}
1478
1479option_ref_type_getters! {
1480 (get_affine_property, Affine, Affine),
1481 (get_string_property, str, String),
1482 (get_coord_slice_property, [f32], CoordSlice),
1483 (get_text_selection_property, TextSelection, TextSelection)
1484}
1485
1486slice_type_getters! {
1487 (get_length_slice_property, u8, LengthSlice)
1488}
1489
1490copy_type_getters! {
1491 (get_rect_property, Rect, Rect),
1492 (get_node_id_property, NodeId, NodeId),
1493 (get_f64_property, f64, F64),
1494 (get_usize_property, usize, Usize),
1495 (get_color_property, u32, Color),
1496 (get_text_decoration_property, TextDecoration, TextDecoration),
1497 (get_bool_property, bool, Bool)
1498}
1499
1500box_type_setters! {
1501 (set_affine_property, Affine, Affine),
1502 (set_string_property, str, String),
1503 (set_length_slice_property, [u8], LengthSlice),
1504 (set_coord_slice_property, [f32], CoordSlice),
1505 (set_text_selection_property, TextSelection, TextSelection)
1506}
1507
1508copy_type_setters! {
1509 (set_rect_property, Rect, Rect),
1510 (set_node_id_property, NodeId, NodeId),
1511 (set_f64_property, f64, F64),
1512 (set_usize_property, usize, Usize),
1513 (set_color_property, u32, Color),
1514 (set_text_decoration_property, TextDecoration, TextDecoration),
1515 (set_bool_property, bool, Bool)
1516}
1517
1518vec_type_methods! {
1519 (NodeId, NodeIdVec, get_node_id_vec, set_node_id_vec, push_to_node_id_vec),
1520 (CustomAction, CustomActionVec, get_custom_action_vec, set_custom_action_vec, push_to_custom_action_vec)
1521}
1522
1523node_id_vec_property_methods! {
1524 (Children, children, set_children, push_child, clear_children),
1525 (Controls, controls, set_controls, push_controlled, clear_controls),
1526 (Details, details, set_details, push_detail, clear_details),
1527 (DescribedBy, described_by, set_described_by, push_described_by, clear_described_by),
1528 (FlowTo, flow_to, set_flow_to, push_flow_to, clear_flow_to),
1529 (LabelledBy, labelled_by, set_labelled_by, push_labelled_by, clear_labelled_by),
1530 (Owns, owns, set_owns, push_owned, clear_owns),
1536 (RadioGroup, radio_group, set_radio_group, push_to_radio_group, clear_radio_group)
1539}
1540
1541node_id_property_methods! {
1542 (ActiveDescendant, active_descendant, set_active_descendant, clear_active_descendant),
1543 (ErrorMessage, error_message, set_error_message, clear_error_message),
1544 (InPageLinkTarget, in_page_link_target, set_in_page_link_target, clear_in_page_link_target),
1545 (MemberOf, member_of, set_member_of, clear_member_of),
1546 (NextOnLine, next_on_line, set_next_on_line, clear_next_on_line),
1547 (PreviousOnLine, previous_on_line, set_previous_on_line, clear_previous_on_line),
1548 (PopupFor, popup_for, set_popup_for, clear_popup_for)
1549}
1550
1551string_property_methods! {
1552 (Label, label, set_label, clear_label),
1557 (Description, description, set_description, clear_description),
1558 (Value, value, set_value, clear_value),
1559 (AccessKey, access_key, set_access_key, clear_access_key),
1567 (AuthorId, author_id, set_author_id, clear_author_id),
1570 (ClassName, class_name, set_class_name, clear_class_name),
1571 (FontFamily, font_family, set_font_family, clear_font_family),
1573 (HtmlTag, html_tag, set_html_tag, clear_html_tag),
1574 (InnerHtml, inner_html, set_inner_html, clear_inner_html),
1577 (KeyboardShortcut, keyboard_shortcut, set_keyboard_shortcut, clear_keyboard_shortcut),
1581 (Language, language, set_language, clear_language),
1583 (Placeholder, placeholder, set_placeholder, clear_placeholder),
1588 (RoleDescription, role_description, set_role_description, clear_role_description),
1592 (StateDescription, state_description, set_state_description, clear_state_description),
1597 (Tooltip, tooltip, set_tooltip, clear_tooltip),
1602 (Url, url, set_url, clear_url),
1603 (RowIndexText, row_index_text, set_row_index_text, clear_row_index_text),
1604 (ColumnIndexText, column_index_text, set_column_index_text, clear_column_index_text)
1605}
1606
1607f64_property_methods! {
1608 (ScrollX, scroll_x, set_scroll_x, clear_scroll_x),
1609 (ScrollXMin, scroll_x_min, set_scroll_x_min, clear_scroll_x_min),
1610 (ScrollXMax, scroll_x_max, set_scroll_x_max, clear_scroll_x_max),
1611 (ScrollY, scroll_y, set_scroll_y, clear_scroll_y),
1612 (ScrollYMin, scroll_y_min, set_scroll_y_min, clear_scroll_y_min),
1613 (ScrollYMax, scroll_y_max, set_scroll_y_max, clear_scroll_y_max),
1614 (NumericValue, numeric_value, set_numeric_value, clear_numeric_value),
1615 (MinNumericValue, min_numeric_value, set_min_numeric_value, clear_min_numeric_value),
1616 (MaxNumericValue, max_numeric_value, set_max_numeric_value, clear_max_numeric_value),
1617 (NumericValueStep, numeric_value_step, set_numeric_value_step, clear_numeric_value_step),
1618 (NumericValueJump, numeric_value_jump, set_numeric_value_jump, clear_numeric_value_jump),
1619 (FontSize, font_size, set_font_size, clear_font_size),
1621 (FontWeight, font_weight, set_font_weight, clear_font_weight)
1624}
1625
1626usize_property_methods! {
1627 (RowCount, row_count, set_row_count, clear_row_count),
1628 (ColumnCount, column_count, set_column_count, clear_column_count),
1629 (RowIndex, row_index, set_row_index, clear_row_index),
1630 (ColumnIndex, column_index, set_column_index, clear_column_index),
1631 (RowSpan, row_span, set_row_span, clear_row_span),
1632 (ColumnSpan, column_span, set_column_span, clear_column_span),
1633 (Level, level, set_level, clear_level),
1634 (SizeOfSet, size_of_set, set_size_of_set, clear_size_of_set),
1636 (PositionInSet, position_in_set, set_position_in_set, clear_position_in_set)
1641}
1642
1643color_property_methods! {
1644 (ColorValue, color_value, set_color_value, clear_color_value),
1646 (BackgroundColor, background_color, set_background_color, clear_background_color),
1648 (ForegroundColor, foreground_color, set_foreground_color, clear_foreground_color)
1650}
1651
1652text_decoration_property_methods! {
1653 (Overline, overline, set_overline, clear_overline),
1654 (Strikethrough, strikethrough, set_strikethrough, clear_strikethrough),
1655 (Underline, underline, set_underline, clear_underline)
1656}
1657
1658length_slice_property_methods! {
1659 (CharacterLengths, character_lengths, set_character_lengths, clear_character_lengths),
1678
1679 (WordLengths, word_lengths, set_word_lengths, clear_word_lengths)
1702}
1703
1704coord_slice_property_methods! {
1705 (CharacterPositions, character_positions, set_character_positions, clear_character_positions),
1722
1723 (CharacterWidths, character_widths, set_character_widths, clear_character_widths)
1742}
1743
1744bool_property_methods! {
1745 (Expanded, is_expanded, set_expanded, clear_expanded),
1750
1751 (Selected, is_selected, set_selected, clear_selected)
1761}
1762
1763unique_enum_property_methods! {
1764 (Invalid, invalid, set_invalid, clear_invalid),
1765 (Toggled, toggled, set_toggled, clear_toggled),
1766 (Live, live, set_live, clear_live),
1767 (TextDirection, text_direction, set_text_direction, clear_text_direction),
1768 (Orientation, orientation, set_orientation, clear_orientation),
1769 (SortDirection, sort_direction, set_sort_direction, clear_sort_direction),
1770 (AriaCurrent, aria_current, set_aria_current, clear_aria_current),
1771 (AutoComplete, auto_complete, set_auto_complete, clear_auto_complete),
1772 (HasPopup, has_popup, set_has_popup, clear_has_popup),
1773 (ListStyle, list_style, set_list_style, clear_list_style),
1775 (TextAlign, text_align, set_text_align, clear_text_align),
1776 (VerticalOffset, vertical_offset, set_vertical_offset, clear_vertical_offset)
1777}
1778
1779property_methods! {
1780 (Transform, transform, get_affine_property, Option<&Affine>, set_transform, set_affine_property, impl Into<Box<Affine>>, clear_transform),
1793
1794 (Bounds, bounds, get_rect_property, Option<Rect>, set_bounds, set_rect_property, Rect, clear_bounds),
1805
1806 (TextSelection, text_selection, get_text_selection_property, Option<&TextSelection>, set_text_selection, set_text_selection_property, impl Into<Box<TextSelection>>, clear_text_selection)
1807}
1808
1809impl FrozenNode {
1810 option_properties_debug_method! { debug_option_properties, [transform, bounds, text_selection,] }
1811}
1812
1813impl Node {
1814 option_properties_debug_method! { debug_option_properties, [transform, bounds, text_selection,] }
1815}
1816
1817vec_property_methods! {
1818 (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)
1819}
1820
1821impl fmt::Debug for FrozenNode {
1822 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1823 let mut fmt = f.debug_struct("FrozenNode");
1824
1825 fmt.field("role", &self.role());
1826
1827 let supported_actions = action_mask_to_action_vec(self.actions);
1828 if !supported_actions.is_empty() {
1829 fmt.field("actions", &supported_actions);
1830 }
1831
1832 self.debug_flag_properties(&mut fmt);
1833 self.debug_node_id_vec_properties(&mut fmt);
1834 self.debug_node_id_properties(&mut fmt);
1835 self.debug_string_properties(&mut fmt);
1836 self.debug_f64_properties(&mut fmt);
1837 self.debug_usize_properties(&mut fmt);
1838 self.debug_color_properties(&mut fmt);
1839 self.debug_text_decoration_properties(&mut fmt);
1840 self.debug_length_slice_properties(&mut fmt);
1841 self.debug_coord_slice_properties(&mut fmt);
1842 self.debug_bool_properties(&mut fmt);
1843 self.debug_unique_enum_properties(&mut fmt);
1844 self.debug_option_properties(&mut fmt);
1845
1846 let custom_actions = self.custom_actions();
1847 if !custom_actions.is_empty() {
1848 fmt.field("custom_actions", &custom_actions);
1849 }
1850
1851 fmt.finish()
1852 }
1853}
1854
1855impl fmt::Debug for Node {
1856 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1857 let mut fmt = f.debug_struct("Node");
1858
1859 fmt.field("role", &self.role());
1860
1861 let supported_actions = action_mask_to_action_vec(self.actions);
1862 if !supported_actions.is_empty() {
1863 fmt.field("actions", &supported_actions);
1864 }
1865
1866 self.debug_flag_properties(&mut fmt);
1867 self.debug_node_id_vec_properties(&mut fmt);
1868 self.debug_node_id_properties(&mut fmt);
1869 self.debug_string_properties(&mut fmt);
1870 self.debug_f64_properties(&mut fmt);
1871 self.debug_usize_properties(&mut fmt);
1872 self.debug_color_properties(&mut fmt);
1873 self.debug_text_decoration_properties(&mut fmt);
1874 self.debug_length_slice_properties(&mut fmt);
1875 self.debug_coord_slice_properties(&mut fmt);
1876 self.debug_bool_properties(&mut fmt);
1877 self.debug_unique_enum_properties(&mut fmt);
1878 self.debug_option_properties(&mut fmt);
1879
1880 let custom_actions = self.custom_actions();
1881 if !custom_actions.is_empty() {
1882 fmt.field("custom_actions", &custom_actions);
1883 }
1884
1885 fmt.finish()
1886 }
1887}
1888
1889#[cfg(feature = "serde")]
1890macro_rules! serialize_property {
1891 ($self:ident, $map:ident, $index:ident, $id:ident, { $($variant:ident),+ }) => {
1892 match &$self.values[$index as usize] {
1893 PropertyValue::None => (),
1894 $(PropertyValue::$variant(value) => {
1895 $map.serialize_entry(&$id, &value)?;
1896 })*
1897 }
1898 }
1899}
1900
1901#[cfg(feature = "serde")]
1902macro_rules! deserialize_property {
1903 ($props:ident, $map:ident, $key:ident, { $($type:ident { $($id:ident),+ }),+ }) => {
1904 match $key {
1905 $($(PropertyId::$id => {
1906 let value = $map.next_value()?;
1907 $props.set(PropertyId::$id, PropertyValue::$type(value));
1908 })*)*
1909 PropertyId::Unset => {
1910 let _ = $map.next_value::<IgnoredAny>()?;
1911 }
1912 }
1913 }
1914}
1915
1916#[cfg(feature = "serde")]
1917impl Serialize for Properties {
1918 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1919 where
1920 S: Serializer,
1921 {
1922 let mut len = 0;
1923 for value in &*self.values {
1924 if !matches!(*value, PropertyValue::None) {
1925 len += 1;
1926 }
1927 }
1928 let mut map = serializer.serialize_map(Some(len))?;
1929 for (id, index) in self.indices.0.iter().copied().enumerate() {
1930 if index == PropertyId::Unset as u8 {
1931 continue;
1932 }
1933 let id = PropertyId::n(id as _).unwrap();
1934 serialize_property!(self, map, index, id, {
1935 NodeIdVec,
1936 NodeId,
1937 String,
1938 F64,
1939 Usize,
1940 Color,
1941 TextDecoration,
1942 LengthSlice,
1943 CoordSlice,
1944 Bool,
1945 Invalid,
1946 Toggled,
1947 Live,
1948 TextDirection,
1949 Orientation,
1950 SortDirection,
1951 AriaCurrent,
1952 AutoComplete,
1953 HasPopup,
1954 ListStyle,
1955 TextAlign,
1956 VerticalOffset,
1957 Affine,
1958 Rect,
1959 TextSelection,
1960 CustomActionVec
1961 });
1962 }
1963 map.end()
1964 }
1965}
1966
1967#[cfg(feature = "serde")]
1968struct PropertiesVisitor;
1969
1970#[cfg(feature = "serde")]
1971impl<'de> Visitor<'de> for PropertiesVisitor {
1972 type Value = Properties;
1973
1974 #[inline]
1975 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
1976 formatter.write_str("property map")
1977 }
1978
1979 fn visit_map<V>(self, mut map: V) -> Result<Self::Value, V::Error>
1980 where
1981 V: MapAccess<'de>,
1982 {
1983 let mut props = Properties::default();
1984 while let Some(id) = map.next_key()? {
1985 deserialize_property!(props, map, id, {
1986 NodeIdVec {
1987 Children,
1988 Controls,
1989 Details,
1990 DescribedBy,
1991 FlowTo,
1992 LabelledBy,
1993 Owns,
1994 RadioGroup
1995 },
1996 NodeId {
1997 ActiveDescendant,
1998 ErrorMessage,
1999 InPageLinkTarget,
2000 MemberOf,
2001 NextOnLine,
2002 PreviousOnLine,
2003 PopupFor
2004 },
2005 String {
2006 Label,
2007 Description,
2008 Value,
2009 AccessKey,
2010 AuthorId,
2011 ClassName,
2012 FontFamily,
2013 HtmlTag,
2014 InnerHtml,
2015 KeyboardShortcut,
2016 Language,
2017 Placeholder,
2018 RoleDescription,
2019 StateDescription,
2020 Tooltip,
2021 Url,
2022 RowIndexText,
2023 ColumnIndexText
2024 },
2025 F64 {
2026 ScrollX,
2027 ScrollXMin,
2028 ScrollXMax,
2029 ScrollY,
2030 ScrollYMin,
2031 ScrollYMax,
2032 NumericValue,
2033 MinNumericValue,
2034 MaxNumericValue,
2035 NumericValueStep,
2036 NumericValueJump,
2037 FontSize,
2038 FontWeight
2039 },
2040 Usize {
2041 RowCount,
2042 ColumnCount,
2043 RowIndex,
2044 ColumnIndex,
2045 RowSpan,
2046 ColumnSpan,
2047 Level,
2048 SizeOfSet,
2049 PositionInSet
2050 },
2051 Color {
2052 ColorValue,
2053 BackgroundColor,
2054 ForegroundColor
2055 },
2056 TextDecoration {
2057 Overline,
2058 Strikethrough,
2059 Underline
2060 },
2061 LengthSlice {
2062 CharacterLengths,
2063 WordLengths
2064 },
2065 CoordSlice {
2066 CharacterPositions,
2067 CharacterWidths
2068 },
2069 Bool {
2070 Expanded,
2071 Selected
2072 },
2073 Invalid { Invalid },
2074 Toggled { Toggled },
2075 Live { Live },
2076 TextDirection { TextDirection },
2077 Orientation { Orientation },
2078 SortDirection { SortDirection },
2079 AriaCurrent { AriaCurrent },
2080 AutoComplete { AutoComplete },
2081 HasPopup { HasPopup },
2082 ListStyle { ListStyle },
2083 TextAlign { TextAlign },
2084 VerticalOffset { VerticalOffset },
2085 Affine { Transform },
2086 Rect { Bounds },
2087 TextSelection { TextSelection },
2088 CustomActionVec { CustomActions }
2089 });
2090 }
2091
2092 Ok(props)
2093 }
2094}
2095
2096#[cfg(feature = "serde")]
2097impl<'de> Deserialize<'de> for Properties {
2098 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
2099 where
2100 D: Deserializer<'de>,
2101 {
2102 deserializer.deserialize_map(PropertiesVisitor)
2103 }
2104}
2105
2106#[cfg(feature = "schemars")]
2107macro_rules! add_schema_property {
2108 ($gen:ident, $properties:ident, $enum_value:expr, $type:ty) => {{
2109 let name = format!("{:?}", $enum_value);
2110 let name = name[..1].to_ascii_lowercase() + &name[1..];
2111 let subschema = $gen.subschema_for::<$type>();
2112 $properties.insert(name, subschema);
2113 }};
2114}
2115
2116#[cfg(feature = "schemars")]
2117macro_rules! add_properties_to_schema {
2118 ($gen:ident, $properties:ident, { $($type:ty { $($id:ident),+ }),+ }) => {
2119 $($(add_schema_property!($gen, $properties, PropertyId::$id, $type);)*)*
2120 }
2121}
2122
2123#[cfg(feature = "schemars")]
2124impl JsonSchema for Properties {
2125 #[inline]
2126 fn schema_name() -> String {
2127 "Properties".into()
2128 }
2129
2130 fn json_schema(gen: &mut SchemaGenerator) -> Schema {
2131 let mut properties = SchemaMap::<String, Schema>::new();
2132 add_properties_to_schema!(gen, properties, {
2133 Vec<NodeId> {
2134 Children,
2135 Controls,
2136 Details,
2137 DescribedBy,
2138 FlowTo,
2139 LabelledBy,
2140 Owns,
2141 RadioGroup
2142 },
2143 NodeId {
2144 ActiveDescendant,
2145 ErrorMessage,
2146 InPageLinkTarget,
2147 MemberOf,
2148 NextOnLine,
2149 PreviousOnLine,
2150 PopupFor
2151 },
2152 Box<str> {
2153 Label,
2154 Description,
2155 Value,
2156 AccessKey,
2157 AuthorId,
2158 ClassName,
2159 FontFamily,
2160 HtmlTag,
2161 InnerHtml,
2162 KeyboardShortcut,
2163 Language,
2164 Placeholder,
2165 RoleDescription,
2166 StateDescription,
2167 Tooltip,
2168 Url,
2169 RowIndexText,
2170 ColumnIndexText
2171 },
2172 f64 {
2173 ScrollX,
2174 ScrollXMin,
2175 ScrollXMax,
2176 ScrollY,
2177 ScrollYMin,
2178 ScrollYMax,
2179 NumericValue,
2180 MinNumericValue,
2181 MaxNumericValue,
2182 NumericValueStep,
2183 NumericValueJump,
2184 FontSize,
2185 FontWeight
2186 },
2187 usize {
2188 RowCount,
2189 ColumnCount,
2190 RowIndex,
2191 ColumnIndex,
2192 RowSpan,
2193 ColumnSpan,
2194 Level,
2195 SizeOfSet,
2196 PositionInSet
2197 },
2198 u32 {
2199 ColorValue,
2200 BackgroundColor,
2201 ForegroundColor
2202 },
2203 TextDecoration {
2204 Overline,
2205 Strikethrough,
2206 Underline
2207 },
2208 Box<[u8]> {
2209 CharacterLengths,
2210 WordLengths
2211 },
2212 Box<[f32]> {
2213 CharacterPositions,
2214 CharacterWidths
2215 },
2216 bool {
2217 Expanded,
2218 Selected
2219 },
2220 Invalid { Invalid },
2221 Toggled { Toggled },
2222 Live { Live },
2223 TextDirection { TextDirection },
2224 Orientation { Orientation },
2225 SortDirection { SortDirection },
2226 AriaCurrent { AriaCurrent },
2227 AutoComplete { AutoComplete },
2228 HasPopup { HasPopup },
2229 ListStyle { ListStyle },
2230 TextAlign { TextAlign },
2231 VerticalOffset { VerticalOffset },
2232 Affine { Transform },
2233 Rect { Bounds },
2234 TextSelection { TextSelection },
2235 Vec<CustomAction> { CustomActions }
2236 });
2237 SchemaObject {
2238 instance_type: Some(InstanceType::Object.into()),
2239 object: Some(
2240 ObjectValidation {
2241 properties,
2242 ..Default::default()
2243 }
2244 .into(),
2245 ),
2246 ..Default::default()
2247 }
2248 .into()
2249 }
2250}
2251
2252#[derive(Clone, Debug, PartialEq, Eq)]
2255#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2256#[cfg_attr(feature = "schemars", derive(JsonSchema))]
2257#[cfg_attr(feature = "serde", serde(deny_unknown_fields))]
2258#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
2259pub struct Tree {
2260 pub root: NodeId,
2262 pub toolkit_name: Option<String>,
2264 pub toolkit_version: Option<String>,
2266}
2267
2268impl Tree {
2269 #[inline]
2270 pub fn new(root: NodeId) -> Tree {
2271 Tree {
2272 root,
2273 toolkit_name: None,
2274 toolkit_version: None,
2275 }
2276 }
2277}
2278
2279#[derive(Clone, Debug, PartialEq)]
2291#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2292#[cfg_attr(feature = "schemars", derive(JsonSchema))]
2293#[cfg_attr(feature = "serde", serde(deny_unknown_fields))]
2294#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
2295pub struct TreeUpdate {
2296 pub nodes: Vec<(NodeId, Node)>,
2317
2318 pub tree: Option<Tree>,
2323
2324 pub focus: NodeId,
2330}
2331
2332#[derive(Clone, Debug, PartialEq)]
2333#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2334#[cfg_attr(feature = "schemars", derive(JsonSchema))]
2335#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
2336#[repr(C)]
2337pub enum ActionData {
2338 CustomAction(i32),
2339 Value(Box<str>),
2340 NumericValue(f64),
2341 ScrollTargetRect(Rect),
2344 ScrollToPoint(Point),
2347 SetScrollOffset(Point),
2350 SetTextSelection(TextSelection),
2351}
2352
2353#[derive(Clone, Debug, PartialEq)]
2354#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2355#[cfg_attr(feature = "schemars", derive(JsonSchema))]
2356#[cfg_attr(feature = "serde", serde(deny_unknown_fields))]
2357#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
2358pub struct ActionRequest {
2359 pub action: Action,
2360 pub target: NodeId,
2361 pub data: Option<ActionData>,
2362}
2363
2364pub trait ActivationHandler {
2366 fn request_initial_tree(&mut self) -> Option<TreeUpdate>;
2388}
2389
2390pub trait ActionHandler {
2392 fn do_action(&mut self, request: ActionRequest);
2402}
2403
2404pub trait DeactivationHandler {
2406 fn deactivate_accessibility(&mut self);
2414}
2415
2416#[cfg(test)]
2417mod tests {
2418 use super::*;
2419
2420 #[test]
2421 fn action_n() {
2422 assert_eq!(Action::n(0), Some(Action::Click));
2423 assert_eq!(Action::n(1), Some(Action::Focus));
2424 assert_eq!(Action::n(2), Some(Action::Blur));
2425 assert_eq!(Action::n(3), Some(Action::Collapse));
2426 assert_eq!(Action::n(4), Some(Action::Expand));
2427 assert_eq!(Action::n(5), Some(Action::CustomAction));
2428 assert_eq!(Action::n(6), Some(Action::Decrement));
2429 assert_eq!(Action::n(7), Some(Action::Increment));
2430 assert_eq!(Action::n(8), Some(Action::HideTooltip));
2431 assert_eq!(Action::n(9), Some(Action::ShowTooltip));
2432 assert_eq!(Action::n(10), Some(Action::ReplaceSelectedText));
2433 assert_eq!(Action::n(11), Some(Action::ScrollBackward));
2434 assert_eq!(Action::n(12), Some(Action::ScrollDown));
2435 assert_eq!(Action::n(13), Some(Action::ScrollForward));
2436 assert_eq!(Action::n(14), Some(Action::ScrollLeft));
2437 assert_eq!(Action::n(15), Some(Action::ScrollRight));
2438 assert_eq!(Action::n(16), Some(Action::ScrollUp));
2439 assert_eq!(Action::n(17), Some(Action::ScrollIntoView));
2440 assert_eq!(Action::n(18), Some(Action::ScrollToPoint));
2441 assert_eq!(Action::n(19), Some(Action::SetScrollOffset));
2442 assert_eq!(Action::n(20), Some(Action::SetTextSelection));
2443 assert_eq!(
2444 Action::n(21),
2445 Some(Action::SetSequentialFocusNavigationStartingPoint)
2446 );
2447 assert_eq!(Action::n(22), Some(Action::SetValue));
2448 assert_eq!(Action::n(23), Some(Action::ShowContextMenu));
2449 assert_eq!(Action::n(24), None);
2450 }
2451
2452 #[test]
2453 fn test_action_mask_to_action_vec() {
2454 assert_eq!(
2455 Vec::<Action>::new(),
2456 action_mask_to_action_vec(Node::new(Role::Unknown).actions)
2457 );
2458
2459 let mut node = Node::new(Role::Unknown);
2460 node.add_action(Action::Click);
2461 assert_eq!(
2462 &[Action::Click],
2463 action_mask_to_action_vec(node.actions).as_slice()
2464 );
2465
2466 let mut node = Node::new(Role::Unknown);
2467 node.add_action(Action::ShowContextMenu);
2468 assert_eq!(
2469 &[Action::ShowContextMenu],
2470 action_mask_to_action_vec(node.actions).as_slice()
2471 );
2472
2473 let mut node = Node::new(Role::Unknown);
2474 node.add_action(Action::Click);
2475 node.add_action(Action::ShowContextMenu);
2476 assert_eq!(
2477 &[Action::Click, Action::ShowContextMenu],
2478 action_mask_to_action_vec(node.actions).as_slice()
2479 );
2480
2481 let mut node = Node::new(Role::Unknown);
2482 node.add_action(Action::Focus);
2483 node.add_action(Action::Blur);
2484 node.add_action(Action::Collapse);
2485 assert_eq!(
2486 &[Action::Focus, Action::Blur, Action::Collapse],
2487 action_mask_to_action_vec(node.actions).as_slice()
2488 );
2489 }
2490}