div.rs

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