1use pathfinder_geometry::{rect::RectF, vector::Vector2F};
2
3use crate::{
4 AnyElement, Element, LayoutContext, PaintContext, SceneBuilder, SizeConstraint, View,
5 ViewContext,
6};
7
8use super::Empty;
9
10pub trait GeneralComponent {
11 fn render<V: View>(self, v: &mut V, cx: &mut ViewContext<V>) -> AnyElement<V>;
12}
13
14pub trait StyleableComponent {
15 type Style: Clone;
16 type Output: GeneralComponent;
17
18 fn with_style(self, style: Self::Style) -> Self::Output;
19}
20
21impl GeneralComponent for () {
22 fn render<V: View>(self, _: &mut V, _: &mut ViewContext<V>) -> AnyElement<V> {
23 Empty::new().into_any()
24 }
25}
26
27impl StyleableComponent for () {
28 type Style = ();
29 type Output = ();
30
31 fn with_style(self, _: Self::Style) -> Self::Output {
32 ()
33 }
34}
35
36pub trait Component<V: View> {
37 fn render(self, v: &mut V, cx: &mut ViewContext<V>) -> AnyElement<V>;
38
39 fn into_element(self) -> ComponentAdapter<V, Self>
40 where
41 Self: Sized,
42 {
43 ComponentAdapter::new(self)
44 }
45}
46
47impl<V: View, C: GeneralComponent> Component<V> for C {
48 fn render(self, v: &mut V, cx: &mut ViewContext<V>) -> AnyElement<V> {
49 self.render(v, cx)
50 }
51}
52
53pub struct ComponentAdapter<V: View, E> {
54 component: Option<E>,
55 element: Option<AnyElement<V>>,
56 #[cfg(debug_assertions)]
57 _component_name: &'static str,
58}
59
60impl<E, V: View> ComponentAdapter<V, E> {
61 pub fn new(e: E) -> Self {
62 Self {
63 component: Some(e),
64 element: None,
65 #[cfg(debug_assertions)]
66 _component_name: std::any::type_name::<E>(),
67 }
68 }
69}
70
71impl<V: View, C: Component<V> + 'static> Element<V> for ComponentAdapter<V, C> {
72 type LayoutState = ();
73
74 type PaintState = ();
75
76 fn layout(
77 &mut self,
78 constraint: SizeConstraint,
79 view: &mut V,
80 cx: &mut LayoutContext<V>,
81 ) -> (Vector2F, Self::LayoutState) {
82 if self.element.is_none() {
83 let component = self.component.take().unwrap();
84 self.element = Some(component.render(view, cx.view_context()));
85 }
86 let constraint = self.element.as_mut().unwrap().layout(constraint, view, cx);
87 (constraint, ())
88 }
89
90 fn paint(
91 &mut self,
92 scene: &mut SceneBuilder,
93 bounds: RectF,
94 visible_bounds: RectF,
95 _: &mut Self::LayoutState,
96 view: &mut V,
97 cx: &mut PaintContext<V>,
98 ) -> Self::PaintState {
99 self.element
100 .as_mut()
101 .unwrap()
102 .paint(scene, bounds.origin(), visible_bounds, view, cx)
103 }
104
105 fn rect_for_text_range(
106 &self,
107 range_utf16: std::ops::Range<usize>,
108 _: RectF,
109 _: RectF,
110 _: &Self::LayoutState,
111 _: &Self::PaintState,
112 view: &V,
113 cx: &ViewContext<V>,
114 ) -> Option<RectF> {
115 self.element
116 .as_ref()
117 .unwrap()
118 .rect_for_text_range(range_utf16, view, cx)
119 }
120
121 fn debug(
122 &self,
123 _: RectF,
124 _: &Self::LayoutState,
125 _: &Self::PaintState,
126 view: &V,
127 cx: &ViewContext<V>,
128 ) -> serde_json::Value {
129 #[cfg(debug_assertions)]
130 let component_name = self._component_name;
131
132 #[cfg(not(debug_assertions))]
133 let component_name = "Unknown";
134
135 serde_json::json!({
136 "type": "ComponentAdapter",
137 "child": self.element.as_ref().unwrap().debug(view, cx),
138 "component_name": component_name
139 })
140 }
141}