use pathfinder_geometry::{rect::RectF, vector::Vector2F}; use crate::{ AnyElement, Element, LayoutContext, PaintContext, SceneBuilder, SizeConstraint, View, ViewContext, }; use super::Empty; pub trait GeneralComponent { fn render(self, v: &mut V, cx: &mut ViewContext) -> AnyElement; } pub trait StyleableComponent { type Style: Clone; type Output: GeneralComponent; fn with_style(self, style: Self::Style) -> Self::Output; } impl GeneralComponent for () { fn render(self, _: &mut V, _: &mut ViewContext) -> AnyElement { Empty::new().into_any() } } impl StyleableComponent for () { type Style = (); type Output = (); fn with_style(self, _: Self::Style) -> Self::Output { () } } pub trait Component { fn render(self, v: &mut V, cx: &mut ViewContext) -> AnyElement; fn into_element(self) -> ComponentAdapter where Self: Sized, { ComponentAdapter::new(self) } } impl Component for C { fn render(self, v: &mut V, cx: &mut ViewContext) -> AnyElement { self.render(v, cx) } } pub struct ComponentAdapter { component: Option, element: Option>, #[cfg(debug_assertions)] _component_name: &'static str, } impl ComponentAdapter { pub fn new(e: E) -> Self { Self { component: Some(e), element: None, #[cfg(debug_assertions)] _component_name: std::any::type_name::(), } } } impl + 'static> Element for ComponentAdapter { type LayoutState = (); type PaintState = (); fn layout( &mut self, constraint: SizeConstraint, view: &mut V, cx: &mut LayoutContext, ) -> (Vector2F, Self::LayoutState) { if self.element.is_none() { let component = self.component.take().unwrap(); self.element = Some(component.render(view, cx.view_context())); } let constraint = self.element.as_mut().unwrap().layout(constraint, view, cx); (constraint, ()) } fn paint( &mut self, scene: &mut SceneBuilder, bounds: RectF, visible_bounds: RectF, _: &mut Self::LayoutState, view: &mut V, cx: &mut PaintContext, ) -> Self::PaintState { self.element .as_mut() .unwrap() .paint(scene, bounds.origin(), visible_bounds, view, cx) } fn rect_for_text_range( &self, range_utf16: std::ops::Range, _: RectF, _: RectF, _: &Self::LayoutState, _: &Self::PaintState, view: &V, cx: &ViewContext, ) -> Option { self.element .as_ref() .unwrap() .rect_for_text_range(range_utf16, view, cx) } fn debug( &self, _: RectF, _: &Self::LayoutState, _: &Self::PaintState, view: &V, cx: &ViewContext, ) -> serde_json::Value { #[cfg(debug_assertions)] let component_name = self._component_name; #[cfg(not(debug_assertions))] let component_name = "Unknown"; serde_json::json!({ "type": "ComponentAdapter", "child": self.element.as_ref().unwrap().debug(view, cx), "component_name": component_name }) } }