Checkpoint
This commit is contained in:
parent
8ad736da8d
commit
3bebfbcd50
10 changed files with 161 additions and 156 deletions
|
@ -25,9 +25,13 @@ pub fn div<V>() -> Div<V> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<V: 'static> Element<V> for Div<V> {
|
impl<V: 'static> Element<V> for Div<V> {
|
||||||
type Layout = ();
|
type PaintState = ();
|
||||||
|
|
||||||
fn layout(&mut self, view: &mut V, cx: &mut LayoutContext<V>) -> Result<Layout<V, ()>>
|
fn layout(
|
||||||
|
&mut self,
|
||||||
|
view: &mut V,
|
||||||
|
cx: &mut LayoutContext<V>,
|
||||||
|
) -> Result<(LayoutId, Self::PaintState)>
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
|
@ -47,14 +51,16 @@ impl<V: 'static> Element<V> for Div<V> {
|
||||||
cx.pop_text_style();
|
cx.pop_text_style();
|
||||||
}
|
}
|
||||||
|
|
||||||
let layout = cx.add_layout_node(style, (), children.clone())?;
|
Ok((cx.add_layout_node(style, children)?, ()))
|
||||||
|
|
||||||
dbg!(layout.id(), children);
|
|
||||||
Ok(layout)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn paint(&mut self, view: &mut V, layout: &mut Layout<V, ()>, cx: &mut PaintContext<V>)
|
fn paint(
|
||||||
where
|
&mut self,
|
||||||
|
view: &mut V,
|
||||||
|
layout: &Layout,
|
||||||
|
paint_state: &mut Self::PaintState,
|
||||||
|
cx: &mut PaintContext<V>,
|
||||||
|
) where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
let style = &self.computed_style();
|
let style = &self.computed_style();
|
||||||
|
@ -62,9 +68,9 @@ impl<V: 'static> Element<V> for Div<V> {
|
||||||
cx.push_text_style(cx.text_style().clone().refined(&style));
|
cx.push_text_style(cx.text_style().clone().refined(&style));
|
||||||
true
|
true
|
||||||
});
|
});
|
||||||
style.paint_background(layout.bounds(cx), cx);
|
style.paint_background(layout.bounds, cx);
|
||||||
self.interaction_handlers()
|
self.interaction_handlers()
|
||||||
.paint(layout.order(cx), layout.bounds(cx), cx);
|
.paint(layout.order, layout.bounds, cx);
|
||||||
for child in &mut self.children {
|
for child in &mut self.children {
|
||||||
child.paint(view, cx);
|
child.paint(view, cx);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,29 +1,25 @@
|
||||||
use anyhow::Result;
|
|
||||||
use gpui::{geometry::rect::RectF, EngineLayout};
|
|
||||||
use smallvec::SmallVec;
|
|
||||||
use std::marker::PhantomData;
|
|
||||||
use util::ResultExt;
|
|
||||||
|
|
||||||
pub use crate::layout_context::LayoutContext;
|
pub use crate::layout_context::LayoutContext;
|
||||||
pub use crate::paint_context::PaintContext;
|
pub use crate::paint_context::PaintContext;
|
||||||
|
use anyhow::Result;
|
||||||
type LayoutId = gpui::LayoutId;
|
pub use gpui::{Layout, LayoutId};
|
||||||
|
use smallvec::SmallVec;
|
||||||
|
|
||||||
pub trait Element<V: 'static>: 'static {
|
pub trait Element<V: 'static>: 'static {
|
||||||
type Layout;
|
type PaintState;
|
||||||
|
|
||||||
fn layout(
|
fn layout(
|
||||||
&mut self,
|
&mut self,
|
||||||
view: &mut V,
|
view: &mut V,
|
||||||
cx: &mut LayoutContext<V>,
|
cx: &mut LayoutContext<V>,
|
||||||
) -> Result<Layout<V, Self::Layout>>
|
) -> Result<(LayoutId, Self::PaintState)>
|
||||||
where
|
where
|
||||||
Self: Sized;
|
Self: Sized;
|
||||||
|
|
||||||
fn paint(
|
fn paint(
|
||||||
&mut self,
|
&mut self,
|
||||||
view: &mut V,
|
view: &mut V,
|
||||||
layout: &mut Layout<V, Self::Layout>,
|
layout: &Layout,
|
||||||
|
state: &mut Self::PaintState,
|
||||||
cx: &mut PaintContext<V>,
|
cx: &mut PaintContext<V>,
|
||||||
) where
|
) where
|
||||||
Self: Sized;
|
Self: Sized;
|
||||||
|
@ -34,7 +30,7 @@ pub trait Element<V: 'static>: 'static {
|
||||||
{
|
{
|
||||||
AnyElement(Box::new(StatefulElement {
|
AnyElement(Box::new(StatefulElement {
|
||||||
element: self,
|
element: self,
|
||||||
layout: None,
|
phase: ElementPhase::Init,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -48,24 +44,71 @@ trait AnyStatefulElement<V> {
|
||||||
/// A wrapper around an element that stores its layout state.
|
/// A wrapper around an element that stores its layout state.
|
||||||
struct StatefulElement<V: 'static, E: Element<V>> {
|
struct StatefulElement<V: 'static, E: Element<V>> {
|
||||||
element: E,
|
element: E,
|
||||||
layout: Option<Layout<V, E::Layout>>,
|
phase: ElementPhase<V, E>,
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ElementPhase<V: 'static, E: Element<V>> {
|
||||||
|
Init,
|
||||||
|
PostLayout {
|
||||||
|
layout_id: LayoutId,
|
||||||
|
paint_state: E::PaintState,
|
||||||
|
},
|
||||||
|
PostPaint {
|
||||||
|
layout: Layout,
|
||||||
|
paint_state: E::PaintState,
|
||||||
|
},
|
||||||
|
Error(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<V: 'static, E: Element<V>> Default for ElementPhase<V, E> {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::Init
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// We blanket-implement the object-safe ElementStateObject interface to make ElementStates into trait objects
|
/// We blanket-implement the object-safe ElementStateObject interface to make ElementStates into trait objects
|
||||||
impl<V, E: Element<V>> AnyStatefulElement<V> for StatefulElement<V, E> {
|
impl<V, E: Element<V>> AnyStatefulElement<V> for StatefulElement<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 = self.element.layout(view, cx)?;
|
let result;
|
||||||
let layout_id = layout.id;
|
self.phase = match std::mem::take(&mut self.phase) {
|
||||||
self.layout = Some(layout);
|
ElementPhase::Init => match self.element.layout(view, cx) {
|
||||||
Ok(layout_id)
|
Ok((layout_id, paint_state)) => {
|
||||||
|
result = Ok(layout_id);
|
||||||
|
ElementPhase::PostLayout {
|
||||||
|
layout_id,
|
||||||
|
paint_state,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(error) => {
|
||||||
|
let message = error.to_string();
|
||||||
|
result = Err(error);
|
||||||
|
ElementPhase::Error(message)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => panic!("invalid element phase to call layout"),
|
||||||
|
};
|
||||||
|
|
||||||
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
fn paint(&mut self, view: &mut V, cx: &mut PaintContext<V>) {
|
fn paint(&mut self, view: &mut V, cx: &mut PaintContext<V>) {
|
||||||
let layout = self.layout.as_mut().expect("paint called before layout");
|
self.phase = match std::mem::take(&mut self.phase) {
|
||||||
if layout.engine_layout.is_none() {
|
ElementPhase::PostLayout {
|
||||||
layout.engine_layout = dbg!(cx.computed_layout(dbg!(layout.id)).log_err())
|
layout_id,
|
||||||
}
|
mut paint_state,
|
||||||
self.element.paint(view, layout, cx)
|
} => match cx.computed_layout(layout_id) {
|
||||||
|
Ok(layout) => {
|
||||||
|
self.element.paint(view, &layout, &mut paint_state, cx);
|
||||||
|
ElementPhase::PostPaint {
|
||||||
|
layout,
|
||||||
|
paint_state,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(error) => ElementPhase::Error(error.to_string()),
|
||||||
|
},
|
||||||
|
phase @ ElementPhase::Error(_) => phase,
|
||||||
|
_ => panic!("invalid element phase to call paint"),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,55 +125,6 @@ impl<V> AnyElement<V> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Layout<V, D> {
|
|
||||||
id: LayoutId,
|
|
||||||
engine_layout: Option<EngineLayout>,
|
|
||||||
element_data: Option<D>,
|
|
||||||
view_type: PhantomData<V>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<V: 'static, D> Layout<V, D> {
|
|
||||||
pub fn new(id: LayoutId, element_data: D) -> Self {
|
|
||||||
Self {
|
|
||||||
id,
|
|
||||||
engine_layout: None,
|
|
||||||
element_data: Some(element_data),
|
|
||||||
view_type: PhantomData,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn id(&self) -> LayoutId {
|
|
||||||
self.id
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn bounds(&mut self, cx: &mut PaintContext<V>) -> RectF {
|
|
||||||
self.engine_layout(cx).bounds
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn order(&mut self, cx: &mut PaintContext<V>) -> u32 {
|
|
||||||
self.engine_layout(cx).order
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn update<F, T>(&mut self, update: F) -> T
|
|
||||||
where
|
|
||||||
F: FnOnce(&mut Self, &mut D) -> T,
|
|
||||||
{
|
|
||||||
self.element_data
|
|
||||||
.take()
|
|
||||||
.map(|mut element_data| {
|
|
||||||
let result = update(self, &mut element_data);
|
|
||||||
self.element_data = Some(element_data);
|
|
||||||
result
|
|
||||||
})
|
|
||||||
.expect("reentrant calls to Layout::update are not supported")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn engine_layout(&mut self, cx: &mut PaintContext<'_, '_, '_, '_, V>) -> &mut EngineLayout {
|
|
||||||
self.engine_layout
|
|
||||||
.get_or_insert_with(|| cx.computed_layout(self.id).log_err().unwrap_or_default())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait ParentElement<V: 'static> {
|
pub trait ParentElement<V: 'static> {
|
||||||
fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<V>; 2]>;
|
fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<V>; 2]>;
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ use crate::{
|
||||||
style::{Style, StyleHelpers, Styleable},
|
style::{Style, StyleHelpers, Styleable},
|
||||||
};
|
};
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use gpui::platform::MouseMovedEvent;
|
use gpui::{platform::MouseMovedEvent, LayoutId};
|
||||||
use refineable::{CascadeSlot, Refineable, RefinementCascade};
|
use refineable::{CascadeSlot, Refineable, RefinementCascade};
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
use std::{cell::Cell, rc::Rc};
|
use std::{cell::Cell, rc::Rc};
|
||||||
|
@ -40,40 +40,44 @@ impl<E: Styleable> Styleable for Hoverable<E> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<V: 'static, E: Element<V> + Styleable> Element<V> for Hoverable<E> {
|
impl<V: 'static, E: Element<V> + Styleable> Element<V> for Hoverable<E> {
|
||||||
type Layout = E::Layout;
|
type PaintState = E::PaintState;
|
||||||
|
|
||||||
fn layout(&mut self, view: &mut V, cx: &mut LayoutContext<V>) -> Result<Layout<V, Self::Layout>>
|
fn layout(
|
||||||
|
&mut self,
|
||||||
|
view: &mut V,
|
||||||
|
cx: &mut LayoutContext<V>,
|
||||||
|
) -> Result<(LayoutId, Self::PaintState)>
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
self.child.layout(view, cx)
|
Ok(self.child.layout(view, cx)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn paint(
|
fn paint(
|
||||||
&mut self,
|
&mut self,
|
||||||
view: &mut V,
|
view: &mut V,
|
||||||
layout: &mut Layout<V, Self::Layout>,
|
layout: &Layout,
|
||||||
|
paint_state: &mut Self::PaintState,
|
||||||
cx: &mut PaintContext<V>,
|
cx: &mut PaintContext<V>,
|
||||||
) where
|
) where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
let bounds = layout.bounds(cx);
|
self.hovered
|
||||||
let order = layout.order(cx);
|
.set(layout.bounds.contains_point(cx.mouse_position()));
|
||||||
|
|
||||||
self.hovered.set(bounds.contains_point(cx.mouse_position()));
|
|
||||||
|
|
||||||
let slot = self.cascade_slot;
|
let slot = self.cascade_slot;
|
||||||
let style = self.hovered.get().then_some(self.hovered_style.clone());
|
let style = self.hovered.get().then_some(self.hovered_style.clone());
|
||||||
self.style_cascade().set(slot, style);
|
self.style_cascade().set(slot, style);
|
||||||
|
|
||||||
let hovered = self.hovered.clone();
|
let hovered = self.hovered.clone();
|
||||||
cx.on_event(order, move |view, event: &MouseMovedEvent, cx| {
|
let bounds = layout.bounds;
|
||||||
|
cx.on_event(layout.order, move |view, event: &MouseMovedEvent, cx| {
|
||||||
if bounds.contains_point(cx.mouse_position()) != hovered.get() {
|
if bounds.contains_point(cx.mouse_position()) != hovered.get() {
|
||||||
cx.repaint();
|
cx.repaint();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
self.child.paint(view, layout, cx);
|
self.child.paint(view, layout, paint_state, cx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
|
use crate::{element::LayoutId, style::Style};
|
||||||
use anyhow::{anyhow, Result};
|
use anyhow::{anyhow, Result};
|
||||||
use derive_more::{Deref, DerefMut};
|
use derive_more::{Deref, DerefMut};
|
||||||
use gpui::{geometry::Size, MeasureParams, RenderContext, ViewContext};
|
use gpui::{geometry::Size, MeasureParams, RenderContext, ViewContext};
|
||||||
pub use gpui::{taffy::tree::NodeId, LayoutContext as LegacyLayoutContext};
|
pub use gpui::{taffy::tree::NodeId, LayoutContext as LegacyLayoutContext};
|
||||||
|
|
||||||
use crate::{element::Layout, style::Style};
|
|
||||||
|
|
||||||
#[derive(Deref, DerefMut)]
|
#[derive(Deref, DerefMut)]
|
||||||
pub struct LayoutContext<'a, 'b, 'c, 'd, V> {
|
pub struct LayoutContext<'a, 'b, 'c, 'd, V> {
|
||||||
#[deref]
|
#[deref]
|
||||||
|
@ -35,12 +34,11 @@ impl<'a, 'b, 'c, 'd, V: 'static> LayoutContext<'a, 'b, 'c, 'd, V> {
|
||||||
Self { legacy_cx }
|
Self { legacy_cx }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_layout_node<D>(
|
pub fn add_layout_node(
|
||||||
&mut self,
|
&mut self,
|
||||||
style: Style,
|
style: Style,
|
||||||
element_data: D,
|
|
||||||
children: impl IntoIterator<Item = NodeId>,
|
children: impl IntoIterator<Item = NodeId>,
|
||||||
) -> Result<Layout<V, D>> {
|
) -> Result<LayoutId> {
|
||||||
let rem_size = self.rem_pixels();
|
let rem_size = self.rem_pixels();
|
||||||
let id = self
|
let id = self
|
||||||
.legacy_cx
|
.legacy_cx
|
||||||
|
@ -48,15 +46,10 @@ impl<'a, 'b, 'c, 'd, V: 'static> LayoutContext<'a, 'b, 'c, 'd, V> {
|
||||||
.ok_or_else(|| anyhow!("no layout engine"))?
|
.ok_or_else(|| anyhow!("no layout engine"))?
|
||||||
.add_node(style.to_taffy(rem_size), children)?;
|
.add_node(style.to_taffy(rem_size), children)?;
|
||||||
|
|
||||||
Ok(Layout::new(id, element_data))
|
Ok(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_measured_layout_node<D, F>(
|
pub fn add_measured_layout_node<F>(&mut self, style: Style, measure: F) -> Result<LayoutId>
|
||||||
&mut self,
|
|
||||||
style: Style,
|
|
||||||
element_data: D,
|
|
||||||
measure: F,
|
|
||||||
) -> Result<Layout<V, D>>
|
|
||||||
where
|
where
|
||||||
F: Fn(MeasureParams) -> Size<f32> + Sync + Send + 'static,
|
F: Fn(MeasureParams) -> Size<f32> + Sync + Send + 'static,
|
||||||
{
|
{
|
||||||
|
@ -66,6 +59,6 @@ impl<'a, 'b, 'c, 'd, V: 'static> LayoutContext<'a, 'b, 'c, 'd, V> {
|
||||||
.ok_or_else(|| anyhow!("no layout engine"))?
|
.ok_or_else(|| anyhow!("no layout engine"))?
|
||||||
.add_measured_node(style.to_taffy(rem_size), measure)?;
|
.add_measured_node(style.to_taffy(rem_size), measure)?;
|
||||||
|
|
||||||
Ok(Layout::new(layout_id, element_data))
|
Ok(layout_id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ use anyhow::{anyhow, Result};
|
||||||
use derive_more::{Deref, DerefMut};
|
use derive_more::{Deref, DerefMut};
|
||||||
pub use gpui::taffy::tree::NodeId;
|
pub use gpui::taffy::tree::NodeId;
|
||||||
use gpui::{
|
use gpui::{
|
||||||
scene::EventHandler, EngineLayout, EventContext, LayoutId, PaintContext as LegacyPaintContext,
|
scene::EventHandler, EventContext, Layout, LayoutId, PaintContext as LegacyPaintContext,
|
||||||
RenderContext, ViewContext,
|
RenderContext, ViewContext,
|
||||||
};
|
};
|
||||||
use std::{any::TypeId, rc::Rc};
|
use std::{any::TypeId, rc::Rc};
|
||||||
|
@ -65,7 +65,7 @@ impl<'a, 'b, 'c, 'd, V: 'static> PaintContext<'a, 'b, 'c, 'd, V> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn computed_layout(&mut self, layout_id: LayoutId) -> Result<EngineLayout> {
|
pub(crate) fn computed_layout(&mut self, layout_id: LayoutId) -> Result<Layout> {
|
||||||
self.layout_engine()
|
self.layout_engine()
|
||||||
.ok_or_else(|| anyhow!("no layout engine present"))?
|
.ok_or_else(|| anyhow!("no layout engine present"))?
|
||||||
.computed_layout(layout_id)
|
.computed_layout(layout_id)
|
||||||
|
|
|
@ -6,7 +6,7 @@ use crate::{
|
||||||
style::{Style, StyleHelpers, Styleable},
|
style::{Style, StyleHelpers, Styleable},
|
||||||
};
|
};
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use gpui::platform::MouseButtonEvent;
|
use gpui::{platform::MouseButtonEvent, LayoutId};
|
||||||
use refineable::{CascadeSlot, Refineable, RefinementCascade};
|
use refineable::{CascadeSlot, Refineable, RefinementCascade};
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
use std::{cell::Cell, rc::Rc};
|
use std::{cell::Cell, rc::Rc};
|
||||||
|
@ -40,9 +40,13 @@ impl<E: Styleable> Styleable for Pressable<E> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<V: 'static, E: Element<V> + Styleable> Element<V> for Pressable<E> {
|
impl<V: 'static, E: Element<V> + Styleable> Element<V> for Pressable<E> {
|
||||||
type Layout = E::Layout;
|
type PaintState = E::PaintState;
|
||||||
|
|
||||||
fn layout(&mut self, view: &mut V, cx: &mut LayoutContext<V>) -> Result<Layout<V, Self::Layout>>
|
fn layout(
|
||||||
|
&mut self,
|
||||||
|
view: &mut V,
|
||||||
|
cx: &mut LayoutContext<V>,
|
||||||
|
) -> Result<(LayoutId, Self::PaintState)>
|
||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
|
@ -52,7 +56,8 @@ impl<V: 'static, E: Element<V> + Styleable> Element<V> for Pressable<E> {
|
||||||
fn paint(
|
fn paint(
|
||||||
&mut self,
|
&mut self,
|
||||||
view: &mut V,
|
view: &mut V,
|
||||||
layout: &mut Layout<V, Self::Layout>,
|
layout: &Layout,
|
||||||
|
paint_state: &mut Self::PaintState,
|
||||||
cx: &mut PaintContext<V>,
|
cx: &mut PaintContext<V>,
|
||||||
) where
|
) where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
|
@ -61,10 +66,9 @@ impl<V: 'static, E: Element<V> + Styleable> Element<V> for Pressable<E> {
|
||||||
let style = self.pressed.get().then_some(self.pressed_style.clone());
|
let style = self.pressed.get().then_some(self.pressed_style.clone());
|
||||||
self.style_cascade().set(slot, style);
|
self.style_cascade().set(slot, style);
|
||||||
|
|
||||||
let bounds = layout.bounds(cx);
|
|
||||||
let order = layout.order(cx);
|
|
||||||
let pressed = self.pressed.clone();
|
let pressed = self.pressed.clone();
|
||||||
cx.on_event(order, move |view, event: &MouseButtonEvent, cx| {
|
let bounds = layout.bounds;
|
||||||
|
cx.on_event(layout.order, move |view, event: &MouseButtonEvent, cx| {
|
||||||
if event.is_down {
|
if event.is_down {
|
||||||
if bounds.contains_point(event.position) {
|
if bounds.contains_point(event.position) {
|
||||||
pressed.set(true);
|
pressed.set(true);
|
||||||
|
@ -76,7 +80,7 @@ impl<V: 'static, E: Element<V> + Styleable> Element<V> for Pressable<E> {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
self.child.paint(view, layout, cx);
|
self.child.paint(view, layout, paint_state, cx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ use crate::{
|
||||||
paint_context::PaintContext,
|
paint_context::PaintContext,
|
||||||
};
|
};
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use gpui::{geometry::Size, text_layout::LineLayout, RenderContext};
|
use gpui::{geometry::Size, text_layout::LineLayout, LayoutId, RenderContext};
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
@ -21,67 +21,71 @@ pub struct Text {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<V: 'static> Element<V> for Text {
|
impl<V: 'static> Element<V> for Text {
|
||||||
type Layout = Arc<Mutex<Option<TextLayout>>>;
|
type PaintState = Arc<Mutex<Option<TextLayout>>>;
|
||||||
|
|
||||||
fn layout(
|
fn layout(
|
||||||
&mut self,
|
&mut self,
|
||||||
view: &mut V,
|
view: &mut V,
|
||||||
cx: &mut LayoutContext<V>,
|
cx: &mut LayoutContext<V>,
|
||||||
) -> Result<Layout<V, Self::Layout>> {
|
) -> Result<(LayoutId, Self::PaintState)> {
|
||||||
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 text = self.text.clone();
|
let text = self.text.clone();
|
||||||
let layout = Arc::new(Mutex::new(None));
|
let paint_state = Arc::new(Mutex::new(None));
|
||||||
|
|
||||||
cx.add_measured_layout_node(Default::default(), layout.clone(), move |params| {
|
let layout_id = cx.add_measured_layout_node(Default::default(), {
|
||||||
let line_layout = fonts.layout_line(
|
let paint_state = paint_state.clone();
|
||||||
text.as_ref(),
|
move |params| {
|
||||||
text_style.font_size,
|
let line_layout = fonts.layout_line(
|
||||||
&[(text.len(), text_style.to_run())],
|
text.as_ref(),
|
||||||
);
|
text_style.font_size,
|
||||||
|
&[(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 {
|
paint_state.lock().replace(TextLayout {
|
||||||
line_layout: Arc::new(line_layout),
|
line_layout: Arc::new(line_layout),
|
||||||
line_height,
|
line_height,
|
||||||
});
|
});
|
||||||
|
|
||||||
size
|
size
|
||||||
})
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Ok((layout_id?, paint_state))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn paint<'a>(
|
fn paint<'a>(
|
||||||
&mut self,
|
&mut self,
|
||||||
view: &mut V,
|
view: &mut V,
|
||||||
layout: &mut Layout<V, Self::Layout>,
|
layout: &Layout,
|
||||||
|
paint_state: &mut Self::PaintState,
|
||||||
cx: &mut PaintContext<V>,
|
cx: &mut PaintContext<V>,
|
||||||
) {
|
) {
|
||||||
let element_layout = layout.update(|layout, element_data| element_data.clone());
|
|
||||||
|
|
||||||
let line_layout;
|
let line_layout;
|
||||||
let line_height;
|
let line_height;
|
||||||
{
|
{
|
||||||
let element_layout = element_layout.lock();
|
let paint_state = paint_state.lock();
|
||||||
let element_layout = element_layout
|
let paint_state = paint_state
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.expect("measurement has not been performed");
|
.expect("measurement has not been performed");
|
||||||
line_layout = element_layout.line_layout.clone();
|
line_layout = paint_state.line_layout.clone();
|
||||||
line_height = element_layout.line_height;
|
line_height = paint_state.line_height;
|
||||||
}
|
}
|
||||||
|
|
||||||
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())]);
|
||||||
|
|
||||||
let origin = layout.bounds(cx).origin();
|
let origin = layout.bounds.origin();
|
||||||
// TODO: We haven't added visible bounds to the new element system yet, so this is a placeholder.
|
// TODO: We haven't added visible bounds to the new element system yet, so this is a placeholder.
|
||||||
let visible_bounds = layout.bounds(cx);
|
let visible_bounds = layout.bounds;
|
||||||
line.paint(cx.scene, origin, visible_bounds, line_height, cx.legacy_cx);
|
line.paint(cx.scene, origin, visible_bounds, line_height, cx.legacy_cx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,25 +62,26 @@ pub fn derive_element(input: TokenStream) -> TokenStream {
|
||||||
impl #impl_generics playground::element::Element<#view_type_name> for #type_name #type_generics
|
impl #impl_generics playground::element::Element<#view_type_name> for #type_name #type_generics
|
||||||
#where_clause
|
#where_clause
|
||||||
{
|
{
|
||||||
type Layout = playground::element::AnyElement<#view_type_name #lifetimes>;
|
type PaintState = playground::element::AnyElement<#view_type_name #lifetimes>;
|
||||||
|
|
||||||
fn layout(
|
fn layout(
|
||||||
&mut self,
|
&mut self,
|
||||||
view: &mut V,
|
view: &mut V,
|
||||||
cx: &mut playground::element::LayoutContext<V>,
|
cx: &mut playground::element::LayoutContext<V>,
|
||||||
) -> anyhow::Result<playground::element::Layout<V, Self::Layout>> {
|
) -> anyhow::Result<(playground::element::LayoutId, Self::PaintState)> {
|
||||||
let mut rendered_element = self.render(view, cx).into_any();
|
let mut rendered_element = self.render(view, cx).into_any();
|
||||||
let layout_id = rendered_element.layout(view, cx)?;
|
let layout_id = rendered_element.layout(view, cx)?;
|
||||||
Ok(playground::element::Layout::new(layout_id, rendered_element))
|
Ok((layout_id, rendered_element))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn paint(
|
fn paint(
|
||||||
&mut self,
|
&mut self,
|
||||||
view: &mut V,
|
view: &mut V,
|
||||||
layout: &mut playground::element::Layout<V, Self::Layout>,
|
layout: &playground::element::Layout,
|
||||||
|
rendered_element: &mut Self::PaintState,
|
||||||
cx: &mut playground::element::PaintContext<V>,
|
cx: &mut playground::element::PaintContext<V>,
|
||||||
) {
|
) {
|
||||||
layout.update(|_, rendered_element| rendered_element.paint(view, cx));
|
rendered_element.paint(view, cx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1304,8 +1304,8 @@ impl LayoutEngine {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn computed_layout(&mut self, node: LayoutId) -> Result<EngineLayout> {
|
pub fn computed_layout(&mut self, node: LayoutId) -> Result<Layout> {
|
||||||
Ok(EngineLayout::from(self.0.layout(node)?))
|
Ok(Layout::from(self.0.layout(node)?))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1329,7 +1329,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Default)]
|
#[derive(Debug, Clone, Default)]
|
||||||
pub struct EngineLayout {
|
pub struct Layout {
|
||||||
pub bounds: RectF,
|
pub bounds: RectF,
|
||||||
pub order: u32,
|
pub order: u32,
|
||||||
}
|
}
|
||||||
|
@ -1365,7 +1365,7 @@ impl From<taffy::prelude::AvailableSpace> for AvailableSpace {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&taffy::tree::Layout> for EngineLayout {
|
impl From<&taffy::tree::Layout> for Layout {
|
||||||
fn from(value: &taffy::tree::Layout) -> Self {
|
fn from(value: &taffy::tree::Layout) -> Self {
|
||||||
Self {
|
Self {
|
||||||
bounds: RectF::new(
|
bounds: RectF::new(
|
||||||
|
|
|
@ -7,8 +7,8 @@ pub use assets::*;
|
||||||
pub mod elements;
|
pub mod elements;
|
||||||
pub mod font_cache;
|
pub mod font_cache;
|
||||||
mod image_data;
|
mod image_data;
|
||||||
pub use taffy;
|
|
||||||
pub use crate::image_data::ImageData;
|
pub use crate::image_data::ImageData;
|
||||||
|
pub use taffy;
|
||||||
pub mod views;
|
pub mod views;
|
||||||
pub use font_cache::FontCache;
|
pub use font_cache::FontCache;
|
||||||
mod clipboard;
|
mod clipboard;
|
||||||
|
@ -29,8 +29,7 @@ pub mod keymap_matcher;
|
||||||
pub mod platform;
|
pub mod platform;
|
||||||
pub use gpui_macros::{test, Element};
|
pub use gpui_macros::{test, Element};
|
||||||
pub use window::{
|
pub use window::{
|
||||||
Axis, EngineLayout, LayoutEngine, LayoutId, RectFExt, SizeConstraint, Vector2FExt,
|
Axis, Layout, LayoutEngine, LayoutId, RectFExt, SizeConstraint, Vector2FExt, WindowContext,
|
||||||
WindowContext,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub use anyhow;
|
pub use anyhow;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue