Skip to main content

gpui_authoring/elements/
surface.rs

1#[cfg(target_os = "macos")]
2use crate::MacWindowExt;
3use crate::{
4    App, Bounds, Element, ElementId, GlobalElementId, IntoElement, LayoutId, ObjectFit, Pixels,
5    Style, StyleRefinement, Styled, Window,
6};
7#[cfg(target_os = "macos")]
8use core_video::pixel_buffer::CVPixelBuffer;
9use refineable::Refineable;
10
11/// A source of a surface's content.
12#[derive(Clone, Debug, PartialEq, Eq)]
13pub enum SurfaceSource {
14    /// A macOS image buffer from CoreVideo
15    #[cfg(target_os = "macos")]
16    Surface(CVPixelBuffer),
17}
18
19#[cfg(target_os = "macos")]
20impl From<CVPixelBuffer> for SurfaceSource {
21    fn from(value: CVPixelBuffer) -> Self {
22        SurfaceSource::Surface(value)
23    }
24}
25
26/// A surface element.
27pub struct Surface {
28    source: SurfaceSource,
29    object_fit: ObjectFit,
30    style: StyleRefinement,
31}
32
33/// Create a new surface element.
34#[cfg(target_os = "macos")]
35pub fn surface(source: impl Into<SurfaceSource>) -> Surface {
36    Surface {
37        source: source.into(),
38        object_fit: ObjectFit::Contain,
39        style: Default::default(),
40    }
41}
42
43impl Surface {
44    /// Set the object fit for the image.
45    pub fn object_fit(mut self, object_fit: ObjectFit) -> Self {
46        self.object_fit = object_fit;
47        self
48    }
49}
50
51impl Element for Surface {
52    type RequestLayoutState = ();
53    type PrepaintState = ();
54
55    fn id(&self) -> Option<ElementId> {
56        None
57    }
58
59    fn source_location(&self) -> Option<&'static core::panic::Location<'static>> {
60        None
61    }
62
63    fn request_layout(
64        &mut self,
65        _global_id: Option<&GlobalElementId>,
66        window: &mut Window,
67        cx: &mut App,
68    ) -> (LayoutId, Self::RequestLayoutState) {
69        let mut style = Style::default();
70        style.refine(&self.style);
71        let layout_id = window.request_layout(style, [], cx);
72        (layout_id, ())
73    }
74
75    fn prepaint(
76        &mut self,
77        _global_id: Option<&GlobalElementId>,
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        #[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}