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