component.rs

  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    fn styleable(self) -> StylableComponentAdapter<Self, V>
 55    where
 56        Self: Sized,
 57    {
 58        StylableComponentAdapter::new(self)
 59    }
 60}
 61
 62impl<V: View, C: GeneralComponent> Component<V> for C {
 63    fn render(self, v: &mut V, cx: &mut ViewContext<V>) -> AnyElement<V> {
 64        self.render(v, cx)
 65    }
 66}
 67
 68// StylableComponent -> GeneralComponent
 69pub struct StylableComponentAdapter<C: Component<V>, V: View> {
 70    component: C,
 71    phantom: std::marker::PhantomData<V>,
 72}
 73
 74impl<C: Component<V>, V: View> StylableComponentAdapter<C, V> {
 75    pub fn new(component: C) -> Self {
 76        Self {
 77            component,
 78            phantom: std::marker::PhantomData,
 79        }
 80    }
 81}
 82
 83impl<C: GeneralComponent, V: View> StyleableComponent for StylableComponentAdapter<C, V> {
 84    type Style = ();
 85
 86    type Output = C;
 87
 88    fn with_style(self, _: Self::Style) -> Self::Output {
 89        self.component
 90    }
 91}
 92
 93// Element -> Component
 94pub struct ElementAdapter<V: View> {
 95    element: AnyElement<V>,
 96    _phantom: std::marker::PhantomData<V>,
 97}
 98
 99impl<V: View> ElementAdapter<V> {
100    pub fn new(element: AnyElement<V>) -> Self {
101        Self {
102            element,
103            _phantom: std::marker::PhantomData,
104        }
105    }
106}
107
108impl<V: View> Component<V> for ElementAdapter<V> {
109    fn render(self, _: &mut V, _: &mut ViewContext<V>) -> AnyElement<V> {
110        self.element
111    }
112}
113
114// Component -> Element
115pub struct ComponentAdapter<V: View, E> {
116    component: Option<E>,
117    element: Option<AnyElement<V>>,
118    phantom: PhantomData<V>,
119}
120
121impl<E, V: View> ComponentAdapter<V, E> {
122    pub fn new(e: E) -> Self {
123        Self {
124            component: Some(e),
125            element: None,
126            phantom: PhantomData,
127        }
128    }
129}
130
131impl<V: View, C: Component<V> + 'static> Element<V> for ComponentAdapter<V, C> {
132    type LayoutState = ();
133
134    type PaintState = ();
135
136    fn layout(
137        &mut self,
138        constraint: SizeConstraint,
139        view: &mut V,
140        cx: &mut LayoutContext<V>,
141    ) -> (Vector2F, Self::LayoutState) {
142        if self.element.is_none() {
143            let element = self
144                .component
145                .take()
146                .expect("Component can only be rendered once")
147                .render(view, cx.view_context());
148            self.element = Some(element);
149        }
150        let constraint = self.element.as_mut().unwrap().layout(constraint, view, cx);
151        (constraint, ())
152    }
153
154    fn paint(
155        &mut self,
156        scene: &mut SceneBuilder,
157        bounds: RectF,
158        visible_bounds: RectF,
159        _: &mut Self::LayoutState,
160        view: &mut V,
161        cx: &mut PaintContext<V>,
162    ) -> Self::PaintState {
163        self.element
164            .as_mut()
165            .expect("Layout should always be called before paint")
166            .paint(scene, bounds.origin(), visible_bounds, view, cx)
167    }
168
169    fn rect_for_text_range(
170        &self,
171        range_utf16: std::ops::Range<usize>,
172        _: RectF,
173        _: RectF,
174        _: &Self::LayoutState,
175        _: &Self::PaintState,
176        view: &V,
177        cx: &ViewContext<V>,
178    ) -> Option<RectF> {
179        self.element
180            .as_ref()
181            .and_then(|el| el.rect_for_text_range(range_utf16, view, cx))
182    }
183
184    fn debug(
185        &self,
186        _: RectF,
187        _: &Self::LayoutState,
188        _: &Self::PaintState,
189        view: &V,
190        cx: &ViewContext<V>,
191    ) -> serde_json::Value {
192        serde_json::json!({
193            "type": "ComponentAdapter",
194            "child": self.element.as_ref().map(|el| el.debug(view, cx)),
195        })
196    }
197}