focusable.rs

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