screencapturekit/stream/configuration/dimensions.rs
1//! Dimension and scaling configuration for stream capture
2//!
3//! This module provides methods to configure the output dimensions, scaling behavior,
4//! and source/destination rectangles for captured streams.
5
6use crate::cg::CGRect;
7
8use super::internal::SCStreamConfiguration;
9
10impl SCStreamConfiguration {
11 /// Set the output width in pixels
12 ///
13 /// The width determines the width of captured frames.
14 ///
15 /// # Examples
16 ///
17 /// ```
18 /// use screencapturekit::prelude::*;
19 ///
20 /// let mut config = SCStreamConfiguration::default();
21 /// config.set_width(1920);
22 /// assert_eq!(config.width(), 1920);
23 /// ```
24 pub fn set_width(&mut self, width: u32) -> &mut Self {
25 // FFI expects isize; u32 may wrap on 32-bit platforms (acceptable)
26 #[allow(clippy::cast_possible_wrap)]
27 unsafe {
28 crate::ffi::sc_stream_configuration_set_width(self.as_ptr(), width as isize);
29 }
30 self
31 }
32
33 /// Set the output width in pixels (builder pattern)
34 ///
35 /// # Examples
36 ///
37 /// ```
38 /// use screencapturekit::prelude::*;
39 ///
40 /// let config = SCStreamConfiguration::new()
41 /// .with_width(1920)
42 /// .with_height(1080);
43 /// ```
44 #[must_use]
45 pub fn with_width(mut self, width: u32) -> Self {
46 self.set_width(width);
47 self
48 }
49
50 /// Get the configured output width in pixels
51 ///
52 /// # Examples
53 ///
54 /// ```
55 /// use screencapturekit::prelude::*;
56 ///
57 /// let mut config = SCStreamConfiguration::default();
58 /// config.set_width(1920);
59 /// assert_eq!(config.width(), 1920);
60 /// ```
61 pub fn width(&self) -> u32 {
62 // FFI returns isize but width is always positive and fits in u32
63 #[allow(clippy::cast_sign_loss, clippy::cast_possible_truncation)]
64 unsafe {
65 crate::ffi::sc_stream_configuration_get_width(self.as_ptr()) as u32
66 }
67 }
68
69 /// Set the output height in pixels
70 ///
71 /// The height determines the height of captured frames.
72 ///
73 /// # Examples
74 ///
75 /// ```
76 /// use screencapturekit::prelude::*;
77 ///
78 /// let mut config = SCStreamConfiguration::default();
79 /// config.set_height(1080);
80 /// assert_eq!(config.height(), 1080);
81 /// ```
82 pub fn set_height(&mut self, height: u32) -> &mut Self {
83 // FFI expects isize; u32 may wrap on 32-bit platforms (acceptable)
84 #[allow(clippy::cast_possible_wrap)]
85 unsafe {
86 crate::ffi::sc_stream_configuration_set_height(self.as_ptr(), height as isize);
87 }
88 self
89 }
90
91 /// Set the output height in pixels (builder pattern)
92 ///
93 /// # Examples
94 ///
95 /// ```
96 /// use screencapturekit::prelude::*;
97 ///
98 /// let config = SCStreamConfiguration::new()
99 /// .with_width(1920)
100 /// .with_height(1080);
101 /// ```
102 #[must_use]
103 pub fn with_height(mut self, height: u32) -> Self {
104 self.set_height(height);
105 self
106 }
107
108 /// Get the configured output height in pixels
109 ///
110 /// # Examples
111 ///
112 /// ```
113 /// use screencapturekit::prelude::*;
114 ///
115 /// let mut config = SCStreamConfiguration::default();
116 /// config.set_height(1080);
117 /// assert_eq!(config.height(), 1080);
118 /// ```
119 pub fn height(&self) -> u32 {
120 // FFI returns isize but height is always positive and fits in u32
121 #[allow(clippy::cast_sign_loss, clippy::cast_possible_truncation)]
122 unsafe {
123 crate::ffi::sc_stream_configuration_get_height(self.as_ptr()) as u32
124 }
125 }
126
127 /// Enable or disable scaling to fit the output dimensions
128 ///
129 /// When enabled, the source content will be scaled to fit within the
130 /// configured width and height, potentially changing aspect ratio.
131 ///
132 /// # Examples
133 ///
134 /// ```
135 /// use screencapturekit::prelude::*;
136 ///
137 /// let mut config = SCStreamConfiguration::default();
138 /// config.set_scales_to_fit(true);
139 /// assert!(config.scales_to_fit());
140 /// ```
141 pub fn set_scales_to_fit(&mut self, scales_to_fit: bool) -> &mut Self {
142 unsafe {
143 crate::ffi::sc_stream_configuration_set_scales_to_fit(self.as_ptr(), scales_to_fit);
144 }
145 self
146 }
147
148 /// Enable or disable scaling to fit (builder pattern)
149 #[must_use]
150 pub fn with_scales_to_fit(mut self, scales_to_fit: bool) -> Self {
151 self.set_scales_to_fit(scales_to_fit);
152 self
153 }
154
155 /// Check if scaling to fit is enabled
156 pub fn scales_to_fit(&self) -> bool {
157 unsafe { crate::ffi::sc_stream_configuration_get_scales_to_fit(self.as_ptr()) }
158 }
159
160 /// Set the source rectangle to capture
161 ///
162 /// Defines which portion of the source content to capture. Coordinates are
163 /// relative to the source content's coordinate system.
164 ///
165 /// # Examples
166 ///
167 /// ```
168 /// use screencapturekit::prelude::*;
169 /// use screencapturekit::cg::CGRect;
170 ///
171 /// // Capture only top-left quarter of screen
172 /// let rect = CGRect::new(0.0, 0.0, 960.0, 540.0);
173 /// let mut config = SCStreamConfiguration::default();
174 /// config.set_source_rect(rect);
175 /// ```
176 pub fn set_source_rect(&mut self, source_rect: CGRect) -> &mut Self {
177 unsafe {
178 crate::ffi::sc_stream_configuration_set_source_rect(
179 self.as_ptr(),
180 source_rect.x,
181 source_rect.y,
182 source_rect.width,
183 source_rect.height,
184 );
185 }
186 self
187 }
188
189 /// Set the source rectangle (builder pattern)
190 #[must_use]
191 pub fn with_source_rect(mut self, source_rect: CGRect) -> Self {
192 self.set_source_rect(source_rect);
193 self
194 }
195
196 /// Get the configured source rectangle
197 pub fn source_rect(&self) -> CGRect {
198 unsafe {
199 let mut x = 0.0;
200 let mut y = 0.0;
201 let mut width = 0.0;
202 let mut height = 0.0;
203 crate::ffi::sc_stream_configuration_get_source_rect(
204 self.as_ptr(),
205 &mut x,
206 &mut y,
207 &mut width,
208 &mut height,
209 );
210 CGRect::new(x, y, width, height)
211 }
212 }
213
214 /// Set the destination rectangle for captured content
215 ///
216 /// Defines where the captured content will be placed in the output frame.
217 /// Useful for picture-in-picture or multi-source compositions.
218 ///
219 /// # Examples
220 ///
221 /// ```
222 /// use screencapturekit::prelude::*;
223 /// use screencapturekit::cg::CGRect;
224 ///
225 /// // Place captured content in top-left corner
226 /// let rect = CGRect::new(0.0, 0.0, 640.0, 480.0);
227 /// let mut config = SCStreamConfiguration::default();
228 /// config.set_destination_rect(rect);
229 /// ```
230 pub fn set_destination_rect(&mut self, destination_rect: CGRect) -> &mut Self {
231 unsafe {
232 crate::ffi::sc_stream_configuration_set_destination_rect(
233 self.as_ptr(),
234 destination_rect.x,
235 destination_rect.y,
236 destination_rect.width,
237 destination_rect.height,
238 );
239 }
240 self
241 }
242
243 /// Set the destination rectangle (builder pattern)
244 #[must_use]
245 pub fn with_destination_rect(mut self, destination_rect: CGRect) -> Self {
246 self.set_destination_rect(destination_rect);
247 self
248 }
249
250 /// Get the configured destination rectangle
251 pub fn destination_rect(&self) -> CGRect {
252 unsafe {
253 let mut x = 0.0;
254 let mut y = 0.0;
255 let mut width = 0.0;
256 let mut height = 0.0;
257 crate::ffi::sc_stream_configuration_get_destination_rect(
258 self.as_ptr(),
259 &mut x,
260 &mut y,
261 &mut width,
262 &mut height,
263 );
264 CGRect::new(x, y, width, height)
265 }
266 }
267
268 /// Preserve aspect ratio when scaling
269 ///
270 /// When enabled, the content will be scaled while maintaining its original
271 /// aspect ratio, potentially adding letterboxing or pillarboxing.
272 ///
273 /// Note: This property requires macOS 14.0+. On older versions, the setter
274 /// is a no-op and the getter returns `false`.
275 ///
276 /// # Examples
277 ///
278 /// ```
279 /// use screencapturekit::prelude::*;
280 ///
281 /// let mut config = SCStreamConfiguration::default();
282 /// config.set_preserves_aspect_ratio(true);
283 /// // Returns true on macOS 14.0+, false on older versions
284 /// let _ = config.preserves_aspect_ratio();
285 /// ```
286 pub fn set_preserves_aspect_ratio(&mut self, preserves_aspect_ratio: bool) -> &mut Self {
287 unsafe {
288 crate::ffi::sc_stream_configuration_set_preserves_aspect_ratio(
289 self.as_ptr(),
290 preserves_aspect_ratio,
291 );
292 }
293 self
294 }
295
296 /// Preserve aspect ratio when scaling (builder pattern)
297 #[must_use]
298 pub fn with_preserves_aspect_ratio(mut self, preserves_aspect_ratio: bool) -> Self {
299 self.set_preserves_aspect_ratio(preserves_aspect_ratio);
300 self
301 }
302
303 /// Check if aspect ratio preservation is enabled
304 pub fn preserves_aspect_ratio(&self) -> bool {
305 unsafe { crate::ffi::sc_stream_configuration_get_preserves_aspect_ratio(self.as_ptr()) }
306 }
307}