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.
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}