forked from SideStore/SideServer-macOS
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathMenuController.swift
More file actions
115 lines (93 loc) · 2.76 KB
/
MenuController.swift
File metadata and controls
115 lines (93 loc) · 2.76 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
//
// MenuController.swift
// AltServer
//
// Created by Riley Testut on 3/3/21.
// Copyright © 2021 Riley Testut. All rights reserved.
//
import Foundation
import AppKit
protocol MenuDisplayable
{
var name: String { get }
}
class MenuController<T: MenuDisplayable & Hashable>: NSObject, NSMenuDelegate
{
let menu: NSMenu
var items: [T] {
didSet {
self.submenus.removeAll()
self.updateMenu()
}
}
var placeholder: String? {
didSet {
self.updateMenu()
}
}
var action: ((T) -> Void)?
var submenuHandler: ((T) -> NSMenu)?
private var submenus = [T: NSMenu]()
init(menu: NSMenu, items: [T])
{
self.menu = menu
self.items = items
super.init()
self.menu.delegate = self
}
@objc
private func performAction(_ menuItem: NSMenuItem)
{
guard case let index = self.menu.index(of: menuItem), index != -1 else { return }
let item = self.items[index]
self.action?(item)
}
@objc
func numberOfItems(in menu: NSMenu) -> Int
{
let numberOfItems = (self.items.isEmpty && self.placeholder != nil) ? 1 : self.items.count
return numberOfItems
}
@objc
func menu(_ menu: NSMenu, update menuItem: NSMenuItem, at index: Int, shouldCancel: Bool) -> Bool
{
if let text = self.placeholder, self.items.isEmpty
{
menuItem.title = text
menuItem.isEnabled = false
menuItem.target = nil
menuItem.action = nil
}
else
{
let item = self.items[index]
menuItem.title = item.name
menuItem.isEnabled = true
menuItem.target = self
menuItem.action = #selector(MenuController.performAction(_:))
menuItem.tag = index
if let submenu = self.submenus[item] ?? self.submenuHandler?(item)
{
menuItem.submenu = submenu
// Cache submenu to prevent duplicate calls to submenuHandler.
self.submenus[item] = submenu
}
}
return true
}
}
private extension MenuController
{
func updateMenu()
{
self.menu.removeAllItems()
let numberOfItems = self.numberOfItems(in: self.menu)
for index in 0 ..< numberOfItems
{
let menuItem = NSMenuItem(title: "", action: nil, keyEquivalent: "")
guard self.menu(self.menu, update: menuItem, at: index, shouldCancel: false) else { break }
self.menu.addItem(menuItem)
}
self.menu.update()
}
}