key_dispatch.rs

  1use crate::{
  2    build_action_from_type, Action, Bounds, DispatchPhase, Element, FocusEvent, FocusHandle,
  3    FocusId, KeyContext, KeyDownEvent, KeyMatch, Keymap, KeystrokeMatcher, MouseDownEvent, Pixels,
  4    Style, StyleRefinement, ViewContext, WindowContext,
  5};
  6use collections::HashMap;
  7use parking_lot::Mutex;
  8use refineable::Refineable;
  9use smallvec::SmallVec;
 10use std::{
 11    any::{Any, TypeId},
 12    sync::Arc,
 13};
 14use util::ResultExt;
 15
 16type KeyListener = Box<dyn Fn(&dyn Any, DispatchPhase, &mut WindowContext)>;
 17pub type FocusListeners<V> = SmallVec<[FocusListener<V>; 2]>;
 18pub type FocusListener<V> =
 19    Box<dyn Fn(&mut V, &FocusHandle, &FocusEvent, &mut ViewContext<V>) + 'static>;
 20
 21#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
 22pub struct DispatchNodeId(usize);
 23
 24pub struct KeyDispatcher {
 25    node_stack: Vec<DispatchNodeId>,
 26    context_stack: Vec<KeyContext>,
 27    nodes: Vec<DispatchNode>,
 28    focusable_node_ids: HashMap<FocusId, DispatchNodeId>,
 29    keystroke_matchers: HashMap<SmallVec<[KeyContext; 4]>, KeystrokeMatcher>,
 30    keymap: Arc<Mutex<Keymap>>,
 31}
 32
 33#[derive(Default)]
 34pub struct DispatchNode {
 35    key_listeners: SmallVec<[KeyListener; 2]>,
 36    action_listeners: SmallVec<[ActionListener; 16]>,
 37    context: KeyContext,
 38    parent: Option<DispatchNodeId>,
 39}
 40
 41struct ActionListener {
 42    action_type: TypeId,
 43    listener: Box<dyn Fn(&dyn Any, DispatchPhase, &mut WindowContext)>,
 44}
 45
 46impl KeyDispatcher {
 47    pub fn new(keymap: Arc<Mutex<Keymap>>) -> Self {
 48        Self {
 49            node_stack: Vec::new(),
 50            context_stack: Vec::new(),
 51            nodes: Vec::new(),
 52            focusable_node_ids: HashMap::default(),
 53            keystroke_matchers: HashMap::default(),
 54            keymap,
 55        }
 56    }
 57
 58    pub fn clear(&mut self) {
 59        self.node_stack.clear();
 60        self.nodes.clear();
 61    }
 62
 63    pub fn push_node(&mut self, context: KeyContext, old_dispatcher: &mut Self) {
 64        let parent = self.node_stack.last().copied();
 65        let node_id = DispatchNodeId(self.nodes.len());
 66        self.nodes.push(DispatchNode {
 67            parent,
 68            ..Default::default()
 69        });
 70        self.node_stack.push(node_id);
 71        if !context.is_empty() {
 72            self.active_node().context = context.clone();
 73            self.context_stack.push(context);
 74            if let Some((context_stack, matcher)) = old_dispatcher
 75                .keystroke_matchers
 76                .remove_entry(self.context_stack.as_slice())
 77            {
 78                self.keystroke_matchers.insert(context_stack, matcher);
 79            }
 80        }
 81    }
 82
 83    pub fn pop_node(&mut self) {
 84        let node_id = self.node_stack.pop().unwrap();
 85        if !self.nodes[node_id.0].context.is_empty() {
 86            self.context_stack.pop();
 87        }
 88    }
 89
 90    pub fn on_key_event(&mut self, listener: KeyListener) {
 91        self.active_node().key_listeners.push(listener);
 92    }
 93
 94    pub fn on_action(
 95        &mut self,
 96        action_type: TypeId,
 97        listener: Box<dyn Fn(&dyn Any, DispatchPhase, &mut WindowContext)>,
 98    ) {
 99        self.active_node().action_listeners.push(ActionListener {
100            action_type,
101            listener,
102        });
103    }
104
105    pub fn make_focusable(&mut self, focus_id: FocusId) {
106        self.focusable_node_ids
107            .insert(focus_id, self.active_node_id());
108    }
109
110    pub fn focus_contains(&self, parent: FocusId, child: FocusId) -> bool {
111        if parent == child {
112            return true;
113        }
114
115        if let Some(parent_node_id) = self.focusable_node_ids.get(&parent) {
116            let mut current_node_id = self.focusable_node_ids.get(&child).copied();
117            while let Some(node_id) = current_node_id {
118                if node_id == *parent_node_id {
119                    return true;
120                }
121                current_node_id = self.nodes[node_id.0].parent;
122            }
123        }
124        false
125    }
126
127    pub fn available_actions(&self, target: FocusId) -> Vec<Box<dyn Action>> {
128        let mut actions = Vec::new();
129        if let Some(node) = self.focusable_node_ids.get(&target) {
130            for node_id in self.dispatch_path(*node) {
131                let node = &self.nodes[node_id.0];
132                for ActionListener { action_type, .. } in &node.action_listeners {
133                    actions.extend(build_action_from_type(action_type).log_err());
134                }
135            }
136        }
137        actions
138    }
139
140    pub fn dispatch_key(&mut self, target: FocusId, event: &dyn Any, cx: &mut WindowContext) {
141        if let Some(target_node_id) = self.focusable_node_ids.get(&target).copied() {
142            self.dispatch_key_on_node(target_node_id, event, cx);
143        }
144    }
145
146    fn dispatch_key_on_node(
147        &mut self,
148        node_id: DispatchNodeId,
149        event: &dyn Any,
150        cx: &mut WindowContext,
151    ) {
152        let dispatch_path = self.dispatch_path(node_id);
153
154        // Capture phase
155        self.context_stack.clear();
156        cx.propagate_event = true;
157
158        for node_id in &dispatch_path {
159            let node = &self.nodes[node_id.0];
160            if !node.context.is_empty() {
161                self.context_stack.push(node.context.clone());
162            }
163
164            for key_listener in &node.key_listeners {
165                key_listener(event, DispatchPhase::Capture, cx);
166                if !cx.propagate_event {
167                    return;
168                }
169            }
170        }
171
172        // Bubble phase
173        for node_id in dispatch_path.iter().rev() {
174            let node = &self.nodes[node_id.0];
175
176            // Handle low level key events
177            for key_listener in &node.key_listeners {
178                key_listener(event, DispatchPhase::Bubble, cx);
179                if !cx.propagate_event {
180                    return;
181                }
182            }
183
184            // Match keystrokes
185            if !node.context.is_empty() {
186                if let Some(key_down_event) = event.downcast_ref::<KeyDownEvent>() {
187                    if !self
188                        .keystroke_matchers
189                        .contains_key(self.context_stack.as_slice())
190                    {
191                        let keystroke_contexts = self.context_stack.iter().cloned().collect();
192                        self.keystroke_matchers.insert(
193                            keystroke_contexts,
194                            KeystrokeMatcher::new(self.keymap.clone()),
195                        );
196                    }
197
198                    let keystroke_matcher = self
199                        .keystroke_matchers
200                        .get_mut(self.context_stack.as_slice())
201                        .unwrap();
202                    if let KeyMatch::Some(action) = keystroke_matcher
203                        .match_keystroke(&key_down_event.keystroke, self.context_stack.as_slice())
204                    {
205                        // Clear all pending keystrokes when an action has been found.
206                        for keystroke_matcher in self.keystroke_matchers.values_mut() {
207                            keystroke_matcher.clear_pending();
208                        }
209
210                        self.dispatch_action_on_node(*node_id, action, cx);
211                        if !cx.propagate_event {
212                            return;
213                        }
214                    }
215                }
216
217                self.context_stack.pop();
218            }
219        }
220    }
221
222    pub fn dispatch_action(
223        &self,
224        target: FocusId,
225        action: Box<dyn Action>,
226        cx: &mut WindowContext,
227    ) {
228        if let Some(target_node_id) = self.focusable_node_ids.get(&target).copied() {
229            self.dispatch_action_on_node(target_node_id, action, cx);
230        }
231    }
232
233    fn dispatch_action_on_node(
234        &self,
235        node_id: DispatchNodeId,
236        action: Box<dyn Action>,
237        cx: &mut WindowContext,
238    ) {
239        let dispatch_path = self.dispatch_path(node_id);
240
241        // Capture phase
242        for node_id in &dispatch_path {
243            let node = &self.nodes[node_id.0];
244            for ActionListener {
245                action_type,
246                listener,
247            } in &node.action_listeners
248            {
249                let any_action = action.as_any();
250                if *action_type == any_action.type_id() {
251                    listener(any_action, DispatchPhase::Capture, cx);
252                    if !cx.propagate_event {
253                        return;
254                    }
255                }
256            }
257        }
258
259        // Bubble phase
260        for node_id in dispatch_path.iter().rev() {
261            let node = &self.nodes[node_id.0];
262            for ActionListener {
263                action_type,
264                listener,
265            } in &node.action_listeners
266            {
267                let any_action = action.as_any();
268                if *action_type == any_action.type_id() {
269                    cx.propagate_event = false; // Actions stop propagation by default during the bubble phase
270                    listener(any_action, DispatchPhase::Bubble, cx);
271                    if !cx.propagate_event {
272                        return;
273                    }
274                }
275            }
276        }
277    }
278
279    fn active_node(&mut self) -> &mut DispatchNode {
280        let active_node_id = self.active_node_id();
281        &mut self.nodes[active_node_id.0]
282    }
283
284    fn active_node_id(&self) -> DispatchNodeId {
285        *self.node_stack.last().unwrap()
286    }
287
288    /// Returns the DispatchNodeIds from the root of the tree to the given target node id.
289    fn dispatch_path(&self, target: DispatchNodeId) -> SmallVec<[DispatchNodeId; 32]> {
290        let mut dispatch_path: SmallVec<[DispatchNodeId; 32]> = SmallVec::new();
291        let mut current_node_id = Some(target);
292        while let Some(node_id) = current_node_id {
293            dispatch_path.push(node_id);
294            current_node_id = self.nodes[node_id.0].parent;
295        }
296        dispatch_path.reverse(); // Reverse the path so it goes from the root to the focused node.
297        dispatch_path
298    }
299}
300
301pub trait KeyDispatch<V: 'static>: 'static {
302    fn as_focusable(&self) -> Option<&FocusableKeyDispatch<V>>;
303    fn as_focusable_mut(&mut self) -> Option<&mut FocusableKeyDispatch<V>>;
304    fn key_context(&self) -> &KeyContext;
305    fn key_context_mut(&mut self) -> &mut KeyContext;
306
307    fn initialize<R>(
308        &mut self,
309        focus_handle: Option<FocusHandle>,
310        cx: &mut ViewContext<V>,
311        f: impl FnOnce(Option<FocusHandle>, &mut ViewContext<V>) -> R,
312    ) -> R {
313        let focus_handle = if let Some(focusable) = self.as_focusable_mut() {
314            let focus_handle = focusable
315                .focus_handle
316                .get_or_insert_with(|| focus_handle.unwrap_or_else(|| cx.focus_handle()))
317                .clone();
318            for listener in focusable.focus_listeners.drain(..) {
319                let focus_handle = focus_handle.clone();
320                cx.on_focus_changed(move |view, event, cx| {
321                    listener(view, &focus_handle, event, cx)
322                });
323            }
324            Some(focus_handle)
325        } else {
326            None
327        };
328
329        cx.with_key_dispatch(self.key_context().clone(), focus_handle, f)
330    }
331
332    fn refine_style(&self, style: &mut Style, cx: &WindowContext) {
333        if let Some(focusable) = self.as_focusable() {
334            let focus_handle = focusable
335                .focus_handle
336                .as_ref()
337                .expect("must call initialize before refine_style");
338            if focus_handle.contains_focused(cx) {
339                style.refine(&focusable.focus_in_style);
340            }
341
342            if focus_handle.within_focused(cx) {
343                style.refine(&focusable.in_focus_style);
344            }
345
346            if focus_handle.is_focused(cx) {
347                style.refine(&focusable.focus_style);
348            }
349        }
350    }
351
352    fn paint(&self, bounds: Bounds<Pixels>, cx: &mut WindowContext) {
353        if let Some(focusable) = self.as_focusable() {
354            let focus_handle = focusable
355                .focus_handle
356                .clone()
357                .expect("must call initialize before paint");
358            cx.on_mouse_event(move |event: &MouseDownEvent, phase, cx| {
359                if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
360                    if !cx.default_prevented() {
361                        cx.focus(&focus_handle);
362                        cx.prevent_default();
363                    }
364                }
365            })
366        }
367    }
368}
369
370pub struct FocusableKeyDispatch<V> {
371    pub key_context: KeyContext,
372    pub focus_handle: Option<FocusHandle>,
373    pub focus_listeners: FocusListeners<V>,
374    pub focus_style: StyleRefinement,
375    pub focus_in_style: StyleRefinement,
376    pub in_focus_style: StyleRefinement,
377}
378
379impl<V> FocusableKeyDispatch<V> {
380    pub fn new() -> Self {
381        Self {
382            key_context: KeyContext::default(),
383            focus_handle: None,
384            focus_listeners: FocusListeners::default(),
385            focus_style: StyleRefinement::default(),
386            focus_in_style: StyleRefinement::default(),
387            in_focus_style: StyleRefinement::default(),
388        }
389    }
390
391    pub fn tracked(handle: &FocusHandle) -> Self {
392        Self {
393            key_context: KeyContext::default(),
394            focus_handle: Some(handle.clone()),
395            focus_listeners: FocusListeners::default(),
396            focus_style: StyleRefinement::default(),
397            focus_in_style: StyleRefinement::default(),
398            in_focus_style: StyleRefinement::default(),
399        }
400    }
401}
402
403impl<V: 'static> KeyDispatch<V> for FocusableKeyDispatch<V> {
404    fn as_focusable(&self) -> Option<&FocusableKeyDispatch<V>> {
405        Some(self)
406    }
407
408    fn as_focusable_mut(&mut self) -> Option<&mut FocusableKeyDispatch<V>> {
409        Some(self)
410    }
411
412    fn key_context(&self) -> &KeyContext {
413        &self.key_context
414    }
415
416    fn key_context_mut(&mut self) -> &mut KeyContext {
417        &mut self.key_context
418    }
419}
420
421impl<V> From<FocusHandle> for FocusableKeyDispatch<V> {
422    fn from(value: FocusHandle) -> Self {
423        Self {
424            key_context: KeyContext::default(),
425            focus_handle: Some(value),
426            focus_listeners: FocusListeners::default(),
427            focus_style: StyleRefinement::default(),
428            focus_in_style: StyleRefinement::default(),
429            in_focus_style: StyleRefinement::default(),
430        }
431    }
432}
433
434#[derive(Default)]
435pub struct NonFocusableKeyDispatch {
436    pub(crate) key_context: KeyContext,
437}
438
439impl<V: 'static> KeyDispatch<V> for NonFocusableKeyDispatch {
440    fn as_focusable(&self) -> Option<&FocusableKeyDispatch<V>> {
441        None
442    }
443
444    fn as_focusable_mut(&mut self) -> Option<&mut FocusableKeyDispatch<V>> {
445        None
446    }
447
448    fn key_context(&self) -> &KeyContext {
449        &self.key_context
450    }
451
452    fn key_context_mut(&mut self) -> &mut KeyContext {
453        &mut self.key_context
454    }
455}
456
457pub trait Focusable<V: 'static>: Element<V> {
458    fn focus_listeners(&mut self) -> &mut FocusListeners<V>;
459    fn set_focus_style(&mut self, style: StyleRefinement);
460    fn set_focus_in_style(&mut self, style: StyleRefinement);
461    fn set_in_focus_style(&mut self, style: StyleRefinement);
462
463    fn focus(mut self, f: impl FnOnce(StyleRefinement) -> StyleRefinement) -> Self
464    where
465        Self: Sized,
466    {
467        self.set_focus_style(f(StyleRefinement::default()));
468        self
469    }
470
471    fn focus_in(mut self, f: impl FnOnce(StyleRefinement) -> StyleRefinement) -> Self
472    where
473        Self: Sized,
474    {
475        self.set_focus_in_style(f(StyleRefinement::default()));
476        self
477    }
478
479    fn in_focus(mut self, f: impl FnOnce(StyleRefinement) -> StyleRefinement) -> Self
480    where
481        Self: Sized,
482    {
483        self.set_in_focus_style(f(StyleRefinement::default()));
484        self
485    }
486
487    fn on_focus(
488        mut self,
489        listener: impl Fn(&mut V, &FocusEvent, &mut ViewContext<V>) + 'static,
490    ) -> Self
491    where
492        Self: Sized,
493    {
494        self.focus_listeners()
495            .push(Box::new(move |view, focus_handle, event, cx| {
496                if event.focused.as_ref() == Some(focus_handle) {
497                    listener(view, event, cx)
498                }
499            }));
500        self
501    }
502
503    fn on_blur(
504        mut self,
505        listener: impl Fn(&mut V, &FocusEvent, &mut ViewContext<V>) + 'static,
506    ) -> Self
507    where
508        Self: Sized,
509    {
510        self.focus_listeners()
511            .push(Box::new(move |view, focus_handle, event, cx| {
512                if event.blurred.as_ref() == Some(focus_handle) {
513                    listener(view, event, cx)
514                }
515            }));
516        self
517    }
518
519    fn on_focus_in(
520        mut self,
521        listener: impl Fn(&mut V, &FocusEvent, &mut ViewContext<V>) + 'static,
522    ) -> Self
523    where
524        Self: Sized,
525    {
526        self.focus_listeners()
527            .push(Box::new(move |view, focus_handle, event, cx| {
528                let descendant_blurred = event
529                    .blurred
530                    .as_ref()
531                    .map_or(false, |blurred| focus_handle.contains(blurred, cx));
532                let descendant_focused = event
533                    .focused
534                    .as_ref()
535                    .map_or(false, |focused| focus_handle.contains(focused, cx));
536
537                if !descendant_blurred && descendant_focused {
538                    listener(view, event, cx)
539                }
540            }));
541        self
542    }
543
544    fn on_focus_out(
545        mut self,
546        listener: impl Fn(&mut V, &FocusEvent, &mut ViewContext<V>) + 'static,
547    ) -> Self
548    where
549        Self: Sized,
550    {
551        self.focus_listeners()
552            .push(Box::new(move |view, focus_handle, event, cx| {
553                let descendant_blurred = event
554                    .blurred
555                    .as_ref()
556                    .map_or(false, |blurred| focus_handle.contains(blurred, cx));
557                let descendant_focused = event
558                    .focused
559                    .as_ref()
560                    .map_or(false, |focused| focus_handle.contains(focused, cx));
561                if descendant_blurred && !descendant_focused {
562                    listener(view, event, cx)
563                }
564            }));
565        self
566    }
567}