Refactor menuitem views
This commit is contained in:
parent
9ad3565242
commit
c2ba79c543
@ -58,6 +58,7 @@
|
|||||||
F9203A26236342820020D57D /* AppDelegate+..swift in Sources */ = {isa = PBXBuildFile; fileRef = F9203A25236342820020D57D /* AppDelegate+..swift */; };
|
F9203A26236342820020D57D /* AppDelegate+..swift in Sources */ = {isa = PBXBuildFile; fileRef = F9203A25236342820020D57D /* AppDelegate+..swift */; };
|
||||||
F92D0B24236BC12000575E15 /* SavedProxyModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = F92D0B23236BC12000575E15 /* SavedProxyModel.swift */; };
|
F92D0B24236BC12000575E15 /* SavedProxyModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = F92D0B23236BC12000575E15 /* SavedProxyModel.swift */; };
|
||||||
F92D0B2A236C759100575E15 /* NSTextField+Vibrancy.swift in Sources */ = {isa = PBXBuildFile; fileRef = F92D0B29236C759100575E15 /* NSTextField+Vibrancy.swift */; };
|
F92D0B2A236C759100575E15 /* NSTextField+Vibrancy.swift in Sources */ = {isa = PBXBuildFile; fileRef = F92D0B29236C759100575E15 /* NSTextField+Vibrancy.swift */; };
|
||||||
|
F92D0B2C236C7C3600575E15 /* MenuItemBaseView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F92D0B2B236C7C3600575E15 /* MenuItemBaseView.swift */; };
|
||||||
F935B2F02307C52E009E4D33 /* com.west2online.ClashX.ProxyConfigHelper in Copy Files */ = {isa = PBXBuildFile; fileRef = F9A7C0692306E874007163C7 /* com.west2online.ClashX.ProxyConfigHelper */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
|
F935B2F02307C52E009E4D33 /* com.west2online.ClashX.ProxyConfigHelper in Copy Files */ = {isa = PBXBuildFile; fileRef = F9A7C0692306E874007163C7 /* com.west2online.ClashX.ProxyConfigHelper */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
|
||||||
F935B2F42307CD32009E4D33 /* ProxyConfigHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = F935B2F32307CD32009E4D33 /* ProxyConfigHelper.m */; };
|
F935B2F42307CD32009E4D33 /* ProxyConfigHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = F935B2F32307CD32009E4D33 /* ProxyConfigHelper.m */; };
|
||||||
F935B2FA23083EE6009E4D33 /* ProxySettingTool.m in Sources */ = {isa = PBXBuildFile; fileRef = F935B2F923083EE6009E4D33 /* ProxySettingTool.m */; };
|
F935B2FA23083EE6009E4D33 /* ProxySettingTool.m in Sources */ = {isa = PBXBuildFile; fileRef = F935B2F923083EE6009E4D33 /* ProxySettingTool.m */; };
|
||||||
@ -166,6 +167,7 @@
|
|||||||
F9203A25236342820020D57D /* AppDelegate+..swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AppDelegate+..swift"; sourceTree = "<group>"; };
|
F9203A25236342820020D57D /* AppDelegate+..swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AppDelegate+..swift"; sourceTree = "<group>"; };
|
||||||
F92D0B23236BC12000575E15 /* SavedProxyModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SavedProxyModel.swift; sourceTree = "<group>"; };
|
F92D0B23236BC12000575E15 /* SavedProxyModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SavedProxyModel.swift; sourceTree = "<group>"; };
|
||||||
F92D0B29236C759100575E15 /* NSTextField+Vibrancy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSTextField+Vibrancy.swift"; sourceTree = "<group>"; };
|
F92D0B29236C759100575E15 /* NSTextField+Vibrancy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSTextField+Vibrancy.swift"; sourceTree = "<group>"; };
|
||||||
|
F92D0B2B236C7C3600575E15 /* MenuItemBaseView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuItemBaseView.swift; sourceTree = "<group>"; };
|
||||||
F935B2EA2307B6BA009E4D33 /* Helper-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "Helper-Info.plist"; sourceTree = "<group>"; };
|
F935B2EA2307B6BA009E4D33 /* Helper-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "Helper-Info.plist"; sourceTree = "<group>"; };
|
||||||
F935B2F12307C802009E4D33 /* Helper-Launchd.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Helper-Launchd.plist"; sourceTree = "<group>"; };
|
F935B2F12307C802009E4D33 /* Helper-Launchd.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Helper-Launchd.plist"; sourceTree = "<group>"; };
|
||||||
F935B2F22307CD32009E4D33 /* ProxyConfigHelper.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ProxyConfigHelper.h; sourceTree = "<group>"; };
|
F935B2F22307CD32009E4D33 /* ProxyConfigHelper.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ProxyConfigHelper.h; sourceTree = "<group>"; };
|
||||||
@ -281,6 +283,7 @@
|
|||||||
499A485922ED781100F6C675 /* RemoteConfigAddView.xib */,
|
499A485922ED781100F6C675 /* RemoteConfigAddView.xib */,
|
||||||
49D176A8235614340093DD7B /* ProxyGroupSpeedTestMenuItem.swift */,
|
49D176A8235614340093DD7B /* ProxyGroupSpeedTestMenuItem.swift */,
|
||||||
49D176AA23575BB20093DD7B /* ProxyGroupMenuItemView.swift */,
|
49D176AA23575BB20093DD7B /* ProxyGroupMenuItemView.swift */,
|
||||||
|
F92D0B2B236C7C3600575E15 /* MenuItemBaseView.swift */,
|
||||||
);
|
);
|
||||||
path = Views;
|
path = Views;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -638,6 +641,7 @@
|
|||||||
F976275C23634DF8000EDEFE /* LoginServiceKit.swift in Sources */,
|
F976275C23634DF8000EDEFE /* LoginServiceKit.swift in Sources */,
|
||||||
4966E9E6211824F300A391FB /* NSImage+extension.swift in Sources */,
|
4966E9E6211824F300A391FB /* NSImage+extension.swift in Sources */,
|
||||||
49B1086A216A356D0064FFCE /* String+Extension.swift in Sources */,
|
49B1086A216A356D0064FFCE /* String+Extension.swift in Sources */,
|
||||||
|
F92D0B2C236C7C3600575E15 /* MenuItemBaseView.swift in Sources */,
|
||||||
4960A6DB2136529200B940C9 /* JSBridgeHandler.swift in Sources */,
|
4960A6DB2136529200B940C9 /* JSBridgeHandler.swift in Sources */,
|
||||||
493AEAE5221AE7230016FE98 /* ProxyMenuItem.swift in Sources */,
|
493AEAE5221AE7230016FE98 /* ProxyMenuItem.swift in Sources */,
|
||||||
499A485E22ED9B7C00F6C675 /* NSTableView+Reload.swift in Sources */,
|
499A485E22ED9B7C00F6C675 /* NSTableView+Reload.swift in Sources */,
|
||||||
|
161
ClashX/Views/MenuItemBaseView.swift
Normal file
161
ClashX/Views/MenuItemBaseView.swift
Normal file
@ -0,0 +1,161 @@
|
|||||||
|
//
|
||||||
|
// MenuItemBaseView.swift
|
||||||
|
// ClashX
|
||||||
|
//
|
||||||
|
// Created by yicheng on 2019/11/1.
|
||||||
|
// Copyright © 2019 west2online. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Cocoa
|
||||||
|
import Carbon
|
||||||
|
|
||||||
|
class MenuItemBaseView: NSView {
|
||||||
|
|
||||||
|
private var isMouseInsideView = false
|
||||||
|
private var isMenuOpen = false
|
||||||
|
private var eventHandler: EventHandlerRef?
|
||||||
|
private let handleClick: Bool
|
||||||
|
private let autolayout: Bool
|
||||||
|
|
||||||
|
// MARK: Public
|
||||||
|
var isHighlighted: Bool {
|
||||||
|
if #available(macOS 10.15.1, *) {
|
||||||
|
return isMouseInsideView || isMenuOpen
|
||||||
|
} else {
|
||||||
|
return enclosingMenuItem?.isHighlighted ?? false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let effectView: NSVisualEffectView = {
|
||||||
|
let effectView = NSVisualEffectView()
|
||||||
|
effectView.material = .popover
|
||||||
|
effectView.state = .active
|
||||||
|
effectView.isEmphasized = true
|
||||||
|
effectView.blendingMode = .behindWindow
|
||||||
|
return effectView
|
||||||
|
}()
|
||||||
|
|
||||||
|
static let labelFont = NSFont.menuFont(ofSize: 14)
|
||||||
|
|
||||||
|
init(frame frameRect: NSRect = .zero, handleClick:Bool, autolayout:Bool) {
|
||||||
|
self.handleClick = handleClick
|
||||||
|
self.autolayout = autolayout
|
||||||
|
super.init(frame: frameRect)
|
||||||
|
setupView()
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder: NSCoder) {
|
||||||
|
fatalError("init(coder:) has not been implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
func setNeedsDisplay() {
|
||||||
|
setNeedsDisplay(bounds)
|
||||||
|
}
|
||||||
|
|
||||||
|
func didClickView() {
|
||||||
|
assertionFailure("Please override this method")
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateBackground(_ label: NSTextField) {
|
||||||
|
label.cell?.backgroundStyle = isHighlighted ? .emphasized : .normal
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: Private
|
||||||
|
private func setupView() {
|
||||||
|
translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
heightAnchor.constraint(equalToConstant: 20).isActive = true
|
||||||
|
// background
|
||||||
|
addSubview(effectView)
|
||||||
|
effectView.translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
effectView.leftAnchor.constraint(equalTo: leftAnchor).isActive = true
|
||||||
|
effectView.rightAnchor.constraint(equalTo: rightAnchor).isActive = true
|
||||||
|
effectView.topAnchor.constraint(equalTo: topAnchor).isActive = true
|
||||||
|
effectView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private func updateCarbon() {
|
||||||
|
if window != nil {
|
||||||
|
if let dispatcher = GetEventDispatcherTarget() {
|
||||||
|
let eventHandlerCallback: EventHandlerUPP = { eventHandlerCallRef, eventRef, userData in
|
||||||
|
guard let userData = userData else { return 0 }
|
||||||
|
let itemView: MenuItemBaseView = bridge(ptr: userData)
|
||||||
|
itemView.didClickView()
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
let eventSpecs = [EventTypeSpec(eventClass: OSType(kEventClassMouse), eventKind: UInt32(kEventMouseUp))]
|
||||||
|
|
||||||
|
InstallEventHandler(dispatcher, eventHandlerCallback, 1, eventSpecs, bridge(obj: self), &eventHandler)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
RemoveEventHandler(eventHandler)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// MARK: Override
|
||||||
|
|
||||||
|
override func draw(_ dirtyRect: NSRect) {
|
||||||
|
super.draw(dirtyRect)
|
||||||
|
effectView.material = isHighlighted ? .selection : .popover
|
||||||
|
}
|
||||||
|
|
||||||
|
override func viewDidMoveToWindow() {
|
||||||
|
super.viewDidMoveToWindow()
|
||||||
|
if handleClick {
|
||||||
|
updateCarbon()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override func viewDidMoveToSuperview() {
|
||||||
|
super.viewDidMoveToSuperview()
|
||||||
|
guard autolayout else { return }
|
||||||
|
if #available(macOS 10.15, *) {} else {
|
||||||
|
if let view = superview {
|
||||||
|
view.autoresizingMask = [.width]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override func updateTrackingAreas() {
|
||||||
|
super.updateTrackingAreas()
|
||||||
|
if #available(macOS 10.15.1, *) {
|
||||||
|
trackingAreas.forEach { removeTrackingArea($0) }
|
||||||
|
enclosingMenuItem?.submenu?.delegate = self
|
||||||
|
addTrackingArea(NSTrackingArea(rect: bounds, options: [.mouseEnteredAndExited, .activeAlways], owner: self, userInfo: nil))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override func mouseEntered(with event: NSEvent) {
|
||||||
|
if #available(macOS 10.15.1, *) {
|
||||||
|
isMouseInsideView = true
|
||||||
|
setNeedsDisplay()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override func mouseExited(with event: NSEvent) {
|
||||||
|
if #available(macOS 10.15.1, *) {
|
||||||
|
isMouseInsideView = false
|
||||||
|
setNeedsDisplay()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension MenuItemBaseView: NSMenuDelegate {
|
||||||
|
func menuWillOpen(_ menu: NSMenu) {
|
||||||
|
if #available(macOS 10.15.1, *) {
|
||||||
|
isMenuOpen = true
|
||||||
|
setNeedsDisplay()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func menuDidClose(_ menu: NSMenu) {
|
||||||
|
if #available(macOS 10.15.1, *) {
|
||||||
|
isMenuOpen = false
|
||||||
|
setNeedsDisplay()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -8,40 +8,16 @@
|
|||||||
|
|
||||||
import Cocoa
|
import Cocoa
|
||||||
|
|
||||||
class ProxyGroupMenuItemView: NSView {
|
class ProxyGroupMenuItemView: MenuItemBaseView {
|
||||||
let groupNameLabel: NSTextField
|
let groupNameLabel: NSTextField
|
||||||
let selectProxyLabel: NSTextField
|
let selectProxyLabel: NSTextField
|
||||||
let arrowLabel = NSTextField(labelWithString: "▶")
|
let arrowLabel = NSTextField(labelWithString: "▶")
|
||||||
var isMouseInsideView = false
|
|
||||||
var isMenuOpen = false
|
|
||||||
let effectView: NSVisualEffectView = {
|
|
||||||
let effectView = NSVisualEffectView()
|
|
||||||
effectView.material = .popover
|
|
||||||
effectView.state = .active
|
|
||||||
effectView.isEmphasized = true
|
|
||||||
effectView.blendingMode = .behindWindow
|
|
||||||
return effectView
|
|
||||||
}()
|
|
||||||
|
|
||||||
init(group: ClashProxyName, targetProxy: ClashProxyName) {
|
init(group: ClashProxyName, targetProxy: ClashProxyName) {
|
||||||
groupNameLabel = VibrancyTextField(labelWithString: group)
|
groupNameLabel = VibrancyTextField(labelWithString: group)
|
||||||
selectProxyLabel = VibrancyTextField(labelWithString: targetProxy)
|
selectProxyLabel = VibrancyTextField(labelWithString: targetProxy)
|
||||||
if #available(macOS 10.15, *) {
|
let rect = NSRect(x: 0, y: 0, width: 0, height: 20) // requeie for system before 10.15
|
||||||
super.init(frame: .zero)
|
super.init(frame: rect, handleClick:false, autolayout: true)
|
||||||
} else {
|
|
||||||
super.init(frame: NSRect(x: 0, y: 0, width: 0, height: 20))
|
|
||||||
}
|
|
||||||
// self
|
|
||||||
translatesAutoresizingMaskIntoConstraints = false
|
|
||||||
heightAnchor.constraint(equalToConstant: 20).isActive = true
|
|
||||||
|
|
||||||
// background
|
|
||||||
addSubview(effectView)
|
|
||||||
effectView.translatesAutoresizingMaskIntoConstraints = false
|
|
||||||
effectView.leftAnchor.constraint(equalTo: leftAnchor).isActive = true
|
|
||||||
effectView.rightAnchor.constraint(equalTo: rightAnchor).isActive = true
|
|
||||||
effectView.topAnchor.constraint(equalTo: topAnchor).isActive = true
|
|
||||||
effectView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
|
|
||||||
|
|
||||||
// arrow
|
// arrow
|
||||||
effectView.addSubview(arrowLabel)
|
effectView.addSubview(arrowLabel)
|
||||||
@ -54,9 +30,9 @@ class ProxyGroupMenuItemView: NSView {
|
|||||||
effectView.addSubview(groupNameLabel)
|
effectView.addSubview(groupNameLabel)
|
||||||
groupNameLabel.leftAnchor.constraint(equalTo: effectView.leftAnchor, constant: 20).isActive = true
|
groupNameLabel.leftAnchor.constraint(equalTo: effectView.leftAnchor, constant: 20).isActive = true
|
||||||
groupNameLabel.centerYAnchor.constraint(equalTo: effectView.centerYAnchor).isActive = true
|
groupNameLabel.centerYAnchor.constraint(equalTo: effectView.centerYAnchor).isActive = true
|
||||||
|
|
||||||
// select
|
// select
|
||||||
selectProxyLabel.translatesAutoresizingMaskIntoConstraints = false
|
selectProxyLabel.translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
|
||||||
effectView.addSubview(selectProxyLabel)
|
effectView.addSubview(selectProxyLabel)
|
||||||
selectProxyLabel.rightAnchor.constraint(equalTo: effectView.rightAnchor, constant: -30).isActive = true
|
selectProxyLabel.rightAnchor.constraint(equalTo: effectView.rightAnchor, constant: -30).isActive = true
|
||||||
selectProxyLabel.centerYAnchor.constraint(equalTo: effectView.centerYAnchor).isActive = true
|
selectProxyLabel.centerYAnchor.constraint(equalTo: effectView.centerYAnchor).isActive = true
|
||||||
@ -64,13 +40,11 @@ class ProxyGroupMenuItemView: NSView {
|
|||||||
// space
|
// space
|
||||||
selectProxyLabel.leftAnchor.constraint(greaterThanOrEqualTo: groupNameLabel.rightAnchor, constant: 30).isActive = true
|
selectProxyLabel.leftAnchor.constraint(greaterThanOrEqualTo: groupNameLabel.rightAnchor, constant: 30).isActive = true
|
||||||
|
|
||||||
// font
|
// font & color
|
||||||
let font = NSFont.menuFont(ofSize: 14)
|
groupNameLabel.font = type(of: self).labelFont
|
||||||
groupNameLabel.font = font
|
selectProxyLabel.font = type(of: self).labelFont
|
||||||
selectProxyLabel.font = font
|
|
||||||
|
|
||||||
groupNameLabel.textColor = NSColor.labelColor
|
groupNameLabel.textColor = NSColor.labelColor
|
||||||
selectProxyLabel.textColor = NSColor.secondaryLabelColor
|
selectProxyLabel.textColor = NSColor.tertiaryLabelColor
|
||||||
arrowLabel.textColor = NSColor.labelColor
|
arrowLabel.textColor = NSColor.labelColor
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,69 +52,13 @@ class ProxyGroupMenuItemView: NSView {
|
|||||||
fatalError("init(coder:) has not been implemented")
|
fatalError("init(coder:) has not been implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
override func updateTrackingAreas() {
|
|
||||||
super.updateTrackingAreas()
|
|
||||||
if #available(macOS 10.15.1, *) {
|
|
||||||
trackingAreas.forEach { removeTrackingArea($0) }
|
|
||||||
enclosingMenuItem?.submenu?.delegate = self
|
|
||||||
addTrackingArea(NSTrackingArea(rect: bounds, options: [.mouseEnteredAndExited, .activeAlways], owner: self, userInfo: nil))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override func viewDidMoveToSuperview() {
|
|
||||||
super.viewDidMoveToSuperview()
|
|
||||||
if #available(macOS 10.15, *) {} else {
|
|
||||||
if let view = superview {
|
|
||||||
view.autoresizingMask = [.width]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override func mouseEntered(with event: NSEvent) {
|
|
||||||
if #available(macOS 10.15.1, *) {
|
|
||||||
isMouseInsideView = true
|
|
||||||
setNeedsDisplay(bounds)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override func mouseExited(with event: NSEvent) {
|
|
||||||
if #available(macOS 10.15.1, *) {
|
|
||||||
isMouseInsideView = false
|
|
||||||
setNeedsDisplay(bounds)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override func draw(_ dirtyRect: NSRect) {
|
override func draw(_ dirtyRect: NSRect) {
|
||||||
super.draw(dirtyRect)
|
super.draw(dirtyRect)
|
||||||
guard let menu = enclosingMenuItem else { return }
|
updateBackground(groupNameLabel)
|
||||||
let isHighlighted: Bool
|
updateBackground(selectProxyLabel)
|
||||||
if #available(macOS 10.15.1, *) {
|
updateBackground(arrowLabel)
|
||||||
isHighlighted = isMouseInsideView || isMenuOpen
|
|
||||||
} else {
|
|
||||||
isHighlighted = menu.isHighlighted
|
|
||||||
}
|
|
||||||
let labelBgStyle: NSView.BackgroundStyle = isHighlighted ? .emphasized : .normal
|
|
||||||
groupNameLabel.cell?.backgroundStyle = labelBgStyle
|
|
||||||
selectProxyLabel.cell?.backgroundStyle = labelBgStyle
|
|
||||||
arrowLabel.cell?.backgroundStyle = labelBgStyle
|
|
||||||
effectView.material = isHighlighted ? .selection : .popover
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension ProxyGroupMenuItemView: NSMenuDelegate {
|
|
||||||
func menuWillOpen(_ menu: NSMenu) {
|
|
||||||
if #available(macOS 10.15.1, *) {
|
|
||||||
isMenuOpen = true
|
|
||||||
setNeedsDisplay(bounds)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func menuDidClose(_ menu: NSMenu) {
|
|
||||||
if #available(macOS 10.15.1, *) {
|
|
||||||
isMenuOpen = false
|
|
||||||
setNeedsDisplay(bounds)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -41,27 +41,28 @@ class ProxyGroupSpeedTestMenuItem: NSMenuItem {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fileprivate class ProxyGroupSpeedTestMenuItemView: NSView {
|
fileprivate class ProxyGroupSpeedTestMenuItemView: MenuItemBaseView {
|
||||||
private let label: NSTextField
|
private let label: NSTextField
|
||||||
private let font = NSFont.menuFont(ofSize: 14)
|
|
||||||
private var isMouseInsideView = false
|
|
||||||
private var eventHandler: EventHandlerRef?
|
|
||||||
|
|
||||||
init(_ title: String) {
|
init(_ title: String) {
|
||||||
label = NSTextField(labelWithString: title)
|
label = NSTextField(labelWithString: title)
|
||||||
label.font = font
|
label.font = Self.labelFont
|
||||||
label.sizeToFit()
|
label.sizeToFit()
|
||||||
super.init(frame: NSRect(x: 0, y: 0, width: label.bounds.width + 40, height: 20))
|
let rect = NSRect(x: 0, y: 0, width: label.bounds.width + 40, height: 20)
|
||||||
translatesAutoresizingMaskIntoConstraints = false
|
super.init(frame: rect, handleClick: true, autolayout: false)
|
||||||
heightAnchor.constraint(equalToConstant: 20).isActive = true
|
|
||||||
addSubview(label)
|
addSubview(label)
|
||||||
label.frame = NSRect(x: 20, y: 0, width: label.bounds.width, height: 20)
|
label.frame = NSRect(x: 20, y: 0, width: label.bounds.width, height: 20)
|
||||||
|
label.textColor = NSColor.labelColor
|
||||||
}
|
}
|
||||||
|
|
||||||
required init?(coder: NSCoder) {
|
required init?(coder: NSCoder) {
|
||||||
fatalError("init(coder:) has not been implemented")
|
fatalError("init(coder:) has not been implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override func didClickView() {
|
||||||
|
startBenchmark()
|
||||||
|
}
|
||||||
|
|
||||||
private func startBenchmark() {
|
private func startBenchmark() {
|
||||||
guard let group = (enclosingMenuItem as? ProxyGroupSpeedTestMenuItem)?.proxyGroup
|
guard let group = (enclosingMenuItem as? ProxyGroupSpeedTestMenuItem)?.proxyGroup
|
||||||
else { return }
|
else { return }
|
||||||
@ -84,99 +85,15 @@ fileprivate class ProxyGroupSpeedTestMenuItemView: NSView {
|
|||||||
[weak self] in
|
[weak self] in
|
||||||
guard let self = self, let menu = self.enclosingMenuItem else { return }
|
guard let self = self, let menu = self.enclosingMenuItem else { return }
|
||||||
self.label.stringValue = menu.title
|
self.label.stringValue = menu.title
|
||||||
self.label.textColor = NSColor.labelColor
|
|
||||||
menu.isEnabled = true
|
menu.isEnabled = true
|
||||||
self.setNeedsDisplay(self.bounds)
|
self.setNeedsDisplay()
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override func updateTrackingAreas() {
|
|
||||||
super.updateTrackingAreas()
|
|
||||||
if #available(macOS 10.15.1, *) {
|
|
||||||
trackingAreas.forEach { removeTrackingArea($0) }
|
|
||||||
addTrackingArea(NSTrackingArea(rect: bounds, options: [.mouseEnteredAndExited, .activeAlways], owner: self, userInfo: nil))
|
|
||||||
addTrackingArea(NSTrackingArea(rect: bounds, options: [.mouseMoved, .activeAlways], owner: self, userInfo: nil))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override func viewDidMoveToWindow() {
|
|
||||||
super.viewDidMoveToWindow()
|
|
||||||
if #available(macOS 10.15.1, *) {
|
|
||||||
setupCarbon()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://gist.github.com/p0deje/da5e5cfda6be8cb87c2e7caad3a3df63
|
|
||||||
// https://stackoverflow.com/questions/53273191/custom-carbon-key-event-handler-fails-after-mouse-events
|
|
||||||
@available(macOS 10.15.1, *)
|
|
||||||
private func setupCarbon() {
|
|
||||||
if window != nil {
|
|
||||||
if let dispatcher = GetEventDispatcherTarget() {
|
|
||||||
let eventHandlerCallback: EventHandlerUPP = { eventHandlerCallRef, eventRef, userData in
|
|
||||||
guard let userData = userData else { return 0 }
|
|
||||||
let itemView: ProxyGroupSpeedTestMenuItemView = bridge(ptr: userData)
|
|
||||||
itemView.startBenchmark()
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
let eventSpecs = [EventTypeSpec(eventClass: OSType(kEventClassMouse), eventKind: UInt32(kEventMouseUp))]
|
|
||||||
|
|
||||||
InstallEventHandler(dispatcher, eventHandlerCallback, 1, eventSpecs, bridge(obj: self), &eventHandler)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
RemoveEventHandler(eventHandler)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override func mouseEntered(with event: NSEvent) {
|
|
||||||
if #available(macOS 10.15.1, *) {
|
|
||||||
isMouseInsideView = true
|
|
||||||
setNeedsDisplay(bounds)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override func mouseExited(with event: NSEvent) {
|
|
||||||
if #available(macOS 10.15.1, *) {
|
|
||||||
isMouseInsideView = false
|
|
||||||
setNeedsDisplay(bounds)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override func hitTest(_ point: NSPoint) -> NSView? {
|
|
||||||
if bounds.contains(point) {
|
|
||||||
return label
|
|
||||||
}
|
|
||||||
return super.hitTest(point)
|
|
||||||
}
|
|
||||||
|
|
||||||
override func mouseUp(with event: NSEvent) {
|
|
||||||
if #available(macOS 10.15.1, *) {} else {
|
|
||||||
startBenchmark()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override func draw(_ dirtyRect: NSRect) {
|
override func draw(_ dirtyRect: NSRect) {
|
||||||
super.draw(dirtyRect)
|
super.draw(dirtyRect)
|
||||||
guard let menu = enclosingMenuItem else { return }
|
label.textColor = (enclosingMenuItem?.isEnabled ?? true) ? NSColor.labelColor : NSColor.placeholderTextColor
|
||||||
|
updateBackground(label)
|
||||||
let isHighlighted: Bool
|
|
||||||
if #available(macOS 10.15.1, *) {
|
|
||||||
isHighlighted = isMouseInsideView
|
|
||||||
} else {
|
|
||||||
isHighlighted = menu.isHighlighted
|
|
||||||
}
|
|
||||||
if isHighlighted && menu.isEnabled {
|
|
||||||
NSColor.selectedMenuItemColor.setFill()
|
|
||||||
label.textColor = NSColor.white
|
|
||||||
} else {
|
|
||||||
NSColor.clear.setFill()
|
|
||||||
if enclosingMenuItem?.isEnabled ?? true {
|
|
||||||
label.textColor = NSColor.labelColor
|
|
||||||
} else {
|
|
||||||
label.textColor = NSColor.secondaryLabelColor
|
|
||||||
}
|
|
||||||
}
|
|
||||||
dirtyRect.fill()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user