div.rs

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