diff --git a/Sources/AquaKit/General Purpose/Geometry/NSSize+Plus.swift b/Sources/AquaKit/General Purpose/Geometry/NSSize+Plus.swift new file mode 100644 index 0000000..3225c92 --- /dev/null +++ b/Sources/AquaKit/General Purpose/Geometry/NSSize+Plus.swift @@ -0,0 +1,7 @@ +import Foundation + +extension NSSize { + public static func + (lhs: NSSize, rhs: NSSize) -> NSSize { + NSSize(width: lhs.width + rhs.width, height: lhs.height + rhs.height) + } +} diff --git a/Sources/AquaKit/General Purpose/Geometry/Orientation.swift b/Sources/AquaKit/General Purpose/Geometry/Orientation.swift new file mode 100644 index 0000000..45aed5e --- /dev/null +++ b/Sources/AquaKit/General Purpose/Geometry/Orientation.swift @@ -0,0 +1,40 @@ +import AppKit + +public enum Orientation { + case vertical + case horizontal +} + +extension NSSize { + public subscript(orientation: Orientation) -> CGFloat { + get { + switch orientation { + case .vertical: height + case .horizontal: width + } + } + set { + switch orientation { + case .vertical: height = newValue + case .horizontal: width = newValue + } + } + } +} + +extension NSPoint { + public subscript(orientation: Orientation) -> CGFloat { + get { + switch orientation { + case .vertical: y + case .horizontal: x + } + } + set { + switch orientation { + case .vertical: y = newValue + case .horizontal: x = newValue + } + } + } +} diff --git a/Sources/AquaKit/Scroll Views/AquaScrollState.swift b/Sources/AquaKit/Scroll Views/AquaScrollState.swift new file mode 100644 index 0000000..f42aba0 --- /dev/null +++ b/Sources/AquaKit/Scroll Views/AquaScrollState.swift @@ -0,0 +1,64 @@ +import Foundation +import AppKit + +public struct AquaScrollState { + public var scrollPosition: NSPoint + public var contentSize: NSSize + public var visibleSize: NSSize + + public init(scrollPosition: NSPoint, contentSize: NSSize, visibleSize: NSSize) { + self.scrollPosition = scrollPosition + self.contentSize = contentSize + self.visibleSize = visibleSize + } + + public var maxOffset: NSSize { + NSSize( + width: max(contentSize.width - visibleSize.width, 0), + height: max(contentSize.height - visibleSize.height, 0) + ) + } + + public var verticalOverscroll: CGFloat { + absoluteExcess(of: scrollPosition.y, in: 0..) -> CGFloat { + if position < range.lowerBound { + range.lowerBound - position + } else if position > range.upperBound { + position - range.upperBound + } else { + 0 + } + } + + public func absoluteExcess(of point: NSPoint, in size: NSSize) -> NSSize { + NSSize( + width: absoluteExcess(of: point.x, in: 0.. 0 ? min(max(state.scrollPosition[orientation] / maxOffset[orientation], 0.0), 1.0) : 0.0 + isEnabled = maxOffset[orientation] > 0 + isHidden = maxOffset[orientation] <= 0 + } +} + +extension AquaScroller { + public func adopt(state: AquaScrollState) { + adopt(state: state, orientation: orientation) + } +} diff --git a/Sources/AquaKit/Scroll Views/AquaScroller.swift b/Sources/AquaKit/Scroll Views/AquaScroller.swift index d133779..cbc7801 100644 --- a/Sources/AquaKit/Scroll Views/AquaScroller.swift +++ b/Sources/AquaKit/Scroll Views/AquaScroller.swift @@ -2,10 +2,6 @@ import AppKit import AquaKit public class AquaScroller: NSScroller { - public enum Orientation { - case vertical, horizontal - } - public let orientation: Orientation public override var floatValue: Float { @@ -269,7 +265,7 @@ public class AquaScroller: NSScroller { } } -extension AquaScroller.Orientation { +fileprivate extension Orientation { /// The affine transform that maps between screen space and canonical (vertical) /// coordinate space. For vertical this is the identity; for horizontal it swaps /// the x and y axes. This transform is its own inverse.