//===----------------------------------------------------------------------===// // // 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.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 { // NOTE: older overlays called this class _CompletionHandlerDelegate. // The two must coexist without a conflicting ObjC class name, so it // was renamed. The old name must not be used in the new runtime. 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() } }