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