crates/gpui/playground/src/adapter.rs 🔗
@@ -4,7 +4,6 @@ use util::ResultExt;
use crate::element::AnyElement;
-#[derive(Clone)]
pub struct Adapter<V>(pub(crate) AnyElement<V>);
impl<V: 'static> gpui::Element<V> for Adapter<V> {
Nathan Sobo created
crates/gpui/playground/src/adapter.rs | 1
crates/gpui/playground/src/components.rs | 72 ++++++-
crates/gpui/playground/src/element.rs | 140 ++++++++++----
crates/gpui/playground/src/frame.rs | 36 +--
crates/gpui/playground/src/playground.rs | 1
crates/gpui/playground/src/style.rs | 8
crates/gpui/playground_macros/src/derive_element.rs | 48 +++++
7 files changed, 224 insertions(+), 82 deletions(-)
@@ -4,7 +4,6 @@ use util::ResultExt;
use crate::element::AnyElement;
-#[derive(Clone)]
pub struct Adapter<V>(pub(crate) AnyElement<V>);
impl<V: 'static> gpui::Element<V> for Adapter<V> {
@@ -1,41 +1,57 @@
-use crate::{element::Element, frame, themes::rose_pine};
+use crate::{
+ element::{AnyElement, Element, ElementMetadata},
+ frame,
+ themes::rose_pine,
+};
use gpui::ViewContext;
-use std::{any::Any, borrow::Cow, marker::PhantomData, rc::Rc};
+use std::{borrow::Cow, marker::PhantomData, rc::Rc};
+
+struct ButtonHandlers<V, D> {
+ click: Option<Rc<dyn Fn(&mut V, &D)>>,
+}
+
+impl<V, D> Default for ButtonHandlers<V, D> {
+ fn default() -> Self {
+ Self { click: None }
+ }
+}
pub struct Button<V: 'static, D: 'static> {
+ metadata: ElementMetadata<V>,
+ button_handlers: ButtonHandlers<V, D>,
label: Cow<'static, str>,
data: Rc<D>,
- click_handler: Option<Rc<dyn Fn(&mut V, &dyn Any)>>,
view_type: PhantomData<V>,
}
impl<V: 'static> Button<V, ()> {
fn new(label: impl Into<Cow<'static, str>>) -> Self {
Self {
+ metadata: Default::default(),
+ button_handlers: ButtonHandlers::default(),
label: label.into(),
data: Rc::new(()),
- click_handler: None,
view_type: PhantomData,
}
}
pub fn data<D: 'static>(self, data: D) -> Button<V, D> {
Button {
+ metadata: Default::default(),
+ button_handlers: ButtonHandlers::default(),
label: self.label,
data: Rc::new(data),
- click_handler: None,
view_type: PhantomData,
}
}
}
impl<V: 'static, D: 'static> Button<V, D> {
- fn click(mut self, handler: impl Fn(&mut V, &D) + 'static) -> Self {
- self.click_handler = Some(Rc::new(move |view, data| {
- let data = data.downcast_ref::<D>().unwrap();
- handler(view, data);
- }));
- self
+ fn click(self, handler: impl Fn(&mut V, &D) + 'static) -> Self {
+ let data = self.data.clone();
+ Element::click(self, move |view, _| {
+ handler(view, data.as_ref());
+ })
}
}
@@ -48,7 +64,7 @@ impl<V: 'static, D: 'static> Button<V, D> {
// TODO: Drive from the context
let button = frame().fill(rose_pine::dawn().error(0.5)).h_5().w_9();
- if let Some(handler) = self.click_handler.clone() {
+ if let Some(handler) = self.button_handlers.click.clone() {
let data = self.data.clone();
button.click(move |view, event| handler(view, data.as_ref()))
} else {
@@ -56,3 +72,35 @@ impl<V: 'static, D: 'static> Button<V, D> {
}
}
}
+
+impl<V: 'static, D> Element<V> for Button<V, D> {
+ type Layout = AnyElement<V>;
+
+ fn style_mut(&mut self) -> &mut crate::style::ElementStyle {
+ &mut self.metadata.style
+ }
+
+ fn handlers_mut(&mut self) -> &mut crate::element::ElementHandlers<V> {
+ &mut self.metadata.handlers
+ }
+
+ fn layout(
+ &mut self,
+ view: &mut V,
+ cx: &mut crate::element::LayoutContext<V>,
+ ) -> anyhow::Result<(taffy::tree::NodeId, Self::Layout)> {
+ let mut element = self.render(view, cx).into_any();
+ let node_id = element.layout(view, cx)?;
+ Ok((node_id, element))
+ }
+
+ fn paint<'a>(
+ &mut self,
+ layout: crate::element::Layout<'a, Self::Layout>,
+ view: &mut V,
+ cx: &mut crate::element::PaintContext<V>,
+ ) -> anyhow::Result<()> {
+ layout.from_element.paint(view, cx)?;
+ Ok(())
+ }
+}
@@ -1,13 +1,14 @@
-use std::{any::Any, sync::Arc};
+use std::{any::Any, rc::Rc};
use crate::{
adapter::Adapter,
- style::{DefinedLength, Display, Fill, Length, Overflow, Position, Style},
+ style::{DefinedLength, Display, ElementStyle, Fill, Length, Overflow, Position},
};
use anyhow::Result;
use derive_more::{Deref, DerefMut};
use gpui::{
- EngineLayout, LayoutContext as LegacyLayoutContext, PaintContext as LegacyPaintContext,
+ scene::MouseClick, EngineLayout, LayoutContext as LegacyLayoutContext,
+ PaintContext as LegacyPaintContext,
};
use playground_macros::tailwind_lengths;
pub use taffy::tree::NodeId;
@@ -25,14 +26,48 @@ pub struct PaintContext<'a, 'b, 'c, 'd, V> {
pub(crate) scene: &'d mut gpui::SceneBuilder,
}
-pub trait Element<V: 'static>: 'static + Clone {
+pub struct Layout<'a, E: ?Sized> {
+ pub from_engine: EngineLayout,
+ pub from_element: &'a mut E,
+}
+
+pub struct ElementHandlers<V> {
+ click: Option<Rc<dyn Fn(&mut V, MouseClick)>>,
+}
+
+pub struct ElementMetadata<V> {
+ pub style: ElementStyle,
+ pub handlers: ElementHandlers<V>,
+}
+
+impl<V> Default for ElementMetadata<V> {
+ fn default() -> Self {
+ Self {
+ style: ElementStyle::default(),
+ handlers: ElementHandlers::default(),
+ }
+ }
+}
+
+impl<V> Default for ElementHandlers<V> {
+ fn default() -> Self {
+ ElementHandlers { click: None }
+ }
+}
+
+pub trait Element<V: 'static>: 'static {
type Layout: 'static;
- fn style_mut(&mut self) -> &mut Style;
+ fn style_mut(&mut self) -> &mut ElementStyle;
+ fn handlers_mut(&mut self) -> &mut ElementHandlers<V>;
fn layout(&mut self, view: &mut V, cx: &mut LayoutContext<V>)
-> Result<(NodeId, Self::Layout)>;
- fn paint(&mut self, layout: EngineLayout, view: &mut V, cx: &mut PaintContext<V>)
- -> Result<()>;
+ fn paint<'a>(
+ &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>
@@ -53,6 +88,16 @@ pub trait Element<V: 'static>: 'static + Clone {
Adapter(self.into_any())
}
+ fn click(mut self, handler: impl Fn(&mut V, MouseClick) + 'static) -> Self
+ where
+ Self: Sized,
+ {
+ self.handlers_mut().click = Some(Rc::new(move |view, event| {
+ handler(view, event);
+ }));
+ self
+ }
+
// Display ////////////////////
fn block(mut self) -> Self
@@ -265,46 +310,59 @@ pub trait Element<V: 'static>: 'static + Clone {
}
pub trait ElementObject<V> {
- fn style_mut(&mut self) -> &mut Style;
+ fn style_mut(&mut self) -> &mut ElementStyle;
+ fn handlers_mut(&mut self) -> &mut ElementHandlers<V>;
fn layout(&mut self, view: &mut V, cx: &mut LayoutContext<V>)
- -> Result<(NodeId, Arc<dyn Any>)>;
- fn paint(&mut self, layout: EngineLayout, view: &mut V, cx: &mut PaintContext<V>)
- -> Result<()>;
- fn clone_object(&self) -> Box<dyn ElementObject<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 style_mut(&mut self) -> &mut Style {
- self.style_mut()
+ fn style_mut(&mut self) -> &mut ElementStyle {
+ Element::style_mut(self)
+ }
+
+ fn handlers_mut(&mut self) -> &mut ElementHandlers<V> {
+ Element::handlers_mut(self)
}
fn layout(
&mut self,
view: &mut V,
cx: &mut LayoutContext<V>,
- ) -> Result<(NodeId, Arc<dyn Any>)> {
+ ) -> Result<(NodeId, Box<dyn Any>)> {
let (node_id, layout) = self.layout(view, cx)?;
- let layout = Arc::new(layout) as Arc<dyn Any>;
+ let layout = Box::new(layout) as Box<dyn Any>;
Ok((node_id, layout))
}
fn paint(
&mut self,
- layout: EngineLayout,
+ 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)
}
- fn clone_object(&self) -> Box<dyn ElementObject<V>> {
- Box::new(Clone::clone(self))
- }
+ // fn clone_object(&self) -> Box<dyn ElementObject<V>> {
+ // Box::new(Clone::clone(self))
+ // }
}
pub struct AnyElement<V> {
element: Box<dyn ElementObject<V>>,
- layout: Option<(NodeId, Arc<dyn Any>)>,
+ layout: Option<(NodeId, Box<dyn Any>)>,
}
impl<V> AnyElement<V> {
@@ -315,32 +373,33 @@ impl<V> AnyElement<V> {
}
pub fn paint(&mut self, view: &mut V, cx: &mut PaintContext<V>) -> Result<()> {
- let (layout_node_id, layout) = self.layout.clone().expect("paint called before layout");
- let layout = cx
- .layout_engine()
- .unwrap()
- .computed_layout(layout_node_id)
- .expect("you can currently only use playground elements within an adapter");
- self.element.paint(layout, view, 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(),
+ };
-impl<V> Clone for AnyElement<V> {
- fn clone(&self) -> Self {
- Self {
- element: self.element.clone_object(),
- layout: self.layout.clone(),
- }
+ self.element.paint(layout, view, cx)
}
}
impl<V: 'static> Element<V> for AnyElement<V> {
type Layout = ();
- fn style_mut(&mut self) -> &mut Style {
+ fn style_mut(&mut self) -> &mut ElementStyle {
self.element.style_mut()
}
+ fn handlers_mut(&mut self) -> &mut ElementHandlers<V> {
+ self.element.handlers_mut()
+ }
+
fn layout(
&mut self,
view: &mut V,
@@ -349,12 +408,7 @@ impl<V: 'static> Element<V> for AnyElement<V> {
Ok((self.layout(view, cx)?, ()))
}
- fn paint(
- &mut self,
- layout: EngineLayout,
- view: &mut V,
- cx: &mut PaintContext<V>,
- ) -> Result<()> {
+ fn paint(&mut self, layout: Layout<()>, view: &mut V, cx: &mut PaintContext<V>) -> Result<()> {
self.paint(view, cx)
}
}
@@ -1,18 +1,20 @@
use crate::{
- element::{AnyElement, Element, LayoutContext, NodeId, PaintContext},
- style::Style,
+ element::{AnyElement, Element, ElementHandlers, Layout, LayoutContext, NodeId, PaintContext},
+ style::ElementStyle,
};
use anyhow::{anyhow, Result};
-use gpui::{EngineLayout, LayoutNodeId};
+use gpui::LayoutNodeId;
pub struct Frame<V> {
- style: Style,
+ style: ElementStyle,
+ handlers: ElementHandlers<V>,
children: Vec<AnyElement<V>>,
}
pub fn frame<V>() -> Frame<V> {
Frame {
- style: Style::default(),
+ style: ElementStyle::default(),
+ handlers: ElementHandlers::default(),
children: Vec::new(),
}
}
@@ -20,10 +22,14 @@ pub fn frame<V>() -> Frame<V> {
impl<V: 'static> Element<V> for Frame<V> {
type Layout = ();
- fn style_mut(&mut self) -> &mut Style {
+ fn style_mut(&mut self) -> &mut ElementStyle {
&mut self.style
}
+ fn handlers_mut(&mut self) -> &mut ElementHandlers<V> {
+ &mut self.handlers
+ }
+
fn layout(
&mut self,
view: &mut V,
@@ -44,14 +50,9 @@ impl<V: 'static> Element<V> for Frame<V> {
Ok((node_id, ()))
}
- fn paint(
- &mut self,
- layout: EngineLayout,
- view: &mut V,
- cx: &mut PaintContext<V>,
- ) -> Result<()> {
+ fn paint(&mut self, layout: Layout<()>, view: &mut V, cx: &mut PaintContext<V>) -> Result<()> {
cx.scene.push_quad(gpui::scene::Quad {
- bounds: layout.bounds,
+ bounds: layout.from_engine.bounds,
background: self.style.fill.color().map(Into::into),
border: Default::default(),
corner_radii: Default::default(),
@@ -63,12 +64,3 @@ impl<V: 'static> Element<V> for Frame<V> {
Ok(())
}
}
-
-impl<V> Clone for Frame<V> {
- fn clone(&self) -> Self {
- Self {
- style: self.style.clone(),
- children: self.children.clone(),
- }
- }
-}
@@ -14,6 +14,7 @@ use view::view;
mod adapter;
mod color;
+mod components;
mod element;
mod frame;
mod style;
@@ -5,7 +5,7 @@ pub use taffy::style::{
};
#[derive(Clone)]
-pub struct Style {
+pub struct ElementStyle {
/// What layout strategy should be used?
pub display: Display,
@@ -67,8 +67,8 @@ pub struct Style {
pub fill: Fill,
}
-impl Style {
- pub const DEFAULT: Style = Style {
+impl ElementStyle {
+ pub const DEFAULT: ElementStyle = ElementStyle {
display: Display::DEFAULT,
overflow: Point {
x: Overflow::Visible,
@@ -137,7 +137,7 @@ impl Style {
}
}
-impl Default for Style {
+impl Default for ElementStyle {
fn default() -> Self {
Self::DEFAULT.clone()
}
@@ -0,0 +1,48 @@
+// type Result = ();
+// type LayoutContext<> = ();
+
+// trait Element<V: 'static>: 'static + Clone {
+// type Layout: 'static;
+
+// fn style_mut(&mut self) -> &mut Style;
+// fn layout(&mut self, view: &mut V, cx: &mut LayoutContext<V>)
+// -> Result<(NodeId, Self::Layout)>;
+// fn paint<'a>(
+// &mut self,
+// layout: Layout<'a, Self::Layout>,
+// view: &mut V,
+// cx: &mut PaintContext<V>,
+// ) -> Result<()>;
+// }
+
+// struct Button {
+// style: Style,
+// }
+
+// type Style = ();
+
+// impl Button {
+// fn render<V>() -> impl Element<V> {
+// todo!()
+// }
+// }
+
+// impl<V: 'static> Element<V> for Foo {
+// type Layout = ();
+
+// fn style_mut(&mut self) -> &mut Style {
+// unimplemented!()
+// }
+
+// fn layout(
+// &mut self,
+// view: &mut V,
+// cx: &mut LayoutContext<V>,
+// ) -> Result<(NodeId, Self::Layout)> {
+// unimplemented!()
+// }
+
+// fn paint(&mut self, layout: Layout<()>, view: &mut V, cx: &mut PaintContext<V>) -> Result<()> {
+// unimplemented!()
+// }
+// }