use crate::win32::menu as mh;
use crate::NwgError;
use super::{ControlBase, ControlHandle};
use std::ptr;
const NOT_BOUND: &'static str = "Menu/MenuItem is not yet bound to a winapi object";
const BAD_HANDLE: &'static str = "INTERNAL ERROR: Menu/MenuItem handle is not HMENU!";
bitflags! {
pub struct PopupMenuFlags: u32 {
const ALIGN_LEFT = 0x0000;
const ALIGN_H_CENTER = 0x0004;
const ALIGN_RIGHT = 0x0008;
const ALIGN_BOTTOM = 0x0020;
const ALIGN_TOP = 0x0000;
const ALIGN_V_CENTER = 0x0010;
const LEFT_BUTTON = 0x0000;
const RIGHT_BUTTON = 0x0002;
const ANIMATE_NONE = 0x4000;
const ANIMATE_RIGHT_TO_LEFT = 0x8000;
const ANIMATE_LEFT_TO_RIGHT = 0x4000;
const ANIMATE_BOTTOM_TO_TOP = 0x2000;
const ANIMATE_TOP_TO_BOTTOM = 0x1000;
}
}
#[derive(Default, PartialEq, Eq)]
pub struct Menu {
pub handle: ControlHandle
}
impl Menu {
pub fn builder<'a>() -> MenuBuilder<'a> {
MenuBuilder {
text: "Menu",
disabled: false,
popup: false,
parent: None
}
}
pub fn enabled(&self) -> bool {
if self.handle.blank() { panic!("{}", NOT_BOUND); }
let (parent_handle, handle) = match self.handle {
ControlHandle::Menu(parent, menu) => (parent, menu),
ControlHandle::PopMenu(_, _) => { return true; },
_ => panic!("{}", BAD_HANDLE)
};
unsafe { mh::is_menu_enabled(parent_handle, handle) }
}
pub fn set_enabled(&self, v: bool) {
if self.handle.blank() { panic!("{}", NOT_BOUND); }
let (parent_handle, handle) = match self.handle {
ControlHandle::Menu(parent, menu) => (parent, menu),
ControlHandle::PopMenu(_, _) => { return; },
_ => panic!("{}", BAD_HANDLE)
};
unsafe { mh::enable_menu(parent_handle, handle, v); }
}
pub fn popup_with_flags(&self, x: i32, y: i32, flags: PopupMenuFlags) {
use winapi::um::winuser::{TrackPopupMenu, SetForegroundWindow};
use winapi::ctypes::c_int;
if self.handle.blank() { panic!("Menu is not bound"); }
let (parent_handle, handle) = match self.handle.pop_hmenu() {
Some(v) => v,
None => { return; }
};
unsafe {
SetForegroundWindow(parent_handle);
TrackPopupMenu(
handle,
flags.bits(),
x as c_int,
y as c_int,
0,
parent_handle,
ptr::null()
);
}
}
pub fn popup(&self, x: i32, y: i32) {
self.popup_with_flags(x, y, PopupMenuFlags::empty())
}
}
impl Drop for Menu {
fn drop(&mut self) {
self.handle.destroy();
}
}
pub struct MenuBuilder<'a> {
text: &'a str,
disabled: bool,
popup: bool,
parent: Option<ControlHandle>
}
impl<'a> MenuBuilder<'a> {
pub fn text(mut self, text: &'a str) -> MenuBuilder<'a> {
self.text = text;
self
}
pub fn disabled(mut self, disabled: bool) -> MenuBuilder<'a> {
self.disabled = disabled;
self
}
pub fn popup(mut self, popup: bool) -> MenuBuilder<'a> {
self.popup = popup;
self
}
pub fn parent<C: Into<ControlHandle>>(mut self, p: C) -> MenuBuilder<'a> {
self.parent = Some(p.into());
self
}
pub fn build(self, menu: &mut Menu) -> Result<(), NwgError> {
if self.parent.is_none() {
return Err(NwgError::no_parent_menu());
}
menu.handle = ControlBase::build_hmenu()
.text(self.text)
.item(false)
.popup(self.popup)
.parent(self.parent.unwrap())
.build()?;
if self.disabled {
menu.set_enabled(false)
}
Ok(())
}
}
#[derive(Default, Debug, PartialEq, Eq)]
pub struct MenuItem {
pub handle: ControlHandle
}
impl MenuItem {
pub fn builder<'a>() -> MenuItemBuilder<'a> {
MenuItemBuilder {
text: "Menu Item",
disabled: false,
check: false,
parent: None
}
}
pub fn enabled(&self) -> bool {
if self.handle.blank() { panic!("{}", NOT_BOUND); }
let (parent_handle, id) = self.handle.hmenu_item().expect(BAD_HANDLE);
unsafe { mh::is_menuitem_enabled(parent_handle, None, Some(id)) }
}
pub fn set_enabled(&self, v: bool) {
if self.handle.blank() { panic!("{}", NOT_BOUND); }
let (parent_handle, id) = self.handle.hmenu_item().expect(BAD_HANDLE);
unsafe { mh::enable_menuitem(parent_handle, None, Some(id), v); }
}
pub fn set_checked(&self, check: bool) {
if self.handle.blank() { panic!("{}", NOT_BOUND); }
let (parent_handle, id) = self.handle.hmenu_item().expect(BAD_HANDLE);
unsafe { mh::check_menu_item(parent_handle, id, check); }
}
pub fn checked(&self) -> bool {
if self.handle.blank() { panic!("{}", NOT_BOUND); }
let (parent_handle, id) = self.handle.hmenu_item().expect(BAD_HANDLE);
unsafe { mh::menu_item_checked(parent_handle, id) }
}
}
impl Drop for MenuItem {
fn drop(&mut self) {
self.handle.destroy();
}
}
pub struct MenuItemBuilder<'a> {
text: &'a str,
disabled: bool,
check: bool,
parent: Option<ControlHandle>
}
impl<'a> MenuItemBuilder<'a> {
pub fn text(mut self, text: &'a str) -> MenuItemBuilder<'a> {
self.text = text;
self
}
pub fn disabled(mut self, disabled: bool) -> MenuItemBuilder<'a> {
self.disabled = disabled;
self
}
pub fn check(mut self, check: bool) -> MenuItemBuilder<'a> {
self.check = check;
self
}
pub fn parent<C: Into<ControlHandle>>(mut self, p: C) -> MenuItemBuilder<'a> {
self.parent = Some(p.into());
self
}
pub fn build(self, item: &mut MenuItem) -> Result<(), NwgError> {
if self.parent.is_none() {
return Err(NwgError::no_parent_menu());
}
item.handle = ControlBase::build_hmenu()
.text(self.text)
.item(true)
.parent(self.parent.unwrap())
.build()?;
if self.disabled {
item.set_enabled(false);
}
if self.check {
item.set_checked(true);
}
Ok(())
}
}
#[derive(Default, Debug, PartialEq, Eq)]
pub struct MenuSeparator {
pub handle: ControlHandle
}
impl MenuSeparator {
pub fn builder() -> MenuSeparatorBuilder {
MenuSeparatorBuilder {
parent: None
}
}
}
pub struct MenuSeparatorBuilder {
parent: Option<ControlHandle>
}
impl MenuSeparatorBuilder {
pub fn parent<C: Into<ControlHandle>>(mut self, p: C) -> MenuSeparatorBuilder {
self.parent = Some(p.into());
self
}
pub fn build(self, sep: &mut MenuSeparator) -> Result<(), NwgError> {
if self.parent.is_none() {
return Err(NwgError::no_parent_menu());
}
sep.handle = ControlBase::build_hmenu()
.separator(true)
.parent(self.parent.unwrap())
.build()?;
Ok(())
}
}
impl Drop for MenuSeparator {
fn drop(&mut self) {
self.handle.destroy();
}
}