ferroui_base/rendering/composition/
composition_clip.rs1use super::composition_object_impls::composition_object_impls;
11use super::generated::{
12 CompositionClipHooks, CompositionClipProps, GeometricClipHooks, GeometricClipProps, InsetClipHooks,
13 InsetClipProps, RectangleClipHooks, RectangleClipProps, ServerGeometricClipProps, ServerInsetClipProps,
14 ServerRectangleClipProps,
15};
16use super::server::{
17 IServerObject, ServerCompositor, ServerGeometricClip, ServerInsetClip, ServerObjectId, ServerRectangleClip,
18};
19use super::{CompositionGeometry, CompositionObject, CompositionViewBox, Compositor, ICompositionObject};
20use crate::{Matrix, Vector};
21use std::ops::Deref;
22use std::rc::{Rc, Weak};
23
24pub(crate) enum CompositionClipKind {
26 Inset(InsetClipProps),
27 Rectangle(RectangleClipProps),
28 Geometric(GeometricClipProps),
29}
30
31pub struct CompositionClip {
40 this: Weak<CompositionClip>,
41 object: CompositionObject,
42 kind: CompositionClipKind,
43}
44
45impl CompositionClip {
46 fn create(
47 compositor: &Rc<Compositor>,
48 kind: CompositionClipKind,
49 server: impl FnOnce(&Rc<ServerCompositor>) -> Rc<dyn IServerObject> + Send + 'static,
50 ) -> Rc<CompositionClip> {
51 let server = compositor.create_server_object(move |compositor, _| server(compositor));
52 let clip = Rc::new_cyclic(|this: &Weak<CompositionClip>| CompositionClip {
53 this: this.clone(),
54 object: CompositionObject::new(compositor, Some(server)),
55 kind,
56 });
57 match &clip.kind {
58 CompositionClipKind::Inset(props) => props.initialize_defaults(&*clip),
59 CompositionClipKind::Rectangle(props) => props.initialize_defaults(&*clip),
60 CompositionClipKind::Geometric(props) => props.initialize_defaults(&*clip),
61 }
62 clip
63 }
64
65 pub fn clip_props(&self) -> &CompositionClipProps {
67 match &self.kind {
68 CompositionClipKind::Inset(props) => props.base(),
69 CompositionClipKind::Rectangle(props) => props.base(),
70 CompositionClipKind::Geometric(props) => props.base(),
71 }
72 }
73
74 pub fn compositor(&self) -> &Rc<Compositor> {
75 self.object.compositor()
76 }
77
78 pub fn object(&self) -> &CompositionObject {
80 &self.object
81 }
82
83 pub fn server(&self) -> ServerObjectId {
85 self.object.required_server()
86 }
87
88 pub fn is_disposed(&self) -> bool {
89 self.object.is_disposed()
90 }
91
92 pub fn dispose(&self) {
93 self.object.dispose();
94 }
95
96 pub fn type_name(&self) -> &'static str {
98 match &self.kind {
99 CompositionClipKind::Inset(_) => "InsetClip",
100 CompositionClipKind::Rectangle(_) => "RectangleClip",
101 CompositionClipKind::Geometric(_) => "GeometricClip",
102 }
103 }
104
105 pub fn anchor_point(&self) -> Vector {
108 self.clip_props().anchor_point()
109 }
110
111 pub fn set_anchor_point(&self, value: Vector) {
112 self.clip_props().set_anchor_point(self, value)
113 }
114
115 pub fn center_point(&self) -> Vector {
117 self.clip_props().center_point()
118 }
119
120 pub fn set_center_point(&self, value: Vector) {
121 self.clip_props().set_center_point(self, value)
122 }
123
124 pub fn offset(&self) -> Vector {
126 self.clip_props().offset()
127 }
128
129 pub fn set_offset(&self, value: Vector) {
130 self.clip_props().set_offset(self, value)
131 }
132
133 pub fn rotation_angle(&self) -> f32 {
135 self.clip_props().rotation_angle()
136 }
137
138 pub fn set_rotation_angle(&self, value: f32) {
139 self.clip_props().set_rotation_angle(self, value)
140 }
141
142 pub fn rotation_angle_in_degrees(&self) -> f32 {
145 self.rotation_angle().to_degrees()
146 }
147
148 pub fn set_rotation_angle_in_degrees(&self, value: f32) {
149 self.set_rotation_angle(value.to_radians())
150 }
151
152 pub fn scale(&self) -> Vector {
154 self.clip_props().scale()
155 }
156
157 pub fn set_scale(&self, value: Vector) {
158 self.clip_props().set_scale(self, value)
159 }
160
161 pub fn transform_matrix(&self) -> Matrix {
163 self.clip_props().transform_matrix()
164 }
165
166 pub fn set_transform_matrix(&self, value: Matrix) {
167 self.clip_props().set_transform_matrix(self, value)
168 }
169}
170
171impl CompositionClipHooks for CompositionClip {}
172
173impl InsetClipHooks for CompositionClip {}
174
175impl RectangleClipHooks for CompositionClip {}
176
177impl GeometricClipHooks for CompositionClip {}
178
179composition_object_impls!(
180 CompositionClip, "CompositionClip",
181 serialize: |this, writer| match &this.kind {
182 CompositionClipKind::Inset(props) => props.serialize_changes_core(this, writer),
183 CompositionClipKind::Rectangle(props) => props.serialize_changes_core(this, writer),
184 CompositionClipKind::Geometric(props) => props.serialize_changes_core(this, writer),
185 },
186 start_animation: |this, name, animation, final_value| match &this.kind {
187 CompositionClipKind::Inset(props) => props.start_animation(this, name, animation, final_value),
188 CompositionClipKind::Rectangle(props) => props.start_animation(this, name, animation, final_value),
189 CompositionClipKind::Geometric(props) => props.start_animation(this, name, animation, final_value),
190 },
191 composition_property: |this, name| match &this.kind {
192 CompositionClipKind::Inset(_) => ServerInsetClipProps::get_composition_property(name),
193 CompositionClipKind::Rectangle(_) => ServerRectangleClipProps::get_composition_property(name),
194 CompositionClipKind::Geometric(_) => ServerGeometricClipProps::get_composition_property(name),
195 },
196);
197
198#[derive(Clone)]
203pub struct InsetClip(Rc<CompositionClip>);
204
205impl Deref for InsetClip {
206 type Target = Rc<CompositionClip>;
207
208 fn deref(&self) -> &Rc<CompositionClip> {
209 &self.0
210 }
211}
212
213impl InsetClip {
214 pub(crate) fn new(compositor: &Rc<Compositor>) -> InsetClip {
215 InsetClip(CompositionClip::create(
216 compositor,
217 CompositionClipKind::Inset(InsetClipProps::new()),
218 |c| ServerInsetClip::new(c),
219 ))
220 }
221
222 pub(crate) fn with_insets(compositor: &Rc<Compositor>, left: f32, top: f32, right: f32, bottom: f32) -> InsetClip {
223 let clip = Self::new(compositor);
224 clip.set_left_inset(left);
225 clip.set_top_inset(top);
226 clip.set_right_inset(right);
227 clip.set_bottom_inset(bottom);
228 clip
229 }
230
231 pub fn from_clip(clip: &Rc<CompositionClip>) -> Option<InsetClip> {
233 matches!(clip.kind, CompositionClipKind::Inset(_)).then(|| InsetClip(clip.clone()))
234 }
235
236 fn props(&self) -> &InsetClipProps {
237 match &self.0.kind {
238 CompositionClipKind::Inset(props) => props,
239 _ => unreachable!("an inset clip handle wraps an inset clip"),
240 }
241 }
242
243 pub fn left_inset(&self) -> f32 {
244 self.props().left_inset()
245 }
246
247 pub fn set_left_inset(&self, value: f32) {
248 self.props().set_left_inset(&*self.0, value)
249 }
250
251 pub fn top_inset(&self) -> f32 {
252 self.props().top_inset()
253 }
254
255 pub fn set_top_inset(&self, value: f32) {
256 self.props().set_top_inset(&*self.0, value)
257 }
258
259 pub fn right_inset(&self) -> f32 {
260 self.props().right_inset()
261 }
262
263 pub fn set_right_inset(&self, value: f32) {
264 self.props().set_right_inset(&*self.0, value)
265 }
266
267 pub fn bottom_inset(&self) -> f32 {
268 self.props().bottom_inset()
269 }
270
271 pub fn set_bottom_inset(&self, value: f32) {
272 self.props().set_bottom_inset(&*self.0, value)
273 }
274}
275
276#[derive(Clone)]
283pub struct RectangleClip(Rc<CompositionClip>);
284
285impl Deref for RectangleClip {
286 type Target = Rc<CompositionClip>;
287
288 fn deref(&self) -> &Rc<CompositionClip> {
289 &self.0
290 }
291}
292
293impl RectangleClip {
294 pub(crate) fn new(compositor: &Rc<Compositor>) -> RectangleClip {
295 RectangleClip(CompositionClip::create(
296 compositor,
297 CompositionClipKind::Rectangle(RectangleClipProps::new()),
298 |c| ServerRectangleClip::new(c),
299 ))
300 }
301
302 pub(crate) fn with_edges(compositor: &Rc<Compositor>, left: f32, top: f32, right: f32, bottom: f32) -> RectangleClip {
303 let clip = Self::new(compositor);
304 clip.set_left(left);
305 clip.set_top(top);
306 clip.set_right(right);
307 clip.set_bottom(bottom);
308 clip
309 }
310
311 #[allow(clippy::too_many_arguments)]
312 pub(crate) fn with_edges_and_radii(
313 compositor: &Rc<Compositor>,
314 left: f32,
315 top: f32,
316 right: f32,
317 bottom: f32,
318 top_left_radius: Vector,
319 top_right_radius: Vector,
320 bottom_right_radius: Vector,
321 bottom_left_radius: Vector,
322 ) -> RectangleClip {
323 let clip = Self::with_edges(compositor, left, top, right, bottom);
324 clip.set_top_left_radius(top_left_radius);
325 clip.set_top_right_radius(top_right_radius);
326 clip.set_bottom_right_radius(bottom_right_radius);
327 clip.set_bottom_left_radius(bottom_left_radius);
328 clip
329 }
330
331 pub fn from_clip(clip: &Rc<CompositionClip>) -> Option<RectangleClip> {
333 matches!(clip.kind, CompositionClipKind::Rectangle(_)).then(|| RectangleClip(clip.clone()))
334 }
335
336 fn props(&self) -> &RectangleClipProps {
337 match &self.0.kind {
338 CompositionClipKind::Rectangle(props) => props,
339 _ => unreachable!("a rectangle clip handle wraps a rectangle clip"),
340 }
341 }
342
343 pub fn left(&self) -> f32 {
344 self.props().left()
345 }
346
347 pub fn set_left(&self, value: f32) {
348 self.props().set_left(&*self.0, value)
349 }
350
351 pub fn top(&self) -> f32 {
352 self.props().top()
353 }
354
355 pub fn set_top(&self, value: f32) {
356 self.props().set_top(&*self.0, value)
357 }
358
359 pub fn right(&self) -> f32 {
360 self.props().right()
361 }
362
363 pub fn set_right(&self, value: f32) {
364 self.props().set_right(&*self.0, value)
365 }
366
367 pub fn bottom(&self) -> f32 {
368 self.props().bottom()
369 }
370
371 pub fn set_bottom(&self, value: f32) {
372 self.props().set_bottom(&*self.0, value)
373 }
374
375 pub fn top_left_radius(&self) -> Vector {
376 self.props().top_left_radius()
377 }
378
379 pub fn set_top_left_radius(&self, value: Vector) {
380 self.props().set_top_left_radius(&*self.0, value)
381 }
382
383 pub fn top_right_radius(&self) -> Vector {
384 self.props().top_right_radius()
385 }
386
387 pub fn set_top_right_radius(&self, value: Vector) {
388 self.props().set_top_right_radius(&*self.0, value)
389 }
390
391 pub fn bottom_left_radius(&self) -> Vector {
392 self.props().bottom_left_radius()
393 }
394
395 pub fn set_bottom_left_radius(&self, value: Vector) {
396 self.props().set_bottom_left_radius(&*self.0, value)
397 }
398
399 pub fn bottom_right_radius(&self) -> Vector {
400 self.props().bottom_right_radius()
401 }
402
403 pub fn set_bottom_right_radius(&self, value: Vector) {
404 self.props().set_bottom_right_radius(&*self.0, value)
405 }
406}
407
408#[derive(Clone)]
419pub struct GeometricClip(Rc<CompositionClip>);
420
421impl Deref for GeometricClip {
422 type Target = Rc<CompositionClip>;
423
424 fn deref(&self) -> &Rc<CompositionClip> {
425 &self.0
426 }
427}
428
429impl GeometricClip {
430 pub(crate) fn new(compositor: &Rc<Compositor>) -> GeometricClip {
431 GeometricClip(CompositionClip::create(
432 compositor,
433 CompositionClipKind::Geometric(GeometricClipProps::new()),
434 |c| ServerGeometricClip::new(c),
435 ))
436 }
437
438 pub(crate) fn with_geometry(compositor: &Rc<Compositor>, geometry: Option<Rc<CompositionGeometry>>) -> GeometricClip {
439 let clip = Self::new(compositor);
440 clip.set_geometry(geometry);
441 clip
442 }
443
444 pub fn from_clip(clip: &Rc<CompositionClip>) -> Option<GeometricClip> {
446 matches!(clip.kind, CompositionClipKind::Geometric(_)).then(|| GeometricClip(clip.clone()))
447 }
448
449 fn props(&self) -> &GeometricClipProps {
450 match &self.0.kind {
451 CompositionClipKind::Geometric(props) => props,
452 _ => unreachable!("a geometric clip handle wraps a geometric clip"),
453 }
454 }
455
456 pub fn geometry(&self) -> Option<Rc<CompositionGeometry>> {
458 self.props().geometry().and_then(|geometry| geometry.into_any_rc().downcast::<CompositionGeometry>().ok())
459 }
460
461 pub fn set_geometry(&self, value: Option<Rc<CompositionGeometry>>) {
462 self.props().set_geometry(&*self.0, value.map(|geometry| geometry as Rc<dyn ICompositionObject>))
463 }
464
465 pub fn view_box(&self) -> Option<Rc<CompositionViewBox>> {
467 self.props().view_box().and_then(|view_box| view_box.into_any_rc().downcast::<CompositionViewBox>().ok())
468 }
469
470 pub fn set_view_box(&self, value: Option<Rc<CompositionViewBox>>) {
471 self.props().set_view_box(&*self.0, value.map(|view_box| view_box as Rc<dyn ICompositionObject>))
472 }
473}