ohos_arkui_binding/animate/options/
keyframe_animate_option.rs1use 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
30pub 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 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 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 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 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 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 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 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}