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}
 15
 16pub trait StyleableComponent {
 17    type Style: Clone;
 18    type Output: GeneralComponent;
 19
 20    fn with_style(self, style: Self::Style) -> Self::Output;
 21}
 22
 23impl GeneralComponent for () {
 24    fn render<V: View>(self, _: &mut V, _: &mut ViewContext<V>) -> AnyElement<V> {
 25        Empty::new().into_any()
 26    }
 27}
 28
 29impl StyleableComponent for () {
 30    type Style = ();
 31    type Output = ();
 32
 33    fn with_style(self, _: Self::Style) -> Self::Output {
 34        ()
 35    }
 36}
 37
 38pub trait Component<V: View> {
 39    fn render(self, v: &mut V, cx: &mut ViewContext<V>) -> AnyElement<V>;
 40
 41    fn into_element(self) -> ComponentAdapter<V, Self>
 42    where
 43        Self: Sized,
 44    {
 45        ComponentAdapter::new(self)
 46    }
 47}
 48
 49impl<V: View, C: GeneralComponent> Component<V> for C {
 50    fn render(self, v: &mut V, cx: &mut ViewContext<V>) -> AnyElement<V> {
 51        self.render(v, cx)
 52    }
 53}
 54
 55pub struct ComponentAdapter<V, E> {
 56    component: Option<E>,
 57    phantom: PhantomData<V>,
 58}
 59
 60impl<E, V> ComponentAdapter<V, E> {
 61    pub fn new(e: E) -> Self {
 62        Self {
 63            component: Some(e),
 64            phantom: PhantomData,
 65        }
 66    }
 67}
 68
 69impl<V: View, C: Component<V> + 'static> Element<V> for ComponentAdapter<V, C> {
 70    type LayoutState = AnyElement<V>;
 71
 72    type PaintState = ();
 73
 74    fn layout(
 75        &mut self,
 76        constraint: SizeConstraint,
 77        view: &mut V,
 78        cx: &mut LayoutContext<V>,
 79    ) -> (Vector2F, Self::LayoutState) {
 80        let component = self.component.take().unwrap();
 81        let mut element = component.render(view, cx.view_context());
 82        let constraint = element.layout(constraint, view, cx);
 83        (constraint, element)
 84    }
 85
 86    fn paint(
 87        &mut self,
 88        scene: &mut SceneBuilder,
 89        bounds: RectF,
 90        visible_bounds: RectF,
 91        layout: &mut Self::LayoutState,
 92        view: &mut V,
 93        cx: &mut PaintContext<V>,
 94    ) -> Self::PaintState {
 95        layout.paint(scene, bounds.origin(), visible_bounds, view, cx)
 96    }
 97
 98    fn rect_for_text_range(
 99        &self,
100        range_utf16: std::ops::Range<usize>,
101        _: RectF,
102        _: RectF,
103        element: &Self::LayoutState,
104        _: &Self::PaintState,
105        view: &V,
106        cx: &ViewContext<V>,
107    ) -> Option<RectF> {
108        element.rect_for_text_range(range_utf16, view, cx)
109    }
110
111    fn debug(
112        &self,
113        _: RectF,
114        element: &Self::LayoutState,
115        _: &Self::PaintState,
116        view: &V,
117        cx: &ViewContext<V>,
118    ) -> serde_json::Value {
119        serde_json::json!({
120            "type": "ComponentAdapter",
121            "child": element.debug(view, cx),
122        })
123    }
124}