nested.rs

  1use crate::{
  2    group_bounds, AnyElement, DispatchPhase, Element, IdentifiedElement, IntoAnyElement,
  3    MouseDownEvent, MouseMoveEvent, MouseUpEvent, SharedString, Style, StyleCascade,
  4    StyleRefinement, ViewContext,
  5};
  6use parking_lot::Mutex;
  7use refineable::{CascadeSlot, Refineable};
  8use smallvec::SmallVec;
  9use std::sync::{
 10    atomic::{AtomicBool, Ordering::SeqCst},
 11    Arc,
 12};
 13
 14trait LayoutNode<V: 'static + Send + Sync> {
 15    fn state(&mut self) -> &mut LayoutNodeState<V>;
 16
 17    fn child(mut self, child: impl IntoAnyElement<V>) -> Self
 18    where
 19        Self: Sized,
 20    {
 21        self.state().children.push(child.into_any());
 22        self
 23    }
 24
 25    fn children<C, E>(mut self, children: C) -> Self
 26    where
 27        C: IntoIterator<Item = E>,
 28        E: IntoAnyElement<V>,
 29        Self: Sized,
 30    {
 31        for child in children {
 32            self.state().children.push(child.into_any());
 33        }
 34        self
 35    }
 36}
 37
 38struct LayoutNodeState<V: 'static + Send + Sync> {
 39    style_cascade: StyleCascade,
 40    computed_style: Option<Style>,
 41    children: SmallVec<[AnyElement<V>; 2]>,
 42}
 43
 44impl<V> IntoAnyElement<V> for LayoutNodeState<V>
 45where
 46    V: 'static + Send + Sync,
 47{
 48    fn into_any(self) -> AnyElement<V> {
 49        AnyElement::new(self)
 50    }
 51}
 52
 53impl<V: 'static + Send + Sync> Element for LayoutNodeState<V> {
 54    type ViewState = V;
 55    type ElementState = ();
 56
 57    fn element_id(&self) -> Option<crate::ElementId> {
 58        None
 59    }
 60
 61    fn layout(
 62        &mut self,
 63        state: &mut Self::ViewState,
 64        _: Option<Self::ElementState>,
 65        cx: &mut crate::ViewContext<Self::ViewState>,
 66    ) -> (crate::LayoutId, Self::ElementState) {
 67        let layout_ids = self
 68            .children
 69            .iter_mut()
 70            .map(|child| child.layout(state, cx))
 71            .collect::<Vec<_>>();
 72
 73        // todo!("pass just the style cascade")
 74        let style = self.computed_style().clone();
 75        let layout_id = cx.request_layout(style, layout_ids);
 76        (layout_id, ())
 77    }
 78
 79    fn paint(
 80        &mut self,
 81        _: crate::Bounds<crate::Pixels>,
 82        state: &mut Self::ViewState,
 83        _: &mut Self::ElementState,
 84        cx: &mut crate::ViewContext<Self::ViewState>,
 85    ) {
 86        for child in &mut self.children {
 87            child.paint(state, None, cx);
 88        }
 89    }
 90}
 91
 92pub trait Styled {
 93    fn style_cascade(&mut self) -> &mut StyleCascade;
 94    fn computed_style(&mut self) -> &Style;
 95}
 96
 97pub struct StyledElement<E> {
 98    child: E,
 99}
100
101impl<E> IntoAnyElement<E::ViewState> for StyledElement<E>
102where
103    E: Element + Styled,
104{
105    fn into_any(self) -> AnyElement<E::ViewState> {
106        AnyElement::new(self)
107    }
108}
109
110impl<E: Element + Styled> Element for StyledElement<E> {
111    type ViewState = E::ViewState;
112    type ElementState = E::ElementState;
113
114    fn element_id(&self) -> Option<crate::ElementId> {
115        self.child.element_id()
116    }
117
118    fn layout(
119        &mut self,
120        state: &mut Self::ViewState,
121        element_state: Option<Self::ElementState>,
122        cx: &mut crate::ViewContext<Self::ViewState>,
123    ) -> (crate::LayoutId, Self::ElementState) {
124        self.child.layout(state, element_state, cx)
125    }
126
127    fn paint(
128        &mut self,
129        bounds: crate::Bounds<crate::Pixels>,
130        state: &mut Self::ViewState,
131        element_state: &mut Self::ElementState,
132        cx: &mut crate::ViewContext<Self::ViewState>,
133    ) {
134        self.child.computed_style().paint(bounds, cx);
135        self.child.paint(bounds, state, element_state, cx);
136    }
137}
138
139pub trait Hoverable {
140    fn hover_style(&mut self) -> &mut StyleRefinement;
141
142    fn hover(mut self, f: impl FnOnce(&mut StyleRefinement) -> &mut StyleRefinement) -> Self
143    where
144        Self: Sized,
145    {
146        f(self.hover_style());
147        self
148    }
149}
150
151struct HoverableElement<Child> {
152    hover_style: StyleRefinement,
153    group: Option<SharedString>,
154    cascade_slot: CascadeSlot,
155    hovered: Arc<AtomicBool>,
156    child: Child,
157}
158
159impl<Child: Styled + Element> HoverableElement<Child> {
160    fn hover_style(&mut self) -> &mut StyleRefinement {
161        &mut self.hover_style
162    }
163}
164
165impl<E> IntoAnyElement<E::ViewState> for HoverableElement<E>
166where
167    E: Element + Styled,
168{
169    fn into_any(self) -> AnyElement<E::ViewState> {
170        AnyElement::new(self)
171    }
172}
173
174impl<E> Element for HoverableElement<E>
175where
176    E: Element + Styled,
177{
178    type ViewState = E::ViewState;
179    type ElementState = E::ElementState;
180
181    fn element_id(&self) -> Option<crate::ElementId> {
182        self.child.element_id()
183    }
184
185    fn layout(
186        &mut self,
187        state: &mut Self::ViewState,
188        element_state: Option<Self::ElementState>,
189        cx: &mut crate::ViewContext<Self::ViewState>,
190    ) -> (crate::LayoutId, Self::ElementState) {
191        self.child.layout(state, element_state, cx)
192    }
193
194    fn paint(
195        &mut self,
196        bounds: crate::Bounds<crate::Pixels>,
197        state: &mut Self::ViewState,
198        element_state: &mut Self::ElementState,
199        cx: &mut crate::ViewContext<Self::ViewState>,
200    ) {
201        let target_bounds = self
202            .group
203            .as_ref()
204            .and_then(|group| group_bounds(group, cx))
205            .unwrap_or(bounds);
206
207        let hovered = target_bounds.contains_point(cx.mouse_position());
208
209        let slot = self.cascade_slot;
210        let style = hovered.then_some(self.hover_style.clone());
211        self.child.style_cascade().set(slot, style);
212        self.hovered.store(hovered, SeqCst);
213
214        let hovered = self.hovered.clone();
215        cx.on_mouse_event(move |_, event: &MouseMoveEvent, phase, cx| {
216            if phase == DispatchPhase::Capture {
217                if target_bounds.contains_point(event.position) != hovered.load(SeqCst) {
218                    cx.notify();
219                }
220            }
221        });
222
223        self.child.paint(bounds, state, element_state, cx);
224    }
225}
226
227pub trait Clickable: IdentifiedElement + Sized {
228    fn active_style(&mut self) -> &mut StyleRefinement;
229    fn listeners(&mut self) -> &mut ClickListeners<Self::ViewState>;
230
231    fn on_click(
232        &mut self,
233        f: impl Fn(&mut Self::ViewState, &MouseClickEvent, &mut ViewContext<Self::ViewState>)
234            + 'static
235            + Send
236            + Sync,
237    ) where
238        Self: Sized,
239    {
240        self.listeners().push(Arc::new(f));
241    }
242
243    fn active(mut self, f: impl FnOnce(&mut StyleRefinement) -> &mut StyleRefinement) -> Self
244    where
245        Self: Sized,
246    {
247        f(self.active_style());
248        self
249    }
250}
251
252type ClickListeners<V> =
253    SmallVec<[Arc<dyn Fn(&mut V, &MouseClickEvent, &mut ViewContext<V>) + Send + Sync>; 1]>;
254
255pub struct ClickableElementState<E: IdentifiedElement> {
256    mouse_down: Arc<Mutex<Option<MouseDownEvent>>>,
257    child_state: E::ElementState,
258}
259
260pub struct MouseClickEvent {
261    down: MouseDownEvent,
262    up: MouseUpEvent,
263}
264
265pub struct ClickableElement<E: IdentifiedElement> {
266    child: E,
267    listeners: ClickListeners<E::ViewState>,
268    active_style: StyleRefinement,
269    cascade_slot: CascadeSlot,
270}
271
272impl<E> IntoAnyElement<E::ViewState> for ClickableElement<E>
273where
274    E: IdentifiedElement + Styled,
275{
276    fn into_any(self) -> AnyElement<E::ViewState> {
277        AnyElement::new(self)
278    }
279}
280
281impl<E> Element for ClickableElement<E>
282where
283    E: IdentifiedElement + Styled,
284{
285    type ViewState = E::ViewState;
286    type ElementState = ClickableElementState<E>;
287
288    fn element_id(&self) -> Option<crate::ElementId> {
289        Some(IdentifiedElement::element_id(&self.child))
290    }
291
292    fn layout(
293        &mut self,
294        state: &mut Self::ViewState,
295        element_state: Option<Self::ElementState>,
296        cx: &mut crate::ViewContext<Self::ViewState>,
297    ) -> (crate::LayoutId, Self::ElementState) {
298        if let Some(element_state) = element_state {
299            if element_state.mouse_down.lock().is_some() {
300                self.child
301                    .style_cascade()
302                    .set(self.cascade_slot, Some(self.active_style.clone()));
303            }
304
305            let (layout_id, child_state) =
306                self.child
307                    .layout(state, Some(element_state.child_state), cx);
308            (
309                layout_id,
310                ClickableElementState {
311                    mouse_down: element_state.mouse_down,
312                    child_state,
313                },
314            )
315        } else {
316            let (layout_id, child_state) = self.child.layout(state, None, cx);
317            (
318                layout_id,
319                ClickableElementState {
320                    mouse_down: Default::default(),
321                    child_state,
322                },
323            )
324        }
325    }
326
327    fn paint(
328        &mut self,
329        bounds: crate::Bounds<crate::Pixels>,
330        state: &mut Self::ViewState,
331        element_state: &mut Self::ElementState,
332        cx: &mut crate::ViewContext<Self::ViewState>,
333    ) {
334        if !self.listeners.is_empty() || self.active_style.is_some() {
335            if let Some(mouse_down) = element_state.mouse_down.lock().clone() {
336                self.child
337                    .style_cascade()
338                    .set(self.cascade_slot, Some(self.active_style.clone()));
339                let listeners = self.listeners.clone();
340                let mouse_down_mutex = element_state.mouse_down.clone();
341                cx.on_mouse_event(move |view, up: &MouseUpEvent, phase, cx| {
342                    if phase == DispatchPhase::Bubble && bounds.contains_point(up.position) {
343                        for listener in &*listeners {
344                            listener(
345                                view,
346                                &MouseClickEvent {
347                                    down: mouse_down.clone(),
348                                    up: up.clone(),
349                                },
350                                cx,
351                            );
352                        }
353                    }
354
355                    mouse_down_mutex.lock().take();
356                    cx.notify();
357                });
358            } else {
359                let mouse_down_mutex = element_state.mouse_down.clone();
360                cx.on_mouse_event(move |_view, down: &MouseDownEvent, phase, cx| {
361                    if phase == DispatchPhase::Bubble && bounds.contains_point(down.position) {
362                        *mouse_down_mutex.lock() = Some(down.clone());
363                        cx.notify();
364                    }
365                });
366            }
367        }
368
369        self.child
370            .paint(bounds, state, &mut element_state.child_state, cx);
371    }
372}
373
374struct Div<V: 'static + Send + Sync>(HoverableElement<LayoutNodeState<V>>);
375
376impl<V: 'static + Send + Sync> LayoutNode<V> for Div<V> {
377    fn state(&mut self) -> &mut LayoutNodeState<V> {
378        &mut self.0.child
379    }
380}
381
382impl<V: 'static + Send + Sync> Styled for LayoutNodeState<V> {
383    fn style_cascade(&mut self) -> &mut StyleCascade {
384        &mut self.style_cascade
385    }
386
387    fn computed_style(&mut self) -> &Style {
388        self.computed_style
389            .get_or_insert_with(|| Style::default().refined(self.style_cascade.merged()))
390    }
391}
392
393impl<V: 'static + Send + Sync> Styled for Div<V> {
394    fn style_cascade(&mut self) -> &mut StyleCascade {
395        self.0.child.style_cascade()
396    }
397
398    fn computed_style(&mut self) -> &Style {
399        self.0.child.computed_style()
400    }
401}
402
403impl<V: 'static + Send + Sync> Hoverable for Div<V> {
404    fn hover_style(&mut self) -> &mut StyleRefinement {
405        self.0.hover_style()
406    }
407}