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(&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 cx.with_focus(focusable.focus_handle.clone(), |cx| f(cx))
156 } else {
157 f(cx)
158 }
159 }
160
161 fn refine_style(&self, style: &mut Style, cx: &WindowContext) {
162 if let Some(focusable) = self.as_focusable() {
163 if focusable.focus_handle.contains_focused(cx) {
164 style.refine(&focusable.focus_in_style);
165 }
166
167 if focusable.focus_handle.within_focused(cx) {
168 style.refine(&focusable.in_focus_style);
169 }
170
171 if focusable.focus_handle.is_focused(cx) {
172 style.refine(&focusable.focus_style);
173 }
174 }
175 }
176
177 fn paint(&self, bounds: Bounds<Pixels>, cx: &mut WindowContext) {
178 if let Some(focusable) = self.as_focusable() {
179 let focus_handle = focusable.focus_handle.clone();
180 cx.on_mouse_event(move |event: &MouseDownEvent, phase, cx| {
181 if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
182 if !cx.default_prevented() {
183 cx.focus(&focus_handle);
184 cx.prevent_default();
185 }
186 }
187 })
188 }
189 }
190}
191
192pub struct FocusEnabled<V: 'static + Send + Sync> {
193 pub focus_handle: FocusHandle,
194 pub focus_listeners: FocusListeners<V>,
195 pub focus_style: StyleRefinement,
196 pub focus_in_style: StyleRefinement,
197 pub in_focus_style: StyleRefinement,
198}
199
200impl<V> ElementFocus<V> for FocusEnabled<V>
201where
202 V: 'static + Send + Sync,
203{
204 fn as_focusable(&self) -> Option<&FocusEnabled<V>> {
205 Some(self)
206 }
207}
208
209impl<V> From<FocusHandle> for FocusEnabled<V>
210where
211 V: 'static + Send + Sync,
212{
213 fn from(value: FocusHandle) -> Self {
214 Self {
215 focus_handle: value,
216 focus_listeners: FocusListeners::default(),
217 focus_style: StyleRefinement::default(),
218 focus_in_style: StyleRefinement::default(),
219 in_focus_style: StyleRefinement::default(),
220 }
221 }
222}
223
224pub struct FocusDisabled;
225
226impl<V> ElementFocus<V> for FocusDisabled
227where
228 V: 'static + Send + Sync,
229{
230 fn as_focusable(&self) -> Option<&FocusEnabled<V>> {
231 None
232 }
233}