div.rs

  1use std::fmt::Debug;
  2
  3use crate::{
  4    point, AnyElement, BorrowWindow, Bounds, Component, Element, ElementId, ElementInteractivity,
  5    FocusHandle, FocusListeners, Focusable, FocusableKeyDispatch, GroupBounds,
  6    InteractiveElementState, KeyContext, KeyDispatch, LayoutId, NonFocusableKeyDispatch, Overflow,
  7    ParentElement, Pixels, Point, SharedString, StatefulInteractive, StatefulInteractivity,
  8    StatelessInteractive, StatelessInteractivity, Style, StyleRefinement, Styled, ViewContext,
  9    Visibility,
 10};
 11use refineable::Refineable;
 12use smallvec::SmallVec;
 13use util::ResultExt;
 14
 15pub struct Div<
 16    V: 'static,
 17    I: ElementInteractivity<V> = StatelessInteractivity<V>,
 18    K: KeyDispatch<V> = NonFocusableKeyDispatch,
 19> {
 20    interactivity: I,
 21    key_dispatch: K,
 22    children: SmallVec<[AnyElement<V>; 2]>,
 23    group: Option<SharedString>,
 24    base_style: StyleRefinement,
 25}
 26
 27pub fn div<V: 'static>() -> Div<V, StatelessInteractivity<V>, NonFocusableKeyDispatch> {
 28    Div {
 29        interactivity: StatelessInteractivity::default(),
 30        key_dispatch: NonFocusableKeyDispatch::default(),
 31        children: SmallVec::new(),
 32        group: None,
 33        base_style: StyleRefinement::default(),
 34    }
 35}
 36
 37impl<V, F> Div<V, StatelessInteractivity<V>, F>
 38where
 39    V: 'static,
 40    F: KeyDispatch<V>,
 41{
 42    pub fn id(self, id: impl Into<ElementId>) -> Div<V, StatefulInteractivity<V>, F> {
 43        Div {
 44            interactivity: StatefulInteractivity::new(id.into(), self.interactivity),
 45            key_dispatch: self.key_dispatch,
 46            children: self.children,
 47            group: self.group,
 48            base_style: self.base_style,
 49        }
 50    }
 51}
 52
 53impl<V, I, F> Div<V, I, F>
 54where
 55    I: ElementInteractivity<V>,
 56    F: KeyDispatch<V>,
 57{
 58    pub fn group(mut self, group: impl Into<SharedString>) -> Self {
 59        self.group = Some(group.into());
 60        self
 61    }
 62
 63    pub fn z_index(mut self, z_index: u32) -> Self {
 64        self.base_style.z_index = Some(z_index);
 65        self
 66    }
 67
 68    pub fn context<C>(mut self, context: C) -> Self
 69    where
 70        Self: Sized,
 71        C: TryInto<KeyContext>,
 72        C::Error: Debug,
 73    {
 74        if let Some(context) = context.try_into().log_err() {
 75            *self.key_dispatch.key_context_mut() = context;
 76        }
 77        self
 78    }
 79
 80    pub fn overflow_hidden(mut self) -> Self {
 81        self.base_style.overflow.x = Some(Overflow::Hidden);
 82        self.base_style.overflow.y = Some(Overflow::Hidden);
 83        self
 84    }
 85
 86    pub fn overflow_hidden_x(mut self) -> Self {
 87        self.base_style.overflow.x = Some(Overflow::Hidden);
 88        self
 89    }
 90
 91    pub fn overflow_hidden_y(mut self) -> Self {
 92        self.base_style.overflow.y = Some(Overflow::Hidden);
 93        self
 94    }
 95
 96    pub fn compute_style(
 97        &self,
 98        bounds: Bounds<Pixels>,
 99        element_state: &DivState,
100        cx: &mut ViewContext<V>,
101    ) -> Style {
102        let mut computed_style = Style::default();
103        computed_style.refine(&self.base_style);
104        self.key_dispatch.refine_style(&mut computed_style, cx);
105        self.interactivity.refine_style(
106            &mut computed_style,
107            bounds,
108            &element_state.interactive,
109            cx,
110        );
111        computed_style
112    }
113}
114
115impl<V: 'static> Div<V, StatefulInteractivity<V>, NonFocusableKeyDispatch> {
116    pub fn focusable(self) -> Div<V, StatefulInteractivity<V>, FocusableKeyDispatch<V>> {
117        Div {
118            interactivity: self.interactivity,
119            key_dispatch: FocusableKeyDispatch::new(self.key_dispatch),
120            children: self.children,
121            group: self.group,
122            base_style: self.base_style,
123        }
124    }
125
126    pub fn track_focus(
127        self,
128        handle: &FocusHandle,
129    ) -> Div<V, StatefulInteractivity<V>, FocusableKeyDispatch<V>> {
130        Div {
131            interactivity: self.interactivity,
132            key_dispatch: FocusableKeyDispatch::tracked(self.key_dispatch, handle),
133            children: self.children,
134            group: self.group,
135            base_style: self.base_style,
136        }
137    }
138
139    pub fn overflow_scroll(mut self) -> Self {
140        self.base_style.overflow.x = Some(Overflow::Scroll);
141        self.base_style.overflow.y = Some(Overflow::Scroll);
142        self
143    }
144
145    pub fn overflow_x_scroll(mut self) -> Self {
146        self.base_style.overflow.x = Some(Overflow::Scroll);
147        self
148    }
149
150    pub fn overflow_y_scroll(mut self) -> Self {
151        self.base_style.overflow.y = Some(Overflow::Scroll);
152        self
153    }
154}
155
156impl<V: 'static> Div<V, StatelessInteractivity<V>, NonFocusableKeyDispatch> {
157    pub fn track_focus(
158        self,
159        handle: &FocusHandle,
160    ) -> Div<V, StatefulInteractivity<V>, FocusableKeyDispatch<V>> {
161        Div {
162            interactivity: self.interactivity.into_stateful(handle),
163            key_dispatch: FocusableKeyDispatch::tracked(self.key_dispatch, handle),
164            children: self.children,
165            group: self.group,
166            base_style: self.base_style,
167        }
168    }
169}
170
171impl<V, I> Focusable<V> for Div<V, I, FocusableKeyDispatch<V>>
172where
173    V: 'static,
174    I: ElementInteractivity<V>,
175{
176    fn focus_listeners(&mut self) -> &mut FocusListeners<V> {
177        &mut self.key_dispatch.focus_listeners
178    }
179
180    fn set_focus_style(&mut self, style: StyleRefinement) {
181        self.key_dispatch.focus_style = style;
182    }
183
184    fn set_focus_in_style(&mut self, style: StyleRefinement) {
185        self.key_dispatch.focus_in_style = style;
186    }
187
188    fn set_in_focus_style(&mut self, style: StyleRefinement) {
189        self.key_dispatch.in_focus_style = style;
190    }
191}
192
193#[derive(Default)]
194pub struct DivState {
195    interactive: InteractiveElementState,
196    focus_handle: Option<FocusHandle>,
197    child_layout_ids: SmallVec<[LayoutId; 4]>,
198}
199
200impl<V, I, F> Element<V> for Div<V, I, F>
201where
202    I: ElementInteractivity<V>,
203    F: KeyDispatch<V>,
204{
205    type ElementState = DivState;
206
207    fn id(&self) -> Option<ElementId> {
208        self.interactivity
209            .as_stateful()
210            .map(|identified| identified.id.clone())
211    }
212
213    fn initialize(
214        &mut self,
215        view_state: &mut V,
216        element_state: Option<Self::ElementState>,
217        cx: &mut ViewContext<V>,
218    ) -> Self::ElementState {
219        let mut element_state = element_state.unwrap_or_default();
220        cx.with_element_id(self.id(), |cx| {
221            self.key_dispatch.initialize(
222                element_state.focus_handle.take(),
223                cx,
224                |focus_handle, cx| {
225                    self.interactivity.initialize(cx);
226                    element_state.focus_handle = focus_handle;
227                    for child in &mut self.children {
228                        child.initialize(view_state, cx);
229                    }
230                },
231            );
232        });
233        element_state
234    }
235
236    fn layout(
237        &mut self,
238        view_state: &mut V,
239        element_state: &mut Self::ElementState,
240        cx: &mut ViewContext<V>,
241    ) -> LayoutId {
242        let style = self.compute_style(Bounds::default(), element_state, cx);
243        style.apply_text_style(cx, |cx| {
244            cx.with_element_id(self.id(), |cx| {
245                let layout_ids = self
246                    .children
247                    .iter_mut()
248                    .map(|child| child.layout(view_state, cx))
249                    .collect::<SmallVec<_>>();
250                element_state.child_layout_ids = layout_ids.clone();
251                cx.request_layout(&style, layout_ids)
252            })
253        })
254    }
255
256    fn paint(
257        &mut self,
258        bounds: Bounds<Pixels>,
259        view_state: &mut V,
260        element_state: &mut Self::ElementState,
261        cx: &mut ViewContext<V>,
262    ) {
263        cx.with_element_id(self.id(), |cx| {
264            let style = self.compute_style(bounds, element_state, cx);
265            if style.visibility == Visibility::Hidden {
266                return;
267            }
268
269            if let Some(mouse_cursor) = style.mouse_cursor {
270                let hovered = bounds.contains_point(&cx.mouse_position());
271                if hovered {
272                    cx.set_cursor_style(mouse_cursor);
273                }
274            }
275
276            if let Some(group) = self.group.clone() {
277                GroupBounds::push(group, bounds, cx);
278            }
279
280            let z_index = style.z_index.unwrap_or(0);
281
282            let mut child_min = point(Pixels::MAX, Pixels::MAX);
283            let mut child_max = Point::default();
284
285            let content_size = if element_state.child_layout_ids.is_empty() {
286                bounds.size
287            } else {
288                for child_layout_id in &element_state.child_layout_ids {
289                    let child_bounds = cx.layout_bounds(*child_layout_id);
290                    child_min = child_min.min(&child_bounds.origin);
291                    child_max = child_max.max(&child_bounds.lower_right());
292                }
293                (child_max - child_min).into()
294            };
295
296            cx.with_z_index(z_index, |cx| {
297                cx.with_z_index(0, |cx| {
298                    style.paint(bounds, cx);
299                    self.key_dispatch.paint(bounds, cx);
300                    self.interactivity.handle_events(
301                        bounds,
302                        content_size,
303                        style.overflow,
304                        &mut element_state.interactive,
305                        cx,
306                    );
307                });
308                cx.with_z_index(1, |cx| {
309                    style.apply_text_style(cx, |cx| {
310                        style.apply_overflow(bounds, cx, |cx| {
311                            let scroll_offset = element_state.interactive.scroll_offset();
312                            cx.with_element_offset(scroll_offset.unwrap_or_default(), |cx| {
313                                for child in &mut self.children {
314                                    child.paint(view_state, cx);
315                                }
316                            });
317                        })
318                    })
319                });
320            });
321
322            if let Some(group) = self.group.as_ref() {
323                GroupBounds::pop(group, cx);
324            }
325        })
326    }
327}
328
329impl<V, I, F> Component<V> for Div<V, I, F>
330where
331    I: ElementInteractivity<V>,
332    F: KeyDispatch<V>,
333{
334    fn render(self) -> AnyElement<V> {
335        AnyElement::new(self)
336    }
337}
338
339impl<V, I, F> ParentElement<V> for Div<V, I, F>
340where
341    I: ElementInteractivity<V>,
342    F: KeyDispatch<V>,
343{
344    fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<V>; 2]> {
345        &mut self.children
346    }
347}
348
349impl<V, I, F> Styled for Div<V, I, F>
350where
351    I: ElementInteractivity<V>,
352    F: KeyDispatch<V>,
353{
354    fn style(&mut self) -> &mut StyleRefinement {
355        &mut self.base_style
356    }
357}
358
359impl<V, I, F> StatelessInteractive<V> for Div<V, I, F>
360where
361    I: ElementInteractivity<V>,
362    F: KeyDispatch<V>,
363{
364    fn stateless_interactivity(&mut self) -> &mut StatelessInteractivity<V> {
365        self.interactivity.as_stateless_mut()
366    }
367}
368
369impl<V, F> StatefulInteractive<V> for Div<V, StatefulInteractivity<V>, F>
370where
371    F: KeyDispatch<V>,
372{
373    fn stateful_interactivity(&mut self) -> &mut StatefulInteractivity<V> {
374        &mut self.interactivity
375    }
376}