gpui/elements/
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}