1use crate::{
2 AppContext, BorrowWindow, Bounds, DispatchPhase, ElementId, FocusHandle, FocusListeners,
3 KeyDownEvent, KeyListener, KeyMatch, LayoutId, MouseClickEvent, MouseClickListener,
4 MouseDownEvent, MouseDownListener, MouseMoveEvent, MouseMoveListener, MouseUpEvent,
5 MouseUpListener, Pixels, Point, ScrollWheelEvent, ScrollWheelListener, SharedString, Style,
6 StyleRefinement, ViewContext, WindowContext,
7};
8use collections::HashMap;
9use derive_more::{Deref, DerefMut};
10use parking_lot::Mutex;
11use refineable::Refineable;
12pub(crate) use smallvec::SmallVec;
13use std::{any::TypeId, mem, sync::Arc};
14
15pub trait Element: 'static + Send + Sync + IntoAnyElement<Self::ViewState> {
16 type ViewState: 'static + Send + Sync;
17 type ElementState: 'static + Send + Sync;
18
19 fn id(&self) -> Option<ElementId>;
20
21 fn initialize(
22 &mut self,
23 view_state: &mut Self::ViewState,
24 element_state: Option<Self::ElementState>,
25 cx: &mut ViewContext<Self::ViewState>,
26 ) -> Self::ElementState;
27
28 fn layout(
29 &mut self,
30 view_state: &mut Self::ViewState,
31 element_state: &mut Self::ElementState,
32 cx: &mut ViewContext<Self::ViewState>,
33 ) -> LayoutId;
34
35 fn paint(
36 &mut self,
37 bounds: Bounds<Pixels>,
38 view_state: &mut Self::ViewState,
39 element_state: &mut Self::ElementState,
40 cx: &mut ViewContext<Self::ViewState>,
41 );
42}
43
44#[derive(Deref, DerefMut, Default, Clone, Debug, Eq, PartialEq, Hash)]
45pub struct GlobalElementId(SmallVec<[ElementId; 32]>);
46
47pub trait ElementInteractivity<V: 'static + Send + Sync>: 'static + Send + Sync {
48 fn as_stateless(&self) -> &StatelessInteractivity<V>;
49 fn as_stateless_mut(&mut self) -> &mut StatelessInteractivity<V>;
50 fn as_stateful(&self) -> Option<&StatefulInteractivity<V>>;
51 fn as_stateful_mut(&mut self) -> Option<&mut StatefulInteractivity<V>>;
52
53 fn initialize<R>(
54 &mut self,
55 cx: &mut ViewContext<V>,
56 f: impl FnOnce(&mut ViewContext<V>) -> R,
57 ) -> R {
58 if let Some(stateful) = self.as_stateful_mut() {
59 cx.with_element_id(stateful.id.clone(), |global_id, cx| {
60 stateful.key_listeners.push((
61 TypeId::of::<KeyDownEvent>(),
62 Arc::new(move |_, key_down, context, phase, cx| {
63 if phase == DispatchPhase::Bubble {
64 let key_down = key_down.downcast_ref::<KeyDownEvent>().unwrap();
65 if let KeyMatch::Some(action) =
66 cx.match_keystroke(&global_id, &key_down.keystroke, context)
67 {
68 return Some(action);
69 }
70 }
71
72 None
73 }),
74 ));
75 let result = stateful.stateless.initialize(cx, f);
76 stateful.key_listeners.pop();
77 result
78 })
79 } else {
80 cx.with_key_listeners(&self.as_stateless().key_listeners, f)
81 }
82 }
83
84 fn refine_style(&self, style: &mut Style, bounds: Bounds<Pixels>, cx: &mut ViewContext<V>) {
85 let mouse_position = cx.mouse_position();
86 let stateless = self.as_stateless();
87 if let Some(group_hover) = stateless.group_hover.as_ref() {
88 if let Some(group_bounds) = group_bounds(&group_hover.group, cx) {
89 if group_bounds.contains_point(&mouse_position) {
90 style.refine(&group_hover.style);
91 }
92 }
93 }
94 if bounds.contains_point(&mouse_position) {
95 style.refine(&stateless.hover_style);
96 }
97 }
98
99 fn paint(
100 &mut self,
101 bounds: Bounds<Pixels>,
102 pending_click: Arc<Mutex<Option<MouseDownEvent>>>,
103 cx: &mut ViewContext<V>,
104 ) {
105 let stateless = self.as_stateless();
106 for listener in stateless.mouse_down_listeners.iter().cloned() {
107 cx.on_mouse_event(move |state, event: &MouseDownEvent, phase, cx| {
108 listener(state, event, &bounds, phase, cx);
109 })
110 }
111
112 for listener in stateless.mouse_up_listeners.iter().cloned() {
113 cx.on_mouse_event(move |state, event: &MouseUpEvent, phase, cx| {
114 listener(state, event, &bounds, phase, cx);
115 })
116 }
117
118 for listener in stateless.mouse_move_listeners.iter().cloned() {
119 cx.on_mouse_event(move |state, event: &MouseMoveEvent, phase, cx| {
120 listener(state, event, &bounds, phase, cx);
121 })
122 }
123
124 for listener in stateless.scroll_wheel_listeners.iter().cloned() {
125 cx.on_mouse_event(move |state, event: &ScrollWheelEvent, phase, cx| {
126 listener(state, event, &bounds, phase, cx);
127 })
128 }
129
130 let hover_group_bounds = stateless
131 .group_hover
132 .as_ref()
133 .and_then(|group_hover| GroupBounds::get(&group_hover.group, cx));
134
135 if let Some(group_bounds) = hover_group_bounds {
136 paint_hover_listener(group_bounds, cx);
137 }
138
139 if stateless.hover_style.is_some() {
140 paint_hover_listener(bounds, cx);
141 }
142
143 if let Some(stateful) = self.as_stateful() {
144 let click_listeners = stateful.mouse_click_listeners.clone();
145
146 let mouse_down = pending_click.lock().clone();
147 if let Some(mouse_down) = mouse_down {
148 cx.on_mouse_event(move |state, event: &MouseUpEvent, phase, cx| {
149 if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
150 let mouse_click = MouseClickEvent {
151 down: mouse_down.clone(),
152 up: event.clone(),
153 };
154 for listener in &click_listeners {
155 listener(state, &mouse_click, cx);
156 }
157 }
158
159 *pending_click.lock() = None;
160 });
161 } else {
162 cx.on_mouse_event(move |_state, event: &MouseDownEvent, phase, _cx| {
163 if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
164 *pending_click.lock() = Some(event.clone());
165 }
166 });
167 };
168 }
169 }
170}
171
172fn paint_hover_listener<V>(bounds: Bounds<Pixels>, cx: &mut ViewContext<V>)
173where
174 V: 'static + Send + Sync,
175{
176 let hovered = bounds.contains_point(&cx.mouse_position());
177 cx.on_mouse_event(move |_, event: &MouseMoveEvent, phase, cx| {
178 if phase == DispatchPhase::Capture {
179 if bounds.contains_point(&event.position) != hovered {
180 cx.notify();
181 }
182 }
183 });
184}
185
186#[derive(Deref, DerefMut)]
187pub struct StatefulInteractivity<V: 'static + Send + Sync> {
188 pub id: ElementId,
189 #[deref]
190 #[deref_mut]
191 stateless: StatelessInteractivity<V>,
192 pub mouse_click_listeners: SmallVec<[MouseClickListener<V>; 2]>,
193}
194
195impl<V> ElementInteractivity<V> for StatefulInteractivity<V>
196where
197 V: 'static + Send + Sync,
198{
199 fn as_stateful(&self) -> Option<&StatefulInteractivity<V>> {
200 Some(self)
201 }
202
203 fn as_stateful_mut(&mut self) -> Option<&mut StatefulInteractivity<V>> {
204 Some(self)
205 }
206
207 fn as_stateless(&self) -> &StatelessInteractivity<V> {
208 &self.stateless
209 }
210
211 fn as_stateless_mut(&mut self) -> &mut StatelessInteractivity<V> {
212 &mut self.stateless
213 }
214}
215
216impl<V> From<ElementId> for StatefulInteractivity<V>
217where
218 V: 'static + Send + Sync,
219{
220 fn from(id: ElementId) -> Self {
221 Self {
222 id,
223 stateless: StatelessInteractivity::default(),
224 mouse_click_listeners: SmallVec::new(),
225 }
226 }
227}
228
229pub struct StatelessInteractivity<V> {
230 pub mouse_down_listeners: SmallVec<[MouseDownListener<V>; 2]>,
231 pub mouse_up_listeners: SmallVec<[MouseUpListener<V>; 2]>,
232 pub mouse_move_listeners: SmallVec<[MouseMoveListener<V>; 2]>,
233 pub scroll_wheel_listeners: SmallVec<[ScrollWheelListener<V>; 2]>,
234 pub key_listeners: SmallVec<[(TypeId, KeyListener<V>); 32]>,
235 pub hover_style: StyleRefinement,
236 pub group_hover: Option<GroupStyle>,
237}
238
239pub struct GroupStyle {
240 pub group: SharedString,
241 pub style: StyleRefinement,
242}
243
244#[derive(Default)]
245pub struct GroupBounds(HashMap<SharedString, SmallVec<[Bounds<Pixels>; 1]>>);
246
247impl GroupBounds {
248 pub fn get(name: &SharedString, cx: &mut AppContext) -> Option<Bounds<Pixels>> {
249 cx.default_global::<Self>()
250 .0
251 .get(name)
252 .and_then(|bounds_stack| bounds_stack.last())
253 .cloned()
254 }
255
256 pub fn push(name: SharedString, bounds: Bounds<Pixels>, cx: &mut AppContext) {
257 cx.default_global::<Self>()
258 .0
259 .entry(name)
260 .or_default()
261 .push(bounds);
262 }
263
264 pub fn pop(name: &SharedString, cx: &mut AppContext) {
265 cx.default_global::<GroupBounds>()
266 .0
267 .get_mut(name)
268 .unwrap()
269 .pop();
270 }
271}
272
273pub fn group_bounds(name: &SharedString, cx: &mut AppContext) -> Option<Bounds<Pixels>> {
274 cx.default_global::<GroupBounds>()
275 .0
276 .get(name)
277 .and_then(|bounds_stack| bounds_stack.last().cloned())
278}
279
280impl<V> Default for StatelessInteractivity<V> {
281 fn default() -> Self {
282 Self {
283 mouse_down_listeners: SmallVec::new(),
284 mouse_up_listeners: SmallVec::new(),
285 mouse_move_listeners: SmallVec::new(),
286 scroll_wheel_listeners: SmallVec::new(),
287 key_listeners: SmallVec::new(),
288 hover_style: StyleRefinement::default(),
289 group_hover: None,
290 }
291 }
292}
293
294impl<V> ElementInteractivity<V> for StatelessInteractivity<V>
295where
296 V: 'static + Send + Sync,
297{
298 fn as_stateful(&self) -> Option<&StatefulInteractivity<V>> {
299 None
300 }
301
302 fn as_stateful_mut(&mut self) -> Option<&mut StatefulInteractivity<V>> {
303 None
304 }
305
306 fn as_stateless(&self) -> &StatelessInteractivity<V> {
307 self
308 }
309
310 fn as_stateless_mut(&mut self) -> &mut StatelessInteractivity<V> {
311 self
312 }
313}
314
315pub trait ElementFocusability<V: 'static + Send + Sync>: 'static + Send + Sync {
316 fn as_focusable(&self) -> Option<&Focusable<V>>;
317
318 fn initialize<R>(
319 &self,
320 cx: &mut ViewContext<V>,
321 f: impl FnOnce(&mut ViewContext<V>) -> R,
322 ) -> R {
323 if let Some(focusable) = self.as_focusable() {
324 for listener in focusable.focus_listeners.iter().cloned() {
325 cx.on_focus_changed(move |view, event, cx| listener(view, event, cx));
326 }
327 cx.with_focus(focusable.focus_handle.clone(), |cx| f(cx))
328 } else {
329 f(cx)
330 }
331 }
332
333 fn refine_style(&self, style: &mut Style, cx: &WindowContext) {
334 if let Some(focusable) = self.as_focusable() {
335 if focusable.focus_handle.contains_focused(cx) {
336 style.refine(&focusable.focus_in_style);
337 }
338
339 if focusable.focus_handle.within_focused(cx) {
340 style.refine(&focusable.in_focus_style);
341 }
342
343 if focusable.focus_handle.is_focused(cx) {
344 style.refine(&focusable.focus_style);
345 }
346 }
347 }
348
349 fn paint(&self, bounds: Bounds<Pixels>, cx: &mut WindowContext) {
350 if let Some(focusable) = self.as_focusable() {
351 let focus_handle = focusable.focus_handle.clone();
352 cx.on_mouse_event(move |event: &MouseDownEvent, phase, cx| {
353 if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
354 if !cx.default_prevented() {
355 cx.focus(&focus_handle);
356 cx.prevent_default();
357 }
358 }
359 })
360 }
361 }
362}
363
364pub struct Focusable<V: 'static + Send + Sync> {
365 pub focus_handle: FocusHandle,
366 pub focus_listeners: FocusListeners<V>,
367 pub focus_style: StyleRefinement,
368 pub focus_in_style: StyleRefinement,
369 pub in_focus_style: StyleRefinement,
370}
371
372impl<V> ElementFocusability<V> for Focusable<V>
373where
374 V: 'static + Send + Sync,
375{
376 fn as_focusable(&self) -> Option<&Focusable<V>> {
377 Some(self)
378 }
379}
380
381impl<V> From<FocusHandle> for Focusable<V>
382where
383 V: 'static + Send + Sync,
384{
385 fn from(value: FocusHandle) -> Self {
386 Self {
387 focus_handle: value,
388 focus_listeners: FocusListeners::default(),
389 focus_style: StyleRefinement::default(),
390 focus_in_style: StyleRefinement::default(),
391 in_focus_style: StyleRefinement::default(),
392 }
393 }
394}
395
396pub struct NonFocusable;
397
398impl<V> ElementFocusability<V> for NonFocusable
399where
400 V: 'static + Send + Sync,
401{
402 fn as_focusable(&self) -> Option<&Focusable<V>> {
403 None
404 }
405}
406
407pub trait ParentElement: Element {
408 fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<Self::ViewState>; 2]>;
409
410 fn child(mut self, child: impl IntoAnyElement<Self::ViewState>) -> Self
411 where
412 Self: Sized,
413 {
414 self.children_mut().push(child.into_any());
415 self
416 }
417
418 fn children(
419 mut self,
420 iter: impl IntoIterator<Item = impl IntoAnyElement<Self::ViewState>>,
421 ) -> Self
422 where
423 Self: Sized,
424 {
425 self.children_mut()
426 .extend(iter.into_iter().map(|item| item.into_any()));
427 self
428 }
429}
430
431trait ElementObject<V>: 'static + Send + Sync {
432 fn initialize(&mut self, view_state: &mut V, cx: &mut ViewContext<V>);
433 fn layout(&mut self, view_state: &mut V, cx: &mut ViewContext<V>) -> LayoutId;
434 fn paint(&mut self, view_state: &mut V, offset: Option<Point<Pixels>>, cx: &mut ViewContext<V>);
435}
436
437struct RenderedElement<E: Element> {
438 element: E,
439 phase: ElementRenderPhase<E::ElementState>,
440}
441
442#[derive(Default)]
443enum ElementRenderPhase<V> {
444 #[default]
445 Start,
446 Initialized {
447 frame_state: Option<V>,
448 },
449 LayoutRequested {
450 layout_id: LayoutId,
451 frame_state: Option<V>,
452 },
453 Painted,
454}
455
456/// Internal struct that wraps an element to store Layout and ElementState after the element is rendered.
457/// It's allocated as a trait object to erase the element type and wrapped in AnyElement<E::State> for
458/// improved usability.
459impl<E: Element> RenderedElement<E> {
460 fn new(element: E) -> Self {
461 RenderedElement {
462 element,
463 phase: ElementRenderPhase::Start,
464 }
465 }
466}
467
468impl<E> ElementObject<E::ViewState> for RenderedElement<E>
469where
470 E: Element,
471{
472 fn initialize(&mut self, view_state: &mut E::ViewState, cx: &mut ViewContext<E::ViewState>) {
473 let frame_state = if let Some(id) = self.element.id() {
474 cx.with_element_state(id, |element_state, cx| {
475 let element_state = self.element.initialize(view_state, element_state, cx);
476 ((), element_state)
477 });
478 None
479 } else {
480 let frame_state = self.element.initialize(view_state, None, cx);
481 Some(frame_state)
482 };
483
484 self.phase = ElementRenderPhase::Initialized { frame_state };
485 }
486
487 fn layout(&mut self, state: &mut E::ViewState, cx: &mut ViewContext<E::ViewState>) -> LayoutId {
488 let layout_id;
489 let mut frame_state;
490 match mem::take(&mut self.phase) {
491 ElementRenderPhase::Initialized {
492 frame_state: initial_frame_state,
493 } => {
494 frame_state = initial_frame_state;
495 if let Some(id) = self.element.id() {
496 layout_id = cx.with_element_state(id, |element_state, cx| {
497 let mut element_state = element_state.unwrap();
498 let layout_id = self.element.layout(state, &mut element_state, cx);
499 (layout_id, element_state)
500 });
501 } else {
502 layout_id = self
503 .element
504 .layout(state, frame_state.as_mut().unwrap(), cx);
505 }
506 }
507 _ => panic!("must call initialize before layout"),
508 };
509
510 self.phase = ElementRenderPhase::LayoutRequested {
511 layout_id,
512 frame_state,
513 };
514 layout_id
515 }
516
517 fn paint(
518 &mut self,
519 view_state: &mut E::ViewState,
520 offset: Option<Point<Pixels>>,
521 cx: &mut ViewContext<E::ViewState>,
522 ) {
523 self.phase = match mem::take(&mut self.phase) {
524 ElementRenderPhase::LayoutRequested {
525 layout_id,
526 mut frame_state,
527 } => {
528 let mut bounds = cx.layout_bounds(layout_id);
529 offset.map(|offset| bounds.origin += offset);
530 if let Some(id) = self.element.id() {
531 cx.with_element_state(id, |element_state, cx| {
532 let mut element_state = element_state.unwrap();
533 self.element
534 .paint(bounds, view_state, &mut element_state, cx);
535 ((), element_state)
536 });
537 } else {
538 self.element
539 .paint(bounds, view_state, frame_state.as_mut().unwrap(), cx);
540 }
541 ElementRenderPhase::Painted
542 }
543
544 _ => panic!("must call layout before paint"),
545 };
546 }
547}
548
549pub struct AnyElement<V>(Box<dyn ElementObject<V>>);
550
551impl<V: 'static + Send + Sync> AnyElement<V> {
552 pub fn new<E: Element<ViewState = V>>(element: E) -> Self {
553 AnyElement(Box::new(RenderedElement::new(element)))
554 }
555
556 pub fn initialize(&mut self, view_state: &mut V, cx: &mut ViewContext<V>) {
557 self.0.initialize(view_state, cx);
558 }
559
560 pub fn layout(&mut self, view_state: &mut V, cx: &mut ViewContext<V>) -> LayoutId {
561 self.0.layout(view_state, cx)
562 }
563
564 pub fn paint(
565 &mut self,
566 view_state: &mut V,
567 offset: Option<Point<Pixels>>,
568 cx: &mut ViewContext<V>,
569 ) {
570 self.0.paint(view_state, offset, cx)
571 }
572}
573
574pub trait IntoAnyElement<V> {
575 fn into_any(self) -> AnyElement<V>;
576}
577
578impl<V> IntoAnyElement<V> for AnyElement<V> {
579 fn into_any(self) -> AnyElement<V> {
580 self
581 }
582}