Swiftgram/submodules/Display/Display/ContextMenuContainerNode.swift
Peter 8f5a4f7dc1 Add 'submodules/Display/' from commit '7bd11013ea936e3d49d937550d599f5816d32560'
git-subtree-dir: submodules/Display
git-subtree-mainline: 9bc996374ffdad37aef175427db72731c9551dcf
git-subtree-split: 7bd11013ea936e3d49d937550d599f5816d32560
2019-06-11 18:44:37 +01:00

91 lines
4.4 KiB
Swift

import Foundation
import UIKit
import AsyncDisplayKit
private struct CachedMaskParams: Equatable {
let size: CGSize
let relativeArrowPosition: CGFloat
let arrowOnBottom: Bool
}
private final class ContextMenuContainerMaskView: UIView {
override class var layerClass: AnyClass {
return CAShapeLayer.self
}
}
public final class ContextMenuContainerNode: ASDisplayNode {
private var cachedMaskParams: CachedMaskParams?
private let maskView = ContextMenuContainerMaskView()
public var relativeArrowPosition: (CGFloat, Bool)?
//private let effectView: UIVisualEffectView
override public init() {
//self.effectView = UIVisualEffectView(effect: UIBlurEffect(style: .light))
super.init()
self.backgroundColor = UIColor(rgb: 0xeaecec)
//self.view.addSubview(self.effectView)
//self.effectView.mask = self.maskView
self.view.mask = self.maskView
}
override public func didLoad() {
super.didLoad()
self.layer.allowsGroupOpacity = true
}
override public func layout() {
super.layout()
self.updateLayout(transition: .immediate)
}
public func updateLayout(transition: ContainedViewLayoutTransition) {
//self.effectView.frame = self.bounds
let maskParams = CachedMaskParams(size: self.bounds.size, relativeArrowPosition: self.relativeArrowPosition?.0 ?? self.bounds.size.width / 2.0, arrowOnBottom: self.relativeArrowPosition?.1 ?? true)
if self.cachedMaskParams != maskParams {
let path = UIBezierPath()
let cornerRadius: CGFloat = 6.0
let verticalInset: CGFloat = 9.0
let arrowWidth: CGFloat = 18.0
let requestedArrowPosition = maskParams.relativeArrowPosition
let arrowPosition = max(cornerRadius + arrowWidth / 2.0, min(maskParams.size.width - cornerRadius - arrowWidth / 2.0, requestedArrowPosition))
let arrowOnBottom = maskParams.arrowOnBottom
path.move(to: CGPoint(x: 0.0, y: verticalInset + cornerRadius))
path.addArc(withCenter: CGPoint(x: cornerRadius, y: verticalInset + cornerRadius), radius: cornerRadius, startAngle: CGFloat.pi, endAngle: CGFloat(3.0 * CGFloat.pi / 2.0), clockwise: true)
if !arrowOnBottom {
path.addLine(to: CGPoint(x: arrowPosition - arrowWidth / 2.0, y: verticalInset))
path.addLine(to: CGPoint(x: arrowPosition, y: 0.0))
path.addLine(to: CGPoint(x: arrowPosition + arrowWidth / 2.0, y: verticalInset))
}
path.addLine(to: CGPoint(x: maskParams.size.width - cornerRadius, y: verticalInset))
path.addArc(withCenter: CGPoint(x: maskParams.size.width - cornerRadius, y: verticalInset + cornerRadius), radius: cornerRadius, startAngle: CGFloat(3.0 * CGFloat.pi / 2.0), endAngle: 0.0, clockwise: true)
path.addLine(to: CGPoint(x: maskParams.size.width, y: maskParams.size.height - cornerRadius - verticalInset))
path.addArc(withCenter: CGPoint(x: maskParams.size.width - cornerRadius, y: maskParams.size.height - cornerRadius - verticalInset), radius: cornerRadius, startAngle: 0.0, endAngle: CGFloat(CGFloat.pi / 2.0), clockwise: true)
if arrowOnBottom {
path.addLine(to: CGPoint(x: arrowPosition + arrowWidth / 2.0, y: maskParams.size.height - verticalInset))
path.addLine(to: CGPoint(x: arrowPosition, y: maskParams.size.height))
path.addLine(to: CGPoint(x: arrowPosition - arrowWidth / 2.0, y: maskParams.size.height - verticalInset))
}
path.addLine(to: CGPoint(x: cornerRadius, y: maskParams.size.height - verticalInset))
path.addArc(withCenter: CGPoint(x: cornerRadius, y: maskParams.size.height - cornerRadius - verticalInset), radius: cornerRadius, startAngle: CGFloat(CGFloat.pi / 2.0), endAngle: CGFloat(M_PI), clockwise: true)
path.close()
self.cachedMaskParams = maskParams
if let layer = self.maskView.layer as? CAShapeLayer {
if case let .animated(duration, curve) = transition, let previousPath = layer.path {
layer.animate(from: previousPath, to: path.cgPath, keyPath: "path", timingFunction: curve.timingFunction, duration: duration)
}
layer.path = path.cgPath
}
}
}
}