Checkpoint

This commit is contained in:
Nathan Sobo 2023-08-21 16:14:59 -06:00
parent f4d8763d2b
commit ff7b25c538
6 changed files with 146 additions and 133 deletions

View file

@ -1,70 +1,78 @@
// use crate::element::{LayoutContext, PaintContext}; use crate::{layout_context::LayoutContext, paint_context::PaintContext};
// use gpui::{geometry::rect::RectF, LayoutEngine}; use gpui::{geometry::rect::RectF, LayoutEngine, LayoutId};
// use util::ResultExt; 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> { fn layout(
// type LayoutState = Option<LayoutEngine>; &mut self,
// type PaintState = (); 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( let size = constraint.max;
// &mut self, let mut cx = LayoutContext::new(cx);
// constraint: gpui::SizeConstraint, let layout_id = self.0.layout(view, &mut cx).log_err();
// view: &mut V, if let Some(layout_id) = layout_id {
// cx: &mut LayoutContext<V>, cx.layout_engine()
// ) -> (gpui::geometry::vector::Vector2F, Self::LayoutState) { .unwrap()
// cx.push_layout_engine(LayoutEngine::new()); .compute_layout(layout_id, constraint.max)
// let node = self.0.layout(view, cx).log_err(); .log_err();
}
// if let Some(node) = node { let layout_engine = cx.pop_layout_engine();
// let layout_engine = cx.layout_engine().unwrap(); debug_assert!(layout_engine.is_some(),
// layout_engine.compute_layout(node, constraint.max).log_err(); "unexpected layout stack state. is there an unmatched pop_layout_engine in the called code?"
// } );
// let layout_engine = cx.pop_layout_engine();
// debug_assert!(layout_engine.is_some());
// (constraint.max, layout_engine)
// }
// fn paint( (constraint.max, layout_engine.zip(layout_id))
// &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());
// }
// fn rect_for_text_range( fn paint(
// &self, &mut self,
// range_utf16: std::ops::Range<usize>, scene: &mut gpui::SceneBuilder,
// bounds: RectF, bounds: RectF,
// visible_bounds: RectF, visible_bounds: RectF,
// layout: &Self::LayoutState, layout_data: &mut Option<(LayoutEngine, LayoutId)>,
// paint: &Self::PaintState, view: &mut V,
// view: &V, legacy_cx: &mut gpui::PaintContext<V>,
// cx: &gpui::ViewContext<V>, ) -> Self::PaintState {
// ) -> Option<RectF> { let (layout_engine, layout_id) = layout_data.take().unwrap();
// todo!("implement before merging to main") 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( fn rect_for_text_range(
// &self, &self,
// bounds: RectF, range_utf16: std::ops::Range<usize>,
// layout: &Self::LayoutState, bounds: RectF,
// paint: &Self::PaintState, visible_bounds: RectF,
// view: &V, layout: &Self::LayoutState,
// cx: &gpui::ViewContext<V>, paint: &Self::PaintState,
// ) -> gpui::serde_json::Value { view: &V,
// todo!("implement before merging to main") 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")
}
}

View file

@ -44,7 +44,7 @@ impl<V: 'static, D> Layout<V, D> {
} }
} }
pub trait Element<V> { pub trait Element<V: 'static>: 'static {
type Layout; type Layout;
fn layout( fn layout(
@ -63,30 +63,33 @@ pub trait Element<V> {
) where ) where
Self: Sized; Self: Sized;
fn into_any(mut self) -> AnyElement<V> fn into_any(self) -> AnyElement<V>
where where
Self: Sized, Self: 'static + Sized,
{ {
AnyElement(Box::new(ElementWithLayout { AnyElement(Box::new(ElementState {
element: self, element: self,
layout: None, 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 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>); 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, element: E,
layout: Option<Layout<V, E::Layout>>, 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> { 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; let layout_id = layout.id;
self.layout = Some(layout); self.layout = Some(layout);
Ok(layout_id) 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>) { 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"); 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> { 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) 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) 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 children_mut(&mut self) -> &mut Vec<AnyElement<V>>;
fn child(mut self, child: impl IntoElement<V>) -> Self 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>; type Element: Element<V>;
fn into_element(self) -> Self::Element; fn into_element(self) -> Self::Element;

View file

@ -9,7 +9,7 @@ use gpui::platform::MouseMovedEvent;
use refineable::Refineable; use refineable::Refineable;
use std::{cell::Cell, marker::PhantomData}; 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>, hovered: Cell<bool>,
child_style: StyleRefinement, child_style: StyleRefinement,
hovered_style: StyleRefinement, hovered_style: StyleRefinement,

View file

@ -11,7 +11,6 @@ pub struct LayoutContext<'a, 'b, 'c, 'd, V> {
#[deref] #[deref]
#[deref_mut] #[deref_mut]
pub(crate) legacy_cx: &'d mut LegacyLayoutContext<'a, 'b, 'c, V>, 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> { 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> { impl<'a, 'b, 'c, 'd, V: 'static> LayoutContext<'a, 'b, 'c, 'd, V> {
pub fn new( pub fn new(legacy_cx: &'d mut LegacyLayoutContext<'a, 'b, 'c, V>) -> Self {
legacy_cx: &'d mut LegacyLayoutContext<'a, 'b, 'c, V>, Self { legacy_cx }
scene: &'d mut gpui::SceneBuilder,
) -> Self {
Self { legacy_cx, scene }
} }
pub fn add_layout_node<D>( pub fn add_layout_node<D>(

View file

@ -2,12 +2,10 @@ use crate::{
element::{Element, IntoElement, Layout}, element::{Element, IntoElement, Layout},
layout_context::LayoutContext, layout_context::LayoutContext,
paint_context::PaintContext, paint_context::PaintContext,
style::Style,
}; };
use anyhow::Result; use anyhow::Result;
use gpui::{geometry::Size, text_layout::LineLayout, RenderContext}; use gpui::text_layout::LineLayout;
use parking_lot::Mutex; use parking_lot::Mutex;
use refineable::Refineable;
use std::sync::Arc; use std::sync::Arc;
impl<V: 'static, S: Into<ArcCow<'static, str>>> IntoElement<V> for S { 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, view: &mut V,
cx: &mut LayoutContext<V>, cx: &mut LayoutContext<V>,
) -> Result<Layout<V, Self::Layout>> { ) -> Result<Layout<V, Self::Layout>> {
let rem_size = cx.rem_pixels(); // let rem_size = cx.rem_pixels();
let fonts = cx.platform().fonts(); // let fonts = cx.platform().fonts();
let text_style = cx.text_style(); // let text_style = cx.text_style();
let line_height = cx.font_cache().line_height(text_style.font_size); // let line_height = cx.font_cache().line_height(text_style.font_size);
let layout_engine = cx.layout_engine().expect("no layout engine present"); // let layout_engine = cx.layout_engine().expect("no layout engine present");
let text = self.text.clone(); // let text = self.text.clone();
let layout = Arc::new(Mutex::new(None)); // let layout = Arc::new(Mutex::new(None));
let style: Style = Style::default().refined(&self.metadata.style); // let style: Style = Style::default().refined(&self.metadata.style);
let node_id = layout_engine.add_measured_node(style.to_taffy(rem_size), { // let node_id = layout_engine.add_measured_node(style.to_taffy(rem_size), {
let layout = layout.clone(); // let layout = layout.clone();
move |params| { // move |params| {
let line_layout = fonts.layout_line( // let line_layout = fonts.layout_line(
text.as_ref(), // text.as_ref(),
text_style.font_size, // text_style.font_size,
&[(text.len(), text_style.to_run())], // &[(text.len(), text_style.to_run())],
); // );
let size = Size { // let size = Size {
width: line_layout.width, // width: line_layout.width,
height: line_height, // height: line_height,
}; // };
layout.lock().replace(TextLayout { // layout.lock().replace(TextLayout {
line_layout: Arc::new(line_layout), // line_layout: Arc::new(line_layout),
line_height, // line_height,
}); // });
size // size
} // }
})?; // })?;
Ok((node_id, layout)) // Ok((node_id, layout))
todo!()
} }
fn paint<'a>( fn paint<'a>(
@ -71,24 +70,26 @@ impl<V: 'static> Element<V> for Text {
layout: &mut Layout<V, Self::Layout>, layout: &mut Layout<V, Self::Layout>,
cx: &mut PaintContext<V>, cx: &mut PaintContext<V>,
) { ) {
let element_layout_lock = layout.from_element.lock(); // ) {
let element_layout = element_layout_lock // let element_layout_lock = layout.from_element.lock();
.as_ref() // let element_layout = element_layout_lock
.expect("layout has not been performed"); // .as_ref()
let line_layout = element_layout.line_layout.clone(); // .expect("layout has not been performed");
let line_height = element_layout.line_height; // let line_layout = element_layout.line_layout.clone();
drop(element_layout_lock); // let line_height = element_layout.line_height;
// drop(element_layout_lock);
let text_style = cx.text_style(); // let text_style = cx.text_style();
let line = // let line =
gpui::text_layout::Line::new(line_layout, &[(self.text.len(), text_style.to_run())]); // gpui::text_layout::Line::new(line_layout, &[(self.text.len(), text_style.to_run())]);
line.paint( // line.paint(
cx.scene, // cx.scene,
layout.from_engine.bounds.origin(), // layout.from_engine.bounds.origin(),
layout.from_engine.bounds, // layout.from_engine.bounds,
line_height, // line_height,
cx.legacy_cx, // cx.legacy_cx,
); // );
todo!()
} }
} }

View file

@ -1,4 +1,7 @@
use crate::element::{AnyElement, Element}; use crate::{
adapter::AdapterElement,
element::{AnyElement, Element},
};
use gpui::ViewContext; use gpui::ViewContext;
pub fn view<F, E>(mut render: F) -> ViewFn pub fn view<F, E>(mut render: F) -> ViewFn
@ -17,6 +20,7 @@ impl gpui::Entity for ViewFn {
impl gpui::View for ViewFn { impl gpui::View for ViewFn {
fn render(&mut self, cx: &mut ViewContext<Self>) -> gpui::AnyElement<Self> { 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()
} }
} }