1use crate::{
35 App, ArenaBox, AvailableSpace, Bounds, Context, DispatchNodeId, ELEMENT_ARENA, ElementId,
36 FocusHandle, InspectorElementId, LayoutId, Pixels, Point, Size, Style, Window,
37 util::FluentBuilder,
38};
39use derive_more::{Deref, DerefMut};
40pub(crate) use smallvec::SmallVec;
41use std::{
42 any::{Any, type_name},
43 fmt::{self, Debug, Display},
44 mem, panic,
45};
46
47pub trait Element: 'static + IntoElement {
52 type RequestLayoutState: 'static;
55
56 type PrepaintState: 'static;
59
60 fn id(&self) -> Option<ElementId>;
66
67 fn source_location(&self) -> Option<&'static panic::Location<'static>>;
70
71 fn request_layout(
74 &mut self,
75 id: Option<&GlobalElementId>,
76 inspector_id: Option<&InspectorElementId>,
77 window: &mut Window,
78 cx: &mut App,
79 ) -> (LayoutId, Self::RequestLayoutState);
80
81 fn prepaint(
84 &mut self,
85 id: Option<&GlobalElementId>,
86 inspector_id: Option<&InspectorElementId>,
87 bounds: Bounds<Pixels>,
88 request_layout: &mut Self::RequestLayoutState,
89 window: &mut Window,
90 cx: &mut App,
91 ) -> Self::PrepaintState;
92
93 fn paint(
96 &mut self,
97 id: Option<&GlobalElementId>,
98 inspector_id: Option<&InspectorElementId>,
99 bounds: Bounds<Pixels>,
100 request_layout: &mut Self::RequestLayoutState,
101 prepaint: &mut Self::PrepaintState,
102 window: &mut Window,
103 cx: &mut App,
104 );
105
106 fn a11y_role(&self) -> Option<accesskit::Role> {
111 None
112 }
113
114 fn write_a11y_info(&self, _node: &mut accesskit::Node) {}
118
119 fn into_any(self) -> AnyElement {
121 AnyElement::new(self)
122 }
123}
124
125pub trait IntoElement: Sized {
127 type Element: Element;
130
131 fn into_element(self) -> Self::Element;
133
134 fn into_any_element(self) -> AnyElement {
136 self.into_element().into_any()
137 }
138}
139
140impl<T: IntoElement> FluentBuilder for T {}
141
142pub trait Render: 'static + Sized {
145 fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement;
147}
148
149impl Render for Empty {
150 fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
151 Empty
152 }
153}
154
155pub trait RenderOnce: 'static {
161 fn render(self, window: &mut Window, cx: &mut App) -> impl IntoElement;
165}
166
167pub trait ParentElement {
170 fn extend(&mut self, elements: impl IntoIterator<Item = AnyElement>);
172
173 fn child(mut self, child: impl IntoElement) -> Self
175 where
176 Self: Sized,
177 {
178 self.extend(std::iter::once(child.into_element().into_any()));
179 self
180 }
181
182 fn children(mut self, children: impl IntoIterator<Item = impl IntoElement>) -> Self
184 where
185 Self: Sized,
186 {
187 self.extend(children.into_iter().map(|child| child.into_any_element()));
188 self
189 }
190}
191
192#[doc(hidden)]
195pub struct Component<C: RenderOnce> {
196 component: Option<C>,
197 #[cfg(debug_assertions)]
198 source: &'static core::panic::Location<'static>,
199}
200
201impl<C: RenderOnce> Component<C> {
202 #[track_caller]
204 pub fn new(component: C) -> Self {
205 Component {
206 component: Some(component),
207 #[cfg(debug_assertions)]
208 source: core::panic::Location::caller(),
209 }
210 }
211}
212
213impl<C: RenderOnce> Element for Component<C> {
214 type RequestLayoutState = AnyElement;
215 type PrepaintState = ();
216
217 fn id(&self) -> Option<ElementId> {
218 None
219 }
220
221 fn source_location(&self) -> Option<&'static core::panic::Location<'static>> {
222 #[cfg(debug_assertions)]
223 return Some(self.source);
224
225 #[cfg(not(debug_assertions))]
226 return None;
227 }
228
229 fn request_layout(
230 &mut self,
231 _id: Option<&GlobalElementId>,
232 _inspector_id: Option<&InspectorElementId>,
233 window: &mut Window,
234 cx: &mut App,
235 ) -> (LayoutId, Self::RequestLayoutState) {
236 window.with_global_id(ElementId::Name(type_name::<C>().into()), |_, window| {
237 let mut element = self
238 .component
239 .take()
240 .unwrap()
241 .render(window, cx)
242 .into_any_element();
243
244 let layout_id = element.request_layout(window, cx);
245 (layout_id, element)
246 })
247 }
248
249 fn prepaint(
250 &mut self,
251 _id: Option<&GlobalElementId>,
252 _inspector_id: Option<&InspectorElementId>,
253 _: Bounds<Pixels>,
254 element: &mut AnyElement,
255 window: &mut Window,
256 cx: &mut App,
257 ) {
258 window.with_global_id(ElementId::Name(type_name::<C>().into()), |_, window| {
259 element.prepaint(window, cx);
260 })
261 }
262
263 fn paint(
264 &mut self,
265 _id: Option<&GlobalElementId>,
266 _inspector_id: Option<&InspectorElementId>,
267 _: Bounds<Pixels>,
268 element: &mut Self::RequestLayoutState,
269 _: &mut Self::PrepaintState,
270 window: &mut Window,
271 cx: &mut App,
272 ) {
273 window.with_global_id(ElementId::Name(type_name::<C>().into()), |_, window| {
274 element.paint(window, cx);
275 })
276 }
277}
278
279impl<C: RenderOnce> IntoElement for Component<C> {
280 type Element = Self;
281
282 fn into_element(self) -> Self::Element {
283 self
284 }
285}
286
287#[derive(Deref, DerefMut, Default, Debug, Eq, PartialEq, Hash)]
289pub struct GlobalElementId(pub(crate) SmallVec<[ElementId; 32]>);
290
291impl Display for GlobalElementId {
292 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
293 for (i, element_id) in self.0.iter().enumerate() {
294 if i > 0 {
295 write!(f, ".")?;
296 }
297 write!(f, "{}", element_id)?;
298 }
299 Ok(())
300 }
301}
302
303impl GlobalElementId {
304 pub(crate) fn accesskit_node_id(&self) -> accesskit::NodeId {
305 use std::hash::{Hash, Hasher};
306
307 let mut hasher = std::hash::DefaultHasher::default();
308 self.hash(&mut hasher);
309 accesskit::NodeId(hasher.finish())
310 }
311}
312
313trait ElementObject {
314 fn inner_element(&mut self) -> &mut dyn Any;
315
316 fn request_layout(&mut self, window: &mut Window, cx: &mut App) -> LayoutId;
317
318 fn prepaint(&mut self, window: &mut Window, cx: &mut App);
319
320 fn paint(&mut self, window: &mut Window, cx: &mut App);
321
322 fn layout_as_root(
323 &mut self,
324 available_space: Size<AvailableSpace>,
325 window: &mut Window,
326 cx: &mut App,
327 ) -> Size<Pixels>;
328}
329
330pub struct Drawable<E: Element> {
332 pub element: E,
334 phase: ElementDrawPhase<E::RequestLayoutState, E::PrepaintState>,
335}
336
337#[derive(Default)]
338enum ElementDrawPhase<RequestLayoutState, PrepaintState> {
339 #[default]
340 Start,
341 RequestLayout {
342 layout_id: LayoutId,
343 global_id: Option<GlobalElementId>,
344 inspector_id: Option<InspectorElementId>,
345 request_layout: RequestLayoutState,
346 },
347 LayoutComputed {
348 layout_id: LayoutId,
349 global_id: Option<GlobalElementId>,
350 inspector_id: Option<InspectorElementId>,
351 available_space: Size<AvailableSpace>,
352 request_layout: RequestLayoutState,
353 },
354 Prepaint {
355 node_id: DispatchNodeId,
356 global_id: Option<GlobalElementId>,
357 inspector_id: Option<InspectorElementId>,
358 bounds: Bounds<Pixels>,
359 request_layout: RequestLayoutState,
360 prepaint: PrepaintState,
361 },
362 Painted,
363}
364
365impl<E: Element> Drawable<E> {
367 pub(crate) fn new(element: E) -> Self {
368 Drawable {
369 element,
370 phase: ElementDrawPhase::Start,
371 }
372 }
373
374 fn request_layout(&mut self, window: &mut Window, cx: &mut App) -> LayoutId {
375 match mem::take(&mut self.phase) {
376 ElementDrawPhase::Start => {
377 let global_id = self.element.id().map(|element_id| {
378 window.element_id_stack.push(element_id);
379 GlobalElementId(window.element_id_stack.clone())
380 });
381
382 let inspector_id;
383 #[cfg(any(feature = "inspector", debug_assertions))]
384 {
385 inspector_id = self.element.source_location().map(|source| {
386 let path = crate::InspectorElementPath {
387 global_id: GlobalElementId(window.element_id_stack.clone()),
388 source_location: source,
389 };
390 window.build_inspector_element_id(path)
391 });
392 }
393 #[cfg(not(any(feature = "inspector", debug_assertions)))]
394 {
395 inspector_id = None;
396 }
397
398 let (layout_id, request_layout) = self.element.request_layout(
399 global_id.as_ref(),
400 inspector_id.as_ref(),
401 window,
402 cx,
403 );
404
405 if global_id.is_some() {
406 window.element_id_stack.pop();
407 }
408
409 self.phase = ElementDrawPhase::RequestLayout {
410 layout_id,
411 global_id,
412 inspector_id,
413 request_layout,
414 };
415 layout_id
416 }
417 _ => panic!("must call request_layout only once"),
418 }
419 }
420
421 pub(crate) fn prepaint(&mut self, window: &mut Window, cx: &mut App) {
422 match mem::take(&mut self.phase) {
423 ElementDrawPhase::RequestLayout {
424 layout_id,
425 global_id,
426 inspector_id,
427 mut request_layout,
428 }
429 | ElementDrawPhase::LayoutComputed {
430 layout_id,
431 global_id,
432 inspector_id,
433 mut request_layout,
434 ..
435 } => {
436 if let Some(element_id) = self.element.id() {
437 window.element_id_stack.push(element_id);
438 debug_assert_eq!(global_id.as_ref().unwrap().0, window.element_id_stack);
439 }
440
441 let bounds = window.layout_bounds(layout_id);
442 let mut pushed_a11y_node = false;
443 if window.a11y.is_active()
444 && let Some(global_id) = global_id.as_ref()
445 && let Some(role) = self.element.a11y_role()
446 {
447 let node_id = global_id.accesskit_node_id();
448 let mut node = accesskit::Node::new(role);
449 let scale = window.scale_factor();
450 node.set_bounds(accesskit::Rect {
451 x0: f64::from(bounds.origin.x.0 * scale),
452 y0: f64::from(bounds.origin.y.0 * scale),
453 x1: f64::from((bounds.origin.x.0 + bounds.size.width.0) * scale),
454 y1: f64::from((bounds.origin.y.0 + bounds.size.height.0) * scale),
455 });
456 self.element.write_a11y_info(&mut node);
457 window.a11y.node_bounds.insert(node_id, bounds);
458 pushed_a11y_node = window.a11y.nodes.push(node_id, node);
459 }
460
461 let node_id = window.next_frame.dispatch_tree.push_node();
462 let prepaint = self.element.prepaint(
463 global_id.as_ref(),
464 inspector_id.as_ref(),
465 bounds,
466 &mut request_layout,
467 window,
468 cx,
469 );
470 window.next_frame.dispatch_tree.pop_node();
471
472 if pushed_a11y_node {
473 window.a11y.nodes.pop();
474 }
475
476 if global_id.is_some() {
477 window.element_id_stack.pop();
478 }
479
480 self.phase = ElementDrawPhase::Prepaint {
481 node_id,
482 global_id,
483 inspector_id,
484 bounds,
485 request_layout,
486 prepaint,
487 };
488 }
489 _ => panic!("must call request_layout before prepaint"),
490 }
491 }
492
493 pub(crate) fn paint(
494 &mut self,
495 window: &mut Window,
496 cx: &mut App,
497 ) -> (E::RequestLayoutState, E::PrepaintState) {
498 match mem::take(&mut self.phase) {
499 ElementDrawPhase::Prepaint {
500 node_id,
501 global_id,
502 inspector_id,
503 bounds,
504 mut request_layout,
505 mut prepaint,
506 ..
507 } => {
508 if let Some(element_id) = self.element.id() {
509 window.element_id_stack.push(element_id);
510 debug_assert_eq!(global_id.as_ref().unwrap().0, window.element_id_stack);
511 }
512
513 window.next_frame.dispatch_tree.set_active_node(node_id);
514 self.element.paint(
515 global_id.as_ref(),
516 inspector_id.as_ref(),
517 bounds,
518 &mut request_layout,
519 &mut prepaint,
520 window,
521 cx,
522 );
523
524 if global_id.is_some() {
525 window.element_id_stack.pop();
526 }
527
528 self.phase = ElementDrawPhase::Painted;
529 (request_layout, prepaint)
530 }
531 _ => panic!("must call prepaint before paint"),
532 }
533 }
534
535 pub(crate) fn layout_as_root(
536 &mut self,
537 available_space: Size<AvailableSpace>,
538 window: &mut Window,
539 cx: &mut App,
540 ) -> Size<Pixels> {
541 if matches!(&self.phase, ElementDrawPhase::Start) {
542 self.request_layout(window, cx);
543 }
544
545 let layout_id = match mem::take(&mut self.phase) {
546 ElementDrawPhase::RequestLayout {
547 layout_id,
548 global_id,
549 inspector_id,
550 request_layout,
551 } => {
552 window.compute_layout(layout_id, available_space, cx);
553 self.phase = ElementDrawPhase::LayoutComputed {
554 layout_id,
555 global_id,
556 inspector_id,
557 available_space,
558 request_layout,
559 };
560 layout_id
561 }
562 ElementDrawPhase::LayoutComputed {
563 layout_id,
564 global_id,
565 inspector_id,
566 available_space: prev_available_space,
567 request_layout,
568 } => {
569 if available_space != prev_available_space {
570 window.compute_layout(layout_id, available_space, cx);
571 }
572 self.phase = ElementDrawPhase::LayoutComputed {
573 layout_id,
574 global_id,
575 inspector_id,
576 available_space,
577 request_layout,
578 };
579 layout_id
580 }
581 _ => panic!("cannot measure after painting"),
582 };
583
584 window.layout_bounds(layout_id).size
585 }
586}
587
588impl<E> ElementObject for Drawable<E>
589where
590 E: Element,
591 E::RequestLayoutState: 'static,
592{
593 fn inner_element(&mut self) -> &mut dyn Any {
594 &mut self.element
595 }
596
597 fn request_layout(&mut self, window: &mut Window, cx: &mut App) -> LayoutId {
598 Drawable::request_layout(self, window, cx)
599 }
600
601 fn prepaint(&mut self, window: &mut Window, cx: &mut App) {
602 Drawable::prepaint(self, window, cx);
603 }
604
605 fn paint(&mut self, window: &mut Window, cx: &mut App) {
606 Drawable::paint(self, window, cx);
607 }
608
609 fn layout_as_root(
610 &mut self,
611 available_space: Size<AvailableSpace>,
612 window: &mut Window,
613 cx: &mut App,
614 ) -> Size<Pixels> {
615 Drawable::layout_as_root(self, available_space, window, cx)
616 }
617}
618
619pub struct AnyElement(ArenaBox<dyn ElementObject>);
621
622impl AnyElement {
623 pub(crate) fn new<E>(element: E) -> Self
624 where
625 E: 'static + Element,
626 E::RequestLayoutState: Any,
627 {
628 let element = ELEMENT_ARENA
629 .with_borrow_mut(|arena| arena.alloc(|| Drawable::new(element)))
630 .map(|element| element as &mut dyn ElementObject);
631 AnyElement(element)
632 }
633
634 pub fn downcast_mut<T: 'static>(&mut self) -> Option<&mut T> {
636 self.0.inner_element().downcast_mut::<T>()
637 }
638
639 pub fn request_layout(&mut self, window: &mut Window, cx: &mut App) -> LayoutId {
642 self.0.request_layout(window, cx)
643 }
644
645 pub fn prepaint(&mut self, window: &mut Window, cx: &mut App) -> Option<FocusHandle> {
648 let focus_assigned = window.next_frame.focus.is_some();
649
650 self.0.prepaint(window, cx);
651
652 if !focus_assigned && let Some(focus_id) = window.next_frame.focus {
653 return FocusHandle::for_id(focus_id, &cx.focus_handles);
654 }
655
656 None
657 }
658
659 pub fn paint(&mut self, window: &mut Window, cx: &mut App) {
661 self.0.paint(window, cx);
662 }
663
664 pub fn layout_as_root(
666 &mut self,
667 available_space: Size<AvailableSpace>,
668 window: &mut Window,
669 cx: &mut App,
670 ) -> Size<Pixels> {
671 self.0.layout_as_root(available_space, window, cx)
672 }
673
674 pub fn prepaint_at(
677 &mut self,
678 origin: Point<Pixels>,
679 window: &mut Window,
680 cx: &mut App,
681 ) -> Option<FocusHandle> {
682 window.with_absolute_element_offset(origin, |window| self.prepaint(window, cx))
683 }
684
685 pub fn prepaint_as_root(
688 &mut self,
689 origin: Point<Pixels>,
690 available_space: Size<AvailableSpace>,
691 window: &mut Window,
692 cx: &mut App,
693 ) -> Option<FocusHandle> {
694 self.layout_as_root(available_space, window, cx);
695 window.with_absolute_element_offset(origin, |window| self.prepaint(window, cx))
696 }
697}
698
699impl Element for AnyElement {
700 type RequestLayoutState = ();
701 type PrepaintState = ();
702
703 fn id(&self) -> Option<ElementId> {
704 None
705 }
706
707 fn source_location(&self) -> Option<&'static panic::Location<'static>> {
708 None
709 }
710
711 fn request_layout(
712 &mut self,
713 _: Option<&GlobalElementId>,
714 _inspector_id: Option<&InspectorElementId>,
715 window: &mut Window,
716 cx: &mut App,
717 ) -> (LayoutId, Self::RequestLayoutState) {
718 let layout_id = self.request_layout(window, cx);
719 (layout_id, ())
720 }
721
722 fn prepaint(
723 &mut self,
724 _: Option<&GlobalElementId>,
725 _inspector_id: Option<&InspectorElementId>,
726 _: Bounds<Pixels>,
727 _: &mut Self::RequestLayoutState,
728 window: &mut Window,
729 cx: &mut App,
730 ) {
731 self.prepaint(window, cx);
732 }
733
734 fn paint(
735 &mut self,
736 _: Option<&GlobalElementId>,
737 _inspector_id: Option<&InspectorElementId>,
738 _: Bounds<Pixels>,
739 _: &mut Self::RequestLayoutState,
740 _: &mut Self::PrepaintState,
741 window: &mut Window,
742 cx: &mut App,
743 ) {
744 self.paint(window, cx);
745 }
746}
747
748impl IntoElement for AnyElement {
749 type Element = Self;
750
751 fn into_element(self) -> Self::Element {
752 self
753 }
754
755 fn into_any_element(self) -> AnyElement {
756 self
757 }
758}
759
760pub struct Empty;
762
763impl IntoElement for Empty {
764 type Element = Self;
765
766 fn into_element(self) -> Self::Element {
767 self
768 }
769}
770
771impl Element for Empty {
772 type RequestLayoutState = ();
773 type PrepaintState = ();
774
775 fn id(&self) -> Option<ElementId> {
776 None
777 }
778
779 fn source_location(&self) -> Option<&'static panic::Location<'static>> {
780 None
781 }
782
783 fn request_layout(
784 &mut self,
785 _id: Option<&GlobalElementId>,
786 _inspector_id: Option<&InspectorElementId>,
787 window: &mut Window,
788 cx: &mut App,
789 ) -> (LayoutId, Self::RequestLayoutState) {
790 (window.request_layout(Style::default(), None, cx), ())
791 }
792
793 fn prepaint(
794 &mut self,
795 _id: Option<&GlobalElementId>,
796 _inspector_id: Option<&InspectorElementId>,
797 _bounds: Bounds<Pixels>,
798 _state: &mut Self::RequestLayoutState,
799 _window: &mut Window,
800 _cx: &mut App,
801 ) {
802 }
803
804 fn paint(
805 &mut self,
806 _id: Option<&GlobalElementId>,
807 _inspector_id: Option<&InspectorElementId>,
808 _bounds: Bounds<Pixels>,
809 _request_layout: &mut Self::RequestLayoutState,
810 _prepaint: &mut Self::PrepaintState,
811 _window: &mut Window,
812 _cx: &mut App,
813 ) {
814 }
815}