Skip to main content

cranpose_ui/layout/
semantics_details.rs

1use cranpose_core::collections::rare::{RareProperties, rare, set_rare, update_rare};
2use cranpose_foundation::{
3    CanvasSemanticsNode, CollectionInfo, LiveRegionMode, ProgressBarRangeInfo, ScrollAxisRange,
4    SemanticsConfiguration, SemanticsCustomAction, SemanticsDismiss, SemanticsExpand,
5    SemanticsLongClick, SemanticsMagicTap, SemanticsScrollBy, SemanticsScrollToIndex,
6    SemanticsSetProgress, SemanticsSetSelection, SemanticsSetText, text::TextRange,
7};
8
9use super::SemanticsNode;
10
11/// What a semantics node reports beyond its place, its name, its value and
12/// its click: the properties few nodes set. A node holds them only when it
13/// sets one, so a node without any stays small.
14#[derive(Clone, Debug, PartialEq)]
15pub struct SemanticsDetails {
16    /// What the control says about itself after its name.
17    pub state_description: Option<String>,
18    /// What activating the control does, as a verb phrase a reader reads out.
19    pub on_click_label: Option<String>,
20    /// What this control does when a screen reader asks for its long press.
21    pub on_long_click: Option<SemanticsLongClick>,
22    /// What the long press does, as a verb phrase a reader reads out.
23    pub on_long_click_label: Option<String>,
24    /// What this control does on VoiceOver's magic tap.
25    pub on_magic_tap: Option<SemanticsMagicTap>,
26    /// What the magic tap does, as a verb phrase a reader reads out.
27    pub on_magic_tap_label: Option<String>,
28    /// The short names a person says to Voice Control to reach this control.
29    pub input_labels: Vec<String>,
30    /// The language of this control's text, as a BCP 47 tag.
31    pub language: Option<String>,
32    /// The actions a screen reader lists for the control beyond its click.
33    pub custom_actions: Vec<SemanticsCustomAction>,
34    /// Controls this node drew rather than laid out; their bounds are relative
35    /// to this node's own top-left. See [`CanvasSemanticsNode`].
36    pub canvas_children: Vec<CanvasSemanticsNode>,
37    /// Whether this node is a field a person types into.
38    pub editable_text: bool,
39    /// Whether an editable field accepts line breaks, independent of its current text.
40    pub multiline: bool,
41    /// Whether this subtree makes content outside it unavailable to assistive technology.
42    pub is_modal: bool,
43    /// Whether the selectable controls under this node form one group.
44    pub selectable_group: bool,
45    /// The title of the screen or pane this node is the root of.
46    pub pane_title: Option<String>,
47    /// Why the control's content is wrong, when it is.
48    pub error: Option<String>,
49    /// What using the control does or what it wants.
50    pub hint_text: Option<String>,
51    /// Whether this field holds a secret, so its text stays unspoken.
52    pub password: bool,
53    /// Where the caret of an editable field sits, or which stretch of its
54    /// text is picked.
55    pub text_selection: Option<TextRange>,
56    /// How urgently a screen reader reads this node when its text changes.
57    /// Compose's `SemanticsProperties.LiveRegion`.
58    pub live_region: Option<LiveRegionMode>,
59    /// The value this control holds inside a range. Compose's
60    /// `ProgressBarRangeInfo`.
61    pub progress: Option<ProgressBarRangeInfo>,
62    /// What this control does when a screen reader moves its value.
63    pub set_progress: Option<SemanticsSetProgress>,
64    /// What this field does when a screen reader hands it text.
65    pub set_text: Option<SemanticsSetText>,
66    /// What this field does when a screen reader moves its caret or picks a
67    /// stretch of its text.
68    pub set_selection: Option<SemanticsSetSelection>,
69    /// What this control does when a screen reader asks it to open.
70    pub expand: Option<SemanticsExpand>,
71    /// What this control does when a screen reader asks it to close.
72    pub collapse: Option<SemanticsExpand>,
73    /// What this control does when a screen reader asks to send it away.
74    pub dismiss: Option<SemanticsDismiss>,
75    /// How far this container scrolled up and down, when it scrolls.
76    pub vertical_scroll: Option<ScrollAxisRange>,
77    /// How far this container scrolled left and right, when it scrolls.
78    pub horizontal_scroll: Option<ScrollAxisRange>,
79    /// What this container does when a screen reader pages it.
80    pub scroll_by: Option<SemanticsScrollBy>,
81    /// What this list does when a screen reader asks for the row at an index.
82    pub scroll_to_index: Option<SemanticsScrollToIndex>,
83    /// How many rows and columns this list holds, when it is a list.
84    pub collection: Option<CollectionInfo>,
85    /// The name tests find this node by; never published to screen readers.
86    pub test_tag: Option<String>,
87}
88
89impl SemanticsDetails {
90    /// Details with nothing set: what a node that holds none reports.
91    pub const NONE: Self = Self {
92        state_description: None,
93        on_click_label: None,
94        on_long_click: None,
95        on_long_click_label: None,
96        on_magic_tap: None,
97        on_magic_tap_label: None,
98        input_labels: Vec::new(),
99        language: None,
100        custom_actions: Vec::new(),
101        canvas_children: Vec::new(),
102        editable_text: false,
103        multiline: false,
104        is_modal: false,
105        selectable_group: false,
106        pane_title: None,
107        error: None,
108        hint_text: None,
109        password: false,
110        text_selection: None,
111        live_region: None,
112        progress: None,
113        set_progress: None,
114        set_text: None,
115        set_selection: None,
116        expand: None,
117        collapse: None,
118        dismiss: None,
119        vertical_scroll: None,
120        horizontal_scroll: None,
121        scroll_by: None,
122        scroll_to_index: None,
123        collection: None,
124        test_tag: None,
125    };
126
127    pub(super) fn from_configuration(
128        config: SemanticsConfiguration,
129        on_click_label: Option<String>,
130        is_modal: bool,
131    ) -> Self {
132        Self {
133            state_description: config.state_description,
134            on_click_label,
135            on_long_click: config.on_long_click,
136            on_long_click_label: config.on_long_click_label,
137            on_magic_tap: config.on_magic_tap,
138            on_magic_tap_label: config.on_magic_tap_label,
139            input_labels: config.input_labels,
140            language: config.language,
141            custom_actions: config.custom_actions,
142            canvas_children: config.canvas_children,
143            editable_text: config.is_editable_text,
144            multiline: config.multiline,
145            is_modal,
146            selectable_group: config.selectable_group,
147            pane_title: config.pane_title,
148            error: config.error,
149            hint_text: config.hint_text,
150            password: config.password,
151            text_selection: config.text_selection,
152            live_region: config.live_region,
153            progress: config.progress,
154            set_progress: config.set_progress,
155            set_text: config.set_text,
156            set_selection: config.set_selection,
157            expand: config.expand,
158            collapse: config.collapse,
159            dismiss: config.dismiss,
160            vertical_scroll: config.vertical_scroll,
161            horizontal_scroll: config.horizontal_scroll,
162            scroll_by: config.scroll_by,
163            scroll_to_index: config.scroll_to_index,
164            collection: config.collection,
165            test_tag: config.test_tag,
166        }
167    }
168}
169
170impl Default for SemanticsDetails {
171    fn default() -> Self {
172        Self::NONE
173    }
174}
175
176impl RareProperties for SemanticsDetails {
177    const EMPTY: &'static Self = &Self::NONE;
178}
179
180impl SemanticsNode {
181    /// The properties few nodes set, with nothing set for a node that holds
182    /// none.
183    pub fn details(&self) -> &SemanticsDetails {
184        rare(&self.details)
185    }
186
187    /// Replaces the node's details. A node holds them only when something is
188    /// set, and keeps the space it already held for them.
189    pub fn set_details(&mut self, details: SemanticsDetails) {
190        set_rare(&mut self.details, details);
191    }
192
193    /// Changes some of the node's details in place, through
194    /// [`SemanticsNode::set_details`].
195    pub fn update_details(&mut self, update: impl FnOnce(&mut SemanticsDetails)) {
196        update_rare(&mut self.details, update);
197    }
198}