use crate::{
core::event::Event,
draw_2d::Image,
prelude::{GuiState, Vkey},
};
use nappgui_sys::{
listener_imp, menuitem_OnClick, menuitem_create, menuitem_enabled, menuitem_image,
menuitem_key, menuitem_separator, menuitem_state, menuitem_submenu, menuitem_text,
menuitem_visible,
};
use super::Menu;
pub struct MenuItem {
pub(crate) inner: *mut nappgui_sys::MenuItem,
}
impl MenuItem {
pub(crate) fn new(ptr: *mut nappgui_sys::MenuItem) -> Self {
if ptr.is_null() {
panic!("ptr is null");
}
Self { inner: ptr }
}
pub fn create() -> Self {
let menu_item = unsafe { menuitem_create() };
Self::new(menu_item)
}
pub fn separator() -> Self {
let menu_item = unsafe { menuitem_separator() };
Self::new(menu_item)
}
pub fn on_click<F>(&self, handler: F)
where
F: FnMut(&mut MenuItem, &Event) + 'static,
{
unsafe extern "C" fn shim(data: *mut std::ffi::c_void, event: *mut nappgui_sys::Event) {
let data = data as *mut (
Box<dyn FnMut(&mut MenuItem, &Event)>,
*mut nappgui_sys::MenuItem,
);
let f = &mut *(*data).0;
let mut obj = MenuItem::new((*data).1);
let ev = Event::new(event as _);
let _r = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| f(&mut obj, &ev)));
}
let cb: Box<dyn FnMut(&mut MenuItem, &Event)> = Box::new(handler);
let data: *mut (
Box<dyn FnMut(&mut MenuItem, &Event)>,
*mut nappgui_sys::MenuItem,
) = Box::into_raw(Box::new((cb, self.inner)));
unsafe {
menuitem_OnClick(
self.inner,
listener_imp(data as *mut std::ffi::c_void, Some(shim)),
);
}
}
pub fn enabled(&self, enabled: bool) {
unsafe { menuitem_enabled(self.inner, enabled as i8) };
}
pub fn visible(&self, visible: bool) {
unsafe { menuitem_visible(self.inner, visible as i8) };
}
pub fn text(&self, text: &str) {
let text = std::ffi::CString::new(text).unwrap();
unsafe { menuitem_text(self.inner, text.as_ptr()) };
}
pub fn image(&self, image: &Image) {
unsafe { menuitem_image(self.inner, image.inner) };
}
pub fn key(&self, key: Vkey, modifiers: u32) {
unsafe { menuitem_key(self.inner, key, modifiers) };
}
pub fn submenu(&self, menu: &mut Menu) {
unsafe { menuitem_submenu(self.inner, &mut menu.inner) };
}
pub fn state(&self, state: GuiState) {
unsafe { menuitem_state(self.inner, state) };
}
}