1use crate::{
2 Active, AnyElement, BorrowWindow, Bounds, DispatchPhase, Element, ElementFocusability,
3 ElementId, ElementInteractivity, Focus, FocusHandle, FocusListeners, Focusable,
4 GlobalElementId, GroupBounds, GroupStyle, Hover, IntoAnyElement, LayoutId, MouseDownEvent,
5 MouseUpEvent, NonFocusable, Overflow, ParentElement, Pixels, Point, SharedString,
6 StatefulInteractivity, StatefullyInteractive, StatelessInteractivity, StatelesslyInteractive,
7 Style, StyleRefinement, Styled, ViewContext,
8};
9use parking_lot::Mutex;
10use refineable::Refineable;
11use smallvec::SmallVec;
12use std::sync::Arc;
13
14#[derive(Default)]
15pub struct DivState {
16 active_state: Arc<Mutex<ActiveState>>,
17 pending_click: Arc<Mutex<Option<MouseDownEvent>>>,
18}
19
20#[derive(Copy, Clone, Default, Eq, PartialEq)]
21struct ActiveState {
22 group: bool,
23 element: bool,
24}
25
26impl ActiveState {
27 pub fn is_none(&self) -> bool {
28 !self.group && !self.element
29 }
30}
31
32#[derive(Default, Clone)]
33pub struct ScrollState(Arc<Mutex<Point<Pixels>>>);
34
35impl ScrollState {
36 pub fn x(&self) -> Pixels {
37 self.0.lock().x
38 }
39
40 pub fn set_x(&self, value: Pixels) {
41 self.0.lock().x = value;
42 }
43
44 pub fn y(&self) -> Pixels {
45 self.0.lock().y
46 }
47
48 pub fn set_y(&self, value: Pixels) {
49 self.0.lock().y = value;
50 }
51}
52
53pub struct Div<
54 V: 'static + Send + Sync,
55 I: ElementInteractivity<V> = StatelessInteractivity<V>,
56 F: ElementFocusability<V> = NonFocusable,
57> {
58 interactivity: I,
59 focusability: F,
60 children: SmallVec<[AnyElement<V>; 2]>,
61 group: Option<SharedString>,
62 base_style: StyleRefinement,
63 active_style: StyleRefinement,
64 group_active: Option<GroupStyle>,
65}
66
67pub fn div<V>() -> Div<V, StatelessInteractivity<V>, NonFocusable>
68where
69 V: 'static + Send + Sync,
70{
71 Div {
72 interactivity: StatelessInteractivity::default(),
73 focusability: NonFocusable,
74 children: SmallVec::new(),
75 group: None,
76 base_style: StyleRefinement::default(),
77 active_style: StyleRefinement::default(),
78 group_active: None,
79 }
80}
81
82impl<V, F> Div<V, StatelessInteractivity<V>, F>
83where
84 F: ElementFocusability<V>,
85 V: 'static + Send + Sync,
86{
87 pub fn id(self, id: impl Into<ElementId>) -> Div<V, StatefulInteractivity<V>, F> {
88 Div {
89 interactivity: id.into().into(),
90 focusability: self.focusability,
91 children: self.children,
92 group: self.group,
93 base_style: self.base_style,
94 active_style: self.active_style,
95 group_active: self.group_active,
96 }
97 }
98}
99
100impl<V, I, F> Div<V, I, F>
101where
102 I: ElementInteractivity<V>,
103 F: ElementFocusability<V>,
104 V: 'static + Send + Sync,
105{
106 pub fn group(mut self, group: impl Into<SharedString>) -> Self {
107 self.group = Some(group.into());
108 self
109 }
110
111 pub fn z_index(mut self, z_index: u32) -> Self {
112 self.base_style.z_index = Some(z_index);
113 self
114 }
115
116 pub fn overflow_hidden(mut self) -> Self {
117 self.base_style.overflow.x = Some(Overflow::Hidden);
118 self.base_style.overflow.y = Some(Overflow::Hidden);
119 self
120 }
121
122 pub fn overflow_hidden_x(mut self) -> Self {
123 self.base_style.overflow.x = Some(Overflow::Hidden);
124 self
125 }
126
127 pub fn overflow_hidden_y(mut self) -> Self {
128 self.base_style.overflow.y = Some(Overflow::Hidden);
129 self
130 }
131
132 pub fn overflow_scroll(mut self, _scroll_state: ScrollState) -> Self {
133 // todo!("impl scrolling")
134 // self.scroll_state = Some(scroll_state);
135 self.base_style.overflow.x = Some(Overflow::Scroll);
136 self.base_style.overflow.y = Some(Overflow::Scroll);
137 self
138 }
139
140 pub fn overflow_x_scroll(mut self, _scroll_state: ScrollState) -> Self {
141 // todo!("impl scrolling")
142 // self.scroll_state = Some(scroll_state);
143 self.base_style.overflow.x = Some(Overflow::Scroll);
144 self
145 }
146
147 pub fn overflow_y_scroll(mut self, _scroll_state: ScrollState) -> Self {
148 // todo!("impl scrolling")
149 // self.scroll_state = Some(scroll_state);
150 self.base_style.overflow.y = Some(Overflow::Scroll);
151 self
152 }
153
154 fn with_element_id<R>(
155 &mut self,
156 cx: &mut ViewContext<V>,
157 f: impl FnOnce(&mut Self, Option<GlobalElementId>, &mut ViewContext<V>) -> R,
158 ) -> R {
159 if let Some(id) = self.id() {
160 cx.with_element_id(id, |global_id, cx| f(self, Some(global_id), cx))
161 } else {
162 f(self, None, cx)
163 }
164 }
165
166 pub fn compute_style(
167 &self,
168 bounds: Bounds<Pixels>,
169 state: &DivState,
170 cx: &mut ViewContext<V>,
171 ) -> Style {
172 let mut computed_style = Style::default();
173 computed_style.refine(&self.base_style);
174
175 self.focusability.refine_style(&mut computed_style, cx);
176 self.interactivity
177 .refine_style(&mut computed_style, bounds, cx);
178
179 let active_state = *state.active_state.lock();
180 if active_state.group {
181 if let Some(GroupStyle { style, .. }) = self.group_active.as_ref() {
182 computed_style.refine(style);
183 }
184 }
185 if active_state.element {
186 computed_style.refine(&self.active_style);
187 }
188
189 computed_style
190 }
191
192 fn paint_active_listener(
193 &self,
194 bounds: Bounds<Pixels>,
195 group_bounds: Option<Bounds<Pixels>>,
196 active_state: Arc<Mutex<ActiveState>>,
197 cx: &mut ViewContext<V>,
198 ) {
199 if active_state.lock().is_none() {
200 cx.on_mouse_event(move |_view, down: &MouseDownEvent, phase, cx| {
201 if phase == DispatchPhase::Bubble {
202 let group =
203 group_bounds.map_or(false, |bounds| bounds.contains_point(&down.position));
204 let element = bounds.contains_point(&down.position);
205 if group || element {
206 *active_state.lock() = ActiveState { group, element };
207 cx.notify();
208 }
209 }
210 });
211 } else {
212 cx.on_mouse_event(move |_, _: &MouseUpEvent, phase, cx| {
213 if phase == DispatchPhase::Capture {
214 *active_state.lock() = ActiveState::default();
215 cx.notify();
216 }
217 });
218 }
219 }
220}
221
222impl<V, I> Div<V, I, NonFocusable>
223where
224 I: ElementInteractivity<V>,
225 V: 'static + Send + Sync,
226{
227 pub fn focusable(self, handle: &FocusHandle) -> Div<V, I, Focusable<V>> {
228 Div {
229 interactivity: self.interactivity,
230 focusability: handle.clone().into(),
231 children: self.children,
232 group: self.group,
233 base_style: self.base_style,
234 active_style: self.active_style,
235 group_active: self.group_active,
236 }
237 }
238}
239
240impl<V, I> Focus for Div<V, I, Focusable<V>>
241where
242 I: ElementInteractivity<V>,
243 V: 'static + Send + Sync,
244{
245 fn focus_listeners(&mut self) -> &mut FocusListeners<V> {
246 &mut self.focusability.focus_listeners
247 }
248
249 fn handle(&self) -> &FocusHandle {
250 &self.focusability.focus_handle
251 }
252
253 fn set_focus_style(&mut self, style: StyleRefinement) {
254 self.focusability.focus_style = style;
255 }
256
257 fn set_focus_in_style(&mut self, style: StyleRefinement) {
258 self.focusability.focus_in_style = style;
259 }
260
261 fn set_in_focus_style(&mut self, style: StyleRefinement) {
262 self.focusability.in_focus_style = style;
263 }
264}
265
266impl<V, I, F> Element for Div<V, I, F>
267where
268 I: ElementInteractivity<V>,
269 F: ElementFocusability<V>,
270 V: 'static + Send + Sync,
271{
272 type ViewState = V;
273 type ElementState = DivState;
274
275 fn id(&self) -> Option<ElementId> {
276 self.interactivity
277 .as_stateful()
278 .map(|identified| identified.id.clone())
279 }
280
281 fn initialize(
282 &mut self,
283 view_state: &mut Self::ViewState,
284 element_state: Option<Self::ElementState>,
285 cx: &mut ViewContext<Self::ViewState>,
286 ) -> Self::ElementState {
287 self.interactivity.initialize(cx, |cx| {
288 self.focusability.initialize(cx, |cx| {
289 for child in &mut self.children {
290 child.initialize(view_state, cx);
291 }
292 });
293 });
294 element_state.unwrap_or_default()
295 }
296
297 fn layout(
298 &mut self,
299 view_state: &mut Self::ViewState,
300 element_state: &mut Self::ElementState,
301 cx: &mut ViewContext<Self::ViewState>,
302 ) -> LayoutId {
303 let style = self.compute_style(Bounds::default(), element_state, cx);
304 style.apply_text_style(cx, |cx| {
305 self.with_element_id(cx, |this, _global_id, cx| {
306 let layout_ids = this
307 .children
308 .iter_mut()
309 .map(|child| child.layout(view_state, cx))
310 .collect::<Vec<_>>();
311 cx.request_layout(&style, layout_ids)
312 })
313 })
314 }
315
316 fn paint(
317 &mut self,
318 bounds: Bounds<Pixels>,
319 view_state: &mut Self::ViewState,
320 element_state: &mut Self::ElementState,
321 cx: &mut ViewContext<Self::ViewState>,
322 ) {
323 self.with_element_id(cx, |this, _global_id, cx| {
324 if let Some(group) = this.group.clone() {
325 GroupBounds::push(group, bounds, cx);
326 }
327
328 let active_group_bounds = this
329 .group_active
330 .as_ref()
331 .and_then(|group_active| GroupBounds::get(&group_active.group, cx));
332 let style = this.compute_style(bounds, element_state, cx);
333 let z_index = style.z_index.unwrap_or(0);
334
335 // Paint background and event handlers.
336 cx.stack(z_index, |cx| {
337 cx.stack(0, |cx| {
338 style.paint(bounds, cx);
339 this.paint_active_listener(
340 bounds,
341 active_group_bounds,
342 element_state.active_state.clone(),
343 cx,
344 );
345 this.focusability.paint(bounds, cx);
346 this.interactivity
347 .paint(bounds, element_state.pending_click.clone(), cx);
348 });
349
350 cx.stack(1, |cx| {
351 style.apply_text_style(cx, |cx| {
352 style.apply_overflow(bounds, cx, |cx| {
353 for child in &mut this.children {
354 child.paint(view_state, None, cx);
355 }
356 })
357 })
358 });
359 });
360
361 if let Some(group) = this.group.as_ref() {
362 GroupBounds::pop(group, cx);
363 }
364 })
365 }
366}
367
368impl<V, I, F> IntoAnyElement<V> for Div<V, I, F>
369where
370 I: ElementInteractivity<V>,
371 F: ElementFocusability<V>,
372 V: 'static + Send + Sync,
373{
374 fn into_any(self) -> AnyElement<V> {
375 AnyElement::new(self)
376 }
377}
378
379impl<V, I, F> ParentElement for Div<V, I, F>
380where
381 I: ElementInteractivity<V>,
382 F: ElementFocusability<V>,
383 V: 'static + Send + Sync,
384{
385 fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<Self::ViewState>; 2]> {
386 &mut self.children
387 }
388}
389
390impl<V, I, F> Styled for Div<V, I, F>
391where
392 I: ElementInteractivity<V>,
393 F: ElementFocusability<V>,
394 V: 'static + Send + Sync,
395{
396 fn style(&mut self) -> &mut StyleRefinement {
397 &mut self.base_style
398 }
399}
400
401impl<V, I, F> StatelesslyInteractive for Div<V, I, F>
402where
403 I: ElementInteractivity<V>,
404 F: ElementFocusability<V>,
405 V: 'static + Send + Sync,
406{
407 fn stateless_interactivity(&mut self) -> &mut StatelessInteractivity<V> {
408 self.interactivity.as_stateless_mut()
409 }
410}
411
412impl<V, I, F> Hover for Div<V, I, F>
413where
414 I: ElementInteractivity<V>,
415 F: ElementFocusability<V>,
416 V: 'static + Send + Sync,
417{
418 fn set_hover_style(&mut self, group: Option<SharedString>, style: StyleRefinement) {
419 let stateless = self.interactivity.as_stateless_mut();
420 if let Some(group) = group {
421 stateless.group_hover = Some(GroupStyle { group, style });
422 } else {
423 stateless.hover_style = style;
424 }
425 }
426}
427
428impl<V, F> StatefullyInteractive for Div<V, StatefulInteractivity<V>, F>
429where
430 F: ElementFocusability<V>,
431 V: 'static + Send + Sync,
432{
433 fn stateful_interactivity(&mut self) -> &mut StatefulInteractivity<Self::ViewState> {
434 &mut self.interactivity
435 }
436}
437
438impl<V, F> Active for Div<V, StatefulInteractivity<V>, F>
439where
440 F: ElementFocusability<V>,
441 V: 'static + Send + Sync,
442{
443 fn set_active_style(&mut self, group: Option<SharedString>, style: StyleRefinement) {
444 if let Some(group) = group {
445 self.group_active = Some(GroupStyle { group, style });
446 } else {
447 self.active_style = style;
448 }
449 }
450}