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