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.
 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 source_location(&self) -> Option<&'static core::panic::Location<'static>> {
 57        None
 58    }
 59
 60    fn request_layout(
 61        &mut self,
 62        _global_id: Option<&GlobalElementId>,
 63        _inspector_id: Option<&InspectorElementId>,
 64        window: &mut Window,
 65        cx: &mut App,
 66    ) -> (LayoutId, Self::RequestLayoutState) {
 67        let mut style = Style::default();
 68        style.refine(&self.style);
 69        let layout_id = window.request_layout(style, [], cx);
 70        (layout_id, ())
 71    }
 72
 73    fn prepaint(
 74        &mut self,
 75        _global_id: Option<&GlobalElementId>,
 76        _inspector_id: Option<&InspectorElementId>,
 77        _bounds: Bounds<Pixels>,
 78        _request_layout: &mut Self::RequestLayoutState,
 79        _window: &mut Window,
 80        _cx: &mut App,
 81    ) -> Self::PrepaintState {
 82    }
 83
 84    fn paint(
 85        &mut self,
 86        _global_id: Option<&GlobalElementId>,
 87        _inspector_id: Option<&InspectorElementId>,
 88        #[cfg_attr(not(target_os = "macos"), allow(unused_variables))] bounds: Bounds<Pixels>,
 89        _: &mut Self::RequestLayoutState,
 90        _: &mut Self::PrepaintState,
 91        #[cfg_attr(not(target_os = "macos"), allow(unused_variables))] window: &mut Window,
 92        _: &mut App,
 93    ) {
 94        match &self.source {
 95            #[cfg(target_os = "macos")]
 96            SurfaceSource::Surface(surface) => {
 97                let size = crate::size(surface.get_width().into(), surface.get_height().into());
 98                let new_bounds = self.object_fit.get_bounds(bounds, size);
 99                // TODO: Add support for corner_radii
100                window.paint_surface(new_bounds, surface.clone());
101            }
102            #[allow(unreachable_patterns)]
103            _ => {}
104        }
105    }
106}
107
108impl IntoElement for Surface {
109    type Element = Self;
110
111    fn into_element(self) -> Self::Element {
112        self
113    }
114}
115
116impl Styled for Surface {
117    fn style(&mut self) -> &mut StyleRefinement {
118        &mut self.style
119    }
120}