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}