9 Commits

Author SHA1 Message Date
Sapozhnik Ivan e1950e0352 Merge pull request #17 from iSapozhnik/feature/hover-insets
Appearance
2020-05-14 19:23:45 +02:00
Ivan Sapozhnik 622cad7feb Appearance 2020-05-14 19:17:48 +02:00
Sapozhnik Ivan 971fd9d77f Merge pull request #14 from iSapozhnik/feature/hover-insets
Hover insets
2020-04-22 22:47:08 +02:00
Ivan Sapozhnik c71aaecd87 Hover edge insets 2020-04-22 22:44:53 +02:00
Sapozhnik Ivan e6801e978a Merge pull request #11 from iSapozhnik/feature/hover-corner-radius
Hover corner radius
2020-04-22 22:14:27 +02:00
Ivan Sapozhnik 83e292f59c Readme 2020-04-22 22:03:54 +02:00
Ivan Sapozhnik abd8f1a338 Hover corner radius 2020-04-22 22:02:00 +02:00
Ivan Sapozhnik 63ea1f9b30 Merge branch 'master' into development 2020-04-22 21:56:07 +02:00
Sapozhnik Ivan 85a7c47899 Update README.md 2020-04-22 21:47:42 +02:00
6 changed files with 71 additions and 16 deletions
+4 -1
View File
@@ -27,7 +27,7 @@ Update your `Package.swift` dependencies:
```
dependencies: [
.package(url: "https://github.com/iSapozhnik/Menu", from: "1.10.0")
.package(url: "https://github.com/iSapozhnik/Menu", from: "1.10.1")
]
```
@@ -63,10 +63,13 @@ public protocol Configuration {
var menuItemHoverBackgroundColor: NSColor { get }
var menuItemTextColor: NSColor { get }
var menuItemHoverTextColor: NSColor { get }
var menuItemHoverCornerRadius: CGFloat { get }
var menuItemHoverEdgeInsets: NSEdgeInsets { get }
var menuItemCheckmarkColor: NSColor { get }
var menuItemHoverCheckmarkColor: NSColor { get }
var menuItemCheckmarkHeight: CGFloat { get }
var menuItemCheckmarkThikness: CGFloat { get }
var menuItemHorizontalSpacing: CGFloat { get }
var menuItemImageHeight: CGFloat? { get }
var menuItemImageTintColor: NSColor? { get }
var menuItemHoverImageTintColor: NSColor? { get }
+7 -9
View File
@@ -11,14 +11,11 @@ class Control: NSControl {
var hover: ((Bool) -> Void)?
private let hoverLayer = CAShapeLayer()
private let hoverColor: NSColor
private let hoverAnimationDuration: TimeInterval
private var trackingArea: NSTrackingArea?
private let configuration: Configuration
init(with configuration: Configuration) {
self.hoverColor = configuration.menuItemHoverBackgroundColor
self.hoverAnimationDuration = configuration.menuItemHoverAnimationDuration
self.configuration = configuration
super.init(frame: .zero)
wantsLayer = true
@@ -33,7 +30,8 @@ class Control: NSControl {
override func layout() {
super.layout()
hoverLayer.path = CGPath(rect: bounds, transform: nil)
let newRect = bounds.inset(by: configuration.menuItemHoverEdgeInsets)
hoverLayer.path = CGPath(roundedRect: newRect, cornerWidth: configuration.menuItemHoverCornerRadius, cornerHeight: configuration.menuItemHoverCornerRadius, transform: nil)
if let trackingArea = trackingArea, trackingAreas.contains(trackingArea) {
removeTrackingArea(trackingArea)
@@ -61,13 +59,13 @@ class Control: NSControl {
override func mouseEntered(with event: NSEvent) {
guard isEnabled else { return }
animateFillColor(from: .clear, to: hoverColor)
animateFillColor(from: .clear, to: configuration.menuItemHoverBackgroundColor)
hover?(true)
}
override func mouseExited(with event: NSEvent) {
guard isEnabled else { return }
animateFillColor(from: hoverColor, to: .clear)
animateFillColor(from: configuration.menuItemHoverBackgroundColor, to: .clear)
hover?(false)
}
@@ -78,7 +76,7 @@ class Control: NSControl {
private func animateFillColor(from oldColor: NSColor, to newColor: NSColor) {
let animation = CABasicAnimation(keyPath: "fillColor")
animation.duration = hoverAnimationDuration
animation.duration = configuration.menuItemHoverAnimationDuration
animation.fromValue = oldColor.cgColor
animation.toValue = newColor.cgColor
animation.fillMode = .both
+11
View File
@@ -190,3 +190,14 @@ extension CGFloat {
/// 48 points
static let grid6: CGFloat = 48.0
}
extension NSRect {
func inset(by insets: NSEdgeInsets) -> NSRect {
var newRect = self
newRect.origin.x += insets.left
newRect.size.width -= insets.left + insets.right
newRect.origin.y += insets.top
newRect.size.height -= insets.top + insets.bottom
return newRect
}
}
+21 -2
View File
@@ -65,6 +65,14 @@ public final class Menu {
item.action?()
}
public func selectItem(withTitle title: String) {
guard let item = items.first(where: { item -> Bool in
item.title == title
}) else { return }
selectedId = item.id
item.action?()
}
// MARK: - Adding and Removing Menu Items
public func insertItem(_ item: MenuItem, at index: Int) {
items.insert(item, at: index)
@@ -218,12 +226,23 @@ public final class Menu {
guard let parentWindow = view.window, let topMostSuperView = parentWindow.contentView else { return }
let locationInWindow = view.convert(topMostSuperView.frame.origin, to: nil)
let rectInWindow = NSRect(origin: locationInWindow, size: CGSize(width: NSWidth(view.frame), height: NSHeight(window.frame)))
let rectInWindow = NSRect(origin: locationInWindow, size: CGSize(width: NSWidth(view.frame), height: NSHeight(view.frame)))
let rectInScreen = parentWindow.convertToScreen(rectInWindow)
let origin = rectInScreen.origin
var additionalYOffset = configuration.appearsBelowSender ? NSHeight(view.frame) : 0
additionalYOffset += abs(configuration.presentingOffset)
let newFrame = NSRect(x: origin.x, y: origin.y - NSHeight(window.frame) - additionalYOffset, width: NSWidth(view.frame), height: NSHeight(window.frame))
let newFrame: NSRect
switch configuration.appearancePosition {
case .rightBottom:
newFrame = NSRect(x: origin.x, y: origin.y - NSHeight(window.frame) - additionalYOffset, width: NSWidth(view.frame), height: NSHeight(window.frame))
case .rightTop:
newFrame = NSRect(x: origin.x, y: origin.y + additionalYOffset, width: NSWidth(view.frame), height: NSHeight(window.frame))
case .leftTop:
newFrame = NSRect(x: origin.x - NSWidth(window.frame) + NSWidth(view.frame), y: origin.y - additionalYOffset, width: NSWidth(view.frame), height: NSHeight(window.frame))
case .leftBottom:
newFrame = NSRect(x: origin.x - NSWidth(window.frame) + NSWidth(view.frame), y: origin.y - NSHeight(window.frame) - additionalYOffset, width: NSWidth(view.frame), height: NSHeight(window.frame))
}
window.setFrame(newFrame, display: true, animate: false)
}
+22
View File
@@ -12,6 +12,13 @@ public enum Alignment {
case right
}
public enum Position {
case leftBottom
case leftTop
case rightTop
case rightBottom
}
public enum Padding {
public struct Horizontal {
let left: CGFloat
@@ -54,6 +61,7 @@ public protocol Configuration {
var cornerRadius: CGFloat { get }
var hasShadow: Bool { get }
var appearsBelowSender: Bool { get }
var appearancePosition: Position { get }
var presentingOffset: CGFloat { get }
var animationDuration: TimeInterval { get }
var contentEdgeInsets: NSEdgeInsets { get }
@@ -70,6 +78,8 @@ public protocol Configuration {
var menuItemHoverBackgroundColor: NSColor { get }
var menuItemTextColor: NSColor { get }
var menuItemHoverTextColor: NSColor { get }
var menuItemHoverCornerRadius: CGFloat { get }
var menuItemHoverEdgeInsets: NSEdgeInsets { get }
var menuItemCheckmarkColor: NSColor { get }
var menuItemHoverCheckmarkColor: NSColor { get }
var menuItemCheckmarkHeight: CGFloat { get }
@@ -112,6 +122,10 @@ open class MenuConfiguration: Configuration {
return true
}
open var appearancePosition: Position {
return .rightBottom
}
open var presentingOffset: CGFloat {
return 0.0
}
@@ -172,6 +186,14 @@ open class MenuConfiguration: Configuration {
return .white
}
open var menuItemHoverEdgeInsets: NSEdgeInsets {
return NSEdgeInsets.zero
}
open var menuItemHoverCornerRadius: CGFloat {
return 0.0
}
open var menuItemTextColor: NSColor {
return .white
}
+6 -4
View File
@@ -208,10 +208,12 @@ class MenuElement: NSView {
control.isEnabled = isEnabled
control.hover = { [weak self] isHover in
guard let self = self else { return }
label.textColor = isHover ? self.configuration.menuItemHoverTextColor : isSelected ? self.configuration.menuItemHoverImageTintColor : self.configuration.menuItemTextColor
if #available(OSX 10.14, *) {
leftImageView?.contentTintColor = isHover ? self.configuration.menuItemHoverImageTintColor : isSelected ? self.configuration.menuItemHoverImageTintColor : self.configuration.menuItemImageTintColor
rightImageView?.contentTintColor = isHover ? self.configuration.menuItemHoverImageTintColor : isSelected ? self.configuration.menuItemHoverImageTintColor : self.configuration.menuItemImageTintColor
if self.configuration.rememberSelection {
label.textColor = isHover ? self.configuration.menuItemHoverTextColor : isSelected ? self.configuration.menuItemHoverImageTintColor : self.configuration.menuItemTextColor
if #available(OSX 10.14, *) {
leftImageView?.contentTintColor = isHover ? self.configuration.menuItemHoverImageTintColor : isSelected ? self.configuration.menuItemHoverImageTintColor : self.configuration.menuItemImageTintColor
rightImageView?.contentTintColor = isHover ? self.configuration.menuItemHoverImageTintColor : isSelected ? self.configuration.menuItemHoverImageTintColor : self.configuration.menuItemImageTintColor
}
}
}