From 4a3eabe8e66bf85a79a2c86631816471ac199e3d Mon Sep 17 00:00:00 2001 From: Daniel Collin Date: Sat, 7 May 2016 12:51:14 +0200 Subject: [PATCH 01/18] WIP on new Menu system --- examples/menu.rs | 22 ++++-- src/lib.rs | 104 ++++++++++++++++++++++++--- src/menu.rs | 78 ++++++++++---------- src/native/macosx/MacMiniFB.m | 43 +++++++++++ src/native/macosx/OSXWindow.m | 104 +++++++++++++++++---------- src/os/macos/mod.rs | 131 +++++++++++++++++++++++++++++++--- 6 files changed, 380 insertions(+), 102 deletions(-) diff --git a/examples/menu.rs b/examples/menu.rs index ceaf4cc..8481637 100644 --- a/examples/menu.rs +++ b/examples/menu.rs @@ -1,17 +1,19 @@ extern crate minifb; -use minifb::{Window, Key, Scale, WindowOptions, Menu}; -use minifb::{MENU_KEY_CTRL, MENU_KEY_COMMAND}; +use minifb::{Window, Key, Scale, WindowOptions, Menu, MenuItem}; +//use minifb::{MENU_KEY_CTRL, MENU_KEY_COMMAND}; const WIDTH: usize = 640; const HEIGHT: usize = 360; +/* const MENU_TEST_ID: usize = 1; const OTHER_MENU_ID: usize = 2; const COLOR_0_ID: usize = 3; const COLOR_1_ID: usize = 4; const COLOR_2_ID: usize = 5; const CLOSE_MENU_ID: usize = 6; +*/ fn main() { let mut buffer: Vec = vec![0; WIDTH * HEIGHT]; @@ -28,6 +30,7 @@ fn main() { // Setup a sub menu + /* let sub_menu = vec![ Menu { name: "Color 0", @@ -81,10 +84,17 @@ fn main() { ..Menu::default() } ]; + */ - window.add_menu("Test", &menu).expect("Unable to add menu"); + //window.add_menu("Test", &menu).expect("Unable to add menu"); - let mut color_mul = 1; + let mut menu = Menu::new("TestMenu").unwrap(); + let mut item = MenuItem::new("Item", 1).enabled(true); + + menu.add_item(&mut item); + let _ = window.add_menu(&menu); + + let color_mul = 1; while window.is_open() && !window.is_key_down(Key::Escape) { for y in 0..HEIGHT { @@ -93,6 +103,7 @@ fn main() { } } + /* window.is_menu_pressed().map(|menu_id| { match menu_id { COLOR_0_ID => { @@ -106,13 +117,14 @@ fn main() { } CLOSE_MENU_ID => { println!("remove menu"); - window.remove_menu("Test").expect("Unable to remove menu"); + //window.remove_menu("Test").expect("Unable to remove menu"); } _ => (), } println!("Menu id {} pressed", menu_id); }); + */ window.get_keys().map(|keys| { for t in keys { diff --git a/src/lib.rs b/src/lib.rs index 7b92226..0cc8d87 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,10 +462,12 @@ 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) -> Result<()> { + self.0.add_menu(&menu.0) } + /* /// /// Updates an existing menu created with [add_menu] @@ -482,6 +484,7 @@ impl Window { pub fn remove_menu(&mut self, menu_name: &str) -> Result<()> { self.0.remove_menu(menu_name) } + */ /// /// Check if a menu item has been pressed @@ -492,6 +495,89 @@ 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); + +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, _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) + } +} + +pub struct MenuItem { + pub id: usize, + pub label: String, + pub enabled: bool, + pub key: Key, + pub modifier: u32, +} + +impl MenuItem { + pub fn new(name: &str, id: usize) -> MenuItem { + MenuItem { + id: id, + label: name.to_owned(), + enabled: true, + key: Key::Unknown, + modifier: 0, + } + } + #[inline] + pub fn shortcut(self, key: Key, modifier: u32) -> 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 + } + } +} + // 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..db192c3 100644 --- a/src/native/macosx/MacMiniFB.m +++ b/src/native/macosx/MacMiniFB.m @@ -383,6 +383,7 @@ int mfb_active_menu(void* window) { /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/* void mfb_add_menu(void* window, const char* name, void* m) { OSXWindow* win = (OSXWindow*)window; @@ -410,9 +411,25 @@ void mfb_add_menu(void* window, const char* name, void* m) menu->menu = windowMenu; menu->menu_item = windowMenuItem; } +*/ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void 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]; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/* void mfb_update_menu(void* window, const char* name, void* m) { OSXWindow* win = (OSXWindow*)window; @@ -433,4 +450,30 @@ void mfb_update_menu(void* window, const char* name, void* m) } } } +*/ + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +void* mfb_create_menu(const char* name) { + const char* n = strdup(name); // WHY? + + NSString* ns_name = [NSString stringWithUTF8String: n]; + + //NSMenuItem* menu_item = [[NSMenuItem alloc] initWithTitle:name action:NULL keyEquivalent:@""]; + NSMenu* menu = [[NSMenu alloc] initWithTitle:ns_name]; + //[menu_item setSubmenu:menu]; + + 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]; +} + + diff --git a/src/native/macosx/OSXWindow.m b/src/native/macosx/OSXWindow.m index 7cc1e02..2a3eec1 100644 --- a/src/native/macosx/OSXWindow.m +++ b/src/native/macosx/OSXWindow.m @@ -71,14 +71,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]; } @@ -274,14 +266,6 @@ 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]; @@ -309,8 +293,6 @@ void build_submenu(NSMenu* menu, MenuDesc* desc) else { int mask = 0; - NSString* key = 0; - NSMenuItem* newItem = [[NSMenuItem alloc] initWithTitle:name action:@selector(onMenuPress:) keyEquivalent:@""]; [newItem setTag:desc->menu_id]; @@ -327,28 +309,13 @@ void build_submenu(NSMenu* menu, MenuDesc* desc) 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 (desc->key != 0x7f) { + NSString* key = convert_key_code_to_string(desc->key); - if (key) { - [newItem setKeyEquivalentModifierMask: mask]; - [newItem setKeyEquivalent:key]; + if (key) { + [newItem setKeyEquivalentModifierMask: mask]; + [newItem setKeyEquivalent:key]; + } } if (desc->enabled) { @@ -366,4 +333,63 @@ void build_submenu(NSMenu* menu, MenuDesc* desc) } } +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +void 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 + { + int mask = 0; + NSMenuItem* newItem = [[NSMenuItem alloc] initWithTitle:name action:@selector(onMenuPress:) keyEquivalent:@""]; + [newItem setTag:menu_id]; + + if ((modfier & MENU_KEY_COMMAND) || + (modfier & MENU_KEY_COMMAND)) { + mask |= NSCommandKeyMask; + } + if (modfier & MENU_KEY_SHIFT) { + mask |= NSShiftKeyMask; + } + if (modfier & MENU_KEY_ALT) { + mask |= NSAlternateKeyMask; + } + + if (key != 0x7f) { + NSString* key = convert_key_code_to_string(key); + + if (key) { + [newItem setKeyEquivalentModifierMask: mask]; + [newItem setKeyEquivalent:key]; + } + } + + if (enabled) { + [newItem setEnabled:YES]; + } else { + [newItem setEnabled:NO]; + } + + [newItem setOnStateImage: newItem.offStateImage]; + [menu addItem:newItem]; + [newItem release]; + } +} + @end + + + diff --git a/src/os/macos/mod.rs b/src/os/macos/mod.rs index bfd43d9..cbb83cb 100644 --- a/src/os/macos/mod.rs +++ b/src/os/macos/mod.rs @@ -4,10 +4,12 @@ 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; +//use menu::Menu; use libc::{c_void, c_char, c_uchar}; use std::ffi::{CString}; @@ -149,8 +151,7 @@ static KEY_MAPPINGS: [Key; 128] = [ ]; -const STRING_SIZE: usize = 512; - +/* #[repr(C)] struct CMenu { name: [i8; STRING_SIZE], @@ -162,6 +163,7 @@ struct CMenu { mac_mod: raw::c_int, enabled: raw::c_int, } +*/ #[link(name = "Cocoa", kind = "framework")] #[link(name = "Carbon", kind = "framework")] @@ -178,10 +180,19 @@ extern { 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_active_menu(window: *mut c_void) -> i32; + fn mfb_add_menu(window: *mut c_void, 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_active_menu(window: *mut c_void) -> i32; + + fn mfb_create_menu(name: *const c_char) -> *mut c_void; + fn mfb_destroy_menu(menu_item: *mut c_void); + + fn mfb_add_menu_item(menu_item: *mut c_void, + menu_id: i32, + name: *const c_char, + key: u32, + modifier: u32) -> *mut c_void; } #[derive(Default)] @@ -363,7 +374,7 @@ impl Window { } pub fn is_menu_pressed(&mut self) -> Option { - let menu_id = unsafe { mfb_active_menu(self.window_handle) }; + let menu_id = 0; //unsafe { mfb_active_menu(self.window_handle) }; if menu_id < 0 { None @@ -372,6 +383,16 @@ impl Window { } } + pub fn add_menu(&mut self, menu: &Menu) -> Result<()> { + unsafe { + mfb_add_menu(self.window_handle, menu.menu_handle); + } + + Ok(()) + } + + /* + pub fn add_menu(&mut self, name: &str, menu: &Vec) -> Result<()> { let mut build_menu = Vec::>::new(); @@ -407,6 +428,7 @@ impl Window { Ok(()) } + */ #[inline] pub fn is_open(&self) -> bool { @@ -451,6 +473,7 @@ impl Window { return factor; } + /* unsafe fn map_key_to_menu_key(key: Key) -> i32 { match key { Key::A => 0x00, @@ -561,7 +584,9 @@ impl Window { _ => 0x7f, } } + */ + /* 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(); @@ -612,8 +637,88 @@ impl Window { menu_build_vec.push(menu_build); ptr } + */ } +pub struct Menu { + menu_handle: *mut c_void, +} + +impl Menu { + pub fn new(name: &str) -> Result { + unsafe { + let menu_name = CString::new(name).unwrap().as_ptr(); + Ok(Menu { menu_handle: mfb_create_menu(menu_name) }) + } + } + + pub fn add_item(&mut self, item: &mut MenuItem) { + unsafe { + let item_name = CString::new(item.label.as_str()).unwrap().as_ptr(); + + mfb_add_menu_item(self.menu_handle, item.id as i32, item_name, + item.key as u32, item.modifier); + } + } + + /* + #[inline] + pub fn remove_item(&mut self, item: &mut MenuItem) { + self.0.remove_item(item) + } + */ +} + +/* +pub struct MenuItem { + id: usize, + label: String, + separator: bool, + key: Key, + modifier: u32, + impl_handle: u64, +} + +impl MenuItem { + pub fn new(name: &str, id: usize) -> MenuItem { + MenuItem { + id: id, + label: "".to_owned(), + enabled: true, + separator: false, + key: Key::Unknown, + modifier: 0, + impl_handle: 0, + } + } + #[inline] + pub fn shortcut(self, key: Key, modifier: u32) -> Self { + MenuItem { + shortcut: key, + modifier: modifier, + .. self + } + } + #[inline] + pub fn separator(self, enabled: bool) -> Self { + MenuItem { + id: 0xffffffff, + .. self + } + } + #[inline] + pub fn enabled(self, enabled: bool) -> Self { + MenuItem { + enabled: enabled, + .. self + } + } +} +*/ + + + + impl Drop for Window { fn drop(&mut self) { unsafe { @@ -622,3 +727,13 @@ impl Drop for Window { } } +impl Drop for Menu { + fn drop(&mut self) { + unsafe { + mfb_destroy_menu(self.menu_handle); + } + } +} + + + From 42ce3b928647d55804af0f179412c027316f7bb2 Mon Sep 17 00:00:00 2001 From: Daniel Collin Date: Sun, 8 May 2016 00:25:31 +0200 Subject: [PATCH 02/18] WIP on new menu stuff --- examples/menu.rs | 6 +- src/key.rs | 2 +- src/lib.rs | 10 +- src/native/macosx/MacMiniFB.m | 13 ++ src/native/macosx/OSXWindow.m | 13 +- src/os/macos/mod.rs | 253 ++++++++++++---------------------- 6 files changed, 120 insertions(+), 177 deletions(-) diff --git a/examples/menu.rs b/examples/menu.rs index 8481637..56bcb09 100644 --- a/examples/menu.rs +++ b/examples/menu.rs @@ -89,9 +89,11 @@ fn main() { //window.add_menu("Test", &menu).expect("Unable to add menu"); let mut menu = Menu::new("TestMenu").unwrap(); - let mut item = MenuItem::new("Item", 1).enabled(true); - menu.add_item(&mut item); + menu.add_item(&MenuItem::new("Item 1", 1)); + menu.add_item(&MenuItem::new("Item 2", 2)); + menu.add_item(&MenuItem::new("Item 3", 3)); + let _ = window.add_menu(&menu); let color_mul = 1; 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 0cc8d87..00f9d34 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -495,6 +495,7 @@ impl Window { } } + /// Command key on Mac OS pub const MENU_KEY_COMMAND: usize = 1; /// Windows key on Windows @@ -510,6 +511,9 @@ const MENU_ID_SEPARATOR:usize = 0xffffffff; pub struct Menu(imp::Menu); +#[derive(Debug)] +pub struct MenuItemHandle(pub u64); + impl Menu { pub fn new(name: &str) -> Result { imp::Menu::new(name).map(Menu) @@ -526,13 +530,13 @@ impl Menu { } #[inline] - pub fn add_item(&mut self, item: &mut MenuItem) { + pub fn add_item(&mut self, item: &MenuItem) -> MenuItemHandle { self.0.add_item(item) } #[inline] - pub fn remove_item(&mut self, _item: &mut MenuItem) { - //self.0.remove_item(item) + pub fn remove_item(&mut self, item: &MenuItemHandle) { + self.0.remove_item(item) } } diff --git a/src/native/macosx/MacMiniFB.m b/src/native/macosx/MacMiniFB.m index db192c3..e5d97be 100644 --- a/src/native/macosx/MacMiniFB.m +++ b/src/native/macosx/MacMiniFB.m @@ -462,6 +462,8 @@ void* mfb_create_menu(const char* name) { //NSMenuItem* menu_item = [[NSMenuItem alloc] initWithTitle:name action:NULL keyEquivalent:@""]; NSMenu* menu = [[NSMenu alloc] initWithTitle:ns_name]; //[menu_item setSubmenu:menu]; + + //printf("created menu %p\n"); return (void*)menu; } @@ -475,5 +477,16 @@ void mfb_destroy_menu(void* menu_item, const char* name) [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; + + printf("remove item menu %p item %p\n", menu, item); + [menu removeItem:item]; +} + + diff --git a/src/native/macosx/OSXWindow.m b/src/native/macosx/OSXWindow.m index 2a3eec1..625c585 100644 --- a/src/native/macosx/OSXWindow.m +++ b/src/native/macosx/OSXWindow.m @@ -265,7 +265,7 @@ const uint32_t MENU_KEY_CTRL = 8; const uint32_t MENU_KEY_ALT = 16; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - +/* void build_submenu(NSMenu* menu, MenuDesc* desc) { [menu removeAllItems]; @@ -332,10 +332,11 @@ void build_submenu(NSMenu* menu, MenuDesc* desc) desc++; } } +*/ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void mfb_add_menu_item( +uint64_t mfb_add_menu_item( void* in_menu, int32_t menu_id, const char* item_name, @@ -345,7 +346,9 @@ void mfb_add_menu_item( { NSMenu* menu = (NSMenu*)in_menu; - NSString* name = [NSString stringWithUTF8String: item_name]; + const char* t = strdup(item_name); + + NSString* name = [NSString stringWithUTF8String: t]; if (menu_id == -1) { @@ -386,7 +389,11 @@ void mfb_add_menu_item( [newItem setOnStateImage: newItem.offStateImage]; [menu addItem:newItem]; [newItem release]; + + return (uint64_t)newItem; } + + return 0; } @end diff --git a/src/os/macos/mod.rs b/src/os/macos/mod.rs index cbb83cb..93c7dbb 100644 --- a/src/os/macos/mod.rs +++ b/src/os/macos/mod.rs @@ -8,7 +8,7 @@ use Result; use InputCallback; use mouse_handler; use window_flags; -use MenuItem; +use {MenuItem, MenuItemHandle}; //use menu::Menu; use libc::{c_void, c_char, c_uchar}; @@ -186,13 +186,14 @@ extern { //fn mfb_active_menu(window: *mut c_void) -> i32; fn mfb_create_menu(name: *const c_char) -> *mut c_void; - fn mfb_destroy_menu(menu_item: *mut c_void); + //fn mfb_destroy_menu(menu_item: *mut c_void); fn mfb_add_menu_item(menu_item: *mut c_void, menu_id: i32, name: *const c_char, key: u32, - modifier: u32) -> *mut c_void; + modifier: u32) -> u64; + fn mfb_remove_menu_item(menu: *mut c_void, item_handle: u64); } #[derive(Default)] @@ -391,45 +392,6 @@ impl Window { Ok(()) } - /* - - pub fn add_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_add_menu(self.window_handle, - CString::new(name).unwrap().as_ptr(), - build_menu[menu_len - 1].as_mut_ptr() as *mut c_void); - } - - 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); - } - - 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] pub fn is_open(&self) -> bool { unsafe { mfb_should_close(self.window_handle) == 0 } @@ -474,7 +436,75 @@ impl Window { } /* - unsafe fn map_key_to_menu_key(key: Key) -> i32 { + */ + + /* + 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(); + } + + let mut menu_build = Vec::::new(); + let menu_vec = in_menu.as_ref().unwrap(); + + 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); + } + + // 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 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, @@ -584,140 +614,25 @@ impl Window { _ => 0x7f, } } - */ - /* - 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(); - } - - let mut menu_build = Vec::::new(); - let menu_vec = in_menu.as_ref().unwrap(); - - 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); - } - - // 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 struct Menu { - menu_handle: *mut c_void, -} - -impl Menu { - pub fn new(name: &str) -> Result { + pub fn add_item(&mut self, item: &MenuItem) -> MenuItemHandle { unsafe { - let menu_name = CString::new(name).unwrap().as_ptr(); - Ok(Menu { menu_handle: mfb_create_menu(menu_name) }) + let item_name = CString::new(item.label.as_str()).unwrap(); + let conv_key = Self::map_key_to_menu_key(item.key); + + println!("key {:?} conv {}", item.key, conv_key); + + MenuItemHandle(mfb_add_menu_item(self.menu_handle, item.id as i32, item_name.as_ptr(), + Self::map_key_to_menu_key(item.key), item.modifier)) } } - pub fn add_item(&mut self, item: &mut MenuItem) { + pub fn remove_item(&mut self, handle: &MenuItemHandle) { unsafe { - let item_name = CString::new(item.label.as_str()).unwrap().as_ptr(); - - mfb_add_menu_item(self.menu_handle, item.id as i32, item_name, - item.key as u32, item.modifier); - } - } - - /* - #[inline] - pub fn remove_item(&mut self, item: &mut MenuItem) { - self.0.remove_item(item) - } - */ -} - -/* -pub struct MenuItem { - id: usize, - label: String, - separator: bool, - key: Key, - modifier: u32, - impl_handle: u64, -} - -impl MenuItem { - pub fn new(name: &str, id: usize) -> MenuItem { - MenuItem { - id: id, - label: "".to_owned(), - enabled: true, - separator: false, - key: Key::Unknown, - modifier: 0, - impl_handle: 0, - } - } - #[inline] - pub fn shortcut(self, key: Key, modifier: u32) -> Self { - MenuItem { - shortcut: key, - modifier: modifier, - .. self - } - } - #[inline] - pub fn separator(self, enabled: bool) -> Self { - MenuItem { - id: 0xffffffff, - .. self - } - } - #[inline] - pub fn enabled(self, enabled: bool) -> Self { - MenuItem { - enabled: enabled, - .. self + mfb_remove_menu_item(self.menu_handle, handle.0); } } } -*/ - - - impl Drop for Window { fn drop(&mut self) { @@ -727,6 +642,7 @@ impl Drop for Window { } } +/* impl Drop for Menu { fn drop(&mut self) { unsafe { @@ -734,6 +650,7 @@ impl Drop for Menu { } } } +*/ From 25ed203497ed753e8b03131dddd3b575bd6fb4ce Mon Sep 17 00:00:00 2001 From: Daniel Collin Date: Sun, 8 May 2016 08:55:22 +0200 Subject: [PATCH 03/18] Fixed shortcuts on Mac --- examples/menu.rs | 2 +- src/native/macosx/OSXWindow.m | 6 +++--- src/os/macos/mod.rs | 5 ++++- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/examples/menu.rs b/examples/menu.rs index 56bcb09..2a0487b 100644 --- a/examples/menu.rs +++ b/examples/menu.rs @@ -90,7 +90,7 @@ fn main() { let mut menu = Menu::new("TestMenu").unwrap(); - menu.add_item(&MenuItem::new("Item 1", 1)); + menu.add_item(&MenuItem::new("Item 1", 1).shortcut(Key::S, 0)); menu.add_item(&MenuItem::new("Item 2", 2)); menu.add_item(&MenuItem::new("Item 3", 3)); diff --git a/src/native/macosx/OSXWindow.m b/src/native/macosx/OSXWindow.m index 625c585..cdc1b5f 100644 --- a/src/native/macosx/OSXWindow.m +++ b/src/native/macosx/OSXWindow.m @@ -372,11 +372,11 @@ uint64_t mfb_add_menu_item( } if (key != 0x7f) { - NSString* key = convert_key_code_to_string(key); + NSString* key_string = convert_key_code_to_string(key); - if (key) { + if (key_string) { [newItem setKeyEquivalentModifierMask: mask]; - [newItem setKeyEquivalent:key]; + [newItem setKeyEquivalent:key_string]; } } diff --git a/src/os/macos/mod.rs b/src/os/macos/mod.rs index 93c7dbb..133209e 100644 --- a/src/os/macos/mod.rs +++ b/src/os/macos/mod.rs @@ -191,6 +191,7 @@ extern { 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); @@ -623,7 +624,9 @@ impl Menu { println!("key {:?} conv {}", item.key, conv_key); MenuItemHandle(mfb_add_menu_item(self.menu_handle, item.id as i32, item_name.as_ptr(), - Self::map_key_to_menu_key(item.key), item.modifier)) + item.enabled, + Self::map_key_to_menu_key(item.key), + item.modifier)) } } From 835837286fddc86bbf454085479b7d36a4243034 Mon Sep 17 00:00:00 2001 From: Daniel Collin Date: Sun, 8 May 2016 09:28:43 +0200 Subject: [PATCH 04/18] Made it possible to add menu items using builder --- examples/menu.rs | 8 ++++--- src/lib.rs | 58 +++++++++++++++++++++++++++++++++++++++------ src/os/macos/mod.rs | 2 +- 3 files changed, 57 insertions(+), 11 deletions(-) diff --git a/examples/menu.rs b/examples/menu.rs index 2a0487b..1dedbd7 100644 --- a/examples/menu.rs +++ b/examples/menu.rs @@ -90,9 +90,11 @@ fn main() { let mut menu = Menu::new("TestMenu").unwrap(); - menu.add_item(&MenuItem::new("Item 1", 1).shortcut(Key::S, 0)); - menu.add_item(&MenuItem::new("Item 2", 2)); - menu.add_item(&MenuItem::new("Item 3", 3)); + menu.add_menu_item(&MenuItem::new("Item 1", 1).shortcut(Key::S, 0)); + menu.add_menu_item(&MenuItem::new("Item 2", 2)); + menu.add_menu_item(&MenuItem::new("Item 3", 3)); + + menu.add_item("Some item", 2).shortcut(Key::Y, 0).build(); let _ = window.add_menu(&menu); diff --git a/src/lib.rs b/src/lib.rs index 00f9d34..554f62e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -530,8 +530,18 @@ impl Menu { } #[inline] - pub fn add_item(&mut self, item: &MenuItem) -> MenuItemHandle { - self.0.add_item(item) + 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] @@ -540,22 +550,47 @@ impl Menu { } } -pub struct MenuItem { +pub struct MenuItem<'a> { pub id: usize, pub label: String, pub enabled: bool, pub key: Key, pub modifier: u32, + pub menu: Option<&'a mut Menu>, } -impl MenuItem { +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(), - enabled: true, - key: Key::Unknown, - modifier: 0, + ..MenuItem::default() } } #[inline] @@ -580,6 +615,15 @@ impl MenuItem { .. 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 diff --git a/src/os/macos/mod.rs b/src/os/macos/mod.rs index 133209e..c987cbc 100644 --- a/src/os/macos/mod.rs +++ b/src/os/macos/mod.rs @@ -616,7 +616,7 @@ impl Menu { } } - pub fn add_item(&mut self, item: &MenuItem) -> MenuItemHandle { + 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); From 6f47d190b64ed253e28893ad970ab4e052b63d24 Mon Sep 17 00:00:00 2001 From: Daniel Collin Date: Sun, 8 May 2016 09:42:21 +0200 Subject: [PATCH 05/18] Cleanup + shortcut work --- examples/menu.rs | 4 +- src/lib.rs | 4 +- src/native/macosx/MacMiniFB.m | 190 ++++++++++++++++++++++++++++++++++ src/native/macosx/OSXWindow.m | 189 --------------------------------- 4 files changed, 194 insertions(+), 193 deletions(-) diff --git a/examples/menu.rs b/examples/menu.rs index 1dedbd7..76eeaf8 100644 --- a/examples/menu.rs +++ b/examples/menu.rs @@ -1,7 +1,7 @@ extern crate minifb; use minifb::{Window, Key, Scale, WindowOptions, Menu, MenuItem}; -//use minifb::{MENU_KEY_CTRL, MENU_KEY_COMMAND}; +use minifb::{MENU_KEY_COMMAND, MENU_KEY_CTRL}; const WIDTH: usize = 640; const HEIGHT: usize = 360; @@ -94,7 +94,7 @@ fn main() { menu.add_menu_item(&MenuItem::new("Item 2", 2)); menu.add_menu_item(&MenuItem::new("Item 3", 3)); - menu.add_item("Some item", 2).shortcut(Key::Y, 0).build(); + menu.add_item("Some item", 2).shortcut(Key::Y, MENU_KEY_CTRL).build(); let _ = window.add_menu(&menu); diff --git a/src/lib.rs b/src/lib.rs index 554f62e..a7e4f05 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -594,10 +594,10 @@ impl<'a> MenuItem<'a> { } } #[inline] - pub fn shortcut(self, key: Key, modifier: u32) -> Self { + pub fn shortcut(self, key: Key, modifier: usize) -> Self { MenuItem { key: key, - modifier: modifier, + modifier: modifier as u32, .. self } } diff --git a/src/native/macosx/MacMiniFB.m b/src/native/macosx/MacMiniFB.m index e5d97be..aae240c 100644 --- a/src/native/macosx/MacMiniFB.m +++ b/src/native/macosx/MacMiniFB.m @@ -2,6 +2,7 @@ #include "OSXWindow.h" #include "OSXWindowFrameView.h" #include +#include #include static bool s_init = false; @@ -452,6 +453,195 @@ void mfb_update_menu(void* window, const char* name, void* m) } */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +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; + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/* +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; + 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; + } + + if (desc->key != 0x7f) { + NSString* 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++; + } +} +*/ + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +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; + + const char* t = strdup(item_name); + + NSString* name = [NSString stringWithUTF8String: t]; + + if (menu_id == -1) + { + [menu addItem:[NSMenuItem separatorItem]]; + } + else + { + int mask = 0; + NSMenuItem* newItem = [[NSMenuItem alloc] initWithTitle:name action:@selector(onMenuPress:) keyEquivalent:@""]; + [newItem setTag:menu_id]; + + if ((modfier & MENU_KEY_COMMAND) || + (modfier & MENU_KEY_COMMAND)) { + mask |= NSCommandKeyMask; + } + if (modfier & MENU_KEY_SHIFT) { + mask |= NSShiftKeyMask; + } + if (modfier & MENU_KEY_ALT) { + mask |= NSAlternateKeyMask; + } + + if (key != 0x7f) { + NSString* 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]; + [newItem release]; + + return (uint64_t)newItem; + } + + return 0; +} + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void* mfb_create_menu(const char* name) { diff --git a/src/native/macosx/OSXWindow.m b/src/native/macosx/OSXWindow.m index cdc1b5f..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 @@ -208,194 +207,6 @@ 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; - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -/* -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; - 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; - } - - if (desc->key != 0x7f) { - NSString* 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++; - } -} -*/ - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -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; - - const char* t = strdup(item_name); - - NSString* name = [NSString stringWithUTF8String: t]; - - if (menu_id == -1) - { - [menu addItem:[NSMenuItem separatorItem]]; - } - else - { - int mask = 0; - NSMenuItem* newItem = [[NSMenuItem alloc] initWithTitle:name action:@selector(onMenuPress:) keyEquivalent:@""]; - [newItem setTag:menu_id]; - - if ((modfier & MENU_KEY_COMMAND) || - (modfier & MENU_KEY_COMMAND)) { - mask |= NSCommandKeyMask; - } - if (modfier & MENU_KEY_SHIFT) { - mask |= NSShiftKeyMask; - } - if (modfier & MENU_KEY_ALT) { - mask |= NSAlternateKeyMask; - } - - if (key != 0x7f) { - NSString* 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]; - [newItem release]; - - return (uint64_t)newItem; - } - - return 0; -} - @end From ab924a4b0da2733104041df3a65298f146c05068 Mon Sep 17 00:00:00 2001 From: Daniel Collin Date: Sun, 8 May 2016 10:24:37 +0200 Subject: [PATCH 06/18] Submenu support --- examples/menu.rs | 7 +++++++ src/lib.rs | 4 ++-- src/native/macosx/MacMiniFB.m | 28 ++++++++++++++++++++++++++-- src/os/macos/mod.rs | 8 ++++++++ 4 files changed, 43 insertions(+), 4 deletions(-) diff --git a/examples/menu.rs b/examples/menu.rs index 76eeaf8..624db03 100644 --- a/examples/menu.rs +++ b/examples/menu.rs @@ -89,13 +89,20 @@ fn main() { //window.add_menu("Test", &menu).expect("Unable to add menu"); let mut menu = Menu::new("TestMenu").unwrap(); + let mut sub = Menu::new("SubMenu").unwrap(); menu.add_menu_item(&MenuItem::new("Item 1", 1).shortcut(Key::S, 0)); menu.add_menu_item(&MenuItem::new("Item 2", 2)); menu.add_menu_item(&MenuItem::new("Item 3", 3)); + sub.add_item("Test", 0).build(); + sub.add_item("Test 2", 0).build(); + + menu.add_item("", 0).separator().build(); menu.add_item("Some item", 2).shortcut(Key::Y, MENU_KEY_CTRL).build(); + menu.add_sub_menu("Sub Test", &sub); + let _ = window.add_menu(&menu); let color_mul = 1; diff --git a/src/lib.rs b/src/lib.rs index a7e4f05..974c227 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -525,8 +525,8 @@ impl Menu { } #[inline] - pub fn add_sub_menu(&mut self, _menu: &Menu) { - //self.0.add_sub_menu(menu) + pub fn add_sub_menu(&mut self, name: &str, menu: &Menu) { + self.0.add_sub_menu(name, &menu.0) } #[inline] diff --git a/src/native/macosx/MacMiniFB.m b/src/native/macosx/MacMiniFB.m index aae240c..39df473 100644 --- a/src/native/macosx/MacMiniFB.m +++ b/src/native/macosx/MacMiniFB.m @@ -605,10 +605,22 @@ uint64_t mfb_add_menu_item( NSMenuItem* newItem = [[NSMenuItem alloc] initWithTitle:name action:@selector(onMenuPress:) keyEquivalent:@""]; [newItem setTag:menu_id]; - if ((modfier & MENU_KEY_COMMAND) || - (modfier & MENU_KEY_COMMAND)) { + // 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; } @@ -641,6 +653,18 @@ uint64_t mfb_add_menu_item( 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]; +} /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/os/macos/mod.rs b/src/os/macos/mod.rs index c987cbc..319aafc 100644 --- a/src/os/macos/mod.rs +++ b/src/os/macos/mod.rs @@ -181,6 +181,7 @@ extern { fn mfb_get_screen_size() -> u32; fn mfb_is_active(window: *mut c_void) -> u32; fn mfb_add_menu(window: *mut c_void, menu: *mut c_void); + fn mfb_add_sub_menu(parent_menu: *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_active_menu(window: *mut c_void) -> i32; @@ -616,6 +617,13 @@ impl Menu { } } + 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) + } + } + pub fn add_menu_item(&mut self, item: &MenuItem) -> MenuItemHandle { unsafe { let item_name = CString::new(item.label.as_str()).unwrap(); From 10de5cd84e5d0a8192a229e668351725e2e8b695 Mon Sep 17 00:00:00 2001 From: Daniel Collin Date: Sun, 8 May 2016 10:31:58 +0200 Subject: [PATCH 07/18] Cleanup --- src/native/macosx/MacMiniFB.m | 26 ++++++----- src/os/macos/mod.rs | 82 ++--------------------------------- 2 files changed, 18 insertions(+), 90 deletions(-) diff --git a/src/native/macosx/MacMiniFB.m b/src/native/macosx/MacMiniFB.m index 39df473..fea6c83 100644 --- a/src/native/macosx/MacMiniFB.m +++ b/src/native/macosx/MacMiniFB.m @@ -645,7 +645,7 @@ uint64_t mfb_add_menu_item( [newItem setOnStateImage: newItem.offStateImage]; [menu addItem:newItem]; - [newItem release]; + //[newItem release]; return (uint64_t)newItem; } @@ -669,15 +669,8 @@ void mfb_add_sub_menu(void* parent_menu, const char* menu_name, void* attach_men /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void* mfb_create_menu(const char* name) { - const char* n = strdup(name); // WHY? - - NSString* ns_name = [NSString stringWithUTF8String: n]; - - //NSMenuItem* menu_item = [[NSMenuItem alloc] initWithTitle:name action:NULL keyEquivalent:@""]; + NSString* ns_name = [NSString stringWithUTF8String: name]; NSMenu* menu = [[NSMenu alloc] initWithTitle:ns_name]; - //[menu_item setSubmenu:menu]; - - //printf("created menu %p\n"); return (void*)menu; } @@ -696,11 +689,22 @@ void mfb_destroy_menu(void* menu_item, const char* name) void mfb_remove_menu_item(void* parent, uint64_t menu_item) { NSMenu* menu = (NSMenu*)parent; NSMenuItem* item = (NSMenuItem*)(uintptr_t)menu_item; - - printf("remove item menu %p item %p\n", menu, item); [menu removeItem:item]; } + + + + + + + + + + + + + diff --git a/src/os/macos/mod.rs b/src/os/macos/mod.rs index 319aafc..91d6862 100644 --- a/src/os/macos/mod.rs +++ b/src/os/macos/mod.rs @@ -151,20 +151,6 @@ static KEY_MAPPINGS: [Key; 128] = [ ]; -/* -#[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 { @@ -182,9 +168,6 @@ extern { fn mfb_is_active(window: *mut c_void) -> u32; fn mfb_add_menu(window: *mut c_void, menu: *mut c_void); fn mfb_add_sub_menu(parent_menu: *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_active_menu(window: *mut c_void) -> i32; fn mfb_create_menu(name: *const c_char) -> *mut c_void; //fn mfb_destroy_menu(menu_item: *mut c_void); @@ -436,62 +419,6 @@ impl Window { return factor; } - - /* - */ - - /* - 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(); - } - - let mut menu_build = Vec::::new(); - let menu_vec = in_menu.as_ref().unwrap(); - - 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); - } - - // 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 struct Menu { @@ -629,12 +556,9 @@ impl Menu { let item_name = CString::new(item.label.as_str()).unwrap(); let conv_key = Self::map_key_to_menu_key(item.key); - println!("key {:?} conv {}", item.key, conv_key); - - MenuItemHandle(mfb_add_menu_item(self.menu_handle, item.id as i32, item_name.as_ptr(), - item.enabled, - Self::map_key_to_menu_key(item.key), - item.modifier)) + MenuItemHandle(mfb_add_menu_item(self.menu_handle, + item.id as i32, item_name.as_ptr(), + item.enabled, conv_key, item.modifier)) } } From 3c2451c2eced7891de9fc635bd9cfeb236811a0e Mon Sep 17 00:00:00 2001 From: Daniel Collin Date: Sun, 8 May 2016 10:33:27 +0200 Subject: [PATCH 08/18] Rustfmt --- src/os/macos/mod.rs | 117 ++++++++++++++++++++++++++------------------ 1 file changed, 69 insertions(+), 48 deletions(-) diff --git a/src/os/macos/mod.rs b/src/os/macos/mod.rs index 91d6862..0f2f558 100644 --- a/src/os/macos/mod.rs +++ b/src/os/macos/mod.rs @@ -4,15 +4,15 @@ use {MouseButton, MouseMode, Scale, Key, KeyRepeat, WindowOptions}; use key_handler::KeyHandler; use error::Error; use Result; -//use MenuItem; +// use MenuItem; use InputCallback; use mouse_handler; use window_flags; use {MenuItem, MenuItemHandle}; -//use menu::Menu; +// 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; @@ -150,18 +150,23 @@ static KEY_MAPPINGS: [Key; 128] = [ /* 7f */ Key::Unknown, ]; - #[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; @@ -170,14 +175,15 @@ extern { fn mfb_add_sub_menu(parent_menu: *mut c_void, name: *const c_char, menu: *mut c_void); fn mfb_create_menu(name: *const c_char) -> *mut c_void; - //fn mfb_destroy_menu(menu_item: *mut c_void); + // fn mfb_destroy_menu(menu_item: *mut c_void); fn mfb_add_menu_item(menu_item: *mut c_void, - menu_id: i32, - name: *const c_char, - enabled: bool, - key: u32, - modifier: u32) -> u64; + 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); } @@ -238,7 +244,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())); @@ -250,7 +260,7 @@ 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, @@ -274,7 +284,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); } } @@ -284,7 +297,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); } } @@ -294,7 +310,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)> { @@ -321,7 +338,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] @@ -355,7 +377,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) } @@ -482,10 +504,10 @@ impl Menu { 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, @@ -495,7 +517,7 @@ impl Menu { Key::RightShift => 0x3c, Key::RightAlt => 0x3d, Key::RightCtrl => 0x3e, - //Key::Equal => 0x51, + // Key::Equal => 0x51, Key::NumPad0 => 0x52, Key::NumPad1 => 0x53, Key::NumPad2 => 0x54, @@ -519,23 +541,23 @@ impl Menu { 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, @@ -556,9 +578,12 @@ impl Menu { let item_name = CString::new(item.label.as_str()).unwrap(); let conv_key = Self::map_key_to_menu_key(item.key); - MenuItemHandle(mfb_add_menu_item(self.menu_handle, - item.id as i32, item_name.as_ptr(), - item.enabled, conv_key, item.modifier)) + MenuItemHandle(mfb_add_menu_item(self.menu_handle, + item.id as i32, + item_name.as_ptr(), + item.enabled, + conv_key, + item.modifier)) } } @@ -577,15 +602,11 @@ impl Drop for Window { } } -/* -impl Drop for Menu { - fn drop(&mut self) { - unsafe { - mfb_destroy_menu(self.menu_handle); - } - } -} -*/ - - - +// impl Drop for Menu { +// fn drop(&mut self) { +// unsafe { +// mfb_destroy_menu(self.menu_handle); +// } +// } +// } +// From d3fcfd4bf08ef0cc0b9bd5ef175702e0841d7e5d Mon Sep 17 00:00:00 2001 From: Daniel Collin Date: Sun, 8 May 2016 11:00:50 +0200 Subject: [PATCH 09/18] Fixed f-keys --- src/lib.rs | 4 ++++ src/native/macosx/MacMiniFB.m | 38 +++++++++++++++++++++++++++++------ src/os/macos/mod.rs | 5 ++++- 3 files changed, 40 insertions(+), 7 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 974c227..12004c5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -529,6 +529,10 @@ impl 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) diff --git a/src/native/macosx/MacMiniFB.m b/src/native/macosx/MacMiniFB.m index fea6c83..a22331f 100644 --- a/src/native/macosx/MacMiniFB.m +++ b/src/native/macosx/MacMiniFB.m @@ -581,6 +581,14 @@ void build_submenu(NSMenu* menu, MenuDesc* desc) /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +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, @@ -601,10 +609,13 @@ uint64_t mfb_add_menu_item( } else { + NSString* key_string = 0; int mask = 0; NSMenuItem* newItem = [[NSMenuItem alloc] initWithTitle:name action:@selector(onMenuPress:) keyEquivalent:@""]; [newItem setTag:menu_id]; + printf("set menu id %d\n", 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 @@ -628,15 +639,30 @@ uint64_t mfb_add_menu_item( mask |= NSAlternateKeyMask; } - if (key != 0x7f) { - NSString* key_string = convert_key_code_to_string(key); - - if (key_string) { - [newItem setKeyEquivalentModifierMask: mask]; - [newItem setKeyEquivalent:key_string]; + 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 { diff --git a/src/os/macos/mod.rs b/src/os/macos/mod.rs index 0f2f558..2be88ae 100644 --- a/src/os/macos/mod.rs +++ b/src/os/macos/mod.rs @@ -173,6 +173,7 @@ extern "C" { fn mfb_is_active(window: *mut c_void) -> u32; fn mfb_add_menu(window: *mut c_void, menu: *mut c_void); 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_destroy_menu(menu_item: *mut c_void); @@ -382,7 +383,7 @@ impl Window { } pub fn is_menu_pressed(&mut self) -> Option { - let menu_id = 0; //unsafe { mfb_active_menu(self.window_handle) }; + let menu_id = unsafe { mfb_active_menu(self.window_handle) }; if menu_id < 0 { None @@ -578,6 +579,8 @@ impl Menu { let item_name = CString::new(item.label.as_str()).unwrap(); let conv_key = Self::map_key_to_menu_key(item.key); + println!("menu id {}", item.id); + MenuItemHandle(mfb_add_menu_item(self.menu_handle, item.id as i32, item_name.as_ptr(), From c6f61804e619f6e3807a5463da7893f259b93b22 Mon Sep 17 00:00:00 2001 From: Daniel Collin Date: Sun, 8 May 2016 11:01:49 +0200 Subject: [PATCH 10/18] Restored f-keys so the work again --- examples/menu.rs | 87 ++++++------------------------------------------ 1 file changed, 11 insertions(+), 76 deletions(-) diff --git a/examples/menu.rs b/examples/menu.rs index 624db03..c6d3565 100644 --- a/examples/menu.rs +++ b/examples/menu.rs @@ -6,14 +6,12 @@ use minifb::{MENU_KEY_COMMAND, MENU_KEY_CTRL}; const WIDTH: usize = 640; const HEIGHT: usize = 360; -/* const MENU_TEST_ID: usize = 1; const OTHER_MENU_ID: usize = 2; const COLOR_0_ID: usize = 3; const COLOR_1_ID: usize = 4; const COLOR_2_ID: usize = 5; const CLOSE_MENU_ID: usize = 6; -*/ fn main() { let mut buffer: Vec = vec![0; WIDTH * HEIGHT]; @@ -28,84 +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 - - 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() - } - ]; - */ - - //window.add_menu("Test", &menu).expect("Unable to add menu"); - - let mut menu = Menu::new("TestMenu").unwrap(); - let mut sub = Menu::new("SubMenu").unwrap(); - - menu.add_menu_item(&MenuItem::new("Item 1", 1).shortcut(Key::S, 0)); - menu.add_menu_item(&MenuItem::new("Item 2", 2)); - menu.add_menu_item(&MenuItem::new("Item 3", 3)); - - sub.add_item("Test", 0).build(); - sub.add_item("Test 2", 0).build(); - - menu.add_item("", 0).separator().build(); - menu.add_item("Some item", 2).shortcut(Key::Y, MENU_KEY_CTRL).build(); + menu.add_item("Menu Test", MENU_TEST_ID).shortcut(Key::W, MENU_KEY_CTRL).build(); + menu.add_separator(); + 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 _ = window.add_menu(&menu); - let color_mul = 1; + let mut color_mul = 1; while window.is_open() && !window.is_key_down(Key::Escape) { for y in 0..HEIGHT { @@ -114,7 +51,6 @@ fn main() { } } - /* window.is_menu_pressed().map(|menu_id| { match menu_id { COLOR_0_ID => { @@ -128,14 +64,13 @@ fn main() { } CLOSE_MENU_ID => { println!("remove menu"); - //window.remove_menu("Test").expect("Unable to remove menu"); + //window.remove_menu( } _ => (), } println!("Menu id {} pressed", menu_id); }); - */ window.get_keys().map(|keys| { for t in keys { From 0ffa3bf196f29fcd7e3f422678d95b8b42afea40 Mon Sep 17 00:00:00 2001 From: Daniel Collin Date: Sun, 8 May 2016 13:27:55 +0200 Subject: [PATCH 11/18] Support for removing menus --- examples/menu.rs | 4 ++-- src/lib.rs | 15 ++++++++------ src/native/macosx/MacMiniFB.m | 13 +++++++++++- src/os/macos/mod.rs | 37 ++++++++++++++++++++--------------- 4 files changed, 44 insertions(+), 25 deletions(-) diff --git a/examples/menu.rs b/examples/menu.rs index c6d3565..b4a9f5c 100644 --- a/examples/menu.rs +++ b/examples/menu.rs @@ -40,7 +40,7 @@ fn main() { menu.add_sub_menu("Sub Test", &sub); - let _ = window.add_menu(&menu); + let menu_handle = window.add_menu(&menu); let mut color_mul = 1; @@ -64,7 +64,7 @@ fn main() { } CLOSE_MENU_ID => { println!("remove menu"); - //window.remove_menu( + window.remove_menu(menu_handle); } _ => (), } diff --git a/src/lib.rs b/src/lib.rs index 12004c5..58ade2e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -464,27 +464,27 @@ impl Window { /// #[inline] - pub fn add_menu(&mut self, menu: &Menu) -> Result<()> { + 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) } - */ /// /// Check if a menu item has been pressed @@ -511,9 +511,12 @@ const MENU_ID_SEPARATOR:usize = 0xffffffff; pub struct Menu(imp::Menu); -#[derive(Debug)] +#[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) diff --git a/src/native/macosx/MacMiniFB.m b/src/native/macosx/MacMiniFB.m index a22331f..8c06cae 100644 --- a/src/native/macosx/MacMiniFB.m +++ b/src/native/macosx/MacMiniFB.m @@ -416,7 +416,7 @@ void mfb_add_menu(void* window, const char* name, void* m) /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void mfb_add_menu(void* window, void* m) +uint64_t mfb_add_menu(void* window, void* m) { OSXWindow* win = (OSXWindow*)window; NSMenu* menu = (NSMenu*)m; @@ -426,6 +426,17 @@ void mfb_add_menu(void* window, void* m) 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/os/macos/mod.rs b/src/os/macos/mod.rs index 2be88ae..b90daaf 100644 --- a/src/os/macos/mod.rs +++ b/src/os/macos/mod.rs @@ -8,7 +8,7 @@ use Result; use InputCallback; use mouse_handler; use window_flags; -use {MenuItem, MenuItemHandle}; +use {MenuItem, MenuItemHandle, MenuHandle}; // use menu::Menu; use libc::{c_void, c_char, c_uchar}; @@ -171,12 +171,12 @@ extern "C" { 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, 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_destroy_menu(menu_item: *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, @@ -206,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) { @@ -265,6 +266,7 @@ impl Window { }, key_handler: KeyHandler::new(), has_set_data: false, + menus: Vec::new(), }) } } @@ -392,12 +394,25 @@ impl Window { } } - pub fn add_menu(&mut self, menu: &Menu) -> Result<()> { + pub fn add_menu(&mut self, menu: &Menu) -> MenuHandle { unsafe { - mfb_add_menu(self.window_handle, menu.menu_handle); + let handle = MenuHandle(mfb_add_menu(self.window_handle, menu.menu_handle)); + self.menus.push(handle); + handle } + } - Ok(()) + 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; + } + } } #[inline] @@ -579,8 +594,6 @@ impl Menu { let item_name = CString::new(item.label.as_str()).unwrap(); let conv_key = Self::map_key_to_menu_key(item.key); - println!("menu id {}", item.id); - MenuItemHandle(mfb_add_menu_item(self.menu_handle, item.id as i32, item_name.as_ptr(), @@ -605,11 +618,3 @@ impl Drop for Window { } } -// impl Drop for Menu { -// fn drop(&mut self) { -// unsafe { -// mfb_destroy_menu(self.menu_handle); -// } -// } -// } -// From df60ca8ecdd78ce56565eb0b24b6fc49b9b2c650 Mon Sep 17 00:00:00 2001 From: Daniel Collin Date: Sun, 8 May 2016 13:34:38 +0200 Subject: [PATCH 12/18] Cleanup --- examples/menu.rs | 4 ++-- src/native/macosx/MacMiniFB.m | 2 -- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/examples/menu.rs b/examples/menu.rs index b4a9f5c..3144647 100644 --- a/examples/menu.rs +++ b/examples/menu.rs @@ -1,7 +1,7 @@ extern crate minifb; -use minifb::{Window, Key, Scale, WindowOptions, Menu, MenuItem}; -use minifb::{MENU_KEY_COMMAND, MENU_KEY_CTRL}; +use minifb::{Window, Key, Scale, WindowOptions, Menu}; +use minifb::{MENU_KEY_CTRL}; const WIDTH: usize = 640; const HEIGHT: usize = 360; diff --git a/src/native/macosx/MacMiniFB.m b/src/native/macosx/MacMiniFB.m index 8c06cae..db71667 100644 --- a/src/native/macosx/MacMiniFB.m +++ b/src/native/macosx/MacMiniFB.m @@ -625,8 +625,6 @@ uint64_t mfb_add_menu_item( NSMenuItem* newItem = [[NSMenuItem alloc] initWithTitle:name action:@selector(onMenuPress:) keyEquivalent:@""]; [newItem setTag:menu_id]; - printf("set menu id %d\n", 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 From 8f687c58db29b509607ae9aa68ddd3049fe01b3b Mon Sep 17 00:00:00 2001 From: Daniel Collin Date: Sun, 8 May 2016 13:37:20 +0200 Subject: [PATCH 13/18] Some more cleanup --- examples/menu.rs | 2 ++ src/native/macosx/MacMiniFB.m | 4 +--- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/menu.rs b/examples/menu.rs index 3144647..cc14026 100644 --- a/examples/menu.rs +++ b/examples/menu.rs @@ -34,7 +34,9 @@ fn main() { sub.add_item("Color 2", COLOR_2_ID).shortcut(Key::F7, 0).build(); menu.add_item("Menu Test", MENU_TEST_ID).shortcut(Key::W, MENU_KEY_CTRL).build(); + menu.add_separator(); + 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(); diff --git a/src/native/macosx/MacMiniFB.m b/src/native/macosx/MacMiniFB.m index db71667..0cc3f91 100644 --- a/src/native/macosx/MacMiniFB.m +++ b/src/native/macosx/MacMiniFB.m @@ -610,9 +610,7 @@ uint64_t mfb_add_menu_item( { NSMenu* menu = (NSMenu*)in_menu; - const char* t = strdup(item_name); - - NSString* name = [NSString stringWithUTF8String: t]; + NSString* name = [NSString stringWithUTF8String: item_name]; if (menu_id == -1) { From 0f1ed50f36f0fd1356f9d2a09cba467d35a83e06 Mon Sep 17 00:00:00 2001 From: Daniel Collin Date: Sun, 8 May 2016 13:43:25 +0200 Subject: [PATCH 14/18] Cleanup --- src/native/macosx/MacMiniFB.m | 196 +++++----------------------------- 1 file changed, 26 insertions(+), 170 deletions(-) diff --git a/src/native/macosx/MacMiniFB.m b/src/native/macosx/MacMiniFB.m index 0cc3f91..edf5d51 100644 --- a/src/native/macosx/MacMiniFB.m +++ b/src/native/macosx/MacMiniFB.m @@ -1,4 +1,3 @@ - #include "OSXWindow.h" #include "OSXWindowFrameView.h" #include @@ -241,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) { @@ -384,88 +384,6 @@ int mfb_active_menu(void* window) { /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -/* -void mfb_add_menu(void* window, const char* name, void* m) -{ - OSXWindow* win = (OSXWindow*)window; - - const char* n = strdup(name); - - NSString* ns_name = [NSString stringWithUTF8String: n]; - - NSMenu* main_menu = [NSApp mainMenu]; - - NSMenuItem* windowMenuItem = [main_menu addItemWithTitle:@"" action:NULL keyEquivalent:@""]; - NSMenu* windowMenu = [[NSMenu alloc] initWithTitle:ns_name]; - [NSApp setWindowsMenu:windowMenu]; - [windowMenuItem setSubmenu:windowMenu]; - - 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; -} -*/ - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -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]; -} - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -/* -void mfb_update_menu(void* window, const char* name, void* m) -{ - 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) - { - Menu* menu = &win->menu_data->menus[i]; - - if (!strcmp(menu->name, name)) { - [menu->menu removeAllItems]; - build_submenu(menu->menu, (MenuDesc*)m); - return; - } - } -} -*/ - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - static CFStringRef create_string_for_key(CGKeyCode keyCode) { TISInputSourceRef currentKeyboard = TISCopyCurrentKeyboardInputSource(); @@ -520,76 +438,6 @@ const uint32_t MENU_KEY_SHIFT= 4; const uint32_t MENU_KEY_CTRL = 8; const uint32_t MENU_KEY_ALT = 16; -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -/* -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; - 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; - } - - if (desc->key != 0x7f) { - NSString* 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++; - } -} -*/ - /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// static NSString* get_string_for_key(uint32_t t) { @@ -678,7 +526,6 @@ uint64_t mfb_add_menu_item( [newItem setOnStateImage: newItem.offStateImage]; [menu addItem:newItem]; - //[newItem release]; return (uint64_t)newItem; } @@ -704,7 +551,6 @@ void mfb_add_sub_menu(void* parent_menu, const char* menu_name, void* attach_men void* mfb_create_menu(const char* name) { NSString* ns_name = [NSString stringWithUTF8String: name]; NSMenu* menu = [[NSMenu alloc] initWithTitle:ns_name]; - return (void*)menu; } @@ -725,19 +571,29 @@ void mfb_remove_menu_item(void* parent, uint64_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]; +} From 37292a70cf9f81466d553b67740a8b63dd3c88d9 Mon Sep 17 00:00:00 2001 From: Daniel Collin Date: Mon, 9 May 2016 15:49:26 +0200 Subject: [PATCH 15/18] Inital menus for Windows implemented --- src/lib.rs | 4 +- src/os/windows/mod.rs | 417 ++++++++++++++++++++++++++++++------------ 2 files changed, 299 insertions(+), 122 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 58ade2e..e20e062 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -562,7 +562,7 @@ pub struct MenuItem<'a> { pub label: String, pub enabled: bool, pub key: Key, - pub modifier: u32, + pub modifier: usize, pub menu: Option<&'a mut Menu>, } @@ -604,7 +604,7 @@ impl<'a> MenuItem<'a> { pub fn shortcut(self, key: Key, modifier: usize) -> Self { MenuItem { key: key, - modifier: modifier as u32, + modifier: modifier, .. self } } diff --git a/src/os/windows/mod.rs b/src/os/windows/mod.rs index 397eac7..44c486b 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, @@ -449,7 +450,7 @@ impl Window { scale_factor: scale_factor, width: width as i32, height: height as i32, - menus: Vec::new(), + //menus: Vec::new(), accel_table: ptr::null_mut(), accel_key: INVALID_ACCEL, }; @@ -635,120 +636,6 @@ impl Window { return factor; } - fn map_key_to_vk_accel(key: Key) -> (raw::c_int, &'static str) { - match key { - Key::Key0 => (0x30, "0"), - Key::Key1 => (0x31, "1"), - Key::Key2 => (0x32, "2"), - Key::Key3 => (0x33, "3"), - Key::Key4 => (0x34, "4"), - Key::Key5 => (0x35, "5"), - Key::Key6 => (0x36, "6"), - Key::Key7 => (0x37, "7"), - Key::Key8 => (0x38, "8"), - Key::Key9 => (0x39, "9"), - - Key::A => (0x41, "a"), - Key::B => (0x42, "b"), - Key::C => (0x43, "c"), - Key::D => (0x44, "d"), - Key::E => (0x45, "e"), - Key::F => (0x46, "f"), - Key::G => (0x47, "g"), - Key::H => (0x48, "h"), - Key::I => (0x49, "i"), - Key::J => (0x4a, "j"), - Key::K => (0x4b, "k"), - Key::L => (0x4c, "l"), - Key::M => (0x4d, "m"), - Key::N => (0x4e, "n"), - Key::O => (0x4f, "o"), - Key::P => (0x50, "p"), - Key::Q => (0x51, "q"), - Key::R => (0x52, "r"), - Key::S => (0x53, "s"), - Key::T => (0x54, "t"), - Key::U => (0x55, "u"), - Key::V => (0x56, "v"), - Key::W => (0x57, "w"), - Key::X => (0x58, "x"), - Key::Y => (0x59, "y"), - Key::Z => (0x5a, "z"), - - Key::F1 => (winapi::winuser::VK_F1, "F1"), - Key::F2 => (winapi::winuser::VK_F2, "F2"), - Key::F3 => (winapi::winuser::VK_F3, "F3"), - Key::F4 => (winapi::winuser::VK_F4, "F4"), - Key::F5 => (winapi::winuser::VK_F5, "F5"), - Key::F6 => (winapi::winuser::VK_F6, "F6"), - Key::F7 => (winapi::winuser::VK_F7, "F7"), - Key::F8 => (winapi::winuser::VK_F8, "F8"), - Key::F9 => (winapi::winuser::VK_F9, "F9"), - Key::F10 => (winapi::winuser::VK_F10, "F10"), - Key::F11 => (winapi::winuser::VK_F11, "F11"), - Key::F12 => (winapi::winuser::VK_F12, "F12"), - Key::F13 => (winapi::winuser::VK_F13, "F14"), - Key::F14 => (winapi::winuser::VK_F14, "F14"), - Key::F15 => (winapi::winuser::VK_F15, "F15"), - - Key::Down => (winapi::winuser::VK_DOWN, "Down"), - Key::Left => (winapi::winuser::VK_LEFT, "Left"), - Key::Right => (winapi::winuser::VK_RIGHT, "Right"), - Key::Up => (winapi::winuser::VK_UP, "Up"), - - Key::Backslash => (winapi::winuser::VK_OEM_102, "Backslash"), - Key::Comma => (winapi::winuser::VK_OEM_COMMA, ","), - Key::Minus => (winapi::winuser::VK_OEM_MINUS, "-"), - Key::Period => (winapi::winuser::VK_OEM_PERIOD, "."), - - Key::Backspace => (winapi::winuser::VK_BACK, "Back"), - Key::Delete => (winapi::winuser::VK_DELETE, "Delete"), - Key::End => (winapi::winuser::VK_END, "End"), - Key::Enter => (winapi::winuser::VK_RETURN, "Enter"), - - Key::Escape => (winapi::winuser::VK_ESCAPE, "Esc"), - - Key::Home => (winapi::winuser::VK_HOME, "Home"), - Key::Insert => (winapi::winuser::VK_INSERT, "Insert"), - Key::Menu => (winapi::winuser::VK_MENU, "Menu"), - - Key::PageDown => (winapi::winuser::VK_NEXT, "PageDown"), - Key::PageUp => (winapi::winuser::VK_PRIOR, "PageUp"), - - Key::Pause => (winapi::winuser::VK_PAUSE, "Pause"), - Key::Space => (winapi::winuser::VK_SPACE, "Space"), - Key::Tab => (winapi::winuser::VK_TAB, "Tab"), - Key::NumLock => (winapi::winuser::VK_NUMLOCK, "NumLock"), - Key::CapsLock => (winapi::winuser::VK_CAPITAL, "CapsLock"), - Key::ScrollLock => (winapi::winuser::VK_SCROLL, "Scroll"), - - Key::LeftShift => (winapi::winuser::VK_LSHIFT, "LeftShift"), - Key::RightShift => (winapi::winuser::VK_RSHIFT, "RightShift"), - Key::LeftCtrl => (winapi::winuser::VK_CONTROL, "Ctrl"), - Key::RightCtrl => (winapi::winuser::VK_CONTROL, "Ctrl"), - - Key::NumPad0 => (winapi::winuser::VK_NUMPAD0, "NumPad0"), - Key::NumPad1 => (winapi::winuser::VK_NUMPAD1, "NumPad1"), - Key::NumPad2 => (winapi::winuser::VK_NUMPAD2, "NumPad2"), - Key::NumPad3 => (winapi::winuser::VK_NUMPAD3, "NumPad3"), - Key::NumPad4 => (winapi::winuser::VK_NUMPAD4, "NumPad4"), - Key::NumPad5 => (winapi::winuser::VK_NUMPAD5, "NumPad5"), - Key::NumPad6 => (winapi::winuser::VK_NUMPAD6, "NumPad6"), - Key::NumPad7 => (winapi::winuser::VK_NUMPAD7, "NumPad7"), - Key::NumPad8 => (winapi::winuser::VK_NUMPAD8, "NumPad8"), - Key::NumPad9 => (winapi::winuser::VK_NUMPAD9, "NumPad9"), - - Key::LeftAlt => (winapi::winuser::VK_MENU, "Alt"), - Key::RightAlt => (winapi::winuser::VK_MENU, "Alt"), - - Key::LeftSuper => (winapi::winuser::VK_LWIN, "LeftWin"), - Key::RightSuper => (winapi::winuser::VK_RWIN, "RightWin"), - - _ => (0, "Unsupported"), - } - } - - // // When attaching a menu to the window we need to resize it so // the current client size is preserved and still show all pixels @@ -767,6 +654,7 @@ impl Window { 1); } + /* fn format_name(menu_item: &Menu, key_name: &'static str) -> String { let mut name = menu_item.name.to_owned(); @@ -946,6 +834,7 @@ impl Window { Ok(()) } + pub fn update_menu(&mut self, menu_name: &str, menu: &Vec) -> Result<()> { try!(Self::remove_menu(self, menu_name)); @@ -967,6 +856,40 @@ impl Window { // TODO: Proper return here Ok(()) } + */ + + 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()); + + // TODO: Setup accel table + + //Self::add_menu_store(self, main_menu, menu_name, menu); + //Self::set_accel_table(self); + + user32::DrawMenuBar(window); + } + + + // TODO: Proper handle + + MenuHandle(0) + } + + pub fn remove_menu(&mut self, _handle: MenuHandle) { + } pub fn is_menu_pressed(&mut self) -> Option { if self.accel_key == INVALID_ACCEL { @@ -978,6 +901,260 @@ impl Window { } } } +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(), + }) + } + } + + 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()); + } + } + + fn map_key_to_vk_accel(key: Key) -> (raw::c_int, &'static str) { + match key { + Key::Key0 => (0x30, "0"), + Key::Key1 => (0x31, "1"), + Key::Key2 => (0x32, "2"), + Key::Key3 => (0x33, "3"), + Key::Key4 => (0x34, "4"), + Key::Key5 => (0x35, "5"), + Key::Key6 => (0x36, "6"), + Key::Key7 => (0x37, "7"), + Key::Key8 => (0x38, "8"), + Key::Key9 => (0x39, "9"), + + Key::A => (0x41, "a"), + Key::B => (0x42, "b"), + Key::C => (0x43, "c"), + Key::D => (0x44, "d"), + Key::E => (0x45, "e"), + Key::F => (0x46, "f"), + Key::G => (0x47, "g"), + Key::H => (0x48, "h"), + Key::I => (0x49, "i"), + Key::J => (0x4a, "j"), + Key::K => (0x4b, "k"), + Key::L => (0x4c, "l"), + Key::M => (0x4d, "m"), + Key::N => (0x4e, "n"), + Key::O => (0x4f, "o"), + Key::P => (0x50, "p"), + Key::Q => (0x51, "q"), + Key::R => (0x52, "r"), + Key::S => (0x53, "s"), + Key::T => (0x54, "t"), + Key::U => (0x55, "u"), + Key::V => (0x56, "v"), + Key::W => (0x57, "w"), + Key::X => (0x58, "x"), + Key::Y => (0x59, "y"), + Key::Z => (0x5a, "z"), + + Key::F1 => (winapi::winuser::VK_F1, "F1"), + Key::F2 => (winapi::winuser::VK_F2, "F2"), + Key::F3 => (winapi::winuser::VK_F3, "F3"), + Key::F4 => (winapi::winuser::VK_F4, "F4"), + Key::F5 => (winapi::winuser::VK_F5, "F5"), + Key::F6 => (winapi::winuser::VK_F6, "F6"), + Key::F7 => (winapi::winuser::VK_F7, "F7"), + Key::F8 => (winapi::winuser::VK_F8, "F8"), + Key::F9 => (winapi::winuser::VK_F9, "F9"), + Key::F10 => (winapi::winuser::VK_F10, "F10"), + Key::F11 => (winapi::winuser::VK_F11, "F11"), + Key::F12 => (winapi::winuser::VK_F12, "F12"), + Key::F13 => (winapi::winuser::VK_F13, "F14"), + Key::F14 => (winapi::winuser::VK_F14, "F14"), + Key::F15 => (winapi::winuser::VK_F15, "F15"), + + Key::Down => (winapi::winuser::VK_DOWN, "Down"), + Key::Left => (winapi::winuser::VK_LEFT, "Left"), + Key::Right => (winapi::winuser::VK_RIGHT, "Right"), + Key::Up => (winapi::winuser::VK_UP, "Up"), + + Key::Backslash => (winapi::winuser::VK_OEM_102, "Backslash"), + Key::Comma => (winapi::winuser::VK_OEM_COMMA, ","), + Key::Minus => (winapi::winuser::VK_OEM_MINUS, "-"), + Key::Period => (winapi::winuser::VK_OEM_PERIOD, "."), + + Key::Backspace => (winapi::winuser::VK_BACK, "Back"), + Key::Delete => (winapi::winuser::VK_DELETE, "Delete"), + Key::End => (winapi::winuser::VK_END, "End"), + Key::Enter => (winapi::winuser::VK_RETURN, "Enter"), + + Key::Escape => (winapi::winuser::VK_ESCAPE, "Esc"), + + Key::Home => (winapi::winuser::VK_HOME, "Home"), + Key::Insert => (winapi::winuser::VK_INSERT, "Insert"), + Key::Menu => (winapi::winuser::VK_MENU, "Menu"), + + Key::PageDown => (winapi::winuser::VK_NEXT, "PageDown"), + Key::PageUp => (winapi::winuser::VK_PRIOR, "PageUp"), + + Key::Pause => (winapi::winuser::VK_PAUSE, "Pause"), + Key::Space => (winapi::winuser::VK_SPACE, "Space"), + Key::Tab => (winapi::winuser::VK_TAB, "Tab"), + Key::NumLock => (winapi::winuser::VK_NUMLOCK, "NumLock"), + Key::CapsLock => (winapi::winuser::VK_CAPITAL, "CapsLock"), + Key::ScrollLock => (winapi::winuser::VK_SCROLL, "Scroll"), + + Key::LeftShift => (winapi::winuser::VK_LSHIFT, "LeftShift"), + Key::RightShift => (winapi::winuser::VK_RSHIFT, "RightShift"), + Key::LeftCtrl => (winapi::winuser::VK_CONTROL, "Ctrl"), + Key::RightCtrl => (winapi::winuser::VK_CONTROL, "Ctrl"), + + Key::NumPad0 => (winapi::winuser::VK_NUMPAD0, "NumPad0"), + Key::NumPad1 => (winapi::winuser::VK_NUMPAD1, "NumPad1"), + Key::NumPad2 => (winapi::winuser::VK_NUMPAD2, "NumPad2"), + Key::NumPad3 => (winapi::winuser::VK_NUMPAD3, "NumPad3"), + Key::NumPad4 => (winapi::winuser::VK_NUMPAD4, "NumPad4"), + Key::NumPad5 => (winapi::winuser::VK_NUMPAD5, "NumPad5"), + Key::NumPad6 => (winapi::winuser::VK_NUMPAD6, "NumPad6"), + Key::NumPad7 => (winapi::winuser::VK_NUMPAD7, "NumPad7"), + Key::NumPad8 => (winapi::winuser::VK_NUMPAD8, "NumPad8"), + Key::NumPad9 => (winapi::winuser::VK_NUMPAD9, "NumPad9"), + + Key::LeftAlt => (winapi::winuser::VK_MENU, "Alt"), + Key::RightAlt => (winapi::winuser::VK_MENU, "Alt"), + + Key::LeftSuper => (winapi::winuser::VK_LWIN, "LeftWin"), + Key::RightSuper => (winapi::winuser::VK_RWIN, "RightWin"), + + _ => (0, "Unsupported"), + } + } + + + + /* + unsafe fn add_menu_item(&mut self, parent_menu: HMENU, menu_item: &Menu) { + let item_name = to_wstring(menu_item.name); + 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()); + } + } + } + */ + + fn format_name(menu_item: &MenuItem, key_name: &'static str) -> String { + let mut name = menu_item.label.clone(); + + name.push_str("\t"); + + if (menu_item.modifier & MENU_KEY_WIN) == MENU_KEY_WIN { + name.push_str("Win-"); + } + + if (menu_item.modifier & MENU_KEY_SHIFT) == MENU_KEY_SHIFT { + name.push_str("Shift-"); + } + + if (menu_item.modifier & MENU_KEY_CTRL) == MENU_KEY_CTRL { + name.push_str("Ctrl-"); + } + + if (menu_item.modifier & MENU_KEY_ALT) == MENU_KEY_ALT { + name.push_str("Alt-"); + } + + name.push_str(key_name); + + name + } + + fn is_key_virtual_range(key: raw::c_int) -> u32 { + if (key >= 0x30 && key <= 0x30) || + (key >= 0x41 && key <= 0x5a) { + 1 + } else { + 0 + } + } + + 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 { + virt |= 0x10; + } + + if (menu_item.modifier & MENU_KEY_CTRL) == MENU_KEY_CTRL { + virt |= 0x8; + } + + if (menu_item.modifier & MENU_KEY_SHIFT) == MENU_KEY_SHIFT { + virt |= 0x4; + } + + virt + } + + 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); + let accel = winuser::ACCEL { + fVirt: virt as BYTE, + cmd: menu_item.id as WORD, + key: vk_accel.0 as WORD }; + + self.accel_table.push(accel); + } + + pub fn add_menu_item(&mut self, menu_item: &MenuItem) -> MenuItemHandle { + let vk_accel = Self::map_key_to_vk_accel(menu_item.key); + + unsafe { + 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: 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 remove_item(&mut self, _item: &MenuItemHandle) { + panic!("remove item hasn't been implemented"); + } +} + impl Drop for Window { fn drop(&mut self) { From 462effd03cd0c4fcb530b41ba0bfc483fb6a794d Mon Sep 17 00:00:00 2001 From: Daniel Collin Date: Mon, 9 May 2016 16:05:53 +0200 Subject: [PATCH 16/18] Added accel keys Fn keys doesn't seem to work yet though --- src/os/windows/mod.rs | 84 +++++++++++++++++++------------------------ 1 file changed, 36 insertions(+), 48 deletions(-) diff --git a/src/os/windows/mod.rs b/src/os/windows/mod.rs index 44c486b..82c7589 100644 --- a/src/os/windows/mod.rs +++ b/src/os/windows/mod.rs @@ -327,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, @@ -450,7 +450,7 @@ impl Window { scale_factor: scale_factor, width: width as i32, height: height as i32, - //menus: Vec::new(), + menus: Vec::new(), accel_table: ptr::null_mut(), accel_key: INVALID_ACCEL, }; @@ -735,24 +735,6 @@ impl Window { } } - 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); @@ -858,6 +840,27 @@ impl Window { } */ + 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(); @@ -874,10 +877,11 @@ impl Window { 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(self); + self.set_accel_table(); user32::DrawMenuBar(window); } @@ -901,6 +905,8 @@ impl Window { } } } + +#[derive(Clone)] pub struct Menu { menu_handle: HMENU, name: Vec, @@ -918,16 +924,6 @@ impl Menu { } } - 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()); - } - } - fn map_key_to_vk_accel(key: Key) -> (raw::c_int, &'static str) { match key { Key::Key0 => (0x30, "0"), @@ -1041,25 +1037,17 @@ impl Menu { } } - - - /* - unsafe fn add_menu_item(&mut self, parent_menu: HMENU, menu_item: &Menu) { - let item_name = to_wstring(menu_item.name); - 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()); - } + 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: &MenuItem, key_name: &'static str) -> String { let mut name = menu_item.label.clone(); From 06c7c6b05bcc44e4e72be80df92bb33ca586cdcc Mon Sep 17 00:00:00 2001 From: Daniel Collin Date: Mon, 9 May 2016 16:41:01 +0200 Subject: [PATCH 17/18] Added code for menu destroy But it doesn't work for some reason --- src/os/windows/mod.rs | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/src/os/windows/mod.rs b/src/os/windows/mod.rs index 82c7589..e5f7521 100644 --- a/src/os/windows/mod.rs +++ b/src/os/windows/mod.rs @@ -339,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 { @@ -886,13 +887,25 @@ impl Window { user32::DrawMenuBar(window); } - // TODO: Proper handle - MenuHandle(0) + MenuHandle(menu.menu_handle as u64) } - pub fn remove_menu(&mut self, _handle: MenuHandle) { + 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 { @@ -1075,13 +1088,17 @@ impl Menu { 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: &MenuItem, key: raw::c_int) -> u32 { From 57906b26b84e33d9dfb007e499bd0e1c5b5bf14d Mon Sep 17 00:00:00 2001 From: Daniel Collin Date: Mon, 9 May 2016 16:42:24 +0200 Subject: [PATCH 18/18] Removed old menu code --- src/os/windows/mod.rs | 186 ------------------------------------------ 1 file changed, 186 deletions(-) diff --git a/src/os/windows/mod.rs b/src/os/windows/mod.rs index e5f7521..ff75965 100644 --- a/src/os/windows/mod.rs +++ b/src/os/windows/mod.rs @@ -655,192 +655,6 @@ impl Window { 1); } - /* - fn format_name(menu_item: &Menu, key_name: &'static str) -> String { - let mut name = menu_item.name.to_owned(); - - name.push_str("\t"); - - if (menu_item.modifier & MENU_KEY_WIN) == MENU_KEY_WIN { - name.push_str("Win-"); - } - - if (menu_item.modifier & MENU_KEY_SHIFT) == MENU_KEY_SHIFT { - name.push_str("Shift-"); - } - - if (menu_item.modifier & MENU_KEY_CTRL) == MENU_KEY_CTRL { - name.push_str("Ctrl-"); - } - - if (menu_item.modifier & MENU_KEY_ALT) == MENU_KEY_ALT { - name.push_str("Alt-"); - } - - name.push_str(key_name); - - name - } - - fn is_key_virtual_range(key: raw::c_int) -> u32 { - if (key >= 0x30 && key <= 0x30) || - (key >= 0x41 && key <= 0x5a) { - 1 - } else { - 0 - } - } - - fn get_virt_key(menu_item: &Menu, key: raw::c_int) -> u32 { - let mut virt = Self::is_key_virtual_range(key); - - if (menu_item.modifier & MENU_KEY_ALT) == MENU_KEY_ALT { - virt |= 0x10; - } - - if (menu_item.modifier & MENU_KEY_CTRL) == MENU_KEY_CTRL { - virt |= 0x8; - } - - if (menu_item.modifier & MENU_KEY_SHIFT) == MENU_KEY_SHIFT { - virt |= 0x4; - } - - virt - } - - fn add_accel(accel_table: &mut Vec, menu_item: &Menu) { - let vk_accel = Self::map_key_to_vk_accel(menu_item.key); - let virt = Self::get_virt_key(menu_item, vk_accel.0); - let accel = winuser::ACCEL { - fVirt: virt as BYTE, - cmd: menu_item.id as WORD, - key: vk_accel.0 as WORD }; - - 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); - 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 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; - } - } - } - - // TODO: Proper return here - Ok(()) - } - */ - unsafe fn set_accel_table(&mut self) { let mut temp_accel_table = Vec::::new();