blob: 6cc836c6bcbfc9d19df432fdf55c6cb2614b9b4a [file] [log] [blame]
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
import Foundation
@_exported import AppKit
extension NSRect {
/// Fills this rect in the current NSGraphicsContext in the context's fill
/// color.
/// The compositing operation of the fill defaults to the context's
/// compositing operation, not necessarily using `.copy` like `NSRectFill()`.
/// - precondition: There must be a set current NSGraphicsContext.
@available(swift 4)
public func fill(using operation: NSCompositingOperation =
NSGraphicsContext.current?.compositingOperation ?? .sourceOver) {
precondition(NSGraphicsContext.current != nil,
"There must be a set current NSGraphicsContext")
__NSRectFillUsingOperation(self, operation)
}
/// Draws a frame around the inside of this rect in the current
/// NSGraphicsContext in the context's fill color
/// The compositing operation of the fill defaults to the context's
/// compositing operation, not necessarily using `.copy` like `NSFrameRect()`.
/// - precondition: There must be a set current NSGraphicsContext.
@available(swift 4)
public func frame(withWidth width: CGFloat = 1.0,
using operation: NSCompositingOperation =
NSGraphicsContext.current?.compositingOperation ?? .sourceOver) {
precondition(NSGraphicsContext.current != nil,
"There must be a set current NSGraphicsContext")
__NSFrameRectWithWidthUsingOperation(self, width, operation)
}
/// Modifies the current graphics context clipping path by intersecting it
/// with this rect.
/// This permanently modifies the graphics state, so the current state should
/// be saved beforehand and restored afterwards.
/// - precondition: There must be a set current NSGraphicsContext.
@available(swift 4)
public func clip() {
precondition(NSGraphicsContext.current != nil,
"There must be a set current NSGraphicsContext")
__NSRectClip(self)
}
}
extension Sequence where Iterator.Element == NSRect {
/// Fills this list of rects in the current NSGraphicsContext in the context's
/// fill color.
/// The compositing operation of the fill defaults to the context's
/// compositing operation, not necessarily using `.copy` like `NSRectFill()`.
/// - precondition: There must be a set current NSGraphicsContext.
@available(swift 4)
public func fill(using operation: NSCompositingOperation =
NSGraphicsContext.current?.compositingOperation ?? .sourceOver) {
precondition(NSGraphicsContext.current != nil,
"There must be a set current NSGraphicsContext")
let rects = Array(self)
let count = rects.count
guard count > 0 else { return }
rects.withUnsafeBufferPointer { rectBufferPointer in
guard let rectArray = rectBufferPointer.baseAddress else { return }
__NSRectFillListUsingOperation(rectArray, count, operation)
}
}
/// Modifies the current graphics context clipping path by intersecting it
/// with the graphical union of this list of rects
/// This permanently modifies the graphics state, so the current state should
/// be saved beforehand and restored afterwards.
/// - precondition: There must be a set current NSGraphicsContext.
@available(swift 4)
public func clip() {
precondition(NSGraphicsContext.current != nil,
"There must be a set current NSGraphicsContext")
let rects = Array(self)
let count = rects.count
guard count > 0 else { return }
rects.withUnsafeBufferPointer { rectBufferPointer in
guard let rectArray = rectBufferPointer.baseAddress else { return }
__NSRectClipList(rectArray, count)
}
}
}
extension Sequence where Iterator.Element == (CGRect, NSColor) {
/// Fills this list of rects in the current NSGraphicsContext with that rect's
/// associated color
/// The compositing operation of the fill defaults to the context's
/// compositing operation, not necessarily using `.copy` like `NSRectFill()`.
/// - precondition: There must be a set current NSGraphicsContext.
@available(swift 4)
public func fill(using operation: NSCompositingOperation =
NSGraphicsContext.current?.compositingOperation ?? .sourceOver) {
precondition(NSGraphicsContext.current != nil,
"There must be a set current NSGraphicsContext")
let rects = map { $0.0 }
let colors = map { $0.1 }
let count = rects.count
guard count > 0 else { return }
rects.withUnsafeBufferPointer { rectBufferPointer in
colors.withUnsafeBufferPointer { colorBufferPointer in
guard let rectArray = rectBufferPointer.baseAddress else { return }
guard let colorArray = colorBufferPointer.baseAddress else { return }
__NSRectFillListWithColorsUsingOperation(
rectArray, colorArray, count, operation)
}
}
}
}
extension Sequence where Iterator.Element == (CGRect, gray: CGFloat) {
/// Fills this list of rects in the current NSGraphicsContext with that rect's
/// associated gray component value in the DeviceGray color space.
/// The compositing operation of the fill defaults to the context's
/// compositing operation, not necessarily using `.copy` like
/// `NSRectFillListWithGrays()`.
/// - precondition: There must be a set current NSGraphicsContext.
@available(swift 4)
public func fill(using operation: NSCompositingOperation =
NSGraphicsContext.current?.compositingOperation ?? .sourceOver) {
// NSRectFillListWithGrays does not have a variant taking an operation, but
// is added here for consistency with the other drawing operations.
guard let graphicsContext = NSGraphicsContext.current else {
fatalError("There must be a set current NSGraphicsContext")
}
let cgContext: CGContext
if #available(macOS 10.10, *) {
cgContext = graphicsContext.cgContext
} else {
cgContext = Unmanaged<CGContext>.fromOpaque(
graphicsContext.graphicsPort).takeUnretainedValue()
}
cgContext.saveGState()
forEach {
cgContext.setFillColor(gray: $0.gray, alpha: 1.0)
__NSRectFillUsingOperation($0.0, operation)
}
cgContext.restoreGState()
}
}
extension NSWindow.Depth {
@available(swift 4)
public static func bestDepth(
colorSpaceName: NSColorSpaceName,
bitsPerSample: Int,
bitsPerPixel: Int,
isPlanar: Bool
) -> (NSWindow.Depth, isExactMatch: Bool) {
var isExactMatch: ObjCBool = false
let depth = __NSBestDepth(
colorSpaceName,
bitsPerSample, bitsPerPixel, isPlanar, &isExactMatch)
return (depth, isExactMatch: isExactMatch.boolValue)
}
@available(swift 4)
public static var availableDepths: [NSWindow.Depth] {
// __NSAvailableWindowDepths is NULL terminated, the length is not known up front
let depthsCArray = __NSAvailableWindowDepths()
var depths: [NSWindow.Depth] = []
var length = 0
var depth = depthsCArray[length]
while depth.rawValue != 0 {
depths.append(depth)
length += 1
depth = depthsCArray[length]
}
return depths
}
}
extension NSAnimationEffect {
private class _CompletionHandlerDelegate : NSObject {
var completionHandler: () -> Void = { }
@objc func animationEffectDidEnd(_ contextInfo: UnsafeMutableRawPointer?) {
completionHandler()
}
}
@available(swift 4)
public func show(centeredAt centerLocation: NSPoint, size: NSSize,
completionHandler: @escaping () -> Void = { }) {
let delegate = _CompletionHandlerDelegate()
delegate.completionHandler = completionHandler
// Note that the delegate of `__NSShowAnimationEffect` is retained for the
// duration of the animation.
__NSShowAnimationEffect(
self,
centerLocation,
size,
delegate,
#selector(_CompletionHandlerDelegate.animationEffectDidEnd(_:)),
nil)
}
}
extension NSSound {
@available(swift 4)
public static func beep() {
__NSBeep()
}
}