surface.rs

  1use crate::{
  2    App, Bounds, Element, ElementId, GlobalElementId, InspectorElementId, IntoElement, LayoutId,
  3    ObjectFit, Pixels, Style, StyleRefinement, Styled, Window,
  4};
  5#[cfg(target_os = "macos")]
  6use core_video::pixel_buffer::CVPixelBuffer;
  7use refineable::Refineable;
  8
  9/// A source of a surface's content.
 10#[derive(Clone, Debug, PartialEq, Eq)]
 11pub enum SurfaceSource {
 12    /// A macOS image buffer from CoreVideo
 13    #[cfg(target_os = "macos")]
 14    Surface(CVPixelBuffer),
 15}
 16
 17#[cfg(target_os = "macos")]
 18impl From<CVPixelBuffer> for SurfaceSource {
 19    fn from(value: CVPixelBuffer) -> Self {
 20        SurfaceSource::Surface(value)
 21    }
 22}
 23
 24/// A surface element.
 25pub struct Surface {
 26    source: SurfaceSource,
 27    object_fit: ObjectFit,
 28    style: StyleRefinement,
 29}
 30
 31/// Create a new surface element.
 32#[cfg(target_os = "macos")]
 33pub fn surface(source: impl Into<SurfaceSource>) -> Surface {
 34    Surface {
 35        source: source.into(),
 36        object_fit: ObjectFit::Contain,
 37        style: Default::default(),
 38    }
 39}
 40
 41impl Surface {
 42    /// Set the object fit for the image.
 43    pub fn object_fit(mut self, object_fit: ObjectFit) -> Self {
 44        self.object_fit = object_fit;
 45        self
 46    }
 47}
 48
 49impl Element for Surface {
 50    type RequestLayoutState = ();
 51    type PrepaintState = ();
 52
 53    fn id(&self) -> Option<ElementId> {
 54        None
 55    }
 56
 57    fn source_location(&self) -> Option<&'static core::panic::Location<'static>> {
 58        None
 59    }
 60
 61    fn request_layout(
 62        &mut self,
 63        _global_id: Option<&GlobalElementId>,
 64        _inspector_id: Option<&InspectorElementId>,
 65        window: &mut Window,
 66        cx: &mut App,
 67    ) -> (LayoutId, Self::RequestLayoutState) {
 68        let mut style = Style::default();
 69        style.refine(&self.style);
 70        let layout_id = window.request_layout(style, [], cx);
 71        (layout_id, ())
 72    }
 73
 74    fn prepaint(
 75        &mut self,
 76        _global_id: Option<&GlobalElementId>,
 77        _inspector_id: Option<&InspectorElementId>,
 78        _bounds: Bounds<Pixels>,
 79        _request_layout: &mut Self::RequestLayoutState,
 80        _window: &mut Window,
 81        _cx: &mut App,
 82    ) -> Self::PrepaintState {
 83    }
 84
 85    fn paint(
 86        &mut self,
 87        _global_id: Option<&GlobalElementId>,
 88        _inspector_id: Option<&InspectorElementId>,
 89        #[cfg_attr(not(target_os = "macos"), allow(unused_variables))] bounds: Bounds<Pixels>,
 90        _: &mut Self::RequestLayoutState,
 91        _: &mut Self::PrepaintState,
 92        #[cfg_attr(not(target_os = "macos"), allow(unused_variables))] window: &mut Window,
 93        _: &mut App,
 94    ) {
 95        match &self.source {
 96            #[cfg(target_os = "macos")]
 97            SurfaceSource::Surface(surface) => {
 98                let size = crate::size(surface.get_width().into(), surface.get_height().into());
 99                let new_bounds = self.object_fit.get_bounds(bounds, size);
100                // TODO: Add support for corner_radii
101                window.paint_surface(new_bounds, surface.clone());
102            }
103            #[allow(unreachable_patterns)]
104            _ => {}
105        }
106    }
107}
108
109impl IntoElement for Surface {
110    type Element = Self;
111
112    fn into_element(self) -> Self::Element {
113        self
114    }
115}
116
117impl Styled for Surface {
118    fn style(&mut self) -> &mut StyleRefinement {
119        &mut self.style
120    }
121}