Checkpoint

Nathan Sobo created

Change summary

crates/gpui2/src/elements/node.rs  | 94 +++++++++++++------------------
crates/ui2/src/components/modal.rs |  2 
2 files changed, 41 insertions(+), 55 deletions(-)

Detailed changes

crates/gpui2/src/elements/node.rs 🔗

@@ -1,9 +1,9 @@
 use crate::{
     point, px, Action, AnyDrag, AnyElement, AnyTooltip, AnyView, AppContext, BorrowAppContext,
-    BorrowWindow, Bounds, ClickEvent, DispatchPhase, Element, ElementId, FocusHandle, KeyContext,
-    KeyDownEvent, KeyUpEvent, LayoutId, MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent,
-    Pixels, Point, Render, ScrollWheelEvent, SharedString, Size, Style, StyleRefinement, Styled,
-    Task, View, ViewContext, Visibility,
+    BorrowWindow, Bounds, ClickEvent, DispatchPhase, Element, ElementId, FocusEvent, FocusHandle,
+    KeyContext, KeyDownEvent, KeyUpEvent, LayoutId, MouseButton, MouseDownEvent, MouseMoveEvent,
+    MouseUpEvent, Pixels, Point, Render, ScrollWheelEvent, SharedString, Size, Style,
+    StyleRefinement, Styled, Task, View, ViewContext, Visibility,
 };
 use collections::HashMap;
 use parking_lot::Mutex;
@@ -371,14 +371,12 @@ pub trait StatefulInteractiveComponent<V: 'static, E: Element<V>>: InteractiveCo
     }
 }
 
-pub trait FocusableComponent<V> {
-    fn focusability(&mut self) -> &mut Focusability<V>;
-
+pub trait FocusableComponent<V: 'static>: InteractiveComponent<V> {
     fn focus(mut self, f: impl FnOnce(StyleRefinement) -> StyleRefinement) -> Self
     where
         Self: Sized,
     {
-        self.focusability().focus_style = f(StyleRefinement::default());
+        self.interactivity().focus_style = f(StyleRefinement::default());
         self
     }
 
@@ -386,7 +384,7 @@ pub trait FocusableComponent<V> {
     where
         Self: Sized,
     {
-        self.focusability().focus_in_style = f(StyleRefinement::default());
+        self.interactivity().focus_in_style = f(StyleRefinement::default());
         self
     }
 
@@ -394,7 +392,7 @@ pub trait FocusableComponent<V> {
     where
         Self: Sized,
     {
-        self.focusability().in_focus_style = f(StyleRefinement::default());
+        self.interactivity().in_focus_style = f(StyleRefinement::default());
         self
     }
 
@@ -405,13 +403,13 @@ pub trait FocusableComponent<V> {
     where
         Self: Sized,
     {
-        self.focusability()
-            .focus_listeners
-            .push(Box::new(move |view, focus_handle, event, cx| {
+        self.interactivity().focus_listeners.push(Box::new(
+            move |view, focus_handle, event, cx| {
                 if event.focused.as_ref() == Some(focus_handle) {
                     listener(view, event, cx)
                 }
-            }));
+            },
+        ));
         self
     }
 
@@ -422,13 +420,13 @@ pub trait FocusableComponent<V> {
     where
         Self: Sized,
     {
-        self.focusability()
-            .focus_listeners
-            .push(Box::new(move |view, focus_handle, event, cx| {
+        self.interactivity().focus_listeners.push(Box::new(
+            move |view, focus_handle, event, cx| {
                 if event.blurred.as_ref() == Some(focus_handle) {
                     listener(view, event, cx)
                 }
-            }));
+            },
+        ));
         self
     }
 
@@ -439,9 +437,8 @@ pub trait FocusableComponent<V> {
     where
         Self: Sized,
     {
-        self.focusability()
-            .focus_listeners
-            .push(Box::new(move |view, focus_handle, event, cx| {
+        self.interactivity().focus_listeners.push(Box::new(
+            move |view, focus_handle, event, cx| {
                 let descendant_blurred = event
                     .blurred
                     .as_ref()
@@ -454,7 +451,8 @@ pub trait FocusableComponent<V> {
                 if !descendant_blurred && descendant_focused {
                     listener(view, event, cx)
                 }
-            }));
+            },
+        ));
         self
     }
 
@@ -465,9 +463,8 @@ pub trait FocusableComponent<V> {
     where
         Self: Sized,
     {
-        self.focusability()
-            .focus_listeners
-            .push(Box::new(move |view, focus_handle, event, cx| {
+        self.interactivity().focus_listeners.push(Box::new(
+            move |view, focus_handle, event, cx| {
                 let descendant_blurred = event
                     .blurred
                     .as_ref()
@@ -479,7 +476,8 @@ pub trait FocusableComponent<V> {
                 if descendant_blurred && !descendant_focused {
                     listener(view, event, cx)
                 }
-            }));
+            },
+        ));
         self
     }
 }
@@ -525,11 +523,6 @@ pub type KeyUpListener<V> =
 pub type ActionListener<V> =
     Box<dyn Fn(&mut V, &dyn Any, DispatchPhase, &mut ViewContext<V>) + 'static>;
 
-pub struct FocusEvent {
-    pub blurred: Option<FocusHandle>,
-    pub focused: Option<FocusHandle>,
-}
-
 pub struct Node<V> {
     interactivity: Interactivity<V>,
     children: Vec<AnyElement<V>>,
@@ -658,8 +651,9 @@ pub struct NodeState {
 pub struct Interactivity<V> {
     element_id: Option<ElementId>,
     key_context: KeyContext,
-    tracked_focus_handle: Option<FocusHandle>,
     focusable: bool,
+    tracked_focus_handle: Option<FocusHandle>,
+    focus_listeners: FocusListeners<V>,
     scroll_offset: Point<Pixels>,
     group: Option<SharedString>,
     base_style: StyleRefinement,
@@ -1007,7 +1001,7 @@ where
         cx.with_element_id(self.element_id.clone(), |cx| {
             cx.with_key_dispatch(
                 self.key_context.clone(),
-                self.tracked_focus_handle.clone(),
+                element_state.focus_handle.clone(),
                 |_, cx| {
                     for listener in self.key_down_listeners.drain(..) {
                         cx.on_key_event(move |state, event: &KeyDownEvent, phase, cx| {
@@ -1025,6 +1019,15 @@ where
                         cx.on_action(action_type, listener)
                     }
 
+                    if let Some(focus_handle) = element_state.focus_handle.as_ref() {
+                        for listener in self.focus_listeners.drain(..) {
+                            let focus_handle = focus_handle.clone();
+                            cx.on_focus_changed(move |view, event, cx| {
+                                listener(view, &focus_handle, event, cx)
+                            });
+                        }
+                    }
+
                     f(style, self.scroll_offset, cx)
                 },
             );
@@ -1114,7 +1117,9 @@ impl<V: 'static> Default for Interactivity<V> {
         Self {
             element_id: None,
             key_context: KeyContext::default(),
+            focusable: false,
             tracked_focus_handle: None,
+            focus_listeners: SmallVec::default(),
             scroll_offset: Point::default(),
             group: None,
             base_style: StyleRefinement::default(),
@@ -1139,7 +1144,6 @@ impl<V: 'static> Default for Interactivity<V> {
             drag_listener: None,
             hover_listener: None,
             tooltip_builder: None,
-            focusable: false,
         }
     }
 }
@@ -1199,24 +1203,11 @@ impl GroupBounds {
 }
 
 pub struct Focusable<V, E> {
-    focusability: Focusability<V>,
     view_type: PhantomData<V>,
     element: E,
 }
 
-pub struct Focusability<V> {
-    focus_handle: Option<FocusHandle>,
-    focus_listeners: FocusListeners<V>,
-    focus_style: StyleRefinement,
-    focus_in_style: StyleRefinement,
-    in_focus_style: StyleRefinement,
-}
-
-impl<V, E> FocusableComponent<V> for Focusable<V, E> {
-    fn focusability(&mut self) -> &mut Focusability<V> {
-        &mut self.focusability
-    }
-}
+impl<V: 'static, E: InteractiveComponent<V>> FocusableComponent<V> for Focusable<V, E> {}
 
 impl<V, E> InteractiveComponent<V> for Focusable<V, E>
 where
@@ -1274,7 +1265,6 @@ where
 }
 
 pub struct Stateful<V, E> {
-    id: SharedString,
     view_type: PhantomData<V>,
     element: E,
 }
@@ -1297,11 +1287,7 @@ where
     }
 }
 
-impl<V, E: FocusableComponent<V>> FocusableComponent<V> for Stateful<V, E> {
-    fn focusability(&mut self) -> &mut Focusability<V> {
-        self.element.focusability()
-    }
-}
+impl<V: 'static, E: FocusableComponent<V>> FocusableComponent<V> for Stateful<V, E> {}
 
 impl<V, E> Element<V> for Stateful<V, E>
 where

crates/ui2/src/components/modal.rs 🔗

@@ -1,4 +1,4 @@
-use gpui::{AnyElement, Pixels};
+use gpui::AnyElement;
 use smallvec::SmallVec;
 
 use crate::{h_stack, prelude::*, v_stack, Button, Icon, IconButton, Label};