Skip to main content

ohos_arkui_binding/animate/options/
keyframe_animate_option.rs

1//! Module animate::options::keyframe_animate_option wrappers and related types.
2
3use std::{cell::RefCell, collections::HashMap, os::raw::c_void, ptr::NonNull, rc::Rc};
4
5use ohos_arkui_input_binding::ArkUIErrorCode;
6use ohos_arkui_sys::{
7    ArkUI_KeyframeAnimateOption, OH_ArkUI_KeyframeAnimateOption_Create,
8    OH_ArkUI_KeyframeAnimateOption_Dispose, OH_ArkUI_KeyframeAnimateOption_GetCurve,
9    OH_ArkUI_KeyframeAnimateOption_GetDelay, OH_ArkUI_KeyframeAnimateOption_GetDuration,
10    OH_ArkUI_KeyframeAnimateOption_GetIterations,
11    OH_ArkUI_KeyframeAnimateOption_RegisterOnEventCallback,
12    OH_ArkUI_KeyframeAnimateOption_RegisterOnFinishCallback,
13    OH_ArkUI_KeyframeAnimateOption_SetCurve, OH_ArkUI_KeyframeAnimateOption_SetDelay,
14    OH_ArkUI_KeyframeAnimateOption_SetDuration, OH_ArkUI_KeyframeAnimateOption_SetIterations,
15};
16
17#[cfg(feature = "api-19")]
18use ohos_arkui_sys::{
19    OH_ArkUI_KeyframeAnimateOption_GetExpectedFrameRate,
20    OH_ArkUI_KeyframeAnimateOption_SetExpectedFrameRate,
21};
22
23use crate::animate::curve::CurveHandle;
24use crate::api::ARK_UI_NATIVE_ANIMATE_API_1;
25use crate::{check_arkui_status, ArkUIContext, ArkUIError, ArkUIResult};
26
27#[cfg(feature = "api-19")]
28use super::AnimationFrameRateRange;
29
30/// High-level wrapper for `ArkUI_KeyframeAnimateOption`.
31pub struct KeyframeAnimation {
32    raw: Rc<RefCell<NonNull<ArkUI_KeyframeAnimateOption>>>,
33    finish_callback: RefCell<Option<*mut KeyframeCallbackContext>>,
34    event_callbacks: RefCell<HashMap<i32, *mut KeyframeCallbackContext>>,
35}
36
37struct KeyframeCallbackContext {
38    callback: Box<dyn Fn()>,
39}
40
41impl KeyframeAnimation {
42    /// Creates keyframe animation options with the given keyframe count.
43    pub fn new(size: i32) -> ArkUIResult<Self> {
44        let option = unsafe { OH_ArkUI_KeyframeAnimateOption_Create(size) };
45        let option = NonNull::new(option).ok_or_else(|| {
46            ArkUIError::new(
47                ArkUIErrorCode::ParamInvalid,
48                "OH_ArkUI_KeyframeAnimateOption_Create returned null",
49            )
50        })?;
51
52        Ok(Self {
53            raw: Rc::new(RefCell::new(option)),
54            finish_callback: RefCell::new(None),
55            event_callbacks: RefCell::new(HashMap::new()),
56        })
57    }
58
59    pub(crate) fn raw(&self) -> *mut ArkUI_KeyframeAnimateOption {
60        self.raw.borrow().as_ptr()
61    }
62
63    pub fn delay(&self, delay: i32) -> ArkUIResult<()> {
64        check_arkui_status!(unsafe { OH_ArkUI_KeyframeAnimateOption_SetDelay(self.raw(), delay) })
65    }
66
67    pub fn get_delay(&self) -> i32 {
68        unsafe { OH_ArkUI_KeyframeAnimateOption_GetDelay(self.raw()) }
69    }
70
71    pub fn iterations(&self, iterations: i32) -> ArkUIResult<()> {
72        check_arkui_status!(unsafe {
73            OH_ArkUI_KeyframeAnimateOption_SetIterations(self.raw(), iterations)
74        })
75    }
76
77    pub fn get_iterations(&self) -> i32 {
78        unsafe { OH_ArkUI_KeyframeAnimateOption_GetIterations(self.raw()) }
79    }
80
81    /// Registers finish callback for keyframe animation.
82    pub fn on_finish_callback<T: Fn() + 'static>(&self, on_finish: T) -> ArkUIResult<()> {
83        let callback = Box::into_raw(Box::new(KeyframeCallbackContext {
84            callback: Box::new(on_finish),
85        }));
86        let result = check_arkui_status!(unsafe {
87            OH_ArkUI_KeyframeAnimateOption_RegisterOnFinishCallback(
88                self.raw(),
89                callback.cast(),
90                Some(keyframe_callback_trampoline),
91            )
92        });
93
94        if let Err(err) = result {
95            unsafe {
96                drop(Box::from_raw(callback));
97            }
98            return Err(err);
99        }
100
101        if let Some(old) = self.finish_callback.borrow_mut().replace(callback) {
102            unsafe {
103                drop(Box::from_raw(old));
104            }
105        }
106
107        Ok(())
108    }
109
110    /// Clears finish callback.
111    pub fn clear_on_finish_callback(&self) -> ArkUIResult<()> {
112        check_arkui_status!(unsafe {
113            OH_ArkUI_KeyframeAnimateOption_RegisterOnFinishCallback(
114                self.raw(),
115                std::ptr::null_mut(),
116                None,
117            )
118        })?;
119
120        if let Some(old) = self.finish_callback.borrow_mut().take() {
121            unsafe {
122                drop(Box::from_raw(old));
123            }
124        }
125
126        Ok(())
127    }
128
129    /// Registers event callback for keyframe at `index`.
130    pub fn on_event_callback<T: Fn() + 'static>(&self, index: i32, event: T) -> ArkUIResult<()> {
131        let callback = Box::into_raw(Box::new(KeyframeCallbackContext {
132            callback: Box::new(event),
133        }));
134        let result = check_arkui_status!(unsafe {
135            OH_ArkUI_KeyframeAnimateOption_RegisterOnEventCallback(
136                self.raw(),
137                callback.cast(),
138                Some(keyframe_callback_trampoline),
139                index,
140            )
141        });
142
143        if let Err(err) = result {
144            unsafe {
145                drop(Box::from_raw(callback));
146            }
147            return Err(err);
148        }
149
150        if let Some(old) = self.event_callbacks.borrow_mut().insert(index, callback) {
151            unsafe {
152                drop(Box::from_raw(old));
153            }
154        }
155
156        Ok(())
157    }
158
159    /// Clears event callback for keyframe at `index`.
160    pub fn clear_on_event_callback(&self, index: i32) -> ArkUIResult<()> {
161        check_arkui_status!(unsafe {
162            OH_ArkUI_KeyframeAnimateOption_RegisterOnEventCallback(
163                self.raw(),
164                std::ptr::null_mut(),
165                None,
166                index,
167            )
168        })?;
169
170        if let Some(old) = self.event_callbacks.borrow_mut().remove(&index) {
171            unsafe {
172                drop(Box::from_raw(old));
173            }
174        }
175
176        Ok(())
177    }
178
179    /// Sets keyframe duration for the specified index.
180    pub fn duration(&self, duration: i32, index: i32) -> ArkUIResult<()> {
181        check_arkui_status!(unsafe {
182            OH_ArkUI_KeyframeAnimateOption_SetDuration(self.raw(), duration, index)
183        })
184    }
185
186    pub fn get_duration(&self, index: i32) -> i32 {
187        unsafe { OH_ArkUI_KeyframeAnimateOption_GetDuration(self.raw(), index) }
188    }
189
190    /// Sets keyframe curve for the specified index.
191    pub fn curve(&self, curve: &CurveHandle, index: i32) -> ArkUIResult<()> {
192        check_arkui_status!(unsafe {
193            OH_ArkUI_KeyframeAnimateOption_SetCurve(self.raw(), curve.as_raw(), index)
194        })
195    }
196
197    pub fn get_curve(&self, index: i32) -> Option<CurveHandle> {
198        let curve = unsafe { OH_ArkUI_KeyframeAnimateOption_GetCurve(self.raw(), index) };
199        CurveHandle::from_raw_borrowed(curve)
200    }
201
202    #[cfg(feature = "api-19")]
203    pub fn rate_range(&self, range: AnimationFrameRateRange) -> ArkUIResult<()> {
204        let mut raw_range = range.raw();
205        check_arkui_status!(unsafe {
206            OH_ArkUI_KeyframeAnimateOption_SetExpectedFrameRate(self.raw(), &mut raw_range)
207        })
208    }
209
210    #[cfg(feature = "api-19")]
211    pub fn get_rate_range(&self) -> AnimationFrameRateRange {
212        let range_ptr = unsafe { OH_ArkUI_KeyframeAnimateOption_GetExpectedFrameRate(self.raw()) };
213        if range_ptr.is_null() {
214            return AnimationFrameRateRange::new();
215        }
216
217        let range = unsafe { *range_ptr };
218        AnimationFrameRateRange::from_raw(range)
219    }
220
221    #[cfg(feature = "napi")]
222    pub fn animate_to(&self, ctx: ArkUIContext) -> ArkUIResult<()> {
223        ARK_UI_NATIVE_ANIMATE_API_1.with(|api| api.keyframe_animate_to(ctx.raw(), self.raw()))?;
224        Ok(())
225    }
226}
227
228impl Drop for KeyframeAnimation {
229    fn drop(&mut self) {
230        if let Some(callback) = self.finish_callback.borrow_mut().take() {
231            unsafe {
232                drop(Box::from_raw(callback));
233            }
234        }
235
236        for (_, callback) in self.event_callbacks.borrow_mut().drain() {
237            unsafe {
238                drop(Box::from_raw(callback));
239            }
240        }
241
242        unsafe { OH_ArkUI_KeyframeAnimateOption_Dispose(self.raw()) };
243    }
244}
245
246unsafe extern "C" fn keyframe_callback_trampoline(data: *mut c_void) {
247    if data.is_null() {
248        return;
249    }
250
251    let callback = unsafe { &*(data as *mut KeyframeCallbackContext) };
252    (callback.callback)();
253}