div.rs

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