WIP

Antonio Scandurra created

Change summary

crates/gpui3/src/elements/nested.rs                          | 139 +++++
crates/gpui3/src/geometry.rs                                 |   6 
crates/gpui3/src/styled.rs                                   |   5 
crates/refineable/derive_refineable/src/derive_refineable.rs | 102 ++++
crates/refineable/src/refineable.rs                          |  16 
5 files changed, 239 insertions(+), 29 deletions(-)

Detailed changes

crates/gpui3/src/elements/nested.rs 🔗

@@ -1,6 +1,13 @@
-use crate::{AnyElement, Element, IntoAnyElement, Style, StyleCascade, StyleRefinement};
-use refineable::Refineable;
+use crate::{
+    group_bounds, AnyElement, DispatchPhase, Element, IntoAnyElement, MouseMoveEvent, SharedString,
+    Style, StyleCascade, StyleRefinement,
+};
+use refineable::CascadeSlot;
 use smallvec::SmallVec;
+use std::sync::{
+    atomic::{AtomicBool, Ordering::SeqCst},
+    Arc,
+};
 
 trait LayoutNode<V: 'static + Send + Sync> {
     fn state(&mut self) -> &mut LayoutNodeState<V>;
@@ -28,6 +35,7 @@ trait LayoutNode<V: 'static + Send + Sync> {
 
 struct LayoutNodeState<V: 'static + Send + Sync> {
     style_cascade: StyleCascade,
+    computed_style: Option<Style>,
     children: SmallVec<[AnyElement<V>; 2]>,
 }
 
@@ -61,7 +69,7 @@ impl<V: 'static + Send + Sync> Element for LayoutNodeState<V> {
             .collect::<Vec<_>>();
 
         // todo!("pass just the style cascade")
-        let style = Style::from_refinement(&self.style_cascade().merged());
+        let style = self.computed_style().clone();
         let layout_id = cx.request_layout(style, layout_ids);
         (layout_id, ())
     }
@@ -81,6 +89,49 @@ impl<V: 'static + Send + Sync> Element for LayoutNodeState<V> {
 
 pub trait Styled {
     fn style_cascade(&mut self) -> &mut StyleCascade;
+    fn computed_style(&mut self) -> &Style;
+}
+
+pub struct StyledElement<E> {
+    child: E,
+}
+
+impl<E> IntoAnyElement<E::ViewState> for StyledElement<E>
+where
+    E: Element + Styled,
+{
+    fn into_any(self) -> AnyElement<E::ViewState> {
+        AnyElement::new(self)
+    }
+}
+
+impl<E: Element + Styled> Element for StyledElement<E> {
+    type ViewState = E::ViewState;
+    type ElementState = E::ElementState;
+
+    fn element_id(&self) -> Option<crate::ElementId> {
+        self.child.element_id()
+    }
+
+    fn layout(
+        &mut self,
+        state: &mut Self::ViewState,
+        element_state: Option<Self::ElementState>,
+        cx: &mut crate::ViewContext<Self::ViewState>,
+    ) -> (crate::LayoutId, Self::ElementState) {
+        self.child.layout(state, element_state, cx)
+    }
+
+    fn paint(
+        &mut self,
+        bounds: crate::Bounds<crate::Pixels>,
+        state: &mut Self::ViewState,
+        element_state: &mut Self::ElementState,
+        cx: &mut crate::ViewContext<Self::ViewState>,
+    ) {
+        self.child.computed_style().paint(bounds, cx);
+        self.child.paint(bounds, state, element_state, cx);
+    }
 }
 
 pub trait Hoverable {
@@ -95,18 +146,83 @@ pub trait Hoverable {
     }
 }
 
-struct HoverableState<Child: Styled + Element> {
+struct HoverableElement<Child> {
     hover_style: StyleRefinement,
+    group: Option<SharedString>,
+    cascade_slot: CascadeSlot,
+    hovered: Arc<AtomicBool>,
     child: Child,
 }
 
-impl<Child: Styled + Element> HoverableState<Child> {
+impl<Child: Styled + Element> HoverableElement<Child> {
     fn hover_style(&mut self) -> &mut StyleRefinement {
         &mut self.hover_style
     }
 }
 
-struct Div<V: 'static + Send + Sync>(HoverableState<LayoutNodeState<V>>);
+impl<E> IntoAnyElement<E::ViewState> for HoverableElement<E>
+where
+    E: Element + Styled,
+{
+    fn into_any(self) -> AnyElement<E::ViewState> {
+        AnyElement::new(self)
+    }
+}
+
+impl<E> Element for HoverableElement<E>
+where
+    E: Element + Styled,
+{
+    type ViewState = E::ViewState;
+    type ElementState = E::ElementState;
+
+    fn element_id(&self) -> Option<crate::ElementId> {
+        self.child.element_id()
+    }
+
+    fn layout(
+        &mut self,
+        state: &mut Self::ViewState,
+        element_state: Option<Self::ElementState>,
+        cx: &mut crate::ViewContext<Self::ViewState>,
+    ) -> (crate::LayoutId, Self::ElementState) {
+        self.child.layout(state, element_state, cx)
+    }
+
+    fn paint(
+        &mut self,
+        bounds: crate::Bounds<crate::Pixels>,
+        state: &mut Self::ViewState,
+        element_state: &mut Self::ElementState,
+        cx: &mut crate::ViewContext<Self::ViewState>,
+    ) {
+        let target_bounds = self
+            .group
+            .as_ref()
+            .and_then(|group| group_bounds(group, cx))
+            .unwrap_or(bounds);
+
+        let hovered = target_bounds.contains_point(cx.mouse_position());
+
+        let slot = self.cascade_slot;
+        let style = hovered.then_some(self.hover_style.clone());
+        self.child.style_cascade().set(slot, style);
+        self.hovered.store(hovered, SeqCst);
+
+        let hovered = self.hovered.clone();
+        cx.on_mouse_event(move |_, event: &MouseMoveEvent, phase, cx| {
+            if phase == DispatchPhase::Capture {
+                if target_bounds.contains_point(event.position) != hovered.load(SeqCst) {
+                    cx.notify();
+                }
+            }
+        });
+
+        self.child.paint(bounds, state, element_state, cx);
+    }
+}
+
+struct Div<V: 'static + Send + Sync>(HoverableElement<LayoutNodeState<V>>);
 
 impl<V: 'static + Send + Sync> LayoutNode<V> for Div<V> {
     fn state(&mut self) -> &mut LayoutNodeState<V> {
@@ -118,11 +234,20 @@ impl<V: 'static + Send + Sync> Styled for LayoutNodeState<V> {
     fn style_cascade(&mut self) -> &mut StyleCascade {
         &mut self.style_cascade
     }
+
+    fn computed_style(&mut self) -> &Style {
+        self.computed_style
+            .get_or_insert_with(|| Style::from(self.style_cascade.merged()))
+    }
 }
 
 impl<V: 'static + Send + Sync> Styled for Div<V> {
     fn style_cascade(&mut self) -> &mut StyleCascade {
-        &mut self.0.child.style_cascade
+        self.0.child.style_cascade()
+    }
+
+    fn computed_style(&mut self) -> &Style {
+        self.0.child.computed_style()
     }
 }
 

crates/gpui3/src/geometry.rs 🔗

@@ -244,12 +244,12 @@ impl Size<Length> {
 #[derive(Refineable, Clone, Default, Debug, Eq, PartialEq)]
 #[refineable(debug)]
 #[repr(C)]
-pub struct Bounds<T: Clone + Debug> {
+pub struct Bounds<T: Clone + Debug + Default> {
     pub origin: Point<T>,
     pub size: Size<T>,
 }
 
-impl<T: Clone + Debug + Sub<Output = T>> Bounds<T> {
+impl<T: Clone + Debug + Sub<Output = T> + Default> Bounds<T> {
     pub fn from_corners(upper_left: Point<T>, lower_right: Point<T>) -> Self {
         let origin = Point {
             x: upper_left.x.clone(),
@@ -263,7 +263,7 @@ impl<T: Clone + Debug + Sub<Output = T>> Bounds<T> {
     }
 }
 
-impl<T: Clone + Debug + PartialOrd + Add<T, Output = T> + Sub<Output = T>> Bounds<T> {
+impl<T: Clone + Debug + PartialOrd + Add<T, Output = T> + Sub<Output = T> + Default> Bounds<T> {
     pub fn intersects(&self, other: &Bounds<T>) -> bool {
         let my_lower_right = self.lower_right();
         let their_lower_right = other.lower_right();

crates/gpui3/src/styled.rs 🔗

@@ -7,7 +7,10 @@ pub trait Styled {
     fn declared_style(&mut self) -> &mut <Self::Style as Refineable>::Refinement;
 
     fn computed_style(&mut self) -> Self::Style {
-        Self::Style::from_refinement(&self.style_cascade().merged())
+        todo!()
+        // let x: StyleRefinement = self.style_cascade().merged();
+
+        // x.into();
     }
 
     fn hover(self) -> Hoverable<Self>

crates/refineable/derive_refineable/src/derive_refineable.rs 🔗

@@ -79,7 +79,11 @@ pub fn derive_refineable(input: TokenStream) -> TokenStream {
         },
     };
 
-    let field_assignments: Vec<TokenStream2> = fields
+    // refinable_refine_assignments
+    // refinable_refined_assignments
+    // refinement_refine_assignments
+
+    let refineable_refine_assignments: Vec<TokenStream2> = fields
         .iter()
         .map(|field| {
             let name = &field.ident;
@@ -106,7 +110,34 @@ pub fn derive_refineable(input: TokenStream) -> TokenStream {
         })
         .collect();
 
-    let refinement_field_assignments: Vec<TokenStream2> = fields
+    let refineable_refined_assignments: Vec<TokenStream2> = fields
+        .iter()
+        .map(|field| {
+            let name = &field.ident;
+            let is_refineable = is_refineable_field(field);
+            let is_optional = is_optional_field(field);
+
+            if is_refineable {
+                quote! {
+                    self.#name = self.#name.refined(refinement.#name);
+                }
+            } else if is_optional {
+                quote! {
+                    if let Some(value) = refinement.#name {
+                        self.#name = Some(value);
+                    }
+                }
+            } else {
+                quote! {
+                    if let Some(value) = refinement.#name {
+                        self.#name = value;
+                    }
+                }
+            }
+        })
+        .collect();
+
+    let refinement_refine_assigments: Vec<TokenStream2> = fields
         .iter()
         .map(|field| {
             let name = &field.ident;
@@ -126,6 +157,49 @@ pub fn derive_refineable(input: TokenStream) -> TokenStream {
         })
         .collect();
 
+    let refinement_refined_assigments: Vec<TokenStream2> = fields
+        .iter()
+        .map(|field| {
+            let name = &field.ident;
+            let is_refineable = is_refineable_field(field);
+
+            if is_refineable {
+                quote! {
+                    self.#name = self.#name.refined(refinement.#name);
+                }
+            } else {
+                quote! {
+                    if let Some(value) = refinement.#name {
+                        self.#name = Some(value);
+                    }
+                }
+            }
+        })
+        .collect();
+
+    let from_refinement_assigments: Vec<TokenStream2> = fields
+        .iter()
+        .map(|field| {
+            let name = &field.ident;
+            let is_refineable = is_refineable_field(field);
+            let is_optional = is_optional_field(field);
+
+            if is_refineable {
+                quote! {
+                    #name: value.#name.into(),
+                }
+            } else if is_optional {
+                quote! {
+                    #name: value.#name.map(|v| v.into()),
+                }
+            } else {
+                quote! {
+                    #name: value.#name.map(|v| v.into()).unwrap_or_default(),
+                }
+            }
+        })
+        .collect();
+
     let debug_impl = if impl_debug_on_refinement {
         let refinement_field_debugs: Vec<TokenStream2> = fields
             .iter()
@@ -173,7 +247,12 @@ pub fn derive_refineable(input: TokenStream) -> TokenStream {
             type Refinement = #refinement_ident #ty_generics;
 
             fn refine(&mut self, refinement: &Self::Refinement) {
-                #( #field_assignments )*
+                #( #refineable_refine_assignments )*
+            }
+
+            fn refined(mut self, refinement: Self::Refinement) -> Self {
+                #( #refineable_refined_assignments )*
+                self
             }
         }
 
@@ -183,7 +262,22 @@ pub fn derive_refineable(input: TokenStream) -> TokenStream {
             type Refinement = #refinement_ident #ty_generics;
 
             fn refine(&mut self, refinement: &Self::Refinement) {
-                #( #refinement_field_assignments )*
+                #( #refinement_refine_assigments )*
+            }
+
+            fn refined(mut self, refinement: Self::Refinement) -> Self {
+                #( #refinement_refined_assigments )*
+                self
+            }
+        }
+
+        impl #impl_generics From<#refinement_ident #ty_generics> for #ident #ty_generics
+            #where_clause
+        {
+            fn from(value: #refinement_ident #ty_generics) -> Self {
+                Self {
+                    #( #from_refinement_assigments )*
+                }
             }
         }
 

crates/refineable/src/refineable.rs 🔗

@@ -4,24 +4,12 @@ pub trait Refineable: Clone {
     type Refinement: Refineable<Refinement = Self::Refinement> + Default;
 
     fn refine(&mut self, refinement: &Self::Refinement);
-    fn refined(mut self, refinement: &Self::Refinement) -> Self
-    where
-        Self: Sized,
-    {
-        self.refine(refinement);
-        self
-    }
-    fn from_refinement(refinement: &Self::Refinement) -> Self
-    where
-        Self: Default + Sized,
-    {
-        Self::default().refined(refinement)
-    }
+    fn refined(self, refinement: Self::Refinement) -> Self;
     fn from_cascade(cascade: &Cascade<Self>) -> Self
     where
         Self: Default + Sized,
     {
-        Self::default().refined(&cascade.merged())
+        Self::default().refined(cascade.merged())
     }
 }