blob: 80c8d25b97de0892d7f8963b38ad84374c17c99e [file] [log] [blame]
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
#if os(OSX) || os(iOS)
import Darwin
#elseif os(Linux) || CYGWIN
import Glibc
#endif
public struct CGPoint {
public var x: CGFloat
public var y: CGFloat
public init() {
self.init(x: CGFloat(), y: CGFloat())
}
public init(x: CGFloat, y: CGFloat) {
self.x = x
self.y = y
}
}
extension CGPoint {
public static var zero: CGPoint {
return CGPoint(x: CGFloat(0), y: CGFloat(0))
}
public init(x: Int, y: Int) {
self.init(x: CGFloat(x), y: CGFloat(y))
}
public init(x: Double, y: Double) {
self.init(x: CGFloat(x), y: CGFloat(y))
}
}
extension CGPoint: Equatable {
public static func ==(lhs: CGPoint, rhs: CGPoint) -> Bool {
return lhs.x == rhs.x && lhs.y == rhs.y
}
}
extension CGPoint: NSSpecialValueCoding {
init(bytes: UnsafeRawPointer) {
self.x = bytes.load(as: CGFloat.self)
self.y = bytes.load(fromByteOffset: MemoryLayout<CGFloat>.stride, as: CGFloat.self)
}
init?(coder aDecoder: NSCoder) {
guard aDecoder.allowsKeyedCoding else {
preconditionFailure("Unkeyed coding is unsupported.")
}
self = aDecoder.decodePoint(forKey: "NS.pointval")
}
func encodeWithCoder(_ aCoder: NSCoder) {
guard aCoder.allowsKeyedCoding else {
preconditionFailure("Unkeyed coding is unsupported.")
}
aCoder.encode(self, forKey: "NS.pointval")
}
static func objCType() -> String {
return "{CGPoint=dd}"
}
func getValue(_ value: UnsafeMutableRawPointer) {
value.initializeMemory(as: CGPoint.self, to: self)
}
func isEqual(_ aValue: Any) -> Bool {
if let other = aValue as? CGPoint {
return other == self
} else {
return false
}
}
var hash: Int {
return self.x.hashValue &+ self.y.hashValue
}
var description: String {
return NSStringFromPoint(self)
}
}
extension CGPoint : Codable {
public init(from decoder: Decoder) throws {
var container = try decoder.unkeyedContainer()
let x = try container.decode(CGFloat.self)
let y = try container.decode(CGFloat.self)
self.init(x: x, y: y)
}
public func encode(to encoder: Encoder) throws {
var container = encoder.unkeyedContainer()
try container.encode(x)
try container.encode(y)
}
}
public struct CGSize {
public var width: CGFloat
public var height: CGFloat
public init() {
self.init(width: CGFloat(), height: CGFloat())
}
public init(width: CGFloat, height: CGFloat) {
self.width = width
self.height = height
}
}
extension CGSize {
public static var zero: CGSize {
return CGSize(width: CGFloat(0), height: CGFloat(0))
}
public init(width: Int, height: Int) {
self.init(width: CGFloat(width), height: CGFloat(height))
}
public init(width: Double, height: Double) {
self.init(width: CGFloat(width), height: CGFloat(height))
}
}
extension CGSize: Equatable {
public static func ==(lhs: CGSize, rhs: CGSize) -> Bool {
return lhs.width == rhs.width && lhs.height == rhs.height
}
}
extension CGSize: NSSpecialValueCoding {
init(bytes: UnsafeRawPointer) {
self.width = bytes.load(as: CGFloat.self)
self.height = bytes.load(fromByteOffset: MemoryLayout<CGFloat>.stride, as: CGFloat.self)
}
init?(coder aDecoder: NSCoder) {
guard aDecoder.allowsKeyedCoding else {
preconditionFailure("Unkeyed coding is unsupported.")
}
self = aDecoder.decodeSize(forKey: "NS.sizeval")
}
func encodeWithCoder(_ aCoder: NSCoder) {
guard aCoder.allowsKeyedCoding else {
preconditionFailure("Unkeyed coding is unsupported.")
}
aCoder.encode(self, forKey: "NS.sizeval")
}
static func objCType() -> String {
return "{CGSize=dd}"
}
func getValue(_ value: UnsafeMutableRawPointer) {
value.initializeMemory(as: CGSize.self, to: self)
}
func isEqual(_ aValue: Any) -> Bool {
if let other = aValue as? CGSize {
return other == self
} else {
return false
}
}
var hash: Int {
return self.width.hashValue &+ self.height.hashValue
}
var description: String {
return NSStringFromSize(self)
}
}
extension CGSize : Codable {
public init(from decoder: Decoder) throws {
var container = try decoder.unkeyedContainer()
let width = try container.decode(CGFloat.self)
let height = try container.decode(CGFloat.self)
self.init(width: width, height: height)
}
public func encode(to encoder: Encoder) throws {
var container = encoder.unkeyedContainer()
try container.encode(width)
try container.encode(height)
}
}
public struct CGRect {
public var origin: CGPoint
public var size: CGSize
public init() {
self.init(origin: CGPoint(), size: CGSize())
}
public init(origin: CGPoint, size: CGSize) {
self.origin = origin
self.size = size
}
}
extension CGRect {
public static var zero: CGRect {
return CGRect(origin: CGPoint(), size: CGSize())
}
public init(x: CGFloat, y: CGFloat, width: CGFloat, height: CGFloat) {
self.init(origin: CGPoint(x: x, y: y), size: CGSize(width: width, height: height))
}
public init(x: Double, y: Double, width: Double, height: Double) {
self.init(origin: CGPoint(x: x, y: y), size: CGSize(width: width, height: height))
}
public init(x: Int, y: Int, width: Int, height: Int) {
self.init(origin: CGPoint(x: x, y: y), size: CGSize(width: width, height: height))
}
}
extension CGRect {
public static let null = CGRect(x: CGFloat.infinity,
y: CGFloat.infinity,
width: CGFloat(0),
height: CGFloat(0))
public static let infinite = CGRect(x: -CGFloat.greatestFiniteMagnitude / 2,
y: -CGFloat.greatestFiniteMagnitude / 2,
width: CGFloat.greatestFiniteMagnitude,
height: CGFloat.greatestFiniteMagnitude)
}
extension CGRect: Equatable {
public static func ==(lhs: CGRect, rhs: CGRect) -> Bool {
return lhs.origin == rhs.origin && lhs.size == rhs.size
}
}
extension CGRect : Codable {
public init(from decoder: Decoder) throws {
var container = try decoder.unkeyedContainer()
let origin = try container.decode(CGPoint.self)
let size = try container.decode(CGSize.self)
self.init(origin: origin, size: size)
}
public func encode(to encoder: Encoder) throws {
var container = encoder.unkeyedContainer()
try container.encode(origin)
try container.encode(size)
}
}
public typealias NSPoint = CGPoint
public typealias NSPointPointer = UnsafeMutablePointer<NSPoint>
public typealias NSPointArray = UnsafeMutablePointer<NSPoint>
public typealias NSSize = CGSize
public typealias NSSizePointer = UnsafeMutablePointer<NSSize>
public typealias NSSizeArray = UnsafeMutablePointer<NSSize>
public typealias NSRect = CGRect
public typealias NSRectPointer = UnsafeMutablePointer<NSRect>
public typealias NSRectArray = UnsafeMutablePointer<NSRect>
extension CGRect: NSSpecialValueCoding {
init(bytes: UnsafeRawPointer) {
self.origin = CGPoint(
x: bytes.load(as: CGFloat.self),
y: bytes.load(fromByteOffset: 1 * MemoryLayout<CGFloat>.stride, as: CGFloat.self))
self.size = CGSize(
width: bytes.load(fromByteOffset: 2 * MemoryLayout<CGFloat>.stride, as: CGFloat.self),
height: bytes.load(fromByteOffset: 3 * MemoryLayout<CGFloat>.stride, as: CGFloat.self))
}
init?(coder aDecoder: NSCoder) {
guard aDecoder.allowsKeyedCoding else {
preconditionFailure("Unkeyed coding is unsupported.")
}
self = aDecoder.decodeRect(forKey: "NS.rectval")
}
func encodeWithCoder(_ aCoder: NSCoder) {
guard aCoder.allowsKeyedCoding else {
preconditionFailure("Unkeyed coding is unsupported.")
}
aCoder.encode(self, forKey: "NS.rectval")
}
static func objCType() -> String {
return "{CGRect={CGPoint=dd}{CGSize=dd}}"
}
func getValue(_ value: UnsafeMutableRawPointer) {
value.initializeMemory(as: CGRect.self, to: self)
}
func isEqual(_ aValue: Any) -> Bool {
if let other = aValue as? CGRect {
return other == self
} else {
return false
}
}
var hash: Int {
return self.origin.hash &+ self.size.hash
}
var description: String {
return NSStringFromRect(self)
}
}
public enum NSRectEdge : UInt {
case minX
case minY
case maxX
case maxY
}
public enum CGRectEdge : UInt32 {
case minXEdge
case minYEdge
case maxXEdge
case maxYEdge
}
extension NSRectEdge {
public init(rectEdge: CGRectEdge) {
switch rectEdge {
case .minXEdge: self = .minX
case .minYEdge: self = .minY
case .maxXEdge: self = .maxX
case .maxYEdge: self = .maxY
}
}
}
public struct NSEdgeInsets {
public var top: CGFloat
public var left: CGFloat
public var bottom: CGFloat
public var right: CGFloat
public init() {
self.init(top: CGFloat(), left: CGFloat(), bottom: CGFloat(), right: CGFloat())
}
public init(top: CGFloat, left: CGFloat, bottom: CGFloat, right: CGFloat) {
self.top = top
self.left = left
self.bottom = bottom
self.right = right
}
}
extension NSEdgeInsets: NSSpecialValueCoding {
init(bytes: UnsafeRawPointer) {
self.top = bytes.load(as: CGFloat.self)
self.left = bytes.load(fromByteOffset: MemoryLayout<CGFloat>.stride, as: CGFloat.self)
self.bottom = bytes.load(fromByteOffset: 2 * MemoryLayout<CGFloat>.stride, as: CGFloat.self)
self.right = bytes.load(fromByteOffset: 3 * MemoryLayout<CGFloat>.stride, as: CGFloat.self)
}
init?(coder aDecoder: NSCoder) {
guard aDecoder.allowsKeyedCoding else {
preconditionFailure("Unkeyed coding is unsupported.")
}
self.top = aDecoder._decodeCGFloatForKey("NS.edgeval.top")
self.left = aDecoder._decodeCGFloatForKey("NS.edgeval.left")
self.bottom = aDecoder._decodeCGFloatForKey("NS.edgeval.bottom")
self.right = aDecoder._decodeCGFloatForKey("NS.edgeval.right")
}
func encodeWithCoder(_ aCoder: NSCoder) {
guard aCoder.allowsKeyedCoding else {
preconditionFailure("Unkeyed coding is unsupported.")
}
aCoder._encodeCGFloat(self.top, forKey: "NS.edgeval.top")
aCoder._encodeCGFloat(self.left, forKey: "NS.edgeval.left")
aCoder._encodeCGFloat(self.bottom, forKey: "NS.edgeval.bottom")
aCoder._encodeCGFloat(self.right, forKey: "NS.edgeval.right")
}
static func objCType() -> String {
return "{NSEdgeInsets=dddd}"
}
func getValue(_ value: UnsafeMutableRawPointer) {
value.initializeMemory(as: NSEdgeInsets.self, to: self)
}
func isEqual(_ aValue: Any) -> Bool {
if let other = aValue as? NSEdgeInsets {
return other.top == self.top && other.left == self.left &&
other.bottom == self.bottom && other.right == self.right
} else {
return false
}
}
var hash: Int {
return self.top.hashValue &+ self.left.hashValue &+ self.bottom.hashValue &+ self.right.hashValue
}
var description: String {
return ""
}
}
public struct AlignmentOptions : OptionSet {
public var rawValue : UInt64
public init(rawValue: UInt64) { self.rawValue = rawValue }
public static let alignMinXInward = AlignmentOptions(rawValue: 1 << 0)
public static let alignMinYInward = AlignmentOptions(rawValue: 1 << 1)
public static let alignMaxXInward = AlignmentOptions(rawValue: 1 << 2)
public static let alignMaxYInward = AlignmentOptions(rawValue: 1 << 3)
public static let alignWidthInward = AlignmentOptions(rawValue: 1 << 4)
public static let alignHeightInward = AlignmentOptions(rawValue: 1 << 5)
public static let alignMinXOutward = AlignmentOptions(rawValue: 1 << 8)
public static let alignMinYOutward = AlignmentOptions(rawValue: 1 << 9)
public static let alignMaxXOutward = AlignmentOptions(rawValue: 1 << 10)
public static let alignMaxYOutward = AlignmentOptions(rawValue: 1 << 11)
public static let alignWidthOutward = AlignmentOptions(rawValue: 1 << 12)
public static let alignHeightOutward = AlignmentOptions(rawValue: 1 << 13)
public static let alignMinXNearest = AlignmentOptions(rawValue: 1 << 16)
public static let alignMinYNearest = AlignmentOptions(rawValue: 1 << 17)
public static let alignMaxXNearest = AlignmentOptions(rawValue: 1 << 18)
public static let alignMaxYNearest = AlignmentOptions(rawValue: 1 << 19)
public static let alignWidthNearest = AlignmentOptions(rawValue: 1 << 20)
public static let alignHeightNearest = AlignmentOptions(rawValue: 1 << 21)
// pass this if the rect is in a flipped coordinate system. This allows 0.5 to be treated in a visually consistent way.
public static let alignRectFlipped = AlignmentOptions(rawValue: 1 << 63)
// convenience combinations
public static let alignAllEdgesInward: AlignmentOptions = [.alignMinXInward, .alignMaxXInward, .alignMinYInward, .alignMaxYInward]
public static let alignAllEdgesOutward: AlignmentOptions = [.alignMinXOutward, .alignMaxXOutward, .alignMinYOutward, .alignMaxYOutward]
public static let alignAllEdgesNearest: AlignmentOptions = [.alignMinXNearest, .alignMaxXNearest, .alignMinYNearest, .alignMaxYNearest]
}
public let NSZeroPoint: NSPoint = NSPoint()
public let NSZeroSize: NSSize = NSSize()
public let NSZeroRect: NSRect = NSRect()
public let NSEdgeInsetsZero: NSEdgeInsets = NSEdgeInsets()
public func NSMakePoint(_ x: CGFloat, _ y: CGFloat) -> NSPoint {
return NSPoint(x: x, y: y)
}
public func NSMakeSize(_ w: CGFloat, _ h: CGFloat) -> NSSize {
return NSSize(width: w, height: h)
}
public func NSMakeRect(_ x: CGFloat, _ y: CGFloat, _ w: CGFloat, _ h: CGFloat) -> NSRect {
return NSRect(origin: NSPoint(x: x, y: y), size: NSSize(width: w, height: h))
}
public func NSMaxX(_ aRect: NSRect) -> CGFloat { return CGFloat(aRect.origin.x.native + aRect.size.width.native) }
public func NSMaxY(_ aRect: NSRect) -> CGFloat { return CGFloat(aRect.origin.y.native + aRect.size.height.native) }
public func NSMidX(_ aRect: NSRect) -> CGFloat { return CGFloat(aRect.origin.x.native + (aRect.size.width.native / 2)) }
public func NSMidY(_ aRect: NSRect) -> CGFloat { return CGFloat(aRect.origin.y.native + (aRect.size.height.native / 2)) }
public func NSMinX(_ aRect: NSRect) -> CGFloat { return aRect.origin.x }
public func NSMinY(_ aRect: NSRect) -> CGFloat { return aRect.origin.y }
public func NSWidth(_ aRect: NSRect) -> CGFloat { return aRect.size.width }
public func NSHeight(_ aRect: NSRect) -> CGFloat { return aRect.size.height }
public func NSRectFromCGRect(_ cgrect: CGRect) -> NSRect { return cgrect }
public func NSRectToCGRect(_ nsrect: NSRect) -> CGRect { return nsrect }
public func NSPointFromCGPoint(_ cgpoint: CGPoint) -> NSPoint { return cgpoint }
public func NSPointToCGPoint(_ nspoint: NSPoint) -> CGPoint { return nspoint }
public func NSSizeFromCGSize(_ cgsize: CGSize) -> NSSize { return cgsize }
public func NSSizeToCGSize(_ nssize: NSSize) -> CGSize { return nssize }
public func NSEdgeInsetsMake(_ top: CGFloat, _ left: CGFloat, _ bottom: CGFloat, _ right: CGFloat) -> NSEdgeInsets {
return NSEdgeInsets(top: top, left: left, bottom: bottom, right: right)
}
public func NSEqualPoints(_ aPoint: NSPoint, _ bPoint: NSPoint) -> Bool { return aPoint == bPoint }
public func NSEqualSizes(_ aSize: NSSize, _ bSize: NSSize) -> Bool { return aSize == bSize }
public func NSEqualRects(_ aRect: NSRect, _ bRect: NSRect) -> Bool { return aRect == bRect }
public func NSIsEmptyRect(_ aRect: NSRect) -> Bool { return (aRect.size.width.native <= 0) || (aRect.size.height.native <= 0) }
public func NSEdgeInsetsEqual(_ aInsets: NSEdgeInsets, _ bInsets: NSEdgeInsets) -> Bool {
return (aInsets.top == bInsets.top) && (aInsets.left == bInsets.left) && (aInsets.bottom == bInsets.bottom) && (aInsets.right == bInsets.right)
}
public func NSInsetRect(_ aRect: NSRect, _ dX: CGFloat, _ dY: CGFloat) -> NSRect {
let x = CGFloat(aRect.origin.x.native + dX.native)
let y = CGFloat(aRect.origin.y.native + dY.native)
let w = CGFloat(aRect.size.width.native - (dX.native * 2))
let h = CGFloat(aRect.size.height.native - (dY.native * 2))
return NSMakeRect(x, y, w, h)
}
public func NSIntegralRect(_ aRect: NSRect) -> NSRect {
if aRect.size.height.native <= 0 || aRect.size.width.native <= 0 {
return NSZeroRect
}
return NSIntegralRectWithOptions(aRect, [.alignMinXOutward, .alignMaxXOutward, .alignMinYOutward, .alignMaxYOutward])
}
public func NSIntegralRectWithOptions(_ aRect: NSRect, _ opts: AlignmentOptions) -> NSRect {
let listOfOptionsIsInconsistentErrorMessage = "List of options is inconsistent"
if opts.contains(.alignRectFlipped) {
NSUnimplemented()
}
var width = CGFloat.NativeType.nan
var height = CGFloat.NativeType.nan
var minX = CGFloat.NativeType.nan
var minY = CGFloat.NativeType.nan
var maxX = CGFloat.NativeType.nan
var maxY = CGFloat.NativeType.nan
if aRect.size.height.native < 0 {
height = 0
}
if aRect.size.width.native < 0 {
width = 0
}
if opts.contains(.alignWidthInward) && width != 0 {
guard width.isNaN else { fatalError(listOfOptionsIsInconsistentErrorMessage) }
width = floor(aRect.size.width.native)
}
if opts.contains(.alignHeightInward) && height != 0 {
guard height.isNaN else { fatalError(listOfOptionsIsInconsistentErrorMessage) }
height = floor(aRect.size.height.native)
}
if opts.contains(.alignWidthOutward) && width != 0 {
guard width.isNaN else { fatalError(listOfOptionsIsInconsistentErrorMessage) }
width = ceil(aRect.size.width.native)
}
if opts.contains(.alignHeightOutward) && height != 0 {
guard height.isNaN else { fatalError(listOfOptionsIsInconsistentErrorMessage) }
height = ceil(aRect.size.height.native)
}
if opts.contains(.alignWidthNearest) && width != 0 {
guard width.isNaN else { fatalError(listOfOptionsIsInconsistentErrorMessage) }
width = round(aRect.size.width.native)
}
if opts.contains(.alignHeightNearest) && height != 0 {
guard height.isNaN else { fatalError(listOfOptionsIsInconsistentErrorMessage) }
height = round(aRect.size.height.native)
}
if opts.contains(.alignMinXInward) {
guard minX.isNaN else { fatalError(listOfOptionsIsInconsistentErrorMessage) }
minX = ceil(aRect.origin.x.native)
}
if opts.contains(.alignMinYInward) {
guard minY.isNaN else { fatalError(listOfOptionsIsInconsistentErrorMessage) }
minY = ceil(aRect.origin.y.native)
}
if opts.contains(.alignMaxXInward) {
guard maxX.isNaN else { fatalError(listOfOptionsIsInconsistentErrorMessage) }
maxX = floor(aRect.origin.x.native + aRect.size.width.native)
}
if opts.contains(.alignMaxYInward) {
guard maxY.isNaN else { fatalError(listOfOptionsIsInconsistentErrorMessage) }
maxY = floor(aRect.origin.y.native + aRect.size.height.native)
}
if opts.contains(.alignMinXOutward) {
guard minX.isNaN else { fatalError(listOfOptionsIsInconsistentErrorMessage) }
minX = floor(aRect.origin.x.native)
}
if opts.contains(.alignMinYOutward) {
guard minY.isNaN else { fatalError(listOfOptionsIsInconsistentErrorMessage) }
minY = floor(aRect.origin.y.native)
}
if opts.contains(.alignMaxXOutward) {
guard maxX.isNaN else { fatalError(listOfOptionsIsInconsistentErrorMessage) }
maxX = ceil(aRect.origin.x.native + aRect.size.width.native)
}
if opts.contains(.alignMaxYOutward) {
guard maxY.isNaN else { fatalError(listOfOptionsIsInconsistentErrorMessage) }
maxY = ceil(aRect.origin.y.native + aRect.size.height.native)
}
if opts.contains(.alignMinXNearest) {
guard minX.isNaN else { fatalError(listOfOptionsIsInconsistentErrorMessage) }
minX = round(aRect.origin.x.native)
}
if opts.contains(.alignMinYNearest) {
guard minY.isNaN else { fatalError(listOfOptionsIsInconsistentErrorMessage) }
minY = round(aRect.origin.y.native)
}
if opts.contains(.alignMaxXNearest) {
guard maxX.isNaN else { fatalError(listOfOptionsIsInconsistentErrorMessage) }
maxX = round(aRect.origin.x.native + aRect.size.width.native)
}
if opts.contains(.alignMaxYNearest) {
guard maxY.isNaN else { fatalError(listOfOptionsIsInconsistentErrorMessage) }
maxY = round(aRect.origin.y.native + aRect.size.height.native)
}
var resultOriginX = CGFloat.NativeType.nan
var resultOriginY = CGFloat.NativeType.nan
var resultWidth = CGFloat.NativeType.nan
var resultHeight = CGFloat.NativeType.nan
if !minX.isNaN {
resultOriginX = minX
}
if !width.isNaN {
resultWidth = width
}
if !maxX.isNaN {
if width.isNaN {
guard resultWidth.isNaN else { fatalError(listOfOptionsIsInconsistentErrorMessage) }
resultWidth = maxX - minX
} else {
guard resultOriginX.isNaN else { fatalError(listOfOptionsIsInconsistentErrorMessage) }
resultOriginX = maxX - width
}
}
if !minY.isNaN {
resultOriginY = minY
}
if !height.isNaN {
resultHeight = height
}
if !maxY.isNaN {
if height.isNaN {
guard resultHeight.isNaN else { fatalError(listOfOptionsIsInconsistentErrorMessage) }
resultHeight = maxY - minY
} else {
guard resultOriginY.isNaN else { fatalError(listOfOptionsIsInconsistentErrorMessage) }
resultOriginY = maxY - height
}
}
if resultOriginX.isNaN || resultOriginY.isNaN
|| resultHeight.isNaN || resultWidth.isNaN {
fatalError(listOfOptionsIsInconsistentErrorMessage)
}
var result = NSZeroRect
result.origin.x.native = resultOriginX
result.origin.y.native = resultOriginY
result.size.width.native = resultWidth
result.size.height.native = resultHeight
return result
}
public func NSUnionRect(_ aRect: NSRect, _ bRect: NSRect) -> NSRect {
let isEmptyFirstRect = NSIsEmptyRect(aRect)
let isEmptySecondRect = NSIsEmptyRect(bRect)
if isEmptyFirstRect && isEmptySecondRect {
return NSZeroRect
} else if isEmptyFirstRect {
return bRect
} else if isEmptySecondRect {
return aRect
}
let x = min(NSMinX(aRect), NSMinX(bRect))
let y = min(NSMinY(aRect), NSMinY(bRect))
let width = max(NSMaxX(aRect), NSMaxX(bRect)) - x
let height = max(NSMaxY(aRect), NSMaxY(bRect)) - y
return NSMakeRect(x, y, width, height)
}
public func NSIntersectionRect(_ aRect: NSRect, _ bRect: NSRect) -> NSRect {
if NSMaxX(aRect) <= NSMinX(bRect) || NSMaxX(bRect) <= NSMinX(aRect) || NSMaxY(aRect) <= NSMinY(bRect) || NSMaxY(bRect) <= NSMinY(aRect) {
return NSZeroRect
}
let x = max(NSMinX(aRect), NSMinX(bRect))
let y = max(NSMinY(aRect), NSMinY(bRect))
let width = min(NSMaxX(aRect), NSMaxX(bRect)) - x
let height = min(NSMaxY(aRect), NSMaxY(bRect)) - y
return NSMakeRect(x, y, width, height)
}
public func NSOffsetRect(_ aRect: NSRect, _ dX: CGFloat, _ dY: CGFloat) -> NSRect {
var result = aRect
result.origin.x += dX
result.origin.y += dY
return result
}
public func NSDivideRect(_ inRect: NSRect, _ slice: UnsafeMutablePointer<NSRect>, _ rem: UnsafeMutablePointer<NSRect>, _ amount: CGFloat, _ edge: NSRectEdge) {
if NSIsEmptyRect(inRect) {
slice.pointee = NSZeroRect
rem.pointee = NSZeroRect
return
}
let width = NSWidth(inRect)
let height = NSHeight(inRect)
switch (edge, amount) {
case (.minX, let amount) where amount > width:
slice.pointee = inRect
rem.pointee = NSMakeRect(NSMaxX(inRect), NSMinY(inRect), CGFloat(0.0), height)
case (.minX, _):
slice.pointee = NSMakeRect(NSMinX(inRect), NSMinY(inRect), amount, height)
rem.pointee = NSMakeRect(NSMaxX(slice.pointee), NSMinY(inRect), NSMaxX(inRect) - NSMaxX(slice.pointee), height)
case (.minY, let amount) where amount > height:
slice.pointee = inRect
rem.pointee = NSMakeRect(NSMinX(inRect), NSMaxY(inRect), width, CGFloat(0.0))
case (.minY, _):
slice.pointee = NSMakeRect(NSMinX(inRect), NSMinY(inRect), width, amount)
rem.pointee = NSMakeRect(NSMinX(inRect), NSMaxY(slice.pointee), width, NSMaxY(inRect) - NSMaxY(slice.pointee))
case (.maxX, let amount) where amount > width:
slice.pointee = inRect
rem.pointee = NSMakeRect(NSMinX(inRect), NSMinY(inRect), CGFloat(0.0), height)
case (.maxX, _):
slice.pointee = NSMakeRect(NSMaxX(inRect) - amount, NSMinY(inRect), amount, height)
rem.pointee = NSMakeRect(NSMinX(inRect), NSMinY(inRect), NSMinX(slice.pointee) - NSMinX(inRect), height)
case (.maxY, let amount) where amount > height:
slice.pointee = inRect
rem.pointee = NSMakeRect(NSMinX(inRect), NSMinY(inRect), width, CGFloat(0.0))
case (.maxY, _):
slice.pointee = NSMakeRect(NSMinX(inRect), NSMaxY(inRect) - amount, width, amount)
rem.pointee = NSMakeRect(NSMinX(inRect), NSMinY(inRect), width, NSMinY(slice.pointee) - NSMinY(inRect))
}
}
public func NSPointInRect(_ aPoint: NSPoint, _ aRect: NSRect) -> Bool {
return NSMouseInRect(aPoint, aRect, true)
}
public func NSMouseInRect(_ aPoint: NSPoint, _ aRect: NSRect, _ flipped: Bool) -> Bool {
if flipped {
return aPoint.x >= NSMinX(aRect) && aPoint.y >= NSMinX(aRect) && aPoint.x < NSMaxX(aRect) && aPoint.y < NSMaxY(aRect)
}
return aPoint.x >= NSMinX(aRect) && aPoint.y > NSMinY(aRect) && aPoint.x < NSMaxX(aRect) && aPoint.y <= NSMaxY(aRect)
}
public func NSContainsRect(_ aRect: NSRect, _ bRect: NSRect) -> Bool {
return !NSIsEmptyRect(bRect) && NSMaxX(bRect) <= NSMaxX(aRect) && NSMinX(bRect) >= NSMinX(aRect) &&
NSMaxY(bRect) <= NSMaxY(aRect) && NSMinY(bRect) >= NSMinY(aRect)
}
public func NSIntersectsRect(_ aRect: NSRect, _ bRect: NSRect) -> Bool {
return !(NSIsEmptyRect(aRect) || NSIsEmptyRect(bRect) ||
NSMaxX(aRect) <= NSMinX(bRect) || NSMaxX(bRect) <= NSMinX(aRect) || NSMaxY(aRect) <= NSMinY(bRect) || NSMaxY(bRect) <= NSMinY(aRect))
}
public func NSStringFromPoint(_ aPoint: NSPoint) -> String {
return "{\(aPoint.x.native), \(aPoint.y.native)}"
}
public func NSStringFromSize(_ aSize: NSSize) -> String {
return "{\(aSize.width.native), \(aSize.height.native)}"
}
public func NSStringFromRect(_ aRect: NSRect) -> String {
let originString = NSStringFromPoint(aRect.origin)
let sizeString = NSStringFromSize(aRect.size)
return "{\(originString), \(sizeString)}"
}
private func _scanDoublesFromString(_ aString: String, number: Int) -> [Double] {
let scanner = Scanner(string: aString)
var digitSet = CharacterSet.decimalDigits
digitSet.insert(charactersIn: "-")
var result = [Double](repeating: 0.0, count: number)
var index = 0
let _ = scanner.scanUpToCharactersFromSet(digitSet)
while !scanner.isAtEnd && index < number {
if let num = scanner.scanDouble() {
result[index] = num
}
let _ = scanner.scanUpToCharactersFromSet(digitSet)
index += 1
}
return result
}
public func NSPointFromString(_ aString: String) -> NSPoint {
if aString.isEmpty {
return NSZeroPoint
}
let parsedNumbers = _scanDoublesFromString(aString, number: 2)
let x = parsedNumbers[0]
let y = parsedNumbers[1]
let result = NSMakePoint(CGFloat(x), CGFloat(y))
return result
}
public func NSSizeFromString(_ aString: String) -> NSSize {
if aString.isEmpty {
return NSZeroSize
}
let parsedNumbers = _scanDoublesFromString(aString, number: 2)
let w = parsedNumbers[0]
let h = parsedNumbers[1]
let result = NSMakeSize(CGFloat(w), CGFloat(h))
return result
}
public func NSRectFromString(_ aString: String) -> NSRect {
if aString.isEmpty {
return NSZeroRect
}
let parsedNumbers = _scanDoublesFromString(aString, number: 4)
let x = parsedNumbers[0]
let y = parsedNumbers[1]
let w = parsedNumbers[2]
let h = parsedNumbers[3]
let result = NSMakeRect(CGFloat(x), CGFloat(y), CGFloat(w), CGFloat(h))
return result
}
extension NSValue {
public convenience init(point: NSPoint) {
self.init()
self._concreteValue = NSSpecialValue(point)
}
public convenience init(size: NSSize) {
self.init()
self._concreteValue = NSSpecialValue(size)
}
public convenience init(rect: NSRect) {
self.init()
self._concreteValue = NSSpecialValue(rect)
}
public convenience init(edgeInsets insets: NSEdgeInsets) {
self.init()
self._concreteValue = NSSpecialValue(insets)
}
public var pointValue: NSPoint {
let specialValue = self._concreteValue as! NSSpecialValue
return specialValue._value as! NSPoint
}
public var sizeValue: NSSize {
let specialValue = self._concreteValue as! NSSpecialValue
return specialValue._value as! NSSize
}
public var rectValue: NSRect {
let specialValue = self._concreteValue as! NSSpecialValue
return specialValue._value as! NSRect
}
public var edgeInsetsValue: NSEdgeInsets {
let specialValue = self._concreteValue as! NSSpecialValue
return specialValue._value as! NSEdgeInsets
}
}
extension NSCoder {
public func encode(_ point: NSPoint) {
self._encodeCGFloat(point.x)
self._encodeCGFloat(point.y)
}
public func decodePoint() -> NSPoint {
return NSPoint(x: _decodeCGFloat(), y: _decodeCGFloat())
}
public func encode(_ size: NSSize) {
self._encodeCGFloat(size.width)
self._encodeCGFloat(size.height)
}
public func decodeSize() -> NSSize {
return NSSize(width: _decodeCGFloat(), height: _decodeCGFloat())
}
public func encode(_ rect: NSRect) {
self.encode(rect.origin)
self.encode(rect.size)
}
public func decodeRect() -> NSRect {
return NSRect(origin: decodePoint(), size: decodeSize())
}
}
extension NSCoder {
public func encode(_ point: NSPoint, forKey key: String) {
self.encode(NSStringFromPoint(point)._bridgeToObjectiveC(), forKey: key)
}
public func encode(_ size: NSSize, forKey key: String) {
self.encode(NSStringFromSize(size)._bridgeToObjectiveC(), forKey: key)
}
public func encode(_ rect: NSRect, forKey key: String) {
self.encode(NSStringFromRect(rect)._bridgeToObjectiveC(), forKey: key)
}
public func decodePoint(forKey key: String) -> NSPoint {
if let string = self.decodeObject(of: NSString.self, forKey: key) {
return NSPointFromString(String._unconditionallyBridgeFromObjectiveC(string))
} else {
return NSPoint()
}
}
public func decodeSize(forKey key: String) -> NSSize {
if let string = self.decodeObject(of: NSString.self, forKey: key) {
return NSSizeFromString(String._unconditionallyBridgeFromObjectiveC(string))
} else {
return NSSize()
}
}
public func decodeRect(forKey key: String) -> NSRect {
if let string = self.decodeObject(of: NSString.self, forKey: key) {
return NSRectFromString(String._unconditionallyBridgeFromObjectiveC(string))
} else {
return NSRect()
}
}
}
private extension NSCoder {
func _encodeCGFloat(_ value: CGFloat) {
guard let keyedArchiver = self as? NSKeyedArchiver else {
preconditionFailure("Unkeyed coding is unsupported.")
}
keyedArchiver._encodeValue(NSNumber(value: value.native))
}
func _decodeCGFloat() -> CGFloat {
guard let keyedUnarchiver = self as? NSKeyedUnarchiver else {
preconditionFailure("Unkeyed coding is unsupported.")
}
guard let result : NSNumber = keyedUnarchiver._decodeValue() else {
return CGFloat(0.0)
}
return CGFloat(result.doubleValue)
}
func _encodeCGFloat(_ value: CGFloat, forKey key: String) {
self.encode(value.native, forKey: key)
}
func _decodeCGFloatForKey(_ key: String) -> CGFloat {
return CGFloat(self.decodeDouble(forKey: key))
}
}