mirror of
https://github.com/exyte/Macaw.git
synced 2024-09-21 09:59:10 +03:00
Merge commit 'c78b3e9605d1e50fed488f98214cbaff8e3808f9' into task/svgViewBox
This commit is contained in:
commit
052003ade0
@ -14,6 +14,7 @@ disabled_rules:
|
||||
- strict_fileprivate
|
||||
- sorted_imports
|
||||
- identifier_name # Disabled due to a lot of one symbol identifiers
|
||||
- let_var_whitespace
|
||||
# Temporary disabled
|
||||
- explicit_type_interface
|
||||
- line_length
|
||||
@ -66,7 +67,6 @@ opt_in_rules:
|
||||
- legacy_cggeometry_functions
|
||||
- legacy_constant
|
||||
- legacy_nsgeometry_functions
|
||||
- let_var_whitespace
|
||||
- mark
|
||||
- multiline_parameters
|
||||
- multiple_closures_with_trailing_closure
|
||||
|
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>IDEDidComputeMac32BitWarning</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
@ -1,9 +1,9 @@
|
||||
import Foundation
|
||||
|
||||
#if os(iOS)
|
||||
import UIKit
|
||||
import UIKit
|
||||
#elseif os(OSX)
|
||||
import AppKit
|
||||
import AppKit
|
||||
#endif
|
||||
|
||||
let animationProducer = AnimationProducer()
|
||||
|
@ -1,7 +1,7 @@
|
||||
import Foundation
|
||||
|
||||
#if os(iOS)
|
||||
import UIKit
|
||||
import UIKit
|
||||
#endif
|
||||
|
||||
public extension Rect {
|
||||
|
@ -1,9 +1,9 @@
|
||||
import Foundation
|
||||
|
||||
#if os(iOS)
|
||||
import UIKit
|
||||
import UIKit
|
||||
#elseif os(OSX)
|
||||
import AppKit
|
||||
import AppKit
|
||||
#endif
|
||||
|
||||
class AnimationCache {
|
||||
|
@ -9,9 +9,9 @@
|
||||
import Foundation
|
||||
|
||||
#if os(iOS)
|
||||
import UIKit
|
||||
import UIKit
|
||||
#elseif os(OSX)
|
||||
import AppKit
|
||||
import AppKit
|
||||
#endif
|
||||
|
||||
func addMorphingAnimation(_ animation: BasicAnimation, sceneLayer: CALayer, animationCache: AnimationCache?, completion: @escaping (() -> Void)) {
|
||||
|
@ -1,9 +1,9 @@
|
||||
import Foundation
|
||||
|
||||
#if os(iOS)
|
||||
import UIKit
|
||||
import UIKit
|
||||
#elseif os(OSX)
|
||||
import AppKit
|
||||
import AppKit
|
||||
#endif
|
||||
|
||||
func addOpacityAnimation(_ animation: BasicAnimation, sceneLayer: CALayer, animationCache: AnimationCache?, completion: @escaping (() -> Void)) {
|
||||
|
@ -9,9 +9,9 @@
|
||||
import Foundation
|
||||
|
||||
#if os(iOS)
|
||||
import UIKit
|
||||
import UIKit
|
||||
#elseif os(OSX)
|
||||
import AppKit
|
||||
import AppKit
|
||||
#endif
|
||||
|
||||
func addShapeAnimation(_ animation: BasicAnimation, sceneLayer: CALayer, animationCache: AnimationCache?, completion: @escaping (() -> Void)) {
|
||||
|
@ -1,9 +1,9 @@
|
||||
import Foundation
|
||||
|
||||
#if os(iOS)
|
||||
import UIKit
|
||||
import UIKit
|
||||
#elseif os(OSX)
|
||||
import AppKit
|
||||
import AppKit
|
||||
#endif
|
||||
|
||||
func caTimingFunction(_ easing: Easing) -> CAMediaTimingFunction {
|
||||
|
@ -1,9 +1,9 @@
|
||||
import Foundation
|
||||
|
||||
#if os(iOS)
|
||||
import UIKit
|
||||
import UIKit
|
||||
#elseif os(OSX)
|
||||
import AppKit
|
||||
import AppKit
|
||||
#endif
|
||||
|
||||
func addTransformAnimation(_ animation: BasicAnimation, sceneLayer: CALayer, animationCache: AnimationCache?, completion: @escaping (() -> Void)) {
|
||||
|
@ -1,7 +1,7 @@
|
||||
import Foundation
|
||||
|
||||
#if os(iOS)
|
||||
import UIKit
|
||||
import UIKit
|
||||
#endif
|
||||
|
||||
open class LinearGradient: Gradient {
|
||||
@ -22,33 +22,33 @@ open class LinearGradient: Gradient {
|
||||
)
|
||||
}
|
||||
|
||||
public convenience init(degree: Double = 0, from: Color, to: Color) {
|
||||
self.init(degree: degree, stops: [Stop(offset: 0, color: from), Stop(offset: 1, color: to)])
|
||||
public convenience init(degree: Double = 0, from: Color, to: Color) {
|
||||
self.init(degree: degree, stops: [Stop(offset: 0, color: from), Stop(offset: 1, color: to)])
|
||||
}
|
||||
|
||||
public init(degree: Double = 0, stops: [Stop]) {
|
||||
public init(degree: Double = 0, stops: [Stop]) {
|
||||
let rad = degree * .pi / 180
|
||||
var v = [0, 0, cos(rad), sin(rad)]
|
||||
let mmax = 1 / max(abs(v[2]), abs(v[3]))
|
||||
v[2] *= mmax
|
||||
v[3] *= mmax
|
||||
if (v[2] < 0) {
|
||||
if v[2] < 0 {
|
||||
v[0] = -v[2]
|
||||
v[2] = 0
|
||||
}
|
||||
if (v[3] < 0) {
|
||||
if v[3] < 0 {
|
||||
v[1] = -v[3]
|
||||
v[3] = 0
|
||||
}
|
||||
|
||||
|
||||
self.x1 = v[0]
|
||||
self.y1 = v[1]
|
||||
self.x2 = v[2]
|
||||
self.y2 = v[3]
|
||||
|
||||
super.init(
|
||||
userSpace: false,
|
||||
stops: stops
|
||||
)
|
||||
}
|
||||
super.init(
|
||||
userSpace: false,
|
||||
stops: stops
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
import Foundation
|
||||
|
||||
#if os(iOS)
|
||||
import UIKit
|
||||
import UIKit
|
||||
#endif
|
||||
|
||||
open class RadialGradient: Gradient {
|
||||
|
@ -155,7 +155,7 @@ open class PathBuilder {
|
||||
}
|
||||
return Path(segments: segments.reversed())
|
||||
}
|
||||
|
||||
|
||||
// GENERATED NOT
|
||||
fileprivate func boolToNum(_ value: Bool) -> Double {
|
||||
return value ? 1 : 0
|
||||
|
@ -114,13 +114,13 @@ open class Group: Node {
|
||||
|
||||
return shouldCheck
|
||||
}
|
||||
|
||||
|
||||
override func shouldCheckForLongTap() -> Bool {
|
||||
var shouldCheck = super.shouldCheckForLongTap()
|
||||
contents.forEach { node in
|
||||
shouldCheck = shouldCheck || node.shouldCheckForLongTap()
|
||||
}
|
||||
|
||||
|
||||
return shouldCheck
|
||||
}
|
||||
|
||||
|
@ -1,11 +1,11 @@
|
||||
import Foundation
|
||||
|
||||
#if os(OSX)
|
||||
import AppKit
|
||||
import AppKit
|
||||
#endif
|
||||
|
||||
#if os(iOS)
|
||||
import UIKit
|
||||
import UIKit
|
||||
#endif
|
||||
|
||||
open class Image: Node {
|
||||
@ -160,9 +160,9 @@ open class Image: Node {
|
||||
|
||||
// General case
|
||||
#if os(iOS)
|
||||
return MImage(named: src)
|
||||
return MImage(named: src)
|
||||
#elseif os(OSX)
|
||||
return MImage(named: NSImage.Name(rawValue: src))
|
||||
return MImage(named: NSImage.Name(rawValue: src))
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
@ -64,12 +64,12 @@ open class Node: Drawable {
|
||||
var touchPressedHandlers = [ChangeHandler<TouchEvent>]()
|
||||
var touchMovedHandlers = [ChangeHandler<TouchEvent>]()
|
||||
var touchReleasedHandlers = [ChangeHandler<TouchEvent>]()
|
||||
|
||||
|
||||
var prevTouchCount: Int = 0
|
||||
var prevTouchTimer: Timer?
|
||||
var isLongTapInProgress = false
|
||||
|
||||
var tapHandlers = [Int : [ChangeHandler<TapEvent>]]()
|
||||
var tapHandlers = [Int: [ChangeHandler<TapEvent>]]()
|
||||
var longTapHandlers = [ChangeHandler<TapEvent>]()
|
||||
var panHandlers = [ChangeHandler<PanEvent>]()
|
||||
var rotateHandlers = [ChangeHandler<RotateEvent>]()
|
||||
@ -130,16 +130,16 @@ open class Node: Drawable {
|
||||
self?.tapHandlers[tapCount]?.remove(at: index)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@discardableResult public func onLongTap(_ f: @escaping (TapEvent) -> Void) -> Disposable {
|
||||
let handler = ChangeHandler<TapEvent>(f)
|
||||
longTapHandlers.append(handler)
|
||||
|
||||
|
||||
return Disposable { [weak self] in
|
||||
guard let index = self?.longTapHandlers.index(of: handler) else {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
self?.longTapHandlers.remove(at: index)
|
||||
}
|
||||
}
|
||||
@ -196,9 +196,9 @@ open class Node: Drawable {
|
||||
func handleTouchMoved(_ event: TouchEvent) {
|
||||
touchMovedHandlers.forEach { handler in handler.handle(event) }
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Multiple tap handling
|
||||
|
||||
|
||||
func handleTap( _ event: TapEvent ) {
|
||||
if isLongTapInProgress {
|
||||
prevTouchCount = 0
|
||||
@ -209,32 +209,32 @@ open class Node: Drawable {
|
||||
prevTouchTimer = nil
|
||||
}
|
||||
prevTouchCount += 1
|
||||
|
||||
|
||||
for tapCount in tapHandlers.keys {
|
||||
if tapCount > prevTouchCount { // wait some more - there is a recognizer for even more taps
|
||||
prevTouchTimer = Timer.scheduledTimer(timeInterval: 0.3, target: self, selector: #selector(onTouchTimer), userInfo: event, repeats: false)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for (tapCount, handlers) in tapHandlers {
|
||||
if tapCount == prevTouchCount { // nothing to wait for - max tap count reached
|
||||
handlers.forEach { handler in handler.handle(event) }
|
||||
prevTouchCount = 0
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@objc func onTouchTimer(timer: Timer) {
|
||||
if isLongTapInProgress {
|
||||
prevTouchCount = 0
|
||||
return
|
||||
}
|
||||
for touchCount in tapHandlers.keys.sorted(by: {$0>$1}) {
|
||||
for touchCount in tapHandlers.keys.sorted(by: { $0>$1 }) {
|
||||
if touchCount <= prevTouchCount, let event = timer.userInfo as? TapEvent {
|
||||
// no more taps coming, settle for next best thing
|
||||
for _ in 0..<prevTouchCount/touchCount { // might need to call it multiple times
|
||||
for _ in 0..<prevTouchCount / touchCount { // might need to call it multiple times
|
||||
tapHandlers[touchCount]?.forEach { handler in handler.handle(event) }
|
||||
}
|
||||
break
|
||||
@ -242,9 +242,9 @@ open class Node: Drawable {
|
||||
}
|
||||
prevTouchCount = 0
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Helpers
|
||||
|
||||
|
||||
func handleLongTap( _ event: TapEvent, touchBegan: Bool ) {
|
||||
isLongTapInProgress = touchBegan
|
||||
if touchBegan {
|
||||
@ -280,7 +280,7 @@ open class Node: Drawable {
|
||||
func shouldCheckForTap() -> Bool {
|
||||
return !tapHandlers.isEmpty
|
||||
}
|
||||
|
||||
|
||||
func shouldCheckForLongTap() -> Bool {
|
||||
return !longTapHandlers.isEmpty
|
||||
}
|
||||
|
@ -9,26 +9,26 @@
|
||||
class SceneUtils {
|
||||
static func shapeCopy(from: Shape) -> Shape {
|
||||
let shape = Shape(form: from.form,
|
||||
fill: from.fill,
|
||||
stroke: from.stroke,
|
||||
place: from.place,
|
||||
opaque: from.opaque,
|
||||
opacity: from.opacity,
|
||||
clip: from.clip,
|
||||
effect: from.effect,
|
||||
visible: from.visible,
|
||||
tag: from.tag)
|
||||
|
||||
shape.touchPressedHandlers = from.touchPressedHandlers
|
||||
shape.touchMovedHandlers = from.touchMovedHandlers
|
||||
shape.touchReleasedHandlers = from.touchReleasedHandlers
|
||||
|
||||
shape.tapHandlers = from.tapHandlers
|
||||
fill: from.fill,
|
||||
stroke: from.stroke,
|
||||
place: from.place,
|
||||
opaque: from.opaque,
|
||||
opacity: from.opacity,
|
||||
clip: from.clip,
|
||||
effect: from.effect,
|
||||
visible: from.visible,
|
||||
tag: from.tag)
|
||||
|
||||
shape.touchPressedHandlers = from.touchPressedHandlers
|
||||
shape.touchMovedHandlers = from.touchMovedHandlers
|
||||
shape.touchReleasedHandlers = from.touchReleasedHandlers
|
||||
|
||||
shape.tapHandlers = from.tapHandlers
|
||||
shape.longTapHandlers = from.longTapHandlers
|
||||
shape.panHandlers = from.panHandlers
|
||||
shape.rotateHandlers = from.rotateHandlers
|
||||
shape.pinchHandlers = from.pinchHandlers
|
||||
|
||||
return shape
|
||||
shape.panHandlers = from.panHandlers
|
||||
shape.rotateHandlers = from.rotateHandlers
|
||||
shape.pinchHandlers = from.pinchHandlers
|
||||
|
||||
return shape
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,9 @@
|
||||
import Foundation
|
||||
|
||||
#if os(iOS)
|
||||
import UIKit
|
||||
import UIKit
|
||||
#elseif os(OSX)
|
||||
import AppKit
|
||||
import AppKit
|
||||
#endif
|
||||
|
||||
open class Text: Node {
|
||||
@ -85,7 +85,7 @@ open class Text: Node {
|
||||
h: size.height.doubleValue
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
fileprivate func getWeight(_ weight: String) -> MFont.Weight {
|
||||
switch weight {
|
||||
case "normal":
|
||||
|
@ -9,80 +9,80 @@
|
||||
import Foundation
|
||||
|
||||
#if os(iOS)
|
||||
import UIKit
|
||||
import UIKit
|
||||
|
||||
public typealias MRectCorner = UIRectCorner
|
||||
public typealias MFont = UIFont
|
||||
public typealias MColor = UIColor
|
||||
public typealias MEvent = UIEvent
|
||||
public typealias MTouch = UITouch
|
||||
public typealias MImage = UIImage
|
||||
public typealias MBezierPath = UIBezierPath
|
||||
public typealias MGestureRecognizer = UIGestureRecognizer
|
||||
public typealias MGestureRecognizerState = UIGestureRecognizerState
|
||||
public typealias MGestureRecognizerDelegate = UIGestureRecognizerDelegate
|
||||
public typealias MTapGestureRecognizer = UITapGestureRecognizer
|
||||
public typealias MLongPressGestureRecognizer = UILongPressGestureRecognizer
|
||||
public typealias MPanGestureRecognizer = UIPanGestureRecognizer
|
||||
public typealias MPinchGestureRecognizer = UIPinchGestureRecognizer
|
||||
public typealias MRotationGestureRecognizer = UIRotationGestureRecognizer
|
||||
public typealias MScreen = UIScreen
|
||||
public typealias MViewContentMode = UIViewContentMode
|
||||
public typealias MRectCorner = UIRectCorner
|
||||
public typealias MFont = UIFont
|
||||
public typealias MColor = UIColor
|
||||
public typealias MEvent = UIEvent
|
||||
public typealias MTouch = UITouch
|
||||
public typealias MImage = UIImage
|
||||
public typealias MBezierPath = UIBezierPath
|
||||
public typealias MGestureRecognizer = UIGestureRecognizer
|
||||
public typealias MGestureRecognizerState = UIGestureRecognizerState
|
||||
public typealias MGestureRecognizerDelegate = UIGestureRecognizerDelegate
|
||||
public typealias MTapGestureRecognizer = UITapGestureRecognizer
|
||||
public typealias MLongPressGestureRecognizer = UILongPressGestureRecognizer
|
||||
public typealias MPanGestureRecognizer = UIPanGestureRecognizer
|
||||
public typealias MPinchGestureRecognizer = UIPinchGestureRecognizer
|
||||
public typealias MRotationGestureRecognizer = UIRotationGestureRecognizer
|
||||
public typealias MScreen = UIScreen
|
||||
public typealias MViewContentMode = UIViewContentMode
|
||||
|
||||
extension MTapGestureRecognizer {
|
||||
func mNumberOfTouches() -> Int {
|
||||
return numberOfTouches
|
||||
extension MTapGestureRecognizer {
|
||||
func mNumberOfTouches() -> Int {
|
||||
return numberOfTouches
|
||||
}
|
||||
}
|
||||
|
||||
extension MPanGestureRecognizer {
|
||||
func mNumberOfTouches() -> Int {
|
||||
return numberOfTouches
|
||||
}
|
||||
|
||||
func mLocationOfTouch(_ touch: Int, inView: UIView?) -> CGPoint {
|
||||
return super.location(ofTouch: touch, in: inView)
|
||||
}
|
||||
}
|
||||
|
||||
extension MRotationGestureRecognizer {
|
||||
final var mRotation: CGFloat {
|
||||
get {
|
||||
return rotation
|
||||
}
|
||||
|
||||
set {
|
||||
rotation = newValue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension MPinchGestureRecognizer {
|
||||
var mScale: CGFloat {
|
||||
get {
|
||||
return scale
|
||||
}
|
||||
|
||||
set {
|
||||
scale = newValue
|
||||
}
|
||||
}
|
||||
|
||||
extension MPanGestureRecognizer {
|
||||
func mNumberOfTouches() -> Int {
|
||||
return numberOfTouches
|
||||
}
|
||||
|
||||
func mLocationOfTouch(_ touch: Int, inView: UIView?) -> CGPoint {
|
||||
return super.location(ofTouch: touch, in: inView)
|
||||
}
|
||||
func mLocationOfTouch(_ touch: Int, inView: UIView?) -> CGPoint {
|
||||
return super.location(ofTouch: touch, in: inView)
|
||||
}
|
||||
}
|
||||
|
||||
extension MRotationGestureRecognizer {
|
||||
final var mRotation: CGFloat {
|
||||
get {
|
||||
return rotation
|
||||
}
|
||||
|
||||
set {
|
||||
rotation = newValue
|
||||
}
|
||||
}
|
||||
extension MFont {
|
||||
class var mSystemFontSize: CGFloat {
|
||||
return UIFont.systemFontSize
|
||||
}
|
||||
}
|
||||
|
||||
extension MPinchGestureRecognizer {
|
||||
var mScale: CGFloat {
|
||||
get {
|
||||
return scale
|
||||
}
|
||||
|
||||
set {
|
||||
scale = newValue
|
||||
}
|
||||
}
|
||||
|
||||
func mLocationOfTouch(_ touch: Int, inView: UIView?) -> CGPoint {
|
||||
return super.location(ofTouch: touch, in: inView)
|
||||
}
|
||||
}
|
||||
|
||||
extension MFont {
|
||||
class var mSystemFontSize: CGFloat {
|
||||
return UIFont.systemFontSize
|
||||
}
|
||||
}
|
||||
|
||||
extension UIScreen {
|
||||
var mScale: CGFloat {
|
||||
return self.scale
|
||||
}
|
||||
extension UIScreen {
|
||||
var mScale: CGFloat {
|
||||
return self.scale
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -9,42 +9,42 @@
|
||||
import Foundation
|
||||
|
||||
#if os(iOS)
|
||||
import UIKit
|
||||
import UIKit
|
||||
|
||||
func MGraphicsGetCurrentContext() -> CGContext? {
|
||||
return UIGraphicsGetCurrentContext()
|
||||
}
|
||||
func MGraphicsGetCurrentContext() -> CGContext? {
|
||||
return UIGraphicsGetCurrentContext()
|
||||
}
|
||||
|
||||
func MGraphicsGetImageFromCurrentImageContext() -> MImage! {
|
||||
return UIGraphicsGetImageFromCurrentImageContext()
|
||||
}
|
||||
func MGraphicsGetImageFromCurrentImageContext() -> MImage! {
|
||||
return UIGraphicsGetImageFromCurrentImageContext()
|
||||
}
|
||||
|
||||
func MGraphicsPushContext(_ context: CGContext) {
|
||||
UIGraphicsPushContext(context)
|
||||
}
|
||||
func MGraphicsPushContext(_ context: CGContext) {
|
||||
UIGraphicsPushContext(context)
|
||||
}
|
||||
|
||||
func MGraphicsPopContext() {
|
||||
UIGraphicsPopContext()
|
||||
}
|
||||
func MGraphicsPopContext() {
|
||||
UIGraphicsPopContext()
|
||||
}
|
||||
|
||||
func MGraphicsEndImageContext() {
|
||||
UIGraphicsEndImageContext()
|
||||
}
|
||||
func MGraphicsEndImageContext() {
|
||||
UIGraphicsEndImageContext()
|
||||
}
|
||||
|
||||
func MImagePNGRepresentation(_ image: MImage) -> Data? {
|
||||
return UIImagePNGRepresentation(image)
|
||||
}
|
||||
func MImagePNGRepresentation(_ image: MImage) -> Data? {
|
||||
return UIImagePNGRepresentation(image)
|
||||
}
|
||||
|
||||
func MImageJPEGRepresentation(_ image: MImage, _ quality: CGFloat = 0.8) -> Data? {
|
||||
return UIImageJPEGRepresentation(image, quality)
|
||||
}
|
||||
func MImageJPEGRepresentation(_ image: MImage, _ quality: CGFloat = 0.8) -> Data? {
|
||||
return UIImageJPEGRepresentation(image, quality)
|
||||
}
|
||||
|
||||
func MMainScreen() -> MScreen? {
|
||||
return MScreen.main
|
||||
}
|
||||
func MMainScreen() -> MScreen? {
|
||||
return MScreen.main
|
||||
}
|
||||
|
||||
func MGraphicsBeginImageContextWithOptions(_ size: CGSize, _ opaque: Bool, _ scale: CGFloat) {
|
||||
UIGraphicsBeginImageContextWithOptions(size, opaque, scale)
|
||||
}
|
||||
func MGraphicsBeginImageContextWithOptions(_ size: CGSize, _ opaque: Bool, _ scale: CGFloat) {
|
||||
UIGraphicsBeginImageContextWithOptions(size, opaque, scale)
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -7,33 +7,33 @@
|
||||
//
|
||||
|
||||
#if os(iOS)
|
||||
import UIKit
|
||||
import UIKit
|
||||
|
||||
class MDisplayLink: MDisplayLinkProtocol {
|
||||
private var displayLink: CADisplayLink?
|
||||
private var onUpdate: (() -> Void)?
|
||||
class MDisplayLink: MDisplayLinkProtocol {
|
||||
private var displayLink: CADisplayLink?
|
||||
private var onUpdate: (() -> Void)?
|
||||
|
||||
// MARK: - Lifecycle
|
||||
deinit {
|
||||
displayLink?.invalidate()
|
||||
}
|
||||
|
||||
// MARK: - MDisplayLinkProtocol
|
||||
func startUpdates(_ onUpdate: @escaping () -> Void) {
|
||||
self.onUpdate = onUpdate
|
||||
|
||||
displayLink = CADisplayLink(target: self, selector: #selector(updateHandler))
|
||||
displayLink?.frameInterval = 1
|
||||
displayLink?.add(to: RunLoop.current, forMode: RunLoopMode.defaultRunLoopMode)
|
||||
}
|
||||
|
||||
func invalidate() {
|
||||
displayLink?.invalidate()
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
@objc func updateHandler() {
|
||||
onUpdate?()
|
||||
}
|
||||
// MARK: - Lifecycle
|
||||
deinit {
|
||||
displayLink?.invalidate()
|
||||
}
|
||||
|
||||
// MARK: - MDisplayLinkProtocol
|
||||
func startUpdates(_ onUpdate: @escaping () -> Void) {
|
||||
self.onUpdate = onUpdate
|
||||
|
||||
displayLink = CADisplayLink(target: self, selector: #selector(updateHandler))
|
||||
displayLink?.frameInterval = 1
|
||||
displayLink?.add(to: RunLoop.current, forMode: RunLoopMode.defaultRunLoopMode)
|
||||
}
|
||||
|
||||
func invalidate() {
|
||||
displayLink?.invalidate()
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
@objc func updateHandler() {
|
||||
onUpdate?()
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -9,88 +9,88 @@
|
||||
import Foundation
|
||||
|
||||
#if os(iOS)
|
||||
import UIKit
|
||||
import UIKit
|
||||
|
||||
open class MView: UIView, Touchable {
|
||||
var mLayer: CALayer? {
|
||||
return self.layer
|
||||
}
|
||||
|
||||
var mGestureRecognizers: [MGestureRecognizer]? {
|
||||
return self.gestureRecognizers
|
||||
}
|
||||
|
||||
func removeGestureRecognizers() {
|
||||
self.gestureRecognizers?.removeAll()
|
||||
}
|
||||
|
||||
open override func touchesBegan(_ touches: Set<MTouch>, with event: MEvent?) {
|
||||
super.touchesBegan(touches, with: event)
|
||||
|
||||
let touchPoints = 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)
|
||||
}
|
||||
|
||||
mTouchesBegan(touchPoints)
|
||||
}
|
||||
|
||||
open override func touchesMoved(_ touches: Set<MTouch>, with event: MEvent?) {
|
||||
super.touchesMoved(touches, with: event)
|
||||
|
||||
let touchPoints = 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)
|
||||
}
|
||||
|
||||
self.mTouchesMoved(touchPoints)
|
||||
}
|
||||
|
||||
open override func touchesEnded(_ touches: Set<MTouch>, with event: MEvent?) {
|
||||
super.touchesEnded(touches, with: event)
|
||||
|
||||
let touchPoints = 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)
|
||||
}
|
||||
|
||||
mTouchesEnded(touchPoints)
|
||||
}
|
||||
|
||||
override open func touchesCancelled(_ touches: Set<MTouch>, with event: MEvent?) {
|
||||
super.touchesCancelled(touches, with: event)
|
||||
|
||||
let touchPoints = 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)
|
||||
}
|
||||
|
||||
mTouchesCancelled(touchPoints)
|
||||
}
|
||||
|
||||
func mTouchesBegan(_ touches: [MTouchEvent]) {
|
||||
|
||||
}
|
||||
|
||||
func mTouchesMoved(_ touches: [MTouchEvent]) {
|
||||
|
||||
}
|
||||
|
||||
func mTouchesEnded(_ touches: [MTouchEvent]) {
|
||||
|
||||
}
|
||||
|
||||
func mTouchesCancelled(_ touches: [MTouchEvent]) {
|
||||
|
||||
}
|
||||
open class MView: UIView, Touchable {
|
||||
var mLayer: CALayer? {
|
||||
return self.layer
|
||||
}
|
||||
|
||||
var mGestureRecognizers: [MGestureRecognizer]? {
|
||||
return self.gestureRecognizers
|
||||
}
|
||||
|
||||
func removeGestureRecognizers() {
|
||||
self.gestureRecognizers?.removeAll()
|
||||
}
|
||||
|
||||
open override func touchesBegan(_ touches: Set<MTouch>, with event: MEvent?) {
|
||||
super.touchesBegan(touches, with: event)
|
||||
|
||||
let touchPoints = 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)
|
||||
}
|
||||
|
||||
mTouchesBegan(touchPoints)
|
||||
}
|
||||
|
||||
open override func touchesMoved(_ touches: Set<MTouch>, with event: MEvent?) {
|
||||
super.touchesMoved(touches, with: event)
|
||||
|
||||
let touchPoints = 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)
|
||||
}
|
||||
|
||||
self.mTouchesMoved(touchPoints)
|
||||
}
|
||||
|
||||
open override func touchesEnded(_ touches: Set<MTouch>, with event: MEvent?) {
|
||||
super.touchesEnded(touches, with: event)
|
||||
|
||||
let touchPoints = 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)
|
||||
}
|
||||
|
||||
mTouchesEnded(touchPoints)
|
||||
}
|
||||
|
||||
override open func touchesCancelled(_ touches: Set<MTouch>, with event: MEvent?) {
|
||||
super.touchesCancelled(touches, with: event)
|
||||
|
||||
let touchPoints = 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)
|
||||
}
|
||||
|
||||
mTouchesCancelled(touchPoints)
|
||||
}
|
||||
|
||||
func mTouchesBegan(_ touches: [MTouchEvent]) {
|
||||
|
||||
}
|
||||
|
||||
func mTouchesMoved(_ touches: [MTouchEvent]) {
|
||||
|
||||
}
|
||||
|
||||
func mTouchesEnded(_ touches: [MTouchEvent]) {
|
||||
|
||||
}
|
||||
|
||||
func mTouchesCancelled(_ touches: [MTouchEvent]) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -9,135 +9,135 @@
|
||||
import Foundation
|
||||
|
||||
#if os(OSX)
|
||||
import Cocoa
|
||||
import Quartz
|
||||
import Cocoa
|
||||
import Quartz
|
||||
|
||||
public typealias MFont = NSFont
|
||||
public typealias MColor = NSColor
|
||||
public typealias MEvent = NSEvent
|
||||
public typealias MTouch = NSTouch
|
||||
public typealias MImage = NSImage
|
||||
public typealias MBezierPath = NSBezierPath
|
||||
public typealias MGestureRecognizer = NSGestureRecognizer
|
||||
public typealias MGestureRecognizerState = NSGestureRecognizer.State
|
||||
public typealias MGestureRecognizerDelegate = NSGestureRecognizerDelegate
|
||||
public typealias MTapGestureRecognizer = NSClickGestureRecognizer
|
||||
public typealias MLongPressGestureRecognizer = NSPressGestureRecognizer
|
||||
public typealias MPanGestureRecognizer = NSPanGestureRecognizer
|
||||
public typealias MPinchGestureRecognizer = NSMagnificationGestureRecognizer
|
||||
public typealias MRotationGestureRecognizer = NSRotationGestureRecognizer
|
||||
public typealias MScreen = NSScreen
|
||||
public typealias MFont = NSFont
|
||||
public typealias MColor = NSColor
|
||||
public typealias MEvent = NSEvent
|
||||
public typealias MTouch = NSTouch
|
||||
public typealias MImage = NSImage
|
||||
public typealias MBezierPath = NSBezierPath
|
||||
public typealias MGestureRecognizer = NSGestureRecognizer
|
||||
public typealias MGestureRecognizerState = NSGestureRecognizer.State
|
||||
public typealias MGestureRecognizerDelegate = NSGestureRecognizerDelegate
|
||||
public typealias MTapGestureRecognizer = NSClickGestureRecognizer
|
||||
public typealias MLongPressGestureRecognizer = NSPressGestureRecognizer
|
||||
public typealias MPanGestureRecognizer = NSPanGestureRecognizer
|
||||
public typealias MPinchGestureRecognizer = NSMagnificationGestureRecognizer
|
||||
public typealias MRotationGestureRecognizer = NSRotationGestureRecognizer
|
||||
public typealias MScreen = NSScreen
|
||||
|
||||
extension MGestureRecognizer {
|
||||
var cancelsTouchesInView: Bool {
|
||||
get {
|
||||
return false
|
||||
} set { }
|
||||
extension MGestureRecognizer {
|
||||
var cancelsTouchesInView: Bool {
|
||||
get {
|
||||
return false
|
||||
} set { }
|
||||
}
|
||||
}
|
||||
|
||||
extension MTapGestureRecognizer {
|
||||
func mNumberOfTouches() -> Int {
|
||||
return 1
|
||||
}
|
||||
}
|
||||
|
||||
extension MPanGestureRecognizer {
|
||||
func mNumberOfTouches() -> Int {
|
||||
return 1
|
||||
}
|
||||
|
||||
func mLocationOfTouch(_ touch: Int, inView: NSView?) -> NSPoint {
|
||||
return super.location(in: inView)
|
||||
}
|
||||
}
|
||||
|
||||
extension MRotationGestureRecognizer {
|
||||
var velocity: CGFloat {
|
||||
return 0.1
|
||||
}
|
||||
|
||||
var mRotation: CGFloat {
|
||||
get {
|
||||
return -rotation
|
||||
}
|
||||
|
||||
set {
|
||||
rotation = -newValue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension MPinchGestureRecognizer {
|
||||
var mScale: CGFloat {
|
||||
get {
|
||||
return magnification + 1.0
|
||||
}
|
||||
|
||||
set {
|
||||
magnification = newValue - 1.0
|
||||
}
|
||||
}
|
||||
|
||||
extension MTapGestureRecognizer {
|
||||
func mNumberOfTouches() -> Int {
|
||||
return 1
|
||||
}
|
||||
func mLocationOfTouch(_ touch: Int, inView view: NSView?) -> NSPoint {
|
||||
return super.location(in: view)
|
||||
}
|
||||
}
|
||||
|
||||
extension NSFont {
|
||||
var lineHeight: CGFloat {
|
||||
return self.boundingRectForFont.size.height
|
||||
}
|
||||
|
||||
extension MPanGestureRecognizer {
|
||||
func mNumberOfTouches() -> Int {
|
||||
return 1
|
||||
}
|
||||
|
||||
func mLocationOfTouch(_ touch: Int, inView: NSView?) -> NSPoint {
|
||||
return super.location(in: inView)
|
||||
}
|
||||
class var mSystemFontSize: CGFloat {
|
||||
return NSFont.systemFontSize
|
||||
}
|
||||
}
|
||||
|
||||
extension MRotationGestureRecognizer {
|
||||
var velocity: CGFloat {
|
||||
return 0.1
|
||||
}
|
||||
|
||||
var mRotation: CGFloat {
|
||||
get {
|
||||
return -rotation
|
||||
}
|
||||
|
||||
set {
|
||||
rotation = -newValue
|
||||
}
|
||||
}
|
||||
extension NSScreen {
|
||||
var mScale: CGFloat {
|
||||
return self.backingScaleFactor
|
||||
}
|
||||
}
|
||||
|
||||
extension MPinchGestureRecognizer {
|
||||
var mScale: CGFloat {
|
||||
get {
|
||||
return magnification + 1.0
|
||||
}
|
||||
|
||||
set {
|
||||
magnification = newValue - 1.0
|
||||
}
|
||||
}
|
||||
|
||||
func mLocationOfTouch(_ touch: Int, inView view: NSView?) -> NSPoint {
|
||||
return super.location(in: view)
|
||||
}
|
||||
extension NSImage {
|
||||
var cgImage: CGImage? {
|
||||
return self.cgImage(forProposedRect: nil, context: nil, hints: nil)
|
||||
}
|
||||
}
|
||||
|
||||
extension NSFont {
|
||||
var lineHeight: CGFloat {
|
||||
return self.boundingRectForFont.size.height
|
||||
}
|
||||
extension NSTouch {
|
||||
func location(in view: NSView) -> NSPoint {
|
||||
let n = self.normalizedPosition
|
||||
let b = view.bounds
|
||||
return NSPoint(x: b.origin.x + b.size.width * n.x, y: b.origin.y + b.size.height * n.y)
|
||||
}
|
||||
}
|
||||
|
||||
class var mSystemFontSize: CGFloat {
|
||||
return NSFont.systemFontSize
|
||||
}
|
||||
extension NSString {
|
||||
@nonobjc
|
||||
func size(attributes attrs: [NSAttributedStringKey: Any]? = nil) -> NSSize {
|
||||
return size(withAttributes: attrs)
|
||||
}
|
||||
}
|
||||
|
||||
extension NSScreen {
|
||||
var mScale: CGFloat {
|
||||
return self.backingScaleFactor
|
||||
}
|
||||
}
|
||||
func MMainScreen() -> MScreen? {
|
||||
return MScreen.main
|
||||
}
|
||||
|
||||
extension NSImage {
|
||||
var cgImage: CGImage? {
|
||||
return self.cgImage(forProposedRect: nil, context: nil, hints: nil)
|
||||
}
|
||||
}
|
||||
extension MBezierPath {
|
||||
func apply(_ transform: CGAffineTransform) {
|
||||
let affineTransform = AffineTransform(
|
||||
m11: transform.a,
|
||||
m12: transform.b,
|
||||
m21: transform.c,
|
||||
m22: transform.d,
|
||||
tX: transform.tx,
|
||||
tY: transform.ty
|
||||
)
|
||||
|
||||
extension NSTouch {
|
||||
func location(in view: NSView) -> NSPoint {
|
||||
let n = self.normalizedPosition
|
||||
let b = view.bounds
|
||||
return NSPoint(x: b.origin.x + b.size.width * n.x, y: b.origin.y + b.size.height * n.y)
|
||||
}
|
||||
}
|
||||
|
||||
extension NSString {
|
||||
@nonobjc
|
||||
func size(attributes attrs: [NSAttributedStringKey: Any]? = nil) -> NSSize {
|
||||
return size(withAttributes: attrs)
|
||||
}
|
||||
}
|
||||
|
||||
func MMainScreen() -> MScreen? {
|
||||
return MScreen.main
|
||||
}
|
||||
|
||||
extension MBezierPath {
|
||||
func apply(_ transform: CGAffineTransform) {
|
||||
let affineTransform = AffineTransform(
|
||||
m11: transform.a,
|
||||
m12: transform.b,
|
||||
m21: transform.c,
|
||||
m22: transform.d,
|
||||
tX: transform.tx,
|
||||
tY: transform.ty
|
||||
)
|
||||
|
||||
self.transform(using: affineTransform)
|
||||
}
|
||||
self.transform(using: affineTransform)
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -9,87 +9,87 @@
|
||||
import Foundation
|
||||
|
||||
#if os(OSX)
|
||||
import AppKit
|
||||
import AppKit
|
||||
|
||||
private var imageContextStack: [CGFloat] = []
|
||||
private var imageContextStack: [CGFloat] = []
|
||||
|
||||
func MGraphicsGetCurrentContext() -> CGContext? {
|
||||
return NSGraphicsContext.current?.cgContext
|
||||
func MGraphicsGetCurrentContext() -> CGContext? {
|
||||
return NSGraphicsContext.current?.cgContext
|
||||
}
|
||||
|
||||
func MGraphicsPushContext(_ context: CGContext) {
|
||||
let cx = NSGraphicsContext(cgContext: context, flipped: true)
|
||||
NSGraphicsContext.saveGraphicsState()
|
||||
NSGraphicsContext.current = cx
|
||||
}
|
||||
|
||||
func MGraphicsPopContext() {
|
||||
NSGraphicsContext.restoreGraphicsState()
|
||||
}
|
||||
|
||||
func MImagePNGRepresentation(_ image: MImage) -> Data? {
|
||||
image.lockFocus()
|
||||
let rep = NSBitmapImageRep(focusedViewRect: NSRect(x: 0, y: 0, width: image.size.width, height: image.size.height))
|
||||
image.unlockFocus()
|
||||
|
||||
return rep?.representation(using: NSBitmapImageRep.FileType.png, properties: [:])
|
||||
}
|
||||
|
||||
func MImageJPEGRepresentation(_ image: MImage, _ quality: CGFloat = 0.9) -> Data? {
|
||||
image.lockFocus()
|
||||
let rep = NSBitmapImageRep(focusedViewRect: NSRect(x: 0, y: 0, width: image.size.width, height: image.size.height))
|
||||
image.unlockFocus()
|
||||
|
||||
return rep?.representation(using: NSBitmapImageRep.FileType.jpeg, properties: [NSBitmapImageRep.PropertyKey.compressionFactor: quality])
|
||||
}
|
||||
|
||||
func MGraphicsBeginImageContextWithOptions(_ size: CGSize, _ opaque: Bool, _ scale: CGFloat) {
|
||||
var scale = scale
|
||||
|
||||
if scale == 0.0 {
|
||||
scale = NSScreen.main?.backingScaleFactor ?? 1.0
|
||||
}
|
||||
|
||||
func MGraphicsPushContext(_ context: CGContext) {
|
||||
let cx = NSGraphicsContext(cgContext: context, flipped: true)
|
||||
NSGraphicsContext.saveGraphicsState()
|
||||
NSGraphicsContext.current = cx
|
||||
}
|
||||
let width = Int(size.width * scale)
|
||||
let height = Int(size.height * scale)
|
||||
|
||||
func MGraphicsPopContext() {
|
||||
NSGraphicsContext.restoreGraphicsState()
|
||||
}
|
||||
if width > 0 && height > 0 {
|
||||
imageContextStack.append(scale)
|
||||
|
||||
func MImagePNGRepresentation(_ image: MImage) -> Data? {
|
||||
image.lockFocus()
|
||||
let rep = NSBitmapImageRep(focusedViewRect: NSRect(x: 0, y: 0, width: image.size.width, height: image.size.height))
|
||||
image.unlockFocus()
|
||||
let colorSpace = CGColorSpaceCreateDeviceRGB()
|
||||
|
||||
return rep?.representation(using: NSBitmapImageRep.FileType.png, properties: [:])
|
||||
}
|
||||
|
||||
func MImageJPEGRepresentation(_ image: MImage, _ quality: CGFloat = 0.9) -> Data? {
|
||||
image.lockFocus()
|
||||
let rep = NSBitmapImageRep(focusedViewRect: NSRect(x: 0, y: 0, width: image.size.width, height: image.size.height))
|
||||
image.unlockFocus()
|
||||
|
||||
return rep?.representation(using: NSBitmapImageRep.FileType.jpeg, properties: [NSBitmapImageRep.PropertyKey.compressionFactor: quality])
|
||||
}
|
||||
|
||||
func MGraphicsBeginImageContextWithOptions(_ size: CGSize, _ opaque: Bool, _ scale: CGFloat) {
|
||||
var scale = scale
|
||||
|
||||
if scale == 0.0 {
|
||||
scale = NSScreen.main?.backingScaleFactor ?? 1.0
|
||||
guard let ctx = CGContext(data: nil, width: width, height: height, bitsPerComponent: 8, bytesPerRow: 4 * width, space: colorSpace, bitmapInfo: (opaque ? CGImageAlphaInfo.noneSkipFirst.rawValue : CGImageAlphaInfo.premultipliedFirst.rawValue)) else {
|
||||
return
|
||||
}
|
||||
|
||||
let width = Int(size.width * scale)
|
||||
let height = Int(size.height * scale)
|
||||
ctx.concatenate(CGAffineTransform(a: 1, b: 0, c: 0, d: -1, tx: 0, ty: CGFloat(height)))
|
||||
ctx.scaleBy(x: scale, y: scale)
|
||||
MGraphicsPushContext(ctx)
|
||||
}
|
||||
}
|
||||
|
||||
if width > 0 && height > 0 {
|
||||
imageContextStack.append(scale)
|
||||
func MGraphicsGetImageFromCurrentImageContext() -> MImage? {
|
||||
if !imageContextStack.isEmpty {
|
||||
guard let ctx = MGraphicsGetCurrentContext() else {
|
||||
return nil
|
||||
}
|
||||
|
||||
let colorSpace = CGColorSpaceCreateDeviceRGB()
|
||||
|
||||
guard let ctx = CGContext(data: nil, width: width, height: height, bitsPerComponent: 8, bytesPerRow: 4 * width, space: colorSpace, bitmapInfo: (opaque ? CGImageAlphaInfo.noneSkipFirst.rawValue : CGImageAlphaInfo.premultipliedFirst.rawValue)) else {
|
||||
return
|
||||
}
|
||||
|
||||
ctx.concatenate(CGAffineTransform(a: 1, b: 0, c: 0, d: -1, tx: 0, ty: CGFloat(height)))
|
||||
ctx.scaleBy(x: scale, y: scale)
|
||||
MGraphicsPushContext(ctx)
|
||||
let scale = imageContextStack.last!
|
||||
if let theCGImage = ctx.makeImage() {
|
||||
let size = CGSize(width: CGFloat(ctx.width) / scale, height: CGFloat(ctx.height) / scale)
|
||||
let image = NSImage(cgImage: theCGImage, size: size)
|
||||
return image
|
||||
}
|
||||
}
|
||||
|
||||
func MGraphicsGetImageFromCurrentImageContext() -> MImage? {
|
||||
if !imageContextStack.isEmpty {
|
||||
guard let ctx = MGraphicsGetCurrentContext() else {
|
||||
return nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
let scale = imageContextStack.last!
|
||||
if let theCGImage = ctx.makeImage() {
|
||||
let size = CGSize(width: CGFloat(ctx.width) / scale, height: CGFloat(ctx.height) / scale)
|
||||
let image = NSImage(cgImage: theCGImage, size: size)
|
||||
return image
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func MGraphicsEndImageContext() {
|
||||
if imageContextStack.last != nil {
|
||||
imageContextStack.removeLast()
|
||||
MGraphicsPopContext()
|
||||
}
|
||||
func MGraphicsEndImageContext() {
|
||||
if imageContextStack.last != nil {
|
||||
imageContextStack.removeLast()
|
||||
MGraphicsPopContext()
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -9,162 +9,162 @@
|
||||
import Foundation
|
||||
|
||||
#if os(OSX)
|
||||
import AppKit
|
||||
import AppKit
|
||||
|
||||
public struct MRectCorner: OptionSet {
|
||||
public let rawValue: UInt
|
||||
public struct MRectCorner: OptionSet {
|
||||
public let rawValue: UInt
|
||||
|
||||
public static let none = MRectCorner(rawValue: 0)
|
||||
public static let topLeft = MRectCorner(rawValue: 1 << 0)
|
||||
public static let topRight = MRectCorner(rawValue: 1 << 1)
|
||||
public static let bottomLeft = MRectCorner(rawValue: 1 << 2)
|
||||
public static let bottomRight = MRectCorner(rawValue: 1 << 3)
|
||||
public static var allCorners: MRectCorner {
|
||||
return [.topLeft, .topRight, .bottomLeft, .bottomRight]
|
||||
}
|
||||
|
||||
public init(rawValue: UInt) {
|
||||
self.rawValue = rawValue
|
||||
}
|
||||
public static let none = MRectCorner(rawValue: 0)
|
||||
public static let topLeft = MRectCorner(rawValue: 1 << 0)
|
||||
public static let topRight = MRectCorner(rawValue: 1 << 1)
|
||||
public static let bottomLeft = MRectCorner(rawValue: 1 << 2)
|
||||
public static let bottomRight = MRectCorner(rawValue: 1 << 3)
|
||||
public static var allCorners: MRectCorner {
|
||||
return [.topLeft, .topRight, .bottomLeft, .bottomRight]
|
||||
}
|
||||
|
||||
extension MBezierPath {
|
||||
|
||||
public var cgPath: CGPath {
|
||||
let path = CGMutablePath()
|
||||
var points = [CGPoint](repeating: .zero, count: 3)
|
||||
|
||||
for i in 0 ..< self.elementCount {
|
||||
let type = self.element(at: i, associatedPoints: &points)
|
||||
|
||||
switch type {
|
||||
case .moveToBezierPathElement:
|
||||
path.move(to: CGPoint(x: points[0].x, y: points[0].y))
|
||||
|
||||
case .lineToBezierPathElement:
|
||||
path.addLine(to: CGPoint(x: points[0].x, y: points[0].y))
|
||||
|
||||
case .curveToBezierPathElement:
|
||||
path.addCurve(
|
||||
to: CGPoint(x: points[2].x, y: points[2].y),
|
||||
control1: CGPoint(x: points[0].x, y: points[0].y),
|
||||
control2: CGPoint(x: points[1].x, y: points[1].y))
|
||||
|
||||
case .closePathBezierPathElement:
|
||||
path.closeSubpath()
|
||||
}
|
||||
}
|
||||
|
||||
return path
|
||||
}
|
||||
|
||||
public convenience init(arcCenter center: CGPoint, radius: CGFloat, startAngle: CGFloat, endAngle: CGFloat, clockwise: Bool) {
|
||||
self.init()
|
||||
self.addArc(withCenter: center, radius: radius, startAngle: startAngle, endAngle: endAngle, clockwise: clockwise)
|
||||
}
|
||||
|
||||
public convenience init(roundedRect rect: NSRect, byRoundingCorners corners: MRectCorner, cornerRadii: NSSize) {
|
||||
self.init()
|
||||
|
||||
let kappa: CGFloat = 1.0 - 0.552228474
|
||||
|
||||
let topLeft = rect.origin
|
||||
let topRight = NSPoint(x: rect.maxX, y: rect.minY)
|
||||
let bottomRight = NSPoint(x: rect.maxX, y: rect.maxY)
|
||||
let bottomLeft = NSPoint(x: rect.minX, y: rect.maxY)
|
||||
|
||||
if corners.contains(.topLeft) {
|
||||
move(to: CGPoint(x: topLeft.x + cornerRadii.width, y: topLeft.y))
|
||||
|
||||
} else {
|
||||
move(to: topLeft)
|
||||
}
|
||||
|
||||
if corners.contains(.topRight) {
|
||||
line(to: CGPoint(x: topRight.x - cornerRadii.width, y: topRight.y))
|
||||
|
||||
curve(to: CGPoint(x: topRight.x, y: topRight.y + cornerRadii.height),
|
||||
controlPoint1: CGPoint(x: topRight.x - cornerRadii.width * kappa, y: topRight.y),
|
||||
controlPoint2: CGPoint(x: topRight.x, y: topRight.y + cornerRadii.height * kappa))
|
||||
|
||||
} else {
|
||||
line(to: topRight)
|
||||
}
|
||||
|
||||
if corners.contains(.bottomRight) {
|
||||
line(to: CGPoint(x: bottomRight.x, y: bottomRight.y - cornerRadii.height))
|
||||
|
||||
curve(to: CGPoint(x: bottomRight.x - cornerRadii.width, y: bottomRight.y),
|
||||
controlPoint1: CGPoint(x: bottomRight.x, y: bottomRight.y - cornerRadii.height * kappa),
|
||||
controlPoint2: CGPoint(x: bottomRight.x - cornerRadii.width * kappa, y: bottomRight.y))
|
||||
|
||||
} else {
|
||||
line(to: bottomRight)
|
||||
}
|
||||
|
||||
if corners.contains(.bottomLeft) {
|
||||
line(to: CGPoint(x: bottomLeft.x + cornerRadii.width, y: bottomLeft.y))
|
||||
|
||||
curve(to: CGPoint(x: bottomLeft.x, y: bottomLeft.y - cornerRadii.height),
|
||||
controlPoint1: CGPoint(x: bottomLeft.x + cornerRadii.width * kappa, y: bottomLeft.y),
|
||||
controlPoint2: CGPoint(x: bottomLeft.x, y: bottomLeft.y - cornerRadii.height * kappa))
|
||||
|
||||
} else {
|
||||
line(to: bottomLeft)
|
||||
}
|
||||
|
||||
if corners.contains(.topLeft) {
|
||||
line(to: CGPoint(x: topLeft.x, y: topLeft.y + cornerRadii.height))
|
||||
|
||||
curve(to: CGPoint(x: topLeft.x + cornerRadii.width, y: topLeft.y),
|
||||
controlPoint1: CGPoint(x: topLeft.x, y: topLeft.y + cornerRadii.height * kappa),
|
||||
controlPoint2: CGPoint(x: topLeft.x + cornerRadii.width * kappa, y: topLeft.y))
|
||||
|
||||
} else {
|
||||
line(to: topLeft)
|
||||
}
|
||||
|
||||
close()
|
||||
}
|
||||
|
||||
func reversing() -> MBezierPath {
|
||||
return self.reversed
|
||||
}
|
||||
|
||||
func addLine(to: NSPoint) {
|
||||
self.line(to: to)
|
||||
}
|
||||
|
||||
func addCurve(to: NSPoint, controlPoint1: NSPoint, controlPoint2: NSPoint) {
|
||||
self.curve(to: to, controlPoint1: controlPoint1, controlPoint2: controlPoint2)
|
||||
}
|
||||
|
||||
func addQuadCurve(to: NSPoint, controlPoint: NSPoint) {
|
||||
let QP0 = self.currentPoint
|
||||
let CP3 = to
|
||||
|
||||
let CP1 = CGPoint(
|
||||
x: QP0.x + ((2.0 / 3.0) * (controlPoint.x - QP0.x)),
|
||||
y: QP0.y + ((2.0 / 3.0) * (controlPoint.y - QP0.y))
|
||||
)
|
||||
|
||||
let CP2 = CGPoint(
|
||||
x: to.x + (2.0 / 3.0) * (controlPoint.x - to.x),
|
||||
y: to.y + (2.0 / 3.0) * (controlPoint.y - to.y)
|
||||
)
|
||||
|
||||
self.addCurve(to: CP3, controlPoint1: CP1, controlPoint2: CP2)
|
||||
}
|
||||
|
||||
func addArc(withCenter: NSPoint, radius: CGFloat, startAngle: CGFloat, endAngle: CGFloat, clockwise: Bool) {
|
||||
let startAngleRadian = ((startAngle) * (180.0 / .pi))
|
||||
let endAngleRadian = ((endAngle) * (180.0 / .pi))
|
||||
self.appendArc(withCenter: withCenter, radius: radius, startAngle: startAngleRadian, endAngle: endAngleRadian, clockwise: !clockwise)
|
||||
}
|
||||
|
||||
func addPath(path: NSBezierPath!) {
|
||||
self.append(path)
|
||||
}
|
||||
public init(rawValue: UInt) {
|
||||
self.rawValue = rawValue
|
||||
}
|
||||
}
|
||||
|
||||
extension MBezierPath {
|
||||
|
||||
public var cgPath: CGPath {
|
||||
let path = CGMutablePath()
|
||||
var points = [CGPoint](repeating: .zero, count: 3)
|
||||
|
||||
for i in 0 ..< self.elementCount {
|
||||
let type = self.element(at: i, associatedPoints: &points)
|
||||
|
||||
switch type {
|
||||
case .moveToBezierPathElement:
|
||||
path.move(to: CGPoint(x: points[0].x, y: points[0].y))
|
||||
|
||||
case .lineToBezierPathElement:
|
||||
path.addLine(to: CGPoint(x: points[0].x, y: points[0].y))
|
||||
|
||||
case .curveToBezierPathElement:
|
||||
path.addCurve(
|
||||
to: CGPoint(x: points[2].x, y: points[2].y),
|
||||
control1: CGPoint(x: points[0].x, y: points[0].y),
|
||||
control2: CGPoint(x: points[1].x, y: points[1].y))
|
||||
|
||||
case .closePathBezierPathElement:
|
||||
path.closeSubpath()
|
||||
}
|
||||
}
|
||||
|
||||
return path
|
||||
}
|
||||
|
||||
public convenience init(arcCenter center: CGPoint, radius: CGFloat, startAngle: CGFloat, endAngle: CGFloat, clockwise: Bool) {
|
||||
self.init()
|
||||
self.addArc(withCenter: center, radius: radius, startAngle: startAngle, endAngle: endAngle, clockwise: clockwise)
|
||||
}
|
||||
|
||||
public convenience init(roundedRect rect: NSRect, byRoundingCorners corners: MRectCorner, cornerRadii: NSSize) {
|
||||
self.init()
|
||||
|
||||
let kappa: CGFloat = 1.0 - 0.552228474
|
||||
|
||||
let topLeft = rect.origin
|
||||
let topRight = NSPoint(x: rect.maxX, y: rect.minY)
|
||||
let bottomRight = NSPoint(x: rect.maxX, y: rect.maxY)
|
||||
let bottomLeft = NSPoint(x: rect.minX, y: rect.maxY)
|
||||
|
||||
if corners.contains(.topLeft) {
|
||||
move(to: CGPoint(x: topLeft.x + cornerRadii.width, y: topLeft.y))
|
||||
|
||||
} else {
|
||||
move(to: topLeft)
|
||||
}
|
||||
|
||||
if corners.contains(.topRight) {
|
||||
line(to: CGPoint(x: topRight.x - cornerRadii.width, y: topRight.y))
|
||||
|
||||
curve(to: CGPoint(x: topRight.x, y: topRight.y + cornerRadii.height),
|
||||
controlPoint1: CGPoint(x: topRight.x - cornerRadii.width * kappa, y: topRight.y),
|
||||
controlPoint2: CGPoint(x: topRight.x, y: topRight.y + cornerRadii.height * kappa))
|
||||
|
||||
} else {
|
||||
line(to: topRight)
|
||||
}
|
||||
|
||||
if corners.contains(.bottomRight) {
|
||||
line(to: CGPoint(x: bottomRight.x, y: bottomRight.y - cornerRadii.height))
|
||||
|
||||
curve(to: CGPoint(x: bottomRight.x - cornerRadii.width, y: bottomRight.y),
|
||||
controlPoint1: CGPoint(x: bottomRight.x, y: bottomRight.y - cornerRadii.height * kappa),
|
||||
controlPoint2: CGPoint(x: bottomRight.x - cornerRadii.width * kappa, y: bottomRight.y))
|
||||
|
||||
} else {
|
||||
line(to: bottomRight)
|
||||
}
|
||||
|
||||
if corners.contains(.bottomLeft) {
|
||||
line(to: CGPoint(x: bottomLeft.x + cornerRadii.width, y: bottomLeft.y))
|
||||
|
||||
curve(to: CGPoint(x: bottomLeft.x, y: bottomLeft.y - cornerRadii.height),
|
||||
controlPoint1: CGPoint(x: bottomLeft.x + cornerRadii.width * kappa, y: bottomLeft.y),
|
||||
controlPoint2: CGPoint(x: bottomLeft.x, y: bottomLeft.y - cornerRadii.height * kappa))
|
||||
|
||||
} else {
|
||||
line(to: bottomLeft)
|
||||
}
|
||||
|
||||
if corners.contains(.topLeft) {
|
||||
line(to: CGPoint(x: topLeft.x, y: topLeft.y + cornerRadii.height))
|
||||
|
||||
curve(to: CGPoint(x: topLeft.x + cornerRadii.width, y: topLeft.y),
|
||||
controlPoint1: CGPoint(x: topLeft.x, y: topLeft.y + cornerRadii.height * kappa),
|
||||
controlPoint2: CGPoint(x: topLeft.x + cornerRadii.width * kappa, y: topLeft.y))
|
||||
|
||||
} else {
|
||||
line(to: topLeft)
|
||||
}
|
||||
|
||||
close()
|
||||
}
|
||||
|
||||
func reversing() -> MBezierPath {
|
||||
return self.reversed
|
||||
}
|
||||
|
||||
func addLine(to: NSPoint) {
|
||||
self.line(to: to)
|
||||
}
|
||||
|
||||
func addCurve(to: NSPoint, controlPoint1: NSPoint, controlPoint2: NSPoint) {
|
||||
self.curve(to: to, controlPoint1: controlPoint1, controlPoint2: controlPoint2)
|
||||
}
|
||||
|
||||
func addQuadCurve(to: NSPoint, controlPoint: NSPoint) {
|
||||
let QP0 = self.currentPoint
|
||||
let CP3 = to
|
||||
|
||||
let CP1 = CGPoint(
|
||||
x: QP0.x + ((2.0 / 3.0) * (controlPoint.x - QP0.x)),
|
||||
y: QP0.y + ((2.0 / 3.0) * (controlPoint.y - QP0.y))
|
||||
)
|
||||
|
||||
let CP2 = CGPoint(
|
||||
x: to.x + (2.0 / 3.0) * (controlPoint.x - to.x),
|
||||
y: to.y + (2.0 / 3.0) * (controlPoint.y - to.y)
|
||||
)
|
||||
|
||||
self.addCurve(to: CP3, controlPoint1: CP1, controlPoint2: CP2)
|
||||
}
|
||||
|
||||
func addArc(withCenter: NSPoint, radius: CGFloat, startAngle: CGFloat, endAngle: CGFloat, clockwise: Bool) {
|
||||
let startAngleRadian = ((startAngle) * (180.0 / .pi))
|
||||
let endAngleRadian = ((endAngle) * (180.0 / .pi))
|
||||
self.appendArc(withCenter: withCenter, radius: radius, startAngle: startAngleRadian, endAngle: endAngleRadian, clockwise: !clockwise)
|
||||
}
|
||||
|
||||
func addPath(path: NSBezierPath!) {
|
||||
self.append(path)
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -9,47 +9,47 @@
|
||||
import Foundation
|
||||
|
||||
#if os(OSX)
|
||||
import AppKit
|
||||
import AppKit
|
||||
|
||||
public class MDisplayLink: MDisplayLinkProtocol {
|
||||
private var displayLink: CVDisplayLink?
|
||||
private var onUpdate: (() -> Void)?
|
||||
public class MDisplayLink: MDisplayLinkProtocol {
|
||||
private var displayLink: CVDisplayLink?
|
||||
private var onUpdate: (() -> Void)?
|
||||
|
||||
// MARK: - Lifecycle
|
||||
deinit {
|
||||
stop()
|
||||
// MARK: - Lifecycle
|
||||
deinit {
|
||||
stop()
|
||||
}
|
||||
|
||||
// MARK: - MDisplayLinkProtocol
|
||||
func startUpdates(_ onUpdate: @escaping () -> Void) {
|
||||
self.onUpdate = onUpdate
|
||||
|
||||
if CVDisplayLinkCreateWithActiveCGDisplays(&displayLink) != kCVReturnSuccess {
|
||||
return
|
||||
}
|
||||
|
||||
// MARK: - MDisplayLinkProtocol
|
||||
func startUpdates(_ onUpdate: @escaping () -> Void) {
|
||||
self.onUpdate = onUpdate
|
||||
CVDisplayLinkSetOutputCallback(displayLink!, { (_, _, _, _, _, userData) -> CVReturn in
|
||||
|
||||
if CVDisplayLinkCreateWithActiveCGDisplays(&displayLink) != kCVReturnSuccess {
|
||||
return
|
||||
}
|
||||
let `self` = unsafeBitCast(userData, to: MDisplayLink.self)
|
||||
`self`.onUpdate?()
|
||||
|
||||
CVDisplayLinkSetOutputCallback(displayLink!, { (_, _, _, _, _, userData) -> CVReturn in
|
||||
return kCVReturnSuccess
|
||||
}, Unmanaged.passUnretained(self).toOpaque())
|
||||
|
||||
let `self` = unsafeBitCast(userData, to: MDisplayLink.self)
|
||||
`self`.onUpdate?()
|
||||
|
||||
return kCVReturnSuccess
|
||||
}, Unmanaged.passUnretained(self).toOpaque())
|
||||
|
||||
if displayLink != nil {
|
||||
CVDisplayLinkStart(displayLink!)
|
||||
}
|
||||
}
|
||||
|
||||
func invalidate() {
|
||||
stop()
|
||||
}
|
||||
|
||||
private func stop() {
|
||||
if displayLink != nil {
|
||||
CVDisplayLinkStop(displayLink!)
|
||||
}
|
||||
if displayLink != nil {
|
||||
CVDisplayLinkStart(displayLink!)
|
||||
}
|
||||
}
|
||||
|
||||
func invalidate() {
|
||||
stop()
|
||||
}
|
||||
|
||||
private func stop() {
|
||||
if displayLink != nil {
|
||||
CVDisplayLinkStop(displayLink!)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -9,189 +9,189 @@
|
||||
import Foundation
|
||||
|
||||
#if os(OSX)
|
||||
import AppKit
|
||||
import AppKit
|
||||
|
||||
public enum MViewContentMode: Int {
|
||||
case scaleToFill = 0
|
||||
case scaleAspectFit = 1
|
||||
case scaleAspectFill = 2
|
||||
case redraw = 3
|
||||
case center = 4
|
||||
case top = 5
|
||||
case bottom = 6
|
||||
case left = 7
|
||||
case right = 8
|
||||
case topLeft = 9
|
||||
case topRight = 10
|
||||
case bottomLeft = 11
|
||||
case bottomRight = 12
|
||||
public enum MViewContentMode: Int {
|
||||
case scaleToFill = 0
|
||||
case scaleAspectFit = 1
|
||||
case scaleAspectFill = 2
|
||||
case redraw = 3
|
||||
case center = 4
|
||||
case top = 5
|
||||
case bottom = 6
|
||||
case left = 7
|
||||
case right = 8
|
||||
case topLeft = 9
|
||||
case topRight = 10
|
||||
case bottomLeft = 11
|
||||
case bottomRight = 12
|
||||
}
|
||||
|
||||
open class MView: NSView, Touchable {
|
||||
public override init(frame frameRect: NSRect) {
|
||||
super.init(frame: frameRect)
|
||||
|
||||
self.wantsLayer = true
|
||||
}
|
||||
|
||||
open class MView: NSView, Touchable {
|
||||
public override init(frame frameRect: NSRect) {
|
||||
super.init(frame: frameRect)
|
||||
public required init?(coder: NSCoder) {
|
||||
super.init(coder: coder)
|
||||
|
||||
self.wantsLayer = true
|
||||
self.wantsLayer = true
|
||||
setupMouse()
|
||||
}
|
||||
|
||||
open override var isFlipped: Bool {
|
||||
return true
|
||||
}
|
||||
|
||||
var mGestureRecognizers: [NSGestureRecognizer]? {
|
||||
return self.gestureRecognizers
|
||||
}
|
||||
|
||||
open var backgroundColor: MColor? {
|
||||
get {
|
||||
return self.layer?.backgroundColor == nil ? nil : NSColor(cgColor: self.layer!.backgroundColor!)
|
||||
}
|
||||
|
||||
public required init?(coder: NSCoder) {
|
||||
super.init(coder: coder)
|
||||
|
||||
self.wantsLayer = true
|
||||
setupMouse()
|
||||
}
|
||||
|
||||
open override var isFlipped: Bool {
|
||||
return true
|
||||
}
|
||||
|
||||
var mGestureRecognizers: [NSGestureRecognizer]? {
|
||||
return self.gestureRecognizers
|
||||
}
|
||||
|
||||
open var backgroundColor: MColor? {
|
||||
get {
|
||||
return self.layer?.backgroundColor == nil ? nil : NSColor(cgColor: self.layer!.backgroundColor!)
|
||||
}
|
||||
|
||||
set {
|
||||
self.layer?.backgroundColor = newValue == nil ? nil : newValue?.cgColor ?? MColor.black.cgColor
|
||||
}
|
||||
}
|
||||
|
||||
var mLayer: CALayer? {
|
||||
return self.layer
|
||||
}
|
||||
|
||||
var contentMode: MViewContentMode = .scaleToFill
|
||||
|
||||
func removeGestureRecognizers() {
|
||||
self.gestureRecognizers.removeAll()
|
||||
}
|
||||
|
||||
func didMoveToSuperview() {
|
||||
super.viewDidMoveToSuperview()
|
||||
}
|
||||
|
||||
func setNeedsDisplay() {
|
||||
self.setNeedsDisplay(self.bounds)
|
||||
}
|
||||
|
||||
func layoutSubviews() {
|
||||
super.resizeSubviews(withOldSize: self.bounds.size)
|
||||
}
|
||||
|
||||
// MARK: - Touch pad
|
||||
open override func touchesBegan(with event: NSEvent) {
|
||||
super.touchesBegan(with: event)
|
||||
|
||||
let touchPoints = event.touches(matching: .any, in: self).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)
|
||||
}
|
||||
|
||||
mTouchesBegan(touchPoints)
|
||||
}
|
||||
|
||||
open override func touchesEnded(with event: NSEvent) {
|
||||
super.touchesEnded(with: event)
|
||||
|
||||
let touchPoints = event.touches(matching: .any, in: self).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)
|
||||
}
|
||||
|
||||
mTouchesEnded(touchPoints)
|
||||
}
|
||||
|
||||
open override func touchesMoved(with event: NSEvent) {
|
||||
super.touchesMoved(with: event)
|
||||
|
||||
let touchPoints = event.touches(matching: .any, in: self).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)
|
||||
}
|
||||
|
||||
mTouchesMoved(touchPoints)
|
||||
}
|
||||
|
||||
open override func touchesCancelled(with event: NSEvent) {
|
||||
super.touchesCancelled(with: event)
|
||||
|
||||
let touchPoints = event.touches(matching: .any, in: self).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)
|
||||
}
|
||||
|
||||
mTouchesCancelled(touchPoints)
|
||||
}
|
||||
|
||||
// MARK: - Mouse
|
||||
private func setupMouse() {
|
||||
subscribeForMouseDown()
|
||||
subscribeForMouseUp()
|
||||
subscribeForMouseDragged()
|
||||
}
|
||||
|
||||
private func subscribeForMouseDown() {
|
||||
NSEvent.addLocalMonitorForEvents(matching: .leftMouseDown) { [weak self] event -> NSEvent? in
|
||||
self?.handleInput(event: event) { touches in
|
||||
self?.mTouchesBegan(touches)
|
||||
}
|
||||
return event
|
||||
}
|
||||
}
|
||||
|
||||
private func subscribeForMouseUp() {
|
||||
NSEvent.addLocalMonitorForEvents(matching: .leftMouseUp) { [weak self] event -> NSEvent? in
|
||||
self?.handleInput(event: event) { touches in
|
||||
self?.mTouchesEnded(touches)
|
||||
}
|
||||
return event
|
||||
}
|
||||
}
|
||||
|
||||
private func subscribeForMouseDragged() {
|
||||
NSEvent.addLocalMonitorForEvents(matching: .leftMouseDragged) { [weak self] event -> NSEvent? in
|
||||
self?.handleInput(event: event) { touches in
|
||||
self?.mTouchesMoved(touches)
|
||||
}
|
||||
return event
|
||||
}
|
||||
}
|
||||
|
||||
private func handleInput(event: NSEvent, handler: (_ touches: [MTouchEvent]) -> Void ) {
|
||||
let location = self.convert(event.locationInWindow, to: .none)
|
||||
let touchPoint = MTouchEvent(x: Double(location.x), y: Double(location.y), id: 0)
|
||||
|
||||
handler([touchPoint])
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// MARK: - Touchable
|
||||
func mTouchesBegan(_ touches: [MTouchEvent]) {
|
||||
|
||||
}
|
||||
|
||||
func mTouchesMoved(_ touches: [MTouchEvent]) {
|
||||
|
||||
}
|
||||
|
||||
func mTouchesEnded(_ touches: [MTouchEvent]) {
|
||||
|
||||
}
|
||||
|
||||
func mTouchesCancelled(_ touches: [MTouchEvent]) {
|
||||
|
||||
set {
|
||||
self.layer?.backgroundColor = newValue == nil ? nil : newValue?.cgColor ?? MColor.black.cgColor
|
||||
}
|
||||
}
|
||||
|
||||
var mLayer: CALayer? {
|
||||
return self.layer
|
||||
}
|
||||
|
||||
var contentMode: MViewContentMode = .scaleToFill
|
||||
|
||||
func removeGestureRecognizers() {
|
||||
self.gestureRecognizers.removeAll()
|
||||
}
|
||||
|
||||
func didMoveToSuperview() {
|
||||
super.viewDidMoveToSuperview()
|
||||
}
|
||||
|
||||
func setNeedsDisplay() {
|
||||
self.setNeedsDisplay(self.bounds)
|
||||
}
|
||||
|
||||
func layoutSubviews() {
|
||||
super.resizeSubviews(withOldSize: self.bounds.size)
|
||||
}
|
||||
|
||||
// MARK: - Touch pad
|
||||
open override func touchesBegan(with event: NSEvent) {
|
||||
super.touchesBegan(with: event)
|
||||
|
||||
let touchPoints = event.touches(matching: .any, in: self).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)
|
||||
}
|
||||
|
||||
mTouchesBegan(touchPoints)
|
||||
}
|
||||
|
||||
open override func touchesEnded(with event: NSEvent) {
|
||||
super.touchesEnded(with: event)
|
||||
|
||||
let touchPoints = event.touches(matching: .any, in: self).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)
|
||||
}
|
||||
|
||||
mTouchesEnded(touchPoints)
|
||||
}
|
||||
|
||||
open override func touchesMoved(with event: NSEvent) {
|
||||
super.touchesMoved(with: event)
|
||||
|
||||
let touchPoints = event.touches(matching: .any, in: self).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)
|
||||
}
|
||||
|
||||
mTouchesMoved(touchPoints)
|
||||
}
|
||||
|
||||
open override func touchesCancelled(with event: NSEvent) {
|
||||
super.touchesCancelled(with: event)
|
||||
|
||||
let touchPoints = event.touches(matching: .any, in: self).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)
|
||||
}
|
||||
|
||||
mTouchesCancelled(touchPoints)
|
||||
}
|
||||
|
||||
// MARK: - Mouse
|
||||
private func setupMouse() {
|
||||
subscribeForMouseDown()
|
||||
subscribeForMouseUp()
|
||||
subscribeForMouseDragged()
|
||||
}
|
||||
|
||||
private func subscribeForMouseDown() {
|
||||
NSEvent.addLocalMonitorForEvents(matching: .leftMouseDown) { [weak self] event -> NSEvent? in
|
||||
self?.handleInput(event: event) { touches in
|
||||
self?.mTouchesBegan(touches)
|
||||
}
|
||||
return event
|
||||
}
|
||||
}
|
||||
|
||||
private func subscribeForMouseUp() {
|
||||
NSEvent.addLocalMonitorForEvents(matching: .leftMouseUp) { [weak self] event -> NSEvent? in
|
||||
self?.handleInput(event: event) { touches in
|
||||
self?.mTouchesEnded(touches)
|
||||
}
|
||||
return event
|
||||
}
|
||||
}
|
||||
|
||||
private func subscribeForMouseDragged() {
|
||||
NSEvent.addLocalMonitorForEvents(matching: .leftMouseDragged) { [weak self] event -> NSEvent? in
|
||||
self?.handleInput(event: event) { touches in
|
||||
self?.mTouchesMoved(touches)
|
||||
}
|
||||
return event
|
||||
}
|
||||
}
|
||||
|
||||
private func handleInput(event: NSEvent, handler: (_ touches: [MTouchEvent]) -> Void ) {
|
||||
let location = self.convert(event.locationInWindow, to: .none)
|
||||
let touchPoint = MTouchEvent(x: Double(location.x), y: Double(location.y), id: 0)
|
||||
|
||||
handler([touchPoint])
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// MARK: - Touchable
|
||||
func mTouchesBegan(_ touches: [MTouchEvent]) {
|
||||
|
||||
}
|
||||
|
||||
func mTouchesMoved(_ touches: [MTouchEvent]) {
|
||||
|
||||
}
|
||||
|
||||
func mTouchesEnded(_ touches: [MTouchEvent]) {
|
||||
|
||||
}
|
||||
|
||||
func mTouchesCancelled(_ touches: [MTouchEvent]) {
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -1,7 +1,7 @@
|
||||
import Foundation
|
||||
|
||||
#if os(iOS)
|
||||
import UIKit
|
||||
import UIKit
|
||||
#endif
|
||||
|
||||
class GroupRenderer: NodeRenderer {
|
||||
|
@ -1,11 +1,11 @@
|
||||
import Foundation
|
||||
|
||||
#if os(OSX)
|
||||
import AppKit
|
||||
import AppKit
|
||||
#endif
|
||||
|
||||
#if os(iOS)
|
||||
import UIKit
|
||||
import UIKit
|
||||
#endif
|
||||
|
||||
class ImageRenderer: NodeRenderer {
|
||||
@ -65,9 +65,9 @@ class ImageRenderer: NodeRenderer {
|
||||
}
|
||||
|
||||
#if os(iOS)
|
||||
let osImage = MImage(named: image.src)
|
||||
let osImage = MImage(named: image.src)
|
||||
#elseif os(OSX)
|
||||
let osImage = MImage(named: NSImage.Name(rawValue: image.src))
|
||||
let osImage = MImage(named: NSImage.Name(rawValue: image.src))
|
||||
#endif
|
||||
|
||||
if let mImage = osImage {
|
||||
|
@ -1,7 +1,7 @@
|
||||
import Foundation
|
||||
|
||||
#if os(iOS)
|
||||
import UIKit
|
||||
import UIKit
|
||||
#endif
|
||||
|
||||
struct RenderingInterval {
|
||||
|
@ -1,7 +1,7 @@
|
||||
import Foundation
|
||||
|
||||
#if os(iOS)
|
||||
import UIKit
|
||||
import UIKit
|
||||
#endif
|
||||
|
||||
class RenderContext {
|
||||
|
@ -1,9 +1,9 @@
|
||||
import Foundation
|
||||
|
||||
#if os(iOS)
|
||||
import UIKit
|
||||
import UIKit
|
||||
#elseif os(OSX)
|
||||
import AppKit
|
||||
import AppKit
|
||||
#endif
|
||||
|
||||
class RenderUtils {
|
||||
@ -316,14 +316,14 @@ class RenderUtils {
|
||||
Q(x1 + dx, y1: y1 + dy, x: x + dx, y: y + dy)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func Q(_ x1: Double, y1: Double, x: Double, y: Double) {
|
||||
let endPoint = CGPoint(x: x, y: y)
|
||||
let controlPoint = CGPoint(x: x1, y: y1)
|
||||
bezierPath.addQuadCurve(to: endPoint, controlPoint: controlPoint)
|
||||
setQuadrPoint(endPoint, quadr: controlPoint)
|
||||
}
|
||||
|
||||
|
||||
func t(_ x: Double, y: Double) {
|
||||
if let cur = currentPoint {
|
||||
let next = CGPoint(x: CGFloat(x) + cur.x, y: CGFloat(y) + cur.y)
|
||||
@ -337,7 +337,7 @@ class RenderUtils {
|
||||
setQuadrPoint(next, quadr: quadr!)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func T(_ x: Double, y: Double) {
|
||||
if let cur = currentPoint {
|
||||
let next = CGPoint(x: CGFloat(x), y: CGFloat(y))
|
||||
@ -367,20 +367,20 @@ class RenderUtils {
|
||||
|
||||
// find arc center coordinates and points angles as per
|
||||
// http://www.w3.org/TR/SVG/implnote.html#ArcConversionEndpointToCenter
|
||||
if (_rx == 0 || _ry == 0) {
|
||||
if _rx == 0 || _ry == 0 {
|
||||
L(x, y: y)
|
||||
} else {
|
||||
var rx = abs(_rx)
|
||||
var ry = abs(_ry)
|
||||
let x1_ = cos(angle) * (x1 - x) / 2 + sin(angle) * (y1 - y) / 2
|
||||
let y1_ = -1 * sin(angle) * (x1 - x) / 2 + cos(angle) * (y1 - y) / 2
|
||||
|
||||
|
||||
let rCheck = (x1_ * x1_) / (rx * rx) + (y1_ * y1_) / (ry * ry)
|
||||
if (rCheck > 1) {
|
||||
if rCheck > 1 {
|
||||
rx = sqrt(rCheck) * rx
|
||||
ry = sqrt(rCheck) * ry
|
||||
}
|
||||
|
||||
|
||||
// make sure the value under the root is positive
|
||||
let underroot = (rx * rx * ry * ry - rx * rx * y1_ * y1_ - ry * ry * x1_ * x1_)
|
||||
/ (rx * rx * y1_ * y1_ + ry * ry * x1_ * x1_)
|
||||
@ -391,18 +391,18 @@ class RenderUtils {
|
||||
let cy_ = -1 * coef * bigRoot * ry * x1_ / rx
|
||||
let cx = cos(angle) * cx_ - sin(angle) * cy_ + (x1 + x) / 2
|
||||
let cy = sin(angle) * cx_ + cos(angle) * cy_ + (y1 + y) / 2
|
||||
|
||||
|
||||
let t1 = calcAngle(ux: 1, uy: 0, vx: (x1_ - cx_) / rx, vy: (y1_ - cy_) / ry)
|
||||
var delta = calcAngle(ux: (x1_ - cx_) / rx, uy: (y1_ - cy_) / ry, vx: (-x1_ - cx_) / rx, vy: (-y1_ - cy_) / ry)
|
||||
let pi2 = Double.pi * 2
|
||||
if (delta > 0) {
|
||||
if delta > 0 {
|
||||
delta = delta.truncatingRemainder(dividingBy: pi2)
|
||||
if (!sweep) {
|
||||
if !sweep {
|
||||
delta -= pi2
|
||||
}
|
||||
} else if (delta < 0) {
|
||||
} else if delta < 0 {
|
||||
delta = -1 * ((-1 * delta).truncatingRemainder(dividingBy: pi2))
|
||||
if (sweep) {
|
||||
if sweep {
|
||||
delta += pi2
|
||||
}
|
||||
}
|
||||
@ -417,20 +417,20 @@ class RenderUtils {
|
||||
let end = extent + CGFloat(arcAngle)
|
||||
let cx = CGFloat(x + w / 2)
|
||||
let cy = CGFloat(y + h / 2)
|
||||
if (w == h && rotation == 0) {
|
||||
if w == h && rotation == 0 {
|
||||
bezierPath.addArc(withCenter: CGPoint(x: cx, y: cy), radius: CGFloat(w / 2), startAngle: extent, endAngle: end, clockwise: arcAngle >= 0)
|
||||
} else {
|
||||
let maxSize = CGFloat(max(w, h))
|
||||
let path = MBezierPath(arcCenter: CGPoint.zero, radius: maxSize / 2, startAngle: extent, endAngle: end, clockwise: arcAngle >= 0)
|
||||
|
||||
#if os(iOS)
|
||||
var transform = CGAffineTransform(translationX: cx, y: cy)
|
||||
transform = transform.rotated(by: CGFloat(rotation))
|
||||
path.apply(transform.scaledBy(x: CGFloat(w) / maxSize, y: CGFloat(h) / maxSize))
|
||||
var transform = CGAffineTransform(translationX: cx, y: cy)
|
||||
transform = transform.rotated(by: CGFloat(rotation))
|
||||
path.apply(transform.scaledBy(x: CGFloat(w) / maxSize, y: CGFloat(h) / maxSize))
|
||||
#elseif os(OSX)
|
||||
var transform = AffineTransform(translationByX: cx, byY: cy)
|
||||
transform.rotate(byDegrees: CGFloat(rotation))
|
||||
path.transform(using: transform)
|
||||
var transform = AffineTransform(translationByX: cx, byY: cy)
|
||||
transform.rotate(byDegrees: CGFloat(rotation))
|
||||
path.transform(using: transform)
|
||||
#endif
|
||||
|
||||
bezierPath.append(path)
|
||||
@ -552,7 +552,7 @@ class RenderUtils {
|
||||
}
|
||||
return bezierPath
|
||||
}
|
||||
|
||||
|
||||
class func calcAngle(ux: Double, uy: Double, vx: Double, vy: Double) -> Double {
|
||||
let sign = copysign(1, ux * vy - uy * vx)
|
||||
let value = (ux * vx + uy * vy) / (sqrt(ux * ux + uy * uy) * sqrt(vx * vx + vy * vy))
|
||||
|
@ -1,9 +1,9 @@
|
||||
import Foundation
|
||||
|
||||
#if os(iOS)
|
||||
import UIKit
|
||||
import UIKit
|
||||
#elseif os(OSX)
|
||||
import AppKit
|
||||
import AppKit
|
||||
#endif
|
||||
|
||||
class ShapeRenderer: NodeRenderer {
|
||||
@ -36,7 +36,7 @@ class ShapeRenderer: NodeRenderer {
|
||||
return
|
||||
}
|
||||
|
||||
if (shape.fill != nil || shape.stroke != nil) {
|
||||
if shape.fill != nil || shape.stroke != nil {
|
||||
setGeometry(shape.form, ctx: ctx.cgContext!)
|
||||
drawPath(shape.fill, stroke: shape.stroke, ctx: ctx.cgContext!, opacity: opacity)
|
||||
}
|
||||
|
@ -1,9 +1,9 @@
|
||||
import Foundation
|
||||
|
||||
#if os(iOS)
|
||||
import UIKit
|
||||
import UIKit
|
||||
#elseif os(OSX)
|
||||
import AppKit
|
||||
import AppKit
|
||||
#endif
|
||||
|
||||
class TextRenderer: NodeRenderer {
|
||||
@ -97,7 +97,7 @@ class TextRenderer: NodeRenderer {
|
||||
guard #available(iOS 9.0, macOS 10.11, *) else {
|
||||
// This case should never happen, since the deployment target is set to iOS 9.0/macOS 10.11.
|
||||
// However it is needed for the Swift Package Manager to work accordingly.
|
||||
return .none
|
||||
return .none
|
||||
}
|
||||
switch weight {
|
||||
case "normal":
|
||||
@ -152,9 +152,9 @@ class TextRenderer: NodeRenderer {
|
||||
if let color = fill as? Color {
|
||||
|
||||
#if os(iOS)
|
||||
return MColor(cgColor: RenderUtils.mapColor(color))
|
||||
return MColor(cgColor: RenderUtils.mapColor(color))
|
||||
#elseif os(OSX)
|
||||
return MColor(cgColor: RenderUtils.mapColor(color)) ?? .black
|
||||
return MColor(cgColor: RenderUtils.mapColor(color)) ?? .black
|
||||
#endif
|
||||
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ import Foundation
|
||||
import CoreGraphics
|
||||
|
||||
#if !CARTHAGE
|
||||
import SWXMLHash
|
||||
import SWXMLHash
|
||||
#endif
|
||||
|
||||
///
|
||||
@ -101,7 +101,7 @@ open class SVGParser {
|
||||
prepareSvg(child)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fileprivate func prepareSvg(_ node: XMLIndexer) {
|
||||
if let element = node.element {
|
||||
if (element.name == "defs") {
|
||||
@ -318,7 +318,7 @@ open class SVGParser {
|
||||
return .none
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fileprivate func parseGroup(_ group: XMLIndexer, groupStyle: [String: String] = [:]) -> Group? {
|
||||
guard let element = group.element else {
|
||||
return .none
|
||||
@ -1060,11 +1060,11 @@ open class SVGParser {
|
||||
if let gradientTransform = element.allAttributes["gradientTransform"]?.text {
|
||||
let transform = parseTransformationAttribute(gradientTransform)
|
||||
let cgTransform = RenderUtils.mapTransform(transform)
|
||||
|
||||
|
||||
let point1 = CGPoint(x: x1, y: y1).applying(cgTransform)
|
||||
x1 = point1.x.doubleValue
|
||||
y1 = point1.y.doubleValue
|
||||
|
||||
|
||||
let point2 = CGPoint(x: x2, y: y2).applying(cgTransform)
|
||||
x2 = point2.x.doubleValue
|
||||
y2 = point2.y.doubleValue
|
||||
@ -1122,11 +1122,11 @@ open class SVGParser {
|
||||
if let gradientTransform = element.allAttributes["gradientTransform"]?.text {
|
||||
let transform = parseTransformationAttribute(gradientTransform)
|
||||
let cgTransform = RenderUtils.mapTransform(transform)
|
||||
|
||||
|
||||
let point1 = CGPoint(x: cx, y: cy).applying(cgTransform)
|
||||
cx = point1.x.doubleValue
|
||||
cy = point1.y.doubleValue
|
||||
|
||||
|
||||
let point2 = CGPoint(x: fx, y: fy).applying(cgTransform)
|
||||
fx = point2.x.doubleValue
|
||||
fy = point2.y.doubleValue
|
||||
@ -1316,7 +1316,7 @@ open class SVGParser {
|
||||
}
|
||||
|
||||
private class PathDataReader {
|
||||
|
||||
|
||||
private let input: String
|
||||
private var current: UnicodeScalar?
|
||||
private var previous: UnicodeScalar?
|
||||
@ -1326,9 +1326,9 @@ private class PathDataReader {
|
||||
self.input = input
|
||||
self.iterator = input.unicodeScalars.makeIterator()
|
||||
}
|
||||
|
||||
|
||||
public func read() -> [PathSegment] {
|
||||
let _ = readNext()
|
||||
_ = readNext()
|
||||
var segments = [PathSegment]()
|
||||
while let array = readSegments() {
|
||||
segments.append(contentsOf: array)
|
||||
@ -1416,11 +1416,11 @@ private class PathDataReader {
|
||||
current = iterator.next()
|
||||
return current
|
||||
}
|
||||
|
||||
|
||||
private func readSegmentType() -> PathSegmentType? {
|
||||
while(true) {
|
||||
if let type = getPathSegmentType() {
|
||||
let _ = readNext()
|
||||
_ = readNext()
|
||||
return type
|
||||
}
|
||||
if (readNext() == nil) {
|
||||
@ -1428,7 +1428,7 @@ private class PathDataReader {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fileprivate func getPathSegmentType() -> PathSegmentType? {
|
||||
if let ch = current {
|
||||
switch(ch) {
|
||||
@ -1456,7 +1456,7 @@ private class PathDataReader {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
fileprivate func getArgCount(segment: PathSegmentType) -> Int {
|
||||
switch(segment) {
|
||||
case .H, .h, .V, .v: return 1
|
||||
|
@ -1,9 +1,9 @@
|
||||
import Foundation
|
||||
|
||||
#if os(iOS)
|
||||
import UIKit
|
||||
import UIKit
|
||||
#elseif os(OSX)
|
||||
import AppKit
|
||||
import AppKit
|
||||
#endif
|
||||
|
||||
open class SVGView: MacawView {
|
||||
|
2
Source/thirdparty/CGFloat+Double.swift
vendored
2
Source/thirdparty/CGFloat+Double.swift
vendored
@ -1,7 +1,7 @@
|
||||
import Foundation
|
||||
|
||||
#if os(iOS)
|
||||
import UIKit
|
||||
import UIKit
|
||||
#endif
|
||||
|
||||
internal extension CGFloat {
|
||||
|
@ -9,7 +9,7 @@
|
||||
import Foundation
|
||||
|
||||
#if os(iOS)
|
||||
import UIKit
|
||||
import UIKit
|
||||
#endif
|
||||
|
||||
var imagesMap = [String: MImage]()
|
||||
|
@ -1,9 +1,9 @@
|
||||
import Foundation
|
||||
|
||||
#if os(iOS)
|
||||
import UIKit
|
||||
import UIKit
|
||||
#elseif os(OSX)
|
||||
import AppKit
|
||||
import AppKit
|
||||
#endif
|
||||
///
|
||||
/// MacawView is a main class used to embed Macaw scene into your Cocoa UI.
|
||||
@ -168,7 +168,7 @@ open class MacawView: MView, MGestureRecognizerDelegate {
|
||||
}
|
||||
MGraphicsEndImageContext()
|
||||
}
|
||||
|
||||
|
||||
public final func findNodeAt(location: CGPoint) -> Node? {
|
||||
guard let ctx = context.cgContext else { return .none }
|
||||
return renderer?.findNodeAt(location: location, ctx: ctx)
|
||||
@ -331,34 +331,34 @@ open class MacawView: MView, MGestureRecognizerDelegate {
|
||||
}
|
||||
|
||||
// MARK: - Tap
|
||||
|
||||
|
||||
@objc func handleLongTap(recognizer: MLongPressGestureRecognizer) {
|
||||
if !self.node.shouldCheckForLongTap() {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
guard let renderer = renderer else {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
let location = recognizer.location(in: self)
|
||||
var foundNodes = [Node]()
|
||||
|
||||
|
||||
localContext { ctx in
|
||||
guard let foundNode = renderer.findNodeAt(location: location, ctx: ctx) else {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
var parent: Node? = foundNode
|
||||
while parent != .none {
|
||||
if parent!.shouldCheckForTap() {
|
||||
foundNodes.append(parent!)
|
||||
}
|
||||
|
||||
|
||||
parent = nodesMap.parents(parent!).first
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
foundNodes.forEach { node in
|
||||
let inverted = node.place.invert()!
|
||||
let loc = location.applying(RenderUtils.mapTransform(inverted))
|
||||
@ -366,7 +366,7 @@ open class MacawView: MView, MGestureRecognizerDelegate {
|
||||
node.handleLongTap(event, touchBegan: recognizer.state == .began)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Pan
|
||||
|
||||
@objc func handlePan(recognizer: MPanGestureRecognizer) {
|
||||
|
@ -1,7 +1,7 @@
|
||||
import Foundation
|
||||
|
||||
#if os(iOS)
|
||||
import UIKit
|
||||
import UIKit
|
||||
#endif
|
||||
|
||||
let nodesMap = NodesMap()
|
||||
|
@ -1,9 +1,9 @@
|
||||
import Foundation
|
||||
|
||||
#if os(iOS)
|
||||
import UIKit
|
||||
import UIKit
|
||||
#elseif os(OSX)
|
||||
import AppKit
|
||||
import AppKit
|
||||
#endif
|
||||
|
||||
class ShapeLayer: CAShapeLayer {
|
||||
|
Loading…
Reference in New Issue
Block a user