From d9a5b27e94972757da4a088d338fd945f78b9e02 Mon Sep 17 00:00:00 2001 From: Alisa Mylnikova Date: Fri, 14 Feb 2020 14:13:53 +0700 Subject: [PATCH 01/11] Add correct zoom-scroll handling --- .../AnimationsHierarchyViewController.swift | 28 ++++++++++++++++++- .../Cache/AnimationCache.swift | 2 +- .../MorphingGenerator.swift | 2 +- .../OpacityGenerator.swift | 2 +- .../ShapeAnimationGenerator.swift | 2 +- .../TransformGenerator.swift | 2 +- Source/views/MacawView.swift | 13 +++++---- 7 files changed, 39 insertions(+), 12 deletions(-) diff --git a/Example/Example/Examples/AnimationsHierarchy/AnimationsHierarchyViewController.swift b/Example/Example/Examples/AnimationsHierarchy/AnimationsHierarchyViewController.swift index 394c4ebc..e1f554d3 100644 --- a/Example/Example/Examples/AnimationsHierarchy/AnimationsHierarchyViewController.swift +++ b/Example/Example/Examples/AnimationsHierarchy/AnimationsHierarchyViewController.swift @@ -13,6 +13,9 @@ class AnimationsHierarchyViewController: UIViewController { @IBOutlet weak var animView: MacawView! + var startCallbacks: [()->()] = [] + var stopCallbacks: [()->()] = [] + override func viewDidLoad() { super.viewDidLoad() @@ -20,6 +23,22 @@ class AnimationsHierarchyViewController: UIViewController { animView.zoom.enable() } + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + + startCallbacks.forEach { + $0() + } + } + + override func viewWillDisappear(_ animated: Bool) { + super.viewWillDisappear(animated) + + stopCallbacks.forEach { + $0() + } + } + func createTree(height: Int) -> Node { let rect = Rect(w: 10, h: 10) @@ -52,7 +71,14 @@ class AnimationsHierarchyViewController: UIViewController { func createLeaf(childForm: Locus, xDelta: Double, yDelta: Double) -> Group { let inset = childForm.bounds().w / 2 let leaf = Shape(form: childForm, fill: Color.teal, place: .move(dx: -inset, dy: -inset)) - leaf.placeVar.animation(angle: 2 * .pi, during: 5).cycle().play() + + let animation = leaf.placeVar.animation(angle: 2 * .pi, during: 5).cycle() + startCallbacks.append({ + animation.play() + }) + stopCallbacks.append({ + animation.stop() + }) let leafGroup = [leaf].group(place: .move(dx: xDelta, dy: yDelta)) leaf.onTap { _ in diff --git a/Source/animation/types/animation_generators/Cache/AnimationCache.swift b/Source/animation/types/animation_generators/Cache/AnimationCache.swift index d54b2c7a..b049f19d 100644 --- a/Source/animation/types/animation_generators/Cache/AnimationCache.swift +++ b/Source/animation/types/animation_generators/Cache/AnimationCache.swift @@ -8,7 +8,7 @@ import AppKit class AnimationUtils { - class func layerForNodeRenderer(_ renderer: NodeRenderer, _ context: AnimationContext, animation: Animation, customBounds: Rect? = .none, shouldRenderContent: Bool = true) -> ShapeLayer { + class func layerForNodeRenderer(_ renderer: NodeRenderer, animation: Animation, customBounds: Rect? = .none, shouldRenderContent: Bool = true) -> ShapeLayer { let node = renderer.node if let cachedLayer = renderer.layer { diff --git a/Source/animation/types/animation_generators/MorphingGenerator.swift b/Source/animation/types/animation_generators/MorphingGenerator.swift index 212cbd9d..09d54277 100644 --- a/Source/animation/types/animation_generators/MorphingGenerator.swift +++ b/Source/animation/types/animation_generators/MorphingGenerator.swift @@ -30,7 +30,7 @@ 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() - let layer = AnimationUtils.layerForNodeRenderer(renderer, context, animation: animation, shouldRenderContent: false) + let layer = AnimationUtils.layerForNodeRenderer(renderer, animation: animation, shouldRenderContent: false) // Creating proper animation let generatedAnimation = pathAnimation( diff --git a/Source/animation/types/animation_generators/OpacityGenerator.swift b/Source/animation/types/animation_generators/OpacityGenerator.swift index 71e9441c..9bcdde1b 100644 --- a/Source/animation/types/animation_generators/OpacityGenerator.swift +++ b/Source/animation/types/animation_generators/OpacityGenerator.swift @@ -58,7 +58,7 @@ func addOpacityAnimation(_ animation: BasicAnimation, _ context: AnimationContex completion() } - let layer = AnimationUtils.layerForNodeRenderer(renderer, context, animation: animation) + let layer = AnimationUtils.layerForNodeRenderer(renderer, animation: animation) let animationId = animation.ID layer.add(generatedAnimation, forKey: animationId) animation.removeFunc = { [weak layer] in diff --git a/Source/animation/types/animation_generators/ShapeAnimationGenerator.swift b/Source/animation/types/animation_generators/ShapeAnimationGenerator.swift index 2d3dd9dd..b64023ca 100644 --- a/Source/animation/types/animation_generators/ShapeAnimationGenerator.swift +++ b/Source/animation/types/animation_generators/ShapeAnimationGenerator.swift @@ -30,7 +30,7 @@ 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() - let layer = AnimationUtils.layerForNodeRenderer(renderer, context, animation: animation, shouldRenderContent: false) + let layer = AnimationUtils.layerForNodeRenderer(renderer, animation: animation, shouldRenderContent: false) // Creating proper animation let generatedAnimation = generateShapeAnimation(context, diff --git a/Source/animation/types/animation_generators/TransformGenerator.swift b/Source/animation/types/animation_generators/TransformGenerator.swift index 98612d1c..bf91385c 100644 --- a/Source/animation/types/animation_generators/TransformGenerator.swift +++ b/Source/animation/types/animation_generators/TransformGenerator.swift @@ -22,7 +22,7 @@ func addTransformAnimation(_ animation: BasicAnimation, _ context: AnimationCont let transactionsDisabled = CATransaction.disableActions() CATransaction.setDisableActions(true) - let layer = AnimationUtils.layerForNodeRenderer(renderer, context, animation: animation, shouldRenderContent: true) + let layer = AnimationUtils.layerForNodeRenderer(renderer, animation: animation, shouldRenderContent: true) // Creating proper animation let generatedAnimation = transformAnimationByFunc(transformAnimation, diff --git a/Source/views/MacawView.swift b/Source/views/MacawView.swift index 0b918eb9..ae01a108 100644 --- a/Source/views/MacawView.swift +++ b/Source/views/MacawView.swift @@ -142,8 +142,14 @@ open class MacawView: MView, MGestureRecognizerDelegate { } private func onZoomChange(t: Transform) { + // TODO: actually we should track all changes placeManager.setZoom(place: t) - self.setNeedsDisplay() + placeManager.setLayout(place: layoutHelper.getTransform(renderer!, contentLayout, bounds.size.toMacaw())) + + if let viewLayer = mLayer { + let deltaTransform = CATransform3DMakeAffineTransform(self.place.toCG()) + viewLayer.transform = CATransform3DConcat(viewLayer.transform, deltaTransform) + } } func initializeView() { @@ -195,11 +201,6 @@ open class MacawView: MView, MGestureRecognizerDelegate { return } renderer.calculateZPositionRecursively() - - // TODO: actually we should track all changes - placeManager.setLayout(place: layoutHelper.getTransform(renderer, contentLayout, bounds.size.toMacaw())) - - ctx.concatenate(self.place.toCG()) renderer.render(in: ctx, force: false, opacity: node.opacity) } From bac14c1e85c024fac6acd235d4d52b2f103e49fe Mon Sep 17 00:00:00 2001 From: Alisa Mylnikova Date: Tue, 17 Mar 2020 17:16:18 +0700 Subject: [PATCH 02/11] Fixes for examples --- Source/animation/AnimationImpl.swift | 11 ++++++----- Source/animation/AnimationProducer.swift | 4 ++-- Source/animation/types/AnimationSequence.swift | 12 ++++-------- .../CombinationAnimationGenerator.swift | 2 ++ .../animation_generators/MorphingGenerator.swift | 1 + .../animation_generators/OpacityGenerator.swift | 10 ++++++++++ .../animation_generators/TransformGenerator.swift | 10 ++++++++++ 7 files changed, 35 insertions(+), 15 deletions(-) diff --git a/Source/animation/AnimationImpl.swift b/Source/animation/AnimationImpl.swift index 0b79032e..a6fca1ab 100644 --- a/Source/animation/AnimationImpl.swift +++ b/Source/animation/AnimationImpl.swift @@ -24,11 +24,8 @@ class BasicAnimation: Animation { weak var node: Node? { didSet { - node?.animations.append(self) - if let group = node as? Group { - for node in group.contents { - node.animations.append(self) - } + if !(self is CombineAnimation || self is AnimationSequence || self is EmptyAnimation) { + node?.animations.append(self) } } } @@ -104,6 +101,8 @@ class BasicAnimation: Animation { } removeFunc?() + node?.animations.removeAll { $0 === self } + nodeRenderer?.freeLayer() } override open func pause() { @@ -115,6 +114,8 @@ class BasicAnimation: Animation { } removeFunc?() + node?.animations.removeAll { $0 === self } + nodeRenderer?.freeLayer() } override func state() -> AnimationState { diff --git a/Source/animation/AnimationProducer.swift b/Source/animation/AnimationProducer.swift index b6c8887d..85728e26 100644 --- a/Source/animation/AnimationProducer.swift +++ b/Source/animation/AnimationProducer.swift @@ -143,9 +143,9 @@ class AnimationProducer { } // MARK: - Sequence animation - func addAnimationSequence(_ animationSequnce: Animation, + func addAnimationSequence(_ animationSequence: Animation, _ context: AnimationContext) { - guard let sequence = animationSequnce as? AnimationSequence else { + guard let sequence = animationSequence as? AnimationSequence else { return } diff --git a/Source/animation/types/AnimationSequence.swift b/Source/animation/types/AnimationSequence.swift index abb711e7..951e0bac 100644 --- a/Source/animation/types/AnimationSequence.swift +++ b/Source/animation/types/AnimationSequence.swift @@ -27,21 +27,17 @@ internal class AnimationSequence: BasicAnimation { open override func stop() { super.stop() - guard let active = animations.first(where: { $0.isActive() }) else { - return + animations.forEach { animation in + animation.stop() } - - active.stop() } open override func pause() { super.pause() - guard let active = animations.first(where: { $0.isActive() }) else { - return + animations.forEach { animation in + animation.pause() } - - active.pause() } open override func play() { diff --git a/Source/animation/types/animation_generators/CombinationAnimationGenerator.swift b/Source/animation/types/animation_generators/CombinationAnimationGenerator.swift index ee38fa7d..d600b4a5 100644 --- a/Source/animation/types/animation_generators/CombinationAnimationGenerator.swift +++ b/Source/animation/types/animation_generators/CombinationAnimationGenerator.swift @@ -116,6 +116,7 @@ extension AnimationProducer { func addCombineAnimation(_ combineAnimation: Animation, _ context: AnimationContext) { guard let combine = combineAnimation as? CombineAnimation, let renderer = combine.nodeRenderer, + let node = combine.node, let view = renderer.view else { return } @@ -176,6 +177,7 @@ extension AnimationProducer { } combine.removeFunc = { + node.animations.removeAll { $0 === combine } animations.forEach { animation in animation.removeFunc?() } diff --git a/Source/animation/types/animation_generators/MorphingGenerator.swift b/Source/animation/types/animation_generators/MorphingGenerator.swift index 09d54277..b077c26b 100644 --- a/Source/animation/types/animation_generators/MorphingGenerator.swift +++ b/Source/animation/types/animation_generators/MorphingGenerator.swift @@ -94,6 +94,7 @@ func addMorphingAnimation(_ animation: BasicAnimation, _ context: AnimationConte let animationId = animation.ID layer.add(generatedAnimation, forKey: animationId) animation.removeFunc = { [weak layer] in + shape.animations.removeAll { $0 === animation } layer?.removeAnimation(forKey: animationId) } diff --git a/Source/animation/types/animation_generators/OpacityGenerator.swift b/Source/animation/types/animation_generators/OpacityGenerator.swift index 9bcdde1b..dc58b087 100644 --- a/Source/animation/types/animation_generators/OpacityGenerator.swift +++ b/Source/animation/types/animation_generators/OpacityGenerator.swift @@ -47,6 +47,15 @@ func addOpacityAnimation(_ animation: BasicAnimation, _ context: AnimationContex node.opacityVar.value = opacityAnimation.getVFunc()(1.0) } + CATransaction.begin() + CATransaction.setValue(kCFBooleanTrue, forKey: kCATransactionDisableActions) + renderer.layer?.animationLayer.opacity = Float(node.opacity) + CATransaction.commit() + + if !animation.paused { + animation.removeFunc?() + } + renderer.freeLayer() if !animation.cycled && @@ -62,6 +71,7 @@ func addOpacityAnimation(_ animation: BasicAnimation, _ context: AnimationContex let animationId = animation.ID layer.add(generatedAnimation, forKey: animationId) animation.removeFunc = { [weak layer] in + node.animations.removeAll { $0 === animation } layer?.removeAnimation(forKey: animationId) } diff --git a/Source/animation/types/animation_generators/TransformGenerator.swift b/Source/animation/types/animation_generators/TransformGenerator.swift index bf91385c..5e45377d 100644 --- a/Source/animation/types/animation_generators/TransformGenerator.swift +++ b/Source/animation/types/animation_generators/TransformGenerator.swift @@ -54,6 +54,15 @@ func addTransformAnimation(_ animation: BasicAnimation, _ context: AnimationCont node.placeVar.value = transformAnimation.getVFunc()(1.0) } + CATransaction.begin() + CATransaction.setValue(kCFBooleanTrue, forKey: kCATransactionDisableActions) + renderer.layer?.animationLayer.transform = CATransform3DMakeAffineTransform(node.place.toCG()) + CATransaction.commit() + + if !animation.paused { + animation.removeFunc?() + } + renderer.freeLayer() if !animation.cycled && @@ -68,6 +77,7 @@ func addTransformAnimation(_ animation: BasicAnimation, _ context: AnimationCont let animationId = animation.ID layer.add(generatedAnimation, forKey: animationId) animation.removeFunc = { [weak layer] in + node.animations.removeAll { $0 === animation } layer?.removeAnimation(forKey: animationId) } From bb5e9e0e395a402177d72ca4173f2843b88787c0 Mon Sep 17 00:00:00 2001 From: Alisa Mylnikova Date: Tue, 17 Mar 2020 17:43:17 +0700 Subject: [PATCH 03/11] Fix --- Source/animation/types/AnimationSequence.swift | 12 ++++++++---- Source/svg/SVGParser.swift | 6 +++--- Source/views/MacawView.swift | 2 +- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/Source/animation/types/AnimationSequence.swift b/Source/animation/types/AnimationSequence.swift index 951e0bac..abb711e7 100644 --- a/Source/animation/types/AnimationSequence.swift +++ b/Source/animation/types/AnimationSequence.swift @@ -27,17 +27,21 @@ internal class AnimationSequence: BasicAnimation { open override func stop() { super.stop() - animations.forEach { animation in - animation.stop() + guard let active = animations.first(where: { $0.isActive() }) else { + return } + + active.stop() } open override func pause() { super.pause() - animations.forEach { animation in - animation.pause() + guard let active = animations.first(where: { $0.isActive() }) else { + return } + + active.pause() } open override func play() { diff --git a/Source/svg/SVGParser.swift b/Source/svg/SVGParser.swift index e4bf1630..f3e0a7c6 100644 --- a/Source/svg/SVGParser.swift +++ b/Source/svg/SVGParser.swift @@ -465,7 +465,7 @@ open class SVGParser { if let units = element.allAttributes["patternContentUnits"]?.text, units == "objectBoundingBox" { contentUserSpace = false } - + var contentNode: Node? if pattern.children.isEmpty { if let parentPattern = parentPattern { @@ -483,7 +483,7 @@ open class SVGParser { } contentNode = Group(contents: shapes) } - + return UserSpacePattern(content: contentNode!, bounds: bounds, userSpace: userSpace, @@ -1599,7 +1599,7 @@ open class SVGParser { guard let element = stop.element else { return .none } - + var offset: Double = 0 // This is default value, value can be omitted if let parsedOffset = getDoubleValueFromPercentage(element, attribute: "offset") { offset = parsedOffset diff --git a/Source/views/MacawView.swift b/Source/views/MacawView.swift index ae01a108..d5279252 100644 --- a/Source/views/MacawView.swift +++ b/Source/views/MacawView.swift @@ -147,7 +147,7 @@ open class MacawView: MView, MGestureRecognizerDelegate { placeManager.setLayout(place: layoutHelper.getTransform(renderer!, contentLayout, bounds.size.toMacaw())) if let viewLayer = mLayer { - let deltaTransform = CATransform3DMakeAffineTransform(self.place.toCG()) + let deltaTransform = CATransform3DMakeAffineTransform(self.place.toCG()) viewLayer.transform = CATransform3DConcat(viewLayer.transform, deltaTransform) } } From 0f96b24db1a33063f018a489a7e2dc47bba3afb0 Mon Sep 17 00:00:00 2001 From: Alisa Mylnikova Date: Fri, 10 Apr 2020 15:58:19 +0700 Subject: [PATCH 04/11] Split zoom and layout matrices --- Source/views/MacawView.swift | 24 ++++++++++++------------ Source/views/MacawZoom.swift | 16 ++++++++++++++-- Source/views/ShapeLayer.swift | 3 --- 3 files changed, 26 insertions(+), 17 deletions(-) diff --git a/Source/views/MacawView.swift b/Source/views/MacawView.swift index d5279252..bb2a13a4 100644 --- a/Source/views/MacawView.swift +++ b/Source/views/MacawView.swift @@ -141,17 +141,6 @@ open class MacawView: MView, MGestureRecognizerDelegate { self.init(node: Group(), coder: aDecoder) } - private func onZoomChange(t: Transform) { - // TODO: actually we should track all changes - placeManager.setZoom(place: t) - placeManager.setLayout(place: layoutHelper.getTransform(renderer!, contentLayout, bounds.size.toMacaw())) - - if let viewLayer = mLayer { - let deltaTransform = CATransform3DMakeAffineTransform(self.place.toCG()) - viewLayer.transform = CATransform3DConcat(viewLayer.transform, deltaTransform) - } - } - func initializeView() { self.contentLayout = .none self.context = RenderContext(view: self) @@ -187,6 +176,12 @@ open class MacawView: MView, MGestureRecognizerDelegate { setNeedsDisplay() } + private func onZoomChange(t: Transform) { + if let viewLayer = mLayer { + viewLayer.transform = CATransform3DMakeAffineTransform(t.toCG()) + } + } + override open func draw(_ rect: CGRect) { context.cgContext = MGraphicsGetCurrentContext() guard let ctx = context.cgContext else { @@ -200,6 +195,11 @@ open class MacawView: MView, MGestureRecognizerDelegate { guard let renderer = renderer else { return } + + // TODO: actually we should track all changes + placeManager.setLayout(place: layoutHelper.getTransform(renderer, contentLayout, bounds.size.toMacaw())) + ctx.concatenate(self.place.toCG()) + renderer.calculateZPositionRecursively() renderer.render(in: ctx, force: false, opacity: node.opacity) } @@ -335,7 +335,7 @@ open class MacawView: MView, MGestureRecognizerDelegate { private func convert(touches: Set) -> [MTouchEvent] { return touches.map { touch -> MTouchEvent in - let location = touch.location(in: self) + let location = touch.applyCurrentLayerTransform(self) let id = Int(bitPattern: Unmanaged.passUnretained(touch).toOpaque()) return MTouchEvent(x: Double(location.x), y: Double(location.y), id: id) } diff --git a/Source/views/MacawZoom.swift b/Source/views/MacawZoom.swift index 1a9532cd..8ffd2701 100644 --- a/Source/views/MacawZoom.swift +++ b/Source/views/MacawZoom.swift @@ -81,6 +81,9 @@ open class MacawZoom { } private func getNewZoom() -> ZoomData { + if !trackMove && !trackScale && !trackRotate { + return zoomData + } if touches.isEmpty || (touches.count == 1 && !trackMove) { return zoomData } @@ -144,7 +147,7 @@ fileprivate class TouchData { let point: Point convenience init(touch: MTouch, in view: MView) { - self.init(touch: touch, point: touch.location(in: view).toMacaw()) + self.init(touch: touch, point: touch.applyCurrentLayerTransform(view)) } init(touch: MTouch, point: Point) { @@ -153,7 +156,16 @@ fileprivate class TouchData { } func current(in view: MView) -> Point { - return touch.location(in: view).toMacaw() + return touch.applyCurrentLayerTransform(view) } } + +extension MTouch { + + func applyCurrentLayerTransform(_ view: MView) -> Point { + let layerTransform = CATransform3DGetAffineTransform(view.mLayer!.transform).toMacaw() + let location = self.location(in: view).toMacaw() + return layerTransform.apply(to: location) + } +} diff --git a/Source/views/ShapeLayer.swift b/Source/views/ShapeLayer.swift index 2551bdc5..8ffab1f2 100644 --- a/Source/views/ShapeLayer.swift +++ b/Source/views/ShapeLayer.swift @@ -17,9 +17,6 @@ class ShapeLayer: CAShapeLayer { return } - let renderContext = RenderContext(view: .none) - renderContext.cgContext = ctx - renderer?.directRender(in: ctx, force: isForceRenderingEnabled) } } From 9e317d78d947cb0229cdfb23b65d2b8708311990 Mon Sep 17 00:00:00 2001 From: Alisa Mylnikova Date: Tue, 14 Apr 2020 14:30:20 +0700 Subject: [PATCH 05/11] Add transparent view for touches --- .../CombinationAnimationGenerator.swift | 1 - Source/views/MacawView.swift | 60 ++++++++++++++++--- Source/views/MacawZoom.swift | 24 +++----- 3 files changed, 59 insertions(+), 26 deletions(-) diff --git a/Source/animation/types/animation_generators/CombinationAnimationGenerator.swift b/Source/animation/types/animation_generators/CombinationAnimationGenerator.swift index 8165361e..9a6f92eb 100644 --- a/Source/animation/types/animation_generators/CombinationAnimationGenerator.swift +++ b/Source/animation/types/animation_generators/CombinationAnimationGenerator.swift @@ -115,7 +115,6 @@ extension AnimationProducer { // MARK: - Combine animation func addCombineAnimation(_ combineAnimation: Animation, _ context: AnimationContext) { guard let combine = combineAnimation as? CombineAnimation, - let renderer = combine.nodeRenderer, let node = combine.node else { return } diff --git a/Source/views/MacawView.swift b/Source/views/MacawView.swift index bb2a13a4..59a0c91f 100644 --- a/Source/views/MacawView.swift +++ b/Source/views/MacawView.swift @@ -10,6 +10,31 @@ import AppKit /// MacawView is a main class used to embed Macaw scene into your Cocoa UI. /// You could create your own view extended from MacawView with predefined scene. /// + +internal class TouchInterceptionView: MView { + weak var macawView: MacawView? + + open override func touchesBegan(_ touches: Set, with event: MEvent?) { + super.touchesBegan(touches, with: event) + macawView?.mTouchesBegan(touches, with: event) + } + + open override func touchesMoved(_ touches: Set, with event: MEvent?) { + super.touchesMoved(touches, with: event) + macawView?.mTouchesMoved(touches, with: event) + } + + open override func touchesEnded(_ touches: Set, with event: MEvent?) { + super.touchesEnded(touches, with: event) + macawView?.mTouchesEnded(touches, with: event) + } + + override open func touchesCancelled(_ touches: Set, with event: MEvent?) { + super.touchesCancelled(touches, with: event) + macawView?.mTouchesCancelled(touches, with: event) + } +} + open class MacawView: MView, MGestureRecognizerDelegate { /// Scene root node @@ -53,6 +78,7 @@ open class MacawView: MView, MGestureRecognizerDelegate { } private let placeManager = RootPlaceManager() + internal let touchInterceptionView = TouchInterceptionView() override open var frame: CGRect { didSet { @@ -133,18 +159,36 @@ open class MacawView: MView, MGestureRecognizerDelegate { public override init(frame: CGRect) { super.init(frame: frame) zoom.initialize(view: self, onChange: onZoomChange) - - initializeView() } @objc public convenience required init?(coder aDecoder: NSCoder) { self.init(node: Group(), coder: aDecoder) } + open override func didMoveToWindow() { + super.didMoveToWindow() + + initializeView() + } + func initializeView() { self.contentLayout = .none self.context = RenderContext(view: self) + if let superview = self.superview { + self.isUserInteractionEnabled = false + touchInterceptionView.isMultipleTouchEnabled = true + touchInterceptionView.macawView = self + touchInterceptionView.backgroundColor = .clear + superview.insertSubview(touchInterceptionView, aboveSubview: self) + + touchInterceptionView.translatesAutoresizingMaskIntoConstraints = false + touchInterceptionView.leftAnchor.constraint(equalTo: self.leftAnchor).isActive = true + touchInterceptionView.rightAnchor.constraint(equalTo: self.rightAnchor).isActive = true + touchInterceptionView.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true + touchInterceptionView.topAnchor.constraint(equalTo: self.topAnchor).isActive = true + } + 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)) @@ -163,12 +207,12 @@ open class MacawView: MView, MGestureRecognizerDelegate { rotationRecognizer.cancelsTouchesInView = false pinchRecognizer.cancelsTouchesInView = false - self.removeGestureRecognizers() - self.addGestureRecognizer(tapRecognizer) - self.addGestureRecognizer(longTapRecognizer) - self.addGestureRecognizer(panRecognizer) - self.addGestureRecognizer(rotationRecognizer) - self.addGestureRecognizer(pinchRecognizer) + touchInterceptionView.removeGestureRecognizers() + touchInterceptionView.addGestureRecognizer(tapRecognizer) + touchInterceptionView.addGestureRecognizer(longTapRecognizer) + touchInterceptionView.addGestureRecognizer(panRecognizer) + touchInterceptionView.addGestureRecognizer(rotationRecognizer) + touchInterceptionView.addGestureRecognizer(pinchRecognizer) } open override func layoutSubviews() { diff --git a/Source/views/MacawZoom.swift b/Source/views/MacawZoom.swift index 8ffd2701..33296d26 100644 --- a/Source/views/MacawZoom.swift +++ b/Source/views/MacawZoom.swift @@ -16,7 +16,7 @@ import AppKit open class MacawZoom { - private var view: MView! + private var view: MacawView! private var onChange: ((Transform) -> Void)! private var touches = [TouchData]() private var zoomData = ZoomData() @@ -50,7 +50,7 @@ open class MacawZoom { onChange(zoomData.transform()) } - func initialize(view: MView, onChange: @escaping ((Transform) -> Void)) { + func initialize(view: MacawView, onChange: @escaping ((Transform) -> Void)) { self.view = view self.onChange = onChange } @@ -96,15 +96,7 @@ open class MacawZoom { let e2 = touches[1].current(in: view) let scale = trackScale ? e1.distance(to: e2) / s1.distance(to: s2) : 1 let a = trackRotate ? (e1 - e2).angle() - (s1 - s2).angle() : 0 - var offset = Size.zero - if trackMove { - let sina = sin(a) - let cosa = cos(a) - let w = e1.x - scale * (s1.x * cosa - s1.y * sina) - let h = e1.y - scale * (s1.x * sina + s1.y * cosa) - offset = Size(w: w, h: h) - } - return ZoomData(offset: offset, scale: scale, angle: a).combine(with: zoomData) + return ZoomData(offset: .zero, scale: scale, angle: a).combine(with: zoomData) } } @@ -146,7 +138,7 @@ fileprivate class TouchData { let touch: MTouch let point: Point - convenience init(touch: MTouch, in view: MView) { + convenience init(touch: MTouch, in view: MacawView) { self.init(touch: touch, point: touch.applyCurrentLayerTransform(view)) } @@ -155,7 +147,7 @@ fileprivate class TouchData { self.point = point } - func current(in view: MView) -> Point { + func current(in view: MacawView) -> Point { return touch.applyCurrentLayerTransform(view) } @@ -163,9 +155,7 @@ fileprivate class TouchData { extension MTouch { - func applyCurrentLayerTransform(_ view: MView) -> Point { - let layerTransform = CATransform3DGetAffineTransform(view.mLayer!.transform).toMacaw() - let location = self.location(in: view).toMacaw() - return layerTransform.apply(to: location) + func applyCurrentLayerTransform(_ view: MacawView) -> Point { + return self.location(in: view.touchInterceptionView).toMacaw() } } From 2aed94aec2102504e44cb4cf6f33da9e5304ae52 Mon Sep 17 00:00:00 2001 From: Alisa Mylnikova Date: Thu, 16 Apr 2020 15:46:02 +0700 Subject: [PATCH 06/11] Split on MacawView and DrawingView --- Source/animation/AnimationProducer.swift | 2 +- Source/export/MacawView+PDF.swift | 4 +- Source/render/GroupRenderer.swift | 2 +- Source/render/ImageRenderer.swift | 2 +- Source/render/NodeRenderer.swift | 4 +- Source/render/RenderContext.swift | 4 +- Source/render/RenderUtils.swift | 2 +- Source/render/ShapeRenderer.swift | 2 +- Source/render/TextRenderer.swift | 2 +- Source/views/MacawView.swift | 295 +++++++++++++---------- Source/views/MacawZoom.swift | 11 +- 11 files changed, 188 insertions(+), 142 deletions(-) diff --git a/Source/animation/AnimationProducer.swift b/Source/animation/AnimationProducer.swift index 9a37fcd1..7ae54475 100644 --- a/Source/animation/AnimationProducer.swift +++ b/Source/animation/AnimationProducer.swift @@ -198,7 +198,7 @@ class AnimationProducer { } // MARK: - Stored animation - func addStoredAnimations(_ node: Node, _ view: MacawView) { + func addStoredAnimations(_ node: Node, _ view: DrawingView) { addStoredAnimations(node, AnimationContext()) } diff --git a/Source/export/MacawView+PDF.swift b/Source/export/MacawView+PDF.swift index b723ec69..e54a1f17 100644 --- a/Source/export/MacawView+PDF.swift +++ b/Source/export/MacawView+PDF.swift @@ -27,8 +27,8 @@ public extension MacawView { y: -size.height / bounds.height ) - context.cgContext = ctx - renderer?.render(in: ctx, force: false, opacity: node.opacity) + drawingView.context.cgContext = ctx + drawingView.renderer?.render(in: ctx, force: false, opacity: node.opacity) ctx.endPDFPage() } diff --git a/Source/render/GroupRenderer.swift b/Source/render/GroupRenderer.swift index 420c9628..2d572327 100644 --- a/Source/render/GroupRenderer.swift +++ b/Source/render/GroupRenderer.swift @@ -13,7 +13,7 @@ class GroupRenderer: NodeRenderer { return group } - init(group: Group, view: MacawView?, parentRenderer: GroupRenderer? = nil) { + init(group: Group, view: DrawingView?, parentRenderer: GroupRenderer? = nil) { self.group = group super.init(node: group, view: view, parentRenderer: parentRenderer) updateRenderers() diff --git a/Source/render/ImageRenderer.swift b/Source/render/ImageRenderer.swift index c9a571cc..693c96d8 100644 --- a/Source/render/ImageRenderer.swift +++ b/Source/render/ImageRenderer.swift @@ -17,7 +17,7 @@ class ImageRenderer: NodeRenderer { return image } - init(image: Image, view: MacawView?, parentRenderer: GroupRenderer? = nil) { + init(image: Image, view: DrawingView?, parentRenderer: GroupRenderer? = nil) { self.image = image super.init(node: image, view: view, parentRenderer: parentRenderer) } diff --git a/Source/render/NodeRenderer.swift b/Source/render/NodeRenderer.swift index 4f5a7cd6..11a8b8b8 100644 --- a/Source/render/NodeRenderer.swift +++ b/Source/render/NodeRenderer.swift @@ -22,7 +22,7 @@ class CachedLayer { class NodeRenderer { - weak var view: MacawView? + weak var view: DrawingView? var sceneLayer: CALayer? { return view?.mLayer } @@ -71,7 +71,7 @@ class NodeRenderer { fatalError("Unsupported") } - init(node: Node, view: MacawView?, parentRenderer: GroupRenderer? = nil) { + init(node: Node, view: DrawingView?, parentRenderer: GroupRenderer? = nil) { self.view = view self.parentRenderer = parentRenderer diff --git a/Source/render/RenderContext.swift b/Source/render/RenderContext.swift index 92c85092..82759f0f 100644 --- a/Source/render/RenderContext.swift +++ b/Source/render/RenderContext.swift @@ -5,10 +5,10 @@ import UIKit #endif class RenderContext { - weak var view: MacawView? + weak var view: DrawingView? var cgContext: CGContext? - init(view: MacawView?) { + init(view: DrawingView?) { self.view = view self.cgContext = nil } diff --git a/Source/render/RenderUtils.swift b/Source/render/RenderUtils.swift index b2166717..9c8dec10 100644 --- a/Source/render/RenderUtils.swift +++ b/Source/render/RenderUtils.swift @@ -16,7 +16,7 @@ class RenderUtils { return p } - class func createNodeRenderer(_ node: Node, view: MacawView?, parentRenderer: GroupRenderer? = nil) -> NodeRenderer { + class func createNodeRenderer(_ node: Node, view: DrawingView?, parentRenderer: GroupRenderer? = nil) -> NodeRenderer { if let group = node as? Group { return GroupRenderer(group: group, view: view, parentRenderer: parentRenderer) } else if let shape = node as? Shape { diff --git a/Source/render/ShapeRenderer.swift b/Source/render/ShapeRenderer.swift index 69f5f417..48345d86 100644 --- a/Source/render/ShapeRenderer.swift +++ b/Source/render/ShapeRenderer.swift @@ -10,7 +10,7 @@ class ShapeRenderer: NodeRenderer { var shape: Shape - init(shape: Shape, view: MacawView?, parentRenderer: GroupRenderer? = nil) { + init(shape: Shape, view: DrawingView?, parentRenderer: GroupRenderer? = nil) { self.shape = shape super.init(node: shape, view: view, parentRenderer: parentRenderer) } diff --git a/Source/render/TextRenderer.swift b/Source/render/TextRenderer.swift index 292e0f3a..c34d373c 100644 --- a/Source/render/TextRenderer.swift +++ b/Source/render/TextRenderer.swift @@ -13,7 +13,7 @@ class TextRenderer: NodeRenderer { return text } - init(text: Text, view: MacawView?, parentRenderer: GroupRenderer? = nil) { + init(text: Text, view: DrawingView?, parentRenderer: GroupRenderer? = nil) { self.text = text super.init(node: text, view: view, parentRenderer: parentRenderer) } diff --git a/Source/views/MacawView.swift b/Source/views/MacawView.swift index 59a0c91f..fa8f838f 100644 --- a/Source/views/MacawView.swift +++ b/Source/views/MacawView.swift @@ -11,31 +11,178 @@ import AppKit /// You could create your own view extended from MacawView with predefined scene. /// -internal class TouchInterceptionView: MView { - weak var macawView: MacawView? +open class MacawView: MView { + + internal var drawingView = DrawingView() + + public let zoom = MacawZoom() + + open var node: Node { + get { return drawingView.node } + set { drawingView.node = newValue } + } + + open var contentLayout: ContentLayout { + get { return drawingView.contentLayout } + set { drawingView.contentLayout = newValue } + } + + open override var contentMode: MViewContentMode { + get { return drawingView.contentMode } + set { drawingView.contentMode = newValue } + } + + open var place: Transform { + get { return drawingView.place } + } + + open var placeVar: Variable { + get { return drawingView.placeVar } + } + + open override var frame: CGRect { + get { return drawingView.frame } + set { drawingView.frame = newValue } + } + + override open var intrinsicContentSize: CGSize { + get { return drawingView.intrinsicContentSize } + } + + #if os(OSX) + open override var layer: CALayer? { + didSet { + guard self.layer != nil else { + return + } + initializeView() + + drawingView.renderer = RenderUtils.createNodeRenderer(node, view: self) + } + } + #endif + + @objc public convenience required init?(coder aDecoder: NSCoder) { + self.init(node: Group(), coder: aDecoder) + } + + @objc public init?(node: Node, coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + + if let drawingView = DrawingView(node: node, coder: aDecoder) { + self.drawingView = drawingView + } + + zoom.initialize(view: self, onChange: onZoomChange) + } + + public convenience init(node: Node, frame: CGRect) { + self.init(frame: frame) + + self.drawingView = DrawingView(node: node, frame: frame) + } + + public override init(frame: CGRect) { + super.init(frame: frame) + + self.drawingView = DrawingView(frame: frame) + + zoom.initialize(view: self, onChange: onZoomChange) + } + + private func onZoomChange(t: Transform) { + if let viewLayer = drawingView.mLayer { + viewLayer.transform = CATransform3DMakeAffineTransform(t.toCG()) + } + } + + open override func didMoveToWindow() { + super.didMoveToWindow() + + initializeView() + } + + func initializeView() { + + if !self.subviews.contains(drawingView) { + self.backgroundColor = .white + self.clipsToBounds = true + self.addSubview(drawingView) + drawingView.backgroundColor = .white + drawingView.isUserInteractionEnabled = false + drawingView.initializeView() + + drawingView.translatesAutoresizingMaskIntoConstraints = false + drawingView.trailingAnchor.constraint(equalTo: self.trailingAnchor).isActive = true + drawingView.leadingAnchor.constraint(equalTo: self.leadingAnchor).isActive = true + drawingView.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true + drawingView.topAnchor.constraint(equalTo: self.topAnchor).isActive = true + } + + let tapRecognizer = MTapGestureRecognizer(target: drawingView, action: #selector(DrawingView.handleTap(recognizer:))) + let longTapRecognizer = MLongPressGestureRecognizer(target: drawingView, action: #selector(DrawingView.handleLongTap(recognizer:))) + let panRecognizer = MPanGestureRecognizer(target: drawingView, action: #selector(DrawingView.handlePan)) + let rotationRecognizer = MRotationGestureRecognizer(target: drawingView, action: #selector(DrawingView.handleRotation)) + let pinchRecognizer = MPinchGestureRecognizer(target: drawingView, action: #selector(DrawingView.handlePinch)) + + tapRecognizer.delegate = drawingView + longTapRecognizer.delegate = drawingView + panRecognizer.delegate = drawingView + rotationRecognizer.delegate = drawingView + pinchRecognizer.delegate = drawingView + + tapRecognizer.cancelsTouchesInView = false + longTapRecognizer.cancelsTouchesInView = false + panRecognizer.cancelsTouchesInView = false + rotationRecognizer.cancelsTouchesInView = false + pinchRecognizer.cancelsTouchesInView = false + + self.removeGestureRecognizers() + self.addGestureRecognizer(tapRecognizer) + self.addGestureRecognizer(longTapRecognizer) + self.addGestureRecognizer(panRecognizer) + self.addGestureRecognizer(rotationRecognizer) + self.addGestureRecognizer(pinchRecognizer) + } open override func touchesBegan(_ touches: Set, with event: MEvent?) { super.touchesBegan(touches, with: event) - macawView?.mTouchesBegan(touches, with: event) + zoom.touchesBegan(touches) + + drawingView.touchesBegan(touchPoints: convert(touches: touches)) } open override func touchesMoved(_ touches: Set, with event: MEvent?) { super.touchesMoved(touches, with: event) - macawView?.mTouchesMoved(touches, with: event) + zoom.touchesMoved(touches) + + drawingView.touchesMoved(touchPoints: convert(touches: touches)) } open override func touchesEnded(_ touches: Set, with event: MEvent?) { super.touchesEnded(touches, with: event) - macawView?.mTouchesEnded(touches, with: event) + zoom.touchesEnded(touches) + + drawingView.touchesEnded(touchPoints: convert(touches: touches)) } override open func touchesCancelled(_ touches: Set, with event: MEvent?) { - super.touchesCancelled(touches, with: event) - macawView?.mTouchesCancelled(touches, with: event) + super.touchesEnded(touches, with: event) + zoom.touchesEnded(touches) + + drawingView.touchesEnded(touchPoints: convert(touches: touches)) + } + + private func convert(touches: Set) -> [MTouchEvent] { + return touches.map { touch -> MTouchEvent in + let location = touch.location(in: self).toMacaw() + let id = Int(bitPattern: Unmanaged.passUnretained(touch).toOpaque()) + return MTouchEvent(x: Double(location.x), y: Double(location.y), id: id) + } } } -open class MacawView: MView, MGestureRecognizerDelegate { +internal class DrawingView: MView, MGestureRecognizerDelegate { /// Scene root node open var node: Node = Group() { @@ -67,8 +214,6 @@ open class MacawView: MView, MGestureRecognizerDelegate { } } - public let zoom = MacawZoom() - public var place: Transform { return placeManager.placeVar.value } @@ -77,9 +222,6 @@ open class MacawView: MView, MGestureRecognizerDelegate { return placeManager.placeVar } - private let placeManager = RootPlaceManager() - internal let touchInterceptionView = TouchInterceptionView() - override open var frame: CGRect { didSet { super.frame = frame @@ -94,6 +236,14 @@ open class MacawView: MView, MGestureRecognizerDelegate { } } + override open var intrinsicContentSize: CGSize { + if let bounds = node.bounds { + return bounds.size().toCG() + } else { + return CGSize(width: MNoIntrinsicMetric(), height: MNoIntrinsicMetric()) + } + } + override open func didMoveToSuperview() { super.didMoveToSuperview() @@ -104,14 +254,7 @@ open class MacawView: MView, MGestureRecognizerDelegate { animationProducer.addStoredAnimations(node, self) } - override open var intrinsicContentSize: CGSize { - if let bounds = node.bounds { - return bounds.size().toCG() - } else { - return CGSize(width: MNoIntrinsicMetric(), height: MNoIntrinsicMetric()) - } - } - + private let placeManager = RootPlaceManager() private let layoutHelper = LayoutHelper() var touchesMap = [MTouchEvent: [NodePath]]() @@ -124,24 +267,17 @@ open class MacawView: MView, MGestureRecognizerDelegate { var toRender = true var frameSetFirstTime = false - #if os(OSX) - open override var layer: CALayer? { - didSet { - guard self.layer != nil else { - return - } - initializeView() - - self.renderer = RenderUtils.createNodeRenderer(node, view: self) - } + func initializeView() { + self.contentLayout = .none + self.context = RenderContext(view: self) + } + + @objc public convenience required init?(coder aDecoder: NSCoder) { + self.init(node: Group(), coder: aDecoder) } - #endif @objc public init?(node: Node, coder aDecoder: NSCoder) { super.init(coder: aDecoder) - zoom.initialize(view: self, onChange: onZoomChange) - - initializeView() self.node = node self.renderer = RenderUtils.createNodeRenderer(node, view: self) @@ -158,61 +294,6 @@ open class MacawView: MView, MGestureRecognizerDelegate { public override init(frame: CGRect) { super.init(frame: frame) - zoom.initialize(view: self, onChange: onZoomChange) - } - - @objc public convenience required init?(coder aDecoder: NSCoder) { - self.init(node: Group(), coder: aDecoder) - } - - open override func didMoveToWindow() { - super.didMoveToWindow() - - initializeView() - } - - func initializeView() { - self.contentLayout = .none - self.context = RenderContext(view: self) - - if let superview = self.superview { - self.isUserInteractionEnabled = false - touchInterceptionView.isMultipleTouchEnabled = true - touchInterceptionView.macawView = self - touchInterceptionView.backgroundColor = .clear - superview.insertSubview(touchInterceptionView, aboveSubview: self) - - touchInterceptionView.translatesAutoresizingMaskIntoConstraints = false - touchInterceptionView.leftAnchor.constraint(equalTo: self.leftAnchor).isActive = true - touchInterceptionView.rightAnchor.constraint(equalTo: self.rightAnchor).isActive = true - touchInterceptionView.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true - touchInterceptionView.topAnchor.constraint(equalTo: self.topAnchor).isActive = true - } - - 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)) - let rotationRecognizer = MRotationGestureRecognizer(target: self, action: #selector(MacawView.handleRotation)) - let pinchRecognizer = MPinchGestureRecognizer(target: self, action: #selector(MacawView.handlePinch)) - - tapRecognizer.delegate = self - longTapRecognizer.delegate = self - panRecognizer.delegate = self - rotationRecognizer.delegate = self - pinchRecognizer.delegate = self - - tapRecognizer.cancelsTouchesInView = false - longTapRecognizer.cancelsTouchesInView = false - panRecognizer.cancelsTouchesInView = false - rotationRecognizer.cancelsTouchesInView = false - pinchRecognizer.cancelsTouchesInView = false - - touchInterceptionView.removeGestureRecognizers() - touchInterceptionView.addGestureRecognizer(tapRecognizer) - touchInterceptionView.addGestureRecognizer(longTapRecognizer) - touchInterceptionView.addGestureRecognizer(panRecognizer) - touchInterceptionView.addGestureRecognizer(rotationRecognizer) - touchInterceptionView.addGestureRecognizer(pinchRecognizer) } open override func layoutSubviews() { @@ -220,12 +301,6 @@ open class MacawView: MView, MGestureRecognizerDelegate { setNeedsDisplay() } - private func onZoomChange(t: Transform) { - if let viewLayer = mLayer { - viewLayer.transform = CATransform3DMakeAffineTransform(t.toCG()) - } - } - override open func draw(_ rect: CGRect) { context.cgContext = MGraphicsGetCurrentContext() guard let ctx = context.cgContext else { @@ -274,10 +349,8 @@ open class MacawView: MView, MGestureRecognizerDelegate { } // MARK: - Touches - override func mTouchesBegan(_ touches: Set, with event: MEvent?) { - zoom.touchesBegan(touches) + func touchesBegan(touchPoints: [MTouchEvent]) { - let touchPoints = convert(touches: touches) if !self.node.shouldCheckForPressed() && !self.node.shouldCheckForMoved() && !self.node.shouldCheckForReleased () { @@ -325,8 +398,7 @@ open class MacawView: MView, MGestureRecognizerDelegate { } } - override func mTouchesMoved(_ touches: Set, with event: MEvent?) { - zoom.touchesMoved(touches) + func touchesMoved(touchPoints: [MTouchEvent]) { if !self.node.shouldCheckForMoved() { return } @@ -335,7 +407,6 @@ open class MacawView: MView, MGestureRecognizerDelegate { return } - let touchPoints = convert(touches: touches) touchesOfNode.keys.forEach { currentNode in guard let initialTouches = touchesOfNode[currentNode] else { return @@ -369,30 +440,12 @@ open class MacawView: MView, MGestureRecognizerDelegate { } } - override func mTouchesCancelled(_ touches: Set, with event: MEvent?) { - touchesEnded(touches: touches) - } - - override func mTouchesEnded(_ touches: Set, with event: MEvent?) { - touchesEnded(touches: touches) - } - - private func convert(touches: Set) -> [MTouchEvent] { - return touches.map { touch -> MTouchEvent in - let location = touch.applyCurrentLayerTransform(self) - let id = Int(bitPattern: Unmanaged.passUnretained(touch).toOpaque()) - return MTouchEvent(x: Double(location.x), y: Double(location.y), id: id) - } - } - - private func touchesEnded(touches: Set) { - zoom.touchesEnded(touches) + func touchesEnded(touchPoints: [MTouchEvent]) { guard let _ = renderer else { return } let invertedViewPlace = self.place.invert() - let touchPoints = convert(touches: touches) for touch in touchPoints { touchesMap[touch]?.forEach { nodePath in diff --git a/Source/views/MacawZoom.swift b/Source/views/MacawZoom.swift index 33296d26..677cb6ba 100644 --- a/Source/views/MacawZoom.swift +++ b/Source/views/MacawZoom.swift @@ -139,7 +139,7 @@ fileprivate class TouchData { let point: Point convenience init(touch: MTouch, in view: MacawView) { - self.init(touch: touch, point: touch.applyCurrentLayerTransform(view)) + self.init(touch: touch, point: touch.location(in: view).toMacaw()) } init(touch: MTouch, point: Point) { @@ -148,14 +148,7 @@ fileprivate class TouchData { } func current(in view: MacawView) -> Point { - return touch.applyCurrentLayerTransform(view) + return touch.location(in: view).toMacaw() } } - -extension MTouch { - - func applyCurrentLayerTransform(_ view: MacawView) -> Point { - return self.location(in: view.touchInterceptionView).toMacaw() - } -} From 9a73bc012fd265c28b93d6d6563ef4f049e31a3e Mon Sep 17 00:00:00 2001 From: Alisa Mylnikova Date: Thu, 16 Apr 2020 16:11:20 +0700 Subject: [PATCH 07/11] Fix compile errors --- Source/views/MacawView.swift | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/Source/views/MacawView.swift b/Source/views/MacawView.swift index fa8f838f..f7a02dd2 100644 --- a/Source/views/MacawView.swift +++ b/Source/views/MacawView.swift @@ -49,6 +49,11 @@ open class MacawView: MView { get { return drawingView.intrinsicContentSize } } + internal var renderer: NodeRenderer? { + get { return drawingView.renderer } + set { drawingView.renderer = newValue } + } + #if os(OSX) open override var layer: CALayer? { didSet { @@ -57,7 +62,7 @@ open class MacawView: MView { } initializeView() - drawingView.renderer = RenderUtils.createNodeRenderer(node, view: self) + renderer = RenderUtils.createNodeRenderer(node, view: drawingView) } } #endif @@ -96,8 +101,8 @@ open class MacawView: MView { } } - open override func didMoveToWindow() { - super.didMoveToWindow() + open override func didMoveToSuperview() { + super.didMoveToSuperview() initializeView() } @@ -145,29 +150,29 @@ open class MacawView: MView { self.addGestureRecognizer(pinchRecognizer) } - open override func touchesBegan(_ touches: Set, with event: MEvent?) { - super.touchesBegan(touches, with: event) + open override func mTouchesBegan(_ touches: Set, with event: MEvent?) { + super.mTouchesBegan(touches, with: event) zoom.touchesBegan(touches) drawingView.touchesBegan(touchPoints: convert(touches: touches)) } - open override func touchesMoved(_ touches: Set, with event: MEvent?) { - super.touchesMoved(touches, with: event) + open override func mTouchesMoved(_ touches: Set, with event: MEvent?) { + super.mTouchesMoved(touches, with: event) zoom.touchesMoved(touches) drawingView.touchesMoved(touchPoints: convert(touches: touches)) } - open override func touchesEnded(_ touches: Set, with event: MEvent?) { - super.touchesEnded(touches, with: event) + open override func mTouchesEnded(_ touches: Set, with event: MEvent?) { + super.mTouchesEnded(touches, with: event) zoom.touchesEnded(touches) drawingView.touchesEnded(touchPoints: convert(touches: touches)) } - override open func touchesCancelled(_ touches: Set, with event: MEvent?) { - super.touchesEnded(touches, with: event) + override open func mTouchesCancelled(_ touches: Set, with event: MEvent?) { + super.mTouchesCancelled(touches, with: event) zoom.touchesEnded(touches) drawingView.touchesEnded(touchPoints: convert(touches: touches)) From bb47def33747190deb0768c479f404d6a0236472 Mon Sep 17 00:00:00 2001 From: Alisa Mylnikova Date: Fri, 17 Apr 2020 15:55:40 +0700 Subject: [PATCH 08/11] Fix some examples --- .../CombinationAnimationGenerator.swift | 7 ++- Source/views/MacawView.swift | 52 +++++++------------ 2 files changed, 25 insertions(+), 34 deletions(-) diff --git a/Source/animation/types/animation_generators/CombinationAnimationGenerator.swift b/Source/animation/types/animation_generators/CombinationAnimationGenerator.swift index 9a6f92eb..6815bcb0 100644 --- a/Source/animation/types/animation_generators/CombinationAnimationGenerator.swift +++ b/Source/animation/types/animation_generators/CombinationAnimationGenerator.swift @@ -115,13 +115,16 @@ extension AnimationProducer { // MARK: - Combine animation func addCombineAnimation(_ combineAnimation: Animation, _ context: AnimationContext) { guard let combine = combineAnimation as? CombineAnimation, + let _ = combine.nodeRenderer, let node = combine.node else { return } var animations = combine.animations - let childAnimations = createChildAnimations(combine) as! [BasicAnimation] - animations.append(contentsOf: childAnimations) + if let _ = combine.node?.bounds, let _ = combine.toNodes.group().bounds { + let childAnimations = createChildAnimations(combine) as! [BasicAnimation] + animations.append(contentsOf: childAnimations) + } // Reversing if combine.autoreverses { diff --git a/Source/views/MacawView.swift b/Source/views/MacawView.swift index f7a02dd2..2dddec6d 100644 --- a/Source/views/MacawView.swift +++ b/Source/views/MacawView.swift @@ -74,9 +74,8 @@ open class MacawView: MView { @objc public init?(node: Node, coder aDecoder: NSCoder) { super.init(coder: aDecoder) - if let drawingView = DrawingView(node: node, coder: aDecoder) { - self.drawingView = drawingView - } + self.node = node + self.renderer = RenderUtils.createNodeRenderer(node, view: drawingView) zoom.initialize(view: self, onChange: onZoomChange) } @@ -84,14 +83,13 @@ open class MacawView: MView { public convenience init(node: Node, frame: CGRect) { self.init(frame: frame) - self.drawingView = DrawingView(node: node, frame: frame) + self.node = node + self.renderer = RenderUtils.createNodeRenderer(node, view: drawingView) } public override init(frame: CGRect) { super.init(frame: frame) - self.drawingView = DrawingView(frame: frame) - zoom.initialize(view: self, onChange: onZoomChange) } @@ -107,21 +105,27 @@ open class MacawView: MView { initializeView() } + open override func layoutSubviews() { + super.layoutSubviews() + + drawingView.frame = self.bounds + } + func initializeView() { if !self.subviews.contains(drawingView) { - self.backgroundColor = .white - self.clipsToBounds = true + if self.backgroundColor == nil { + self.backgroundColor = .white + } + drawingView.removeFromSuperview() self.addSubview(drawingView) - drawingView.backgroundColor = .white - drawingView.isUserInteractionEnabled = false + drawingView.backgroundColor = .clear drawingView.initializeView() - drawingView.translatesAutoresizingMaskIntoConstraints = false - drawingView.trailingAnchor.constraint(equalTo: self.trailingAnchor).isActive = true - drawingView.leadingAnchor.constraint(equalTo: self.leadingAnchor).isActive = true - drawingView.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true - drawingView.topAnchor.constraint(equalTo: self.topAnchor).isActive = true + #if os(iOS) + self.clipsToBounds = true + drawingView.isUserInteractionEnabled = false + #endif } let tapRecognizer = MTapGestureRecognizer(target: drawingView, action: #selector(DrawingView.handleTap(recognizer:))) @@ -277,24 +281,8 @@ internal class DrawingView: MView, MGestureRecognizerDelegate { self.context = RenderContext(view: self) } - @objc public convenience required init?(coder aDecoder: NSCoder) { - self.init(node: Group(), coder: aDecoder) - } - - @objc public init?(node: Node, coder aDecoder: NSCoder) { + @objc public required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) - - self.node = node - self.renderer = RenderUtils.createNodeRenderer(node, view: self) - backgroundColor = .white - } - - public convenience init(node: Node, frame: CGRect) { - self.init(frame: frame) - - self.node = node - self.renderer = RenderUtils.createNodeRenderer(node, view: self) - backgroundColor = .white } public override init(frame: CGRect) { From 496ef399d1b80ed9a6ed24460e0bd49576a14a3a Mon Sep 17 00:00:00 2001 From: Alisa Mylnikova Date: Mon, 20 Apr 2020 13:18:40 +0700 Subject: [PATCH 09/11] Fix layer inset issue --- Source/views/MacawView.swift | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Source/views/MacawView.swift b/Source/views/MacawView.swift index 2dddec6d..a28b57f8 100644 --- a/Source/views/MacawView.swift +++ b/Source/views/MacawView.swift @@ -40,9 +40,11 @@ open class MacawView: MView { get { return drawingView.placeVar } } - open override var frame: CGRect { - get { return drawingView.frame } - set { drawingView.frame = newValue } + override open var frame: CGRect { + didSet { + super.frame = frame + drawingView.frame = frame + } } override open var intrinsicContentSize: CGSize { From 5c0f812f0c8638a89540d5d7e08f14e460244bf0 Mon Sep 17 00:00:00 2001 From: Alisa Mylnikova Date: Mon, 20 Apr 2020 14:18:16 +0700 Subject: [PATCH 10/11] Fix for liquid swipe --- Source/views/MacawView.swift | 42 ++++++++++++++++-------------------- 1 file changed, 19 insertions(+), 23 deletions(-) diff --git a/Source/views/MacawView.swift b/Source/views/MacawView.swift index a28b57f8..582db76a 100644 --- a/Source/views/MacawView.swift +++ b/Source/views/MacawView.swift @@ -11,7 +11,7 @@ import AppKit /// You could create your own view extended from MacawView with predefined scene. /// -open class MacawView: MView { +open class MacawView: MView, MGestureRecognizerDelegate { internal var drawingView = DrawingView() @@ -80,6 +80,7 @@ open class MacawView: MView { self.renderer = RenderUtils.createNodeRenderer(node, view: drawingView) zoom.initialize(view: self, onChange: onZoomChange) + initializeView() } public convenience init(node: Node, frame: CGRect) { @@ -93,6 +94,7 @@ open class MacawView: MView { super.init(frame: frame) zoom.initialize(view: self, onChange: onZoomChange) + initializeView() } private func onZoomChange(t: Transform) { @@ -101,12 +103,6 @@ open class MacawView: MView { } } - open override func didMoveToSuperview() { - super.didMoveToSuperview() - - initializeView() - } - open override func layoutSubviews() { super.layoutSubviews() @@ -136,11 +132,11 @@ open class MacawView: MView { let rotationRecognizer = MRotationGestureRecognizer(target: drawingView, action: #selector(DrawingView.handleRotation)) let pinchRecognizer = MPinchGestureRecognizer(target: drawingView, action: #selector(DrawingView.handlePinch)) - tapRecognizer.delegate = drawingView - longTapRecognizer.delegate = drawingView - panRecognizer.delegate = drawingView - rotationRecognizer.delegate = drawingView - pinchRecognizer.delegate = drawingView + tapRecognizer.delegate = self + longTapRecognizer.delegate = self + panRecognizer.delegate = self + rotationRecognizer.delegate = self + pinchRecognizer.delegate = self tapRecognizer.cancelsTouchesInView = false longTapRecognizer.cancelsTouchesInView = false @@ -191,9 +187,19 @@ open class MacawView: MView { return MTouchEvent(x: Double(location.x), y: Double(location.y), id: id) } } + + // MARK: - MGestureRecognizerDelegate + + public func gestureRecognizer(_ gestureRecognizer: MGestureRecognizer, shouldReceive touch: MTouch) -> Bool { + return true + } + + public func gestureRecognizer(_ gestureRecognizer: MGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: MGestureRecognizer) -> Bool { + return true + } } -internal class DrawingView: MView, MGestureRecognizerDelegate { +internal class DrawingView: MView { /// Scene root node open var node: Node = Group() { @@ -659,16 +665,6 @@ internal class DrawingView: MView, MGestureRecognizerDelegate { recognizersMap.removeValue(forKey: recognizer) } } - - // MARK: - MGestureRecognizerDelegate - - public func gestureRecognizer(_ gestureRecognizer: MGestureRecognizer, shouldReceive touch: MTouch) -> Bool { - return true - } - - public func gestureRecognizer(_ gestureRecognizer: MGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: MGestureRecognizer) -> Bool { - return true - } } class LayoutHelper { From 67b7bb132fed03418e10c57bea470d7adf179171 Mon Sep 17 00:00:00 2001 From: Alisa Mylnikova Date: Tue, 21 Apr 2020 13:59:37 +0700 Subject: [PATCH 11/11] Fix for animation hierarchy movement --- Source/views/MacawView.swift | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/Source/views/MacawView.swift b/Source/views/MacawView.swift index 582db76a..d957b3e8 100644 --- a/Source/views/MacawView.swift +++ b/Source/views/MacawView.swift @@ -103,23 +103,22 @@ open class MacawView: MView, MGestureRecognizerDelegate { } } - open override func layoutSubviews() { - super.layoutSubviews() - - drawingView.frame = self.bounds - } - func initializeView() { if !self.subviews.contains(drawingView) { if self.backgroundColor == nil { self.backgroundColor = .white } - drawingView.removeFromSuperview() self.addSubview(drawingView) drawingView.backgroundColor = .clear drawingView.initializeView() + drawingView.translatesAutoresizingMaskIntoConstraints = false + drawingView.trailingAnchor.constraint(equalTo: self.trailingAnchor).isActive = true + drawingView.leadingAnchor.constraint(equalTo: self.leadingAnchor).isActive = true + drawingView.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true + drawingView.topAnchor.constraint(equalTo: self.topAnchor).isActive = true + #if os(iOS) self.clipsToBounds = true drawingView.isUserInteractionEnabled = false