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