mirror of
https://github.com/exyte/Macaw.git
synced 2024-10-26 04:49:57 +03:00
Use layout cache during animation start
This commit is contained in:
parent
bf79a59f6f
commit
ccb125d872
@ -83,7 +83,7 @@ class BasicAnimation: Animation {
|
||||
manualStop = false
|
||||
paused = false
|
||||
|
||||
animationProducer.addAnimation(self)
|
||||
animationProducer.play(self, AnimationContext())
|
||||
}
|
||||
|
||||
override open func stop() {
|
||||
|
@ -25,13 +25,13 @@ class AnimationProducer {
|
||||
|
||||
var contentsAnimations = [ContentAnimationDesc]()
|
||||
|
||||
func addAnimation(_ animation: BasicAnimation, withoutDelay: Bool = false) {
|
||||
func play(_ animation: BasicAnimation, _ context: AnimationContext, withoutDelay: Bool = false) {
|
||||
|
||||
// Delay - launching timer
|
||||
if animation.delay > 0.0 && !withoutDelay {
|
||||
|
||||
let timer = Timer.schedule(delay: animation.delay) { [weak self] _ in
|
||||
self?.addAnimation(animation, withoutDelay: true)
|
||||
self?.play(animation, context, withoutDelay: true)
|
||||
_ = self?.delayedAnimations.removeValue(forKey: animation)
|
||||
animation.delayed = false
|
||||
}
|
||||
@ -55,7 +55,7 @@ class AnimationProducer {
|
||||
}
|
||||
|
||||
let reAdd = EmptyAnimation {
|
||||
self.addAnimation(animation)
|
||||
self.play(animation, context)
|
||||
}
|
||||
|
||||
if let nextAnimation = animation.next {
|
||||
@ -79,9 +79,9 @@ class AnimationProducer {
|
||||
case .empty:
|
||||
executeCompletion(animation)
|
||||
case .sequence:
|
||||
addAnimationSequence(animation)
|
||||
addAnimationSequence(animation, context)
|
||||
case .combine:
|
||||
addCombineAnimation(animation)
|
||||
addCombineAnimation(animation, context)
|
||||
default:
|
||||
break
|
||||
}
|
||||
@ -102,33 +102,33 @@ class AnimationProducer {
|
||||
// swiftlint:disable superfluous_disable_command switch_case_alignment
|
||||
switch animation.type {
|
||||
case .affineTransformation:
|
||||
addTransformAnimation(animation, sceneLayer: layer, animationCache: cache, completion: {
|
||||
addTransformAnimation(animation, context, sceneLayer: layer, animationCache: cache, completion: {
|
||||
if let next = animation.next {
|
||||
self.addAnimation(next)
|
||||
self.play(next, context)
|
||||
}
|
||||
})
|
||||
case .opacity:
|
||||
addOpacityAnimation(animation, sceneLayer: layer, animationCache: cache, completion: {
|
||||
addOpacityAnimation(animation, context, sceneLayer: layer, animationCache: cache, completion: {
|
||||
if let next = animation.next {
|
||||
self.addAnimation(next)
|
||||
self.play(next, context)
|
||||
}
|
||||
})
|
||||
case .contents:
|
||||
addContentsAnimation(animation, cache: cache) {
|
||||
addContentsAnimation(animation, context, cache: cache) {
|
||||
if let next = animation.next {
|
||||
self.addAnimation(next)
|
||||
self.play(next, context)
|
||||
}
|
||||
}
|
||||
case .morphing:
|
||||
addMorphingAnimation(animation, sceneLayer: layer, animationCache: cache) {
|
||||
addMorphingAnimation(animation, context, sceneLayer: layer, animationCache: cache) {
|
||||
if let next = animation.next {
|
||||
self.addAnimation(next)
|
||||
self.play(next, context)
|
||||
}
|
||||
}
|
||||
case .shape:
|
||||
addShapeAnimation(animation, sceneLayer: layer, animationCache: cache) {
|
||||
addShapeAnimation(animation, context, sceneLayer: layer, animationCache: cache) {
|
||||
if let next = animation.next {
|
||||
self.addAnimation(next)
|
||||
self.play(next, context)
|
||||
}
|
||||
}
|
||||
default:
|
||||
@ -149,7 +149,8 @@ class AnimationProducer {
|
||||
}
|
||||
|
||||
// MARK: - Sequence animation
|
||||
func addAnimationSequence(_ animationSequnce: Animation) {
|
||||
func addAnimationSequence(_ animationSequnce: Animation,
|
||||
_ context: AnimationContext) {
|
||||
guard let sequence = animationSequnce as? AnimationSequence else {
|
||||
return
|
||||
}
|
||||
@ -193,7 +194,7 @@ class AnimationProducer {
|
||||
|
||||
// Launching
|
||||
if let firstAnimation = sequence.animations.first {
|
||||
self.addAnimation(firstAnimation)
|
||||
self.play(firstAnimation, context)
|
||||
}
|
||||
}
|
||||
|
||||
@ -203,9 +204,13 @@ class AnimationProducer {
|
||||
}
|
||||
|
||||
// MARK: - Stored animation
|
||||
func addStoredAnimations(_ node: Node) {
|
||||
func addStoredAnimations(_ node: Node, _ view: MacawView) {
|
||||
addStoredAnimations(node, AnimationContext())
|
||||
}
|
||||
|
||||
func addStoredAnimations(_ node: Node, _ context: AnimationContext) {
|
||||
if let animation = storedAnimations[node] {
|
||||
addAnimation(animation)
|
||||
play(animation, context)
|
||||
storedAnimations.removeValue(forKey: node)
|
||||
}
|
||||
|
||||
@ -214,20 +219,20 @@ class AnimationProducer {
|
||||
}
|
||||
|
||||
group.contents.forEach { child in
|
||||
addStoredAnimations(child)
|
||||
addStoredAnimations(child, context)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Contents animation
|
||||
|
||||
func addContentsAnimation(_ animation: BasicAnimation, cache: AnimationCache?, completion: @escaping (() -> Void)) {
|
||||
func addContentsAnimation(_ animation: BasicAnimation, _ context: AnimationContext, cache: AnimationCache?, completion: @escaping (() -> Void)) {
|
||||
guard let contentsAnimation = animation as? ContentsAnimation else {
|
||||
return
|
||||
}
|
||||
|
||||
if animation.autoreverses {
|
||||
animation.autoreverses = false
|
||||
addAnimation([animation, animation.reverse()].sequence() as! BasicAnimation)
|
||||
play([animation, animation.reverse()].sequence() as! BasicAnimation, context)
|
||||
return
|
||||
}
|
||||
|
||||
@ -238,7 +243,7 @@ class AnimationProducer {
|
||||
animSequence.append(animation)
|
||||
}
|
||||
|
||||
addAnimation(animSequence.sequence() as! BasicAnimation)
|
||||
play(animSequence.sequence() as! BasicAnimation, context)
|
||||
return
|
||||
}
|
||||
|
||||
@ -250,7 +255,7 @@ class AnimationProducer {
|
||||
unionBounds = unionBounds?.union(rect: contentsAnimation.getVFunc()(t).group().bounds!)
|
||||
}
|
||||
|
||||
guard let renderer = animation.nodeRenderer, let layer = cache?.layerForNodeRenderer(renderer, animation: contentsAnimation, customBounds: unionBounds) else {
|
||||
guard let renderer = animation.nodeRenderer, let layer = cache?.layerForNodeRenderer(renderer, context, animation: contentsAnimation, customBounds: unionBounds) else {
|
||||
return
|
||||
}
|
||||
|
||||
@ -338,3 +343,18 @@ class AnimationProducer {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class AnimationContext {
|
||||
|
||||
var rootTransform: Transform?
|
||||
|
||||
func getLayoutTransform(_ renderer: NodeRenderer?) -> Transform {
|
||||
if (rootTransform == nil) {
|
||||
if let view = renderer?.view, let node = view.renderer?.node() {
|
||||
rootTransform = LayoutHelper.calcTransform(node, view.contentLayout, view.bounds.size.toMacaw())
|
||||
}
|
||||
}
|
||||
return rootTransform ?? Transform.identity
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,37 +1,21 @@
|
||||
import Foundation
|
||||
|
||||
class AnimationUtils {
|
||||
class func absolutePosition(_ nodeRenderer: NodeRenderer?) -> Transform {
|
||||
return AnimationUtils.absoluteTransform(nodeRenderer, pos: nodeRenderer?.node()?.place ?? .identity)
|
||||
|
||||
class func absolutePosition(_ nodeRenderer: NodeRenderer?, _ context: AnimationContext) -> Transform {
|
||||
return AnimationUtils.absoluteTransform(nodeRenderer, context, pos: nodeRenderer?.node()?.place ?? .identity)
|
||||
}
|
||||
|
||||
class func absoluteTransform(_ nodeRenderer: NodeRenderer?, pos: Transform) -> Transform {
|
||||
class func absoluteTransform(_ nodeRenderer: NodeRenderer?, _ context: AnimationContext, pos: Transform) -> Transform {
|
||||
var transform = pos
|
||||
var parentRenderer = nodeRenderer?.parentRenderer
|
||||
while parentRenderer != nil {
|
||||
|
||||
if let canvas = parentRenderer?.node() as? SVGCanvas,
|
||||
let view = parentRenderer?.view {
|
||||
let rect = canvas.layout(size: view.bounds.size.toMacaw()).rect()
|
||||
let canvasTransform = view.contentLayout.layout(rect: rect, into: view.bounds.size.toMacaw()).move(dx: rect.x, dy: rect.y)
|
||||
transform = canvasTransform.concat(with: transform)
|
||||
} else if let node = parentRenderer?.node() {
|
||||
if let node = parentRenderer?.node() {
|
||||
transform = node.place.concat(with: transform)
|
||||
}
|
||||
|
||||
parentRenderer = parentRenderer?.parentRenderer
|
||||
}
|
||||
|
||||
var rootRenderer = nodeRenderer
|
||||
while rootRenderer?.parentRenderer != nil {
|
||||
rootRenderer = rootRenderer?.parentRenderer
|
||||
}
|
||||
if let view = rootRenderer?.view, let bounds = rootRenderer?.node()?.bounds {
|
||||
let a = view.contentLayout.layout(rect: bounds, into: view.bounds.size.toMacaw())
|
||||
transform = transform.concat(with: a)
|
||||
}
|
||||
|
||||
return transform
|
||||
return transform.concat(with: context.getLayoutTransform(nodeRenderer))
|
||||
}
|
||||
|
||||
class func absoluteClip(_ nodeRenderer: NodeRenderer?) -> Locus? {
|
||||
|
@ -26,7 +26,7 @@ class AnimationCache {
|
||||
self.sceneLayer = sceneLayer
|
||||
}
|
||||
|
||||
func layerForNodeRenderer(_ renderer: NodeRenderer, animation: Animation, customBounds: Rect? = .none, shouldRenderContent: Bool = true) -> ShapeLayer {
|
||||
func layerForNodeRenderer(_ renderer: NodeRenderer, _ context: AnimationContext, animation: Animation, customBounds: Rect? = .none, shouldRenderContent: Bool = true) -> ShapeLayer {
|
||||
|
||||
guard let node = renderer.node() else {
|
||||
return ShapeLayer()
|
||||
@ -63,7 +63,7 @@ class AnimationCache {
|
||||
|
||||
layer.renderTransform = CGAffineTransform(translationX: -1.0 * cgRect.origin.x, y: -1.0 * cgRect.origin.y)
|
||||
|
||||
let nodeTransform = AnimationUtils.absolutePosition(renderer).toCG()
|
||||
let nodeTransform = AnimationUtils.absolutePosition(renderer, context).toCG()
|
||||
layer.transform = CATransform3DMakeAffineTransform(nodeTransform)
|
||||
|
||||
// Clip
|
||||
|
@ -111,7 +111,7 @@ extension AnimationProducer {
|
||||
}
|
||||
|
||||
// MARK: - Combine animation
|
||||
func addCombineAnimation(_ combineAnimation: Animation) {
|
||||
func addCombineAnimation(_ combineAnimation: Animation, _ context: AnimationContext) {
|
||||
guard let combine = combineAnimation as? CombineAnimation,
|
||||
let renderer = combine.nodeRenderer,
|
||||
let view = renderer.view else {
|
||||
@ -141,7 +141,7 @@ extension AnimationProducer {
|
||||
}
|
||||
|
||||
combine.repeatCount = 0.0
|
||||
addAnimationSequence(sequence.sequence())
|
||||
addAnimationSequence(sequence.sequence(), context)
|
||||
return
|
||||
}
|
||||
|
||||
@ -182,7 +182,7 @@ extension AnimationProducer {
|
||||
|
||||
// Launching
|
||||
animations.forEach { animation in
|
||||
self.addAnimation(animation)
|
||||
self.play(animation, context)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -14,7 +14,7 @@ import UIKit
|
||||
import AppKit
|
||||
#endif
|
||||
|
||||
func addMorphingAnimation(_ animation: BasicAnimation, sceneLayer: CALayer, animationCache: AnimationCache?, completion: @escaping (() -> Void)) {
|
||||
func addMorphingAnimation(_ animation: BasicAnimation, _ context: AnimationContext, sceneLayer: CALayer, animationCache: AnimationCache?, completion: @escaping (() -> Void)) {
|
||||
guard let morphingAnimation = animation as? MorphingAnimation else {
|
||||
return
|
||||
}
|
||||
@ -31,7 +31,7 @@ func addMorphingAnimation(_ animation: BasicAnimation, sceneLayer: CALayer, anim
|
||||
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, animation: animation, shouldRenderContent: false) else {
|
||||
guard let layer = animationCache?.layerForNodeRenderer(renderer, context, animation: animation, shouldRenderContent: false) else {
|
||||
return
|
||||
}
|
||||
// Creating proper animation
|
||||
|
@ -6,7 +6,7 @@ import UIKit
|
||||
import AppKit
|
||||
#endif
|
||||
|
||||
func addOpacityAnimation(_ animation: BasicAnimation, sceneLayer: CALayer, animationCache: AnimationCache?, completion: @escaping (() -> Void)) {
|
||||
func addOpacityAnimation(_ animation: BasicAnimation, _ context: AnimationContext, sceneLayer: CALayer, animationCache: AnimationCache?, completion: @escaping (() -> Void)) {
|
||||
guard let opacityAnimation = animation as? OpacityAnimation else {
|
||||
return
|
||||
}
|
||||
@ -58,7 +58,7 @@ func addOpacityAnimation(_ animation: BasicAnimation, sceneLayer: CALayer, anima
|
||||
animation.onProgressUpdate?(t)
|
||||
}
|
||||
|
||||
if let renderer = animation.nodeRenderer, let layer = animationCache?.layerForNodeRenderer(renderer, animation: animation) {
|
||||
if let renderer = animation.nodeRenderer, let layer = animationCache?.layerForNodeRenderer(renderer, context, animation: animation) {
|
||||
let animationId = animation.ID
|
||||
layer.add(generatedAnimation, forKey: animationId)
|
||||
animation.removeFunc = { [weak layer] in
|
||||
|
@ -14,7 +14,7 @@ import UIKit
|
||||
import AppKit
|
||||
#endif
|
||||
|
||||
func addShapeAnimation(_ animation: BasicAnimation, sceneLayer: CALayer, animationCache: AnimationCache?, completion: @escaping (() -> Void)) {
|
||||
func addShapeAnimation(_ animation: BasicAnimation, _ context: AnimationContext, sceneLayer: CALayer, animationCache: AnimationCache?, completion: @escaping (() -> Void)) {
|
||||
guard let shapeAnimation = animation as? ShapeAnimation else {
|
||||
return
|
||||
}
|
||||
@ -30,17 +30,17 @@ func addShapeAnimation(_ animation: BasicAnimation, sceneLayer: CALayer, animati
|
||||
let mutatingShape = SceneUtils.shapeCopy(from: fromShape)
|
||||
renderer.replaceNode(with: mutatingShape)
|
||||
|
||||
guard let layer = animationCache?.layerForNodeRenderer(renderer, animation: animation, shouldRenderContent: false) else {
|
||||
guard let layer = animationCache?.layerForNodeRenderer(renderer, context, animation: animation, shouldRenderContent: false) else {
|
||||
return
|
||||
}
|
||||
|
||||
// Creating proper animation
|
||||
let generatedAnim = generateShapeAnimation(
|
||||
from: mutatingShape,
|
||||
to: toShape,
|
||||
animation: shapeAnimation,
|
||||
duration: duration,
|
||||
renderTransform: layer.renderTransform!)
|
||||
let generatedAnim = generateShapeAnimation(context,
|
||||
from: mutatingShape,
|
||||
to: toShape,
|
||||
animation: shapeAnimation,
|
||||
duration: duration,
|
||||
renderTransform: layer.renderTransform!)
|
||||
|
||||
generatedAnim.repeatCount = Float(animation.repeatCount)
|
||||
generatedAnim.timingFunction = caTimingFunction(animation.easing)
|
||||
@ -127,7 +127,7 @@ func addShapeAnimation(_ animation: BasicAnimation, sceneLayer: CALayer, animati
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate func generateShapeAnimation(from: Shape, to: Shape, animation: ShapeAnimation, duration: Double, renderTransform: CGAffineTransform) -> CAAnimation {
|
||||
fileprivate func generateShapeAnimation(_ context: AnimationContext, from: Shape, to: Shape, animation: ShapeAnimation, duration: Double, renderTransform: CGAffineTransform) -> CAAnimation {
|
||||
|
||||
let group = CAAnimationGroup()
|
||||
|
||||
@ -147,7 +147,7 @@ fileprivate func generateShapeAnimation(from: Shape, to: Shape, animation: Shape
|
||||
// Transform
|
||||
let scaleAnimation = CABasicAnimation(keyPath: "transform")
|
||||
scaleAnimation.duration = duration
|
||||
let parentPos = AnimationUtils.absolutePosition(animation.nodeRenderer?.parentRenderer)
|
||||
let parentPos = AnimationUtils.absolutePosition(animation.nodeRenderer?.parentRenderer, context)
|
||||
let fromPos = parentPos.concat(with: from.place)
|
||||
let toParentPos = animation.toParentGlobalTransfrom
|
||||
let toPos = toParentPos.concat(with: to.place)
|
||||
|
@ -6,7 +6,7 @@ import UIKit
|
||||
import AppKit
|
||||
#endif
|
||||
|
||||
func addTransformAnimation(_ animation: BasicAnimation, sceneLayer: CALayer, animationCache: AnimationCache?, completion: @escaping (() -> Void)) {
|
||||
func addTransformAnimation(_ animation: BasicAnimation, _ context: AnimationContext, sceneLayer: CALayer, animationCache: AnimationCache?, completion: @escaping (() -> Void)) {
|
||||
guard let transformAnimation = animation as? TransformAnimation else {
|
||||
return
|
||||
}
|
||||
@ -25,6 +25,7 @@ func addTransformAnimation(_ animation: BasicAnimation, sceneLayer: CALayer, ani
|
||||
var generatedAnimation: CAAnimation?
|
||||
|
||||
generatedAnimation = transformAnimationByFunc(transformAnimation,
|
||||
context,
|
||||
node: node,
|
||||
duration: animation.getDuration(),
|
||||
offset: animation.pausedProgress,
|
||||
@ -71,7 +72,7 @@ func addTransformAnimation(_ animation: BasicAnimation, sceneLayer: CALayer, ani
|
||||
animation.onProgressUpdate?(t)
|
||||
}
|
||||
|
||||
if let renderer = animation.nodeRenderer, let layer = animationCache?.layerForNodeRenderer(renderer, animation: animation) {
|
||||
if let renderer = animation.nodeRenderer, let layer = animationCache?.layerForNodeRenderer(renderer, context, animation: animation) {
|
||||
let animationId = animation.ID
|
||||
layer.add(generatedAnim, forKey: animationId)
|
||||
animation.removeFunc = { [weak layer] in
|
||||
@ -80,7 +81,7 @@ func addTransformAnimation(_ animation: BasicAnimation, sceneLayer: CALayer, ani
|
||||
}
|
||||
}
|
||||
|
||||
func transformAnimationByFunc(_ animation: TransformAnimation, node: Node, duration: Double, offset: Double, fps: UInt) -> CAAnimation {
|
||||
func transformAnimationByFunc(_ animation: TransformAnimation, _ context: AnimationContext, node: Node, duration: Double, offset: Double, fps: UInt) -> CAAnimation {
|
||||
|
||||
let valueFunc = animation.getVFunc()
|
||||
|
||||
@ -89,7 +90,7 @@ func transformAnimationByFunc(_ animation: TransformAnimation, node: Node, durat
|
||||
pathAnimation.timingFunction = caTimingFunction(animation.easing)
|
||||
pathAnimation.duration = duration / 2
|
||||
pathAnimation.autoreverses = animation.autoreverses
|
||||
let value = AnimationUtils.absoluteTransform(animation.nodeRenderer, pos: valueFunc(0))
|
||||
let value = AnimationUtils.absoluteTransform(animation.nodeRenderer, context, pos: valueFunc(0))
|
||||
pathAnimation.values = [NSValue(caTransform3D: CATransform3DMakeAffineTransform(value.toCG()))]
|
||||
pathAnimation.fillMode = MCAMediaTimingFillMode.forwards
|
||||
pathAnimation.isRemovedOnCompletion = false
|
||||
@ -104,7 +105,7 @@ func transformAnimationByFunc(_ animation: TransformAnimation, node: Node, durat
|
||||
tValue.append(1.0)
|
||||
for t in tValue {
|
||||
let progress = animation.easing.progressFor(time: t)
|
||||
let value = AnimationUtils.absoluteTransform(animation.nodeRenderer, pos: valueFunc(offset + progress))
|
||||
let value = AnimationUtils.absoluteTransform(animation.nodeRenderer, context, pos: valueFunc(offset + progress))
|
||||
let cgValue = CATransform3DMakeAffineTransform(value.toCG())
|
||||
transformValues.append(cgValue)
|
||||
}
|
||||
|
@ -144,7 +144,7 @@ public extension Node {
|
||||
ctx.clear(rect.toCG())
|
||||
|
||||
let transform = LayoutHelper.calcTransform(self, layout, size)
|
||||
ctx.concatenate(transform)
|
||||
ctx.concatenate(transform.toCG())
|
||||
renderer.render(in: ctx, force: false, opacity: self.opacity)
|
||||
|
||||
let img = MGraphicsGetImageFromCurrentImageContext()
|
||||
|
@ -21,7 +21,7 @@ open class MacawView: MView, MGestureRecognizerDelegate {
|
||||
}
|
||||
|
||||
if let _ = superview {
|
||||
animationProducer.addStoredAnimations(node)
|
||||
animationProducer.addStoredAnimations(node, self)
|
||||
}
|
||||
|
||||
self.setNeedsDisplay()
|
||||
@ -53,7 +53,7 @@ open class MacawView: MView, MGestureRecognizerDelegate {
|
||||
return
|
||||
}
|
||||
|
||||
animationProducer.addStoredAnimations(node)
|
||||
animationProducer.addStoredAnimations(node, self)
|
||||
}
|
||||
}
|
||||
|
||||
@ -64,7 +64,7 @@ open class MacawView: MView, MGestureRecognizerDelegate {
|
||||
return
|
||||
}
|
||||
|
||||
animationProducer.addStoredAnimations(node)
|
||||
animationProducer.addStoredAnimations(node, self)
|
||||
}
|
||||
|
||||
override open var intrinsicContentSize: CGSize {
|
||||
@ -571,14 +571,14 @@ class LayoutHelper {
|
||||
return CGAffineTransform.identity
|
||||
}
|
||||
|
||||
public class func calcTransform(_ node: Node, _ layout: ContentLayout, _ size: Size) -> CGAffineTransform {
|
||||
public class func calcTransform(_ node: Node, _ layout: ContentLayout, _ size: Size) -> Transform {
|
||||
if let canvas = node as? SVGCanvas {
|
||||
return layout.layout(size: canvas.layout(size: size), into: size).toCG()
|
||||
return layout.layout(size: canvas.layout(size: size), into: size)
|
||||
}
|
||||
if let rect = node.bounds {
|
||||
return layout.layout(rect: rect, into: size).toCG()
|
||||
return layout.layout(rect: rect, into: size)
|
||||
}
|
||||
return CGAffineTransform.identity
|
||||
return Transform.identity
|
||||
}
|
||||
|
||||
public func nodeChanged() {
|
||||
|
Loading…
Reference in New Issue
Block a user