use crate::{ adapter::Adapter, style::{DefinedLength, Display, Fill, Length, Overflow, Position, Style}, }; use anyhow::Result; use derive_more::{Deref, DerefMut}; use gpui::{ EngineLayout, LayoutContext as LegacyLayoutContext, PaintContext as LegacyPaintContext, }; use playground_macros::tailwind_lengths; pub use taffy::tree::NodeId; #[derive(Deref, DerefMut)] pub struct LayoutContext<'a, 'b, 'c, 'd, V> { pub(crate) legacy_cx: &'d mut LegacyLayoutContext<'a, 'b, 'c, V>, } #[derive(Deref, DerefMut)] pub struct PaintContext<'a, 'b, 'c, 'd, V> { #[deref] #[deref_mut] pub(crate) legacy_cx: &'d mut LegacyPaintContext<'a, 'b, 'c, V>, pub(crate) scene: &'d mut gpui::SceneBuilder, } pub trait Element: 'static + Clone { fn style_mut(&mut self) -> &mut Style; fn layout(&mut self, view: &mut V, cx: &mut LayoutContext) -> Result; fn paint(&mut self, layout: EngineLayout, view: &mut V, cx: &mut PaintContext) -> Result<()>; /// Convert to a dynamically-typed element suitable for layout and paint. fn into_any(self) -> AnyElement where Self: 'static + Sized, { AnyElement { element: Box::new(self) as Box>, layout_node_id: None, } } fn adapt(self) -> Adapter where Self: Sized, Self: Element, { Adapter(self.into_any()) } // Display //////////////////// fn block(mut self) -> Self where Self: Sized, { self.style_mut().display = Display::Block; self } fn flex(mut self) -> Self where Self: Sized, { self.style_mut().display = Display::Flex; self } fn grid(mut self) -> Self where Self: Sized, { self.style_mut().display = Display::Grid; self } // style::Overflow /////////////////// fn overflow_visible(mut self) -> Self where Self: Sized, { self.style_mut().overflow.x = Overflow::Visible; self.style_mut().overflow.y = Overflow::Visible; self } fn overflow_hidden(mut self) -> Self where Self: Sized, { self.style_mut().overflow.x = Overflow::Hidden; self.style_mut().overflow.y = Overflow::Hidden; self } fn overflow_scroll(mut self) -> Self where Self: Sized, { self.style_mut().overflow.x = Overflow::Scroll; self.style_mut().overflow.y = Overflow::Scroll; self } fn overflow_x_visible(mut self) -> Self where Self: Sized, { self.style_mut().overflow.x = Overflow::Visible; self } fn overflow_x_hidden(mut self) -> Self where Self: Sized, { self.style_mut().overflow.x = Overflow::Hidden; self } fn overflow_x_scroll(mut self) -> Self where Self: Sized, { self.style_mut().overflow.x = Overflow::Scroll; self } fn overflow_y_visible(mut self) -> Self where Self: Sized, { self.style_mut().overflow.y = Overflow::Visible; self } fn overflow_y_hidden(mut self) -> Self where Self: Sized, { self.style_mut().overflow.y = Overflow::Hidden; self } fn overflow_y_scroll(mut self) -> Self where Self: Sized, { self.style_mut().overflow.y = Overflow::Scroll; self } // Position /////////////////// fn relative(mut self) -> Self where Self: Sized, { self.style_mut().position = Position::Relative; self } fn absolute(mut self) -> Self where Self: Sized, { self.style_mut().position = Position::Absolute; self } #[tailwind_lengths] fn inset_(mut self, length: DefinedLength) -> Self where Self: Sized, { self.style_mut().inset.top = length; self.style_mut().inset.right = length; self.style_mut().inset.bottom = length; self.style_mut().inset.left = length; self } fn w(mut self, width: impl Into) -> Self where Self: Sized, { self.style_mut().size.width = width.into(); self } fn w_auto(mut self) -> Self where Self: Sized, { self.style_mut().size.width = Length::Auto; self } #[tailwind_lengths] fn w_(mut self, length: DefinedLength) -> Self where Self: Sized, { self.style_mut().size.width = length; self } #[tailwind_lengths] fn min_w_(mut self, length: DefinedLength) -> Self where Self: Sized, { self.style_mut().min_size.width = length; self } fn h(mut self, height: impl Into) -> Self where Self: Sized, { self.style_mut().size.height = height.into(); self } fn h_auto(mut self) -> Self where Self: Sized, { self.style_mut().size.height = Length::Auto; self } #[tailwind_lengths] fn h_(mut self, height: DefinedLength) -> Self where Self: Sized, { self.style_mut().size.height = height; self } #[tailwind_lengths] fn min_h_(mut self, length: DefinedLength) -> Self where Self: Sized, { self.style_mut().min_size.height = length; self } fn fill(mut self, fill: impl Into) -> Self where Self: Sized, { self.style_mut().fill = fill.into(); self } } pub trait ElementObject { fn style_mut(&mut self) -> &mut Style; fn layout(&mut self, view: &mut V, cx: &mut LayoutContext) -> Result; fn paint(&mut self, layout: EngineLayout, view: &mut V, cx: &mut PaintContext) -> Result<()>; fn clone_object(&self) -> Box>; } impl> ElementObject for E { fn style_mut(&mut self) -> &mut Style { self.style_mut() } fn layout(&mut self, view: &mut V, cx: &mut LayoutContext) -> Result { self.layout(view, cx) } fn paint( &mut self, layout: EngineLayout, view: &mut V, cx: &mut PaintContext, ) -> Result<()> { self.paint(layout, view, cx) } fn clone_object(&self) -> Box> { Box::new(Clone::clone(self)) } } pub struct AnyElement { element: Box>, layout_node_id: Option, } // enum LayoutState { // None, // Registered(NodeId, Box), // Computed(Layout, Box), // } impl AnyElement { pub fn layout(&mut self, view: &mut V, cx: &mut LayoutContext) -> Result { let layout_node_id = self.element.layout(view, cx)?; self.layout_node_id = Some(layout_node_id); Ok(layout_node_id) } pub fn paint(&mut self, view: &mut V, cx: &mut PaintContext) -> Result<()> { let layout_node_id = self.layout_node_id.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) } } impl Clone for AnyElement { fn clone(&self) -> Self { Self { element: self.element.clone_object(), layout_node_id: self.layout_node_id, } } } impl Element for AnyElement { fn style_mut(&mut self) -> &mut Style { self.element.style_mut() } fn layout(&mut self, view: &mut V, cx: &mut LayoutContext) -> Result { self.layout(view, cx) } fn paint( &mut self, layout: EngineLayout, view: &mut V, cx: &mut PaintContext, ) -> Result<()> { self.paint(view, cx) } }