1use std::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 GeneralComponent {
13 fn render<V: View>(self, v: &mut V, cx: &mut ViewContext<V>) -> AnyElement<V>;
14 fn element<V: View>(self) -> ComponentAdapter<V, Self>
15 where
16 Self: Sized,
17 {
18 ComponentAdapter::new(self)
19 }
20}
21
22pub trait StyleableComponent {
23 type Style: Clone;
24 type Output: GeneralComponent;
25
26 fn with_style(self, style: Self::Style) -> Self::Output;
27}
28
29impl GeneralComponent for () {
30 fn render<V: View>(self, _: &mut V, _: &mut ViewContext<V>) -> AnyElement<V> {
31 Empty::new().into_any()
32 }
33}
34
35impl StyleableComponent for () {
36 type Style = ();
37 type Output = ();
38
39 fn with_style(self, _: Self::Style) -> Self::Output {
40 ()
41 }
42}
43
44pub trait Component<V: View> {
45 fn render(self, v: &mut V, cx: &mut ViewContext<V>) -> AnyElement<V>;
46
47 fn element(self) -> ComponentAdapter<V, Self>
48 where
49 Self: Sized,
50 {
51 ComponentAdapter::new(self)
52 }
53}
54
55impl<V: View, C: GeneralComponent> Component<V> for C {
56 fn render(self, v: &mut V, cx: &mut ViewContext<V>) -> AnyElement<V> {
57 self.render(v, cx)
58 }
59}
60
61// StylableComponent -> GeneralComponent
62pub struct StylableComponentAdapter<C: Component<V>, V: View> {
63 component: C,
64 phantom: std::marker::PhantomData<V>,
65}
66
67impl<C: Component<V>, V: View> StylableComponentAdapter<C, V> {
68 pub fn new(component: C) -> Self {
69 Self {
70 component,
71 phantom: std::marker::PhantomData,
72 }
73 }
74}
75
76impl<C: GeneralComponent, V: View> StyleableComponent for StylableComponentAdapter<C, V> {
77 type Style = ();
78
79 type Output = C;
80
81 fn with_style(self, _: Self::Style) -> Self::Output {
82 self.component
83 }
84}
85
86// Element -> Component
87pub struct ElementAdapter<V: View> {
88 element: AnyElement<V>,
89 _phantom: std::marker::PhantomData<V>,
90}
91
92impl<V: View> ElementAdapter<V> {
93 pub fn new(element: AnyElement<V>) -> Self {
94 Self {
95 element,
96 _phantom: std::marker::PhantomData,
97 }
98 }
99}
100
101impl<V: View> Component<V> for ElementAdapter<V> {
102 fn render(self, _: &mut V, _: &mut ViewContext<V>) -> AnyElement<V> {
103 self.element
104 }
105}
106
107// Component -> Element
108pub struct ComponentAdapter<V, E> {
109 component: Option<E>,
110 phantom: PhantomData<V>,
111}
112
113impl<E, V> ComponentAdapter<V, E> {
114 pub fn new(e: E) -> Self {
115 Self {
116 component: Some(e),
117 phantom: PhantomData,
118 }
119 }
120}
121
122impl<V: View, C: Component<V> + 'static> Element<V> for ComponentAdapter<V, C> {
123 type LayoutState = AnyElement<V>;
124
125 type PaintState = ();
126
127 fn layout(
128 &mut self,
129 constraint: SizeConstraint,
130 view: &mut V,
131 cx: &mut LayoutContext<V>,
132 ) -> (Vector2F, Self::LayoutState) {
133 let component = self.component.take().unwrap();
134 let mut element = component.render(view, cx.view_context());
135 let constraint = element.layout(constraint, view, cx);
136 (constraint, element)
137 }
138
139 fn paint(
140 &mut self,
141 scene: &mut SceneBuilder,
142 bounds: RectF,
143 visible_bounds: RectF,
144 layout: &mut Self::LayoutState,
145 view: &mut V,
146 cx: &mut PaintContext<V>,
147 ) -> Self::PaintState {
148 layout.paint(scene, bounds.origin(), visible_bounds, view, cx)
149 }
150
151 fn rect_for_text_range(
152 &self,
153 range_utf16: std::ops::Range<usize>,
154 _: RectF,
155 _: RectF,
156 element: &Self::LayoutState,
157 _: &Self::PaintState,
158 view: &V,
159 cx: &ViewContext<V>,
160 ) -> Option<RectF> {
161 element.rect_for_text_range(range_utf16, view, cx)
162 }
163
164 fn debug(
165 &self,
166 _: RectF,
167 element: &Self::LayoutState,
168 _: &Self::PaintState,
169 view: &V,
170 cx: &ViewContext<V>,
171 ) -> serde_json::Value {
172 serde_json::json!({
173 "type": "ComponentAdapter",
174 "child": element.debug(view, cx),
175 })
176 }
177}