Remove V parameter on elements

Mikayla created

Change summary

crates/gpui2/src/app/test_context.rs      |   2 
crates/gpui2/src/element.rs               | 144 +++----
crates/gpui2/src/elements/div.rs          | 495 +++++++++++-------------
crates/gpui2/src/elements/img.rs          |  36 -
crates/gpui2/src/elements/overlay.rs      |  30 
crates/gpui2/src/elements/svg.rs          |  28 
crates/gpui2/src/elements/text.rs         |  43 -
crates/gpui2/src/elements/uniform_list.rs |  74 +--
crates/gpui2/src/gpui2.rs                 |  24 +
crates/gpui2/src/interactive.rs           |  55 -
crates/gpui2/src/style.rs                 |   4 
crates/gpui2/src/view.rs                  |  81 +--
crates/gpui2/src/window.rs                | 123 +++--
13 files changed, 536 insertions(+), 603 deletions(-)

Detailed changes

crates/gpui2/src/app/test_context.rs 🔗

@@ -631,7 +631,7 @@ impl AnyWindowHandle {
 pub struct EmptyView {}
 
 impl Render for EmptyView {
-    type Element = Div<Self>;
+    type Element = Div;
 
     fn render(&mut self, _cx: &mut crate::ViewContext<Self>) -> Self::Element {
         div()

crates/gpui2/src/element.rs 🔗

@@ -1,37 +1,34 @@
 use crate::{
-    AvailableSpace, BorrowWindow, Bounds, ElementId, LayoutId, Pixels, Point, Size, ViewContext,
+    AvailableSpace, BorrowWindow, Bounds, ElementId, LayoutId, Pixels, Point, Size, WindowContext,
 };
 use derive_more::{Deref, DerefMut};
 pub(crate) use smallvec::SmallVec;
 use std::{any::Any, fmt::Debug, mem};
 
-pub trait Element<V: 'static> {
+pub trait Element {
     type ElementState: 'static;
 
     fn element_id(&self) -> Option<ElementId>;
 
     fn layout(
         &mut self,
-        view_state: &mut V,
         element_state: Option<Self::ElementState>,
-        cx: &mut ViewContext<V>,
+        cx: &mut WindowContext,
     ) -> (LayoutId, Self::ElementState);
 
     fn paint(
         &mut self,
         bounds: Bounds<Pixels>,
-        view_state: &mut V,
         element_state: &mut Self::ElementState,
-        cx: &mut ViewContext<V>,
+        cx: &mut WindowContext,
     );
 
     fn draw<T, R>(
         self,
         origin: Point<Pixels>,
         available_space: Size<T>,
-        view_state: &mut V,
-        cx: &mut ViewContext<V>,
-        f: impl FnOnce(&Self::ElementState, &mut ViewContext<V>) -> R,
+        cx: &mut WindowContext,
+        f: impl FnOnce(&Self::ElementState, &mut WindowContext) -> R,
     ) -> R
     where
         Self: Sized,
@@ -41,7 +38,7 @@ pub trait Element<V: 'static> {
             element: self,
             phase: ElementRenderPhase::Start,
         };
-        element.draw(origin, available_space.map(Into::into), view_state, cx);
+        element.draw(origin, available_space.map(Into::into), cx);
         if let ElementRenderPhase::Painted { frame_state } = &element.phase {
             if let Some(frame_state) = frame_state.as_ref() {
                 f(&frame_state, cx)
@@ -65,10 +62,10 @@ pub trait Element<V: 'static> {
 #[derive(Deref, DerefMut, Default, Clone, Debug, Eq, PartialEq, Hash)]
 pub struct GlobalElementId(SmallVec<[ElementId; 32]>);
 
-pub trait ParentComponent<V: 'static> {
-    fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<V>; 2]>;
+pub trait ParentComponent {
+    fn children_mut(&mut self) -> &mut SmallVec<[AnyElement; 2]>;
 
-    fn child(mut self, child: impl Component<V>) -> Self
+    fn child(mut self, child: impl Component) -> Self
     where
         Self: Sized,
     {
@@ -76,7 +73,7 @@ pub trait ParentComponent<V: 'static> {
         self
     }
 
-    fn children(mut self, iter: impl IntoIterator<Item = impl Component<V>>) -> Self
+    fn children(mut self, iter: impl IntoIterator<Item = impl Component>) -> Self
     where
         Self: Sized,
     {
@@ -86,26 +83,24 @@ pub trait ParentComponent<V: 'static> {
     }
 }
 
-trait ElementObject<V> {
+trait ElementObject {
     fn element_id(&self) -> Option<ElementId>;
-    fn layout(&mut self, view_state: &mut V, cx: &mut ViewContext<V>) -> LayoutId;
-    fn paint(&mut self, view_state: &mut V, cx: &mut ViewContext<V>);
+    fn layout(&mut self, cx: &mut WindowContext) -> LayoutId;
+    fn paint(&mut self, cx: &mut WindowContext);
     fn measure(
         &mut self,
         available_space: Size<AvailableSpace>,
-        view_state: &mut V,
-        cx: &mut ViewContext<V>,
+        cx: &mut WindowContext,
     ) -> Size<Pixels>;
     fn draw(
         &mut self,
         origin: Point<Pixels>,
         available_space: Size<AvailableSpace>,
-        view_state: &mut V,
-        cx: &mut ViewContext<V>,
+        cx: &mut WindowContext,
     );
 }
 
-struct RenderedElement<V: 'static, E: Element<V>> {
+struct RenderedElement<E: Element> {
     element: E,
     phase: ElementRenderPhase<E::ElementState>,
 }
@@ -131,7 +126,7 @@ enum ElementRenderPhase<V> {
 /// Internal struct that wraps an element to store Layout and ElementState after the element is rendered.
 /// It's allocated as a trait object to erase the element type and wrapped in AnyElement<E::State> for
 /// improved usability.
-impl<V, E: Element<V>> RenderedElement<V, E> {
+impl<E: Element> RenderedElement<E> {
     fn new(element: E) -> Self {
         RenderedElement {
             element,
@@ -140,25 +135,25 @@ impl<V, E: Element<V>> RenderedElement<V, E> {
     }
 }
 
-impl<V, E> ElementObject<V> for RenderedElement<V, E>
+impl<E> ElementObject for RenderedElement<E>
 where
-    E: Element<V>,
+    E: Element,
     E::ElementState: 'static,
 {
     fn element_id(&self) -> Option<ElementId> {
         self.element.element_id()
     }
 
-    fn layout(&mut self, state: &mut V, cx: &mut ViewContext<V>) -> LayoutId {
+    fn layout(&mut self, cx: &mut WindowContext) -> LayoutId {
         let (layout_id, frame_state) = match mem::take(&mut self.phase) {
             ElementRenderPhase::Start => {
                 if let Some(id) = self.element.element_id() {
                     let layout_id = cx.with_element_state(id, |element_state, cx| {
-                        self.element.layout(state, element_state, cx)
+                        self.element.layout(element_state, cx)
                     });
                     (layout_id, None)
                 } else {
-                    let (layout_id, frame_state) = self.element.layout(state, None, cx);
+                    let (layout_id, frame_state) = self.element.layout(None, cx);
                     (layout_id, Some(frame_state))
                 }
             }
@@ -176,7 +171,7 @@ where
         layout_id
     }
 
-    fn paint(&mut self, view_state: &mut V, cx: &mut ViewContext<V>) {
+    fn paint(&mut self, cx: &mut WindowContext) {
         self.phase = match mem::take(&mut self.phase) {
             ElementRenderPhase::LayoutRequested {
                 layout_id,
@@ -191,13 +186,12 @@ where
                 if let Some(id) = self.element.element_id() {
                     cx.with_element_state(id, |element_state, cx| {
                         let mut element_state = element_state.unwrap();
-                        self.element
-                            .paint(bounds, view_state, &mut element_state, cx);
+                        self.element.paint(bounds, &mut element_state, cx);
                         ((), element_state)
                     });
                 } else {
                     self.element
-                        .paint(bounds, view_state, frame_state.as_mut().unwrap(), cx);
+                        .paint(bounds, frame_state.as_mut().unwrap(), cx);
                 }
                 ElementRenderPhase::Painted { frame_state }
             }
@@ -209,11 +203,10 @@ where
     fn measure(
         &mut self,
         available_space: Size<AvailableSpace>,
-        view_state: &mut V,
-        cx: &mut ViewContext<V>,
+        cx: &mut WindowContext,
     ) -> Size<Pixels> {
         if matches!(&self.phase, ElementRenderPhase::Start) {
-            self.layout(view_state, cx);
+            self.layout(cx);
         }
 
         let layout_id = match &mut self.phase {
@@ -251,21 +244,19 @@ where
         &mut self,
         origin: Point<Pixels>,
         available_space: Size<AvailableSpace>,
-        view_state: &mut V,
-        cx: &mut ViewContext<V>,
+        cx: &mut WindowContext,
     ) {
-        self.measure(available_space, view_state, cx);
-        cx.with_absolute_element_offset(origin, |cx| self.paint(view_state, cx))
+        self.measure(available_space, cx);
+        cx.with_absolute_element_offset(origin, |cx| self.paint(cx))
     }
 }
 
-pub struct AnyElement<V>(Box<dyn ElementObject<V>>);
+pub struct AnyElement(Box<dyn ElementObject>);
 
-impl<V> AnyElement<V> {
+impl AnyElement {
     pub fn new<E>(element: E) -> Self
     where
-        V: 'static,
-        E: 'static + Element<V>,
+        E: 'static + Element,
         E::ElementState: Any,
     {
         AnyElement(Box::new(RenderedElement::new(element)))
@@ -275,22 +266,21 @@ impl<V> AnyElement<V> {
         self.0.element_id()
     }
 
-    pub fn layout(&mut self, view_state: &mut V, cx: &mut ViewContext<V>) -> LayoutId {
-        self.0.layout(view_state, cx)
+    pub fn layout(&mut self, cx: &mut WindowContext) -> LayoutId {
+        self.0.layout(cx)
     }
 
-    pub fn paint(&mut self, view_state: &mut V, cx: &mut ViewContext<V>) {
-        self.0.paint(view_state, cx)
+    pub fn paint(&mut self, cx: &mut WindowContext) {
+        self.0.paint(cx)
     }
 
     /// Initializes this element and performs layout within the given available space to determine its size.
     pub fn measure(
         &mut self,
         available_space: Size<AvailableSpace>,
-        view_state: &mut V,
-        cx: &mut ViewContext<V>,
+        cx: &mut WindowContext,
     ) -> Size<Pixels> {
-        self.0.measure(available_space, view_state, cx)
+        self.0.measure(available_space, cx)
     }
 
     /// Initializes this element and performs layout in the available space, then paints it at the given origin.
@@ -298,20 +288,19 @@ impl<V> AnyElement<V> {
         &mut self,
         origin: Point<Pixels>,
         available_space: Size<AvailableSpace>,
-        view_state: &mut V,
-        cx: &mut ViewContext<V>,
+        cx: &mut WindowContext,
     ) {
-        self.0.draw(origin, available_space, view_state, cx)
+        self.0.draw(origin, available_space, cx)
     }
 }
 
-pub trait Component<V> {
-    fn render(self) -> AnyElement<V>;
+pub trait Component {
+    fn render(self) -> AnyElement;
 
     fn map<U>(self, f: impl FnOnce(Self) -> U) -> U
     where
         Self: Sized,
-        U: Component<V>,
+        U: Component,
     {
         f(self)
     }
@@ -337,19 +326,18 @@ pub trait Component<V> {
     }
 }
 
-impl<V> Component<V> for AnyElement<V> {
-    fn render(self) -> AnyElement<V> {
+impl Component for AnyElement {
+    fn render(self) -> AnyElement {
         self
     }
 }
 
-impl<V, E, F> Element<V> for Option<F>
+impl<E, F> Element for Option<F>
 where
-    V: 'static,
-    E: 'static + Component<V>,
-    F: FnOnce(&mut V, &mut ViewContext<'_, V>) -> E + 'static,
+    E: 'static + Component,
+    F: FnOnce(&mut WindowContext) -> E + 'static,
 {
-    type ElementState = AnyElement<V>;
+    type ElementState = AnyElement;
 
     fn element_id(&self) -> Option<ElementId> {
         None
@@ -357,45 +345,41 @@ where
 
     fn layout(
         &mut self,
-        view_state: &mut V,
         _: Option<Self::ElementState>,
-        cx: &mut ViewContext<V>,
+        cx: &mut WindowContext,
     ) -> (LayoutId, Self::ElementState) {
         let render = self.take().unwrap();
-        let mut rendered_element = (render)(view_state, cx).render();
-        let layout_id = rendered_element.layout(view_state, cx);
+        let mut rendered_element = (render)(cx).render();
+        let layout_id = rendered_element.layout(cx);
         (layout_id, rendered_element)
     }
 
     fn paint(
         &mut self,
         _bounds: Bounds<Pixels>,
-        view_state: &mut V,
         rendered_element: &mut Self::ElementState,
-        cx: &mut ViewContext<V>,
+        cx: &mut WindowContext,
     ) {
-        rendered_element.paint(view_state, cx)
+        rendered_element.paint(cx)
     }
 }
 
-impl<V, E, F> Component<V> for Option<F>
+impl<E, F> Component for Option<F>
 where
-    V: 'static,
-    E: 'static + Component<V>,
-    F: FnOnce(&mut V, &mut ViewContext<'_, V>) -> E + 'static,
+    E: 'static + Component,
+    F: FnOnce(&mut WindowContext) -> E + 'static,
 {
-    fn render(self) -> AnyElement<V> {
+    fn render(self) -> AnyElement {
         AnyElement::new(self)
     }
 }
 
-impl<V, E, F> Component<V> for F
+impl<E, F> Component for F
 where
-    V: 'static,
-    E: 'static + Component<V>,
-    F: FnOnce(&mut V, &mut ViewContext<'_, V>) -> E + 'static,
+    E: 'static + Component,
+    F: FnOnce(&mut WindowContext) -> E + 'static,
 {
-    fn render(self) -> AnyElement<V> {
+    fn render(self) -> AnyElement {
         AnyElement::new(Some(self))
     }
 }

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

@@ -1,9 +1,10 @@
 use crate::{
     point, px, Action, AnyDrag, AnyElement, AnyTooltip, AnyView, AppContext, BorrowAppContext,
-    BorrowWindow, Bounds, ClickEvent, Component, DispatchPhase, Element, ElementId, FocusEvent,
-    FocusHandle, KeyContext, KeyDownEvent, KeyUpEvent, LayoutId, MouseButton, MouseDownEvent,
-    MouseMoveEvent, MouseUpEvent, ParentComponent, Pixels, Point, Render, ScrollWheelEvent,
-    SharedString, Size, Style, StyleRefinement, Styled, Task, View, ViewContext, Visibility,
+    BorrowWindow, Bounds, CallbackHandle, ClickEvent, Component, ConstructorHandle, DispatchPhase,
+    Element, ElementId, FocusEvent, FocusHandle, KeyContext, KeyDownEvent, KeyUpEvent, LayoutId,
+    MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, ParentComponent, Pixels, Point,
+    Render, ScrollWheelEvent, SharedString, Size, Style, StyleRefinement, Styled, Task, View,
+    Visibility, WindowContext,
 };
 use collections::HashMap;
 use refineable::Refineable;
@@ -12,7 +13,6 @@ use std::{
     any::{Any, TypeId},
     cell::RefCell,
     fmt::Debug,
-    marker::PhantomData,
     mem,
     rc::Rc,
     time::Duration,
@@ -28,30 +28,24 @@ pub struct GroupStyle {
     pub style: StyleRefinement,
 }
 
-pub trait InteractiveComponent<V: 'static>: Sized + Element<V> {
-    fn interactivity(&mut self) -> &mut Interactivity<V>;
+pub trait InteractiveComponent: Sized + Element {
+    fn interactivity(&mut self) -> &mut Interactivity;
 
     fn group(mut self, group: impl Into<SharedString>) -> Self {
         self.interactivity().group = Some(group.into());
         self
     }
 
-    fn id(mut self, id: impl Into<ElementId>) -> Stateful<V, Self> {
+    fn id(mut self, id: impl Into<ElementId>) -> Stateful<Self> {
         self.interactivity().element_id = Some(id.into());
 
-        Stateful {
-            element: self,
-            view_type: PhantomData,
-        }
+        Stateful { element: self }
     }
 
-    fn track_focus(mut self, focus_handle: &FocusHandle) -> Focusable<V, Self> {
+    fn track_focus(mut self, focus_handle: &FocusHandle) -> Focusable<Self> {
         self.interactivity().focusable = true;
         self.interactivity().tracked_focus_handle = Some(focus_handle.clone());
-        Focusable {
-            element: self,
-            view_type: PhantomData,
-        }
+        Focusable { element: self }
     }
 
     fn key_context<C, E>(mut self, key_context: C) -> Self
@@ -85,29 +79,28 @@ pub trait InteractiveComponent<V: 'static>: Sized + Element<V> {
     fn on_mouse_down(
         mut self,
         button: MouseButton,
-        handler: impl Fn(&mut V, &MouseDownEvent, &mut ViewContext<V>) + 'static,
+        handler: impl Into<CallbackHandle<MouseDownEvent>>,
     ) -> Self {
+        let handler = handler.into();
         self.interactivity().mouse_down_listeners.push(Box::new(
-            move |view, event, bounds, phase, cx| {
+            move |event, bounds, phase, cx| {
                 if phase == DispatchPhase::Bubble
                     && event.button == button
                     && bounds.contains_point(&event.position)
                 {
-                    handler(view, event, cx)
+                    (handler.callback)(event, cx)
                 }
             },
         ));
         self
     }
 
-    fn on_any_mouse_down(
-        mut self,
-        handler: impl Fn(&mut V, &MouseDownEvent, &mut ViewContext<V>) + 'static,
-    ) -> Self {
+    fn on_any_mouse_down(mut self, handler: impl Into<CallbackHandle<MouseDownEvent>>) -> Self {
+        let handler = handler.into();
         self.interactivity().mouse_down_listeners.push(Box::new(
-            move |view, event, bounds, phase, cx| {
+            move |event, bounds, phase, cx| {
                 if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
-                    handler(view, event, cx)
+                    (handler.callback)(event, cx)
                 }
             },
         ));
@@ -117,43 +110,40 @@ pub trait InteractiveComponent<V: 'static>: Sized + Element<V> {
     fn on_mouse_up(
         mut self,
         button: MouseButton,
-        handler: impl Fn(&mut V, &MouseUpEvent, &mut ViewContext<V>) + 'static,
+        handler: impl Into<CallbackHandle<MouseUpEvent>>,
     ) -> Self {
-        self.interactivity().mouse_up_listeners.push(Box::new(
-            move |view, event, bounds, phase, cx| {
+        let handler = handler.into();
+        self.interactivity()
+            .mouse_up_listeners
+            .push(Box::new(move |event, bounds, phase, cx| {
                 if phase == DispatchPhase::Bubble
                     && event.button == button
                     && bounds.contains_point(&event.position)
                 {
-                    handler(view, event, cx)
+                    (handler.callback)(event, cx)
                 }
-            },
-        ));
+            }));
         self
     }
 
-    fn on_any_mouse_up(
-        mut self,
-        handler: impl Fn(&mut V, &MouseUpEvent, &mut ViewContext<V>) + 'static,
-    ) -> Self {
-        self.interactivity().mouse_up_listeners.push(Box::new(
-            move |view, event, bounds, phase, cx| {
+    fn on_any_mouse_up(mut self, handler: impl Into<CallbackHandle<MouseUpEvent>>) -> Self {
+        let handler = handler.into();
+        self.interactivity()
+            .mouse_up_listeners
+            .push(Box::new(move |event, bounds, phase, cx| {
                 if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
-                    handler(view, event, cx)
+                    (handler.callback)(event, cx)
                 }
-            },
-        ));
+            }));
         self
     }
 
-    fn on_mouse_down_out(
-        mut self,
-        handler: impl Fn(&mut V, &MouseDownEvent, &mut ViewContext<V>) + 'static,
-    ) -> Self {
+    fn on_mouse_down_out(mut self, handler: impl Into<CallbackHandle<MouseDownEvent>>) -> Self {
+        let handler = handler.into();
         self.interactivity().mouse_down_listeners.push(Box::new(
-            move |view, event, bounds, phase, cx| {
+            move |event, bounds, phase, cx| {
                 if phase == DispatchPhase::Capture && !bounds.contains_point(&event.position) {
-                    handler(view, event, cx)
+                    (handler.callback)(event, cx)
                 }
             },
         ));
@@ -163,60 +153,55 @@ pub trait InteractiveComponent<V: 'static>: Sized + Element<V> {
     fn on_mouse_up_out(
         mut self,
         button: MouseButton,
-        handler: impl Fn(&mut V, &MouseUpEvent, &mut ViewContext<V>) + 'static,
+        handler: impl Into<CallbackHandle<MouseUpEvent>>,
     ) -> Self {
-        self.interactivity().mouse_up_listeners.push(Box::new(
-            move |view, event, bounds, phase, cx| {
+        let handler = handler.into();
+        self.interactivity()
+            .mouse_up_listeners
+            .push(Box::new(move |event, bounds, phase, cx| {
                 if phase == DispatchPhase::Capture
                     && event.button == button
                     && !bounds.contains_point(&event.position)
                 {
-                    handler(view, event, cx);
+                    (handler.callback)(event, cx);
                 }
-            },
-        ));
+            }));
         self
     }
 
-    fn on_mouse_move(
-        mut self,
-        handler: impl Fn(&mut V, &MouseMoveEvent, &mut ViewContext<V>) + 'static,
-    ) -> Self {
+    fn on_mouse_move(mut self, handler: impl Into<CallbackHandle<MouseMoveEvent>>) -> Self {
+        let handler = handler.into();
         self.interactivity().mouse_move_listeners.push(Box::new(
-            move |view, event, bounds, phase, cx| {
+            move |event, bounds, phase, cx| {
                 if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
-                    handler(view, event, cx);
+                    (handler.callback)(event, cx);
                 }
             },
         ));
         self
     }
 
-    fn on_scroll_wheel(
-        mut self,
-        handler: impl Fn(&mut V, &ScrollWheelEvent, &mut ViewContext<V>) + 'static,
-    ) -> Self {
+    fn on_scroll_wheel(mut self, handler: impl Into<CallbackHandle<ScrollWheelEvent>>) -> Self {
+        let handler = handler.into();
         self.interactivity().scroll_wheel_listeners.push(Box::new(
-            move |view, event, bounds, phase, cx| {
+            move |event, bounds, phase, cx| {
                 if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
-                    handler(view, event, cx);
+                    (handler.callback)(event, cx);
                 }
             },
         ));
         self
     }
 
-    /// Capture the given action, fires during the capture phase
-    fn capture_action<A: Action>(
-        mut self,
-        listener: impl Fn(&mut V, &A, &mut ViewContext<V>) + 'static,
-    ) -> Self {
+    /// 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();
         self.interactivity().action_listeners.push((
             TypeId::of::<A>(),
-            Box::new(move |view, action, phase, cx| {
+            Box::new(move |action, phase, cx| {
                 let action = action.downcast_ref().unwrap();
                 if phase == DispatchPhase::Capture {
-                    listener(view, action, cx)
+                    (listener.callback)(action, cx)
                 }
             }),
         ));
@@ -224,10 +209,8 @@ pub trait InteractiveComponent<V: 'static>: Sized + Element<V> {
     }
 
     /// Add a listener for the given action, fires during the bubble event phase
-    fn on_action<A: Action>(
-        mut self,
-        listener: impl Fn(&mut V, &A, &mut ViewContext<V>) + 'static,
-    ) -> Self {
+    fn on_action<A: Action>(mut self, listener: impl Into<CallbackHandle<A>> + 'static) -> Self {
+        let handle = listener.into();
         // 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:
@@ -244,36 +227,60 @@ pub trait InteractiveComponent<V: 'static>: Sized + Element<V> {
         // );
         self.interactivity().action_listeners.push((
             TypeId::of::<A>(),
-            Box::new(move |view, action, phase, cx| {
+            Box::new(move |action, phase, cx| {
                 let action = action.downcast_ref().unwrap();
                 if phase == DispatchPhase::Bubble {
-                    listener(view, action, cx)
+                    (handle.callback)(action, cx)
                 }
             }),
         ));
         self
     }
 
-    fn on_key_down(
-        mut self,
-        listener: impl Fn(&mut V, &KeyDownEvent, DispatchPhase, &mut ViewContext<V>) + 'static,
-    ) -> Self {
+    fn on_key_down(mut self, listener: impl Into<CallbackHandle<KeyDownEvent>>) -> Self {
+        let listener = listener.into();
         self.interactivity()
             .key_down_listeners
-            .push(Box::new(move |view, event, phase, cx| {
-                listener(view, event, phase, cx)
+            .push(Box::new(move |event, phase, cx| {
+                if phase == DispatchPhase::Bubble {
+                    (listener.callback)(event, cx)
+                }
             }));
         self
     }
 
-    fn on_key_up(
-        mut self,
-        listener: impl Fn(&mut V, &KeyUpEvent, DispatchPhase, &mut ViewContext<V>) + 'static,
-    ) -> Self {
+    fn capture_key_down(mut self, listener: impl Into<CallbackHandle<KeyDownEvent>>) -> Self {
+        let listener = listener.into();
+        self.interactivity()
+            .key_down_listeners
+            .push(Box::new(move |event, phase, cx| {
+                if phase == DispatchPhase::Capture {
+                    (listener.callback)(event, cx)
+                }
+            }));
+        self
+    }
+
+    fn on_key_up(mut self, listener: impl Into<CallbackHandle<KeyUpEvent>>) -> Self {
+        let listener = listener.into();
         self.interactivity()
             .key_up_listeners
-            .push(Box::new(move |view, event, phase, cx| {
-                listener(view, event, phase, cx)
+            .push(Box::new(move |event, phase, cx| {
+                if phase == DispatchPhase::Bubble {
+                    (listener.callback)(event, cx)
+                }
+            }));
+        self
+    }
+
+    fn capture_key_up(mut self, listener: impl Into<CallbackHandle<KeyUpEvent>>) -> Self {
+        let listener = listener.into();
+        self.interactivity()
+            .key_up_listeners
+            .push(Box::new(move |event, phase, cx| {
+                if phase == DispatchPhase::Capture {
+                    (listener.callback)(event, cx)
+                }
             }));
         self
     }
@@ -300,27 +307,22 @@ pub trait InteractiveComponent<V: 'static>: Sized + Element<V> {
         self
     }
 
-    fn on_drop<W: 'static>(
-        mut self,
-        listener: impl Fn(&mut V, View<W>, &mut ViewContext<V>) + 'static,
-    ) -> Self {
+    fn on_drop<W: 'static>(mut self, listener: impl Into<CallbackHandle<View<W>>>) -> Self {
+        let listener = listener.into();
         self.interactivity().drop_listeners.push((
             TypeId::of::<W>(),
-            Box::new(move |view, dragged_view, cx| {
-                listener(view, dragged_view.downcast().unwrap(), cx);
+            Box::new(move |dragged_view, cx| {
+                (listener.callback)(&dragged_view.downcast().unwrap(), cx);
             }),
         ));
         self
     }
 }
 
-pub trait StatefulInteractiveComponent<V: 'static, E: Element<V>>: InteractiveComponent<V> {
-    fn focusable(mut self) -> Focusable<V, Self> {
+pub trait StatefulInteractiveComponent: InteractiveComponent {
+    fn focusable(mut self) -> Focusable<Self> {
         self.interactivity().focusable = true;
-        Focusable {
-            element: self,
-            view_type: PhantomData,
-        }
+        Focusable { element: self }
     }
 
     fn overflow_scroll(mut self) -> Self {
@@ -362,70 +364,64 @@ pub trait StatefulInteractiveComponent<V: 'static, E: Element<V>>: InteractiveCo
         self
     }
 
-    fn on_click(
-        mut self,
-        listener: impl Fn(&mut V, &ClickEvent, &mut ViewContext<V>) + 'static,
-    ) -> Self
+    fn on_click(mut self, listener: impl Into<CallbackHandle<ClickEvent>>) -> Self
     where
         Self: Sized,
     {
+        let listener = listener.into();
         self.interactivity()
             .click_listeners
-            .push(Box::new(move |view, event, cx| listener(view, event, cx)));
+            .push(Box::new(move |event, cx| (listener.callback)(event, cx)));
         self
     }
 
-    fn on_drag<W>(
-        mut self,
-        listener: impl Fn(&mut V, &mut ViewContext<V>) -> View<W> + 'static,
-    ) -> Self
+    fn on_drag<W>(mut self, listener: impl Into<ConstructorHandle<View<W>>>) -> 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"
         );
-        self.interactivity().drag_listener =
-            Some(Box::new(move |view_state, cursor_offset, cx| AnyDrag {
-                view: listener(view_state, cx).into(),
-                cursor_offset,
-            }));
+        self.interactivity().drag_listener = Some(Box::new(move |cursor_offset, cx| AnyDrag {
+            view: (listener.callback)(cx).into(),
+            cursor_offset,
+        }));
         self
     }
 
-    fn on_hover(mut self, listener: impl 'static + Fn(&mut V, bool, &mut ViewContext<V>)) -> Self
+    fn on_hover(mut self, listener: impl Into<CallbackHandle<bool>>) -> 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(Box::new(listener));
+        self.interactivity().hover_listener = Some(listener);
         self
     }
 
-    fn tooltip(
-        mut self,
-        build_tooltip: impl Fn(&mut V, &mut ViewContext<V>) -> AnyView + 'static,
-    ) -> Self
+    fn tooltip(mut self, build_tooltip: impl Into<ConstructorHandle<AnyView>>) -> 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"
         );
         self.interactivity().tooltip_builder =
-            Some(Rc::new(move |view_state, cx| build_tooltip(view_state, cx)));
+            Some(Rc::new(move |cx| (build_tooltip.callback)(cx)));
 
         self
     }
 }
 
-pub trait FocusableComponent<V: 'static>: InteractiveComponent<V> {
+pub trait FocusableComponent: InteractiveComponent {
     fn focus(mut self, f: impl FnOnce(StyleRefinement) -> StyleRefinement) -> Self
     where
         Self: Sized,
@@ -442,49 +438,44 @@ pub trait FocusableComponent<V: 'static>: InteractiveComponent<V> {
         self
     }
 
-    fn on_focus(
-        mut self,
-        listener: impl Fn(&mut V, &FocusEvent, &mut ViewContext<V>) + 'static,
-    ) -> Self
+    fn on_focus(mut self, listener: impl Into<CallbackHandle<FocusEvent>>) -> Self
     where
         Self: Sized,
     {
-        self.interactivity().focus_listeners.push(Box::new(
-            move |view, focus_handle, event, cx| {
+        let listener = listener.into();
+        self.interactivity()
+            .focus_listeners
+            .push(Box::new(move |focus_handle, event, cx| {
                 if event.focused.as_ref() == Some(focus_handle) {
-                    listener(view, event, cx)
+                    (listener.callback)(event, cx)
                 }
-            },
-        ));
+            }));
         self
     }
 
-    fn on_blur(
-        mut self,
-        listener: impl Fn(&mut V, &FocusEvent, &mut ViewContext<V>) + 'static,
-    ) -> Self
+    fn on_blur(mut self, listener: impl Into<CallbackHandle<FocusEvent>>) -> Self
     where
         Self: Sized,
     {
-        self.interactivity().focus_listeners.push(Box::new(
-            move |view, focus_handle, event, cx| {
+        let listener = listener.into();
+        self.interactivity()
+            .focus_listeners
+            .push(Box::new(move |focus_handle, event, cx| {
                 if event.blurred.as_ref() == Some(focus_handle) {
-                    listener(view, event, cx)
+                    (listener.callback)(event, cx)
                 }
-            },
-        ));
+            }));
         self
     }
 
-    fn on_focus_in(
-        mut self,
-        listener: impl Fn(&mut V, &FocusEvent, &mut ViewContext<V>) + 'static,
-    ) -> Self
+    fn on_focus_in(mut self, listener: impl Into<CallbackHandle<FocusEvent>>) -> Self
     where
         Self: Sized,
     {
-        self.interactivity().focus_listeners.push(Box::new(
-            move |view, focus_handle, event, cx| {
+        let listener = listener.into();
+        self.interactivity()
+            .focus_listeners
+            .push(Box::new(move |focus_handle, event, cx| {
                 let descendant_blurred = event
                     .blurred
                     .as_ref()
@@ -495,22 +486,20 @@ pub trait FocusableComponent<V: 'static>: InteractiveComponent<V> {
                     .map_or(false, |focused| focus_handle.contains(focused, cx));
 
                 if !descendant_blurred && descendant_focused {
-                    listener(view, event, cx)
+                    (listener.callback)(event, cx)
                 }
-            },
-        ));
+            }));
         self
     }
 
-    fn on_focus_out(
-        mut self,
-        listener: impl Fn(&mut V, &FocusEvent, &mut ViewContext<V>) + 'static,
-    ) -> Self
+    fn on_focus_out(mut self, listener: impl Into<CallbackHandle<FocusEvent>>) -> Self
     where
         Self: Sized,
     {
-        self.interactivity().focus_listeners.push(Box::new(
-            move |view, focus_handle, event, cx| {
+        let listener = listener.into();
+        self.interactivity()
+            .focus_listeners
+            .push(Box::new(move |focus_handle, event, cx| {
                 let descendant_blurred = event
                     .blurred
                     .as_ref()
@@ -520,86 +509,73 @@ pub trait FocusableComponent<V: 'static>: InteractiveComponent<V> {
                     .as_ref()
                     .map_or(false, |focused| focus_handle.contains(focused, cx));
                 if descendant_blurred && !descendant_focused {
-                    listener(view, event, cx)
+                    (listener.callback)(event, cx)
                 }
-            },
-        ));
+            }));
         self
     }
 }
 
-pub type FocusListeners<V> = SmallVec<[FocusListener<V>; 2]>;
+pub type FocusListeners = SmallVec<[FocusListener; 2]>;
 
-pub type FocusListener<V> =
-    Box<dyn Fn(&mut V, &FocusHandle, &FocusEvent, &mut ViewContext<V>) + 'static>;
+pub type FocusListener = Box<dyn Fn(&FocusHandle, &FocusEvent, &mut WindowContext) + 'static>;
 
-pub type MouseDownListener<V> = Box<
-    dyn Fn(&mut V, &MouseDownEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>) + 'static,
->;
-pub type MouseUpListener<V> = Box<
-    dyn Fn(&mut V, &MouseUpEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>) + 'static,
->;
+pub type MouseDownListener =
+    Box<dyn Fn(&MouseDownEvent, &Bounds<Pixels>, DispatchPhase, &mut WindowContext) + 'static>;
+pub type MouseUpListener =
+    Box<dyn Fn(&MouseUpEvent, &Bounds<Pixels>, DispatchPhase, &mut WindowContext) + 'static>;
 
-pub type MouseMoveListener<V> = Box<
-    dyn Fn(&mut V, &MouseMoveEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>) + 'static,
->;
+pub type MouseMoveListener =
+    Box<dyn Fn(&MouseMoveEvent, &Bounds<Pixels>, DispatchPhase, &mut WindowContext) + 'static>;
 
-pub type ScrollWheelListener<V> = Box<
-    dyn Fn(&mut V, &ScrollWheelEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
-        + 'static,
->;
+pub type ScrollWheelListener =
+    Box<dyn Fn(&ScrollWheelEvent, &Bounds<Pixels>, DispatchPhase, &mut WindowContext) + 'static>;
 
-pub type ClickListener<V> = Box<dyn Fn(&mut V, &ClickEvent, &mut ViewContext<V>) + 'static>;
+pub type ClickListener = Box<dyn Fn(&ClickEvent, &mut WindowContext) + 'static>;
 
-pub type DragListener<V> =
-    Box<dyn Fn(&mut V, Point<Pixels>, &mut ViewContext<V>) -> AnyDrag + 'static>;
+pub type DragListener = Box<dyn Fn(Point<Pixels>, &mut WindowContext) -> AnyDrag + 'static>;
 
-type DropListener<V> = dyn Fn(&mut V, AnyView, &mut ViewContext<V>) + 'static;
+type DropListener = dyn Fn(AnyView, &mut WindowContext) + 'static;
 
-pub type HoverListener<V> = Box<dyn Fn(&mut V, bool, &mut ViewContext<V>) + 'static>;
+pub type TooltipBuilder = Rc<dyn Fn(&mut WindowContext) -> AnyView + 'static>;
 
-pub type TooltipBuilder<V> = Rc<dyn Fn(&mut V, &mut ViewContext<V>) -> AnyView + 'static>;
+pub type KeyDownListener = Box<dyn Fn(&KeyDownEvent, DispatchPhase, &mut WindowContext) + 'static>;
 
-pub type KeyDownListener<V> =
-    Box<dyn Fn(&mut V, &KeyDownEvent, DispatchPhase, &mut ViewContext<V>) + 'static>;
+pub type KeyUpListener = Box<dyn Fn(&KeyUpEvent, DispatchPhase, &mut WindowContext) + 'static>;
 
-pub type KeyUpListener<V> =
-    Box<dyn Fn(&mut V, &KeyUpEvent, DispatchPhase, &mut ViewContext<V>) + 'static>;
+pub type ActionListener = Box<dyn Fn(&dyn Any, DispatchPhase, &mut WindowContext) + 'static>;
 
-pub type ActionListener<V> =
-    Box<dyn Fn(&mut V, &dyn Any, DispatchPhase, &mut ViewContext<V>) + 'static>;
-
-pub fn div<V: 'static>() -> Div<V> {
+pub fn div() -> Div {
     Div {
         interactivity: Interactivity::default(),
         children: SmallVec::default(),
     }
 }
 
-pub struct Div<V> {
-    interactivity: Interactivity<V>,
-    children: SmallVec<[AnyElement<V>; 2]>,
+pub struct Div {
+    interactivity: Interactivity,
+    children: SmallVec<[AnyElement; 2]>,
 }
 
-impl<V> Styled for Div<V> {
+impl Styled for Div {
     fn style(&mut self) -> &mut StyleRefinement {
         &mut self.interactivity.base_style
     }
 }
 
-impl<V: 'static> InteractiveComponent<V> for Div<V> {
-    fn interactivity(&mut self) -> &mut Interactivity<V> {
+impl InteractiveComponent for Div {
+    fn interactivity(&mut self) -> &mut Interactivity {
         &mut self.interactivity
     }
 }
 
-impl<V: 'static> ParentComponent<V> for Div<V> {
-    fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<V>; 2]> {
+impl ParentComponent for Div {
+    fn children_mut(&mut self) -> &mut SmallVec<[AnyElement; 2]> {
         &mut self.children
     }
 }
 
-impl<V: 'static> Element<V> for Div<V> {
+impl Element for Div {
     type ElementState = DivState;
 
     fn element_id(&self) -> Option<ElementId> {
@@ -608,9 +584,8 @@ impl<V: 'static> Element<V> for Div<V> {
 
     fn layout(
         &mut self,
-        view_state: &mut V,
         element_state: Option<Self::ElementState>,
-        cx: &mut ViewContext<V>,
+        cx: &mut WindowContext,
     ) -> (LayoutId, Self::ElementState) {
         let mut child_layout_ids = SmallVec::new();
         let mut interactivity = mem::take(&mut self.interactivity);
@@ -622,7 +597,7 @@ impl<V: 'static> Element<V> for Div<V> {
                     child_layout_ids = self
                         .children
                         .iter_mut()
-                        .map(|child| child.layout(view_state, cx))
+                        .map(|child| child.layout(cx))
                         .collect::<SmallVec<_>>();
                     cx.request_layout(&style, child_layout_ids.iter().copied())
                 })
@@ -641,9 +616,8 @@ impl<V: 'static> Element<V> for Div<V> {
     fn paint(
         &mut self,
         bounds: Bounds<Pixels>,
-        view_state: &mut V,
         element_state: &mut Self::ElementState,
-        cx: &mut ViewContext<V>,
+        cx: &mut WindowContext,
     ) {
         let mut child_min = point(Pixels::MAX, Pixels::MAX);
         let mut child_max = Point::default();
@@ -680,7 +654,7 @@ impl<V: 'static> Element<V> for Div<V> {
                             cx.with_content_mask(style.overflow_mask(bounds), |cx| {
                                 cx.with_element_offset(scroll_offset, |cx| {
                                     for child in &mut self.children {
-                                        child.paint(view_state, cx);
+                                        child.paint(cx);
                                     }
                                 })
                             })
@@ -693,8 +667,8 @@ impl<V: 'static> Element<V> for Div<V> {
     }
 }
 
-impl<V: 'static> Component<V> for Div<V> {
-    fn render(self) -> AnyElement<V> {
+impl Component for Div {
+    fn render(self) -> AnyElement {
         AnyElement::new(self)
     }
 }
@@ -710,12 +684,12 @@ impl DivState {
     }
 }
 
-pub struct Interactivity<V> {
+pub struct Interactivity {
     pub element_id: Option<ElementId>,
     pub key_context: KeyContext,
     pub focusable: bool,
     pub tracked_focus_handle: Option<FocusHandle>,
-    pub focus_listeners: FocusListeners<V>,
+    pub focus_listeners: FocusListeners,
     pub group: Option<SharedString>,
     pub base_style: StyleRefinement,
     pub focus_style: StyleRefinement,
@@ -726,29 +700,26 @@ pub struct Interactivity<V> {
     pub group_active_style: Option<GroupStyle>,
     pub drag_over_styles: SmallVec<[(TypeId, StyleRefinement); 2]>,
     pub group_drag_over_styles: SmallVec<[(TypeId, GroupStyle); 2]>,
-    pub mouse_down_listeners: SmallVec<[MouseDownListener<V>; 2]>,
-    pub mouse_up_listeners: SmallVec<[MouseUpListener<V>; 2]>,
-    pub mouse_move_listeners: SmallVec<[MouseMoveListener<V>; 2]>,
-    pub scroll_wheel_listeners: SmallVec<[ScrollWheelListener<V>; 2]>,
-    pub key_down_listeners: SmallVec<[KeyDownListener<V>; 2]>,
-    pub key_up_listeners: SmallVec<[KeyUpListener<V>; 2]>,
-    pub action_listeners: SmallVec<[(TypeId, ActionListener<V>); 8]>,
-    pub drop_listeners: SmallVec<[(TypeId, Box<DropListener<V>>); 2]>,
-    pub click_listeners: SmallVec<[ClickListener<V>; 2]>,
-    pub drag_listener: Option<DragListener<V>>,
-    pub hover_listener: Option<HoverListener<V>>,
-    pub tooltip_builder: Option<TooltipBuilder<V>>,
+    pub mouse_down_listeners: SmallVec<[MouseDownListener; 2]>,
+    pub mouse_up_listeners: SmallVec<[MouseUpListener; 2]>,
+    pub mouse_move_listeners: SmallVec<[MouseMoveListener; 2]>,
+    pub scroll_wheel_listeners: SmallVec<[ScrollWheelListener; 2]>,
+    pub key_down_listeners: SmallVec<[KeyDownListener; 2]>,
+    pub key_up_listeners: SmallVec<[KeyUpListener; 2]>,
+    pub action_listeners: SmallVec<[(TypeId, ActionListener); 8]>,
+    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 tooltip_builder: Option<TooltipBuilder>,
 }
 
-impl<V> Interactivity<V>
-where
-    V: 'static,
-{
+impl Interactivity {
     pub fn layout(
         &mut self,
         element_state: Option<InteractiveElementState>,
-        cx: &mut ViewContext<V>,
-        f: impl FnOnce(Style, &mut ViewContext<V>) -> LayoutId,
+        cx: &mut WindowContext,
+        f: impl FnOnce(Style, &mut WindowContext) -> LayoutId,
     ) -> (LayoutId, InteractiveElementState) {
         let mut element_state = element_state.unwrap_or_default();
 
@@ -774,8 +745,8 @@ where
         bounds: Bounds<Pixels>,
         content_size: Size<Pixels>,
         element_state: &mut InteractiveElementState,
-        cx: &mut ViewContext<V>,
-        f: impl FnOnce(Style, Point<Pixels>, &mut ViewContext<V>),
+        cx: &mut WindowContext,
+        f: impl FnOnce(Style, Point<Pixels>, &mut WindowContext),
     ) {
         let style = self.compute_style(Some(bounds), element_state, cx);
 
@@ -787,26 +758,26 @@ where
         }
 
         for listener in self.mouse_down_listeners.drain(..) {
-            cx.on_mouse_event(move |state, event: &MouseDownEvent, phase, cx| {
-                listener(state, event, &bounds, phase, cx);
+            cx.on_mouse_event(move |event: &MouseDownEvent, phase, cx| {
+                listener(event, &bounds, phase, cx);
             })
         }
 
         for listener in self.mouse_up_listeners.drain(..) {
-            cx.on_mouse_event(move |state, event: &MouseUpEvent, phase, cx| {
-                listener(state, event, &bounds, phase, cx);
+            cx.on_mouse_event(move |event: &MouseUpEvent, phase, cx| {
+                listener(event, &bounds, phase, cx);
             })
         }
 
         for listener in self.mouse_move_listeners.drain(..) {
-            cx.on_mouse_event(move |state, event: &MouseMoveEvent, phase, cx| {
-                listener(state, event, &bounds, phase, cx);
+            cx.on_mouse_event(move |event: &MouseMoveEvent, phase, cx| {
+                listener(event, &bounds, phase, cx);
             })
         }
 
         for listener in self.scroll_wheel_listeners.drain(..) {
-            cx.on_mouse_event(move |state, event: &ScrollWheelEvent, phase, cx| {
-                listener(state, event, &bounds, phase, cx);
+            cx.on_mouse_event(move |event: &ScrollWheelEvent, phase, cx| {
+                listener(event, &bounds, phase, cx);
             })
         }
 
@@ -817,7 +788,7 @@ where
 
         if let Some(group_bounds) = hover_group_bounds {
             let hovered = group_bounds.contains_point(&cx.mouse_position());
-            cx.on_mouse_event(move |_, event: &MouseMoveEvent, phase, cx| {
+            cx.on_mouse_event(move |event: &MouseMoveEvent, phase, cx| {
                 if phase == DispatchPhase::Capture {
                     if group_bounds.contains_point(&event.position) != hovered {
                         cx.notify();
@@ -830,7 +801,7 @@ where
             || (cx.active_drag.is_some() && !self.drag_over_styles.is_empty())
         {
             let hovered = bounds.contains_point(&cx.mouse_position());
-            cx.on_mouse_event(move |_, event: &MouseMoveEvent, phase, cx| {
+            cx.on_mouse_event(move |event: &MouseMoveEvent, phase, cx| {
                 if phase == DispatchPhase::Capture {
                     if bounds.contains_point(&event.position) != hovered {
                         cx.notify();
@@ -841,7 +812,7 @@ where
 
         if cx.active_drag.is_some() {
             let drop_listeners = mem::take(&mut self.drop_listeners);
-            cx.on_mouse_event(move |view, event: &MouseUpEvent, phase, cx| {
+            cx.on_mouse_event(move |event: &MouseUpEvent, phase, cx| {
                 if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
                     if let Some(drag_state_type) =
                         cx.active_drag.as_ref().map(|drag| drag.view.entity_type())
@@ -852,7 +823,7 @@ where
                                     .active_drag
                                     .take()
                                     .expect("checked for type drag state type above");
-                                listener(view, drag.view.clone(), cx);
+                                listener(drag.view.clone(), cx);
                                 cx.notify();
                                 cx.stop_propagation();
                             }
@@ -872,7 +843,7 @@ where
                 if let Some(drag_listener) = drag_listener {
                     let active_state = element_state.clicked_state.clone();
 
-                    cx.on_mouse_event(move |view_state, event: &MouseMoveEvent, phase, cx| {
+                    cx.on_mouse_event(move |event: &MouseMoveEvent, phase, cx| {
                         if cx.active_drag.is_some() {
                             if phase == DispatchPhase::Capture {
                                 cx.notify();
@@ -883,7 +854,7 @@ where
                         {
                             *active_state.borrow_mut() = ElementClickedState::default();
                             let cursor_offset = event.position - bounds.origin;
-                            let drag = drag_listener(view_state, cursor_offset, cx);
+                            let drag = drag_listener(cursor_offset, cx);
                             cx.active_drag = Some(drag);
                             cx.notify();
                             cx.stop_propagation();
@@ -891,21 +862,21 @@ where
                     });
                 }
 
-                cx.on_mouse_event(move |view_state, event: &MouseUpEvent, phase, cx| {
+                cx.on_mouse_event(move |event: &MouseUpEvent, phase, cx| {
                     if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
                         let mouse_click = ClickEvent {
                             down: mouse_down.clone(),
                             up: event.clone(),
                         };
                         for listener in &click_listeners {
-                            listener(view_state, &mouse_click, cx);
+                            listener(&mouse_click, cx);
                         }
                     }
                     *pending_mouse_down.borrow_mut() = None;
                     cx.notify();
                 });
             } else {
-                cx.on_mouse_event(move |_view_state, event: &MouseDownEvent, phase, cx| {
+                cx.on_mouse_event(move |event: &MouseDownEvent, phase, cx| {
                     if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
                         *pending_mouse_down.borrow_mut() = Some(event.clone());
                         cx.notify();
@@ -918,7 +889,7 @@ where
             let was_hovered = element_state.hover_state.clone();
             let has_mouse_down = element_state.pending_mouse_down.clone();
 
-            cx.on_mouse_event(move |view_state, event: &MouseMoveEvent, phase, cx| {
+            cx.on_mouse_event(move |event: &MouseMoveEvent, phase, cx| {
                 if phase != DispatchPhase::Bubble {
                     return;
                 }
@@ -930,7 +901,7 @@ where
                     *was_hovered = is_hovered;
                     drop(was_hovered);
 
-                    hover_listener(view_state, is_hovered, cx);
+                    (hover_listener.callback)(&is_hovered, cx);
                 }
             });
         }
@@ -939,7 +910,7 @@ where
             let active_tooltip = element_state.active_tooltip.clone();
             let pending_mouse_down = element_state.pending_mouse_down.clone();
 
-            cx.on_mouse_event(move |_, event: &MouseMoveEvent, phase, cx| {
+            cx.on_mouse_event(move |event: &MouseMoveEvent, phase, cx| {
                 if phase != DispatchPhase::Bubble {
                     return;
                 }
@@ -956,12 +927,12 @@ where
                         let active_tooltip = active_tooltip.clone();
                         let tooltip_builder = tooltip_builder.clone();
 
-                        move |view, mut cx| async move {
+                        move |mut cx| async move {
                             cx.background_executor().timer(TOOLTIP_DELAY).await;
-                            view.update(&mut cx, move |view_state, cx| {
+                            cx.update(|_, cx| {
                                 active_tooltip.borrow_mut().replace(ActiveTooltip {
                                     tooltip: Some(AnyTooltip {
-                                        view: tooltip_builder(view_state, cx),
+                                        view: tooltip_builder(cx),
                                         cursor_offset: cx.mouse_position(),
                                     }),
                                     _task: None,
@@ -979,7 +950,7 @@ where
             });
 
             let active_tooltip = element_state.active_tooltip.clone();
-            cx.on_mouse_event(move |_, _: &MouseDownEvent, _, _| {
+            cx.on_mouse_event(move |_: &MouseDownEvent, _, _| {
                 active_tooltip.borrow_mut().take();
             });
 
@@ -992,7 +963,7 @@ where
 
         let active_state = element_state.clicked_state.clone();
         if !active_state.borrow().is_clicked() {
-            cx.on_mouse_event(move |_, _: &MouseUpEvent, phase, cx| {
+            cx.on_mouse_event(move |_: &MouseUpEvent, phase, cx| {
                 if phase == DispatchPhase::Capture {
                     *active_state.borrow_mut() = ElementClickedState::default();
                     cx.notify();
@@ -1003,7 +974,7 @@ where
                 .group_active_style
                 .as_ref()
                 .and_then(|group_active| GroupBounds::get(&group_active.group, cx));
-            cx.on_mouse_event(move |_view, down: &MouseDownEvent, phase, cx| {
+            cx.on_mouse_event(move |down: &MouseDownEvent, phase, cx| {
                 if phase == DispatchPhase::Bubble {
                     let group = active_group_bounds
                         .map_or(false, |bounds| bounds.contains_point(&down.position));
@@ -1025,7 +996,7 @@ where
             let line_height = cx.line_height();
             let scroll_max = (content_size - bounds.size).max(&Size::default());
 
-            cx.on_mouse_event(move |_, event: &ScrollWheelEvent, phase, cx| {
+            cx.on_mouse_event(move |event: &ScrollWheelEvent, phase, cx| {
                 if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
                     let mut scroll_offset = scroll_offset.borrow_mut();
                     let old_scroll_offset = *scroll_offset;
@@ -1063,14 +1034,14 @@ where
             element_state.focus_handle.clone(),
             |_, cx| {
                 for listener in self.key_down_listeners.drain(..) {
-                    cx.on_key_event(move |state, event: &KeyDownEvent, phase, cx| {
-                        listener(state, event, phase, cx);
+                    cx.on_key_event(move |event: &KeyDownEvent, phase, cx| {
+                        listener(event, phase, cx);
                     })
                 }
 
                 for listener in self.key_up_listeners.drain(..) {
-                    cx.on_key_event(move |state, event: &KeyUpEvent, phase, cx| {
-                        listener(state, event, phase, cx);
+                    cx.on_key_event(move |event: &KeyUpEvent, phase, cx| {
+                        listener(event, phase, cx);
                     })
                 }
 
@@ -1081,9 +1052,7 @@ where
                 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)
-                        });
+                        cx.on_focus_changed(move |event, cx| listener(&focus_handle, event, cx));
                     }
                 }
 

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

@@ -1,18 +1,17 @@
 use crate::{
-    AnyElement, BorrowWindow, Bounds, Component, Element, InteractiveComponent,
-    InteractiveElementState, Interactivity, LayoutId, Pixels, SharedString, StyleRefinement,
-    Styled, ViewContext,
+    AnyElement, Bounds, Component, Element, InteractiveComponent, InteractiveElementState,
+    Interactivity, LayoutId, Pixels, SharedString, StyleRefinement, Styled, WindowContext,
 };
 use futures::FutureExt;
 use util::ResultExt;
 
-pub struct Img<V: 'static> {
-    interactivity: Interactivity<V>,
+pub struct Img {
+    interactivity: Interactivity,
     uri: Option<SharedString>,
     grayscale: bool,
 }
 
-pub fn img<V: 'static>() -> Img<V> {
+pub fn img() -> Img {
     Img {
         interactivity: Interactivity::default(),
         uri: None,
@@ -20,10 +19,7 @@ pub fn img<V: 'static>() -> Img<V> {
     }
 }
 
-impl<V> Img<V>
-where
-    V: 'static,
-{
+impl Img {
     pub fn uri(mut self, uri: impl Into<SharedString>) -> Self {
         self.uri = Some(uri.into());
         self
@@ -35,13 +31,13 @@ where
     }
 }
 
-impl<V> Component<V> for Img<V> {
-    fn render(self) -> AnyElement<V> {
+impl Component for Img {
+    fn render(self) -> AnyElement {
         AnyElement::new(self)
     }
 }
 
-impl<V> Element<V> for Img<V> {
+impl Element for Img {
     type ElementState = InteractiveElementState;
 
     fn element_id(&self) -> Option<crate::ElementId> {
@@ -50,9 +46,8 @@ impl<V> Element<V> for Img<V> {
 
     fn layout(
         &mut self,
-        _view_state: &mut V,
         element_state: Option<Self::ElementState>,
-        cx: &mut ViewContext<V>,
+        cx: &mut WindowContext,
     ) -> (LayoutId, Self::ElementState) {
         self.interactivity.layout(element_state, cx, |style, cx| {
             cx.request_layout(&style, None)
@@ -62,9 +57,8 @@ impl<V> Element<V> for Img<V> {
     fn paint(
         &mut self,
         bounds: Bounds<Pixels>,
-        _view_state: &mut V,
         element_state: &mut Self::ElementState,
-        cx: &mut ViewContext<V>,
+        cx: &mut WindowContext,
     ) {
         self.interactivity.paint(
             bounds,
@@ -89,7 +83,7 @@ impl<V> Element<V> for Img<V> {
                                 .log_err()
                         });
                     } else {
-                        cx.spawn(|_, mut cx| async move {
+                        cx.spawn(|mut cx| async move {
                             if image_future.await.ok().is_some() {
                                 cx.on_next_frame(|cx| cx.notify());
                             }
@@ -102,14 +96,14 @@ impl<V> Element<V> for Img<V> {
     }
 }
 
-impl<V> Styled for Img<V> {
+impl Styled for Img {
     fn style(&mut self) -> &mut StyleRefinement {
         &mut self.interactivity.base_style
     }
 }
 
-impl<V> InteractiveComponent<V> for Img<V> {
-    fn interactivity(&mut self) -> &mut Interactivity<V> {
+impl InteractiveComponent for Img {
+    fn interactivity(&mut self) -> &mut Interactivity {
         &mut self.interactivity
     }
 }

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

@@ -3,15 +3,15 @@ use taffy::style::{Display, Position};
 
 use crate::{
     point, AnyElement, BorrowWindow, Bounds, Component, Element, LayoutId, ParentComponent, Pixels,
-    Point, Size, Style,
+    Point, Size, Style, WindowContext,
 };
 
 pub struct OverlayState {
     child_layout_ids: SmallVec<[LayoutId; 4]>,
 }
 
-pub struct Overlay<V> {
-    children: SmallVec<[AnyElement<V>; 2]>,
+pub struct Overlay {
+    children: SmallVec<[AnyElement; 2]>,
     anchor_corner: AnchorCorner,
     fit_mode: OverlayFitMode,
     // todo!();
@@ -21,7 +21,7 @@ pub struct Overlay<V> {
 
 /// overlay gives you a floating element that will avoid overflowing the window bounds.
 /// Its children should have no margin to avoid measurement issues.
-pub fn overlay<V: 'static>() -> Overlay<V> {
+pub fn overlay() -> Overlay {
     Overlay {
         children: SmallVec::new(),
         anchor_corner: AnchorCorner::TopLeft,
@@ -30,7 +30,7 @@ pub fn overlay<V: 'static>() -> Overlay<V> {
     }
 }
 
-impl<V> Overlay<V> {
+impl Overlay {
     /// Sets which corner of the overlay should be anchored to the current position.
     pub fn anchor(mut self, anchor: AnchorCorner) -> Self {
         self.anchor_corner = anchor;
@@ -51,19 +51,19 @@ impl<V> Overlay<V> {
     }
 }
 
-impl<V: 'static> ParentComponent<V> for Overlay<V> {
-    fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<V>; 2]> {
+impl ParentComponent for Overlay {
+    fn children_mut(&mut self) -> &mut SmallVec<[AnyElement; 2]> {
         &mut self.children
     }
 }
 
-impl<V: 'static> Component<V> for Overlay<V> {
-    fn render(self) -> AnyElement<V> {
+impl Component for Overlay {
+    fn render(self) -> AnyElement {
         AnyElement::new(self)
     }
 }
 
-impl<V: 'static> Element<V> for Overlay<V> {
+impl Element for Overlay {
     type ElementState = OverlayState;
 
     fn element_id(&self) -> Option<crate::ElementId> {
@@ -72,14 +72,13 @@ impl<V: 'static> Element<V> for Overlay<V> {
 
     fn layout(
         &mut self,
-        view_state: &mut V,
         _: Option<Self::ElementState>,
-        cx: &mut crate::ViewContext<V>,
+        cx: &mut WindowContext,
     ) -> (crate::LayoutId, Self::ElementState) {
         let child_layout_ids = self
             .children
             .iter_mut()
-            .map(|child| child.layout(view_state, cx))
+            .map(|child| child.layout(cx))
             .collect::<SmallVec<_>>();
 
         let mut overlay_style = Style::default();
@@ -94,9 +93,8 @@ impl<V: 'static> Element<V> for Overlay<V> {
     fn paint(
         &mut self,
         bounds: crate::Bounds<crate::Pixels>,
-        view_state: &mut V,
         element_state: &mut Self::ElementState,
-        cx: &mut crate::ViewContext<V>,
+        cx: &mut WindowContext,
     ) {
         if element_state.child_layout_ids.is_empty() {
             return;
@@ -157,7 +155,7 @@ impl<V: 'static> Element<V> for Overlay<V> {
 
         cx.with_element_offset(desired.origin - bounds.origin, |cx| {
             for child in &mut self.children {
-                child.paint(view_state, cx);
+                child.paint(cx);
             }
         })
     }

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

@@ -1,36 +1,36 @@
 use crate::{
     AnyElement, Bounds, Component, Element, ElementId, InteractiveComponent,
     InteractiveElementState, Interactivity, LayoutId, Pixels, SharedString, StyleRefinement,
-    Styled, ViewContext,
+    Styled, WindowContext,
 };
 use util::ResultExt;
 
-pub struct Svg<V: 'static> {
-    interactivity: Interactivity<V>,
+pub struct Svg {
+    interactivity: Interactivity,
     path: Option<SharedString>,
 }
 
-pub fn svg<V: 'static>() -> Svg<V> {
+pub fn svg() -> Svg {
     Svg {
         interactivity: Interactivity::default(),
         path: None,
     }
 }
 
-impl<V> Svg<V> {
+impl Svg {
     pub fn path(mut self, path: impl Into<SharedString>) -> Self {
         self.path = Some(path.into());
         self
     }
 }
 
-impl<V> Component<V> for Svg<V> {
-    fn render(self) -> AnyElement<V> {
+impl Component for Svg {
+    fn render(self) -> AnyElement {
         AnyElement::new(self)
     }
 }
 
-impl<V> Element<V> for Svg<V> {
+impl Element for Svg {
     type ElementState = InteractiveElementState;
 
     fn element_id(&self) -> Option<ElementId> {
@@ -39,9 +39,8 @@ impl<V> Element<V> for Svg<V> {
 
     fn layout(
         &mut self,
-        _view_state: &mut V,
         element_state: Option<Self::ElementState>,
-        cx: &mut ViewContext<V>,
+        cx: &mut WindowContext,
     ) -> (LayoutId, Self::ElementState) {
         self.interactivity.layout(element_state, cx, |style, cx| {
             cx.request_layout(&style, None)
@@ -51,9 +50,8 @@ impl<V> Element<V> for Svg<V> {
     fn paint(
         &mut self,
         bounds: Bounds<Pixels>,
-        _view_state: &mut V,
         element_state: &mut Self::ElementState,
-        cx: &mut ViewContext<V>,
+        cx: &mut WindowContext,
     ) where
         Self: Sized,
     {
@@ -66,14 +64,14 @@ impl<V> Element<V> for Svg<V> {
     }
 }
 
-impl<V> Styled for Svg<V> {
+impl Styled for Svg {
     fn style(&mut self) -> &mut StyleRefinement {
         &mut self.interactivity.base_style
     }
 }
 
-impl<V> InteractiveComponent<V> for Svg<V> {
-    fn interactivity(&mut self) -> &mut Interactivity<V> {
+impl InteractiveComponent for Svg {
+    fn interactivity(&mut self) -> &mut Interactivity {
         &mut self.interactivity
     }
 }

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

@@ -1,6 +1,6 @@
 use crate::{
-    AnyElement, BorrowWindow, Bounds, Component, Element, ElementId, LayoutId, Pixels,
-    SharedString, Size, TextRun, ViewContext, WrappedLine,
+    AnyElement, Bounds, Component, Element, ElementId, LayoutId, Pixels, SharedString, Size,
+    TextRun, WindowContext, WrappedLine,
 };
 use parking_lot::{Mutex, MutexGuard};
 use smallvec::SmallVec;
@@ -26,13 +26,13 @@ impl Text {
     }
 }
 
-impl<V: 'static> Component<V> for Text {
-    fn render(self) -> AnyElement<V> {
+impl Component for Text {
+    fn render(self) -> AnyElement {
         AnyElement::new(self)
     }
 }
 
-impl<V: 'static> Element<V> for Text {
+impl Element for Text {
     type ElementState = TextState;
 
     fn element_id(&self) -> Option<crate::ElementId> {
@@ -41,9 +41,8 @@ impl<V: 'static> Element<V> for Text {
 
     fn layout(
         &mut self,
-        _view: &mut V,
         element_state: Option<Self::ElementState>,
-        cx: &mut ViewContext<V>,
+        cx: &mut WindowContext,
     ) -> (LayoutId, Self::ElementState) {
         let element_state = element_state.unwrap_or_default();
         let text_system = cx.text_system().clone();
@@ -120,9 +119,8 @@ impl<V: 'static> Element<V> for Text {
     fn paint(
         &mut self,
         bounds: Bounds<Pixels>,
-        _: &mut V,
         element_state: &mut Self::ElementState,
-        cx: &mut ViewContext<V>,
+        cx: &mut WindowContext,
     ) {
         let element_state = element_state.lock();
         let element_state = element_state
@@ -165,7 +163,7 @@ struct InteractiveTextState {
     clicked_range_ixs: Rc<Cell<SmallVec<[usize; 1]>>>,
 }
 
-impl<V: 'static> Element<V> for InteractiveText {
+impl Element for InteractiveText {
     type ElementState = InteractiveTextState;
 
     fn element_id(&self) -> Option<ElementId> {
@@ -174,23 +172,22 @@ impl<V: 'static> Element<V> for InteractiveText {
 
     fn layout(
         &mut self,
-        view_state: &mut V,
         element_state: Option<Self::ElementState>,
-        cx: &mut ViewContext<V>,
+        cx: &mut WindowContext,
     ) -> (LayoutId, Self::ElementState) {
         if let Some(InteractiveTextState {
             text_state,
             clicked_range_ixs,
         }) = element_state
         {
-            let (layout_id, text_state) = self.text.layout(view_state, Some(text_state), cx);
+            let (layout_id, text_state) = self.text.layout(Some(text_state), cx);
             let element_state = InteractiveTextState {
                 text_state,
                 clicked_range_ixs,
             };
             (layout_id, element_state)
         } else {
-            let (layout_id, text_state) = self.text.layout(view_state, None, cx);
+            let (layout_id, text_state) = self.text.layout(None, cx);
             let element_state = InteractiveTextState {
                 text_state,
                 clicked_range_ixs: Rc::default(),
@@ -202,17 +199,15 @@ impl<V: 'static> Element<V> for InteractiveText {
     fn paint(
         &mut self,
         bounds: Bounds<Pixels>,
-        view_state: &mut V,
         element_state: &mut Self::ElementState,
-        cx: &mut ViewContext<V>,
+        cx: &mut WindowContext,
     ) {
-        self.text
-            .paint(bounds, view_state, &mut element_state.text_state, cx)
+        self.text.paint(bounds, &mut element_state.text_state, cx)
     }
 }
 
-impl<V: 'static> Component<V> for SharedString {
-    fn render(self) -> AnyElement<V> {
+impl Component for SharedString {
+    fn render(self) -> AnyElement {
         Text {
             text: self,
             runs: None,
@@ -221,8 +216,8 @@ impl<V: 'static> Component<V> for SharedString {
     }
 }
 
-impl<V: 'static> Component<V> for &'static str {
-    fn render(self) -> AnyElement<V> {
+impl Component for &'static str {
+    fn render(self) -> AnyElement {
         Text {
             text: self.into(),
             runs: None,
@@ -233,8 +228,8 @@ impl<V: 'static> Component<V> for &'static str {
 
 // TODO: Figure out how to pass `String` to `child` without this.
 // This impl doesn't exist in the `gpui2` crate.
-impl<V: 'static> Component<V> for String {
-    fn render(self) -> AnyElement<V> {
+impl Component for String {
+    fn render(self) -> AnyElement {
         Text {
             text: self.into(),
             runs: None,

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

@@ -1,7 +1,7 @@
 use crate::{
-    point, px, size, AnyElement, AvailableSpace, BorrowWindow, Bounds, Component, Element,
-    ElementId, InteractiveComponent, InteractiveElementState, Interactivity, LayoutId, Pixels,
-    Point, Size, StyleRefinement, Styled, ViewContext,
+    point, px, size, AnyElement, AvailableSpace, Bounds, Component, Element, ElementId,
+    InteractiveComponent, InteractiveElementState, Interactivity, LayoutId, Pixels, Point, Size,
+    StyleRefinement, Styled, WindowContext,
 };
 use smallvec::SmallVec;
 use std::{cell::RefCell, cmp, mem, ops::Range, rc::Rc};
@@ -10,15 +10,14 @@ use taffy::style::Overflow;
 /// uniform_list provides lazy rendering for a set of items that are of uniform height.
 /// When rendered into a container with overflow-y: hidden and a fixed (or max) height,
 /// uniform_list will only render the visibile subset of items.
-pub fn uniform_list<I, V, C>(
+pub fn uniform_list<I, C>(
     id: I,
     item_count: usize,
-    f: impl 'static + Fn(&mut V, Range<usize>, &mut ViewContext<V>) -> Vec<C>,
-) -> UniformList<V>
+    f: impl 'static + Fn(Range<usize>, &mut WindowContext) -> Vec<C>,
+) -> UniformList
 where
     I: Into<ElementId>,
-    V: 'static,
-    C: Component<V>,
+    C: Component,
 {
     let id = id.into();
     let mut style = StyleRefinement::default();
@@ -29,8 +28,8 @@ where
         style,
         item_count,
         item_to_measure_index: 0,
-        render_items: Box::new(move |view, visible_range, cx| {
-            f(view, visible_range, cx)
+        render_items: Box::new(move |visible_range, cx| {
+            f(visible_range, cx)
                 .into_iter()
                 .map(|component| component.render())
                 .collect()
@@ -43,19 +42,14 @@ where
     }
 }
 
-pub struct UniformList<V: 'static> {
+pub struct UniformList {
     id: ElementId,
     style: StyleRefinement,
     item_count: usize,
     item_to_measure_index: usize,
-    render_items: Box<
-        dyn for<'a> Fn(
-            &'a mut V,
-            Range<usize>,
-            &'a mut ViewContext<V>,
-        ) -> SmallVec<[AnyElement<V>; 64]>,
-    >,
-    interactivity: Interactivity<V>,
+    render_items:
+        Box<dyn for<'a> Fn(Range<usize>, &'a mut WindowContext) -> SmallVec<[AnyElement; 64]>>,
+    interactivity: Interactivity,
     scroll_handle: Option<UniformListScrollHandle>,
 }
 
@@ -89,7 +83,7 @@ impl UniformListScrollHandle {
     }
 }
 
-impl<V: 'static> Styled for UniformList<V> {
+impl Styled for UniformList {
     fn style(&mut self) -> &mut StyleRefinement {
         &mut self.style
     }
@@ -101,7 +95,7 @@ pub struct UniformListState {
     item_size: Size<Pixels>,
 }
 
-impl<V: 'static> Element<V> for UniformList<V> {
+impl Element for UniformList {
     type ElementState = UniformListState;
 
     fn element_id(&self) -> Option<crate::ElementId> {
@@ -110,16 +104,15 @@ impl<V: 'static> Element<V> for UniformList<V> {
 
     fn layout(
         &mut self,
-        view_state: &mut V,
         element_state: Option<Self::ElementState>,
-        cx: &mut ViewContext<V>,
+        cx: &mut WindowContext,
     ) -> (LayoutId, Self::ElementState) {
         let max_items = self.item_count;
         let rem_size = cx.rem_size();
         let item_size = element_state
             .as_ref()
             .map(|s| s.item_size)
-            .unwrap_or_else(|| self.measure_item(view_state, None, cx));
+            .unwrap_or_else(|| self.measure_item(None, cx));
 
         let (layout_id, interactive) =
             self.interactivity
@@ -161,9 +154,8 @@ impl<V: 'static> Element<V> for UniformList<V> {
     fn paint(
         &mut self,
         bounds: Bounds<crate::Pixels>,
-        view_state: &mut V,
         element_state: &mut Self::ElementState,
-        cx: &mut ViewContext<V>,
+        cx: &mut WindowContext,
     ) {
         let style =
             self.interactivity
@@ -209,9 +201,8 @@ impl<V: 'static> Element<V> for UniformList<V> {
                     style.paint(bounds, cx);
 
                     if self.item_count > 0 {
-                        let item_height = self
-                            .measure_item(view_state, Some(padded_bounds.size.width), cx)
-                            .height;
+                        let item_height =
+                            self.measure_item(Some(padded_bounds.size.width), cx).height;
                         if let Some(scroll_handle) = self.scroll_handle.clone() {
                             scroll_handle.0.borrow_mut().replace(ScrollHandleState {
                                 item_height,
@@ -233,7 +224,7 @@ impl<V: 'static> Element<V> for UniformList<V> {
                                 self.item_count,
                             );
 
-                        let mut items = (self.render_items)(view_state, visible_range.clone(), cx);
+                        let mut items = (self.render_items)(visible_range.clone(), cx);
                         cx.with_z_index(1, |cx| {
                             for (item, ix) in items.iter_mut().zip(visible_range) {
                                 let item_origin = padded_bounds.origin
@@ -242,7 +233,7 @@ impl<V: 'static> Element<V> for UniformList<V> {
                                     AvailableSpace::Definite(padded_bounds.size.width),
                                     AvailableSpace::Definite(item_height),
                                 );
-                                item.draw(item_origin, available_space, view_state, cx);
+                                item.draw(item_origin, available_space, cx);
                             }
                         });
                     }
@@ -253,24 +244,19 @@ impl<V: 'static> Element<V> for UniformList<V> {
     }
 }
 
-impl<V> UniformList<V> {
+impl UniformList {
     pub fn with_width_from_item(mut self, item_index: Option<usize>) -> Self {
         self.item_to_measure_index = item_index.unwrap_or(0);
         self
     }
 
-    fn measure_item(
-        &self,
-        view_state: &mut V,
-        list_width: Option<Pixels>,
-        cx: &mut ViewContext<V>,
-    ) -> Size<Pixels> {
+    fn measure_item(&self, list_width: Option<Pixels>, cx: &mut WindowContext) -> Size<Pixels> {
         if self.item_count == 0 {
             return Size::default();
         }
 
         let item_ix = cmp::min(self.item_to_measure_index, self.item_count - 1);
-        let mut items = (self.render_items)(view_state, item_ix..item_ix + 1, cx);
+        let mut items = (self.render_items)(item_ix..item_ix + 1, cx);
         let mut item_to_measure = items.pop().unwrap();
         let available_space = size(
             list_width.map_or(AvailableSpace::MinContent, |width| {
@@ -278,7 +264,7 @@ impl<V> UniformList<V> {
             }),
             AvailableSpace::MinContent,
         );
-        item_to_measure.measure(available_space, view_state, cx)
+        item_to_measure.measure(available_space, cx)
     }
 
     pub fn track_scroll(mut self, handle: UniformListScrollHandle) -> Self {
@@ -287,14 +273,14 @@ impl<V> UniformList<V> {
     }
 }
 
-impl<V> InteractiveComponent<V> for UniformList<V> {
-    fn interactivity(&mut self) -> &mut crate::Interactivity<V> {
+impl InteractiveComponent for UniformList {
+    fn interactivity(&mut self) -> &mut crate::Interactivity {
         &mut self.interactivity
     }
 }
 
-impl<V: 'static> Component<V> for UniformList<V> {
-    fn render(self) -> AnyElement<V> {
+impl Component for UniformList {
+    fn render(self) -> AnyElement {
         AnyElement::new(self)
     }
 }

crates/gpui2/src/gpui2.rs 🔗

@@ -196,6 +196,30 @@ 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 🔗

@@ -1,9 +1,8 @@
 use crate::{
-    div, point, Component, Div, FocusHandle, Keystroke, Modifiers, Pixels, Point, Render,
-    ViewContext,
+    div, point, Div, FocusHandle, Keystroke, Modifiers, Pixels, Point, Render, ViewContext,
 };
 use smallvec::SmallVec;
-use std::{any::Any, fmt::Debug, marker::PhantomData, ops::Deref, path::PathBuf};
+use std::{any::Any, fmt::Debug, ops::Deref, path::PathBuf};
 
 #[derive(Clone, Debug, Eq, PartialEq)]
 pub struct KeyDownEvent {
@@ -60,32 +59,6 @@ pub struct ClickEvent {
     pub up: MouseUpEvent,
 }
 
-pub struct Drag<S, R, V, E>
-where
-    R: Fn(&mut V, &mut ViewContext<V>) -> E,
-    V: 'static,
-    E: Component<()>,
-{
-    pub state: S,
-    pub render_drag_handle: R,
-    view_type: PhantomData<V>,
-}
-
-impl<S, R, V, E> Drag<S, R, V, E>
-where
-    R: Fn(&mut V, &mut ViewContext<V>) -> E,
-    V: 'static,
-    E: Component<()>,
-{
-    pub fn new(state: S, render_drag_handle: R) -> Self {
-        Drag {
-            state,
-            render_drag_handle,
-            view_type: PhantomData,
-        }
-    }
-}
-
 #[derive(Hash, PartialEq, Eq, Copy, Clone, Debug)]
 pub enum MouseButton {
     Left,
@@ -194,7 +167,7 @@ impl Deref for MouseExitEvent {
 pub struct ExternalPaths(pub(crate) SmallVec<[PathBuf; 2]>);
 
 impl Render for ExternalPaths {
-    type Element = Div<Self>;
+    type Element = Div;
 
     fn render(&mut self, _: &mut ViewContext<Self>) -> Self::Element {
         div() // Intentionally left empty because the platform will render icons for the dragged files
@@ -287,7 +260,7 @@ pub struct FocusEvent {
 mod test {
     use crate::{
         self as gpui, div, Component, Div, FocusHandle, InteractiveComponent, KeyBinding,
-        Keystroke, ParentComponent, Render, Stateful, TestAppContext, ViewContext, VisualContext,
+        Keystroke, ParentComponent, Render, Stateful, TestAppContext, VisualContext,
     };
 
     struct TestView {
@@ -299,20 +272,24 @@ mod test {
     actions!(TestAction);
 
     impl Render for TestView {
-        type Element = Stateful<Self, Div<Self>>;
+        type Element = Stateful<Div>;
 
-        fn render(&mut self, _: &mut gpui::ViewContext<Self>) -> Self::Element {
+        fn render(&mut self, cx: &mut gpui::ViewContext<Self>) -> Self::Element {
             div().id("testview").child(
                 div()
                     .key_context("parent")
-                    .on_key_down(|this: &mut TestView, _, _, _| this.saw_key_down = true)
-                    .on_action(|this: &mut TestView, _: &TestAction, _| this.saw_action = true)
-                    .child(|this: &mut Self, _cx: &mut ViewContext<Self>| {
+                    .on_key_down(cx.callback(|this, _, _| this.saw_key_down = true))
+                    .on_action(
+                        cx.callback(|this: &mut TestView, _: &TestAction, _| {
+                            this.saw_action = true
+                        }),
+                    )
+                    .child(
                         div()
                             .key_context("nested")
-                            .track_focus(&this.focus_handle)
-                            .render()
-                    }),
+                            .track_focus(&self.focus_handle)
+                            .render(),
+                    ),
             )
         }
     }

crates/gpui2/src/style.rs 🔗

@@ -2,7 +2,7 @@ use crate::{
     black, phi, point, rems, AbsoluteLength, BorrowAppContext, BorrowWindow, Bounds, ContentMask,
     Corners, CornersRefinement, CursorStyle, DefiniteLength, Edges, EdgesRefinement, Font,
     FontFeatures, FontStyle, FontWeight, Hsla, Length, Pixels, Point, PointRefinement, Rgba,
-    SharedString, Size, SizeRefinement, Styled, TextRun, ViewContext,
+    SharedString, Size, SizeRefinement, Styled, TextRun, WindowContext,
 };
 use refineable::{Cascade, Refineable};
 use smallvec::SmallVec;
@@ -313,7 +313,7 @@ impl Style {
     }
 
     /// Paints the background of an element styled with this style.
-    pub fn paint<V: 'static>(&self, bounds: Bounds<Pixels>, cx: &mut ViewContext<V>) {
+    pub fn paint(&self, bounds: Bounds<Pixels>, cx: &mut WindowContext) {
         let rem_size = cx.rem_size();
 
         cx.with_z_index(0, |cx| {

crates/gpui2/src/view.rs 🔗

@@ -11,7 +11,7 @@ use std::{
 };
 
 pub trait Render: 'static + Sized {
-    type Element: Element<Self> + 'static;
+    type Element: Element + 'static;
 
     fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element;
 }
@@ -67,7 +67,7 @@ impl<V: 'static> View<V> {
 
     pub fn render_with<C>(&self, component: C) -> RenderViewWith<C, V>
     where
-        C: 'static + Component<V>,
+        C: 'static + Component,
     {
         RenderViewWith {
             view: self.clone(),
@@ -105,8 +105,8 @@ impl<V> PartialEq for View<V> {
 
 impl<V> Eq for View<V> {}
 
-impl<V: Render, ParentViewState: 'static> Component<ParentViewState> for View<V> {
-    fn render(self) -> AnyElement<ParentViewState> {
+impl<V: Render> Component for View<V> {
+    fn render(self) -> AnyElement {
         AnyElement::new(AnyView::from(self))
     }
 }
@@ -211,8 +211,8 @@ impl AnyView {
     }
 }
 
-impl<V: 'static> Component<V> for AnyView {
-    fn render(self) -> AnyElement<V> {
+impl Component for AnyView {
+    fn render(self) -> AnyElement {
         AnyElement::new(self)
     }
 }
@@ -227,7 +227,7 @@ impl<V: Render> From<View<V>> for AnyView {
     }
 }
 
-impl<ParentViewState: 'static> Element<ParentViewState> for AnyView {
+impl Element for AnyView {
     type ElementState = Box<dyn Any>;
 
     fn element_id(&self) -> Option<ElementId> {
@@ -236,9 +236,8 @@ impl<ParentViewState: 'static> Element<ParentViewState> for AnyView {
 
     fn layout(
         &mut self,
-        _view_state: &mut ParentViewState,
         _element_state: Option<Self::ElementState>,
-        cx: &mut ViewContext<ParentViewState>,
+        cx: &mut WindowContext,
     ) -> (LayoutId, Self::ElementState) {
         (self.layout)(self, cx)
     }
@@ -246,9 +245,8 @@ impl<ParentViewState: 'static> Element<ParentViewState> for AnyView {
     fn paint(
         &mut self,
         _bounds: Bounds<Pixels>,
-        _view_state: &mut ParentViewState,
         rendered_element: &mut Self::ElementState,
-        cx: &mut ViewContext<ParentViewState>,
+        cx: &mut WindowContext,
     ) {
         (self.paint)(self, rendered_element, cx)
     }
@@ -281,41 +279,39 @@ impl<V: Render> From<WeakView<V>> for AnyWeakView {
     }
 }
 
-// impl<T, E> Render for T
-// where
-//     T: 'static + FnMut(&mut WindowContext) -> E,
-//     E: 'static + Send + Element<T>,
-// {
-//     type Element = E;
+impl<T, E> Render for T
+where
+    T: 'static + FnMut(&mut WindowContext) -> E,
+    E: 'static + Send + Element,
+{
+    type Element = E;
 
-//     fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
-//         (self)(cx)
-//     }
-// }
+    fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
+        (self)(cx)
+    }
+}
 
 pub struct RenderViewWith<C, V> {
     view: View<V>,
     component: Option<C>,
 }
 
-impl<C, ParentViewState, ViewState> Component<ParentViewState> for RenderViewWith<C, ViewState>
+impl<C, V> Component for RenderViewWith<C, V>
 where
-    C: 'static + Component<ViewState>,
-    ParentViewState: 'static,
-    ViewState: 'static,
+    V: 'static + Render,
+    C: 'static + Component,
 {
-    fn render(self) -> AnyElement<ParentViewState> {
+    fn render(self) -> AnyElement {
         AnyElement::new(self)
     }
 }
 
-impl<C, ParentViewState, ViewState> Element<ParentViewState> for RenderViewWith<C, ViewState>
+impl<C, V> Element for RenderViewWith<C, V>
 where
-    C: 'static + Component<ViewState>,
-    ParentViewState: 'static,
-    ViewState: 'static,
+    V: 'static + Render,
+    C: 'static + Component,
 {
-    type ElementState = AnyElement<ViewState>;
+    type ElementState = AnyElement;
 
     fn element_id(&self) -> Option<ElementId> {
         Some(self.view.entity_id().into())
@@ -323,25 +319,21 @@ where
 
     fn layout(
         &mut self,
-        _: &mut ParentViewState,
         _: Option<Self::ElementState>,
-        cx: &mut ViewContext<ParentViewState>,
+        cx: &mut WindowContext,
     ) -> (LayoutId, Self::ElementState) {
-        self.view.update(cx, |view, cx| {
-            let mut element = self.component.take().unwrap().render();
-            let layout_id = element.layout(view, cx);
-            (layout_id, element)
-        })
+        let mut element = self.component.take().unwrap().render();
+        let layout_id = element.layout(cx);
+        (layout_id, element)
     }
 
     fn paint(
         &mut self,
         _: Bounds<Pixels>,
-        _: &mut ParentViewState,
         element: &mut Self::ElementState,
-        cx: &mut ViewContext<ParentViewState>,
+        cx: &mut WindowContext,
     ) {
-        self.view.update(cx, |view, cx| element.paint(view, cx))
+        element.paint(cx)
     }
 }
 
@@ -357,7 +349,7 @@ mod any_view {
             let view = view.clone().downcast::<V>().unwrap();
             view.update(cx, |view, cx| {
                 let mut element = AnyElement::new(view.render(cx));
-                let layout_id = element.layout(view, cx);
+                let layout_id = element.layout(cx);
                 (layout_id, Box::new(element) as Box<dyn Any>)
             })
         })
@@ -369,9 +361,8 @@ mod any_view {
         cx: &mut WindowContext,
     ) {
         cx.with_element_id(Some(view.model.entity_id), |cx| {
-            let view = view.clone().downcast::<V>().unwrap();
-            let element = element.downcast_mut::<AnyElement<V>>().unwrap();
-            view.update(cx, |view, cx| element.paint(view, cx))
+            let element = element.downcast_mut::<AnyElement>().unwrap();
+            element.paint(cx);
         })
     }
 }

crates/gpui2/src/window.rs 🔗

@@ -1,15 +1,15 @@
 use crate::{
     key_dispatch::DispatchActionListener, px, size, Action, AnyBox, AnyDrag, AnyView, AppContext,
-    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,
+    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,
 };
 use anyhow::{anyhow, Context as _, Result};
 use collections::HashMap;
@@ -1436,6 +1436,47 @@ impl<'a> WindowContext<'a> {
             .dispatch_tree
             .bindings_for_action(action)
     }
+
+    ///========== ELEMENT RELATED FUNCTIONS ===========
+    pub fn with_key_dispatch<R>(
+        &mut self,
+        context: KeyContext,
+        focus_handle: Option<FocusHandle>,
+        f: impl FnOnce(Option<FocusHandle>, &mut Self) -> R,
+    ) -> R {
+        let window = &mut self.window;
+        window
+            .current_frame
+            .dispatch_tree
+            .push_node(context.clone());
+        if let Some(focus_handle) = focus_handle.as_ref() {
+            window
+                .current_frame
+                .dispatch_tree
+                .make_focusable(focus_handle.id);
+        }
+        let result = f(focus_handle, self);
+
+        self.window.current_frame.dispatch_tree.pop_node();
+
+        result
+    }
+
+    /// Register a focus listener for the current frame only. It will be cleared
+    /// on the next frame render. You should use this method only from within elements,
+    /// and we may want to enforce that better via a different context type.
+    // todo!() Move this to `FrameContext` to emphasize its individuality?
+    pub fn on_focus_changed(
+        &mut self,
+        listener: impl Fn(&FocusEvent, &mut WindowContext) + 'static,
+    ) {
+        self.window
+            .current_frame
+            .focus_listeners
+            .push(Box::new(move |event, cx| {
+                listener(event, cx);
+            }));
+    }
 }
 
 impl Context for WindowContext<'_> {
@@ -2124,49 +2165,6 @@ impl<'a, V: 'static> ViewContext<'a, V> {
         )
     }
 
-    /// Register a focus listener for the current frame only. It will be cleared
-    /// on the next frame render. You should use this method only from within elements,
-    /// and we may want to enforce that better via a different context type.
-    // todo!() Move this to `FrameContext` to emphasize its individuality?
-    pub fn on_focus_changed(
-        &mut self,
-        listener: impl Fn(&mut V, &FocusEvent, &mut ViewContext<V>) + 'static,
-    ) {
-        let handle = self.view().downgrade();
-        self.window
-            .current_frame
-            .focus_listeners
-            .push(Box::new(move |event, cx| {
-                handle
-                    .update(cx, |view, cx| listener(view, event, cx))
-                    .log_err();
-            }));
-    }
-
-    pub fn with_key_dispatch<R>(
-        &mut self,
-        context: KeyContext,
-        focus_handle: Option<FocusHandle>,
-        f: impl FnOnce(Option<FocusHandle>, &mut Self) -> R,
-    ) -> R {
-        let window = &mut self.window;
-        window
-            .current_frame
-            .dispatch_tree
-            .push_node(context.clone());
-        if let Some(focus_handle) = focus_handle.as_ref() {
-            window
-                .current_frame
-                .dispatch_tree
-                .make_focusable(focus_handle.id);
-        }
-        let result = f(focus_handle, self);
-
-        self.window.current_frame.dispatch_tree.pop_node();
-
-        result
-    }
-
     pub fn spawn<Fut, R>(
         &mut self,
         f: impl FnOnce(WeakView<V>, AsyncWindowContext) -> Fut,
@@ -2284,6 +2282,25 @@ impl<'a, V: 'static> ViewContext<'a, V> {
     {
         self.defer(|_, cx| cx.emit(Manager::Dismiss))
     }
+
+    pub fn callback<E>(
+        &self,
+        f: impl Fn(&mut V, &E, &mut ViewContext<V>) + 'static,
+    ) -> CallbackHandle<E> {
+        let view = self.view().clone();
+        (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> {
+        let view = self.view().clone();
+        (move |cx: &mut WindowContext| view.update(cx, |view, cx| f(view, cx))).into()
+    }
 }
 
 impl<V> Context for ViewContext<'_, V> {