use crate::{ point, AnyElement, BorrowWindow, Bounds, Component, Element, ElementFocus, ElementId, ElementInteraction, FocusDisabled, FocusEnabled, FocusHandle, FocusListeners, Focusable, GlobalElementId, GroupBounds, InteractiveElementState, LayoutId, Overflow, ParentElement, Pixels, Point, SharedString, StatefulInteraction, StatefulInteractive, StatelessInteraction, StatelessInteractive, Style, StyleRefinement, Styled, ViewContext, }; use refineable::Refineable; use smallvec::SmallVec; pub struct Div< V: 'static, I: ElementInteraction = StatelessInteraction, F: ElementFocus = FocusDisabled, > { interaction: I, focus: F, children: SmallVec<[AnyElement; 2]>, group: Option, base_style: StyleRefinement, } pub fn div() -> Div, FocusDisabled> { Div { interaction: StatelessInteraction::default(), focus: FocusDisabled, children: SmallVec::new(), group: None, base_style: StyleRefinement::default(), } } impl Div, F> where V: 'static, F: ElementFocus, { pub fn id(self, id: impl Into) -> Div, F> { Div { interaction: id.into().into(), focus: self.focus, children: self.children, group: self.group, base_style: self.base_style, } } } impl Div where I: ElementInteraction, F: ElementFocus, { pub fn group(mut self, group: impl Into) -> Self { self.group = Some(group.into()); self } pub fn z_index(mut self, z_index: u32) -> Self { self.base_style.z_index = Some(z_index); self } pub fn overflow_hidden(mut self) -> Self { self.base_style.overflow.x = Some(Overflow::Hidden); self.base_style.overflow.y = Some(Overflow::Hidden); self } pub fn overflow_hidden_x(mut self) -> Self { self.base_style.overflow.x = Some(Overflow::Hidden); self } pub fn overflow_hidden_y(mut self) -> Self { self.base_style.overflow.y = Some(Overflow::Hidden); self } fn with_element_id( &mut self, cx: &mut ViewContext, f: impl FnOnce(&mut Self, Option, &mut ViewContext) -> R, ) -> R { if let Some(id) = self.id() { cx.with_element_id(id, |global_id, cx| f(self, Some(global_id), cx)) } else { f(self, None, cx) } } pub fn compute_style( &self, bounds: Bounds, element_state: &DivState, cx: &mut ViewContext, ) -> Style { let mut computed_style = Style::default(); computed_style.refine(&self.base_style); self.focus.refine_style(&mut computed_style, cx); self.interaction .refine_style(&mut computed_style, bounds, &element_state.interactive, cx); computed_style } } impl Div, FocusDisabled> { pub fn focusable(self) -> Div, FocusEnabled> { Div { interaction: self.interaction, focus: FocusEnabled::new(), children: self.children, group: self.group, base_style: self.base_style, } } pub fn track_focus( self, handle: &FocusHandle, ) -> Div, FocusEnabled> { Div { interaction: self.interaction, focus: FocusEnabled::tracked(handle), children: self.children, group: self.group, base_style: self.base_style, } } pub fn overflow_scroll(mut self) -> Self { self.base_style.overflow.x = Some(Overflow::Scroll); self.base_style.overflow.y = Some(Overflow::Scroll); self } pub fn overflow_x_scroll(mut self) -> Self { self.base_style.overflow.x = Some(Overflow::Scroll); self } pub fn overflow_y_scroll(mut self) -> Self { self.base_style.overflow.y = Some(Overflow::Scroll); self } } impl Div, FocusDisabled> { pub fn track_focus( self, handle: &FocusHandle, ) -> Div, FocusEnabled> { Div { interaction: self.interaction.into_stateful(handle), focus: handle.clone().into(), children: self.children, group: self.group, base_style: self.base_style, } } } impl Focusable for Div> where V: 'static, I: ElementInteraction, { fn focus_listeners(&mut self) -> &mut FocusListeners { &mut self.focus.focus_listeners } fn set_focus_style(&mut self, style: StyleRefinement) { self.focus.focus_style = style; } fn set_focus_in_style(&mut self, style: StyleRefinement) { self.focus.focus_in_style = style; } fn set_in_focus_style(&mut self, style: StyleRefinement) { self.focus.in_focus_style = style; } } #[derive(Default)] pub struct DivState { interactive: InteractiveElementState, focus_handle: Option, child_layout_ids: SmallVec<[LayoutId; 4]>, } impl Element for Div where I: ElementInteraction, F: ElementFocus, { type ElementState = DivState; fn id(&self) -> Option { self.interaction .as_stateful() .map(|identified| identified.id.clone()) } fn initialize( &mut self, view_state: &mut V, element_state: Option, cx: &mut ViewContext, ) -> Self::ElementState { let mut element_state = element_state.unwrap_or_default(); self.focus .initialize(element_state.focus_handle.take(), cx, |focus_handle, cx| { element_state.focus_handle = focus_handle; self.interaction.initialize(cx, |cx| { for child in &mut self.children { child.initialize(view_state, cx); } }) }); element_state } fn layout( &mut self, view_state: &mut V, element_state: &mut Self::ElementState, cx: &mut ViewContext, ) -> LayoutId { let style = self.compute_style(Bounds::default(), element_state, cx); style.apply_text_style(cx, |cx| { self.with_element_id(cx, |this, _global_id, cx| { let layout_ids = this .children .iter_mut() .map(|child| child.layout(view_state, cx)) .collect::>(); element_state.child_layout_ids = layout_ids.clone(); cx.request_layout(&style, layout_ids) }) }) } fn paint( &mut self, bounds: Bounds, view_state: &mut V, element_state: &mut Self::ElementState, cx: &mut ViewContext, ) { self.with_element_id(cx, |this, _global_id, cx| { if let Some(group) = this.group.clone() { GroupBounds::push(group, bounds, cx); } let style = this.compute_style(bounds, element_state, cx); let z_index = style.z_index.unwrap_or(0); let mut child_min = point(Pixels::MAX, Pixels::MAX); let mut child_max = Point::default(); let content_size = if element_state.child_layout_ids.is_empty() { bounds.size } else { for child_layout_id in &element_state.child_layout_ids { let child_bounds = cx.layout_bounds(*child_layout_id); child_min = child_min.min(&child_bounds.origin); child_max = child_max.max(&child_bounds.lower_right()); } (child_max - child_min).into() }; cx.stack(z_index, |cx| { cx.stack(0, |cx| { style.paint(bounds, cx); this.focus.paint(bounds, cx); this.interaction.paint( bounds, content_size, style.overflow, &mut element_state.interactive, cx, ); }); cx.stack(1, |cx| { style.apply_text_style(cx, |cx| { style.apply_overflow(bounds, cx, |cx| { let scroll_offset = element_state.interactive.scroll_offset(); cx.with_element_offset(scroll_offset, |cx| { for child in &mut this.children { child.paint(view_state, cx); } }); }) }) }); }); if let Some(group) = this.group.as_ref() { GroupBounds::pop(group, cx); } }) } } impl Component for Div where I: ElementInteraction, F: ElementFocus, { fn render(self) -> AnyElement { AnyElement::new(self) } } impl ParentElement for Div where I: ElementInteraction, F: ElementFocus, { fn children_mut(&mut self) -> &mut SmallVec<[AnyElement; 2]> { &mut self.children } } impl Styled for Div where I: ElementInteraction, F: ElementFocus, { fn style(&mut self) -> &mut StyleRefinement { &mut self.base_style } } impl StatelessInteractive for Div where I: ElementInteraction, F: ElementFocus, { fn stateless_interaction(&mut self) -> &mut StatelessInteraction { self.interaction.as_stateless_mut() } } impl StatefulInteractive for Div, F> where F: ElementFocus, { fn stateful_interaction(&mut self) -> &mut StatefulInteraction { &mut self.interaction } }