surface.rs

  1use crate::{
  2    Bounds, Element, ElementId, GlobalElementId, IntoElement, LayoutId, ObjectFit, Pixels, Style,
  3    StyleRefinement, Styled, WindowContext,
  4};
  5#[cfg(target_os = "macos")]
  6use media::core_video::CVImageBuffer;
  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(CVImageBuffer),
 15}
 16
 17#[cfg(target_os = "macos")]
 18impl From<CVImageBuffer> for SurfaceSource {
 19    fn from(value: CVImageBuffer) -> 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        cx: &mut WindowContext,
 60    ) -> (LayoutId, Self::RequestLayoutState) {
 61        let mut style = Style::default();
 62        style.refine(&self.style);
 63        let layout_id = cx.request_layout(style, []);
 64        (layout_id, ())
 65    }
 66
 67    fn prepaint(
 68        &mut self,
 69        _global_id: Option<&GlobalElementId>,
 70        _bounds: Bounds<Pixels>,
 71        _request_layout: &mut Self::RequestLayoutState,
 72        _cx: &mut WindowContext,
 73    ) -> Self::PrepaintState {
 74    }
 75
 76    fn paint(
 77        &mut self,
 78        _global_id: Option<&GlobalElementId>,
 79        #[cfg_attr(not(target_os = "macos"), allow(unused_variables))] bounds: Bounds<Pixels>,
 80        _: &mut Self::RequestLayoutState,
 81        _: &mut Self::PrepaintState,
 82        #[cfg_attr(not(target_os = "macos"), allow(unused_variables))] cx: &mut WindowContext,
 83    ) {
 84        match &self.source {
 85            #[cfg(target_os = "macos")]
 86            SurfaceSource::Surface(surface) => {
 87                let size = crate::size(surface.width().into(), surface.height().into());
 88                let new_bounds = self.object_fit.get_bounds(bounds, size);
 89                // TODO: Add support for corner_radii
 90                cx.paint_surface(new_bounds, surface.clone());
 91            }
 92            #[allow(unreachable_patterns)]
 93            _ => {}
 94        }
 95    }
 96}
 97
 98impl IntoElement for Surface {
 99    type Element = Self;
100
101    fn into_element(self) -> Self::Element {
102        self
103    }
104}
105
106impl Styled for Surface {
107    fn style(&mut self) -> &mut StyleRefinement {
108        &mut self.style
109    }
110}