Checkpoint

Antonio Scandurra created

Change summary

crates/gpui3/src/element.rs      |  17 -
crates/gpui3/src/elements/div.rs | 195 +++---------------------------
crates/gpui3/src/elements/img.rs |  40 +++--
crates/gpui3/src/elements/svg.rs |  40 +++--
crates/gpui3/src/gpui3.rs        |   2 
crates/gpui3/src/interactive.rs  | 218 ++++++++++++++++++++++++++++++++++
crates/gpui3/src/view.rs         |  10 
crates/gpui3/src/window.rs       |  13 ++
8 files changed, 309 insertions(+), 226 deletions(-)

Detailed changes

crates/gpui3/src/element.rs 🔗

@@ -24,35 +24,28 @@ pub trait Element: 'static + Send + Sync + IntoAnyElement<Self::ViewState> {
     );
 }
 
-pub trait IdentifiedElement: Element {
-    fn id(&self) -> ElementId {
-        Element::id(self).unwrap()
-    }
-}
-
 #[derive(Deref, DerefMut, Default, Clone, Debug, Eq, PartialEq, Hash)]
 pub(crate) struct GlobalElementId(SmallVec<[ElementId; 8]>);
 
-pub trait ElementKind: 'static + Send + Sync {
+pub trait ElementIdentity: 'static + Send + Sync {
     fn id(&self) -> Option<ElementId>;
 }
 
-pub struct IdentifiedElementKind(pub(crate) ElementId);
-pub struct AnonymousElementKind;
+pub struct IdentifiedElement(pub(crate) ElementId);
+pub struct AnonymousElement;
 
-impl ElementKind for IdentifiedElementKind {
+impl ElementIdentity for IdentifiedElement {
     fn id(&self) -> Option<ElementId> {
         Some(self.0.clone())
     }
 }
 
-impl ElementKind for AnonymousElementKind {
+impl ElementIdentity for AnonymousElement {
     fn id(&self) -> Option<ElementId> {
         None
     }
 }
 
-
 pub trait ParentElement: Element {
     fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<Self::ViewState>; 2]>;
     fn group_mut(&mut self) -> &mut Option<SharedString>;

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

@@ -1,8 +1,8 @@
 use crate::{
-    AnonymousElementKind, AnyElement, AppContext, BorrowWindow, Bounds, DispatchPhase, Element,
-    ElementId, ElementKind, IdentifiedElement, IdentifiedElementKind, IntoAnyElement, LayoutId,
-    MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, Overflow, Pixels, Point,
-    ScrollWheelEvent, SharedString, Style, StyleRefinement, Styled, ViewContext,
+    AnonymousElement, AnyElement, AppContext, BorrowWindow, Bounds, Clickable, DispatchPhase,
+    Element, ElementId, ElementIdentity, IdentifiedElement, Interactive, IntoAnyElement, LayoutId,
+    MouseClickEvent, MouseDownEvent, MouseEventListeners, MouseMoveEvent, MouseUpEvent, Overflow,
+    Pixels, Point, ScrollWheelEvent, SharedString, Style, StyleRefinement, Styled, ViewContext,
 };
 use collections::HashMap;
 use parking_lot::Mutex;
@@ -59,12 +59,12 @@ impl ScrollState {
     }
 }
 
-pub fn div<S>() -> Div<S, AnonymousElementKind>
+pub fn div<S>() -> Div<S, AnonymousElement>
 where
     S: 'static + Send + Sync,
 {
     Div {
-        kind: AnonymousElementKind,
+        kind: AnonymousElement,
         children: SmallVec::new(),
         group: None,
         base_style: StyleRefinement::default(),
@@ -76,7 +76,7 @@ where
     }
 }
 
-pub struct Div<V: 'static + Send + Sync, K: ElementKind = AnonymousElementKind> {
+pub struct Div<V: 'static + Send + Sync, K: ElementIdentity = AnonymousElement> {
     kind: K,
     children: SmallVec<[AnyElement<V>; 2]>,
     group: Option<SharedString>,
@@ -93,13 +93,13 @@ struct GroupStyle {
     style: StyleRefinement,
 }
 
-impl<V> Div<V, AnonymousElementKind>
+impl<V> Div<V, AnonymousElement>
 where
     V: 'static + Send + Sync,
 {
-    pub fn id(self, id: impl Into<ElementId>) -> Div<V, IdentifiedElementKind> {
+    pub fn id(self, id: impl Into<ElementId>) -> Div<V, IdentifiedElement> {
         Div {
-            kind: IdentifiedElementKind(id.into()),
+            kind: IdentifiedElement(id.into()),
             children: self.children,
             group: self.group,
             base_style: self.base_style,
@@ -112,115 +112,22 @@ where
     }
 }
 
-impl<V> Div<V, IdentifiedElementKind>
+impl<V, K> Interactive for Div<V, K>
 where
     V: 'static + Send + Sync,
+    K: ElementIdentity,
 {
-    pub fn on_mouse_down(
-        mut self,
-        button: MouseButton,
-        handler: impl Fn(&mut V, &MouseDownEvent, &mut ViewContext<V>) + Send + Sync + 'static,
-    ) -> Self {
-        self.listeners
-            .mouse_down
-            .push(Arc::new(move |view, event, bounds, phase, cx| {
-                if phase == DispatchPhase::Bubble
-                    && event.button == button
-                    && bounds.contains_point(&event.position)
-                {
-                    handler(view, event, cx)
-                }
-            }));
-        self
-    }
-
-    pub fn on_mouse_up(
-        mut self,
-        button: MouseButton,
-        handler: impl Fn(&mut V, &MouseUpEvent, &mut ViewContext<V>) + Send + Sync + 'static,
-    ) -> Self {
-        self.listeners
-            .mouse_up
-            .push(Arc::new(move |view, event, bounds, phase, cx| {
-                if phase == DispatchPhase::Bubble
-                    && event.button == button
-                    && bounds.contains_point(&event.position)
-                {
-                    handler(view, event, cx)
-                }
-            }));
-        self
-    }
-
-    pub fn on_mouse_down_out(
-        mut self,
-        button: MouseButton,
-        handler: impl Fn(&mut V, &MouseDownEvent, &mut ViewContext<V>) + Send + Sync + 'static,
-    ) -> Self {
-        self.listeners
-            .mouse_down
-            .push(Arc::new(move |view, event, bounds, phase, cx| {
-                if phase == DispatchPhase::Capture
-                    && event.button == button
-                    && !bounds.contains_point(&event.position)
-                {
-                    handler(view, event, cx)
-                }
-            }));
-        self
-    }
-
-    pub fn on_mouse_up_out(
-        mut self,
-        button: MouseButton,
-        handler: impl Fn(&mut V, &MouseUpEvent, &mut ViewContext<V>) + Send + Sync + 'static,
-    ) -> Self {
-        self.listeners
-            .mouse_up
-            .push(Arc::new(move |view, event, bounds, phase, cx| {
-                if phase == DispatchPhase::Capture
-                    && event.button == button
-                    && !bounds.contains_point(&event.position)
-                {
-                    handler(view, event, cx);
-                }
-            }));
-        self
-    }
-
-    pub fn on_mouse_move(
-        mut self,
-        handler: impl Fn(&mut V, &MouseMoveEvent, &mut ViewContext<V>) + Send + Sync + 'static,
-    ) -> Self {
-        self.listeners
-            .mouse_move
-            .push(Arc::new(move |view, event, bounds, phase, cx| {
-                if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
-                    handler(view, event, cx);
-                }
-            }));
-        self
-    }
-
-    pub fn on_scroll_wheel(
-        mut self,
-        handler: impl Fn(&mut V, &ScrollWheelEvent, &mut ViewContext<V>) + Send + Sync + 'static,
-    ) -> Self {
-        self.listeners
-            .scroll_wheel
-            .push(Arc::new(move |view, event, bounds, phase, cx| {
-                if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
-                    handler(view, event, cx);
-                }
-            }));
-        self
+    fn listeners(&mut self) -> &mut MouseEventListeners<V> {
+        &mut self.listeners
     }
 }
 
+impl<V> Clickable for Div<V, IdentifiedElement> where V: 'static + Send + Sync {}
+
 impl<V, K> Div<V, K>
 where
     V: 'static + Send + Sync,
-    K: ElementKind,
+    K: ElementIdentity,
 {
     pub fn group(mut self, group: impl Into<SharedString>) -> Self {
         self.group = Some(group.into());
@@ -378,7 +285,7 @@ where
                         up: event.clone(),
                     };
                     for listener in &click_listeners {
-                        listener(state, &mouse_click, &bounds, cx);
+                        listener(state, &mouse_click, cx);
                     }
                 }
 
@@ -421,7 +328,7 @@ where
 impl<V, K> Element for Div<V, K>
 where
     V: 'static + Send + Sync,
-    K: ElementKind,
+    K: ElementIdentity,
 {
     type ViewState = V;
     type ElementState = DivState;
@@ -513,16 +420,10 @@ where
     }
 }
 
-impl<V: 'static + Send + Sync> IdentifiedElement for Div<V, IdentifiedElementKind> {
-    fn id(&self) -> ElementId {
-        self.kind.0.clone()
-    }
-}
-
 impl<V, K> IntoAnyElement<V> for Div<V, K>
 where
     V: 'static + Send + Sync,
-    K: ElementKind,
+    K: ElementIdentity,
 {
     fn into_any(self) -> AnyElement<V> {
         AnyElement::new(self)
@@ -532,67 +433,13 @@ where
 impl<V, K> Styled for Div<V, K>
 where
     V: 'static + Send + Sync,
-    K: ElementKind,
+    K: ElementIdentity,
 {
     fn style(&mut self) -> &mut StyleRefinement {
         &mut self.base_style
     }
 }
 
-pub struct MouseClickEvent {
-    pub down: MouseDownEvent,
-    pub up: MouseUpEvent,
-}
-
-type MouseDownHandler<V> = Arc<
-    dyn Fn(&mut V, &MouseDownEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
-        + Send
-        + Sync
-        + 'static,
->;
-type MouseUpHandler<V> = Arc<
-    dyn Fn(&mut V, &MouseUpEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
-        + Send
-        + Sync
-        + 'static,
->;
-type MouseClickHandler<V> = Arc<
-    dyn Fn(&mut V, &MouseClickEvent, &Bounds<Pixels>, &mut ViewContext<V>) + Send + Sync + 'static,
->;
-
-type MouseMoveHandler<V> = Arc<
-    dyn Fn(&mut V, &MouseMoveEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
-        + Send
-        + Sync
-        + 'static,
->;
-type ScrollWheelHandler<V> = Arc<
-    dyn Fn(&mut V, &ScrollWheelEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
-        + Send
-        + Sync
-        + 'static,
->;
-
-pub struct MouseEventListeners<V: 'static> {
-    mouse_down: SmallVec<[MouseDownHandler<V>; 2]>,
-    mouse_up: SmallVec<[MouseUpHandler<V>; 2]>,
-    mouse_click: SmallVec<[MouseClickHandler<V>; 2]>,
-    mouse_move: SmallVec<[MouseMoveHandler<V>; 2]>,
-    scroll_wheel: SmallVec<[ScrollWheelHandler<V>; 2]>,
-}
-
-impl<V> Default for MouseEventListeners<V> {
-    fn default() -> Self {
-        Self {
-            mouse_down: SmallVec::new(),
-            mouse_up: SmallVec::new(),
-            mouse_click: SmallVec::new(),
-            mouse_move: SmallVec::new(),
-            scroll_wheel: SmallVec::new(),
-        }
-    }
-}
-
 fn paint_hover_listener<V>(bounds: Bounds<Pixels>, cx: &mut ViewContext<V>)
 where
     V: 'static + Send + Sync,

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

@@ -1,18 +1,18 @@
 use crate::{
-    div, AnonymousElementKind, AnyElement, BorrowWindow, Bounds, Div, DivState, Element, ElementId,
-    ElementKind, IdentifiedElement, IdentifiedElementKind, IntoAnyElement, LayoutId, Pixels,
-    SharedString, StyleRefinement, Styled, ViewContext,
+    div, AnonymousElement, AnyElement, BorrowWindow, Bounds, Clickable, Div, DivState, Element,
+    ElementId, ElementIdentity, IdentifiedElement, Interactive, IntoAnyElement, LayoutId,
+    MouseEventListeners, Pixels, SharedString, StyleRefinement, Styled, ViewContext,
 };
 use futures::FutureExt;
 use util::ResultExt;
 
-pub struct Img<V: 'static + Send + Sync, K: ElementKind = AnonymousElementKind> {
+pub struct Img<V: 'static + Send + Sync, K: ElementIdentity = AnonymousElement> {
     base: Div<V, K>,
     uri: Option<SharedString>,
     grayscale: bool,
 }
 
-pub fn img<V>() -> Img<V, AnonymousElementKind>
+pub fn img<V>() -> Img<V, AnonymousElement>
 where
     V: 'static + Send + Sync,
 {
@@ -26,7 +26,7 @@ where
 impl<V, K> Img<V, K>
 where
     V: 'static + Send + Sync,
-    K: ElementKind,
+    K: ElementIdentity,
 {
     pub fn uri(mut self, uri: impl Into<SharedString>) -> Self {
         self.uri = Some(uri.into());
@@ -39,8 +39,8 @@ where
     }
 }
 
-impl<V: 'static + Send + Sync> Img<V, AnonymousElementKind> {
-    pub fn id(self, id: impl Into<ElementId>) -> Img<V, IdentifiedElementKind> {
+impl<V: 'static + Send + Sync> Img<V, AnonymousElement> {
+    pub fn id(self, id: impl Into<ElementId>) -> Img<V, IdentifiedElement> {
         Img {
             base: self.base.id(id),
             uri: self.uri,
@@ -52,7 +52,7 @@ impl<V: 'static + Send + Sync> Img<V, AnonymousElementKind> {
 impl<V, K> IntoAnyElement<V> for Img<V, K>
 where
     V: 'static + Send + Sync,
-    K: ElementKind,
+    K: ElementIdentity,
 {
     fn into_any(self) -> AnyElement<V> {
         AnyElement::new(self)
@@ -62,7 +62,7 @@ where
 impl<V, K> Element for Img<V, K>
 where
     V: Send + Sync + 'static,
-    K: ElementKind,
+    K: ElementIdentity,
 {
     type ViewState = V;
     type ElementState = DivState;
@@ -121,18 +121,24 @@ where
     }
 }
 
-impl<V: 'static + Send + Sync> IdentifiedElement for Img<V, IdentifiedElementKind> {
-    fn id(&self) -> ElementId {
-        IdentifiedElement::id(&self.base)
-    }
-}
-
 impl<V, K> Styled for Img<V, K>
 where
     V: 'static + Send + Sync,
-    K: ElementKind,
+    K: ElementIdentity,
 {
     fn style(&mut self) -> &mut StyleRefinement {
         self.base.style()
     }
 }
+
+impl<V, K> Interactive for Img<V, K>
+where
+    V: 'static + Send + Sync,
+    K: ElementIdentity,
+{
+    fn listeners(&mut self) -> &mut MouseEventListeners<V> {
+        self.base.listeners()
+    }
+}
+
+impl<V> Clickable for Img<V, IdentifiedElement> where V: 'static + Send + Sync {}

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

@@ -1,16 +1,16 @@
 use crate::{
-    div, AnonymousElementKind, AnyElement, Bounds, Div, DivState, Element, ElementId, ElementKind,
-    IdentifiedElement, IdentifiedElementKind, IntoAnyElement, LayoutId, Pixels, SharedString,
-    StyleRefinement, Styled,
+    div, AnonymousElement, AnyElement, Bounds, Clickable, Div, DivState, Element, ElementId,
+    ElementIdentity, IdentifiedElement, Interactive, IntoAnyElement, LayoutId, MouseEventListeners,
+    Pixels, SharedString, StyleRefinement, Styled,
 };
 use util::ResultExt;
 
-pub struct Svg<V: 'static + Send + Sync, K: ElementKind = AnonymousElementKind> {
+pub struct Svg<V: 'static + Send + Sync, K: ElementIdentity = AnonymousElement> {
     base: Div<V, K>,
     path: Option<SharedString>,
 }
 
-pub fn svg<V>() -> Svg<V, AnonymousElementKind>
+pub fn svg<V>() -> Svg<V, AnonymousElement>
 where
     V: 'static + Send + Sync,
 {
@@ -23,7 +23,7 @@ where
 impl<V, K> Svg<V, K>
 where
     V: 'static + Send + Sync,
-    K: ElementKind,
+    K: ElementIdentity,
 {
     pub fn path(mut self, path: impl Into<SharedString>) -> Self {
         self.path = Some(path.into());
@@ -31,8 +31,8 @@ where
     }
 }
 
-impl<V: 'static + Send + Sync> Svg<V, AnonymousElementKind> {
-    pub fn id(self, id: impl Into<ElementId>) -> Svg<V, IdentifiedElementKind> {
+impl<V: 'static + Send + Sync> Svg<V, AnonymousElement> {
+    pub fn id(self, id: impl Into<ElementId>) -> Svg<V, IdentifiedElement> {
         Svg {
             base: self.base.id(id),
             path: self.path,
@@ -43,7 +43,7 @@ impl<V: 'static + Send + Sync> Svg<V, AnonymousElementKind> {
 impl<V, K> IntoAnyElement<V> for Svg<V, K>
 where
     V: 'static + Send + Sync,
-    K: ElementKind,
+    K: ElementIdentity,
 {
     fn into_any(self) -> AnyElement<V> {
         AnyElement::new(self)
@@ -53,7 +53,7 @@ where
 impl<V, K> Element for Svg<V, K>
 where
     V: 'static + Send + Sync,
-    K: ElementKind,
+    K: ElementIdentity,
 {
     type ViewState = V;
     type ElementState = DivState;
@@ -96,18 +96,24 @@ where
     }
 }
 
-impl<V: 'static + Send + Sync> IdentifiedElement for Svg<V, IdentifiedElementKind> {
-    fn id(&self) -> ElementId {
-        IdentifiedElement::id(&self.base)
-    }
-}
-
 impl<V, K> Styled for Svg<V, K>
 where
     V: 'static + Send + Sync,
-    K: ElementKind,
+    K: ElementIdentity,
 {
     fn style(&mut self) -> &mut StyleRefinement {
         self.base.style()
     }
 }
+
+impl<V, K> Interactive for Svg<V, K>
+where
+    V: 'static + Send + Sync,
+    K: ElementIdentity,
+{
+    fn listeners(&mut self) -> &mut MouseEventListeners<V> {
+        self.base.listeners()
+    }
+}
+
+impl<V> Clickable for Svg<V, IdentifiedElement> where V: 'static + Send + Sync {}

crates/gpui3/src/gpui3.rs 🔗

@@ -7,6 +7,7 @@ mod events;
 mod executor;
 mod geometry;
 mod image_cache;
+mod interactive;
 mod platform;
 mod scene;
 mod style;
@@ -30,6 +31,7 @@ pub use executor::*;
 pub use geometry::*;
 pub use gpui3_macros::*;
 pub use image_cache::*;
+pub use interactive::*;
 pub use platform::*;
 pub use refineable::*;
 pub use scene::*;

crates/gpui3/src/interactive.rs 🔗

@@ -0,0 +1,218 @@
+use smallvec::SmallVec;
+
+use crate::{
+    Bounds, DispatchPhase, Element, MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent,
+    Pixels, ScrollWheelEvent, ViewContext,
+};
+use std::sync::Arc;
+
+pub trait Interactive: Element {
+    fn listeners(&mut self) -> &mut MouseEventListeners<Self::ViewState>;
+
+    fn on_mouse_down(
+        mut self,
+        button: MouseButton,
+        handler: impl Fn(&mut Self::ViewState, &MouseDownEvent, &mut ViewContext<Self::ViewState>)
+            + Send
+            + Sync
+            + 'static,
+    ) -> Self
+    where
+        Self: Sized,
+    {
+        self.listeners()
+            .mouse_down
+            .push(Arc::new(move |view, event, bounds, phase, cx| {
+                if phase == DispatchPhase::Bubble
+                    && event.button == button
+                    && bounds.contains_point(&event.position)
+                {
+                    handler(view, event, cx)
+                }
+            }));
+        self
+    }
+
+    fn on_mouse_up(
+        mut self,
+        button: MouseButton,
+        handler: impl Fn(&mut Self::ViewState, &MouseUpEvent, &mut ViewContext<Self::ViewState>)
+            + Send
+            + Sync
+            + 'static,
+    ) -> Self
+    where
+        Self: Sized,
+    {
+        self.listeners()
+            .mouse_up
+            .push(Arc::new(move |view, event, bounds, phase, cx| {
+                if phase == DispatchPhase::Bubble
+                    && event.button == button
+                    && bounds.contains_point(&event.position)
+                {
+                    handler(view, event, cx)
+                }
+            }));
+        self
+    }
+
+    fn on_mouse_down_out(
+        mut self,
+        button: MouseButton,
+        handler: impl Fn(&mut Self::ViewState, &MouseDownEvent, &mut ViewContext<Self::ViewState>)
+            + Send
+            + Sync
+            + 'static,
+    ) -> Self
+    where
+        Self: Sized,
+    {
+        self.listeners()
+            .mouse_down
+            .push(Arc::new(move |view, event, bounds, phase, cx| {
+                if phase == DispatchPhase::Capture
+                    && event.button == button
+                    && !bounds.contains_point(&event.position)
+                {
+                    handler(view, event, cx)
+                }
+            }));
+        self
+    }
+
+    fn on_mouse_up_out(
+        mut self,
+        button: MouseButton,
+        handler: impl Fn(&mut Self::ViewState, &MouseUpEvent, &mut ViewContext<Self::ViewState>)
+            + Send
+            + Sync
+            + 'static,
+    ) -> Self
+    where
+        Self: Sized,
+    {
+        self.listeners()
+            .mouse_up
+            .push(Arc::new(move |view, event, bounds, phase, cx| {
+                if phase == DispatchPhase::Capture
+                    && event.button == button
+                    && !bounds.contains_point(&event.position)
+                {
+                    handler(view, event, cx);
+                }
+            }));
+        self
+    }
+
+    fn on_mouse_move(
+        mut self,
+        handler: impl Fn(&mut Self::ViewState, &MouseMoveEvent, &mut ViewContext<Self::ViewState>)
+            + Send
+            + Sync
+            + 'static,
+    ) -> Self
+    where
+        Self: Sized,
+    {
+        self.listeners()
+            .mouse_move
+            .push(Arc::new(move |view, event, bounds, phase, cx| {
+                if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
+                    handler(view, event, cx);
+                }
+            }));
+        self
+    }
+
+    fn on_scroll_wheel(
+        mut self,
+        handler: impl Fn(&mut Self::ViewState, &ScrollWheelEvent, &mut ViewContext<Self::ViewState>)
+            + Send
+            + Sync
+            + 'static,
+    ) -> Self
+    where
+        Self: Sized,
+    {
+        self.listeners()
+            .scroll_wheel
+            .push(Arc::new(move |view, event, bounds, phase, cx| {
+                if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
+                    handler(view, event, cx);
+                }
+            }));
+        self
+    }
+}
+
+pub trait Clickable: Interactive {
+    fn on_click(
+        mut self,
+        handler: impl Fn(&mut Self::ViewState, &MouseClickEvent, &mut ViewContext<Self::ViewState>)
+            + Send
+            + Sync
+            + 'static,
+    ) -> Self
+    where
+        Self: Sized,
+    {
+        self.listeners()
+            .mouse_click
+            .push(Arc::new(move |view, event, cx| handler(view, event, cx)));
+        self
+    }
+}
+
+type MouseDownHandler<V> = Arc<
+    dyn Fn(&mut V, &MouseDownEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
+        + Send
+        + Sync
+        + 'static,
+>;
+type MouseUpHandler<V> = Arc<
+    dyn Fn(&mut V, &MouseUpEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
+        + Send
+        + Sync
+        + 'static,
+>;
+type MouseClickHandler<V> =
+    Arc<dyn Fn(&mut V, &MouseClickEvent, &mut ViewContext<V>) + Send + Sync + 'static>;
+
+type MouseMoveHandler<V> = Arc<
+    dyn Fn(&mut V, &MouseMoveEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
+        + Send
+        + Sync
+        + 'static,
+>;
+type ScrollWheelHandler<V> = Arc<
+    dyn Fn(&mut V, &ScrollWheelEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
+        + Send
+        + Sync
+        + 'static,
+>;
+
+pub struct MouseEventListeners<V: 'static> {
+    pub mouse_down: SmallVec<[MouseDownHandler<V>; 2]>,
+    pub mouse_up: SmallVec<[MouseUpHandler<V>; 2]>,
+    pub mouse_click: SmallVec<[MouseClickHandler<V>; 2]>,
+    pub mouse_move: SmallVec<[MouseMoveHandler<V>; 2]>,
+    pub scroll_wheel: SmallVec<[ScrollWheelHandler<V>; 2]>,
+}
+
+impl<V> Default for MouseEventListeners<V> {
+    fn default() -> Self {
+        Self {
+            mouse_down: SmallVec::new(),
+            mouse_up: SmallVec::new(),
+            mouse_click: SmallVec::new(),
+            mouse_move: SmallVec::new(),
+            scroll_wheel: SmallVec::new(),
+        }
+    }
+}
+
+pub struct MouseClickEvent {
+    pub down: MouseDownEvent,
+    pub up: MouseUpEvent,
+}

crates/gpui3/src/view.rs 🔗

@@ -1,8 +1,8 @@
 use parking_lot::Mutex;
 
 use crate::{
-    AnyBox, AnyElement, BorrowWindow, Bounds, Element, ElementId, EntityId, Handle,
-    IdentifiedElement, IntoAnyElement, LayoutId, Pixels, ViewContext, WindowContext,
+    AnyBox, AnyElement, BorrowWindow, Bounds, Element, ElementId, EntityId, Handle, IntoAnyElement,
+    LayoutId, Pixels, ViewContext, WindowContext,
 };
 use std::{marker::PhantomData, sync::Arc};
 
@@ -86,8 +86,6 @@ impl<S: 'static + Send + Sync> Element for View<S> {
     }
 }
 
-impl<S: Send + Sync + 'static> IdentifiedElement for View<S> {}
-
 struct EraseViewState<ViewState: 'static + Send + Sync, ParentViewState> {
     view: View<ViewState>,
     parent_view_state_type: PhantomData<ParentViewState>,
@@ -148,7 +146,7 @@ impl<S: Send + Sync + 'static> ViewObject for View<S> {
     }
 
     fn layout(&mut self, cx: &mut WindowContext) -> (LayoutId, AnyBox) {
-        cx.with_element_id(IdentifiedElement::id(self), |cx| {
+        cx.with_element_id(self.entity_id(), |cx| {
             self.state.update(cx, |state, cx| {
                 let mut element = (self.render)(state, cx);
                 let layout_id = element.layout(state, cx);
@@ -159,7 +157,7 @@ impl<S: Send + Sync + 'static> ViewObject for View<S> {
     }
 
     fn paint(&mut self, _: Bounds<Pixels>, element: &mut AnyBox, cx: &mut WindowContext) {
-        cx.with_element_id(IdentifiedElement::id(self), |cx| {
+        cx.with_element_id(self.entity_id(), |cx| {
             self.state.update(cx, |state, cx| {
                 let element = element.downcast_mut::<AnyElement<S>>().unwrap();
                 element.paint(state, None, cx);

crates/gpui3/src/window.rs 🔗

@@ -1145,6 +1145,13 @@ impl From<SmallVec<[u32; 16]>> for StackingOrder {
 pub enum ElementId {
     View(EntityId),
     Number(usize),
+    Name(SharedString),
+}
+
+impl From<EntityId> for ElementId {
+    fn from(id: EntityId) -> Self {
+        ElementId::View(id)
+    }
 }
 
 impl From<usize> for ElementId {
@@ -1158,3 +1165,9 @@ impl From<i32> for ElementId {
         Self::Number(id as usize)
     }
 }
+
+impl From<SharedString> for ElementId {
+    fn from(id: SharedString) -> Self {
+        ElementId::Name(id)
+    }
+}