use objc2::rc::Retained;
use objc2::runtime::Sel;
use objc2::sel;
use objc2_app_kit::{NSApplication, NSEventModifierFlags, NSMenu, NSMenuItem};
use objc2_foundation::{MainThreadMarker, NSString};
struct Item {
title: String,
action: Sel,
key: &'static str,
mask: NSEventModifierFlags,
}
fn item(mtm: MainThreadMarker, spec: &Item) -> Retained<NSMenuItem> {
let it = NSMenuItem::new(mtm);
it.setTitle(&NSString::from_str(&spec.title));
unsafe { it.setAction(Some(spec.action)) };
it.setKeyEquivalent(&NSString::from_str(spec.key));
it.setKeyEquivalentModifierMask(spec.mask);
it
}
fn menu(mtm: MainThreadMarker, title: &str, items: &[Option<Item>]) -> Retained<NSMenu> {
let m = NSMenu::new(mtm);
m.setTitle(&NSString::from_str(title));
for spec in items {
match spec {
Some(spec) => m.addItem(&item(mtm, spec)),
None => m.addItem(&NSMenuItem::separatorItem(mtm)),
}
}
m
}
fn cmd(title: impl Into<String>, action: Sel, key: &'static str) -> Option<Item> {
Some(Item {
title: title.into(),
action,
key,
mask: NSEventModifierFlags::Command,
})
}
pub fn install_main_menu(app: &NSApplication, mtm: MainThreadMarker, name: &str) {
let app_menu = menu(
mtm,
name,
&[
cmd(format!("Hide {name}"), sel!(hide:), "h"),
Some(Item {
title: "Hide Others".into(),
action: sel!(hideOtherApplications:),
key: "h",
mask: NSEventModifierFlags::Command | NSEventModifierFlags::Option,
}),
cmd("Show All", sel!(unhideAllApplications:), ""),
None,
cmd(format!("Quit {name}"), sel!(terminate:), "q"),
],
);
let edit = menu(
mtm,
"Edit",
&[
cmd("Copy", sel!(copy:), "c"),
cmd("Paste", sel!(paste:), "v"),
],
);
let view = menu(
mtm,
"View",
&[
cmd("Bigger", sel!(zoomIn:), "+"),
cmd("Smaller", sel!(zoomOut:), "-"),
cmd("Actual Size", sel!(zoomActual:), "0"),
],
);
let window = menu(
mtm,
"Window",
&[
cmd("Minimize", sel!(performMiniaturize:), "m"),
cmd("Zoom", sel!(performZoom:), ""),
None,
cmd("Close", sel!(performClose:), "w"),
],
);
let bar = NSMenu::new(mtm);
for sub in [&app_menu, &edit, &view, &window] {
let holder = NSMenuItem::new(mtm);
holder.setSubmenu(Some(sub));
bar.addItem(&holder);
}
app.setMainMenu(Some(&bar));
app.setWindowsMenu(Some(&window));
}