diff --git a/examples/menu.rs b/examples/menu.rs index ceaf4cc..cc14026 100644 --- a/examples/menu.rs +++ b/examples/menu.rs @@ -1,7 +1,7 @@ extern crate minifb; use minifb::{Window, Key, Scale, WindowOptions, Menu}; -use minifb::{MENU_KEY_CTRL, MENU_KEY_COMMAND}; +use minifb::{MENU_KEY_CTRL}; const WIDTH: usize = 640; const HEIGHT: usize = 360; @@ -26,63 +26,23 @@ fn main() { }) .expect("Unable to Open Window"); - // Setup a sub menu + let mut menu = Menu::new("Test").unwrap(); + let mut sub = Menu::new("Select Color").unwrap(); - let sub_menu = vec![ - Menu { - name: "Color 0", - key: Key::F1, - id: COLOR_0_ID, - ..Menu::default() - }, - Menu { - name: "Color 1", - key: Key::F2, - id: COLOR_1_ID, - ..Menu::default() - }, - Menu { - name: "Color 2", - key: Key::F12, - id: COLOR_2_ID, - ..Menu::default() - }, - ]; + sub.add_item("Color 0", COLOR_0_ID).shortcut(Key::F1, 0).build(); + sub.add_item("Color 1", COLOR_1_ID).shortcut(Key::F2, 0).build(); + sub.add_item("Color 2", COLOR_2_ID).shortcut(Key::F7, 0).build(); - // Main menu + menu.add_item("Menu Test", MENU_TEST_ID).shortcut(Key::W, MENU_KEY_CTRL).build(); - let menu = vec![ - Menu { - name: "Menu Test", - key: Key::W, - id: MENU_TEST_ID, - modifier: MENU_KEY_CTRL, - mac_mod: MENU_KEY_COMMAND, - ..Menu::default() - }, - Menu::separotor(), - Menu { - name: "Other menu!", - key: Key::S, - modifier: MENU_KEY_CTRL, - mac_mod: MENU_KEY_CTRL, - id: OTHER_MENU_ID, - ..Menu::default() - }, - Menu { - name: "Remove Menu", - key: Key::R, - id: CLOSE_MENU_ID, - ..Menu::default() - }, - Menu { - name: "Select Color", - sub_menu: Some(&sub_menu), - ..Menu::default() - } - ]; + menu.add_separator(); - window.add_menu("Test", &menu).expect("Unable to add menu"); + menu.add_item("Other Menu", OTHER_MENU_ID).shortcut(Key::W, MENU_KEY_CTRL).build(); + menu.add_item("Remove Menu", CLOSE_MENU_ID).shortcut(Key::R, 0).build(); + + menu.add_sub_menu("Sub Test", &sub); + + let menu_handle = window.add_menu(&menu); let mut color_mul = 1; @@ -106,7 +66,7 @@ fn main() { } CLOSE_MENU_ID => { println!("remove menu"); - window.remove_menu("Test").expect("Unable to remove menu"); + window.remove_menu(menu_handle); } _ => (), } diff --git a/src/key.rs b/src/key.rs index 920ab88..cfad8c3 100644 --- a/src/key.rs +++ b/src/key.rs @@ -1,5 +1,5 @@ /// Key is used by the get key functions to check if some keys on the keyboard has been pressed -#[derive(PartialEq, Clone, Copy)] +#[derive(Debug, PartialEq, Clone, Copy)] pub enum Key { Key0 = 0, Key1 = 1, diff --git a/src/lib.rs b/src/lib.rs index 7b92226..e20e062 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -75,13 +75,13 @@ pub mod os; mod mouse_handler; mod key_handler; mod window_flags; -mod menu; -pub use menu::Menu as Menu; -pub use menu::MENU_KEY_COMMAND; -pub use menu::MENU_KEY_WIN; -pub use menu::MENU_KEY_SHIFT; -pub use menu::MENU_KEY_CTRL; -pub use menu::MENU_KEY_ALT; +//mod menu; +//pub use menu::Menu as Menu; +//pub use menu::MENU_KEY_COMMAND; +//pub use menu::MENU_KEY_WIN; +//pub use menu::MENU_KEY_SHIFT; +//pub use menu::MENU_KEY_CTRL; +//pub use menu::MENU_KEY_ALT; #[cfg(target_os = "macos")] @@ -462,25 +462,28 @@ impl Window { /// scope for this library to support. /// ``` /// + #[inline] - pub fn add_menu(&mut self, menu_name: &str, menu: &Vec) -> Result<()> { - self.0.add_menu(menu_name, menu) + pub fn add_menu(&mut self, menu: &Menu) -> MenuHandle { + self.0.add_menu(&menu.0) } /// /// Updates an existing menu created with [add_menu] /// + /* #[inline] pub fn update_menu(&mut self, menu_name: &str, menu: &Vec) -> Result<()> { self.0.update_menu(menu_name, menu) } + */ /// /// Remove a menu that has been added with [add_menu] /// #[inline] - pub fn remove_menu(&mut self, menu_name: &str) -> Result<()> { - self.0.remove_menu(menu_name) + pub fn remove_menu(&mut self, handle: MenuHandle) { + self.0.remove_menu(handle) } /// @@ -492,6 +495,144 @@ impl Window { } } + +/// Command key on Mac OS +pub const MENU_KEY_COMMAND: usize = 1; +/// Windows key on Windows +pub const MENU_KEY_WIN: usize = 2; +/// Shift key +pub const MENU_KEY_SHIFT: usize = 4; +/// Control key +pub const MENU_KEY_CTRL: usize = 8; +/// Alt key +pub const MENU_KEY_ALT: usize = 16; + +const MENU_ID_SEPARATOR:usize = 0xffffffff; + +pub struct Menu(imp::Menu); + +#[derive(Copy, Clone)] +pub struct MenuItemHandle(pub u64); + +#[derive(Copy, Clone, PartialEq)] +pub struct MenuHandle(pub u64); + +impl Menu { + pub fn new(name: &str) -> Result { + imp::Menu::new(name).map(Menu) + } + + #[inline] + pub fn destroy_menu(&mut self) { + //self.0.destroy_menu() + } + + #[inline] + pub fn add_sub_menu(&mut self, name: &str, menu: &Menu) { + self.0.add_sub_menu(name, &menu.0) + } + + pub fn add_separator(&mut self) { + self.add_menu_item(&MenuItem { id: MENU_ID_SEPARATOR, ..MenuItem::default() }); + } + + #[inline] + pub fn add_menu_item(&mut self, item: &MenuItem) -> MenuItemHandle { + self.0.add_menu_item(item) + } + + #[inline] + pub fn add_item(&mut self, name: &str, id: usize) -> MenuItem { + MenuItem { + id: id, + label: name.to_owned(), + menu: Some(self), + ..MenuItem::default() + } + } + + #[inline] + pub fn remove_item(&mut self, item: &MenuItemHandle) { + self.0.remove_item(item) + } +} + +pub struct MenuItem<'a> { + pub id: usize, + pub label: String, + pub enabled: bool, + pub key: Key, + pub modifier: usize, + pub menu: Option<&'a mut Menu>, +} + +impl<'a> Default for MenuItem<'a> { + fn default() -> Self { + MenuItem { + id: MENU_ID_SEPARATOR, + label: "".to_owned(), + enabled: true, + key: Key::Unknown, + modifier: 0, + menu: None, + } + } +} + +impl<'a> Clone for MenuItem<'a> { + fn clone(&self) -> Self { + MenuItem { + id: self.id, + label: self.label.clone(), + enabled: self.enabled, + key: self.key, + modifier: self.modifier, + menu: None, + } + } +} + +impl<'a> MenuItem<'a> { + pub fn new(name: &str, id: usize) -> MenuItem { + MenuItem { + id: id, + label: name.to_owned(), + ..MenuItem::default() + } + } + #[inline] + pub fn shortcut(self, key: Key, modifier: usize) -> Self { + MenuItem { + key: key, + modifier: modifier, + .. self + } + } + #[inline] + pub fn separator(self) -> Self { + MenuItem { + id: MENU_ID_SEPARATOR, + .. self + } + } + #[inline] + pub fn enabled(self, enabled: bool) -> Self { + MenuItem { + enabled: enabled, + .. self + } + } + #[inline] + pub fn build(&mut self) -> MenuItemHandle { + let t = self.clone(); + if let Some(ref mut menu) = self.menu { + menu.0.add_menu_item(&t) + } else { + MenuItemHandle(0) + } + } +} + // Impl for WindowOptions #[doc(hidden)] diff --git a/src/menu.rs b/src/menu.rs index 7b24ed2..fa22461 100644 --- a/src/menu.rs +++ b/src/menu.rs @@ -1,3 +1,4 @@ +/* use Key; /// Command key on Mac OS @@ -13,47 +14,42 @@ pub const MENU_KEY_ALT: usize = 16; const MENU_ID_SEPARATOR:usize = 0xffffffff; -/// -/// Used to hold the data for creating menus for the Application -/// -pub struct Menu<'a> { - /// Name of the menu item - pub name: &'a str, - /// User-defined Id thot will be sent back to the application in [get_menu_event] - pub id: usize, - /// Shortcut key for the menu item - pub key: Key, - /// Modifier on Windows for the menu - pub modifier: usize, - /// Modifier on Mac OS - pub mac_mod: usize, - /// Menu item should be enabled on grayed out - pub enabled: bool, - /// Sub-menu. Vector of a sub-menu, otherwise None if no sub-menu - pub sub_menu: Option<&'a Vec>>, -} +#[cfg(target_os = "macos")] +use self::os::macos as imp; +#[cfg(target_os = "windows")] +use self::os::windows as imp; +#[cfg(any(target_os="linux", + target_os="freebsd", + target_os="dragonfly", + target_os="netbsd", + target_os="openbsd"))] +use self::os::unix as imp; -impl<'a> Menu<'a> { - pub fn separotor() -> Menu<'a> { - Menu { - id: MENU_ID_SEPARATOR, - .. Self::default() - } +pub struct Menu(imp::Menu); + +impl Menu { + pub fn new(name: &name) -> Result { + imp::Menu::new(name).map(Menu) + } + + #[inline] + pub fn destroy_menu(&mut self) { + self.0.destroy_menu() + } + + #[inline] + pub fn add_sub_menu(&mut self, menu: &Menu) { + self.0.add_sub_menu(menu) + } + + #[inline] + pub fn add_item(&mut self, item: &mut MenuItem) { + self.0.add_item(item) + } + + #[inline] + pub fn remove_item(&mut self, item: &mut MenuItem) { + self.0.remove_item(item) } } - -impl<'a> Default for Menu<'a> { - fn default() -> Menu<'a> { - Menu { - name: "", - id: 0, - key: Key::Unknown, - modifier: 0, - mac_mod: 0, - enabled: true, - sub_menu: None, - } - } -} - - +*/ diff --git a/src/native/macosx/MacMiniFB.m b/src/native/macosx/MacMiniFB.m index 70f9985..edf5d51 100644 --- a/src/native/macosx/MacMiniFB.m +++ b/src/native/macosx/MacMiniFB.m @@ -1,7 +1,7 @@ - #include "OSXWindow.h" #include "OSXWindowFrameView.h" #include +#include #include static bool s_init = false; @@ -240,7 +240,8 @@ static int update_events() /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -static int generic_update(OSXWindow* win) { +static int generic_update(OSXWindow* win) +{ int state = update_events(); if (win->shared_data) { @@ -383,54 +384,216 @@ int mfb_active_menu(void* window) { /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void mfb_add_menu(void* window, const char* name, void* m) +static CFStringRef create_string_for_key(CGKeyCode keyCode) { - OSXWindow* win = (OSXWindow*)window; + TISInputSourceRef currentKeyboard = TISCopyCurrentKeyboardInputSource(); + CFDataRef layoutData = TISGetInputSourceProperty(currentKeyboard, kTISPropertyUnicodeKeyLayoutData); - const char* n = strdup(name); + if (!layoutData) + return 0; - NSString* ns_name = [NSString stringWithUTF8String: n]; + const UCKeyboardLayout *keyboardLayout = (const UCKeyboardLayout *)CFDataGetBytePtr(layoutData); - NSMenu* main_menu = [NSApp mainMenu]; + UInt32 keysDown = 0; + UniChar chars[4]; + UniCharCount realLength; - NSMenuItem* windowMenuItem = [main_menu addItemWithTitle:@"" action:NULL keyEquivalent:@""]; - NSMenu* windowMenu = [[NSMenu alloc] initWithTitle:ns_name]; - [NSApp setWindowsMenu:windowMenu]; - [windowMenuItem setSubmenu:windowMenu]; + UCKeyTranslate(keyboardLayout, + keyCode, + kUCKeyActionDisplay, + 0, + LMGetKbdType(), + kUCKeyTranslateNoDeadKeysBit, + &keysDown, + sizeof(chars) / sizeof(chars[0]), + &realLength, + chars); + CFRelease(currentKeyboard); - MenuDesc* menu_desc = (MenuDesc*)m; - - [windowMenu setAutoenablesItems:NO]; - - build_submenu(windowMenu, menu_desc); - - Menu* menu = &win->menu_data->menus[win->menu_data->menu_count++]; - - menu->name = n; - menu->menu = windowMenu; - menu->menu_item = windowMenuItem; + return CFStringCreateWithCharacters(kCFAllocatorDefault, chars, 1); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void mfb_update_menu(void* window, const char* name, void* m) +static NSString* convert_key_code_to_string(int key) { - OSXWindow* win = (OSXWindow*)window; - - NSString* ns_name = [NSString stringWithUTF8String: name]; - NSMenu* main_menu = [NSApp mainMenu]; - - int len = win->menu_data->menu_count; - - for (int i = 0; i < len; ++i) + if (key < 128) { - Menu* menu = &win->menu_data->menus[i]; + NSString* charName = (NSString*)create_string_for_key(key); - if (!strcmp(menu->name, name)) { - [menu->menu removeAllItems]; - build_submenu(menu->menu, (MenuDesc*)m); - return; - } + if (charName) + return charName; + + return [NSString stringWithFormat:@"%c", (char)key]; } + + return [NSString stringWithFormat:@"%C", (uint16_t)key]; } +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +const uint32_t MENU_KEY_COMMAND = 1; +const uint32_t MENU_KEY_WIN = 2; +const uint32_t MENU_KEY_SHIFT= 4; +const uint32_t MENU_KEY_CTRL = 8; +const uint32_t MENU_KEY_ALT = 16; + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +static NSString* get_string_for_key(uint32_t t) { + unichar c = (unichar)t; + NSString* key = [NSString stringWithCharacters:&c length:1]; + return key; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +uint64_t mfb_add_menu_item( + void* in_menu, + int32_t menu_id, + const char* item_name, + bool enabled, + uint32_t key, + uint32_t modfier) +{ + NSMenu* menu = (NSMenu*)in_menu; + + NSString* name = [NSString stringWithUTF8String: item_name]; + + if (menu_id == -1) + { + [menu addItem:[NSMenuItem separatorItem]]; + } + else + { + NSString* key_string = 0; + int mask = 0; + NSMenuItem* newItem = [[NSMenuItem alloc] initWithTitle:name action:@selector(onMenuPress:) keyEquivalent:@""]; + [newItem setTag:menu_id]; + + // This code may look a bit weird but is here for a reason: + // + // In order to make it easier to bulid cross-platform apps Ctrl is often used as + // default modifier on Windows/Nix* while it's Command on Mac. Now we when Ctrl + // is set we default to Command on Mac for that reason but if Command AND Ctrl is + // set we allow both Ctrl and Command to be used but then it's up to the developer + // to deal with diffrent shortcuts depending on OS. + // + + if ((modfier & MENU_KEY_CTRL)) { + mask |= NSCommandKeyMask; + } + if ((modfier & MENU_KEY_CTRL) && + (modfier & MENU_KEY_COMMAND)) { + mask |= NSControlKeyMask; + } + if (modfier & MENU_KEY_SHIFT) { + mask |= NSShiftKeyMask; + } + if (modfier & MENU_KEY_ALT) { + mask |= NSAlternateKeyMask; + } + + switch (key) { + case 0x7a: { key_string = get_string_for_key(NSF1FunctionKey); break; } // F1 + case 0x78: { key_string = get_string_for_key(NSF2FunctionKey); break; } // F2 + case 0x63: { key_string = get_string_for_key(NSF3FunctionKey); break; } // F3 + case 0x76: { key_string = get_string_for_key(NSF4FunctionKey); break; } // F4 + case 0x60: { key_string = get_string_for_key(NSF5FunctionKey); break; } // F5 + case 0x61: { key_string = get_string_for_key(NSF6FunctionKey); break; } // F6 + case 0x62: { key_string = get_string_for_key(NSF7FunctionKey); break; } // F7 + case 0x64: { key_string = get_string_for_key(NSF8FunctionKey); break; } // F8 + case 0x65: { key_string = get_string_for_key(NSF9FunctionKey); break; } // F9 + case 0x6d: { key_string = get_string_for_key(NSF10FunctionKey); break; } // F10 + case 0x67: { key_string = get_string_for_key(NSF11FunctionKey); break; } // F11 + case 0x6f: { key_string = get_string_for_key(NSF12FunctionKey); break; } // F12 + case 0x7f: break; + default: { + key_string = convert_key_code_to_string(key); + } + } + + if (key_string) { + [newItem setKeyEquivalentModifierMask: mask]; + [newItem setKeyEquivalent:key_string]; + } + + if (enabled) { + [newItem setEnabled:YES]; + } else { + [newItem setEnabled:NO]; + } + + [newItem setOnStateImage: newItem.offStateImage]; + [menu addItem:newItem]; + + return (uint64_t)newItem; + } + + return 0; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +void mfb_add_sub_menu(void* parent_menu, const char* menu_name, void* attach_menu) { + NSMenu* parent = (NSMenu*)parent_menu; + NSMenu* attach = (NSMenu*)attach_menu; + NSString* name = [NSString stringWithUTF8String: menu_name]; + + NSMenuItem* newItem = [[NSMenuItem alloc] initWithTitle:name action:NULL keyEquivalent:@""]; + [newItem setSubmenu:attach]; + + [parent addItem:newItem]; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +void* mfb_create_menu(const char* name) { + NSString* ns_name = [NSString stringWithUTF8String: name]; + NSMenu* menu = [[NSMenu alloc] initWithTitle:ns_name]; + return (void*)menu; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +void mfb_destroy_menu(void* menu_item, const char* name) +{ + NSMenuItem* item = (NSMenuItem*)menu_item; + NSMenu* main_menu = [NSApp mainMenu]; + [main_menu removeItem:item]; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +void mfb_remove_menu_item(void* parent, uint64_t menu_item) { + NSMenu* menu = (NSMenu*)parent; + NSMenuItem* item = (NSMenuItem*)(uintptr_t)menu_item; + [menu removeItem:item]; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +uint64_t mfb_add_menu(void* window, void* m) +{ + OSXWindow* win = (OSXWindow*)window; + NSMenu* menu = (NSMenu*)m; + + NSMenu* main_menu = [NSApp mainMenu]; + + NSMenuItem* windowMenuItem = [main_menu addItemWithTitle:@"" action:NULL keyEquivalent:@""]; + [NSApp setWindowsMenu:menu]; + [windowMenuItem setSubmenu:menu]; + + return (uint64_t)menu; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +void mfb_remove_menu_at(void* window, int index) +{ + (void)window; + NSMenu* main_menu = [NSApp mainMenu]; + [main_menu removeItemAtIndex:index]; +} + + diff --git a/src/native/macosx/OSXWindow.m b/src/native/macosx/OSXWindow.m index 7cc1e02..bfa6447 100644 --- a/src/native/macosx/OSXWindow.m +++ b/src/native/macosx/OSXWindow.m @@ -1,6 +1,5 @@ #import "OSXWindow.h" #import "OSXWindowFrameView.h" -#include @implementation OSXWindow @@ -71,14 +70,6 @@ key_callback(rust_data, [event keyCode], 1); } - if (char_callback) { - NSString* characters = [event characters]; - NSUInteger i, length = [characters length]; - - for (i = 0; i < length; i++) - char_callback(rust_data, [characters characterAtIndex:i]); - } - [super keyDown:event]; } @@ -216,154 +207,7 @@ self->active_menu_id = menu_id; } -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -static CFStringRef create_string_for_key(CGKeyCode keyCode) -{ - TISInputSourceRef currentKeyboard = TISCopyCurrentKeyboardInputSource(); - CFDataRef layoutData = TISGetInputSourceProperty(currentKeyboard, kTISPropertyUnicodeKeyLayoutData); - - if (!layoutData) - return 0; - - const UCKeyboardLayout *keyboardLayout = (const UCKeyboardLayout *)CFDataGetBytePtr(layoutData); - - UInt32 keysDown = 0; - UniChar chars[4]; - UniCharCount realLength; - - UCKeyTranslate(keyboardLayout, - keyCode, - kUCKeyActionDisplay, - 0, - LMGetKbdType(), - kUCKeyTranslateNoDeadKeysBit, - &keysDown, - sizeof(chars) / sizeof(chars[0]), - &realLength, - chars); - CFRelease(currentKeyboard); - - return CFStringCreateWithCharacters(kCFAllocatorDefault, chars, 1); -} - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -static NSString* convert_key_code_to_string(int key) -{ - if (key < 128) - { - NSString* charName = (NSString*)create_string_for_key(key); - - if (charName) - return charName; - - return [NSString stringWithFormat:@"%c", (char)key]; - } - - return [NSString stringWithFormat:@"%C", (uint16_t)key]; -} - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -const uint32_t MENU_KEY_COMMAND = 1; -const uint32_t MENU_KEY_WIN = 2; -const uint32_t MENU_KEY_SHIFT= 4; -const uint32_t MENU_KEY_CTRL = 8; -const uint32_t MENU_KEY_ALT = 16; - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -static NSString* get_string_for_key(uint32_t t) { - unichar c = (unichar)t; - NSString* key = [NSString stringWithCharacters:&c length:1]; - return key; -} - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -void build_submenu(NSMenu* menu, MenuDesc* desc) -{ - [menu removeAllItems]; - - while (desc->menu_id != -2) - { - NSString* name = [NSString stringWithUTF8String: desc->name]; - - if (desc->menu_id == -1) - { - [menu addItem:[NSMenuItem separatorItem]]; - } - else if (desc->sub_menu) - { - NSMenuItem* newItem = [[NSMenuItem alloc] initWithTitle:name action:NULL keyEquivalent:@""]; - NSMenu* newMenu = [[NSMenu alloc] initWithTitle:name]; - [newItem setSubmenu:newMenu]; - - build_submenu(newMenu, desc->sub_menu); - - [newMenu release]; - [menu addItem:newItem]; - [newItem release]; - } - else - { - int mask = 0; - NSString* key = 0; - - NSMenuItem* newItem = [[NSMenuItem alloc] initWithTitle:name action:@selector(onMenuPress:) keyEquivalent:@""]; - [newItem setTag:desc->menu_id]; - - if (desc->modifier_mac & MENU_KEY_COMMAND) { - mask |= NSCommandKeyMask; - } - if (desc->modifier_mac & MENU_KEY_SHIFT) { - mask |= NSShiftKeyMask; - } - if (desc->modifier_mac & MENU_KEY_CTRL) { - mask |= NSControlKeyMask; - } - if (desc->modifier_mac & MENU_KEY_ALT) { - mask |= NSAlternateKeyMask; - } - - switch (desc->key) { - case 0x7a: { key = get_string_for_key(NSF1FunctionKey); break; } // F1 - case 0x78: { key = get_string_for_key(NSF2FunctionKey); break; } // F2 - case 0x63: { key = get_string_for_key(NSF3FunctionKey); break; } // F3 - case 0x76: { key = get_string_for_key(NSF4FunctionKey); break; } // F4 - case 0x60: { key = get_string_for_key(NSF5FunctionKey); break; } // F5 - case 0x61: { key = get_string_for_key(NSF6FunctionKey); break; } // F6 - case 0x62: { key = get_string_for_key(NSF7FunctionKey); break; } // F7 - case 0x64: { key = get_string_for_key(NSF8FunctionKey); break; } // F8 - case 0x65: { key = get_string_for_key(NSF9FunctionKey); break; } // F9 - case 0x6d: { key = get_string_for_key(NSF10FunctionKey); break; } // F10 - case 0x67: { key = get_string_for_key(NSF11FunctionKey); break; } // F11 - case 0x6f: { key = get_string_for_key(NSF12FunctionKey); break; } // F12 - case 0x7f: break; - default: { - key = convert_key_code_to_string(desc->key); - } - } - - if (key) { - [newItem setKeyEquivalentModifierMask: mask]; - [newItem setKeyEquivalent:key]; - } - - if (desc->enabled) { - [newItem setEnabled:YES]; - } else { - [newItem setEnabled:NO]; - } - - [newItem setOnStateImage: newItem.offStateImage]; - [menu addItem:newItem]; - [newItem release]; - } - - desc++; - } -} - @end + + + diff --git a/src/os/macos/mod.rs b/src/os/macos/mod.rs index bfd43d9..b90daaf 100644 --- a/src/os/macos/mod.rs +++ b/src/os/macos/mod.rs @@ -4,13 +4,15 @@ use {MouseButton, MouseMode, Scale, Key, KeyRepeat, WindowOptions}; use key_handler::KeyHandler; use error::Error; use Result; +// use MenuItem; use InputCallback; use mouse_handler; use window_flags; -use menu::Menu; +use {MenuItem, MenuItemHandle, MenuHandle}; +// use menu::Menu; use libc::{c_void, c_char, c_uchar}; -use std::ffi::{CString}; +use std::ffi::CString; use std::ptr; use std::mem; use std::os::raw; @@ -148,40 +150,42 @@ static KEY_MAPPINGS: [Key; 128] = [ /* 7f */ Key::Unknown, ]; - -const STRING_SIZE: usize = 512; - -#[repr(C)] -struct CMenu { - name: [i8; STRING_SIZE], - sub_menu: *mut raw::c_void, - id: raw::c_int, - key: raw::c_int, - special_key: raw::c_int, - modifier: raw::c_int, - mac_mod: raw::c_int, - enabled: raw::c_int, -} - #[link(name = "Cocoa", kind = "framework")] #[link(name = "Carbon", kind = "framework")] -extern { - fn mfb_open(name: *const c_char, width: u32, height: u32, flags: u32, scale: i32) -> *mut c_void; +extern "C" { + fn mfb_open(name: *const c_char, + width: u32, + height: u32, + flags: u32, + scale: i32) + -> *mut c_void; fn mfb_close(window: *mut c_void); fn mfb_update(window: *mut c_void); fn mfb_update_with_buffer(window: *mut c_void, buffer: *const c_uchar); fn mfb_set_position(window: *mut c_void, x: i32, y: i32); - fn mfb_set_key_callback(window: *mut c_void, target: *mut c_void, - cb: unsafe extern fn(*mut c_void, i32, i32), - cb: unsafe extern fn(*mut c_void, u32)); + fn mfb_set_key_callback(window: *mut c_void, + target: *mut c_void, + cb: unsafe extern "C" fn(*mut c_void, i32, i32), + cb: unsafe extern "C" fn(*mut c_void, u32)); fn mfb_set_mouse_data(window_handle: *mut c_void, shared_data: *mut SharedData); fn mfb_should_close(window: *mut c_void) -> i32; fn mfb_get_screen_size() -> u32; fn mfb_is_active(window: *mut c_void) -> u32; - fn mfb_add_menu(window: *mut c_void, name: *const c_char, menu: *mut c_void); - fn mfb_remove_menu(window: *mut c_void, name: *const c_char); - fn mfb_update_menu(window: *mut c_void, name: *const c_char, menu: *mut c_void); + fn mfb_add_menu(window: *mut c_void, menu: *mut c_void) -> u64; + fn mfb_add_sub_menu(parent_menu: *mut c_void, name: *const c_char, menu: *mut c_void); fn mfb_active_menu(window: *mut c_void) -> i32; + + fn mfb_create_menu(name: *const c_char) -> *mut c_void; + fn mfb_remove_menu_at(window: *mut c_void, index: i32); + + fn mfb_add_menu_item(menu_item: *mut c_void, + menu_id: i32, + name: *const c_char, + enabled: bool, + key: u32, + modifier: u32) + -> u64; + fn mfb_remove_menu_item(menu: *mut c_void, item_handle: u64); } #[derive(Default)] @@ -202,6 +206,7 @@ pub struct Window { pub shared_data: SharedData, key_handler: KeyHandler, pub has_set_data: bool, + menus: Vec, } unsafe extern "C" fn key_callback(window: *mut c_void, key: i32, state: i32) { @@ -241,7 +246,11 @@ impl Window { unsafe { let scale_factor = Self::get_scale_factor(width, height, opts.scale) as usize; - let handle = mfb_open(n.as_ptr(), width as u32, height as u32, window_flags::get_flags(opts), scale_factor as i32); + let handle = mfb_open(n.as_ptr(), + width as u32, + height as u32, + window_flags::get_flags(opts), + scale_factor as i32); if handle == ptr::null_mut() { return Err(Error::WindowCreate("Unable to open Window".to_owned())); @@ -253,10 +262,11 @@ impl Window { shared_data: SharedData { width: width as u32 * scale_factor as u32, height: height as u32 * scale_factor as u32, - .. SharedData::default() + ..SharedData::default() }, key_handler: KeyHandler::new(), has_set_data: false, + menus: Vec::new(), }) } } @@ -277,7 +287,10 @@ impl Window { unsafe { mfb_update_with_buffer(self.window_handle, buffer.as_ptr() as *const u8); Self::set_mouse_data(self); - mfb_set_key_callback(self.window_handle, mem::transmute(self), key_callback, char_callback); + mfb_set_key_callback(self.window_handle, + mem::transmute(self), + key_callback, + char_callback); } } @@ -287,7 +300,10 @@ impl Window { unsafe { mfb_update(self.window_handle); Self::set_mouse_data(self); - mfb_set_key_callback(self.window_handle, mem::transmute(self), key_callback, char_callback); + mfb_set_key_callback(self.window_handle, + mem::transmute(self), + key_callback, + char_callback); } } @@ -297,7 +313,8 @@ impl Window { } pub fn get_size(&self) -> (usize, usize) { - (self.shared_data.width as usize, self.shared_data.height as usize) + (self.shared_data.width as usize, + self.shared_data.height as usize) } pub fn get_scroll_wheel(&self) -> Option<(f32, f32)> { @@ -324,7 +341,12 @@ impl Window { let w = self.shared_data.width as f32; let h = self.shared_data.height as f32; - mouse_handler::get_pos(mode, self.shared_data.mouse_x, self.shared_data.mouse_y, s, w, h) + mouse_handler::get_pos(mode, + self.shared_data.mouse_x, + self.shared_data.mouse_y, + s, + w, + h) } #[inline] @@ -358,7 +380,7 @@ impl Window { } #[inline] - pub fn set_input_callback(&mut self, callback: Box) { + pub fn set_input_callback(&mut self, callback: Box) { self.key_handler.set_input_callback(callback) } @@ -372,40 +394,25 @@ impl Window { } } - pub fn add_menu(&mut self, name: &str, menu: &Vec) -> Result<()> { - let mut build_menu = Vec::>::new(); - + pub fn add_menu(&mut self, menu: &Menu) -> MenuHandle { unsafe { - Self::recursive_convert(&mut build_menu, &Some(menu)); - let menu_len = build_menu.len(); - mfb_add_menu(self.window_handle, - CString::new(name).unwrap().as_ptr(), - build_menu[menu_len - 1].as_mut_ptr() as *mut c_void); + let handle = MenuHandle(mfb_add_menu(self.window_handle, menu.menu_handle)); + self.menus.push(handle); + handle } - - Ok(()) } - pub fn update_menu(&mut self, name: &str, menu: &Vec) -> Result<()> { - let mut build_menu = Vec::>::new(); - - unsafe { - Self::recursive_convert(&mut build_menu, &Some(menu)); - let menu_len = build_menu.len(); - mfb_update_menu(self.window_handle, - CString::new(name).unwrap().as_ptr(), - build_menu[menu_len - 1].as_mut_ptr() as *mut c_void); + pub fn remove_menu(&mut self, handle: MenuHandle) { + for i in 0..self.menus.len() { + if self.menus[i] == handle { + self.menus.remove(i); + unsafe { + // + 1 here as we always have a default menu we shouldn't remove + mfb_remove_menu_at(self.window_handle, (i + 1) as i32); + } + return; + } } - - Ok(()) - } - - pub fn remove_menu(&mut self, name: &str) -> Result<()> { - unsafe { - mfb_remove_menu(self.window_handle, CString::new(name).unwrap().as_ptr()); - } - - Ok(()) } #[inline] @@ -450,8 +457,21 @@ impl Window { return factor; } +} - unsafe fn map_key_to_menu_key(key: Key) -> i32 { +pub struct Menu { + menu_handle: *mut c_void, +} + +impl Menu { + pub fn new(name: &str) -> Result { + unsafe { + let menu_name = CString::new(name).unwrap(); + Ok(Menu { menu_handle: mfb_create_menu(menu_name.as_ptr()) }) + } + } + + unsafe fn map_key_to_menu_key(key: Key) -> u32 { match key { Key::A => 0x00, Key::S => 0x01, @@ -500,10 +520,10 @@ impl Window { Key::N => 0x2d, Key::M => 0x2e, Key::Period => 0x2f, - //Key::Tab => 0x30, + // Key::Tab => 0x30, Key::Space => 0x31, - //Key::Backspace => 0x33, - //Key::Escape => 0x35, + // Key::Backspace => 0x33, + // Key::Escape => 0x35, Key::RightSuper => 0x36, Key::LeftSuper => 0x37, Key::LeftShift => 0x38, @@ -513,7 +533,7 @@ impl Window { Key::RightShift => 0x3c, Key::RightAlt => 0x3d, Key::RightCtrl => 0x3e, - //Key::Equal => 0x51, + // Key::Equal => 0x51, Key::NumPad0 => 0x52, Key::NumPad1 => 0x53, Key::NumPad2 => 0x54, @@ -537,23 +557,23 @@ impl Window { Key::F15 => 0x71, Key::Insert => 0x72, /* Really Help... */ Key::Home => 0x73, - //Key::PageUp => 0x74, + // Key::PageUp => 0x74, Key::Delete => 0x75, Key::F4 => 0x76, Key::End => 0x77, Key::F2 => 0x78, - //Key::PageDown => 0x79, + // Key::PageDown => 0x79, Key::F1 => 0x7a, - //Key::Left => 0x7b, - //Key::Right => 0x7c, - //Key::Down => 0x7d, - //Key::Up => 0x7e, + // Key::Left => 0x7b, + // Key::Right => 0x7c, + // Key::Down => 0x7d, + // Key::Up => 0x7e, Key::Left => 0x2190, Key::Up => 0x2191, Key::Down => 0x2193, Key::Right => 0x2192, Key::Escape => 0x238b, - //Key::Enter => 0x000d, + // Key::Enter => 0x000d, Key::Backspace => 0x232b, Key::Tab => 0x21e4, Key::PageUp => 0x21de, @@ -562,55 +582,31 @@ impl Window { } } - unsafe fn recursive_convert(menu_build_vec: &mut Vec>, in_menu: &Option<&Vec>) -> *mut raw::c_void { - if in_menu.is_none() { - return ptr::null_mut(); + pub fn add_sub_menu(&mut self, name: &str, sub_menu: &Menu) { + unsafe { + let menu_name = CString::new(name).unwrap(); + mfb_add_sub_menu(self.menu_handle, menu_name.as_ptr(), sub_menu.menu_handle) } + } - let mut menu_build = Vec::::new(); - let menu_vec = in_menu.as_ref().unwrap(); + pub fn add_menu_item(&mut self, item: &MenuItem) -> MenuItemHandle { + unsafe { + let item_name = CString::new(item.label.as_str()).unwrap(); + let conv_key = Self::map_key_to_menu_key(item.key); - for m in menu_vec.iter() { - let key_map = Self::map_key_to_menu_key(m.key); - - let mut menu = CMenu { - name: mem::uninitialized(), - id: m.id as raw::c_int, - key: key_map as raw::c_int, - special_key: 0, - modifier: m.modifier as raw::c_int, - mac_mod: m.mac_mod as raw::c_int, - enabled: m.enabled as raw::c_int, - sub_menu : Self::recursive_convert(menu_build_vec, &m.sub_menu), - }; - - let name = CString::new(m.name).unwrap(); - let name_len = m.name.len(); - - ptr::copy_nonoverlapping(name.as_ptr(), - menu.name.as_mut_ptr() as *mut i8, - name_len); - menu.name[name_len] = 0; - - menu_build.push(menu); + MenuItemHandle(mfb_add_menu_item(self.menu_handle, + item.id as i32, + item_name.as_ptr(), + item.enabled, + conv_key, + item.modifier)) } + } - // end marker - - menu_build.push(CMenu { - name: [0; STRING_SIZE], - id: -2, - key: 0, - special_key: 0, - modifier: 0, - mac_mod: 0, - enabled: 0, - sub_menu : ptr::null_mut(), - }); - - let ptr = menu_build.as_mut_ptr() as *mut raw::c_void ; - menu_build_vec.push(menu_build); - ptr + pub fn remove_item(&mut self, handle: &MenuItemHandle) { + unsafe { + mfb_remove_menu_item(self.menu_handle, handle.0); + } } } diff --git a/src/os/windows/mod.rs b/src/os/windows/mod.rs index 397eac7..ff75965 100644 --- a/src/os/windows/mod.rs +++ b/src/os/windows/mod.rs @@ -10,10 +10,10 @@ const INVALID_ACCEL: usize = 0xffffffff; use {Scale, Key, KeyRepeat, MouseButton, MouseMode, WindowOptions, InputCallback}; use key_handler::KeyHandler; -use menu::Menu; use error::Error; use Result; -use menu::{MENU_KEY_WIN, MENU_KEY_SHIFT, MENU_KEY_CTRL, MENU_KEY_ALT}; +use {MenuItem, MenuItemHandle, MenuHandle}; +use {MENU_KEY_WIN, MENU_KEY_SHIFT, MENU_KEY_CTRL, MENU_KEY_ALT}; use std::ptr; use std::os::windows::ffi::OsStrExt; @@ -298,8 +298,7 @@ pub enum MinifbError { } fn to_wstring(str: &str) -> Vec { - let mut v: Vec = OsStr::new(str).encode_wide().chain(Some(0).into_iter()).collect(); - v.push(0u16); + let v: Vec = OsStr::new(str).encode_wide().chain(Some(0).into_iter()).collect(); v } @@ -311,11 +310,13 @@ struct MouseData { pub scroll: f32, } +/* struct MenuStore { name: String, menu: HMENU, accel_items: Vec, } +*/ pub struct Window { mouse: MouseData, @@ -326,7 +327,7 @@ pub struct Window { scale_factor: i32, width: i32, height: i32, - menus: Vec, + menus: Vec, key_handler: KeyHandler, accel_table: HACCEL, accel_key: usize, @@ -338,6 +339,7 @@ pub struct Window { #[allow(non_snake_case)] extern "system" { fn TranslateAcceleratorW(hWnd: HWND, accel: *const ACCEL, pmsg: *const MSG) -> INT; + fn RemoveMenu(menu: HMENU, pos: UINT, flags: UINT) -> BOOL; } impl Window { @@ -635,6 +637,120 @@ impl Window { return factor; } + // + // When attaching a menu to the window we need to resize it so + // the current client size is preserved and still show all pixels + // + unsafe fn adjust_window_size_for_menu(handle: HWND) { + let mut rect: winapi::RECT = mem::uninitialized(); + + let menu_height = user32::GetSystemMetrics(winapi::winuser::SM_CYMENU); + + user32::GetWindowRect(handle, &mut rect); + user32::MoveWindow(handle, + rect.left, + rect.top, + rect.right - rect.left, + (rect.bottom - rect.top) + menu_height, + 1); + } + + unsafe fn set_accel_table(&mut self) { + let mut temp_accel_table = Vec::::new(); + + for menu in self.menus.iter() { + for item in menu.accel_table.iter() { + println!("virt {} - cmd {} - key {}", item.fVirt, item.cmd, item.key); + temp_accel_table.push(item.clone()); + } + } + + if self.accel_table != ptr::null_mut() { + user32::DestroyAcceleratorTable(self.accel_table); + } + + self.accel_table = user32::CreateAcceleratorTableW(temp_accel_table.as_mut_ptr(), + temp_accel_table.len() as i32); + + println!("accel {:?}", self.accel_table); + } + + + pub fn add_menu(&mut self, menu: &Menu) -> MenuHandle { + unsafe { + let window = self.window.unwrap(); + let mut main_menu = user32::GetMenu(window); + + if main_menu == ptr::null_mut() { + main_menu = user32::CreateMenu(); + user32::SetMenu(window, main_menu); + Self::adjust_window_size_for_menu(window); + } + + user32::AppendMenuW(main_menu, + 0x10, + menu.menu_handle as UINT_PTR, + menu.name.as_ptr()); + + self.menus.push(menu.clone()); + // TODO: Setup accel table + + //Self::add_menu_store(self, main_menu, menu_name, menu); + self.set_accel_table(); + + user32::DrawMenuBar(window); + } + + // TODO: Proper handle + + MenuHandle(menu.menu_handle as u64) + } + + pub fn remove_menu(&mut self, handle: MenuHandle) { + let window = self.window.unwrap(); + let main_menu = unsafe { user32::GetMenu(window) }; + for i in 0..self.menus.len() { + if self.menus[i].menu_handle == handle.0 as HMENU { + unsafe { + println!("Removed menu at {}", i); + let _t = RemoveMenu(main_menu, i as UINT, 0); + user32::DrawMenuBar(self.window.unwrap()); + } + self.menus.swap_remove(i); + return; + } + } + } + + pub fn is_menu_pressed(&mut self) -> Option { + if self.accel_key == INVALID_ACCEL { + None + } else { + let t = self.accel_key; + self.accel_key = INVALID_ACCEL; + Some(t) + } + } +} + +#[derive(Clone)] +pub struct Menu { + menu_handle: HMENU, + name: Vec, + accel_table: Vec, +} + +impl Menu { + pub fn new(name: &str) -> Result { + unsafe { + Ok(Menu { + menu_handle: user32::CreatePopupMenu(), + name: to_wstring(name), + accel_table: Vec::new(), + }) + } + } + fn map_key_to_vk_accel(key: Key) -> (raw::c_int, &'static str) { match key { Key::Key0 => (0x30, "0"), @@ -748,27 +864,20 @@ impl Window { } } - - // - // When attaching a menu to the window we need to resize it so - // the current client size is preserved and still show all pixels - // - unsafe fn adjust_window_size_for_menu(handle: HWND) { - let mut rect: winapi::RECT = mem::uninitialized(); - - let menu_height = user32::GetSystemMetrics(winapi::winuser::SM_CYMENU); - - user32::GetWindowRect(handle, &mut rect); - user32::MoveWindow(handle, - rect.left, - rect.top, - rect.right - rect.left, - (rect.bottom - rect.top) + menu_height, - 1); + pub fn add_sub_menu(&mut self, name: &str, menu: &Menu) { + unsafe { + let menu_name = to_wstring(name); + user32::AppendMenuW(self.menu_handle, + 0x10, + menu.menu_handle as UINT_PTR, + menu_name.as_ptr()); + self.accel_table.extend_from_slice(menu.accel_table.as_slice()); + } } - fn format_name(menu_item: &Menu, key_name: &'static str) -> String { - let mut name = menu_item.name.to_owned(); + + fn format_name(menu_item: &MenuItem, key_name: &'static str) -> String { + let mut name = menu_item.label.clone(); name.push_str("\t"); @@ -793,16 +902,20 @@ impl Window { name } - fn is_key_virtual_range(key: raw::c_int) -> u32 { + fn is_key_virtual_range(_key: raw::c_int) -> u32 { + /* if (key >= 0x30 && key <= 0x30) || (key >= 0x41 && key <= 0x5a) { - 1 - } else { 0 + } else { + 1 } + */ + + 1 } - fn get_virt_key(menu_item: &Menu, key: raw::c_int) -> u32 { + fn get_virt_key(menu_item: &MenuItem, key: raw::c_int) -> u32 { let mut virt = Self::is_key_virtual_range(key); if (menu_item.modifier & MENU_KEY_ALT) == MENU_KEY_ALT { @@ -820,165 +933,48 @@ impl Window { virt } - fn add_accel(accel_table: &mut Vec, menu_item: &Menu) { + fn add_accel(&mut self, vk: raw::c_int, menu_item: &MenuItem) { let vk_accel = Self::map_key_to_vk_accel(menu_item.key); - let virt = Self::get_virt_key(menu_item, vk_accel.0); + let virt = Self::get_virt_key(menu_item, vk); let accel = winuser::ACCEL { fVirt: virt as BYTE, cmd: menu_item.id as WORD, key: vk_accel.0 as WORD }; - accel_table.push(accel); + self.accel_table.push(accel); } - unsafe fn add_menu_item(&mut self, parent_menu: HMENU, menu_item: &Menu) { - let item_name = to_wstring(menu_item.name); + pub fn add_menu_item(&mut self, menu_item: &MenuItem) -> MenuItemHandle { let vk_accel = Self::map_key_to_vk_accel(menu_item.key); - match vk_accel.0 { - 0 => { - user32::AppendMenuW(parent_menu, 0x10, menu_item.id as UINT_PTR, item_name.as_ptr()); - }, - _ => { - let menu_name = Self::format_name(menu_item, vk_accel.1); - let w_name = to_wstring(&menu_name); - user32::AppendMenuW(parent_menu, 0x10, menu_item.id as UINT_PTR, w_name.as_ptr()); - } - } - } - - unsafe fn set_accel_table(&mut self) { - let mut temp_accel_table = Vec::::new(); - - for menu in self.menus.iter() { - for item in menu.accel_items.iter() { - println!("virt {} - cmd {} - key {}", item.fVirt, item.cmd, item.key); - temp_accel_table.push(item.clone()); - } - } - - if self.accel_table != ptr::null_mut() { - user32::DestroyAcceleratorTable(self.accel_table); - } - - self.accel_table = user32::CreateAcceleratorTableW(temp_accel_table.as_mut_ptr(), - temp_accel_table.len() as i32); - } - - - unsafe fn recursive_add_menu(&mut self, parent_menu: HMENU, name: &str, menu: &Vec) -> HMENU { - let menu_name = to_wstring(name); - - let popup_menu = user32::CreatePopupMenu(); - - user32::AppendMenuW(parent_menu, 0x10, popup_menu as UINT_PTR, menu_name.as_ptr()); - - for m in menu.iter() { - if let Some(ref sub_menu) = m.sub_menu { - Self::recursive_add_menu(self, popup_menu, m.name, sub_menu); - } else { - if m.id == 0xffffffff { - user32::AppendMenuW(popup_menu, 0x800, 0, ptr::null()); // separator - } else { - Self::add_menu_item(self, popup_menu, m); - } - } - } - - popup_menu - } - - pub fn menu_exists(&mut self, menu_name: &str) -> bool { - for menu in self.menus.iter() { - if menu.name == menu_name { - return true; - } - } - - false - } - - fn clone_menu(accel_dest: &mut Vec, menu: &Vec) { - for m in menu.iter() { - if let Some(ref sub_menu) = m.sub_menu { - Self::clone_menu(accel_dest, sub_menu); - } - - if m.key != Key::Unknown { - Self::add_accel(accel_dest, m); - } - } - } - - unsafe fn add_menu_store(&mut self, parent_menu: HMENU, menu_name: &str, menu: &Vec) { - let mut items = Vec::::new(); - let menu_handle = Self::recursive_add_menu(self, parent_menu, menu_name, menu); - - Self::clone_menu(&mut items, menu); - - self.menus.push(MenuStore { - name: menu_name.to_owned(), - menu: menu_handle, - accel_items: items - }); - } - - pub fn add_menu(&mut self, menu_name: &str, menu: &Vec) -> Result<()> { - if Self::menu_exists(self, menu_name) { - return Err(Error::MenuExists(menu_name.to_owned())); - } - unsafe { - let window = self.window.unwrap(); - let mut main_menu = user32::GetMenu(window); - - if main_menu == ptr::null_mut() { - main_menu = user32::CreateMenu(); - user32::SetMenu(window, main_menu); - Self::adjust_window_size_for_menu(window); - } - - Self::add_menu_store(self, main_menu, menu_name, menu); - Self::set_accel_table(self); - - user32::DrawMenuBar(window); - } - - Ok(()) - } - - pub fn update_menu(&mut self, menu_name: &str, menu: &Vec) -> Result<()> { - try!(Self::remove_menu(self, menu_name)); - Self::add_menu(self, menu_name, menu) - } - - pub fn remove_menu(&mut self, menu_name: &str) -> Result<()> { - for i in 0..self.menus.len() { - if self.menus[i].name == menu_name { - unsafe { - user32::DestroyMenu(self.menus[i].menu); - user32::DrawMenuBar(self.window.unwrap()); - self.menus.swap_remove(i); - break; + match vk_accel.0 { + 0 => { + let item_name = to_wstring(&menu_item.label); + user32::AppendMenuW(self.menu_handle, 0x10, menu_item.id as UINT_PTR, item_name.as_ptr()); + }, + _ => { + let menu_name = Self::format_name(menu_item, vk_accel.1); + let w_name = to_wstring(&menu_name); + user32::AppendMenuW(self.menu_handle, 0x10, menu_item.id as UINT_PTR, w_name.as_ptr()); + self.add_accel(vk_accel.0, menu_item); } } } - // TODO: Proper return here - Ok(()) + // TODO: This is not correct and needs to be fixed if remove_item is added. The + // issue here is that AppendMenuW doesn't return a handle so it's hard to track + // in an easy way :( + + MenuItemHandle(0) } - pub fn is_menu_pressed(&mut self) -> Option { - if self.accel_key == INVALID_ACCEL { - None - } else { - let t = self.accel_key; - self.accel_key = INVALID_ACCEL; - Some(t) - } + pub fn remove_item(&mut self, _item: &MenuItemHandle) { + panic!("remove item hasn't been implemented"); } } + impl Drop for Window { fn drop(&mut self) { unsafe {