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}