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