1use iced_core as core;
3
4mod find;
5mod target;
6
7pub use find::{Find, FindAll};
8pub use target::{Bounded, Candidate, Target, Text};
9
10use crate::core::Point;
11use crate::core::widget;
12
13pub trait Selector {
15 type Output;
25
26 fn select(&mut self, candidate: Candidate<'_>) -> Option<Self::Output>;
30
31 fn description(&self) -> String;
33
34 fn find(self) -> Find<Self>
37 where
38 Self: Sized,
39 {
40 Find::new(find::One::new(self))
41 }
42
43 fn find_all(self) -> FindAll<Self>
46 where
47 Self: Sized,
48 {
49 FindAll::new(find::All::new(self))
50 }
51}
52
53impl Selector for &str {
54 type Output = target::Text;
55
56 fn select(&mut self, candidate: Candidate<'_>) -> Option<Self::Output> {
57 match candidate {
58 Candidate::TextInput {
59 id,
60 bounds,
61 visible_bounds,
62 state,
63 } if state.text() == *self => Some(target::Text::Input {
64 id: id.cloned(),
65 bounds,
66 visible_bounds,
67 }),
68 Candidate::Text {
69 id,
70 bounds,
71 visible_bounds,
72 content,
73 } if content == *self => Some(target::Text::Raw {
74 id: id.cloned(),
75 bounds,
76 visible_bounds,
77 }),
78 _ => None,
79 }
80 }
81
82 fn description(&self) -> String {
83 format!("text == {self:?}")
84 }
85}
86
87impl Selector for String {
88 type Output = target::Text;
89
90 fn select(&mut self, candidate: Candidate<'_>) -> Option<Self::Output> {
91 self.as_str().select(candidate)
92 }
93
94 fn description(&self) -> String {
95 self.as_str().description()
96 }
97}
98
99impl Selector for widget::Id {
100 type Output = Target;
101
102 fn select(&mut self, candidate: Candidate<'_>) -> Option<Self::Output> {
103 if candidate.id() != Some(self) {
104 return None;
105 }
106
107 Some(Target::from(candidate))
108 }
109
110 fn description(&self) -> String {
111 format!("id == {self:?}")
112 }
113}
114
115impl Selector for Point {
116 type Output = Target;
117
118 fn select(&mut self, candidate: Candidate<'_>) -> Option<Self::Output> {
119 candidate
120 .visible_bounds()
121 .is_some_and(|visible_bounds| visible_bounds.contains(*self))
122 .then(|| Target::from(candidate))
123 }
124
125 fn description(&self) -> String {
126 format!("bounds contains {self:?}")
127 }
128}
129
130impl<F, T> Selector for F
131where
132 F: FnMut(Candidate<'_>) -> Option<T>,
133{
134 type Output = T;
135
136 fn select(&mut self, candidate: Candidate<'_>) -> Option<Self::Output> {
137 (self)(candidate)
138 }
139
140 fn description(&self) -> String {
141 format!("custom selector: {}", std::any::type_name_of_val(self))
142 }
143}
144
145pub fn id(id: impl Into<widget::Id>) -> impl Selector<Output = Target> {
147 id.into()
148}
149
150pub fn is_focused() -> impl Selector<Output = Target> {
152 struct IsFocused;
153
154 impl Selector for IsFocused {
155 type Output = Target;
156
157 fn select(&mut self, candidate: Candidate<'_>) -> Option<Self::Output> {
158 if let Candidate::Focusable { state, .. } = candidate
159 && state.is_focused()
160 {
161 Some(Target::from(candidate))
162 } else {
163 None
164 }
165 }
166
167 fn description(&self) -> String {
168 "is focused".to_owned()
169 }
170 }
171
172 IsFocused
173}