Files

160 lines
4.6 KiB
Swift

//
// ProgressIndicator.swift
// TGUIKit
//
// Created by keepcoder on 06/07/2017.
// Copyright © 2017 Telegram. All rights reserved.
//
import Cocoa
private class ProgressLayer : CALayer {
fileprivate var progressColor: NSColor? = nil
fileprivate func update(_ hasAnimation: Bool) {
if hasAnimation {
var fromValue: Float = 0
if let layer = presentation(), let from = layer.value(forKeyPath: "transform.rotation.z") as? Float {
fromValue = from
}
let basicAnimation = CABasicAnimation(keyPath: "transform.rotation.z")
basicAnimation.duration = 0.8
basicAnimation.fromValue = fromValue
basicAnimation.isRemovedOnCompletion = false
basicAnimation.toValue = Double.pi * 2.0
basicAnimation.repeatCount = Float.infinity
basicAnimation.timingFunction = CAMediaTimingFunction(name: .linear)
add(basicAnimation, forKey: "progressRotation")
} else {
removeAnimation(forKey: "progressRotation")
}
}
fileprivate var lineWidth: CGFloat = 2 {
didSet {
setNeedsDisplay()
}
}
override func draw(in ctx: CGContext) {
ctx.setStrokeColor((progressColor ?? PresentationTheme.current.colors.indicatorColor).cgColor)
let startAngle = 2.0 * (CGFloat.pi) * 0.8 - CGFloat.pi / 2
let endAngle = -(CGFloat.pi / 2)
let diameter = floorToScreenPixels(System.backingScale, frame.height)
let pathDiameter = diameter - lineWidth - lineWidth * 2
ctx.addArc(center: NSMakePoint(diameter / 2.0, floorToScreenPixels(System.backingScale, diameter / 2.0)), radius: pathDiameter / 2.0, startAngle: startAngle, endAngle: endAngle, clockwise: true)
ctx.setLineWidth(lineWidth);
ctx.setLineCap(.round);
ctx.strokePath()
}
}
public class ProgressIndicator : Control {
public var alwaysAnimate: Bool = false
private var visualEffect: VisualEffect?
public var blurBackground: NSColor? = nil {
didSet {
updateBackgroundBlur()
}
}
private func updateBackgroundBlur() {
if let blurBackground = blurBackground {
if self.visualEffect == nil {
self.visualEffect = VisualEffect(frame: self.bounds)
self.addSubview(self.visualEffect!, positioned: .below, relativeTo: self.subviews.first)
}
self.visualEffect?.bgColor = blurBackground
} else {
self.visualEffect?.removeFromSuperview()
self.visualEffect = nil
}
needsLayout = true
}
public var progressColor: NSColor? = nil {
didSet {
indicator.color = progressColor ?? presentation.colors.text
indicator.setNeedsDisplay()
}
}
public var innerInset: CGFloat = 0 {
didSet {
needsLayout = true
// indicator.lineWidth = lineWidth
}
}
private let indicator: SpinningProgressView = SpinningProgressView(frame: NSZeroRect)
public required init(frame frameRect: NSRect) {
super.init(frame: frameRect)
indicator.frame = bounds
self.addSubview(indicator)
}
public override func setFrameSize(_ newSize: NSSize) {
let prev = self.frame
super.setFrameSize(newSize)
if prev != self.frame {
updateWantsAnimation()
}
}
public override func layout() {
super.layout()
indicator.setFrameSize(NSMakeSize(frame.width - innerInset, frame.height - innerInset))
indicator.center()
visualEffect?.frame = bounds
}
public override init() {
super.init(frame: NSMakeRect(0, 0, 20, 20))
indicator.frame = bounds
self.addSubview(indicator)
}
public override func viewDidMoveToSuperview() {
updateWantsAnimation()
}
public override func viewDidMoveToWindow() {
updateWantsAnimation()
}
public override func viewDidHide() {
updateWantsAnimation()
}
public override func viewDidUnhide() {
updateWantsAnimation()
}
private func updateWantsAnimation() {
if (window != nil && !isHidden) || alwaysAnimate {
indicator.startAnimation()
} else {
indicator.stopAnimation()
}
}
override public func draw(_ layer: CALayer, in ctx: CGContext) {
super.draw(layer, in: ctx)
}
required public init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}