use alloc::ffi::CString;
use alloc::string::String;
use alloc::vec::Vec;
use crate::animation::Animation;
use crate::error::{Error, Result};
use thorvg_sys as sys;
#[derive(Debug, Clone)]
pub struct Marker {
pub name: String,
pub begin: f32,
pub end: f32,
}
pub struct LottieAnimation<'eng> {
inner: Animation<'eng>,
}
impl LottieAnimation<'_> {
pub(crate) fn new() -> Result<Self> {
let raw = unsafe { sys::tvg_lottie_animation_new() };
if raw.is_null() {
return Err(Error::FailedAllocation);
}
Ok(Self {
inner: unsafe { Animation::from_raw(raw) },
})
}
pub fn load_data(&mut self, data: &[u8]) -> Result<()> {
let pic = self.picture_mut();
pic.load_data(data, crate::picture::MimeType::Lottie, None)
}
#[cfg(feature = "std")]
pub fn load_file(&mut self, path: &str) -> Result<()> {
let pic = self.picture_mut();
pic.load_from_str(path)
}
pub fn set_size(&mut self, w: f32, h: f32) -> Result<()> {
let pic = self.picture_mut();
pic.set_size(w, h)
}
pub fn gen_slot(&mut self, slot_json: &str) -> Option<u32> {
let c_slot = CString::new(slot_json).ok()?;
let id = unsafe { sys::tvg_lottie_animation_gen_slot(self.inner.raw(), c_slot.as_ptr()) };
if id == 0 {
None
} else {
Some(id)
}
}
pub fn apply_slot(&mut self, id: u32) -> Result<()> {
Error::from_raw(unsafe { sys::tvg_lottie_animation_apply_slot(self.inner.raw(), id) })
}
pub fn del_slot(&mut self, id: u32) -> Result<()> {
Error::from_raw(unsafe { sys::tvg_lottie_animation_del_slot(self.inner.raw(), id) })
}
pub fn markers_count(&self) -> Result<u32> {
let mut cnt: u32 = 0;
Error::from_raw(unsafe {
sys::tvg_lottie_animation_get_markers_cnt(self.inner.raw(), &raw mut cnt)
})?;
Ok(cnt)
}
pub fn marker_name(&self, idx: u32) -> Result<String> {
let mut name_ptr: *const core::ffi::c_char = core::ptr::null();
Error::from_raw(unsafe {
sys::tvg_lottie_animation_get_marker(self.inner.raw(), idx, &raw mut name_ptr)
})?;
if name_ptr.is_null() {
return Ok(String::new());
}
Ok(unsafe { core::ffi::CStr::from_ptr(name_ptr) }
.to_string_lossy()
.into_owned())
}
pub fn marker_info(&self, idx: u32) -> Result<Marker> {
let mut name_ptr: *const core::ffi::c_char = core::ptr::null();
let mut begin: f32 = 0.0;
let mut end: f32 = 0.0;
Error::from_raw(unsafe {
sys::tvg_lottie_animation_get_marker_info(
self.inner.raw(),
idx,
&raw mut name_ptr,
&raw mut begin,
&raw mut end,
)
})?;
let name = if name_ptr.is_null() {
String::new()
} else {
unsafe { core::ffi::CStr::from_ptr(name_ptr) }
.to_string_lossy()
.into_owned()
};
Ok(Marker { name, begin, end })
}
pub fn markers(&self) -> Result<Vec<Marker>> {
let count = self.markers_count()?;
let mut markers = Vec::with_capacity(count as usize);
for i in 0..count {
markers.push(self.marker_info(i)?);
}
Ok(markers)
}
pub fn set_marker(&mut self, marker: &str) -> Result<()> {
let c_marker = CString::new(marker)?;
Error::from_raw(unsafe {
sys::tvg_lottie_animation_set_marker(self.inner.raw(), c_marker.as_ptr())
})
}
pub fn tween(&mut self, from: f32, to: f32, progress: f32) -> Result<()> {
Error::from_raw(unsafe {
sys::tvg_lottie_animation_tween(self.inner.raw(), from, to, progress)
})
}
pub fn assign(
&mut self,
layer: &str,
property_index: u32,
variable: &str,
value: f32,
) -> Result<()> {
let c_layer = CString::new(layer)?;
let c_var = CString::new(variable)?;
Error::from_raw(unsafe {
sys::tvg_lottie_animation_assign(
self.inner.raw(),
c_layer.as_ptr(),
property_index,
c_var.as_ptr(),
value,
)
})
}
pub fn set_quality(&mut self, value: u8) -> Result<()> {
Error::from_raw(unsafe { sys::tvg_lottie_animation_set_quality(self.inner.raw(), value) })
}
}
impl<'eng> core::ops::Deref for LottieAnimation<'eng> {
type Target = Animation<'eng>;
fn deref(&self) -> &Animation<'eng> {
&self.inner
}
}
impl<'eng> core::ops::DerefMut for LottieAnimation<'eng> {
fn deref_mut(&mut self) -> &mut Animation<'eng> {
&mut self.inner
}
}
impl core::fmt::Debug for LottieAnimation<'_> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("LottieAnimation").finish_non_exhaustive()
}
}