@@ -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<V, E: Element<V>> {
+pub struct Layout<V, D> {
id: LayoutId,
engine_layout: Option<EngineLayout>,
#[deref]
#[deref_mut]
- element_data: E::Layout,
+ element_data: D,
+ view_type: PhantomData<V>,
}
-impl<V: 'static, E: Element<V>> Layout<V, E> {
- pub fn new(id: LayoutId, engine_layout: Option<EngineLayout>, element_data: E::Layout) -> Self {
+impl<V: 'static, D> Layout<V, D> {
+ pub fn new(id: LayoutId, engine_layout: Option<EngineLayout>, element_data: D) -> Self {
Self {
id,
engine_layout,
element_data,
+ view_type: PhantomData,
}
}
@@ -36,6 +39,10 @@ impl<V: 'static, E: Element<V>> Layout<V, E> {
self.engine_layout(cx).bounds
}
+ pub fn order(&mut self, cx: &mut PaintContext<V>) -> 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<V: 'static, E: Element<V>> Layout<V, E> {
pub trait Element<V> {
type Layout;
- fn layout(&mut self, view: &mut V, cx: &mut LayoutContext<V>) -> Result<Layout<V, Self>>
+ fn layout(
+ &mut self,
+ view: &mut V,
+ cx: &mut LayoutContext<V>,
+ ) -> Result<Layout<V, Self::Layout>>
where
Self: Sized;
- fn paint(&mut self, view: &mut V, cx: &mut PaintContext<V>)
- where
+ fn paint(
+ &mut self,
+ view: &mut V,
+ layout: &mut Layout<V, Self::Layout>,
+ cx: &mut PaintContext<V>,
+ ) where
Self: Sized;
/// ## Helpers
@@ -106,7 +121,7 @@ pub fn div<V>() -> Div<V> {
impl<V: 'static> Element<V> for Div<V> {
type Layout = ();
- fn layout(&mut self, view: &mut V, cx: &mut LayoutContext<V>) -> Result<Layout<V, Self>>
+ fn layout(&mut self, view: &mut V, cx: &mut LayoutContext<V>) -> Result<Layout<V, ()>>
where
Self: Sized,
{
@@ -119,7 +134,7 @@ impl<V: 'static> Element<V> for Div<V> {
cx.add_layout_node(self.style(), (), children)
}
- fn paint(&mut self, view: &mut V, cx: &mut PaintContext<V>)
+ fn paint(&mut self, view: &mut V, layout: &mut Layout<V, ()>, cx: &mut PaintContext<V>)
where
Self: Sized,
{
@@ -128,35 +143,17 @@ impl<V: 'static> Element<V> for Div<V> {
}
pub struct Hoverable<V, E: Element<V> + Styleable> {
- default_style: Style,
+ hovered: Cell<bool>,
+ child_style: StyleRefinement,
hovered_style: StyleRefinement,
child: E,
view_type: PhantomData<V>,
}
-pub trait Interactive<V> {
- fn declared_interactions(&mut self) -> &mut Interactions<V>;
-
- fn on_mouse_move<H>(mut self, handler: H) -> Self
- where
- H: 'static + Fn(&mut V, &MouseMovedEvent, &mut EventContext<V>),
- Self: Sized,
- {
- self.declared_interactions().mouse_moved = Some(Rc::new(move |view, event, cx| {
- handler(view, event, cx);
- cx.bubble
- }));
- self
- }
-}
-
-pub struct Interactions<V> {
- mouse_moved: Option<Rc<dyn Fn(&mut V, &MouseMovedEvent, &mut EventContext<V>) -> bool>>,
-}
-
pub fn hoverable<V, E: Element<V> + Styleable>(mut child: E) -> Hoverable<V, E> {
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<V, E: Element<V> + Styleable> Styleable for Hoverable<V, E> {
}
}
-impl<V, E: Element<V> + Styleable> Element<V> for Hoverable<V, E> {
+impl<V: 'static, E: Element<V> + Styleable> Element<V> for Hoverable<V, E> {
type Layout = E::Layout;
- fn layout(&mut self, view: &mut V, cx: &mut LayoutContext<V>) -> Result<Layout<V, Self>>
+ fn layout(&mut self, view: &mut V, cx: &mut LayoutContext<V>) -> Result<Layout<V, Self::Layout>>
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<V>)
+ fn paint(
+ &mut self,
+ view: &mut V,
+ layout: &mut Layout<V, Self::Layout>,
+ cx: &mut PaintContext<V>,
+ ) 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<V> {
+ fn declared_interactions(&mut self) -> &mut Interactions<V>;
+
+ fn on_mouse_move<H>(mut self, handler: H) -> Self
where
+ H: 'static + Fn(&mut V, &MouseMovedEvent, &mut EventContext<V>),
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<V> {
+ mouse_moved: Option<Rc<dyn Fn(&mut V, &MouseMovedEvent, &mut EventContext<V>) -> bool>>,
+}
+
#[test]
fn test() {
// let elt = div().w_auto();
@@ -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<E: Element<V>>(
+ pub fn add_layout_node<D>(
&mut self,
style: Style,
- element_data: E::Layout,
+ element_data: D,
children: impl IntoIterator<Item = NodeId>,
- ) -> Result<Layout<V, E>> {
+ ) -> Result<Layout<V, D>> {
let rem_size = self.rem_pixels();
let id = self
.legacy_cx
@@ -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<E: 'static>(
+ &mut self,
+ order: u32,
+ handler: impl Fn(&mut V, &E, &mut ViewContext<V>) + '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::<E>(),
+ })
+ }
+
pub fn draw_interactive_region<E: 'static>(
&mut self,
order: u32,
@@ -31,8 +31,10 @@ pub struct SceneBuilder {
scale_factor: f32,
stacking_contexts: Vec<StackingContext>,
active_stacking_context_stack: Vec<usize>,
- /// Used by the playground crate.
+ /// Used by the playground crate. I hope to replace it with event_handlers.
pub interactive_regions: Vec<InteractiveRegion>,
+ /// Used by the playground crate.
+ pub event_handlers: Vec<EventHandler>,
#[cfg(debug_assertions)]
mouse_region_ids: HashSet<MouseRegionId>,
}
@@ -41,6 +43,7 @@ pub struct Scene {
scale_factor: f32,
stacking_contexts: Vec<StackingContext>,
interactive_regions: Vec<InteractiveRegion>,
+ event_handlers: Vec<EventHandler>,
}
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<InteractiveRegion> {
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<EventHandler> {
+ 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<dyn Fn(&mut dyn Any, &dyn Any, &mut WindowContext, usize)>,
+ pub event_type: TypeId,
+}
+
fn can_draw(bounds: RectF) -> bool {
let size = bounds.size();
size.x() > 0. && size.y() > 0.