1use crate::{
2 Bounds, DispatchPhase, Element, FocusEvent, FocusHandle, MouseDownEvent, Pixels, Style,
3 StyleRefinement, ViewContext, WindowContext,
4};
5use refineable::Refineable;
6use smallvec::SmallVec;
7
8pub type FocusListeners<V> = SmallVec<[FocusListener<V>; 2]>;
9
10pub type FocusListener<V> =
11 Box<dyn Fn(&mut V, &FocusHandle, &FocusEvent, &mut ViewContext<V>) + Send + 'static>;
12
13pub trait Focusable<V: 'static>: Element<V> {
14 fn focus_listeners(&mut self) -> &mut FocusListeners<V>;
15 fn set_focus_style(&mut self, style: StyleRefinement);
16 fn set_focus_in_style(&mut self, style: StyleRefinement);
17 fn set_in_focus_style(&mut self, style: StyleRefinement);
18
19 fn focus(mut self, f: impl FnOnce(StyleRefinement) -> StyleRefinement) -> Self
20 where
21 Self: Sized,
22 {
23 self.set_focus_style(f(StyleRefinement::default()));
24 self
25 }
26
27 fn focus_in(mut self, f: impl FnOnce(StyleRefinement) -> StyleRefinement) -> Self
28 where
29 Self: Sized,
30 {
31 self.set_focus_in_style(f(StyleRefinement::default()));
32 self
33 }
34
35 fn in_focus(mut self, f: impl FnOnce(StyleRefinement) -> StyleRefinement) -> Self
36 where
37 Self: Sized,
38 {
39 self.set_in_focus_style(f(StyleRefinement::default()));
40 self
41 }
42
43 fn on_focus(
44 mut self,
45 listener: impl Fn(&mut V, &FocusEvent, &mut ViewContext<V>) + Send + 'static,
46 ) -> Self
47 where
48 Self: Sized,
49 {
50 self.focus_listeners()
51 .push(Box::new(move |view, focus_handle, event, cx| {
52 if event.focused.as_ref() == Some(focus_handle) {
53 listener(view, event, cx)
54 }
55 }));
56 self
57 }
58
59 fn on_blur(
60 mut self,
61 listener: impl Fn(&mut V, &FocusEvent, &mut ViewContext<V>) + Send + 'static,
62 ) -> Self
63 where
64 Self: Sized,
65 {
66 self.focus_listeners()
67 .push(Box::new(move |view, focus_handle, event, cx| {
68 if event.blurred.as_ref() == Some(focus_handle) {
69 listener(view, event, cx)
70 }
71 }));
72 self
73 }
74
75 fn on_focus_in(
76 mut self,
77 listener: impl Fn(&mut V, &FocusEvent, &mut ViewContext<V>) + Send + 'static,
78 ) -> Self
79 where
80 Self: Sized,
81 {
82 self.focus_listeners()
83 .push(Box::new(move |view, focus_handle, event, cx| {
84 let descendant_blurred = event
85 .blurred
86 .as_ref()
87 .map_or(false, |blurred| focus_handle.contains(blurred, cx));
88 let descendant_focused = event
89 .focused
90 .as_ref()
91 .map_or(false, |focused| focus_handle.contains(focused, cx));
92
93 if !descendant_blurred && descendant_focused {
94 listener(view, event, cx)
95 }
96 }));
97 self
98 }
99
100 fn on_focus_out(
101 mut self,
102 listener: impl Fn(&mut V, &FocusEvent, &mut ViewContext<V>) + Send + 'static,
103 ) -> Self
104 where
105 Self: Sized,
106 {
107 self.focus_listeners()
108 .push(Box::new(move |view, focus_handle, event, cx| {
109 let descendant_blurred = event
110 .blurred
111 .as_ref()
112 .map_or(false, |blurred| focus_handle.contains(blurred, cx));
113 let descendant_focused = event
114 .focused
115 .as_ref()
116 .map_or(false, |focused| focus_handle.contains(focused, cx));
117 if descendant_blurred && !descendant_focused {
118 listener(view, event, cx)
119 }
120 }));
121 self
122 }
123}
124
125pub trait ElementFocus<V: 'static>: 'static + Send {
126 fn as_focusable(&self) -> Option<&FocusEnabled<V>>;
127 fn as_focusable_mut(&mut self) -> Option<&mut FocusEnabled<V>>;
128
129 fn initialize<R>(
130 &mut self,
131 focus_handle: Option<FocusHandle>,
132 cx: &mut ViewContext<V>,
133 f: impl FnOnce(Option<FocusHandle>, &mut ViewContext<V>) -> R,
134 ) -> R {
135 if let Some(focusable) = self.as_focusable_mut() {
136 let focus_handle = focusable
137 .focus_handle
138 .get_or_insert_with(|| focus_handle.unwrap_or_else(|| cx.focus_handle()))
139 .clone();
140 for listener in focusable.focus_listeners.drain(..) {
141 let focus_handle = focus_handle.clone();
142 cx.on_focus_changed(move |view, event, cx| {
143 listener(view, &focus_handle, event, cx)
144 });
145 }
146 cx.with_focus(focus_handle.clone(), |cx| f(Some(focus_handle), cx))
147 } else {
148 f(None, cx)
149 }
150 }
151
152 fn refine_style(&self, style: &mut Style, cx: &WindowContext) {
153 if let Some(focusable) = self.as_focusable() {
154 let focus_handle = focusable
155 .focus_handle
156 .as_ref()
157 .expect("must call initialize before refine_style");
158 if focus_handle.contains_focused(cx) {
159 style.refine(&focusable.focus_in_style);
160 }
161
162 if focus_handle.within_focused(cx) {
163 style.refine(&focusable.in_focus_style);
164 }
165
166 if focus_handle.is_focused(cx) {
167 style.refine(&focusable.focus_style);
168 }
169 }
170 }
171
172 fn paint(&self, bounds: Bounds<Pixels>, cx: &mut WindowContext) {
173 if let Some(focusable) = self.as_focusable() {
174 let focus_handle = focusable
175 .focus_handle
176 .clone()
177 .expect("must call initialize before paint");
178 cx.on_mouse_event(move |event: &MouseDownEvent, phase, cx| {
179 if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
180 if !cx.default_prevented() {
181 cx.focus(&focus_handle);
182 cx.prevent_default();
183 }
184 }
185 })
186 }
187 }
188}
189
190pub struct FocusEnabled<V> {
191 pub focus_handle: Option<FocusHandle>,
192 pub focus_listeners: FocusListeners<V>,
193 pub focus_style: StyleRefinement,
194 pub focus_in_style: StyleRefinement,
195 pub in_focus_style: StyleRefinement,
196}
197
198impl<V> FocusEnabled<V> {
199 pub fn new() -> Self {
200 Self {
201 focus_handle: None,
202 focus_listeners: FocusListeners::default(),
203 focus_style: StyleRefinement::default(),
204 focus_in_style: StyleRefinement::default(),
205 in_focus_style: StyleRefinement::default(),
206 }
207 }
208
209 pub fn tracked(handle: &FocusHandle) -> Self {
210 Self {
211 focus_handle: Some(handle.clone()),
212 focus_listeners: FocusListeners::default(),
213 focus_style: StyleRefinement::default(),
214 focus_in_style: StyleRefinement::default(),
215 in_focus_style: StyleRefinement::default(),
216 }
217 }
218}
219
220impl<V: 'static> ElementFocus<V> for FocusEnabled<V> {
221 fn as_focusable(&self) -> Option<&FocusEnabled<V>> {
222 Some(self)
223 }
224
225 fn as_focusable_mut(&mut self) -> Option<&mut FocusEnabled<V>> {
226 Some(self)
227 }
228}
229
230impl<V> From<FocusHandle> for FocusEnabled<V> {
231 fn from(value: FocusHandle) -> Self {
232 Self {
233 focus_handle: Some(value),
234 focus_listeners: FocusListeners::default(),
235 focus_style: StyleRefinement::default(),
236 focus_in_style: StyleRefinement::default(),
237 in_focus_style: StyleRefinement::default(),
238 }
239 }
240}
241
242pub struct FocusDisabled;
243
244impl<V: 'static> ElementFocus<V> for FocusDisabled {
245 fn as_focusable(&self) -> Option<&FocusEnabled<V>> {
246 None
247 }
248
249 fn as_focusable_mut(&mut self) -> Option<&mut FocusEnabled<V>> {
250 None
251 }
252}