component.rs

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