use crate::event::{Event, EventType};
use crate::geometry::Point;
use wxdragon_sys as ffi;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum MenuEvent {
Selected,
Opened,
Closed,
Highlighted,
ContextRequested,
}
#[derive(Debug)]
pub struct MenuEventData {
event: Event,
}
impl MenuEventData {
pub(crate) fn new(event: Event) -> Self {
Self { event }
}
pub fn event(&self) -> &Event {
&self.event
}
pub fn get_menu_id(&self) -> Option<i32> {
if self.event.is_null() {
return None;
}
let menu_id = unsafe { ffi::wxd_MenuEvent_GetMenuId(self.event._as_ptr()) };
if menu_id == -1 { None } else { Some(menu_id) }
}
pub fn is_popup(&self) -> bool {
if self.event.is_null() {
return false;
}
unsafe { ffi::wxd_MenuEvent_IsPopup(self.event._as_ptr()) }
}
pub fn get_context_position(&self) -> Option<Point> {
if self.event.is_null() {
return None;
}
let c_point = unsafe { ffi::wxd_ContextMenuEvent_GetPosition(self.event._as_ptr()) };
if c_point.x == -1 && c_point.y == -1 {
None
} else {
Some(Point {
x: c_point.x,
y: c_point.y,
})
}
}
pub fn get_id(&self) -> i32 {
self.event.get_id()
}
pub fn skip(&self, skip: bool) {
self.event.skip(skip);
}
pub fn can_veto(&self) -> bool {
self.event.can_veto()
}
pub fn veto(&self) {
self.event.veto();
}
pub fn is_vetoed(&self) -> bool {
self.event.is_vetoed()
}
}
pub trait MenuEvents: crate::event::WxEvtHandler {
fn on_menu_selected<F>(&self, callback: F)
where
F: FnMut(MenuEventData) + 'static,
{
self.bind_menu_event(MenuEvent::Selected, callback);
}
fn on_menu_opened<F>(&self, callback: F)
where
F: FnMut(MenuEventData) + 'static,
{
self.bind_menu_event(MenuEvent::Opened, callback);
}
fn on_menu_closed<F>(&self, callback: F)
where
F: FnMut(MenuEventData) + 'static,
{
self.bind_menu_event(MenuEvent::Closed, callback);
}
fn on_menu_highlighted<F>(&self, callback: F)
where
F: FnMut(MenuEventData) + 'static,
{
self.bind_menu_event(MenuEvent::Highlighted, callback);
}
fn on_context_menu<F>(&self, callback: F)
where
F: FnMut(MenuEventData) + 'static,
{
self.bind_menu_event(MenuEvent::ContextRequested, callback);
}
#[doc(hidden)]
fn bind_menu_event<F>(&self, event: MenuEvent, mut callback: F)
where
F: FnMut(MenuEventData) + 'static,
{
let event_type = match event {
MenuEvent::Selected => EventType::MENU,
MenuEvent::Opened => EventType::MENU_OPEN,
MenuEvent::Closed => EventType::MENU_CLOSE,
MenuEvent::Highlighted => EventType::MENU_HIGHLIGHT,
MenuEvent::ContextRequested => EventType::CONTEXT_MENU,
};
let wrapper = move |event: Event| {
let menu_event_data = MenuEventData::new(event);
callback(menu_event_data);
};
crate::event::WxEvtHandler::bind_internal(self, event_type, wrapper);
}
}
impl MenuEventData {
pub fn get_event_type_name(&self) -> &'static str {
if let Some(event_type) = self.event.get_event_type() {
match event_type {
EventType::MENU => "Menu Selected",
EventType::MENU_OPEN => "Menu Opened",
EventType::MENU_CLOSE => "Menu Closed",
EventType::MENU_HIGHLIGHT => "Menu Highlighted",
EventType::CONTEXT_MENU => "Context Menu Requested",
_ => "Unknown Menu Event",
}
} else {
"Invalid Event"
}
}
pub fn format_for_logging(&self) -> String {
let event_name = self.get_event_type_name();
let id = self.get_id();
match self.event.get_event_type() {
Some(EventType::CONTEXT_MENU) => {
if let Some(pos) = self.get_context_position() {
format!("{event_name} - ID: {id}, Position: ({}, {})", pos.x, pos.y)
} else {
format!("{event_name} - ID: {id}")
}
}
Some(EventType::MENU_OPEN | EventType::MENU_CLOSE | EventType::MENU_HIGHLIGHT) => {
let popup_info = if self.is_popup() { " (Popup)" } else { " (Menu Bar)" };
if let Some(menu_id) = self.get_menu_id() {
format!("{event_name} - ID: {id}, Menu ID: {menu_id}{popup_info}")
} else {
format!("{event_name} - ID: {id}{popup_info}")
}
}
_ => {
format!("{event_name} - ID: {id}")
}
}
}
}