-
Notifications
You must be signed in to change notification settings - Fork 12
/
InfoButton.swift
152 lines (125 loc) · 5.52 KB
/
InfoButton.swift
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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
//
// InfoButton.swift
// InfoButton
//
// Created by Kauntey Suryawanshi on 25/06/15.
// Copyright (c) 2015 Kauntey Suryawanshi. All rights reserved.
//
import Foundation
import Cocoa
@IBDesignable
open class InfoButton : NSControl, NSPopoverDelegate {
var mainSize: CGFloat!
@IBInspectable var showOnHover: Bool = false
@IBInspectable var fillMode: Bool = true
@IBInspectable var animatePopover: Bool = false
@IBInspectable var content: String = ""
@IBInspectable var primaryColor: NSColor = NSColor.scrollBarColor
var secondaryColor: NSColor = NSColor.white
var mouseInside = false {
didSet {
self.needsDisplay = true
if showOnHover {
if popover == nil {
popover = NSPopover(content: self.content, doesAnimate: self.animatePopover)
}
if mouseInside {
popover.show(relativeTo: self.frame, of: self.superview!, preferredEdge: NSRectEdge.maxX)
} else {
popover.close()
}
}
}
}
var trackingArea: NSTrackingArea!
override open func updateTrackingAreas() {
super.updateTrackingAreas()
if trackingArea != nil {
self.removeTrackingArea(trackingArea)
}
trackingArea = NSTrackingArea(rect: self.bounds, options: [NSTrackingArea.Options.mouseEnteredAndExited, NSTrackingArea.Options.activeAlways], owner: self, userInfo: nil)
self.addTrackingArea(trackingArea)
}
fileprivate var stringAttributeDict = [String: AnyObject]()
fileprivate var circlePath: NSBezierPath!
var popover: NSPopover!
required public init?(coder: NSCoder) {
super.init(coder: coder)
let frameSize = self.frame.size
if frameSize.width != frameSize.height {
self.frame.size.height = self.frame.size.width
}
self.mainSize = self.frame.size.height
stringAttributeDict[convertFromNSAttributedStringKey(NSAttributedString.Key.font)] = NSFont.systemFont(ofSize: mainSize * 0.6)
let inSet: CGFloat = 2
let rect = NSMakeRect(inSet, inSet, mainSize - inSet * 2, mainSize - inSet * 2)
circlePath = NSBezierPath(ovalIn: rect)
}
override open func draw(_ dirtyRect: NSRect) {
var activeColor: NSColor!
if mouseInside || (popover != nil && popover!.isShown){
activeColor = primaryColor
} else {
activeColor = primaryColor.withAlphaComponent(0.35)
}
if fillMode {
activeColor.setFill()
circlePath.fill()
stringAttributeDict[convertFromNSAttributedStringKey(NSAttributedString.Key.foregroundColor)] = secondaryColor
} else {
activeColor.setStroke()
circlePath.stroke()
stringAttributeDict[convertFromNSAttributedStringKey(NSAttributedString.Key.foregroundColor)] = (mouseInside ? primaryColor : primaryColor.withAlphaComponent(0.35))
}
let attributedString = NSAttributedString(string: "?", attributes: convertToOptionalNSAttributedStringKeyDictionary(stringAttributeDict))
let stringLocation = NSMakePoint(mainSize / 2 - attributedString.size().width / 2, mainSize / 2 - attributedString.size().height / 2)
attributedString.draw(at: stringLocation)
}
override open func mouseDown(with theEvent: NSEvent) {
if popover == nil {
popover = NSPopover(content: self.content, doesAnimate: self.animatePopover)
}
if popover.isShown {
popover.close()
} else {
popover.show(relativeTo: self.frame, of: self.superview!, preferredEdge: NSRectEdge.maxX)
}
}
override open func mouseEntered(with theEvent: NSEvent) { mouseInside = true }
override open func mouseExited(with theEvent: NSEvent) { mouseInside = false }
}
//MARK: Extension for making a popover from string
extension NSPopover {
convenience init(content: String, doesAnimate: Bool) {
self.init()
self.behavior = NSPopover.Behavior.transient
self.animates = doesAnimate
self.contentViewController = NSViewController()
self.contentViewController!.view = NSView(frame: NSZeroRect)//remove this ??
let popoverMargin = CGFloat(20)
let textField: NSTextField = {
content in
let textField = NSTextField(frame: NSZeroRect)
textField.isEditable = false
textField.stringValue = content
textField.isBordered = false
textField.drawsBackground = false
textField.sizeToFit()
textField.setFrameOrigin(NSMakePoint(popoverMargin, popoverMargin))
return textField
}(content)
self.contentViewController!.view.addSubview(textField)
var viewSize = textField.frame.size; viewSize.width += (popoverMargin * 2); viewSize.height += (popoverMargin * 2)
self.contentSize = viewSize
}
}
//NSMinXEdge NSMinYEdge NSMaxXEdge NSMaxYEdge
// Helper function inserted by Swift 4.2 migrator.
fileprivate func convertFromNSAttributedStringKey(_ input: NSAttributedString.Key) -> String {
return input.rawValue
}
// Helper function inserted by Swift 4.2 migrator.
fileprivate func convertToOptionalNSAttributedStringKeyDictionary(_ input: [String: Any]?) -> [NSAttributedString.Key: Any]? {
guard let input = input else { return nil }
return Dictionary(uniqueKeysWithValues: input.map { key, value in (NSAttributedString.Key(rawValue: key), value)})
}