div.rs

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