div2.rs

  1use crate::{
  2    AnonymousElementKind, AnyElement, AppContext, BorrowWindow, Bounds, DispatchPhase, Element,
  3    ElementId, ElementKind, IntoAnyElement, LayoutId, MouseDownEvent, MouseMoveEvent, MouseUpEvent,
  4    Pixels, ScrollWheelEvent, SharedString, Style, StyleRefinement, ViewContext,
  5};
  6use collections::HashMap;
  7use parking_lot::Mutex;
  8use refineable::Refineable;
  9use smallvec::SmallVec;
 10use std::sync::Arc;
 11
 12#[derive(Default)]
 13pub struct DivState {
 14    active_state: Arc<Mutex<ActiveState>>,
 15}
 16
 17#[derive(Copy, Clone, Default, Eq, PartialEq)]
 18struct ActiveState {
 19    group: bool,
 20    element: bool,
 21}
 22
 23impl ActiveState {
 24    pub fn is_none(&self) -> bool {
 25        !self.group && !self.element
 26    }
 27}
 28
 29#[derive(Default)]
 30struct GroupBounds(HashMap<SharedString, SmallVec<[Bounds<Pixels>; 1]>>);
 31
 32pub fn group_bounds(name: &SharedString, cx: &mut AppContext) -> Option<Bounds<Pixels>> {
 33    cx.default_global::<GroupBounds>()
 34        .0
 35        .get(name)
 36        .and_then(|bounds_stack| bounds_stack.last().cloned())
 37}
 38
 39pub struct Div<V: 'static + Send + Sync, K: ElementKind = AnonymousElementKind> {
 40    kind: K,
 41    children: SmallVec<[AnyElement<V>; 2]>,
 42    group: Option<SharedString>,
 43    base_style: StyleRefinement,
 44    hover_style: StyleRefinement,
 45    group_hover: Option<GroupStyle>,
 46    active_style: StyleRefinement,
 47    group_active: Option<GroupStyle>,
 48    listeners: MouseEventListeners<V>,
 49}
 50
 51struct GroupStyle {
 52    group: SharedString,
 53    style: StyleRefinement,
 54}
 55
 56impl<V, K> Div<V, K>
 57where
 58    V: 'static + Send + Sync,
 59    K: ElementKind,
 60{
 61    fn with_element_id<R>(
 62        &mut self,
 63        cx: &mut ViewContext<V>,
 64        f: impl FnOnce(&mut Self, &mut ViewContext<V>) -> R,
 65    ) -> R {
 66        if let Some(id) = self.id() {
 67            cx.with_element_id(id, |cx| f(self, cx))
 68        } else {
 69            f(self, cx)
 70        }
 71    }
 72
 73    fn compute_style(
 74        &self,
 75        bounds: Bounds<Pixels>,
 76        group_bounds: Option<Bounds<Pixels>>,
 77        active_state: ActiveState,
 78        cx: &mut ViewContext<V>,
 79    ) -> Style {
 80        let mut computed_style = Style::default();
 81        computed_style.refine(&self.base_style);
 82
 83        let mouse_position = cx.mouse_position();
 84        if let Some(group_bounds) = group_bounds {
 85            if group_bounds.contains_point(mouse_position) {
 86                if let Some(GroupStyle { style, .. }) = self.group_hover.as_ref() {
 87                    computed_style.refine(style);
 88                }
 89            }
 90        }
 91        if bounds.contains_point(mouse_position) {
 92            computed_style.refine(&self.hover_style);
 93        }
 94
 95        if active_state.group {
 96            if let Some(GroupStyle { style, .. }) = self.group_active.as_ref() {
 97                computed_style.refine(style);
 98            }
 99        }
100
101        if active_state.element {
102            computed_style.refine(&self.active_style);
103        }
104
105        computed_style
106    }
107
108    fn paint_hover_listeners(
109        &self,
110        bounds: Bounds<Pixels>,
111        group_bounds: Option<Bounds<Pixels>>,
112        cx: &mut ViewContext<V>,
113    ) {
114        if let Some(group_bounds) = group_bounds {
115            paint_hover_listener(group_bounds, cx);
116        }
117
118        if self.hover_style.is_some() {
119            paint_hover_listener(bounds, cx);
120        }
121    }
122
123    fn paint_active_listener(
124        &self,
125        bounds: Bounds<Pixels>,
126        group_bounds: Option<Bounds<Pixels>>,
127        active_state: Arc<Mutex<ActiveState>>,
128        cx: &mut ViewContext<V>,
129    ) {
130        if active_state.lock().is_none() {
131            cx.on_mouse_event(move |_view, down: &MouseDownEvent, phase, cx| {
132                if phase == DispatchPhase::Bubble {
133                    let group =
134                        group_bounds.map_or(false, |bounds| bounds.contains_point(down.position));
135                    let element = bounds.contains_point(down.position);
136                    if group || element {
137                        *active_state.lock() = ActiveState { group, element };
138                        cx.notify();
139                    }
140                }
141            });
142        } else {
143            cx.on_mouse_event(move |_, _: &MouseUpEvent, phase, cx| {
144                if phase == DispatchPhase::Capture {
145                    *active_state.lock() = ActiveState::default();
146                    cx.notify();
147                }
148            });
149        }
150
151        // for listener in self.listeners.mouse_down.iter().cloned() {
152        //     cx.on_mouse_event(move |state, event: &MouseDownEvent, phase, cx| {
153        //         listener(state, event, &bounds, phase, cx);
154        //     })
155        // }
156
157        // for listener in self.listeners.mouse_up.iter().cloned() {
158        //     cx.on_mouse_event(move |state, event: &MouseUpEvent, phase, cx| {
159        //         listener(state, event, &bounds, phase, cx);
160        //     })
161        // }
162
163        // for listener in self.listeners.mouse_move.iter().cloned() {
164        //     cx.on_mouse_event(move |state, event: &MouseMoveEvent, phase, cx| {
165        //         listener(state, event, &bounds, phase, cx);
166        //     })
167        // }
168
169        // for listener in self.listeners.scroll_wheel.iter().cloned() {
170        //     cx.on_mouse_event(move |state, event: &ScrollWheelEvent, phase, cx| {
171        //         listener(state, event, &bounds, phase, cx);
172        //     })
173        // }
174    }
175}
176
177fn paint_hover_listener<V>(bounds: Bounds<Pixels>, cx: &mut ViewContext<V>)
178where
179    V: 'static + Send + Sync,
180{
181    let hovered = bounds.contains_point(cx.mouse_position());
182    cx.on_mouse_event(move |_, event: &MouseMoveEvent, phase, cx| {
183        if phase == DispatchPhase::Capture {
184            if bounds.contains_point(event.position) != hovered {
185                cx.notify();
186            }
187        }
188    });
189}
190
191impl<V, K> Element for Div<V, K>
192where
193    V: 'static + Send + Sync,
194    K: ElementKind,
195{
196    type ViewState = V;
197    type ElementState = DivState;
198
199    fn id(&self) -> Option<ElementId> {
200        self.kind.id()
201    }
202
203    fn layout(
204        &mut self,
205        view_state: &mut Self::ViewState,
206        element_state: Option<Self::ElementState>,
207        cx: &mut ViewContext<Self::ViewState>,
208    ) -> (LayoutId, Self::ElementState) {
209        self.with_element_id(cx, |this, cx| {
210            let layout_ids = this
211                .children
212                .iter_mut()
213                .map(|child| child.layout(view_state, cx))
214                .collect::<Vec<_>>();
215
216            let element_state = element_state.unwrap_or_default();
217            let style = this.compute_style(
218                Bounds::default(),
219                None,
220                *element_state.active_state.lock(),
221                cx,
222            );
223            let layout_id = cx.request_layout(&style, layout_ids);
224            (layout_id, element_state)
225        })
226    }
227
228    fn paint(
229        &mut self,
230        bounds: Bounds<Pixels>,
231        view_state: &mut Self::ViewState,
232        element_state: &mut Self::ElementState,
233        cx: &mut ViewContext<Self::ViewState>,
234    ) {
235        self.with_element_id(cx, |this, cx| {
236            if let Some(group) = this.group.clone() {
237                cx.default_global::<GroupBounds>()
238                    .0
239                    .entry(group)
240                    .or_default()
241                    .push(bounds);
242            }
243
244            let hover_group_bounds = this
245                .group_hover
246                .as_ref()
247                .and_then(|group_hover| group_bounds(&group_hover.group, cx));
248            let active_group_bounds = this
249                .group_active
250                .as_ref()
251                .and_then(|group_active| group_bounds(&group_active.group, cx));
252            let active_state = *element_state.active_state.lock();
253            let style = this.compute_style(bounds, hover_group_bounds, active_state, cx);
254            let z_index = style.z_index.unwrap_or(0);
255
256            // Paint background and event handlers.
257            cx.stack(z_index, |cx| {
258                cx.stack(0, |cx| {
259                    style.paint(bounds, cx);
260                    this.paint_hover_listeners(bounds, hover_group_bounds, cx);
261                    this.paint_active_listener(
262                        bounds,
263                        active_group_bounds,
264                        element_state.active_state.clone(),
265                        cx,
266                    );
267                });
268            });
269
270            style.apply_text_style(cx, |cx| {
271                style.apply_overflow(bounds, cx, |cx| {
272                    cx.stack(z_index + 1, |cx| {
273                        for child in &mut this.children {
274                            child.paint(view_state, None, cx);
275                        }
276                    })
277                })
278            });
279
280            if let Some(group) = this.group.as_ref() {
281                cx.default_global::<GroupBounds>()
282                    .0
283                    .get_mut(group)
284                    .unwrap()
285                    .pop();
286            }
287        })
288    }
289}
290
291impl<V, K> IntoAnyElement<V> for Div<V, K>
292where
293    V: 'static + Send + Sync,
294    K: ElementKind,
295{
296    fn into_any(self) -> AnyElement<V> {
297        AnyElement::new(self)
298    }
299}
300
301pub struct MouseClickEvent {
302    pub down: MouseDownEvent,
303    pub up: MouseUpEvent,
304}
305
306type MouseDownHandler<V> = Arc<
307    dyn Fn(&mut V, &MouseDownEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
308        + Send
309        + Sync
310        + 'static,
311>;
312type MouseUpHandler<V> = Arc<
313    dyn Fn(&mut V, &MouseUpEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
314        + Send
315        + Sync
316        + 'static,
317>;
318type MouseClickHandler<V> = Arc<
319    dyn Fn(&mut V, &MouseClickEvent, &Bounds<Pixels>, &mut ViewContext<V>) + Send + Sync + 'static,
320>;
321
322type MouseMoveHandler<V> = Arc<
323    dyn Fn(&mut V, &MouseMoveEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
324        + Send
325        + Sync
326        + 'static,
327>;
328type ScrollWheelHandler<V> = Arc<
329    dyn Fn(&mut V, &ScrollWheelEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
330        + Send
331        + Sync
332        + 'static,
333>;
334
335pub struct MouseEventListeners<V: 'static> {
336    mouse_down: SmallVec<[MouseDownHandler<V>; 2]>,
337    mouse_up: SmallVec<[MouseUpHandler<V>; 2]>,
338    mouse_click: SmallVec<[MouseClickHandler<V>; 2]>,
339    mouse_move: SmallVec<[MouseMoveHandler<V>; 2]>,
340    scroll_wheel: SmallVec<[ScrollWheelHandler<V>; 2]>,
341}
342
343impl<V> Default for MouseEventListeners<V> {
344    fn default() -> Self {
345        Self {
346            mouse_down: SmallVec::new(),
347            mouse_up: SmallVec::new(),
348            mouse_click: SmallVec::new(),
349            mouse_move: SmallVec::new(),
350            scroll_wheel: SmallVec::new(),
351        }
352    }
353}