iced_core/widget/operation/
focusable.rs1use 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 traverse(&mut self, operate: &mut dyn FnMut(&mut dyn Operation<T>)) {
52 operate(self);
53 }
54 }
55
56 Focus { target }
57}
58
59pub fn unfocus<T>() -> impl Operation<T> {
61 struct Unfocus;
62
63 impl<T> Operation<T> for Unfocus {
64 fn focusable(
65 &mut self,
66 _id: Option<&Id>,
67 _bounds: Rectangle,
68 state: &mut dyn Focusable,
69 ) {
70 state.unfocus();
71 }
72
73 fn traverse(&mut self, operate: &mut dyn FnMut(&mut dyn Operation<T>)) {
74 operate(self);
75 }
76 }
77
78 Unfocus
79}
80
81pub fn count() -> impl Operation<Count> {
84 struct CountFocusable {
85 count: Count,
86 }
87
88 impl Operation<Count> for CountFocusable {
89 fn focusable(
90 &mut self,
91 _id: Option<&Id>,
92 _bounds: Rectangle,
93 state: &mut dyn Focusable,
94 ) {
95 if state.is_focused() {
96 self.count.focused = Some(self.count.total);
97 }
98
99 self.count.total += 1;
100 }
101
102 fn traverse(
103 &mut self,
104 operate: &mut dyn FnMut(&mut dyn Operation<Count>),
105 ) {
106 operate(self);
107 }
108
109 fn finish(&self) -> Outcome<Count> {
110 Outcome::Some(self.count)
111 }
112 }
113
114 CountFocusable {
115 count: Count::default(),
116 }
117}
118
119pub fn focus_previous<T>() -> impl Operation<T>
123where
124 T: Send + 'static,
125{
126 struct FocusPrevious {
127 count: Count,
128 current: usize,
129 }
130
131 impl<T> Operation<T> for FocusPrevious {
132 fn focusable(
133 &mut self,
134 _id: Option<&Id>,
135 _bounds: Rectangle,
136 state: &mut dyn Focusable,
137 ) {
138 if self.count.total == 0 {
139 return;
140 }
141
142 match self.count.focused {
143 None if self.current == self.count.total - 1 => state.focus(),
144 Some(0) if self.current == 0 => state.unfocus(),
145 Some(0) => {}
146 Some(focused) if focused == self.current => state.unfocus(),
147 Some(focused) if focused - 1 == self.current => state.focus(),
148 _ => {}
149 }
150
151 self.current += 1;
152 }
153
154 fn traverse(&mut self, operate: &mut dyn FnMut(&mut dyn Operation<T>)) {
155 operate(self);
156 }
157 }
158
159 operation::then(count(), |count| FocusPrevious { count, current: 0 })
160}
161
162pub fn focus_next<T>() -> impl Operation<T>
166where
167 T: Send + 'static,
168{
169 struct FocusNext {
170 count: Count,
171 current: usize,
172 }
173
174 impl<T> Operation<T> for FocusNext {
175 fn focusable(
176 &mut self,
177 _id: Option<&Id>,
178 _bounds: Rectangle,
179 state: &mut dyn Focusable,
180 ) {
181 match self.count.focused {
182 None if self.current == 0 => state.focus(),
183 Some(focused) if focused == self.current => state.unfocus(),
184 Some(focused) if focused + 1 == self.current => state.focus(),
185 _ => {}
186 }
187
188 self.current += 1;
189 }
190
191 fn traverse(&mut self, operate: &mut dyn FnMut(&mut dyn Operation<T>)) {
192 operate(self);
193 }
194 }
195
196 operation::then(count(), |count| FocusNext { count, current: 0 })
197}
198
199pub fn find_focused() -> impl Operation<Id> {
202 struct FindFocused {
203 focused: Option<Id>,
204 }
205
206 impl Operation<Id> for FindFocused {
207 fn focusable(
208 &mut self,
209 id: Option<&Id>,
210 _bounds: Rectangle,
211 state: &mut dyn Focusable,
212 ) {
213 if state.is_focused() && id.is_some() {
214 self.focused = id.cloned();
215 }
216 }
217
218 fn traverse(
219 &mut self,
220 operate: &mut dyn FnMut(&mut dyn Operation<Id>),
221 ) {
222 operate(self);
223 }
224
225 fn finish(&self) -> Outcome<Id> {
226 if let Some(id) = &self.focused {
227 Outcome::Some(id.clone())
228 } else {
229 Outcome::None
230 }
231 }
232 }
233
234 FindFocused { focused: None }
235}
236
237pub fn is_focused(target: Id) -> impl Operation<bool> {
241 struct IsFocused {
242 target: Id,
243 is_focused: Option<bool>,
244 }
245
246 impl Operation<bool> for IsFocused {
247 fn focusable(
248 &mut self,
249 id: Option<&Id>,
250 _bounds: Rectangle,
251 state: &mut dyn Focusable,
252 ) {
253 if id.is_some_and(|id| *id == self.target) {
254 self.is_focused = Some(state.is_focused());
255 }
256 }
257
258 fn traverse(
259 &mut self,
260 operate: &mut dyn FnMut(&mut dyn Operation<bool>),
261 ) {
262 if self.is_focused.is_some() {
263 return;
264 }
265
266 operate(self);
267 }
268
269 fn finish(&self) -> Outcome<bool> {
270 self.is_focused.map_or(Outcome::None, Outcome::Some)
271 }
272 }
273
274 IsFocused {
275 target,
276 is_focused: None,
277 }
278}