diff --git a/Sources/Sliders/LSlider.swift b/Sources/Sliders/LSlider.swift index a208b20..8e6badd 100644 --- a/Sources/Sliders/LSlider.swift +++ b/Sources/Sliders/LSlider.swift @@ -171,20 +171,30 @@ public struct LSlider: View { public var range: ClosedRange = 0...1 public var angle: Angle = .zero public var isDisabled: Bool = false - + public init(_ value: Binding, range: ClosedRange, angle: Angle, isDisabled: Bool = false) { self._value = value self.range = range self.angle = angle self.isDisabled = isDisabled } - + + public init(_ value: Binding, range: ClosedRange, isDisabled: Bool = false) { + self._value = value + self.range = range + self.isDisabled = isDisabled + } + + public init(_ value: Binding, angle: Angle, isDisabled: Bool = false) { + self._value = value + self.angle = angle + self.isDisabled = isDisabled + } + public init(_ value: Binding) { self._value = value - } - - + // MARK: Calculations // uses an arbitrarily large number to gesture a line segment that is guarenteed to intersect with the // bounding box, then finds those points of intersection to be used as the start and end points of the slider @@ -192,7 +202,7 @@ public struct LSlider: View { let w = proxy.size.width let h = proxy.size.height let big: CGFloat = 50000000 - + let x1 = w/2 + big*CGFloat(cos(self.angle.radians)) let y1 = h/2 + big*CGFloat(sin(self.angle.radians)) let x2 = w/2 - big*CGFloat(cos(self.angle.radians)) @@ -201,7 +211,7 @@ public struct LSlider: View { if points.count < 2 { return (.zero, .zero) } - + return (points[0], points[1]) } private func thumbOffset(_ proxy: GeometryProxy) -> CGSize { @@ -211,7 +221,7 @@ public struct LSlider: View { let y = (1-value)*Double(ends.start.y) + value*Double(ends.end.y) - Double(proxy.size.height/2) return CGSize(width: x, height: y) } - + private var configuration: LSliderConfiguration { .init(isDisabled: isDisabled, isActive: isActive, @@ -221,7 +231,7 @@ public struct LSlider: View { min: range.lowerBound, max: range.upperBound) } - + // MARK: Haptics private func impactOccured() { #if os(macOS) @@ -230,6 +240,7 @@ public struct LSlider: View { generator.impactOccurred() #endif } + private func impactHandler(_ parameterAtLimit: Bool) { if parameterAtLimit { if !atLimit { @@ -240,36 +251,39 @@ public struct LSlider: View { atLimit = false } } + + // MARK: - Gesture + private func makeGesture(_ proxy: GeometryProxy) -> some Gesture { + DragGesture(minimumDistance: 10, coordinateSpace: .named(self.space)) + .onChanged({ drag in + let ends = self.calculateEndPoints(proxy) + let parameter = Double(calculateParameter(ends.start, ends.end, drag.location)) + self.impactHandler(parameter == 1 || parameter == 0) + self.value = (self.range.upperBound-self.range.lowerBound)*parameter + self.range.lowerBound + self.isActive = true + }) + .onEnded({ (drag) in + let ends = self.calculateEndPoints(proxy) + let parameter = Double(calculateParameter(ends.start, ends.end, drag.location)) + self.impactHandler(parameter == 1 || parameter == 0) + self.value = (self.range.upperBound-self.range.lowerBound)*parameter + self.range.lowerBound + self.isActive = false + }) + } + // MARK: View public var body: some View { ZStack { style.makeTrack(configuration: configuration) - .overlay( - GeometryReader { proxy in - ZStack { - self.style.makeThumb(configuration: self.configuration) - .offset(self.thumbOffset(proxy)) - .gesture(DragGesture(minimumDistance: 10, coordinateSpace: .named(self.space)) - .onChanged({ drag in - let ends = self.calculateEndPoints(proxy) - let parameter = Double(calculateParameter(ends.start, ends.end, drag.location)) - self.impactHandler(parameter == 1 || parameter == 0) - self.value = (self.range.upperBound-self.range.lowerBound)*parameter + self.range.lowerBound - self.isActive = true - }) - .onEnded({ (drag) in - let ends = self.calculateEndPoints(proxy) - let parameter = Double(calculateParameter(ends.start, ends.end, drag.location)) - self.impactHandler(parameter == 1 || parameter == 0) - self.value = (self.range.upperBound-self.range.lowerBound)*parameter + self.range.lowerBound - self.isActive = false - }) - ).allowsHitTesting(!self.isDisabled) - } - } - ) - }.frame(idealWidth: 200, idealHeight: 50) - .coordinateSpace(name: space) + GeometryReader { proxy in + self.style.makeThumb(configuration: self.configuration) + .position(x: proxy.size.width/2, y: proxy.size.height/2) + .offset(self.thumbOffset(proxy)) + .gesture(self.makeGesture(proxy)).allowsHitTesting(!self.isDisabled) + } + } + .coordinateSpace(name: space) } } + diff --git a/Sources/Sliders/TrackPad.swift b/Sources/Sliders/TrackPad.swift index 13a5188..01b368b 100644 --- a/Sources/Sliders/TrackPad.swift +++ b/Sources/Sliders/TrackPad.swift @@ -175,7 +175,7 @@ public struct TrackPad: View { self.rangeY = rangeY self.isDisabled = isDisabled } - + public init(_ value: Binding){ self._value = value } @@ -185,8 +185,8 @@ public struct TrackPad: View { self.rangeX = range self.rangeY = range } - - + + private var configuration: TrackPadConfiguration { .init(isDisabled: isDisabled, isActive: isActive, @@ -199,7 +199,7 @@ public struct TrackPad: View { minY: Double(rangeY.lowerBound), maxY: Double(rangeY.upperBound)) } - + // MARK: Calculations // Limits the value of the drag gesture to be within the frame of the trackpad // If the gesture hits an edge of the trackpad a haptic impact is played, an state @@ -220,7 +220,7 @@ public struct TrackPad: View { } else { self.atXLimit = false } - // vertical haptix handling + // vertical haptic handling if pctY == 1 || pctY == 0 { if !self.atYLimit { self.impactOccured() @@ -241,7 +241,7 @@ public struct TrackPad: View { let pctY = (value.y - rangeY.lowerBound)/(rangeY.upperBound - rangeY.lowerBound) return CGSize(width: w*(pctX-0.5), height: h*(pctY-0.5)) } - + // MARK: Haptics private func impactOccured() { #if os(macOS) @@ -254,24 +254,21 @@ public struct TrackPad: View { public var body: some View { ZStack { style.makeTrack(configuration: configuration) - .overlay(GeometryReader { proxy in - ZStack { - self.style.makeThumb(configuration: self.configuration) - .offset(self.thumbOffset(proxy)) - .gesture( - DragGesture(minimumDistance: 0, coordinateSpace: .named(self.space)) - .onChanged({ - self.constrainValue(proxy, $0.location) - self.isActive = true - }) - .onEnded({ - self.constrainValue(proxy, $0.location) - self.isActive = false - })) - } - }) + GeometryReader { proxy in + self.style.makeThumb(configuration: self.configuration) + .position(x: proxy.size.width/2, y: proxy.size.height/2) + .offset(self.thumbOffset(proxy)) + .gesture( + DragGesture(minimumDistance: 0, coordinateSpace: .named(self.space)) + .onChanged({ + self.constrainValue(proxy, $0.location) + self.isActive = true + }) + .onEnded({ + self.constrainValue(proxy, $0.location) + self.isActive = false + })) + } }.coordinateSpace(name: space) - } } -