This commit is contained in:
Nathan Sobo 2023-08-25 21:41:21 -06:00
parent cf007a3d3b
commit 147aa0f695
17 changed files with 150 additions and 138 deletions

3
Cargo.lock generated
View file

@ -5119,7 +5119,6 @@ dependencies = [
"serde", "serde",
"simplelog", "simplelog",
"smallvec", "smallvec",
"taffy",
"util", "util",
] ]
@ -7435,7 +7434,7 @@ dependencies = [
[[package]] [[package]]
name = "taffy" name = "taffy"
version = "0.3.11" version = "0.3.11"
source = "git+https://github.com/DioxusLabs/taffy?rev=dab541d6104d58e2e10ce90c4a1dad0b703160cd#dab541d6104d58e2e10ce90c4a1dad0b703160cd" source = "git+https://github.com/DioxusLabs/taffy?rev=4fb530bdd71609bb1d3f76c6a8bde1ba82805d5e#4fb530bdd71609bb1d3f76c6a8bde1ba82805d5e"
dependencies = [ dependencies = [
"arrayvec 0.7.4", "arrayvec 0.7.4",
"grid", "grid",

View file

@ -4866,7 +4866,6 @@ impl Editor {
if let Some(clipboard_selection) = clipboard_selections.get(ix) { if let Some(clipboard_selection) = clipboard_selections.get(ix) {
let end_offset = start_offset + clipboard_selection.len; let end_offset = start_offset + clipboard_selection.len;
to_insert = &clipboard_text[start_offset..end_offset]; to_insert = &clipboard_text[start_offset..end_offset];
dbg!(start_offset, end_offset, &clipboard_text, &to_insert);
entire_line = clipboard_selection.is_entire_line; entire_line = clipboard_selection.is_entire_line;
start_offset = end_offset + 1; start_offset = end_offset + 1;
original_indent_column = original_indent_column =

View file

@ -48,7 +48,7 @@ serde_derive.workspace = true
serde_json.workspace = true serde_json.workspace = true
smallvec.workspace = true smallvec.workspace = true
smol.workspace = true smol.workspace = true
taffy = { git = "https://github.com/DioxusLabs/taffy", rev = "dab541d6104d58e2e10ce90c4a1dad0b703160cd", features = ["flexbox"] } taffy = { git = "https://github.com/DioxusLabs/taffy", rev = "4fb530bdd71609bb1d3f76c6a8bde1ba82805d5e" }
time.workspace = true time.workspace = true
tiny-skia = "0.5" tiny-skia = "0.5"
usvg = { version = "0.14", features = [] } usvg = { version = "0.14", features = [] }

View file

@ -19,7 +19,6 @@ refineable.workspace = true
serde.workspace = true serde.workspace = true
simplelog = "0.9" simplelog = "0.9"
smallvec.workspace = true smallvec.workspace = true
taffy = { git = "https://github.com/DioxusLabs/taffy", rev = "dab541d6104d58e2e10ce90c4a1dad0b703160cd", features = ["flexbox"] }
util = { path = "../../util" } util = { path = "../../util" }
[dev-dependencies] [dev-dependencies]

View file

@ -6,7 +6,7 @@ use crate::{
style::{Style, StyleHelpers, Styleable}, style::{Style, StyleHelpers, Styleable},
}; };
use anyhow::Result; use anyhow::Result;
use gpui::LayoutId; use gpui::{LayoutId, RenderContext};
use refineable::{Refineable, RefinementCascade}; use refineable::{Refineable, RefinementCascade};
use smallvec::SmallVec; use smallvec::SmallVec;
@ -31,27 +31,46 @@ impl<V: 'static> Element<V> for Div<V> {
where where
Self: Sized, Self: Sized,
{ {
let style = self.computed_style();
let pop_text_style = style.text_style().map_or(false, |style| {
cx.push_text_style(cx.text_style().clone().refined(&style));
true
});
let children = self let children = self
.children .children
.iter_mut() .iter_mut()
.map(|child| child.layout(view, cx)) .map(|child| child.layout(view, cx))
.collect::<Result<Vec<LayoutId>>>()?; .collect::<Result<Vec<LayoutId>>>()?;
let style = Style::from_refinement(&self.style_cascade().merged()); if pop_text_style {
cx.add_layout_node(style.clone(), (), children) cx.pop_text_style();
}
let layout = cx.add_layout_node(style, (), children.clone())?;
dbg!(layout.id(), children);
Ok(layout)
} }
fn paint(&mut self, view: &mut V, layout: &mut Layout<V, ()>, cx: &mut PaintContext<V>) fn paint(&mut self, view: &mut V, layout: &mut Layout<V, ()>, cx: &mut PaintContext<V>)
where where
Self: Sized, Self: Sized,
{ {
self.computed_style() let style = &self.computed_style();
.paint_background(layout.bounds(cx), cx); let pop_text_style = style.text_style().map_or(false, |style| {
cx.push_text_style(cx.text_style().clone().refined(&style));
true
});
style.paint_background(layout.bounds(cx), cx);
self.interaction_handlers() self.interaction_handlers()
.paint(layout.order(cx), layout.bounds(cx), cx); .paint(layout.order(cx), layout.bounds(cx), cx);
for child in &mut self.children { for child in &mut self.children {
child.paint(view, cx); child.paint(view, cx);
} }
if pop_text_style {
cx.pop_text_style();
}
} }
} }

View file

@ -1,4 +1,4 @@
use anyhow::{anyhow, Result}; use anyhow::Result;
use gpui::{geometry::rect::RectF, EngineLayout}; use gpui::{geometry::rect::RectF, EngineLayout};
use smallvec::SmallVec; use smallvec::SmallVec;
use std::marker::PhantomData; use std::marker::PhantomData;
@ -32,7 +32,7 @@ pub trait Element<V: 'static>: 'static {
where where
Self: 'static + Sized, Self: 'static + Sized,
{ {
AnyElement(Box::new(ElementState { AnyElement(Box::new(StatefulElement {
element: self, element: self,
layout: None, layout: None,
})) }))
@ -40,19 +40,19 @@ pub trait Element<V: 'static>: 'static {
} }
/// Used to make ElementState<V, E> into a trait object, so we can wrap it in AnyElement<V>. /// Used to make ElementState<V, E> into a trait object, so we can wrap it in AnyElement<V>.
trait ElementStateObject<V> { trait AnyStatefulElement<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, cx: &mut PaintContext<V>); fn paint(&mut self, view: &mut V, cx: &mut PaintContext<V>);
} }
/// A wrapper around an element that stores its layout state. /// A wrapper around an element that stores its layout state.
struct ElementState<V: 'static, E: Element<V>> { struct StatefulElement<V: 'static, E: Element<V>> {
element: E, element: E,
layout: Option<Layout<V, E::Layout>>, layout: Option<Layout<V, E::Layout>>,
} }
/// 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>> ElementStateObject<V> for ElementState<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 layout = self.element.layout(view, cx)?;
let layout_id = layout.id; let layout_id = layout.id;
@ -63,14 +63,14 @@ impl<V, E: Element<V>> ElementStateObject<V> for ElementState<V, E> {
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"); let layout = self.layout.as_mut().expect("paint called before layout");
if layout.engine_layout.is_none() { if layout.engine_layout.is_none() {
layout.engine_layout = cx.computed_layout(layout.id).log_err() layout.engine_layout = dbg!(cx.computed_layout(dbg!(layout.id)).log_err())
} }
self.element.paint(view, layout, cx) self.element.paint(view, layout, cx)
} }
} }
/// A dynamic element. /// A dynamic element.
pub struct AnyElement<V>(Box<dyn ElementStateObject<V>>); pub struct AnyElement<V>(Box<dyn AnyStatefulElement<V>>);
impl<V> AnyElement<V> { impl<V> AnyElement<V> {
pub 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> {
@ -99,6 +99,10 @@ impl<V: 'static, D> Layout<V, D> {
} }
} }
pub fn id(&self) -> LayoutId {
self.id
}
pub fn bounds(&mut self, cx: &mut PaintContext<V>) -> RectF { pub fn bounds(&mut self, cx: &mut PaintContext<V>) -> RectF {
self.engine_layout(cx).bounds self.engine_layout(cx).bounds
} }
@ -107,7 +111,7 @@ impl<V: 'static, D> Layout<V, D> {
self.engine_layout(cx).order self.engine_layout(cx).order
} }
pub fn update<F, T>(&mut self, update: F) -> Result<T> pub fn update<F, T>(&mut self, update: F) -> T
where where
F: FnOnce(&mut Self, &mut D) -> T, F: FnOnce(&mut Self, &mut D) -> T,
{ {
@ -118,7 +122,7 @@ impl<V: 'static, D> Layout<V, D> {
self.element_data = Some(element_data); self.element_data = Some(element_data);
result result
}) })
.ok_or_else(|| anyhow!("reentrant calls to Layout::update are not allowed")) .expect("reentrant calls to Layout::update are not supported")
} }
fn engine_layout(&mut self, cx: &mut PaintContext<'_, '_, '_, '_, V>) -> &mut EngineLayout { fn engine_layout(&mut self, cx: &mut PaintContext<'_, '_, '_, '_, V>) -> &mut EngineLayout {

View file

@ -11,6 +11,7 @@ use crate::element::PaintContext;
pub trait Interactive<V: 'static> { pub trait Interactive<V: 'static> {
fn interaction_handlers(&mut self) -> &mut InteractionHandlers<V>; fn interaction_handlers(&mut self) -> &mut InteractionHandlers<V>;
// One line change.
fn on_mouse_down( fn on_mouse_down(
mut self, mut self,
button: MouseButton, button: MouseButton,

View file

@ -1,8 +1,7 @@
use anyhow::{anyhow, Result}; use anyhow::{anyhow, Result};
use derive_more::{Deref, DerefMut}; use derive_more::{Deref, DerefMut};
pub use gpui::LayoutContext as LegacyLayoutContext; use gpui::{geometry::Size, MeasureParams, RenderContext, ViewContext};
use gpui::{RenderContext, ViewContext}; pub use gpui::{taffy::tree::NodeId, LayoutContext as LegacyLayoutContext};
pub use taffy::tree::NodeId;
use crate::{element::Layout, style::Style}; use crate::{element::Layout, style::Style};
@ -51,4 +50,22 @@ impl<'a, 'b, 'c, 'd, V: 'static> LayoutContext<'a, 'b, 'c, 'd, V> {
Ok(Layout::new(id, element_data)) Ok(Layout::new(id, element_data))
} }
pub fn add_measured_layout_node<D, F>(
&mut self,
style: Style,
element_data: D,
measure: F,
) -> Result<Layout<V, D>>
where
F: Fn(MeasureParams) -> Size<f32> + Sync + Send + 'static,
{
let rem_size = self.rem_pixels();
let layout_id = self
.layout_engine()
.ok_or_else(|| anyhow!("no layout engine"))?
.add_measured_node(style.to_taffy(rem_size), measure)?;
Ok(Layout::new(layout_id, element_data))
}
} }

View file

@ -1,9 +1,11 @@
use anyhow::{anyhow, Result}; use anyhow::{anyhow, Result};
use derive_more::{Deref, DerefMut}; use derive_more::{Deref, DerefMut};
use gpui::{scene::EventHandler, EngineLayout, EventContext, LayoutId, RenderContext, ViewContext}; pub use gpui::taffy::tree::NodeId;
pub use gpui::{LayoutContext, PaintContext as LegacyPaintContext}; use gpui::{
scene::EventHandler, EngineLayout, EventContext, LayoutId, PaintContext as LegacyPaintContext,
RenderContext, ViewContext,
};
use std::{any::TypeId, rc::Rc}; use std::{any::TypeId, rc::Rc};
pub use taffy::tree::NodeId;
#[derive(Deref, DerefMut)] #[derive(Deref, DerefMut)]
pub struct PaintContext<'a, 'b, 'c, 'd, V> { pub struct PaintContext<'a, 'b, 'c, 'd, V> {

View file

@ -1,9 +1,6 @@
#![allow(dead_code, unused_variables)] #![allow(dead_code, unused_variables)]
use crate::{ use crate::{
color::black, color::black, element::ParentElement, style::StyleHelpers, themes::rose_pine::RosePinePalette,
components::button,
element::ParentElement,
style::{StyleHelpers, Styleable},
}; };
use element::Element; use element::Element;
use gpui::{ use gpui::{
@ -51,64 +48,24 @@ fn main() {
fn playground<V: 'static>(theme: &ThemeColors) -> impl Element<V> { fn playground<V: 'static>(theme: &ThemeColors) -> impl Element<V> {
use div::div; use div::div;
let p = RosePinePalette::dawn();
div() div()
.text_color(black()) .text_color(black())
.h_full() .h_full()
.w_1_2() .w_full()
.fill(theme.success(0.5)) .fill(p.rose)
.hovered() .block()
.fill(theme.error(0.5))
.pressed()
.fill(theme.warning(0.5))
.child( .child(
div() div()
.h_6() .block()
.w_6() .fill(p.pine)
.absolute() .child(div().block().fill(p.love).w_6().h_3()),
.bottom_0()
.fill(theme.success(0.)),
) )
.child( .child(
button() div()
.label("Click me") .block()
.data(1_usize) .fill(p.gold)
.on_click(|_, data, _| { .child(div().block().fill(p.iris).w_3().h_3()),
dbg!(*data);
}),
)
.child(
button()
.label("And me")
.data(2_usize)
.on_click(|_, data, _| {
dbg!(*data);
}),
) )
} }
// todo!()
// // column()
// // .size(auto())
// // .fill(theme.base(0.5))
// // .text_color(theme.text(0.5))
// // .child(title_bar(theme))
// // .child(stage(theme))
// // .child(status_bar(theme))
// }
// fn title_bar<V: 'static>(theme: &ThemeColors) -> impl Element<V> {
// row()
// .fill(theme.base(0.2))
// .justify(0.)
// .width(auto())
// .child(text("Zed Playground"))
// }
// fn stage<V: 'static>(theme: &ThemeColors) -> impl Element<V> {
// row().fill(theme.surface(0.9))
// }
// fn status_bar<V: 'static>(theme: &ThemeColors) -> impl Element<V> {
// row().fill(theme.surface(0.1))
// }

View file

@ -4,19 +4,20 @@ use crate::{
paint_context::PaintContext, paint_context::PaintContext,
pressable::{pressable, Pressable}, pressable::{pressable, Pressable},
}; };
pub use gpui::taffy::style::{
AlignContent, AlignItems, AlignSelf, Display, FlexDirection, FlexWrap, JustifyContent,
Overflow, Position,
};
use gpui::{ use gpui::{
fonts::TextStyleRefinement, fonts::TextStyleRefinement,
geometry::{ geometry::{
rect::RectF, AbsoluteLength, DefiniteLength, Edges, EdgesRefinement, Length, Point, rect::RectF, AbsoluteLength, DefiniteLength, Edges, EdgesRefinement, Length, Point,
PointRefinement, Size, SizeRefinement, PointRefinement, Size, SizeRefinement,
}, },
taffy,
}; };
use playground_macros::styleable_helpers; use playground_macros::styleable_helpers;
use refineable::{Refineable, RefinementCascade}; use refineable::{Refineable, RefinementCascade};
pub use taffy::style::{
AlignContent, AlignItems, AlignSelf, Display, FlexDirection, FlexWrap, JustifyContent,
Overflow, Position,
};
#[derive(Clone, Refineable)] #[derive(Clone, Refineable)]
pub struct Style { pub struct Style {
@ -137,12 +138,23 @@ impl Style {
}); });
} }
} }
pub fn text_style(&self) -> Option<TextStyleRefinement> {
if let Some(color) = self.text_color {
Some(TextStyleRefinement {
color: Some(color.into()),
..Default::default()
})
} else {
None
}
}
} }
impl Default for Style { impl Default for Style {
fn default() -> Self { fn default() -> Self {
Style { Style {
display: Display::DEFAULT, display: Display::Block,
overflow: Point { overflow: Point {
x: Overflow::Visible, x: Overflow::Visible,
y: Overflow::Visible, y: Overflow::Visible,
@ -290,6 +302,14 @@ pub trait StyleHelpers: Styleable<Style = Style> {
self self
} }
fn block(mut self) -> Self
where
Self: Sized,
{
self.declared_style().display = Some(Display::Block);
self
}
fn fill<F>(mut self, fill: F) -> Self fn fill<F>(mut self, fill: F) -> Self
where where
F: Into<Fill>, F: Into<Fill>,

View file

@ -4,7 +4,7 @@ use crate::{
paint_context::PaintContext, paint_context::PaintContext,
}; };
use anyhow::Result; use anyhow::Result;
use gpui::text_layout::LineLayout; use gpui::{geometry::Size, text_layout::LineLayout, RenderContext};
use parking_lot::Mutex; use parking_lot::Mutex;
use std::sync::Arc; use std::sync::Arc;
@ -28,40 +28,32 @@ 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 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); cx.add_measured_layout_node(Default::default(), layout.clone(), move |params| {
// let node_id = layout_engine.add_measured_node(style.to_taffy(rem_size), { let line_layout = fonts.layout_line(
// let layout = layout.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 { 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))
todo!()
} }
fn paint<'a>( fn paint<'a>(
@ -70,26 +62,27 @@ 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 = layout.update(|layout, element_data| element_data.clone());
// 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_layout;
// let line = let line_height;
// gpui::text_layout::Line::new(line_layout, &[(self.text.len(), text_style.to_run())]); {
// line.paint( let element_layout = element_layout.lock();
// cx.scene, let element_layout = element_layout
// layout.from_engine.bounds.origin(), .as_ref()
// layout.from_engine.bounds, .expect("measurement has not been performed");
// line_height, line_layout = element_layout.line_layout.clone();
// cx.legacy_cx, line_height = element_layout.line_height;
// ); }
todo!()
let text_style = cx.text_style();
let line =
gpui::text_layout::Line::new(line_layout, &[(self.text.len(), text_style.to_run())]);
let origin = layout.bounds(cx).origin();
// TODO: We haven't added visible bounds to the new element system yet, so this is a placeholder.
let visible_bounds = layout.bounds(cx);
line.paint(cx.scene, origin, visible_bounds, line_height, cx.legacy_cx);
} }
} }

View file

@ -80,7 +80,7 @@ pub fn derive_element(input: TokenStream) -> TokenStream {
layout: &mut playground::element::Layout<V, Self::Layout>, layout: &mut playground::element::Layout<V, Self::Layout>,
cx: &mut playground::element::PaintContext<V>, cx: &mut playground::element::PaintContext<V>,
) { ) {
layout.update(|_, rendered_element| rendered_element.paint(view, cx)).ok(); layout.update(|_, rendered_element| rendered_element.paint(view, cx));
} }
} }

View file

@ -53,6 +53,7 @@ use std::{
pub use test_app_context::{ContextHandle, TestAppContext}; pub use test_app_context::{ContextHandle, TestAppContext};
use util::ResultExt; use util::ResultExt;
use uuid::Uuid; use uuid::Uuid;
pub use window::MeasureParams;
use window_input_handler::WindowInputHandler; use window_input_handler::WindowInputHandler;
pub trait Entity: 'static { pub trait Entity: 'static {

View file

@ -1302,7 +1302,7 @@ impl LayoutEngine {
} }
pub fn computed_layout(&mut self, node: LayoutId) -> Result<EngineLayout> { pub fn computed_layout(&mut self, node: LayoutId) -> Result<EngineLayout> {
Ok(self.0.layout(node)?.into()) dbg!(Ok(self.0.layout(node)?.into()))
} }
} }

View file

@ -157,7 +157,7 @@ impl<T: Clone + Default> Into<taffy::geometry::Point<T>> for Point<T> {
} }
} }
#[derive(Clone, Refineable)] #[derive(Clone, Refineable, Debug)]
pub struct Size<T: Clone + Default> { pub struct Size<T: Clone + Default> {
pub width: T, pub width: T,
pub height: T, pub height: T,

View file

@ -7,6 +7,7 @@ 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 mod views; pub mod views;
pub use font_cache::FontCache; pub use font_cache::FontCache;