Skip to main content

swiftui_native/views/
effects.rs

1//! Visual effects.
2
3use super::*;
4use crate::abi;
5use crate::resolve;
6use crate::mangle;
7mangle::modifier_types! {
8    /// `ModifiedContent<AnyView, _ShadowEffect>`
9    pub(crate) SHADOW_T = ty("_ShadowEffect");
10    /// `ModifiedContent<AnyView, _BlurEffect>`
11    pub(crate) BLUR_T = ty("_BlurEffect");
12    /// `ModifiedContent<AnyView, _RotationEffect>`
13    pub(crate) ROTATION_T = ty("_RotationEffect");
14    /// `ModifiedContent<AnyView, _ScaleEffect>`
15    pub(crate) SCALE_T = ty("_ScaleEffect");
16    /// `ModifiedContent<AnyView, _OffsetEffect>`
17    pub(crate) OFFSET_T = ty("_OffsetEffect");
18    /// `ModifiedContent<AnyView, _BrightnessEffect>`
19    pub(crate) BRIGHTNESS_T = ty("_BrightnessEffect");
20    /// `ModifiedContent<AnyView, _SaturationEffect>`
21    pub(crate) SATURATION_T = ty("_SaturationEffect");
22    /// `ModifiedContent<AnyView, _ContrastEffect>`
23    pub(crate) CONTRAST_T = ty("_ContrastEffect");
24    /// `ModifiedContent<AnyView, _GrayscaleEffect>`
25    pub(crate) GRAYSCALE_T = ty("_GrayscaleEffect");
26}
27
28
29
30
31
32
33
34
35
36/// Apply `.shadow(color:radius:x:y:)`.
37pub fn shadow(view: &ViewHandle, c: crate::Color, radius: f64, dx: f64, dy: f64) -> ViewHandle {
38    unsafe {
39        let (_, _, size) = SHADOW_T.applied_to(view.meta);
40        // Color is a single class reference, so it goes in an integer register.
41        let col = color_value(c.r, c.g, c.b, c.a);
42        let r = abi::call_modifier(resolve::shadow_fn(), view.value_ptr(), view.meta, view.wt,
43            &[col],
44            [radius, dx, dy, 0.0],
45            size,
46        );
47        wrap_modified(r, &SHADOW_T, view)
48    }
49}
50
51/// Apply `.blur(radius:)`.
52pub fn blur(view: &ViewHandle, radius: f64) -> ViewHandle {
53    unsafe {
54        let (_, _, size) = BLUR_T.applied_to(view.meta);
55        let r = abi::call_modifier(resolve::blur_fn(), view.value_ptr(), view.meta, view.wt, &[0], [radius, 0.0, 0.0, 0.0], size);
56        wrap_modified(r, &BLUR_T, view)
57    }
58}
59
60/// Apply `.rotationEffect(.degrees(_), anchor:)`.
61pub fn rotation(view: &ViewHandle, degrees: f64, anchor_x: f64, anchor_y: f64) -> ViewHandle {
62    unsafe {
63        let (_, _, size) = ROTATION_T.applied_to(view.meta);
64        // Angle stores radians; UnitPoint is two CGFloats.
65        let radians = degrees * std::f64::consts::PI / 180.0;
66        let r = abi::call_modifier(resolve::rotation_fn(), view.value_ptr(), view.meta, view.wt,
67            &[],
68            [radians, anchor_x, anchor_y, 0.0],
69            size,
70        );
71        wrap_modified(r, &ROTATION_T, view)
72    }
73}
74
75/// Apply `.scaleEffect(_:anchor:)`.
76pub fn scale(view: &ViewHandle, sx: f64, sy: f64, anchor_x: f64, anchor_y: f64) -> ViewHandle {
77    unsafe {
78        let (_, _, size) = SCALE_T.applied_to(view.meta);
79        let r = abi::call_modifier(resolve::scale_fn(), view.value_ptr(), view.meta, view.wt, &[], [sx, sy, anchor_x, anchor_y], size);
80        wrap_modified(r, &SCALE_T, view)
81    }
82}
83
84/// Apply `.offset(x:y:)`.
85pub fn offset(view: &ViewHandle, dx: f64, dy: f64) -> ViewHandle {
86    unsafe {
87        let (_, _, size) = OFFSET_T.applied_to(view.meta);
88        let r = abi::call_modifier(resolve::offset_fn(), view.value_ptr(), view.meta, view.wt, &[], [dx, dy, 0.0, 0.0], size);
89        wrap_modified(r, &OFFSET_T, view)
90    }
91}
92
93macro_rules! scalar_effect {
94    ($name:ident, $sym:ident, $ty:ident, $doc:literal) => {
95        #[doc = $doc]
96        pub fn $name(view: &ViewHandle, amount: f64) -> ViewHandle {
97            unsafe {
98                let (_, _, size) = $ty.applied_to(view.meta);
99                let r =
100                    abi::call_modifier(resolve::$sym(), view.value_ptr(), view.meta, view.wt, &[], [amount, 0.0, 0.0, 0.0], size);
101                wrap_modified(r, &$ty, view)
102            }
103        }
104    };
105}
106
107scalar_effect!(brightness, brightness_fn, BRIGHTNESS_T, "Apply `.brightness(_:)`.");
108scalar_effect!(saturation, saturation_fn, SATURATION_T, "Apply `.saturation(_:)`.");
109scalar_effect!(contrast, contrast_fn, CONTRAST_T, "Apply `.contrast(_:)`.");
110scalar_effect!(grayscale, grayscale_fn, GRAYSCALE_T, "Apply `.grayscale(_:)`.");