WIP

Conrad Irwin created

Change summary

crates/gpui2/src/elements/div.rs | 134 +++++++++++++++++----------------
crates/gpui2/src/gpui2.rs        |  24 ------
crates/gpui2/src/interactive.rs  |   2 
crates/gpui2/src/window.rs       |  33 ++++----
4 files changed, 87 insertions(+), 106 deletions(-)

Detailed changes

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

@@ -1,10 +1,9 @@
 use crate::{
     point, px, Action, AnyDrag, AnyElement, AnyTooltip, AnyView, AppContext, BorrowAppContext,
-    BorrowWindow, Bounds, CallbackHandle, ClickEvent, ConstructorHandle, DispatchPhase, Element,
-    ElementId, FocusEvent, FocusHandle, KeyContext, KeyDownEvent, KeyUpEvent, LayoutId,
-    MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, ParentElement, Pixels, Point,
-    Render, RenderOnce, ScrollWheelEvent, SharedString, Size, Style, StyleRefinement, Styled, Task,
-    View, Visibility, WindowContext,
+    BorrowWindow, Bounds, ClickEvent, DispatchPhase, Element, ElementId, FocusEvent, FocusHandle,
+    KeyContext, KeyDownEvent, KeyUpEvent, LayoutId, MouseButton, MouseDownEvent, MouseMoveEvent,
+    MouseUpEvent, ParentElement, Pixels, Point, Render, RenderOnce, ScrollWheelEvent, SharedString,
+    Size, Style, StyleRefinement, Styled, Task, View, Visibility, WindowContext,
 };
 use collections::HashMap;
 use refineable::Refineable;
@@ -79,28 +78,29 @@ pub trait InteractiveElement: Sized + Element {
     fn on_mouse_down(
         mut self,
         button: MouseButton,
-        handler: impl Into<CallbackHandle<MouseDownEvent>>,
+        listener: impl Fn(&MouseDownEvent, &mut WindowContext) + 'static,
     ) -> Self {
-        let handler = handler.into();
         self.interactivity().mouse_down_listeners.push(Box::new(
             move |event, bounds, phase, cx| {
                 if phase == DispatchPhase::Bubble
                     && event.button == button
                     && bounds.contains_point(&event.position)
                 {
-                    (handler.callback)(event, cx)
+                    (listener)(event, cx)
                 }
             },
         ));
         self
     }
 
-    fn on_any_mouse_down(mut self, handler: impl Into<CallbackHandle<MouseDownEvent>>) -> Self {
-        let handler = handler.into();
+    fn on_any_mouse_down(
+        mut self,
+        listener: impl Fn(&MouseDownEvent, &mut WindowContext) + 'static,
+    ) -> Self {
         self.interactivity().mouse_down_listeners.push(Box::new(
             move |event, bounds, phase, cx| {
                 if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
-                    (handler.callback)(event, cx)
+                    (listener)(event, cx)
                 }
             },
         ));
@@ -110,9 +110,8 @@ pub trait InteractiveElement: Sized + Element {
     fn on_mouse_up(
         mut self,
         button: MouseButton,
-        handler: impl Into<CallbackHandle<MouseUpEvent>>,
+        listener: impl Fn(&MouseUpEvent, &mut WindowContext) + 'static,
     ) -> Self {
-        let handler = handler.into();
         self.interactivity()
             .mouse_up_listeners
             .push(Box::new(move |event, bounds, phase, cx| {
@@ -120,30 +119,34 @@ pub trait InteractiveElement: Sized + Element {
                     && event.button == button
                     && bounds.contains_point(&event.position)
                 {
-                    (handler.callback)(event, cx)
+                    (listener)(event, cx)
                 }
             }));
         self
     }
 
-    fn on_any_mouse_up(mut self, handler: impl Into<CallbackHandle<MouseUpEvent>>) -> Self {
-        let handler = handler.into();
+    fn on_any_mouse_up(
+        mut self,
+        listener: impl Fn(&MouseUpEvent, &mut WindowContext) + 'static,
+    ) -> Self {
         self.interactivity()
             .mouse_up_listeners
             .push(Box::new(move |event, bounds, phase, cx| {
                 if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
-                    (handler.callback)(event, cx)
+                    (listener)(event, cx)
                 }
             }));
         self
     }
 
-    fn on_mouse_down_out(mut self, handler: impl Into<CallbackHandle<MouseDownEvent>>) -> Self {
-        let handler = handler.into();
+    fn on_mouse_down_out(
+        mut self,
+        listener: impl Fn(&MouseDownEvent, &mut WindowContext) + 'static,
+    ) -> Self {
         self.interactivity().mouse_down_listeners.push(Box::new(
             move |event, bounds, phase, cx| {
                 if phase == DispatchPhase::Capture && !bounds.contains_point(&event.position) {
-                    (handler.callback)(event, cx)
+                    (listener)(event, cx)
                 }
             },
         ));
@@ -153,9 +156,8 @@ pub trait InteractiveElement: Sized + Element {
     fn on_mouse_up_out(
         mut self,
         button: MouseButton,
-        handler: impl Into<CallbackHandle<MouseUpEvent>>,
+        listener: impl Fn(&MouseUpEvent, &mut WindowContext) + 'static,
     ) -> Self {
-        let handler = handler.into();
         self.interactivity()
             .mouse_up_listeners
             .push(Box::new(move |event, bounds, phase, cx| {
@@ -163,30 +165,34 @@ pub trait InteractiveElement: Sized + Element {
                     && event.button == button
                     && !bounds.contains_point(&event.position)
                 {
-                    (handler.callback)(event, cx);
+                    (listener)(event, cx);
                 }
             }));
         self
     }
 
-    fn on_mouse_move(mut self, handler: impl Into<CallbackHandle<MouseMoveEvent>>) -> Self {
-        let handler = handler.into();
+    fn on_mouse_move(
+        mut self,
+        listener: impl Fn(&MouseMoveEvent, &mut WindowContext) + 'static,
+    ) -> Self {
         self.interactivity().mouse_move_listeners.push(Box::new(
             move |event, bounds, phase, cx| {
                 if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
-                    (handler.callback)(event, cx);
+                    (listener)(event, cx);
                 }
             },
         ));
         self
     }
 
-    fn on_scroll_wheel(mut self, handler: impl Into<CallbackHandle<ScrollWheelEvent>>) -> Self {
-        let handler = handler.into();
+    fn on_scroll_wheel(
+        mut self,
+        listener: impl Fn(&ScrollWheelEvent, &mut WindowContext) + 'static,
+    ) -> Self {
         self.interactivity().scroll_wheel_listeners.push(Box::new(
             move |event, bounds, phase, cx| {
                 if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
-                    (handler.callback)(event, cx);
+                    (listener)(event, cx);
                 }
             },
         ));
@@ -194,14 +200,16 @@ pub trait InteractiveElement: Sized + Element {
     }
 
     /// Capture the given action, before normal action dispatch can fire
-    fn capture_action<A: Action>(mut self, listener: impl Into<CallbackHandle<A>>) -> Self {
-        let listener = listener.into();
+    fn capture_action<A: Action>(
+        mut self,
+        listener: impl Fn(&A, &mut WindowContext) + 'static,
+    ) -> Self {
         self.interactivity().action_listeners.push((
             TypeId::of::<A>(),
             Box::new(move |action, phase, cx| {
                 let action = action.downcast_ref().unwrap();
                 if phase == DispatchPhase::Capture {
-                    (listener.callback)(action, cx)
+                    (listener)(action, cx)
                 }
             }),
         ));
@@ -209,8 +217,7 @@ pub trait InteractiveElement: Sized + Element {
     }
 
     /// Add a listener for the given action, fires during the bubble event phase
-    fn on_action<A: Action>(mut self, listener: impl Into<CallbackHandle<A>> + 'static) -> Self {
-        let handle = listener.into();
+    fn on_action<A: Action>(mut self, listener: impl Fn(&A, &mut WindowContext) + 'static) -> Self {
         // NOTE: this debug assert has the side-effect of working around
         // a bug where a crate consisting only of action definitions does
         // not register the actions in debug builds:
@@ -230,27 +237,31 @@ pub trait InteractiveElement: Sized + Element {
             Box::new(move |action, phase, cx| {
                 let action = action.downcast_ref().unwrap();
                 if phase == DispatchPhase::Bubble {
-                    (handle.callback)(action, cx)
+                    (listener)(action, cx)
                 }
             }),
         ));
         self
     }
 
-    fn on_key_down(mut self, listener: impl Into<CallbackHandle<KeyDownEvent>>) -> Self {
-        let listener = listener.into();
+    fn on_key_down(
+        mut self,
+        listener: impl Fn(&KeyDownEvent, &mut WindowContext) + 'static,
+    ) -> Self {
         self.interactivity()
             .key_down_listeners
             .push(Box::new(move |event, phase, cx| {
                 if phase == DispatchPhase::Bubble {
-                    (listener.callback)(event, cx)
+                    (listener)(event, cx)
                 }
             }));
         self
     }
 
-    fn capture_key_down(mut self, listener: impl Into<CallbackHandle<KeyDownEvent>>) -> Self {
-        let listener = listener.into();
+    fn capture_key_down(
+        mut self,
+        listener: impl Fn(&KeyDownEvent, &mut WindowContext) + 'static,
+    ) -> Self {
         self.interactivity()
             .key_down_listeners
             .push(Box::new(move |event, phase, cx| {
@@ -261,8 +272,7 @@ pub trait InteractiveElement: Sized + Element {
         self
     }
 
-    fn on_key_up(mut self, listener: impl Into<CallbackHandle<KeyUpEvent>>) -> Self {
-        let listener = listener.into();
+    fn on_key_up(mut self, listener: impl Fn(&KeyUpEvent, &mut WindowContext) + 'static) -> Self {
         self.interactivity()
             .key_up_listeners
             .push(Box::new(move |event, phase, cx| {
@@ -273,8 +283,10 @@ pub trait InteractiveElement: Sized + Element {
         self
     }
 
-    fn capture_key_up(mut self, listener: impl Into<CallbackHandle<KeyUpEvent>>) -> Self {
-        let listener = listener.into();
+    fn capture_key_up(
+        mut self,
+        listener: impl Fn(&KeyUpEvent, &mut WindowContext) + 'static,
+    ) -> Self {
         self.interactivity()
             .key_up_listeners
             .push(Box::new(move |event, phase, cx| {
@@ -307,8 +319,10 @@ pub trait InteractiveElement: Sized + Element {
         self
     }
 
-    fn on_drop<W: 'static>(mut self, listener: impl Into<CallbackHandle<View<W>>>) -> Self {
-        let listener = listener.into();
+    fn on_drop<W: 'static>(
+        mut self,
+        listener: impl Fn(&View<W>, &mut WindowContext) + 'static,
+    ) -> Self {
         self.interactivity().drop_listeners.push((
             TypeId::of::<W>(),
             Box::new(move |dragged_view, cx| {
@@ -364,23 +378,21 @@ pub trait StatefulInteractiveElement: InteractiveElement {
         self
     }
 
-    fn on_click(mut self, listener: impl Into<CallbackHandle<ClickEvent>>) -> Self
+    fn on_click(mut self, listener: impl Fn(&ClickEvent, &mut WindowContext) + 'static) -> Self
     where
         Self: Sized,
     {
-        let listener = listener.into();
         self.interactivity()
             .click_listeners
             .push(Box::new(move |event, cx| (listener.callback)(event, cx)));
         self
     }
 
-    fn on_drag<W>(mut self, listener: impl Into<ConstructorHandle<View<W>>>) -> Self
+    fn on_drag<W>(mut self, listener: impl Fn(&mut WindowContext) -> View<W> + 'static) -> Self
     where
         Self: Sized,
         W: 'static + Render,
     {
-        let listener = listener.into();
         debug_assert!(
             self.interactivity().drag_listener.is_none(),
             "calling on_drag more than once on the same element is not supported"
@@ -392,24 +404,22 @@ pub trait StatefulInteractiveElement: InteractiveElement {
         self
     }
 
-    fn on_hover(mut self, listener: impl Into<CallbackHandle<bool>>) -> Self
+    fn on_hover(mut self, listener: impl Fn(&bool, &mut WindowContext) + 'static) -> Self
     where
         Self: Sized,
     {
-        let listener = listener.into();
         debug_assert!(
             self.interactivity().hover_listener.is_none(),
             "calling on_hover more than once on the same element is not supported"
         );
-        self.interactivity().hover_listener = Some(listener);
+        self.interactivity().hover_listener = Some(Box::new(listener));
         self
     }
 
-    fn tooltip(mut self, build_tooltip: impl Into<ConstructorHandle<AnyView>>) -> Self
+    fn tooltip(mut self, build_tooltip: impl Fn(&mut WindowContext) -> AnyView + 'static) -> Self
     where
         Self: Sized,
     {
-        let build_tooltip = build_tooltip.into();
         debug_assert!(
             self.interactivity().tooltip_builder.is_none(),
             "calling tooltip more than once on the same element is not supported"
@@ -438,11 +448,10 @@ pub trait FocusableElement: InteractiveElement {
         self
     }
 
-    fn on_focus(mut self, listener: impl Into<CallbackHandle<FocusEvent>>) -> Self
+    fn on_focus(mut self, listener: impl Fn(&FocusEvent, &mut WindowContext) + 'static) -> Self
     where
         Self: Sized,
     {
-        let listener = listener.into();
         self.interactivity()
             .focus_listeners
             .push(Box::new(move |focus_handle, event, cx| {
@@ -453,11 +462,10 @@ pub trait FocusableElement: InteractiveElement {
         self
     }
 
-    fn on_blur(mut self, listener: impl Into<CallbackHandle<FocusEvent>>) -> Self
+    fn on_blur(mut self, listener: impl Fn(&FocusEvent, &mut WindowContext) + 'static) -> Self
     where
         Self: Sized,
     {
-        let listener = listener.into();
         self.interactivity()
             .focus_listeners
             .push(Box::new(move |focus_handle, event, cx| {
@@ -468,11 +476,10 @@ pub trait FocusableElement: InteractiveElement {
         self
     }
 
-    fn on_focus_in(mut self, listener: impl Into<CallbackHandle<FocusEvent>>) -> Self
+    fn on_focus_in(mut self, listener: impl Fn(&FocusEvent, &mut WindowContext) + 'static) -> Self
     where
         Self: Sized,
     {
-        let listener = listener.into();
         self.interactivity()
             .focus_listeners
             .push(Box::new(move |focus_handle, event, cx| {
@@ -492,11 +499,10 @@ pub trait FocusableElement: InteractiveElement {
         self
     }
 
-    fn on_focus_out(mut self, listener: impl Into<CallbackHandle<FocusEvent>>) -> Self
+    fn on_focus_out(mut self, listener: impl Fn(&FocusEvent, &mut WindowContext) + 'static) -> Self
     where
         Self: Sized,
     {
-        let listener = listener.into();
         self.interactivity()
             .focus_listeners
             .push(Box::new(move |focus_handle, event, cx| {
@@ -710,7 +716,7 @@ pub struct Interactivity {
     pub drop_listeners: SmallVec<[(TypeId, Box<DropListener>); 2]>,
     pub click_listeners: SmallVec<[ClickListener; 2]>,
     pub drag_listener: Option<DragListener>,
-    pub hover_listener: Option<CallbackHandle<bool>>,
+    pub hover_listener: Option<Box<dyn Fn(&bool, &mut WindowContext)>>,
     pub tooltip_builder: Option<TooltipBuilder>,
 }
 

crates/gpui2/src/gpui2.rs 🔗

@@ -194,30 +194,6 @@ where
     }
 }
 
-pub struct CallbackHandle<E> {
-    callback: Box<dyn Fn(&E, &mut WindowContext) + 'static>,
-}
-
-impl<E, F: Fn(&E, &mut WindowContext) + 'static> From<F> for CallbackHandle<E> {
-    fn from(value: F) -> Self {
-        CallbackHandle {
-            callback: Box::new(value),
-        }
-    }
-}
-
-pub struct ConstructorHandle<R> {
-    callback: Box<dyn Fn(&mut WindowContext) -> R + 'static>,
-}
-
-impl<R, F: Fn(&mut WindowContext) -> R + 'static> From<F> for ConstructorHandle<R> {
-    fn from(value: F) -> Self {
-        ConstructorHandle {
-            callback: Box::new(value),
-        }
-    }
-}
-
 pub trait Flatten<T> {
     fn flatten(self) -> Result<T>;
 }

crates/gpui2/src/interactive.rs 🔗

@@ -305,7 +305,7 @@ mod test {
             div().id("testview").child(
                 div()
                     .key_context("parent")
-                    .on_key_down(cx.callback(|this, _, _| this.saw_key_down = true))
+                    .on_key_down(cx.listener(|this, _, _| this.saw_key_down = true))
                     .on_action(
                         cx.callback(|this: &mut TestView, _: &TestAction, _| {
                             this.saw_action = true

crates/gpui2/src/window.rs 🔗

@@ -1,15 +1,15 @@
 use crate::{
     key_dispatch::DispatchActionListener, px, size, Action, AnyDrag, AnyView, AppContext,
-    AsyncWindowContext, AvailableSpace, Bounds, BoxShadow, CallbackHandle, ConstructorHandle,
-    Context, Corners, CursorStyle, DevicePixels, DispatchNodeId, DispatchTree, DisplayId, Edges,
-    Effect, Entity, EntityId, EventEmitter, FileDropEvent, Flatten, FocusEvent, FontId,
-    GlobalElementId, GlyphId, Hsla, ImageData, InputEvent, IsZero, KeyBinding, KeyContext,
-    KeyDownEvent, LayoutId, Model, ModelContext, Modifiers, MonochromeSprite, MouseButton,
-    MouseDownEvent, MouseMoveEvent, MouseUpEvent, Path, Pixels, PlatformAtlas, PlatformDisplay,
-    PlatformInputHandler, PlatformWindow, Point, PolychromeSprite, PromptLevel, Quad, Render,
-    RenderGlyphParams, RenderImageParams, RenderSvgParams, ScaledPixels, SceneBuilder, Shadow,
-    SharedString, Size, Style, SubscriberSet, Subscription, TaffyLayoutEngine, Task, Underline,
-    UnderlineStyle, View, VisualContext, WeakView, WindowBounds, WindowOptions, SUBPIXEL_VARIANTS,
+    AsyncWindowContext, AvailableSpace, Bounds, BoxShadow, Context, Corners, CursorStyle,
+    DevicePixels, DispatchNodeId, DispatchTree, DisplayId, Edges, Effect, Entity, EntityId,
+    EventEmitter, FileDropEvent, Flatten, FocusEvent, FontId, GlobalElementId, GlyphId, Hsla,
+    ImageData, InputEvent, IsZero, KeyBinding, KeyContext, KeyDownEvent, LayoutId, Model,
+    ModelContext, Modifiers, MonochromeSprite, MouseButton, MouseDownEvent, MouseMoveEvent,
+    MouseUpEvent, Path, Pixels, PlatformAtlas, PlatformDisplay, PlatformInputHandler,
+    PlatformWindow, Point, PolychromeSprite, PromptLevel, Quad, Render, RenderGlyphParams,
+    RenderImageParams, RenderSvgParams, ScaledPixels, SceneBuilder, Shadow, SharedString, Size,
+    Style, SubscriberSet, Subscription, TaffyLayoutEngine, Task, Underline, UnderlineStyle, View,
+    VisualContext, WeakView, WindowBounds, WindowOptions, SUBPIXEL_VARIANTS,
 };
 use anyhow::{anyhow, Context as _, Result};
 use collections::HashMap;
@@ -2283,23 +2283,22 @@ impl<'a, V: 'static> ViewContext<'a, V> {
         self.defer(|_, cx| cx.emit(Manager::Dismiss))
     }
 
-    pub fn callback<E>(
+    pub fn listener<E>(
         &self,
         f: impl Fn(&mut V, &E, &mut ViewContext<V>) + 'static,
-    ) -> CallbackHandle<E> {
+    ) -> impl Fn(&E, &mut WindowContext) + 'static {
         let view = self.view().clone();
-        (move |e: &E, cx: &mut WindowContext| {
+        move |e: &E, cx: &mut WindowContext| {
             view.update(cx, |view, cx| f(view, e, cx));
-        })
-        .into()
+        }
     }
 
     pub fn constructor<R>(
         &self,
         f: impl Fn(&mut V, &mut ViewContext<V>) -> R + 'static,
-    ) -> ConstructorHandle<R> {
+    ) -> impl Fn(&mut WindowContext) -> R {
         let view = self.view().clone();
-        (move |cx: &mut WindowContext| view.update(cx, |view, cx| f(view, cx))).into()
+        move |cx: &mut WindowContext| view.update(cx, |view, cx| f(view, cx))
     }
 }