div.rs

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