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, KeyDownEvent, KeyMatch, LayoutId,
5 MouseClickEvent, MouseDownEvent, MouseMoveEvent, MouseUpEvent, NonFocusable, Overflow,
6 ParentElement, Pixels, Point, ScrollWheelEvent, SharedString, Style, StyleRefinement, Styled,
7 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, &mut ViewContext<V>) -> R,
192 ) -> R {
193 if let Some(id) = self.id() {
194 cx.with_element_id(id, |cx| f(self, cx))
195 } else {
196 f(self, 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 let element_state = element_state.unwrap_or_default();
428 for listener in self.listeners.focus.iter().cloned() {
429 cx.on_focus_changed(move |view, event, cx| listener(view, event, cx));
430 }
431
432 let mut key_listeners = mem::take(&mut self.listeners.key);
433
434 if let Some(id) = self.id() {
435 key_listeners.push((
436 TypeId::of::<KeyDownEvent>(),
437 Arc::new(move |_, key_down, phase, cx| {
438 if phase == DispatchPhase::Bubble {
439 let key_down = key_down.downcast_ref::<KeyDownEvent>().unwrap();
440 if let KeyMatch::Some(action) = cx.match_keystroke(&id, &key_down.keystroke)
441 {
442 return Some(action);
443 }
444 }
445
446 None
447 }),
448 ));
449 }
450
451 cx.with_key_listeners(&key_listeners, |cx| {
452 if let Some(focus_handle) = self.focusability.focus_handle().cloned() {
453 cx.with_focus(focus_handle, |cx| {
454 for child in &mut self.children {
455 child.initialize(view_state, cx);
456 }
457 })
458 } else {
459 for child in &mut self.children {
460 child.initialize(view_state, cx);
461 }
462 }
463 });
464 self.listeners.key = key_listeners;
465
466 element_state
467 }
468
469 fn layout(
470 &mut self,
471 view_state: &mut Self::ViewState,
472 element_state: &mut Self::ElementState,
473 cx: &mut ViewContext<Self::ViewState>,
474 ) -> LayoutId {
475 let style = self.compute_style(Bounds::default(), element_state, cx);
476 style.apply_text_style(cx, |cx| {
477 self.with_element_id(cx, |this, cx| {
478 let layout_ids = this
479 .children
480 .iter_mut()
481 .map(|child| child.layout(view_state, cx))
482 .collect::<Vec<_>>();
483 cx.request_layout(&style, layout_ids)
484 })
485 })
486 }
487
488 fn paint(
489 &mut self,
490 bounds: Bounds<Pixels>,
491 view_state: &mut Self::ViewState,
492 element_state: &mut Self::ElementState,
493 cx: &mut ViewContext<Self::ViewState>,
494 ) {
495 self.with_element_id(cx, |this, cx| {
496 if let Some(group) = this.group.clone() {
497 cx.default_global::<GroupBounds>()
498 .0
499 .entry(group)
500 .or_default()
501 .push(bounds);
502 }
503
504 let hover_group_bounds = this
505 .group_hover
506 .as_ref()
507 .and_then(|group_hover| group_bounds(&group_hover.group, cx));
508 let active_group_bounds = this
509 .group_active
510 .as_ref()
511 .and_then(|group_active| group_bounds(&group_active.group, cx));
512 let style = this.compute_style(bounds, element_state, cx);
513 let z_index = style.z_index.unwrap_or(0);
514
515 // Paint background and event handlers.
516 cx.stack(z_index, |cx| {
517 cx.stack(0, |cx| {
518 style.paint(bounds, cx);
519 this.paint_hover_listeners(bounds, hover_group_bounds, cx);
520 this.paint_active_listener(
521 bounds,
522 active_group_bounds,
523 element_state.active_state.clone(),
524 cx,
525 );
526 this.paint_event_listeners(bounds, element_state.pending_click.clone(), cx);
527 });
528
529 cx.stack(1, |cx| {
530 style.apply_text_style(cx, |cx| {
531 style.apply_overflow(bounds, cx, |cx| {
532 for child in &mut this.children {
533 child.paint(view_state, None, cx);
534 }
535 })
536 })
537 });
538 });
539
540 if let Some(group) = this.group.as_ref() {
541 cx.default_global::<GroupBounds>()
542 .0
543 .get_mut(group)
544 .unwrap()
545 .pop();
546 }
547 })
548 }
549}
550
551impl<V, I, F> IntoAnyElement<V> for Div<V, I, F>
552where
553 I: ElementIdentity,
554 F: ElementFocusability,
555 V: 'static + Send + Sync,
556{
557 fn into_any(self) -> AnyElement<V> {
558 AnyElement::new(self)
559 }
560}
561
562impl<V, I, F> ParentElement for Div<V, I, F>
563where
564 I: ElementIdentity,
565 F: ElementFocusability,
566 V: 'static + Send + Sync,
567{
568 fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<Self::ViewState>; 2]> {
569 &mut self.children
570 }
571}
572
573impl<V, I, F> Styled for Div<V, I, F>
574where
575 I: ElementIdentity,
576 F: ElementFocusability,
577 V: 'static + Send + Sync,
578{
579 fn style(&mut self) -> &mut StyleRefinement {
580 &mut self.base_style
581 }
582}
583
584impl<V, I, F> Interactive for Div<V, I, F>
585where
586 I: ElementIdentity,
587 F: ElementFocusability,
588 V: 'static + Send + Sync,
589{
590 fn listeners(&mut self) -> &mut EventListeners<V> {
591 &mut self.listeners
592 }
593}
594
595impl<V, I, F> Hover for Div<V, I, F>
596where
597 I: ElementIdentity,
598 F: ElementFocusability,
599 V: 'static + Send + Sync,
600{
601 fn set_hover_style(&mut self, group: Option<SharedString>, style: StyleRefinement) {
602 if let Some(group) = group {
603 self.group_hover = Some(GroupStyle { group, style });
604 } else {
605 self.hover_style = style;
606 }
607 }
608}
609
610impl<V, F> Click for Div<V, Identified, F>
611where
612 F: ElementFocusability,
613 V: 'static + Send + Sync,
614{
615}
616
617impl<V, F> Active for Div<V, Identified, F>
618where
619 F: ElementFocusability,
620 V: 'static + Send + Sync,
621{
622 fn set_active_style(&mut self, group: Option<SharedString>, style: StyleRefinement) {
623 if let Some(group) = group {
624 self.group_active = Some(GroupStyle { group, style });
625 } else {
626 self.active_style = style;
627 }
628 }
629}
630
631fn paint_hover_listener<V>(bounds: Bounds<Pixels>, cx: &mut ViewContext<V>)
632where
633 V: 'static + Send + Sync,
634{
635 let hovered = bounds.contains_point(&cx.mouse_position());
636 cx.on_mouse_event(move |_, event: &MouseMoveEvent, phase, cx| {
637 if phase == DispatchPhase::Capture {
638 if bounds.contains_point(&event.position) != hovered {
639 cx.notify();
640 }
641 }
642 });
643}