5 Commits

Author SHA1 Message Date
Sapozhnik Ivan 76733940b2 Update README.md 2021-11-19 23:04:48 +01:00
Sapozhnik Ivan a58be98a55 Update README.md 2020-09-15 11:22:31 +02:00
Sapozhnik Ivan 5f506926e0 Update README.md 2020-04-23 14:57:03 +02:00
Ivan Sapozhnik bde7399d29 Merge branch 'master' of https://github.com/iSapozhnik/Menu
# Conflicts:
#	README.md
2020-04-23 14:55:42 +02:00
Ivan Sapozhnik bcf6ce5e79 update readme 2020-04-23 14:53:23 +02:00
10 changed files with 61 additions and 74 deletions
+8 -7
View File
@@ -5,6 +5,7 @@
![Swift](https://img.shields.io/badge/%20in-swift%205.0-orange.svg)
![macOS](https://img.shields.io/badge/macOS-10.12-green.svg)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2FiSapozhnik%2FMenu%2Fbadge%3Ftype%3Dplatforms)](https://swiftpackageindex.com/iSapozhnik/Menu)
</div>
@@ -63,8 +64,6 @@ 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 }
@@ -123,7 +122,7 @@ class ViewController: NSViewController {
myMenu.addItems(menuItems)
}
@IBAction func didClickedButton(_ sender: NSButton) {
@IBAction func didClickButton(_ sender: NSButton) {
myMenu.show(from: sender)
}
}
@@ -131,12 +130,14 @@ class ViewController: NSViewController {
## Examples
In this section I've collected some examples of what can be implemented by using **Menu** control. On the left side some random examples from Dribbble and on the right side there is my implementation.
In this section I've collected some examples of what can be i,plemented do using **Menu** control. On the left side some random example from Dribbble and on the right side my implementation.
| Dribbble | Menu |
| ------------- |:-------------:|
| Dribbble | Menu | Code |
| ------------- |:-------------:|:-------------:|
| [link](https://dribbble.com/shots/4233782-Snooze-notifications-in-Twist) | |
| ![](examples/twist.png) | ![](examples/example_twist.png) |
| ![](examples/twist.png) | ![](examples/menu_twist.png) | |
| [link](https://dribbble.com/shots/7055473-Dropdowns) | | |
| ![](examples/example_0.png) | ![](examples/menu_0.png) | [code](examples/examples.md) |
## Credits
+9 -7
View File
@@ -11,11 +11,14 @@ 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.configuration = configuration
self.hoverColor = configuration.menuItemHoverBackgroundColor
self.hoverAnimationDuration = configuration.menuItemHoverAnimationDuration
super.init(frame: .zero)
wantsLayer = true
@@ -30,8 +33,7 @@ class Control: NSControl {
override func layout() {
super.layout()
let newRect = bounds.inset(by: configuration.menuItemHoverEdgeInsets)
hoverLayer.path = CGPath(roundedRect: newRect, cornerWidth: configuration.menuItemHoverCornerRadius, cornerHeight: configuration.menuItemHoverCornerRadius, transform: nil)
hoverLayer.path = CGPath(rect: bounds, transform: nil)
if let trackingArea = trackingArea, trackingAreas.contains(trackingArea) {
removeTrackingArea(trackingArea)
@@ -59,13 +61,13 @@ class Control: NSControl {
override func mouseEntered(with event: NSEvent) {
guard isEnabled else { return }
animateFillColor(from: .clear, to: configuration.menuItemHoverBackgroundColor)
animateFillColor(from: .clear, to: hoverColor)
hover?(true)
}
override func mouseExited(with event: NSEvent) {
guard isEnabled else { return }
animateFillColor(from: configuration.menuItemHoverBackgroundColor, to: .clear)
animateFillColor(from: hoverColor, to: .clear)
hover?(false)
}
@@ -76,7 +78,7 @@ class Control: NSControl {
private func animateFillColor(from oldColor: NSColor, to newColor: NSColor) {
let animation = CABasicAnimation(keyPath: "fillColor")
animation.duration = configuration.menuItemHoverAnimationDuration
animation.duration = hoverAnimationDuration
animation.fromValue = oldColor.cgColor
animation.toValue = newColor.cgColor
animation.fillMode = .both
-11
View File
@@ -190,14 +190,3 @@ 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
}
}
+2 -21
View File
@@ -65,14 +65,6 @@ 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)
@@ -226,23 +218,12 @@ 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(view.frame)))
let rectInWindow = NSRect(origin: locationInWindow, size: CGSize(width: NSWidth(view.frame), height: NSHeight(window.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
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))
}
let newFrame = NSRect(x: origin.x, 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,13 +12,6 @@ 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
@@ -61,7 +54,6 @@ 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 }
@@ -78,8 +70,6 @@ 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 }
@@ -122,10 +112,6 @@ open class MenuConfiguration: Configuration {
return true
}
open var appearancePosition: Position {
return .rightBottom
}
open var presentingOffset: CGFloat {
return 0.0
}
@@ -186,14 +172,6 @@ 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
}
+4 -6
View File
@@ -208,12 +208,10 @@ class MenuElement: NSView {
control.isEnabled = isEnabled
control.hover = { [weak self] isHover in
guard let self = self else { return }
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
}
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
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

+38
View File
@@ -0,0 +1,38 @@
## Example
![](menu_0.png)
### Code:
```
class Config: MenuConfiguration {
override var cornerRadius: CGFloat {
return 15.0
}
override var backgroundColor: NSColor {
return NSColor(red: 63/255, green: 59/255, blue: 59/255, alpha: 1.0)
}
override var menuItemHoverBackgroundColor: NSColor {
return NSColor(red: 86/255, green: 81/255, blue: 81/255, alpha: 1.0)
}
override var menuItemHoverCornerRadius: CGFloat {
return 10.0
}
override var contentEdgeInsets: NSEdgeInsets {
return NSEdgeInsets(top: 8, left: 16, bottom: 8, right: 16)
}
override var menuItemHeight: CGFloat {
return 40.0
}
override var menuItemHoverEdgeInsets: NSEdgeInsets {
return NSEdgeInsets(top: 0, left: 8, bottom: 0, right: 8)
}
}
```
Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 KiB