libobs_wrapper\scenes/
transform_info.rs1use 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
14pub 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 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 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 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 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}