use ::alloc::boxed::Box;
use ::core::{ffi::c_void, mem::MaybeUninit, ptr::NonNull, time::Duration};
use bevy_ecs::{component::Component, lifecycle::HookContext, world::DeferredWorld};
use crate::widgets::{Wdg, Widget};
#[derive(Component)]
#[component(on_insert = add_animation)]
#[component(storage = "SparseSet")]
pub struct Animation {
raw: lightvgl_sys::lv_anim_t,
}
impl Animation {
pub fn new<F>(duration: Duration, start: i32, end: i32, animator: F) -> Self
where
F: FnMut(&mut Wdg, i32),
{
unsafe {
let mut anim = MaybeUninit::<lightvgl_sys::lv_anim_t>::uninit();
lightvgl_sys::lv_anim_init(anim.as_mut_ptr());
let mut raw = anim.assume_init();
lightvgl_sys::lv_anim_set_duration(
&mut raw,
duration.as_millis().try_into().unwrap_or(0),
);
lightvgl_sys::lv_anim_set_values(&mut raw, start, end);
lightvgl_sys::lv_anim_set_user_data(
&mut raw,
Box::<F>::into_raw(Box::new(animator)).cast(),
);
lightvgl_sys::lv_anim_set_exec_cb(&mut raw, Some(animator_trampoline::<F>));
Self { raw }
}
}
#[cfg(feature = "no_ecs")]
pub fn set_widget(&mut self, widget: &mut Wdg) {
unsafe {
lightvgl_sys::lv_anim_set_var(self.raw_mut(), widget.raw_mut().cast());
}
}
pub fn start(&mut self) {
unsafe {
let old_ptr = &mut self.raw;
let new_ptr = lightvgl_sys::lv_anim_start(old_ptr);
self.raw = *new_ptr;
}
}
pub fn raw(&self) -> &lightvgl_sys::lv_anim_t {
&self.raw
}
pub fn raw_mut(&mut self) -> &mut lightvgl_sys::lv_anim_t {
&mut self.raw
}
}
unsafe impl Send for Animation {}
unsafe impl Sync for Animation {}
impl Drop for Animation {
fn drop(&mut self) {
crate::info!("Dropping Animation");
}
}
fn add_animation(mut world: DeferredWorld, ctx: HookContext) {
let obj = world
.get_mut::<Widget>(ctx.entity)
.expect("Animation components must be added entities with a Widget component")
.as_mut()
.raw_mut();
let mut anim = world.get_mut::<Animation>(ctx.entity).unwrap();
unsafe {
lightvgl_sys::lv_anim_set_var(anim.raw_mut(), obj.cast());
}
anim.start();
crate::info!("Added Animation");
}
unsafe extern "C" fn animator_trampoline<F>(obj: *mut c_void, val: i32)
where
F: FnMut(&mut Wdg, i32),
{
unsafe {
let ptr = lightvgl_sys::lv_anim_get(obj, None);
let anim = NonNull::new(ptr).unwrap();
let obj = obj.cast();
let user_data = lightvgl_sys::lv_anim_get_user_data(anim.as_ref());
if user_data.is_null() {
crate::warn!("Animation user data was null, this should never happen!");
return;
}
let mut obj_wdg = Wdg::from_ptr(obj);
let callback = &mut *(user_data.cast::<F>());
callback(&mut obj_wdg, val);
}
}