mirror of
https://github.com/zed-industries/zed.git
synced 2024-12-28 20:42:09 +03:00
Get text rendering
Co-Authored-By: Antonio Scandurra <antonio@zed.dev>
This commit is contained in:
parent
fea987b459
commit
f1aafab61d
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -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()
|
||||
|
95
crates/gpui/playground_macros/src/derive_into_element.rs
Normal file
95
crates/gpui/playground_macros/src/derive_into_element.rs
Normal file
@ -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,24 +3443,8 @@ impl<'a, 'b, 'c, V> LayoutContext<'a, 'b, 'c, V> {
|
||||
.push(self_view_id);
|
||||
}
|
||||
|
||||
pub fn text_style(&self) -> Arc<TextStyle> {
|
||||
self.text_style_stack
|
||||
.last()
|
||||
.cloned()
|
||||
.unwrap_or(Arc::new(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());
|
||||
}
|
||||
|
||||
pub 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
|
||||
pub fn with_text_style<F, T>(&mut self, style: TextStyle, f: F) -> T
|
||||
where
|
||||
S: Into<Arc<TextStyle>>,
|
||||
F: FnOnce(&mut Self) -> T,
|
||||
{
|
||||
self.push_text_style(style);
|
||||
@ -3460,6 +3454,23 @@ impl<'a, 'b, 'c, V> LayoutContext<'a, 'b, 'c, V> {
|
||||
}
|
||||
}
|
||||
|
||||
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(TextStyle::default(&self.font_cache))
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b, 'c, V> Deref for LayoutContext<'a, 'b, 'c, V> {
|
||||
type Target = ViewContext<'a, 'b, 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,
|
||||
});
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user