diff --git a/crates/gpui/playground/src/div.rs b/crates/gpui/playground/src/div.rs index 946d77e1f12cba2669553eceeac754af2d40c051..1cc1d1761e0e7ab3439a910d6392008fc5c8e05b 100644 --- a/crates/gpui/playground/src/div.rs +++ b/crates/gpui/playground/src/div.rs @@ -1,3 +1,4 @@ +use std::cell::Cell; use std::{marker::PhantomData, rc::Rc}; use crate::element::{AnyElement, PaintContext}; @@ -15,20 +16,22 @@ use util::ResultExt; type LayoutId = gpui::LayoutId; #[derive(Deref, DerefMut)] -pub struct Layout> { +pub struct Layout { id: LayoutId, engine_layout: Option, #[deref] #[deref_mut] - element_data: E::Layout, + element_data: D, + view_type: PhantomData, } -impl> Layout { - pub fn new(id: LayoutId, engine_layout: Option, element_data: E::Layout) -> Self { +impl Layout { + pub fn new(id: LayoutId, engine_layout: Option, element_data: D) -> Self { Self { id, engine_layout, element_data, + view_type: PhantomData, } } @@ -36,6 +39,10 @@ impl> Layout { self.engine_layout(cx).bounds } + pub fn order(&mut self, cx: &mut PaintContext) -> u32 { + self.engine_layout(cx).order + } + fn engine_layout(&mut self, cx: &mut PaintContext<'_, '_, '_, '_, V>) -> &mut EngineLayout { self.engine_layout .get_or_insert_with(|| cx.computed_layout(self.id).log_err().unwrap_or_default()) @@ -45,12 +52,20 @@ impl> Layout { pub trait Element { type Layout; - fn layout(&mut self, view: &mut V, cx: &mut LayoutContext) -> Result> + fn layout( + &mut self, + view: &mut V, + cx: &mut LayoutContext, + ) -> Result> where Self: Sized; - fn paint(&mut self, view: &mut V, cx: &mut PaintContext) - where + fn paint( + &mut self, + view: &mut V, + layout: &mut Layout, + cx: &mut PaintContext, + ) where Self: Sized; /// ## Helpers @@ -106,7 +121,7 @@ pub fn div() -> Div { impl Element for Div { type Layout = (); - fn layout(&mut self, view: &mut V, cx: &mut LayoutContext) -> Result> + fn layout(&mut self, view: &mut V, cx: &mut LayoutContext) -> Result> where Self: Sized, { @@ -119,7 +134,7 @@ impl Element for Div { cx.add_layout_node(self.style(), (), children) } - fn paint(&mut self, view: &mut V, cx: &mut PaintContext) + fn paint(&mut self, view: &mut V, layout: &mut Layout, cx: &mut PaintContext) where Self: Sized, { @@ -128,35 +143,17 @@ impl Element for Div { } pub struct Hoverable + Styleable> { - default_style: Style, + hovered: Cell, + child_style: StyleRefinement, hovered_style: StyleRefinement, child: E, view_type: PhantomData, } -pub trait Interactive { - fn declared_interactions(&mut self) -> &mut Interactions; - - fn on_mouse_move(mut self, handler: H) -> Self - where - H: 'static + Fn(&mut V, &MouseMovedEvent, &mut EventContext), - Self: Sized, - { - self.declared_interactions().mouse_moved = Some(Rc::new(move |view, event, cx| { - handler(view, event, cx); - cx.bubble - })); - self - } -} - -pub struct Interactions { - mouse_moved: Option) -> bool>>, -} - pub fn hoverable + Styleable>(mut child: E) -> Hoverable { Hoverable { - default_style: child.style(), + hovered: Cell::new(false), + child_style: child.declared_style().clone(), hovered_style: Default::default(), child, view_type: PhantomData, @@ -171,24 +168,60 @@ impl + Styleable> Styleable for Hoverable { } } -impl + Styleable> Element for Hoverable { +impl + Styleable> Element for Hoverable { type Layout = E::Layout; - fn layout(&mut self, view: &mut V, cx: &mut LayoutContext) -> Result> + fn layout(&mut self, view: &mut V, cx: &mut LayoutContext) -> Result> where Self: Sized, { - todo!() + if self.hovered.get() { + // If hovered, refine the child's style with this element's style. + self.child.declared_style().refine(&self.hovered_style); + } else { + // Otherwise, set the child's style back to its original style. + *self.child.declared_style() = self.child_style.clone(); + } + + self.child.layout(view, cx) } - fn paint(&mut self, view: &mut V, cx: &mut PaintContext) + fn paint( + &mut self, + view: &mut V, + layout: &mut Layout, + cx: &mut PaintContext, + ) where + Self: Sized, + { + let bounds = layout.bounds(cx); + let order = layout.order(cx); + self.hovered.set(bounds.contains_point(cx.mouse_position())); + let hovered = self.hovered.clone(); + cx.on_event(order, move |view, event: &MouseMovedEvent, cx| {}); + } +} + +pub trait Interactive { + fn declared_interactions(&mut self) -> &mut Interactions; + + fn on_mouse_move(mut self, handler: H) -> Self where + H: 'static + Fn(&mut V, &MouseMovedEvent, &mut EventContext), Self: Sized, { - todo!() + self.declared_interactions().mouse_moved = Some(Rc::new(move |view, event, cx| { + handler(view, event, cx); + cx.bubble + })); + self } } +pub struct Interactions { + mouse_moved: Option) -> bool>>, +} + #[test] fn test() { // let elt = div().w_auto(); diff --git a/crates/gpui/playground/src/layout_context.rs b/crates/gpui/playground/src/layout_context.rs index a424e561b3ae3d17a9ba8d13bcc604afe538d2a4..32155de3386ac08d77c36ee90fe8f8cd706841f3 100644 --- a/crates/gpui/playground/src/layout_context.rs +++ b/crates/gpui/playground/src/layout_context.rs @@ -4,10 +4,7 @@ pub use gpui::LayoutContext as LegacyLayoutContext; use gpui::{RenderContext, ViewContext}; pub use taffy::tree::NodeId; -use crate::{ - div::{Element, Layout}, - style::Style, -}; +use crate::{div::Layout, style::Style}; #[derive(Deref, DerefMut)] pub struct LayoutContext<'a, 'b, 'c, 'd, V> { @@ -43,12 +40,12 @@ impl<'a, 'b, 'c, 'd, V: 'static> LayoutContext<'a, 'b, 'c, 'd, V> { Self { legacy_cx, scene } } - pub fn add_layout_node>( + pub fn add_layout_node( &mut self, style: Style, - element_data: E::Layout, + element_data: D, children: impl IntoIterator, - ) -> Result> { + ) -> Result> { let rem_size = self.rem_pixels(); let id = self .legacy_cx diff --git a/crates/gpui/playground/src/paint_context.rs b/crates/gpui/playground/src/paint_context.rs index b849c3f13119314854ef4e5532942d8e7d080642..59e728b6f7520226376074b4be4804e154e6453c 100644 --- a/crates/gpui/playground/src/paint_context.rs +++ b/crates/gpui/playground/src/paint_context.rs @@ -1,7 +1,8 @@ use anyhow::{anyhow, Result}; use derive_more::{Deref, DerefMut}; use gpui::{ - geometry::rect::RectF, EngineLayout, EventContext, LayoutId, RenderContext, ViewContext, + geometry::rect::RectF, scene::EventHandler, EngineLayout, EventContext, LayoutId, + RenderContext, ViewContext, }; pub use gpui::{LayoutContext, PaintContext as LegacyPaintContext}; use std::{any::TypeId, rc::Rc}; @@ -41,6 +42,25 @@ impl<'a, 'b, 'c, 'd, V: 'static> PaintContext<'a, 'b, 'c, 'd, V> { Self { legacy_cx, scene } } + pub fn on_event( + &mut self, + order: u32, + handler: impl Fn(&mut V, &E, &mut ViewContext) + 'static, + ) { + self.scene.event_handlers.push(EventHandler { + order, + handler: Rc::new(move |view, event, window_cx, view_id| { + let mut view_context = ViewContext::mutable(window_cx, view_id); + handler( + view.downcast_mut().unwrap(), + event.downcast_ref().unwrap(), + &mut view_context, + ); + }), + event_type: TypeId::of::(), + }) + } + pub fn draw_interactive_region( &mut self, order: u32, diff --git a/crates/gpui/src/scene.rs b/crates/gpui/src/scene.rs index 7b6c98d8e7bb37d383dcaf3bc68ef4a4a087a48d..830ffa857e4fad3f3279cc3a8741f8ceff4f5010 100644 --- a/crates/gpui/src/scene.rs +++ b/crates/gpui/src/scene.rs @@ -31,8 +31,10 @@ pub struct SceneBuilder { scale_factor: f32, stacking_contexts: Vec, active_stacking_context_stack: Vec, - /// Used by the playground crate. + /// Used by the playground crate. I hope to replace it with event_handlers. pub interactive_regions: Vec, + /// Used by the playground crate. + pub event_handlers: Vec, #[cfg(debug_assertions)] mouse_region_ids: HashSet, } @@ -41,6 +43,7 @@ pub struct Scene { scale_factor: f32, stacking_contexts: Vec, interactive_regions: Vec, + event_handlers: Vec, } struct StackingContext { @@ -282,11 +285,17 @@ impl Scene { .collect() } + /// TODO: Hoping to replace this with take_event_handlers pub fn take_interactive_regions(&mut self) -> Vec { self.interactive_regions .sort_by(|a, b| a.order.cmp(&b.order)); std::mem::take(&mut self.interactive_regions) } + + pub fn take_event_handlers(&mut self) -> Vec { + self.event_handlers.sort_by(|a, b| a.order.cmp(&b.order)); + std::mem::take(&mut self.event_handlers) + } } impl SceneBuilder { @@ -299,6 +308,7 @@ impl SceneBuilder { #[cfg(debug_assertions)] mouse_region_ids: Default::default(), interactive_regions: Vec::new(), + event_handlers: Vec::new(), } } @@ -309,6 +319,7 @@ impl SceneBuilder { scale_factor: self.scale_factor, stacking_contexts: self.stacking_contexts, interactive_regions: self.interactive_regions, + event_handlers: self.event_handlers, } } @@ -717,6 +728,14 @@ pub struct InteractiveRegion { pub view_id: usize, } +pub struct EventHandler { + pub order: u32, + // First param is a dynamic view reference + // Second param is a dynamic event reference + pub handler: Rc, + pub event_type: TypeId, +} + fn can_draw(bounds: RectF) -> bool { let size = bounds.size(); size.x() > 0. && size.y() > 0.