1use std::fmt::Debug;
2
3use crate::{
4 point, AnyElement, BorrowWindow, Bounds, Component, Element, ElementId, ElementInteractivity,
5 FocusHandle, FocusListeners, Focusable, FocusableKeyDispatch, GlobalElementId, 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 fn with_element_id<R>(
97 &mut self,
98 cx: &mut ViewContext<V>,
99 f: impl FnOnce(&mut Self, Option<GlobalElementId>, &mut ViewContext<V>) -> R,
100 ) -> R {
101 if let Some(id) = self.id() {
102 cx.with_element_id(id, |global_id, cx| f(self, Some(global_id), cx))
103 } else {
104 f(self, None, cx)
105 }
106 }
107
108 pub fn compute_style(
109 &self,
110 bounds: Bounds<Pixels>,
111 element_state: &DivState,
112 cx: &mut ViewContext<V>,
113 ) -> Style {
114 let mut computed_style = Style::default();
115 computed_style.refine(&self.base_style);
116 self.key_dispatch.refine_style(&mut computed_style, cx);
117 self.interactivity.refine_style(
118 &mut computed_style,
119 bounds,
120 &element_state.interactive,
121 cx,
122 );
123 computed_style
124 }
125}
126
127impl<V: 'static> Div<V, StatefulInteractivity<V>, NonFocusableKeyDispatch> {
128 pub fn focusable(self) -> Div<V, StatefulInteractivity<V>, FocusableKeyDispatch<V>> {
129 Div {
130 interactivity: self.interactivity,
131 key_dispatch: FocusableKeyDispatch::new(self.key_dispatch),
132 children: self.children,
133 group: self.group,
134 base_style: self.base_style,
135 }
136 }
137
138 pub fn track_focus(
139 self,
140 handle: &FocusHandle,
141 ) -> Div<V, StatefulInteractivity<V>, FocusableKeyDispatch<V>> {
142 Div {
143 interactivity: self.interactivity,
144 key_dispatch: FocusableKeyDispatch::tracked(self.key_dispatch, handle),
145 children: self.children,
146 group: self.group,
147 base_style: self.base_style,
148 }
149 }
150
151 pub fn overflow_scroll(mut self) -> Self {
152 self.base_style.overflow.x = Some(Overflow::Scroll);
153 self.base_style.overflow.y = Some(Overflow::Scroll);
154 self
155 }
156
157 pub fn overflow_x_scroll(mut self) -> Self {
158 self.base_style.overflow.x = Some(Overflow::Scroll);
159 self
160 }
161
162 pub fn overflow_y_scroll(mut self) -> Self {
163 self.base_style.overflow.y = Some(Overflow::Scroll);
164 self
165 }
166}
167
168impl<V: 'static> Div<V, StatelessInteractivity<V>, NonFocusableKeyDispatch> {
169 pub fn track_focus(
170 self,
171 handle: &FocusHandle,
172 ) -> Div<V, StatefulInteractivity<V>, FocusableKeyDispatch<V>> {
173 Div {
174 interactivity: self.interactivity.into_stateful(handle),
175 key_dispatch: FocusableKeyDispatch::tracked(self.key_dispatch, handle),
176 children: self.children,
177 group: self.group,
178 base_style: self.base_style,
179 }
180 }
181}
182
183impl<V, I> Focusable<V> for Div<V, I, FocusableKeyDispatch<V>>
184where
185 V: 'static,
186 I: ElementInteractivity<V>,
187{
188 fn focus_listeners(&mut self) -> &mut FocusListeners<V> {
189 &mut self.key_dispatch.focus_listeners
190 }
191
192 fn set_focus_style(&mut self, style: StyleRefinement) {
193 self.key_dispatch.focus_style = style;
194 }
195
196 fn set_focus_in_style(&mut self, style: StyleRefinement) {
197 self.key_dispatch.focus_in_style = style;
198 }
199
200 fn set_in_focus_style(&mut self, style: StyleRefinement) {
201 self.key_dispatch.in_focus_style = style;
202 }
203}
204
205#[derive(Default)]
206pub struct DivState {
207 interactive: InteractiveElementState,
208 focus_handle: Option<FocusHandle>,
209 child_layout_ids: SmallVec<[LayoutId; 4]>,
210}
211
212impl<V, I, F> Element<V> for Div<V, I, F>
213where
214 I: ElementInteractivity<V>,
215 F: KeyDispatch<V>,
216{
217 type ElementState = DivState;
218
219 fn id(&self) -> Option<ElementId> {
220 self.interactivity
221 .as_stateful()
222 .map(|identified| identified.id.clone())
223 }
224
225 fn initialize(
226 &mut self,
227 view_state: &mut V,
228 element_state: Option<Self::ElementState>,
229 cx: &mut ViewContext<V>,
230 ) -> Self::ElementState {
231 let mut element_state = element_state.unwrap_or_default();
232 self.with_element_id(cx, |this, _global_id, cx| {
233 this.key_dispatch.initialize(
234 element_state.focus_handle.take(),
235 cx,
236 |focus_handle, cx| {
237 this.interactivity.initialize(cx);
238 element_state.focus_handle = focus_handle;
239 for child in &mut this.children {
240 child.initialize(view_state, cx);
241 }
242 },
243 );
244 });
245 element_state
246 }
247
248 fn layout(
249 &mut self,
250 view_state: &mut V,
251 element_state: &mut Self::ElementState,
252 cx: &mut ViewContext<V>,
253 ) -> LayoutId {
254 let style = self.compute_style(Bounds::default(), element_state, cx);
255 style.apply_text_style(cx, |cx| {
256 self.with_element_id(cx, |this, _global_id, cx| {
257 let layout_ids = this
258 .children
259 .iter_mut()
260 .map(|child| child.layout(view_state, cx))
261 .collect::<SmallVec<_>>();
262 element_state.child_layout_ids = layout_ids.clone();
263 cx.request_layout(&style, layout_ids)
264 })
265 })
266 }
267
268 fn paint(
269 &mut self,
270 bounds: Bounds<Pixels>,
271 view_state: &mut V,
272 element_state: &mut Self::ElementState,
273 cx: &mut ViewContext<V>,
274 ) {
275 self.with_element_id(cx, |this, _global_id, cx| {
276 let style = this.compute_style(bounds, element_state, cx);
277 if style.visibility == Visibility::Hidden {
278 return;
279 }
280
281 if let Some(mouse_cursor) = style.mouse_cursor {
282 let hovered = bounds.contains_point(&cx.mouse_position());
283 if hovered {
284 cx.set_cursor_style(mouse_cursor);
285 }
286 }
287
288 if let Some(group) = this.group.clone() {
289 GroupBounds::push(group, bounds, cx);
290 }
291
292 let z_index = style.z_index.unwrap_or(0);
293
294 let mut child_min = point(Pixels::MAX, Pixels::MAX);
295 let mut child_max = Point::default();
296
297 let content_size = if element_state.child_layout_ids.is_empty() {
298 bounds.size
299 } else {
300 for child_layout_id in &element_state.child_layout_ids {
301 let child_bounds = cx.layout_bounds(*child_layout_id);
302 child_min = child_min.min(&child_bounds.origin);
303 child_max = child_max.max(&child_bounds.lower_right());
304 }
305 (child_max - child_min).into()
306 };
307
308 cx.with_z_index(z_index, |cx| {
309 cx.with_z_index(0, |cx| {
310 style.paint(bounds, cx);
311 this.key_dispatch.paint(bounds, cx);
312 this.interactivity.paint(
313 bounds,
314 content_size,
315 style.overflow,
316 &mut element_state.interactive,
317 cx,
318 );
319 });
320 cx.with_z_index(1, |cx| {
321 style.apply_text_style(cx, |cx| {
322 style.apply_overflow(bounds, cx, |cx| {
323 let scroll_offset = element_state.interactive.scroll_offset();
324 cx.with_element_offset(scroll_offset, |cx| {
325 for child in &mut this.children {
326 child.paint(view_state, cx);
327 }
328 });
329 })
330 })
331 });
332 });
333
334 if let Some(group) = this.group.as_ref() {
335 GroupBounds::pop(group, cx);
336 }
337 })
338 }
339}
340
341impl<V, I, F> Component<V> for Div<V, I, F>
342where
343 I: ElementInteractivity<V>,
344 F: KeyDispatch<V>,
345{
346 fn render(self) -> AnyElement<V> {
347 AnyElement::new(self)
348 }
349}
350
351impl<V, I, F> ParentElement<V> for Div<V, I, F>
352where
353 I: ElementInteractivity<V>,
354 F: KeyDispatch<V>,
355{
356 fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<V>; 2]> {
357 &mut self.children
358 }
359}
360
361impl<V, I, F> Styled for Div<V, I, F>
362where
363 I: ElementInteractivity<V>,
364 F: KeyDispatch<V>,
365{
366 fn style(&mut self) -> &mut StyleRefinement {
367 &mut self.base_style
368 }
369}
370
371impl<V, I, F> StatelessInteractive<V> for Div<V, I, F>
372where
373 I: ElementInteractivity<V>,
374 F: KeyDispatch<V>,
375{
376 fn stateless_interactivity(&mut self) -> &mut StatelessInteractivity<V> {
377 self.interactivity.as_stateless_mut()
378 }
379}
380
381impl<V, F> StatefulInteractive<V> for Div<V, StatefulInteractivity<V>, F>
382where
383 F: KeyDispatch<V>,
384{
385 fn stateful_interactivity(&mut self) -> &mut StatefulInteractivity<V> {
386 &mut self.interactivity
387 }
388}