Cargo.lock 🔗
@@ -5304,6 +5304,7 @@ dependencies = [
"gpui",
"log",
"optional_struct",
+ "parking_lot 0.11.2",
"playground_macros",
"serde",
"simplelog",
Nathan Sobo and Antonio Scandurra created
Co-Authored-By: Antonio Scandurra <antonio@zed.dev>
Cargo.lock | 1
crates/gpui/playground/Cargo.toml | 1
crates/gpui/playground/src/color.rs | 9
crates/gpui/playground/src/components.rs | 20
crates/gpui/playground/src/element.rs | 69 ++++
crates/gpui/playground/src/frame.rs | 24 +
crates/gpui/playground/src/playground.rs | 13
crates/gpui/playground/src/style.rs | 25 +
crates/gpui/playground/src/text.rs | 147 +++++++++
crates/gpui/playground_macros/src/derive_element.rs | 13
crates/gpui/playground_macros/src/derive_into_element.rs | 95 ++++++
crates/gpui/playground_macros/src/playground_macros.rs | 16
crates/gpui/src/app.rs | 66 ++-
crates/gpui/src/app/window.rs | 1
crates/gpui/src/text_layout.rs | 6
15 files changed, 436 insertions(+), 70 deletions(-)
@@ -5304,6 +5304,7 @@ dependencies = [
"gpui",
"log",
"optional_struct",
+ "parking_lot 0.11.2",
"playground_macros",
"serde",
"simplelog",
@@ -14,6 +14,7 @@ gpui = { path = ".." }
log.workspace = true
optional_struct = "0.3.1"
playground_macros = { path = "../playground_macros" }
+parking_lot.workspace = true
serde.workspace = true
simplelog = "0.9"
smallvec.workspace = true
@@ -116,6 +116,15 @@ pub fn hsla(h: f32, s: f32, l: f32, a: f32) -> Hsla {
}
}
+pub fn black() -> Hsla {
+ Hsla {
+ h: 0.,
+ s: 0.,
+ l: 0.,
+ a: 1.,
+ }
+}
+
impl From<Rgba> for Hsla {
fn from(color: Rgba) -> Self {
let r = color.r;
@@ -1,11 +1,12 @@
use crate::{
element::{Element, ElementMetadata},
frame,
+ text::ArcCow,
themes::rose_pine,
};
use gpui::ViewContext;
use playground_macros::Element;
-use std::{borrow::Cow, marker::PhantomData, rc::Rc};
+use std::{marker::PhantomData, rc::Rc};
struct ButtonHandlers<V, D> {
click: Option<Rc<dyn Fn(&mut V, &D)>>,
@@ -22,8 +23,8 @@ impl<V, D> Default for ButtonHandlers<V, D> {
pub struct Button<V: 'static, D: 'static> {
metadata: ElementMetadata<V>,
handlers: ButtonHandlers<V, D>,
- label: Option<Cow<'static, str>>,
- icon: Option<Cow<'static, str>>,
+ label: Option<ArcCow<'static, str>>,
+ icon: Option<ArcCow<'static, str>>,
data: Rc<D>,
view_type: PhantomData<V>,
}
@@ -56,17 +57,17 @@ impl<V: 'static> Button<V, ()> {
// Impl block for *any* button.
impl<V: 'static, D: 'static> Button<V, D> {
- fn label(mut self, label: impl Into<Cow<'static, str>>) -> Self {
+ pub fn label(mut self, label: impl Into<ArcCow<'static, str>>) -> Self {
self.label = Some(label.into());
self
}
- fn icon(mut self, icon: impl Into<Cow<'static, str>>) -> Self {
+ pub fn icon(mut self, icon: impl Into<ArcCow<'static, str>>) -> Self {
self.icon = Some(icon.into());
self
}
- fn click(self, handler: impl Fn(&mut V, &D) + 'static) -> Self {
+ pub fn click(self, handler: impl Fn(&mut V, &D) + 'static) -> Self {
let data = self.data.clone();
Element::click(self, move |view, _| {
handler(view, data.as_ref());
@@ -80,8 +81,11 @@ pub fn button<V>() -> Button<V, ()> {
impl<V: 'static, D: 'static> Button<V, D> {
fn render(&mut self, view: &mut V, cx: &mut ViewContext<V>) -> impl Element<V> {
- // TODO: Drive from the context
- let button = frame().fill(rose_pine::dawn().error(0.5)).h_5().w_9();
+ // TODO: Drive theme from the context
+ let button = frame()
+ .fill(rose_pine::dawn().error(0.5))
+ .h_4()
+ .children(self.label.clone());
if let Some(handler) = self.handlers.click.clone() {
let data = self.data.clone();
@@ -1,5 +1,6 @@
use crate::{
adapter::Adapter,
+ color::Hsla,
style::{Display, ElementStyle, Fill, Overflow, Position},
};
use anyhow::Result;
@@ -8,7 +9,7 @@ pub use gpui::LayoutContext;
use gpui::{
geometry::{DefinedLength, Length},
scene::MouseClick,
- EngineLayout, PaintContext as LegacyPaintContext,
+ EngineLayout, PaintContext as LegacyPaintContext, RenderContext,
};
use playground_macros::tailwind_lengths;
use std::{any::Any, rc::Rc};
@@ -22,6 +23,20 @@ pub struct PaintContext<'a, 'b, 'c, 'd, V> {
pub(crate) scene: &'d mut gpui::SceneBuilder,
}
+impl<V> RenderContext for PaintContext<'_, '_, '_, '_, V> {
+ fn text_style(&self) -> gpui::fonts::TextStyle {
+ self.legacy_cx.text_style()
+ }
+
+ fn push_text_style(&mut self, style: gpui::fonts::TextStyle) {
+ self.legacy_cx.push_text_style(style)
+ }
+
+ fn pop_text_style(&mut self) {
+ self.legacy_cx.pop_text_style()
+ }
+}
+
pub struct Layout<'a, E: ?Sized> {
pub from_engine: EngineLayout,
pub from_element: &'a mut E,
@@ -303,9 +318,18 @@ pub trait Element<V: 'static>: 'static {
self.style_mut().fill = fill.into();
self
}
+
+ fn text_color(mut self, color: impl Into<Hsla>) -> Self
+ where
+ Self: Sized,
+ {
+ self.style_mut().text_color = Some(color.into());
+ self
+ }
}
-pub trait ElementObject<V> {
+// Object-safe counterpart of Element used by AnyElement to store elements as trait objects.
+trait ElementObject<V> {
fn style_mut(&mut self) -> &mut ElementStyle;
fn handlers_mut(&mut self) -> &mut ElementHandlers<V>;
fn layout(&mut self, view: &mut V, cx: &mut LayoutContext<V>)
@@ -360,12 +384,33 @@ pub struct AnyElement<V> {
impl<V> AnyElement<V> {
pub fn layout(&mut self, view: &mut V, cx: &mut LayoutContext<V>) -> Result<NodeId> {
+ let pushed_text_style = self.push_text_style(cx);
+
let (node_id, layout) = self.element.layout(view, cx)?;
self.layout = Some((node_id, layout));
+
+ if pushed_text_style {
+ cx.pop_text_style();
+ }
+
Ok(node_id)
}
+ pub fn push_text_style(&mut self, cx: &mut impl RenderContext) -> bool {
+ let text_style = self.element.style_mut().text_style();
+ if let Some(text_style) = text_style {
+ let mut current_text_style = cx.text_style();
+ text_style.apply(&mut current_text_style);
+ cx.push_text_style(current_text_style);
+ true
+ } else {
+ false
+ }
+ }
+
pub fn paint(&mut self, view: &mut V, cx: &mut PaintContext<V>) -> Result<()> {
+ let pushed_text_style = self.push_text_style(cx);
+
let (layout_node_id, element_layout) =
self.layout.as_mut().expect("paint called before layout");
@@ -378,7 +423,12 @@ impl<V> AnyElement<V> {
from_element: element_layout.as_mut(),
};
- self.element.paint(layout, view, cx)
+ self.element.paint(layout, view, cx)?;
+ if pushed_text_style {
+ cx.pop_text_style();
+ }
+
+ Ok(())
}
}
@@ -405,3 +455,16 @@ impl<V: 'static> Element<V> for AnyElement<V> {
self.paint(view, cx)
}
}
+
+pub trait IntoElement<V: 'static> {
+ type Element: Element<V>;
+
+ fn into_element(self) -> Self::Element;
+
+ fn into_any_element(self) -> AnyElement<V>
+ where
+ Self: Sized,
+ {
+ self.into_element().into_any()
+ }
+}
@@ -1,11 +1,17 @@
use crate::{
- element::{AnyElement, Element, ElementHandlers, Layout, LayoutContext, NodeId, PaintContext},
+ element::{
+ AnyElement, Element, ElementHandlers, IntoElement, Layout, LayoutContext, NodeId,
+ PaintContext,
+ },
style::ElementStyle,
};
use anyhow::{anyhow, Result};
use gpui::LayoutNodeId;
+use playground_macros::IntoElement;
-pub struct Frame<V> {
+#[derive(IntoElement)]
+#[element_crate = "crate"]
+pub struct Frame<V: 'static> {
style: ElementStyle,
handlers: ElementHandlers<V>,
children: Vec<AnyElement<V>>,
@@ -66,8 +72,18 @@ impl<V: 'static> Element<V> for Frame<V> {
}
impl<V: 'static> Frame<V> {
- pub fn child(mut self, child: impl Element<V>) -> Self {
- self.children.push(child.into_any());
+ pub fn child(mut self, child: impl IntoElement<V>) -> Self {
+ self.children.push(child.into_any_element());
+ self
+ }
+
+ pub fn children<I, E>(mut self, children: I) -> Self
+ where
+ I: IntoIterator<Item = E>,
+ E: IntoElement<V>,
+ {
+ self.children
+ .extend(children.into_iter().map(|e| e.into_any_element()));
self
}
}
@@ -1,9 +1,10 @@
#![allow(dead_code, unused_variables)]
+use color::black;
use components::button;
use element::Element;
use frame::frame;
use gpui::{
- geometry::{percent, rect::RectF, vector::vec2f},
+ geometry::{rect::RectF, vector::vec2f},
platform::WindowOptions,
};
use log::LevelFilter;
@@ -35,19 +36,21 @@ fn main() {
center: true,
..Default::default()
},
- |_| view(|_| workspace(&rose_pine::moon())),
+ |_| view(|_| playground(&rose_pine::moon())),
);
cx.platform().activate(true);
});
}
-fn workspace<V: 'static>(theme: &ThemeColors) -> impl Element<V> {
+fn playground<V: 'static>(theme: &ThemeColors) -> impl Element<V> {
frame()
+ .text_color(black())
.h_full()
- .w(percent(50.))
+ .w_half()
.fill(theme.success(0.5))
- .child(button())
+ .child(button().label("Hello").click(|_, _| (println!("hey!"))))
}
+
// todo!()
// // column()
// // .size(auto())
@@ -66,6 +66,8 @@ pub struct ElementStyle {
/// The fill color of this element
pub fill: Fill,
+ /// The color of text within this element. Cascades to children unless overridden.
+ pub text_color: Option<Hsla>,
}
impl ElementStyle {
@@ -103,6 +105,7 @@ impl ElementStyle {
l: 0.,
a: 0.,
}),
+ text_color: None,
};
pub fn new() -> Self {
@@ -136,6 +139,16 @@ impl ElementStyle {
..Default::default() // Ignore grid properties for now
}
}
+
+ pub fn text_style(&self) -> Option<OptionalTextStyle> {
+ if self.text_color.is_some() {
+ Some(OptionalTextStyle {
+ color: self.text_color,
+ })
+ } else {
+ None
+ }
+ }
}
impl Default for ElementStyle {
@@ -144,6 +157,18 @@ impl Default for ElementStyle {
}
}
+pub struct OptionalTextStyle {
+ color: Option<Hsla>,
+}
+
+impl OptionalTextStyle {
+ pub fn apply(&self, style: &mut gpui::fonts::TextStyle) {
+ if let Some(color) = self.color {
+ style.color = color.into();
+ }
+ }
+}
+
#[derive(Clone)]
pub enum Fill {
Color(Hsla),
@@ -1,36 +1,155 @@
-use std::borrow::Cow;
+use crate::element::{Element, ElementMetadata, IntoElement};
+use gpui::{geometry::Size, text_layout::LineLayout, RenderContext};
+use parking_lot::Mutex;
+use std::sync::Arc;
-use crate::element::Element;
+impl<V: 'static, S: Into<ArcCow<'static, str>>> IntoElement<V> for S {
+ type Element = Text<V>;
-impl<V, S> Element<V> for S
-where
- V: 'static,
- S: 'static + Into<Cow<'static, str>>,
-{
- type Layout = Cow<'static, str>;
+ fn into_element(self) -> Self::Element {
+ Text {
+ text: self.into(),
+ metadata: Default::default(),
+ }
+ }
+}
+
+pub struct Text<V> {
+ text: ArcCow<'static, str>,
+ metadata: ElementMetadata<V>,
+}
+
+impl<V: 'static> Element<V> for Text<V> {
+ type Layout = Arc<Mutex<Option<TextLayout>>>;
fn style_mut(&mut self) -> &mut crate::style::ElementStyle {
- todo!()
+ &mut self.metadata.style
}
fn handlers_mut(&mut self) -> &mut crate::element::ElementHandlers<V> {
- todo!()
+ &mut self.metadata.handlers
}
fn layout(
&mut self,
view: &mut V,
- cx: &mut crate::element::LayoutContext<V>,
+ cx: &mut gpui::LayoutContext<V>,
) -> anyhow::Result<(taffy::tree::NodeId, Self::Layout)> {
- todo!()
+ 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 node_id = layout_engine.add_measured_node(self.metadata.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))
}
fn paint<'a>(
&mut self,
- layout: crate::element::Layout<Self::Layout>,
+ layout: crate::element::Layout<Arc<Mutex<Option<TextLayout>>>>,
view: &mut V,
cx: &mut crate::element::PaintContext<V>,
) -> anyhow::Result<()> {
- todo!()
+ 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,
+ );
+ Ok(())
+ }
+}
+
+pub struct TextLayout {
+ line_layout: Arc<LineLayout>,
+ line_height: f32,
+}
+
+pub enum ArcCow<'a, T: ?Sized> {
+ Borrowed(&'a T),
+ Owned(Arc<T>),
+}
+
+impl<'a, T: ?Sized> Clone for ArcCow<'a, T> {
+ fn clone(&self) -> Self {
+ match self {
+ Self::Borrowed(borrowed) => Self::Borrowed(borrowed),
+ Self::Owned(owned) => Self::Owned(owned.clone()),
+ }
+ }
+}
+
+impl<'a, T: ?Sized> From<&'a T> for ArcCow<'a, T> {
+ fn from(s: &'a T) -> Self {
+ Self::Borrowed(s)
+ }
+}
+
+impl<T> From<Arc<T>> for ArcCow<'_, T> {
+ fn from(s: Arc<T>) -> Self {
+ Self::Owned(s)
+ }
+}
+
+impl From<String> for ArcCow<'_, str> {
+ fn from(value: String) -> Self {
+ Self::Owned(value.into())
+ }
+}
+
+impl<T: ?Sized> std::ops::Deref for ArcCow<'_, T> {
+ type Target = T;
+
+ fn deref(&self) -> &Self::Target {
+ match self {
+ ArcCow::Borrowed(s) => s,
+ ArcCow::Owned(s) => s.as_ref(),
+ }
+ }
+}
+
+impl<T: ?Sized> AsRef<T> for ArcCow<'_, T> {
+ fn as_ref(&self) -> &T {
+ match self {
+ ArcCow::Borrowed(borrowed) => borrowed,
+ ArcCow::Owned(owned) => owned.as_ref(),
+ }
}
}
@@ -5,6 +5,8 @@ use syn::{
WhereClause,
};
+use crate::derive_into_element::impl_into_element;
+
pub fn derive_element(input: TokenStream) -> TokenStream {
let ast = parse_macro_input!(input as DeriveInput);
let type_name = ast.ident;
@@ -62,6 +64,15 @@ pub fn derive_element(input: TokenStream) -> TokenStream {
}
}
+ let impl_into_element = impl_into_element(
+ &impl_generics,
+ &crate_name,
+ &view_type_name,
+ &type_name,
+ &type_generics,
+ &where_clause,
+ );
+
let gen = quote! {
impl #impl_generics #crate_name::element::Element<#view_type_name> for #type_name #type_generics
#where_clause
@@ -96,6 +107,8 @@ pub fn derive_element(input: TokenStream) -> TokenStream {
Ok(())
}
}
+
+ #impl_into_element
};
gen.into()
@@ -0,0 +1,95 @@
+use proc_macro::TokenStream;
+use quote::{format_ident, quote};
+use syn::{
+ parse_macro_input, parse_quote, DeriveInput, GenericParam, Generics, Ident, Lit, Meta,
+ WhereClause,
+};
+
+pub fn derive_into_element(input: TokenStream) -> TokenStream {
+ let ast = parse_macro_input!(input as DeriveInput);
+ let type_name = ast.ident;
+
+ let crate_name: String = ast
+ .attrs
+ .iter()
+ .find_map(|attr| {
+ if attr.path.is_ident("element_crate") {
+ match attr.parse_meta() {
+ Ok(Meta::NameValue(nv)) => {
+ if let Lit::Str(s) = nv.lit {
+ Some(s.value())
+ } else {
+ None
+ }
+ }
+ _ => None,
+ }
+ } else {
+ None
+ }
+ })
+ .unwrap_or_else(|| String::from("playground"));
+
+ let crate_name = format_ident!("{}", crate_name);
+
+ let placeholder_view_generics: Generics = parse_quote! { <V: 'static> };
+ let placeholder_view_type_name: Ident = parse_quote! { V };
+ let view_type_name: Ident;
+ let impl_generics: syn::ImplGenerics<'_>;
+ let type_generics: Option<syn::TypeGenerics<'_>>;
+ let where_clause: Option<&'_ WhereClause>;
+
+ match ast.generics.params.iter().find_map(|param| {
+ if let GenericParam::Type(type_param) = param {
+ Some(type_param.ident.clone())
+ } else {
+ None
+ }
+ }) {
+ Some(type_name) => {
+ view_type_name = type_name;
+ let generics = ast.generics.split_for_impl();
+ impl_generics = generics.0;
+ type_generics = Some(generics.1);
+ where_clause = generics.2;
+ }
+ _ => {
+ view_type_name = placeholder_view_type_name;
+ let generics = placeholder_view_generics.split_for_impl();
+ impl_generics = generics.0;
+ type_generics = None;
+ where_clause = generics.2;
+ }
+ }
+
+ impl_into_element(
+ &impl_generics,
+ &crate_name,
+ &view_type_name,
+ &type_name,
+ &type_generics,
+ &where_clause,
+ )
+ .into()
+}
+
+pub fn impl_into_element(
+ impl_generics: &syn::ImplGenerics<'_>,
+ crate_name: &Ident,
+ view_type_name: &Ident,
+ type_name: &Ident,
+ type_generics: &Option<syn::TypeGenerics<'_>>,
+ where_clause: &Option<&WhereClause>,
+) -> proc_macro2::TokenStream {
+ quote! {
+ impl #impl_generics #crate_name::element::IntoElement<#view_type_name> for #type_name #type_generics
+ #where_clause
+ {
+ type Element = Self;
+
+ fn into_element(self) -> Self {
+ self
+ }
+ }
+ }
+}
@@ -1,14 +1,20 @@
use proc_macro::TokenStream;
mod derive_element;
+mod derive_into_element;
mod tailwind_lengths;
-#[proc_macro_attribute]
-pub fn tailwind_lengths(attr: TokenStream, item: TokenStream) -> TokenStream {
- tailwind_lengths::tailwind_lengths(attr, item)
-}
-
#[proc_macro_derive(Element, attributes(element_crate))]
pub fn derive_element(input: TokenStream) -> TokenStream {
derive_element::derive_element(input)
}
+
+#[proc_macro_derive(IntoElement, attributes(element_crate))]
+pub fn derive_into_element(input: TokenStream) -> TokenStream {
+ derive_into_element::derive_into_element(input)
+}
+
+#[proc_macro_attribute]
+pub fn tailwind_lengths(attr: TokenStream, item: TokenStream) -> TokenStream {
+ tailwind_lengths::tailwind_lengths(attr, item)
+}
@@ -3361,11 +3361,21 @@ impl<V> BorrowWindowContext for ViewContext<'_, '_, V> {
}
}
+/// Methods shared by both LayoutContext and PaintContext
+///
+/// It's that PaintContext should be implemented in terms of layout context and
+/// deref to it, in which case we wouldn't need this.
+pub trait RenderContext {
+ fn text_style(&self) -> TextStyle;
+ fn push_text_style(&mut self, style: TextStyle);
+ fn pop_text_style(&mut self);
+}
+
pub struct LayoutContext<'a, 'b, 'c, V> {
view_context: &'c mut ViewContext<'a, 'b, V>,
new_parents: &'c mut HashMap<usize, usize>,
views_to_notify_if_ancestors_change: &'c mut HashMap<usize, SmallVec<[usize; 2]>>,
- text_style_stack: Vec<Arc<TextStyle>>,
+ text_style_stack: Vec<TextStyle>,
pub refreshing: bool,
}
@@ -3433,31 +3443,32 @@ impl<'a, 'b, 'c, V> LayoutContext<'a, 'b, 'c, V> {
.push(self_view_id);
}
- pub fn text_style(&self) -> Arc<TextStyle> {
+ pub fn with_text_style<F, T>(&mut self, style: TextStyle, f: F) -> T
+ where
+ F: FnOnce(&mut Self) -> T,
+ {
+ self.push_text_style(style);
+ let result = f(self);
+ self.pop_text_style();
+ result
+ }
+}
+
+impl<'a, 'b, 'c, V> RenderContext for LayoutContext<'a, 'b, 'c, V> {
+ fn text_style(&self) -> TextStyle {
self.text_style_stack
.last()
.cloned()
- .unwrap_or(Arc::new(TextStyle::default(&self.font_cache)))
+ .unwrap_or(TextStyle::default(&self.font_cache))
}
- pub fn push_text_style<S: Into<Arc<TextStyle>>>(&mut self, style: S) {
- self.text_style_stack.push(style.into());
+ fn push_text_style(&mut self, style: TextStyle) {
+ self.text_style_stack.push(style);
}
- pub fn pop_text_style(&mut self) {
+ fn pop_text_style(&mut self) {
self.text_style_stack.pop();
}
-
- pub fn with_text_style<S, F, T>(&mut self, style: S, f: F) -> T
- where
- S: Into<Arc<TextStyle>>,
- F: FnOnce(&mut Self) -> T,
- {
- self.push_text_style(style);
- let result = f(self);
- self.pop_text_style();
- result
- }
}
impl<'a, 'b, 'c, V> Deref for LayoutContext<'a, 'b, 'c, V> {
@@ -3516,7 +3527,7 @@ impl<V> BorrowWindowContext for LayoutContext<'_, '_, '_, V> {
pub struct PaintContext<'a, 'b, 'c, V> {
view_context: &'c mut ViewContext<'a, 'b, V>,
- text_style_stack: Vec<Arc<TextStyle>>,
+ text_style_stack: Vec<TextStyle>,
}
impl<'a, 'b, 'c, V> PaintContext<'a, 'b, 'c, V> {
@@ -3526,23 +3537,22 @@ impl<'a, 'b, 'c, V> PaintContext<'a, 'b, 'c, V> {
text_style_stack: Vec::new(),
}
}
+}
- pub fn text_style(&self) -> Arc<TextStyle> {
+impl<'a, 'b, 'c, V> RenderContext for PaintContext<'a, 'b, 'c, V> {
+ fn text_style(&self) -> TextStyle {
self.text_style_stack
.last()
.cloned()
- .unwrap_or(Arc::new(TextStyle::default(&self.font_cache)))
+ .unwrap_or(TextStyle::default(&self.font_cache))
}
- pub fn with_text_style<S, F, T>(&mut self, style: S, f: F) -> T
- where
- S: Into<Arc<TextStyle>>,
- F: FnOnce(&mut Self) -> T,
- {
- self.text_style_stack.push(style.into());
- let result = f(self);
+ fn push_text_style(&mut self, style: TextStyle) {
+ self.text_style_stack.push(style);
+ }
+
+ fn pop_text_style(&mut self) {
self.text_style_stack.pop();
- result
}
}
@@ -1300,6 +1300,7 @@ where
}
}
+#[derive(Debug, Clone)]
pub struct EngineLayout {
pub bounds: RectF,
pub order: u32,
@@ -212,7 +212,7 @@ pub struct Glyph {
}
impl Line {
- fn new(layout: Arc<LineLayout>, runs: &[(usize, RunStyle)]) -> Self {
+ pub fn new(layout: Arc<LineLayout>, runs: &[(usize, RunStyle)]) -> Self {
let mut style_runs = SmallVec::new();
for (len, style) in runs {
style_runs.push(StyleRun {
@@ -364,13 +364,13 @@ impl Line {
origin: glyph_origin,
});
} else {
- scene.push_glyph(scene::Glyph {
+ scene.push_glyph(dbg!(scene::Glyph {
font_id: run.font_id,
font_size: self.layout.font_size,
id: glyph.id,
origin: glyph_origin,
color,
- });
+ }));
}
}
}