diff --git a/crates/gpui3/src/element.rs b/crates/gpui3/src/element.rs index c430ce3b5b..c42d867e94 100644 --- a/crates/gpui3/src/element.rs +++ b/crates/gpui3/src/element.rs @@ -22,10 +22,12 @@ pub trait Element: 'static { ) -> Result<()>; } -pub trait ParentElement { - fn children_mut(&mut self) -> &mut SmallVec<[AnyElement; 2]>; +pub trait ParentElement { + type State; - fn child(mut self, child: impl IntoAnyElement) -> Self + fn children_mut(&mut self) -> &mut SmallVec<[AnyElement; 2]>; + + fn child(mut self, child: impl IntoAnyElement) -> Self where Self: Sized, { @@ -33,7 +35,7 @@ pub trait ParentElement { self } - fn children(mut self, iter: impl IntoIterator>) -> Self + fn children(mut self, iter: impl IntoIterator>) -> Self where Self: Sized, { diff --git a/crates/gpui3/src/elements.rs b/crates/gpui3/src/elements.rs index 81d64ea132..d879153488 100644 --- a/crates/gpui3/src/elements.rs +++ b/crates/gpui3/src/elements.rs @@ -6,6 +6,7 @@ mod svg; mod text; pub use div::*; +pub use hoverable::*; pub use img::*; pub use stateless::*; pub use svg::*; diff --git a/crates/gpui3/src/elements/div.rs b/crates/gpui3/src/elements/div.rs index 646890e1b3..5fd4b0b243 100644 --- a/crates/gpui3/src/elements/div.rs +++ b/crates/gpui3/src/elements/div.rs @@ -1,7 +1,7 @@ use crate::{ AnyElement, Bounds, Element, Interactive, LayoutId, MouseEventListeners, Overflow, - ParentElement, Pixels, Point, Refineable, RefinementCascade, Result, Style, StyleHelpers, - Styled, ViewContext, + ParentElement, Pixels, Point, Refineable, RefinementCascade, Result, Style, Styled, + ViewContext, }; use parking_lot::Mutex; use smallvec::SmallVec; @@ -249,16 +249,16 @@ impl Styled for Div { } } -impl StyleHelpers for Div {} - impl Interactive for Div { fn listeners(&mut self) -> &mut MouseEventListeners { &mut self.listeners } } -impl ParentElement for Div { - fn children_mut(&mut self) -> &mut SmallVec<[AnyElement; 2]> { +impl ParentElement for Div { + type State = S; + + fn children_mut(&mut self) -> &mut SmallVec<[AnyElement; 2]> { &mut self.children } } diff --git a/crates/gpui3/src/elements/hoverable.rs b/crates/gpui3/src/elements/hoverable.rs index d6d9e1b1e5..fc43c895ce 100644 --- a/crates/gpui3/src/elements/hoverable.rs +++ b/crates/gpui3/src/elements/hoverable.rs @@ -1,26 +1,33 @@ use crate::{ - Bounds, Element, Interactive, MouseEventListeners, Pixels, Style, Styled, ViewContext, + AnyElement, Bounds, DispatchPhase, Element, Interactive, MouseEventListeners, MouseMoveEvent, + ParentElement, Pixels, Styled, ViewContext, }; use anyhow::Result; -use refineable::{CascadeSlot, RefinementCascade}; -use std::{cell::Cell, rc::Rc}; - -pub fn hoverable(mut child: E) -> Hoverable { - Hoverable { - hovered: Rc::new(Cell::new(false)), - cascade_slot: child.style_cascade().reserve(), - hovered_style: Default::default(), - child, - } -} +use refineable::{CascadeSlot, Refineable, RefinementCascade}; +use smallvec::SmallVec; +use std::sync::{ + atomic::{AtomicBool, Ordering::SeqCst}, + Arc, +}; pub struct Hoverable { - hovered: Rc>, + hovered: Arc, cascade_slot: CascadeSlot, - hovered_style: RefinementCascade, + hovered_style: ::Refinement, child: E, } +impl Hoverable { + pub fn new(mut child: E) -> Self { + Self { + hovered: Arc::new(AtomicBool::new(false)), + cascade_slot: child.style_cascade().reserve(), + hovered_style: Default::default(), + child, + } + } +} + impl Styled for Hoverable where E: Styled, @@ -61,22 +68,30 @@ impl Element for Hoverable { frame_state: &mut Self::FrameState, cx: &mut ViewContext, ) -> Result<()> { - todo!() - // self.hovered.set(bounds.contains_point(cx.mouse_position())); + let hovered = bounds.contains_point(cx.mouse_position()); + let slot = self.cascade_slot; + let style = hovered.then_some(self.hovered_style.clone()); + self.style_cascade().set(slot, style); + self.hovered.store(hovered, SeqCst); - // let slot = self.cascade_slot; - // let style = self.hovered.get().then_some(self.hovered_style.clone()); - // self.style_cascade().set(slot, style); + let hovered = self.hovered.clone(); + cx.on_mouse_event(move |event: &MouseMoveEvent, phase, cx| { + if phase == DispatchPhase::Capture { + if bounds.contains_point(event.position) != hovered.load(SeqCst) { + cx.notify(); + } + } + }); - // let hovered = self.hovered.clone(); - // cx.on_event(layout.order, move |_view, _: &MouseMovedEvent, cx| { - // cx.bubble_event(); - // if bounds.contains_point(cx.mouse_position()) != hovered.get() { - // cx.repaint(); - // } - // }); - - // self.child - // .paint(view, parent_origin, layout, paint_state, cx); + self.child.paint(bounds, state, frame_state, cx)?; + Ok(()) + } +} + +impl ParentElement for Hoverable { + type State = E::State; + + fn children_mut(&mut self) -> &mut SmallVec<[AnyElement; 2]> { + self.child.children_mut() } } diff --git a/crates/gpui3/src/elements/img.rs b/crates/gpui3/src/elements/img.rs index 68aac46446..26315bb54a 100644 --- a/crates/gpui3/src/elements/img.rs +++ b/crates/gpui3/src/elements/img.rs @@ -1,6 +1,6 @@ use crate::{ - BorrowWindow, Bounds, Element, LayoutId, Pixels, Result, SharedString, Style, StyleHelpers, - Styled, ViewContext, + BorrowWindow, Bounds, Element, LayoutId, Pixels, Result, SharedString, Style, Styled, + ViewContext, }; use futures::FutureExt; use refineable::RefinementCascade; @@ -98,5 +98,3 @@ impl Styled for Img { self.style.base() } } - -impl StyleHelpers for Img {} diff --git a/crates/gpui3/src/elements/pressable.rs b/crates/gpui3/src/elements/pressable.rs index 960342a5e6..6e9b031eda 100644 --- a/crates/gpui3/src/elements/pressable.rs +++ b/crates/gpui3/src/elements/pressable.rs @@ -85,8 +85,6 @@ impl + Styleable> Element for Pressable { } } -impl> StyleHelpers for Pressable {} - impl + Styleable> Interactive for Pressable { fn interaction_handlers(&mut self) -> &mut InteractionHandlers { self.child.interaction_handlers() diff --git a/crates/gpui3/src/elements/svg.rs b/crates/gpui3/src/elements/svg.rs index 4af620ec06..b5db4a1d39 100644 --- a/crates/gpui3/src/elements/svg.rs +++ b/crates/gpui3/src/elements/svg.rs @@ -1,4 +1,4 @@ -use crate::{Bounds, Element, LayoutId, Pixels, Result, SharedString, Style, StyleHelpers, Styled}; +use crate::{Bounds, Element, LayoutId, Pixels, Result, SharedString, Style, Styled}; use refineable::RefinementCascade; use std::marker::PhantomData; @@ -68,5 +68,3 @@ impl Styled for Svg { self.style.base() } } - -impl StyleHelpers for Svg {} diff --git a/crates/gpui3/src/style_helpers.rs b/crates/gpui3/src/style_helpers.rs index a0cdbffd91..ece5341b12 100644 --- a/crates/gpui3/src/style_helpers.rs +++ b/crates/gpui3/src/style_helpers.rs @@ -516,3 +516,5 @@ pub trait StyleHelpers: Styled