nested.rs

  1use crate::{
  2    group_bounds, AnyElement, BorrowWindow, Bounds, DispatchPhase, Element, ElementId,
  3    IdentifiedElement, IntoAnyElement, MouseDownEvent, MouseMoveEvent, MouseUpEvent, SharedString,
  4    Style, StyleCascade, 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, K: ElementKind> {
 15    fn state(&mut self) -> &mut LayoutNodeElement<V, K>;
 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
 38pub trait ElementKind: 'static + Send + Sync {
 39    fn id(&self) -> Option<ElementId>;
 40}
 41
 42pub struct Identified(ElementId);
 43pub struct Anonymous;
 44
 45impl ElementKind for Identified {
 46    fn id(&self) -> Option<ElementId> {
 47        Some(self.0.clone())
 48    }
 49}
 50
 51impl ElementKind for Anonymous {
 52    fn id(&self) -> Option<ElementId> {
 53        None
 54    }
 55}
 56
 57struct LayoutNodeElement<V: 'static + Send + Sync, K: ElementKind> {
 58    style_cascade: StyleCascade,
 59    computed_style: Option<Style>,
 60    children: SmallVec<[AnyElement<V>; 2]>,
 61    kind: K,
 62}
 63
 64impl<V: 'static + Send + Sync> LayoutNodeElement<V, Anonymous> {
 65    pub fn identify(self, id: impl Into<ElementId>) -> LayoutNodeElement<V, Identified> {
 66        LayoutNodeElement {
 67            style_cascade: self.style_cascade,
 68            computed_style: self.computed_style,
 69            children: self.children,
 70            kind: Identified(id.into()),
 71        }
 72    }
 73}
 74
 75impl<V: 'static + Send + Sync, E: ElementKind> LayoutNodeElement<V, E> {
 76    fn with_element_id<R>(
 77        &mut self,
 78        cx: &mut ViewContext<V>,
 79        f: impl FnOnce(&mut Self, &mut ViewContext<V>) -> R,
 80    ) -> R {
 81        if let Some(id) = self.id() {
 82            cx.with_element_id(id, |cx| f(self, cx))
 83        } else {
 84            f(self, cx)
 85        }
 86    }
 87}
 88
 89impl<V: 'static + Send + Sync, K: ElementKind> Styled for LayoutNodeElement<V, K> {
 90    fn style_cascade(&mut self) -> &mut StyleCascade {
 91        &mut self.style_cascade
 92    }
 93
 94    fn computed_style(&mut self) -> &Style {
 95        self.computed_style
 96            .get_or_insert_with(|| Style::default().refined(self.style_cascade.merged()))
 97    }
 98}
 99
100impl<V: 'static + Send + Sync> IdentifiedElement for LayoutNodeElement<V, Identified> {
101    fn element_id(&self) -> ElementId {
102        self.kind.0.clone()
103    }
104}
105
106impl<V, K> IntoAnyElement<V> for LayoutNodeElement<V, K>
107where
108    V: 'static + Send + Sync,
109    K: ElementKind,
110{
111    fn into_any(self) -> AnyElement<V> {
112        AnyElement::new(self)
113    }
114}
115
116impl<V: 'static + Send + Sync, K: ElementKind> Element for LayoutNodeElement<V, K> {
117    type ViewState = V;
118    type ElementState = ();
119
120    fn id(&self) -> Option<ElementId> {
121        self.kind.id()
122    }
123
124    fn layout(
125        &mut self,
126        state: &mut Self::ViewState,
127        _: Option<Self::ElementState>,
128        cx: &mut ViewContext<Self::ViewState>,
129    ) -> (crate::LayoutId, Self::ElementState) {
130        self.with_element_id(cx, |this, cx| {
131            let layout_ids = this
132                .children
133                .iter_mut()
134                .map(|child| child.layout(state, cx))
135                .collect::<Vec<_>>();
136
137            let style = this.computed_style();
138            let layout_id = cx.request_layout(style, layout_ids);
139            (layout_id, ())
140        })
141    }
142
143    fn paint(
144        &mut self,
145        bounds: Bounds<crate::Pixels>,
146        state: &mut Self::ViewState,
147        _: &mut Self::ElementState,
148        cx: &mut ViewContext<Self::ViewState>,
149    ) {
150        self.with_element_id(cx, |this, cx| {
151            let style = this.computed_style().clone();
152            let z_index = style.z_index.unwrap_or(0);
153            cx.stack(z_index, |cx| style.paint(bounds, cx));
154
155            // todo!("implement overflow")
156            // let overflow = &style.overflow;
157
158            style.apply_text_style(cx, |cx| {
159                cx.stack(z_index + 1, |cx| {
160                    style.apply_overflow(bounds, cx, |cx| {
161                        for child in &mut this.children {
162                            child.paint(state, None, cx);
163                        }
164                    })
165                })
166            });
167        })
168    }
169}
170
171pub trait Styled {
172    fn style_cascade(&mut self) -> &mut StyleCascade;
173    fn computed_style(&mut self) -> &Style;
174}
175
176pub trait Hoverable {
177    fn hover_style(&mut self) -> &mut StyleRefinement;
178
179    fn hover(mut self, f: impl FnOnce(&mut StyleRefinement) -> &mut StyleRefinement) -> Self
180    where
181        Self: Sized,
182    {
183        f(self.hover_style());
184        self
185    }
186}
187
188struct HoverableElement<E> {
189    hover_style: StyleRefinement,
190    group: Option<SharedString>,
191    cascade_slot: CascadeSlot,
192    hovered: Arc<AtomicBool>,
193    child: E,
194}
195
196impl<E: Styled + Element> HoverableElement<E> {
197    pub fn replace_child<E2: Element<ViewState = E::ViewState>>(
198        self,
199        replace: impl FnOnce(E) -> E2,
200    ) -> HoverableElement<E2> {
201        HoverableElement {
202            hover_style: self.hover_style,
203            group: self.group,
204            cascade_slot: self.cascade_slot,
205            hovered: self.hovered,
206            child: replace(self.child),
207        }
208    }
209
210    fn hover_style(&mut self) -> &mut StyleRefinement {
211        &mut self.hover_style
212    }
213}
214
215impl<E> IntoAnyElement<E::ViewState> for HoverableElement<E>
216where
217    E: Styled + Element,
218{
219    fn into_any(self) -> AnyElement<E::ViewState> {
220        AnyElement::new(self)
221    }
222}
223
224impl<E> Element for HoverableElement<E>
225where
226    E: Styled + Element,
227{
228    type ViewState = E::ViewState;
229    type ElementState = E::ElementState;
230
231    fn id(&self) -> Option<ElementId> {
232        self.child.id()
233    }
234
235    fn layout(
236        &mut self,
237        state: &mut Self::ViewState,
238        element_state: Option<Self::ElementState>,
239        cx: &mut ViewContext<Self::ViewState>,
240    ) -> (crate::LayoutId, Self::ElementState) {
241        self.child.layout(state, element_state, cx)
242    }
243
244    fn paint(
245        &mut self,
246        bounds: Bounds<crate::Pixels>,
247        state: &mut Self::ViewState,
248        element_state: &mut Self::ElementState,
249        cx: &mut ViewContext<Self::ViewState>,
250    ) {
251        let target_bounds = self
252            .group
253            .as_ref()
254            .and_then(|group| group_bounds(group, cx))
255            .unwrap_or(bounds);
256
257        let hovered = target_bounds.contains_point(cx.mouse_position());
258
259        let slot = self.cascade_slot;
260        let style = hovered.then_some(self.hover_style.clone());
261        self.child.style_cascade().set(slot, style);
262        self.hovered.store(hovered, SeqCst);
263
264        let hovered = self.hovered.clone();
265        cx.on_mouse_event(move |_, event: &MouseMoveEvent, phase, cx| {
266            if phase == DispatchPhase::Capture {
267                if target_bounds.contains_point(event.position) != hovered.load(SeqCst) {
268                    cx.notify();
269                }
270            }
271        });
272
273        self.child.paint(bounds, state, element_state, cx);
274    }
275}
276
277impl<E: Styled + Element> Styled for HoverableElement<E> {
278    fn style_cascade(&mut self) -> &mut StyleCascade {
279        self.child.style_cascade()
280    }
281
282    fn computed_style(&mut self) -> &Style {
283        self.child.computed_style()
284    }
285}
286
287impl<E: Styled + IdentifiedElement> IdentifiedElement for HoverableElement<E> {}
288
289pub trait Clickable: Element + Sized {
290    fn active_style(&mut self) -> &mut StyleRefinement;
291    fn listeners(&mut self) -> &mut ClickListeners<Self::ViewState>;
292
293    fn on_click(
294        &mut self,
295        f: impl Fn(&mut Self::ViewState, &MouseClickEvent, &mut ViewContext<Self::ViewState>)
296            + 'static
297            + Send
298            + Sync,
299    ) where
300        Self: Sized,
301    {
302        self.listeners().push(Arc::new(f));
303    }
304
305    fn active(mut self, f: impl FnOnce(&mut StyleRefinement) -> &mut StyleRefinement) -> Self
306    where
307        Self: Sized,
308    {
309        f(self.active_style());
310        self
311    }
312}
313
314type ClickListeners<V> =
315    SmallVec<[Arc<dyn Fn(&mut V, &MouseClickEvent, &mut ViewContext<V>) + Send + Sync>; 1]>;
316
317pub struct ClickableElementState<E: 'static + Send + Sync> {
318    mouse_down: Arc<Mutex<Option<MouseDownEvent>>>,
319    child_state: E,
320}
321
322pub struct MouseClickEvent {
323    pub down: MouseDownEvent,
324    pub up: MouseUpEvent,
325}
326
327pub struct ClickableElement<E: Element> {
328    child: E,
329    listeners: ClickListeners<E::ViewState>,
330    active_style: StyleRefinement,
331    cascade_slot: CascadeSlot,
332}
333
334impl<E: Element> ClickableElement<E> {
335    pub fn replace_child<E2: Element<ViewState = E::ViewState>>(
336        self,
337        replace: impl FnOnce(E) -> E2,
338    ) -> ClickableElement<E2> {
339        ClickableElement {
340            child: replace(self.child),
341            listeners: self.listeners,
342            active_style: self.active_style,
343            cascade_slot: self.cascade_slot,
344        }
345    }
346}
347
348impl<E> IntoAnyElement<E::ViewState> for ClickableElement<E>
349where
350    E: Styled + Element,
351{
352    fn into_any(self) -> AnyElement<E::ViewState> {
353        AnyElement::new(self)
354    }
355}
356
357impl<E> Element for ClickableElement<E>
358where
359    E: Styled + Element,
360{
361    type ViewState = E::ViewState;
362    type ElementState = ClickableElementState<E::ElementState>;
363
364    fn id(&self) -> Option<ElementId> {
365        self.child.id()
366    }
367
368    fn layout(
369        &mut self,
370        state: &mut Self::ViewState,
371        element_state: Option<Self::ElementState>,
372        cx: &mut ViewContext<Self::ViewState>,
373    ) -> (crate::LayoutId, Self::ElementState) {
374        if let Some(element_state) = element_state {
375            if element_state.mouse_down.lock().is_some() {
376                self.child
377                    .style_cascade()
378                    .set(self.cascade_slot, Some(self.active_style.clone()));
379            }
380
381            let (layout_id, child_state) =
382                self.child
383                    .layout(state, Some(element_state.child_state), cx);
384            (
385                layout_id,
386                ClickableElementState {
387                    mouse_down: element_state.mouse_down,
388                    child_state,
389                },
390            )
391        } else {
392            let (layout_id, child_state) = self.child.layout(state, None, cx);
393            (
394                layout_id,
395                ClickableElementState {
396                    mouse_down: Default::default(),
397                    child_state,
398                },
399            )
400        }
401    }
402
403    fn paint(
404        &mut self,
405        bounds: Bounds<crate::Pixels>,
406        state: &mut Self::ViewState,
407        element_state: &mut Self::ElementState,
408        cx: &mut ViewContext<Self::ViewState>,
409    ) {
410        if !self.listeners.is_empty() || self.active_style.is_some() {
411            if let Some(mouse_down) = element_state.mouse_down.lock().clone() {
412                self.child
413                    .style_cascade()
414                    .set(self.cascade_slot, Some(self.active_style.clone()));
415                let listeners = self.listeners.clone();
416                let mouse_down_mutex = element_state.mouse_down.clone();
417                cx.on_mouse_event(move |view, up: &MouseUpEvent, phase, cx| {
418                    if phase == DispatchPhase::Bubble && bounds.contains_point(up.position) {
419                        for listener in &*listeners {
420                            listener(
421                                view,
422                                &MouseClickEvent {
423                                    down: mouse_down.clone(),
424                                    up: up.clone(),
425                                },
426                                cx,
427                            );
428                        }
429                    }
430
431                    mouse_down_mutex.lock().take();
432                    cx.notify();
433                });
434            } else {
435                let mouse_down_mutex = element_state.mouse_down.clone();
436                cx.on_mouse_event(move |_view, down: &MouseDownEvent, phase, cx| {
437                    if phase == DispatchPhase::Bubble && bounds.contains_point(down.position) {
438                        *mouse_down_mutex.lock() = Some(down.clone());
439                        cx.notify();
440                    }
441                });
442            }
443        }
444
445        self.child
446            .paint(bounds, state, &mut element_state.child_state, cx);
447    }
448}
449
450impl<E: Styled + IdentifiedElement> IdentifiedElement for ClickableElement<E> {}
451
452impl<E> Clickable for ClickableElement<E>
453where
454    E: Styled + IdentifiedElement,
455{
456    fn active_style(&mut self) -> &mut StyleRefinement {
457        &mut self.active_style
458    }
459
460    fn listeners(&mut self) -> &mut ClickListeners<Self::ViewState> {
461        &mut self.listeners
462    }
463}
464
465pub struct Div<V: 'static + Send + Sync, K: ElementKind>(
466    ClickableElement<HoverableElement<LayoutNodeElement<V, K>>>,
467);
468
469impl<V: 'static + Send + Sync> Div<V, Anonymous> {
470    pub fn id(self, id: impl Into<ElementId>) -> Div<V, Identified> {
471        Div(self.0.replace_child(|hoverable| {
472            hoverable.replace_child(|layout_node| layout_node.identify(id))
473        }))
474    }
475}
476
477impl<V: 'static + Send + Sync, K: ElementKind> LayoutNode<V, K> for Div<V, K> {
478    fn state(&mut self) -> &mut LayoutNodeElement<V, K> {
479        &mut self.0.child.child
480    }
481}
482
483impl<V: 'static + Send + Sync, K: ElementKind> Styled for Div<V, K> {
484    fn style_cascade(&mut self) -> &mut StyleCascade {
485        self.0.child.child.style_cascade()
486    }
487
488    fn computed_style(&mut self) -> &Style {
489        self.0.child.child.computed_style()
490    }
491}
492
493impl<V: 'static + Send + Sync, K: ElementKind> Hoverable for Div<V, K> {
494    fn hover_style(&mut self) -> &mut StyleRefinement {
495        self.0.child.hover_style()
496    }
497}
498
499impl<V: 'static + Send + Sync> Clickable for Div<V, Identified> {
500    fn active_style(&mut self) -> &mut StyleRefinement {
501        self.0.active_style()
502    }
503
504    fn listeners(&mut self) -> &mut ClickListeners<V> {
505        self.0.listeners()
506    }
507}
508
509impl<V, K> IntoAnyElement<V> for Div<V, K>
510where
511    V: 'static + Send + Sync,
512    K: ElementKind,
513{
514    fn into_any(self) -> AnyElement<V> {
515        AnyElement::new(self)
516    }
517}
518
519impl<V, K> Element for Div<V, K>
520where
521    V: 'static + Send + Sync,
522    K: ElementKind,
523{
524    type ViewState = V;
525    type ElementState = ClickableElementState<()>;
526
527    fn id(&self) -> Option<ElementId> {
528        self.0.id()
529    }
530
531    fn layout(
532        &mut self,
533        state: &mut Self::ViewState,
534        element_state: Option<Self::ElementState>,
535        cx: &mut ViewContext<Self::ViewState>,
536    ) -> (crate::LayoutId, Self::ElementState) {
537        self.0.layout(state, element_state, cx)
538    }
539
540    fn paint(
541        &mut self,
542        bounds: Bounds<crate::Pixels>,
543        state: &mut Self::ViewState,
544        element_state: &mut Self::ElementState,
545        cx: &mut ViewContext<Self::ViewState>,
546    ) {
547        self.0.paint(bounds, state, element_state, cx);
548    }
549}