1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-07-06 01:28:57 +00:00

Makes ViewFader the full master of fading.

This commit is contained in:
Thomas Harte 2021-07-14 19:03:44 -04:00
parent 616f8efc47
commit eb8ec1efb1

View File

@ -213,6 +213,16 @@ class MachineDocument:
} }
} }
// Set up a fader for the volume and options.
var fadingViews: [NSView] = []
if let optionsView = self.optionsView {
fadingViews.append(optionsView)
}
if let volumeView = self.volumeView {
fadingViews.append(volumeView)
}
optionsFader = ViewFader(views: fadingViews)
// Create and populate an activity display if required. // Create and populate an activity display if required.
setupActivityDisplay() setupActivityDisplay()
@ -608,7 +618,7 @@ class MachineDocument:
var isBlinking = false var isBlinking = false
} }
private var leds: [String: LED] = [:] private var leds: [String: LED] = [:]
private var activityFader: ViewFader? = nil private var activityFader: ViewFader! = nil
func setupActivityDisplay() { func setupActivityDisplay() {
var leds = machine.leds var leds = machine.leds
@ -709,92 +719,85 @@ class MachineDocument:
// Otherwise, hide it. // Otherwise, hide it.
let litLEDs = self.leds.filter { $0.value.isLit } let litLEDs = self.leds.filter { $0.value.isLit }
if litLEDs.isEmpty { if litLEDs.isEmpty {
self.animateOutView(self.activityView, withDelay: 1.0, fader: activityFader!) activityFader.animateOut(delay: 1.0)
} else { } else {
self.animateInView(self.activityView) activityFader.animateIn()
} }
} }
// MARK: - In-window panels (i.e. options, volume). // MARK: - In-window panels (i.e. options, volume).
private var animationFader: ViewFader? = nil private var optionsFader: ViewFader! = nil
var fadingViews: [NSView] {
get {
var views: [NSView] = []
if let optionsView = self.optionsView {
views.append(optionsView)
}
if let volumeView = self.volumeView {
views.append(volumeView)
}
return views
}
}
internal func scanTargetViewDidShowOSMouseCursor(_ view: CSScanTargetView) { internal func scanTargetViewDidShowOSMouseCursor(_ view: CSScanTargetView) {
// The OS mouse cursor became visible, so show the volume controls. // The OS mouse cursor became visible, so show the volume controls.
animationFader = nil optionsFader.animateIn()
for view in self.fadingViews {
animateInView(view)
}
} }
internal func scanTargetViewWillHideOSMouseCursor(_ view: CSScanTargetView) { internal func scanTargetViewWillHideOSMouseCursor(_ view: CSScanTargetView) {
// The OS mouse cursor will be hidden, so hide the volume controls. // The OS mouse cursor will be hidden, so hide the volume controls.
let fadingViews = self.fadingViews optionsFader.animateOut(delay: 0.0)
if !fadingViews[0].isHidden && fadingViews[0].layer?.animation(forKey: "opacity") == nil {
animationFader = ViewFader(views: fadingViews)
for view in self.fadingViews {
animateOutView(view, withDelay: 0.0, fader: animationFader!)
}
}
} }
// MARK: - Helpers for fading things in and out. // MARK: - Helpers for fading things in and out.
// This class exists to provide a delegate to the generated CAAnimations /// Maintains a list of views and offers in-and-out animations on those,
// that knows which views they refer to. /// testing current state as necessary and otherwise coordinating with
/// CoreAnimation.
private class ViewFader: NSObject, CAAnimationDelegate { private class ViewFader: NSObject, CAAnimationDelegate {
var views: [NSView] private var views: [NSView]
private var opacity: Float = 0.0
init(views: [NSView]) { init(views: [NSView]) {
self.views = views self.views = views
}
func animationDidStart(_ anim: CAAnimation) {
for view in views {
view.layer!.opacity = 0.0
}
}
func animationDidStop(_ animation: CAAnimation, finished: Bool) {
for view in views { for view in views {
view.isHidden = true view.isHidden = true
} }
} }
}
private func animateInView(_ view: NSView) { func animationDidStart(_ anim: CAAnimation) {
// Show immediately. for view in views {
view.layer?.removeAllAnimations() view.layer!.opacity = opacity
view.isHidden = false }
view.layer?.opacity = 1.0 }
}
private func animateOutView(_ view: NSView, withDelay delay: TimeInterval, fader: ViewFader) { func animationDidStop(_ animation: CAAnimation, finished: Bool) {
let fadeAnimation = CABasicAnimation(keyPath: "opacity") if finished {
fadeAnimation.beginTime = CACurrentMediaTime() + delay for view in views {
fadeAnimation.fromValue = 1.0 view.isHidden = true
fadeAnimation.toValue = 0.0 }
fadeAnimation.duration = 0.2 }
fadeAnimation.delegate = fader }
// The delegate will ensure the views stay hidden once animation is complete. func animateIn() {
opacity = 1.0
view.layer?.removeAllAnimations() for view in views {
view.layer!.add(fadeAnimation, forKey: "opacity") view.layer?.removeAllAnimations()
view.isHidden = false
view.layer?.opacity = 1.0
}
}
func animateOut(delay : TimeInterval) {
// Do nothing if already animating out.
if views[0].isHidden || views[0].layer?.animation(forKey: "opacity") != nil {
return
}
opacity = 0.0
for view in views {
let fadeAnimation = CABasicAnimation(keyPath: "opacity")
fadeAnimation.beginTime = CACurrentMediaTime() + delay
fadeAnimation.fromValue = 1.0
fadeAnimation.toValue = 0.0
fadeAnimation.duration = 0.2
fadeAnimation.delegate = self
view.layer?.removeAllAnimations()
view.layer!.add(fadeAnimation, forKey: "opacity")
}
}
} }
// MARK: - Volume Control. // MARK: - Volume Control.