Skip to content

Instantly share code, notes, and snippets.

@marksands
Last active April 21, 2022 18:13
Show Gist options
  • Save marksands/8c7059d30834ac080f0740c83b2a77d6 to your computer and use it in GitHub Desktop.
Save marksands/8c7059d30834ac080f0740c83b2a77d6 to your computer and use it in GitHub Desktop.
AppKit NSMenu Helper
import AppKit
public struct MenuHotKeyPress: ExpressibleByStringLiteral {
public let character: String
public let modifierKeys: NSEvent.ModifierFlags?
public init(stringLiteral value: String) {
character = value
modifierKeys = nil
}
fileprivate init() {
character = ""
modifierKeys = nil
}
private init(_ character: String, _ modifierKeys: NSEvent.ModifierFlags) {
self.character = character
self.modifierKeys = modifierKeys
}
public static func +(_ lhs: MenuHotKeyPress, _ rhs: NSEvent.ModifierFlags) -> MenuHotKeyPress {
return MenuHotKeyPress(lhs.character, rhs)
}
}
public enum NSAppEvent {
case about
case hide
case hideOthers
case unhideOthers
case terminate
fileprivate var target: NSApplication {
return NSApp
}
fileprivate var selector: Selector {
switch self {
case .about:
return #selector(NSApp.orderFrontStandardAboutPanel(_:))
case .hide:
return #selector(NSApp.hide(_:))
case .hideOthers:
return #selector(NSApp.hideOtherApplications(_:))
case .unhideOthers:
return #selector(NSApp.unhideAllApplications(_:))
case .terminate:
return #selector(NSApp.terminate(_:))
}
}
fileprivate var keyPress: MenuHotKeyPress {
switch self {
case .about: return ""
case .hide: return "h" + .command
case .hideOthers: return "h" + [.option, .command]
case .unhideOthers: return ""
case .terminate: return "q" + .command
}
}
}
public struct MenuItem {
private let menuItem: NSMenuItem
public var item: NSMenuItem {
return menuItem
}
public init(title: String) {
self.init(title: title, target: nil, action: nil, key: MenuHotKeyPress())
}
public init(title: String, target: AnyObject?, action: Selector?) {
self.init(title: title, target: target, action: action, key: MenuHotKeyPress())
}
public init(title: String, appKitEvent: NSAppEvent) {
self.init(title: title, target: appKitEvent.target, action: appKitEvent.selector, key: appKitEvent.keyPress)
}
public init(title: String, target: AnyObject?, action: Selector?, key: MenuHotKeyPress) {
menuItem = NSMenuItem(title: title, action: action, keyEquivalent: key.character)
menuItem.target = target
if let modifier = key.modifierKeys {
menuItem.keyEquivalentModifierMask = modifier
}
}
private init(menuItem: NSMenuItem) {
self.menuItem = menuItem
}
public static var separator: MenuItem {
return MenuItem(menuItem: .separator())
}
}
public struct MainMenu {
public let main = NSMenu(title: "Application Menu")
public init(title: String, menuItems: [MenuItem] = []) {
MainMenu.appendSubmenu(to: main, title: title, menuItems: menuItems)
}
public func addSubmenu(withTitle title: String, menuItems: [MenuItem]) {
MainMenu.appendSubmenu(to: main, title: title, menuItems: menuItems)
}
private static func appendSubmenu(to menu: NSMenu, title: String, menuItems: [MenuItem]) {
let subMenuItem = menu.addItem(withTitle: title, action: nil, keyEquivalent: "")
let subMenu = NSMenu(title: title)
menuItems.forEach { menuItem in
subMenu.addItem(menuItem.item)
}
menu.setSubmenu(subMenu, for: subMenuItem)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment