div.rs

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