mirror of
https://github.com/italicsjenga/muda.git
synced 2024-12-23 12:01:31 +11:00
Merge branch 'feat/macOS-ns-menu' into dev
This commit is contained in:
commit
c09eab7ef2
|
@ -209,6 +209,9 @@ pub trait ContextMenu {
|
||||||
/// (the click which triggered the menu to be shown).
|
/// (the click which triggered the menu to be shown).
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
fn show_context_menu_for_nsview(&self, view: cocoa::base::id, x: f64, y: f64);
|
fn show_context_menu_for_nsview(&self, view: cocoa::base::id, x: f64, y: f64);
|
||||||
|
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
fn ns_menu(&self) -> *mut std::ffi::c_void;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Describes a menu event emitted when a menu item is activated
|
/// Describes a menu event emitted when a menu item is activated
|
||||||
|
|
|
@ -46,6 +46,11 @@ impl ContextMenu for Menu {
|
||||||
fn show_context_menu_for_nsview(&self, view: cocoa::base::id, x: f64, y: f64) {
|
fn show_context_menu_for_nsview(&self, view: cocoa::base::id, x: f64, y: f64) {
|
||||||
self.0.show_context_menu_for_nsview(view, x, y)
|
self.0.show_context_menu_for_nsview(view, x, y)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
fn ns_menu(&self) -> *mut std::ffi::c_void {
|
||||||
|
self.0.ns_menu()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Menu {
|
impl Menu {
|
||||||
|
|
|
@ -27,7 +27,7 @@ static BLOCK_PTR: &str = "mudaMenuItemBlockPtr";
|
||||||
/// A generic child in a menu
|
/// A generic child in a menu
|
||||||
///
|
///
|
||||||
/// Be careful when cloning this item and treat it as read-only
|
/// Be careful when cloning this item and treat it as read-only
|
||||||
#[derive(Debug, Default, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
struct MenuChild {
|
struct MenuChild {
|
||||||
// shared fields between submenus and menu items
|
// shared fields between submenus and menu items
|
||||||
|
@ -50,6 +50,25 @@ struct MenuChild {
|
||||||
// submenu fields
|
// submenu fields
|
||||||
children: Option<Vec<Rc<RefCell<MenuChild>>>>,
|
children: Option<Vec<Rc<RefCell<MenuChild>>>>,
|
||||||
ns_menus: HashMap<u32, Vec<id>>,
|
ns_menus: HashMap<u32, Vec<id>>,
|
||||||
|
ns_menu: (u32, id),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for MenuChild {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
type_: Default::default(),
|
||||||
|
id: Default::default(),
|
||||||
|
text: Default::default(),
|
||||||
|
enabled: Default::default(),
|
||||||
|
ns_menu_items: Default::default(),
|
||||||
|
accelerator: Default::default(),
|
||||||
|
predefined_item_type: Default::default(),
|
||||||
|
checked: Default::default(),
|
||||||
|
children: Default::default(),
|
||||||
|
ns_menus: Default::default(),
|
||||||
|
ns_menu: (0, 0 as _),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MenuChild {
|
impl MenuChild {
|
||||||
|
@ -242,6 +261,10 @@ impl Menu {
|
||||||
msg_send![self.ns_menu, popUpMenuPositioningItem: nil atLocation: location inView: view]
|
msg_send![self.ns_menu, popUpMenuPositioningItem: nil atLocation: location inView: view]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn ns_menu(&self) -> *mut std::ffi::c_void {
|
||||||
|
self.ns_menu as _
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
@ -254,6 +277,7 @@ impl Submenu {
|
||||||
text: strip_mnemonic(text),
|
text: strip_mnemonic(text),
|
||||||
enabled,
|
enabled,
|
||||||
children: Some(Vec::new()),
|
children: Some(Vec::new()),
|
||||||
|
ns_menu: (COUNTER.next(), unsafe { NSMenu::alloc(nil).autorelease() }),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})))
|
})))
|
||||||
}
|
}
|
||||||
|
@ -335,6 +359,10 @@ impl Submenu {
|
||||||
ns_menu.addItem_(ns_menu_item);
|
ns_menu.addItem_(ns_menu_item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let ns_menu_item: *mut Object = item.make_ns_item_for_menu(self_.ns_menu.0);
|
||||||
|
self_.ns_menu.1.addItem_(ns_menu_item);
|
||||||
|
|
||||||
self_.children.as_mut().unwrap().push(item_child);
|
self_.children.as_mut().unwrap().push(item_child);
|
||||||
}
|
}
|
||||||
AddOp::Insert(position) => {
|
AddOp::Insert(position) => {
|
||||||
|
@ -344,6 +372,10 @@ impl Submenu {
|
||||||
let () = msg_send![ns_menu, insertItem: ns_menu_item atIndex: position as NSInteger];
|
let () = msg_send![ns_menu, insertItem: ns_menu_item atIndex: position as NSInteger];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let ns_menu_item: *mut Object = item.make_ns_item_for_menu(self_.ns_menu.0);
|
||||||
|
let () = msg_send![ self_.ns_menu.1, insertItem: ns_menu_item atIndex: position as NSInteger];
|
||||||
|
|
||||||
self_
|
self_
|
||||||
.children
|
.children
|
||||||
.as_mut()
|
.as_mut()
|
||||||
|
@ -355,29 +387,39 @@ impl Submenu {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn remove(&self, item: &dyn crate::MenuItemExt) -> crate::Result<()> {
|
pub fn remove(&self, item: &dyn crate::MenuItemExt) -> crate::Result<()> {
|
||||||
let mut child = self.0.borrow_mut();
|
let mut self_ = self.0.borrow_mut();
|
||||||
|
|
||||||
let item_child: Rc<RefCell<MenuChild>> = item.get_child();
|
let child: Rc<RefCell<MenuChild>> = item.get_child();
|
||||||
|
|
||||||
// get a list of instances of the specified NSMenuItem in this menu
|
// get a list of instances of the specified NSMenuItem in this menu
|
||||||
if let Some(ns_menu_items) = item_child.borrow_mut().ns_menu_items.remove(&child.id) {
|
if let Some(ns_menu_items) = child.borrow_mut().ns_menu_items.remove(&self_.id) {
|
||||||
// remove each NSMenuItem from the NSMenu
|
// remove each NSMenuItem from the NSMenu
|
||||||
unsafe {
|
unsafe {
|
||||||
for item in ns_menu_items {
|
for item in ns_menu_items {
|
||||||
for menus in child.ns_menus.values() {
|
for menus in self_.ns_menus.values() {
|
||||||
for &ns_menu in menus {
|
for &ns_menu in menus {
|
||||||
let () = msg_send![ns_menu, removeItem: item];
|
let () = msg_send![ns_menu, removeItem: item];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let () = msg_send![self_.ns_menu.1, removeItem: item];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(ns_menu_items) = child.borrow_mut().ns_menu_items.remove(&self_.ns_menu.0) {
|
||||||
|
unsafe {
|
||||||
|
for item in ns_menu_items {
|
||||||
|
let () = msg_send![self_.ns_menu.1, removeItem: item];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// remove the item from our internal list of children
|
// remove the item from our internal list of children
|
||||||
let children = child.children.as_mut().unwrap();
|
let children = self_.children.as_mut().unwrap();
|
||||||
let index = children
|
let index = children
|
||||||
.iter()
|
.iter()
|
||||||
.position(|e| e == &item_child)
|
.position(|e| e == &child)
|
||||||
.ok_or(crate::Error::NotAChildOfThisMenu)?;
|
.ok_or(crate::Error::NotAChildOfThisMenu)?;
|
||||||
children.remove(index);
|
children.remove(index);
|
||||||
|
|
||||||
|
@ -422,29 +464,26 @@ impl Submenu {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn show_context_menu_for_nsview(&self, view: id, x: f64, y: f64) {
|
pub fn show_context_menu_for_nsview(&self, view: id, x: f64, y: f64) {
|
||||||
// TODO: this needs to work even if it hasn't already been added to a menu
|
unsafe {
|
||||||
if let Some(ns_menus) = self.0.borrow().ns_menus.get(&1) {
|
let window: id = msg_send![view, window];
|
||||||
unsafe {
|
let scale_factor: CGFloat = msg_send![window, backingScaleFactor];
|
||||||
let window: id = msg_send![view, window];
|
let view_point = NSPoint::new(x / scale_factor, y / scale_factor);
|
||||||
let scale_factor: CGFloat = msg_send![window, backingScaleFactor];
|
let view_rect: NSRect = msg_send![view, frame];
|
||||||
let view_point = NSPoint::new(x / scale_factor, y / scale_factor);
|
let location = NSPoint::new(view_point.x, view_rect.size.height - view_point.y);
|
||||||
let view_rect: NSRect = msg_send![view, frame];
|
msg_send![self.0.borrow().ns_menu.1, popUpMenuPositioningItem: nil atLocation: location inView: view]
|
||||||
let location = NSPoint::new(view_point.x, view_rect.size.height - view_point.y);
|
|
||||||
msg_send![ns_menus[0], popUpMenuPositioningItem: nil atLocation: location inView: view]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_windows_menu_for_nsapp(&self) {
|
pub fn set_windows_menu_for_nsapp(&self) {
|
||||||
if let Some(ns_menus) = self.0.borrow().ns_menus.get(&1) {
|
unsafe { NSApp().setWindowsMenu_(self.0.borrow().ns_menu.1) }
|
||||||
unsafe { NSApp().setWindowsMenu_(ns_menus[0]) }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_help_menu_for_nsapp(&self) {
|
pub fn set_help_menu_for_nsapp(&self) {
|
||||||
if let Some(ns_menus) = self.0.borrow().ns_menus.get(&1) {
|
unsafe { msg_send![NSApp(), setHelpMenu: self.0.borrow().ns_menu.1] }
|
||||||
unsafe { msg_send![NSApp(), setHelpMenu: ns_menus[0]] }
|
}
|
||||||
}
|
|
||||||
|
pub fn ns_menu(&self) -> *mut std::ffi::c_void {
|
||||||
|
self.0.borrow().ns_menu.1 as _
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -54,6 +54,11 @@ impl ContextMenu for Submenu {
|
||||||
fn show_context_menu_for_nsview(&self, view: cocoa::base::id, x: f64, y: f64) {
|
fn show_context_menu_for_nsview(&self, view: cocoa::base::id, x: f64, y: f64) {
|
||||||
self.0.show_context_menu_for_nsview(view, x, y)
|
self.0.show_context_menu_for_nsview(view, x, y)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
fn ns_menu(&self) -> *mut std::ffi::c_void {
|
||||||
|
self.0.ns_menu()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Submenu {
|
impl Submenu {
|
||||||
|
|
Loading…
Reference in a new issue