libobs_wrapper\scenes/
transform_info.rs

1use std::fmt::Debug;
2
3use libobs::obs_transform_info;
4
5use crate::{
6    enums::{ObsBoundsType, OsEnumType},
7    graphics::Vec2,
8    macros::enum_from_number,
9    scenes::ObsSceneRef,
10    sources::ObsSourceRef,
11    utils::ObsError,
12};
13
14/// Use `ObsTransformInfoBuilder` to create an instance of this struct.
15pub struct ObsTransformInfo(pub(crate) obs_transform_info);
16impl Debug for ObsTransformInfo {
17    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
18        f.debug_struct("ObsTransformInfo")
19            .field("pos", &Vec2::from(self.0.pos))
20            .field("scale", &Vec2::from(self.0.scale))
21            .field("alignment", &self.0.alignment)
22            .field("rot", &self.0.rot)
23            .field("bounds", &Vec2::from(self.0.bounds))
24            .field("bounds_type", &self.0.bounds_type)
25            .field("bounds_alignment", &self.0.bounds_alignment)
26            .field("crop_to_bounds", &self.0.crop_to_bounds)
27            .finish()
28    }
29}
30
31impl Clone for ObsTransformInfo {
32    fn clone(&self) -> Self {
33        ObsTransformInfo(obs_transform_info {
34            pos: self.0.pos,
35            scale: self.0.scale,
36            alignment: self.0.alignment,
37            rot: self.0.rot,
38            bounds: self.0.bounds,
39            bounds_type: self.0.bounds_type,
40            bounds_alignment: self.0.bounds_alignment,
41            crop_to_bounds: self.0.crop_to_bounds,
42        })
43    }
44}
45
46impl ObsTransformInfo {
47    pub fn get_pos(&self) -> Vec2 {
48        Vec2::from(self.0.pos)
49    }
50
51    pub fn get_scale(&self) -> Vec2 {
52        Vec2::from(self.0.scale)
53    }
54
55    pub fn get_alignment(&self) -> u32 {
56        self.0.alignment
57    }
58
59    pub fn get_rot(&self) -> f32 {
60        self.0.rot
61    }
62
63    pub fn get_bounds(&self) -> Vec2 {
64        Vec2::from(self.0.bounds)
65    }
66
67    pub fn get_bounds_type(&self) -> ObsBoundsType {
68        enum_from_number!(ObsBoundsType, self.0.bounds_type).unwrap()
69    }
70
71    pub fn get_bounds_alignment(&self) -> u32 {
72        self.0.bounds_alignment
73    }
74
75    pub fn get_crop_to_bounds(&self) -> bool {
76        self.0.crop_to_bounds
77    }
78}
79
80pub struct ObsTransformInfoBuilder {
81    pos: Option<Vec2>,
82    scale: Option<Vec2>,
83    alignment: Option<u32>,
84    rot: Option<f32>,
85    bounds: Option<Vec2>,
86    bounds_type: Option<ObsBoundsType>,
87    bounds_alignment: Option<u32>,
88    crop_to_bounds: Option<bool>,
89}
90
91impl Default for ObsTransformInfoBuilder {
92    fn default() -> Self {
93        Self::new()
94    }
95}
96
97impl ObsTransformInfoBuilder {
98    pub fn new() -> Self {
99        Self {
100            pos: None,
101            scale: None,
102            alignment: None,
103            rot: None,
104            bounds: None,
105            bounds_type: None,
106            bounds_alignment: None,
107            crop_to_bounds: None,
108        }
109    }
110
111    pub fn set_pos(mut self, pos: Vec2) -> Self {
112        self.pos = Some(pos);
113        self
114    }
115
116    pub fn set_scale(mut self, scale: Vec2) -> Self {
117        self.scale = Some(scale);
118        self
119    }
120
121    /// Use alignment constants like so: `obs_alignment::LEFT | obs_alignment::TOP`
122    pub fn set_alignment(mut self, alignment: u32) -> Self {
123        self.alignment = Some(alignment);
124        self
125    }
126
127    pub fn set_rot(mut self, rot: f32) -> Self {
128        self.rot = Some(rot);
129        self
130    }
131
132    pub fn set_bounds(mut self, bounds: Vec2) -> Self {
133        self.bounds = Some(bounds);
134        self
135    }
136
137    pub fn set_bounds_type(mut self, bounds_type: ObsBoundsType) -> Self {
138        self.bounds_type = Some(bounds_type);
139        self
140    }
141
142    /// Use alignment constants like so: `obs_alignment::LEFT | obs_alignment::TOP`
143    pub fn set_bounds_alignment(mut self, bounds_alignment: u32) -> Self {
144        self.bounds_alignment = Some(bounds_alignment);
145        self
146    }
147
148    pub fn set_crop_to_bounds(mut self, crop_to_bounds: bool) -> Self {
149        self.crop_to_bounds = Some(crop_to_bounds);
150        self
151    }
152
153    /// Builds the `ObsTransformInfo` instance and keeps values that have not been set the same.
154    pub fn build_with_fallback(
155        self,
156        scene: &ObsSceneRef,
157        source: &ObsSourceRef,
158    ) -> Result<ObsTransformInfo, ObsError> {
159        let current = scene.get_transform_info(source)?;
160        let bounds_type = self
161            .bounds_type
162            .unwrap_or_else(|| current.get_bounds_type());
163
164        let bounds_type = bounds_type as OsEnumType;
165        Ok(ObsTransformInfo(obs_transform_info {
166            pos: self.pos.unwrap_or_else(|| current.get_pos()).into(),
167            scale: self.scale.unwrap_or_else(|| current.get_scale()).into(),
168            alignment: self.alignment.unwrap_or_else(|| current.get_alignment()),
169            rot: self.rot.unwrap_or_else(|| current.get_rot()),
170            bounds: self.bounds.unwrap_or_else(|| current.get_bounds()).into(),
171            bounds_type,
172            bounds_alignment: self
173                .bounds_alignment
174                .unwrap_or_else(|| current.get_bounds_alignment()),
175            crop_to_bounds: self
176                .crop_to_bounds
177                .unwrap_or_else(|| current.get_crop_to_bounds()),
178        }))
179    }
180
181    /// Builds the transform info with only the values set in the builder. Unset values will be defaulted.
182    pub fn build(self, base_width: u32, base_height: u32) -> ObsTransformInfo {
183        let bounds_type = self.bounds_type.unwrap_or(ObsBoundsType::ScaleInner) as OsEnumType;
184
185        ObsTransformInfo(obs_transform_info {
186            pos: self.pos.unwrap_or_else(|| Vec2::new(0.0, 0.0)).into(),
187            scale: self.scale.unwrap_or_else(|| Vec2::new(1.0, 1.0)).into(),
188            alignment: self
189                .alignment
190                .unwrap_or(libobs::OBS_ALIGN_LEFT | libobs::OBS_ALIGN_TOP),
191            rot: self.rot.unwrap_or(0.0),
192            bounds: self
193                .bounds
194                .unwrap_or_else(|| Vec2::new(base_width as f32, base_height as f32))
195                .into(),
196            bounds_type,
197            bounds_alignment: self.bounds_alignment.unwrap_or(libobs::OBS_ALIGN_CENTER),
198            crop_to_bounds: self.crop_to_bounds.unwrap_or(false),
199        })
200    }
201}