Detailed changes
@@ -1,70 +1,70 @@
-use crate::element::{LayoutContext, PaintContext};
-use gpui::{geometry::rect::RectF, LayoutEngine};
-use util::ResultExt;
+// use crate::element::{LayoutContext, PaintContext};
+// use gpui::{geometry::rect::RectF, LayoutEngine};
+// use util::ResultExt;
-use crate::element::AnyElement;
+// use crate::element::AnyElement;
-pub struct Adapter<V>(pub(crate) AnyElement<V>);
+// pub struct Adapter<V>(pub(crate) AnyElement<V>);
-impl<V: 'static> gpui::Element<V> for Adapter<V> {
- type LayoutState = Option<LayoutEngine>;
- type PaintState = ();
+// impl<V: 'static> gpui::Element<V> for Adapter<V> {
+// type LayoutState = Option<LayoutEngine>;
+// type PaintState = ();
- fn layout(
- &mut self,
- constraint: gpui::SizeConstraint,
- view: &mut V,
- cx: &mut LayoutContext<V>,
- ) -> (gpui::geometry::vector::Vector2F, Self::LayoutState) {
- cx.push_layout_engine(LayoutEngine::new());
- let node = self.0.layout(view, cx).log_err();
+// fn layout(
+// &mut self,
+// constraint: gpui::SizeConstraint,
+// view: &mut V,
+// cx: &mut LayoutContext<V>,
+// ) -> (gpui::geometry::vector::Vector2F, Self::LayoutState) {
+// cx.push_layout_engine(LayoutEngine::new());
+// let node = self.0.layout(view, cx).log_err();
- if let Some(node) = node {
- let layout_engine = cx.layout_engine().unwrap();
- layout_engine.compute_layout(node, constraint.max).log_err();
- }
- let layout_engine = cx.pop_layout_engine();
- debug_assert!(layout_engine.is_some());
- (constraint.max, layout_engine)
- }
+// if let Some(node) = node {
+// let layout_engine = cx.layout_engine().unwrap();
+// layout_engine.compute_layout(node, constraint.max).log_err();
+// }
+// let layout_engine = cx.pop_layout_engine();
+// debug_assert!(layout_engine.is_some());
+// (constraint.max, layout_engine)
+// }
- fn paint(
- &mut self,
- scene: &mut gpui::SceneBuilder,
- bounds: RectF,
- visible_bounds: RectF,
- layout_engine: &mut Option<LayoutEngine>,
- view: &mut V,
- legacy_cx: &mut gpui::PaintContext<V>,
- ) -> Self::PaintState {
- legacy_cx.push_layout_engine(layout_engine.take().unwrap());
- let mut cx = PaintContext::new(legacy_cx, scene);
- self.0.paint(view, &mut cx).log_err();
- *layout_engine = legacy_cx.pop_layout_engine();
- debug_assert!(layout_engine.is_some());
- }
+// fn paint(
+// &mut self,
+// scene: &mut gpui::SceneBuilder,
+// bounds: RectF,
+// visible_bounds: RectF,
+// layout_engine: &mut Option<LayoutEngine>,
+// view: &mut V,
+// legacy_cx: &mut gpui::PaintContext<V>,
+// ) -> Self::PaintState {
+// legacy_cx.push_layout_engine(layout_engine.take().unwrap());
+// let mut cx = PaintContext::new(legacy_cx, scene);
+// self.0.paint(view, &mut cx).log_err();
+// *layout_engine = legacy_cx.pop_layout_engine();
+// debug_assert!(layout_engine.is_some());
+// }
- fn rect_for_text_range(
- &self,
- range_utf16: std::ops::Range<usize>,
- bounds: RectF,
- visible_bounds: RectF,
- layout: &Self::LayoutState,
- paint: &Self::PaintState,
- view: &V,
- cx: &gpui::ViewContext<V>,
- ) -> Option<RectF> {
- todo!("implement before merging to main")
- }
+// fn rect_for_text_range(
+// &self,
+// range_utf16: std::ops::Range<usize>,
+// bounds: RectF,
+// visible_bounds: RectF,
+// layout: &Self::LayoutState,
+// paint: &Self::PaintState,
+// view: &V,
+// cx: &gpui::ViewContext<V>,
+// ) -> Option<RectF> {
+// todo!("implement before merging to main")
+// }
- fn debug(
- &self,
- bounds: RectF,
- layout: &Self::LayoutState,
- paint: &Self::PaintState,
- view: &V,
- cx: &gpui::ViewContext<V>,
- ) -> gpui::serde_json::Value {
- todo!("implement before merging to main")
- }
-}
+// fn debug(
+// &self,
+// bounds: RectF,
+// layout: &Self::LayoutState,
+// paint: &Self::PaintState,
+// view: &V,
+// cx: &gpui::ViewContext<V>,
+// ) -> gpui::serde_json::Value {
+// todo!("implement before merging to main")
+// }
+// }
@@ -1,104 +1,13 @@
-use std::cell::Cell;
-use std::{marker::PhantomData, rc::Rc};
-
-use crate::element::{AnyElement, PaintContext};
-use crate::layout_context::LayoutContext;
-use crate::style::{Style, StyleRefinement};
+use crate::{
+ element::{AnyElement, Element, Layout},
+ layout_context::LayoutContext,
+ paint_context::PaintContext,
+ style::{Style, StyleRefinement, Styleable},
+};
use anyhow::Result;
-use derive_more::{Deref, DerefMut};
-use gpui::EngineLayout;
-use gpui::{geometry::rect::RectF, platform::MouseMovedEvent, EventContext};
-use playground_macros::styleable_helpers;
-use refineable::Refineable;
+use gpui::{platform::MouseMovedEvent, EventContext, LayoutId};
use smallvec::SmallVec;
-use util::ResultExt;
-
-type LayoutId = gpui::LayoutId;
-
-#[derive(Deref, DerefMut)]
-pub struct Layout<V, D> {
- id: LayoutId,
- engine_layout: Option<EngineLayout>,
- #[deref]
- #[deref_mut]
- element_data: D,
- view_type: PhantomData<V>,
-}
-
-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,
- }
- }
-
- pub fn bounds(&mut self, cx: &mut PaintContext<V>) -> RectF {
- 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())
- }
-}
-
-pub trait Element<V> {
- type Layout;
-
- 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,
- layout: &mut Layout<V, Self::Layout>,
- cx: &mut PaintContext<V>,
- ) where
- Self: Sized;
-
- /// ## Helpers
-
- fn hoverable(self) -> Hoverable<V, Self>
- where
- Self: Styleable + Sized,
- {
- hoverable(self)
- }
-}
-
-pub trait Styleable {
- type Style: refineable::Refineable;
-
- fn declared_style(&mut self) -> &mut playground::style::StyleRefinement;
-
- fn style(&mut self) -> playground::style::Style {
- let mut style = playground::style::Style::default();
- style.refine(self.declared_style());
- style
- }
-}
-
-// Tailwind-style helpers methods that take and return mut self
-//
-// Example:
-// // Sets the padding to 0.5rem, just like class="p-2" in Tailwind.
-// fn p_2(mut self) -> Self where Self: Sized;
-use crate as playground; // Macro invocation references this crate as playground.
-pub trait StyleHelpers: Styleable<Style = Style> {
- styleable_helpers!();
-}
+use std::rc::Rc;
pub struct Div<V> {
style: StyleRefinement,
@@ -146,66 +55,6 @@ impl<V: 'static> Element<V> for Div<V> {
}
}
-pub struct Hoverable<V, E: Element<V> + Styleable> {
- hovered: Cell<bool>,
- child_style: StyleRefinement,
- hovered_style: StyleRefinement,
- child: E,
- view_type: PhantomData<V>,
-}
-
-pub fn hoverable<V, E: Element<V> + Styleable>(mut child: E) -> Hoverable<V, E> {
- Hoverable {
- hovered: Cell::new(false),
- child_style: child.declared_style().clone(),
- hovered_style: Default::default(),
- child,
- view_type: PhantomData,
- }
-}
-
-impl<V, E: Element<V> + Styleable> Styleable for Hoverable<V, E> {
- type Style = E::Style;
-
- fn declared_style(&mut self) -> &mut playground::style::StyleRefinement {
- self.child.declared_style()
- }
-}
-
-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::Layout>>
- where
- Self: Sized,
- {
- 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,
- 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>;
@@ -1,552 +1,143 @@
-use crate::{
- adapter::Adapter,
- color::Hsla,
- style::{Display, Fill, Overflow, Position, StyleRefinement},
-};
use anyhow::Result;
-pub use gpui::LayoutContext;
-use gpui::{
- geometry::PointRefinement,
- platform::{MouseButton, MouseButtonEvent},
- EngineLayout, EventContext, RenderContext, ViewContext,
-};
-use refineable::Refineable;
-use std::{
- any::{Any, TypeId},
- cell::Cell,
- rc::Rc,
-};
-
-pub use crate::paint_context::PaintContext;
-pub use taffy::tree::NodeId;
-
-pub struct Layout<'a, E: ?Sized> {
- pub from_engine: EngineLayout,
- pub from_element: &'a mut E,
-}
-
-pub struct ElementMetadata<V> {
- pub style: StyleRefinement,
- pub handlers: Vec<EventHandler<V>>,
+use derive_more::{Deref, DerefMut};
+use gpui::geometry::rect::RectF;
+use gpui::EngineLayout;
+use std::marker::PhantomData;
+use util::ResultExt;
+
+use crate::layout_context::LayoutContext;
+use crate::paint_context::PaintContext;
+
+type LayoutId = gpui::LayoutId;
+
+#[derive(Deref, DerefMut)]
+pub struct Layout<V, D> {
+ id: LayoutId,
+ engine_layout: Option<EngineLayout>,
+ #[deref]
+ #[deref_mut]
+ element_data: D,
+ view_type: PhantomData<V>,
}
-pub struct EventHandler<V> {
- handler: Rc<dyn Fn(&mut V, &dyn Any, &mut EventContext<V>)>,
- event_type: TypeId,
- outside_bounds: bool,
-}
-
-impl<V> Clone for EventHandler<V> {
- fn clone(&self) -> Self {
+impl<V: 'static, D> Layout<V, D> {
+ pub fn new(id: LayoutId, engine_layout: Option<EngineLayout>, element_data: D) -> Self {
Self {
- handler: self.handler.clone(),
- event_type: self.event_type,
- outside_bounds: self.outside_bounds,
+ id,
+ engine_layout,
+ element_data,
+ view_type: PhantomData,
}
}
-}
-impl<V> Default for ElementMetadata<V> {
- fn default() -> Self {
- Self {
- style: StyleRefinement::default(),
- handlers: Vec::new(),
- }
+ pub fn bounds(&mut self, cx: &mut PaintContext<V>) -> RectF {
+ self.engine_layout(cx).bounds
}
-}
-
-pub trait Element<V: 'static>: 'static {
- type Layout: 'static;
- fn declared_style(&mut self) -> &mut StyleRefinement;
-
- fn computed_style(&mut self, cx: &mut ViewContext<V>) -> &StyleRefinement {
- self.declared_style()
+ pub fn order(&mut self, cx: &mut PaintContext<V>) -> u32 {
+ self.engine_layout(cx).order
}
- fn handlers_mut(&mut self) -> &mut Vec<EventHandler<V>>;
+ 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())
+ }
+}
- fn layout(&mut self, view: &mut V, cx: &mut LayoutContext<V>)
- -> Result<(NodeId, Self::Layout)>;
+pub trait Element<V> {
+ type Layout;
- fn paint<'a>(
+ fn layout(
&mut self,
- layout: Layout<Self::Layout>,
view: &mut V,
- cx: &mut PaintContext<V>,
- ) -> Result<()>;
-
- /// Convert to a dynamically-typed element suitable for layout and paint.
- fn into_any(self) -> AnyElement<V>
- where
- Self: 'static + Sized,
- {
- AnyElement {
- element: Box::new(self) as Box<dyn ElementObject<V>>,
- layout: None,
- }
- }
-
- fn adapt(self) -> Adapter<V>
- where
- Self: Sized,
- Self: Element<V>,
- {
- Adapter(self.into_any())
- }
-
- fn click(
- self,
- button: MouseButton,
- handler: impl Fn(&mut V, &MouseButtonEvent, &mut ViewContext<V>) + 'static,
- ) -> Self
- where
- Self: Sized,
- {
- let pressed: Rc<Cell<bool>> = Default::default();
- self.mouse_down(button, {
- let pressed = pressed.clone();
- move |_, _, _| {
- pressed.set(true);
- }
- })
- .mouse_up_outside(button, {
- let pressed = pressed.clone();
- move |_, _, _| {
- pressed.set(false);
- }
- })
- .mouse_up(button, move |view, event, event_cx| {
- if pressed.get() {
- pressed.set(false);
- handler(view, event, event_cx);
- }
- })
- }
-
- fn mouse_down(
- mut self,
- button: MouseButton,
- handler: impl Fn(&mut V, &MouseButtonEvent, &mut EventContext<V>) + 'static,
- ) -> Self
- where
- Self: Sized,
- {
- self.handlers_mut().push(EventHandler {
- handler: Rc::new(move |view, event, event_cx| {
- let event = event.downcast_ref::<MouseButtonEvent>().unwrap();
- if event.button == button && event.is_down {
- handler(view, event, event_cx);
- }
- }),
- event_type: TypeId::of::<MouseButtonEvent>(),
- outside_bounds: false,
- });
- self
- }
-
- fn mouse_down_outside(
- mut self,
- button: MouseButton,
- handler: impl Fn(&mut V, &MouseButtonEvent, &mut EventContext<V>) + 'static,
- ) -> Self
- where
- Self: Sized,
- {
- self.handlers_mut().push(EventHandler {
- handler: Rc::new(move |view, event, event_cx| {
- let event = event.downcast_ref::<MouseButtonEvent>().unwrap();
- if event.button == button && event.is_down {
- handler(view, event, event_cx);
- }
- }),
- event_type: TypeId::of::<MouseButtonEvent>(),
- outside_bounds: true,
- });
- self
- }
-
- fn mouse_up(
- mut self,
- button: MouseButton,
- handler: impl Fn(&mut V, &MouseButtonEvent, &mut EventContext<V>) + 'static,
- ) -> Self
- where
- Self: Sized,
- {
- self.handlers_mut().push(EventHandler {
- handler: Rc::new(move |view, event, event_cx| {
- let event = event.downcast_ref::<MouseButtonEvent>().unwrap();
- if event.button == button && !event.is_down {
- handler(view, event, event_cx);
- }
- }),
- event_type: TypeId::of::<MouseButtonEvent>(),
- outside_bounds: false,
- });
- self
- }
-
- fn mouse_up_outside(
- mut self,
- button: MouseButton,
- handler: impl Fn(&mut V, &MouseButtonEvent, &mut EventContext<V>) + 'static,
- ) -> Self
- where
- Self: Sized,
- {
- self.handlers_mut().push(EventHandler {
- handler: Rc::new(move |view, event, event_cx| {
- let event = event.downcast_ref::<MouseButtonEvent>().unwrap();
- if event.button == button && !event.is_down {
- handler(view, event, event_cx);
- }
- }),
- event_type: TypeId::of::<MouseButtonEvent>(),
- outside_bounds: true,
- });
- self
- }
-
- // Display ////////////////////
-
- fn block(mut self) -> Self
- where
- Self: Sized,
- {
- self.declared_style().display = Some(Display::Block);
- self
- }
-
- fn flex(mut self) -> Self
- where
- Self: Sized,
- {
- self.declared_style().display = Some(Display::Flex);
- self
- }
-
- fn grid(mut self) -> Self
- where
- Self: Sized,
- {
- self.declared_style().display = Some(Display::Grid);
- self
- }
-
- // style::Overflow ///////////////////
-
- fn overflow_visible(mut self) -> Self
+ cx: &mut LayoutContext<V>,
+ ) -> Result<Layout<V, Self::Layout>>
where
- Self: Sized,
- {
- self.declared_style().overflow = PointRefinement {
- x: Some(Overflow::Visible),
- y: Some(Overflow::Visible),
- };
- self
- }
+ Self: Sized;
- fn overflow_hidden(mut self) -> Self
- where
- Self: Sized,
- {
- self.declared_style().overflow = PointRefinement {
- x: Some(Overflow::Hidden),
- y: Some(Overflow::Hidden),
- };
- self
- }
+ fn paint(
+ &mut self,
+ view: &mut V,
+ layout: &mut Layout<V, Self::Layout>,
+ cx: &mut PaintContext<V>,
+ ) where
+ Self: Sized;
- fn overflow_scroll(mut self) -> Self
+ fn into_any(mut self) -> AnyElement<V>
where
Self: Sized,
{
- self.declared_style().overflow = PointRefinement {
- x: Some(Overflow::Scroll),
- y: Some(Overflow::Scroll),
- };
- self
+ AnyElement(Box::new(ElementWithLayout {
+ element: self,
+ layout: None,
+ }))
}
+}
- fn overflow_x_visible(mut self) -> Self
- where
- Self: Sized,
- {
- self.declared_style().overflow.x = Some(Overflow::Visible);
- self
- }
+trait ElementTraitObject<V> {
+ fn layout(&mut self, view: &mut V, cx: &mut LayoutContext<V>) -> Result<LayoutId>;
+ fn paint(&mut self, view: &mut V, layout_id: LayoutId, cx: &mut PaintContext<V>);
+}
- fn overflow_x_hidden(mut self) -> Self
- where
- Self: Sized,
- {
- self.declared_style().overflow.x = Some(Overflow::Hidden);
- self
- }
+struct ElementWithLayout<V, E: Element<V>> {
+ element: E,
+ layout: Option<Layout<V, E::Layout>>,
+}
- fn overflow_x_scroll(mut self) -> Self
- where
- Self: Sized,
- {
- self.declared_style().overflow.x = Some(Overflow::Scroll);
- self
+impl<V, E: Element<V>> ElementTraitObject<V> for ElementWithLayout<V, E> {
+ fn layout(&mut self, view: &mut V, cx: &mut LayoutContext<V>) -> Result<LayoutId> {
+ let layout = Element::layout(self, view, cx)?;
+ let layout_id = layout.id;
+ self.layout = Some(layout);
+ Ok(layout_id)
}
- fn overflow_y_visible(mut self) -> Self
- where
- Self: Sized,
- {
- self.declared_style().overflow.y = Some(Overflow::Visible);
- self
+ fn paint(&mut self, view: &mut V, layout_id: LayoutId, cx: &mut PaintContext<V>) {
+ let layout = self.layout.as_mut().expect("paint called before layout");
+ Element::paint(self, view, layout, cx);
}
+}
- fn overflow_y_hidden(mut self) -> Self
- where
- Self: Sized,
- {
- self.declared_style().overflow.y = Some(Overflow::Hidden);
- self
- }
+pub struct AnyElement<V>(Box<dyn ElementTraitObject<V>>);
- fn overflow_y_scroll(mut self) -> Self
- where
- Self: Sized,
- {
- self.declared_style().overflow.y = Some(Overflow::Scroll);
- self
+impl<V> AnyElement<V> {
+ fn layout(&mut self, view: &mut V, cx: &mut LayoutContext<V>) -> Result<LayoutId> {
+ self.0.layout(view, cx)
}
- // Position ///////////////////
-
- fn relative(mut self) -> Self
- where
- Self: Sized,
- {
- self.declared_style().position = Some(Position::Relative);
- self
+ fn paint(&mut self, view: &mut V, layout_id: LayoutId, cx: &mut PaintContext<V>) {
+ self.0.paint(view, layout_id, cx)
}
+}
- fn absolute(mut self) -> Self
- where
- Self: Sized,
- {
- self.declared_style().position = Some(Position::Absolute);
-
- self
- }
+pub trait ParentElement<V> {
+ fn children_mut(&mut self) -> &mut Vec<AnyElement<V>>;
- fn fill(mut self, fill: impl Into<Fill>) -> Self
+ fn child(mut self, child: impl IntoElement<V>) -> Self
where
Self: Sized,
{
- self.declared_style().fill = Some(fill.into());
+ self.children_mut().push(child.into_element().into_any());
self
}
- fn text_color(mut self, color: impl Into<Hsla>) -> Self
+ fn children<I, E>(mut self, children: I) -> Self
where
+ I: IntoIterator<Item = E>,
+ E: IntoElement<V>,
Self: Sized,
{
- self.declared_style().text_color = Some(color.into());
+ self.children_mut().extend(
+ children
+ .into_iter()
+ .map(|child| child.into_element().into_any()),
+ );
self
}
}
-pub trait ParentElement<V: 'static>: Element<V> {
- fn child(self, child: impl IntoElement<V>) -> Self
- where
- Self: Sized;
-
- fn children<I, E>(self, children: I) -> Self
- where
- Self: Sized,
- I: IntoIterator<Item = E>,
- E: IntoElement<V>;
-}
-
-// Object-safe counterpart of Element used by AnyElement to store elements as trait objects.
-trait ElementObject<V> {
- fn declared_style(&mut self) -> &mut StyleRefinement;
- fn computed_style(&mut self, cx: &mut ViewContext<V>) -> &StyleRefinement;
- fn handlers_mut(&mut self) -> &mut Vec<EventHandler<V>>;
- fn layout(&mut self, view: &mut V, cx: &mut LayoutContext<V>)
- -> Result<(NodeId, Box<dyn Any>)>;
- fn paint(
- &mut self,
- layout: Layout<dyn Any>,
- view: &mut V,
- cx: &mut PaintContext<V>,
- ) -> Result<()>;
-}
-
-impl<V: 'static, E: Element<V>> ElementObject<V> for E {
- fn declared_style(&mut self) -> &mut StyleRefinement {
- Element::declared_style(self)
- }
-
- fn computed_style(&mut self, cx: &mut ViewContext<V>) -> &StyleRefinement {
- Element::computed_style(self, cx)
- }
-
- fn handlers_mut(&mut self) -> &mut Vec<EventHandler<V>> {
- Element::handlers_mut(self)
- }
-
- fn layout(
- &mut self,
- view: &mut V,
- cx: &mut LayoutContext<V>,
- ) -> Result<(NodeId, Box<dyn Any>)> {
- let (node_id, layout) = self.layout(view, cx)?;
- let layout = Box::new(layout) as Box<dyn Any>;
- Ok((node_id, layout))
- }
-
- fn paint(
- &mut self,
- layout: Layout<dyn Any>,
- view: &mut V,
- cx: &mut PaintContext<V>,
- ) -> Result<()> {
- let layout = Layout {
- from_engine: layout.from_engine,
- from_element: layout.from_element.downcast_mut::<E::Layout>().unwrap(),
- };
-
- self.paint(layout, view, cx)
- }
-}
-
-/// A dynamically typed element.
-pub struct AnyElement<V> {
- element: Box<dyn ElementObject<V>>,
- layout: Option<(NodeId, Box<dyn Any>)>,
-}
-
-impl<V: 'static> AnyElement<V> {
- pub fn layout(&mut self, view: &mut V, cx: &mut LayoutContext<V>) -> Result<NodeId> {
- let pushed_text_style = self.push_text_style(cx);
-
- let (node_id, layout) = self.element.layout(view, cx)?;
- self.layout = Some((node_id, layout));
-
- if pushed_text_style {
- cx.pop_text_style();
- }
-
- Ok(node_id)
- }
-
- pub fn paint(&mut self, view: &mut V, cx: &mut PaintContext<V>) -> Result<()> {
- let pushed_text_style = self.push_text_style(cx);
-
- let (layout_node_id, element_layout) =
- self.layout.as_mut().expect("paint called before layout");
-
- let layout = Layout {
- from_engine: cx
- .layout_engine()
- .unwrap()
- .computed_layout(*layout_node_id)
- .expect("you can currently only use playground elements within an adapter"),
- from_element: element_layout.as_mut(),
- };
-
- let style = self.element.computed_style(cx.as_view_context());
-
- let fill_color = style.fill.as_ref().and_then(|fill| fill.color());
- if let Some(fill_color) = fill_color {
- cx.scene.push_quad(gpui::scene::Quad {
- bounds: layout.from_engine.bounds,
- background: Some(fill_color.into()),
- border: Default::default(),
- corner_radii: Default::default(),
- });
- }
-
- for event_handler in self.element.handlers_mut().iter().cloned() {
- let EngineLayout { order, bounds } = layout.from_engine;
-
- let view_id = cx.view_id();
- let view_event_handler = event_handler.handler.clone();
-
- // TODO: Tuck this into a method on PaintContext.
- cx.scene
- .interactive_regions
- .push(gpui::scene::InteractiveRegion {
- order,
- bounds,
- outside_bounds: event_handler.outside_bounds,
- event_handler: Rc::new(move |view, event, window_cx, view_id| {
- let mut view_context = ViewContext::mutable(window_cx, view_id);
- let mut event_context = EventContext::new(&mut view_context);
- view_event_handler(view.downcast_mut().unwrap(), event, &mut event_context);
- }),
- event_type: event_handler.event_type,
- view_id,
- });
- }
-
- self.element.paint(layout, view, cx)?;
- if pushed_text_style {
- cx.pop_text_style();
- }
-
- 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<V: 'static> Element<V> for AnyElement<V> {
- type Layout = ();
-
- fn declared_style(&mut self) -> &mut StyleRefinement {
- self.element.declared_style()
- }
-
- fn computed_style(&mut self, cx: &mut ViewContext<V>) -> &StyleRefinement {
- self.element.computed_style(cx)
- }
-
- fn handlers_mut(&mut self) -> &mut Vec<EventHandler<V>> {
- self.element.handlers_mut()
- }
-
- fn layout(
- &mut self,
- view: &mut V,
- cx: &mut LayoutContext<V>,
- ) -> Result<(NodeId, Self::Layout)> {
- Ok((self.layout(view, cx)?, ()))
- }
-
- fn paint(&mut self, layout: Layout<()>, view: &mut V, cx: &mut PaintContext<V>) -> Result<()> {
- self.paint(view, cx)
- }
-}
-
-pub trait IntoElement<V: 'static> {
+pub trait IntoElement<V> {
type Element: Element<V>;
fn into_element(self) -> Self::Element;
-
- fn into_any_element(self) -> AnyElement<V>
- where
- Self: Sized,
- {
- self.into_element().into_any()
- }
}
@@ -1,84 +0,0 @@
-use crate::{
- element::{
- AnyElement, Element, EventHandler, IntoElement, Layout, LayoutContext, NodeId,
- PaintContext, ParentElement,
- },
- style::{Style, StyleRefinement},
-};
-use anyhow::{anyhow, Result};
-use gpui::LayoutId;
-use playground_macros::IntoElement;
-use refineable::Refineable;
-
-#[derive(IntoElement)]
-#[element_crate = "crate"]
-pub struct Frame<V: 'static> {
- style: StyleRefinement,
- handlers: Vec<EventHandler<V>>,
- children: Vec<AnyElement<V>>,
-}
-
-pub fn frame<V>() -> Frame<V> {
- Frame {
- style: StyleRefinement::default(),
- handlers: Vec::new(),
- children: Vec::new(),
- }
-}
-
-impl<V: 'static> Element<V> for Frame<V> {
- type Layout = ();
-
- fn declared_style(&mut self) -> &mut StyleRefinement {
- &mut self.style
- }
-
- fn handlers_mut(&mut self) -> &mut Vec<EventHandler<V>> {
- &mut self.handlers
- }
-
- fn layout(
- &mut self,
- view: &mut V,
- cx: &mut LayoutContext<V>,
- ) -> Result<(NodeId, Self::Layout)> {
- let child_layout_node_ids = self
- .children
- .iter_mut()
- .map(|child| child.layout(view, cx))
- .collect::<Result<Vec<LayoutId>>>()?;
-
- let rem_size = cx.rem_pixels();
- let style = Style::default().refined(&self.style);
- let node_id = cx
- .layout_engine()
- .ok_or_else(|| anyhow!("no layout engine"))?
- .add_node(style.to_taffy(rem_size), child_layout_node_ids)?;
-
- Ok((node_id, ()))
- }
-
- fn paint(&mut self, layout: Layout<()>, view: &mut V, cx: &mut PaintContext<V>) -> Result<()> {
- for child in &mut self.children {
- child.paint(view, cx)?;
- }
- Ok(())
- }
-}
-
-impl<V: 'static> ParentElement<V> for Frame<V> {
- fn child(mut self, child: impl IntoElement<V>) -> Self {
- self.children.push(child.into_any_element());
- self
- }
-
- fn children<I, E>(mut self, children: I) -> Self
- where
- I: IntoIterator<Item = E>,
- E: IntoElement<V>,
- {
- self.children
- .extend(children.into_iter().map(|e| e.into_any_element()));
- self
- }
-}
@@ -1,119 +1,70 @@
-use std::{cell::Cell, marker::PhantomData, rc::Rc};
-
-use gpui::{
- geometry::{rect::RectF, vector::Vector2F},
- platform::MouseMovedEvent,
- EngineLayout, ViewContext,
-};
-use refineable::Refineable;
-
use crate::{
- element::{Element, ParentElement},
- style::StyleRefinement,
+ element::{Element, Layout},
+ layout_context::LayoutContext,
+ paint_context::PaintContext,
+ style::{StyleRefinement, Styleable},
};
+use anyhow::Result;
+use gpui::platform::MouseMovedEvent;
+use refineable::Refineable;
+use std::{cell::Cell, marker::PhantomData};
-pub struct Hoverable<V, E> {
- hover_style: StyleRefinement,
- computed_style: Option<StyleRefinement>,
- hovered: Rc<Cell<bool>>,
- view_type: PhantomData<V>,
+pub struct Hoverable<V, E: Element<V> + Styleable> {
+ hovered: Cell<bool>,
+ child_style: StyleRefinement,
+ hovered_style: StyleRefinement,
child: E,
+ view_type: PhantomData<V>,
}
-impl<V, E> Hoverable<V, E> {
- pub fn new(child: E) -> Self {
- Self {
- hover_style: StyleRefinement::default(),
- computed_style: None,
- hovered: Default::default(),
- view_type: PhantomData,
- child,
- }
+pub fn hoverable<V, E: Element<V> + Styleable>(mut child: E) -> Hoverable<V, E> {
+ Hoverable {
+ hovered: Cell::new(false),
+ child_style: child.declared_style().clone(),
+ hovered_style: Default::default(),
+ child,
+ view_type: PhantomData,
}
}
-impl<V: 'static, E: Element<V>> Element<V> for Hoverable<V, E> {
- type Layout = E::Layout;
+impl<V, E: Element<V> + Styleable> Styleable for Hoverable<V, E> {
+ type Style = E::Style;
- fn declared_style(&mut self) -> &mut StyleRefinement {
- &mut self.hover_style
+ fn declared_style(&mut self) -> &mut crate::style::StyleRefinement {
+ self.child.declared_style()
}
+}
- fn computed_style(&mut self, cx: &mut ViewContext<V>) -> &StyleRefinement {
- dbg!(self.computed_style.is_some());
-
- self.computed_style.get_or_insert_with(|| {
- let mut style = self.child.computed_style(cx).clone();
- if self.hovered.get() {
- style.refine(&self.hover_style);
- }
- style
- })
- }
+impl<V: 'static, E: Element<V> + Styleable> Element<V> for Hoverable<V, E> {
+ type Layout = E::Layout;
- fn handlers_mut(&mut self) -> &mut Vec<crate::element::EventHandler<V>> {
- self.child.handlers_mut()
- }
+ fn layout(&mut self, view: &mut V, cx: &mut LayoutContext<V>) -> Result<Layout<V, Self::Layout>>
+ where
+ Self: Sized,
+ {
+ 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();
+ }
- fn layout(
- &mut self,
- view: &mut V,
- cx: &mut gpui::LayoutContext<V>,
- ) -> anyhow::Result<(taffy::tree::NodeId, Self::Layout)> {
self.child.layout(view, cx)
}
- fn paint<'a>(
+ fn paint(
&mut self,
- layout: crate::element::Layout<Self::Layout>,
view: &mut V,
- cx: &mut crate::element::PaintContext<V>,
- ) -> anyhow::Result<()> {
- let EngineLayout { bounds, order } = layout.from_engine;
- let window_bounds = RectF::new(Vector2F::zero(), cx.window_size());
- 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: &MouseMovedEvent, cx| {
- let mouse_within_bounds = bounds.contains_point(cx.mouse_position());
- if mouse_within_bounds != hovered.get() {
- dbg!("hovered", mouse_within_bounds);
- hovered.set(mouse_within_bounds);
- cx.repaint();
- }
- },
- );
- Ok(())
- }
-}
-
-impl<V: 'static, P: ParentElement<V>> ParentElement<V> for Hoverable<V, P> {
- fn child(mut self, child: impl crate::element::IntoElement<V>) -> Self
- where
- Self: Sized,
- {
- self.child = self.child.child(child);
- self
- }
-
- fn children<I, E>(mut self, children: I) -> Self
- where
+ layout: &mut Layout<V, Self::Layout>,
+ cx: &mut PaintContext<V>,
+ ) where
Self: Sized,
- I: IntoIterator<Item = E>,
- E: crate::element::IntoElement<V>,
{
- self.child = self.child.children(children);
- self
+ 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| {});
}
}
@@ -4,7 +4,7 @@ pub use gpui::LayoutContext as LegacyLayoutContext;
use gpui::{RenderContext, ViewContext};
pub use taffy::tree::NodeId;
-use crate::{div::Layout, style::Style};
+use crate::{element::Layout, style::Style};
#[derive(Deref, DerefMut)]
pub struct LayoutContext<'a, 'b, 'c, 'd, V> {
@@ -9,7 +9,6 @@ mod color;
mod components;
mod div;
mod element;
-mod frame;
mod hoverable;
mod layout_context;
mod paint_context;
@@ -1,7 +1,7 @@
use crate::{
color::Hsla,
- div::{Element, Layout},
- element::PaintContext,
+ element::{Element, Layout},
+ paint_context::PaintContext,
};
use gpui::{
fonts::TextStyleRefinement,
@@ -10,6 +10,7 @@ use gpui::{
Size, SizeRefinement,
},
};
+use playground_macros::styleable_helpers;
use refineable::Refineable;
pub use taffy::style::{
AlignContent, AlignItems, AlignSelf, Display, FlexDirection, FlexWrap, JustifyContent,
@@ -243,3 +244,25 @@ impl CornerRadii {
}
}
}
+
+pub trait Styleable {
+ type Style: refineable::Refineable;
+
+ fn declared_style(&mut self) -> &mut playground::style::StyleRefinement;
+
+ fn style(&mut self) -> playground::style::Style {
+ let mut style = playground::style::Style::default();
+ style.refine(self.declared_style());
+ style
+ }
+}
+
+// Tailwind-style helpers methods that take and return mut self
+//
+// Example:
+// // Sets the padding to 0.5rem, just like class="p-2" in Tailwind.
+// fn p_2(mut self) -> Self where Self: Sized;
+use crate as playground; // Macro invocation references this crate as playground.
+pub trait StyleHelpers: Styleable<Style = Style> {
+ styleable_helpers!();
+}
@@ -1,40 +1,35 @@
use crate::{
- element::{Element, ElementMetadata, EventHandler, IntoElement},
+ element::{Element, IntoElement, Layout},
+ layout_context::LayoutContext,
+ paint_context::PaintContext,
style::Style,
};
+use anyhow::Result;
use gpui::{geometry::Size, text_layout::LineLayout, RenderContext};
use parking_lot::Mutex;
use refineable::Refineable;
use std::sync::Arc;
impl<V: 'static, S: Into<ArcCow<'static, str>>> IntoElement<V> for S {
- type Element = Text<V>;
+ type Element = Text;
fn into_element(self) -> Self::Element {
- Text {
- text: self.into(),
- metadata: Default::default(),
- }
+ Text { text: self.into() }
}
}
-pub struct Text<V> {
+pub struct Text {
text: ArcCow<'static, str>,
- metadata: ElementMetadata<V>,
}
-impl<V: 'static> Element<V> for Text<V> {
+impl<V: 'static> Element<V> for Text {
type Layout = Arc<Mutex<Option<TextLayout>>>;
- fn declared_style(&mut self) -> &mut crate::style::StyleRefinement {
- &mut self.metadata.style
- }
-
fn layout(
&mut self,
view: &mut V,
- cx: &mut gpui::LayoutContext<V>,
- ) -> anyhow::Result<(taffy::tree::NodeId, Self::Layout)> {
+ cx: &mut LayoutContext<V>,
+ ) -> Result<Layout<V, Self::Layout>> {
let rem_size = cx.rem_pixels();
let fonts = cx.platform().fonts();
let text_style = cx.text_style();
@@ -72,10 +67,10 @@ impl<V: 'static> Element<V> for Text<V> {
fn paint<'a>(
&mut self,
- layout: crate::element::Layout<Arc<Mutex<Option<TextLayout>>>>,
view: &mut V,
- cx: &mut crate::element::PaintContext<V>,
- ) -> anyhow::Result<()> {
+ layout: &mut Layout<V, Self::Layout>,
+ cx: &mut PaintContext<V>,
+ ) {
let element_layout_lock = layout.from_element.lock();
let element_layout = element_layout_lock
.as_ref()
@@ -94,11 +89,6 @@ impl<V: 'static> Element<V> for Text<V> {
line_height,
cx.legacy_cx,
);
- Ok(())
- }
-
- fn handlers_mut(&mut self) -> &mut Vec<EventHandler<V>> {
- &mut self.metadata.handlers
}
}
@@ -1,5 +1,5 @@
use crate::element::{AnyElement, Element};
-use gpui::{Element as _, ViewContext};
+use gpui::ViewContext;
pub fn view<F, E>(mut render: F) -> ViewFn
where