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