Detailed changes
@@ -22,10 +22,12 @@ pub trait Element: 'static {
) -> Result<()>;
}
-pub trait ParentElement<S> {
- fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<S>; 2]>;
+pub trait ParentElement {
+ type State;
+
+ fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<Self::State>; 2]>;
- fn child(mut self, child: impl IntoAnyElement<S>) -> Self
+ fn child(mut self, child: impl IntoAnyElement<Self::State>) -> Self
where
Self: Sized,
{
@@ -33,7 +35,7 @@ pub trait ParentElement<S> {
self
}
- fn children(mut self, iter: impl IntoIterator<Item = impl IntoAnyElement<S>>) -> Self
+ fn children(mut self, iter: impl IntoIterator<Item = impl IntoAnyElement<Self::State>>) -> Self
where
Self: Sized,
{
@@ -6,6 +6,7 @@ mod svg;
mod text;
pub use div::*;
+pub use hoverable::*;
pub use img::*;
pub use stateless::*;
pub use svg::*;
@@ -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<V> Styled for Div<V> {
}
}
-impl<V> StyleHelpers for Div<V> {}
-
impl<V: Send + Sync + 'static> Interactive<V> for Div<V> {
fn listeners(&mut self) -> &mut MouseEventListeners<V> {
&mut self.listeners
}
}
-impl<V: 'static> ParentElement<V> for Div<V> {
- fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<V>; 2]> {
+impl<S: 'static> ParentElement for Div<S> {
+ type State = S;
+
+ fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<S>; 2]> {
&mut self.children
}
}
@@ -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<E: Styled>(mut child: E) -> Hoverable<E> {
- 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<E: Styled> {
- hovered: Rc<Cell<bool>>,
+ hovered: Arc<AtomicBool>,
cascade_slot: CascadeSlot,
- hovered_style: RefinementCascade<E::Style>,
+ hovered_style: <E::Style as Refineable>::Refinement,
child: E,
}
+impl<E: Styled> Hoverable<E> {
+ 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<E> Styled for Hoverable<E>
where
E: Styled,
@@ -61,22 +68,30 @@ impl<E: Element + Styled> Element for Hoverable<E> {
frame_state: &mut Self::FrameState,
cx: &mut ViewContext<Self::State>,
) -> 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(bounds, state, frame_state, cx)?;
+ Ok(())
+ }
+}
+
+impl<E: ParentElement + Styled> ParentElement for Hoverable<E> {
+ type State = E::State;
- // self.child
- // .paint(view, parent_origin, layout, paint_state, cx);
+ fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<Self::State>; 2]> {
+ self.child.children_mut()
}
}
@@ -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<S> Styled for Img<S> {
self.style.base()
}
}
-
-impl<S> StyleHelpers for Img<S> {}
@@ -85,8 +85,6 @@ impl<V: 'static, E: Element<V> + Styleable> Element<V> for Pressable<E> {
}
}
-impl<E: Styleable<Style = Style>> StyleHelpers for Pressable<E> {}
-
impl<V: 'static, E: Interactive<V> + Styleable> Interactive<V> for Pressable<E> {
fn interaction_handlers(&mut self) -> &mut InteractionHandlers<V> {
self.child.interaction_handlers()
@@ -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<S> Styled for Svg<S> {
self.style.base()
}
}
-
-impl<S> StyleHelpers for Svg<S> {}
@@ -516,3 +516,5 @@ pub trait StyleHelpers: Styled<Style = Style> {
self
}
}
+
+impl<E: Styled<Style = Style>> StyleHelpers for E {}
@@ -1,4 +1,4 @@
-use crate::{Refineable, RefinementCascade};
+use crate::{Hoverable, Refineable, RefinementCascade};
pub trait Styled {
type Style: Refineable + Default;
@@ -14,7 +14,7 @@ pub trait Styled {
where
Self: Sized,
{
- hoverable(self)
+ Hoverable::new(self)
}
// fn active(self) -> Pressable<Self>
@@ -2,10 +2,11 @@ use crate::{
image_cache::RenderImageParams, px, size, AnyView, AppContext, AsyncWindowContext,
AvailableSpace, BorrowAppContext, Bounds, BoxShadow, Context, Corners, DevicePixels, DisplayId,
Edges, Effect, Element, EntityId, Event, FontId, GlyphId, Handle, Hsla, ImageData, IsZero,
- LayoutId, MainThread, MainThreadOnly, MonochromeSprite, Path, Pixels, PlatformAtlas,
- PlatformWindow, Point, PolychromeSprite, Quad, Reference, RenderGlyphParams, RenderSvgParams,
- ScaledPixels, SceneBuilder, Shadow, SharedString, Size, Style, TaffyLayoutEngine, Task,
- Underline, UnderlineStyle, WeakHandle, WindowOptions, SUBPIXEL_VARIANTS,
+ LayoutId, MainThread, MainThreadOnly, MonochromeSprite, MouseMoveEvent, Path, Pixels,
+ PlatformAtlas, PlatformWindow, Point, PolychromeSprite, Quad, Reference, RenderGlyphParams,
+ RenderSvgParams, ScaledPixels, SceneBuilder, Shadow, SharedString, Size, Style,
+ TaffyLayoutEngine, Task, Underline, UnderlineStyle, WeakHandle, WindowOptions,
+ SUBPIXEL_VARIANTS,
};
use anyhow::Result;
use collections::HashMap;
@@ -619,6 +620,10 @@ impl<'a, 'w> WindowContext<'a, 'w> {
fn dispatch_event(&mut self, event: Event) -> bool {
if let Some(any_mouse_event) = event.mouse_event() {
+ if let Some(MouseMoveEvent { position, .. }) = any_mouse_event.downcast_ref() {
+ self.window.mouse_position = *position;
+ }
+
if let Some(mut handlers) = self
.window
.mouse_event_handlers
@@ -1,7 +1,8 @@
use crate::theme::{theme, Theme};
use gpui3::{
div, img, svg, view, AppContext, Context, Element, Interactive, IntoAnyElement, MouseButton,
- ParentElement, ScrollState, SharedString, StyleHelpers, View, ViewContext, WindowContext,
+ ParentElement, ScrollState, SharedString, StyleHelpers, Styled, View, ViewContext,
+ WindowContext,
};
pub struct CollabPanel {
@@ -129,6 +130,8 @@ impl CollabPanel {
.flex()
.justify_between()
.items_center()
+ .hover()
+ .fill(theme.lowest.base.active.background)
.child(div().flex().gap_1().text_sm().child(label))
.child(
div().flex().h_full().gap_1().items_center().child(