diff --git a/Sources/AquaKit/Drawers/AquaDrawerFrameView.swift b/Sources/AquaKit/Drawers/AquaDrawerFrameView.swift index 457e572..ed97b29 100644 --- a/Sources/AquaKit/Drawers/AquaDrawerFrameView.swift +++ b/Sources/AquaKit/Drawers/AquaDrawerFrameView.swift @@ -46,15 +46,15 @@ final class AquaDrawerFrameView: NSView { override func draw(_ dirtyRect: NSRect) { super.draw(dirtyRect) - NSGraphicsContext.saveGraphicsState() - let shadow = NSShadow() - shadow.shadowColor = .black.withAlphaComponent(0.7) - shadow.shadowBlurRadius = 5.0 - shadow.set() - - NSColor.controlColor.setStroke() - strokePath.stroke() - NSGraphicsContext.restoreGraphicsState() + NSGraphicsContext.scope { + let shadow = NSShadow() + shadow.shadowColor = .black.withAlphaComponent(0.7) + shadow.shadowBlurRadius = 5.0 + shadow.set() + + NSColor.controlColor.setStroke() + strokePath.stroke() + } } required init?(coder: NSCoder) { fatalError() } diff --git a/Sources/AquaKit/General Purpose/NSGraphicsContext+Scope.swift b/Sources/AquaKit/General Purpose/NSGraphicsContext+Scope.swift new file mode 100644 index 0000000..6bd308d --- /dev/null +++ b/Sources/AquaKit/General Purpose/NSGraphicsContext+Scope.swift @@ -0,0 +1,13 @@ +// SPDX-FileCopyrightText: 2026 Jon Sterling +// +// SPDX-License-Identifier: MIT + +import AppKit + +extension NSGraphicsContext { + public static func scope(_ body: () -> Value) -> Value { + saveGraphicsState() + defer { restoreGraphicsState() } + return body() + } +} diff --git a/Sources/AquaKit/Scroll Views/AquaScroller.swift b/Sources/AquaKit/Scroll Views/AquaScroller.swift index 0be530b..d12fe89 100644 --- a/Sources/AquaKit/Scroll Views/AquaScroller.swift +++ b/Sources/AquaKit/Scroll Views/AquaScroller.swift @@ -142,148 +142,129 @@ public class AquaScroller: NSScroller { let knobPath = NSBezierPath(roundedRect: knobRect, xRadius: radius, yRadius: radius) - NSGraphicsContext.saveGraphicsState() + NSGraphicsContext.scope { - do { - NSGraphicsContext.saveGraphicsState() + NSGraphicsContext.scope { + let shadow = NSShadow() + shadow.shadowColor = .black + shadow.shadowBlurRadius = 2 + shadow.set() - let shadow = NSShadow() - shadow.shadowColor = .black - shadow.shadowBlurRadius = 2 - shadow.set() - - NSColor.black.withAlphaComponent(0.4).setStroke() - - knobPath.stroke() - - if isInKeyWindow { - NSColor(patternImage: wavePatternImage).setFill() - knobPath.fill() - } - - NSGraphicsContext.restoreGraphicsState() - } + NSColor.black.withAlphaComponent(0.4).setStroke() - do { - NSGraphicsContext.saveGraphicsState() - knobPath.addClip() + knobPath.stroke() - var baseColor: NSColor - if let window, window.isKeyWindow { - baseColor = NSColor.controlAccentColor.usingColorSpace(.displayP3)! - if baseColor.isGrayscale { - baseColor = NSColor.graphiteColor - } else { - baseColor = NSColor( - calibratedHue: baseColor.hueComponent - 0.03, - saturation: 0.8, - brightness: 0.9, - alpha: 1.0 - ) + if isInKeyWindow { + NSColor(patternImage: wavePatternImage).setFill() + knobPath.fill() } - } else { - baseColor = NSColor.graphiteColor.highlight(withLevel: 0.5)! } - if effectiveAppearance.isDarkAqua { - baseColor = baseColor.blended(withFraction: 0.3, of: .graphiteColor.shadow(withLevel: 0.8)!)! - } - - do { - NSGraphicsContext.saveGraphicsState() - NSGraphicsContext.current?.cgContext.setAlpha(0.9) - baseColor.setFill() - knobRect.fill() - NSGraphicsContext.restoreGraphicsState() - } - - // shading at the ends of the knob - if isInKeyWindow { - let frontEdge: CGRectEdge = - switch axis { - case .vertical: .minYEdge - case .horizontal: .minXEdge - } - - let backEdge: CGRectEdge = - switch axis { - case .vertical: .maxYEdge - case .horizontal: .maxXEdge + NSGraphicsContext.scope { + knobPath.addClip() + + var baseColor: NSColor + if let window, window.isKeyWindow { + baseColor = NSColor.controlAccentColor.usingColorSpace(.displayP3)! + if baseColor.isGrayscale { + baseColor = NSColor.graphiteColor + } else { + baseColor = NSColor( + calibratedHue: baseColor.hueComponent - 0.03, + saturation: 0.8, + brightness: 0.9, + alpha: 1.0 + ) } + } else { + baseColor = NSColor.graphiteColor.highlight(withLevel: 0.5)! + } - let distance = min(scrollerWidth / 1.5, knobRect.size[axis] / 3.0) - let gradient = NSGradient(colors: [baseColor.shadow(withLevel: 0.6)!.withAlphaComponent(0.5), .clear]) - let frontRect = knobRect.divided(atDistance: distance, from: frontEdge).slice - let backRect = knobRect.divided(atDistance: distance, from: backEdge).slice - gradient?.draw(in: frontRect, angle: axis.mainGradientAngle) - gradient?.draw(in: backRect, angle: 180.0 + axis.mainGradientAngle) - } + if effectiveAppearance.isDarkAqua { + baseColor = baseColor.blended(withFraction: 0.3, of: .graphiteColor.shadow(withLevel: 0.8)!)! + } - // shine highlight along leading cross edge - do { - NSGraphicsContext.saveGraphicsState() - - let shineGradient = NSGradient(colors: [ - .white, - .white.withAlphaComponent(isInKeyWindow ? 0.4 : 0.8) - ])! - - let shineRect = NSRect( - along: axis, - at: knobRect.origin[axis] + 3, - across: knobRect.origin[axis.opposite] - 6, - length: knobRect.size[axis] - 6, - breadth: 10 - ) - let shinePath = NSBezierPath(roundedRect: shineRect, xRadius: 5, yRadius: 5) - - shineGradient.draw(in: shinePath, angle: axis.crossGradientAngle) - NSGraphicsContext.restoreGraphicsState() - } + NSGraphicsContext.scope { + NSGraphicsContext.current?.cgContext.setAlpha(0.9) + baseColor.setFill() + knobRect.fill() + } - // trailing cross edge glow - do { - NSGraphicsContext.saveGraphicsState() + // shading at the ends of the knob + if isInKeyWindow { + let frontEdge: CGRectEdge = + switch axis { + case .vertical: .minYEdge + case .horizontal: .minXEdge + } + + let backEdge: CGRectEdge = + switch axis { + case .vertical: .maxYEdge + case .horizontal: .maxXEdge + } + + let distance = min(scrollerWidth / 1.5, knobRect.size[axis] / 3.0) + let gradient = NSGradient(colors: [baseColor.shadow(withLevel: 0.6)!.withAlphaComponent(0.5), .clear]) + let frontRect = knobRect.divided(atDistance: distance, from: frontEdge).slice + let backRect = knobRect.divided(atDistance: distance, from: backEdge).slice + gradient?.draw(in: frontRect, angle: axis.mainGradientAngle) + gradient?.draw(in: backRect, angle: 180.0 + axis.mainGradientAngle) + } - let glowGradient = NSGradient(colors: [ - .clear, - .clear, - baseColor.highlight(withLevel: 0.6)! - ])! + // shine highlight along leading cross edge + NSGraphicsContext.scope { + let shineGradient = NSGradient(colors: [ + .white, + .white.withAlphaComponent(isInKeyWindow ? 0.4 : 0.8) + ])! + + let shineRect = NSRect( + along: axis, + at: knobRect.origin[axis] + 3, + across: knobRect.origin[axis.opposite] - 6, + length: knobRect.size[axis] - 6, + breadth: 10 + ) + let shinePath = NSBezierPath(roundedRect: shineRect, xRadius: 5, yRadius: 5) - let glowPath = NSBezierPath( - roundedRect: knobRect.insetBy(along: axis, length: 1, breadth: 0), - xRadius: radius, - yRadius: radius - ) - glowGradient.draw(in: glowPath, angle: axis.crossGradientAngle) + shineGradient.draw(in: shinePath, angle: axis.crossGradientAngle) + } - NSGraphicsContext.restoreGraphicsState() - } + // trailing cross edge glow + NSGraphicsContext.scope { + let glowGradient = NSGradient(colors: [ + .clear, + .clear, + baseColor.highlight(withLevel: 0.6)! + ])! + + let glowPath = NSBezierPath( + roundedRect: knobRect.insetBy(along: axis, length: 1, breadth: 0), + xRadius: radius, + yRadius: radius + ) + glowGradient.draw(in: glowPath, angle: axis.crossGradientAngle) + } - // leading cross edge glow - do { - NSGraphicsContext.saveGraphicsState() - - let glowGradient = NSGradient(colors: [ - baseColor.highlight(withLevel: 0.6)!, - .clear, - .clear - ])! - - let glowPath = NSBezierPath( - roundedRect: knobRect.insetBy(along: axis, length: 1, breadth: 0), - xRadius: radius, - yRadius: radius - ) - glowGradient.draw(in: glowPath, angle: axis.crossGradientAngle) - NSGraphicsContext.restoreGraphicsState() + // leading cross edge glow + NSGraphicsContext.scope { + let glowGradient = NSGradient(colors: [ + baseColor.highlight(withLevel: 0.6)!, + .clear, + .clear + ])! + + let glowPath = NSBezierPath( + roundedRect: knobRect.insetBy(along: axis, length: 1, breadth: 0), + xRadius: radius, + yRadius: radius + ) + glowGradient.draw(in: glowPath, angle: axis.crossGradientAngle) + } } - NSGraphicsContext.restoreGraphicsState() } - - NSGraphicsContext.restoreGraphicsState() } public override func drawKnobSlot(in slotRect: NSRect, highlight flag: Bool) { @@ -293,24 +274,22 @@ public class AquaScroller: NSScroller { NSColor.windowBackgroundColor.highlight(withLevel: 0.05)!.setFill() bedPath.fill() - NSGraphicsContext.saveGraphicsState() - - bedPath.addClip() - - let shadow = NSShadow() - shadow.shadowColor = .black.withAlphaComponent(0.6) - shadow.shadowOffset = NSSize(width: 0, height: 0) - shadow.shadowBlurRadius = 3 - shadow.set() - - let outerRect = slotRect.insetBy(dx: -10, dy: -10) - let outerPath = NSBezierPath(rect: outerRect) - outerPath.append(bedPath) - outerPath.windingRule = .evenOdd - NSColor.windowBackgroundColor.setFill() - outerPath.fill() - - NSGraphicsContext.restoreGraphicsState() + NSGraphicsContext.scope { + bedPath.addClip() + + let shadow = NSShadow() + shadow.shadowColor = .black.withAlphaComponent(0.6) + shadow.shadowOffset = NSSize(width: 0, height: 0) + shadow.shadowBlurRadius = 3 + shadow.set() + + let outerRect = slotRect.insetBy(dx: -10, dy: -10) + let outerPath = NSBezierPath(rect: outerRect) + outerPath.append(bedPath) + outerPath.windingRule = .evenOdd + NSColor.windowBackgroundColor.setFill() + outerPath.fill() + } } } @@ -339,7 +318,7 @@ extension Axis { return [ (NSPoint(along: self, at: mainMin, across: crossMin), NSPoint(along: self, at: mainMax, across: crossMin)), - (NSPoint(along: self, at: mainMin, across: crossMax), NSPoint(along: self, at: mainMax, across: crossMax)), + (NSPoint(along: self, at: mainMin, across: crossMax), NSPoint(along: self, at: mainMax, across: crossMax)) ] } } diff --git a/Sources/AquaKit/Source Lists/SourceListBottomBarViewController.swift b/Sources/AquaKit/Source Lists/SourceListBottomBarViewController.swift index b54808e..203e516 100644 --- a/Sources/AquaKit/Source Lists/SourceListBottomBarViewController.swift +++ b/Sources/AquaKit/Source Lists/SourceListBottomBarViewController.swift @@ -29,40 +29,39 @@ open class SourceListBottomBarViewController: NSSplitViewItemAccessoryViewContro } override func draw(_ dirtyRect: NSRect) { - NSGraphicsContext.saveGraphicsState() - - var alpha = 1.0 - if let window, !window.isKeyWindow { - alpha *= 0.6 - } - if effectiveAppearance.isDarkAqua { - alpha *= 0.3 + NSGraphicsContext.scope { + var alpha = 1.0 + if let window, !window.isKeyWindow { + alpha *= 0.6 + } + if effectiveAppearance.isDarkAqua { + alpha *= 0.3 + } + + NSGraphicsContext.current?.cgContext.setAlpha(alpha) + + let color1 = NSColor( + light: NSColor(white: 0.98, alpha: 1), + dark: NSColor(white: 0.98, alpha: 1), + ) + let color2 = NSColor( + light: NSColor(white: 0.96, alpha: 1), + dark: NSColor.graphiteColor.highlight(withLevel: 0.7)! + ) + let color3 = NSColor( + light: NSColor(white: 0.92, alpha: 1), + dark: NSColor.graphiteColor.shadow(withLevel: 0.2)! + ) + + let gradient = NSGradient( + colorsAndLocations: (color1, 0), + (color2, 0.48), + (color3, 0.52), + ) + + gradient?.draw(in: bounds, angle: 270) } - NSGraphicsContext.current?.cgContext.setAlpha(alpha) - - let color1 = NSColor( - light: NSColor(white: 0.98, alpha: 1), - dark: NSColor(white: 0.98, alpha: 1), - ) - let color2 = NSColor( - light: NSColor(white: 0.96, alpha: 1), - dark: NSColor.graphiteColor.highlight(withLevel: 0.7)! - ) - let color3 = NSColor( - light: NSColor(white: 0.92, alpha: 1), - dark: NSColor.graphiteColor.shadow(withLevel: 0.2)! - ) - - let gradient = NSGradient( - colorsAndLocations: (color1, 0), - (color2, 0.48), - (color3, 0.52), - ) - - gradient?.draw(in: bounds, angle: 270) - NSGraphicsContext.restoreGraphicsState() - NSColor.aquaSeparatorColor.setFill() NSBezierPath.fill(NSRect(x: bounds.minX, y: bounds.maxY - 1, width: bounds.width, height: 1)) } diff --git a/Sources/AquaKit/Table Headers/AquaTableCornerView.swift b/Sources/AquaKit/Table Headers/AquaTableCornerView.swift index 1c3ef34..29bb712 100644 --- a/Sources/AquaKit/Table Headers/AquaTableCornerView.swift +++ b/Sources/AquaKit/Table Headers/AquaTableCornerView.swift @@ -17,14 +17,13 @@ open class AquaTableCornerView: NSView { } override open func draw(_ dirtyRect: NSRect) { - NSGraphicsContext.saveGraphicsState() - if let window, !window.isKeyWindow { - NSGraphicsContext.current?.cgContext.setAlpha(0.4) - } - - AquaTableHeaderCell.backgroundFillGradient.draw(in: bounds, angle: -90) + NSGraphicsContext.scope { + if let window, !window.isKeyWindow { + NSGraphicsContext.current?.cgContext.setAlpha(0.4) + } - NSGraphicsContext.restoreGraphicsState() + AquaTableHeaderCell.backgroundFillGradient.draw(in: bounds, angle: -90) + } NSColor.aquaSeparatorColor.setFill() NSBezierPath.fill(NSRect(x: bounds.minX, y: bounds.maxY - 1, width: bounds.width, height: 1)) diff --git a/Sources/AquaKit/Table Headers/AquaTableHeaderView.swift b/Sources/AquaKit/Table Headers/AquaTableHeaderView.swift index e19572e..295f9cc 100644 --- a/Sources/AquaKit/Table Headers/AquaTableHeaderView.swift +++ b/Sources/AquaKit/Table Headers/AquaTableHeaderView.swift @@ -18,12 +18,12 @@ open class AquaTableHeaderView: NSTableHeaderView { } override open func draw(_ dirtyRect: NSRect) { - NSGraphicsContext.saveGraphicsState() - if let window, !window.isKeyWindow { - NSGraphicsContext.current?.cgContext.setAlpha(0.4) + NSGraphicsContext.scope { + if let window, !window.isKeyWindow { + NSGraphicsContext.current?.cgContext.setAlpha(0.4) + } + super.draw(dirtyRect) } - super.draw(dirtyRect) - NSGraphicsContext.restoreGraphicsState() NSColor.aquaSeparatorColor.setFill() NSBezierPath.fill(NSRect(x: bounds.minX, y: bounds.maxY - 1, width: bounds.width, height: 1)) diff --git a/Sources/AquaKit/Windows/AquaTrafficLightButton.swift b/Sources/AquaKit/Windows/AquaTrafficLightButton.swift index 3022ecc..3563939 100644 --- a/Sources/AquaKit/Windows/AquaTrafficLightButton.swift +++ b/Sources/AquaKit/Windows/AquaTrafficLightButton.swift @@ -71,67 +71,66 @@ open class AquaTrafficLightButton: AquaWindowControlButton, AquaTrafficLightButt } override open func draw(_ dirtyRect: NSRect) { - NSGraphicsContext.saveGraphicsState() - - var color = baseColor - if NSColor.controlAccentColor.isGrayscale { - color = .graphiteColor - } - if isHighlighted { - color = color.shadow(withLevel: 0.4)! - } - if let window, !window.isKeyWindow { - color = .graphiteColor.highlight(withLevel: 0.8)! - NSGraphicsContext.current?.cgContext.setAlpha(0.4) + NSGraphicsContext.scope { + + var color = baseColor + if NSColor.controlAccentColor.isGrayscale { + color = .graphiteColor + } + if isHighlighted { + color = color.shadow(withLevel: 0.4)! + } + if let window, !window.isKeyWindow { + color = .graphiteColor.highlight(withLevel: 0.8)! + NSGraphicsContext.current?.cgContext.setAlpha(0.4) + } + if effectiveAppearance.isDarkAqua { + color = color.blended(withFraction: 0.5, of: .graphiteColor.shadow(withLevel: 0.9)!)! + } + + let strokeWidth = 1.0 + let bounds = bounds + let ellipse = NSBezierPath(ovalIn: bounds) + + NSGraphicsContext.scope { + ellipse.setClip() + do { + ellipse.lineWidth = strokeWidth + color.shadow(withLevel: 0.4)!.setFill() + ellipse.fill() + } + + do { + let bottomGlowGradient = NSGradient( + colorsAndLocations: (.white, 0.0), + (.white.withAlphaComponent(0.8), 0.2), + (.clear, 0.5) + )! + + let gradientRect = bounds.insetBy(dx: 0, dy: 0) + bottomGlowGradient.draw(in: gradientRect, relativeCenterPosition: NSPoint(x: 0, y: -0.7)) + } + + do { + let centerGlowGradient = NSGradient( + colorsAndLocations: (color.withAlphaComponent(0.7), 0.0), + (color.withAlphaComponent(0.5), 0.5), + (color.withAlphaComponent(0.1), 1), + )! + + centerGlowGradient.draw(in: bounds, relativeCenterPosition: .zero) + } + + do { + let innerEllipse = NSBezierPath(ovalIn: bounds.insetBy(dx: bounds.width * 0.05, dy: bounds.width * 0.05)) + let innerEllipseGradient = NSGradient(colorsAndLocations: (.white.withAlphaComponent(0.7), 0.0), (.clear, 0.4))! + innerEllipseGradient.draw(in: innerEllipse, angle: 270) + } + } + + color.shadow(withLevel: 0.7)!.setStroke() + ellipse.stroke() } - if effectiveAppearance.isDarkAqua { - color = color.blended(withFraction: 0.5, of: .graphiteColor.shadow(withLevel: 0.9)!)! - } - - let strokeWidth = 1.0 - let bounds = bounds - let ellipse = NSBezierPath(ovalIn: bounds) - - NSGraphicsContext.saveGraphicsState() - ellipse.setClip() - do { - ellipse.lineWidth = strokeWidth - color.shadow(withLevel: 0.4)!.setFill() - ellipse.fill() - } - - do { - let bottomGlowGradient = NSGradient( - colorsAndLocations: (.white, 0.0), - (.white.withAlphaComponent(0.8), 0.2), - (.clear, 0.5) - )! - - let gradientRect = bounds.insetBy(dx: 0, dy: 0) - bottomGlowGradient.draw(in: gradientRect, relativeCenterPosition: NSPoint(x: 0, y: -0.7)) - } - - do { - let centerGlowGradient = NSGradient( - colorsAndLocations: (color.withAlphaComponent(0.7), 0.0), - (color.withAlphaComponent(0.5), 0.5), - (color.withAlphaComponent(0.1), 1), - )! - - centerGlowGradient.draw(in: bounds, relativeCenterPosition: .zero) - } - - do { - let innerEllipse = NSBezierPath(ovalIn: bounds.insetBy(dx: bounds.width * 0.05, dy: bounds.width * 0.05)) - let innerEllipseGradient = NSGradient(colorsAndLocations: (.white.withAlphaComponent(0.7), 0.0), (.clear, 0.4))! - innerEllipseGradient.draw(in: innerEllipse, angle: 270) - } - NSGraphicsContext.restoreGraphicsState() - - color.shadow(withLevel: 0.7)!.setStroke() - ellipse.stroke() - - NSGraphicsContext.restoreGraphicsState() } @objc public func setDocumentEdited(_ edited: Bool) {} diff --git a/Sources/AquaKit/Windows/AquaWindowToolbarButton.swift b/Sources/AquaKit/Windows/AquaWindowToolbarButton.swift index 20b64e4..b66e729 100644 --- a/Sources/AquaKit/Windows/AquaWindowToolbarButton.swift +++ b/Sources/AquaKit/Windows/AquaWindowToolbarButton.swift @@ -18,47 +18,46 @@ open class AquaWindowToolbarButton: AquaWindowControlButton { } override open func draw(_ dirtyRect: NSRect) { - NSGraphicsContext.saveGraphicsState() - - if let window, !window.isKeyWindow { - NSGraphicsContext.current?.cgContext.setAlpha( - effectiveAppearance.isDarkAqua ? 0.3 : 0.4 - ) - } - - let lozengeRect = bounds.insetBy(dx: 0, dy: 2) - let lozenge = NSBezierPath(roundedRect: lozengeRect, xRadius: 6, yRadius: 6) - lozenge.lineWidth = 1.0 - NSColor.gray.shadow(withLevel: 0.5)!.setStroke() - lozenge.stroke() - - func shadow(_ color: NSColor) -> NSColor { - color.shadow(withLevel: 0.2)! - } - - let gradient = NSGradient( - colorsAndLocations: ( - #colorLiteral(red: 0.7792062163, green: 0.7657493949, blue: 0.7566991448, alpha: 1).modifyDark(shadow(_:)), 0.0 - ), - (#colorLiteral(red: 0.9971552491, green: 0.9922525287, blue: 0.9795755744, alpha: 1).modifyDark(shadow(_:)), 1.0) - )! - gradient.draw(in: lozenge, angle: 270) - - do { - let shinePath = NSBezierPath( - roundedRect: lozengeRect.insetBy(dx: bounds.width * 0.02, dy: bounds.width * 0.02), - xRadius: 6, - yRadius: 6 - ) - let shineGradient = NSGradient(colorsAndLocations: (.white, 0.0), (.clear, 0.4))! - shineGradient.draw(in: shinePath, angle: 270) + NSGraphicsContext.scope { + + if let window, !window.isKeyWindow { + NSGraphicsContext.current?.cgContext.setAlpha( + effectiveAppearance.isDarkAqua ? 0.3 : 0.4 + ) + } + + let lozengeRect = bounds.insetBy(dx: 0, dy: 2) + let lozenge = NSBezierPath(roundedRect: lozengeRect, xRadius: 6, yRadius: 6) + lozenge.lineWidth = 1.0 + NSColor.gray.shadow(withLevel: 0.5)!.setStroke() + lozenge.stroke() + + func shadow(_ color: NSColor) -> NSColor { + color.shadow(withLevel: 0.2)! + } + + let gradient = NSGradient( + colorsAndLocations: ( + #colorLiteral(red: 0.7792062163, green: 0.7657493949, blue: 0.7566991448, alpha: 1).modifyDark(shadow(_:)), 0.0 + ), + (#colorLiteral(red: 0.9971552491, green: 0.9922525287, blue: 0.9795755744, alpha: 1).modifyDark(shadow(_:)), 1.0) + )! + gradient.draw(in: lozenge, angle: 270) + + do { + let shinePath = NSBezierPath( + roundedRect: lozengeRect.insetBy(dx: bounds.width * 0.02, dy: bounds.width * 0.02), + xRadius: 6, + yRadius: 6 + ) + let shineGradient = NSGradient(colorsAndLocations: (.white, 0.0), (.clear, 0.4))! + shineGradient.draw(in: shinePath, angle: 270) + } + + if isHighlighted { + NSColor.gray.withAlphaComponent(0.4).setFill() + lozenge.fill() + } } - - if isHighlighted { - NSColor.gray.withAlphaComponent(0.4).setFill() - lozenge.fill() - } - - NSGraphicsContext.restoreGraphicsState() } }