Detailed changes
@@ -12,6 +12,7 @@ use gpui::{
EngineLayout, EventContext, RenderContext, ViewContext,
};
use playground_macros::tailwind_lengths;
+use refineable::Refineable;
use std::{
any::{Any, TypeId},
cell::Cell,
@@ -61,7 +62,7 @@ pub trait Element<V: 'static>: 'static {
fn declared_style(&mut self) -> &mut StyleRefinement;
- fn computed_style(&mut self) -> &StyleRefinement {
+ fn computed_style(&mut self, cx: &mut ViewContext<V>) -> &StyleRefinement {
self.declared_style()
}
@@ -444,7 +445,8 @@ pub trait Element<V: 'static>: 'static {
// Object-safe counterpart of Element used by AnyElement to store elements as trait objects.
trait ElementObject<V> {
- fn style(&mut self) -> &mut StyleRefinement;
+ fn declared_style(&mut self) -> &mut StyleRefinement;
+ fn computed_style(&mut self, cx: &mut ViewContext<V>) -> &StyleRefinement;
fn handlers_mut(&mut self) -> &mut Vec<EventHandler<V>>;
fn layout(&mut self, view: &mut V, cx: &mut LayoutContext<V>)
-> Result<(NodeId, Box<dyn Any>)>;
@@ -457,10 +459,14 @@ trait ElementObject<V> {
}
impl<V: 'static, E: Element<V>> ElementObject<V> for E {
- fn style(&mut self) -> &mut StyleRefinement {
+ fn declared_style(&mut self) -> &mut StyleRefinement {
Element::declared_style(self)
}
+ fn computed_style(&mut self, cx: &mut ViewContext<V>) -> &StyleRefinement {
+ Element::computed_style(self, cx)
+ }
+
fn handlers_mut(&mut self) -> &mut Vec<EventHandler<V>> {
Element::handlers_mut(self)
}
@@ -510,10 +516,13 @@ impl<V: 'static> AnyElement<V> {
Ok(node_id)
}
- pub fn push_text_style(&mut self, cx: &mut impl RenderContext) -> bool {
- let text_style = self.element.style().text_style();
+ pub fn push_text_style<'a: 'b, 'b>(&mut self, cx: &mut impl RenderContext<'a, 'b, V>) -> bool {
+ let text_style = self
+ .element
+ .computed_style(cx.as_view_context())
+ .text_style();
if let Some(text_style) = text_style {
- cx.push_text_style(cx.text_style().refine(text_style));
+ cx.push_text_style(cx.text_style().refined(&text_style));
true
} else {
false
@@ -535,7 +544,7 @@ impl<V: 'static> AnyElement<V> {
from_element: element_layout.as_mut(),
};
- let style = self.element.style();
+ let style = self.element.computed_style(cx.as_view_context());
let fill_color = style.fill.as_ref().and_then(|fill| fill.color());
if let Some(fill_color) = fill_color {
@@ -583,7 +592,11 @@ impl<V: 'static> Element<V> for AnyElement<V> {
type Layout = ();
fn declared_style(&mut self) -> &mut StyleRefinement {
- self.element.style()
+ self.element.declared_style()
+ }
+
+ fn computed_style(&mut self, cx: &mut ViewContext<V>) -> &StyleRefinement {
+ self.element.computed_style(cx)
}
fn handlers_mut(&mut self) -> &mut Vec<EventHandler<V>> {
@@ -48,7 +48,7 @@ impl<V: 'static> Element<V> for Frame<V> {
.collect::<Result<Vec<LayoutNodeId>>>()?;
let rem_size = cx.rem_pixels();
- let style = Style::default().refine(&self.style);
+ let style = Style::default().refined(&self.style);
let node_id = cx
.layout_engine()
.ok_or_else(|| anyhow!("no layout engine"))?
@@ -3,17 +3,15 @@ use std::{cell::Cell, marker::PhantomData, rc::Rc};
use gpui::{
geometry::{rect::RectF, vector::Vector2F},
scene::MouseMove,
- EngineLayout,
+ EngineLayout, ViewContext,
};
+use refineable::Refineable;
-use crate::{
- element::Element,
- style::{Style, StyleRefinement},
-};
+use crate::{element::Element, style::StyleRefinement};
pub struct Hoverable<V, E> {
hover_style: StyleRefinement,
- computed_style: Option<Style>,
+ computed_style: Option<StyleRefinement>,
view_type: PhantomData<V>,
child: E,
}
@@ -36,8 +34,13 @@ impl<V: 'static, E: Element<V>> Element<V> for Hoverable<V, E> {
&mut self.hover_style
}
- fn computed_style(&mut self) -> &StyleRefinement {
- todo!()
+ fn computed_style(&mut self, cx: &mut ViewContext<V>) -> &StyleRefinement {
+ self.computed_style.get_or_insert_with(|| {
+ let mut style = self.child.computed_style(cx).clone();
+ // if hovered
+ style.refine(&self.hover_style);
+ style
+ })
}
fn handlers_mut(&mut self) -> &mut Vec<crate::element::EventHandler<V>> {
@@ -13,7 +13,7 @@ pub struct PaintContext<'a, 'b, 'c, 'd, V> {
pub(crate) scene: &'d mut gpui::SceneBuilder,
}
-impl<V> RenderContext for PaintContext<'_, '_, '_, '_, V> {
+impl<'a, 'b, V> RenderContext<'a, 'b, V> for PaintContext<'a, 'b, '_, '_, V> {
fn text_style(&self) -> gpui::fonts::TextStyle {
self.legacy_cx.text_style()
}
@@ -25,6 +25,10 @@ impl<V> RenderContext for PaintContext<'_, '_, '_, '_, V> {
fn pop_text_style(&mut self) {
self.legacy_cx.pop_text_style()
}
+
+ fn as_view_context(&mut self) -> &mut ViewContext<'a, 'b, V> {
+ &mut self.view_context
+ }
}
impl<'a, 'b, 'c, 'd, V: 'static> PaintContext<'a, 'b, 'c, 'd, V> {
@@ -43,7 +43,7 @@ impl<V: 'static> Element<V> for Text<V> {
let text = self.text.clone();
let layout = Arc::new(Mutex::new(None));
- let style: Style = Style::default().refine(&self.metadata.style);
+ let style: Style = Style::default().refined(&self.metadata.style);
let node_id = layout_engine.add_measured_node(style.to_taffy(rem_size), {
let layout = layout.clone();
move |params| {
@@ -3383,10 +3383,11 @@ impl<V> BorrowWindowContext for ViewContext<'_, '_, V> {
///
/// 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 {
+pub trait RenderContext<'a, 'b, V> {
fn text_style(&self) -> TextStyle;
fn push_text_style(&mut self, style: TextStyle);
fn pop_text_style(&mut self);
+ fn as_view_context(&mut self) -> &mut ViewContext<'a, 'b, V>;
}
pub struct LayoutContext<'a, 'b, 'c, V> {
@@ -3472,7 +3473,7 @@ impl<'a, 'b, 'c, V> LayoutContext<'a, 'b, 'c, V> {
}
}
-impl<'a, 'b, 'c, V> RenderContext for LayoutContext<'a, 'b, 'c, V> {
+impl<'a, 'b, 'c, V> RenderContext<'a, 'b, V> for LayoutContext<'a, 'b, 'c, V> {
fn text_style(&self) -> TextStyle {
self.text_style_stack
.last()
@@ -3487,6 +3488,10 @@ impl<'a, 'b, 'c, V> RenderContext for LayoutContext<'a, 'b, 'c, V> {
fn pop_text_style(&mut self) {
self.text_style_stack.pop();
}
+
+ fn as_view_context(&mut self) -> &mut ViewContext<'a, 'b, V> {
+ &mut self.view_context
+ }
}
impl<'a, 'b, 'c, V> Deref for LayoutContext<'a, 'b, 'c, V> {
@@ -3544,7 +3549,7 @@ impl<V> BorrowWindowContext for LayoutContext<'_, '_, '_, V> {
}
pub struct PaintContext<'a, 'b, 'c, V> {
- view_context: &'c mut ViewContext<'a, 'b, V>,
+ pub view_context: &'c mut ViewContext<'a, 'b, V>,
text_style_stack: Vec<TextStyle>,
}
@@ -3557,7 +3562,7 @@ impl<'a, 'b, 'c, V> PaintContext<'a, 'b, 'c, V> {
}
}
-impl<'a, 'b, 'c, V> RenderContext for PaintContext<'a, 'b, 'c, V> {
+impl<'a, 'b, 'c, V> RenderContext<'a, 'b, V> for PaintContext<'a, 'b, 'c, V> {
fn text_style(&self) -> TextStyle {
self.text_style_stack
.last()
@@ -3572,6 +3577,10 @@ impl<'a, 'b, 'c, V> RenderContext for PaintContext<'a, 'b, 'c, V> {
fn pop_text_style(&mut self) {
self.text_style_stack.pop();
}
+
+ fn as_view_context(&mut self) -> &mut ViewContext<'a, 'b, V> {
+ &mut self.view_context
+ }
}
impl<'a, 'b, 'c, V> Deref for PaintContext<'a, 'b, 'c, V> {
@@ -44,14 +44,14 @@ pub fn derive_refineable(input: TokenStream) -> TokenStream {
paren_token: None,
modifier: syn::TraitBoundModifier::None,
lifetimes: None,
- path: parse_quote!(std::clone::Clone),
+ path: parse_quote!(Clone),
}));
punctuated.push_punct(syn::token::Add::default());
punctuated.push_value(TypeParamBound::Trait(TraitBound {
paren_token: None,
modifier: syn::TraitBoundModifier::None,
lifetimes: None,
- path: parse_quote!(std::default::Default),
+ path: parse_quote!(Default),
}));
punctuated
},
@@ -73,7 +73,7 @@ pub fn derive_refineable(input: TokenStream) -> TokenStream {
},
};
- let field_initializations: Vec<TokenStream2> = fields
+ let field_assignments: Vec<TokenStream2> = fields
.iter()
.map(|field| {
let name = &field.ident;
@@ -82,18 +82,38 @@ pub fn derive_refineable(input: TokenStream) -> TokenStream {
if is_refineable {
quote! {
- clone.#name = self.#name.refine(&refinement.#name);
+ self.#name.refine(&refinement.#name);
}
} else if is_optional {
quote! {
if let Some(ref value) = &refinement.#name {
- clone.#name = Some(value.clone());
+ self.#name = Some(value.clone());
}
}
} else {
quote! {
if let Some(ref value) = &refinement.#name {
- clone.#name = value.clone();
+ self.#name = value.clone();
+ }
+ }
+ }
+ })
+ .collect();
+
+ let refinement_field_assignments: Vec<TokenStream2> = fields
+ .iter()
+ .map(|field| {
+ let name = &field.ident;
+ let is_refineable = is_refineable_field(field);
+
+ if is_refineable {
+ quote! {
+ self.#name.refine(&refinement.#name);
+ }
+ } else {
+ quote! {
+ if let Some(ref value) = &refinement.#name {
+ self.#name = Some(value.clone());
}
}
}
@@ -111,10 +131,18 @@ pub fn derive_refineable(input: TokenStream) -> TokenStream {
{
type Refinement = #refinement_ident #ty_generics;
- fn refine(&self, refinement: &Self::Refinement) -> Self {
- let mut clone = self.clone();
- #( #field_initializations )*
- clone
+ fn refine(&mut self, refinement: &Self::Refinement) {
+ #( #field_assignments )*
+ }
+ }
+
+ impl #impl_generics Refineable for #refinement_ident #ty_generics
+ #where_clause
+ {
+ type Refinement = #refinement_ident #ty_generics;
+
+ fn refine(&mut self, refinement: &Self::Refinement) {
+ #( #refinement_field_assignments )*
}
}
};
@@ -3,11 +3,12 @@ pub use derive_refineable::Refineable;
pub trait Refineable {
type Refinement;
- fn refine(&self, refinement: &Self::Refinement) -> Self;
- fn from_refinement(refinement: &Self::Refinement) -> Self
+ fn refine(&mut self, refinement: &Self::Refinement);
+ fn refined(mut self, refinement: &Self::Refinement) -> Self
where
- Self: Sized + Default,
+ Self: Sized,
{
- Self::default().refine(refinement)
+ self.refine(refinement);
+ self
}
}