1use crate::{
2 Active, Anonymous, AnyElement, AppContext, BorrowWindow, Bounds, Click, DispatchPhase, Element,
3 ElementFocusability, ElementId, ElementIdentity, EventListeners, Focus, FocusHandle, Focusable,
4 Hover, Identified, Interactive, IntoAnyElement, LayoutId, MouseClickEvent, MouseDownEvent,
5 MouseMoveEvent, MouseUpEvent, NonFocusable, Overflow, ParentElement, Pixels, Point,
6 ScrollWheelEvent, SharedString, Style, StyleRefinement, Styled, ViewContext,
7};
8use collections::HashMap;
9use parking_lot::Mutex;
10use refineable::Refineable;
11use smallvec::SmallVec;
12use std::{mem, 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)]
33struct GroupBounds(HashMap<SharedString, SmallVec<[Bounds<Pixels>; 1]>>);
34
35pub fn group_bounds(name: &SharedString, cx: &mut AppContext) -> Option<Bounds<Pixels>> {
36 cx.default_global::<GroupBounds>()
37 .0
38 .get(name)
39 .and_then(|bounds_stack| bounds_stack.last().cloned())
40}
41
42#[derive(Default, Clone)]
43pub struct ScrollState(Arc<Mutex<Point<Pixels>>>);
44
45impl ScrollState {
46 pub fn x(&self) -> Pixels {
47 self.0.lock().x
48 }
49
50 pub fn set_x(&self, value: Pixels) {
51 self.0.lock().x = value;
52 }
53
54 pub fn y(&self) -> Pixels {
55 self.0.lock().y
56 }
57
58 pub fn set_y(&self, value: Pixels) {
59 self.0.lock().y = value;
60 }
61}
62
63pub fn div<V>() -> Div<V, Anonymous, NonFocusable>
64where
65 V: 'static + Send + Sync,
66{
67 Div {
68 identity: Anonymous,
69 focusability: NonFocusable,
70 children: SmallVec::new(),
71 group: None,
72 base_style: StyleRefinement::default(),
73 hover_style: StyleRefinement::default(),
74 group_hover: None,
75 active_style: StyleRefinement::default(),
76 group_active: None,
77 focus_style: StyleRefinement::default(),
78 focus_in_style: StyleRefinement::default(),
79 in_focus_style: StyleRefinement::default(),
80 listeners: EventListeners::default(),
81 }
82}
83
84pub struct Div<
85 V: 'static + Send + Sync,
86 I: ElementIdentity = Anonymous,
87 F: ElementFocusability = NonFocusable,
88> {
89 identity: I,
90 focusability: F,
91 children: SmallVec<[AnyElement<V>; 2]>,
92 group: Option<SharedString>,
93 base_style: StyleRefinement,
94 hover_style: StyleRefinement,
95 group_hover: Option<GroupStyle>,
96 active_style: StyleRefinement,
97 group_active: Option<GroupStyle>,
98 focus_style: StyleRefinement,
99 focus_in_style: StyleRefinement,
100 in_focus_style: StyleRefinement,
101 listeners: EventListeners<V>,
102}
103
104struct GroupStyle {
105 group: SharedString,
106 style: StyleRefinement,
107}
108
109impl<V, F> Div<V, Anonymous, F>
110where
111 F: ElementFocusability,
112 V: 'static + Send + Sync,
113{
114 pub fn id(self, id: impl Into<ElementId>) -> Div<V, Identified, F> {
115 Div {
116 identity: Identified(id.into()),
117 focusability: self.focusability,
118 children: self.children,
119 group: self.group,
120 base_style: self.base_style,
121 hover_style: self.hover_style,
122 group_hover: self.group_hover,
123 active_style: self.active_style,
124 group_active: self.group_active,
125 focus_style: self.focus_style,
126 focus_in_style: self.focus_in_style,
127 in_focus_style: self.in_focus_style,
128 listeners: self.listeners,
129 }
130 }
131}
132
133impl<V, I, F> Div<V, I, F>
134where
135 I: ElementIdentity,
136 F: ElementFocusability,
137 V: 'static + Send + Sync,
138{
139 pub fn group(mut self, group: impl Into<SharedString>) -> Self {
140 self.group = Some(group.into());
141 self
142 }
143
144 pub fn z_index(mut self, z_index: u32) -> Self {
145 self.base_style.z_index = Some(z_index);
146 self
147 }
148
149 pub fn overflow_hidden(mut self) -> Self {
150 self.base_style.overflow.x = Some(Overflow::Hidden);
151 self.base_style.overflow.y = Some(Overflow::Hidden);
152 self
153 }
154
155 pub fn overflow_hidden_x(mut self) -> Self {
156 self.base_style.overflow.x = Some(Overflow::Hidden);
157 self
158 }
159
160 pub fn overflow_hidden_y(mut self) -> Self {
161 self.base_style.overflow.y = Some(Overflow::Hidden);
162 self
163 }
164
165 pub fn overflow_scroll(mut self, _scroll_state: ScrollState) -> Self {
166 // todo!("impl scrolling")
167 // self.scroll_state = Some(scroll_state);
168 self.base_style.overflow.x = Some(Overflow::Scroll);
169 self.base_style.overflow.y = Some(Overflow::Scroll);
170 self
171 }
172
173 pub fn overflow_x_scroll(mut self, _scroll_state: ScrollState) -> Self {
174 // todo!("impl scrolling")
175 // self.scroll_state = Some(scroll_state);
176 self.base_style.overflow.x = Some(Overflow::Scroll);
177 self
178 }
179
180 pub fn overflow_y_scroll(mut self, _scroll_state: ScrollState) -> Self {
181 // todo!("impl scrolling")
182 // self.scroll_state = Some(scroll_state);
183 self.base_style.overflow.y = Some(Overflow::Scroll);
184 self
185 }
186
187 fn with_element_id<R>(
188 &mut self,
189 cx: &mut ViewContext<V>,
190 f: impl FnOnce(&mut Self, &mut ViewContext<V>) -> R,
191 ) -> R {
192 if let Some(id) = self.id() {
193 cx.with_element_id(id, |cx| f(self, cx))
194 } else {
195 f(self, cx)
196 }
197 }
198
199 pub fn compute_style(
200 &self,
201 bounds: Bounds<Pixels>,
202 state: &DivState,
203 cx: &mut ViewContext<V>,
204 ) -> Style {
205 let mut computed_style = Style::default();
206 computed_style.refine(&self.base_style);
207
208 if let Some(handle) = self.focusability.focus_handle() {
209 if handle.contains_focused(cx) {
210 computed_style.refine(&self.focus_in_style);
211 }
212
213 if handle.within_focused(cx) {
214 computed_style.refine(&self.in_focus_style);
215 }
216
217 if handle.is_focused(cx) {
218 computed_style.refine(&self.focus_style);
219 }
220 }
221
222 let mouse_position = cx.mouse_position();
223
224 if let Some(group_hover) = self.group_hover.as_ref() {
225 if let Some(group_bounds) = group_bounds(&group_hover.group, cx) {
226 if group_bounds.contains_point(&mouse_position) {
227 computed_style.refine(&group_hover.style);
228 }
229 }
230 }
231 if bounds.contains_point(&mouse_position) {
232 computed_style.refine(&self.hover_style);
233 }
234
235 let active_state = *state.active_state.lock();
236 if active_state.group {
237 if let Some(GroupStyle { style, .. }) = self.group_active.as_ref() {
238 computed_style.refine(style);
239 }
240 }
241 if active_state.element {
242 computed_style.refine(&self.active_style);
243 }
244
245 computed_style
246 }
247
248 fn paint_hover_listeners(
249 &self,
250 bounds: Bounds<Pixels>,
251 group_bounds: Option<Bounds<Pixels>>,
252 cx: &mut ViewContext<V>,
253 ) {
254 if let Some(group_bounds) = group_bounds {
255 paint_hover_listener(group_bounds, cx);
256 }
257
258 if self.hover_style.is_some() {
259 paint_hover_listener(bounds, cx);
260 }
261 }
262
263 fn paint_active_listener(
264 &self,
265 bounds: Bounds<Pixels>,
266 group_bounds: Option<Bounds<Pixels>>,
267 active_state: Arc<Mutex<ActiveState>>,
268 cx: &mut ViewContext<V>,
269 ) {
270 if active_state.lock().is_none() {
271 cx.on_mouse_event(move |_view, down: &MouseDownEvent, phase, cx| {
272 if phase == DispatchPhase::Bubble {
273 let group =
274 group_bounds.map_or(false, |bounds| bounds.contains_point(&down.position));
275 let element = bounds.contains_point(&down.position);
276 if group || element {
277 *active_state.lock() = ActiveState { group, element };
278 cx.notify();
279 }
280 }
281 });
282 } else {
283 cx.on_mouse_event(move |_, _: &MouseUpEvent, phase, cx| {
284 if phase == DispatchPhase::Capture {
285 *active_state.lock() = ActiveState::default();
286 cx.notify();
287 }
288 });
289 }
290 }
291
292 fn paint_event_listeners(
293 &mut self,
294 bounds: Bounds<Pixels>,
295 pending_click: Arc<Mutex<Option<MouseDownEvent>>>,
296 cx: &mut ViewContext<V>,
297 ) {
298 let click_listeners = mem::take(&mut self.listeners.mouse_click);
299
300 let mouse_down = pending_click.lock().clone();
301 if let Some(mouse_down) = mouse_down {
302 cx.on_mouse_event(move |state, event: &MouseUpEvent, phase, cx| {
303 if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
304 let mouse_click = MouseClickEvent {
305 down: mouse_down.clone(),
306 up: event.clone(),
307 };
308 for listener in &click_listeners {
309 listener(state, &mouse_click, cx);
310 }
311 }
312
313 *pending_click.lock() = None;
314 });
315 } else {
316 cx.on_mouse_event(move |_state, event: &MouseDownEvent, phase, _cx| {
317 if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
318 *pending_click.lock() = Some(event.clone());
319 }
320 });
321 }
322
323 if let Some(focus_handle) = self.focusability.focus_handle() {
324 let focus_handle = focus_handle.clone();
325 cx.on_mouse_event(move |_, event: &MouseDownEvent, phase, cx| {
326 if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
327 if !cx.default_prevented() {
328 cx.focus(&focus_handle);
329 cx.prevent_default();
330 }
331 }
332 })
333 }
334
335 for listener in mem::take(&mut self.listeners.mouse_down) {
336 cx.on_mouse_event(move |state, event: &MouseDownEvent, phase, cx| {
337 listener(state, event, &bounds, phase, cx);
338 })
339 }
340
341 for listener in mem::take(&mut self.listeners.mouse_up) {
342 cx.on_mouse_event(move |state, event: &MouseUpEvent, phase, cx| {
343 listener(state, event, &bounds, phase, cx);
344 })
345 }
346
347 for listener in mem::take(&mut self.listeners.mouse_move) {
348 cx.on_mouse_event(move |state, event: &MouseMoveEvent, phase, cx| {
349 listener(state, event, &bounds, phase, cx);
350 })
351 }
352
353 for listener in mem::take(&mut self.listeners.scroll_wheel) {
354 cx.on_mouse_event(move |state, event: &ScrollWheelEvent, phase, cx| {
355 listener(state, event, &bounds, phase, cx);
356 })
357 }
358 }
359}
360
361impl<V, I> Div<V, I, NonFocusable>
362where
363 I: ElementIdentity,
364 V: 'static + Send + Sync,
365{
366 pub fn focusable(self, handle: &FocusHandle) -> Div<V, I, Focusable> {
367 Div {
368 identity: self.identity,
369 focusability: handle.clone().into(),
370 children: self.children,
371 group: self.group,
372 base_style: self.base_style,
373 hover_style: self.hover_style,
374 group_hover: self.group_hover,
375 active_style: self.active_style,
376 group_active: self.group_active,
377 focus_style: self.focus_style,
378 focus_in_style: self.focus_in_style,
379 in_focus_style: self.in_focus_style,
380 listeners: self.listeners,
381 }
382 }
383}
384
385impl<V, I> Focus for Div<V, I, Focusable>
386where
387 I: ElementIdentity,
388 V: 'static + Send + Sync,
389{
390 fn handle(&self) -> &FocusHandle {
391 self.focusability.as_ref()
392 }
393
394 fn set_focus_style(&mut self, style: StyleRefinement) {
395 self.focus_style = style;
396 }
397
398 fn set_focus_in_style(&mut self, style: StyleRefinement) {
399 self.focus_in_style = style;
400 }
401
402 fn set_in_focus_style(&mut self, style: StyleRefinement) {
403 self.in_focus_style = style;
404 }
405}
406
407impl<V, I, F> Element for Div<V, I, F>
408where
409 I: ElementIdentity,
410 F: ElementFocusability,
411 V: 'static + Send + Sync,
412{
413 type ViewState = V;
414 type ElementState = DivState;
415
416 fn id(&self) -> Option<ElementId> {
417 self.identity.id()
418 }
419
420 fn initialize(
421 &mut self,
422 view_state: &mut Self::ViewState,
423 element_state: Option<Self::ElementState>,
424 cx: &mut ViewContext<Self::ViewState>,
425 ) -> Self::ElementState {
426 for listener in self.listeners.focus.iter().cloned() {
427 cx.on_focus_changed(move |view, event, cx| listener(view, event, cx));
428 }
429
430 let key_listeners = mem::take(&mut self.listeners.key);
431 cx.with_key_listeners(&key_listeners, |cx| {
432 if let Some(focus_handle) = self.focusability.focus_handle().cloned() {
433 cx.with_focus(focus_handle, |cx| {
434 for child in &mut self.children {
435 child.initialize(view_state, cx);
436 }
437 })
438 } else {
439 for child in &mut self.children {
440 child.initialize(view_state, cx);
441 }
442 }
443 });
444 self.listeners.key = key_listeners;
445
446 element_state.unwrap_or_default()
447 }
448
449 fn layout(
450 &mut self,
451 view_state: &mut Self::ViewState,
452 element_state: &mut Self::ElementState,
453 cx: &mut ViewContext<Self::ViewState>,
454 ) -> LayoutId {
455 let style = self.compute_style(Bounds::default(), element_state, cx);
456 style.apply_text_style(cx, |cx| {
457 self.with_element_id(cx, |this, cx| {
458 let layout_ids = this
459 .children
460 .iter_mut()
461 .map(|child| child.layout(view_state, cx))
462 .collect::<Vec<_>>();
463 cx.request_layout(&style, layout_ids)
464 })
465 })
466 }
467
468 fn paint(
469 &mut self,
470 bounds: Bounds<Pixels>,
471 view_state: &mut Self::ViewState,
472 element_state: &mut Self::ElementState,
473 cx: &mut ViewContext<Self::ViewState>,
474 ) {
475 self.with_element_id(cx, |this, cx| {
476 if let Some(group) = this.group.clone() {
477 cx.default_global::<GroupBounds>()
478 .0
479 .entry(group)
480 .or_default()
481 .push(bounds);
482 }
483
484 let hover_group_bounds = this
485 .group_hover
486 .as_ref()
487 .and_then(|group_hover| group_bounds(&group_hover.group, cx));
488 let active_group_bounds = this
489 .group_active
490 .as_ref()
491 .and_then(|group_active| group_bounds(&group_active.group, cx));
492 let style = this.compute_style(bounds, element_state, cx);
493 let z_index = style.z_index.unwrap_or(0);
494
495 // Paint background and event handlers.
496 cx.stack(z_index, |cx| {
497 cx.stack(0, |cx| {
498 style.paint(bounds, cx);
499 this.paint_hover_listeners(bounds, hover_group_bounds, cx);
500 this.paint_active_listener(
501 bounds,
502 active_group_bounds,
503 element_state.active_state.clone(),
504 cx,
505 );
506 this.paint_event_listeners(bounds, element_state.pending_click.clone(), cx);
507 });
508
509 cx.stack(1, |cx| {
510 style.apply_text_style(cx, |cx| {
511 style.apply_overflow(bounds, cx, |cx| {
512 for child in &mut this.children {
513 child.paint(view_state, None, cx);
514 }
515 })
516 })
517 });
518 });
519
520 if let Some(group) = this.group.as_ref() {
521 cx.default_global::<GroupBounds>()
522 .0
523 .get_mut(group)
524 .unwrap()
525 .pop();
526 }
527 })
528 }
529}
530
531impl<V, I, F> IntoAnyElement<V> for Div<V, I, F>
532where
533 I: ElementIdentity,
534 F: ElementFocusability,
535 V: 'static + Send + Sync,
536{
537 fn into_any(self) -> AnyElement<V> {
538 AnyElement::new(self)
539 }
540}
541
542impl<V, I, F> ParentElement for Div<V, I, F>
543where
544 I: ElementIdentity,
545 F: ElementFocusability,
546 V: 'static + Send + Sync,
547{
548 fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<Self::ViewState>; 2]> {
549 &mut self.children
550 }
551}
552
553impl<V, I, F> Styled for Div<V, I, F>
554where
555 I: ElementIdentity,
556 F: ElementFocusability,
557 V: 'static + Send + Sync,
558{
559 fn style(&mut self) -> &mut StyleRefinement {
560 &mut self.base_style
561 }
562}
563
564impl<V, I, F> Interactive for Div<V, I, F>
565where
566 I: ElementIdentity,
567 F: ElementFocusability,
568 V: 'static + Send + Sync,
569{
570 fn listeners(&mut self) -> &mut EventListeners<V> {
571 &mut self.listeners
572 }
573}
574
575impl<V, I, F> Hover for Div<V, I, F>
576where
577 I: ElementIdentity,
578 F: ElementFocusability,
579 V: 'static + Send + Sync,
580{
581 fn set_hover_style(&mut self, group: Option<SharedString>, style: StyleRefinement) {
582 if let Some(group) = group {
583 self.group_hover = Some(GroupStyle { group, style });
584 } else {
585 self.hover_style = style;
586 }
587 }
588}
589
590impl<V, F> Click for Div<V, Identified, F>
591where
592 F: ElementFocusability,
593 V: 'static + Send + Sync,
594{
595}
596
597impl<V, F> Active for Div<V, Identified, F>
598where
599 F: ElementFocusability,
600 V: 'static + Send + Sync,
601{
602 fn set_active_style(&mut self, group: Option<SharedString>, style: StyleRefinement) {
603 if let Some(group) = group {
604 self.group_active = Some(GroupStyle { group, style });
605 } else {
606 self.active_style = style;
607 }
608 }
609}
610
611fn paint_hover_listener<V>(bounds: Bounds<Pixels>, cx: &mut ViewContext<V>)
612where
613 V: 'static + Send + Sync,
614{
615 let hovered = bounds.contains_point(&cx.mouse_position());
616 cx.on_mouse_event(move |_, event: &MouseMoveEvent, phase, cx| {
617 if phase == DispatchPhase::Capture {
618 if bounds.contains_point(&event.position) != hovered {
619 cx.notify();
620 }
621 }
622 });
623}