diff --git a/crates/gpui/playground/src/components.rs b/crates/gpui/playground/src/components.rs index 0ea1b6d02b..aa476e2a9d 100644 --- a/crates/gpui/playground/src/components.rs +++ b/crates/gpui/playground/src/components.rs @@ -1,131 +1,101 @@ -// use crate::{ -// element::{Element, ElementMetadata, ParentElement}, -// frame, -// text::ArcCow, -// themes::rose_pine, -// }; -// use gpui::{platform::MouseButton, ViewContext}; -// use playground_macros::Element; -// use std::{marker::PhantomData, rc::Rc}; +use crate::{ + div::div, + element::{Element, ParentElement}, + style::StyleHelpers, + text::ArcCow, + themes::rose_pine, +}; +use gpui::ViewContext; +use playground_macros::Element; -// struct ButtonHandlers { -// click: Option)>>, -// } +use std::{marker::PhantomData, rc::Rc}; -// impl Default for ButtonHandlers { -// fn default() -> Self { -// Self { click: None } -// } -// } +struct ButtonHandlers { + click: Option)>>, +} -// #[derive(Element)] -// #[element_crate = "crate"] -// pub struct Button { -// metadata: ElementMetadata, -// handlers: ButtonHandlers, -// label: Option>, -// icon: Option>, -// data: Rc, -// view_type: PhantomData, -// } +impl Default for ButtonHandlers { + fn default() -> Self { + Self { click: None } + } +} -// // Impl block for buttons without data. -// // See below for an impl block for any button. -// impl Button { -// fn new() -> Self { -// Self { -// metadata: Default::default(), -// handlers: ButtonHandlers::default(), -// label: None, -// icon: None, -// data: Rc::new(()), -// view_type: PhantomData, -// } -// } +use crate as playground; +#[derive(Element)] +pub struct Button { + handlers: ButtonHandlers, + label: Option>, + icon: Option>, + data: Rc, + view_type: PhantomData, +} -// pub fn data(self, data: D) -> Button { -// Button { -// metadata: Default::default(), -// handlers: ButtonHandlers::default(), -// label: self.label, -// icon: self.icon, -// data: Rc::new(data), -// view_type: PhantomData, -// } -// } -// } +// Impl block for buttons without data. +// See below for an impl block for any button. +impl Button { + fn new() -> Self { + Self { + handlers: ButtonHandlers::default(), + label: None, + icon: None, + data: Rc::new(()), + view_type: PhantomData, + } + } -// // Impl block for *any* button. -// impl Button { -// pub fn label(mut self, label: impl Into>) -> Self { -// self.label = Some(label.into()); -// self -// } + pub fn data(self, data: D) -> Button { + Button { + handlers: ButtonHandlers::default(), + label: self.label, + icon: self.icon, + data: Rc::new(data), + view_type: PhantomData, + } + } +} -// pub fn icon(mut self, icon: impl Into>) -> Self { -// self.icon = Some(icon.into()); -// self -// } +// Impl block for *any* button. +impl Button { + pub fn label(mut self, label: impl Into>) -> Self { + self.label = Some(label.into()); + self + } -// pub fn click(self, handler: impl Fn(&mut V, &D, &mut ViewContext) + 'static) -> Self { -// let data = self.data.clone(); -// Element::click(self, MouseButton::Left, move |view, _, cx| { -// handler(view, data.as_ref(), cx); -// }) -// } -// } + pub fn icon(mut self, icon: impl Into>) -> Self { + self.icon = Some(icon.into()); + self + } -// pub fn button() -> Button { -// Button::new() -// } + // pub fn click(self, handler: impl Fn(&mut V, &D, &mut ViewContext) + 'static) -> Self { + // let data = self.data.clone(); + // Self::click(self, MouseButton::Left, move |view, _, cx| { + // handler(view, data.as_ref(), cx); + // }) + // } +} -// impl Button { -// fn render(&mut self, view: &mut V, cx: &mut ViewContext) -> impl Element { -// // TODO: Drive theme from the context -// let button = frame() -// .fill(rose_pine::dawn().error(0.5)) -// .h_4() -// .children(self.label.clone()); +pub fn button() -> Button { + Button::new() +} -// if let Some(handler) = self.handlers.click.clone() { -// let data = self.data.clone(); -// button.mouse_down(MouseButton::Left, move |view, event, cx| { -// handler(view, data.as_ref(), cx) -// }) -// } else { -// button -// } -// } -// } +impl Button { + fn render(&mut self, view: &mut V, cx: &mut ViewContext) -> impl Element { + // TODO: Drive theme from the context + let button = div() + .fill(rose_pine::dawn().error(0.5)) + .h_4() + .children(self.label.clone()); -// // impl Element for Button { -// // type Layout = AnyElement; + button -// // fn style_mut(&mut self) -> &mut crate::style::ElementStyle { -// // &mut self.metadata.style -// // } - -// // fn handlers_mut(&mut self) -> &mut crate::element::ElementHandlers { -// // &mut self.metadata.handlers -// // } - -// // fn layout( -// // &mut self, -// // view: &mut V, -// // cx: &mut crate::element::LayoutContext, -// // ) -> 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, -// // ) -> anyhow::Result<()> { -// // layout.from_element.paint(view, cx)?; -// // Ok(()) -// // } -// // } + // TODO: Event handling + // if let Some(handler) = self.handlers.click.clone() { + // let data = self.data.clone(); + // // button.mouse_down(MouseButton::Left, move |view, event, cx| { + // // handler(view, data.as_ref(), cx) + // // }) + // } else { + // button + // } + } +} diff --git a/crates/gpui/playground/src/div.rs b/crates/gpui/playground/src/div.rs index 57d334506c..37bd69376d 100644 --- a/crates/gpui/playground/src/div.rs +++ b/crates/gpui/playground/src/div.rs @@ -1,8 +1,8 @@ use crate::{ - element::{AnyElement, Element, Layout}, + element::{AnyElement, Element, Layout, ParentElement}, layout_context::LayoutContext, paint_context::PaintContext, - style::{Style, StyleRefinement, Styleable}, + style::{Style, StyleHelpers, StyleRefinement, Styleable}, }; use anyhow::Result; use gpui::{platform::MouseMovedEvent, EventContext, LayoutId}; @@ -14,14 +14,6 @@ pub struct Div { children: SmallVec<[AnyElement; 2]>, } -impl Styleable for Div { - type Style = Style; - - fn declared_style(&mut self) -> &mut StyleRefinement { - &mut self.style - } -} - pub fn div() -> Div { Div { style: Default::default(), @@ -55,6 +47,22 @@ impl Element for Div { } } +impl Styleable for Div { + type Style = Style; + + fn declared_style(&mut self) -> &mut crate::style::StyleRefinement { + &mut self.style + } +} + +impl StyleHelpers for Div {} + +impl ParentElement for Div { + fn children_mut(&mut self) -> &mut SmallVec<[AnyElement; 2]> { + &mut self.children + } +} + pub trait Interactive { fn declared_interactions(&mut self) -> &mut Interactions; diff --git a/crates/gpui/playground/src/element.rs b/crates/gpui/playground/src/element.rs index 296baa5280..24ad7bcfda 100644 --- a/crates/gpui/playground/src/element.rs +++ b/crates/gpui/playground/src/element.rs @@ -1,12 +1,12 @@ use anyhow::Result; use derive_more::{Deref, DerefMut}; -use gpui::geometry::rect::RectF; -use gpui::EngineLayout; +use gpui::{geometry::rect::RectF, EngineLayout}; +use smallvec::SmallVec; use std::marker::PhantomData; use util::ResultExt; -use crate::layout_context::LayoutContext; -use crate::paint_context::PaintContext; +pub use crate::layout_context::LayoutContext; +pub use crate::paint_context::PaintContext; type LayoutId = gpui::LayoutId; @@ -21,11 +21,11 @@ pub struct Layout { } impl Layout { - pub fn new(id: LayoutId, engine_layout: Option, element_data: D) -> Self { + pub fn new(id: LayoutId, element_data: D) -> Self { Self { id, - engine_layout, - element_data, + engine_layout: None, + element_data: element_data, view_type: PhantomData, } } @@ -44,6 +44,14 @@ impl Layout { } } +impl Layout>> { + pub fn paint(&mut self, view: &mut V, cx: &mut PaintContext) { + let mut element = self.element_data.take().unwrap(); + element.paint(view, self.id, cx); + self.element_data = Some(element); + } +} + pub trait Element: 'static { type Layout; @@ -97,6 +105,9 @@ impl> ElementStateObject for ElementState { fn paint(&mut self, view: &mut V, layout_id: LayoutId, cx: &mut PaintContext) { let layout = self.layout.as_mut().expect("paint called before layout"); + if layout.engine_layout.is_none() { + layout.engine_layout = cx.computed_layout(layout_id).log_err() + } self.element.paint(view, layout, cx) } } @@ -115,7 +126,7 @@ impl AnyElement { } pub trait ParentElement { - fn children_mut(&mut self) -> &mut Vec>; + fn children_mut(&mut self) -> &mut SmallVec<[AnyElement; 2]>; fn child(mut self, child: impl IntoElement) -> Self where diff --git a/crates/gpui/playground/src/layout_context.rs b/crates/gpui/playground/src/layout_context.rs index 8241cbc9c5..7c9f13e7f0 100644 --- a/crates/gpui/playground/src/layout_context.rs +++ b/crates/gpui/playground/src/layout_context.rs @@ -49,6 +49,6 @@ impl<'a, 'b, 'c, 'd, V: 'static> LayoutContext<'a, 'b, 'c, 'd, V> { .ok_or_else(|| anyhow!("no layout engine"))? .add_node(style.to_taffy(rem_size), children)?; - Ok(Layout::new(id, None, element_data)) + Ok(Layout::new(id, element_data)) } } diff --git a/crates/gpui/playground/src/playground.rs b/crates/gpui/playground/src/playground.rs index 7b05893798..ed7aa2995d 100644 --- a/crates/gpui/playground/src/playground.rs +++ b/crates/gpui/playground/src/playground.rs @@ -1,8 +1,14 @@ #![allow(dead_code, unused_variables)] +use crate::{color::black, style::StyleHelpers}; +use element::Element; +use gpui::{ + geometry::{rect::RectF, vector::vec2f}, + platform::WindowOptions, +}; use log::LevelFilter; use simplelog::SimpleLogger; - -use themes::ThemeColors; +use themes::{rose_pine, ThemeColors}; +use view::view; mod adapter; mod color; @@ -21,32 +27,33 @@ fn main() { SimpleLogger::init(LevelFilter::Info, Default::default()).expect("could not initialize logger"); gpui::App::new(()).unwrap().run(|cx| { - // cx.add_window( - // WindowOptions { - // bounds: gpui::platform::WindowBounds::Fixed(RectF::new( - // vec2f(0., 0.), - // vec2f(400., 300.), - // )), - // center: true, - // ..Default::default() - // }, - // |_| view(|_| playground(&rose_pine::moon())), - // ); + cx.add_window( + WindowOptions { + bounds: gpui::platform::WindowBounds::Fixed(RectF::new( + vec2f(0., 0.), + vec2f(400., 300.), + )), + center: true, + ..Default::default() + }, + |_| view(|_| playground(&rose_pine::moon())), + ); cx.platform().activate(true); }); } -// fn playground(theme: &ThemeColors) -> impl Element { -// todo!() -// // frame() -// // .text_color(black()) -// // .h_full() -// // .w_half() -// // .fill(theme.success(0.5)) -// // .hover() -// // .fill(theme.error(0.5)) -// // .child(button().label("Hello").click(|_, _, _| println!("click!"))) -// } +fn playground(theme: &ThemeColors) -> impl Element { + use div::div; + + div() + .text_color(black()) + .h_full() + .w_24() + .fill(theme.success(0.5)) + // .hover() + // .fill(theme.error(0.5)) + // .child(button().label("Hello").click(|_, _, _| println!("click!"))) +} // todo!() // // column() diff --git a/crates/gpui/playground/src/style.rs b/crates/gpui/playground/src/style.rs index ed4dd7fe82..9216702f7f 100644 --- a/crates/gpui/playground/src/style.rs +++ b/crates/gpui/playground/src/style.rs @@ -257,7 +257,7 @@ pub trait Styleable { } } -// Tailwind-style helpers methods that take and return mut self +// Helpers methods that take and return mut self. This includes tailwind style methods for standard sizes etc. // // Example: // // Sets the padding to 0.5rem, just like class="p-2" in Tailwind. @@ -265,4 +265,22 @@ pub trait Styleable { use crate as playground; // Macro invocation references this crate as playground. pub trait StyleHelpers: Styleable