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