iced_core/widget/operation/
focusable.rs
1use crate::Rectangle;
3use crate::widget::Id;
4use crate::widget::operation::{self, Operation, Outcome};
5
6pub trait Focusable {
8 fn is_focused(&self) -> bool;
10
11 fn focus(&mut self);
13
14 fn unfocus(&mut self);
16}
17
18#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
20pub struct Count {
21 pub focused: Option<usize>,
23
24 pub total: usize,
26}
27
28pub fn focus<T>(target: Id) -> impl Operation<T> {
30 struct Focus {
31 target: Id,
32 }
33
34 impl<T> Operation<T> for Focus {
35 fn focusable(
36 &mut self,
37 id: Option<&Id>,
38 _bounds: Rectangle,
39 state: &mut dyn Focusable,
40 ) {
41 match id {
42 Some(id) if id == &self.target => {
43 state.focus();
44 }
45 _ => {
46 state.unfocus();
47 }
48 }
49 }
50
51 fn container(
52 &mut self,
53 _id: Option<&Id>,
54 _bounds: Rectangle,
55 operate_on_children: &mut dyn FnMut(&mut dyn Operation<T>),
56 ) {
57 operate_on_children(self);
58 }
59 }
60
61 Focus { target }
62}
63
64pub fn unfocus<T>() -> impl Operation<T> {
66 struct Unfocus;
67
68 impl<T> Operation<T> for Unfocus {
69 fn focusable(
70 &mut self,
71 _id: Option<&Id>,
72 _bounds: Rectangle,
73 state: &mut dyn Focusable,
74 ) {
75 state.unfocus();
76 }
77
78 fn container(
79 &mut self,
80 _id: Option<&Id>,
81 _bounds: Rectangle,
82 operate_on_children: &mut dyn FnMut(&mut dyn Operation<T>),
83 ) {
84 operate_on_children(self);
85 }
86 }
87
88 Unfocus
89}
90
91pub fn count() -> impl Operation<Count> {
94 struct CountFocusable {
95 count: Count,
96 }
97
98 impl Operation<Count> for CountFocusable {
99 fn focusable(
100 &mut self,
101 _id: Option<&Id>,
102 _bounds: Rectangle,
103 state: &mut dyn Focusable,
104 ) {
105 if state.is_focused() {
106 self.count.focused = Some(self.count.total);
107 }
108
109 self.count.total += 1;
110 }
111
112 fn container(
113 &mut self,
114 _id: Option<&Id>,
115 _bounds: Rectangle,
116 operate_on_children: &mut dyn FnMut(&mut dyn Operation<Count>),
117 ) {
118 operate_on_children(self);
119 }
120
121 fn finish(&self) -> Outcome<Count> {
122 Outcome::Some(self.count)
123 }
124 }
125
126 CountFocusable {
127 count: Count::default(),
128 }
129}
130
131pub fn focus_previous<T>() -> impl Operation<T>
135where
136 T: Send + 'static,
137{
138 struct FocusPrevious {
139 count: Count,
140 current: usize,
141 }
142
143 impl<T> Operation<T> for FocusPrevious {
144 fn focusable(
145 &mut self,
146 _id: Option<&Id>,
147 _bounds: Rectangle,
148 state: &mut dyn Focusable,
149 ) {
150 if self.count.total == 0 {
151 return;
152 }
153
154 match self.count.focused {
155 None if self.current == self.count.total - 1 => state.focus(),
156 Some(0) if self.current == 0 => state.unfocus(),
157 Some(0) => {}
158 Some(focused) if focused == self.current => state.unfocus(),
159 Some(focused) if focused - 1 == self.current => state.focus(),
160 _ => {}
161 }
162
163 self.current += 1;
164 }
165
166 fn container(
167 &mut self,
168 _id: Option<&Id>,
169 _bounds: Rectangle,
170 operate_on_children: &mut dyn FnMut(&mut dyn Operation<T>),
171 ) {
172 operate_on_children(self);
173 }
174 }
175
176 operation::then(count(), |count| FocusPrevious { count, current: 0 })
177}
178
179pub fn focus_next<T>() -> impl Operation<T>
183where
184 T: Send + 'static,
185{
186 struct FocusNext {
187 count: Count,
188 current: usize,
189 }
190
191 impl<T> Operation<T> for FocusNext {
192 fn focusable(
193 &mut self,
194 _id: Option<&Id>,
195 _bounds: Rectangle,
196 state: &mut dyn Focusable,
197 ) {
198 match self.count.focused {
199 None if self.current == 0 => state.focus(),
200 Some(focused) if focused == self.current => state.unfocus(),
201 Some(focused) if focused + 1 == self.current => state.focus(),
202 _ => {}
203 }
204
205 self.current += 1;
206 }
207
208 fn container(
209 &mut self,
210 _id: Option<&Id>,
211 _bounds: Rectangle,
212 operate_on_children: &mut dyn FnMut(&mut dyn Operation<T>),
213 ) {
214 operate_on_children(self);
215 }
216 }
217
218 operation::then(count(), |count| FocusNext { count, current: 0 })
219}
220
221pub fn find_focused() -> impl Operation<Id> {
224 struct FindFocused {
225 focused: Option<Id>,
226 }
227
228 impl Operation<Id> for FindFocused {
229 fn focusable(
230 &mut self,
231 id: Option<&Id>,
232 _bounds: Rectangle,
233 state: &mut dyn Focusable,
234 ) {
235 if state.is_focused() && id.is_some() {
236 self.focused = id.cloned();
237 }
238 }
239
240 fn container(
241 &mut self,
242 _id: Option<&Id>,
243 _bounds: Rectangle,
244 operate_on_children: &mut dyn FnMut(&mut dyn Operation<Id>),
245 ) {
246 operate_on_children(self);
247 }
248
249 fn finish(&self) -> Outcome<Id> {
250 if let Some(id) = &self.focused {
251 Outcome::Some(id.clone())
252 } else {
253 Outcome::None
254 }
255 }
256 }
257
258 FindFocused { focused: None }
259}
260
261pub fn is_focused(target: Id) -> impl Operation<bool> {
265 struct IsFocused {
266 target: Id,
267 is_focused: Option<bool>,
268 }
269
270 impl Operation<bool> for IsFocused {
271 fn focusable(
272 &mut self,
273 id: Option<&Id>,
274 _bounds: Rectangle,
275 state: &mut dyn Focusable,
276 ) {
277 if id.is_some_and(|id| *id == self.target) {
278 self.is_focused = Some(state.is_focused());
279 }
280 }
281
282 fn container(
283 &mut self,
284 _id: Option<&Id>,
285 _bounds: Rectangle,
286 operate_on_children: &mut dyn FnMut(&mut dyn Operation<bool>),
287 ) {
288 if self.is_focused.is_some() {
289 return;
290 }
291
292 operate_on_children(self);
293 }
294
295 fn finish(&self) -> Outcome<bool> {
296 self.is_focused.map_or(Outcome::None, Outcome::Some)
297 }
298 }
299
300 IsFocused {
301 target,
302 is_focused: None,
303 }
304}