use alloc::boxed::Box;
use alloc::vec::Vec;
use core::{ffi::c_void, pin::Pin};
use oxivgl_sys::*;
use super::obj::AsLvHandle;
pub struct Subject {
inner: Pin<Box<lv_subject_t>>,
_group_ptrs: Option<Box<[*mut lv_subject_t]>>,
}
impl core::fmt::Debug for Subject {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("Subject").finish_non_exhaustive()
}
}
impl Subject {
pub fn new_int(value: i32) -> Self {
let mut inner: Pin<Box<lv_subject_t>> = Box::pin(unsafe { core::mem::zeroed() });
unsafe {
let ptr: *mut lv_subject_t =
Pin::as_mut(&mut inner).get_unchecked_mut() as *mut lv_subject_t;
lv_subject_init_int(ptr, value);
}
Self {
inner,
_group_ptrs: None,
}
}
pub fn new_group(members: &[&Subject]) -> Self {
let ptrs: Vec<*mut lv_subject_t> = members.iter().map(|s| s.as_ptr()).collect();
let mut ptrs_box: Box<[*mut lv_subject_t]> = ptrs.into_boxed_slice();
let mut inner: Pin<Box<lv_subject_t>> = Box::pin(unsafe { core::mem::zeroed() });
unsafe {
let group_ptr: *mut lv_subject_t =
Pin::as_mut(&mut inner).get_unchecked_mut() as *mut lv_subject_t;
let arr_ptr: *mut *mut lv_subject_t = ptrs_box.as_mut_ptr();
lv_subject_init_group(group_ptr, arr_ptr, members.len() as u32);
}
Self {
inner,
_group_ptrs: Some(ptrs_box),
}
}
pub fn set_int(&self, value: i32) -> &Self {
unsafe { lv_subject_set_int(self.as_ptr(), value) };
self
}
pub fn get_int(&self) -> i32 {
unsafe { lv_subject_get_int(self.as_ptr()) }
}
pub fn get_previous_int(&self) -> i32 {
unsafe { lv_subject_get_previous_int(self.as_ptr()) }
}
pub fn add_observer(&self, cb: ObserverCb, user_data: *mut c_void) -> &Self {
unsafe { lv_subject_add_observer(self.as_ptr(), Some(cb), user_data) };
self
}
pub fn add_observer_with_target(
&self,
cb: ObserverCb,
target: *mut c_void,
user_data: *mut c_void,
) -> &Self {
unsafe {
lv_subject_add_observer_with_target(self.as_ptr(), Some(cb), target, user_data)
};
self
}
pub fn on_change(&self, cb: fn(i32)) -> &Self {
const _: () = assert!(core::mem::size_of::<fn(i32)>() == core::mem::size_of::<*mut core::ffi::c_void>());
unsafe extern "C" fn trampoline(
observer: *mut lv_observer_t,
subject: *mut lv_subject_t,
) {
unsafe {
let cb_ptr = lv_observer_get_user_data(observer) as *const ();
let cb: fn(i32) = core::mem::transmute(cb_ptr);
cb(lv_subject_get_int(subject));
}
}
unsafe {
lv_subject_add_observer(
self.as_ptr(),
Some(trampoline),
cb as *const () as *mut c_void,
)
};
self
}
pub fn add_observer_obj(
&self,
cb: ObserverCb,
obj: &impl AsLvHandle,
user_data: *mut c_void,
) -> &Self {
unsafe { lv_subject_add_observer_obj(self.as_ptr(), Some(cb), obj.lv_handle(), user_data) };
self
}
pub fn notify(&self) -> &Self {
unsafe { lv_subject_notify(self.as_ptr()) };
self
}
pub fn raw_ptr(&self) -> *mut lv_subject_t {
self.as_ptr()
}
pub(crate) fn as_ptr(&self) -> *mut lv_subject_t {
&*self.inner as *const lv_subject_t as *mut lv_subject_t
}
}
impl Drop for Subject {
fn drop(&mut self) {
unsafe { lv_subject_deinit(self.as_ptr()) };
}
}
pub type ObserverCb = unsafe extern "C" fn(*mut lv_observer_t, *mut lv_subject_t);
pub unsafe fn observer_get_target_obj(observer: *mut lv_observer_t) -> *mut lv_obj_t {
unsafe { lv_observer_get_target_obj(observer) }
}
pub unsafe fn subject_get_int_raw(subject: *mut lv_subject_t) -> i32 {
unsafe { lv_subject_get_int(subject) }
}
pub unsafe fn subject_get_group_element(
subject: *mut lv_subject_t,
index: i32,
) -> *mut lv_subject_t {
unsafe { lv_subject_get_group_element(subject, index) }
}
pub unsafe fn observer_get_target(observer: *mut lv_observer_t) -> *mut c_void {
unsafe { lv_observer_get_target(observer) }
}