1use crate::core::widget::Id;
2use crate::core::widget::operation::accessible::{Accessible, Role};
3use crate::core::widget::operation::{Focusable, Scrollable, TextInput};
4use crate::core::{Rectangle, Vector};
5
6use std::any::Any;
7
8#[allow(missing_docs)]
10#[derive(Debug, Clone, PartialEq)]
11pub enum Target {
12 Container {
13 id: Option<Id>,
14 bounds: Rectangle,
15 visible_bounds: Option<Rectangle>,
16 },
17 Focusable {
18 id: Option<Id>,
19 bounds: Rectangle,
20 visible_bounds: Option<Rectangle>,
21 },
22 Scrollable {
23 id: Option<Id>,
24 bounds: Rectangle,
25 visible_bounds: Option<Rectangle>,
26 content_bounds: Rectangle,
27 translation: Vector,
28 },
29 TextInput {
30 id: Option<Id>,
31 bounds: Rectangle,
32 visible_bounds: Option<Rectangle>,
33 content: String,
34 },
35 Text {
36 id: Option<Id>,
37 bounds: Rectangle,
38 visible_bounds: Option<Rectangle>,
39 content: String,
40 },
41 Custom {
42 id: Option<Id>,
43 bounds: Rectangle,
44 visible_bounds: Option<Rectangle>,
45 },
46 Accessible {
47 id: Option<Id>,
48 bounds: Rectangle,
49 visible_bounds: Option<Rectangle>,
50 role: Role,
51 label: Option<String>,
52 description: Option<String>,
53 },
54}
55
56impl Target {
57 pub fn bounds(&self) -> Rectangle {
59 match self {
60 Target::Container { bounds, .. }
61 | Target::Focusable { bounds, .. }
62 | Target::Scrollable { bounds, .. }
63 | Target::TextInput { bounds, .. }
64 | Target::Text { bounds, .. }
65 | Target::Custom { bounds, .. }
66 | Target::Accessible { bounds, .. } => *bounds,
67 }
68 }
69
70 pub fn visible_bounds(&self) -> Option<Rectangle> {
72 match self {
73 Target::Container { visible_bounds, .. }
74 | Target::Focusable { visible_bounds, .. }
75 | Target::Scrollable { visible_bounds, .. }
76 | Target::TextInput { visible_bounds, .. }
77 | Target::Text { visible_bounds, .. }
78 | Target::Custom { visible_bounds, .. }
79 | Target::Accessible { visible_bounds, .. } => *visible_bounds,
80 }
81 }
82}
83
84impl From<Candidate<'_>> for Target {
85 fn from(candidate: Candidate<'_>) -> Self {
86 match candidate {
87 Candidate::Container {
88 id,
89 bounds,
90 visible_bounds,
91 } => Self::Container {
92 id: id.cloned(),
93 bounds,
94 visible_bounds,
95 },
96 Candidate::Focusable {
97 id,
98 bounds,
99 visible_bounds,
100 ..
101 } => Self::Focusable {
102 id: id.cloned(),
103 bounds,
104 visible_bounds,
105 },
106 Candidate::Scrollable {
107 id,
108 bounds,
109 visible_bounds,
110 content_bounds,
111 translation,
112 ..
113 } => Self::Scrollable {
114 id: id.cloned(),
115 bounds,
116 visible_bounds,
117 content_bounds,
118 translation,
119 },
120 Candidate::TextInput {
121 id,
122 bounds,
123 visible_bounds,
124 state,
125 } => Self::TextInput {
126 id: id.cloned(),
127 bounds,
128 visible_bounds,
129 content: state.text().to_owned(),
130 },
131 Candidate::Text {
132 id,
133 bounds,
134 visible_bounds,
135 content,
136 } => Self::Text {
137 id: id.cloned(),
138 bounds,
139 visible_bounds,
140 content: content.to_owned(),
141 },
142 Candidate::Custom {
143 id,
144 bounds,
145 visible_bounds,
146 ..
147 } => Self::Custom {
148 id: id.cloned(),
149 bounds,
150 visible_bounds,
151 },
152 Candidate::Accessible {
153 id,
154 bounds,
155 visible_bounds,
156 accessible,
157 } => Self::Accessible {
158 id: id.cloned(),
159 bounds,
160 visible_bounds,
161 role: accessible.role,
162 label: accessible.label.map(str::to_owned),
163 description: accessible.description.map(str::to_owned),
164 },
165 }
166 }
167}
168
169impl Bounded for Target {
170 fn bounds(&self) -> Rectangle {
171 self.bounds()
172 }
173
174 fn visible_bounds(&self) -> Option<Rectangle> {
175 self.visible_bounds()
176 }
177}
178
179#[allow(missing_docs)]
183#[derive(Clone)]
184pub enum Candidate<'a> {
185 Container {
186 id: Option<&'a Id>,
187 bounds: Rectangle,
188 visible_bounds: Option<Rectangle>,
189 },
190 Focusable {
191 id: Option<&'a Id>,
192 bounds: Rectangle,
193 visible_bounds: Option<Rectangle>,
194 state: &'a dyn Focusable,
195 },
196 Scrollable {
197 id: Option<&'a Id>,
198 bounds: Rectangle,
199 content_bounds: Rectangle,
200 visible_bounds: Option<Rectangle>,
201 translation: Vector,
202 state: &'a dyn Scrollable,
203 },
204 TextInput {
205 id: Option<&'a Id>,
206 bounds: Rectangle,
207 visible_bounds: Option<Rectangle>,
208 state: &'a dyn TextInput,
209 },
210 Text {
211 id: Option<&'a Id>,
212 bounds: Rectangle,
213 visible_bounds: Option<Rectangle>,
214 content: &'a str,
215 },
216 Custom {
217 id: Option<&'a Id>,
218 bounds: Rectangle,
219 visible_bounds: Option<Rectangle>,
220 state: &'a dyn Any,
221 },
222 Accessible {
223 id: Option<&'a Id>,
224 bounds: Rectangle,
225 visible_bounds: Option<Rectangle>,
226 accessible: &'a Accessible<'a>,
227 },
228}
229
230impl<'a> Candidate<'a> {
231 pub fn id(&self) -> Option<&'a Id> {
233 match self {
234 Candidate::Container { id, .. }
235 | Candidate::Focusable { id, .. }
236 | Candidate::Scrollable { id, .. }
237 | Candidate::TextInput { id, .. }
238 | Candidate::Text { id, .. }
239 | Candidate::Custom { id, .. }
240 | Candidate::Accessible { id, .. } => *id,
241 }
242 }
243
244 pub fn bounds(&self) -> Rectangle {
246 match self {
247 Candidate::Container { bounds, .. }
248 | Candidate::Focusable { bounds, .. }
249 | Candidate::Scrollable { bounds, .. }
250 | Candidate::TextInput { bounds, .. }
251 | Candidate::Text { bounds, .. }
252 | Candidate::Custom { bounds, .. }
253 | Candidate::Accessible { bounds, .. } => *bounds,
254 }
255 }
256
257 pub fn visible_bounds(&self) -> Option<Rectangle> {
259 match self {
260 Candidate::Container { visible_bounds, .. }
261 | Candidate::Focusable { visible_bounds, .. }
262 | Candidate::Scrollable { visible_bounds, .. }
263 | Candidate::TextInput { visible_bounds, .. }
264 | Candidate::Text { visible_bounds, .. }
265 | Candidate::Custom { visible_bounds, .. }
266 | Candidate::Accessible { visible_bounds, .. } => *visible_bounds,
267 }
268 }
269}
270
271pub trait Bounded: std::fmt::Debug {
276 fn bounds(&self) -> Rectangle;
278
279 fn visible_bounds(&self) -> Option<Rectangle>;
281}
282
283#[allow(missing_docs)]
285#[derive(Debug, Clone, PartialEq)]
286pub enum Text {
287 Raw {
288 id: Option<Id>,
289 bounds: Rectangle,
290 visible_bounds: Option<Rectangle>,
291 },
292 Input {
293 id: Option<Id>,
294 bounds: Rectangle,
295 visible_bounds: Option<Rectangle>,
296 },
297}
298
299impl Text {
300 pub fn bounds(&self) -> Rectangle {
302 match self {
303 Text::Raw { bounds, .. } | Text::Input { bounds, .. } => *bounds,
304 }
305 }
306
307 pub fn visible_bounds(&self) -> Option<Rectangle> {
309 match self {
310 Text::Raw { visible_bounds, .. } | Text::Input { visible_bounds, .. } => {
311 *visible_bounds
312 }
313 }
314 }
315}
316
317impl Bounded for Text {
318 fn bounds(&self) -> Rectangle {
319 self.bounds()
320 }
321
322 fn visible_bounds(&self) -> Option<Rectangle> {
323 self.visible_bounds()
324 }
325}
326
327#[derive(Debug, Clone, PartialEq)]
329pub struct AccessibleMatch {
330 pub id: Option<Id>,
332 pub bounds: Rectangle,
334 pub visible_bounds: Option<Rectangle>,
336 pub role: Role,
338 pub label: Option<String>,
340 pub description: Option<String>,
342}
343
344impl AccessibleMatch {
345 pub fn bounds(&self) -> Rectangle {
347 self.bounds
348 }
349
350 pub fn visible_bounds(&self) -> Option<Rectangle> {
352 self.visible_bounds
353 }
354}
355
356impl Bounded for AccessibleMatch {
357 fn bounds(&self) -> Rectangle {
358 self.bounds()
359 }
360
361 fn visible_bounds(&self) -> Option<Rectangle> {
362 self.visible_bounds()
363 }
364}