add dedicated ns_menu for context menus and such

This commit is contained in:
amrbashir 2022-11-26 15:13:30 +02:00
parent 37153b826f
commit 35912d699d
No known key found for this signature in database
GPG key ID: BBD7A47A2003FF33

View file

@ -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 {
@ -258,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()
}))) })))
} }
@ -339,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) => {
@ -348,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()
@ -359,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);
@ -426,42 +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
if let Some(ns_menus) = self.0.borrow().ns_menus.get(&1) {
unsafe { unsafe {
let window: id = msg_send![view, window]; let window: id = msg_send![view, window];
let scale_factor: CGFloat = msg_send![window, backingScaleFactor]; let scale_factor: CGFloat = msg_send![window, backingScaleFactor];
let view_point = NSPoint::new(x / scale_factor, y / scale_factor); let view_point = NSPoint::new(x / scale_factor, y / scale_factor);
let view_rect: NSRect = msg_send![view, frame]; let view_rect: NSRect = msg_send![view, frame];
let location = NSPoint::new(view_point.x, view_rect.size.height - view_point.y); 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] msg_send![self.0.borrow().ns_menu.1, 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 { pub fn ns_menu(&self) -> *mut std::ffi::c_void {
*self self.0.borrow().ns_menu.1 as _
.0
.borrow()
.ns_menus
.values()
.collect::<Vec<_>>()
.get(0)
.unwrap()
.get(0)
.unwrap() as _
} }
} }