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    /// Whether this field holds a secret, so its text stays unspoken.
50    pub password: bool,
51    /// Where the caret of an editable field sits, or which stretch of its
52    /// text is picked.
53    pub text_selection: Option<TextRange>,
54    /// How urgently a screen reader reads this node when its text changes.
55    /// Compose's `SemanticsProperties.LiveRegion`.
56    pub live_region: Option<LiveRegionMode>,
57    /// The value this control holds inside a range. Compose's
58    /// `ProgressBarRangeInfo`.
59    pub progress: Option<ProgressBarRangeInfo>,
60    /// What this control does when a screen reader moves its value.
61    pub set_progress: Option<SemanticsSetProgress>,
62    /// What this field does when a screen reader hands it text.
63    pub set_text: Option<SemanticsSetText>,
64    /// What this field does when a screen reader moves its caret or picks a
65    /// stretch of its text.
66    pub set_selection: Option<SemanticsSetSelection>,
67    /// What this control does when a screen reader asks it to open.
68    pub expand: Option<SemanticsExpand>,
69    /// What this control does when a screen reader asks it to close.
70    pub collapse: Option<SemanticsExpand>,
71    /// What this control does when a screen reader asks to send it away.
72    pub dismiss: Option<SemanticsDismiss>,
73    /// How far this container scrolled up and down, when it scrolls.
74    pub vertical_scroll: Option<ScrollAxisRange>,
75    /// How far this container scrolled left and right, when it scrolls.
76    pub horizontal_scroll: Option<ScrollAxisRange>,
77    /// What this container does when a screen reader pages it.
78    pub scroll_by: Option<SemanticsScrollBy>,
79    /// What this list does when a screen reader asks for the row at an index.
80    pub scroll_to_index: Option<SemanticsScrollToIndex>,
81    /// How many rows and columns this list holds, when it is a list.
82    pub collection: Option<CollectionInfo>,
83}
84
85impl SemanticsDetails {
86    /// Details with nothing set: what a node that holds none reports.
87    pub const NONE: Self = Self {
88        state_description: None,
89        on_click_label: None,
90        on_long_click: None,
91        on_long_click_label: None,
92        on_magic_tap: None,
93        on_magic_tap_label: None,
94        input_labels: Vec::new(),
95        language: None,
96        custom_actions: Vec::new(),
97        canvas_children: Vec::new(),
98        editable_text: false,
99        multiline: false,
100        is_modal: false,
101        selectable_group: false,
102        pane_title: None,
103        error: None,
104        password: false,
105        text_selection: None,
106        live_region: None,
107        progress: None,
108        set_progress: None,
109        set_text: None,
110        set_selection: None,
111        expand: None,
112        collapse: None,
113        dismiss: None,
114        vertical_scroll: None,
115        horizontal_scroll: None,
116        scroll_by: None,
117        scroll_to_index: None,
118        collection: None,
119    };
120
121    pub(super) fn from_configuration(
122        config: SemanticsConfiguration,
123        on_click_label: Option<String>,
124        is_modal: bool,
125    ) -> Self {
126        Self {
127            state_description: config.state_description,
128            on_click_label,
129            on_long_click: config.on_long_click,
130            on_long_click_label: config.on_long_click_label,
131            on_magic_tap: config.on_magic_tap,
132            on_magic_tap_label: config.on_magic_tap_label,
133            input_labels: config.input_labels,
134            language: config.language,
135            custom_actions: config.custom_actions,
136            canvas_children: config.canvas_children,
137            editable_text: config.is_editable_text,
138            multiline: config.multiline,
139            is_modal,
140            selectable_group: config.selectable_group,
141            pane_title: config.pane_title,
142            error: config.error,
143            password: config.password,
144            text_selection: config.text_selection,
145            live_region: config.live_region,
146            progress: config.progress,
147            set_progress: config.set_progress,
148            set_text: config.set_text,
149            set_selection: config.set_selection,
150            expand: config.expand,
151            collapse: config.collapse,
152            dismiss: config.dismiss,
153            vertical_scroll: config.vertical_scroll,
154            horizontal_scroll: config.horizontal_scroll,
155            scroll_by: config.scroll_by,
156            scroll_to_index: config.scroll_to_index,
157            collection: config.collection,
158        }
159    }
160}
161
162impl Default for SemanticsDetails {
163    fn default() -> Self {
164        Self::NONE
165    }
166}
167
168impl RareProperties for SemanticsDetails {
169    const EMPTY: &'static Self = &Self::NONE;
170}
171
172impl SemanticsNode {
173    /// The properties few nodes set, with nothing set for a node that holds
174    /// none.
175    pub fn details(&self) -> &SemanticsDetails {
176        rare(&self.details)
177    }
178
179    /// Replaces the node's details. A node holds them only when something is
180    /// set, and keeps the space it already held for them.
181    pub fn set_details(&mut self, details: SemanticsDetails) {
182        set_rare(&mut self.details, details);
183    }
184
185    /// Changes some of the node's details in place, through
186    /// [`SemanticsNode::set_details`].
187    pub fn update_details(&mut self, update: impl FnOnce(&mut SemanticsDetails)) {
188        update_rare(&mut self.details, update);
189    }
190}