mirror of
https://github.com/exyte/Macaw.git
synced 2024-11-13 13:14:20 +03:00
Merge pull request #207 from exyte/task/swiftlint
Integrate SwiftLint in project
This commit is contained in:
commit
ff7c3e2df7
115
.swiftlint.yml
Normal file
115
.swiftlint.yml
Normal file
@ -0,0 +1,115 @@
|
||||
included:
|
||||
- Source
|
||||
- Tests
|
||||
excluded:
|
||||
- Dependencies
|
||||
disabled_rules:
|
||||
- unused_optional_binding
|
||||
- file_header
|
||||
- no_extension_access_modifier
|
||||
- number_separator
|
||||
- object_literal
|
||||
- pattern_matching_keywords
|
||||
- private_over_fileprivate
|
||||
- strict_fileprivate
|
||||
- sorted_imports
|
||||
- identifier_name # Disabled due to a lot of one symbol identifiers
|
||||
# Temporary disabled
|
||||
- explicit_type_interface
|
||||
- line_length
|
||||
- file_length
|
||||
- type_body_length
|
||||
- function_body_length
|
||||
- cyclomatic_complexity
|
||||
- function_parameter_count
|
||||
- type_name
|
||||
- force_unwrapping
|
||||
- explicit_top_level_acl
|
||||
- legacy_constructor
|
||||
- todo
|
||||
- implicitly_unwrapped_optional
|
||||
- attributes
|
||||
- force_cast
|
||||
- extension_access_modifier
|
||||
- large_tuple
|
||||
- no_grouping_extension
|
||||
opt_in_rules:
|
||||
- block_based_kvo
|
||||
- class_delegate_protocol
|
||||
- closing_brace
|
||||
- closure_end_indentation
|
||||
- closure_parameter_position
|
||||
- closure_spacing
|
||||
- colon
|
||||
- comma
|
||||
- compiler_protocol_init
|
||||
- conditional_returns_on_newline
|
||||
- control_statement
|
||||
- discarded_notification_center_observer
|
||||
- discouraged_direct_init
|
||||
- dynamic_inline
|
||||
- empty_count
|
||||
- empty_enum_arguments
|
||||
- empty_parameters
|
||||
- empty_parentheses_with_trailing_closure
|
||||
- explicit_enum_raw_value
|
||||
- explicit_init
|
||||
- fatal_error_message
|
||||
- first_where
|
||||
- for_where
|
||||
- force_try
|
||||
- generic_type_name
|
||||
- identifier_name
|
||||
- implicit_getter
|
||||
- implicit_return
|
||||
- is_disjoint
|
||||
- joined_default_parameter
|
||||
- leading_whitespace
|
||||
- legacy_cggeometry_functions
|
||||
- legacy_constant
|
||||
- legacy_nsgeometry_functions
|
||||
- let_var_whitespace
|
||||
- mark
|
||||
- multiline_parameters
|
||||
- multiple_closures_with_trailing_closure
|
||||
- nesting
|
||||
- nimble_operator
|
||||
- notification_center_detachment
|
||||
- opening_brace
|
||||
- operator_usage_whitespace
|
||||
- operator_whitespace
|
||||
- overridden_super_call
|
||||
- private_outlet
|
||||
- private_unit_test
|
||||
- prohibited_super_call
|
||||
- protocol_property_accessors_order
|
||||
- quick_discouraged_call
|
||||
- redundant_discardable_let
|
||||
- redundant_nil_coalescing
|
||||
- redundant_optional_initialization
|
||||
- redundant_string_enum_value
|
||||
- redundant_void_return
|
||||
- return_arrow_whitespace
|
||||
- shorthand_operator
|
||||
- single_test_class
|
||||
- statement_position
|
||||
- superfluous_disable_command
|
||||
- switch_case_on_newline
|
||||
- syntactic_sugar
|
||||
- trailing_closure
|
||||
- trailing_comma
|
||||
- trailing_newline
|
||||
- trailing_semicolon
|
||||
- trailing_whitespace
|
||||
- unneeded_parentheses_in_closure_argument
|
||||
- unused_closure_parameter
|
||||
- unused_enumerated
|
||||
- valid_ibinspectable
|
||||
- vertical_parameter_alignment
|
||||
- vertical_whitespace
|
||||
- void_return
|
||||
- weak_delegate
|
||||
- xctfail_message
|
||||
force_cast: warning
|
||||
shorthand_operator: warning
|
||||
empty_count: warning
|
@ -911,6 +911,7 @@
|
||||
57614B731F83D15600875933 /* Headers */,
|
||||
57614B741F83D15600875933 /* Resources */,
|
||||
57614B751F83D15600875933 /* CopyFiles */,
|
||||
665742FC1F988D93006612C6 /* ShellScript */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
@ -930,6 +931,7 @@
|
||||
57FCD2691D76EA4600CC0FB6 /* Headers */,
|
||||
57FCD26A1D76EA4600CC0FB6 /* Resources */,
|
||||
57D202181D78047000A90D4F /* CopyFiles */,
|
||||
669D360B1F8F9B4C0048EF8B /* ShellScript */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
@ -1040,6 +1042,35 @@
|
||||
};
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXShellScriptBuildPhase section */
|
||||
665742FC1F988D93006612C6 /* ShellScript */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "if which swiftlint >/dev/null; then\n swiftlint autocorrect --format\n swiftlint\nelse\n echo \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\nfi";
|
||||
};
|
||||
669D360B1F8F9B4C0048EF8B /* ShellScript */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "if which swiftlint >/dev/null; then\n swiftlint autocorrect --format\n swiftlint\nelse\n echo \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\nfi";
|
||||
};
|
||||
/* End PBXShellScriptBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
57614AFC1F83D15600875933 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
|
@ -35,7 +35,7 @@ public class Animation {
|
||||
return self
|
||||
}
|
||||
|
||||
public func cycle() -> Animation{
|
||||
public func cycle() -> Animation {
|
||||
return self
|
||||
}
|
||||
|
||||
@ -47,7 +47,7 @@ public class Animation {
|
||||
return self
|
||||
}
|
||||
|
||||
@discardableResult public func onComplete(_: @escaping (() -> ())) -> Animation {
|
||||
@discardableResult public func onComplete(_: @escaping (() -> Void)) -> Animation {
|
||||
return self
|
||||
}
|
||||
}
|
||||
|
@ -26,7 +26,7 @@ class BasicAnimation: Animation {
|
||||
var type = AnimationType.unknown
|
||||
let ID: String
|
||||
var next: BasicAnimation?
|
||||
var removeFunc: (() -> ())?
|
||||
var removeFunc: (() -> Void)?
|
||||
var delayed = false
|
||||
var manualStop = false
|
||||
var paused = false
|
||||
@ -36,9 +36,9 @@ class BasicAnimation: Animation {
|
||||
var cycled = false
|
||||
var delay = 0.0
|
||||
var autoreverses = false
|
||||
var onProgressUpdate: ((Double) -> ())?
|
||||
var onProgressUpdate: ((Double) -> Void)?
|
||||
var easing = Easing.ease
|
||||
var completion: (() -> ())?
|
||||
var completion: (() -> Void)?
|
||||
|
||||
override init() {
|
||||
ID = UUID().uuidString
|
||||
@ -72,7 +72,7 @@ class BasicAnimation: Animation {
|
||||
return self
|
||||
}
|
||||
|
||||
override open func onComplete(_ f: @escaping (() -> ())) -> Animation {
|
||||
override open func onComplete(_ f: @escaping (() -> Void)) -> Animation {
|
||||
self.completion = f
|
||||
return self
|
||||
}
|
||||
@ -136,7 +136,7 @@ extension BasicAnimation: Hashable {
|
||||
return ID.hashValue
|
||||
}
|
||||
|
||||
public static func ==(lhs: BasicAnimation, rhs: BasicAnimation) -> Bool {
|
||||
public static func == (lhs: BasicAnimation, rhs: BasicAnimation) -> Bool {
|
||||
return lhs.ID == rhs.ID
|
||||
}
|
||||
}
|
||||
@ -148,7 +148,6 @@ extension BasicAnimation {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Animated property list https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/CoreAnimation_guide/AnimatableProperties/AnimatableProperties.html
|
||||
internal class AnimationImpl<T: Interpolable>: BasicAnimation {
|
||||
|
||||
@ -248,7 +247,7 @@ internal class AnimationImpl<T: Interpolable>: BasicAnimation {
|
||||
|
||||
// For sequence completion
|
||||
class EmptyAnimation: BasicAnimation {
|
||||
required init(completion: @escaping (() -> ())) {
|
||||
required init(completion: @escaping (() -> Void)) {
|
||||
super.init()
|
||||
|
||||
self.completion = completion
|
||||
@ -259,9 +258,11 @@ class EmptyAnimation: BasicAnimation {
|
||||
// MARK: - Animation Description
|
||||
|
||||
open class AnimationDescription <T> {
|
||||
|
||||
open let valueFunc: (Double) -> T
|
||||
open var duration = 0.0
|
||||
open var delay = 0.0
|
||||
|
||||
public init(valueFunc: @escaping (Double) -> T, duration: Double = 1.0, delay: Double = 0.0) {
|
||||
self.valueFunc = valueFunc
|
||||
self.duration = duration
|
||||
|
@ -10,7 +10,6 @@ let animationProducer = AnimationProducer()
|
||||
|
||||
class AnimationProducer {
|
||||
|
||||
|
||||
var storedAnimations = [Node: BasicAnimation]()
|
||||
var delayedAnimations = [BasicAnimation: Timer]()
|
||||
var displayLink: MDisplayLinkProtocol?
|
||||
@ -21,7 +20,7 @@ class AnimationProducer {
|
||||
weak var cache: AnimationCache?
|
||||
let startDate: Date
|
||||
let finishDate: Date
|
||||
let completion: (()->())?
|
||||
let completion: (() -> Void)?
|
||||
}
|
||||
|
||||
var contentsAnimations = [ContentAnimationDesc]()
|
||||
@ -31,11 +30,11 @@ class AnimationProducer {
|
||||
// Delay - launching timer
|
||||
if animation.delay > 0.0 && !withoutDelay {
|
||||
|
||||
let timer = Timer.schedule(delay: animation.delay, handler: { [weak self] _ in
|
||||
let timer = Timer.schedule(delay: animation.delay) { [weak self] _ in
|
||||
self?.addAnimation(animation, withoutDelay: true)
|
||||
_ = self?.delayedAnimations.removeValue(forKey: animation)
|
||||
animation.delayed = false
|
||||
})
|
||||
}
|
||||
|
||||
animation.delayed = true
|
||||
delayedAnimations[animation] = timer
|
||||
@ -66,7 +65,6 @@ class AnimationProducer {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// General case
|
||||
guard let nodeId = animation.nodeId, let node = Node.nodeBy(id: nodeId) else {
|
||||
return
|
||||
@ -81,11 +79,11 @@ class AnimationProducer {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
guard let cache = macawView.animationCache else {
|
||||
return
|
||||
}
|
||||
|
||||
// swiftlint:disable superfluous_disable_command switch_case_alignment
|
||||
switch animation.type {
|
||||
case .unknown:
|
||||
return
|
||||
@ -107,26 +105,27 @@ class AnimationProducer {
|
||||
case .combine:
|
||||
addCombineAnimation(animation)
|
||||
case .contents:
|
||||
addContentsAnimation(animation, cache: cache, completion: {
|
||||
addContentsAnimation(animation, cache: cache) {
|
||||
if let next = animation.next {
|
||||
self.addAnimation(next)
|
||||
}
|
||||
})
|
||||
}
|
||||
case .morphing:
|
||||
addMorphingAnimation(animation, sceneLayer: layer, animationCache: cache, completion: {
|
||||
addMorphingAnimation(animation, sceneLayer: layer, animationCache: cache) {
|
||||
if let next = animation.next {
|
||||
self.addAnimation(next)
|
||||
}
|
||||
})
|
||||
}
|
||||
case .shape:
|
||||
addShapeAnimation(animation, sceneLayer: layer, animationCache: cache, completion: {
|
||||
addShapeAnimation(animation, sceneLayer: layer, animationCache: cache) {
|
||||
if let next = animation.next {
|
||||
self.addAnimation(next)
|
||||
}
|
||||
})
|
||||
}
|
||||
case .empty:
|
||||
executeCompletion(animation)
|
||||
}
|
||||
// swiftlint:enable superfluous_disable_command switch_case_alignment
|
||||
}
|
||||
|
||||
func removeDelayed(animation: BasicAnimation) {
|
||||
@ -279,7 +278,7 @@ class AnimationProducer {
|
||||
|
||||
// MARK: - Contents animation
|
||||
|
||||
func addContentsAnimation(_ animation: BasicAnimation, cache: AnimationCache?, completion: @escaping (() -> ())) {
|
||||
func addContentsAnimation(_ animation: BasicAnimation, cache: AnimationCache?, completion: @escaping (() -> Void)) {
|
||||
guard let contentsAnimation = animation as? ContentsAnimation else {
|
||||
return
|
||||
}
|
||||
@ -339,7 +338,7 @@ class AnimationProducer {
|
||||
}
|
||||
|
||||
@objc func updateContentAnimations() {
|
||||
if contentsAnimations.count == 0 {
|
||||
if contentsAnimations.isEmpty {
|
||||
displayLink?.invalidate()
|
||||
displayLink = .none
|
||||
}
|
||||
|
@ -35,6 +35,7 @@ class AnimationUtils {
|
||||
}
|
||||
|
||||
private static var indexCache = [Node: Int]()
|
||||
|
||||
class func absoluteIndex(_ node: Node, useCache: Bool = false) -> Int {
|
||||
if useCache {
|
||||
if let cachedIndex = indexCache[node] {
|
||||
@ -44,8 +45,7 @@ class AnimationUtils {
|
||||
indexCache.removeAll()
|
||||
}
|
||||
|
||||
|
||||
func childrenTotalCount(_ node: Node) -> Int{
|
||||
func childrenTotalCount(_ node: Node) -> Int {
|
||||
guard let group = node as? Group else {
|
||||
return 1
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
import Foundation
|
||||
|
||||
// swiftlint:disable trailing_closure
|
||||
public func >> (a: Double, b: Double) -> OpacityAnimationDescription {
|
||||
return OpacityAnimationDescription(valueFunc: { t in
|
||||
return a.interpolate(b, progress: t)
|
||||
@ -22,3 +23,4 @@ public func >> (a: Locus, b: Locus) -> MorphingAnimationDescription {
|
||||
return b
|
||||
})
|
||||
}
|
||||
// swiftlint:enable trailing_closure
|
||||
|
@ -1,4 +1,3 @@
|
||||
|
||||
public protocol TransformInterpolation: Interpolable {
|
||||
|
||||
}
|
||||
|
@ -1,19 +1,18 @@
|
||||
|
||||
func solveEquation(a: Double, b: Double, c: Double) -> (s1: Double?, s2: Double?) {
|
||||
let epsilon: Double = 0.000000001
|
||||
if (abs(a) < epsilon) {
|
||||
if (abs(b) < epsilon) {
|
||||
if abs(a) < epsilon {
|
||||
if abs(b) < epsilon {
|
||||
return (.none, .none)
|
||||
}
|
||||
let s = -c / b
|
||||
if (0.0 < s && s < 1.0) {
|
||||
if 0.0 < s && s < 1.0 {
|
||||
return (s, .none)
|
||||
}
|
||||
return (.none, .none)
|
||||
}
|
||||
|
||||
let b2ac = b * b - 4.0 * c * a
|
||||
if (b2ac < 0.0) {
|
||||
if b2ac < 0.0 {
|
||||
return (.none, .none)
|
||||
}
|
||||
let sqrtb2ac = b2ac.squareRoot()
|
||||
@ -24,7 +23,7 @@ func solveEquation(a: Double, b: Double, c: Double) -> (s1: Double?, s2: Double?
|
||||
}
|
||||
let s2 = (-b - sqrtb2ac) / (2.0 * a)
|
||||
var r2: Double? = .none
|
||||
if ((epsilon < s2) && (1-s2 > epsilon)) {
|
||||
if (epsilon < s2) && (1-s2 > epsilon) {
|
||||
r2 = s2
|
||||
}
|
||||
return (r1, r2)
|
||||
@ -42,10 +41,10 @@ func boundsWithDerivative(p0: Point, p1: Point, p2: Point, p3: Point) -> Rect? {
|
||||
let sy = solveEquation(a: ay, b: by, c: cy)
|
||||
|
||||
let solutions = [sx.s1, sx.s2, sy.s1, sy.s2].flatMap { $0 }
|
||||
var minX:Double? = .none
|
||||
var minY:Double? = .none
|
||||
var maxX:Double? = .none
|
||||
var maxY:Double? = .none
|
||||
var minX: Double? = .none
|
||||
var minY: Double? = .none
|
||||
var maxX: Double? = .none
|
||||
var maxY: Double? = .none
|
||||
for s in solutions {
|
||||
let p = BezierFunc2D(s, p0: p0, p1: p1, p2: p2, p3: p3)
|
||||
if let mx = minX {
|
||||
|
@ -1,4 +1,3 @@
|
||||
|
||||
func pathBounds(_ path: Path) -> Rect? {
|
||||
|
||||
guard let firstSegment = path.segments.first else {
|
||||
@ -67,7 +66,7 @@ func pathSegmenInfo(_ segment: PathSegment, currentPoint: Point?, currentBezierP
|
||||
Point(x: p2.x, y: p2.y))
|
||||
case .H:
|
||||
if let p = currentPoint {
|
||||
if (data[0] > p.x) {
|
||||
if data[0] > p.x {
|
||||
return (Rect(x: p.x, y: p.y, w: data[0] - p.x, h: 0.0), Point(x: data[0], y: p.y), .none)
|
||||
} else {
|
||||
return (Rect(x: data[0], y: p.y, w: p.x - data[0], h: 0.0), Point(x: data[0], y: p.y), .none)
|
||||
@ -78,7 +77,7 @@ func pathSegmenInfo(_ segment: PathSegment, currentPoint: Point?, currentBezierP
|
||||
return (Rect(x: 0.0, y: 0.0, w: data[0], h: 0.0), Point(x: data[0], y: 0.0), .none)
|
||||
case .V:
|
||||
if let p = currentPoint {
|
||||
if (data[0] > p.y) {
|
||||
if data[0] > p.y {
|
||||
return (Rect(x: p.x, y: p.y, w: 0.0, h: data[0] - p.y), Point(x: p.x, y: data[0]), .none)
|
||||
} else {
|
||||
return (Rect(x: p.x, y: data[0], w: 0.0, h: p.y - data[0]), Point(x: p.x, y: data[0]), .none)
|
||||
@ -100,7 +99,7 @@ private func cubicBounds(_ data: [Double], currentPoint: Point?) -> Rect {
|
||||
let p2 = Point(x: data[2], y: data[3])
|
||||
let p3 = Point(x: data[4], y: data[5])
|
||||
|
||||
return boundsWithDerivative(p0: p0, p1: p1, p2: p2, p3: p3) ?? Rect(x: 0, y: 0, w: 0, h:0)
|
||||
return boundsWithDerivative(p0: p0, p1: p1, p2: p2, p3: p3) ?? Rect(x: 0, y: 0, w: 0, h: 0)
|
||||
}
|
||||
|
||||
private func sCubicBounds(_ data: [Double], currentPoint: Point, currentBezierPoint: Point?) -> Rect {
|
||||
@ -115,5 +114,5 @@ private func sCubicBounds(_ data: [Double], currentPoint: Point, currentBezierPo
|
||||
y: 2.0 * currentPoint.y - bezierPoint.y)
|
||||
}
|
||||
|
||||
return boundsWithDerivative(p0: p0, p1: p1, p2: p2, p3: p3) ?? Rect(x: 0, y: 0, w: 0, h:0)
|
||||
return boundsWithDerivative(p0: p0, p1: p1, p2: p2, p3: p3) ?? Rect(x: 0, y: 0, w: 0, h: 0)
|
||||
}
|
||||
|
@ -1,4 +1,3 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
internal class AnimationSequence: BasicAnimation {
|
||||
@ -16,7 +15,7 @@ internal class AnimationSequence: BasicAnimation {
|
||||
}
|
||||
|
||||
override func getDuration() -> Double {
|
||||
let originalDuration = animations.map({ $0.getDuration() }).reduce(0, { $0 + $1 })
|
||||
let originalDuration = animations.map { $0.getDuration() } .reduce(0) { $0 + $1 }
|
||||
|
||||
if autoreverses {
|
||||
return originalDuration * 2.0
|
||||
|
@ -1,4 +1,3 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
internal class CombineAnimation: BasicAnimation {
|
||||
|
@ -1,4 +1,3 @@
|
||||
|
||||
internal class ContentsAnimation: AnimationImpl<[Node]> {
|
||||
|
||||
init(animatedGroup: Group, valueFunc: @escaping (Double) -> [Node], animationDuration: Double, delay: Double = 0.0, autostart: Bool = false, fps: UInt = 30) {
|
||||
@ -22,7 +21,6 @@ internal class ContentsAnimation: AnimationImpl<[Node]> {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
open override func reverse() -> Animation {
|
||||
let factory = { () -> (Double) -> [Node] in
|
||||
let original = self.timeFactory()
|
||||
@ -55,11 +53,11 @@ public extension AnimatableVariable where T: ContentsInterpolation {
|
||||
|
||||
public func animate(_ f: @escaping (Double) -> [Node]) {
|
||||
let group = node! as! Group
|
||||
let _ = ContentsAnimation(animatedGroup: group, valueFunc: f, animationDuration: 1.0, delay: 0.0, autostart: true)
|
||||
_ = ContentsAnimation(animatedGroup: group, valueFunc: f, animationDuration: 1.0, delay: 0.0, autostart: true)
|
||||
}
|
||||
|
||||
public func animate(_ f: @escaping ((Double) -> [Node]), during: Double = 1.0, delay: Double = 0.0) {
|
||||
let group = node! as! Group
|
||||
let _ = ContentsAnimation(animatedGroup: group, valueFunc: f, animationDuration: during, delay: delay, autostart: true)
|
||||
_ = ContentsAnimation(animatedGroup: group, valueFunc: f, animationDuration: during, delay: delay, autostart: true)
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,3 @@
|
||||
|
||||
class MorphingAnimation: AnimationImpl<Locus> {
|
||||
|
||||
convenience init(animatedNode: Shape, startValue: Locus, finalValue: Locus, animationDuration: Double, delay: Double = 0.0, autostart: Bool = false, fps: UInt = 30) {
|
||||
@ -40,15 +39,14 @@ public typealias MorphingAnimationDescription = AnimationDescription<Locus>
|
||||
|
||||
public extension AnimatableVariable where T: LocusInterpolation {
|
||||
public func animate(_ desc: MorphingAnimationDescription) {
|
||||
let _ = MorphingAnimation(animatedNode: node as! Shape, valueFunc: desc.valueFunc, animationDuration: desc.duration, delay: desc.delay, autostart: true)
|
||||
_ = MorphingAnimation(animatedNode: node as! Shape, valueFunc: desc.valueFunc, animationDuration: desc.duration, delay: desc.delay, autostart: true)
|
||||
}
|
||||
|
||||
public func animation(_ desc: MorphingAnimationDescription) -> Animation {
|
||||
return MorphingAnimation(animatedNode: node as! Shape, valueFunc: desc.valueFunc, animationDuration: desc.duration, delay: desc.delay, autostart: false)
|
||||
}
|
||||
|
||||
public func animate(from: Locus? =
|
||||
nil, to: Locus, during: Double = 1.0, delay: Double = 0.0) {
|
||||
public func animate(from: Locus? = nil, to: Locus, during: Double = 1.0, delay: Double = 0.0) {
|
||||
self.animate(((from ?? (node as! Shape).form) >> to).t(during, delay: delay))
|
||||
}
|
||||
|
||||
@ -86,8 +84,8 @@ public extension AnimatableVariable where T: ContentsInterpolation {
|
||||
}
|
||||
|
||||
// Shapes on same hierarhy level
|
||||
let fromShapes = fromNode.contents.flatMap{$0 as? Shape}
|
||||
let toShapes = to.flatMap{$0 as? Shape}
|
||||
let fromShapes = fromNode.contents.flatMap { $0 as? Shape }
|
||||
let toShapes = to.flatMap { $0 as? Shape }
|
||||
let minPathsNumber = min(fromShapes.count, toShapes.count)
|
||||
|
||||
var animations = [Animation]()
|
||||
@ -102,7 +100,7 @@ public extension AnimatableVariable where T: ContentsInterpolation {
|
||||
if fromShapes.count > minPathsNumber {
|
||||
for i in minPathsNumber..<fromShapes.count {
|
||||
let shapeToHide = fromShapes[i]
|
||||
let animation = shapeToHide.opacityVar.animation(to: 0.0, during:during, delay: delay)
|
||||
let animation = shapeToHide.opacityVar.animation(to: 0.0, during: during, delay: delay)
|
||||
animations.append(animation)
|
||||
}
|
||||
}
|
||||
@ -113,14 +111,14 @@ public extension AnimatableVariable where T: ContentsInterpolation {
|
||||
shapeToShow.opacity = 0.0
|
||||
fromNode.contents.append(shapeToShow)
|
||||
|
||||
let animation = shapeToShow.opacityVar.animation(to: 1.0, during:during, delay: delay)
|
||||
let animation = shapeToShow.opacityVar.animation(to: 1.0, during: during, delay: delay)
|
||||
animations.append(animation)
|
||||
}
|
||||
}
|
||||
|
||||
// Groups on same hierahy level
|
||||
let fromGroups = fromNode.contents.flatMap{$0 as? Group}
|
||||
let toGroups = to.flatMap{$0 as? Group}
|
||||
let fromGroups = fromNode.contents.flatMap { $0 as? Group }
|
||||
let toGroups = to.flatMap { $0 as? Group }
|
||||
let minGroupsNumber = min(fromGroups.count, toGroups.count)
|
||||
for i in 0..<minGroupsNumber {
|
||||
let fromGroup = fromGroups[i]
|
||||
@ -131,7 +129,7 @@ public extension AnimatableVariable where T: ContentsInterpolation {
|
||||
|
||||
for i in minGroupsNumber..<fromGroups.count {
|
||||
let groupToHide = fromGroups[i]
|
||||
let animation = groupToHide.opacityVar.animation(to: 0.0, during:during, delay: delay)
|
||||
let animation = groupToHide.opacityVar.animation(to: 0.0, during: during, delay: delay)
|
||||
animations.append(animation)
|
||||
}
|
||||
|
||||
@ -140,22 +138,21 @@ public extension AnimatableVariable where T: ContentsInterpolation {
|
||||
groupToShow.opacity = 0.0
|
||||
fromNode.contents.append(groupToShow)
|
||||
|
||||
let animation = groupToShow.opacityVar.animation(to: 1.0, during:during, delay: delay)
|
||||
let animation = groupToShow.opacityVar.animation(to: 1.0, during: during, delay: delay)
|
||||
animations.append(animation)
|
||||
}
|
||||
|
||||
|
||||
// Rest nodes
|
||||
let fromNodes = fromNode.contents.filter {
|
||||
return !($0 is Group || $0 is Shape)
|
||||
!($0 is Group || $0 is Shape)
|
||||
}
|
||||
|
||||
let toNodes = to.filter {
|
||||
return !($0 is Group || $0 is Shape)
|
||||
!($0 is Group || $0 is Shape)
|
||||
}
|
||||
|
||||
fromNodes.forEach { node in
|
||||
let animation = node.opacityVar.animation(to: 0.0, during:during, delay: delay)
|
||||
let animation = node.opacityVar.animation(to: 0.0, during: during, delay: delay)
|
||||
animations.append(animation)
|
||||
}
|
||||
|
||||
@ -163,7 +160,7 @@ public extension AnimatableVariable where T: ContentsInterpolation {
|
||||
node.opacity = 0.0
|
||||
fromNode.contents.append(node)
|
||||
|
||||
let animation = node.opacityVar.animation(to: 1.0, during:during, delay: delay)
|
||||
let animation = node.opacityVar.animation(to: 1.0, during: during, delay: delay)
|
||||
animations.append(animation)
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,3 @@
|
||||
|
||||
internal class OpacityAnimation: AnimationImpl<Double> {
|
||||
|
||||
convenience init(animatedNode: Node, startValue: Double, finalValue: Double, animationDuration: Double, delay: Double = 0.0, autostart: Bool = false, fps: UInt = 30) {
|
||||
@ -52,7 +51,7 @@ public typealias OpacityAnimationDescription = AnimationDescription<Double>
|
||||
|
||||
public extension AnimatableVariable where T: DoubleInterpolation {
|
||||
public func animate(_ desc: OpacityAnimationDescription) {
|
||||
let _ = OpacityAnimation(animatedNode: node!, valueFunc: desc.valueFunc, animationDuration: desc.duration, delay: desc.delay, autostart: true)
|
||||
_ = OpacityAnimation(animatedNode: node!, valueFunc: desc.valueFunc, animationDuration: desc.duration, delay: desc.delay, autostart: true)
|
||||
}
|
||||
|
||||
public func animation(_ desc: OpacityAnimationDescription) -> Animation {
|
||||
|
@ -59,7 +59,7 @@ class ShapeAnimation: AnimationImpl<Shape> {
|
||||
}
|
||||
|
||||
public extension AnimatableVariable {
|
||||
public func animate<T:Stroke>(from: T? = nil, to: T, during: Double = 1.0, delay: Double = 0.0) {
|
||||
public func animate<T: Stroke>(from: T? = nil, to: T, during: Double = 1.0, delay: Double = 0.0) {
|
||||
let shape = node as! Shape
|
||||
|
||||
var safeFrom = from
|
||||
@ -76,10 +76,10 @@ public extension AnimatableVariable {
|
||||
let finalShape = SceneUtils.shapeCopy(from: shape)
|
||||
finalShape.stroke = to
|
||||
|
||||
let _ = ShapeAnimation(animatedNode: shape, finalValue: finalShape, animationDuration: during, delay: delay, autostart: true)
|
||||
_ = ShapeAnimation(animatedNode: shape, finalValue: finalShape, animationDuration: during, delay: delay, autostart: true)
|
||||
}
|
||||
|
||||
public func animation<T:Stroke>(from: T? = nil, to: T, during: Double = 1.0, delay: Double = 0.0) -> Animation {
|
||||
public func animation<T: Stroke>(from: T? = nil, to: T, during: Double = 1.0, delay: Double = 0.0) -> Animation {
|
||||
let shape = node as! Shape
|
||||
|
||||
var safeFrom = from
|
||||
@ -101,7 +101,7 @@ public extension AnimatableVariable {
|
||||
}
|
||||
|
||||
public extension AnimatableVariable {
|
||||
public func animate<T:Fill>(from: T? = nil, to: T, during: Double = 1.0, delay: Double = 0.0) {
|
||||
public func animate<T: Fill>(from: T? = nil, to: T, during: Double = 1.0, delay: Double = 0.0) {
|
||||
let shape = node as! Shape
|
||||
|
||||
var safeFrom = from
|
||||
@ -118,10 +118,10 @@ public extension AnimatableVariable {
|
||||
let finalShape = SceneUtils.shapeCopy(from: shape)
|
||||
finalShape.fill = to
|
||||
|
||||
let _ = ShapeAnimation(animatedNode: shape, finalValue: finalShape, animationDuration: during, delay: delay, autostart: true)
|
||||
_ = ShapeAnimation(animatedNode: shape, finalValue: finalShape, animationDuration: during, delay: delay, autostart: true)
|
||||
}
|
||||
|
||||
public func animation<T:Fill>(from: T? = nil, to: T, during: Double = 1.0, delay: Double = 0.0) -> Animation {
|
||||
public func animation<T: Fill>(from: T? = nil, to: T, during: Double = 1.0, delay: Double = 0.0) -> Animation {
|
||||
let shape = node as! Shape
|
||||
|
||||
var safeFrom = from
|
||||
|
@ -54,7 +54,7 @@ public typealias TransformAnimationDescription = AnimationDescription<Transform>
|
||||
|
||||
public extension AnimatableVariable where T: TransformInterpolation {
|
||||
public func animate(_ desc: TransformAnimationDescription) {
|
||||
let _ = TransformAnimation(animatedNode: node!, valueFunc: desc.valueFunc, animationDuration: desc.duration, delay: desc.delay, autostart: true)
|
||||
_ = TransformAnimation(animatedNode: node!, valueFunc: desc.valueFunc, animationDuration: desc.duration, delay: desc.delay, autostart: true)
|
||||
}
|
||||
|
||||
public func animation(_ desc: TransformAnimationDescription) -> Animation {
|
||||
@ -70,7 +70,6 @@ public extension AnimatableVariable where T: TransformInterpolation {
|
||||
animation.play()
|
||||
}
|
||||
|
||||
|
||||
public func animation(from: Transform? = nil, to: Transform, during: Double = 1.0, delay: Double = 0.0) -> Animation {
|
||||
if let safeFrom = from {
|
||||
return self.animation((safeFrom >> to).t(during, delay: delay))
|
||||
|
@ -68,8 +68,6 @@ class AnimationCache {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
layer.opacity = Float(node.opacity)
|
||||
layer.node = node
|
||||
|
||||
@ -121,7 +119,7 @@ class AnimationCache {
|
||||
maxArea = currentArea
|
||||
}
|
||||
|
||||
t = t + step
|
||||
t += step
|
||||
}
|
||||
|
||||
return defaultScale * CGFloat(sqrt(maxArea))
|
||||
@ -182,7 +180,7 @@ class AnimationCache {
|
||||
|
||||
func animations() -> [Animation] {
|
||||
|
||||
return layerCache.map ({ $0.1.animation })
|
||||
return layerCache.map { $0.1.animation }
|
||||
}
|
||||
|
||||
func replace(original: Node, replacement: Node) {
|
||||
|
@ -1,8 +1,11 @@
|
||||
import Foundation
|
||||
|
||||
let animationRestorer = AnimationRestorer()
|
||||
|
||||
open class AnimationRestorer {
|
||||
typealias RestoreClosure = () -> ()
|
||||
|
||||
typealias RestoreClosure = () -> Void
|
||||
|
||||
var restoreClosures = [RestoreClosure]()
|
||||
|
||||
func addRestoreClosure(_ closure: @escaping RestoreClosure) {
|
||||
|
@ -1,4 +1,3 @@
|
||||
|
||||
// TODO: Implement better hash
|
||||
|
||||
extension Node: Hashable {
|
||||
|
@ -1,4 +1,3 @@
|
||||
|
||||
extension Transform: Hashable {
|
||||
public var hashValue: Int {
|
||||
return m11.hashValue ^
|
||||
|
@ -14,8 +14,7 @@ import Foundation
|
||||
import AppKit
|
||||
#endif
|
||||
|
||||
|
||||
func addMorphingAnimation(_ animation: BasicAnimation, sceneLayer: CALayer, animationCache: AnimationCache?, completion: @escaping (() -> ())) {
|
||||
func addMorphingAnimation(_ animation: BasicAnimation, sceneLayer: CALayer, animationCache: AnimationCache?, completion: @escaping (() -> Void)) {
|
||||
guard let morphingAnimation = animation as? MorphingAnimation else {
|
||||
return
|
||||
}
|
||||
@ -39,8 +38,8 @@ func addMorphingAnimation(_ animation: BasicAnimation, sceneLayer: CALayer, anim
|
||||
|
||||
// Creating proper animation
|
||||
let generatedAnim = pathAnimation(
|
||||
from:fromLocus,
|
||||
to:toLocus,
|
||||
from: fromLocus,
|
||||
to: toLocus,
|
||||
duration: duration,
|
||||
renderTransform: layer.renderTransform!)
|
||||
|
||||
@ -95,7 +94,7 @@ func addMorphingAnimation(_ animation: BasicAnimation, sceneLayer: CALayer, anim
|
||||
layer.lineWidth = CGFloat(stroke.width)
|
||||
layer.lineCap = RenderUtils.mapLineCapToString(stroke.cap)
|
||||
layer.lineJoin = RenderUtils.mapLineJoinToString(stroke.join)
|
||||
layer.lineDashPattern = stroke.dashes.map{ NSNumber(value: $0)}
|
||||
layer.lineDashPattern = stroke.dashes.map { NSNumber(value: $0) }
|
||||
} else {
|
||||
layer.strokeColor = MColor.black.cgColor
|
||||
layer.lineWidth = 1.0
|
||||
@ -114,7 +113,7 @@ func addMorphingAnimation(_ animation: BasicAnimation, sceneLayer: CALayer, anim
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate func pathAnimation(from:Locus, to: Locus, duration: Double, renderTransform: CGAffineTransform) -> CAAnimation {
|
||||
fileprivate func pathAnimation(from: Locus, to: Locus, duration: Double, renderTransform: CGAffineTransform) -> CAAnimation {
|
||||
|
||||
var transform = renderTransform
|
||||
let fromPath = RenderUtils.toCGPath(from).copy(using: &transform)
|
||||
|
@ -6,7 +6,7 @@ import Foundation
|
||||
import AppKit
|
||||
#endif
|
||||
|
||||
func addOpacityAnimation(_ animation: BasicAnimation, sceneLayer: CALayer, animationCache: AnimationCache?, completion: @escaping (() -> ())) {
|
||||
func addOpacityAnimation(_ animation: BasicAnimation, sceneLayer: CALayer, animationCache: AnimationCache?, completion: @escaping (() -> Void)) {
|
||||
guard let opacityAnimation = animation as? OpacityAnimation else {
|
||||
return
|
||||
}
|
||||
@ -28,7 +28,7 @@ func addOpacityAnimation(_ animation: BasicAnimation, sceneLayer: CALayer, anima
|
||||
animationCache?.freeLayer(node)
|
||||
|
||||
if animation.paused {
|
||||
animation.pausedProgress = animation.pausedProgress + animation.progress
|
||||
animation.pausedProgress += animation.progress
|
||||
node.opacityVar.value = opacityAnimation.getVFunc()(animation.pausedProgress)
|
||||
} else if animation.manualStop {
|
||||
animation.pausedProgress = 0.0
|
||||
|
@ -14,7 +14,7 @@ import Foundation
|
||||
import AppKit
|
||||
#endif
|
||||
|
||||
func addShapeAnimation(_ animation: BasicAnimation, sceneLayer: CALayer, animationCache: AnimationCache?, completion: @escaping (() -> ())) {
|
||||
func addShapeAnimation(_ animation: BasicAnimation, sceneLayer: CALayer, animationCache: AnimationCache?, completion: @escaping (() -> Void)) {
|
||||
guard let shapeAnimation = animation as? ShapeAnimation else {
|
||||
return
|
||||
}
|
||||
@ -35,11 +35,10 @@ func addShapeAnimation(_ animation: BasicAnimation, sceneLayer: CALayer, animati
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
// Creating proper animation
|
||||
let generatedAnim = generateShapeAnimation(
|
||||
from:fromShape,
|
||||
to:toShape,
|
||||
from: fromShape,
|
||||
to: toShape,
|
||||
duration: duration,
|
||||
renderTransform: layer.renderTransform!)
|
||||
|
||||
@ -106,7 +105,7 @@ func addShapeAnimation(_ animation: BasicAnimation, sceneLayer: CALayer, animati
|
||||
layer.lineWidth = CGFloat(stroke.width)
|
||||
layer.lineCap = RenderUtils.mapLineCapToString(stroke.cap)
|
||||
layer.lineJoin = RenderUtils.mapLineJoinToString(stroke.join)
|
||||
layer.lineDashPattern = stroke.dashes.map{ NSNumber(value: $0)}
|
||||
layer.lineDashPattern = stroke.dashes.map { NSNumber(value: $0) }
|
||||
} else if shape.fill == nil {
|
||||
layer.strokeColor = MColor.black.cgColor
|
||||
layer.lineWidth = 1.0
|
||||
@ -125,7 +124,7 @@ func addShapeAnimation(_ animation: BasicAnimation, sceneLayer: CALayer, animati
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate func generateShapeAnimation(from:Shape, to: Shape, duration: Double, renderTransform: CGAffineTransform) -> CAAnimation {
|
||||
fileprivate func generateShapeAnimation(from: Shape, to: Shape, duration: Double, renderTransform: CGAffineTransform) -> CAAnimation {
|
||||
|
||||
let group = CAAnimationGroup()
|
||||
|
||||
@ -155,7 +154,6 @@ fileprivate func generateShapeAnimation(from:Shape, to: Shape, duration: Double,
|
||||
group.animations?.append(fillAnimation)
|
||||
}
|
||||
|
||||
|
||||
// Stroke
|
||||
let fromStroke = from.stroke ?? Stroke(fill: Color.black, width: 1.0)
|
||||
let toStroke = to.stroke ?? Stroke(fill: Color.black, width: 1.0)
|
||||
|
@ -6,7 +6,7 @@ import Foundation
|
||||
import AppKit
|
||||
#endif
|
||||
|
||||
func addTransformAnimation(_ animation: BasicAnimation, sceneLayer: CALayer, animationCache: AnimationCache?, completion: @escaping (() -> ())) {
|
||||
func addTransformAnimation(_ animation: BasicAnimation, sceneLayer: CALayer, animationCache: AnimationCache?, completion: @escaping (() -> Void)) {
|
||||
guard let transformAnimation = animation as? TransformAnimation else {
|
||||
return
|
||||
}
|
||||
@ -34,7 +34,7 @@ func addTransformAnimation(_ animation: BasicAnimation, sceneLayer: CALayer, ani
|
||||
generatedAnim.completion = { finished in
|
||||
|
||||
if animation.paused {
|
||||
animation.pausedProgress = animation.pausedProgress + animation.progress
|
||||
animation.pausedProgress += animation.progress
|
||||
node.placeVar.value = transformAnimation.getVFunc()(animation.pausedProgress)
|
||||
} else if animation.manualStop {
|
||||
animation.pausedProgress = 0.0
|
||||
|
@ -10,9 +10,9 @@ import Foundation
|
||||
|
||||
open class Disposable {
|
||||
|
||||
let handler: (()->())
|
||||
let handler: (() -> Void)
|
||||
|
||||
init (_ disposeHandler: @escaping (()->()) ) {
|
||||
init (_ disposeHandler: @escaping (() -> Void) ) {
|
||||
handler = disposeHandler
|
||||
}
|
||||
|
||||
|
@ -9,13 +9,13 @@
|
||||
import Foundation
|
||||
|
||||
class ChangeHandler<T>: Equatable {
|
||||
let handle: ((T)->())
|
||||
let handle: ((T) -> Void)
|
||||
|
||||
init(_ f: @escaping ((T)->()) ) {
|
||||
init(_ f: @escaping ((T) -> Void) ) {
|
||||
handle = f
|
||||
}
|
||||
|
||||
static func ==(lhs: ChangeHandler<T>, rhs: ChangeHandler<T>) -> Bool {
|
||||
static func == (lhs: ChangeHandler<T>, rhs: ChangeHandler<T>) -> Bool {
|
||||
return lhs === rhs
|
||||
}
|
||||
}
|
||||
@ -33,15 +33,15 @@ open class Variable<T> {
|
||||
value = v
|
||||
}
|
||||
|
||||
@discardableResult open func onChange(_ f: @escaping ((T)->())) -> Disposable {
|
||||
@discardableResult open func onChange(_ f: @escaping ((T) -> Void)) -> Disposable {
|
||||
let handler = ChangeHandler<T>(f)
|
||||
handlers.append(handler)
|
||||
return Disposable({ [weak self] in
|
||||
return Disposable { [weak self] in
|
||||
guard let index = self?.handlers.index(of: handler) else {
|
||||
return
|
||||
}
|
||||
|
||||
self?.handlers.remove(at: index)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
open class PanEvent : Event {
|
||||
open class PanEvent: Event {
|
||||
|
||||
open let dx: Double
|
||||
open let dy: Double
|
||||
|
@ -1,4 +1,4 @@
|
||||
open class PinchEvent : Event {
|
||||
open class PinchEvent: Event {
|
||||
|
||||
open let scale: Double
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
open class RotateEvent : Event {
|
||||
open class RotateEvent: Event {
|
||||
|
||||
open let angle: Double
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
open class TapEvent : Event {
|
||||
open class TapEvent: Event {
|
||||
|
||||
open let location: Point
|
||||
|
||||
|
@ -6,13 +6,12 @@
|
||||
//
|
||||
//
|
||||
|
||||
|
||||
public struct TouchPoint {
|
||||
public let id: Int
|
||||
public let location: Point
|
||||
}
|
||||
|
||||
public class TouchEvent : Event {
|
||||
public class TouchEvent: Event {
|
||||
|
||||
public let points: [TouchPoint]
|
||||
|
||||
|
@ -70,7 +70,7 @@ open class Color: Fill, Equatable {
|
||||
return rgbt( r: r, g: g, b: b, t: 0 )
|
||||
}
|
||||
|
||||
public static func ==(lhs: Color, rhs: Color) -> Bool {
|
||||
public static func == (lhs: Color, rhs: Color) -> Bool {
|
||||
return lhs.val == rhs.val
|
||||
}
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ open class GeomUtils {
|
||||
let cy = arc.ellipse.cy
|
||||
|
||||
var delta = arc.extent
|
||||
if (arc.shift == 0.0 && abs(arc.extent - Double.pi * 2.0) < 0.00001) {
|
||||
if arc.shift == 0.0 && abs(arc.extent - Double.pi * 2.0) < 0.00001 {
|
||||
delta = Double.pi * 2.0 - 0.001
|
||||
}
|
||||
let theta1 = arc.shift
|
||||
@ -42,7 +42,7 @@ open class GeomUtils {
|
||||
|
||||
fileprivate class func pointsToPath(_ points: [Double], close: Bool = false) -> Path {
|
||||
var pb = PathBuilder(segment: PathSegment(type: .M, data: [points[0], points[1]]))
|
||||
if (points.count > 2) {
|
||||
if points.count > 2 {
|
||||
let parts = stride(from: 2, to: points.count, by: 2).map { Array(points[$0 ..< $0 + 2]) }
|
||||
for part in parts {
|
||||
pb = pb.lineTo(x: part[0], y: part[1])
|
||||
|
@ -147,9 +147,9 @@ open class PathBuilder {
|
||||
|
||||
// GENERATED NOT
|
||||
open func build() -> Path {
|
||||
var segments : [PathSegment] = []
|
||||
var builder : PathBuilder? = self
|
||||
while(builder != nil) {
|
||||
var segments: [PathSegment] = []
|
||||
var builder: PathBuilder? = self
|
||||
while builder != nil {
|
||||
segments.append(builder!.segment)
|
||||
builder = builder!.rest
|
||||
}
|
||||
@ -158,6 +158,6 @@ open class PathBuilder {
|
||||
|
||||
// GENERATED NOT
|
||||
fileprivate func boolsToNum(_ largeArc: Bool, sweep: Bool) -> Double {
|
||||
return (largeArc ? 1 : 0) + (sweep ? 1 : 0) * 2;
|
||||
return (largeArc ? 1 : 0) + (sweep ? 1 : 0) * 2
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,9 @@ open class Polygon: Locus {
|
||||
}
|
||||
|
||||
override open func bounds() -> Rect {
|
||||
guard !points.isEmpty else { return Rect.zero() }
|
||||
guard !points.isEmpty else {
|
||||
return Rect.zero()
|
||||
}
|
||||
|
||||
var minX = Double(INT16_MAX)
|
||||
var minY = Double(INT16_MAX)
|
||||
|
@ -9,7 +9,9 @@ open class Polyline: Locus {
|
||||
}
|
||||
|
||||
override open func bounds() -> Rect {
|
||||
guard !points.isEmpty else { return Rect.zero() }
|
||||
guard !points.isEmpty else {
|
||||
return Rect.zero()
|
||||
}
|
||||
|
||||
var minX = Double(INT16_MAX)
|
||||
var minY = Double(INT16_MAX)
|
||||
|
@ -59,7 +59,7 @@ open class Rect: Locus {
|
||||
}
|
||||
|
||||
extension Rect {
|
||||
public static func ==(lhs: Rect, rhs: Rect) -> Bool {
|
||||
public static func == (lhs: Rect, rhs: Rect) -> Bool {
|
||||
return lhs.x == rhs.x
|
||||
&& lhs.y == rhs.y
|
||||
&& lhs.w == rhs.w
|
||||
|
@ -78,7 +78,7 @@ public final class Transform {
|
||||
// GENERATED NOT
|
||||
public func invert() -> Transform? {
|
||||
let det = self.m11 * self.m22 - self.m12 * self.m21
|
||||
if (det == 0) {
|
||||
if det == 0 {
|
||||
return nil
|
||||
}
|
||||
return Transform(m11: m22 / det, m12: -m12 / det, m21: -m21 / det, m22: m11 / det,
|
||||
|
@ -20,7 +20,6 @@ open class Group: Node {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public init(contents: [Node] = [], place: Transform = Transform.identity, opaque: Bool = true, opacity: Double = 1, clip: Locus? = nil, effect: Effect? = nil, visible: Bool = true, tag: [String] = []) {
|
||||
self.contentsVar = AnimatableVariable<[Node]>(contents)
|
||||
super.init(
|
||||
|
@ -69,11 +69,9 @@ open class Image: Node {
|
||||
public init(image: MImage, xAlign: Align = .min, yAlign: Align = .min, aspectRatio: AspectRatio = .none, w: Int = 0, h: Int = 0, place: Transform = Transform.identity, opaque: Bool = true, opacity: Double = 1, clip: Locus? = nil, effect: Effect? = nil, visible: Bool = true, tag: [String] = []) {
|
||||
|
||||
var oldId: String?
|
||||
for key in imagesMap.keys {
|
||||
if image === imagesMap[key] {
|
||||
for key in imagesMap.keys where image === imagesMap[key] {
|
||||
oldId = key
|
||||
}
|
||||
}
|
||||
|
||||
let id = oldId ?? UUID().uuidString
|
||||
imagesMap[id] = image
|
||||
@ -117,9 +115,9 @@ open class Image: Node {
|
||||
case PNG
|
||||
}
|
||||
|
||||
internal func base64encoded(type:ImageRepresentationType) -> String? {
|
||||
internal func base64encoded(type: ImageRepresentationType) -> String? {
|
||||
if let image = self.image() {
|
||||
switch (type) {
|
||||
switch type {
|
||||
case .JPEG:
|
||||
if let data = MImageJPEGRepresentation(image) {
|
||||
return data.base64EncodedString()
|
||||
|
@ -46,7 +46,6 @@ open class Node: Drawable {
|
||||
return Node.map.object(forKey: id as NSString)
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Searching
|
||||
public func nodeBy(tag: String) -> Node? {
|
||||
if self.tag.contains(tag) {
|
||||
@ -71,95 +70,95 @@ open class Node: Drawable {
|
||||
var rotateHandlers = [ChangeHandler<RotateEvent>]()
|
||||
var pinchHandlers = [ChangeHandler<PinchEvent>]()
|
||||
|
||||
@discardableResult public func onTouchPressed (_ f: @escaping (TouchEvent) -> ()) -> Disposable {
|
||||
@discardableResult public func onTouchPressed (_ f: @escaping (TouchEvent) -> Void) -> Disposable {
|
||||
let handler = ChangeHandler<TouchEvent>(f)
|
||||
touchPressedHandlers.append(handler)
|
||||
|
||||
return Disposable({ [weak self] in
|
||||
return Disposable { [weak self] in
|
||||
guard let index = self?.touchPressedHandlers.index(of: handler) else {
|
||||
return
|
||||
}
|
||||
|
||||
self?.touchPressedHandlers.remove(at: index)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@discardableResult public func onTouchMoved (_ f: @escaping (TouchEvent) -> ()) -> Disposable {
|
||||
@discardableResult public func onTouchMoved (_ f: @escaping (TouchEvent) -> Void) -> Disposable {
|
||||
let handler = ChangeHandler<TouchEvent>(f)
|
||||
touchMovedHandlers.append(handler)
|
||||
|
||||
return Disposable({ [weak self] in
|
||||
return Disposable { [weak self] in
|
||||
guard let index = self?.touchMovedHandlers.index(of: handler) else {
|
||||
return
|
||||
}
|
||||
|
||||
self?.touchMovedHandlers.remove(at: index)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@discardableResult public func onTouchReleased(_ f: @escaping (TouchEvent) -> ()) -> Disposable {
|
||||
@discardableResult public func onTouchReleased(_ f: @escaping (TouchEvent) -> Void) -> Disposable {
|
||||
let handler = ChangeHandler<TouchEvent>(f)
|
||||
touchReleasedHandlers.append(handler)
|
||||
|
||||
return Disposable({ [weak self] in
|
||||
return Disposable { [weak self] in
|
||||
guard let index = self?.touchReleasedHandlers.index(of: handler) else {
|
||||
return
|
||||
}
|
||||
|
||||
self?.touchReleasedHandlers.remove(at: index)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@discardableResult public func onTap(_ f: @escaping (TapEvent) -> ()) -> Disposable {
|
||||
@discardableResult public func onTap(_ f: @escaping (TapEvent) -> Void) -> Disposable {
|
||||
let handler = ChangeHandler<TapEvent>(f)
|
||||
tapHandlers.append(handler)
|
||||
|
||||
return Disposable({ [weak self] in
|
||||
return Disposable { [weak self] in
|
||||
guard let index = self?.tapHandlers.index(of: handler) else {
|
||||
return
|
||||
}
|
||||
|
||||
self?.tapHandlers.remove(at: index)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@discardableResult public func onPan(_ f: @escaping (PanEvent) -> ()) -> Disposable {
|
||||
@discardableResult public func onPan(_ f: @escaping (PanEvent) -> Void) -> Disposable {
|
||||
let handler = ChangeHandler<PanEvent>(f)
|
||||
panHandlers.append(handler)
|
||||
|
||||
return Disposable({ [weak self] in
|
||||
return Disposable { [weak self] in
|
||||
guard let index = self?.panHandlers.index(of: handler) else {
|
||||
return
|
||||
}
|
||||
|
||||
self?.panHandlers.remove(at: index)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@discardableResult public func onRotate(_ f: @escaping (RotateEvent) -> ()) -> Disposable {
|
||||
@discardableResult public func onRotate(_ f: @escaping (RotateEvent) -> Void) -> Disposable {
|
||||
let handler = ChangeHandler<RotateEvent>(f)
|
||||
rotateHandlers.append(handler)
|
||||
|
||||
return Disposable({ [weak self] in
|
||||
return Disposable { [weak self] in
|
||||
guard let index = self?.rotateHandlers.index(of: handler) else {
|
||||
return
|
||||
}
|
||||
|
||||
self?.rotateHandlers.remove(at: index)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@discardableResult public func onPinch(_ f: @escaping (PinchEvent) -> ()) -> Disposable {
|
||||
@discardableResult public func onPinch(_ f: @escaping (PinchEvent) -> Void) -> Disposable {
|
||||
let handler = ChangeHandler<PinchEvent>(f)
|
||||
pinchHandlers.append(handler)
|
||||
|
||||
return Disposable({ [weak self] in
|
||||
return Disposable { [weak self] in
|
||||
guard let index = self?.pinchHandlers.index(of: handler) else {
|
||||
return
|
||||
}
|
||||
|
||||
self?.pinchHandlers.remove(at: index)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Helpers
|
||||
@ -193,34 +192,31 @@ open class Node: Drawable {
|
||||
}
|
||||
|
||||
func shouldCheckForPressed() -> Bool {
|
||||
return touchPressedHandlers.count > 0
|
||||
return !touchPressedHandlers.isEmpty
|
||||
}
|
||||
|
||||
func shouldCheckForMoved() -> Bool {
|
||||
return touchMovedHandlers.count > 0
|
||||
return !touchMovedHandlers.isEmpty
|
||||
}
|
||||
|
||||
|
||||
func shouldCheckForReleased() -> Bool {
|
||||
return touchReleasedHandlers.count > 0
|
||||
return !touchReleasedHandlers.isEmpty
|
||||
}
|
||||
|
||||
func shouldCheckForTap() -> Bool {
|
||||
return tapHandlers.count > 0
|
||||
return !tapHandlers.isEmpty
|
||||
}
|
||||
|
||||
func shouldCheckForPan() -> Bool {
|
||||
return panHandlers.count > 0
|
||||
return !panHandlers.isEmpty
|
||||
}
|
||||
|
||||
|
||||
func shouldCheckForRotate() -> Bool {
|
||||
return rotateHandlers.count > 0
|
||||
return !rotateHandlers.isEmpty
|
||||
}
|
||||
|
||||
|
||||
func shouldCheckForPinch() -> Bool {
|
||||
return pinchHandlers.count > 0
|
||||
return !pinchHandlers.isEmpty
|
||||
}
|
||||
|
||||
public init(place: Transform = Transform.identity, opaque: Bool = true, opacity: Double = 1, clip: Locus? = nil, effect: Effect? = nil, visible: Bool = true, tag: [String] = []) {
|
||||
|
@ -6,7 +6,6 @@ import Foundation
|
||||
import AppKit
|
||||
#endif
|
||||
|
||||
|
||||
open class Text: Node {
|
||||
|
||||
open let textVar: Variable<String>
|
||||
@ -68,7 +67,7 @@ open class Text: Node {
|
||||
let font: MFont
|
||||
if let f = self.font {
|
||||
|
||||
if let customFont = RenderUtils.loadFont(name: f.name, size:f.size) {
|
||||
if let customFont = RenderUtils.loadFont(name: f.name, size: f.size) {
|
||||
font = customFont
|
||||
} else {
|
||||
font = MFont.systemFont(ofSize: CGFloat(f.size))
|
||||
|
@ -85,4 +85,3 @@ import Foundation
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -18,7 +18,7 @@
|
||||
displayLink?.invalidate()
|
||||
}
|
||||
|
||||
//MARK: - MDisplayLinkProtocol
|
||||
// MARK: - MDisplayLinkProtocol
|
||||
func startUpdates(_ onUpdate: @escaping () -> Void) {
|
||||
self.onUpdate = onUpdate
|
||||
|
||||
|
@ -94,4 +94,3 @@ import Foundation
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -115,7 +115,7 @@ import Foundation
|
||||
|
||||
extension NSString {
|
||||
@nonobjc
|
||||
func size(attributes attrs: [NSAttributedStringKey : Any]? = nil) -> NSSize {
|
||||
func size(attributes attrs: [NSAttributedStringKey: Any]? = nil) -> NSSize {
|
||||
return size(withAttributes: attrs)
|
||||
}
|
||||
}
|
||||
@ -124,7 +124,4 @@ import Foundation
|
||||
return MScreen.main
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -43,7 +43,6 @@ import Foundation
|
||||
return rep?.representation(using: NSBitmapImageRep.FileType.jpeg, properties: [NSBitmapImageRep.PropertyKey.compressionFactor: quality])
|
||||
}
|
||||
|
||||
|
||||
func MGraphicsBeginImageContextWithOptions(_ size: CGSize, _ opaque: Bool, _ scale: CGFloat) {
|
||||
var scale = scale
|
||||
|
||||
@ -59,7 +58,7 @@ import Foundation
|
||||
|
||||
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 {
|
||||
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
|
||||
}
|
||||
|
||||
|
@ -31,7 +31,7 @@ import Foundation
|
||||
extension MBezierPath {
|
||||
|
||||
public var cgPath: CGPath {
|
||||
get { let path = CGMutablePath()
|
||||
let path = CGMutablePath()
|
||||
var points = [CGPoint](repeating: .zero, count: 3)
|
||||
|
||||
for i in 0 ..< self.elementCount {
|
||||
@ -57,7 +57,6 @@ import Foundation
|
||||
|
||||
return path
|
||||
}
|
||||
}
|
||||
|
||||
public convenience init(arcCenter center: CGPoint, radius: CGFloat, startAngle: CGFloat, endAngle: CGFloat, clockwise: Bool) {
|
||||
self.init()
|
||||
@ -70,9 +69,9 @@ import Foundation
|
||||
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);
|
||||
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))
|
||||
@ -88,7 +87,6 @@ import Foundation
|
||||
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)
|
||||
}
|
||||
|
@ -12,19 +12,19 @@ import Foundation
|
||||
import AppKit
|
||||
|
||||
public enum MViewContentMode: Int {
|
||||
case scaleToFill
|
||||
case scaleAspectFit
|
||||
case scaleAspectFill
|
||||
case redraw
|
||||
case center
|
||||
case top
|
||||
case bottom
|
||||
case left
|
||||
case right
|
||||
case topLeft
|
||||
case topRight
|
||||
case bottomLeft
|
||||
case bottomRight
|
||||
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 {
|
||||
@ -142,33 +142,30 @@ import Foundation
|
||||
}
|
||||
|
||||
private func subscribeForMouseDown() {
|
||||
NSEvent.addLocalMonitorForEvents(matching: .leftMouseDown, handler: { [weak self] event -> NSEvent? in
|
||||
self?.handleInput(event: event, handler: { touches in
|
||||
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, handler: { [weak self] event -> NSEvent? in
|
||||
self?.handleInput(event: event, handler: { touches in
|
||||
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, handler: { [weak self] event -> NSEvent? in
|
||||
self?.handleInput(event: event, handler: { touches in
|
||||
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 ) {
|
||||
|
@ -57,10 +57,10 @@ class GroupRenderer: NodeRenderer {
|
||||
}
|
||||
|
||||
private func updateRenderers() {
|
||||
renderers.forEach{ $0.dispose() }
|
||||
renderers.forEach { $0.dispose() }
|
||||
renderers.removeAll()
|
||||
|
||||
if let updatedRenderers = group?.contents.flatMap ({ (child) -> NodeRenderer? in
|
||||
if let updatedRenderers = group?.contents.flatMap ({ child -> NodeRenderer? in
|
||||
guard let interval = renderingInterval else {
|
||||
return RenderUtils.createNodeRenderer(child, context: ctx, animationCache: animationCache)
|
||||
}
|
||||
|
@ -72,7 +72,7 @@ class ImageRenderer: NodeRenderer {
|
||||
|
||||
if let mImage = osImage {
|
||||
let rect = getRect(mImage)
|
||||
if (rect.contains(location)) {
|
||||
if rect.contains(location) {
|
||||
return node()
|
||||
}
|
||||
}
|
||||
@ -87,15 +87,15 @@ class ImageRenderer: NodeRenderer {
|
||||
let imageSize = mImage.size
|
||||
var w = CGFloat(image.w)
|
||||
var h = CGFloat(image.h)
|
||||
if ((w == 0 || w == imageSize.width) && (h == 0 || h == imageSize.height)) {
|
||||
if (w == 0 || w == imageSize.width) && (h == 0 || h == imageSize.height) {
|
||||
return CGRect(x: 0, y: 0, width: imageSize.width, height: imageSize.height)
|
||||
} else {
|
||||
if (w == 0) {
|
||||
if w == 0 {
|
||||
w = imageSize.width * h / imageSize.height
|
||||
} else if (h == 0) {
|
||||
} else if h == 0 {
|
||||
h = imageSize.height * w / imageSize.width
|
||||
}
|
||||
switch (image.aspectRatio) {
|
||||
switch image.aspectRatio {
|
||||
case AspectRatio.meet:
|
||||
return calculateMeetAspectRatio(image, size: imageSize)
|
||||
case AspectRatio.slice:
|
||||
@ -117,7 +117,7 @@ class ImageRenderer: NodeRenderer {
|
||||
var resultH = h
|
||||
var destX = CGFloat(0)
|
||||
var destY = CGFloat(0)
|
||||
if (destAR < srcAR) {
|
||||
if destAR < srcAR {
|
||||
// fill all available width and scale height
|
||||
resultH = size.height * w / size.width
|
||||
} else {
|
||||
@ -125,7 +125,7 @@ class ImageRenderer: NodeRenderer {
|
||||
resultW = size.width * h / size.height
|
||||
}
|
||||
let xalign = image.xAlign
|
||||
switch (xalign) {
|
||||
switch xalign {
|
||||
case Align.min:
|
||||
destX = 0
|
||||
case Align.mid:
|
||||
@ -134,7 +134,7 @@ class ImageRenderer: NodeRenderer {
|
||||
destX = w - resultW
|
||||
}
|
||||
let yalign = image.yAlign
|
||||
switch (yalign) {
|
||||
switch yalign {
|
||||
case Align.min:
|
||||
destY = 0
|
||||
case Align.mid:
|
||||
@ -155,11 +155,11 @@ class ImageRenderer: NodeRenderer {
|
||||
// destination and source aspect ratios
|
||||
let destAR = w / h
|
||||
let srcAR = size.width / size.height
|
||||
if (destAR > srcAR) {
|
||||
if destAR > srcAR {
|
||||
// fill all available width and scale height
|
||||
totalH = size.height * w / size.width
|
||||
totalW = w
|
||||
switch (image.yAlign) {
|
||||
switch image.yAlign {
|
||||
case Align.min:
|
||||
srcY = 0
|
||||
case Align.mid:
|
||||
@ -171,7 +171,7 @@ class ImageRenderer: NodeRenderer {
|
||||
// fill all available height and scale width
|
||||
totalW = size.width * h / size.height
|
||||
totalH = h
|
||||
switch (image.xAlign) {
|
||||
switch image.xAlign {
|
||||
case Align.min:
|
||||
srcX = 0
|
||||
case Align.mid:
|
||||
|
@ -4,7 +4,6 @@ import Foundation
|
||||
import UIKit
|
||||
#endif
|
||||
|
||||
|
||||
struct RenderingInterval {
|
||||
let from: Int
|
||||
let to: Int
|
||||
@ -14,7 +13,7 @@ class NodeRenderer {
|
||||
|
||||
let ctx: RenderContext
|
||||
|
||||
fileprivate let onNodeChange: ()->()
|
||||
fileprivate let onNodeChange: () -> Void
|
||||
fileprivate let disposables = GroupDisposable()
|
||||
fileprivate var active = false
|
||||
weak var animationCache: AnimationCache?
|
||||
@ -92,7 +91,7 @@ class NodeRenderer {
|
||||
|
||||
if let isAnimating = animationCache?.isAnimating(node), isAnimating {
|
||||
self.removeObservers()
|
||||
if (!force) {
|
||||
if !force {
|
||||
return
|
||||
}
|
||||
} else {
|
||||
@ -110,7 +109,7 @@ class NodeRenderer {
|
||||
return .none
|
||||
}
|
||||
|
||||
if (node.opaque) {
|
||||
if node.opaque {
|
||||
let place = node.place
|
||||
if let inverted = place.invert() {
|
||||
ctx.saveGState()
|
||||
@ -155,14 +154,14 @@ class NodeRenderer {
|
||||
}
|
||||
|
||||
private func addObservers() {
|
||||
if (!active) {
|
||||
if !active {
|
||||
active = true
|
||||
doAddObservers()
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate func removeObservers() {
|
||||
if (active) {
|
||||
if active {
|
||||
active = false
|
||||
disposables.dispose()
|
||||
}
|
||||
|
@ -22,38 +22,50 @@ class RenderUtils {
|
||||
|
||||
class func mapLineJoin(_ join: LineJoin?) -> CGLineJoin {
|
||||
switch join {
|
||||
case LineJoin.round?: return CGLineJoin.round
|
||||
case LineJoin.bevel?: return CGLineJoin.bevel
|
||||
default: return CGLineJoin.miter
|
||||
case LineJoin.round?:
|
||||
return CGLineJoin.round
|
||||
case LineJoin.bevel?:
|
||||
return CGLineJoin.bevel
|
||||
default:
|
||||
return CGLineJoin.miter
|
||||
}
|
||||
}
|
||||
|
||||
class func mapLineJoinToString(_ join: LineJoin?) -> String {
|
||||
switch join {
|
||||
case LineJoin.round?: return kCALineJoinRound
|
||||
case LineJoin.bevel?: return kCALineJoinBevel
|
||||
default: return kCALineJoinMiter
|
||||
case LineJoin.round?:
|
||||
return kCALineJoinRound
|
||||
case LineJoin.bevel?:
|
||||
return kCALineJoinBevel
|
||||
default:
|
||||
return kCALineJoinMiter
|
||||
}
|
||||
}
|
||||
|
||||
class func mapLineCap(_ cap: LineCap?) -> CGLineCap {
|
||||
switch cap {
|
||||
case LineCap.round?: return CGLineCap.round
|
||||
case LineCap.square?: return CGLineCap.square
|
||||
default: return CGLineCap.butt
|
||||
case LineCap.round?:
|
||||
return CGLineCap.round
|
||||
case LineCap.square?:
|
||||
return CGLineCap.square
|
||||
default:
|
||||
return CGLineCap.butt
|
||||
}
|
||||
}
|
||||
|
||||
class func mapLineCapToString(_ cap: LineCap?) -> String {
|
||||
switch cap {
|
||||
case LineCap.round?: return kCALineCapRound
|
||||
case LineCap.square?: return kCALineCapSquare
|
||||
default: return kCALineCapButt
|
||||
case LineCap.round?:
|
||||
return kCALineCapRound
|
||||
case LineCap.square?:
|
||||
return kCALineCapSquare
|
||||
default:
|
||||
return kCALineCapButt
|
||||
}
|
||||
}
|
||||
|
||||
class func mapDash(_ dashes: [Double]) -> UnsafeMutablePointer<CGFloat> {
|
||||
let p = UnsafeMutablePointer<CGFloat>.allocate(capacity:dashes.count * MemoryLayout<CGFloat>.size)
|
||||
let p = UnsafeMutablePointer<CGFloat>.allocate(capacity: dashes.count * MemoryLayout<CGFloat>.size)
|
||||
for (index, item) in dashes.enumerated() {
|
||||
p[index] = CGFloat(item)
|
||||
}
|
||||
@ -75,11 +87,11 @@ class RenderUtils {
|
||||
} else if let image = node as? Image {
|
||||
return ImageRenderer(image: image, ctx: context, animationCache: animationCache)
|
||||
}
|
||||
fatalError("Unsupported node: \(node)");
|
||||
fatalError("Unsupported node: \(node)")
|
||||
}
|
||||
|
||||
class func loadFont(name: String, size: Int) -> MFont? {
|
||||
let separationSet = CharacterSet(charactersIn:",")
|
||||
let separationSet = CharacterSet(charactersIn: ",")
|
||||
let names = name.components(separatedBy: separationSet)
|
||||
var customFont: MFont? = .none
|
||||
names.forEach { fontName in
|
||||
@ -88,7 +100,7 @@ class RenderUtils {
|
||||
}
|
||||
|
||||
if fontName.characters.first == " " {
|
||||
let index = fontName.index(fontName.startIndex, offsetBy:1)
|
||||
let index = fontName.index(fontName.startIndex, offsetBy: 1)
|
||||
let fixedName = String(fontName.suffix(from: index))
|
||||
customFont = MFont(name: fixedName, size: CGFloat(size))
|
||||
return
|
||||
@ -173,7 +185,7 @@ class RenderUtils {
|
||||
var first = true
|
||||
for part in parts {
|
||||
let point = CGPoint(x: CGFloat(part[0]), y: CGFloat(part[1]))
|
||||
if (first) {
|
||||
if first {
|
||||
path.move(to: point)
|
||||
first = false
|
||||
} else {
|
||||
@ -310,35 +322,35 @@ class RenderUtils {
|
||||
|
||||
// find arc center coordinates and points angles as per
|
||||
// http://www.w3.org/TR/SVG/implnote.html#ArcConversionEndpointToCenter
|
||||
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 x1_ = cos(angle) * (x1 - x) / 2 + sin(angle) * (y1 - y) / 2
|
||||
let y1_ = -1 * sin(angle) * (x1 - x) / 2 + cos(angle) * (y1 - y) / 2
|
||||
// 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_);
|
||||
var bigRoot = (underroot > 0) ? sqrt(underroot) : 0;
|
||||
/ (rx * rx * y1_ * y1_ + ry * ry * x1_ * x1_)
|
||||
var bigRoot = (underroot > 0) ? sqrt(underroot) : 0
|
||||
// TODO: Replace concrete number with 1e-2
|
||||
bigRoot = (bigRoot <= 0.01) ? 0 : bigRoot;
|
||||
let coef: Double = (sweep != largeArc) ? 1 : -1;
|
||||
let cx_ = coef * bigRoot * rx * y1_ / ry;
|
||||
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 = -1 * atan2(y1 - cy, x1 - cx);
|
||||
let t2 = atan2(y - cy, x - cx);
|
||||
var delta = -(t1 + t2);
|
||||
bigRoot = (bigRoot <= 0.01) ? 0 : bigRoot
|
||||
let coef: Double = (sweep != largeArc) ? 1 : -1
|
||||
let cx_ = coef * bigRoot * rx * y1_ / ry
|
||||
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 = -1 * atan2(y1 - cy, x1 - cx)
|
||||
let t2 = atan2(y - cy, x - cx)
|
||||
var delta = -(t1 + t2)
|
||||
// recalculate delta depending on arc. Preserve rotation direction
|
||||
if (largeArc) {
|
||||
let sg = copysign(1.0, delta);
|
||||
if (abs(delta) < Double.pi) {
|
||||
delta = -1 * (sg * M_2_PI - delta);
|
||||
if largeArc {
|
||||
let sg = copysign(1.0, delta)
|
||||
if abs(delta) < Double.pi {
|
||||
delta = -1 * (sg * M_2_PI - delta)
|
||||
}
|
||||
} else {
|
||||
let sg = copysign(1.0, delta);
|
||||
if (abs(delta) > Double.pi) {
|
||||
delta = -1 * (sg * M_2_PI - delta);
|
||||
let sg = copysign(1.0, delta)
|
||||
if abs(delta) > Double.pi {
|
||||
delta = -1 * (sg * M_2_PI - delta)
|
||||
}
|
||||
}
|
||||
E(cx - rx, y: cy - ry, w: 2 * rx, h: 2 * ry, startAngle: t1, arcAngle: delta);
|
||||
E(cx - rx, y: cy - ry, w: 2 * rx, h: 2 * ry, startAngle: t1, arcAngle: delta)
|
||||
setPoint(CGPoint(x: CGFloat(x), y: CGFloat(y)))
|
||||
}
|
||||
}
|
||||
@ -458,8 +470,8 @@ class RenderUtils {
|
||||
}
|
||||
|
||||
class func numToBools(_ num: Double) -> [Bool] {
|
||||
let val: Int = Int(num);
|
||||
return [(val & 1) > 0, (val & 2) > 0];
|
||||
let val: Int = Int(num)
|
||||
return [(val & 1) > 0, (val & 2) > 0]
|
||||
}
|
||||
|
||||
fileprivate class func newCGRect(_ rect: Rect) -> CGRect {
|
||||
|
@ -118,7 +118,7 @@ class ShapeRenderer: NodeRenderer {
|
||||
var first = true
|
||||
for part in parts {
|
||||
let point = CGPoint(x: CGFloat(part[0]), y: CGFloat(part[1]))
|
||||
if (first) {
|
||||
if first {
|
||||
path.move(to: point)
|
||||
first = false
|
||||
} else {
|
||||
@ -255,35 +255,35 @@ class ShapeRenderer: NodeRenderer {
|
||||
|
||||
// find arc center coordinates and points angles as per
|
||||
// http://www.w3.org/TR/SVG/implnote.html#ArcConversionEndpointToCenter
|
||||
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 x1_ = cos(angle) * (x1 - x) / 2 + sin(angle) * (y1 - y) / 2
|
||||
let y1_ = -1 * sin(angle) * (x1 - x) / 2 + cos(angle) * (y1 - y) / 2
|
||||
// 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_);
|
||||
var bigRoot = (underroot > 0) ? sqrt(underroot) : 0;
|
||||
/ (rx * rx * y1_ * y1_ + ry * ry * x1_ * x1_)
|
||||
var bigRoot = (underroot > 0) ? sqrt(underroot) : 0
|
||||
// TODO: Replace concrete number with 1e-2
|
||||
bigRoot = (bigRoot <= 0.01) ? 0 : bigRoot;
|
||||
let coef: Double = (sweep != largeArc) ? 1 : -1;
|
||||
let cx_ = coef * bigRoot * rx * y1_ / ry;
|
||||
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 = -1 * atan2(y1 - cy, x1 - cx);
|
||||
let t2 = atan2(y - cy, x - cx);
|
||||
var delta = -(t1 + t2);
|
||||
bigRoot = (bigRoot <= 0.01) ? 0 : bigRoot
|
||||
let coef: Double = (sweep != largeArc) ? 1 : -1
|
||||
let cx_ = coef * bigRoot * rx * y1_ / ry
|
||||
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 = -1 * atan2(y1 - cy, x1 - cx)
|
||||
let t2 = atan2(y - cy, x - cx)
|
||||
var delta = -(t1 + t2)
|
||||
// recalculate delta depending on arc. Preserve rotation direction
|
||||
if (largeArc) {
|
||||
let sg = copysign(1.0, delta);
|
||||
if (abs(delta) < Double.pi) {
|
||||
delta = -1 * (sg * M_2_PI - delta);
|
||||
if largeArc {
|
||||
let sg = copysign(1.0, delta)
|
||||
if abs(delta) < Double.pi {
|
||||
delta = -1 * (sg * M_2_PI - delta)
|
||||
}
|
||||
} else {
|
||||
let sg = copysign(1.0, delta);
|
||||
if (abs(delta) > Double.pi) {
|
||||
delta = -1 * (sg * M_2_PI - delta);
|
||||
let sg = copysign(1.0, delta)
|
||||
if abs(delta) > Double.pi {
|
||||
delta = -1 * (sg * M_2_PI - delta)
|
||||
}
|
||||
}
|
||||
E(cx - rx, y: cy - ry, w: 2 * rx, h: 2 * ry, startAngle: t1, arcAngle: delta);
|
||||
E(cx - rx, y: cy - ry, w: 2 * rx, h: 2 * ry, startAngle: t1, arcAngle: delta)
|
||||
setPoint(CGPoint(x: CGFloat(x), y: CGFloat(y)))
|
||||
}
|
||||
}
|
||||
@ -403,8 +403,8 @@ class ShapeRenderer: NodeRenderer {
|
||||
}
|
||||
|
||||
fileprivate func numToBools(_ num: Double) -> [Bool] {
|
||||
let val: Int = Int(num);
|
||||
return [(val & 1) > 0, (val & 2) > 0];
|
||||
let val: Int = Int(num)
|
||||
return [(val & 1) > 0, (val & 2) > 0]
|
||||
}
|
||||
|
||||
fileprivate func newCGRect(_ rect: Rect) -> CGRect {
|
||||
@ -458,7 +458,7 @@ class ShapeRenderer: NodeRenderer {
|
||||
}
|
||||
|
||||
fileprivate func drawWithStroke(_ stroke: Stroke, ctx: CGContext?, opacity: Double, shouldStrokePath: Bool = false, path: CGPath? = nil, mode: CGPathDrawingMode) {
|
||||
if let path = path , shouldStrokePath {
|
||||
if let path = path, shouldStrokePath {
|
||||
ctx!.addPath(path)
|
||||
}
|
||||
setStrokeAttributes(stroke, ctx: ctx)
|
||||
|
@ -89,12 +89,17 @@ class TextRenderer: NodeRenderer {
|
||||
}
|
||||
|
||||
fileprivate func getWeight(_ weight: String) -> MFont.Weight? {
|
||||
switch (weight) {
|
||||
case "normal": return MFont.Weight.regular
|
||||
case "bold": return MFont.Weight.bold
|
||||
case "bolder": return MFont.Weight.semibold
|
||||
case "lighter": return MFont.Weight.light
|
||||
default: return .none
|
||||
switch weight {
|
||||
case "normal":
|
||||
return MFont.Weight.regular
|
||||
case "bold":
|
||||
return MFont.Weight.bold
|
||||
case "bolder":
|
||||
return MFont.Weight.semibold
|
||||
case "lighter":
|
||||
return MFont.Weight.light
|
||||
default:
|
||||
return .none
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -294,7 +294,7 @@ open class SVGConstants {
|
||||
]
|
||||
|
||||
open static func valueToColor(_ color: Int) -> String? {
|
||||
return SVGConstants.colorList.filter { (k, v) -> Bool in v == color }.map { (k, v) -> String in k }.first
|
||||
return SVGConstants.colorList.filter { (_, v) -> Bool in v == color }.map { (k, _) -> String in k }.first
|
||||
}
|
||||
|
||||
open static let defaultStrokeLineCap = LineCap.butt
|
||||
|
@ -47,7 +47,6 @@ open class SVGParser {
|
||||
fileprivate var defMasks = [String: Shape]()
|
||||
fileprivate var defClip = [String: Locus]()
|
||||
|
||||
|
||||
fileprivate enum PathCommandType {
|
||||
case moveTo
|
||||
case lineTo
|
||||
@ -105,7 +104,8 @@ open class SVGParser {
|
||||
return .none
|
||||
}
|
||||
|
||||
fileprivate var styleTable: [String:[String:String]] = [:]
|
||||
fileprivate var styleTable: [String: [String: String]] = [:]
|
||||
|
||||
fileprivate func parseStyle(_ styleNode: XMLIndexer) {
|
||||
if let rawStyle = styleNode.element?.text {
|
||||
var styleAttributes: [String: String] = [:]
|
||||
@ -250,6 +250,7 @@ open class SVGParser {
|
||||
}
|
||||
|
||||
var count = 0
|
||||
|
||||
fileprivate func parseTransformationAttribute(_ attributes: String, transform: Transform = Transform()) -> Transform {
|
||||
guard let matcher = SVGParserRegexHelper.getTransformAttributeMatcher() else {
|
||||
return transform
|
||||
@ -312,7 +313,8 @@ open class SVGParser {
|
||||
let transformMatrix = Transform(m11: m11, m12: m12, m21: m21, m22: m22, dx: dx, dy: dy)
|
||||
finalTransform = GeomUtils.concat(t1: transform, t2: transformMatrix)
|
||||
}
|
||||
default: break
|
||||
default:
|
||||
break
|
||||
}
|
||||
let rangeToRemove = NSRange(location: 0, length: matchedAttribute.range.location + matchedAttribute.range.length)
|
||||
let newAttributeString = (attributes as NSString).replacingCharacters(in: rangeToRemove, with: "")
|
||||
@ -335,7 +337,7 @@ open class SVGParser {
|
||||
var red = 0.0
|
||||
var green = 0.0
|
||||
var blue = 0.0
|
||||
if (x.count == 3) {
|
||||
if x.count == 3 {
|
||||
if let r = Double(x[0]), let g = Double(x[1]), let b = Double(x[2]) {
|
||||
blue = b
|
||||
green = g
|
||||
@ -490,7 +492,7 @@ open class SVGParser {
|
||||
if let strokeWidth = styleParts["stroke-width"] {
|
||||
let characterSet = NSCharacterSet.decimalDigits.union(NSCharacterSet.punctuationCharacters).inverted
|
||||
let digitsArray = strokeWidth.components(separatedBy: characterSet)
|
||||
let digits = digitsArray.joined(separator: "")
|
||||
let digits = digitsArray.joined()
|
||||
if let value = NumberFormatter().number(from: digits) {
|
||||
return value.doubleValue
|
||||
}
|
||||
@ -570,8 +572,7 @@ open class SVGParser {
|
||||
fileprivate func parseRect(_ rect: XMLIndexer) -> Locus? {
|
||||
guard let element = rect.element,
|
||||
let width = getDoubleValue(element, attribute: "width"),
|
||||
let height = getDoubleValue(element, attribute: "height")
|
||||
, width > 0 && height > 0 else {
|
||||
let height = getDoubleValue(element, attribute: "height"), width > 0 && height > 0 else {
|
||||
|
||||
return .none
|
||||
}
|
||||
@ -584,14 +585,14 @@ open class SVGParser {
|
||||
return RoundRect(rect: resultRect, rx: rx, ry: ry)
|
||||
}
|
||||
let rOpt = rxOpt ?? ryOpt
|
||||
if let r = rOpt , r >= 0 {
|
||||
if let r = rOpt, r >= 0 {
|
||||
return RoundRect(rect: resultRect, rx: r, ry: r)
|
||||
}
|
||||
return resultRect
|
||||
}
|
||||
|
||||
fileprivate func parseCircle(_ circle: XMLIndexer) -> Circle? {
|
||||
guard let element = circle.element, let r = getDoubleValue(element, attribute: "r") , r > 0 else {
|
||||
guard let element = circle.element, let r = getDoubleValue(element, attribute: "r"), r > 0 else {
|
||||
return .none
|
||||
}
|
||||
|
||||
@ -601,8 +602,7 @@ open class SVGParser {
|
||||
fileprivate func parseEllipse(_ ellipse: XMLIndexer) -> Arc? {
|
||||
guard let element = ellipse.element,
|
||||
let rx = getDoubleValue(element, attribute: "rx"),
|
||||
let ry = getDoubleValue(element, attribute: "ry")
|
||||
, rx > 0 && ry > 0 else {
|
||||
let ry = getDoubleValue(element, attribute: "ry"), rx > 0 && ry > 0 else {
|
||||
return .none
|
||||
}
|
||||
return Arc(
|
||||
@ -747,7 +747,7 @@ open class SVGParser {
|
||||
place: Transform().move(dx: bounds.x + bounds.w, dy: bounds.y), opacity: opacity)
|
||||
collection.append(text)
|
||||
return collectTspans(fullString.substring(from: tagRange.location), collectedTspans: collection,
|
||||
withWhitespace: nextStringWhitespace, textAnchor: textAnchor, fill: fill, stroke:stroke,
|
||||
withWhitespace: nextStringWhitespace, textAnchor: textAnchor, fill: fill, stroke: stroke,
|
||||
opacity: opacity, fontName: fontName, fontSize: fontSize, fontWeight: fontWeight, bounds: text.bounds())
|
||||
}
|
||||
|
||||
@ -894,8 +894,7 @@ open class SVGParser {
|
||||
}
|
||||
|
||||
var parentGradient: Gradient?
|
||||
if let link = element.allAttributes["xlink:href"]?.text.replacingOccurrences(of: " ", with: "")
|
||||
, link.hasPrefix("#") {
|
||||
if let link = element.allAttributes["xlink:href"]?.text.replacingOccurrences(of: " ", with: ""), link.hasPrefix("#") {
|
||||
|
||||
let id = link.replacingOccurrences(of: "#", with: "")
|
||||
parentGradient = defFills[id] as? Gradient
|
||||
@ -928,7 +927,7 @@ open class SVGParser {
|
||||
let y2 = getDoubleValueFromPercentage(element, attribute: "y2") ?? parentLinearGradient?.y2 ?? 0
|
||||
|
||||
var userSpace = false
|
||||
if let gradientUnits = element.allAttributes["gradientUnits"]?.text , gradientUnits == "userSpaceOnUse" {
|
||||
if let gradientUnits = element.allAttributes["gradientUnits"]?.text, gradientUnits == "userSpaceOnUse" {
|
||||
userSpace = true
|
||||
} else if let parent = parentGradient {
|
||||
userSpace = parent.userSpace
|
||||
@ -951,8 +950,7 @@ open class SVGParser {
|
||||
}
|
||||
|
||||
var parentGradient: Gradient?
|
||||
if let link = element.allAttributes["xlink:href"]?.text.replacingOccurrences(of: " ", with: "")
|
||||
, link.hasPrefix("#") {
|
||||
if let link = element.allAttributes["xlink:href"]?.text.replacingOccurrences(of: " ", with: ""), link.hasPrefix("#") {
|
||||
|
||||
let id = link.replacingOccurrences(of: "#", with: "")
|
||||
parentGradient = defFills[id] as? Gradient
|
||||
@ -986,7 +984,7 @@ open class SVGParser {
|
||||
let r = getDoubleValueFromPercentage(element, attribute: "r") ?? parentRadialGradient?.r ?? 0.5
|
||||
|
||||
var userSpace = false
|
||||
if let gradientUnits = element.allAttributes["gradientUnits"]?.text , gradientUnits == "userSpaceOnUse" {
|
||||
if let gradientUnits = element.allAttributes["gradientUnits"]?.text, gradientUnits == "userSpaceOnUse" {
|
||||
userSpace = true
|
||||
} else if let parent = parentGradient {
|
||||
userSpace = parent.userSpace
|
||||
|
@ -6,6 +6,6 @@
|
||||
//
|
||||
//
|
||||
|
||||
enum SVGParserError : Error {
|
||||
enum SVGParserError: Error {
|
||||
case noSuchFile(path: String)
|
||||
}
|
||||
|
@ -53,13 +53,13 @@ open class SVGSerializer {
|
||||
fileprivate let indentPrefixSymbol = " "
|
||||
fileprivate let SVGClipPathName = "clipPath"
|
||||
|
||||
fileprivate let SVGEpsilon:Double = 0.00001
|
||||
fileprivate let SVGDefaultOpacityValueAsAlpha = 1*255
|
||||
fileprivate let SVGEpsilon: Double = 0.00001
|
||||
fileprivate let SVGDefaultOpacityValueAsAlpha = 1 * 255
|
||||
|
||||
fileprivate func indentTextWithOffset(_ text: String, _ offset: Int) -> String {
|
||||
if self.indent != 0 {
|
||||
let prefix = String(repeating: indentPrefixSymbol, count:self.indent)
|
||||
return "\n\(String(repeating: prefix, count:offset))\(text)"
|
||||
let prefix = String(repeating: indentPrefixSymbol, count: self.indent)
|
||||
return "\n\(String(repeating: prefix, count: offset))\(text)"
|
||||
}
|
||||
return text
|
||||
}
|
||||
@ -68,15 +68,15 @@ open class SVGSerializer {
|
||||
return String(Int(a))
|
||||
}
|
||||
|
||||
fileprivate func tag(_ tag: String, _ args: [String:String]=[:], close: Bool=false) -> String {
|
||||
fileprivate func tag(_ tag: String, _ args: [String: String]=[:], close: Bool = false) -> String {
|
||||
let attrs = args.map { "\($0)=\"\($1)\"" }.joined(separator: " ")
|
||||
let closeTag = close ? " />" : ""
|
||||
return "\(tag) \(attrs) \(closeTag)"
|
||||
}
|
||||
|
||||
fileprivate func arcToSVG(_ arc: Arc) -> String {
|
||||
if (arc.shift == 0.0 && abs(arc.extent - Double.pi * 2.0) < SVGEpsilon) {
|
||||
return tag(SVGEllipseOpenTag, ["cx":att(arc.ellipse.cx), "cy":att(arc.ellipse.cy), "rx":att(arc.ellipse.rx), "ry":att(arc.ellipse.ry)])
|
||||
if arc.shift == 0.0 && abs(arc.extent - Double.pi * 2.0) < SVGEpsilon {
|
||||
return tag(SVGEllipseOpenTag, ["cx": att(arc.ellipse.cx), "cy": att(arc.ellipse.cy), "rx": att(arc.ellipse.rx), "ry": att(arc.ellipse.ry)])
|
||||
} else {
|
||||
let rx = arc.ellipse.rx
|
||||
let ry = arc.ellipse.ry
|
||||
@ -98,19 +98,18 @@ open class SVGSerializer {
|
||||
|
||||
var d = "M\(x1),\(y1) "
|
||||
d += "A \(rx),\(ry) 0.0 \(largeArcFlag), \(sweepFlag) \(x2),\(y2)"
|
||||
return tag(SVGPathOpenTag, ["d":d])
|
||||
return tag(SVGPathOpenTag, ["d": d])
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fileprivate func polygonToSVG(_ polygon: Polygon) -> String {
|
||||
let points = polygon.points.flatMap { String($0) }.joined(separator: ",")
|
||||
return tag(SVGPolygonOpenTag, ["points":points])
|
||||
return tag(SVGPolygonOpenTag, ["points": points])
|
||||
}
|
||||
|
||||
fileprivate func polylineToSVG(_ polyline: Polyline) -> String {
|
||||
let points = polyline.points.flatMap { String($0) }.joined(separator: ",")
|
||||
return tag(SVGPolylineOpenTag, ["points":points])
|
||||
return tag(SVGPolylineOpenTag, ["points": points])
|
||||
}
|
||||
|
||||
fileprivate func pathToSVG(_ path: Path) -> String {
|
||||
@ -118,34 +117,34 @@ open class SVGSerializer {
|
||||
for segment in path.segments {
|
||||
if segment.type == .A || segment.type == .a {
|
||||
let flags = RenderUtils.numToBools(segment.data[3])
|
||||
let large:Double = flags[0] ? 1 : 0
|
||||
let sweep:Double = flags[1] ? 1 : 0
|
||||
let large: Double = flags[0] ? 1 : 0
|
||||
let sweep: Double = flags[1] ? 1 : 0
|
||||
d += "\(segment.type) \([segment.data[0], segment.data[1], segment.data[2], large, sweep, segment.data[4], segment.data[5]].flatMap { String(Int($0)) }.joined(separator: " "))"
|
||||
} else {
|
||||
d += "\(segment.type) \(segment.data.flatMap { String(Int($0)) }.joined(separator: " "))"
|
||||
}
|
||||
}
|
||||
return tag(SVGPathOpenTag, ["d":d])
|
||||
return tag(SVGPathOpenTag, ["d": d])
|
||||
}
|
||||
|
||||
fileprivate func lineToSVG(_ line: Line) -> String {
|
||||
return tag(SVGLineOpenTag, ["x1":String(Int(line.x1)), "y1":att(line.y1), "x2":att(line.x2), "y2":att(line.y2)])
|
||||
return tag(SVGLineOpenTag, ["x1": String(Int(line.x1)), "y1": att(line.y1), "x2": att(line.x2), "y2": att(line.y2)])
|
||||
}
|
||||
|
||||
fileprivate func ellipseToSVG(_ ellipse: Ellipse) -> String {
|
||||
return tag(SVGEllipseOpenTag, ["cx":att(ellipse.cx), "cy":att(ellipse.cy), "rx":att(ellipse.rx), "ry":att(ellipse.ry)])
|
||||
return tag(SVGEllipseOpenTag, ["cx": att(ellipse.cx), "cy": att(ellipse.cy), "rx": att(ellipse.rx), "ry": att(ellipse.ry)])
|
||||
}
|
||||
|
||||
fileprivate func circleToSVG(_ circle: Circle) -> String {
|
||||
return tag(SVGCircleOpenTag, ["cx":att(circle.cx), "cy":att(circle.cy), "r":att(circle.r)])
|
||||
return tag(SVGCircleOpenTag, ["cx": att(circle.cx), "cy": att(circle.cy), "r": att(circle.r)])
|
||||
}
|
||||
|
||||
fileprivate func roundRectToSVG(_ roundRect: RoundRect) -> String {
|
||||
return tag(SVGRectOpenTag, ["rx":att(roundRect.rx), "ry":att(roundRect.ry), "width":att(roundRect.rect.w), "height":att(roundRect.rect.h)])
|
||||
return tag(SVGRectOpenTag, ["rx": att(roundRect.rx), "ry": att(roundRect.ry), "width": att(roundRect.rect.w), "height": att(roundRect.rect.h)])
|
||||
}
|
||||
|
||||
fileprivate func rectToSVG(_ rect: Rect) -> String {
|
||||
return tag(SVGRectOpenTag, ["x":att(rect.x), "y":att(rect.y), "width":att(rect.w), "height":att(rect.h)])
|
||||
return tag(SVGRectOpenTag, ["x": att(rect.x), "y": att(rect.y), "width": att(rect.w), "height": att(rect.h)])
|
||||
}
|
||||
|
||||
fileprivate func imageToSVG(_ image: Image) -> String {
|
||||
@ -167,15 +166,18 @@ open class SVGSerializer {
|
||||
}
|
||||
|
||||
fileprivate func alignToSVG(_ align: Align) -> String {
|
||||
switch (align) {
|
||||
case .mid: return " text-anchor=\"middle\" "
|
||||
case .max: return " text-anchor=\"end "
|
||||
default: return ""
|
||||
switch align {
|
||||
case .mid:
|
||||
return " text-anchor=\"middle\" "
|
||||
case .max:
|
||||
return " text-anchor=\"end "
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate func baselineToSVG(_ baseline: Baseline) -> String {
|
||||
if (baseline == .top) {
|
||||
if baseline == .top {
|
||||
return " dominant-baseline=\"text-before-edge\" "
|
||||
}
|
||||
return ""
|
||||
@ -210,7 +212,7 @@ open class SVGSerializer {
|
||||
let r = color.r()
|
||||
let g = color.g()
|
||||
let b = color.b()
|
||||
return "#\(String(format:"%02X%02X%02X", r, g, b))"
|
||||
return "#\(String(format: "%02X%02X%02X", r, g, b))"
|
||||
}
|
||||
}
|
||||
|
||||
@ -229,7 +231,7 @@ open class SVGSerializer {
|
||||
if alpha == SVGDefaultOpacityValueAsAlpha {
|
||||
return .none
|
||||
}
|
||||
return String(Double(alpha)/Double(SVGDefaultOpacityValueAsAlpha))
|
||||
return String(Double(alpha) / Double(SVGDefaultOpacityValueAsAlpha))
|
||||
}
|
||||
|
||||
fileprivate func strokeToSVG(_ stroke: Stroke?) -> String {
|
||||
@ -272,7 +274,7 @@ open class SVGSerializer {
|
||||
}
|
||||
return " transform=\"translate(\(Int(shape.place.dx)),\(Int(shape.place.dy)))\" "
|
||||
}
|
||||
let matrixArgs = [shape.place.m11, shape.place.m12, shape.place.m21, shape.place.m22, shape.place.dx, shape.place.dy].map{ String($0) }.joined(separator: ",")
|
||||
let matrixArgs = [shape.place.m11, shape.place.m12, shape.place.m21, shape.place.m22, shape.place.dx, shape.place.dy].map { String($0) }.joined(separator: ",")
|
||||
return " transform=\"matrix(\(matrixArgs))\" "
|
||||
}
|
||||
|
||||
@ -302,6 +304,7 @@ open class SVGSerializer {
|
||||
}
|
||||
|
||||
fileprivate var defs: String = ""
|
||||
|
||||
fileprivate func getDefs() -> String {
|
||||
if defs.isEmpty {
|
||||
return ""
|
||||
@ -310,7 +313,8 @@ open class SVGSerializer {
|
||||
}
|
||||
|
||||
fileprivate var clipPathCount: Int = 0
|
||||
fileprivate func addClipToDefs(_ clip:Locus) {
|
||||
|
||||
fileprivate func addClipToDefs(_ clip: Locus) {
|
||||
clipPathCount += 1
|
||||
defs += "<clipPath id=\"\(SVGClipPathName)\(clipPathCount)\">" + locusToSVG(clip) + SVGGenericCloseTag + "</clipPath>"
|
||||
}
|
||||
@ -334,7 +338,6 @@ open class SVGSerializer {
|
||||
return result
|
||||
}
|
||||
|
||||
|
||||
fileprivate func serialize(node: Node, offset: Int) -> String {
|
||||
if let shape = node as? Shape {
|
||||
return indentTextWithOffset(macawShapeToSvgShape(macawShape: shape), offset)
|
||||
@ -359,7 +362,7 @@ open class SVGSerializer {
|
||||
return "SVGUndefinedTag \(node)"
|
||||
}
|
||||
|
||||
fileprivate func serialize(node:Node) -> String {
|
||||
fileprivate func serialize(node: Node) -> String {
|
||||
var optionalSection = ""
|
||||
if let w = width {
|
||||
optionalSection += "width=\"\(w)\""
|
||||
@ -378,7 +381,7 @@ open class SVGSerializer {
|
||||
}
|
||||
|
||||
open class func serialize(node: Node, width: Int? = nil, height: Int? = nil, id: String? = nil) -> String {
|
||||
return SVGSerializer(width: width, height:height, id: id).serialize(node: node)
|
||||
return SVGSerializer(width: width, height: height, id: id).serialize(node: node)
|
||||
}
|
||||
|
||||
}
|
||||
|
2
Source/thirdparty/CAAnimationClosure.swift
vendored
2
Source/thirdparty/CAAnimationClosure.swift
vendored
@ -9,7 +9,7 @@
|
||||
import QuartzCore
|
||||
|
||||
/// CAAnimation Delegation class implementation
|
||||
class CAAnimationDelegateImpl:NSObject, CAAnimationDelegate {
|
||||
class CAAnimationDelegateImpl: NSObject, CAAnimationDelegate {
|
||||
/// start: A block (closure) object to be executed when the animation starts. This block has no return value and takes no argument.
|
||||
var start: (() -> Void)?
|
||||
|
||||
|
@ -13,15 +13,14 @@ import Foundation
|
||||
#endif
|
||||
|
||||
var imagesMap = [String: MImage]()
|
||||
|
||||
public extension MImage {
|
||||
public func image( xAlign: Align = .min, yAlign: Align = .min, aspectRatio: AspectRatio = .none, w: Int = 0, h: Int = 0, place: Transform = Transform.identity, opaque: Bool = true, opacity: Double = 1, clip: Locus? = nil, effect: Effect? = nil, visible: Bool = true, tag: [String] = []) -> Image {
|
||||
|
||||
var oldId: String?
|
||||
for key in imagesMap.keys {
|
||||
if self === imagesMap[key] {
|
||||
for key in imagesMap.keys where self === imagesMap[key] {
|
||||
oldId = key
|
||||
}
|
||||
}
|
||||
|
||||
let id = oldId ?? UUID().uuidString
|
||||
imagesMap[id] = self
|
||||
|
@ -96,7 +96,7 @@ open class MacawView: MView, MGestureRecognizerDelegate {
|
||||
}
|
||||
|
||||
public convenience init(node: Node, frame: CGRect) {
|
||||
self.init(frame:frame)
|
||||
self.init(frame: frame)
|
||||
|
||||
self.node = node
|
||||
nodesMap.add(node, view: self)
|
||||
@ -157,7 +157,7 @@ open class MacawView: MView, MGestureRecognizerDelegate {
|
||||
renderer?.render(force: false, opacity: node.opacity)
|
||||
}
|
||||
|
||||
private func localContext( _ callback: (CGContext) -> ()) {
|
||||
private func localContext( _ callback: (CGContext) -> Void) {
|
||||
MGraphicsBeginImageContextWithOptions(self.bounds.size, false, 1.0)
|
||||
if let ctx = MGraphicsGetCurrentContext() {
|
||||
callback(ctx)
|
||||
@ -167,11 +167,11 @@ open class MacawView: MView, MGestureRecognizerDelegate {
|
||||
|
||||
// MARK: - Touches
|
||||
|
||||
override func mTouchesBegan(_ touches: [MTouchEvent]) {
|
||||
override func mTouchesBegan(_ touches: [MTouchEvent]) {
|
||||
|
||||
if !self.node.shouldCheckForPressed() &&
|
||||
!self.node.shouldCheckForMoved() &&
|
||||
!self.node.shouldCheckForReleased (){
|
||||
!self.node.shouldCheckForReleased () {
|
||||
return
|
||||
}
|
||||
|
||||
@ -245,7 +245,6 @@ override func mTouchesBegan(_ touches: [MTouchEvent]) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override func mTouchesCancelled(_ touches: [MTouchEvent]) {
|
||||
touchesEnded(touches: touches)
|
||||
}
|
||||
@ -273,9 +272,11 @@ override func mTouchesBegan(_ touches: [MTouchEvent]) {
|
||||
node.handleTouchReleased(touchEvent)
|
||||
if let index = touchesOfNode[node]?.index(of: touch) {
|
||||
touchesOfNode[node]?.remove(at: index)
|
||||
// swiftlint:disable empty_count
|
||||
if let count = touchesOfNode[node]?.count, count == 0 {
|
||||
touchesOfNode.removeValue(forKey: node)
|
||||
}
|
||||
// swiftlint:enable empty_count
|
||||
}
|
||||
}
|
||||
|
||||
@ -312,7 +313,6 @@ override func mTouchesBegan(_ touches: [MTouchEvent]) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
foundNodes.forEach { node in
|
||||
let inverted = node.place.invert()!
|
||||
let loc = location.applying(RenderUtils.mapTransform(inverted))
|
||||
@ -389,7 +389,6 @@ override func mTouchesBegan(_ touches: [MTouchEvent]) {
|
||||
if recognizer.state == .began {
|
||||
let location = recognizer.location(in: self)
|
||||
|
||||
|
||||
localContext { ctx in
|
||||
guard let foundNode = renderer.findNodeAt(location: location, ctx: ctx) else {
|
||||
return
|
||||
|
@ -1,4 +1,3 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
#if os(iOS)
|
||||
@ -83,7 +82,6 @@ class NodesMap {
|
||||
add(to, view: view)
|
||||
}
|
||||
|
||||
|
||||
// Replacing node in hosting view if needed
|
||||
guard let hostingNode = hostingView?.node else {
|
||||
return
|
||||
|
@ -13,7 +13,7 @@ class MTouchEvent: Hashable {
|
||||
return id.hashValue
|
||||
}
|
||||
|
||||
public static func ==(lhs: MTouchEvent, rhs: MTouchEvent) -> Bool {
|
||||
public static func == (lhs: MTouchEvent, rhs: MTouchEvent) -> Bool {
|
||||
return lhs.id == rhs.id
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user