div.rs

  1use crate::{
  2    Active, Anonymous, AnyElement, AppContext, BorrowWindow, Bounds, Click, DispatchPhase, Element,
  3    ElementFocusability, ElementId, ElementIdentity, EventListeners, Focus, FocusHandle, Focusable,
  4    Hover, Identified, Interactive, IntoAnyElement, LayoutId, MouseClickEvent, MouseDownEvent,
  5    MouseMoveEvent, MouseUpEvent, NonFocusable, Overflow, ParentElement, Pixels, Point,
  6    ScrollWheelEvent, SharedString, Style, StyleRefinement, Styled, ViewContext,
  7};
  8use collections::HashMap;
  9use parking_lot::Mutex;
 10use refineable::Refineable;
 11use smallvec::SmallVec;
 12use std::{mem, sync::Arc};
 13
 14#[derive(Default)]
 15pub struct DivState {
 16    active_state: Arc<Mutex<ActiveState>>,
 17    pending_click: Arc<Mutex<Option<MouseDownEvent>>>,
 18}
 19
 20#[derive(Copy, Clone, Default, Eq, PartialEq)]
 21struct ActiveState {
 22    group: bool,
 23    element: bool,
 24}
 25
 26impl ActiveState {
 27    pub fn is_none(&self) -> bool {
 28        !self.group && !self.element
 29    }
 30}
 31
 32#[derive(Default)]
 33struct GroupBounds(HashMap<SharedString, SmallVec<[Bounds<Pixels>; 1]>>);
 34
 35pub fn group_bounds(name: &SharedString, cx: &mut AppContext) -> Option<Bounds<Pixels>> {
 36    cx.default_global::<GroupBounds>()
 37        .0
 38        .get(name)
 39        .and_then(|bounds_stack| bounds_stack.last().cloned())
 40}
 41
 42#[derive(Default, Clone)]
 43pub struct ScrollState(Arc<Mutex<Point<Pixels>>>);
 44
 45impl ScrollState {
 46    pub fn x(&self) -> Pixels {
 47        self.0.lock().x
 48    }
 49
 50    pub fn set_x(&self, value: Pixels) {
 51        self.0.lock().x = value;
 52    }
 53
 54    pub fn y(&self) -> Pixels {
 55        self.0.lock().y
 56    }
 57
 58    pub fn set_y(&self, value: Pixels) {
 59        self.0.lock().y = value;
 60    }
 61}
 62
 63pub fn div<V>() -> Div<V, Anonymous, NonFocusable>
 64where
 65    V: 'static + Send + Sync,
 66{
 67    Div {
 68        identity: Anonymous,
 69        focusability: NonFocusable,
 70        children: SmallVec::new(),
 71        group: None,
 72        base_style: StyleRefinement::default(),
 73        hover_style: StyleRefinement::default(),
 74        group_hover: None,
 75        active_style: StyleRefinement::default(),
 76        group_active: None,
 77        focus_style: StyleRefinement::default(),
 78        focus_in_style: StyleRefinement::default(),
 79        in_focus_style: StyleRefinement::default(),
 80        listeners: EventListeners::default(),
 81    }
 82}
 83
 84pub struct Div<
 85    V: 'static + Send + Sync,
 86    I: ElementIdentity = Anonymous,
 87    F: ElementFocusability = NonFocusable,
 88> {
 89    identity: I,
 90    focusability: F,
 91    children: SmallVec<[AnyElement<V>; 2]>,
 92    group: Option<SharedString>,
 93    base_style: StyleRefinement,
 94    hover_style: StyleRefinement,
 95    group_hover: Option<GroupStyle>,
 96    active_style: StyleRefinement,
 97    group_active: Option<GroupStyle>,
 98    focus_style: StyleRefinement,
 99    focus_in_style: StyleRefinement,
100    in_focus_style: StyleRefinement,
101    listeners: EventListeners<V>,
102}
103
104struct GroupStyle {
105    group: SharedString,
106    style: StyleRefinement,
107}
108
109impl<V, F> Div<V, Anonymous, F>
110where
111    F: ElementFocusability,
112    V: 'static + Send + Sync,
113{
114    pub fn id(self, id: impl Into<ElementId>) -> Div<V, Identified, F> {
115        Div {
116            identity: Identified(id.into()),
117            focusability: self.focusability,
118            children: self.children,
119            group: self.group,
120            base_style: self.base_style,
121            hover_style: self.hover_style,
122            group_hover: self.group_hover,
123            active_style: self.active_style,
124            group_active: self.group_active,
125            focus_style: self.focus_style,
126            focus_in_style: self.focus_in_style,
127            in_focus_style: self.in_focus_style,
128            listeners: self.listeners,
129        }
130    }
131}
132
133impl<V, I, F> Div<V, I, F>
134where
135    I: ElementIdentity,
136    F: ElementFocusability,
137    V: 'static + Send + Sync,
138{
139    pub fn group(mut self, group: impl Into<SharedString>) -> Self {
140        self.group = Some(group.into());
141        self
142    }
143
144    pub fn z_index(mut self, z_index: u32) -> Self {
145        self.base_style.z_index = Some(z_index);
146        self
147    }
148
149    pub fn overflow_hidden(mut self) -> Self {
150        self.base_style.overflow.x = Some(Overflow::Hidden);
151        self.base_style.overflow.y = Some(Overflow::Hidden);
152        self
153    }
154
155    pub fn overflow_hidden_x(mut self) -> Self {
156        self.base_style.overflow.x = Some(Overflow::Hidden);
157        self
158    }
159
160    pub fn overflow_hidden_y(mut self) -> Self {
161        self.base_style.overflow.y = Some(Overflow::Hidden);
162        self
163    }
164
165    pub fn overflow_scroll(mut self, _scroll_state: ScrollState) -> Self {
166        // todo!("impl scrolling")
167        // self.scroll_state = Some(scroll_state);
168        self.base_style.overflow.x = Some(Overflow::Scroll);
169        self.base_style.overflow.y = Some(Overflow::Scroll);
170        self
171    }
172
173    pub fn overflow_x_scroll(mut self, _scroll_state: ScrollState) -> Self {
174        // todo!("impl scrolling")
175        // self.scroll_state = Some(scroll_state);
176        self.base_style.overflow.x = Some(Overflow::Scroll);
177        self
178    }
179
180    pub fn overflow_y_scroll(mut self, _scroll_state: ScrollState) -> Self {
181        // todo!("impl scrolling")
182        // self.scroll_state = Some(scroll_state);
183        self.base_style.overflow.y = Some(Overflow::Scroll);
184        self
185    }
186
187    fn with_element_id<R>(
188        &mut self,
189        cx: &mut ViewContext<V>,
190        f: impl FnOnce(&mut Self, &mut ViewContext<V>) -> R,
191    ) -> R {
192        if let Some(id) = self.id() {
193            cx.with_element_id(id, |cx| f(self, cx))
194        } else {
195            f(self, cx)
196        }
197    }
198
199    pub fn compute_style(
200        &self,
201        bounds: Bounds<Pixels>,
202        state: &DivState,
203        cx: &mut ViewContext<V>,
204    ) -> Style {
205        let mut computed_style = Style::default();
206        computed_style.refine(&self.base_style);
207
208        if let Some(handle) = self.focusability.focus_handle() {
209            if handle.contains_focused(cx) {
210                computed_style.refine(&self.focus_in_style);
211            }
212
213            if handle.within_focused(cx) {
214                computed_style.refine(&self.in_focus_style);
215            }
216
217            if handle.is_focused(cx) {
218                computed_style.refine(&self.focus_style);
219            }
220        }
221
222        let mouse_position = cx.mouse_position();
223
224        if let Some(group_hover) = self.group_hover.as_ref() {
225            if let Some(group_bounds) = group_bounds(&group_hover.group, cx) {
226                if group_bounds.contains_point(&mouse_position) {
227                    computed_style.refine(&group_hover.style);
228                }
229            }
230        }
231        if bounds.contains_point(&mouse_position) {
232            computed_style.refine(&self.hover_style);
233        }
234
235        let active_state = *state.active_state.lock();
236        if active_state.group {
237            if let Some(GroupStyle { style, .. }) = self.group_active.as_ref() {
238                computed_style.refine(style);
239            }
240        }
241        if active_state.element {
242            computed_style.refine(&self.active_style);
243        }
244
245        computed_style
246    }
247
248    fn paint_hover_listeners(
249        &self,
250        bounds: Bounds<Pixels>,
251        group_bounds: Option<Bounds<Pixels>>,
252        cx: &mut ViewContext<V>,
253    ) {
254        if let Some(group_bounds) = group_bounds {
255            paint_hover_listener(group_bounds, cx);
256        }
257
258        if self.hover_style.is_some() {
259            paint_hover_listener(bounds, cx);
260        }
261    }
262
263    fn paint_active_listener(
264        &self,
265        bounds: Bounds<Pixels>,
266        group_bounds: Option<Bounds<Pixels>>,
267        active_state: Arc<Mutex<ActiveState>>,
268        cx: &mut ViewContext<V>,
269    ) {
270        if active_state.lock().is_none() {
271            cx.on_mouse_event(move |_view, down: &MouseDownEvent, phase, cx| {
272                if phase == DispatchPhase::Bubble {
273                    let group =
274                        group_bounds.map_or(false, |bounds| bounds.contains_point(&down.position));
275                    let element = bounds.contains_point(&down.position);
276                    if group || element {
277                        *active_state.lock() = ActiveState { group, element };
278                        cx.notify();
279                    }
280                }
281            });
282        } else {
283            cx.on_mouse_event(move |_, _: &MouseUpEvent, phase, cx| {
284                if phase == DispatchPhase::Capture {
285                    *active_state.lock() = ActiveState::default();
286                    cx.notify();
287                }
288            });
289        }
290    }
291
292    fn paint_event_listeners(
293        &mut self,
294        bounds: Bounds<Pixels>,
295        pending_click: Arc<Mutex<Option<MouseDownEvent>>>,
296        cx: &mut ViewContext<V>,
297    ) {
298        let click_listeners = mem::take(&mut self.listeners.mouse_click);
299
300        let mouse_down = pending_click.lock().clone();
301        if let Some(mouse_down) = mouse_down {
302            cx.on_mouse_event(move |state, event: &MouseUpEvent, phase, cx| {
303                if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
304                    let mouse_click = MouseClickEvent {
305                        down: mouse_down.clone(),
306                        up: event.clone(),
307                    };
308                    for listener in &click_listeners {
309                        listener(state, &mouse_click, cx);
310                    }
311                }
312
313                *pending_click.lock() = None;
314            });
315        } else {
316            cx.on_mouse_event(move |_state, event: &MouseDownEvent, phase, _cx| {
317                if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
318                    *pending_click.lock() = Some(event.clone());
319                }
320            });
321        }
322
323        if let Some(focus_handle) = self.focusability.focus_handle() {
324            let focus_handle = focus_handle.clone();
325            cx.on_mouse_event(move |_, event: &MouseDownEvent, phase, cx| {
326                if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
327                    if !cx.default_prevented() {
328                        cx.focus(&focus_handle);
329                        cx.prevent_default();
330                    }
331                }
332            })
333        }
334
335        for listener in mem::take(&mut self.listeners.mouse_down) {
336            cx.on_mouse_event(move |state, event: &MouseDownEvent, phase, cx| {
337                listener(state, event, &bounds, phase, cx);
338            })
339        }
340
341        for listener in mem::take(&mut self.listeners.mouse_up) {
342            cx.on_mouse_event(move |state, event: &MouseUpEvent, phase, cx| {
343                listener(state, event, &bounds, phase, cx);
344            })
345        }
346
347        for listener in mem::take(&mut self.listeners.mouse_move) {
348            cx.on_mouse_event(move |state, event: &MouseMoveEvent, phase, cx| {
349                listener(state, event, &bounds, phase, cx);
350            })
351        }
352
353        for listener in mem::take(&mut self.listeners.scroll_wheel) {
354            cx.on_mouse_event(move |state, event: &ScrollWheelEvent, phase, cx| {
355                listener(state, event, &bounds, phase, cx);
356            })
357        }
358    }
359}
360
361impl<V, I> Div<V, I, NonFocusable>
362where
363    I: ElementIdentity,
364    V: 'static + Send + Sync,
365{
366    pub fn focusable(self, handle: &FocusHandle) -> Div<V, I, Focusable> {
367        Div {
368            identity: self.identity,
369            focusability: handle.clone().into(),
370            children: self.children,
371            group: self.group,
372            base_style: self.base_style,
373            hover_style: self.hover_style,
374            group_hover: self.group_hover,
375            active_style: self.active_style,
376            group_active: self.group_active,
377            focus_style: self.focus_style,
378            focus_in_style: self.focus_in_style,
379            in_focus_style: self.in_focus_style,
380            listeners: self.listeners,
381        }
382    }
383}
384
385impl<V, I> Focus for Div<V, I, Focusable>
386where
387    I: ElementIdentity,
388    V: 'static + Send + Sync,
389{
390    fn handle(&self) -> &FocusHandle {
391        self.focusability.as_ref()
392    }
393
394    fn set_focus_style(&mut self, style: StyleRefinement) {
395        self.focus_style = style;
396    }
397
398    fn set_focus_in_style(&mut self, style: StyleRefinement) {
399        self.focus_in_style = style;
400    }
401
402    fn set_in_focus_style(&mut self, style: StyleRefinement) {
403        self.in_focus_style = style;
404    }
405}
406
407impl<V, I, F> Element for Div<V, I, F>
408where
409    I: ElementIdentity,
410    F: ElementFocusability,
411    V: 'static + Send + Sync,
412{
413    type ViewState = V;
414    type ElementState = DivState;
415
416    fn id(&self) -> Option<ElementId> {
417        self.identity.id()
418    }
419
420    fn initialize(
421        &mut self,
422        view_state: &mut Self::ViewState,
423        element_state: Option<Self::ElementState>,
424        cx: &mut ViewContext<Self::ViewState>,
425    ) -> Self::ElementState {
426        for listener in self.listeners.focus.iter().cloned() {
427            cx.on_focus_changed(move |view, event, cx| listener(view, event, cx));
428        }
429
430        let key_listeners = mem::take(&mut self.listeners.key);
431        cx.with_key_listeners(&key_listeners, |cx| {
432            if let Some(focus_handle) = self.focusability.focus_handle().cloned() {
433                cx.with_focus(focus_handle, |cx| {
434                    for child in &mut self.children {
435                        child.initialize(view_state, cx);
436                    }
437                })
438            } else {
439                for child in &mut self.children {
440                    child.initialize(view_state, cx);
441                }
442            }
443        });
444        self.listeners.key = key_listeners;
445
446        element_state.unwrap_or_default()
447    }
448
449    fn layout(
450        &mut self,
451        view_state: &mut Self::ViewState,
452        element_state: &mut Self::ElementState,
453        cx: &mut ViewContext<Self::ViewState>,
454    ) -> LayoutId {
455        let style = self.compute_style(Bounds::default(), element_state, cx);
456        style.apply_text_style(cx, |cx| {
457            self.with_element_id(cx, |this, cx| {
458                let layout_ids = this
459                    .children
460                    .iter_mut()
461                    .map(|child| child.layout(view_state, cx))
462                    .collect::<Vec<_>>();
463                cx.request_layout(&style, layout_ids)
464            })
465        })
466    }
467
468    fn paint(
469        &mut self,
470        bounds: Bounds<Pixels>,
471        view_state: &mut Self::ViewState,
472        element_state: &mut Self::ElementState,
473        cx: &mut ViewContext<Self::ViewState>,
474    ) {
475        self.with_element_id(cx, |this, cx| {
476            if let Some(group) = this.group.clone() {
477                cx.default_global::<GroupBounds>()
478                    .0
479                    .entry(group)
480                    .or_default()
481                    .push(bounds);
482            }
483
484            let hover_group_bounds = this
485                .group_hover
486                .as_ref()
487                .and_then(|group_hover| group_bounds(&group_hover.group, cx));
488            let active_group_bounds = this
489                .group_active
490                .as_ref()
491                .and_then(|group_active| group_bounds(&group_active.group, cx));
492            let style = this.compute_style(bounds, element_state, cx);
493            let z_index = style.z_index.unwrap_or(0);
494
495            // Paint background and event handlers.
496            cx.stack(z_index, |cx| {
497                cx.stack(0, |cx| {
498                    style.paint(bounds, cx);
499                    this.paint_hover_listeners(bounds, hover_group_bounds, cx);
500                    this.paint_active_listener(
501                        bounds,
502                        active_group_bounds,
503                        element_state.active_state.clone(),
504                        cx,
505                    );
506                    this.paint_event_listeners(bounds, element_state.pending_click.clone(), cx);
507                });
508
509                cx.stack(1, |cx| {
510                    style.apply_text_style(cx, |cx| {
511                        style.apply_overflow(bounds, cx, |cx| {
512                            for child in &mut this.children {
513                                child.paint(view_state, None, cx);
514                            }
515                        })
516                    })
517                });
518            });
519
520            if let Some(group) = this.group.as_ref() {
521                cx.default_global::<GroupBounds>()
522                    .0
523                    .get_mut(group)
524                    .unwrap()
525                    .pop();
526            }
527        })
528    }
529}
530
531impl<V, I, F> IntoAnyElement<V> for Div<V, I, F>
532where
533    I: ElementIdentity,
534    F: ElementFocusability,
535    V: 'static + Send + Sync,
536{
537    fn into_any(self) -> AnyElement<V> {
538        AnyElement::new(self)
539    }
540}
541
542impl<V, I, F> ParentElement for Div<V, I, F>
543where
544    I: ElementIdentity,
545    F: ElementFocusability,
546    V: 'static + Send + Sync,
547{
548    fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<Self::ViewState>; 2]> {
549        &mut self.children
550    }
551}
552
553impl<V, I, F> Styled for Div<V, I, F>
554where
555    I: ElementIdentity,
556    F: ElementFocusability,
557    V: 'static + Send + Sync,
558{
559    fn style(&mut self) -> &mut StyleRefinement {
560        &mut self.base_style
561    }
562}
563
564impl<V, I, F> Interactive for Div<V, I, F>
565where
566    I: ElementIdentity,
567    F: ElementFocusability,
568    V: 'static + Send + Sync,
569{
570    fn listeners(&mut self) -> &mut EventListeners<V> {
571        &mut self.listeners
572    }
573}
574
575impl<V, I, F> Hover for Div<V, I, F>
576where
577    I: ElementIdentity,
578    F: ElementFocusability,
579    V: 'static + Send + Sync,
580{
581    fn set_hover_style(&mut self, group: Option<SharedString>, style: StyleRefinement) {
582        if let Some(group) = group {
583            self.group_hover = Some(GroupStyle { group, style });
584        } else {
585            self.hover_style = style;
586        }
587    }
588}
589
590impl<V, F> Click for Div<V, Identified, F>
591where
592    F: ElementFocusability,
593    V: 'static + Send + Sync,
594{
595}
596
597impl<V, F> Active for Div<V, Identified, F>
598where
599    F: ElementFocusability,
600    V: 'static + Send + Sync,
601{
602    fn set_active_style(&mut self, group: Option<SharedString>, style: StyleRefinement) {
603        if let Some(group) = group {
604            self.group_active = Some(GroupStyle { group, style });
605        } else {
606            self.active_style = style;
607        }
608    }
609}
610
611fn paint_hover_listener<V>(bounds: Bounds<Pixels>, cx: &mut ViewContext<V>)
612where
613    V: 'static + Send + Sync,
614{
615    let hovered = bounds.contains_point(&cx.mouse_position());
616    cx.on_mouse_event(move |_, event: &MouseMoveEvent, phase, cx| {
617        if phase == DispatchPhase::Capture {
618            if bounds.contains_point(&event.position) != hovered {
619                cx.notify();
620            }
621        }
622    });
623}