diff --git a/crates/gpui/playground/src/adapter.rs b/crates/gpui/playground/src/adapter.rs index bb3a417ae7..392186e295 100644 --- a/crates/gpui/playground/src/adapter.rs +++ b/crates/gpui/playground/src/adapter.rs @@ -1,70 +1,78 @@ -// use crate::element::{LayoutContext, PaintContext}; -// use gpui::{geometry::rect::RectF, LayoutEngine}; -// use util::ResultExt; +use crate::{layout_context::LayoutContext, paint_context::PaintContext}; +use gpui::{geometry::rect::RectF, LayoutEngine, LayoutId}; +use util::ResultExt; -// use crate::element::AnyElement; +/// Makes a new, playground-style element into a legacy element. +pub struct AdapterElement(pub(crate) crate::element::AnyElement); -// pub struct Adapter(pub(crate) AnyElement); +impl gpui::Element for AdapterElement { + type LayoutState = Option<(LayoutEngine, LayoutId)>; + type PaintState = (); -// impl gpui::Element for Adapter { -// type LayoutState = Option; -// type PaintState = (); + fn layout( + &mut self, + constraint: gpui::SizeConstraint, + view: &mut V, + cx: &mut gpui::LayoutContext, + ) -> (gpui::geometry::vector::Vector2F, Self::LayoutState) { + cx.push_layout_engine(LayoutEngine::new()); -// fn layout( -// &mut self, -// constraint: gpui::SizeConstraint, -// view: &mut V, -// cx: &mut LayoutContext, -// ) -> (gpui::geometry::vector::Vector2F, Self::LayoutState) { -// cx.push_layout_engine(LayoutEngine::new()); -// let node = self.0.layout(view, cx).log_err(); + let size = constraint.max; + let mut cx = LayoutContext::new(cx); + let layout_id = self.0.layout(view, &mut cx).log_err(); + if let Some(layout_id) = layout_id { + cx.layout_engine() + .unwrap() + .compute_layout(layout_id, constraint.max) + .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) -// } + let layout_engine = cx.pop_layout_engine(); + debug_assert!(layout_engine.is_some(), + "unexpected layout stack state. is there an unmatched pop_layout_engine in the called code?" + ); -// fn paint( -// &mut self, -// scene: &mut gpui::SceneBuilder, -// bounds: RectF, -// visible_bounds: RectF, -// layout_engine: &mut Option, -// view: &mut V, -// legacy_cx: &mut gpui::PaintContext, -// ) -> 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()); -// } + (constraint.max, layout_engine.zip(layout_id)) + } -// fn rect_for_text_range( -// &self, -// range_utf16: std::ops::Range, -// bounds: RectF, -// visible_bounds: RectF, -// layout: &Self::LayoutState, -// paint: &Self::PaintState, -// view: &V, -// cx: &gpui::ViewContext, -// ) -> Option { -// todo!("implement before merging to main") -// } + fn paint( + &mut self, + scene: &mut gpui::SceneBuilder, + bounds: RectF, + visible_bounds: RectF, + layout_data: &mut Option<(LayoutEngine, LayoutId)>, + view: &mut V, + legacy_cx: &mut gpui::PaintContext, + ) -> Self::PaintState { + let (layout_engine, layout_id) = layout_data.take().unwrap(); + legacy_cx.push_layout_engine(layout_engine); + let mut cx = PaintContext::new(legacy_cx, scene); + self.0.paint(view, layout_id, &mut cx); + *layout_data = legacy_cx.pop_layout_engine().zip(Some(layout_id)); + debug_assert!(layout_data.is_some()); + } -// fn debug( -// &self, -// bounds: RectF, -// layout: &Self::LayoutState, -// paint: &Self::PaintState, -// view: &V, -// cx: &gpui::ViewContext, -// ) -> gpui::serde_json::Value { -// todo!("implement before merging to main") -// } -// } + fn rect_for_text_range( + &self, + range_utf16: std::ops::Range, + bounds: RectF, + visible_bounds: RectF, + layout: &Self::LayoutState, + paint: &Self::PaintState, + view: &V, + cx: &gpui::ViewContext, + ) -> Option { + todo!("implement before merging to main") + } + + fn debug( + &self, + bounds: RectF, + layout: &Self::LayoutState, + paint: &Self::PaintState, + view: &V, + cx: &gpui::ViewContext, + ) -> gpui::serde_json::Value { + todo!("implement before merging to main") + } +} diff --git a/crates/gpui/playground/src/element.rs b/crates/gpui/playground/src/element.rs index 47e7e46cd8..296baa5280 100644 --- a/crates/gpui/playground/src/element.rs +++ b/crates/gpui/playground/src/element.rs @@ -44,7 +44,7 @@ impl Layout { } } -pub trait Element { +pub trait Element: 'static { type Layout; fn layout( @@ -63,30 +63,33 @@ pub trait Element { ) where Self: Sized; - fn into_any(mut self) -> AnyElement + fn into_any(self) -> AnyElement where - Self: Sized, + Self: 'static + Sized, { - AnyElement(Box::new(ElementWithLayout { + AnyElement(Box::new(ElementState { element: self, layout: None, })) } } -trait ElementTraitObject { +/// Used to make ElementState into a trait object, so we can wrap it in AnyElement. +trait ElementStateObject { fn layout(&mut self, view: &mut V, cx: &mut LayoutContext) -> Result; fn paint(&mut self, view: &mut V, layout_id: LayoutId, cx: &mut PaintContext); } -struct ElementWithLayout> { +/// A wrapper around an element that stores its layout state. +struct ElementState> { element: E, layout: Option>, } -impl> ElementTraitObject for ElementWithLayout { +/// We blanket-implement the object-safe ElementStateObject interface to make ElementStates into trait objects +impl> ElementStateObject for ElementState { fn layout(&mut self, view: &mut V, cx: &mut LayoutContext) -> Result { - let layout = Element::layout(self, view, cx)?; + let layout = self.element.layout(view, cx)?; let layout_id = layout.id; self.layout = Some(layout); Ok(layout_id) @@ -94,23 +97,24 @@ impl> ElementTraitObject for ElementWithLayout { fn paint(&mut self, view: &mut V, layout_id: LayoutId, cx: &mut PaintContext) { let layout = self.layout.as_mut().expect("paint called before layout"); - Element::paint(self, view, layout, cx); + self.element.paint(view, layout, cx) } } -pub struct AnyElement(Box>); +/// A dynamic element. +pub struct AnyElement(Box>); impl AnyElement { - fn layout(&mut self, view: &mut V, cx: &mut LayoutContext) -> Result { + pub fn layout(&mut self, view: &mut V, cx: &mut LayoutContext) -> Result { self.0.layout(view, cx) } - fn paint(&mut self, view: &mut V, layout_id: LayoutId, cx: &mut PaintContext) { + pub fn paint(&mut self, view: &mut V, layout_id: LayoutId, cx: &mut PaintContext) { self.0.paint(view, layout_id, cx) } } -pub trait ParentElement { +pub trait ParentElement { fn children_mut(&mut self) -> &mut Vec>; fn child(mut self, child: impl IntoElement) -> Self @@ -136,7 +140,7 @@ pub trait ParentElement { } } -pub trait IntoElement { +pub trait IntoElement { type Element: Element; fn into_element(self) -> Self::Element; diff --git a/crates/gpui/playground/src/hoverable.rs b/crates/gpui/playground/src/hoverable.rs index 2ed0769b53..5335850870 100644 --- a/crates/gpui/playground/src/hoverable.rs +++ b/crates/gpui/playground/src/hoverable.rs @@ -9,7 +9,7 @@ use gpui::platform::MouseMovedEvent; use refineable::Refineable; use std::{cell::Cell, marker::PhantomData}; -pub struct Hoverable + Styleable> { +pub struct Hoverable + Styleable> { hovered: Cell, child_style: StyleRefinement, hovered_style: StyleRefinement, diff --git a/crates/gpui/playground/src/layout_context.rs b/crates/gpui/playground/src/layout_context.rs index fd642ad3e2..8241cbc9c5 100644 --- a/crates/gpui/playground/src/layout_context.rs +++ b/crates/gpui/playground/src/layout_context.rs @@ -11,7 +11,6 @@ pub struct LayoutContext<'a, 'b, 'c, 'd, V> { #[deref] #[deref_mut] pub(crate) legacy_cx: &'d mut LegacyLayoutContext<'a, 'b, 'c, V>, - pub(crate) scene: &'d mut gpui::SceneBuilder, } impl<'a, 'b, V> RenderContext<'a, 'b, V> for LayoutContext<'a, 'b, '_, '_, V> { @@ -33,11 +32,8 @@ impl<'a, 'b, V> RenderContext<'a, 'b, V> for LayoutContext<'a, 'b, '_, '_, V> { } impl<'a, 'b, 'c, 'd, V: 'static> LayoutContext<'a, 'b, 'c, 'd, V> { - pub fn new( - legacy_cx: &'d mut LegacyLayoutContext<'a, 'b, 'c, V>, - scene: &'d mut gpui::SceneBuilder, - ) -> Self { - Self { legacy_cx, scene } + pub fn new(legacy_cx: &'d mut LegacyLayoutContext<'a, 'b, 'c, V>) -> Self { + Self { legacy_cx } } pub fn add_layout_node( diff --git a/crates/gpui/playground/src/text.rs b/crates/gpui/playground/src/text.rs index 25c99c676a..b15f7f123e 100644 --- a/crates/gpui/playground/src/text.rs +++ b/crates/gpui/playground/src/text.rs @@ -2,12 +2,10 @@ use crate::{ element::{Element, IntoElement, Layout}, layout_context::LayoutContext, paint_context::PaintContext, - style::Style, }; use anyhow::Result; -use gpui::{geometry::Size, text_layout::LineLayout, RenderContext}; +use gpui::text_layout::LineLayout; use parking_lot::Mutex; -use refineable::Refineable; use std::sync::Arc; impl>> IntoElement for S { @@ -30,39 +28,40 @@ impl Element for Text { view: &mut V, cx: &mut LayoutContext, ) -> Result> { - let rem_size = cx.rem_pixels(); - let fonts = cx.platform().fonts(); - let text_style = cx.text_style(); - let line_height = cx.font_cache().line_height(text_style.font_size); - let layout_engine = cx.layout_engine().expect("no layout engine present"); - let text = self.text.clone(); - let layout = Arc::new(Mutex::new(None)); + // let rem_size = cx.rem_pixels(); + // let fonts = cx.platform().fonts(); + // let text_style = cx.text_style(); + // let line_height = cx.font_cache().line_height(text_style.font_size); + // let layout_engine = cx.layout_engine().expect("no layout engine present"); + // let text = self.text.clone(); + // let layout = Arc::new(Mutex::new(None)); - let style: Style = Style::default().refined(&self.metadata.style); - let node_id = layout_engine.add_measured_node(style.to_taffy(rem_size), { - let layout = layout.clone(); - move |params| { - let line_layout = fonts.layout_line( - text.as_ref(), - text_style.font_size, - &[(text.len(), text_style.to_run())], - ); + // let style: Style = Style::default().refined(&self.metadata.style); + // let node_id = layout_engine.add_measured_node(style.to_taffy(rem_size), { + // let layout = layout.clone(); + // move |params| { + // let line_layout = fonts.layout_line( + // text.as_ref(), + // text_style.font_size, + // &[(text.len(), text_style.to_run())], + // ); - let size = Size { - width: line_layout.width, - height: line_height, - }; + // let size = Size { + // width: line_layout.width, + // height: line_height, + // }; - layout.lock().replace(TextLayout { - line_layout: Arc::new(line_layout), - line_height, - }); + // layout.lock().replace(TextLayout { + // line_layout: Arc::new(line_layout), + // line_height, + // }); - size - } - })?; + // size + // } + // })?; - Ok((node_id, layout)) + // Ok((node_id, layout)) + todo!() } fn paint<'a>( @@ -71,24 +70,26 @@ impl Element for Text { layout: &mut Layout, cx: &mut PaintContext, ) { - let element_layout_lock = layout.from_element.lock(); - let element_layout = element_layout_lock - .as_ref() - .expect("layout has not been performed"); - let line_layout = element_layout.line_layout.clone(); - let line_height = element_layout.line_height; - drop(element_layout_lock); + // ) { + // let element_layout_lock = layout.from_element.lock(); + // let element_layout = element_layout_lock + // .as_ref() + // .expect("layout has not been performed"); + // let line_layout = element_layout.line_layout.clone(); + // let line_height = element_layout.line_height; + // drop(element_layout_lock); - let text_style = cx.text_style(); - let line = - gpui::text_layout::Line::new(line_layout, &[(self.text.len(), text_style.to_run())]); - line.paint( - cx.scene, - layout.from_engine.bounds.origin(), - layout.from_engine.bounds, - line_height, - cx.legacy_cx, - ); + // let text_style = cx.text_style(); + // let line = + // gpui::text_layout::Line::new(line_layout, &[(self.text.len(), text_style.to_run())]); + // line.paint( + // cx.scene, + // layout.from_engine.bounds.origin(), + // layout.from_engine.bounds, + // line_height, + // cx.legacy_cx, + // ); + todo!() } } diff --git a/crates/gpui/playground/src/view.rs b/crates/gpui/playground/src/view.rs index 8309814327..cb0eebed7b 100644 --- a/crates/gpui/playground/src/view.rs +++ b/crates/gpui/playground/src/view.rs @@ -1,4 +1,7 @@ -use crate::element::{AnyElement, Element}; +use crate::{ + adapter::AdapterElement, + element::{AnyElement, Element}, +}; use gpui::ViewContext; pub fn view(mut render: F) -> ViewFn @@ -17,6 +20,7 @@ impl gpui::Entity for ViewFn { impl gpui::View for ViewFn { fn render(&mut self, cx: &mut ViewContext) -> gpui::AnyElement { - (self.0)(cx).adapt().into_any() + use gpui::Element as _; + AdapterElement((self.0)(cx)).into_any() } }