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