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/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 e4fc0a3e..7ae54475 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 } @@ -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/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/CombinationAnimationGenerator.swift b/Source/animation/types/animation_generators/CombinationAnimationGenerator.swift index 7012323c..6815bcb0 100644 --- a/Source/animation/types/animation_generators/CombinationAnimationGenerator.swift +++ b/Source/animation/types/animation_generators/CombinationAnimationGenerator.swift @@ -115,8 +115,8 @@ extension AnimationProducer { // MARK: - Combine animation func addCombineAnimation(_ combineAnimation: Animation, _ context: AnimationContext) { guard let combine = combineAnimation as? CombineAnimation, - let renderer = combine.nodeRenderer, - let _ = renderer.view else { + let _ = combine.nodeRenderer, + let node = combine.node else { return } @@ -176,6 +176,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 212cbd9d..b077c26b 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( @@ -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 71e9441c..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 && @@ -58,10 +67,11 @@ 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 + node.animations.removeAll { $0 === animation } layer?.removeAnimation(forKey: animationId) } 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..5e45377d 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, @@ -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) } 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 0b918eb9..d957b3e8 100644 --- a/Source/views/MacawView.swift +++ b/Source/views/MacawView.swift @@ -10,8 +10,196 @@ 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. /// + open class MacawView: MView, MGestureRecognizerDelegate { + 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 } + } + + override open var frame: CGRect { + didSet { + super.frame = frame + drawingView.frame = frame + } + } + + override open var intrinsicContentSize: CGSize { + 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 { + guard self.layer != nil else { + return + } + initializeView() + + renderer = RenderUtils.createNodeRenderer(node, view: drawingView) + } + } + #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) + + self.node = node + self.renderer = RenderUtils.createNodeRenderer(node, view: drawingView) + + zoom.initialize(view: self, onChange: onZoomChange) + initializeView() + } + + public convenience init(node: Node, frame: CGRect) { + self.init(frame: frame) + + self.node = node + self.renderer = RenderUtils.createNodeRenderer(node, view: drawingView) + } + + public override init(frame: CGRect) { + super.init(frame: frame) + + zoom.initialize(view: self, onChange: onZoomChange) + initializeView() + } + + private func onZoomChange(t: Transform) { + if let viewLayer = drawingView.mLayer { + viewLayer.transform = CATransform3DMakeAffineTransform(t.toCG()) + } + } + + func initializeView() { + + if !self.subviews.contains(drawingView) { + if self.backgroundColor == nil { + self.backgroundColor = .white + } + 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 + #endif + } + + 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 = 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 + + self.removeGestureRecognizers() + self.addGestureRecognizer(tapRecognizer) + self.addGestureRecognizer(longTapRecognizer) + self.addGestureRecognizer(panRecognizer) + self.addGestureRecognizer(rotationRecognizer) + self.addGestureRecognizer(pinchRecognizer) + } + + 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 mTouchesMoved(_ touches: Set, with event: MEvent?) { + super.mTouchesMoved(touches, with: event) + zoom.touchesMoved(touches) + + drawingView.touchesMoved(touchPoints: convert(touches: touches)) + } + + 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 mTouchesCancelled(_ touches: Set, with event: MEvent?) { + super.mTouchesCancelled(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) + } + } + + // 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 { + /// Scene root node open var node: Node = Group() { didSet { @@ -42,8 +230,6 @@ open class MacawView: MView, MGestureRecognizerDelegate { } } - public let zoom = MacawZoom() - public var place: Transform { return placeManager.placeVar.value } @@ -52,8 +238,6 @@ open class MacawView: MView, MGestureRecognizerDelegate { return placeManager.placeVar } - private let placeManager = RootPlaceManager() - override open var frame: CGRect { didSet { super.frame = frame @@ -68,6 +252,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() @@ -78,14 +270,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]]() @@ -98,82 +283,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) } - #endif - @objc public init?(node: Node, coder aDecoder: NSCoder) { + @objc public required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) - zoom.initialize(view: self, onChange: onZoomChange) - - initializeView() - - 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) { 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) - } - - private func onZoomChange(t: Transform) { - placeManager.setZoom(place: t) - self.setNeedsDisplay() - } - - func initializeView() { - self.contentLayout = .none - self.context = RenderContext(view: self) - - 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 - - self.removeGestureRecognizers() - self.addGestureRecognizer(tapRecognizer) - self.addGestureRecognizer(longTapRecognizer) - self.addGestureRecognizer(panRecognizer) - self.addGestureRecognizer(rotationRecognizer) - self.addGestureRecognizer(pinchRecognizer) } open override func layoutSubviews() { @@ -194,12 +314,12 @@ open class MacawView: MView, MGestureRecognizerDelegate { guard let renderer = renderer else { 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.calculateZPositionRecursively() renderer.render(in: ctx, force: false, opacity: node.opacity) } @@ -229,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 () { @@ -280,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 } @@ -290,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 @@ -324,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.location(in: 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 @@ -566,16 +664,6 @@ open class MacawView: 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 { diff --git a/Source/views/MacawZoom.swift b/Source/views/MacawZoom.swift index 1a9532cd..677cb6ba 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 } @@ -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 } @@ -93,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) } } @@ -143,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.location(in: view).toMacaw()) } @@ -152,7 +147,7 @@ fileprivate class TouchData { self.point = point } - func current(in view: MView) -> Point { + func current(in view: MacawView) -> Point { return touch.location(in: view).toMacaw() } 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) } }