nested.rs

  1use crate::{
  2    group_bounds, AnyElement, DispatchPhase, Element, IntoAnyElement, MouseMoveEvent, SharedString,
  3    Style, StyleCascade, StyleRefinement,
  4};
  5use refineable::{CascadeSlot, Refineable};
  6use smallvec::SmallVec;
  7use std::sync::{
  8    atomic::{AtomicBool, Ordering::SeqCst},
  9    Arc,
 10};
 11
 12trait LayoutNode<V: 'static + Send + Sync> {
 13    fn state(&mut self) -> &mut LayoutNodeState<V>;
 14
 15    fn child(mut self, child: impl IntoAnyElement<V>) -> Self
 16    where
 17        Self: Sized,
 18    {
 19        self.state().children.push(child.into_any());
 20        self
 21    }
 22
 23    fn children<C, E>(mut self, children: C) -> Self
 24    where
 25        C: IntoIterator<Item = E>,
 26        E: IntoAnyElement<V>,
 27        Self: Sized,
 28    {
 29        for child in children {
 30            self.state().children.push(child.into_any());
 31        }
 32        self
 33    }
 34}
 35
 36struct LayoutNodeState<V: 'static + Send + Sync> {
 37    style_cascade: StyleCascade,
 38    computed_style: Option<Style>,
 39    children: SmallVec<[AnyElement<V>; 2]>,
 40}
 41
 42impl<V> IntoAnyElement<V> for LayoutNodeState<V>
 43where
 44    V: 'static + Send + Sync,
 45{
 46    fn into_any(self) -> AnyElement<V> {
 47        AnyElement::new(self)
 48    }
 49}
 50
 51impl<V: 'static + Send + Sync> Element for LayoutNodeState<V> {
 52    type ViewState = V;
 53    type ElementState = ();
 54
 55    fn element_id(&self) -> Option<crate::ElementId> {
 56        None
 57    }
 58
 59    fn layout(
 60        &mut self,
 61        state: &mut Self::ViewState,
 62        _: Option<Self::ElementState>,
 63        cx: &mut crate::ViewContext<Self::ViewState>,
 64    ) -> (crate::LayoutId, Self::ElementState) {
 65        let layout_ids = self
 66            .children
 67            .iter_mut()
 68            .map(|child| child.layout(state, cx))
 69            .collect::<Vec<_>>();
 70
 71        // todo!("pass just the style cascade")
 72        let style = self.computed_style().clone();
 73        let layout_id = cx.request_layout(style, layout_ids);
 74        (layout_id, ())
 75    }
 76
 77    fn paint(
 78        &mut self,
 79        _: crate::Bounds<crate::Pixels>,
 80        state: &mut Self::ViewState,
 81        _: &mut Self::ElementState,
 82        cx: &mut crate::ViewContext<Self::ViewState>,
 83    ) {
 84        for child in &mut self.children {
 85            child.paint(state, None, cx);
 86        }
 87    }
 88}
 89
 90pub trait Styled {
 91    fn style_cascade(&mut self) -> &mut StyleCascade;
 92    fn computed_style(&mut self) -> &Style;
 93}
 94
 95pub struct StyledElement<E> {
 96    child: E,
 97}
 98
 99impl<E> IntoAnyElement<E::ViewState> for StyledElement<E>
100where
101    E: Element + Styled,
102{
103    fn into_any(self) -> AnyElement<E::ViewState> {
104        AnyElement::new(self)
105    }
106}
107
108impl<E: Element + Styled> Element for StyledElement<E> {
109    type ViewState = E::ViewState;
110    type ElementState = E::ElementState;
111
112    fn element_id(&self) -> Option<crate::ElementId> {
113        self.child.element_id()
114    }
115
116    fn layout(
117        &mut self,
118        state: &mut Self::ViewState,
119        element_state: Option<Self::ElementState>,
120        cx: &mut crate::ViewContext<Self::ViewState>,
121    ) -> (crate::LayoutId, Self::ElementState) {
122        self.child.layout(state, element_state, cx)
123    }
124
125    fn paint(
126        &mut self,
127        bounds: crate::Bounds<crate::Pixels>,
128        state: &mut Self::ViewState,
129        element_state: &mut Self::ElementState,
130        cx: &mut crate::ViewContext<Self::ViewState>,
131    ) {
132        self.child.computed_style().paint(bounds, cx);
133        self.child.paint(bounds, state, element_state, cx);
134    }
135}
136
137pub trait Hoverable {
138    fn hover_style(&mut self) -> &mut StyleRefinement;
139
140    fn hover(mut self, f: impl FnOnce(&mut StyleRefinement) -> &mut StyleRefinement) -> Self
141    where
142        Self: Sized,
143    {
144        f(self.hover_style());
145        self
146    }
147}
148
149struct HoverableElement<Child> {
150    hover_style: StyleRefinement,
151    group: Option<SharedString>,
152    cascade_slot: CascadeSlot,
153    hovered: Arc<AtomicBool>,
154    child: Child,
155}
156
157impl<Child: Styled + Element> HoverableElement<Child> {
158    fn hover_style(&mut self) -> &mut StyleRefinement {
159        &mut self.hover_style
160    }
161}
162
163impl<E> IntoAnyElement<E::ViewState> for HoverableElement<E>
164where
165    E: Element + Styled,
166{
167    fn into_any(self) -> AnyElement<E::ViewState> {
168        AnyElement::new(self)
169    }
170}
171
172impl<E> Element for HoverableElement<E>
173where
174    E: Element + Styled,
175{
176    type ViewState = E::ViewState;
177    type ElementState = E::ElementState;
178
179    fn element_id(&self) -> Option<crate::ElementId> {
180        self.child.element_id()
181    }
182
183    fn layout(
184        &mut self,
185        state: &mut Self::ViewState,
186        element_state: Option<Self::ElementState>,
187        cx: &mut crate::ViewContext<Self::ViewState>,
188    ) -> (crate::LayoutId, Self::ElementState) {
189        self.child.layout(state, element_state, cx)
190    }
191
192    fn paint(
193        &mut self,
194        bounds: crate::Bounds<crate::Pixels>,
195        state: &mut Self::ViewState,
196        element_state: &mut Self::ElementState,
197        cx: &mut crate::ViewContext<Self::ViewState>,
198    ) {
199        let target_bounds = self
200            .group
201            .as_ref()
202            .and_then(|group| group_bounds(group, cx))
203            .unwrap_or(bounds);
204
205        let hovered = target_bounds.contains_point(cx.mouse_position());
206
207        let slot = self.cascade_slot;
208        let style = hovered.then_some(self.hover_style.clone());
209        self.child.style_cascade().set(slot, style);
210        self.hovered.store(hovered, SeqCst);
211
212        let hovered = self.hovered.clone();
213        cx.on_mouse_event(move |_, event: &MouseMoveEvent, phase, cx| {
214            if phase == DispatchPhase::Capture {
215                if target_bounds.contains_point(event.position) != hovered.load(SeqCst) {
216                    cx.notify();
217                }
218            }
219        });
220
221        self.child.paint(bounds, state, element_state, cx);
222    }
223}
224
225struct Div<V: 'static + Send + Sync>(HoverableElement<LayoutNodeState<V>>);
226
227impl<V: 'static + Send + Sync> LayoutNode<V> for Div<V> {
228    fn state(&mut self) -> &mut LayoutNodeState<V> {
229        &mut self.0.child
230    }
231}
232
233impl<V: 'static + Send + Sync> Styled for LayoutNodeState<V> {
234    fn style_cascade(&mut self) -> &mut StyleCascade {
235        &mut self.style_cascade
236    }
237
238    fn computed_style(&mut self) -> &Style {
239        self.computed_style
240            .get_or_insert_with(|| Style::default().refined(self.style_cascade.merged()))
241    }
242}
243
244impl<V: 'static + Send + Sync> Styled for Div<V> {
245    fn style_cascade(&mut self) -> &mut StyleCascade {
246        self.0.child.style_cascade()
247    }
248
249    fn computed_style(&mut self) -> &Style {
250        self.0.child.computed_style()
251    }
252}
253
254impl<V: 'static + Send + Sync> Hoverable for Div<V> {
255    fn hover_style(&mut self) -> &mut StyleRefinement {
256        self.0.hover_style()
257    }
258}