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(&mut self, id: Option<&Id>, _bounds: Rectangle, state: &mut dyn Focusable) {
36 match id {
37 Some(id) if id == &self.target => {
38 state.focus();
39 }
40 _ => {
41 state.unfocus();
42 }
43 }
44 }
45
46 fn traverse(&mut self, operate: &mut dyn FnMut(&mut dyn Operation<T>)) {
47 operate(self);
48 }
49 }
50
51 Focus { target }
52}
53
54pub fn unfocus<T>() -> impl Operation<T> {
56 struct Unfocus;
57
58 impl<T> Operation<T> for Unfocus {
59 fn focusable(&mut self, _id: Option<&Id>, _bounds: Rectangle, state: &mut dyn Focusable) {
60 state.unfocus();
61 }
62
63 fn traverse(&mut self, operate: &mut dyn FnMut(&mut dyn Operation<T>)) {
64 operate(self);
65 }
66 }
67
68 Unfocus
69}
70
71pub fn count() -> impl Operation<Count> {
74 struct CountFocusable {
75 count: Count,
76 }
77
78 impl Operation<Count> for CountFocusable {
79 fn focusable(&mut self, _id: Option<&Id>, _bounds: Rectangle, state: &mut dyn Focusable) {
80 if state.is_focused() {
81 self.count.focused = Some(self.count.total);
82 }
83
84 self.count.total += 1;
85 }
86
87 fn traverse(&mut self, operate: &mut dyn FnMut(&mut dyn Operation<Count>)) {
88 operate(self);
89 }
90
91 fn finish(&self) -> Outcome<Count> {
92 Outcome::Some(self.count)
93 }
94 }
95
96 CountFocusable {
97 count: Count::default(),
98 }
99}
100
101pub fn focus_previous<T>() -> impl Operation<T>
105where
106 T: Send + 'static,
107{
108 struct FocusPrevious {
109 count: Count,
110 current: usize,
111 }
112
113 impl<T> Operation<T> for FocusPrevious {
114 fn focusable(&mut self, _id: Option<&Id>, _bounds: Rectangle, state: &mut dyn Focusable) {
115 if self.count.total == 0 {
116 return;
117 }
118
119 match self.count.focused {
120 None if self.current == self.count.total - 1 => state.focus(),
121 Some(0) if self.current == 0 => state.unfocus(),
122 Some(0) => {}
123 Some(focused) if focused == self.current => state.unfocus(),
124 Some(focused) if focused - 1 == self.current => state.focus(),
125 _ => {}
126 }
127
128 self.current += 1;
129 }
130
131 fn traverse(&mut self, operate: &mut dyn FnMut(&mut dyn Operation<T>)) {
132 operate(self);
133 }
134 }
135
136 operation::then(count(), |count| FocusPrevious { count, current: 0 })
137}
138
139pub fn focus_next<T>() -> impl Operation<T>
143where
144 T: Send + 'static,
145{
146 struct FocusNext {
147 count: Count,
148 current: usize,
149 }
150
151 impl<T> Operation<T> for FocusNext {
152 fn focusable(&mut self, _id: Option<&Id>, _bounds: Rectangle, state: &mut dyn Focusable) {
153 match self.count.focused {
154 None if self.current == 0 => state.focus(),
155 Some(focused) if focused == self.current => state.unfocus(),
156 Some(focused) if focused + 1 == self.current => state.focus(),
157 _ => {}
158 }
159
160 self.current += 1;
161 }
162
163 fn traverse(&mut self, operate: &mut dyn FnMut(&mut dyn Operation<T>)) {
164 operate(self);
165 }
166 }
167
168 operation::then(count(), |count| FocusNext { count, current: 0 })
169}
170
171pub fn find_focused() -> impl Operation<Id> {
174 struct FindFocused {
175 focused: Option<Id>,
176 }
177
178 impl Operation<Id> for FindFocused {
179 fn focusable(&mut self, id: Option<&Id>, _bounds: Rectangle, state: &mut dyn Focusable) {
180 if state.is_focused() && id.is_some() {
181 self.focused = id.cloned();
182 }
183 }
184
185 fn traverse(&mut self, operate: &mut dyn FnMut(&mut dyn Operation<Id>)) {
186 operate(self);
187 }
188
189 fn finish(&self) -> Outcome<Id> {
190 if let Some(id) = &self.focused {
191 Outcome::Some(id.clone())
192 } else {
193 Outcome::None
194 }
195 }
196 }
197
198 FindFocused { focused: None }
199}
200
201pub fn is_focused(target: Id) -> impl Operation<bool> {
205 struct IsFocused {
206 target: Id,
207 is_focused: Option<bool>,
208 }
209
210 impl Operation<bool> for IsFocused {
211 fn focusable(&mut self, id: Option<&Id>, _bounds: Rectangle, state: &mut dyn Focusable) {
212 if id.is_some_and(|id| *id == self.target) {
213 self.is_focused = Some(state.is_focused());
214 }
215 }
216
217 fn traverse(&mut self, operate: &mut dyn FnMut(&mut dyn Operation<bool>)) {
218 if self.is_focused.is_some() {
219 return;
220 }
221
222 operate(self);
223 }
224
225 fn finish(&self) -> Outcome<bool> {
226 self.is_focused.map_or(Outcome::None, Outcome::Some)
227 }
228 }
229
230 IsFocused {
231 target,
232 is_focused: None,
233 }
234}