Detailed changes
@@ -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<V>(pub(crate) crate::element::AnyElement<V>);
-// pub struct Adapter<V>(pub(crate) AnyElement<V>);
+impl<V: 'static> gpui::Element<V> for AdapterElement<V> {
+ type LayoutState = Option<(LayoutEngine, LayoutId)>;
+ 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 gpui::LayoutContext<V>,
+ ) -> (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<V>,
-// ) -> (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<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());
-// }
+ (constraint.max, layout_engine.zip(layout_id))
+ }
-// 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 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<V>,
+ ) -> 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<V>,
-// ) -> gpui::serde_json::Value {
-// 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")
+ }
+}
@@ -44,7 +44,7 @@ impl<V: 'static, D> Layout<V, D> {
}
}
-pub trait Element<V> {
+pub trait Element<V: 'static>: 'static {
type Layout;
fn layout(
@@ -63,30 +63,33 @@ pub trait Element<V> {
) where
Self: Sized;
- fn into_any(mut self) -> AnyElement<V>
+ fn into_any(self) -> AnyElement<V>
where
- Self: Sized,
+ Self: 'static + Sized,
{
- AnyElement(Box::new(ElementWithLayout {
+ AnyElement(Box::new(ElementState {
element: self,
layout: None,
}))
}
}
-trait ElementTraitObject<V> {
+/// Used to make ElementState<V, E> into a trait object, so we can wrap it in AnyElement<V>.
+trait ElementStateObject<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>);
}
-struct ElementWithLayout<V, E: Element<V>> {
+/// A wrapper around an element that stores its layout state.
+struct ElementState<V: 'static, E: Element<V>> {
element: E,
layout: Option<Layout<V, E::Layout>>,
}
-impl<V, E: Element<V>> ElementTraitObject<V> for ElementWithLayout<V, E> {
+/// We blanket-implement the object-safe ElementStateObject interface to make ElementStates into trait objects
+impl<V, E: Element<V>> ElementStateObject<V> for ElementState<V, E> {
fn layout(&mut self, view: &mut V, cx: &mut LayoutContext<V>) -> Result<LayoutId> {
- 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<V, E: Element<V>> ElementTraitObject<V> for ElementWithLayout<V, E> {
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);
+ self.element.paint(view, layout, cx)
}
}
-pub struct AnyElement<V>(Box<dyn ElementTraitObject<V>>);
+/// A dynamic element.
+pub struct AnyElement<V>(Box<dyn ElementStateObject<V>>);
impl<V> AnyElement<V> {
- fn layout(&mut self, view: &mut V, cx: &mut LayoutContext<V>) -> Result<LayoutId> {
+ pub fn layout(&mut self, view: &mut V, cx: &mut LayoutContext<V>) -> Result<LayoutId> {
self.0.layout(view, cx)
}
- fn paint(&mut self, view: &mut V, layout_id: LayoutId, cx: &mut PaintContext<V>) {
+ pub fn paint(&mut self, view: &mut V, layout_id: LayoutId, cx: &mut PaintContext<V>) {
self.0.paint(view, layout_id, cx)
}
}
-pub trait ParentElement<V> {
+pub trait ParentElement<V: 'static> {
fn children_mut(&mut self) -> &mut Vec<AnyElement<V>>;
fn child(mut self, child: impl IntoElement<V>) -> Self
@@ -136,7 +140,7 @@ pub trait ParentElement<V> {
}
}
-pub trait IntoElement<V> {
+pub trait IntoElement<V: 'static> {
type Element: Element<V>;
fn into_element(self) -> Self::Element;
@@ -9,7 +9,7 @@ use gpui::platform::MouseMovedEvent;
use refineable::Refineable;
use std::{cell::Cell, marker::PhantomData};
-pub struct Hoverable<V, E: Element<V> + Styleable> {
+pub struct Hoverable<V: 'static, E: Element<V> + Styleable> {
hovered: Cell<bool>,
child_style: StyleRefinement,
hovered_style: StyleRefinement,
@@ -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<D>(
@@ -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<V: 'static, S: Into<ArcCow<'static, str>>> IntoElement<V> for S {
@@ -30,39 +28,40 @@ impl<V: 'static> Element<V> for Text {
view: &mut V,
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();
- 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 size = Size {
- width: line_layout.width,
- height: line_height,
- };
-
- layout.lock().replace(TextLayout {
- line_layout: Arc::new(line_layout),
- line_height,
- });
-
- size
- }
- })?;
-
- Ok((node_id, layout))
+ // 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 size = Size {
+ // width: line_layout.width,
+ // height: line_height,
+ // };
+
+ // layout.lock().replace(TextLayout {
+ // line_layout: Arc::new(line_layout),
+ // line_height,
+ // });
+
+ // size
+ // }
+ // })?;
+
+ // Ok((node_id, layout))
+ todo!()
}
fn paint<'a>(
@@ -71,24 +70,26 @@ impl<V: 'static> Element<V> for Text {
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()
- .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 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,
+ // );
+ todo!()
}
}
@@ -1,4 +1,7 @@
-use crate::element::{AnyElement, Element};
+use crate::{
+ adapter::AdapterElement,
+ element::{AnyElement, Element},
+};
use gpui::ViewContext;
pub fn view<F, E>(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<Self>) -> gpui::AnyElement<Self> {
- (self.0)(cx).adapt().into_any()
+ use gpui::Element as _;
+ AdapterElement((self.0)(cx)).into_any()
}
}