surface.rs

  1use crate::{
  2    App, Bounds, Element, ElementId, GlobalElementId, IntoElement, LayoutId, ObjectFit, Pixels,
  3    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.
 32pub fn surface(source: impl Into<SurfaceSource>) -> Surface {
 33    Surface {
 34        source: source.into(),
 35        object_fit: ObjectFit::Contain,
 36        style: Default::default(),
 37    }
 38}
 39
 40impl Surface {
 41    /// Set the object fit for the image.
 42    pub fn object_fit(mut self, object_fit: ObjectFit) -> Self {
 43        self.object_fit = object_fit;
 44        self
 45    }
 46}
 47
 48impl Element for Surface {
 49    type RequestLayoutState = ();
 50    type PrepaintState = ();
 51
 52    fn id(&self) -> Option<ElementId> {
 53        None
 54    }
 55
 56    fn request_layout(
 57        &mut self,
 58        _global_id: Option<&GlobalElementId>,
 59        window: &mut Window,
 60        cx: &mut App,
 61    ) -> (LayoutId, Self::RequestLayoutState) {
 62        let mut style = Style::default();
 63        style.refine(&self.style);
 64        let layout_id = window.request_layout(style, [], cx);
 65        (layout_id, ())
 66    }
 67
 68    fn prepaint(
 69        &mut self,
 70        _global_id: Option<&GlobalElementId>,
 71        _bounds: Bounds<Pixels>,
 72        _request_layout: &mut Self::RequestLayoutState,
 73        _window: &mut Window,
 74        _cx: &mut App,
 75    ) -> Self::PrepaintState {
 76    }
 77
 78    fn paint(
 79        &mut self,
 80        _global_id: Option<&GlobalElementId>,
 81        #[cfg_attr(not(target_os = "macos"), allow(unused_variables))] bounds: Bounds<Pixels>,
 82        _: &mut Self::RequestLayoutState,
 83        _: &mut Self::PrepaintState,
 84        #[cfg_attr(not(target_os = "macos"), allow(unused_variables))] window: &mut Window,
 85        _: &mut App,
 86    ) {
 87        match &self.source {
 88            #[cfg(target_os = "macos")]
 89            SurfaceSource::Surface(surface) => {
 90                let size = crate::size(surface.get_width().into(), surface.get_height().into());
 91                let new_bounds = self.object_fit.get_bounds(bounds, size);
 92                // TODO: Add support for corner_radii
 93                window.paint_surface(new_bounds, surface.clone());
 94            }
 95            #[allow(unreachable_patterns)]
 96            _ => {}
 97        }
 98    }
 99}
100
101impl IntoElement for Surface {
102    type Element = Self;
103
104    fn into_element(self) -> Self::Element {
105        self
106    }
107}
108
109impl Styled for Surface {
110    fn style(&mut self) -> &mut StyleRefinement {
111        &mut self.style
112    }
113}