@@ -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()
}
}
@@ -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();
@@ -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 )*
+ }
}
}