mirror of
https://github.com/exyte/Macaw.git
synced 2024-09-11 05:05:23 +03:00
Move layer to renderer
This commit is contained in:
parent
44dfb89d16
commit
eabb1810f0
@ -16,7 +16,6 @@ class AnimationProducer {
|
||||
|
||||
struct ContentAnimationDesc {
|
||||
let animation: ContentsAnimation
|
||||
weak var cache: AnimationCache?
|
||||
let startDate: Date
|
||||
let finishDate: Date
|
||||
let completion: (() -> Void)?
|
||||
@ -90,38 +89,38 @@ class AnimationProducer {
|
||||
return
|
||||
}
|
||||
|
||||
guard let layer = macawView.mLayer, let cache = macawView.animationCache else {
|
||||
guard let layer = macawView.mLayer else {
|
||||
return
|
||||
}
|
||||
|
||||
// swiftlint:disable superfluous_disable_command switch_case_alignment
|
||||
switch animation.type {
|
||||
case .affineTransformation:
|
||||
addTransformAnimation(animation, context, sceneLayer: layer, animationCache: cache, completion: {
|
||||
addTransformAnimation(animation, context, sceneLayer: layer, completion: {
|
||||
if let next = animation.next {
|
||||
self.play(next, context)
|
||||
}
|
||||
})
|
||||
case .opacity:
|
||||
addOpacityAnimation(animation, context, sceneLayer: layer, animationCache: cache, completion: {
|
||||
addOpacityAnimation(animation, context, sceneLayer: layer, completion: {
|
||||
if let next = animation.next {
|
||||
self.play(next, context)
|
||||
}
|
||||
})
|
||||
case .contents:
|
||||
addContentsAnimation(animation, context, cache: cache) {
|
||||
addContentsAnimation(animation, context) {
|
||||
if let next = animation.next {
|
||||
self.play(next, context)
|
||||
}
|
||||
}
|
||||
case .morphing:
|
||||
addMorphingAnimation(animation, context, sceneLayer: layer, animationCache: cache) {
|
||||
addMorphingAnimation(animation, context, sceneLayer: layer) {
|
||||
if let next = animation.next {
|
||||
self.play(next, context)
|
||||
}
|
||||
}
|
||||
case .shape:
|
||||
addShapeAnimation(animation, context, sceneLayer: layer, animationCache: cache) {
|
||||
addShapeAnimation(animation, context, sceneLayer: layer) {
|
||||
if let next = animation.next {
|
||||
self.play(next, context)
|
||||
}
|
||||
@ -220,7 +219,7 @@ class AnimationProducer {
|
||||
|
||||
// MARK: - Contents animation
|
||||
|
||||
func addContentsAnimation(_ animation: BasicAnimation, _ context: AnimationContext, cache: AnimationCache?, completion: @escaping (() -> Void)) {
|
||||
func addContentsAnimation(_ animation: BasicAnimation, _ context: AnimationContext, completion: @escaping (() -> Void)) {
|
||||
guard let contentsAnimation = animation as? ContentsAnimation else {
|
||||
return
|
||||
}
|
||||
@ -252,7 +251,6 @@ class AnimationProducer {
|
||||
|
||||
let animationDesc = ContentAnimationDesc(
|
||||
animation: contentsAnimation,
|
||||
cache: cache,
|
||||
startDate: Date(),
|
||||
finishDate: Date(timeInterval: contentsAnimation.duration, since: startDate),
|
||||
completion: completion
|
||||
@ -302,7 +300,7 @@ class AnimationProducer {
|
||||
}
|
||||
|
||||
contentsAnimations.remove(at: count - 1 - index)
|
||||
animationDesc.cache?.freeLayer(renderer)
|
||||
renderer.freeLayer()
|
||||
animationDesc.completion?()
|
||||
continue
|
||||
}
|
||||
@ -315,7 +313,7 @@ class AnimationProducer {
|
||||
if animation.manualStop || animation.paused {
|
||||
defer {
|
||||
contentsAnimations.remove(at: count - 1 - index)
|
||||
animationDesc.cache?.freeLayer(renderer)
|
||||
renderer.freeLayer()
|
||||
}
|
||||
|
||||
if animation.manualStop {
|
||||
|
@ -1,9 +1,9 @@
|
||||
import Foundation
|
||||
|
||||
class AnimationUtils {
|
||||
class AbsoluteUtils {
|
||||
|
||||
class func absolutePosition(_ nodeRenderer: NodeRenderer?, _ context: AnimationContext) -> Transform {
|
||||
return AnimationUtils.absoluteTransform(nodeRenderer, context, pos: nodeRenderer?.node.place ?? .identity)
|
||||
return AbsoluteUtils.absoluteTransform(nodeRenderer, context, pos: nodeRenderer?.node.place ?? .identity)
|
||||
}
|
||||
|
||||
class func absoluteTransform(_ nodeRenderer: NodeRenderer?, _ context: AnimationContext, pos: Transform) -> Transform {
|
||||
|
@ -6,29 +6,12 @@ import UIKit
|
||||
import AppKit
|
||||
#endif
|
||||
|
||||
class AnimationCache {
|
||||
class AnimationUtils {
|
||||
|
||||
class CachedLayer {
|
||||
let rootLayer: ShapeLayer
|
||||
let animationLayer: ShapeLayer
|
||||
|
||||
required init(rootLayer: ShapeLayer, animationLayer: ShapeLayer) {
|
||||
self.rootLayer = rootLayer
|
||||
self.animationLayer = animationLayer
|
||||
}
|
||||
}
|
||||
|
||||
weak var sceneLayer: CALayer?
|
||||
var cache = [NodeRenderer: CachedLayer]()
|
||||
|
||||
required init(sceneLayer: CALayer) {
|
||||
self.sceneLayer = sceneLayer
|
||||
}
|
||||
|
||||
func layerForNodeRenderer(_ renderer: NodeRenderer, _ context: AnimationContext, animation: Animation, customBounds: Rect? = .none, shouldRenderContent: Bool = true) -> ShapeLayer {
|
||||
class func layerForNodeRenderer(_ renderer: NodeRenderer, _ context: AnimationContext, animation: Animation, customBounds: Rect? = .none, shouldRenderContent: Bool = true) -> ShapeLayer {
|
||||
|
||||
let node = renderer.node
|
||||
if let cachedLayer = cache[renderer] {
|
||||
if let cachedLayer = renderer.layer {
|
||||
cachedLayer.rootLayer.transform = CATransform3DMakeAffineTransform(uncachedParentsPlace(renderer).toCG())
|
||||
cachedLayer.animationLayer.opacity = Float(node.opacity)
|
||||
return cachedLayer.animationLayer
|
||||
@ -37,19 +20,18 @@ class AnimationCache {
|
||||
// 'sublayer' is for actual CAAnimations, and 'layer' is for manual transforming and hierarchy changes
|
||||
let sublayer = ShapeLayer()
|
||||
sublayer.shouldRenderContent = shouldRenderContent
|
||||
sublayer.animationCache = self
|
||||
|
||||
let layer = ShapeLayer()
|
||||
layer.addSublayer(sublayer)
|
||||
layer.masksToBounds = false
|
||||
|
||||
// Use to debug animation layers
|
||||
// sublayer.backgroundColor = MColor.green.cgColor
|
||||
// sublayer.borderWidth = 2.0
|
||||
// sublayer.borderColor = MColor.red.cgColor
|
||||
// layer.backgroundColor = MColor.blue.cgColor
|
||||
// layer.borderWidth = 2.0
|
||||
// layer.borderColor = MColor.cyan.cgColor
|
||||
// sublayer.backgroundColor = MColor.green.cgColor
|
||||
// sublayer.borderWidth = 2.0
|
||||
// sublayer.borderColor = MColor.red.cgColor
|
||||
// layer.backgroundColor = MColor.blue.cgColor
|
||||
// layer.borderWidth = 2.0
|
||||
// layer.borderColor = MColor.cyan.cgColor
|
||||
|
||||
let calculatedBounds = customBounds ?? node.bounds
|
||||
if let shapeBounds = calculatedBounds {
|
||||
@ -67,7 +49,7 @@ class AnimationCache {
|
||||
layer.zPosition = CGFloat(renderer.zPosition)
|
||||
|
||||
// Clip
|
||||
if let clip = AnimationUtils.absoluteClip(renderer) {
|
||||
if let clip = AbsoluteUtils.absoluteClip(renderer) {
|
||||
let maskLayer = CAShapeLayer()
|
||||
let origPath = clip.toCGPath()
|
||||
var offsetTransform = CGAffineTransform(translationX: -1.0 * cgRect.origin.x, y: -1.0 * cgRect.origin.y)
|
||||
@ -84,10 +66,10 @@ class AnimationCache {
|
||||
|
||||
// find first parent with cached layer
|
||||
var parent: NodeRenderer? = renderer.parentRenderer
|
||||
var parentCachedLayer: CALayer? = sceneLayer
|
||||
var parentCachedLayer: CALayer? = renderer.sceneLayer
|
||||
while parent != nil {
|
||||
if let parent = parent {
|
||||
if let cached = cache[parent] {
|
||||
if let cached = parent.layer {
|
||||
parentCachedLayer = cached.animationLayer
|
||||
break
|
||||
}
|
||||
@ -99,11 +81,11 @@ class AnimationCache {
|
||||
parentCachedLayer?.addSublayer(layer)
|
||||
parentCachedLayer?.setNeedsDisplay()
|
||||
|
||||
cache[renderer] = CachedLayer(rootLayer: layer, animationLayer: sublayer)
|
||||
renderer.layer = CachedLayer(rootLayer: layer, animationLayer: sublayer)
|
||||
|
||||
// move children to new layer
|
||||
for child in renderer.getAllChildrenRecursive() {
|
||||
if let cachedChildLayer = cache[child], let parentCachedLayer = parentCachedLayer {
|
||||
if let cachedChildLayer = child.layer, let parentCachedLayer = parentCachedLayer {
|
||||
parentCachedLayer.sublayers?.forEach { childLayer in
|
||||
if childLayer === cachedChildLayer.rootLayer {
|
||||
|
||||
@ -116,12 +98,12 @@ class AnimationCache {
|
||||
}
|
||||
}
|
||||
|
||||
sceneLayer?.setNeedsDisplay()
|
||||
renderer.sceneLayer?.setNeedsDisplay()
|
||||
|
||||
return sublayer
|
||||
}
|
||||
|
||||
private func calculateAnimationScale(animation: Animation) -> CGFloat {
|
||||
class private func calculateAnimationScale(animation: Animation) -> CGFloat {
|
||||
guard let defaultScale = MMainScreen()?.mScale else {
|
||||
return 1.0
|
||||
}
|
||||
@ -159,22 +141,41 @@ class AnimationCache {
|
||||
return defaultScale * CGFloat(sqrt(maxArea))
|
||||
}
|
||||
|
||||
func freeLayerHard(_ renderer: NodeRenderer) {
|
||||
freeLayer(renderer)
|
||||
class func uncachedParentsPlace(_ renderer: NodeRenderer) -> Transform {
|
||||
var parent: NodeRenderer? = renderer.parentRenderer
|
||||
var uncachedParentsPlace = Transform.identity
|
||||
while parent != nil {
|
||||
if let parent = parent {
|
||||
if parent.layer != nil {
|
||||
break
|
||||
}
|
||||
uncachedParentsPlace = uncachedParentsPlace.concat(with: parent.node.place)
|
||||
}
|
||||
parent = parent?.parentRenderer
|
||||
}
|
||||
return uncachedParentsPlace
|
||||
}
|
||||
}
|
||||
|
||||
extension NodeRenderer {
|
||||
|
||||
func isAnimating() -> Bool {
|
||||
return layer != nil
|
||||
}
|
||||
|
||||
func freeLayer(_ renderer: NodeRenderer?) {
|
||||
guard let nodeRenderer = renderer, let layer = cache[nodeRenderer] else {
|
||||
func freeLayer() {
|
||||
|
||||
let nodeRenderer = self
|
||||
guard let layer = nodeRenderer.layer else {
|
||||
return
|
||||
}
|
||||
|
||||
cache.removeValue(forKey: nodeRenderer)
|
||||
nodeRenderer.layer = nil
|
||||
|
||||
// find first parent with cached layer
|
||||
var parent: NodeRenderer? = nodeRenderer.parentRenderer
|
||||
var parentCachedLayer: CALayer? = sceneLayer
|
||||
var parentCachedLayer: CALayer? = nodeRenderer.sceneLayer
|
||||
while parent != nil {
|
||||
if let parent = parent, let cached = cache[parent] {
|
||||
if let parent = parent, let cached = parent.layer {
|
||||
parentCachedLayer = cached.animationLayer
|
||||
break
|
||||
}
|
||||
@ -183,12 +184,12 @@ class AnimationCache {
|
||||
|
||||
// move children to closest parent layer
|
||||
for child in nodeRenderer.getAllChildrenRecursive() {
|
||||
if let cachedChildLayer = cache[child], let parentCachedLayer = parentCachedLayer {
|
||||
if let cachedChildLayer = child.layer, let parentCachedLayer = parentCachedLayer {
|
||||
layer.animationLayer.sublayers?.forEach { childLayer in
|
||||
if childLayer === cachedChildLayer.rootLayer {
|
||||
CATransaction.setValue(kCFBooleanTrue, forKey:kCATransactionDisableActions)
|
||||
CATransaction.setValue(kCFBooleanTrue, forKey: kCATransactionDisableActions)
|
||||
childLayer.removeFromSuperlayer()
|
||||
childLayer.transform = CATransform3DMakeAffineTransform(uncachedParentsPlace(child).toCG())
|
||||
childLayer.transform = CATransform3DMakeAffineTransform(AnimationUtils.uncachedParentsPlace(child).toCG())
|
||||
parentCachedLayer.addSublayer(childLayer)
|
||||
childLayer.setNeedsDisplay()
|
||||
CATransaction.commit()
|
||||
@ -202,31 +203,4 @@ class AnimationCache {
|
||||
parentCachedLayer?.setNeedsDisplay()
|
||||
sceneLayer?.setNeedsDisplay()
|
||||
}
|
||||
|
||||
func isAnimating(_ nodeRenderer: NodeRenderer) -> Bool {
|
||||
return cache[nodeRenderer] != nil
|
||||
}
|
||||
|
||||
func isAnimating(_ node: Node) -> Bool {
|
||||
if let renderer = cache.keys.first(where: { $0.node === node }) {
|
||||
return isAnimating(renderer)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func uncachedParentsPlace(_ renderer: NodeRenderer) -> Transform {
|
||||
var parent: NodeRenderer? = renderer.parentRenderer
|
||||
var uncachedParentsPlace = Transform.identity
|
||||
while parent != nil {
|
||||
if let parent = parent {
|
||||
if cache[parent] != nil {
|
||||
break
|
||||
}
|
||||
uncachedParentsPlace = uncachedParentsPlace.concat(with: parent.node.place)
|
||||
}
|
||||
parent = parent?.parentRenderer
|
||||
}
|
||||
return uncachedParentsPlace
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ import UIKit
|
||||
import AppKit
|
||||
#endif
|
||||
|
||||
func addMorphingAnimation(_ animation: BasicAnimation, _ context: AnimationContext, sceneLayer: CALayer, animationCache: AnimationCache?, completion: @escaping (() -> Void)) {
|
||||
func addMorphingAnimation(_ animation: BasicAnimation, _ context: AnimationContext, sceneLayer: CALayer?, completion: @escaping (() -> Void)) {
|
||||
guard let morphingAnimation = animation as? MorphingAnimation else {
|
||||
return
|
||||
}
|
||||
@ -30,9 +30,8 @@ func addMorphingAnimation(_ animation: BasicAnimation, _ context: AnimationConte
|
||||
let toLocus = morphingAnimation.getVFunc()(animation.autoreverses ? 0.5 : 1.0)
|
||||
let duration = animation.autoreverses ? animation.getDuration() / 2.0 : animation.getDuration()
|
||||
|
||||
guard let layer = animationCache?.layerForNodeRenderer(renderer, context, animation: animation, shouldRenderContent: false) else {
|
||||
return
|
||||
}
|
||||
let layer = AnimationUtils.layerForNodeRenderer(renderer, context, animation: animation, shouldRenderContent: false)
|
||||
|
||||
// Creating proper animation
|
||||
let generatedAnimation = pathAnimation(
|
||||
from: fromLocus,
|
||||
@ -59,7 +58,7 @@ func addMorphingAnimation(_ animation: BasicAnimation, _ context: AnimationConte
|
||||
shape.form = morphingAnimation.getVFunc()(1.0)
|
||||
}
|
||||
|
||||
animationCache?.freeLayer(renderer)
|
||||
renderer.freeLayer()
|
||||
|
||||
if !animation.cycled &&
|
||||
!animation.manualStop {
|
||||
|
@ -6,7 +6,7 @@ import UIKit
|
||||
import AppKit
|
||||
#endif
|
||||
|
||||
func addOpacityAnimation(_ animation: BasicAnimation, _ context: AnimationContext, sceneLayer: CALayer, animationCache: AnimationCache?, completion: @escaping (() -> Void)) {
|
||||
func addOpacityAnimation(_ animation: BasicAnimation, _ context: AnimationContext, sceneLayer: CALayer?, completion: @escaping (() -> Void)) {
|
||||
guard let opacityAnimation = animation as? OpacityAnimation else {
|
||||
return
|
||||
}
|
||||
@ -34,7 +34,7 @@ func addOpacityAnimation(_ animation: BasicAnimation, _ context: AnimationContex
|
||||
|
||||
generatedAnimation.completion = { finished in
|
||||
|
||||
animationCache?.freeLayer(renderer)
|
||||
renderer.freeLayer()
|
||||
|
||||
if animation.paused {
|
||||
animation.pausedProgress += animation.progress
|
||||
@ -58,12 +58,11 @@ func addOpacityAnimation(_ animation: BasicAnimation, _ context: AnimationContex
|
||||
completion()
|
||||
}
|
||||
|
||||
if let layer = animationCache?.layerForNodeRenderer(renderer, context, animation: animation) {
|
||||
let animationId = animation.ID
|
||||
layer.add(generatedAnimation, forKey: animationId)
|
||||
animation.removeFunc = { [weak layer] in
|
||||
layer?.removeAnimation(forKey: animationId)
|
||||
}
|
||||
let layer = AnimationUtils.layerForNodeRenderer(renderer, context, animation: animation)
|
||||
let animationId = animation.ID
|
||||
layer.add(generatedAnimation, forKey: animationId)
|
||||
animation.removeFunc = { [weak layer] in
|
||||
layer?.removeAnimation(forKey: animationId)
|
||||
}
|
||||
|
||||
if !transactionsDisabled {
|
||||
|
@ -14,7 +14,7 @@ import UIKit
|
||||
import AppKit
|
||||
#endif
|
||||
|
||||
func addShapeAnimation(_ animation: BasicAnimation, _ context: AnimationContext, sceneLayer: CALayer, animationCache: AnimationCache?, completion: @escaping (() -> Void)) {
|
||||
func addShapeAnimation(_ animation: BasicAnimation, _ context: AnimationContext, sceneLayer: CALayer?, completion: @escaping (() -> Void)) {
|
||||
guard let shapeAnimation = animation as? ShapeAnimation else {
|
||||
return
|
||||
}
|
||||
@ -30,16 +30,14 @@ func addShapeAnimation(_ animation: BasicAnimation, _ context: AnimationContext,
|
||||
let toShape = shapeAnimation.getVFunc()(animation.autoreverses ? 0.5 : 1.0)
|
||||
let duration = animation.autoreverses ? animation.getDuration() / 2.0 : animation.getDuration()
|
||||
|
||||
guard let layer = animationCache?.layerForNodeRenderer(renderer, context, animation: animation, shouldRenderContent: false) else {
|
||||
return
|
||||
}
|
||||
let layer = AnimationUtils.layerForNodeRenderer(renderer, context, animation: animation, shouldRenderContent: false)
|
||||
|
||||
// Creating proper animation
|
||||
let generatedAnimation = generateShapeAnimation(context,
|
||||
from: fromShape,
|
||||
to: toShape,
|
||||
animation: shapeAnimation,
|
||||
duration: duration)
|
||||
from: fromShape,
|
||||
to: toShape,
|
||||
animation: shapeAnimation,
|
||||
duration: duration)
|
||||
|
||||
generatedAnimation.repeatCount = Float(animation.repeatCount)
|
||||
generatedAnimation.timingFunction = caTimingFunction(animation.easing)
|
||||
@ -68,7 +66,7 @@ func addShapeAnimation(_ animation: BasicAnimation, _ context: AnimationContext,
|
||||
shape.fill = fromShape.fill
|
||||
}
|
||||
|
||||
animationCache?.freeLayer(renderer)
|
||||
renderer.freeLayer()
|
||||
|
||||
if !animation.cycled && !animation.manualStop {
|
||||
animation.completion?()
|
||||
|
@ -6,7 +6,7 @@ import UIKit
|
||||
import AppKit
|
||||
#endif
|
||||
|
||||
func addTransformAnimation(_ animation: BasicAnimation, _ context: AnimationContext, sceneLayer: CALayer, animationCache: AnimationCache?, completion: @escaping (() -> Void)) {
|
||||
func addTransformAnimation(_ animation: BasicAnimation, _ context: AnimationContext, sceneLayer: CALayer?, completion: @escaping (() -> Void)) {
|
||||
guard let transformAnimation = animation as? TransformAnimation else {
|
||||
return
|
||||
}
|
||||
@ -22,16 +22,14 @@ func addTransformAnimation(_ animation: BasicAnimation, _ context: AnimationCont
|
||||
let transactionsDisabled = CATransaction.disableActions()
|
||||
CATransaction.setDisableActions(true)
|
||||
|
||||
guard let layer = animationCache?.layerForNodeRenderer(renderer, context, animation: animation, shouldRenderContent: true) else {
|
||||
return
|
||||
}
|
||||
let layer = AnimationUtils.layerForNodeRenderer(renderer, context, animation: animation, shouldRenderContent: true)
|
||||
|
||||
// Creating proper animation
|
||||
let generatedAnimation = transformAnimationByFunc(transformAnimation,
|
||||
context,
|
||||
duration: animation.getDuration(),
|
||||
offset: animation.pausedProgress,
|
||||
fps: transformAnimation.logicalFps)
|
||||
context,
|
||||
duration: animation.getDuration(),
|
||||
offset: animation.pausedProgress,
|
||||
fps: transformAnimation.logicalFps)
|
||||
|
||||
generatedAnimation.repeatCount = Float(animation.repeatCount)
|
||||
|
||||
@ -56,7 +54,7 @@ func addTransformAnimation(_ animation: BasicAnimation, _ context: AnimationCont
|
||||
node.placeVar.value = transformAnimation.getVFunc()(1.0)
|
||||
}
|
||||
|
||||
animationCache?.freeLayer(renderer)
|
||||
renderer.freeLayer()
|
||||
|
||||
if !animation.cycled &&
|
||||
!animation.manualStop &&
|
||||
|
@ -12,6 +12,12 @@ import UIKit
|
||||
import AppKit
|
||||
#endif
|
||||
|
||||
public enum Relativity {
|
||||
case parent
|
||||
case scene
|
||||
case view
|
||||
}
|
||||
|
||||
class NodePath {
|
||||
let node: Node
|
||||
let location: CGPoint
|
||||
|
@ -13,9 +13,9 @@ class GroupRenderer: NodeRenderer {
|
||||
return group
|
||||
}
|
||||
|
||||
init(group: Group, view: MacawView?, animationCache: AnimationCache?, parentRenderer: GroupRenderer? = nil) {
|
||||
init(group: Group, view: MacawView?, parentRenderer: GroupRenderer? = nil) {
|
||||
self.group = group
|
||||
super.init(node: group, view: view, animationCache: animationCache, parentRenderer: parentRenderer)
|
||||
super.init(node: group, view: view, parentRenderer: parentRenderer)
|
||||
updateRenderers()
|
||||
}
|
||||
|
||||
@ -40,7 +40,7 @@ class GroupRenderer: NodeRenderer {
|
||||
|
||||
override func doRender(in context: CGContext, force: Bool, opacity: Double, coloringMode: ColoringMode = .rgb) {
|
||||
renderers.forEach { renderer in
|
||||
if !(animationCache?.isAnimating(renderer) ?? false) {
|
||||
if !renderer.isAnimating() {
|
||||
renderer.render(in: context, force: force, opacity: opacity, coloringMode: coloringMode)
|
||||
}
|
||||
}
|
||||
@ -64,13 +64,12 @@ class GroupRenderer: NodeRenderer {
|
||||
private func updateRenderers() {
|
||||
|
||||
renderers.forEach {
|
||||
animationCache?.freeLayerHard($0)
|
||||
$0.dispose()
|
||||
}
|
||||
renderers.removeAll()
|
||||
|
||||
renderers = group.contents.compactMap { child -> NodeRenderer? in
|
||||
return RenderUtils.createNodeRenderer(child, view: view, animationCache: animationCache, parentRenderer: self)
|
||||
return RenderUtils.createNodeRenderer(child, view: view, parentRenderer: self)
|
||||
}
|
||||
|
||||
var parent: NodeRenderer = self
|
||||
|
@ -17,9 +17,9 @@ class ImageRenderer: NodeRenderer {
|
||||
return image
|
||||
}
|
||||
|
||||
init(image: Image, view: MacawView?, animationCache: AnimationCache?, parentRenderer: GroupRenderer? = nil) {
|
||||
init(image: Image, view: MacawView?, parentRenderer: GroupRenderer? = nil) {
|
||||
self.image = image
|
||||
super.init(node: image, view: view, animationCache: animationCache, parentRenderer: parentRenderer)
|
||||
super.init(node: image, view: view, parentRenderer: parentRenderer)
|
||||
}
|
||||
|
||||
deinit {
|
||||
|
@ -6,26 +6,34 @@ import UIKit
|
||||
import AppKit
|
||||
#endif
|
||||
|
||||
public enum Relativity {
|
||||
case parent
|
||||
case scene
|
||||
case view
|
||||
}
|
||||
|
||||
enum ColoringMode {
|
||||
case rgb, greyscale, alphaOnly
|
||||
}
|
||||
|
||||
class CachedLayer {
|
||||
let rootLayer: ShapeLayer
|
||||
let animationLayer: ShapeLayer
|
||||
|
||||
required init(rootLayer: ShapeLayer, animationLayer: ShapeLayer) {
|
||||
self.rootLayer = rootLayer
|
||||
self.animationLayer = animationLayer
|
||||
}
|
||||
}
|
||||
|
||||
class NodeRenderer {
|
||||
|
||||
weak var view: MacawView?
|
||||
let parentRenderer: GroupRenderer?
|
||||
var sceneLayer: CALayer? {
|
||||
return view?.mLayer
|
||||
}
|
||||
var layer: CachedLayer?
|
||||
var zPosition: Int = 0
|
||||
|
||||
let parentRenderer: GroupRenderer?
|
||||
|
||||
fileprivate let onNodeChange: () -> Void
|
||||
fileprivate let disposables = GroupDisposable()
|
||||
fileprivate var active = false
|
||||
weak var animationCache: AnimationCache?
|
||||
|
||||
fileprivate var cachedAbsPlace: Transform?
|
||||
fileprivate var absPlace: Transform {
|
||||
@ -63,19 +71,14 @@ class NodeRenderer {
|
||||
fatalError("Unsupported")
|
||||
}
|
||||
|
||||
init(node: Node, view: MacawView?, animationCache: AnimationCache?, parentRenderer: GroupRenderer? = nil) {
|
||||
init(node: Node, view: MacawView?, parentRenderer: GroupRenderer? = nil) {
|
||||
self.view = view
|
||||
self.animationCache = animationCache
|
||||
self.parentRenderer = parentRenderer
|
||||
|
||||
onNodeChange = { [unowned node, weak view] in
|
||||
guard let isAnimating = animationCache?.isAnimating(node) else {
|
||||
return
|
||||
}
|
||||
|
||||
if isAnimating {
|
||||
return
|
||||
}
|
||||
onNodeChange = { [weak view] in
|
||||
// if self.isAnimating() {
|
||||
// return
|
||||
// }
|
||||
|
||||
view?.setNeedsDisplay()
|
||||
}
|
||||
@ -116,6 +119,7 @@ class NodeRenderer {
|
||||
open func dispose() {
|
||||
removeObservers()
|
||||
node.animationObservers = node.animationObservers.filter { !($0 as? NodeRenderer === self) }
|
||||
freeLayer()
|
||||
}
|
||||
|
||||
final public func render(in context: CGContext, force: Bool, opacity: Double, coloringMode: ColoringMode = .rgb) {
|
||||
@ -169,7 +173,7 @@ class NodeRenderer {
|
||||
}
|
||||
|
||||
final func directRender(in context: CGContext, force: Bool = true, opacity: Double = 1.0, coloringMode: ColoringMode = .rgb) {
|
||||
if let isAnimating = animationCache?.isAnimating(self), isAnimating {
|
||||
if isAnimating() {
|
||||
self.removeObservers()
|
||||
if !force {
|
||||
return
|
||||
@ -329,7 +333,7 @@ class NodeRenderer {
|
||||
private func getMaskedImage(bounds: Rect) -> CGImage {
|
||||
let mask = node.mask!
|
||||
let image = renderToImage(bounds: bounds)
|
||||
let nodeRenderer = RenderUtils.createNodeRenderer(mask, view: .none, animationCache: animationCache)
|
||||
let nodeRenderer = RenderUtils.createNodeRenderer(mask, view: .none)
|
||||
let maskImage = nodeRenderer.renderToImage(bounds: bounds, coloringMode: .greyscale)
|
||||
return apply(maskImage: maskImage, to: image)
|
||||
}
|
||||
@ -371,7 +375,7 @@ class NodeRenderer {
|
||||
|
||||
func getAllChildrenRecursive() -> [NodeRenderer] {
|
||||
var children = getAllChildren(self)
|
||||
children.removeAll(where: { (r) -> Bool in
|
||||
children.removeAll(where: { r -> Bool in
|
||||
r === self
|
||||
})
|
||||
return children
|
||||
|
@ -16,15 +16,15 @@ class RenderUtils {
|
||||
return p
|
||||
}
|
||||
|
||||
class func createNodeRenderer(_ node: Node, view: MacawView?, animationCache: AnimationCache?, parentRenderer: GroupRenderer? = nil) -> NodeRenderer {
|
||||
class func createNodeRenderer(_ node: Node, view: MacawView?, parentRenderer: GroupRenderer? = nil) -> NodeRenderer {
|
||||
if let group = node as? Group {
|
||||
return GroupRenderer(group: group, view: view, animationCache: animationCache, parentRenderer: parentRenderer)
|
||||
return GroupRenderer(group: group, view: view, parentRenderer: parentRenderer)
|
||||
} else if let shape = node as? Shape {
|
||||
return ShapeRenderer(shape: shape, view: view, animationCache: animationCache, parentRenderer: parentRenderer)
|
||||
return ShapeRenderer(shape: shape, view: view, parentRenderer: parentRenderer)
|
||||
} else if let text = node as? Text {
|
||||
return TextRenderer(text: text, view: view, animationCache: animationCache, parentRenderer: parentRenderer)
|
||||
return TextRenderer(text: text, view: view, parentRenderer: parentRenderer)
|
||||
} else if let image = node as? Image {
|
||||
return ImageRenderer(image: image, view: view, animationCache: animationCache, parentRenderer: parentRenderer)
|
||||
return ImageRenderer(image: image, view: view, parentRenderer: parentRenderer)
|
||||
}
|
||||
fatalError("Unsupported node: \(node)")
|
||||
}
|
||||
|
@ -10,9 +10,9 @@ class ShapeRenderer: NodeRenderer {
|
||||
|
||||
var shape: Shape
|
||||
|
||||
init(shape: Shape, view: MacawView?, animationCache: AnimationCache?, parentRenderer: GroupRenderer? = nil) {
|
||||
init(shape: Shape, view: MacawView?, parentRenderer: GroupRenderer? = nil) {
|
||||
self.shape = shape
|
||||
super.init(node: shape, view: view, animationCache: animationCache, parentRenderer: parentRenderer)
|
||||
super.init(node: shape, view: view, parentRenderer: parentRenderer)
|
||||
}
|
||||
|
||||
deinit {
|
||||
@ -165,7 +165,7 @@ class ShapeRenderer: NodeRenderer {
|
||||
if !pattern.userSpace, let node = BoundsUtils.createNodeFromRespectiveCoords(respectiveNode: pattern.content, absoluteLocus: shape.form) {
|
||||
patternNode = node
|
||||
}
|
||||
let renderer = RenderUtils.createNodeRenderer(patternNode, view: view, animationCache: animationCache)
|
||||
let renderer = RenderUtils.createNodeRenderer(patternNode, view: view)
|
||||
|
||||
var patternBounds = pattern.bounds
|
||||
if !pattern.userSpace {
|
||||
|
@ -13,9 +13,9 @@ class TextRenderer: NodeRenderer {
|
||||
return text
|
||||
}
|
||||
|
||||
init(text: Text, view: MacawView?, animationCache: AnimationCache?, parentRenderer: GroupRenderer? = nil) {
|
||||
init(text: Text, view: MacawView?, parentRenderer: GroupRenderer? = nil) {
|
||||
self.text = text
|
||||
super.init(node: text, view: view, animationCache: animationCache, parentRenderer: parentRenderer)
|
||||
super.init(node: text, view: view, parentRenderer: parentRenderer)
|
||||
}
|
||||
|
||||
deinit {
|
||||
|
@ -136,7 +136,7 @@ public extension CGAffineTransform {
|
||||
public extension Node {
|
||||
|
||||
func toNativeImage(size: Size, layout: ContentLayout = .of()) -> MImage {
|
||||
let renderer = RenderUtils.createNodeRenderer(self, view: nil, animationCache: nil)
|
||||
let renderer = RenderUtils.createNodeRenderer(self, view: nil)
|
||||
let rect = size.rect()
|
||||
|
||||
MGraphicsBeginImageContextWithOptions(size.toCG(), false, 1)
|
||||
|
@ -17,9 +17,7 @@ open class MacawView: MView, MGestureRecognizerDelegate {
|
||||
didSet {
|
||||
layoutHelper.nodeChanged()
|
||||
self.renderer?.dispose()
|
||||
if let cache = animationCache {
|
||||
self.renderer = RenderUtils.createNodeRenderer(node, view: self, animationCache: cache)
|
||||
}
|
||||
self.renderer = RenderUtils.createNodeRenderer(node, view: self)
|
||||
|
||||
if let _ = superview {
|
||||
animationProducer.addStoredAnimations(node, self)
|
||||
@ -100,8 +98,6 @@ open class MacawView: MView, MGestureRecognizerDelegate {
|
||||
var toRender = true
|
||||
var frameSetFirstTime = false
|
||||
|
||||
internal var animationCache: AnimationCache?
|
||||
|
||||
#if os(OSX)
|
||||
open override var layer: CALayer? {
|
||||
didSet {
|
||||
@ -111,7 +107,7 @@ open class MacawView: MView, MGestureRecognizerDelegate {
|
||||
initializeView()
|
||||
|
||||
if let cache = self.animationCache {
|
||||
self.renderer = RenderUtils.createNodeRenderer(node, view: self, animationCache: cache)
|
||||
self.renderer = RenderUtils.createNodeRenderer(node, view: self)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -124,9 +120,7 @@ open class MacawView: MView, MGestureRecognizerDelegate {
|
||||
initializeView()
|
||||
|
||||
self.node = node
|
||||
if let cache = self.animationCache {
|
||||
self.renderer = RenderUtils.createNodeRenderer(node, view: self, animationCache: cache)
|
||||
}
|
||||
self.renderer = RenderUtils.createNodeRenderer(node, view: self)
|
||||
backgroundColor = .white
|
||||
}
|
||||
|
||||
@ -134,9 +128,7 @@ open class MacawView: MView, MGestureRecognizerDelegate {
|
||||
self.init(frame: frame)
|
||||
|
||||
self.node = node
|
||||
if let cache = self.animationCache {
|
||||
self.renderer = RenderUtils.createNodeRenderer(node, view: self, animationCache: cache)
|
||||
}
|
||||
self.renderer = RenderUtils.createNodeRenderer(node, view: self)
|
||||
backgroundColor = .white
|
||||
}
|
||||
|
||||
@ -160,12 +152,6 @@ open class MacawView: MView, MGestureRecognizerDelegate {
|
||||
self.contentLayout = .none
|
||||
self.context = RenderContext(view: self)
|
||||
|
||||
guard let layer = self.mLayer else {
|
||||
return
|
||||
}
|
||||
|
||||
self.animationCache = AnimationCache(sceneLayer: layer)
|
||||
|
||||
let tapRecognizer = MTapGestureRecognizer(target: self, action: #selector(MacawView.handleTap))
|
||||
let longTapRecognizer = MLongPressGestureRecognizer(target: self, action: #selector(MacawView.handleLongTap(recognizer:)))
|
||||
let panRecognizer = MPanGestureRecognizer(target: self, action: #selector(MacawView.handlePan))
|
||||
|
@ -8,7 +8,6 @@ import AppKit
|
||||
|
||||
class ShapeLayer: CAShapeLayer {
|
||||
weak var renderer: NodeRenderer?
|
||||
weak var animationCache: AnimationCache?
|
||||
var shouldRenderContent = true
|
||||
var isForceRenderingEnabled = true
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user