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