diff --git a/crates/gpui/playground/src/components.rs b/crates/gpui/playground/src/components.rs index eecbc3104b..77855b07c2 100644 --- a/crates/gpui/playground/src/components.rs +++ b/crates/gpui/playground/src/components.rs @@ -1,5 +1,5 @@ use crate::{ - element::{Element, ElementMetadata}, + element::{Element, ElementMetadata, ParentElement}, frame, text::ArcCow, themes::rose_pine, diff --git a/crates/gpui/playground/src/element.rs b/crates/gpui/playground/src/element.rs index 7b9a9910a2..e776268ffa 100644 --- a/crates/gpui/playground/src/element.rs +++ b/crates/gpui/playground/src/element.rs @@ -419,7 +419,7 @@ pub trait Element: 'static { self } - fn hoverable(self) -> Hoverable + fn hover(self) -> Hoverable where Self: Sized, { @@ -443,6 +443,18 @@ pub trait Element: 'static { } } +pub trait ParentElement: Element { + fn child(self, child: impl IntoElement) -> Self + where + Self: Sized; + + fn children(self, children: I) -> Self + where + Self: Sized, + I: IntoIterator, + E: IntoElement; +} + // Object-safe counterpart of Element used by AnyElement to store elements as trait objects. trait ElementObject { fn declared_style(&mut self) -> &mut StyleRefinement; @@ -516,19 +528,6 @@ impl AnyElement { Ok(node_id) } - pub fn push_text_style<'a: 'b, 'b>(&mut self, cx: &mut impl RenderContext<'a, 'b, V>) -> bool { - let text_style = self - .element - .computed_style(cx.as_view_context()) - .text_style(); - if let Some(text_style) = text_style { - cx.push_text_style(cx.text_style().refined(&text_style)); - true - } else { - false - } - } - pub fn paint(&mut self, view: &mut V, cx: &mut PaintContext) -> Result<()> { let pushed_text_style = self.push_text_style(cx); @@ -586,6 +585,19 @@ impl AnyElement { Ok(()) } + + fn push_text_style<'a: 'b, 'b>(&mut self, cx: &mut impl RenderContext<'a, 'b, V>) -> bool { + let text_style = self + .element + .computed_style(cx.as_view_context()) + .text_style(); + if let Some(text_style) = text_style { + cx.push_text_style(cx.text_style().refined(&text_style)); + true + } else { + false + } + } } impl Element for AnyElement { diff --git a/crates/gpui/playground/src/frame.rs b/crates/gpui/playground/src/frame.rs index 9b7bbbe520..c7ab6acabb 100644 --- a/crates/gpui/playground/src/frame.rs +++ b/crates/gpui/playground/src/frame.rs @@ -1,6 +1,7 @@ use crate::{ element::{ - AnyElement, Element, EventHandler, IntoElement, Layout, LayoutContext, NodeId, PaintContext, + AnyElement, Element, EventHandler, IntoElement, Layout, LayoutContext, NodeId, + PaintContext, ParentElement, }, style::{Style, StyleRefinement}, }; @@ -65,13 +66,13 @@ impl Element for Frame { } } -impl Frame { - pub fn child(mut self, child: impl IntoElement) -> Self { +impl ParentElement for Frame { + fn child(mut self, child: impl IntoElement) -> Self { self.children.push(child.into_any_element()); self } - pub fn children(mut self, children: I) -> Self + fn children(mut self, children: I) -> Self where I: IntoIterator, E: IntoElement, diff --git a/crates/gpui/playground/src/hoverable.rs b/crates/gpui/playground/src/hoverable.rs index 6b41871db7..b09e1079f5 100644 --- a/crates/gpui/playground/src/hoverable.rs +++ b/crates/gpui/playground/src/hoverable.rs @@ -7,11 +7,15 @@ use gpui::{ }; use refineable::Refineable; -use crate::{element::Element, style::StyleRefinement}; +use crate::{ + element::{Element, ParentElement}, + style::StyleRefinement, +}; pub struct Hoverable { hover_style: StyleRefinement, computed_style: Option, + hovered: Rc>, view_type: PhantomData, child: E, } @@ -21,6 +25,7 @@ impl Hoverable { Self { hover_style: StyleRefinement::default(), computed_style: None, + hovered: Default::default(), view_type: PhantomData, child, } @@ -37,8 +42,9 @@ impl> Element for Hoverable { fn computed_style(&mut self, cx: &mut ViewContext) -> &StyleRefinement { self.computed_style.get_or_insert_with(|| { let mut style = self.child.computed_style(cx).clone(); - // if hovered - style.refine(&self.hover_style); + if self.hovered.get() { + style.refine(&self.hover_style); + } style }) } @@ -63,17 +69,24 @@ impl> Element for Hoverable { ) -> anyhow::Result<()> { let EngineLayout { bounds, order } = layout.from_engine; let window_bounds = RectF::new(Vector2F::zero(), cx.window_size()); - let was_hovered = Rc::new(Cell::new(false)); + let hovered = self.hovered.clone(); self.child.paint(layout, view, cx)?; + + let mouse_within_bounds = bounds.contains_point(cx.mouse_position()); + if mouse_within_bounds != hovered.get() { + hovered.set(mouse_within_bounds); + cx.repaint(); + } + cx.draw_interactive_region( order, window_bounds, false, move |view, event: &MouseMove, cx| { - let is_hovered = bounds.contains_point(cx.mouse_position()); - if is_hovered != was_hovered.get() { - was_hovered.set(is_hovered); + let mouse_within_bounds = bounds.contains_point(cx.mouse_position()); + if mouse_within_bounds != hovered.get() { + hovered.set(mouse_within_bounds); cx.repaint(); } }, @@ -81,3 +94,23 @@ impl> Element for Hoverable { Ok(()) } } + +impl> ParentElement for Hoverable { + fn child(mut self, child: impl crate::element::IntoElement) -> Self + where + Self: Sized, + { + self.child = self.child.child(child); + self + } + + fn children(mut self, children: I) -> Self + where + Self: Sized, + I: IntoIterator, + E: crate::element::IntoElement, + { + self.child = self.child.children(children); + self + } +} diff --git a/crates/gpui/playground/src/playground.rs b/crates/gpui/playground/src/playground.rs index 38725e7f96..ec7aeecb47 100644 --- a/crates/gpui/playground/src/playground.rs +++ b/crates/gpui/playground/src/playground.rs @@ -1,7 +1,7 @@ #![allow(dead_code, unused_variables)] use color::black; use components::button; -use element::Element; +use element::{Element, ParentElement}; use frame::frame; use gpui::{ geometry::{rect::RectF, vector::vec2f}, @@ -50,6 +50,8 @@ fn playground(theme: &ThemeColors) -> impl Element { .h_full() .w_half() .fill(theme.success(0.5)) + .hover() + .fill(theme.error(0.5)) .child(button().label("Hello").click(|_, _, _| println!("click!"))) } diff --git a/crates/gpui/src/app.rs b/crates/gpui/src/app.rs index 522a82a5cb..04eb0f0b40 100644 --- a/crates/gpui/src/app.rs +++ b/crates/gpui/src/app.rs @@ -1890,6 +1890,7 @@ impl AppContext { fn handle_repaint_window_effect(&mut self, window: AnyWindowHandle) { self.update_window(window, |cx| { + cx.layout(false).log_err(); if let Some(scene) = cx.paint().log_err() { cx.window.platform_window.present_scene(scene); } @@ -3655,12 +3656,6 @@ impl<'a, 'b, 'c, V: 'static> EventContext<'a, 'b, 'c, V> { pub fn propagate_event(&mut self) { self.handled = false; } - - pub fn repaint(&mut self) { - let window = self.window(); - self.pending_effects - .push_back(Effect::RepaintWindow { window }); - } } impl<'a, 'b, 'c, V> Deref for EventContext<'a, 'b, 'c, V> { diff --git a/crates/gpui/src/app/window.rs b/crates/gpui/src/app/window.rs index b568e5dfd5..17ad10b0be 100644 --- a/crates/gpui/src/app/window.rs +++ b/crates/gpui/src/app/window.rs @@ -220,6 +220,12 @@ impl<'a> WindowContext<'a> { } } + pub fn repaint(&mut self) { + let window = self.window(); + self.pending_effects + .push_back(Effect::RepaintWindow { window }); + } + pub fn layout_engine(&mut self) -> Option<&mut LayoutEngine> { self.window.layout_engines.last_mut() }