use ::core::{
ops::{Deref, DerefMut},
ptr::NonNull,
};
use bevy_ecs::{
component::Component,
hierarchy::ChildOf,
lifecycle::Insert,
observer::On,
system::{ParamSet, Query},
world::World,
};
use lightvgl_sys::lv_obj_t;
use crate::info;
pub struct LvglWorld(World);
impl Default for LvglWorld {
fn default() -> Self {
let mut world = World::new();
world.add_observer(on_insert_parent);
Self(world)
}
}
impl Deref for LvglWorld {
type Target = World;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for LvglWorld {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
#[derive(Component, PartialEq)]
pub struct Widget {
raw: NonNull<lv_obj_t>,
}
impl Widget {
pub fn raw(&self) -> *const lv_obj_t {
self.raw.as_ptr()
}
pub fn raw_mut(&mut self) -> *mut lv_obj_t {
self.raw.as_ptr()
}
pub fn from_ptr(ptr: *mut lv_obj_t) -> Option<Self> {
Some(Self {
raw: NonNull::new(ptr)?,
})
}
pub fn from_non_null(ptr: NonNull<lv_obj_t>) -> Self {
Self { raw: ptr }
}
pub fn leak(self) -> Wdg {
let wdg = Wdg::from_ptr(self.raw.as_ptr());
::core::mem::forget(self);
wdg
}
#[inline]
pub fn create_widget() -> Self {
Self::default()
}
}
impl Default for Widget {
fn default() -> Self {
unsafe {
Widget::from_ptr(lightvgl_sys::lv_obj_create(lightvgl_sys::lv_screen_active())).unwrap()
}
}
}
impl AsRef<Wdg> for Widget {
fn as_ref(&self) -> &Wdg {
Wdg::from_non_null(&self.raw)
}
}
impl AsMut<Wdg> for Widget {
fn as_mut(&mut self) -> &mut Wdg {
Wdg::from_non_null_mut(&mut self.raw)
}
}
unsafe impl Send for Widget {}
unsafe impl Sync for Widget {}
impl Drop for Widget {
fn drop(&mut self) {
unsafe {
info!("Dropping Obj");
lightvgl_sys::lv_obj_delete_async(self.raw.as_ptr());
}
}
}
pub type Obj = Widget;
macro_rules! impl_widget {
($t:ident, $func:path) => {
#[derive(bevy_ecs::component::Component)]
#[component(storage = "SparseSet")]
pub struct $t;
impl $t {
#[allow(dead_code)]
pub fn create_widget() -> crate::widgets::Widget {
Self::try_create_widget().expect("Could not create widget")
}
pub fn try_create_widget() -> Option<crate::widgets::Widget> {
unsafe {
let default_screen = lightvgl_sys::lv_display_get_screen_active(
lightvgl_sys::lv_display_get_default(),
);
let ptr = $func(default_screen);
crate::widgets::Widget::from_ptr(ptr)
}
}
}
};
}
#[allow(clippy::type_complexity)]
fn on_insert_parent(
trigger: On<Insert, ChildOf>,
mut set: ParamSet<(
/* widgets */ Query<&mut Widget>,
/* children */ Query<(&mut Widget, &ChildOf)>,
)>,
) {
let event = trigger.event();
let parent_widget = set.p1().get_mut(event.entity).unwrap().1.0;
let parent_ptr = set.p0().get_mut(parent_widget).unwrap().raw_mut();
let child_ptr = set.p1().get_mut(event.entity).unwrap().0.raw_mut();
unsafe {
lightvgl_sys::lv_obj_set_parent(child_ptr, parent_ptr);
}
info!("On Insert Parent");
}
#[derive(PartialEq)]
pub struct Wdg {
raw: NonNull<lv_obj_t>,
}
impl Wdg {
pub fn from_ptr(ptr: *mut lv_obj_t) -> Self {
Self {
raw: NonNull::new(ptr).unwrap(),
}
}
pub fn try_from_ptr(ptr: *mut lv_obj_t) -> Option<Self> {
Some(Self {
raw: NonNull::new(ptr)?,
})
}
pub fn from_non_null(ptr: &NonNull<lv_obj_t>) -> &Self {
unsafe { &*(ptr as *const _ as *const Self) }
}
pub fn from_non_null_mut(ptr: &mut NonNull<lv_obj_t>) -> &mut Self {
unsafe { &mut *(ptr as *mut _ as *mut Self) }
}
pub fn raw(&self) -> *const lv_obj_t {
self.raw.as_ptr()
}
pub fn raw_mut(&mut self) -> *mut lv_obj_t {
self.raw.as_ptr()
}
}
impl Deref for Widget {
type Target = Wdg;
fn deref(&self) -> &Self::Target {
Wdg::from_non_null(&self.raw)
}
}
impl DerefMut for Widget {
fn deref_mut(&mut self) -> &mut Self::Target {
Wdg::from_non_null_mut(&mut self.raw)
}
}
include!(concat!(env!("OUT_DIR"), "/widgets.rs"));