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); + } + } +} + + +