Skip to content

Instantly share code, notes, and snippets.

@bubudrc
Created June 2, 2020 23:28
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bubudrc/fd2785080420e5c118a0cec0d49d9616 to your computer and use it in GitHub Desktop.
Save bubudrc/fd2785080420e5c118a0cec0d49d9616 to your computer and use it in GitHub Desktop.
macOS - NSButton. Custom view to works like a circular button, but full customizer
//
// MWPCircularButton.swift
// StoreVisualizer
//
// Created by Perretta, Marcelo on 5/19/20.
// Copyright © 2020 MAWAPE Mobile. All rights reserved.
//
import Cocoa
import AppKit
protocol MWPCircularButtonDelegate: AnyObject {
func userDidClickedLeftButton(sender: MWPCircularButton)
}
@IBDesignable
open class MWPCircularButton: NSView {
@IBInspectable
public var backgroundColor: NSColor = .white{
didSet {
self.needsDisplay = true
}
}
@IBInspectable
public var highlightBackgroundColor: NSColor = .blue {
didSet {
self.needsDisplay = true
}
}
@IBInspectable
public var titleButton: String = String.warning {
didSet {
self.needsDisplay = true
}
}
@IBInspectable
public var fontSize: CGFloat = 24.0
@IBInspectable
public var titleYPosition: CGFloat = 7.0
@IBInspectable
public var titleColor: NSColor = .white
@IBInspectable
public var isEnabled: Bool = true
@IBInspectable
public var borderWidth: CGFloat = 0
@IBInspectable
public var borderColor: NSColor = .clear
weak var circularButtonDelegate: MWPCircularButtonDelegate?
override open func draw(_ dirtyRect: NSRect) {
super.draw(dirtyRect)
// Drawing code here.
let path = NSBezierPath(ovalIn: dirtyRect)
backgroundColor.setFill()
path.fill()
if borderWidth > 0 {
let borderRect = CGRect(x: 1.2, y: 1.2, width: self.bounds.size.width-borderWidth, height: self.bounds.size.height-borderWidth)
let border = CAShapeLayer()
border.frame = borderRect
border.lineWidth = borderWidth
border.path = NSBezierPath(ovalIn: borderRect).CGPath
border.strokeColor = borderColor.cgColor
border.fillColor = NSColor.clear.cgColor
self.layer?.addSublayer(border)
}
let textRect = NSRect(x: 0, y: 0, width: self.frame.width, height: self.frame.height)
let textTextContent = titleButton
let textStyle = NSMutableParagraphStyle()
textStyle.alignment = .center
let textFontAttributes = [NSAttributedString.Key.font: NSFont.systemFont(ofSize: fontSize), NSAttributedString.Key.foregroundColor: titleColor, NSAttributedString.Key.paragraphStyle: textStyle]
let textTextHeight: CGFloat = textTextContent.boundingRect(with: NSSize(width: textRect.width, height: CGFloat.infinity), options: NSString.DrawingOptions.usesLineFragmentOrigin, attributes: textFontAttributes).height
let textTextRect: NSRect = NSRect(x: 0, y:titleYPosition, width: textRect.width, height: textTextHeight)
NSGraphicsContext.saveGraphicsState()
textRect.clip()
textTextContent.draw(in: textTextRect.offsetBy(dx: 0, dy: 0), withAttributes: textFontAttributes)
NSGraphicsContext.restoreGraphicsState()
}
override open func mouseDown(with event: NSEvent) {
//TODO: highlight color / font
}
override open func mouseUp(with event: NSEvent) {
if isEnabled {
circularButtonDelegate?.userDidClickedLeftButton(sender: self)
}
}
}
public extension NSBezierPath {
var CGPath: CGPath {
let path = CGMutablePath()
var points = [CGPoint](repeating: .zero, count: 3)
for i in 0 ..< self.elementCount {
let type = self.element(at: i, associatedPoints: &points)
switch type {
case .moveTo:
path.move(to: CGPoint(x: points[0].x, y: points[0].y) )
case .lineTo:
path.addLine(to: CGPoint(x: points[0].x, y: points[0].y) )
case .curveTo:
path.addCurve( to: CGPoint(x: points[2].x, y: points[2].y),
control1: CGPoint(x: points[0].x, y: points[0].y),
control2: CGPoint(x: points[1].x, y: points[1].y) )
case .closePath:
path.closeSubpath()
@unknown default:
break
}
}
return path
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment