component.rs

  1use pathfinder_geometry::{rect::RectF, vector::Vector2F};
  2
  3use crate::{
  4    AnyElement, Element, LayoutContext, PaintContext, SceneBuilder, SizeConstraint, View,
  5    ViewContext,
  6};
  7
  8use super::Empty;
  9
 10pub trait GeneralComponent {
 11    fn render<V: View>(self, v: &mut V, cx: &mut ViewContext<V>) -> AnyElement<V>;
 12}
 13
 14pub trait StyleableComponent {
 15    type Style: Clone;
 16    type Output: GeneralComponent;
 17
 18    fn with_style(self, style: Self::Style) -> Self::Output;
 19}
 20
 21impl GeneralComponent for () {
 22    fn render<V: View>(self, _: &mut V, _: &mut ViewContext<V>) -> AnyElement<V> {
 23        Empty::new().into_any()
 24    }
 25}
 26
 27impl StyleableComponent for () {
 28    type Style = ();
 29    type Output = ();
 30
 31    fn with_style(self, _: Self::Style) -> Self::Output {
 32        ()
 33    }
 34}
 35
 36pub trait Component<V: View> {
 37    fn render(self, v: &mut V, cx: &mut ViewContext<V>) -> AnyElement<V>;
 38
 39    fn into_element(self) -> ComponentAdapter<V, Self>
 40    where
 41        Self: Sized,
 42    {
 43        ComponentAdapter::new(self)
 44    }
 45}
 46
 47impl<V: View, C: GeneralComponent> Component<V> for C {
 48    fn render(self, v: &mut V, cx: &mut ViewContext<V>) -> AnyElement<V> {
 49        self.render(v, cx)
 50    }
 51}
 52
 53pub struct ComponentAdapter<V: View, E> {
 54    component: Option<E>,
 55    element: Option<AnyElement<V>>,
 56    #[cfg(debug_assertions)]
 57    _component_name: &'static str,
 58}
 59
 60impl<E, V: View> ComponentAdapter<V, E> {
 61    pub fn new(e: E) -> Self {
 62        Self {
 63            component: Some(e),
 64            element: None,
 65            #[cfg(debug_assertions)]
 66            _component_name: std::any::type_name::<E>(),
 67        }
 68    }
 69}
 70
 71impl<V: View, C: Component<V> + 'static> Element<V> for ComponentAdapter<V, C> {
 72    type LayoutState = ();
 73
 74    type PaintState = ();
 75
 76    fn layout(
 77        &mut self,
 78        constraint: SizeConstraint,
 79        view: &mut V,
 80        cx: &mut LayoutContext<V>,
 81    ) -> (Vector2F, Self::LayoutState) {
 82        if self.element.is_none() {
 83            let component = self.component.take().unwrap();
 84            self.element = Some(component.render(view, cx.view_context()));
 85        }
 86        let constraint = self.element.as_mut().unwrap().layout(constraint, view, cx);
 87        (constraint, ())
 88    }
 89
 90    fn paint(
 91        &mut self,
 92        scene: &mut SceneBuilder,
 93        bounds: RectF,
 94        visible_bounds: RectF,
 95        _: &mut Self::LayoutState,
 96        view: &mut V,
 97        cx: &mut PaintContext<V>,
 98    ) -> Self::PaintState {
 99        self.element
100            .as_mut()
101            .unwrap()
102            .paint(scene, bounds.origin(), visible_bounds, view, cx)
103    }
104
105    fn rect_for_text_range(
106        &self,
107        range_utf16: std::ops::Range<usize>,
108        _: RectF,
109        _: RectF,
110        _: &Self::LayoutState,
111        _: &Self::PaintState,
112        view: &V,
113        cx: &ViewContext<V>,
114    ) -> Option<RectF> {
115        self.element
116            .as_ref()
117            .unwrap()
118            .rect_for_text_range(range_utf16, view, cx)
119    }
120
121    fn debug(
122        &self,
123        _: RectF,
124        _: &Self::LayoutState,
125        _: &Self::PaintState,
126        view: &V,
127        cx: &ViewContext<V>,
128    ) -> serde_json::Value {
129        #[cfg(debug_assertions)]
130        let component_name = self._component_name;
131
132        #[cfg(not(debug_assertions))]
133        let component_name = "Unknown";
134
135        serde_json::json!({
136            "type": "ComponentAdapter",
137            "child": self.element.as_ref().unwrap().debug(view, cx),
138            "component_name": component_name
139        })
140    }
141}