use core::{ffi::c_char, ops::Deref, ptr::null_mut};
use oxivgl_sys::*;
use super::{
WidgetError,
child::Child,
obj::{AsLvHandle, Obj},
};
#[derive(Debug)]
pub struct Menu<'p> {
obj: Obj<'p>,
}
impl<'p> AsLvHandle for Menu<'p> {
fn lv_handle(&self) -> *mut lv_obj_t {
self.obj.lv_handle()
}
}
impl<'p> Deref for Menu<'p> {
type Target = Obj<'p>;
fn deref(&self) -> &Obj<'p> {
&self.obj
}
}
#[repr(u32)]
#[derive(Debug, Clone, Copy)]
pub enum MenuHeaderMode {
TopFixed = lv_menu_mode_header_t_LV_MENU_HEADER_TOP_FIXED,
TopUnfixed = lv_menu_mode_header_t_LV_MENU_HEADER_TOP_UNFIXED,
BottomFixed = lv_menu_mode_header_t_LV_MENU_HEADER_BOTTOM_FIXED,
}
impl<'p> Menu<'p> {
pub fn new(parent: &impl AsLvHandle) -> Result<Self, WidgetError> {
let parent_ptr = parent.lv_handle();
assert_ne!(parent_ptr, null_mut(), "Parent widget cannot be null");
let handle = unsafe { lv_menu_create(parent_ptr) };
if handle.is_null() {
Err(WidgetError::LvglNullPointer)
} else {
Ok(Menu { obj: Obj::from_raw(handle) })
}
}
pub fn page_create(&self, title: Option<&str>) -> Child<Obj<'p>> {
assert_ne!(self.obj.handle(), null_mut(), "Menu handle cannot be null");
let (ptr, _buf) = match title {
Some(t) => {
let bytes = t.as_bytes();
let len = bytes.len().min(127);
let mut buf = [0u8; 128];
buf[..len].copy_from_slice(&bytes[..len]);
(buf.as_ptr() as *const c_char, Some(buf))
}
None => (core::ptr::null(), None),
};
let page = unsafe { lv_menu_page_create(self.obj.handle(), ptr) };
assert!(!page.is_null(), "lv_menu_page_create returned NULL");
Child::new(Obj::from_raw(page))
}
pub fn cont_create(parent: &impl AsLvHandle) -> Child<Obj<'_>> {
let parent_ptr = parent.lv_handle();
assert_ne!(parent_ptr, null_mut(), "Parent cannot be null");
let cont = unsafe { lv_menu_cont_create(parent_ptr) };
assert!(!cont.is_null(), "lv_menu_cont_create returned NULL");
Child::new(Obj::from_raw(cont))
}
pub fn section_create(parent: &impl AsLvHandle) -> Child<Obj<'_>> {
let parent_ptr = parent.lv_handle();
assert_ne!(parent_ptr, null_mut(), "Parent cannot be null");
let sec = unsafe { lv_menu_section_create(parent_ptr) };
assert!(!sec.is_null(), "lv_menu_section_create returned NULL");
Child::new(Obj::from_raw(sec))
}
pub fn separator_create(parent: &impl AsLvHandle) -> Child<Obj<'_>> {
let parent_ptr = parent.lv_handle();
assert_ne!(parent_ptr, null_mut(), "Parent cannot be null");
let sep = unsafe { lv_menu_separator_create(parent_ptr) };
assert!(!sep.is_null(), "lv_menu_separator_create returned NULL");
Child::new(Obj::from_raw(sep))
}
pub fn set_page(&self, page: &impl AsLvHandle) -> &Self {
assert_ne!(self.obj.handle(), null_mut(), "Menu handle cannot be null");
unsafe { lv_menu_set_page(self.obj.handle(), page.lv_handle()) };
self
}
pub fn clear_page(&self) -> &Self {
assert_ne!(self.obj.handle(), null_mut(), "Menu handle cannot be null");
unsafe { lv_menu_set_page(self.obj.handle(), null_mut()) };
self
}
pub fn set_sidebar_page(&self, page: &impl AsLvHandle) -> &Self {
assert_ne!(self.obj.handle(), null_mut(), "Menu handle cannot be null");
unsafe { lv_menu_set_sidebar_page(self.obj.handle(), page.lv_handle()) };
self
}
pub fn clear_sidebar(&self) -> &Self {
assert_ne!(self.obj.handle(), null_mut(), "Menu handle cannot be null");
unsafe { lv_menu_set_sidebar_page(self.obj.handle(), null_mut()) };
self
}
pub fn set_load_page_event(&self, cont: &impl AsLvHandle, page: &impl AsLvHandle) -> &Self {
assert_ne!(self.obj.handle(), null_mut(), "Menu handle cannot be null");
unsafe { lv_menu_set_load_page_event(self.obj.handle(), cont.lv_handle(), page.lv_handle()) };
self
}
pub fn set_mode_root_back_button(&self, enabled: bool) -> &Self {
assert_ne!(self.obj.handle(), null_mut(), "Menu handle cannot be null");
let mode = if enabled {
lv_menu_mode_root_back_button_t_LV_MENU_ROOT_BACK_BUTTON_ENABLED
} else {
lv_menu_mode_root_back_button_t_LV_MENU_ROOT_BACK_BUTTON_DISABLED
};
unsafe { lv_menu_set_mode_root_back_button(self.obj.handle(), mode) };
self
}
pub fn set_mode_header(&self, mode: MenuHeaderMode) -> &Self {
assert_ne!(self.obj.handle(), null_mut(), "Menu handle cannot be null");
unsafe { lv_menu_set_mode_header(self.obj.handle(), mode as lv_menu_mode_header_t) };
self
}
pub fn back_button_is_root(&self, obj: &impl AsLvHandle) -> bool {
assert_ne!(self.obj.handle(), null_mut(), "Menu handle cannot be null");
unsafe { lv_menu_back_button_is_root(self.obj.handle(), obj.lv_handle()) }
}
pub fn get_main_header(&self) -> Child<Obj<'_>> {
assert_ne!(self.obj.handle(), null_mut(), "Menu handle cannot be null");
let ptr = unsafe { lv_menu_get_main_header(self.obj.handle()) };
assert!(!ptr.is_null(), "lv_menu_get_main_header returned NULL");
Child::new(Obj::from_raw(ptr))
}
pub fn get_main_header_back_button(&self) -> Child<Obj<'_>> {
assert_ne!(self.obj.handle(), null_mut(), "Menu handle cannot be null");
let ptr = unsafe { lv_menu_get_main_header_back_button(self.obj.handle()) };
assert!(!ptr.is_null(), "lv_menu_get_main_header_back_button returned NULL");
Child::new(Obj::from_raw(ptr))
}
pub fn get_cur_sidebar_page(&self) -> Option<Child<Obj<'_>>> {
assert_ne!(self.obj.handle(), null_mut(), "Menu handle cannot be null");
let ptr = unsafe { lv_menu_get_cur_sidebar_page(self.obj.handle()) };
if ptr.is_null() { None } else { Some(Child::new(Obj::from_raw(ptr))) }
}
pub fn get_cur_main_page(&self) -> Option<Child<Obj<'_>>> {
assert_ne!(self.obj.handle(), null_mut(), "Menu handle cannot be null");
let ptr = unsafe { lv_menu_get_cur_main_page(self.obj.handle()) };
if ptr.is_null() { None } else { Some(Child::new(Obj::from_raw(ptr))) }
}
pub fn clear_history(&self) -> &Self {
assert_ne!(self.obj.handle(), null_mut(), "Menu handle cannot be null");
unsafe { lv_menu_clear_history(self.obj.handle()) };
self
}
pub fn get_mode_header(&self) -> MenuHeaderMode {
let raw = unsafe { lv_menu_get_mode_header(self.lv_handle()) };
match raw {
x if x == lv_menu_mode_header_t_LV_MENU_HEADER_TOP_UNFIXED => MenuHeaderMode::TopUnfixed,
x if x == lv_menu_mode_header_t_LV_MENU_HEADER_BOTTOM_FIXED => MenuHeaderMode::BottomFixed,
_ => MenuHeaderMode::TopFixed,
}
}
pub fn get_sidebar_header(&self) -> Child<Obj<'_>> {
let ptr = unsafe { lv_menu_get_sidebar_header(self.lv_handle()) };
assert!(!ptr.is_null(), "lv_menu_get_sidebar_header returned NULL");
Child::new(Obj::from_raw(ptr))
}
}