1use std::{any::Any, marker::PhantomData};
2
3use pathfinder_geometry::{rect::RectF, vector::Vector2F};
4
5use crate::{
6 AnyElement, Element, LayoutContext, PaintContext, SceneBuilder, SizeConstraint, View,
7 ViewContext,
8};
9
10use super::Empty;
11
12pub trait Component {
13 fn render<V: View>(self, v: &mut V, cx: &mut ViewContext<V>) -> AnyElement<V>;
14
15 fn element<V: View>(self) -> StatefulAdapter<V, Self>
16 where
17 Self: Sized,
18 {
19 StatefulAdapter::new(self)
20 }
21
22 fn stylable(self) -> StylableAdapter<Self>
23 where
24 Self: Sized,
25 {
26 StylableAdapter::new(self)
27 }
28}
29
30pub struct StylableAdapter<C: Component> {
31 component: C,
32}
33
34impl<C: Component> StylableAdapter<C> {
35 pub fn new(component: C) -> Self {
36 Self { component }
37 }
38}
39
40impl<C: Component> StyleableComponent for StylableAdapter<C> {
41 type Style = ();
42
43 type Output = C;
44
45 fn with_style(self, _: Self::Style) -> Self::Output {
46 self.component
47 }
48}
49
50pub trait StyleableComponent {
51 type Style: Clone;
52 type Output: Component;
53
54 fn with_style(self, style: Self::Style) -> Self::Output;
55}
56
57impl Component for () {
58 fn render<V: View>(self, _: &mut V, _: &mut ViewContext<V>) -> AnyElement<V> {
59 Empty::new().into_any()
60 }
61}
62
63impl StyleableComponent for () {
64 type Style = ();
65 type Output = ();
66
67 fn with_style(self, _: Self::Style) -> Self::Output {
68 ()
69 }
70}
71
72pub trait StatefulStyleableComponent<V: View> {
73 type Style: Clone;
74 type Output: StatefulComponent<V>;
75
76 fn stateful_with_style(self, style: Self::Style) -> Self::Output;
77}
78
79impl<V: View, C: StyleableComponent> StatefulStyleableComponent<V> for C {
80 type Style = C::Style;
81
82 type Output = C::Output;
83
84 fn stateful_with_style(self, style: Self::Style) -> Self::Output {
85 self.with_style(style)
86 }
87}
88
89pub trait StatefulComponent<V: View> {
90 fn render(self, v: &mut V, cx: &mut ViewContext<V>) -> AnyElement<V>;
91
92 fn stateful_element(self) -> StatefulAdapter<V, Self>
93 where
94 Self: Sized,
95 {
96 StatefulAdapter::new(self)
97 }
98
99 fn stateful_styleable(self) -> StatefulStylableAdapter<Self, V>
100 where
101 Self: Sized,
102 {
103 StatefulStylableAdapter::new(self)
104 }
105}
106
107impl<V: View, C: Component> StatefulComponent<V> for C {
108 fn render(self, v: &mut V, cx: &mut ViewContext<V>) -> AnyElement<V> {
109 self.render(v, cx)
110 }
111}
112
113// StylableComponent -> Component
114pub struct StatefulStylableAdapter<C: StatefulComponent<V>, V: View> {
115 component: C,
116 phantom: std::marker::PhantomData<V>,
117}
118
119impl<C: StatefulComponent<V>, V: View> StatefulStylableAdapter<C, V> {
120 pub fn new(component: C) -> Self {
121 Self {
122 component,
123 phantom: std::marker::PhantomData,
124 }
125 }
126}
127
128impl<C: StatefulComponent<V>, V: View> StatefulStyleableComponent<V>
129 for StatefulStylableAdapter<C, V>
130{
131 type Style = ();
132
133 type Output = C;
134
135 fn stateful_with_style(self, _: Self::Style) -> Self::Output {
136 self.component
137 }
138}
139
140// Element -> GeneralComponent
141
142pub struct DynamicElementAdapter {
143 element: Box<dyn Any>,
144}
145
146impl DynamicElementAdapter {
147 pub fn new<V: View>(element: AnyElement<V>) -> Self {
148 DynamicElementAdapter {
149 element: Box::new(element) as Box<dyn Any>,
150 }
151 }
152}
153
154impl Component for DynamicElementAdapter {
155 fn render<V: View>(self, _: &mut V, _: &mut ViewContext<V>) -> AnyElement<V> {
156 let element = self
157 .element
158 .downcast::<AnyElement<V>>()
159 .expect("Don't move elements out of their view :(");
160 *element
161 }
162}
163
164// Element -> Component
165pub struct ElementAdapter<V: View> {
166 element: AnyElement<V>,
167 _phantom: std::marker::PhantomData<V>,
168}
169
170impl<V: View> ElementAdapter<V> {
171 pub fn new(element: AnyElement<V>) -> Self {
172 Self {
173 element,
174 _phantom: std::marker::PhantomData,
175 }
176 }
177}
178
179impl<V: View> StatefulComponent<V> for ElementAdapter<V> {
180 fn render(self, _: &mut V, _: &mut ViewContext<V>) -> AnyElement<V> {
181 self.element
182 }
183}
184
185// Component -> Element
186pub struct StatefulAdapter<V: View, E> {
187 component: Option<E>,
188 element: Option<AnyElement<V>>,
189 phantom: PhantomData<V>,
190}
191
192impl<E, V: View> StatefulAdapter<V, E> {
193 pub fn new(e: E) -> Self {
194 Self {
195 component: Some(e),
196 element: None,
197 phantom: PhantomData,
198 }
199 }
200}
201
202impl<V: View, C: StatefulComponent<V> + 'static> Element<V> for StatefulAdapter<V, C> {
203 type LayoutState = ();
204
205 type PaintState = ();
206
207 fn layout(
208 &mut self,
209 constraint: SizeConstraint,
210 view: &mut V,
211 cx: &mut LayoutContext<V>,
212 ) -> (Vector2F, Self::LayoutState) {
213 if self.element.is_none() {
214 let element = self
215 .component
216 .take()
217 .expect("Component can only be rendered once")
218 .render(view, cx.view_context());
219 self.element = Some(element);
220 }
221 let constraint = self.element.as_mut().unwrap().layout(constraint, view, cx);
222 (constraint, ())
223 }
224
225 fn paint(
226 &mut self,
227 scene: &mut SceneBuilder,
228 bounds: RectF,
229 visible_bounds: RectF,
230 _: &mut Self::LayoutState,
231 view: &mut V,
232 cx: &mut PaintContext<V>,
233 ) -> Self::PaintState {
234 self.element
235 .as_mut()
236 .expect("Layout should always be called before paint")
237 .paint(scene, bounds.origin(), visible_bounds, view, cx)
238 }
239
240 fn rect_for_text_range(
241 &self,
242 range_utf16: std::ops::Range<usize>,
243 _: RectF,
244 _: RectF,
245 _: &Self::LayoutState,
246 _: &Self::PaintState,
247 view: &V,
248 cx: &ViewContext<V>,
249 ) -> Option<RectF> {
250 self.element
251 .as_ref()
252 .and_then(|el| el.rect_for_text_range(range_utf16, view, cx))
253 }
254
255 fn debug(
256 &self,
257 _: RectF,
258 _: &Self::LayoutState,
259 _: &Self::PaintState,
260 view: &V,
261 cx: &ViewContext<V>,
262 ) -> serde_json::Value {
263 serde_json::json!({
264 "type": "ComponentAdapter",
265 "child": self.element.as_ref().map(|el| el.debug(view, cx)),
266 })
267 }
268}