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}