Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
82f39581a7 | ||
|
|
1b34b23c58 | ||
|
|
d63379d099 | ||
|
|
ee8634c724 |
@@ -26,7 +26,7 @@ public class Popover: NSObject {
|
||||
)
|
||||
let contentFrame = NSRect(
|
||||
x: 0,
|
||||
y: (Constants.maxContainerSize-Constants.maxContentHeight)/2,
|
||||
y: (Constants.maxContainerSize-Constants.maxContentHeight) / 2,
|
||||
width: NSWidth(view.bounds),
|
||||
height: Constants.maxContentHeight
|
||||
)
|
||||
@@ -36,17 +36,10 @@ public class Popover: NSObject {
|
||||
}
|
||||
}
|
||||
|
||||
enum PopoverPresentationMode {
|
||||
case undefined
|
||||
case image
|
||||
case customView
|
||||
}
|
||||
|
||||
public var item: NSStatusItem!
|
||||
|
||||
private var popoverWindowController: PopoverWindowController?
|
||||
private let windowConfiguration: PopoverConfiguration
|
||||
private var observation: NSKeyValueObservation?
|
||||
private var statusItemContainer: StatusItemContainerView?
|
||||
|
||||
private var isPopoverWindowVisible: Bool {
|
||||
|
||||
@@ -9,48 +9,48 @@
|
||||
import Cocoa
|
||||
|
||||
public protocol PopoverConfiguration {
|
||||
var windowToPopoverMargin: CGFloat { get }
|
||||
var popoverToStatusItemMargin: CGFloat { get }
|
||||
var backgroundColor: NSColor { get }
|
||||
var lineColor: NSColor? { get }
|
||||
var lineWidth: CGFloat { get }
|
||||
var borderColor: NSColor? { get }
|
||||
var borderWidth: CGFloat { get }
|
||||
var arrowHeight: CGFloat { get }
|
||||
var arrowWidth: CGFloat { get }
|
||||
var cornerRadius: CGFloat { get }
|
||||
var contentInset: NSEdgeInsets { get }
|
||||
}
|
||||
|
||||
public class DefaultConfiguration: PopoverConfiguration {
|
||||
open class DefaultConfiguration: PopoverConfiguration {
|
||||
public init() {}
|
||||
|
||||
public var windowToPopoverMargin: CGFloat {
|
||||
return 22
|
||||
open var popoverToStatusItemMargin: CGFloat {
|
||||
return 2
|
||||
}
|
||||
|
||||
public var backgroundColor: NSColor {
|
||||
return NSColor.windowBackgroundColor//NSColor(calibratedRed: 0.213, green: 0.213, blue: 0.213, alpha: 1.0)
|
||||
open var backgroundColor: NSColor {
|
||||
return NSColor.windowBackgroundColor
|
||||
}
|
||||
|
||||
public var lineColor: NSColor? {
|
||||
return nil//NSColor(calibratedRed: 0.413, green: 0.413, blue: 0.413, alpha: 1.0)
|
||||
open var borderColor: NSColor? {
|
||||
return NSColor.white
|
||||
}
|
||||
|
||||
public var lineWidth: CGFloat {
|
||||
return lineColor != nil ? 6 : 0
|
||||
open var borderWidth: CGFloat {
|
||||
return 2
|
||||
}
|
||||
|
||||
public var arrowHeight: CGFloat {
|
||||
return 11.0
|
||||
open var arrowHeight: CGFloat {
|
||||
return 12.0
|
||||
}
|
||||
|
||||
public var arrowWidth: CGFloat {
|
||||
open var arrowWidth: CGFloat {
|
||||
return 62.0
|
||||
}
|
||||
|
||||
public var cornerRadius: CGFloat {
|
||||
return 20.0
|
||||
open var cornerRadius: CGFloat {
|
||||
return 12
|
||||
}
|
||||
|
||||
public var contentInset: NSEdgeInsets {
|
||||
return NSEdgeInsets(top: 0, left: 0.0, bottom: 0, right: 0.0)
|
||||
open var contentInset: NSEdgeInsets {
|
||||
return NSEdgeInsetsZero
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,13 +9,18 @@
|
||||
import Cocoa
|
||||
|
||||
public class PopoverWindow: NSPanel {
|
||||
private let windowConfiguration: PopoverConfiguration
|
||||
private let wConfig: PopoverConfiguration
|
||||
private var childContentView: NSView?
|
||||
private var backgroundView: PopoverWindowBackgroundView?
|
||||
|
||||
public static func window(with configuration: PopoverConfiguration) -> PopoverWindow {
|
||||
|
||||
let window = PopoverWindow.init(contentRect: .zero, styleMask: .nonactivatingPanel, backing: .buffered, defer: true, configuration: configuration)
|
||||
let window = PopoverWindow.init(
|
||||
contentRect: .zero,
|
||||
styleMask: .nonactivatingPanel,
|
||||
backing: .buffered,
|
||||
defer: true,
|
||||
configuration: configuration
|
||||
)
|
||||
|
||||
return window
|
||||
}
|
||||
@@ -32,7 +37,7 @@ public class PopoverWindow: NSPanel {
|
||||
|
||||
backgroundView = super.contentView as? PopoverWindowBackgroundView
|
||||
if (backgroundView == nil) {
|
||||
backgroundView = PopoverWindowBackgroundView(frame: bounds, windowConfiguration: windowConfiguration)
|
||||
backgroundView = PopoverWindowBackgroundView(frame: bounds, windowConfiguration: wConfig)
|
||||
backgroundView?.layer?.edgeAntialiasingMask = antialiasingMask
|
||||
super.contentView = backgroundView
|
||||
}
|
||||
@@ -44,17 +49,18 @@ public class PopoverWindow: NSPanel {
|
||||
childContentView = newValue
|
||||
childContentView?.translatesAutoresizingMaskIntoConstraints = false
|
||||
childContentView?.wantsLayer = true
|
||||
childContentView?.layer?.cornerRadius = windowConfiguration.cornerRadius
|
||||
childContentView?.layer?.cornerRadius = wConfig.cornerRadius
|
||||
childContentView?.layer?.masksToBounds = true
|
||||
childContentView?.layer?.edgeAntialiasingMask = antialiasingMask
|
||||
|
||||
guard let userContentView = self.childContentView, let backgroundView = self.backgroundView else { return }
|
||||
backgroundView.addSubview(userContentView)
|
||||
|
||||
let left = windowConfiguration.lineWidth + windowConfiguration.contentInset.left
|
||||
let right = windowConfiguration.lineWidth + windowConfiguration.contentInset.right
|
||||
let top = windowConfiguration.arrowHeight + windowConfiguration.lineWidth + windowConfiguration.contentInset.top
|
||||
let bottom = windowConfiguration.lineWidth + windowConfiguration.contentInset.bottom
|
||||
let borderWidth = wConfig.borderColor != nil ? wConfig.borderWidth : 0
|
||||
let left = borderWidth + wConfig.contentInset.left
|
||||
let right = borderWidth + wConfig.contentInset.right
|
||||
let top = wConfig.arrowHeight + borderWidth + wConfig.contentInset.top
|
||||
let bottom = borderWidth + wConfig.contentInset.bottom
|
||||
|
||||
NSLayoutConstraint.activate([
|
||||
userContentView.leadingAnchor.constraint(equalTo: backgroundView.leadingAnchor, constant: left),
|
||||
@@ -70,11 +76,11 @@ public class PopoverWindow: NSPanel {
|
||||
}
|
||||
|
||||
public override func frameRect(forContentRect contentRect: NSRect) -> NSRect {
|
||||
NSMakeRect(NSMinX(contentRect), NSMinY(contentRect), NSWidth(contentRect), NSHeight(contentRect) + windowConfiguration.arrowHeight)
|
||||
NSMakeRect(NSMinX(contentRect), NSMinY(contentRect), NSWidth(contentRect), NSHeight(contentRect) + wConfig.arrowHeight)
|
||||
}
|
||||
|
||||
private init(contentRect: NSRect, styleMask style: NSWindow.StyleMask, backing backingStoreType: NSWindow.BackingStoreType, defer flag: Bool, configuration: PopoverConfiguration) {
|
||||
windowConfiguration = configuration
|
||||
wConfig = configuration
|
||||
super.init(contentRect: contentRect, styleMask: style, backing: backingStoreType, defer: flag)
|
||||
|
||||
isOpaque = false
|
||||
|
||||
@@ -9,10 +9,10 @@
|
||||
import Cocoa
|
||||
|
||||
class PopoverWindowBackgroundView: NSView {
|
||||
private let windowConfiguration: PopoverConfiguration
|
||||
private let wConfig: PopoverConfiguration
|
||||
|
||||
init(frame frameRect: NSRect, windowConfiguration: PopoverConfiguration) {
|
||||
self.windowConfiguration = windowConfiguration
|
||||
self.wConfig = windowConfiguration
|
||||
super.init(frame: frameRect)
|
||||
}
|
||||
|
||||
@@ -20,8 +20,8 @@ class PopoverWindowBackgroundView: NSView {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
private var lineWidth: CGFloat {
|
||||
return windowConfiguration.lineColor != nil ? windowConfiguration.lineWidth : 0
|
||||
private var borderWidth: CGFloat {
|
||||
return wConfig.borderColor != nil ? wConfig.borderWidth : 0
|
||||
}
|
||||
|
||||
override func draw(_ dirtyRect: NSRect) {
|
||||
@@ -29,20 +29,20 @@ class PopoverWindowBackgroundView: NSView {
|
||||
|
||||
// Drawing code here.
|
||||
|
||||
let backgroundRect = NSMakeRect(NSMinX(bounds), NSMinY(bounds), NSWidth(bounds), NSHeight(bounds) - windowConfiguration.arrowHeight).insetBy(dx: lineWidth, dy: lineWidth)
|
||||
let backgroundRect = NSMakeRect(NSMinX(bounds), NSMinY(bounds), NSWidth(bounds), NSHeight(bounds) - wConfig.arrowHeight).insetBy(dx: borderWidth, dy: borderWidth)
|
||||
|
||||
let controlPoints = NSBezierPath()
|
||||
let windowPath = NSBezierPath()
|
||||
let arrowPath = NSBezierPath()
|
||||
let backgroundPath = NSBezierPath(roundedRect: backgroundRect, xRadius: windowConfiguration.cornerRadius, yRadius: windowConfiguration.cornerRadius)
|
||||
let backgroundPath = NSBezierPath(roundedRect: backgroundRect, xRadius: wConfig.cornerRadius, yRadius: wConfig.cornerRadius)
|
||||
|
||||
let leftPoint = NSPoint(x: NSWidth(backgroundRect) / 2 - windowConfiguration.arrowWidth / 2, y: NSMaxY(backgroundRect))
|
||||
let toPoint = NSPoint(x: NSWidth(backgroundRect) / 2, y: NSMaxY(backgroundRect) + windowConfiguration.arrowHeight)
|
||||
let rightPoint = NSPoint(x: NSWidth(backgroundRect) / 2 + windowConfiguration.arrowWidth / 2, y: NSMaxY(backgroundRect))
|
||||
let cp11 = NSPoint(x: NSWidth(backgroundRect) / 2 - windowConfiguration.arrowWidth / 6, y: NSMaxY(backgroundRect))
|
||||
let cp12 = NSPoint(x: NSWidth(backgroundRect) / 2 - windowConfiguration.arrowWidth / 9, y: NSMaxY(backgroundRect) + windowConfiguration.arrowHeight)
|
||||
let cp21 = NSPoint(x: NSWidth(backgroundRect) / 2 + windowConfiguration.arrowWidth / 9, y: NSMaxY(backgroundRect) + windowConfiguration.arrowHeight)
|
||||
let cp22 = NSPoint(x: NSWidth(backgroundRect) / 2 + windowConfiguration.arrowWidth / 6, y: NSMaxY(backgroundRect))
|
||||
let leftPoint = NSPoint(x: NSWidth(backgroundRect) / 2 - wConfig.arrowWidth / 2, y: NSMaxY(backgroundRect))
|
||||
let toPoint = NSPoint(x: NSWidth(backgroundRect) / 2, y: NSMaxY(backgroundRect) + wConfig.arrowHeight)
|
||||
let rightPoint = NSPoint(x: NSWidth(backgroundRect) / 2 + wConfig.arrowWidth / 2, y: NSMaxY(backgroundRect))
|
||||
let cp11 = NSPoint(x: NSWidth(backgroundRect) / 2 - wConfig.arrowWidth / 6, y: NSMaxY(backgroundRect))
|
||||
let cp12 = NSPoint(x: NSWidth(backgroundRect) / 2 - wConfig.arrowWidth / 9, y: NSMaxY(backgroundRect) + wConfig.arrowHeight)
|
||||
let cp21 = NSPoint(x: NSWidth(backgroundRect) / 2 + wConfig.arrowWidth / 9, y: NSMaxY(backgroundRect) + wConfig.arrowHeight)
|
||||
let cp22 = NSPoint(x: NSWidth(backgroundRect) / 2 + wConfig.arrowWidth / 6, y: NSMaxY(backgroundRect))
|
||||
|
||||
controlPoints.append(NSBezierPath(ovalIn: NSMakeRect(leftPoint.x - 2, leftPoint.y - 2, 4, 4)))
|
||||
controlPoints.append(NSBezierPath(ovalIn: NSMakeRect(toPoint.x - 2, toPoint.y - 2, 4, 4)))
|
||||
@@ -61,14 +61,14 @@ class PopoverWindowBackgroundView: NSView {
|
||||
windowPath.append(arrowPath)
|
||||
windowPath.append(backgroundPath)
|
||||
|
||||
if let lineColor = windowConfiguration.lineColor {
|
||||
if let lineColor = wConfig.borderColor {
|
||||
lineColor.setStroke()
|
||||
windowPath.lineWidth = windowConfiguration.lineWidth
|
||||
windowPath.lineWidth = wConfig.borderWidth
|
||||
windowPath.stroke()
|
||||
}
|
||||
|
||||
|
||||
windowConfiguration.backgroundColor.setFill()
|
||||
wConfig.backgroundColor.setFill()
|
||||
windowPath.fill()
|
||||
|
||||
// controlPoints.fill()
|
||||
|
||||
@@ -13,11 +13,11 @@ class PopoverWindowController: NSWindowController {
|
||||
public private(set) var isAnimating: Bool = false
|
||||
|
||||
private let popover: Popover
|
||||
private let windowConfiguration: PopoverConfiguration
|
||||
private let wConfig: PopoverConfiguration
|
||||
|
||||
init(with popover: Popover, contentViewController: NSViewController, windowConfiguration: PopoverConfiguration) {
|
||||
self.popover = popover
|
||||
self.windowConfiguration = windowConfiguration
|
||||
self.wConfig = windowConfiguration
|
||||
|
||||
super.init(window: PopoverWindow.window(with: windowConfiguration))
|
||||
self.contentViewController = contentViewController
|
||||
@@ -30,7 +30,7 @@ class PopoverWindowController: NSWindowController {
|
||||
public func show() {
|
||||
guard !isAnimating else { return }
|
||||
|
||||
updateWindwFrame()
|
||||
updateWindowFrame()
|
||||
window?.alphaValue = 1.0
|
||||
showWindow(nil)
|
||||
windowIsOpen = true
|
||||
@@ -46,14 +46,41 @@ class PopoverWindowController: NSWindowController {
|
||||
windowIsOpen = false
|
||||
}
|
||||
|
||||
private func updateWindwFrame() {
|
||||
guard let popoverRect = popover.item.button?.window?.frame, let window = window else { return }
|
||||
let x = NSMinX(popoverRect) - NSWidth(window.frame)/2 + NSWidth(popoverRect)/2 + windowConfiguration.lineWidth
|
||||
let y = min(NSMinY(popoverRect), NSScreen.main!.frame.size.height - NSHeight(window.frame) - windowConfiguration.windowToPopoverMargin)
|
||||
private func updateWindowFrame() {
|
||||
let windowFrame = visibleStatusItemWindowFrame()
|
||||
window?.setFrame(windowFrame, display: true)
|
||||
window?.appearance = NSAppearance.current
|
||||
}
|
||||
|
||||
let windowFrame = NSMakeRect(x, y, NSWidth(window.frame), NSHeight(window.frame))
|
||||
window.setFrame(windowFrame, display: true)
|
||||
window.appearance = NSAppearance.current
|
||||
private func visibleStatusItemWindowFrame() -> NSRect {
|
||||
let screenFrame = currentMouseScreen().frame
|
||||
let popoverRect = popover.item.button?.window?.frame ?? .zero
|
||||
|
||||
guard let window = self.window else { return .zero }
|
||||
|
||||
let borderWidth = wConfig.borderColor != nil ? wConfig.borderWidth : 0
|
||||
let x = NSMinX(popoverRect) - NSWidth(window.frame) / 2 + NSWidth(popoverRect) / 2 + borderWidth
|
||||
let y = min(NSMinY(popoverRect), NSMaxY(screenFrame)) - NSHeight(window.frame) - wConfig.popoverToStatusItemMargin + borderWidth / 2
|
||||
|
||||
return NSMakeRect(
|
||||
x,
|
||||
y,
|
||||
NSWidth(window.frame),
|
||||
NSHeight(window.frame)
|
||||
)
|
||||
}
|
||||
|
||||
private func currentMouseScreen() -> NSScreen {
|
||||
let currentMousePoint = NSEvent.mouseLocation
|
||||
var currentScreen: NSScreen?
|
||||
|
||||
while currentScreen != nil {
|
||||
NSScreen.screens.forEach { screen in
|
||||
currentScreen = NSMouseInRect(currentMousePoint, screen.frame, false) ? screen : nil
|
||||
}
|
||||
}
|
||||
|
||||
return currentScreen ?? NSScreen.main ?? NSScreen()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user