From 4ce7f059c3db625e33abe37424d6a09768b731b8 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Tue, 17 Oct 2023 21:37:09 +0200 Subject: [PATCH] Checkpoint --- 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(-) create mode 100644 crates/gpui3/src/interactive.rs diff --git a/crates/gpui3/src/element.rs b/crates/gpui3/src/element.rs index 60a0171664..06cc7ff6ca 100644 --- a/crates/gpui3/src/element.rs +++ b/crates/gpui3/src/element.rs @@ -24,35 +24,28 @@ pub trait Element: 'static + Send + Sync + IntoAnyElement { ); } -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; } -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 { Some(self.0.clone()) } } -impl ElementKind for AnonymousElementKind { +impl ElementIdentity for AnonymousElement { fn id(&self) -> Option { None } } - pub trait ParentElement: Element { fn children_mut(&mut self) -> &mut SmallVec<[AnyElement; 2]>; fn group_mut(&mut self) -> &mut Option; diff --git a/crates/gpui3/src/elements/div.rs b/crates/gpui3/src/elements/div.rs index 43a917975f..43034787ff 100644 --- a/crates/gpui3/src/elements/div.rs +++ b/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() -> Div +pub fn div() -> Div 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 { +pub struct Div { kind: K, children: SmallVec<[AnyElement; 2]>, group: Option, @@ -93,13 +93,13 @@ struct GroupStyle { style: StyleRefinement, } -impl Div +impl Div where V: 'static + Send + Sync, { - pub fn id(self, id: impl Into) -> Div { + pub fn id(self, id: impl Into) -> Div { 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 Div +impl Interactive for Div where V: 'static + Send + Sync, + K: ElementIdentity, { - pub fn on_mouse_down( - mut self, - button: MouseButton, - handler: impl Fn(&mut V, &MouseDownEvent, &mut ViewContext) + 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) + 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) + 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) + 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) + 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) + 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 { + &mut self.listeners } } +impl Clickable for Div where V: 'static + Send + Sync {} + impl Div where V: 'static + Send + Sync, - K: ElementKind, + K: ElementIdentity, { pub fn group(mut self, group: impl Into) -> 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 Element for Div where V: 'static + Send + Sync, - K: ElementKind, + K: ElementIdentity, { type ViewState = V; type ElementState = DivState; @@ -513,16 +420,10 @@ where } } -impl IdentifiedElement for Div { - fn id(&self) -> ElementId { - self.kind.0.clone() - } -} - impl IntoAnyElement for Div where V: 'static + Send + Sync, - K: ElementKind, + K: ElementIdentity, { fn into_any(self) -> AnyElement { AnyElement::new(self) @@ -532,67 +433,13 @@ where impl Styled for Div 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 = Arc< - dyn Fn(&mut V, &MouseDownEvent, &Bounds, DispatchPhase, &mut ViewContext) - + Send - + Sync - + 'static, ->; -type MouseUpHandler = Arc< - dyn Fn(&mut V, &MouseUpEvent, &Bounds, DispatchPhase, &mut ViewContext) - + Send - + Sync - + 'static, ->; -type MouseClickHandler = Arc< - dyn Fn(&mut V, &MouseClickEvent, &Bounds, &mut ViewContext) + Send + Sync + 'static, ->; - -type MouseMoveHandler = Arc< - dyn Fn(&mut V, &MouseMoveEvent, &Bounds, DispatchPhase, &mut ViewContext) - + Send - + Sync - + 'static, ->; -type ScrollWheelHandler = Arc< - dyn Fn(&mut V, &ScrollWheelEvent, &Bounds, DispatchPhase, &mut ViewContext) - + Send - + Sync - + 'static, ->; - -pub struct MouseEventListeners { - mouse_down: SmallVec<[MouseDownHandler; 2]>, - mouse_up: SmallVec<[MouseUpHandler; 2]>, - mouse_click: SmallVec<[MouseClickHandler; 2]>, - mouse_move: SmallVec<[MouseMoveHandler; 2]>, - scroll_wheel: SmallVec<[ScrollWheelHandler; 2]>, -} - -impl Default for MouseEventListeners { - 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(bounds: Bounds, cx: &mut ViewContext) where V: 'static + Send + Sync, diff --git a/crates/gpui3/src/elements/img.rs b/crates/gpui3/src/elements/img.rs index e90a865723..ce74a78990 100644 --- a/crates/gpui3/src/elements/img.rs +++ b/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 { +pub struct Img { base: Div, uri: Option, grayscale: bool, } -pub fn img() -> Img +pub fn img() -> Img where V: 'static + Send + Sync, { @@ -26,7 +26,7 @@ where impl Img where V: 'static + Send + Sync, - K: ElementKind, + K: ElementIdentity, { pub fn uri(mut self, uri: impl Into) -> Self { self.uri = Some(uri.into()); @@ -39,8 +39,8 @@ where } } -impl Img { - pub fn id(self, id: impl Into) -> Img { +impl Img { + pub fn id(self, id: impl Into) -> Img { Img { base: self.base.id(id), uri: self.uri, @@ -52,7 +52,7 @@ impl Img { impl IntoAnyElement for Img where V: 'static + Send + Sync, - K: ElementKind, + K: ElementIdentity, { fn into_any(self) -> AnyElement { AnyElement::new(self) @@ -62,7 +62,7 @@ where impl Element for Img where V: Send + Sync + 'static, - K: ElementKind, + K: ElementIdentity, { type ViewState = V; type ElementState = DivState; @@ -121,18 +121,24 @@ where } } -impl IdentifiedElement for Img { - fn id(&self) -> ElementId { - IdentifiedElement::id(&self.base) - } -} - impl Styled for Img where V: 'static + Send + Sync, - K: ElementKind, + K: ElementIdentity, { fn style(&mut self) -> &mut StyleRefinement { self.base.style() } } + +impl Interactive for Img +where + V: 'static + Send + Sync, + K: ElementIdentity, +{ + fn listeners(&mut self) -> &mut MouseEventListeners { + self.base.listeners() + } +} + +impl Clickable for Img where V: 'static + Send + Sync {} diff --git a/crates/gpui3/src/elements/svg.rs b/crates/gpui3/src/elements/svg.rs index 6c03e0850d..92b9d9ef9b 100644 --- a/crates/gpui3/src/elements/svg.rs +++ b/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 { +pub struct Svg { base: Div, path: Option, } -pub fn svg() -> Svg +pub fn svg() -> Svg where V: 'static + Send + Sync, { @@ -23,7 +23,7 @@ where impl Svg where V: 'static + Send + Sync, - K: ElementKind, + K: ElementIdentity, { pub fn path(mut self, path: impl Into) -> Self { self.path = Some(path.into()); @@ -31,8 +31,8 @@ where } } -impl Svg { - pub fn id(self, id: impl Into) -> Svg { +impl Svg { + pub fn id(self, id: impl Into) -> Svg { Svg { base: self.base.id(id), path: self.path, @@ -43,7 +43,7 @@ impl Svg { impl IntoAnyElement for Svg where V: 'static + Send + Sync, - K: ElementKind, + K: ElementIdentity, { fn into_any(self) -> AnyElement { AnyElement::new(self) @@ -53,7 +53,7 @@ where impl Element for Svg where V: 'static + Send + Sync, - K: ElementKind, + K: ElementIdentity, { type ViewState = V; type ElementState = DivState; @@ -96,18 +96,24 @@ where } } -impl IdentifiedElement for Svg { - fn id(&self) -> ElementId { - IdentifiedElement::id(&self.base) - } -} - impl Styled for Svg where V: 'static + Send + Sync, - K: ElementKind, + K: ElementIdentity, { fn style(&mut self) -> &mut StyleRefinement { self.base.style() } } + +impl Interactive for Svg +where + V: 'static + Send + Sync, + K: ElementIdentity, +{ + fn listeners(&mut self) -> &mut MouseEventListeners { + self.base.listeners() + } +} + +impl Clickable for Svg where V: 'static + Send + Sync {} diff --git a/crates/gpui3/src/gpui3.rs b/crates/gpui3/src/gpui3.rs index 30abb7559b..f858191e6b 100644 --- a/crates/gpui3/src/gpui3.rs +++ b/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::*; diff --git a/crates/gpui3/src/interactive.rs b/crates/gpui3/src/interactive.rs new file mode 100644 index 0000000000..a482f0366c --- /dev/null +++ b/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; + + fn on_mouse_down( + mut self, + button: MouseButton, + handler: impl Fn(&mut Self::ViewState, &MouseDownEvent, &mut ViewContext) + + 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) + + 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) + + 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) + + 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) + + 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) + + 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) + + 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 = Arc< + dyn Fn(&mut V, &MouseDownEvent, &Bounds, DispatchPhase, &mut ViewContext) + + Send + + Sync + + 'static, +>; +type MouseUpHandler = Arc< + dyn Fn(&mut V, &MouseUpEvent, &Bounds, DispatchPhase, &mut ViewContext) + + Send + + Sync + + 'static, +>; +type MouseClickHandler = + Arc) + Send + Sync + 'static>; + +type MouseMoveHandler = Arc< + dyn Fn(&mut V, &MouseMoveEvent, &Bounds, DispatchPhase, &mut ViewContext) + + Send + + Sync + + 'static, +>; +type ScrollWheelHandler = Arc< + dyn Fn(&mut V, &ScrollWheelEvent, &Bounds, DispatchPhase, &mut ViewContext) + + Send + + Sync + + 'static, +>; + +pub struct MouseEventListeners { + pub mouse_down: SmallVec<[MouseDownHandler; 2]>, + pub mouse_up: SmallVec<[MouseUpHandler; 2]>, + pub mouse_click: SmallVec<[MouseClickHandler; 2]>, + pub mouse_move: SmallVec<[MouseMoveHandler; 2]>, + pub scroll_wheel: SmallVec<[ScrollWheelHandler; 2]>, +} + +impl Default for MouseEventListeners { + 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, +} diff --git a/crates/gpui3/src/view.rs b/crates/gpui3/src/view.rs index c129f2b868..99e8c58b64 100644 --- a/crates/gpui3/src/view.rs +++ b/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 Element for View { } } -impl IdentifiedElement for View {} - struct EraseViewState { view: View, parent_view_state_type: PhantomData, @@ -148,7 +146,7 @@ impl ViewObject for View { } 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 ViewObject for View { } fn paint(&mut self, _: Bounds, 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::>().unwrap(); element.paint(state, None, cx); diff --git a/crates/gpui3/src/window.rs b/crates/gpui3/src/window.rs index fa52941ead..42786c0033 100644 --- a/crates/gpui3/src/window.rs +++ b/crates/gpui3/src/window.rs @@ -1145,6 +1145,13 @@ impl From> for StackingOrder { pub enum ElementId { View(EntityId), Number(usize), + Name(SharedString), +} + +impl From for ElementId { + fn from(id: EntityId) -> Self { + ElementId::View(id) + } } impl From for ElementId { @@ -1158,3 +1165,9 @@ impl From for ElementId { Self::Number(id as usize) } } + +impl From for ElementId { + fn from(id: SharedString) -> Self { + ElementId::Name(id) + } +}