mirror of
https://github.com/exyte/Macaw.git
synced 2024-09-11 13:15:35 +03:00
Merge branch 'macos_support'
# Conflicts: # Source/animation/AnimationImpl.swift # Source/animation/AnimationProducer.swift # Source/animation/types/AnimationSequence.swift # Source/animation/types/CombineAnimation.swift # Source/animation/types/ContentsAnimation.swift # Source/animation/types/MorphingAnimation.swift # Source/animation/types/OpacityAnimation.swift # Source/animation/types/ShapeAnimation.swift # Source/animation/types/TransformAnimation.swift # Source/animation/types/animation_generators/MorphingGenerator.swift # Source/animation/types/animation_generators/OpacityGenerator.swift # Source/animation/types/animation_generators/ShapeAnimationGenerator.swift # Source/animation/types/animation_generators/TransformGenerator.swift # Source/model/scene/Node.swift # Source/render/NodeRenderer.swift # Source/svg/SVGConstants.swift # Source/svg/SVGParser.swift # Source/views/NodesMap.swift
This commit is contained in:
commit
ffff19619e
480
Example-macOS/Example-macOS.xcodeproj/project.pbxproj
Normal file
480
Example-macOS/Example-macOS.xcodeproj/project.pbxproj
Normal file
@ -0,0 +1,480 @@
|
||||
// !$*UTF8*$!
|
||||
{
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 46;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
970AB811D179560D74930D39 /* Pods_Example_macOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5184A00051CAC5E360198B48 /* Pods_Example_macOS.framework */; };
|
||||
A72862CB1F4308A50033893D /* AnimationsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A72862CA1F4308A50033893D /* AnimationsViewController.swift */; };
|
||||
A72862CE1F430DF00033893D /* EasingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A72862CC1F430DF00033893D /* EasingViewController.swift */; };
|
||||
A753C9E81F3DB18A006615A4 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = A753C9E71F3DB18A006615A4 /* AppDelegate.swift */; };
|
||||
A753C9EA1F3DB18A006615A4 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A753C9E91F3DB18A006615A4 /* ViewController.swift */; };
|
||||
A753C9EC1F3DB18A006615A4 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A753C9EB1F3DB18A006615A4 /* Assets.xcassets */; };
|
||||
A753C9EF1F3DB18A006615A4 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = A753C9ED1F3DB18A006615A4 /* Main.storyboard */; };
|
||||
A75939A21F41C54E000CE329 /* ShapesExampleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A75939A11F41C54E000CE329 /* ShapesExampleView.swift */; };
|
||||
A75939A51F41C571000CE329 /* MorphingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A75939A41F41C571000CE329 /* MorphingView.swift */; };
|
||||
A75939A81F41C5A8000CE329 /* TransformExampleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A75939A71F41C5A8000CE329 /* TransformExampleView.swift */; };
|
||||
A768EAD81F42C98E00F22A17 /* EventsExampleController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A768EAD71F42C98E00F22A17 /* EventsExampleController.swift */; };
|
||||
A768EADC1F42CC7C00F22A17 /* EasingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A768EADB1F42CC7C00F22A17 /* EasingView.swift */; };
|
||||
A768EADE1F42CCBC00F22A17 /* AnimationsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A768EADD1F42CCBC00F22A17 /* AnimationsView.swift */; };
|
||||
A768EAE21F42EDAE00F22A17 /* tiger.svg in Resources */ = {isa = PBXBuildFile; fileRef = A768EAE11F42EDAE00F22A17 /* tiger.svg */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
5184A00051CAC5E360198B48 /* Pods_Example_macOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Example_macOS.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
A72862CA1F4308A50033893D /* AnimationsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AnimationsViewController.swift; path = Examples/Animations/AnimationsViewController.swift; sourceTree = "<group>"; };
|
||||
A72862CC1F430DF00033893D /* EasingViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = EasingViewController.swift; path = Examples/Easing/EasingViewController.swift; sourceTree = "<group>"; };
|
||||
A753C9E41F3DB18A006615A4 /* Example-macOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Example-macOS.app"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
A753C9E71F3DB18A006615A4 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||
A753C9E91F3DB18A006615A4 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = "<group>"; };
|
||||
A753C9EB1F3DB18A006615A4 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||
A753C9EE1F3DB18A006615A4 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
|
||||
A753C9F01F3DB18A006615A4 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
A75939A11F41C54E000CE329 /* ShapesExampleView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ShapesExampleView.swift; path = Examples/Shapes/ShapesExampleView.swift; sourceTree = "<group>"; };
|
||||
A75939A41F41C571000CE329 /* MorphingView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = MorphingView.swift; path = Examples/Morphing/MorphingView.swift; sourceTree = "<group>"; };
|
||||
A75939A71F41C5A8000CE329 /* TransformExampleView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TransformExampleView.swift; path = Examples/Transform/TransformExampleView.swift; sourceTree = "<group>"; };
|
||||
A768EAD71F42C98E00F22A17 /* EventsExampleController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = EventsExampleController.swift; path = Examples/Events/EventsExampleController.swift; sourceTree = "<group>"; };
|
||||
A768EADB1F42CC7C00F22A17 /* EasingView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = EasingView.swift; path = Examples/Easing/EasingView.swift; sourceTree = "<group>"; };
|
||||
A768EADD1F42CCBC00F22A17 /* AnimationsView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AnimationsView.swift; path = Examples/Animations/AnimationsView.swift; sourceTree = "<group>"; };
|
||||
A768EAE11F42EDAE00F22A17 /* tiger.svg */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; name = tiger.svg; path = "Example-macOS/Assets/SVG/tiger.svg"; sourceTree = "<group>"; };
|
||||
B752613023F25BBB88A17503 /* Pods-Example-macOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Example-macOS.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Example-macOS/Pods-Example-macOS.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
BEA3A0212E620A41C8362253 /* Pods-Example-macOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Example-macOS.release.xcconfig"; path = "Pods/Target Support Files/Pods-Example-macOS/Pods-Example-macOS.release.xcconfig"; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
A753C9E11F3DB18A006615A4 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
970AB811D179560D74930D39 /* Pods_Example_macOS.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
1CB6DE34952A084DD8BB425B /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
5184A00051CAC5E360198B48 /* Pods_Example_macOS.framework */,
|
||||
);
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
4F8946156C3F28DC7B262776 /* Pods */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
B752613023F25BBB88A17503 /* Pods-Example-macOS.debug.xcconfig */,
|
||||
BEA3A0212E620A41C8362253 /* Pods-Example-macOS.release.xcconfig */,
|
||||
);
|
||||
name = Pods;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
A753C9DB1F3DB18A006615A4 = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
A768EADF1F42ED9700F22A17 /* Assets */,
|
||||
A753C9E61F3DB18A006615A4 /* Example-macOS */,
|
||||
A753C9E51F3DB18A006615A4 /* Products */,
|
||||
4F8946156C3F28DC7B262776 /* Pods */,
|
||||
1CB6DE34952A084DD8BB425B /* Frameworks */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
A753C9E51F3DB18A006615A4 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
A753C9E41F3DB18A006615A4 /* Example-macOS.app */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
A753C9E61F3DB18A006615A4 /* Example-macOS */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
A759399F1F41C51A000CE329 /* Examples */,
|
||||
A753C9E71F3DB18A006615A4 /* AppDelegate.swift */,
|
||||
A753C9E91F3DB18A006615A4 /* ViewController.swift */,
|
||||
A753C9ED1F3DB18A006615A4 /* Main.storyboard */,
|
||||
A753C9EB1F3DB18A006615A4 /* Assets.xcassets */,
|
||||
A753C9F01F3DB18A006615A4 /* Info.plist */,
|
||||
);
|
||||
path = "Example-macOS";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
A759399F1F41C51A000CE329 /* Examples */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
A75939A01F41C544000CE329 /* Shapes */,
|
||||
A75939A61F41C58D000CE329 /* Transform */,
|
||||
A768EADA1F42CBF600F22A17 /* Animations */,
|
||||
A75939A91F41CE45000CE329 /* Easing */,
|
||||
A75939A31F41C566000CE329 /* Morphing */,
|
||||
A768EAD61F42C97900F22A17 /* Events */,
|
||||
);
|
||||
name = Examples;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
A75939A01F41C544000CE329 /* Shapes */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
A75939A11F41C54E000CE329 /* ShapesExampleView.swift */,
|
||||
);
|
||||
name = Shapes;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
A75939A31F41C566000CE329 /* Morphing */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
A75939A41F41C571000CE329 /* MorphingView.swift */,
|
||||
);
|
||||
name = Morphing;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
A75939A61F41C58D000CE329 /* Transform */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
A75939A71F41C5A8000CE329 /* TransformExampleView.swift */,
|
||||
);
|
||||
name = Transform;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
A75939A91F41CE45000CE329 /* Easing */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
A768EADB1F42CC7C00F22A17 /* EasingView.swift */,
|
||||
A72862CC1F430DF00033893D /* EasingViewController.swift */,
|
||||
);
|
||||
name = Easing;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
A768EAD61F42C97900F22A17 /* Events */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
A768EAD71F42C98E00F22A17 /* EventsExampleController.swift */,
|
||||
);
|
||||
name = Events;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
A768EADA1F42CBF600F22A17 /* Animations */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
A768EADD1F42CCBC00F22A17 /* AnimationsView.swift */,
|
||||
A72862CA1F4308A50033893D /* AnimationsViewController.swift */,
|
||||
);
|
||||
name = Animations;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
A768EADF1F42ED9700F22A17 /* Assets */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
A768EAE01F42EDA300F22A17 /* SVG */,
|
||||
);
|
||||
name = Assets;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
A768EAE01F42EDA300F22A17 /* SVG */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
A768EAE11F42EDAE00F22A17 /* tiger.svg */,
|
||||
);
|
||||
name = SVG;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
A753C9E31F3DB18A006615A4 /* Example-macOS */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = A753C9F31F3DB18A006615A4 /* Build configuration list for PBXNativeTarget "Example-macOS" */;
|
||||
buildPhases = (
|
||||
1F28568372F4741200F4770C /* [CP] Check Pods Manifest.lock */,
|
||||
A753C9E01F3DB18A006615A4 /* Sources */,
|
||||
A753C9E11F3DB18A006615A4 /* Frameworks */,
|
||||
A753C9E21F3DB18A006615A4 /* Resources */,
|
||||
D4AD26F62FE37F7476EC4BCA /* [CP] Embed Pods Frameworks */,
|
||||
3AE877354B4133CFC7CAF0DD /* [CP] Copy Pods Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = "Example-macOS";
|
||||
productName = "Example-macOS";
|
||||
productReference = A753C9E41F3DB18A006615A4 /* Example-macOS.app */;
|
||||
productType = "com.apple.product-type.application";
|
||||
};
|
||||
/* End PBXNativeTarget section */
|
||||
|
||||
/* Begin PBXProject section */
|
||||
A753C9DC1F3DB18A006615A4 /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastSwiftUpdateCheck = 0830;
|
||||
LastUpgradeCheck = 0830;
|
||||
TargetAttributes = {
|
||||
A753C9E31F3DB18A006615A4 = {
|
||||
CreatedOnToolsVersion = 8.3.3;
|
||||
ProvisioningStyle = Automatic;
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = A753C9DF1F3DB18A006615A4 /* Build configuration list for PBXProject "Example-macOS" */;
|
||||
compatibilityVersion = "Xcode 3.2";
|
||||
developmentRegion = English;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
en,
|
||||
Base,
|
||||
);
|
||||
mainGroup = A753C9DB1F3DB18A006615A4;
|
||||
productRefGroup = A753C9E51F3DB18A006615A4 /* Products */;
|
||||
projectDirPath = "";
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
A753C9E31F3DB18A006615A4 /* Example-macOS */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
||||
/* Begin PBXResourcesBuildPhase section */
|
||||
A753C9E21F3DB18A006615A4 /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
A753C9EC1F3DB18A006615A4 /* Assets.xcassets in Resources */,
|
||||
A753C9EF1F3DB18A006615A4 /* Main.storyboard in Resources */,
|
||||
A768EAE21F42EDAE00F22A17 /* tiger.svg in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXShellScriptBuildPhase section */
|
||||
1F28568372F4741200F4770C /* [CP] Check Pods Manifest.lock */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
name = "[CP] Check Pods Manifest.lock";
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
3AE877354B4133CFC7CAF0DD /* [CP] Copy Pods Resources */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
name = "[CP] Copy Pods Resources";
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Example-macOS/Pods-Example-macOS-resources.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
D4AD26F62FE37F7476EC4BCA /* [CP] Embed Pods Frameworks */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
name = "[CP] Embed Pods Frameworks";
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Example-macOS/Pods-Example-macOS-frameworks.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
/* End PBXShellScriptBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
A753C9E01F3DB18A006615A4 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
A75939A51F41C571000CE329 /* MorphingView.swift in Sources */,
|
||||
A753C9EA1F3DB18A006615A4 /* ViewController.swift in Sources */,
|
||||
A75939A21F41C54E000CE329 /* ShapesExampleView.swift in Sources */,
|
||||
A753C9E81F3DB18A006615A4 /* AppDelegate.swift in Sources */,
|
||||
A768EAD81F42C98E00F22A17 /* EventsExampleController.swift in Sources */,
|
||||
A72862CE1F430DF00033893D /* EasingViewController.swift in Sources */,
|
||||
A72862CB1F4308A50033893D /* AnimationsViewController.swift in Sources */,
|
||||
A768EADE1F42CCBC00F22A17 /* AnimationsView.swift in Sources */,
|
||||
A75939A81F41C5A8000CE329 /* TransformExampleView.swift in Sources */,
|
||||
A768EADC1F42CC7C00F22A17 /* EasingView.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXVariantGroup section */
|
||||
A753C9ED1F3DB18A006615A4 /* Main.storyboard */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
A753C9EE1F3DB18A006615A4 /* Base */,
|
||||
);
|
||||
name = Main.storyboard;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXVariantGroup section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
A753C9F11F3DB18A006615A4 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
CODE_SIGN_IDENTITY = "-";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"DEBUG=1",
|
||||
"$(inherited)",
|
||||
);
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.12;
|
||||
MTL_ENABLE_DEBUG_INFO = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = macosx;
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
A753C9F21F3DB18A006615A4 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
CODE_SIGN_IDENTITY = "-";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.12;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
SDKROOT = macosx;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
A753C9F41F3DB18A006615A4 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = B752613023F25BBB88A17503 /* Pods-Example-macOS.debug.xcconfig */;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
INFOPLIST_FILE = "Example-macOS/Info.plist";
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.exyte.Example-macOS";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_VERSION = 3.0;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
A753C9F51F3DB18A006615A4 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = BEA3A0212E620A41C8362253 /* Pods-Example-macOS.release.xcconfig */;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
INFOPLIST_FILE = "Example-macOS/Info.plist";
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.exyte.Example-macOS";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_VERSION = 3.0;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
A753C9DF1F3DB18A006615A4 /* Build configuration list for PBXProject "Example-macOS" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
A753C9F11F3DB18A006615A4 /* Debug */,
|
||||
A753C9F21F3DB18A006615A4 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
A753C9F31F3DB18A006615A4 /* Build configuration list for PBXNativeTarget "Example-macOS" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
A753C9F41F3DB18A006615A4 /* Debug */,
|
||||
A753C9F51F3DB18A006615A4 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
};
|
||||
rootObject = A753C9DC1F3DB18A006615A4 /* Project object */;
|
||||
}
|
26
Example-macOS/Example-macOS/AppDelegate.swift
Normal file
26
Example-macOS/Example-macOS/AppDelegate.swift
Normal file
@ -0,0 +1,26 @@
|
||||
//
|
||||
// AppDelegate.swift
|
||||
// Example-macOS
|
||||
//
|
||||
// Created by Daniil Manin on 8/11/17.
|
||||
//
|
||||
//
|
||||
|
||||
import Cocoa
|
||||
|
||||
@NSApplicationMain
|
||||
class AppDelegate: NSObject, NSApplicationDelegate {
|
||||
|
||||
|
||||
|
||||
func applicationDidFinishLaunching(_ aNotification: Notification) {
|
||||
// Insert code here to initialize your application
|
||||
}
|
||||
|
||||
func applicationWillTerminate(_ aNotification: Notification) {
|
||||
// Insert code here to tear down your application
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,58 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "mac",
|
||||
"size" : "16x16",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "mac",
|
||||
"size" : "16x16",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "mac",
|
||||
"size" : "32x32",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "mac",
|
||||
"size" : "32x32",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "mac",
|
||||
"size" : "128x128",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "mac",
|
||||
"size" : "128x128",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "mac",
|
||||
"size" : "256x256",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "mac",
|
||||
"size" : "256x256",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "mac",
|
||||
"size" : "512x512",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "mac",
|
||||
"size" : "512x512",
|
||||
"scale" : "2x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
729
Example-macOS/Example-macOS/Assets/SVG/tiger.svg
Normal file
729
Example-macOS/Example-macOS/Assets/SVG/tiger.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 94 KiB |
343
Example-macOS/Example-macOS/Base.lproj/Main.storyboard
Normal file
343
Example-macOS/Example-macOS/Base.lproj/Main.storyboard
Normal file
@ -0,0 +1,343 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.Storyboard.XIB" version="3.0" toolsVersion="12121" systemVersion="16G29" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" initialViewController="B8D-0N-5wS">
|
||||
<dependencies>
|
||||
<deployment identifier="macosx"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="12121"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
<!--Application-->
|
||||
<scene sceneID="JPo-4y-FX3">
|
||||
<objects>
|
||||
<application id="hnw-xV-0zn" sceneMemberID="viewController">
|
||||
<menu key="mainMenu" title="Main Menu" systemMenu="main" id="AYu-sK-qS6">
|
||||
<items>
|
||||
<menuItem title="Example-macOS" id="1Xt-HY-uBw">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<menu key="submenu" title="Example-macOS" systemMenu="apple" id="uQy-DD-JDr">
|
||||
<items>
|
||||
<menuItem title="About Example-macOS" id="5kV-Vb-QxS">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="orderFrontStandardAboutPanel:" target="Ady-hI-5gd" id="Exp-CZ-Vem"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem isSeparatorItem="YES" id="VOq-y0-SEH"/>
|
||||
<menuItem title="Preferences…" keyEquivalent="," id="BOF-NM-1cW"/>
|
||||
<menuItem isSeparatorItem="YES" id="wFC-TO-SCJ"/>
|
||||
<menuItem title="Services" id="NMo-om-nkz">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<menu key="submenu" title="Services" systemMenu="services" id="hz9-B4-Xy5"/>
|
||||
</menuItem>
|
||||
<menuItem isSeparatorItem="YES" id="4je-JR-u6R"/>
|
||||
<menuItem title="Hide Example-macOS" keyEquivalent="h" id="Olw-nP-bQN">
|
||||
<connections>
|
||||
<action selector="hide:" target="Ady-hI-5gd" id="PnN-Uc-m68"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Hide Others" keyEquivalent="h" id="Vdr-fp-XzO">
|
||||
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
|
||||
<connections>
|
||||
<action selector="hideOtherApplications:" target="Ady-hI-5gd" id="VT4-aY-XCT"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Show All" id="Kd2-mp-pUS">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="unhideAllApplications:" target="Ady-hI-5gd" id="Dhg-Le-xox"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem isSeparatorItem="YES" id="kCx-OE-vgT"/>
|
||||
<menuItem title="Quit Example-macOS" keyEquivalent="q" id="4sb-4s-VLi">
|
||||
<connections>
|
||||
<action selector="terminate:" target="Ady-hI-5gd" id="Te7-pn-YzF"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
</menuItem>
|
||||
<menuItem title="File" id="dMs-cI-mzQ">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
</menuItem>
|
||||
<menuItem title="Edit" id="5QF-Oa-p0T">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
</menuItem>
|
||||
<menuItem title="Format" id="jxT-CU-nIS">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
</menuItem>
|
||||
<menuItem title="View" id="H8h-7b-M4v">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
</menuItem>
|
||||
<menuItem title="Window" id="aUF-d1-5bR">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
</menuItem>
|
||||
<menuItem title="Help" id="wpr-3q-Mcd">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
<connections>
|
||||
<outlet property="delegate" destination="Voe-Tx-rLC" id="PrD-fu-P6m"/>
|
||||
</connections>
|
||||
</application>
|
||||
<customObject id="Voe-Tx-rLC" customClass="AppDelegate" customModule="Example_macOS" customModuleProvider="target"/>
|
||||
<customObject id="Ady-hI-5gd" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="58" y="-294"/>
|
||||
</scene>
|
||||
<!--Window Controller-->
|
||||
<scene sceneID="R2V-B0-nI4">
|
||||
<objects>
|
||||
<windowController id="B8D-0N-5wS" sceneMemberID="viewController">
|
||||
<window key="window" title="Macaw-Example" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" oneShot="NO" releasedWhenClosed="NO" showsToolbarButton="NO" visibleAtLaunch="NO" animationBehavior="default" id="IQv-IB-iLA">
|
||||
<windowStyleMask key="styleMask" titled="YES" closable="YES"/>
|
||||
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
|
||||
<rect key="contentRect" x="196" y="240" width="600" height="500"/>
|
||||
<rect key="screenRect" x="0.0" y="0.0" width="1680" height="1027"/>
|
||||
<value key="minSize" type="size" width="600" height="500"/>
|
||||
<value key="maxSize" type="size" width="600" height="500"/>
|
||||
</window>
|
||||
<connections>
|
||||
<segue destination="hdB-7F-R9Q" kind="relationship" relationship="window.shadowedContentViewController" id="2sy-Hm-TOK"/>
|
||||
</connections>
|
||||
</windowController>
|
||||
<customObject id="Oky-zY-oP4" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="57" y="91"/>
|
||||
</scene>
|
||||
<!--Tab View Controller-->
|
||||
<scene sceneID="HCD-4m-c8h">
|
||||
<objects>
|
||||
<tabViewController selectedTabViewItemIndex="0" id="hdB-7F-R9Q" sceneMemberID="viewController">
|
||||
<tabViewItems>
|
||||
<tabViewItem identifier="" id="3QN-7z-LrX"/>
|
||||
<tabViewItem id="1e3-gs-UK8"/>
|
||||
<tabViewItem id="Kue-lk-AJ2"/>
|
||||
<tabViewItem id="lLO-HO-JXp"/>
|
||||
<tabViewItem id="cOY-ae-H1s"/>
|
||||
<tabViewItem id="h85-ch-mEO"/>
|
||||
<tabViewItem id="fd7-0D-v5P"/>
|
||||
</tabViewItems>
|
||||
<tabView key="tabView" type="noTabsNoBorder" id="2WP-RT-S1E">
|
||||
<rect key="frame" x="-57" y="5" width="615" height="95"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<font key="font" metaFont="message"/>
|
||||
<tabViewItems/>
|
||||
</tabView>
|
||||
<connections>
|
||||
<segue destination="GQJ-Hp-Pf9" kind="relationship" relationship="tabItems" id="NpD-f5-aHg"/>
|
||||
<segue destination="jao-64-FWC" kind="relationship" relationship="tabItems" id="2YP-Vc-nYb"/>
|
||||
<segue destination="mWu-e3-ocB" kind="relationship" relationship="tabItems" id="Elo-Zo-5ec"/>
|
||||
<segue destination="iWh-Ne-7Ns" kind="relationship" relationship="tabItems" id="b7l-i9-xc7"/>
|
||||
<segue destination="6Ok-1N-J6E" kind="relationship" relationship="tabItems" id="Oei-AM-VA1"/>
|
||||
<segue destination="Rn8-Li-WZ2" kind="relationship" relationship="tabItems" id="XnE-5e-LQB"/>
|
||||
<segue destination="9aj-uf-eJX" kind="relationship" relationship="tabItems" id="dm1-xg-c0C"/>
|
||||
</connections>
|
||||
</tabViewController>
|
||||
<customObject id="vzO-zk-Zwd" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="58" y="541"/>
|
||||
</scene>
|
||||
<!--Shapes-->
|
||||
<scene sceneID="X9O-0j-kca">
|
||||
<objects>
|
||||
<viewController title="Shapes" id="GQJ-Hp-Pf9" sceneMemberID="viewController">
|
||||
<view key="view" id="To1-Fe-AtI">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="500"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<customView translatesAutoresizingMaskIntoConstraints="NO" id="D3z-wL-l2P" customClass="ShapesExampleView" customModule="Example_macOS" customModuleProvider="target">
|
||||
<rect key="frame" x="125" y="0.0" width="350" height="480"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="350" id="2E2-Lj-XMk"/>
|
||||
</constraints>
|
||||
</customView>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstAttribute="bottom" secondItem="D3z-wL-l2P" secondAttribute="bottom" id="8Im-Qx-btY"/>
|
||||
<constraint firstItem="D3z-wL-l2P" firstAttribute="top" secondItem="To1-Fe-AtI" secondAttribute="top" constant="20" id="8w2-gW-Wjf"/>
|
||||
<constraint firstItem="D3z-wL-l2P" firstAttribute="centerX" secondItem="To1-Fe-AtI" secondAttribute="centerX" id="Sg0-C8-DDx"/>
|
||||
</constraints>
|
||||
</view>
|
||||
</viewController>
|
||||
<customObject id="EYN-Mf-krY" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="57" y="1044"/>
|
||||
</scene>
|
||||
<!--Animations-->
|
||||
<scene sceneID="mQS-s7-7Qq">
|
||||
<objects>
|
||||
<viewController title="Animations" id="mWu-e3-ocB" customClass="AnimationsViewController" customModule="Example_macOS" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<view key="view" id="K6m-Lx-cTz">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="500"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<customView translatesAutoresizingMaskIntoConstraints="NO" id="1Rb-D3-XW9" customClass="AnimationsView" customModule="Example_macOS" customModuleProvider="target">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="500"/>
|
||||
</customView>
|
||||
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="bPP-dr-CnF">
|
||||
<rect key="frame" x="260" y="39" width="80" height="19"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="18" id="3MY-fR-U9d"/>
|
||||
<constraint firstAttribute="width" constant="80" id="Te3-mr-Bce"/>
|
||||
</constraints>
|
||||
<buttonCell key="cell" type="roundRect" title="Start" bezelStyle="roundedRect" alignment="center" state="on" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="wkK-UK-u12">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="cellTitle"/>
|
||||
</buttonCell>
|
||||
<connections>
|
||||
<action selector="startAnimationsAction:" target="mWu-e3-ocB" id="8K1-bW-xw9"/>
|
||||
</connections>
|
||||
</button>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstAttribute="bottom" secondItem="bPP-dr-CnF" secondAttribute="bottom" constant="40" id="94k-Vi-ybb"/>
|
||||
<constraint firstAttribute="trailing" secondItem="1Rb-D3-XW9" secondAttribute="trailing" id="9cE-er-ZBS"/>
|
||||
<constraint firstItem="1Rb-D3-XW9" firstAttribute="leading" secondItem="K6m-Lx-cTz" secondAttribute="leading" id="J8j-Tu-jSk"/>
|
||||
<constraint firstItem="1Rb-D3-XW9" firstAttribute="top" secondItem="K6m-Lx-cTz" secondAttribute="top" id="SdM-su-R3z"/>
|
||||
<constraint firstItem="bPP-dr-CnF" firstAttribute="centerX" secondItem="K6m-Lx-cTz" secondAttribute="centerX" id="eod-st-ImC"/>
|
||||
<constraint firstAttribute="bottom" secondItem="1Rb-D3-XW9" secondAttribute="bottom" id="iJZ-ip-cKT"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<connections>
|
||||
<outlet property="actionButton" destination="bPP-dr-CnF" id="2Ql-Wv-czh"/>
|
||||
<outlet property="animationsView" destination="1Rb-D3-XW9" id="Qgh-aE-e3M"/>
|
||||
</connections>
|
||||
</viewController>
|
||||
<customObject id="ggI-l3-NeJ" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="828" y="1037"/>
|
||||
</scene>
|
||||
<!--Easing-->
|
||||
<scene sceneID="UPp-EA-zFu">
|
||||
<objects>
|
||||
<viewController title="Easing" id="6Ok-1N-J6E" customClass="EasingViewController" customModule="Example_macOS" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<view key="view" id="8S8-en-dQ9">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="500"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<customView translatesAutoresizingMaskIntoConstraints="NO" id="rMi-Lt-xst" customClass="EasingView" customModule="Example_macOS" customModuleProvider="target">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="500"/>
|
||||
</customView>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstItem="rMi-Lt-xst" firstAttribute="leading" secondItem="8S8-en-dQ9" secondAttribute="leading" id="E6d-Fs-XSu"/>
|
||||
<constraint firstItem="rMi-Lt-xst" firstAttribute="top" secondItem="8S8-en-dQ9" secondAttribute="top" id="F4Q-5G-KAY"/>
|
||||
<constraint firstAttribute="bottom" secondItem="rMi-Lt-xst" secondAttribute="bottom" id="STw-fO-vXO"/>
|
||||
<constraint firstAttribute="trailing" secondItem="rMi-Lt-xst" secondAttribute="trailing" id="YpZ-0X-Eb4"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<connections>
|
||||
<outlet property="easingView" destination="rMi-Lt-xst" id="1Lm-UJ-vZD"/>
|
||||
</connections>
|
||||
</viewController>
|
||||
<customObject id="97s-Ny-kLm" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="57" y="1631"/>
|
||||
</scene>
|
||||
<!--Tranform-->
|
||||
<scene sceneID="BDK-cT-fde">
|
||||
<objects>
|
||||
<viewController title="Tranform" id="jao-64-FWC" sceneMemberID="viewController">
|
||||
<view key="view" id="LOa-Et-9Z8">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="500"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<customView translatesAutoresizingMaskIntoConstraints="NO" id="CHZ-ou-3pJ" customClass="TransformExampleView" customModule="Example_macOS" customModuleProvider="target">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="500"/>
|
||||
</customView>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstItem="CHZ-ou-3pJ" firstAttribute="top" secondItem="LOa-Et-9Z8" secondAttribute="top" id="MQ2-71-Q8T"/>
|
||||
<constraint firstAttribute="bottom" secondItem="CHZ-ou-3pJ" secondAttribute="bottom" id="j0W-Jy-EsB"/>
|
||||
<constraint firstAttribute="trailing" secondItem="CHZ-ou-3pJ" secondAttribute="trailing" id="xaj-cY-w1R"/>
|
||||
<constraint firstItem="CHZ-ou-3pJ" firstAttribute="leading" secondItem="LOa-Et-9Z8" secondAttribute="leading" id="yJd-5F-Abz"/>
|
||||
</constraints>
|
||||
</view>
|
||||
</viewController>
|
||||
<customObject id="qef-Rz-hXA" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="-701" y="1037"/>
|
||||
</scene>
|
||||
<!--Morhing-->
|
||||
<scene sceneID="Plb-hR-bEv">
|
||||
<objects>
|
||||
<viewController title="Morhing" id="Rn8-Li-WZ2" sceneMemberID="viewController">
|
||||
<view key="view" id="ZyY-lN-6hI">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="500"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<customView translatesAutoresizingMaskIntoConstraints="NO" id="tFf-Vb-fQM" customClass="MorphingView" customModule="Example_macOS" customModuleProvider="target">
|
||||
<rect key="frame" x="200" y="150" width="200" height="200"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="200" id="O3r-f7-WR6"/>
|
||||
<constraint firstAttribute="width" constant="200" id="akU-YZ-kuF"/>
|
||||
</constraints>
|
||||
</customView>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstItem="tFf-Vb-fQM" firstAttribute="centerX" secondItem="ZyY-lN-6hI" secondAttribute="centerX" id="3vl-dy-NeQ"/>
|
||||
<constraint firstItem="tFf-Vb-fQM" firstAttribute="centerY" secondItem="ZyY-lN-6hI" secondAttribute="centerY" id="p6G-C4-Mkb"/>
|
||||
</constraints>
|
||||
</view>
|
||||
</viewController>
|
||||
<customObject id="hfo-iR-W9t" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="-701" y="1631"/>
|
||||
</scene>
|
||||
<!--SVG-->
|
||||
<scene sceneID="ZLO-Eh-m1d">
|
||||
<objects>
|
||||
<viewController title="SVG" id="iWh-Ne-7Ns" sceneMemberID="viewController">
|
||||
<view key="view" id="Vz6-zz-0Xw">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="500"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<customView translatesAutoresizingMaskIntoConstraints="NO" id="yvE-72-Fe6" customClass="SVGView" customModule="Macaw">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="500"/>
|
||||
<userDefinedRuntimeAttributes>
|
||||
<userDefinedRuntimeAttribute type="string" keyPath="fileName" value="tiger"/>
|
||||
</userDefinedRuntimeAttributes>
|
||||
</customView>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstAttribute="trailing" secondItem="yvE-72-Fe6" secondAttribute="trailing" id="4UL-4W-9YN"/>
|
||||
<constraint firstItem="yvE-72-Fe6" firstAttribute="leading" secondItem="Vz6-zz-0Xw" secondAttribute="leading" id="Xi8-t8-OlL"/>
|
||||
<constraint firstAttribute="bottom" secondItem="yvE-72-Fe6" secondAttribute="bottom" id="l48-pg-5Kp"/>
|
||||
<constraint firstItem="yvE-72-Fe6" firstAttribute="top" secondItem="Vz6-zz-0Xw" secondAttribute="top" id="nQP-Ld-hzQ"/>
|
||||
</constraints>
|
||||
</view>
|
||||
</viewController>
|
||||
<customObject id="SgK-6P-fu5" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="828" y="1631"/>
|
||||
</scene>
|
||||
<!--Events-->
|
||||
<scene sceneID="kTj-Ru-vPq">
|
||||
<objects>
|
||||
<viewController title="Events" id="9aj-uf-eJX" customClass="EventsExampleController" customModule="Example_macOS" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<view key="view" id="Fg0-AZ-zer">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="500"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<customView translatesAutoresizingMaskIntoConstraints="NO" id="3dq-O5-WZ6" customClass="MacawView" customModule="Macaw">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="500"/>
|
||||
</customView>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstAttribute="trailing" secondItem="3dq-O5-WZ6" secondAttribute="trailing" id="FzC-3s-Kku"/>
|
||||
<constraint firstItem="3dq-O5-WZ6" firstAttribute="leading" secondItem="Fg0-AZ-zer" secondAttribute="leading" id="PUF-Il-bp3"/>
|
||||
<constraint firstItem="3dq-O5-WZ6" firstAttribute="top" secondItem="Fg0-AZ-zer" secondAttribute="top" id="Utd-UH-Vzg"/>
|
||||
<constraint firstAttribute="bottom" secondItem="3dq-O5-WZ6" secondAttribute="bottom" id="eNi-iP-YzC"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<connections>
|
||||
<outlet property="macawView" destination="3dq-O5-WZ6" id="diH-cZ-09G"/>
|
||||
</connections>
|
||||
</viewController>
|
||||
<customObject id="RA2-nh-XE7" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="57" y="2256"/>
|
||||
</scene>
|
||||
</scenes>
|
||||
</document>
|
@ -0,0 +1,118 @@
|
||||
import Macaw
|
||||
|
||||
class AnimationsView: MacawView {
|
||||
|
||||
var animation: Animation?
|
||||
var ballNodes = [Group]()
|
||||
var onComplete: (() -> ()) = {}
|
||||
|
||||
let n = 100
|
||||
let speed = 20.0
|
||||
let r = 10.0
|
||||
|
||||
let ballColors = [
|
||||
Color(val: 0x1abc9c),
|
||||
Color(val: 0x2ecc71),
|
||||
Color(val: 0x3498db),
|
||||
Color(val: 0x9b59b6),
|
||||
Color(val: 0xf1c40f),
|
||||
Color(val: 0xe67e22),
|
||||
Color(val: 0xe67e22),
|
||||
Color(val: 0xe74c3c)
|
||||
]
|
||||
|
||||
required init?(coder aDecoder: NSCoder) {
|
||||
super.init(node: Group(), coder: aDecoder)
|
||||
}
|
||||
|
||||
func startAnimation() {
|
||||
if let animation = self.animation {
|
||||
animation.play()
|
||||
}
|
||||
}
|
||||
|
||||
func prepareAnimation() {
|
||||
ballNodes.removeAll()
|
||||
|
||||
var animations = [Animation]()
|
||||
|
||||
let screenBounds = self.bounds
|
||||
let startPos = Transform.move(
|
||||
dx: Double(screenBounds.width / 2) - r,
|
||||
dy: Double(screenBounds.height / 2) - r
|
||||
)
|
||||
|
||||
var velocities = [Point]()
|
||||
var positions = [Point]()
|
||||
|
||||
func posForTime(_ t: Double, index: Int) -> Point {
|
||||
|
||||
let prevPos = positions[index]
|
||||
var velocity = velocities[index]
|
||||
|
||||
var pos = prevPos.add(velocity)
|
||||
|
||||
// Borders
|
||||
if pos.x < Double(self.bounds.width) / -2.0 || pos.x > Double(self.bounds.width) / 2.0 {
|
||||
velocity = Point(x: -1.0 * velocity.x, y: velocity.y)
|
||||
velocities[index] = velocity
|
||||
pos = prevPos.add(velocity)
|
||||
}
|
||||
|
||||
if pos.y < Double(self.bounds.height) / -2.0 || pos.y > Double(self.bounds.height) / 2.0 {
|
||||
velocity = Point(x: velocity.x, y: -1.0 * velocity.y)
|
||||
velocities[index] = velocity
|
||||
pos = prevPos.add(velocity)
|
||||
}
|
||||
|
||||
return pos
|
||||
}
|
||||
|
||||
for i in 0 ... (n - 1) {
|
||||
// Node
|
||||
let circle = Circle(cx: r, cy: r, r: r)
|
||||
let shape = Shape(
|
||||
form: circle,
|
||||
fill: ballColors[Int(arc4random() % 7)]
|
||||
)
|
||||
|
||||
let ballGroup = Group(contents: [shape])
|
||||
ballNodes.append(ballGroup)
|
||||
|
||||
// Animation
|
||||
let velocity = Point(
|
||||
x: -0.5 * speed + speed * Double(arc4random() % 1000) / 1000.0,
|
||||
y: -0.5 * speed + speed * Double(arc4random() % 1000) / 1000.0)
|
||||
velocities.append(velocity)
|
||||
positions.append(Point(x: 0.0, y: 0.0))
|
||||
|
||||
let anim = ballGroup.placeVar.animation({ (t) -> Transform in
|
||||
let pos = posForTime(t, index: i)
|
||||
positions[i] = pos
|
||||
return Transform().move(
|
||||
dx: pos.x,
|
||||
dy: pos.y)
|
||||
}, during: 3.0)
|
||||
|
||||
animations.append([
|
||||
anim,
|
||||
ballGroup.opacityVar.animation((0.1 >> 1.0).t(3.0))
|
||||
].combine())
|
||||
}
|
||||
|
||||
animation = animations.combine().autoreversed().onComplete {
|
||||
self.completeAnimation()
|
||||
}
|
||||
|
||||
let node = Group(contents: ballNodes)
|
||||
node.place = Transform().move(dx: startPos.dx, dy: startPos.dy)
|
||||
self.node = node
|
||||
}
|
||||
|
||||
func completeAnimation() {
|
||||
self.node = Group()
|
||||
self.prepareAnimation()
|
||||
self.onComplete()
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
//
|
||||
// AnimationsViewController.swift
|
||||
// Example-macOS
|
||||
//
|
||||
// Created by Daniil Manin on 8/15/17.
|
||||
//
|
||||
//
|
||||
|
||||
import Cocoa
|
||||
|
||||
class AnimationsViewController: NSViewController {
|
||||
|
||||
@IBOutlet weak var animationsView: AnimationsView!
|
||||
@IBOutlet weak var actionButton: NSButton!
|
||||
|
||||
override func viewDidAppear() {
|
||||
super.viewDidAppear()
|
||||
|
||||
animationsView?.onComplete = {
|
||||
self.actionButton?.isEnabled = true
|
||||
}
|
||||
animationsView?.prepareAnimation()
|
||||
}
|
||||
|
||||
override func viewDidDisappear() {
|
||||
super.viewDidDisappear()
|
||||
|
||||
self.actionButton?.isEnabled = true
|
||||
}
|
||||
|
||||
@IBAction func startAnimationsAction(_ sender: Any) {
|
||||
animationsView?.startAnimation()
|
||||
actionButton?.isEnabled = false
|
||||
}
|
||||
}
|
44
Example-macOS/Example-macOS/Examples/Easing/EasingView.swift
Normal file
44
Example-macOS/Example-macOS/Examples/Easing/EasingView.swift
Normal file
@ -0,0 +1,44 @@
|
||||
import Macaw
|
||||
|
||||
class EasingView: MacawView {
|
||||
var mAnimations = [Animation]()
|
||||
var circlesNodes = [Group]()
|
||||
var animation: Animation!
|
||||
|
||||
required init?(coder aDecoder: NSCoder) {
|
||||
let screenSize = CGRect(origin: CGPoint.zero, size: CGSize(width: 600.0, height: 500.0))
|
||||
let centerX = Double(screenSize.width / 2)
|
||||
|
||||
let fromStroke = Stroke(fill: Color.black, width: 3)
|
||||
|
||||
let all = [Easing.ease, Easing.linear, Easing.easeIn, Easing.easeOut, Easing.easeInOut]
|
||||
|
||||
for (i, easing) in all.enumerated() {
|
||||
let y = Double(75 + i * 80)
|
||||
let title = EasingView.title(easing: easing)
|
||||
let titleText = Text(text: title, align: .mid, place: .move(dx: centerX, dy: y - 45))
|
||||
|
||||
let fromCircle = Circle(cx: centerX - 100, cy: y, r: 25).stroke(with: fromStroke)
|
||||
let toPlace = fromCircle.place.move(dx: 200, dy: 0)
|
||||
|
||||
let toAnimation = fromCircle.placeVar.animation(to: toPlace).easing(easing)
|
||||
|
||||
mAnimations.append([toAnimation.autoreversed()].sequence())
|
||||
circlesNodes.append(Group(contents: [titleText]))
|
||||
circlesNodes.append(Group(contents: [fromCircle]))
|
||||
}
|
||||
|
||||
animation = mAnimations.combine().cycle()
|
||||
super.init(node: circlesNodes.group(), coder: aDecoder)
|
||||
}
|
||||
|
||||
fileprivate static func title(easing: Easing) -> String {
|
||||
switch easing {
|
||||
case .ease: return "Ease"
|
||||
case .linear: return "Linear"
|
||||
case .easeIn: return "Ease In"
|
||||
case .easeOut: return "Ease Out"
|
||||
case .easeInOut: return "Ease InOut"
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
//
|
||||
// EasingViewController.swift
|
||||
// Example-macOS
|
||||
//
|
||||
// Created by Daniil Manin on 8/15/17.
|
||||
//
|
||||
//
|
||||
|
||||
import Cocoa
|
||||
|
||||
class EasingViewController: NSViewController {
|
||||
@IBOutlet weak var easingView: EasingView!
|
||||
|
||||
override func viewDidAppear() {
|
||||
super.viewDidAppear()
|
||||
easingView.animation.play()
|
||||
}
|
||||
|
||||
override func viewWillDisappear() {
|
||||
super.viewDidDisappear()
|
||||
easingView.animation.stop()
|
||||
}
|
||||
}
|
@ -0,0 +1,139 @@
|
||||
//
|
||||
// EventsExampleController.swift
|
||||
// Example
|
||||
//
|
||||
// Created by Victor Sukochev on 02/03/2017.
|
||||
// Copyright © 2017 Exyte. All rights reserved.
|
||||
//
|
||||
|
||||
import Macaw
|
||||
|
||||
class EventsExampleController: NSViewController {
|
||||
|
||||
@IBOutlet weak var macawView: MacawView?
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
macawView?.node = loadScene()
|
||||
}
|
||||
|
||||
enum PanelTool {
|
||||
case ellipse
|
||||
case rectangle
|
||||
}
|
||||
|
||||
var selectedTool: PanelTool?
|
||||
|
||||
private func loadScene() -> Node {
|
||||
|
||||
return [createCanvas(), createPanel()].group()
|
||||
}
|
||||
|
||||
private func createPanel() -> Node {
|
||||
let panel = Shape(form: Rect(x: 10.0, y: 10.0, w: 80.0, h: 120.0), fill: Color.clear, stroke: Stroke(fill: Color.black, width: 1.0))
|
||||
let panelGroup = [panel, createTools()].group()
|
||||
|
||||
panelGroup.onPan { event in
|
||||
panelGroup.place = panelGroup.place.move(dx: event.dx, dy: event.dy)
|
||||
}
|
||||
|
||||
return panelGroup
|
||||
}
|
||||
|
||||
private func createCanvas() -> Node {
|
||||
let canvas = Shape(form: Rect(x: 0.0, y: 0.0,
|
||||
w: Double(macawView!.bounds.width),
|
||||
h: Double(macawView!.bounds.height)),
|
||||
fill: Color.white)
|
||||
let objectsGroup = Group(contents:[])
|
||||
|
||||
var startPoint = Point()
|
||||
var currentFigure: Shape?
|
||||
|
||||
canvas.onTouchPressed { event in
|
||||
guard let tool = self.selectedTool else {
|
||||
return
|
||||
}
|
||||
|
||||
guard let loc = event.points.first?.location else {
|
||||
return
|
||||
}
|
||||
|
||||
startPoint = loc
|
||||
switch tool {
|
||||
case .ellipse:
|
||||
currentFigure = Shape(form: Ellipse(cx: startPoint.x, cy: startPoint.y, rx: 0.0, ry: 0.0))
|
||||
break
|
||||
|
||||
case .rectangle:
|
||||
currentFigure = Shape(form: Rect(x: startPoint.x, y: startPoint.y, w: 0.0, h: 0.0))
|
||||
break
|
||||
}
|
||||
|
||||
var updatedContents = objectsGroup.contents
|
||||
updatedContents.append(currentFigure!)
|
||||
|
||||
objectsGroup.contents = updatedContents
|
||||
}
|
||||
|
||||
canvas.onTouchMoved { event in
|
||||
guard let tool = self.selectedTool else {
|
||||
return
|
||||
}
|
||||
|
||||
guard let loc = event.points.first?.location else {
|
||||
return
|
||||
}
|
||||
|
||||
let width = loc.x - startPoint.x
|
||||
let height = loc.y - startPoint.y
|
||||
|
||||
switch tool {
|
||||
case .ellipse:
|
||||
|
||||
currentFigure?.form = Ellipse(
|
||||
cx: startPoint.x + width / 2.0,
|
||||
cy: startPoint.y + height / 2.0,
|
||||
rx: width / 2.0,
|
||||
ry: height / 2.0)
|
||||
break
|
||||
|
||||
case .rectangle:
|
||||
currentFigure?.form = Rect(x: startPoint.x, y: startPoint.y, w: width, h: height)
|
||||
break
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return [
|
||||
canvas,
|
||||
objectsGroup
|
||||
].group()
|
||||
}
|
||||
|
||||
private func createTools() -> Node {
|
||||
let ellipseTool = Shape(form: Ellipse(cx: 50.0, cy: 50.0, rx: 25, ry: 15),
|
||||
fill: Color.clear,
|
||||
stroke: Stroke(fill: Color.black, width: 1.0))
|
||||
|
||||
let rectTool = Shape(form: Rect(x: 25.0, y: 75.0, w: 50.0, h: 30.0),
|
||||
fill: Color.clear,
|
||||
stroke: Stroke(fill: Color.black, width: 1.0))
|
||||
|
||||
ellipseTool.onTap { _ in
|
||||
self.selectedTool = .ellipse
|
||||
ellipseTool.stroke = Stroke(fill: Color.blue, width: 2.0)
|
||||
rectTool.stroke = Stroke(fill: Color.black, width: 1.0)
|
||||
}
|
||||
|
||||
rectTool.onTap { _ in
|
||||
self.selectedTool = .rectangle
|
||||
rectTool.stroke = Stroke(fill: Color.blue, width: 2.0)
|
||||
ellipseTool.stroke = Stroke(fill: Color.black, width: 1.0)
|
||||
}
|
||||
|
||||
return [ellipseTool, rectTool].group()
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,40 @@
|
||||
//
|
||||
// MorphingView.swift
|
||||
// Example
|
||||
//
|
||||
// Created by Victor Sukochev on 25/01/2017.
|
||||
// Copyright © 2017 Exyte. All rights reserved.
|
||||
//
|
||||
|
||||
import Macaw
|
||||
|
||||
class MorphingView: MacawView {
|
||||
|
||||
required init?(coder aDecoder: NSCoder) {
|
||||
super.init(node: MorphingView.newScene(), coder: aDecoder)
|
||||
}
|
||||
|
||||
class func newScene() -> Node {
|
||||
let stroke = Stroke(width: 15.0, cap: .round)
|
||||
|
||||
let contents1 = [
|
||||
Shape(form: Line(x1: 50.0, y1: 50.0, x2: 75.0, y2: 25.0), stroke: stroke),
|
||||
Shape(form: Line(x1: 50.0, y1: 50.0, x2: 125.0, y2: 50.0), stroke: stroke),
|
||||
Shape(form: Line(x1: 50.0, y1: 50.0, x2: 75.0, y2: 75.0), stroke: stroke),
|
||||
]
|
||||
|
||||
let contents2 = [
|
||||
Shape(form: Line(x1: 50.0, y1: 10.0, x2: 165.0, y2: 10.0), stroke: stroke),
|
||||
Shape(form: Line(x1: 50.0, y1: 50.0, x2: 165.0, y2: 50.0), stroke: stroke),
|
||||
Shape(form: Line(x1: 50.0, y1: 90.0, x2: 165.0, y2: 90.0), stroke: stroke),
|
||||
]
|
||||
|
||||
var switched = false
|
||||
let group = contents1.group()
|
||||
group.onTap { e in
|
||||
group.contentsVar.animate(to: switched ? contents1 : contents2)
|
||||
switched = !switched
|
||||
}
|
||||
return group
|
||||
}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
import UIKit
|
||||
import Macaw
|
||||
|
||||
class SVGExampleView: MacawView {
|
||||
|
||||
required init?(coder aDecoder: NSCoder) {
|
||||
super.init(node: SVGParser.parse(path: "tiger"), coder: aDecoder)
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,79 @@
|
||||
//
|
||||
// CustomView.swift
|
||||
// Example
|
||||
//
|
||||
// Created by Yuri Strot on 12/19/15.
|
||||
// Copyright © 2015 Exyte. All rights reserved.
|
||||
//
|
||||
|
||||
import Macaw
|
||||
|
||||
class ShapesExampleView: MacawView {
|
||||
|
||||
required init?(coder aDecoder: NSCoder) {
|
||||
let text1 = ShapesExampleView.newText("Point", .move(dx: 100, dy: 40))
|
||||
let point = Point(x: 100, y: 50).stroke(fill: Color.black, width: 7, cap: .round)
|
||||
|
||||
let text2 = ShapesExampleView.newText("Line", .move(dx: 250, dy: 40))
|
||||
let line = Line(x1: 200, y1: 50, x2: 300, y2: 50).stroke(fill: Color.black, width: 4)
|
||||
|
||||
let text3 = ShapesExampleView.newText("Polyline", .move(dx: 100, dy: 90))
|
||||
let polyline = Polyline(points: [100, 100, 150, 150, 50, 150]).stroke(fill: Color.navy, dashes: [3, 3])
|
||||
|
||||
let text4 = ShapesExampleView.newText("Polygon", .move(dx: 250, dy: 90))
|
||||
let polygon = Polygon(points: [250, 100, 300, 150, 200, 150]).fill(with: Color.blue)
|
||||
|
||||
let text5 = ShapesExampleView.newText("Rect", .move(dx: 100, dy: 200))
|
||||
let rect = Rect(x: 50, y: 210, w: 100, h: 50).fill(with: LinearGradient(
|
||||
x2: 1, y2: 1,
|
||||
stops: [
|
||||
Stop(offset: 0, color: Color(val: 0xFFAE27)),
|
||||
Stop(offset: 1, color: Color(val: 0xDE496D))
|
||||
]
|
||||
))
|
||||
|
||||
let text6 = ShapesExampleView.newText("RoundRect", .move(dx: 250, dy: 200))
|
||||
let round = Rect(x: 200, y: 210, w: 100, h: 50).round(rx: 10, ry: 10).fill(with: LinearGradient(
|
||||
x2: 1, y2: 1,
|
||||
stops: [
|
||||
Stop(offset: 0, color: Color(val: 0xDE496D)),
|
||||
Stop(offset: 0.5, color: Color(val: 0xAB49DE)),
|
||||
Stop(offset: 1, color: Color(val: 0x4954DE))
|
||||
]
|
||||
))
|
||||
|
||||
let text7 = ShapesExampleView.newText("Circle", .move(dx: 75, dy: 300))
|
||||
let circle = Circle(cx: 75, cy: 335, r: 25).fill(with: RadialGradient(
|
||||
stops: [
|
||||
Stop(offset: 0, color: Color(val: 0xF5027C)),
|
||||
Stop(offset: 1, color: Color(val: 0x850143))
|
||||
]
|
||||
))
|
||||
|
||||
let text8 = ShapesExampleView.newText("Ellipse", .move(dx: 175, dy: 300))
|
||||
let ellipse = Ellipse(cx: 175, cy: 335, rx: 50, ry: 25).fill(with: RadialGradient(
|
||||
fx: 0.05, fy: 0.05, r: 0.65,
|
||||
stops: [
|
||||
Stop(offset: 0, color: Color(val: 0x00ee00)),
|
||||
Stop(offset: 1, color: Color(val: 0x006600))
|
||||
]
|
||||
))
|
||||
|
||||
let text9 = ShapesExampleView.newText("Arc", .move(dx: 275, dy: 300))
|
||||
let arc = Circle(cx: 250, cy: 310, r: 50).arc(shift: 0, extent: Double.pi / 2.0).stroke(fill: Color.green)
|
||||
|
||||
let group = Group(
|
||||
contents: [
|
||||
point, line, polyline, polygon, rect, round, circle, ellipse, arc,
|
||||
text1, text2, text3, text4, text5, text6, text7, text8, text9
|
||||
]
|
||||
)
|
||||
|
||||
super.init(node: group, coder: aDecoder)
|
||||
}
|
||||
|
||||
fileprivate static func newText(_ text: String, _ place: Transform, baseline: Baseline = .bottom) -> Text {
|
||||
return Text(text: text, fill: Color.black, align: .mid, baseline: baseline, place: place)
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,70 @@
|
||||
//
|
||||
// TransformExampleView.swift
|
||||
// Example
|
||||
//
|
||||
// Created by Yuri Strot on 9/10/16.
|
||||
// Copyright © 2016 Exyte. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Macaw
|
||||
|
||||
class TransformExampleView: MacawView {
|
||||
|
||||
fileprivate static let transforms = [Transform.scale(sx: 2, sy: 2),
|
||||
Transform.move(dx: 100, dy: 30),
|
||||
Transform.rotate(angle: Double.pi / 4.0, x: 150, y: 80),
|
||||
Transform.rotate(angle: Double.pi / 4.0)]
|
||||
|
||||
fileprivate static let titles = ["Transform.scale(sx: 2, sy: 2)",
|
||||
"Transform.move(dx: 100, dy: 30)",
|
||||
"Transform.rotate(angle: M_PI_4, x: 150, y: 80)",
|
||||
"Transform.rotate(angle: M_PI_4)"]
|
||||
|
||||
required init?(coder aDecoder: NSCoder) {
|
||||
super.init(node: TransformExampleView.newScene(), coder: aDecoder)
|
||||
}
|
||||
|
||||
fileprivate static func newScene() -> Node {
|
||||
let shape = Shape(form: Rect(x: 0, y: 0, w: 50, h: 50), fill: Color.blue)
|
||||
let textes = Group(place: .move(dx: 50, dy: 275))
|
||||
for (i, item) in titles.enumerated() {
|
||||
let place = Transform.move(dx: 0, dy: Double(i * 25))
|
||||
textes.contents.append(Text(text: item, baseline: .bottom, place: place, opacity: 0))
|
||||
}
|
||||
var combines: [Transform] = [Transform.identity]
|
||||
for transform in transforms {
|
||||
combines.append(GeomUtils.concat(t1: transform, t2: combines.last!))
|
||||
}
|
||||
var state = 0
|
||||
|
||||
shape.onTap { _ in
|
||||
if (state < textes.contents.count) {
|
||||
textes.contents[state].opacityVar.animate(from: 0.0, to: 1.0, during: 0.6)
|
||||
} else {
|
||||
for item in textes.contents {
|
||||
item.opacityVar.animate(from: 1.0, to: 0.0, during: 0.6)
|
||||
}
|
||||
}
|
||||
state = (state + 1) % 5;
|
||||
shape.placeVar.animate(to: combines[state], during: 0.6)
|
||||
}
|
||||
|
||||
let group = Group(contents: [newAxes(), shape, textes], place: .move(dx: 10, dy: 10))
|
||||
return group
|
||||
}
|
||||
|
||||
fileprivate static func newAxes() -> Node {
|
||||
var items: [Node] = []
|
||||
|
||||
for i in 1...20 {
|
||||
let shift = Double(i) * 50.0
|
||||
items.append(Line(x1: -50, y1: shift, x2: 1000, y2: shift).stroke(fill: Color.gray))
|
||||
items.append(Line(x1: shift, y1: -50, x2: shift, y2: 1000).stroke(fill: Color.gray))
|
||||
}
|
||||
|
||||
items.append(Line(x1: -10, y1: 0, x2: 1000, y2: 0).stroke())
|
||||
items.append(Line(x1: 0, y1: -10, x2: 0, y2: 1000).stroke())
|
||||
return Group(contents: items)
|
||||
}
|
||||
}
|
30
Example-macOS/Example-macOS/Info.plist
Normal file
30
Example-macOS/Example-macOS/Info.plist
Normal file
@ -0,0 +1,30 @@
|
||||
<?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>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIconFile</key>
|
||||
<string></string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>$(MACOSX_DEPLOYMENT_TARGET)</string>
|
||||
<key>NSMainStoryboardFile</key>
|
||||
<string>Main</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string>NSApplication</string>
|
||||
</dict>
|
||||
</plist>
|
22
Example-macOS/Example-macOS/ViewController.swift
Normal file
22
Example-macOS/Example-macOS/ViewController.swift
Normal file
@ -0,0 +1,22 @@
|
||||
//
|
||||
// ViewController.swift
|
||||
// Example-macOS
|
||||
//
|
||||
// Created by Daniil Manin on 8/11/17.
|
||||
//
|
||||
//
|
||||
|
||||
import Cocoa
|
||||
import Macaw
|
||||
|
||||
class ViewController: NSViewController {
|
||||
|
||||
@IBOutlet weak var mainView: EasingView!
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
//mainView.animation.play()
|
||||
}
|
||||
}
|
||||
|
5
Example-macOS/Podfile
Normal file
5
Example-macOS/Podfile
Normal file
@ -0,0 +1,5 @@
|
||||
use_frameworks!
|
||||
|
||||
target 'Example-macOS' do
|
||||
pod 'Macaw', :path => '../'
|
||||
end
|
19
Example-macOS/Podfile.lock
Normal file
19
Example-macOS/Podfile.lock
Normal file
@ -0,0 +1,19 @@
|
||||
PODS:
|
||||
- Macaw (0.8.2):
|
||||
- SWXMLHash (~> 3.0.0)
|
||||
- SWXMLHash (3.0.5)
|
||||
|
||||
DEPENDENCIES:
|
||||
- Macaw (from `../`)
|
||||
|
||||
EXTERNAL SOURCES:
|
||||
Macaw:
|
||||
:path: "../"
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
Macaw: 5bd466e34d3602084f43486abbc31fc4a8060c74
|
||||
SWXMLHash: 701f7d07c032089b9ff34e0352bd4fed1a24652a
|
||||
|
||||
PODFILE CHECKSUM: d31ba0b2048e70405adc9fbdda765e648c849781
|
||||
|
||||
COCOAPODS: 1.1.1
|
@ -69,6 +69,8 @@ class EventsExampleController: UIViewController {
|
||||
return
|
||||
}
|
||||
|
||||
print("canvas pressed:\(loc.x) \(loc.y)")
|
||||
|
||||
startPoint = loc
|
||||
switch tool {
|
||||
case .ellipse:
|
||||
@ -87,6 +89,7 @@ class EventsExampleController: UIViewController {
|
||||
}
|
||||
|
||||
canvas.onTouchMoved { event in
|
||||
|
||||
guard let tool = self.selectedTool else {
|
||||
return
|
||||
}
|
||||
@ -95,6 +98,8 @@ class EventsExampleController: UIViewController {
|
||||
return
|
||||
}
|
||||
|
||||
print("canvas moving \(loc.x) \(loc.y)")
|
||||
|
||||
let width = loc.x - startPoint.x
|
||||
let height = loc.y - startPoint.y
|
||||
|
||||
|
@ -11,7 +11,7 @@ EXTERNAL SOURCES:
|
||||
:path: "../"
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
Macaw: d6cc4946fab3fb7dfb588fdc6701a0c92159d763
|
||||
Macaw: 5bd466e34d3602084f43486abbc31fc4a8060c74
|
||||
SWXMLHash: 701f7d07c032089b9ff34e0352bd4fed1a24652a
|
||||
|
||||
PODFILE CHECKSUM: cf6c204dbe194da8e03fcb9ffd9c99d086057155
|
||||
|
@ -26,12 +26,13 @@ Pod::Spec.new do |s|
|
||||
s.source = { :git => 'https://github.com/exyte/Macaw.git', :tag => s.version.to_s }
|
||||
s.social_media_url = 'http://exyte.com'
|
||||
|
||||
s.platform = :ios, '8.0'
|
||||
s.ios.deployment_target = "8.0"
|
||||
s.osx.deployment_target = "10.12"
|
||||
s.requires_arc = true
|
||||
s.pod_target_xcconfig = { 'SWIFT_VERSION' => '3.0' }
|
||||
|
||||
s.source_files = [
|
||||
'Source/**/*.*'
|
||||
'Source/**/*.swift'
|
||||
]
|
||||
# s.resource_bundles = {
|
||||
# 'Macaw' => ['Pod/Assets/*.png']
|
||||
|
@ -132,6 +132,14 @@
|
||||
57E5E1B41E3B393900D1CB28 /* ShapeLayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57E5E1521E3B393900D1CB28 /* ShapeLayer.swift */; };
|
||||
57FCD2771D76EA4600CC0FB6 /* Macaw.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 57FCD26C1D76EA4600CC0FB6 /* Macaw.framework */; };
|
||||
57FCD27C1D76EA4600CC0FB6 /* MacawTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57FCD27B1D76EA4600CC0FB6 /* MacawTests.swift */; };
|
||||
A718CD441F45C28200966E06 /* Common_iOS.swift in Sources */ = {isa = PBXBuildFile; fileRef = A718CD431F45C28200966E06 /* Common_iOS.swift */; };
|
||||
A718CD471F45C28700966E06 /* Graphics_iOS.swift in Sources */ = {isa = PBXBuildFile; fileRef = A718CD451F45C28700966E06 /* Graphics_iOS.swift */; };
|
||||
A718CD481F45C28700966E06 /* MView_iOS.swift in Sources */ = {isa = PBXBuildFile; fileRef = A718CD461F45C28700966E06 /* MView_iOS.swift */; };
|
||||
A718CD4D1F45C28F00966E06 /* Common_macOS.swift in Sources */ = {isa = PBXBuildFile; fileRef = A718CD491F45C28F00966E06 /* Common_macOS.swift */; };
|
||||
A718CD4E1F45C28F00966E06 /* Graphics_macOS.swift in Sources */ = {isa = PBXBuildFile; fileRef = A718CD4A1F45C28F00966E06 /* Graphics_macOS.swift */; };
|
||||
A718CD4F1F45C28F00966E06 /* MDisplayLink_macOS.swift in Sources */ = {isa = PBXBuildFile; fileRef = A718CD4B1F45C28F00966E06 /* MDisplayLink_macOS.swift */; };
|
||||
A718CD501F45C28F00966E06 /* MView_macOS.swift in Sources */ = {isa = PBXBuildFile; fileRef = A718CD4C1F45C28F00966E06 /* MView_macOS.swift */; };
|
||||
A718CD521F45C2A400966E06 /* MBezierPath+Extension_macOS.swift in Sources */ = {isa = PBXBuildFile; fileRef = A718CD511F45C2A400966E06 /* MBezierPath+Extension_macOS.swift */; };
|
||||
A7E675561EC4213500BD9ECB /* NodeBoundsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7E675551EC4213500BD9ECB /* NodeBoundsTests.swift */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
@ -286,6 +294,14 @@
|
||||
57FCD2761D76EA4600CC0FB6 /* MacawTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = MacawTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
57FCD27B1D76EA4600CC0FB6 /* MacawTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MacawTests.swift; sourceTree = "<group>"; };
|
||||
57FCD27D1D76EA4600CC0FB6 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
A718CD431F45C28200966E06 /* Common_iOS.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Common_iOS.swift; path = Source/platform/iOS/Common_iOS.swift; sourceTree = SOURCE_ROOT; };
|
||||
A718CD451F45C28700966E06 /* Graphics_iOS.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Graphics_iOS.swift; path = Source/platform/iOS/Graphics_iOS.swift; sourceTree = SOURCE_ROOT; };
|
||||
A718CD461F45C28700966E06 /* MView_iOS.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = MView_iOS.swift; path = Source/platform/iOS/MView_iOS.swift; sourceTree = SOURCE_ROOT; };
|
||||
A718CD491F45C28F00966E06 /* Common_macOS.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Common_macOS.swift; path = Source/platform/macOS/Common_macOS.swift; sourceTree = SOURCE_ROOT; };
|
||||
A718CD4A1F45C28F00966E06 /* Graphics_macOS.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Graphics_macOS.swift; path = Source/platform/macOS/Graphics_macOS.swift; sourceTree = SOURCE_ROOT; };
|
||||
A718CD4B1F45C28F00966E06 /* MDisplayLink_macOS.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = MDisplayLink_macOS.swift; path = Source/platform/macOS/MDisplayLink_macOS.swift; sourceTree = SOURCE_ROOT; };
|
||||
A718CD4C1F45C28F00966E06 /* MView_macOS.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = MView_macOS.swift; path = Source/platform/macOS/MView_macOS.swift; sourceTree = SOURCE_ROOT; };
|
||||
A718CD511F45C2A400966E06 /* MBezierPath+Extension_macOS.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "MBezierPath+Extension_macOS.swift"; path = "Source/platform/macOS/MBezierPath+Extension_macOS.swift"; sourceTree = SOURCE_ROOT; };
|
||||
A7E675551EC4213500BD9ECB /* NodeBoundsTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = NodeBoundsTests.swift; path = Bounds/NodeBoundsTests.swift; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
@ -621,6 +637,7 @@
|
||||
57FCD26E1D76EA4600CC0FB6 /* Macaw */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
A718CD2C1F45BC5300966E06 /* Platform */,
|
||||
572CEFC31E2CED4B008C7C83 /* Dependencies */,
|
||||
57E5E0E01E3B393900D1CB28 /* Source */,
|
||||
);
|
||||
@ -640,6 +657,37 @@
|
||||
path = MacawTests;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
A718CD2C1F45BC5300966E06 /* Platform */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
A718CD361F45BD0B00966E06 /* iOS */,
|
||||
A718CD351F45BCF800966E06 /* macOS */,
|
||||
);
|
||||
name = Platform;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
A718CD351F45BCF800966E06 /* macOS */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
A718CD491F45C28F00966E06 /* Common_macOS.swift */,
|
||||
A718CD4A1F45C28F00966E06 /* Graphics_macOS.swift */,
|
||||
A718CD4B1F45C28F00966E06 /* MDisplayLink_macOS.swift */,
|
||||
A718CD4C1F45C28F00966E06 /* MView_macOS.swift */,
|
||||
A718CD511F45C2A400966E06 /* MBezierPath+Extension_macOS.swift */,
|
||||
);
|
||||
name = macOS;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
A718CD361F45BD0B00966E06 /* iOS */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
A718CD431F45C28200966E06 /* Common_iOS.swift */,
|
||||
A718CD451F45C28700966E06 /* Graphics_iOS.swift */,
|
||||
A718CD461F45C28700966E06 /* MView_iOS.swift */,
|
||||
);
|
||||
name = iOS;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
A7E675541EC4211E00BD9ECB /* Bounds */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@ -708,7 +756,7 @@
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastSwiftUpdateCheck = 0730;
|
||||
LastUpgradeCheck = 0820;
|
||||
LastUpgradeCheck = 0830;
|
||||
ORGANIZATIONNAME = Exyte;
|
||||
TargetAttributes = {
|
||||
57FCD26B1D76EA4600CC0FB6 = {
|
||||
@ -717,7 +765,9 @@
|
||||
};
|
||||
57FCD2751D76EA4600CC0FB6 = {
|
||||
CreatedOnToolsVersion = 7.3.1;
|
||||
DevelopmentTeam = 7T95R85V93;
|
||||
LastSwiftMigration = 0800;
|
||||
ProvisioningStyle = Automatic;
|
||||
};
|
||||
};
|
||||
};
|
||||
@ -784,14 +834,17 @@
|
||||
57E5E1B31E3B393900D1CB28 /* NodesMap.swift in Sources */,
|
||||
57E5E1A71E3B393900D1CB28 /* RenderUtils.swift in Sources */,
|
||||
57E5E1601E3B393900D1CB28 /* FuncBounds.swift in Sources */,
|
||||
A718CD481F45C28700966E06 /* MView_iOS.swift in Sources */,
|
||||
57E5E15B1E3B393900D1CB28 /* DoubleInterpolation.swift in Sources */,
|
||||
57E5E1961E3B393900D1CB28 /* PathSegmentType.swift in Sources */,
|
||||
57E5E1531E3B393900D1CB28 /* AnimatableVariable.swift in Sources */,
|
||||
57E5E1691E3B393900D1CB28 /* TimingFunction.swift in Sources */,
|
||||
57E5E1631E3B393900D1CB28 /* AnimationCache.swift in Sources */,
|
||||
57E5E19D1E3B393900D1CB28 /* Transform.swift in Sources */,
|
||||
A718CD4E1F45C28F00966E06 /* Graphics_macOS.swift in Sources */,
|
||||
57E5E1A81E3B393900D1CB28 /* ShapeRenderer.swift in Sources */,
|
||||
57E5E1851E3B393900D1CB28 /* LinearGradient.swift in Sources */,
|
||||
A718CD4F1F45C28F00966E06 /* MDisplayLink_macOS.swift in Sources */,
|
||||
57E5E1721E3B393900D1CB28 /* GroupDisposable.swift in Sources */,
|
||||
57E5E18A1E3B393900D1CB28 /* Stroke.swift in Sources */,
|
||||
57E5E1781E3B393900D1CB28 /* TapEvent.swift in Sources */,
|
||||
@ -832,6 +885,7 @@
|
||||
57E5E1561E3B393900D1CB28 /* AnimationProducer.swift in Sources */,
|
||||
57E5E1811E3B393900D1CB28 /* Fill.swift in Sources */,
|
||||
57A27BD51E44C5840057BD3A /* ShapeInterpolation.swift in Sources */,
|
||||
A718CD471F45C28700966E06 /* Graphics_iOS.swift in Sources */,
|
||||
57E5E1871E3B393900D1CB28 /* LineJoin.swift in Sources */,
|
||||
57E5E1881E3B393900D1CB28 /* RadialGradient.swift in Sources */,
|
||||
57E5E1891E3B393900D1CB28 /* Stop.swift in Sources */,
|
||||
@ -841,6 +895,8 @@
|
||||
57E5E1991E3B393900D1CB28 /* Polyline.swift in Sources */,
|
||||
57E5E16D1E3B393900D1CB28 /* ContentsAnimation.swift in Sources */,
|
||||
5713C4E21E51EC8F00BBA4D9 /* TouchEvent.swift in Sources */,
|
||||
A718CD521F45C2A400966E06 /* MBezierPath+Extension_macOS.swift in Sources */,
|
||||
A718CD501F45C28F00966E06 /* MView_macOS.swift in Sources */,
|
||||
57E5E1581E3B393900D1CB28 /* Easing.swift in Sources */,
|
||||
57E5E1971E3B393900D1CB28 /* Point.swift in Sources */,
|
||||
57E5E1681E3B393900D1CB28 /* OpacityGenerator.swift in Sources */,
|
||||
@ -852,6 +908,8 @@
|
||||
57E5E18E1E3B393900D1CB28 /* GeomUtils.swift in Sources */,
|
||||
57E5E1AF1E3B393900D1CB28 /* CAAnimationClosure.swift in Sources */,
|
||||
57E5E17F1E3B393900D1CB28 /* DropShadow.swift in Sources */,
|
||||
A718CD441F45C28200966E06 /* Common_iOS.swift in Sources */,
|
||||
A718CD4D1F45C28F00966E06 /* Common_macOS.swift in Sources */,
|
||||
57E5E1641E3B393900D1CB28 /* AnimationRestorer.swift in Sources */,
|
||||
57E5E1741E3B393900D1CB28 /* Event.swift in Sources */,
|
||||
57E5E1841E3B393900D1CB28 /* Gradient.swift in Sources */,
|
||||
@ -933,6 +991,7 @@
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
FRAMEWORK_SEARCH_PATHS = "";
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
@ -948,12 +1007,16 @@
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = "";
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.11;
|
||||
MTL_ENABLE_DEBUG_INFO = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = iphoneos;
|
||||
SDKROOT = macosx;
|
||||
SUPPORTED_PLATFORMS = "macosx iphoneos iphonesimulator";
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 3.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
VALID_ARCHS = "x86_64 i386";
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
VERSION_INFO_PREFIX = "";
|
||||
};
|
||||
@ -985,6 +1048,7 @@
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
FRAMEWORK_SEARCH_PATHS = "";
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
@ -994,12 +1058,16 @@
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = "";
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.11;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
SDKROOT = iphoneos;
|
||||
SDKROOT = macosx;
|
||||
SUPPORTED_PLATFORMS = "macosx iphoneos iphonesimulator";
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
|
||||
SWIFT_VERSION = 3.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
VALIDATE_PRODUCT = YES;
|
||||
VALID_ARCHS = "x86_64 i386";
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
VERSION_INFO_PREFIX = "";
|
||||
};
|
||||
@ -1008,42 +1076,46 @@
|
||||
57FCD2811D76EA4600CC0FB6 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
APPLICATION_EXTENSION_API_ONLY = NO;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
|
||||
DEFINES_MODULE = YES;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
DYLIB_CURRENT_VERSION = 1;
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
FRAMEWORK_SEARCH_PATHS = "$(inherited)";
|
||||
FRAMEWORK_SEARCH_PATHS = "";
|
||||
GCC_PRECOMPILE_PREFIX_HEADER = NO;
|
||||
INFOPLIST_FILE = "$(SRCROOT)/Source/Info.plist";
|
||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
LD_RUNPATH_SEARCH_PATHS = "";
|
||||
OTHER_SWIFT_FLAGS = "-D CARTHAGE";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.exyte.Macaw;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_VERSION = 3.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2,3,4";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
57FCD2821D76EA4600CC0FB6 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
APPLICATION_EXTENSION_API_ONLY = NO;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
|
||||
DEFINES_MODULE = YES;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
DYLIB_CURRENT_VERSION = 1;
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
FRAMEWORK_SEARCH_PATHS = "$(inherited)";
|
||||
FRAMEWORK_SEARCH_PATHS = "";
|
||||
GCC_PRECOMPILE_PREFIX_HEADER = NO;
|
||||
INFOPLIST_FILE = "$(SRCROOT)/Source/Info.plist";
|
||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
LD_RUNPATH_SEARCH_PATHS = "";
|
||||
OTHER_SWIFT_FLAGS = "-D CARTHAGE";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.exyte.Macaw;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_VERSION = 3.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2,3,4";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
@ -1051,11 +1123,22 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
DEVELOPMENT_TEAM = 7T95R85V93;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(SDKROOT)",
|
||||
);
|
||||
INFOPLIST_FILE = MacawTests/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks @executable_path/../Frameworks @loader_path/../Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.exyte.MacawTests;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
SDKROOT = macosx10.12;
|
||||
SUPPORTED_PLATFORMS = "iphonesimulator iphoneos macosx";
|
||||
SWIFT_VERSION = 3.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2,3,4";
|
||||
VALID_ARCHS = "x86_64 i386";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
@ -1063,11 +1146,22 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
DEVELOPMENT_TEAM = 7T95R85V93;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(SDKROOT)",
|
||||
);
|
||||
INFOPLIST_FILE = MacawTests/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks @executable_path/../Frameworks @loader_path/../Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.exyte.MacawTests;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
SDKROOT = macosx10.12;
|
||||
SUPPORTED_PLATFORMS = "iphonesimulator iphoneos macosx";
|
||||
SWIFT_VERSION = 3.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2,3,4";
|
||||
VALID_ARCHS = "x86_64 i386";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
|
@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0820"
|
||||
LastUpgradeVersion = "0830"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
@ -28,26 +28,7 @@
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
<TestableReference
|
||||
skipped = "NO">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "57FCD2751D76EA4600CC0FB6"
|
||||
BuildableName = "MacawTests.xctest"
|
||||
BlueprintName = "MacawTests"
|
||||
ReferencedContainer = "container:Macaw.xcodeproj">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
</Testables>
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "57FCD26B1D76EA4600CC0FB6"
|
||||
BuildableName = "Macaw.framework"
|
||||
BlueprintName = "Macaw"
|
||||
ReferencedContainer = "container:Macaw.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</TestAction>
|
56
Macaw.xcodeproj/xcshareddata/xcschemes/MacawTests.xcscheme
Normal file
56
Macaw.xcodeproj/xcshareddata/xcschemes/MacawTests.xcscheme
Normal file
@ -0,0 +1,56 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0830"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
<TestableReference
|
||||
skipped = "NO">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "57FCD2751D76EA4600CC0FB6"
|
||||
BuildableName = "MacawTests.xctest"
|
||||
BlueprintName = "MacawTests"
|
||||
ReferencedContainer = "container:Macaw.xcodeproj">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
</Testables>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
@ -52,12 +52,12 @@ class ImageBoundsTests: XCTestCase {
|
||||
|
||||
func testInMemoryImage() {
|
||||
let bundle = Bundle(for: type(of: TestUtils()))
|
||||
guard let uiImage = UIImage(named: "logo.png", in: bundle, compatibleWith: .none) else {
|
||||
guard let mImage = MImage(named: "logo.png", in: bundle, compatibleWith: .none) else {
|
||||
XCTFail()
|
||||
return
|
||||
}
|
||||
|
||||
let image = Image(image: uiImage)
|
||||
let image = Image(image: mImage)
|
||||
guard let bounds = image.bounds() else {
|
||||
XCTFail("Bounds not available")
|
||||
return
|
||||
|
@ -144,7 +144,7 @@ class NodeBoundsTests: XCTestCase {
|
||||
texts.forEach { text in
|
||||
let text = Text(text: text)
|
||||
|
||||
let stringAttributes = [NSFontAttributeName: UIFont.systemFont(ofSize: UIFont.systemFontSize)]
|
||||
let stringAttributes = [NSFontAttributeName: MFont.systemFont(ofSize: MFont.systemFontSize)]
|
||||
let size = text.text.size(attributes: stringAttributes)
|
||||
let targetRect = Rect(x: 0.0, y: 0.0, w: size.width.doubleValue, h: size.height.doubleValue)
|
||||
|
||||
|
@ -8,7 +8,6 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
|
||||
open class AnimatableVariable<T>: Variable<T> {
|
||||
weak internal var node: Node?
|
||||
weak internal var node: Node?
|
||||
}
|
||||
|
@ -1,53 +1,53 @@
|
||||
public enum AnimationState {
|
||||
case initial
|
||||
case running
|
||||
case paused
|
||||
case initial
|
||||
case running
|
||||
case paused
|
||||
}
|
||||
|
||||
public class Animation {
|
||||
|
||||
internal init() {
|
||||
}
|
||||
|
||||
public func play() {
|
||||
}
|
||||
|
||||
public func stop() {
|
||||
}
|
||||
|
||||
public func pause() {
|
||||
|
||||
}
|
||||
|
||||
internal init() {
|
||||
}
|
||||
|
||||
public func play() {
|
||||
}
|
||||
|
||||
public func stop() {
|
||||
}
|
||||
|
||||
public func pause() {
|
||||
|
||||
public func state() -> AnimationState {
|
||||
return .initial
|
||||
}
|
||||
|
||||
public func easing(_ easing: Easing) -> Animation {
|
||||
return self
|
||||
}
|
||||
|
||||
public func delay(_ delay: Double) -> Animation {
|
||||
return self
|
||||
}
|
||||
|
||||
public func cycle(_ count: Double) -> Animation {
|
||||
return self
|
||||
}
|
||||
|
||||
public func cycle() -> Animation{
|
||||
return self
|
||||
}
|
||||
|
||||
public func reverse() -> Animation {
|
||||
return self
|
||||
}
|
||||
|
||||
public func autoreversed() -> Animation {
|
||||
return self
|
||||
}
|
||||
|
||||
@discardableResult public func onComplete(_: @escaping (() -> ())) -> Animation {
|
||||
return self
|
||||
}
|
||||
}
|
||||
|
||||
public func state() -> AnimationState {
|
||||
return .initial
|
||||
}
|
||||
|
||||
public func easing(_ easing: Easing) -> Animation {
|
||||
return self
|
||||
}
|
||||
|
||||
public func delay(_ delay: Double) -> Animation {
|
||||
return self
|
||||
}
|
||||
|
||||
public func cycle(_ count: Double) -> Animation {
|
||||
return self
|
||||
}
|
||||
|
||||
public func cycle() -> Animation{
|
||||
return self
|
||||
}
|
||||
|
||||
public func reverse() -> Animation {
|
||||
return self
|
||||
}
|
||||
|
||||
public func autoreversed() -> Animation {
|
||||
return self
|
||||
}
|
||||
|
||||
@discardableResult public func onComplete(_: @escaping (() -> ())) -> Animation {
|
||||
return self
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,10 @@
|
||||
import UIKit
|
||||
import Foundation
|
||||
|
||||
#if os(iOS)
|
||||
import UIKit
|
||||
#elseif os(OSX)
|
||||
import AppKit
|
||||
#endif
|
||||
|
||||
let animationProducer = AnimationProducer()
|
||||
|
||||
@ -7,7 +13,7 @@ class AnimationProducer {
|
||||
|
||||
var storedAnimations = [Node: BasicAnimation]()
|
||||
var delayedAnimations = [BasicAnimation: Timer]()
|
||||
var displayLink: CADisplayLink?
|
||||
var displayLink: MDisplayLink?
|
||||
|
||||
struct ContentAnimationDesc {
|
||||
let animation: ContentsAnimation
|
||||
@ -70,6 +76,11 @@ class AnimationProducer {
|
||||
storedAnimations[node] = animation
|
||||
return
|
||||
}
|
||||
|
||||
guard let layer = macawView.mLayer else {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
guard let cache = macawView.animationCache else {
|
||||
return
|
||||
@ -79,14 +90,14 @@ class AnimationProducer {
|
||||
case .unknown:
|
||||
return
|
||||
case .affineTransformation:
|
||||
addTransformAnimation(animation, sceneLayer: macawView.layer, animationCache: cache, completion: {
|
||||
addTransformAnimation(animation, sceneLayer: layer, animationCache: cache, completion: {
|
||||
if let next = animation.next {
|
||||
self.addAnimation(next)
|
||||
}
|
||||
})
|
||||
|
||||
case .opacity:
|
||||
addOpacityAnimation(animation, sceneLayer: macawView.layer, animationCache: cache, completion: {
|
||||
addOpacityAnimation(animation, sceneLayer: layer, animationCache: cache, completion: {
|
||||
if let next = animation.next {
|
||||
self.addAnimation(next)
|
||||
}
|
||||
@ -102,13 +113,13 @@ class AnimationProducer {
|
||||
}
|
||||
})
|
||||
case .morphing:
|
||||
addMorphingAnimation(animation, sceneLayer: macawView.layer, animationCache: cache, completion: {
|
||||
addMorphingAnimation(animation, sceneLayer: layer, animationCache: cache, completion: {
|
||||
if let next = animation.next {
|
||||
self.addAnimation(next)
|
||||
}
|
||||
})
|
||||
case .shape:
|
||||
addShapeAnimation(animation, sceneLayer: macawView.layer, animationCache: cache, completion: {
|
||||
addShapeAnimation(animation, sceneLayer: layer, animationCache: cache, completion: {
|
||||
if let next = animation.next {
|
||||
self.addAnimation(next)
|
||||
}
|
||||
@ -317,9 +328,9 @@ class AnimationProducer {
|
||||
|
||||
contentsAnimations.append(animationDesc)
|
||||
|
||||
if displayLink == .none {
|
||||
displayLink = CADisplayLink(target: self, selector: #selector(updateContentAnimations))
|
||||
displayLink?.frameInterval = 1
|
||||
if displayLink == nil {
|
||||
displayLink = MDisplayLink(target: self, selector: #selector(updateContentAnimations))
|
||||
//displayLink?.frameInterval = 1
|
||||
displayLink?.add(to: RunLoop.current, forMode: RunLoopMode.defaultRunLoopMode)
|
||||
}
|
||||
}
|
||||
|
@ -1,104 +1,103 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
class AnimationUtils {
|
||||
class func absolutePosition(_ node: Node) -> Transform {
|
||||
return AnimationUtils.absoluteTransform(node, pos: node.place)
|
||||
}
|
||||
|
||||
class func absoluteTransform(_ node: Node, pos: Transform) -> Transform {
|
||||
var transform = pos
|
||||
var parent = nodesMap.parents(node).first
|
||||
while parent != .none {
|
||||
transform = GeomUtils.concat(t1: parent!.place, t2: transform)
|
||||
parent = nodesMap.parents(parent!).first
|
||||
}
|
||||
|
||||
return transform
|
||||
}
|
||||
|
||||
class func absoluteClip(node: Node) -> Locus? {
|
||||
|
||||
if let _ = node.clip {
|
||||
return node.clip
|
||||
}
|
||||
|
||||
var parent = nodesMap.parents(node).first
|
||||
while parent != .none {
|
||||
if let _ = parent?.clip {
|
||||
return parent?.clip
|
||||
}
|
||||
|
||||
parent = nodesMap.parents(parent!).first
|
||||
}
|
||||
|
||||
return .none
|
||||
class func absolutePosition(_ node: Node) -> Transform {
|
||||
return AnimationUtils.absoluteTransform(node, pos: node.place)
|
||||
}
|
||||
|
||||
class func absoluteTransform(_ node: Node, pos: Transform) -> Transform {
|
||||
var transform = pos
|
||||
var parent = nodesMap.parents(node).first
|
||||
while parent != .none {
|
||||
transform = GeomUtils.concat(t1: parent!.place, t2: transform)
|
||||
parent = nodesMap.parents(parent!).first
|
||||
}
|
||||
|
||||
private static var indexCache = [Node: Int]()
|
||||
class func absoluteIndex(_ node: Node, useCache: Bool = false) -> Int {
|
||||
if useCache {
|
||||
if let cachedIndex = indexCache[node] {
|
||||
return cachedIndex
|
||||
}
|
||||
} else {
|
||||
indexCache.removeAll()
|
||||
}
|
||||
|
||||
|
||||
func childrenTotalCount(_ node: Node) -> Int{
|
||||
guard let group = node as? Group else {
|
||||
return 1
|
||||
}
|
||||
|
||||
var count = 1
|
||||
for child in group.contents {
|
||||
count += childrenTotalCount(child)
|
||||
}
|
||||
|
||||
return count
|
||||
}
|
||||
|
||||
var zIndex = 0
|
||||
var parent = nodesMap.parents(node).first
|
||||
var currentNode = node
|
||||
while parent != .none {
|
||||
if let group = parent as? Group {
|
||||
let localIndex = group.contents.index(of: currentNode) ?? group.contents.count
|
||||
|
||||
for i in 0..<localIndex {
|
||||
zIndex += childrenTotalCount(group.contents[i])
|
||||
}
|
||||
}
|
||||
|
||||
zIndex += 1
|
||||
|
||||
currentNode = parent!
|
||||
parent = nodesMap.parents(parent!).first
|
||||
}
|
||||
|
||||
if useCache {
|
||||
indexCache[node] = zIndex
|
||||
}
|
||||
|
||||
return zIndex
|
||||
return transform
|
||||
}
|
||||
|
||||
class func absoluteClip(node: Node) -> Locus? {
|
||||
|
||||
if let _ = node.clip {
|
||||
return node.clip
|
||||
}
|
||||
|
||||
class func animatedNodes(root: Node, animationCache: AnimationCache) -> [Node] {
|
||||
if animationCache.isAnimating(root) {
|
||||
return [root]
|
||||
}
|
||||
|
||||
guard let rootGroup = root as? Group else {
|
||||
return []
|
||||
}
|
||||
|
||||
var result = [Node]()
|
||||
rootGroup.contents.forEach { child in
|
||||
let childAnimatedNodes = animatedNodes(root: child, animationCache: animationCache)
|
||||
result.append(contentsOf: childAnimatedNodes)
|
||||
}
|
||||
|
||||
return result
|
||||
var parent = nodesMap.parents(node).first
|
||||
while parent != .none {
|
||||
if let _ = parent?.clip {
|
||||
return parent?.clip
|
||||
}
|
||||
|
||||
parent = nodesMap.parents(parent!).first
|
||||
}
|
||||
|
||||
return .none
|
||||
}
|
||||
|
||||
private static var indexCache = [Node: Int]()
|
||||
class func absoluteIndex(_ node: Node, useCache: Bool = false) -> Int {
|
||||
if useCache {
|
||||
if let cachedIndex = indexCache[node] {
|
||||
return cachedIndex
|
||||
}
|
||||
} else {
|
||||
indexCache.removeAll()
|
||||
}
|
||||
|
||||
|
||||
func childrenTotalCount(_ node: Node) -> Int{
|
||||
guard let group = node as? Group else {
|
||||
return 1
|
||||
}
|
||||
|
||||
var count = 1
|
||||
for child in group.contents {
|
||||
count += childrenTotalCount(child)
|
||||
}
|
||||
|
||||
return count
|
||||
}
|
||||
|
||||
var zIndex = 0
|
||||
var parent = nodesMap.parents(node).first
|
||||
var currentNode = node
|
||||
while parent != .none {
|
||||
if let group = parent as? Group {
|
||||
let localIndex = group.contents.index(of: currentNode) ?? group.contents.count
|
||||
|
||||
for i in 0..<localIndex {
|
||||
zIndex += childrenTotalCount(group.contents[i])
|
||||
}
|
||||
}
|
||||
|
||||
zIndex += 1
|
||||
|
||||
currentNode = parent!
|
||||
parent = nodesMap.parents(parent!).first
|
||||
}
|
||||
|
||||
if useCache {
|
||||
indexCache[node] = zIndex
|
||||
}
|
||||
|
||||
return zIndex
|
||||
}
|
||||
|
||||
class func animatedNodes(root: Node, animationCache: AnimationCache) -> [Node] {
|
||||
if animationCache.isAnimating(root) {
|
||||
return [root]
|
||||
}
|
||||
|
||||
guard let rootGroup = root as? Group else {
|
||||
return []
|
||||
}
|
||||
|
||||
var result = [Node]()
|
||||
rootGroup.contents.forEach { child in
|
||||
let childAnimatedNodes = animatedNodes(root: child, animationCache: animationCache)
|
||||
result.append(contentsOf: childAnimatedNodes)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
@ -7,9 +7,9 @@
|
||||
//
|
||||
|
||||
public enum Easing {
|
||||
case ease
|
||||
case linear
|
||||
case easeIn
|
||||
case easeOut
|
||||
case easeInOut
|
||||
case ease
|
||||
case linear
|
||||
case easeIn
|
||||
case easeOut
|
||||
case easeInOut
|
||||
}
|
||||
|
@ -1,38 +1,42 @@
|
||||
import UIKit
|
||||
import Foundation
|
||||
|
||||
#if os(iOS)
|
||||
import UIKit
|
||||
#endif
|
||||
|
||||
public extension Rect {
|
||||
|
||||
convenience init(cgRect: CGRect) {
|
||||
self.init(
|
||||
x: Double(cgRect.origin.x),
|
||||
y: Double(cgRect.origin.y),
|
||||
w: Double(cgRect.size.width),
|
||||
h: Double(cgRect.size.height))
|
||||
}
|
||||
|
||||
func cgRect() -> CGRect {
|
||||
return CGRect(x: self.x, y: self.y, width: self.w, height: self.h)
|
||||
}
|
||||
|
||||
func applyTransform(_ transform: Transform) -> Rect {
|
||||
|
||||
// TODO: Rewrite using math
|
||||
|
||||
let cgTransform = RenderUtils.mapTransform(transform)
|
||||
return Rect(cgRect: self.cgRect().applying(cgTransform))
|
||||
}
|
||||
|
||||
public func description() -> String {
|
||||
return "x: \(self.x) y:\(self.y) w:\(self.w) h:\(self.h)"
|
||||
}
|
||||
|
||||
convenience init(cgRect: CGRect) {
|
||||
self.init(
|
||||
x: Double(cgRect.origin.x),
|
||||
y: Double(cgRect.origin.y),
|
||||
w: Double(cgRect.size.width),
|
||||
h: Double(cgRect.size.height))
|
||||
}
|
||||
|
||||
func cgRect() -> CGRect {
|
||||
return CGRect(x: self.x, y: self.y, width: self.w, height: self.h)
|
||||
}
|
||||
|
||||
func applyTransform(_ transform: Transform) -> Rect {
|
||||
|
||||
// TODO: Rewrite using math
|
||||
|
||||
let cgTransform = RenderUtils.mapTransform(transform)
|
||||
return Rect(cgRect: self.cgRect().applying(cgTransform))
|
||||
}
|
||||
|
||||
public func description() -> String {
|
||||
return "x: \(self.x) y:\(self.y) w:\(self.w) h:\(self.h)"
|
||||
}
|
||||
}
|
||||
|
||||
public extension Point {
|
||||
public func cgPoint() -> CGPoint {
|
||||
return CGPoint(x: self.x, y: self.y)
|
||||
}
|
||||
|
||||
public func description() -> String {
|
||||
return "x: \(self.x) y:\(self.y)"
|
||||
}
|
||||
public func cgPoint() -> CGPoint {
|
||||
return CGPoint(x: self.x, y: self.y)
|
||||
}
|
||||
|
||||
public func description() -> String {
|
||||
return "x: \(self.x) y:\(self.y)"
|
||||
}
|
||||
}
|
||||
|
@ -1,25 +1,24 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
public func >> (a: Double, b: Double) -> OpacityAnimationDescription {
|
||||
return OpacityAnimationDescription(valueFunc: { t in
|
||||
return a.interpolate(b, progress: t)
|
||||
})
|
||||
return OpacityAnimationDescription(valueFunc: { t in
|
||||
return a.interpolate(b, progress: t)
|
||||
})
|
||||
}
|
||||
|
||||
public func >> (a: Transform, b: Transform) -> TransformAnimationDescription {
|
||||
return TransformAnimationDescription(valueFunc: { t in
|
||||
return a.interpolate(b, progress: t)
|
||||
})
|
||||
return TransformAnimationDescription(valueFunc: { t in
|
||||
return a.interpolate(b, progress: t)
|
||||
})
|
||||
}
|
||||
|
||||
public func >> (a: Locus, b: Locus) -> MorphingAnimationDescription {
|
||||
return MorphingAnimationDescription(valueFunc: { t in
|
||||
// return a.interpolate(b, progress: t)
|
||||
if t == 0.0 {
|
||||
return a
|
||||
}
|
||||
|
||||
return b
|
||||
})
|
||||
return MorphingAnimationDescription(valueFunc: { t in
|
||||
// return a.interpolate(b, progress: t)
|
||||
if t == 0.0 {
|
||||
return a
|
||||
}
|
||||
|
||||
return b
|
||||
})
|
||||
}
|
||||
|
@ -1,9 +1,9 @@
|
||||
public protocol ContentsInterpolation: Interpolable {
|
||||
|
||||
|
||||
}
|
||||
|
||||
extension Array: ContentsInterpolation {
|
||||
public func interpolate(_ endValue: Array, progress: Double) -> Array {
|
||||
return self
|
||||
}
|
||||
public func interpolate(_ endValue: Array, progress: Double) -> Array {
|
||||
return self
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,9 @@
|
||||
public protocol DoubleInterpolation: Interpolable {
|
||||
|
||||
|
||||
}
|
||||
|
||||
extension Double: DoubleInterpolation {
|
||||
public func interpolate(_ endValue: Double, progress: Double) -> Double {
|
||||
return self + (endValue - self) * progress
|
||||
}
|
||||
|
||||
public func interpolate(_ endValue: Double, progress: Double) -> Double {
|
||||
return self + (endValue - self) * progress
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,9 @@
|
||||
public protocol LocusInterpolation: Interpolable {
|
||||
|
||||
|
||||
}
|
||||
|
||||
extension Locus: LocusInterpolation {
|
||||
public func interpolate(_ endValue: Locus, progress: Double) -> Self {
|
||||
|
||||
return self
|
||||
}
|
||||
public func interpolate(_ endValue: Locus, progress: Double) -> Self {
|
||||
return self
|
||||
}
|
||||
}
|
||||
|
@ -7,11 +7,11 @@
|
||||
//
|
||||
|
||||
public protocol ShapeInterpolation: Interpolable {
|
||||
|
||||
|
||||
}
|
||||
|
||||
extension Shape: ShapeInterpolation {
|
||||
public func interpolate(_ endValue: Shape, progress: Double) -> Self {
|
||||
return self
|
||||
}
|
||||
public func interpolate(_ endValue: Shape, progress: Double) -> Self {
|
||||
return self
|
||||
}
|
||||
}
|
||||
|
@ -1,15 +1,15 @@
|
||||
|
||||
public protocol TransformInterpolation: Interpolable {
|
||||
|
||||
|
||||
}
|
||||
|
||||
extension Transform: TransformInterpolation {
|
||||
public func interpolate(_ endValue: Transform, progress: Double) -> Transform {
|
||||
return Transform(m11: self.m11.interpolate(endValue.m11, progress: progress),
|
||||
m12: self.m12.interpolate(endValue.m12, progress: progress),
|
||||
m21: self.m21.interpolate(endValue.m21, progress: progress),
|
||||
m22: self.m22.interpolate(endValue.m22, progress: progress),
|
||||
dx: self.dx.interpolate(endValue.dx, progress: progress),
|
||||
dy: self.dy.interpolate(endValue.dy, progress: progress))
|
||||
}
|
||||
public func interpolate(_ endValue: Transform, progress: Double) -> Transform {
|
||||
return Transform(m11: self.m11.interpolate(endValue.m11, progress: progress),
|
||||
m12: self.m12.interpolate(endValue.m12, progress: progress),
|
||||
m21: self.m21.interpolate(endValue.m21, progress: progress),
|
||||
m22: self.m22.interpolate(endValue.m22, progress: progress),
|
||||
dx: self.dx.interpolate(endValue.dx, progress: progress),
|
||||
dy: self.dy.interpolate(endValue.dy, progress: progress))
|
||||
}
|
||||
}
|
||||
|
@ -1,32 +1,31 @@
|
||||
|
||||
|
||||
func boundsForFunc(_ func2d: func2D) -> Rect {
|
||||
|
||||
var p = func2d(0.0)
|
||||
var minX = p.x
|
||||
var minY = p.y
|
||||
var maxX = minX
|
||||
var maxY = minY
|
||||
|
||||
for t in stride(from: 0.0, to: 1.0, by: 0.01) {
|
||||
p = func2d(t)
|
||||
|
||||
if minX > p.x {
|
||||
minX = p.x
|
||||
}
|
||||
|
||||
if minY > p.y {
|
||||
minY = p.y
|
||||
}
|
||||
|
||||
if maxX < p.x {
|
||||
maxX = p.x
|
||||
}
|
||||
|
||||
if maxY < p.y {
|
||||
maxY = p.y
|
||||
}
|
||||
}
|
||||
|
||||
return Rect(x: minX, y: minY, w: maxX - minX, h: maxY - minY)
|
||||
|
||||
var p = func2d(0.0)
|
||||
var minX = p.x
|
||||
var minY = p.y
|
||||
var maxX = minX
|
||||
var maxY = minY
|
||||
|
||||
for t in stride(from: 0.0, to: 1.0, by: 0.01) {
|
||||
p = func2d(t)
|
||||
|
||||
if minX > p.x {
|
||||
minX = p.x
|
||||
}
|
||||
|
||||
if minY > p.y {
|
||||
minY = p.y
|
||||
}
|
||||
|
||||
if maxX < p.x {
|
||||
maxX = p.x
|
||||
}
|
||||
|
||||
if maxY < p.y {
|
||||
maxY = p.y
|
||||
}
|
||||
}
|
||||
|
||||
return Rect(x: minX, y: minY, w: maxX - minX, h: maxY - minY)
|
||||
}
|
||||
|
@ -1,107 +1,107 @@
|
||||
|
||||
func pathBounds(_ path: Path) -> Rect? {
|
||||
|
||||
guard let firstSegment = path.segments.first else {
|
||||
return .none
|
||||
}
|
||||
|
||||
let firstSegmentInfo = pathSegmenInfo(firstSegment, currentPoint: .none, currentBezierPoint: .none)
|
||||
var bounds = firstSegmentInfo.0
|
||||
var currentPoint = firstSegmentInfo.1 ?? Point.origin
|
||||
var cubicBezierPoint: Point?
|
||||
|
||||
for segment in path.segments {
|
||||
let segmentInfo = pathSegmenInfo(segment, currentPoint: currentPoint, currentBezierPoint: cubicBezierPoint)
|
||||
if let segmentBounds = segmentInfo.0 {
|
||||
if segment.isAbsolute() {
|
||||
bounds = bounds?.union(rect: segmentBounds)
|
||||
} else {
|
||||
bounds = bounds?.union(rect: segmentBounds.move(offset: currentPoint))
|
||||
}
|
||||
}
|
||||
|
||||
if let segmentLastPoint = segmentInfo.1 {
|
||||
if segment.isAbsolute() {
|
||||
currentPoint = segmentLastPoint
|
||||
} else {
|
||||
currentPoint = segmentLastPoint.add(currentPoint)
|
||||
}
|
||||
}
|
||||
|
||||
if let segmentBezierPoint = segmentInfo.2 {
|
||||
if segment.isAbsolute() {
|
||||
cubicBezierPoint = segmentBezierPoint
|
||||
} else {
|
||||
cubicBezierPoint = segmentBezierPoint.add(currentPoint)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return bounds
|
||||
|
||||
guard let firstSegment = path.segments.first else {
|
||||
return .none
|
||||
}
|
||||
|
||||
let firstSegmentInfo = pathSegmenInfo(firstSegment, currentPoint: .none, currentBezierPoint: .none)
|
||||
var bounds = firstSegmentInfo.0
|
||||
var currentPoint = firstSegmentInfo.1 ?? Point.origin
|
||||
var cubicBezierPoint: Point?
|
||||
|
||||
for segment in path.segments {
|
||||
let segmentInfo = pathSegmenInfo(segment, currentPoint: currentPoint, currentBezierPoint: cubicBezierPoint)
|
||||
if let segmentBounds = segmentInfo.0 {
|
||||
if segment.isAbsolute() {
|
||||
bounds = bounds?.union(rect: segmentBounds)
|
||||
} else {
|
||||
bounds = bounds?.union(rect: segmentBounds.move(offset: currentPoint))
|
||||
}
|
||||
}
|
||||
|
||||
if let segmentLastPoint = segmentInfo.1 {
|
||||
if segment.isAbsolute() {
|
||||
currentPoint = segmentLastPoint
|
||||
} else {
|
||||
currentPoint = segmentLastPoint.add(currentPoint)
|
||||
}
|
||||
}
|
||||
|
||||
if let segmentBezierPoint = segmentInfo.2 {
|
||||
if segment.isAbsolute() {
|
||||
cubicBezierPoint = segmentBezierPoint
|
||||
} else {
|
||||
cubicBezierPoint = segmentBezierPoint.add(currentPoint)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return bounds
|
||||
}
|
||||
|
||||
func pathSegmenInfo(_ segment: PathSegment, currentPoint: Point?, currentBezierPoint: Point?)
|
||||
-> (Rect?, Point?, Point?) { // Bounds, last point, last bezier point TODO: Replace as struct
|
||||
|
||||
let data = segment.data
|
||||
switch segment.type {
|
||||
case .m, .M:
|
||||
let point = Point(x: data[0], y: data[1])
|
||||
return (Rect(x: point.x, y: point.y, w: 0.0, h: 0.0), point, .none)
|
||||
case .c, .C:
|
||||
return (cubicBounds(data), Point(x: data[4], y: data[5]), Point(x: data[2], y: data[3]))
|
||||
case .s, .S:
|
||||
guard let currentPoint = currentPoint else {
|
||||
return (.none, .none, .none)
|
||||
}
|
||||
|
||||
var p2 = currentPoint
|
||||
if let bezierPoint = currentBezierPoint {
|
||||
p2 = Point(
|
||||
x: 2.0 * currentPoint.x - bezierPoint.x,
|
||||
y: 2.0 * currentPoint.y - bezierPoint.y)
|
||||
}
|
||||
|
||||
return (sCubicBounds(data, currentPoint: currentPoint, currentBezierPoint: currentBezierPoint),
|
||||
Point(x: data[2], y: data[3]),
|
||||
Point(x: p2.x, y: p2.y))
|
||||
case .h, .H:
|
||||
return (Rect(x: 0.0, y: 0.0, w: data[0], h: 0.0), Point(x: data[0], y: 0.0), .none)
|
||||
case .v, .V:
|
||||
return (Rect(x: 0.0, y: 0.0, w: 0.0, h: data[0]), Point(x: 0.0, y: data[0]), .none)
|
||||
case .l, .L:
|
||||
return (Rect(x: data[0], y: data[1], w: 0.0, h: 0.0), Point(x: data[0], y: data[1]), .none)
|
||||
default:
|
||||
return (.none, .none, .none)
|
||||
}
|
||||
-> (Rect?, Point?, Point?) { // Bounds, last point, last bezier point TODO: Replace as struct
|
||||
|
||||
let data = segment.data
|
||||
switch segment.type {
|
||||
case .m, .M:
|
||||
let point = Point(x: data[0], y: data[1])
|
||||
return (Rect(x: point.x, y: point.y, w: 0.0, h: 0.0), point, .none)
|
||||
case .c, .C:
|
||||
return (cubicBounds(data), Point(x: data[4], y: data[5]), Point(x: data[2], y: data[3]))
|
||||
case .s, .S:
|
||||
guard let currentPoint = currentPoint else {
|
||||
return (.none, .none, .none)
|
||||
}
|
||||
|
||||
var p2 = currentPoint
|
||||
if let bezierPoint = currentBezierPoint {
|
||||
p2 = Point(
|
||||
x: 2.0 * currentPoint.x - bezierPoint.x,
|
||||
y: 2.0 * currentPoint.y - bezierPoint.y)
|
||||
}
|
||||
|
||||
return (sCubicBounds(data, currentPoint: currentPoint, currentBezierPoint: currentBezierPoint),
|
||||
Point(x: data[2], y: data[3]),
|
||||
Point(x: p2.x, y: p2.y))
|
||||
case .h, .H:
|
||||
return (Rect(x: 0.0, y: 0.0, w: data[0], h: 0.0), Point(x: data[0], y: 0.0), .none)
|
||||
case .v, .V:
|
||||
return (Rect(x: 0.0, y: 0.0, w: 0.0, h: data[0]), Point(x: 0.0, y: data[0]), .none)
|
||||
case .l, .L:
|
||||
return (Rect(x: data[0], y: data[1], w: 0.0, h: 0.0), Point(x: data[0], y: data[1]), .none)
|
||||
default:
|
||||
return (.none, .none, .none)
|
||||
}
|
||||
}
|
||||
|
||||
private func cubicBounds(_ data: [Double]) -> Rect {
|
||||
let p0 = Point(x: 0, y: 0)
|
||||
let p1 = Point(x: data[0], y: data[1])
|
||||
let p2 = Point(x: data[2], y: data[3])
|
||||
let p3 = Point(x: data[4], y: data[5])
|
||||
|
||||
let bezier3 = { (t: Double) -> Point in return BezierFunc2D(t, p0: p0, p1: p1, p2: p2, p3: p3) }
|
||||
|
||||
// TODO: Replace with accurate implementation via derivative
|
||||
return boundsForFunc(bezier3)
|
||||
let p0 = Point(x: 0, y: 0)
|
||||
let p1 = Point(x: data[0], y: data[1])
|
||||
let p2 = Point(x: data[2], y: data[3])
|
||||
let p3 = Point(x: data[4], y: data[5])
|
||||
|
||||
let bezier3 = { (t: Double) -> Point in return BezierFunc2D(t, p0: p0, p1: p1, p2: p2, p3: p3) }
|
||||
|
||||
// TODO: Replace with accurate implementation via derivative
|
||||
return boundsForFunc(bezier3)
|
||||
}
|
||||
|
||||
private func sCubicBounds(_ data: [Double], currentPoint: Point, currentBezierPoint: Point?) -> Rect {
|
||||
|
||||
let p0 = Point(x: 0, y: 0)
|
||||
let p1 = Point(x: data[0], y: data[1])
|
||||
let p3 = Point(x: data[2], y: data[3])
|
||||
var p2 = currentPoint
|
||||
if let bezierPoint = currentBezierPoint {
|
||||
p2 = Point(
|
||||
x: 2.0 * currentPoint.x - bezierPoint.x,
|
||||
y: 2.0 * currentPoint.y - bezierPoint.y)
|
||||
}
|
||||
|
||||
let bezier3 = { (t: Double) -> Point in return BezierFunc2D(t, p0: p0, p1: p1, p2: p2, p3: p3) }
|
||||
|
||||
// TODO: Replace with accurate implementation via derivative
|
||||
return boundsForFunc(bezier3)
|
||||
|
||||
let p0 = Point(x: 0, y: 0)
|
||||
let p1 = Point(x: data[0], y: data[1])
|
||||
let p3 = Point(x: data[2], y: data[3])
|
||||
var p2 = currentPoint
|
||||
if let bezierPoint = currentBezierPoint {
|
||||
p2 = Point(
|
||||
x: 2.0 * currentPoint.x - bezierPoint.x,
|
||||
y: 2.0 * currentPoint.y - bezierPoint.y)
|
||||
}
|
||||
|
||||
let bezier3 = { (t: Double) -> Point in return BezierFunc2D(t, p0: p0, p1: p1, p2: p2, p3: p3) }
|
||||
|
||||
// TODO: Replace with accurate implementation via derivative
|
||||
return boundsForFunc(bezier3)
|
||||
}
|
||||
|
@ -3,12 +3,12 @@ import Foundation
|
||||
typealias func2D = ((_ t: Double) -> (Point))
|
||||
|
||||
func BezierFunc2D(_ t: Double, p0: Point, p1: Point, p2: Point, p3: Point) -> Point {
|
||||
return Point(
|
||||
x: polynom3(t, p0: p0.x, p1: p1.x, p2: p2.x, p3: p3.x),
|
||||
y: polynom3(t, p0: p0.y, p1: p1.y, p2: p2.y, p3: p3.y))
|
||||
return Point(
|
||||
x: polynom3(t, p0: p0.x, p1: p1.x, p2: p2.x, p3: p3.x),
|
||||
y: polynom3(t, p0: p0.y, p1: p1.y, p2: p2.y, p3: p3.y))
|
||||
}
|
||||
|
||||
func polynom3(_ t: Double, p0: Double, p1: Double, p2: Double, p3: Double) -> Double {
|
||||
let t1 = 1.0 - t
|
||||
return pow(t1, 3.0) * p0 + 3.0 * t * pow(t1, 2.0) * p1 + 3.0 * t * t * t1 * p2 + pow(t, 3.0) * p3
|
||||
let t1 = 1.0 - t
|
||||
return pow(t1, 3.0) * p0 + 3.0 * t * pow(t1, 2.0) * p1 + 3.0 * t * t * t1 * p2 + pow(t, 3.0) * p3
|
||||
}
|
||||
|
@ -1,189 +1,196 @@
|
||||
import Foundation
|
||||
|
||||
import UIKit
|
||||
#if os(iOS)
|
||||
import UIKit
|
||||
#elseif os(OSX)
|
||||
import AppKit
|
||||
#endif
|
||||
|
||||
class AnimationCache {
|
||||
|
||||
class CachedLayer {
|
||||
let layer: ShapeLayer
|
||||
let animation: Animation
|
||||
var linksCounter = 1
|
||||
|
||||
required init(layer: ShapeLayer, animation: Animation) {
|
||||
self.layer = layer
|
||||
self.animation = animation
|
||||
}
|
||||
}
|
||||
|
||||
let sceneLayer: CALayer
|
||||
var layerCache = [Node: CachedLayer]()
|
||||
|
||||
required init(sceneLayer: CALayer) {
|
||||
self.sceneLayer = sceneLayer
|
||||
}
|
||||
|
||||
func layerForNode(_ node: Node, animation: Animation, customBounds: Rect? = .none, shouldRenderContent: Bool = true) -> ShapeLayer {
|
||||
guard let cachedLayer = layerCache[node] else {
|
||||
let layer = ShapeLayer()
|
||||
layer.shouldRenderContent = shouldRenderContent
|
||||
layer.animationCache = self
|
||||
|
||||
// Use to debug animation layers
|
||||
// layer.backgroundColor = UIColor.green.cgColor
|
||||
// layer.borderWidth = 1.0
|
||||
// layer.borderColor = UIColor.blue.cgColor
|
||||
|
||||
let calculatedBounds = customBounds ?? node.bounds()
|
||||
if let shapeBounds = calculatedBounds {
|
||||
let cgRect = shapeBounds.cgRect()
|
||||
|
||||
let origFrame = CGRect(x: 0.0, y: 0.0,
|
||||
width: round(cgRect.width),
|
||||
height: round(cgRect.height))
|
||||
|
||||
layer.bounds = origFrame
|
||||
layer.anchorPoint = CGPoint(
|
||||
x: -1.0 * cgRect.origin.x / cgRect.width,
|
||||
y: -1.0 * cgRect.origin.y / cgRect.height
|
||||
)
|
||||
layer.zPosition = CGFloat(AnimationUtils.absoluteIndex(node))
|
||||
|
||||
layer.renderTransform = CGAffineTransform(translationX: -1.0 * cgRect.origin.x, y: -1.0 * cgRect.origin.y)
|
||||
|
||||
let nodeTransform = RenderUtils.mapTransform(AnimationUtils.absolutePosition(node))
|
||||
layer.transform = CATransform3DMakeAffineTransform(nodeTransform)
|
||||
|
||||
// Clip
|
||||
if let clip = AnimationUtils.absoluteClip(node: node) {
|
||||
let maskLayer = CAShapeLayer()
|
||||
let origPath = RenderUtils.toBezierPath(clip).cgPath
|
||||
var offsetTransform = CGAffineTransform(translationX: -1.0 * cgRect.origin.x, y: -1.0 * cgRect.origin.y)
|
||||
let clipPath = origPath.mutableCopy(using: &offsetTransform)
|
||||
maskLayer.path = clipPath
|
||||
layer.mask = maskLayer
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
layer.opacity = Float(node.opacity)
|
||||
layer.node = node
|
||||
|
||||
layer.contentsScale = calculateAnimationScale(animation: animation)
|
||||
|
||||
layer.setNeedsDisplay()
|
||||
sceneLayer.addSublayer(layer)
|
||||
|
||||
layerCache[node] = CachedLayer(layer: layer, animation: animation)
|
||||
sceneLayer.setNeedsDisplay()
|
||||
|
||||
return layer
|
||||
}
|
||||
|
||||
cachedLayer.linksCounter += 1
|
||||
|
||||
return cachedLayer.layer
|
||||
}
|
||||
|
||||
class CachedLayer {
|
||||
let layer: ShapeLayer
|
||||
let animation: Animation
|
||||
var linksCounter = 1
|
||||
|
||||
private func calculateAnimationScale(animation: Animation) -> CGFloat {
|
||||
let defaultScale = UIScreen.main.scale
|
||||
|
||||
guard let transformAnimation = animation as? TransformAnimation else {
|
||||
return defaultScale
|
||||
}
|
||||
|
||||
let animFunc = transformAnimation.getVFunc()
|
||||
let origBounds = Rect(x: 0.0, y: 0.0, w: 1.0, h: 1.0)
|
||||
|
||||
let startTransform = animFunc(0.0)
|
||||
let startBounds = origBounds.applyTransform(startTransform)
|
||||
var startArea = startBounds.w * startBounds.h
|
||||
|
||||
// zero scale protection
|
||||
if startArea == 0.0 {
|
||||
startArea = 0.1
|
||||
}
|
||||
|
||||
var maxArea = startArea
|
||||
var t = 0.0
|
||||
let step = 0.1
|
||||
while t <= 1.0 {
|
||||
let currentTransform = animFunc(t)
|
||||
let currentBounds = origBounds.applyTransform(currentTransform)
|
||||
let currentArea = currentBounds.w * currentBounds.h
|
||||
if maxArea < currentArea {
|
||||
maxArea = currentArea
|
||||
}
|
||||
|
||||
t = t + step
|
||||
}
|
||||
|
||||
return defaultScale * CGFloat(sqrt(maxArea))
|
||||
required init(layer: ShapeLayer, animation: Animation) {
|
||||
self.layer = layer
|
||||
self.animation = animation
|
||||
}
|
||||
}
|
||||
|
||||
let sceneLayer: CALayer
|
||||
var layerCache = [Node: CachedLayer]()
|
||||
|
||||
required init(sceneLayer: CALayer) {
|
||||
self.sceneLayer = sceneLayer
|
||||
}
|
||||
|
||||
func layerForNode(_ node: Node, animation: Animation, customBounds: Rect? = .none, shouldRenderContent: Bool = true) -> ShapeLayer {
|
||||
guard let cachedLayer = layerCache[node] else {
|
||||
let layer = ShapeLayer()
|
||||
layer.shouldRenderContent = shouldRenderContent
|
||||
layer.animationCache = self
|
||||
|
||||
// Use to debug animation layers
|
||||
// layer.backgroundColor = MColor.green.cgColor
|
||||
// layer.borderWidth = 1.0
|
||||
// layer.borderColor = MColor.blue.cgColor
|
||||
|
||||
let calculatedBounds = customBounds ?? node.bounds()
|
||||
if let shapeBounds = calculatedBounds {
|
||||
let cgRect = shapeBounds.cgRect()
|
||||
|
||||
let origFrame = CGRect(x: 0.0, y: 0.0,
|
||||
width: round(cgRect.width),
|
||||
height: round(cgRect.height))
|
||||
|
||||
layer.bounds = origFrame
|
||||
layer.anchorPoint = CGPoint(
|
||||
x: -1.0 * cgRect.origin.x / cgRect.width,
|
||||
y: -1.0 * cgRect.origin.y / cgRect.height
|
||||
)
|
||||
layer.zPosition = CGFloat(AnimationUtils.absoluteIndex(node))
|
||||
|
||||
layer.renderTransform = CGAffineTransform(translationX: -1.0 * cgRect.origin.x, y: -1.0 * cgRect.origin.y)
|
||||
|
||||
let nodeTransform = RenderUtils.mapTransform(AnimationUtils.absolutePosition(node))
|
||||
layer.transform = CATransform3DMakeAffineTransform(nodeTransform)
|
||||
|
||||
// Clip
|
||||
if let clip = AnimationUtils.absoluteClip(node: node) {
|
||||
let maskLayer = CAShapeLayer()
|
||||
let origPath = RenderUtils.toBezierPath(clip).cgPath
|
||||
var offsetTransform = CGAffineTransform(translationX: -1.0 * cgRect.origin.x, y: -1.0 * cgRect.origin.y)
|
||||
let clipPath = origPath.mutableCopy(using: &offsetTransform)
|
||||
maskLayer.path = clipPath
|
||||
layer.mask = maskLayer
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
layer.opacity = Float(node.opacity)
|
||||
layer.node = node
|
||||
|
||||
layer.contentsScale = calculateAnimationScale(animation: animation)
|
||||
|
||||
layer.setNeedsDisplay()
|
||||
sceneLayer.addSublayer(layer)
|
||||
|
||||
layerCache[node] = CachedLayer(layer: layer, animation: animation)
|
||||
sceneLayer.setNeedsDisplay()
|
||||
|
||||
return layer
|
||||
}
|
||||
|
||||
func freeLayer(_ node: Node) {
|
||||
guard let cachedLayer = layerCache[node] else {
|
||||
return
|
||||
}
|
||||
|
||||
cachedLayer.linksCounter -= 1
|
||||
|
||||
if cachedLayer.linksCounter != 0 {
|
||||
return
|
||||
}
|
||||
|
||||
let layer = cachedLayer.layer
|
||||
layerCache.removeValue(forKey: node)
|
||||
sceneLayer.setNeedsDisplay()
|
||||
layer.removeFromSuperlayer()
|
||||
}
|
||||
|
||||
func isAnimating(_ node: Node) -> Bool {
|
||||
|
||||
if let _ = layerCache[node] {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func isChildrenAnimating(_ group: Group) -> Bool {
|
||||
|
||||
for child in group.contents {
|
||||
if isAnimating(child) {
|
||||
return true
|
||||
}
|
||||
|
||||
if let childGroup = child as? Group {
|
||||
return isChildrenAnimating(childGroup)
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func containsAnimation(_ node: Node) -> Bool {
|
||||
if isAnimating(node) {
|
||||
return true
|
||||
}
|
||||
|
||||
if let group = node as? Group {
|
||||
return isChildrenAnimating(group)
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func animations() -> [Animation] {
|
||||
|
||||
return layerCache.map ({ $0.1.animation })
|
||||
}
|
||||
|
||||
func replace(original: Node, replacement: Node) {
|
||||
guard let layer = layerCache[original] else {
|
||||
return
|
||||
}
|
||||
|
||||
layerCache[replacement] = layer
|
||||
layerCache.removeValue(forKey: original)
|
||||
cachedLayer.linksCounter += 1
|
||||
|
||||
return cachedLayer.layer
|
||||
}
|
||||
|
||||
private func calculateAnimationScale(animation: Animation) -> CGFloat {
|
||||
guard let defaultScale = MMainScreen()?.mScale else {
|
||||
return 1.0
|
||||
}
|
||||
|
||||
guard let transformAnimation = animation as? TransformAnimation else {
|
||||
return defaultScale
|
||||
}
|
||||
|
||||
let animFunc = transformAnimation.getVFunc()
|
||||
let origBounds = Rect(x: 0.0, y: 0.0, w: 1.0, h: 1.0)
|
||||
|
||||
let startTransform = animFunc(0.0)
|
||||
let startBounds = origBounds.applyTransform(startTransform)
|
||||
var startArea = startBounds.w * startBounds.h
|
||||
|
||||
// zero scale protection
|
||||
if startArea == 0.0 {
|
||||
startArea = 0.1
|
||||
}
|
||||
|
||||
var maxArea = startArea
|
||||
var t = 0.0
|
||||
let step = 0.1
|
||||
while t <= 1.0 {
|
||||
let currentTransform = animFunc(t)
|
||||
let currentBounds = origBounds.applyTransform(currentTransform)
|
||||
let currentArea = currentBounds.w * currentBounds.h
|
||||
if maxArea < currentArea {
|
||||
maxArea = currentArea
|
||||
}
|
||||
|
||||
t = t + step
|
||||
}
|
||||
|
||||
return defaultScale * CGFloat(sqrt(maxArea))
|
||||
}
|
||||
|
||||
func freeLayer(_ node: Node) {
|
||||
guard let cachedLayer = layerCache[node] else {
|
||||
return
|
||||
}
|
||||
|
||||
cachedLayer.linksCounter -= 1
|
||||
|
||||
if cachedLayer.linksCounter != 0 {
|
||||
return
|
||||
}
|
||||
|
||||
let layer = cachedLayer.layer
|
||||
layerCache.removeValue(forKey: node)
|
||||
sceneLayer.setNeedsDisplay()
|
||||
layer.removeFromSuperlayer()
|
||||
}
|
||||
|
||||
func isAnimating(_ node: Node) -> Bool {
|
||||
|
||||
if let _ = layerCache[node] {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func isChildrenAnimating(_ group: Group) -> Bool {
|
||||
|
||||
for child in group.contents {
|
||||
if isAnimating(child) {
|
||||
return true
|
||||
}
|
||||
|
||||
if let childGroup = child as? Group {
|
||||
return isChildrenAnimating(childGroup)
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func containsAnimation(_ node: Node) -> Bool {
|
||||
if isAnimating(node) {
|
||||
return true
|
||||
}
|
||||
|
||||
if let group = node as? Group {
|
||||
return isChildrenAnimating(group)
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func animations() -> [Animation] {
|
||||
|
||||
return layerCache.map ({ $0.1.animation })
|
||||
}
|
||||
|
||||
func replace(original: Node, replacement: Node) {
|
||||
guard let layer = layerCache[original] else {
|
||||
return
|
||||
}
|
||||
|
||||
layerCache[replacement] = layer
|
||||
layerCache.removeValue(forKey: original)
|
||||
}
|
||||
}
|
||||
|
@ -2,20 +2,20 @@ import Foundation
|
||||
|
||||
let animationRestorer = AnimationRestorer()
|
||||
open class AnimationRestorer {
|
||||
typealias RestoreClosure = () -> ()
|
||||
var restoreClosures = [RestoreClosure]()
|
||||
|
||||
func addRestoreClosure(_ closure: @escaping RestoreClosure) {
|
||||
restoreClosures.append(closure)
|
||||
}
|
||||
|
||||
open class func restore() {
|
||||
DispatchQueue.main.async {
|
||||
animationRestorer.restoreClosures.forEach { restoreClosure in
|
||||
restoreClosure()
|
||||
}
|
||||
|
||||
animationRestorer.restoreClosures.removeAll()
|
||||
}
|
||||
}
|
||||
typealias RestoreClosure = () -> ()
|
||||
var restoreClosures = [RestoreClosure]()
|
||||
|
||||
func addRestoreClosure(_ closure: @escaping RestoreClosure) {
|
||||
restoreClosures.append(closure)
|
||||
}
|
||||
|
||||
open class func restore() {
|
||||
DispatchQueue.main.async {
|
||||
animationRestorer.restoreClosures.forEach { restoreClosure in
|
||||
restoreClosure()
|
||||
}
|
||||
|
||||
animationRestorer.restoreClosures.removeAll()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,14 +1,12 @@
|
||||
|
||||
|
||||
// TODO: Implement better hash
|
||||
|
||||
extension Node: Hashable {
|
||||
public var hashValue: Int {
|
||||
|
||||
return Unmanaged.passUnretained(self).toOpaque().hashValue
|
||||
}
|
||||
public var hashValue: Int {
|
||||
return Unmanaged.passUnretained(self).toOpaque().hashValue
|
||||
}
|
||||
}
|
||||
|
||||
public func == (lhs: Node, rhs: Node) -> Bool {
|
||||
return lhs === rhs
|
||||
return lhs === rhs
|
||||
}
|
||||
|
@ -1,21 +1,20 @@
|
||||
|
||||
|
||||
extension Transform: Hashable {
|
||||
public var hashValue: Int {
|
||||
return m11.hashValue ^
|
||||
m12.hashValue ^
|
||||
m21.hashValue ^
|
||||
m22.hashValue ^
|
||||
dx.hashValue ^
|
||||
dy.hashValue
|
||||
}
|
||||
public var hashValue: Int {
|
||||
return m11.hashValue ^
|
||||
m12.hashValue ^
|
||||
m21.hashValue ^
|
||||
m22.hashValue ^
|
||||
dx.hashValue ^
|
||||
dy.hashValue
|
||||
}
|
||||
}
|
||||
|
||||
public func == (lhs: Transform, rhs: Transform) -> Bool {
|
||||
return lhs.m11 == rhs.m11 &&
|
||||
lhs.m12 == rhs.m12 &&
|
||||
lhs.m21 == rhs.m21 &&
|
||||
lhs.m22 == rhs.m22 &&
|
||||
lhs.dx == rhs.dx &&
|
||||
lhs.dy == rhs.dy
|
||||
return lhs.m11 == rhs.m11 &&
|
||||
lhs.m12 == rhs.m12 &&
|
||||
lhs.m21 == rhs.m21 &&
|
||||
lhs.m22 == rhs.m22 &&
|
||||
lhs.dx == rhs.dx &&
|
||||
lhs.dy == rhs.dy
|
||||
}
|
||||
|
@ -6,7 +6,14 @@
|
||||
//
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import Foundation
|
||||
|
||||
#if os(iOS)
|
||||
import UIKit
|
||||
#elseif os(OSX)
|
||||
import AppKit
|
||||
#endif
|
||||
|
||||
|
||||
func addMorphingAnimation(_ animation: BasicAnimation, sceneLayer: CALayer, animationCache: AnimationCache?, completion: @escaping (() -> ())) {
|
||||
guard let morphingAnimation = animation as? MorphingAnimation else {
|
||||
@ -82,7 +89,7 @@ func addMorphingAnimation(_ animation: BasicAnimation, sceneLayer: CALayer, anim
|
||||
if let color = stroke.fill as? Color {
|
||||
layer.strokeColor = RenderUtils.mapColor(color)
|
||||
} else {
|
||||
layer.strokeColor = UIColor.black.cgColor
|
||||
layer.strokeColor = MColor.black.cgColor
|
||||
}
|
||||
|
||||
layer.lineWidth = CGFloat(stroke.width)
|
||||
@ -90,7 +97,7 @@ func addMorphingAnimation(_ animation: BasicAnimation, sceneLayer: CALayer, anim
|
||||
layer.lineJoin = RenderUtils.mapLineJoinToString(stroke.join)
|
||||
layer.lineDashPattern = stroke.dashes.map{ NSNumber(value: $0)}
|
||||
} else {
|
||||
layer.strokeColor = UIColor.black.cgColor
|
||||
layer.strokeColor = MColor.black.cgColor
|
||||
layer.lineWidth = 1.0
|
||||
}
|
||||
|
||||
@ -98,7 +105,7 @@ func addMorphingAnimation(_ animation: BasicAnimation, sceneLayer: CALayer, anim
|
||||
if let color = mutatingShape.fill as? Color {
|
||||
layer.fillColor = RenderUtils.mapColor(color)
|
||||
} else {
|
||||
layer.fillColor = UIColor.clear.cgColor
|
||||
layer.fillColor = MColor.clear.cgColor
|
||||
}
|
||||
|
||||
layer.add(generatedAnim, forKey: animation.ID)
|
||||
|
@ -1,5 +1,10 @@
|
||||
import Foundation
|
||||
|
||||
import UIKit
|
||||
#if os(iOS)
|
||||
import UIKit
|
||||
#elseif os(OSX)
|
||||
import AppKit
|
||||
#endif
|
||||
|
||||
func addOpacityAnimation(_ animation: BasicAnimation, sceneLayer: CALayer, animationCache: AnimationCache?, completion: @escaping (() -> ())) {
|
||||
guard let opacityAnimation = animation as? OpacityAnimation else {
|
||||
|
@ -6,7 +6,13 @@
|
||||
//
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import Foundation
|
||||
|
||||
#if os(iOS)
|
||||
import UIKit
|
||||
#elseif os(OSX)
|
||||
import AppKit
|
||||
#endif
|
||||
|
||||
func addShapeAnimation(_ animation: BasicAnimation, sceneLayer: CALayer, animationCache: AnimationCache?, completion: @escaping (() -> ())) {
|
||||
guard let shapeAnimation = animation as? ShapeAnimation else {
|
||||
@ -94,7 +100,7 @@ func addShapeAnimation(_ animation: BasicAnimation, sceneLayer: CALayer, animati
|
||||
if let color = stroke.fill as? Color {
|
||||
layer.strokeColor = RenderUtils.mapColor(color)
|
||||
} else {
|
||||
layer.strokeColor = UIColor.black.cgColor
|
||||
layer.strokeColor = MColor.black.cgColor
|
||||
}
|
||||
|
||||
layer.lineWidth = CGFloat(stroke.width)
|
||||
@ -102,7 +108,7 @@ func addShapeAnimation(_ animation: BasicAnimation, sceneLayer: CALayer, animati
|
||||
layer.lineJoin = RenderUtils.mapLineJoinToString(stroke.join)
|
||||
layer.lineDashPattern = stroke.dashes.map{ NSNumber(value: $0)}
|
||||
} else if shape.fill == nil {
|
||||
layer.strokeColor = UIColor.black.cgColor
|
||||
layer.strokeColor = MColor.black.cgColor
|
||||
layer.lineWidth = 1.0
|
||||
}
|
||||
|
||||
@ -110,7 +116,7 @@ func addShapeAnimation(_ animation: BasicAnimation, sceneLayer: CALayer, animati
|
||||
if let color = shape.fill as? Color {
|
||||
layer.fillColor = RenderUtils.mapColor(color)
|
||||
} else {
|
||||
layer.fillColor = UIColor.clear.cgColor
|
||||
layer.fillColor = MColor.clear.cgColor
|
||||
}
|
||||
|
||||
layer.add(generatedAnim, forKey: animation.ID)
|
||||
|
@ -1,37 +1,43 @@
|
||||
import UIKit
|
||||
import Foundation
|
||||
|
||||
#if os(iOS)
|
||||
import UIKit
|
||||
#elseif os(OSX)
|
||||
import AppKit
|
||||
#endif
|
||||
|
||||
func caTimingFunction(_ easing: Easing) -> CAMediaTimingFunction {
|
||||
switch easing {
|
||||
case .ease:
|
||||
return CAMediaTimingFunction(name: kCAMediaTimingFunctionDefault)
|
||||
case .linear:
|
||||
return CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear)
|
||||
case .easeIn:
|
||||
return CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseIn)
|
||||
case .easeOut:
|
||||
return CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseOut)
|
||||
case .easeInOut:
|
||||
return CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
|
||||
}
|
||||
switch easing {
|
||||
case .ease:
|
||||
return CAMediaTimingFunction(name: kCAMediaTimingFunctionDefault)
|
||||
case .linear:
|
||||
return CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear)
|
||||
case .easeIn:
|
||||
return CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseIn)
|
||||
case .easeOut:
|
||||
return CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseOut)
|
||||
case .easeInOut:
|
||||
return CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
|
||||
}
|
||||
}
|
||||
|
||||
func progressForTimingFunction(_ easing: Easing, progress: Double) -> Double {
|
||||
let t = progress
|
||||
|
||||
switch easing {
|
||||
case .ease:
|
||||
return t
|
||||
case .linear:
|
||||
return t
|
||||
case .easeIn:
|
||||
return t * t
|
||||
case .easeOut:
|
||||
return -(t * (t - 2))
|
||||
case .easeInOut:
|
||||
if t < 0.5 {
|
||||
return 2.0 * t * t
|
||||
} else {
|
||||
return -2.0 * t * t + 4.0 * t - 1.0
|
||||
}
|
||||
let t = progress
|
||||
|
||||
switch easing {
|
||||
case .ease:
|
||||
return t
|
||||
case .linear:
|
||||
return t
|
||||
case .easeIn:
|
||||
return t * t
|
||||
case .easeOut:
|
||||
return -(t * (t - 2))
|
||||
case .easeInOut:
|
||||
if t < 0.5 {
|
||||
return 2.0 * t * t
|
||||
} else {
|
||||
return -2.0 * t * t + 4.0 * t - 1.0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,10 @@
|
||||
import UIKit
|
||||
import Foundation
|
||||
|
||||
#if os(iOS)
|
||||
import UIKit
|
||||
#elseif os(OSX)
|
||||
import AppKit
|
||||
#endif
|
||||
|
||||
func addTransformAnimation(_ animation: BasicAnimation, sceneLayer: CALayer, animationCache: AnimationCache?, completion: @escaping (() -> ())) {
|
||||
guard let transformAnimation = animation as? TransformAnimation else {
|
||||
|
@ -9,14 +9,14 @@
|
||||
import Foundation
|
||||
|
||||
open class Disposable {
|
||||
|
||||
let handler: (()->())
|
||||
|
||||
init (_ disposeHandler: @escaping (()->()) ) {
|
||||
handler = disposeHandler
|
||||
}
|
||||
|
||||
open func dispose() {
|
||||
handler()
|
||||
}
|
||||
|
||||
let handler: (()->())
|
||||
|
||||
init (_ disposeHandler: @escaping (()->()) ) {
|
||||
handler = disposeHandler
|
||||
}
|
||||
|
||||
open func dispose() {
|
||||
handler()
|
||||
}
|
||||
}
|
||||
|
@ -6,26 +6,25 @@
|
||||
//
|
||||
//
|
||||
|
||||
|
||||
open class GroupDisposable {
|
||||
|
||||
fileprivate var items: [Disposable] = []
|
||||
|
||||
open func dispose() {
|
||||
for disposable in items {
|
||||
disposable.dispose()
|
||||
}
|
||||
items = []
|
||||
}
|
||||
|
||||
open func add(_ item: Disposable) {
|
||||
items.append(item)
|
||||
}
|
||||
|
||||
|
||||
fileprivate var items: [Disposable] = []
|
||||
|
||||
open func dispose() {
|
||||
for disposable in items {
|
||||
disposable.dispose()
|
||||
}
|
||||
items = []
|
||||
}
|
||||
|
||||
open func add(_ item: Disposable) {
|
||||
items.append(item)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension Disposable {
|
||||
public func addTo(_ group: GroupDisposable) {
|
||||
group.add(self)
|
||||
}
|
||||
public func addTo(_ group: GroupDisposable) {
|
||||
group.add(self)
|
||||
}
|
||||
}
|
||||
|
@ -9,39 +9,39 @@
|
||||
import Foundation
|
||||
|
||||
class ChangeHandler<T>: Equatable {
|
||||
let handle: ((T)->())
|
||||
|
||||
init(_ f: @escaping ((T)->()) ) {
|
||||
handle = f
|
||||
}
|
||||
|
||||
static func ==(lhs: ChangeHandler<T>, rhs: ChangeHandler<T>) -> Bool {
|
||||
return lhs === rhs
|
||||
}
|
||||
let handle: ((T)->())
|
||||
|
||||
init(_ f: @escaping ((T)->()) ) {
|
||||
handle = f
|
||||
}
|
||||
|
||||
static func ==(lhs: ChangeHandler<T>, rhs: ChangeHandler<T>) -> Bool {
|
||||
return lhs === rhs
|
||||
}
|
||||
}
|
||||
|
||||
open class Variable<T> {
|
||||
var handlers = [ChangeHandler<T>]()
|
||||
|
||||
open var value: T {
|
||||
didSet {
|
||||
handlers.forEach { handler in handler.handle(value) }
|
||||
}
|
||||
}
|
||||
|
||||
init(_ v: T) {
|
||||
value = v
|
||||
}
|
||||
|
||||
@discardableResult open func onChange(_ f: @escaping ((T)->())) -> Disposable {
|
||||
let handler = ChangeHandler<T>(f)
|
||||
handlers.append(handler)
|
||||
return Disposable({ [weak self] in
|
||||
guard let index = self?.handlers.index(of: handler) else {
|
||||
return
|
||||
}
|
||||
|
||||
self?.handlers.remove(at: index)
|
||||
})
|
||||
var handlers = [ChangeHandler<T>]()
|
||||
|
||||
open var value: T {
|
||||
didSet {
|
||||
handlers.forEach { handler in handler.handle(value) }
|
||||
}
|
||||
}
|
||||
|
||||
init(_ v: T) {
|
||||
value = v
|
||||
}
|
||||
|
||||
@discardableResult open func onChange(_ f: @escaping ((T)->())) -> Disposable {
|
||||
let handler = ChangeHandler<T>(f)
|
||||
handlers.append(handler)
|
||||
return Disposable({ [weak self] in
|
||||
guard let index = self?.handlers.index(of: handler) else {
|
||||
return
|
||||
}
|
||||
|
||||
self?.handlers.remove(at: index)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -9,17 +9,16 @@
|
||||
import Foundation
|
||||
|
||||
open class Event {
|
||||
|
||||
public weak var node: Node?
|
||||
|
||||
var consumed = false
|
||||
|
||||
init(node: Node) {
|
||||
self.node = node
|
||||
}
|
||||
|
||||
public func consume() {
|
||||
consumed = true
|
||||
}
|
||||
|
||||
|
||||
public weak var node: Node?
|
||||
|
||||
var consumed = false
|
||||
|
||||
init(node: Node) {
|
||||
self.node = node
|
||||
}
|
||||
|
||||
public func consume() {
|
||||
consumed = true
|
||||
}
|
||||
}
|
||||
|
@ -1,14 +1,14 @@
|
||||
open class PanEvent : Event {
|
||||
|
||||
open let dx: Double
|
||||
open let dy: Double
|
||||
open let count: Int
|
||||
|
||||
init(node: Node, dx: Double, dy: Double, count: Int) {
|
||||
self.dx = dx
|
||||
self.dy = dy
|
||||
self.count = count
|
||||
super.init(node: node)
|
||||
}
|
||||
|
||||
|
||||
open let dx: Double
|
||||
open let dy: Double
|
||||
open let count: Int
|
||||
|
||||
init(node: Node, dx: Double, dy: Double, count: Int) {
|
||||
self.dx = dx
|
||||
self.dy = dy
|
||||
self.count = count
|
||||
super.init(node: node)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,10 +1,10 @@
|
||||
open class PinchEvent : Event {
|
||||
|
||||
open let scale: Double
|
||||
|
||||
init(node: Node, scale: Double) {
|
||||
self.scale = scale
|
||||
super.init(node: node)
|
||||
}
|
||||
|
||||
|
||||
open let scale: Double
|
||||
|
||||
init(node: Node, scale: Double) {
|
||||
self.scale = scale
|
||||
super.init(node: node)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,10 +1,10 @@
|
||||
open class RotateEvent : Event {
|
||||
|
||||
open let angle: Double
|
||||
|
||||
init(node: Node, angle: Double) {
|
||||
self.angle = angle
|
||||
super.init(node: node)
|
||||
}
|
||||
|
||||
|
||||
open let angle: Double
|
||||
|
||||
init(node: Node, angle: Double) {
|
||||
self.angle = angle
|
||||
super.init(node: node)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,10 +1,10 @@
|
||||
open class TapEvent : Event {
|
||||
|
||||
open let location: Point
|
||||
|
||||
init(node: Node, location: Point) {
|
||||
self.location = location
|
||||
super.init(node: node)
|
||||
}
|
||||
|
||||
|
||||
open let location: Point
|
||||
|
||||
init(node: Node, location: Point) {
|
||||
self.location = location
|
||||
super.init(node: node)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -8,17 +8,17 @@
|
||||
|
||||
|
||||
public struct TouchPoint {
|
||||
public let id: Int
|
||||
public let location: Point
|
||||
public let id: Int
|
||||
public let location: Point
|
||||
}
|
||||
|
||||
public class TouchEvent : Event {
|
||||
|
||||
public let points: [TouchPoint]
|
||||
|
||||
public init(node: Node, points: [TouchPoint]) {
|
||||
self.points = points
|
||||
|
||||
public let points: [TouchPoint]
|
||||
|
||||
public init(node: Node, points: [TouchPoint]) {
|
||||
self.points = points
|
||||
|
||||
super.init(node: node)
|
||||
}
|
||||
super.init(node: node)
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
public enum Align {
|
||||
case min
|
||||
case mid
|
||||
case max
|
||||
case min
|
||||
case mid
|
||||
case max
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
public enum AspectRatio {
|
||||
case none
|
||||
case meet
|
||||
case slice
|
||||
case none
|
||||
case meet
|
||||
case slice
|
||||
}
|
||||
|
@ -1,72 +1,72 @@
|
||||
import Foundation
|
||||
|
||||
open class Color: Fill, Equatable {
|
||||
|
||||
open let val: Int
|
||||
|
||||
open static let white: Color = Color( val: 0xFFFFFF )
|
||||
open static let silver: Color = Color( val: 0xC0C0C0 )
|
||||
open static let gray: Color = Color( val: 0x808080 )
|
||||
open static let black: Color = Color( val: 0 )
|
||||
open static let red: Color = Color( val: 0xFF0000 )
|
||||
open static let maroon: Color = Color( val: 0x800000 )
|
||||
open static let yellow: Color = Color( val: 0xFFFF00 )
|
||||
open static let olive: Color = Color( val: 0x808000 )
|
||||
open static let lime: Color = Color( val: 0x00FF00 )
|
||||
open static let green: Color = Color( val: 0x008000 )
|
||||
open static let aqua: Color = Color( val: 0x00FFFF )
|
||||
open static let teal: Color = Color( val: 0x008080 )
|
||||
open static let blue: Color = Color( val: 0x0000FF )
|
||||
open static let navy: Color = Color( val: 0x000080 )
|
||||
open static let fuchsia: Color = Color( val: 0xFF00FF )
|
||||
open static let purple: Color = Color( val: 0x800080 )
|
||||
open static let clear: Color = Color.rgba(r: 0, g: 0, b: 0, a: 0)
|
||||
|
||||
public init(val: Int = 0) {
|
||||
self.val = val
|
||||
}
|
||||
|
||||
// GENERATED
|
||||
open func r() -> Int {
|
||||
return ( ( val >> 16 ) & 0xff )
|
||||
}
|
||||
|
||||
// GENERATED
|
||||
open func g() -> Int {
|
||||
return ( ( val >> 8 ) & 0xff )
|
||||
}
|
||||
|
||||
// GENERATED
|
||||
open func b() -> Int {
|
||||
return ( val & 0xff )
|
||||
}
|
||||
|
||||
// GENERATED
|
||||
open func a() -> Int {
|
||||
return ( 255 - ( ( val >> 24 ) & 0xff ) )
|
||||
}
|
||||
|
||||
// GENERATED
|
||||
public func with(a: Double) -> Color {
|
||||
return Color.rgba(r: r(), g: g(), b: b(), a: a)
|
||||
}
|
||||
|
||||
// GENERATED
|
||||
open class func rgbt(r: Int, g: Int, b: Int, t: Int) -> Color {
|
||||
return Color( val: ( ( ( ( ( t & 0xff ) << 24 ) | ( ( r & 0xff ) << 16 ) ) | ( ( g & 0xff ) << 8 ) ) | ( b & 0xff ) ) )
|
||||
}
|
||||
|
||||
// GENERATED
|
||||
open class func rgba(r: Int, g: Int, b: Int, a: Double) -> Color {
|
||||
return rgbt( r: r, g: g, b: b, t: Int( ( ( 1 - a ) * 255 ) ) )
|
||||
}
|
||||
|
||||
// GENERATED
|
||||
open class func rgb(r: Int, g: Int, b: Int) -> Color {
|
||||
return rgbt( r: r, g: g, b: b, t: 0 )
|
||||
}
|
||||
|
||||
public static func ==(lhs: Color, rhs: Color) -> Bool {
|
||||
return lhs.val == rhs.val
|
||||
}
|
||||
|
||||
open let val: Int
|
||||
|
||||
open static let white: Color = Color( val: 0xFFFFFF )
|
||||
open static let silver: Color = Color( val: 0xC0C0C0 )
|
||||
open static let gray: Color = Color( val: 0x808080 )
|
||||
open static let black: Color = Color( val: 0 )
|
||||
open static let red: Color = Color( val: 0xFF0000 )
|
||||
open static let maroon: Color = Color( val: 0x800000 )
|
||||
open static let yellow: Color = Color( val: 0xFFFF00 )
|
||||
open static let olive: Color = Color( val: 0x808000 )
|
||||
open static let lime: Color = Color( val: 0x00FF00 )
|
||||
open static let green: Color = Color( val: 0x008000 )
|
||||
open static let aqua: Color = Color( val: 0x00FFFF )
|
||||
open static let teal: Color = Color( val: 0x008080 )
|
||||
open static let blue: Color = Color( val: 0x0000FF )
|
||||
open static let navy: Color = Color( val: 0x000080 )
|
||||
open static let fuchsia: Color = Color( val: 0xFF00FF )
|
||||
open static let purple: Color = Color( val: 0x800080 )
|
||||
open static let clear: Color = Color.rgba(r: 0, g: 0, b: 0, a: 0)
|
||||
|
||||
public init(val: Int = 0) {
|
||||
self.val = val
|
||||
}
|
||||
|
||||
// GENERATED
|
||||
open func r() -> Int {
|
||||
return ( ( val >> 16 ) & 0xff )
|
||||
}
|
||||
|
||||
// GENERATED
|
||||
open func g() -> Int {
|
||||
return ( ( val >> 8 ) & 0xff )
|
||||
}
|
||||
|
||||
// GENERATED
|
||||
open func b() -> Int {
|
||||
return ( val & 0xff )
|
||||
}
|
||||
|
||||
// GENERATED
|
||||
open func a() -> Int {
|
||||
return ( 255 - ( ( val >> 24 ) & 0xff ) )
|
||||
}
|
||||
|
||||
// GENERATED
|
||||
public func with(a: Double) -> Color {
|
||||
return Color.rgba(r: r(), g: g(), b: b(), a: a)
|
||||
}
|
||||
|
||||
// GENERATED
|
||||
open class func rgbt(r: Int, g: Int, b: Int, t: Int) -> Color {
|
||||
return Color( val: ( ( ( ( ( t & 0xff ) << 24 ) | ( ( r & 0xff ) << 16 ) ) | ( ( g & 0xff ) << 8 ) ) | ( b & 0xff ) ) )
|
||||
}
|
||||
|
||||
// GENERATED
|
||||
open class func rgba(r: Int, g: Int, b: Int, a: Double) -> Color {
|
||||
return rgbt( r: r, g: g, b: b, t: Int( ( ( 1 - a ) * 255 ) ) )
|
||||
}
|
||||
|
||||
// GENERATED
|
||||
open class func rgb(r: Int, g: Int, b: Int) -> Color {
|
||||
return rgbt( r: r, g: g, b: b, t: 0 )
|
||||
}
|
||||
|
||||
public static func ==(lhs: Color, rhs: Color) -> Bool {
|
||||
return lhs.val == rhs.val
|
||||
}
|
||||
}
|
||||
|
@ -1,13 +1,12 @@
|
||||
import Foundation
|
||||
|
||||
open class Drawable {
|
||||
|
||||
open let visible: Bool
|
||||
open let tag: [String]
|
||||
|
||||
public init(visible: Bool = true, tag: [String] = []) {
|
||||
self.visible = visible
|
||||
self.tag = tag
|
||||
}
|
||||
|
||||
|
||||
open let visible: Bool
|
||||
open let tag: [String]
|
||||
|
||||
public init(visible: Bool = true, tag: [String] = []) {
|
||||
self.visible = visible
|
||||
self.tag = tag
|
||||
}
|
||||
}
|
||||
|
@ -1,17 +1,16 @@
|
||||
import Foundation
|
||||
|
||||
open class DropShadow: Effect {
|
||||
|
||||
open let radius: Double
|
||||
open let offset: Point
|
||||
open let color: Color
|
||||
open let input: Effect?
|
||||
|
||||
public init(radius: Double = 0, offset: Point = Point.origin, color: Color = Color.black, input: Effect? = nil) {
|
||||
self.radius = radius
|
||||
self.offset = offset
|
||||
self.color = color
|
||||
self.input = input
|
||||
}
|
||||
|
||||
|
||||
open let radius: Double
|
||||
open let offset: Point
|
||||
open let color: Color
|
||||
open let input: Effect?
|
||||
|
||||
public init(radius: Double = 0, offset: Point = Point.origin, color: Color = Color.black, input: Effect? = nil) {
|
||||
self.radius = radius
|
||||
self.offset = offset
|
||||
self.color = color
|
||||
self.input = input
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
import Foundation
|
||||
|
||||
open class Effect {
|
||||
|
||||
public init() {
|
||||
}
|
||||
|
||||
|
||||
public init() {
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,13 +1,12 @@
|
||||
import Foundation
|
||||
|
||||
open class Font {
|
||||
|
||||
open let name: String
|
||||
open let size: Int
|
||||
|
||||
public init(name: String = "Serif", size: Int = 12) {
|
||||
self.name = name
|
||||
self.size = size
|
||||
}
|
||||
|
||||
|
||||
open let name: String
|
||||
open let size: Int
|
||||
|
||||
public init(name: String = "Serif", size: Int = 12) {
|
||||
self.name = name
|
||||
self.size = size
|
||||
}
|
||||
}
|
||||
|
@ -9,5 +9,4 @@ open class GaussianBlur: Effect {
|
||||
self.radius = radius
|
||||
self.input = input
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -9,5 +9,4 @@ open class Gradient: Fill {
|
||||
self.userSpace = userSpace
|
||||
self.stops = stops
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,46 +1,49 @@
|
||||
import Foundation
|
||||
import UIKit
|
||||
|
||||
#if os(iOS)
|
||||
import UIKit
|
||||
#endif
|
||||
|
||||
open class LinearGradient: Gradient {
|
||||
|
||||
open var x1: Double
|
||||
open var y1: Double
|
||||
open var x2: Double
|
||||
open var y2: Double
|
||||
|
||||
public init(x1: Double = 0, y1: Double = 0, x2: Double = 0, y2: Double = 0, userSpace: Bool = false, stops: [Stop] = []) {
|
||||
self.x1 = x1
|
||||
self.y1 = y1
|
||||
self.x2 = x2
|
||||
self.y2 = y2
|
||||
super.init(
|
||||
userSpace: userSpace,
|
||||
stops: stops
|
||||
)
|
||||
}
|
||||
|
||||
public init(degree: Double = 0, from: Color, to: Color) {
|
||||
self.x1 = degree >= 135 && degree < 270 ? 1 : 0
|
||||
self.y1 = degree < 225 ? 0 : 1
|
||||
self.x2 = degree < 90 || degree >= 315 ? 1 : 0
|
||||
self.y2 = degree >= 45 && degree < 180 ? 1 : 0
|
||||
super.init(
|
||||
userSpace: false,
|
||||
stops: [Stop(offset: 0, color: from), Stop(offset: 1, color: to)]
|
||||
)
|
||||
}
|
||||
|
||||
func applyTransform(_ transform: Transform) {
|
||||
// TODO: - Check logic
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
open var x1: Double
|
||||
open var y1: Double
|
||||
open var x2: Double
|
||||
open var y2: Double
|
||||
|
||||
public init(x1: Double = 0, y1: Double = 0, x2: Double = 0, y2: Double = 0, userSpace: Bool = false, stops: [Stop] = []) {
|
||||
self.x1 = x1
|
||||
self.y1 = y1
|
||||
self.x2 = x2
|
||||
self.y2 = y2
|
||||
super.init(
|
||||
userSpace: userSpace,
|
||||
stops: stops
|
||||
)
|
||||
}
|
||||
|
||||
public init(degree: Double = 0, from: Color, to: Color) {
|
||||
self.x1 = degree >= 135 && degree < 270 ? 1 : 0
|
||||
self.y1 = degree < 225 ? 0 : 1
|
||||
self.x2 = degree < 90 || degree >= 315 ? 1 : 0
|
||||
self.y2 = degree >= 45 && degree < 180 ? 1 : 0
|
||||
super.init(
|
||||
userSpace: false,
|
||||
stops: [Stop(offset: 0, color: from), Stop(offset: 1, color: to)]
|
||||
)
|
||||
}
|
||||
|
||||
func applyTransform(_ transform: Transform) {
|
||||
// TODO: - Check logic
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
@ -1,37 +1,40 @@
|
||||
import Foundation
|
||||
import UIKit
|
||||
|
||||
#if os(iOS)
|
||||
import UIKit
|
||||
#endif
|
||||
|
||||
open class RadialGradient: Gradient {
|
||||
|
||||
open var cx: Double
|
||||
open var cy: Double
|
||||
open var fx: Double
|
||||
open var fy: Double
|
||||
open let r: Double
|
||||
|
||||
public init(cx: Double = 0.5, cy: Double = 0.5, fx: Double = 0.5, fy: Double = 0.5, r: Double = 0.5, userSpace: Bool = false, stops: [Stop] = []) {
|
||||
self.cx = cx
|
||||
self.cy = cy
|
||||
self.fx = fx
|
||||
self.fy = fy
|
||||
self.r = r
|
||||
super.init(
|
||||
userSpace: userSpace,
|
||||
stops: stops
|
||||
)
|
||||
}
|
||||
|
||||
func applyTransform(_ transform: Transform) {
|
||||
// TODO: - Check logic
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
open var cx: Double
|
||||
open var cy: Double
|
||||
open var fx: Double
|
||||
open var fy: Double
|
||||
open let r: Double
|
||||
|
||||
public init(cx: Double = 0.5, cy: Double = 0.5, fx: Double = 0.5, fy: Double = 0.5, r: Double = 0.5, userSpace: Bool = false, stops: [Stop] = []) {
|
||||
self.cx = cx
|
||||
self.cy = cy
|
||||
self.fx = fx
|
||||
self.fy = fy
|
||||
self.r = r
|
||||
super.init(
|
||||
userSpace: userSpace,
|
||||
stops: stops
|
||||
)
|
||||
}
|
||||
|
||||
func applyTransform(_ transform: Transform) {
|
||||
// TODO: - Check logic
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
@ -9,5 +9,4 @@ open class Stop {
|
||||
self.offset = offset
|
||||
self.color = color
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -15,5 +15,4 @@ open class Stroke {
|
||||
self.join = join
|
||||
self.dashes = dashes
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,23 +1,22 @@
|
||||
import Foundation
|
||||
|
||||
open class Arc: Locus {
|
||||
|
||||
open let ellipse: Ellipse
|
||||
open let shift: Double
|
||||
open let extent: Double
|
||||
|
||||
public init(ellipse: Ellipse, shift: Double = 0, extent: Double = 0) {
|
||||
self.ellipse = ellipse
|
||||
self.shift = shift
|
||||
self.extent = extent
|
||||
}
|
||||
|
||||
override open func bounds() -> Rect {
|
||||
return Rect(
|
||||
x: ellipse.cx - ellipse.rx,
|
||||
y: ellipse.cy - ellipse.ry,
|
||||
w: ellipse.rx * 2.0,
|
||||
h: ellipse.ry * 2.0)
|
||||
}
|
||||
|
||||
|
||||
open let ellipse: Ellipse
|
||||
open let shift: Double
|
||||
open let extent: Double
|
||||
|
||||
public init(ellipse: Ellipse, shift: Double = 0, extent: Double = 0) {
|
||||
self.ellipse = ellipse
|
||||
self.shift = shift
|
||||
self.extent = extent
|
||||
}
|
||||
|
||||
override open func bounds() -> Rect {
|
||||
return Rect(
|
||||
x: ellipse.cx - ellipse.rx,
|
||||
y: ellipse.cy - ellipse.ry,
|
||||
w: ellipse.rx * 2.0,
|
||||
h: ellipse.ry * 2.0)
|
||||
}
|
||||
}
|
||||
|
@ -1,28 +1,27 @@
|
||||
import Foundation
|
||||
|
||||
open class Circle: Locus {
|
||||
|
||||
open let cx: Double
|
||||
open let cy: Double
|
||||
open let r: Double
|
||||
|
||||
public init(cx: Double = 0, cy: Double = 0, r: Double = 0) {
|
||||
self.cx = cx
|
||||
self.cy = cy
|
||||
self.r = r
|
||||
}
|
||||
|
||||
override open func bounds() -> Rect {
|
||||
return Rect(
|
||||
x: cx - r,
|
||||
y: cy - r,
|
||||
w: r * 2.0,
|
||||
h: r * 2.0)
|
||||
}
|
||||
|
||||
// GENERATED NOT
|
||||
open func arc(shift: Double, extent: Double) -> Arc {
|
||||
return Arc(ellipse: Ellipse(cx: cx, cy: cy, rx: r, ry: r), shift: shift, extent: extent)
|
||||
}
|
||||
|
||||
|
||||
open let cx: Double
|
||||
open let cy: Double
|
||||
open let r: Double
|
||||
|
||||
public init(cx: Double = 0, cy: Double = 0, r: Double = 0) {
|
||||
self.cx = cx
|
||||
self.cy = cy
|
||||
self.r = r
|
||||
}
|
||||
|
||||
override open func bounds() -> Rect {
|
||||
return Rect(
|
||||
x: cx - r,
|
||||
y: cy - r,
|
||||
w: r * 2.0,
|
||||
h: r * 2.0)
|
||||
}
|
||||
|
||||
// GENERATED NOT
|
||||
open func arc(shift: Double, extent: Double) -> Arc {
|
||||
return Arc(ellipse: Ellipse(cx: cx, cy: cy, rx: r, ry: r), shift: shift, extent: extent)
|
||||
}
|
||||
}
|
||||
|
@ -1,30 +1,29 @@
|
||||
import Foundation
|
||||
|
||||
open class Ellipse: Locus {
|
||||
|
||||
open let cx: Double
|
||||
open let cy: Double
|
||||
open let rx: Double
|
||||
open let ry: Double
|
||||
|
||||
public init(cx: Double = 0, cy: Double = 0, rx: Double = 0, ry: Double = 0) {
|
||||
self.cx = cx
|
||||
self.cy = cy
|
||||
self.rx = rx
|
||||
self.ry = ry
|
||||
}
|
||||
|
||||
override open func bounds() -> Rect {
|
||||
return Rect(
|
||||
x: cx - rx,
|
||||
y: cy - ry,
|
||||
w: rx * 2.0,
|
||||
h: ry * 2.0)
|
||||
}
|
||||
|
||||
// GENERATED NOT
|
||||
open func arc(shift: Double, extent: Double) -> Arc {
|
||||
return Arc(ellipse: self, shift: shift, extent: extent)
|
||||
}
|
||||
|
||||
|
||||
open let cx: Double
|
||||
open let cy: Double
|
||||
open let rx: Double
|
||||
open let ry: Double
|
||||
|
||||
public init(cx: Double = 0, cy: Double = 0, rx: Double = 0, ry: Double = 0) {
|
||||
self.cx = cx
|
||||
self.cy = cy
|
||||
self.rx = rx
|
||||
self.ry = ry
|
||||
}
|
||||
|
||||
override open func bounds() -> Rect {
|
||||
return Rect(
|
||||
x: cx - rx,
|
||||
y: cy - ry,
|
||||
w: rx * 2.0,
|
||||
h: ry * 2.0)
|
||||
}
|
||||
|
||||
// GENERATED NOT
|
||||
open func arc(shift: Double, extent: Double) -> Arc {
|
||||
return Arc(ellipse: self, shift: shift, extent: extent)
|
||||
}
|
||||
}
|
||||
|
@ -1,42 +1,42 @@
|
||||
open class GeomUtils {
|
||||
|
||||
open class func concat(t1: Transform, t2: Transform) -> Transform {
|
||||
let nm11 = t2.m11 * t1.m11 + t2.m12 * t1.m21
|
||||
let nm21 = t2.m21 * t1.m11 + t2.m22 * t1.m21
|
||||
let ndx = t2.dx * t1.m11 + t2.dy * t1.m21 + t1.dx
|
||||
let nm12 = t2.m11 * t1.m12 + t2.m12 * t1.m22
|
||||
let nm22 = t2.m21 * t1.m12 + t2.m22 * t1.m22
|
||||
let ndy = t2.dx * t1.m12 + t2.dy * t1.m22 + t1.dy
|
||||
return Transform(m11: nm11, m12: nm12, m21: nm21, m22: nm22, dx: ndx, dy: ndy)
|
||||
}
|
||||
|
||||
open class func centerRotation(node: Node, place: Transform, angle: Double) -> Transform {
|
||||
|
||||
let center = GeomUtils.center(node: node)
|
||||
let move = Transform.move(dx: center.x, dy: center.y)
|
||||
|
||||
guard let moveInv = move.invert() else {
|
||||
return Transform()
|
||||
}
|
||||
|
||||
let r = Transform().rotate(angle: angle)
|
||||
|
||||
let moveAndRotate = GeomUtils.concat(t1: moveInv, t2: r)
|
||||
let returnToOrig = GeomUtils.concat(t1: moveAndRotate, t2: move)
|
||||
|
||||
return GeomUtils.concat(t1: returnToOrig, t2: place)
|
||||
}
|
||||
|
||||
open class func concat(t1: Transform, t2: Transform) -> Transform {
|
||||
let nm11 = t2.m11 * t1.m11 + t2.m12 * t1.m21
|
||||
let nm21 = t2.m21 * t1.m11 + t2.m22 * t1.m21
|
||||
let ndx = t2.dx * t1.m11 + t2.dy * t1.m21 + t1.dx
|
||||
let nm12 = t2.m11 * t1.m12 + t2.m12 * t1.m22
|
||||
let nm22 = t2.m21 * t1.m12 + t2.m22 * t1.m22
|
||||
let ndy = t2.dx * t1.m12 + t2.dy * t1.m22 + t1.dy
|
||||
return Transform(m11: nm11, m12: nm12, m21: nm21, m22: nm22, dx: ndx, dy: ndy)
|
||||
}
|
||||
|
||||
open class func centerRotation(node: Node, place: Transform, angle: Double) -> Transform {
|
||||
|
||||
open class func centerScale(node: Node, sx: Double, sy: Double) -> Transform {
|
||||
let center = GeomUtils.center(node: node)
|
||||
return Transform.move(dx: center.x * (1.0 - sx), dy: center.y * (1.0 - sy)).scale(sx: sx, sy: sy)
|
||||
let center = GeomUtils.center(node: node)
|
||||
let move = Transform.move(dx: center.x, dy: center.y)
|
||||
|
||||
guard let moveInv = move.invert() else {
|
||||
return Transform()
|
||||
}
|
||||
|
||||
open class func center(node: Node) -> Point {
|
||||
guard let bounds = node.bounds() else {
|
||||
return Point()
|
||||
}
|
||||
|
||||
return Point(x: bounds.x + bounds.w / 2.0, y: bounds.y + bounds.h / 2.0)
|
||||
let r = Transform().rotate(angle: angle)
|
||||
|
||||
let moveAndRotate = GeomUtils.concat(t1: moveInv, t2: r)
|
||||
let returnToOrig = GeomUtils.concat(t1: moveAndRotate, t2: move)
|
||||
|
||||
return GeomUtils.concat(t1: returnToOrig, t2: place)
|
||||
}
|
||||
|
||||
open class func centerScale(node: Node, sx: Double, sy: Double) -> Transform {
|
||||
let center = GeomUtils.center(node: node)
|
||||
return Transform.move(dx: center.x * (1.0 - sx), dy: center.y * (1.0 - sy)).scale(sx: sx, sy: sy)
|
||||
}
|
||||
|
||||
open class func center(node: Node) -> Point {
|
||||
guard let bounds = node.bounds() else {
|
||||
return Point()
|
||||
}
|
||||
|
||||
return Point(x: bounds.x + bounds.w / 2.0, y: bounds.y + bounds.h / 2.0)
|
||||
}
|
||||
}
|
||||
|
@ -1,17 +1,16 @@
|
||||
import Foundation
|
||||
|
||||
open class Insets {
|
||||
|
||||
open let top: Double
|
||||
open let right: Double
|
||||
open let bottom: Double
|
||||
open let left: Double
|
||||
|
||||
public init(top: Double = 0, right: Double = 0, bottom: Double = 0, left: Double = 0) {
|
||||
self.top = top
|
||||
self.right = right
|
||||
self.bottom = bottom
|
||||
self.left = left
|
||||
}
|
||||
|
||||
|
||||
open let top: Double
|
||||
open let right: Double
|
||||
open let bottom: Double
|
||||
open let left: Double
|
||||
|
||||
public init(top: Double = 0, right: Double = 0, bottom: Double = 0, left: Double = 0) {
|
||||
self.top = top
|
||||
self.right = right
|
||||
self.bottom = bottom
|
||||
self.left = left
|
||||
}
|
||||
}
|
||||
|
@ -1,24 +1,24 @@
|
||||
import Foundation
|
||||
|
||||
open class Line: Locus {
|
||||
|
||||
open let x1: Double
|
||||
open let y1: Double
|
||||
open let x2: Double
|
||||
open let y2: Double
|
||||
|
||||
public init(x1: Double = 0, y1: Double = 0, x2: Double = 0, y2: Double = 0) {
|
||||
self.x1 = x1
|
||||
self.y1 = y1
|
||||
self.x2 = x2
|
||||
self.y2 = y2
|
||||
}
|
||||
|
||||
override open func bounds() -> Rect {
|
||||
return Rect(
|
||||
x: min(x1, x2),
|
||||
y: min(y1, y2),
|
||||
w: abs(x1 - x2),
|
||||
h: abs(y1 - y2))
|
||||
}
|
||||
|
||||
open let x1: Double
|
||||
open let y1: Double
|
||||
open let x2: Double
|
||||
open let y2: Double
|
||||
|
||||
public init(x1: Double = 0, y1: Double = 0, x2: Double = 0, y2: Double = 0) {
|
||||
self.x1 = x1
|
||||
self.y1 = y1
|
||||
self.x2 = x2
|
||||
self.y2 = y2
|
||||
}
|
||||
|
||||
override open func bounds() -> Rect {
|
||||
return Rect(
|
||||
x: min(x1, x2),
|
||||
y: min(y1, y2),
|
||||
w: abs(x1 - x2),
|
||||
h: abs(y1 - y2))
|
||||
}
|
||||
}
|
||||
|
@ -1,28 +1,27 @@
|
||||
import Foundation
|
||||
|
||||
open class Locus {
|
||||
|
||||
public init() {
|
||||
}
|
||||
|
||||
// GENERATED NOT
|
||||
open func bounds() -> Rect {
|
||||
return Rect()
|
||||
}
|
||||
|
||||
// GENERATED NOT
|
||||
open func stroke(with: Stroke) -> Shape {
|
||||
return Shape(form: self, stroke: with)
|
||||
}
|
||||
|
||||
// GENERATED NOT
|
||||
open func fill(with: Fill) -> Shape {
|
||||
return Shape(form: self, fill: with)
|
||||
}
|
||||
|
||||
// GENERATED NOT
|
||||
open func stroke(fill: Fill = Color.black, width: Double = 1, cap: LineCap = .butt, join: LineJoin = .miter, dashes: [Double] = []) -> Shape {
|
||||
return Shape(form: self, stroke: Stroke(fill: fill, width: width, cap: cap, join: join, dashes: dashes))
|
||||
}
|
||||
|
||||
|
||||
public init() {
|
||||
}
|
||||
|
||||
// GENERATED NOT
|
||||
open func bounds() -> Rect {
|
||||
return Rect()
|
||||
}
|
||||
|
||||
// GENERATED NOT
|
||||
open func stroke(with: Stroke) -> Shape {
|
||||
return Shape(form: self, stroke: with)
|
||||
}
|
||||
|
||||
// GENERATED NOT
|
||||
open func fill(with: Fill) -> Shape {
|
||||
return Shape(form: self, fill: with)
|
||||
}
|
||||
|
||||
// GENERATED NOT
|
||||
open func stroke(fill: Fill = Color.black, width: Double = 1, cap: LineCap = .butt, join: LineJoin = .miter, dashes: [Double] = []) -> Shape {
|
||||
return Shape(form: self, stroke: Stroke(fill: fill, width: width, cap: cap, join: join, dashes: dashes))
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,9 @@
|
||||
import Foundation
|
||||
|
||||
open class MoveTo: PathBuilder {
|
||||
|
||||
// GENERATED NOT
|
||||
public init(x: Double, y: Double) {
|
||||
super.init(segment: PathSegment(type: .M, data: [x, y]))
|
||||
}
|
||||
|
||||
|
||||
// GENERATED NOT
|
||||
public init(x: Double, y: Double) {
|
||||
super.init(segment: PathSegment(type: .M, data: [x, y]))
|
||||
}
|
||||
}
|
||||
|
@ -1,14 +1,14 @@
|
||||
import Foundation
|
||||
|
||||
open class Path: Locus {
|
||||
|
||||
open let segments: [PathSegment]
|
||||
|
||||
public init(segments: [PathSegment] = []) {
|
||||
self.segments = segments
|
||||
}
|
||||
|
||||
override open func bounds() -> Rect {
|
||||
return pathBounds(self)!
|
||||
}
|
||||
|
||||
open let segments: [PathSegment]
|
||||
|
||||
public init(segments: [PathSegment] = []) {
|
||||
self.segments = segments
|
||||
}
|
||||
|
||||
override open func bounds() -> Rect {
|
||||
return pathBounds(self)!
|
||||
}
|
||||
}
|
||||
|
@ -1,154 +1,153 @@
|
||||
import Foundation
|
||||
|
||||
open class PathBuilder {
|
||||
|
||||
open let segment: PathSegment
|
||||
open let rest: PathBuilder?
|
||||
|
||||
public init(segment: PathSegment, rest: PathBuilder? = nil) {
|
||||
self.segment = segment
|
||||
self.rest = rest
|
||||
}
|
||||
|
||||
// GENERATED NOT
|
||||
open func moveTo(x: Double, y: Double) -> PathBuilder {
|
||||
return M(x, y)
|
||||
|
||||
open let segment: PathSegment
|
||||
open let rest: PathBuilder?
|
||||
|
||||
public init(segment: PathSegment, rest: PathBuilder? = nil) {
|
||||
self.segment = segment
|
||||
self.rest = rest
|
||||
}
|
||||
|
||||
// GENERATED NOT
|
||||
open func moveTo(x: Double, y: Double) -> PathBuilder {
|
||||
return M(x, y)
|
||||
}
|
||||
|
||||
// GENERATED NOT
|
||||
open func lineTo(x: Double, y: Double) -> PathBuilder {
|
||||
return L(x, y)
|
||||
}
|
||||
|
||||
// GENERATED NOT
|
||||
open func cubicTo(x1: Double, y1: Double, x2: Double, y2: Double, x: Double, y: Double) -> PathBuilder {
|
||||
return C(x1, y1, x2, y2, x, y)
|
||||
}
|
||||
|
||||
// GENERATED NOT
|
||||
open func quadraticTo(x1: Double, y1: Double, x: Double, y: Double) -> PathBuilder {
|
||||
return Q(x1, y1, x, y)
|
||||
}
|
||||
|
||||
// GENERATED NOT
|
||||
open func arcTo(rx: Double, ry: Double, angle: Double, largeArc: Bool, sweep: Bool, x: Double, y: Double) -> PathBuilder {
|
||||
return A(rx, ry, angle, largeArc, sweep, x, y)
|
||||
}
|
||||
|
||||
// GENERATED NOT
|
||||
open func close() -> PathBuilder {
|
||||
return Z()
|
||||
}
|
||||
|
||||
// GENERATED NOT
|
||||
open func m(_ x: Double, _ y: Double) -> PathBuilder {
|
||||
return PathBuilder(segment: PathSegment(type: .m, data: [x, y]), rest: self)
|
||||
}
|
||||
|
||||
// GENERATED NOT
|
||||
open func M(_ x: Double, _ y: Double) -> PathBuilder {
|
||||
return PathBuilder(segment: PathSegment(type: .M, data: [x, y]), rest: self)
|
||||
}
|
||||
|
||||
// GENERATED NOT
|
||||
open func l(_ x: Double, _ y: Double) -> PathBuilder {
|
||||
return PathBuilder(segment: PathSegment(type: .l, data: [x, y]), rest: self)
|
||||
}
|
||||
|
||||
// GENERATED NOT
|
||||
open func L(_ x: Double, _ y: Double) -> PathBuilder {
|
||||
return PathBuilder(segment: PathSegment(type: .L, data: [x, y]), rest: self)
|
||||
}
|
||||
|
||||
// GENERATED NOT
|
||||
open func h(_ x: Double) -> PathBuilder {
|
||||
return PathBuilder(segment: PathSegment(type: .h, data: [x]), rest: self)
|
||||
}
|
||||
|
||||
// GENERATED NOT
|
||||
open func H(_ x: Double) -> PathBuilder {
|
||||
return PathBuilder(segment: PathSegment(type: .H, data: [x]), rest: self)
|
||||
}
|
||||
|
||||
// GENERATED NOT
|
||||
open func v(_ y: Double) -> PathBuilder {
|
||||
return PathBuilder(segment: PathSegment(type: .v, data: [y]), rest: self)
|
||||
}
|
||||
|
||||
// GENERATED NOT
|
||||
open func V(_ y: Double) -> PathBuilder {
|
||||
return PathBuilder(segment: PathSegment(type: .V, data: [y]), rest: self)
|
||||
}
|
||||
|
||||
// GENERATED NOT
|
||||
open func c(_ x1: Double, _ y1: Double, _ x2: Double, _ y2: Double, _ x: Double, _ y: Double) -> PathBuilder {
|
||||
return PathBuilder(segment: PathSegment(type: .c, data: [x1, y1, x2, y2, x, y]), rest: self)
|
||||
}
|
||||
|
||||
// GENERATED NOT
|
||||
open func C(_ x1: Double, _ y1: Double, _ x2: Double, _ y2: Double, _ x: Double, _ y: Double) -> PathBuilder {
|
||||
return PathBuilder(segment: PathSegment(type: .C, data: [x1, y1, x2, y2, x, y]), rest: self)
|
||||
}
|
||||
|
||||
// GENERATED NOT
|
||||
open func s(_ x2: Double, _ y2: Double, _ x: Double, _ y: Double) -> PathBuilder {
|
||||
return PathBuilder(segment: PathSegment(type: .s, data: [x2, y2, x, y]), rest: self)
|
||||
}
|
||||
|
||||
// GENERATED NOT
|
||||
open func S(_ x2: Double, _ y2: Double, _ x: Double, _ y: Double) -> PathBuilder {
|
||||
return PathBuilder(segment: PathSegment(type: .S, data: [x2, y2, x, y]), rest: self)
|
||||
}
|
||||
|
||||
// GENERATED NOT
|
||||
open func q(_ x1: Double, _ y1: Double, _ x: Double, _ y: Double) -> PathBuilder {
|
||||
return PathBuilder(segment: PathSegment(type: .q, data: [x1, y1, x, y]), rest: self)
|
||||
}
|
||||
|
||||
// GENERATED NOT
|
||||
open func Q(_ x1: Double, _ y1: Double, _ x: Double, _ y: Double) -> PathBuilder {
|
||||
return PathBuilder(segment: PathSegment(type: .Q, data: [x1, y1, x, y]), rest: self)
|
||||
}
|
||||
|
||||
// GENERATED NOT
|
||||
open func t(_ x: Double, _ y: Double) -> PathBuilder {
|
||||
return PathBuilder(segment: PathSegment(type: .t, data: [x, y]), rest: self)
|
||||
}
|
||||
|
||||
// GENERATED NOT
|
||||
open func T(_ x: Double, _ y: Double) -> PathBuilder {
|
||||
return PathBuilder(segment: PathSegment(type: .T, data: [x, y]), rest: self)
|
||||
}
|
||||
|
||||
// GENERATED NOT
|
||||
open func a(_ rx: Double, _ ry: Double, _ angle: Double, _ largeArc: Bool, _ sweep: Bool, _ x: Double, _ y: Double) -> PathBuilder {
|
||||
return PathBuilder(segment: PathSegment(type: .a, data: [rx, ry, angle, boolsToNum(largeArc, sweep: sweep), x, y]), rest: self)
|
||||
}
|
||||
|
||||
// GENERATED NOT
|
||||
open func A(_ rx: Double, _ ry: Double, _ angle: Double, _ largeArc: Bool, _ sweep: Bool, _ x: Double, _ y: Double) -> PathBuilder {
|
||||
return PathBuilder(segment: PathSegment(type: .A, data: [rx, ry, angle, boolsToNum(largeArc, sweep: sweep), x, y]), rest: self)
|
||||
}
|
||||
|
||||
// GENERATED NOT
|
||||
open func Z() -> PathBuilder {
|
||||
return PathBuilder(segment: PathSegment(type: .z), rest: self)
|
||||
}
|
||||
|
||||
// GENERATED NOT
|
||||
open func build() -> Path {
|
||||
var segments : [PathSegment] = []
|
||||
var builder : PathBuilder? = self
|
||||
while(builder != nil) {
|
||||
segments.append(builder!.segment)
|
||||
builder = builder!.rest
|
||||
}
|
||||
|
||||
// GENERATED NOT
|
||||
open func lineTo(x: Double, y: Double) -> PathBuilder {
|
||||
return L(x, y)
|
||||
}
|
||||
|
||||
// GENERATED NOT
|
||||
open func cubicTo(x1: Double, y1: Double, x2: Double, y2: Double, x: Double, y: Double) -> PathBuilder {
|
||||
return C(x1, y1, x2, y2, x, y)
|
||||
}
|
||||
|
||||
// GENERATED NOT
|
||||
open func quadraticTo(x1: Double, y1: Double, x: Double, y: Double) -> PathBuilder {
|
||||
return Q(x1, y1, x, y)
|
||||
}
|
||||
|
||||
// GENERATED NOT
|
||||
open func arcTo(rx: Double, ry: Double, angle: Double, largeArc: Bool, sweep: Bool, x: Double, y: Double) -> PathBuilder {
|
||||
return A(rx, ry, angle, largeArc, sweep, x, y)
|
||||
}
|
||||
|
||||
// GENERATED NOT
|
||||
open func close() -> PathBuilder {
|
||||
return Z()
|
||||
}
|
||||
|
||||
// GENERATED NOT
|
||||
open func m(_ x: Double, _ y: Double) -> PathBuilder {
|
||||
return PathBuilder(segment: PathSegment(type: .m, data: [x, y]), rest: self)
|
||||
}
|
||||
|
||||
// GENERATED NOT
|
||||
open func M(_ x: Double, _ y: Double) -> PathBuilder {
|
||||
return PathBuilder(segment: PathSegment(type: .M, data: [x, y]), rest: self)
|
||||
}
|
||||
|
||||
// GENERATED NOT
|
||||
open func l(_ x: Double, _ y: Double) -> PathBuilder {
|
||||
return PathBuilder(segment: PathSegment(type: .l, data: [x, y]), rest: self)
|
||||
}
|
||||
|
||||
// GENERATED NOT
|
||||
open func L(_ x: Double, _ y: Double) -> PathBuilder {
|
||||
return PathBuilder(segment: PathSegment(type: .L, data: [x, y]), rest: self)
|
||||
}
|
||||
|
||||
// GENERATED NOT
|
||||
open func h(_ x: Double) -> PathBuilder {
|
||||
return PathBuilder(segment: PathSegment(type: .h, data: [x]), rest: self)
|
||||
}
|
||||
|
||||
// GENERATED NOT
|
||||
open func H(_ x: Double) -> PathBuilder {
|
||||
return PathBuilder(segment: PathSegment(type: .H, data: [x]), rest: self)
|
||||
}
|
||||
|
||||
// GENERATED NOT
|
||||
open func v(_ y: Double) -> PathBuilder {
|
||||
return PathBuilder(segment: PathSegment(type: .v, data: [y]), rest: self)
|
||||
}
|
||||
|
||||
// GENERATED NOT
|
||||
open func V(_ y: Double) -> PathBuilder {
|
||||
return PathBuilder(segment: PathSegment(type: .V, data: [y]), rest: self)
|
||||
}
|
||||
|
||||
// GENERATED NOT
|
||||
open func c(_ x1: Double, _ y1: Double, _ x2: Double, _ y2: Double, _ x: Double, _ y: Double) -> PathBuilder {
|
||||
return PathBuilder(segment: PathSegment(type: .c, data: [x1, y1, x2, y2, x, y]), rest: self)
|
||||
}
|
||||
|
||||
// GENERATED NOT
|
||||
open func C(_ x1: Double, _ y1: Double, _ x2: Double, _ y2: Double, _ x: Double, _ y: Double) -> PathBuilder {
|
||||
return PathBuilder(segment: PathSegment(type: .C, data: [x1, y1, x2, y2, x, y]), rest: self)
|
||||
}
|
||||
|
||||
// GENERATED NOT
|
||||
open func s(_ x2: Double, _ y2: Double, _ x: Double, _ y: Double) -> PathBuilder {
|
||||
return PathBuilder(segment: PathSegment(type: .s, data: [x2, y2, x, y]), rest: self)
|
||||
}
|
||||
|
||||
// GENERATED NOT
|
||||
open func S(_ x2: Double, _ y2: Double, _ x: Double, _ y: Double) -> PathBuilder {
|
||||
return PathBuilder(segment: PathSegment(type: .S, data: [x2, y2, x, y]), rest: self)
|
||||
}
|
||||
|
||||
// GENERATED NOT
|
||||
open func q(_ x1: Double, _ y1: Double, _ x: Double, _ y: Double) -> PathBuilder {
|
||||
return PathBuilder(segment: PathSegment(type: .q, data: [x1, y1, x, y]), rest: self)
|
||||
}
|
||||
|
||||
// GENERATED NOT
|
||||
open func Q(_ x1: Double, _ y1: Double, _ x: Double, _ y: Double) -> PathBuilder {
|
||||
return PathBuilder(segment: PathSegment(type: .Q, data: [x1, y1, x, y]), rest: self)
|
||||
}
|
||||
|
||||
// GENERATED NOT
|
||||
open func t(_ x: Double, _ y: Double) -> PathBuilder {
|
||||
return PathBuilder(segment: PathSegment(type: .t, data: [x, y]), rest: self)
|
||||
}
|
||||
|
||||
// GENERATED NOT
|
||||
open func T(_ x: Double, _ y: Double) -> PathBuilder {
|
||||
return PathBuilder(segment: PathSegment(type: .T, data: [x, y]), rest: self)
|
||||
}
|
||||
|
||||
// GENERATED NOT
|
||||
open func a(_ rx: Double, _ ry: Double, _ angle: Double, _ largeArc: Bool, _ sweep: Bool, _ x: Double, _ y: Double) -> PathBuilder {
|
||||
return PathBuilder(segment: PathSegment(type: .a, data: [rx, ry, angle, boolsToNum(largeArc, sweep: sweep), x, y]), rest: self)
|
||||
}
|
||||
|
||||
// GENERATED NOT
|
||||
open func A(_ rx: Double, _ ry: Double, _ angle: Double, _ largeArc: Bool, _ sweep: Bool, _ x: Double, _ y: Double) -> PathBuilder {
|
||||
return PathBuilder(segment: PathSegment(type: .A, data: [rx, ry, angle, boolsToNum(largeArc, sweep: sweep), x, y]), rest: self)
|
||||
}
|
||||
|
||||
// GENERATED NOT
|
||||
open func Z() -> PathBuilder {
|
||||
return PathBuilder(segment: PathSegment(type: .z), rest: self)
|
||||
}
|
||||
|
||||
// GENERATED NOT
|
||||
open func build() -> Path {
|
||||
var segments : [PathSegment] = []
|
||||
var builder : PathBuilder? = self
|
||||
while(builder != nil) {
|
||||
segments.append(builder!.segment)
|
||||
builder = builder!.rest
|
||||
}
|
||||
return Path(segments: segments.reversed())
|
||||
}
|
||||
|
||||
// GENERATED NOT
|
||||
fileprivate func boolsToNum(_ largeArc: Bool, sweep: Bool) -> Double {
|
||||
return (largeArc ? 1 : 0) + (sweep ? 1 : 0) * 2;
|
||||
}
|
||||
|
||||
return Path(segments: segments.reversed())
|
||||
}
|
||||
|
||||
// GENERATED NOT
|
||||
fileprivate func boolsToNum(_ largeArc: Bool, sweep: Bool) -> Double {
|
||||
return (largeArc ? 1 : 0) + (sweep ? 1 : 0) * 2;
|
||||
}
|
||||
}
|
||||
|
@ -1,23 +1,22 @@
|
||||
import Foundation
|
||||
|
||||
open class PathSegment {
|
||||
|
||||
open let type: PathSegmentType
|
||||
open let data: [Double]
|
||||
|
||||
public init(type: PathSegmentType = .M, data: [Double] = []) {
|
||||
self.type = type
|
||||
self.data = data
|
||||
}
|
||||
|
||||
// GENERATED NOT
|
||||
open func isAbsolute() -> Bool {
|
||||
switch type {
|
||||
case .M, .L, .H, .V, .C, .S, .Q, .T, .A:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
|
||||
open let type: PathSegmentType
|
||||
open let data: [Double]
|
||||
|
||||
public init(type: PathSegmentType = .M, data: [Double] = []) {
|
||||
self.type = type
|
||||
self.data = data
|
||||
}
|
||||
|
||||
// GENERATED NOT
|
||||
open func isAbsolute() -> Bool {
|
||||
switch type {
|
||||
case .M, .L, .H, .V, .C, .S, .Q, .T, .A:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -1,30 +1,29 @@
|
||||
import Foundation
|
||||
|
||||
open class Point: Locus {
|
||||
|
||||
open let x: Double
|
||||
open let y: Double
|
||||
|
||||
open static let origin: Point = Point( x: 0, y: 0 )
|
||||
|
||||
public init(x: Double = 0, y: Double = 0) {
|
||||
self.x = x
|
||||
self.y = y
|
||||
}
|
||||
|
||||
override open func bounds() -> Rect {
|
||||
return Rect(
|
||||
x: x,
|
||||
y: y,
|
||||
w: 0.0,
|
||||
h: 0.0)
|
||||
}
|
||||
|
||||
// GENERATED NOT
|
||||
open func add(_ point: Point) -> Point {
|
||||
return Point(
|
||||
x: self.x + point.x,
|
||||
y: self.y + point.y)
|
||||
}
|
||||
|
||||
|
||||
open let x: Double
|
||||
open let y: Double
|
||||
|
||||
open static let origin: Point = Point( x: 0, y: 0 )
|
||||
|
||||
public init(x: Double = 0, y: Double = 0) {
|
||||
self.x = x
|
||||
self.y = y
|
||||
}
|
||||
|
||||
override open func bounds() -> Rect {
|
||||
return Rect(
|
||||
x: x,
|
||||
y: y,
|
||||
w: 0.0,
|
||||
h: 0.0)
|
||||
}
|
||||
|
||||
// GENERATED NOT
|
||||
open func add(_ point: Point) -> Point {
|
||||
return Point(
|
||||
x: self.x + point.x,
|
||||
y: self.y + point.y)
|
||||
}
|
||||
}
|
||||
|
@ -1,46 +1,46 @@
|
||||
import Foundation
|
||||
|
||||
open class Polygon: Locus {
|
||||
|
||||
open let points: [Double]
|
||||
|
||||
public init(points: [Double] = []) {
|
||||
self.points = points
|
||||
}
|
||||
|
||||
override open func bounds() -> Rect {
|
||||
guard !points.isEmpty else { return Rect.zero() }
|
||||
|
||||
open let points: [Double]
|
||||
var minX = Double(INT16_MAX)
|
||||
var minY = Double(INT16_MAX)
|
||||
var maxX = Double(INT16_MIN)
|
||||
var maxY = Double(INT16_MIN)
|
||||
|
||||
public init(points: [Double] = []) {
|
||||
self.points = points
|
||||
}
|
||||
|
||||
override open func bounds() -> Rect {
|
||||
guard !points.isEmpty else { return Rect.zero() }
|
||||
|
||||
var minX = Double(INT16_MAX)
|
||||
var minY = Double(INT16_MAX)
|
||||
var maxX = Double(INT16_MIN)
|
||||
var maxY = Double(INT16_MIN)
|
||||
|
||||
var isX = true
|
||||
for point in points {
|
||||
if isX {
|
||||
if minX > point {
|
||||
minX = point
|
||||
}
|
||||
|
||||
if maxX < point {
|
||||
maxX = point
|
||||
}
|
||||
} else {
|
||||
if minY > point {
|
||||
minY = point
|
||||
}
|
||||
|
||||
if maxY < point {
|
||||
maxY = point
|
||||
}
|
||||
}
|
||||
|
||||
isX = !isX
|
||||
var isX = true
|
||||
for point in points {
|
||||
if isX {
|
||||
if minX > point {
|
||||
minX = point
|
||||
}
|
||||
|
||||
return Rect(x: minX, y: minY,
|
||||
w: maxX - minX,
|
||||
h: maxY - minY)
|
||||
if maxX < point {
|
||||
maxX = point
|
||||
}
|
||||
} else {
|
||||
if minY > point {
|
||||
minY = point
|
||||
}
|
||||
|
||||
if maxY < point {
|
||||
maxY = point
|
||||
}
|
||||
}
|
||||
|
||||
isX = !isX
|
||||
}
|
||||
|
||||
return Rect(x: minX, y: minY,
|
||||
w: maxX - minX,
|
||||
h: maxY - minY)
|
||||
}
|
||||
}
|
||||
|
@ -1,46 +1,46 @@
|
||||
import Foundation
|
||||
|
||||
open class Polyline: Locus {
|
||||
|
||||
open let points: [Double]
|
||||
|
||||
public init(points: [Double] = []) {
|
||||
self.points = points
|
||||
}
|
||||
|
||||
open let points: [Double]
|
||||
|
||||
public init(points: [Double] = []) {
|
||||
self.points = points
|
||||
}
|
||||
|
||||
override open func bounds() -> Rect {
|
||||
guard !points.isEmpty else { return Rect.zero() }
|
||||
|
||||
override open func bounds() -> Rect {
|
||||
guard !points.isEmpty else { return Rect.zero() }
|
||||
|
||||
var minX = Double(INT16_MAX)
|
||||
var minY = Double(INT16_MAX)
|
||||
var maxX = Double(INT16_MIN)
|
||||
var maxY = Double(INT16_MIN)
|
||||
|
||||
var isX = true
|
||||
for point in points {
|
||||
if isX {
|
||||
if minX > point {
|
||||
minX = point
|
||||
}
|
||||
|
||||
if maxX < point {
|
||||
maxX = point
|
||||
}
|
||||
} else {
|
||||
if minY > point {
|
||||
minY = point
|
||||
}
|
||||
|
||||
if maxY < point {
|
||||
maxY = point
|
||||
}
|
||||
}
|
||||
|
||||
isX = !isX
|
||||
var minX = Double(INT16_MAX)
|
||||
var minY = Double(INT16_MAX)
|
||||
var maxX = Double(INT16_MIN)
|
||||
var maxY = Double(INT16_MIN)
|
||||
|
||||
var isX = true
|
||||
for point in points {
|
||||
if isX {
|
||||
if minX > point {
|
||||
minX = point
|
||||
}
|
||||
|
||||
return Rect(x: minX, y: minY,
|
||||
w: maxX - minX,
|
||||
h: maxY - minY)
|
||||
if maxX < point {
|
||||
maxX = point
|
||||
}
|
||||
} else {
|
||||
if minY > point {
|
||||
minY = point
|
||||
}
|
||||
|
||||
if maxY < point {
|
||||
maxY = point
|
||||
}
|
||||
}
|
||||
|
||||
isX = !isX
|
||||
}
|
||||
|
||||
return Rect(x: minX, y: minY,
|
||||
w: maxX - minX,
|
||||
h: maxY - minY)
|
||||
}
|
||||
}
|
||||
|
@ -1,68 +1,68 @@
|
||||
import Foundation
|
||||
|
||||
open class Rect: Locus {
|
||||
|
||||
open let x: Double
|
||||
open let y: Double
|
||||
open let w: Double
|
||||
open let h: Double
|
||||
|
||||
public init(x: Double = 0, y: Double = 0, w: Double = 0, h: Double = 0) {
|
||||
self.x = x
|
||||
self.y = y
|
||||
self.w = w
|
||||
self.h = h
|
||||
}
|
||||
|
||||
override open func bounds() -> Rect {
|
||||
return self
|
||||
}
|
||||
|
||||
// GENERATED NOT
|
||||
open func round(rx: Double, ry: Double) -> RoundRect {
|
||||
return RoundRect(rect: self, rx: rx, ry: ry)
|
||||
}
|
||||
|
||||
// GENERATED NOT
|
||||
public func round(r: Double) -> RoundRect {
|
||||
return RoundRect(rect: self, rx: r, ry: r)
|
||||
}
|
||||
|
||||
// GENERATED NOT
|
||||
open func contains(locus: Locus) -> Bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// GENERATED NOT
|
||||
class func zero() -> Rect {
|
||||
return Rect(x: 0.0, y: 0.0, w: 0.0, h: 0.0)
|
||||
}
|
||||
|
||||
// GENERATED NOT
|
||||
open func move(offset: Point) -> Rect {
|
||||
return Rect(
|
||||
x: self.x + offset.x,
|
||||
y: self.y + offset.y,
|
||||
w: self.w,
|
||||
h: self.h)
|
||||
}
|
||||
|
||||
// GENERATED NOT
|
||||
open func union(rect: Rect) -> Rect {
|
||||
return Rect(
|
||||
x: min(self.x, rect.x),
|
||||
y: min(self.y, rect.y),
|
||||
w: max(self.x + self.w, rect.x + rect.w) - min(self.x, rect.x),
|
||||
h: max(self.y + self.h, rect.y + rect.h) - min(self.y, rect.y))
|
||||
}
|
||||
|
||||
|
||||
open let x: Double
|
||||
open let y: Double
|
||||
open let w: Double
|
||||
open let h: Double
|
||||
|
||||
public init(x: Double = 0, y: Double = 0, w: Double = 0, h: Double = 0) {
|
||||
self.x = x
|
||||
self.y = y
|
||||
self.w = w
|
||||
self.h = h
|
||||
}
|
||||
|
||||
override open func bounds() -> Rect {
|
||||
return self
|
||||
}
|
||||
|
||||
// GENERATED NOT
|
||||
open func round(rx: Double, ry: Double) -> RoundRect {
|
||||
return RoundRect(rect: self, rx: rx, ry: ry)
|
||||
}
|
||||
|
||||
// GENERATED NOT
|
||||
public func round(r: Double) -> RoundRect {
|
||||
return RoundRect(rect: self, rx: r, ry: r)
|
||||
}
|
||||
|
||||
// GENERATED NOT
|
||||
open func contains(locus: Locus) -> Bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// GENERATED NOT
|
||||
class func zero() -> Rect {
|
||||
return Rect(x: 0.0, y: 0.0, w: 0.0, h: 0.0)
|
||||
}
|
||||
|
||||
// GENERATED NOT
|
||||
open func move(offset: Point) -> Rect {
|
||||
return Rect(
|
||||
x: self.x + offset.x,
|
||||
y: self.y + offset.y,
|
||||
w: self.w,
|
||||
h: self.h)
|
||||
}
|
||||
|
||||
// GENERATED NOT
|
||||
open func union(rect: Rect) -> Rect {
|
||||
return Rect(
|
||||
x: min(self.x, rect.x),
|
||||
y: min(self.y, rect.y),
|
||||
w: max(self.x + self.w, rect.x + rect.w) - min(self.x, rect.x),
|
||||
h: max(self.y + self.h, rect.y + rect.h) - min(self.y, rect.y))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension Rect {
|
||||
public static func ==(lhs: Rect, rhs: Rect) -> Bool {
|
||||
return lhs.x == rhs.x
|
||||
&& lhs.y == rhs.y
|
||||
&& lhs.w == rhs.w
|
||||
&& lhs.h == rhs.h
|
||||
}
|
||||
public static func ==(lhs: Rect, rhs: Rect) -> Bool {
|
||||
return lhs.x == rhs.x
|
||||
&& lhs.y == rhs.y
|
||||
&& lhs.w == rhs.w
|
||||
&& lhs.h == rhs.h
|
||||
}
|
||||
}
|
||||
|
@ -1,18 +1,18 @@
|
||||
import Foundation
|
||||
|
||||
open class RoundRect: Locus {
|
||||
|
||||
open let rect: Rect
|
||||
open let rx: Double
|
||||
open let ry: Double
|
||||
|
||||
public init(rect: Rect, rx: Double = 0, ry: Double = 0) {
|
||||
self.rect = rect
|
||||
self.rx = rx
|
||||
self.ry = ry
|
||||
}
|
||||
|
||||
override open func bounds() -> Rect {
|
||||
return rect
|
||||
}
|
||||
|
||||
open let rect: Rect
|
||||
open let rx: Double
|
||||
open let ry: Double
|
||||
|
||||
public init(rect: Rect, rx: Double = 0, ry: Double = 0) {
|
||||
self.rect = rect
|
||||
self.rx = rx
|
||||
self.ry = ry
|
||||
}
|
||||
|
||||
override open func bounds() -> Rect {
|
||||
return rect
|
||||
}
|
||||
}
|
||||
|
@ -1,13 +1,12 @@
|
||||
import Foundation
|
||||
|
||||
open class Size {
|
||||
|
||||
open let w: Double
|
||||
open let h: Double
|
||||
|
||||
public init(w: Double = 0, h: Double = 0) {
|
||||
self.w = w
|
||||
self.h = h
|
||||
}
|
||||
|
||||
|
||||
open let w: Double
|
||||
open let h: Double
|
||||
|
||||
public init(w: Double = 0, h: Double = 0) {
|
||||
self.w = w
|
||||
self.h = h
|
||||
}
|
||||
}
|
||||
|
@ -1,89 +1,88 @@
|
||||
import Foundation
|
||||
|
||||
public final class Transform {
|
||||
|
||||
public let m11: Double
|
||||
public let m12: Double
|
||||
public let m21: Double
|
||||
public let m22: Double
|
||||
public let dx: Double
|
||||
public let dy: Double
|
||||
|
||||
public static let identity: Transform = Transform()
|
||||
|
||||
public init(m11: Double = 1, m12: Double = 0, m21: Double = 0, m22: Double = 1, dx: Double = 0, dy: Double = 0) {
|
||||
self.m11 = m11
|
||||
self.m12 = m12
|
||||
self.m21 = m21
|
||||
self.m22 = m22
|
||||
self.dx = dx
|
||||
self.dy = dy
|
||||
}
|
||||
|
||||
// GENERATED NOT
|
||||
public func move(dx: Double, dy: Double) -> Transform {
|
||||
return Transform(m11: m11, m12: m12, m21: m21, m22: m22,
|
||||
dx: dx * m11 + dy * m21 + self.dx, dy: dx * m12 + dy * m22 + self.dy)
|
||||
}
|
||||
|
||||
// GENERATED NOT
|
||||
public func scale(sx: Double, sy: Double) -> Transform {
|
||||
return Transform(m11: m11 * sx, m12: m12 * sx, m21: m21 * sy, m22: m22 * sy, dx: dx, dy: dy)
|
||||
}
|
||||
|
||||
// GENERATED NOT
|
||||
public func shear(shx: Double, shy: Double) -> Transform {
|
||||
return Transform(m11: m11 + m21 * shy, m12: m12 + m22 * shy,
|
||||
m21: m11 * shx + m21, m22: m12 * shx + m22, dx: dx, dy: dy)
|
||||
}
|
||||
|
||||
// GENERATED NOT
|
||||
public func rotate(angle: Double) -> Transform {
|
||||
let asin = sin(angle); let acos = cos(angle)
|
||||
return Transform(m11: acos * m11 + asin * m21, m12: acos * m12 + asin * m22,
|
||||
m21: -asin * m11 + acos * m21, m22: -asin * m12 + acos * m22, dx: dx, dy: dy)
|
||||
}
|
||||
|
||||
// GENERATED NOT
|
||||
public func rotate(angle: Double, x: Double, y: Double) -> Transform {
|
||||
return move(dx: x, dy: y).rotate(angle: angle).move(dx: -x, dy: -y)
|
||||
}
|
||||
|
||||
// GENERATED
|
||||
public class func move(dx: Double, dy: Double) -> Transform {
|
||||
return Transform(dx: dx, dy: dy)
|
||||
}
|
||||
|
||||
// GENERATED
|
||||
public class func scale(sx: Double, sy: Double) -> Transform {
|
||||
return Transform(m11: sx, m22: sy)
|
||||
}
|
||||
|
||||
// GENERATED
|
||||
public class func shear(shx: Double, shy: Double) -> Transform {
|
||||
return Transform(m12: shy, m21: shx)
|
||||
}
|
||||
|
||||
// GENERATED NOT
|
||||
public class func rotate(angle: Double) -> Transform {
|
||||
let asin = sin(angle); let acos = cos(angle)
|
||||
return Transform(m11: acos, m12: asin, m21: -asin, m22: acos)
|
||||
}
|
||||
|
||||
// GENERATED NOT
|
||||
public class func rotate(angle: Double, x: Double, y: Double) -> Transform {
|
||||
return Transform.move(dx: x, dy: y).rotate(angle: angle).move(dx: -x, dy: -y)
|
||||
}
|
||||
|
||||
// GENERATED NOT
|
||||
public func invert() -> Transform? {
|
||||
let det = self.m11 * self.m22 - self.m12 * self.m21
|
||||
if (det == 0) {
|
||||
return nil
|
||||
}
|
||||
return Transform(m11: m22 / det, m12: -m12 / det, m21: -m21 / det, m22: m11 / det,
|
||||
dx: (m21 * dy - m22 * dx) / det,
|
||||
dy: (m12 * dx - m11 * dy) / det)
|
||||
}
|
||||
|
||||
|
||||
public let m11: Double
|
||||
public let m12: Double
|
||||
public let m21: Double
|
||||
public let m22: Double
|
||||
public let dx: Double
|
||||
public let dy: Double
|
||||
|
||||
public static let identity: Transform = Transform()
|
||||
|
||||
public init(m11: Double = 1, m12: Double = 0, m21: Double = 0, m22: Double = 1, dx: Double = 0, dy: Double = 0) {
|
||||
self.m11 = m11
|
||||
self.m12 = m12
|
||||
self.m21 = m21
|
||||
self.m22 = m22
|
||||
self.dx = dx
|
||||
self.dy = dy
|
||||
}
|
||||
|
||||
// GENERATED NOT
|
||||
public func move(dx: Double, dy: Double) -> Transform {
|
||||
return Transform(m11: m11, m12: m12, m21: m21, m22: m22,
|
||||
dx: dx * m11 + dy * m21 + self.dx, dy: dx * m12 + dy * m22 + self.dy)
|
||||
}
|
||||
|
||||
// GENERATED NOT
|
||||
public func scale(sx: Double, sy: Double) -> Transform {
|
||||
return Transform(m11: m11 * sx, m12: m12 * sx, m21: m21 * sy, m22: m22 * sy, dx: dx, dy: dy)
|
||||
}
|
||||
|
||||
// GENERATED NOT
|
||||
public func shear(shx: Double, shy: Double) -> Transform {
|
||||
return Transform(m11: m11 + m21 * shy, m12: m12 + m22 * shy,
|
||||
m21: m11 * shx + m21, m22: m12 * shx + m22, dx: dx, dy: dy)
|
||||
}
|
||||
|
||||
// GENERATED NOT
|
||||
public func rotate(angle: Double) -> Transform {
|
||||
let asin = sin(angle); let acos = cos(angle)
|
||||
return Transform(m11: acos * m11 + asin * m21, m12: acos * m12 + asin * m22,
|
||||
m21: -asin * m11 + acos * m21, m22: -asin * m12 + acos * m22, dx: dx, dy: dy)
|
||||
}
|
||||
|
||||
// GENERATED NOT
|
||||
public func rotate(angle: Double, x: Double, y: Double) -> Transform {
|
||||
return move(dx: x, dy: y).rotate(angle: angle).move(dx: -x, dy: -y)
|
||||
}
|
||||
|
||||
// GENERATED
|
||||
public class func move(dx: Double, dy: Double) -> Transform {
|
||||
return Transform(dx: dx, dy: dy)
|
||||
}
|
||||
|
||||
// GENERATED
|
||||
public class func scale(sx: Double, sy: Double) -> Transform {
|
||||
return Transform(m11: sx, m22: sy)
|
||||
}
|
||||
|
||||
// GENERATED
|
||||
public class func shear(shx: Double, shy: Double) -> Transform {
|
||||
return Transform(m12: shy, m21: shx)
|
||||
}
|
||||
|
||||
// GENERATED NOT
|
||||
public class func rotate(angle: Double) -> Transform {
|
||||
let asin = sin(angle); let acos = cos(angle)
|
||||
return Transform(m11: acos, m12: asin, m21: -asin, m22: acos)
|
||||
}
|
||||
|
||||
// GENERATED NOT
|
||||
public class func rotate(angle: Double, x: Double, y: Double) -> Transform {
|
||||
return Transform.move(dx: x, dy: y).rotate(angle: angle).move(dx: -x, dy: -y)
|
||||
}
|
||||
|
||||
// GENERATED NOT
|
||||
public func invert() -> Transform? {
|
||||
let det = self.m11 * self.m22 - self.m12 * self.m21
|
||||
if (det == 0) {
|
||||
return nil
|
||||
}
|
||||
return Transform(m11: m22 / det, m12: -m12 / det, m21: -m21 / det, m22: m11 / det,
|
||||
dx: (m21 * dy - m22 * dx) / det,
|
||||
dy: (m12 * dx - m11 * dy) / det)
|
||||
}
|
||||
}
|
||||
|
@ -1,152 +1,151 @@
|
||||
import Foundation
|
||||
|
||||
open class Group: Node {
|
||||
|
||||
open var contentsVar: AnimatableVariable<[Node]>
|
||||
open var contents: [Node] {
|
||||
get { return contentsVar.value }
|
||||
set(val) {
|
||||
contentsVar.value = val
|
||||
|
||||
if let view = nodesMap.getView(self) {
|
||||
val.forEach { subNode in
|
||||
nodesMap.add(subNode, view: view)
|
||||
}
|
||||
}
|
||||
|
||||
val.forEach { subNode in
|
||||
nodesMap.add(subNode, parent: self)
|
||||
}
|
||||
|
||||
open var contentsVar: AnimatableVariable<[Node]>
|
||||
open var contents: [Node] {
|
||||
get { return contentsVar.value }
|
||||
set(val) {
|
||||
contentsVar.value = val
|
||||
|
||||
if let view = nodesMap.getView(self) {
|
||||
val.forEach { subNode in
|
||||
nodesMap.add(subNode, view: view)
|
||||
}
|
||||
}
|
||||
|
||||
val.forEach { subNode in
|
||||
nodesMap.add(subNode, parent: self)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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(
|
||||
place: place,
|
||||
opaque: opaque,
|
||||
opacity: opacity,
|
||||
clip: clip,
|
||||
effect: effect,
|
||||
visible: visible,
|
||||
tag: tag
|
||||
)
|
||||
|
||||
self.contentsVar.node = self
|
||||
}
|
||||
|
||||
// Searching
|
||||
|
||||
override public func nodeBy(tag: String) -> Node? {
|
||||
if let node = super.nodeBy(tag: tag) {
|
||||
return 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(
|
||||
place: place,
|
||||
opaque: opaque,
|
||||
opacity: opacity,
|
||||
clip: clip,
|
||||
effect: effect,
|
||||
visible: visible,
|
||||
tag: tag
|
||||
)
|
||||
|
||||
self.contentsVar.node = self
|
||||
for child in contents {
|
||||
if let node = child.nodeBy(tag: tag) {
|
||||
return node
|
||||
}
|
||||
}
|
||||
|
||||
// Searching
|
||||
|
||||
override public func nodeBy(tag: String) -> Node? {
|
||||
if let node = super.nodeBy(tag: tag) {
|
||||
return node
|
||||
}
|
||||
|
||||
for child in contents {
|
||||
if let node = child.nodeBy(tag: tag) {
|
||||
return node
|
||||
}
|
||||
}
|
||||
|
||||
return .none
|
||||
return .none
|
||||
}
|
||||
|
||||
override public func nodesBy(tag: String) -> [Node] {
|
||||
var result = [Node]()
|
||||
contents.forEach { child in
|
||||
result.append(contentsOf: child.nodesBy(tag: tag))
|
||||
}
|
||||
|
||||
override public func nodesBy(tag: String) -> [Node] {
|
||||
|
||||
var result = [Node]()
|
||||
contents.forEach { child in
|
||||
result.append(contentsOf: child.nodesBy(tag: tag))
|
||||
}
|
||||
|
||||
if let node = super.nodeBy(tag: tag) {
|
||||
result.append(node)
|
||||
}
|
||||
|
||||
return result
|
||||
if let node = super.nodeBy(tag: tag) {
|
||||
result.append(node)
|
||||
}
|
||||
|
||||
// GENERATED NOT
|
||||
override internal func bounds() -> Rect? {
|
||||
var union: Rect?
|
||||
|
||||
contents.forEach { node in
|
||||
guard let nodeBounds = node.bounds()?.applyTransform(node.place) else {
|
||||
return
|
||||
}
|
||||
|
||||
union = union?.union(rect: nodeBounds) ?? nodeBounds
|
||||
}
|
||||
|
||||
return union
|
||||
return result
|
||||
}
|
||||
|
||||
// GENERATED NOT
|
||||
override internal func bounds() -> Rect? {
|
||||
var union: Rect?
|
||||
|
||||
contents.forEach { node in
|
||||
guard let nodeBounds = node.bounds()?.applyTransform(node.place) else {
|
||||
return
|
||||
}
|
||||
|
||||
union = union?.union(rect: nodeBounds) ?? nodeBounds
|
||||
}
|
||||
|
||||
override func shouldCheckForPressed() -> Bool {
|
||||
var shouldCheck = super.shouldCheckForPressed()
|
||||
contents.forEach { node in
|
||||
shouldCheck = shouldCheck || node.shouldCheckForPressed()
|
||||
}
|
||||
|
||||
return shouldCheck
|
||||
return union
|
||||
}
|
||||
|
||||
override func shouldCheckForPressed() -> Bool {
|
||||
var shouldCheck = super.shouldCheckForPressed()
|
||||
contents.forEach { node in
|
||||
shouldCheck = shouldCheck || node.shouldCheckForPressed()
|
||||
}
|
||||
|
||||
override func shouldCheckForMoved() -> Bool {
|
||||
var shouldCheck = super.shouldCheckForMoved()
|
||||
contents.forEach { node in
|
||||
shouldCheck = shouldCheck || node.shouldCheckForMoved()
|
||||
}
|
||||
|
||||
return shouldCheck
|
||||
return shouldCheck
|
||||
}
|
||||
|
||||
override func shouldCheckForMoved() -> Bool {
|
||||
var shouldCheck = super.shouldCheckForMoved()
|
||||
contents.forEach { node in
|
||||
shouldCheck = shouldCheck || node.shouldCheckForMoved()
|
||||
}
|
||||
|
||||
override func shouldCheckForReleased() -> Bool {
|
||||
var shouldCheck = super.shouldCheckForReleased()
|
||||
contents.forEach { node in
|
||||
shouldCheck = shouldCheck || node.shouldCheckForReleased()
|
||||
}
|
||||
|
||||
return shouldCheck
|
||||
return shouldCheck
|
||||
}
|
||||
|
||||
override func shouldCheckForReleased() -> Bool {
|
||||
var shouldCheck = super.shouldCheckForReleased()
|
||||
contents.forEach { node in
|
||||
shouldCheck = shouldCheck || node.shouldCheckForReleased()
|
||||
}
|
||||
|
||||
override func shouldCheckForTap() -> Bool {
|
||||
var shouldCheck = super.shouldCheckForTap()
|
||||
contents.forEach { node in
|
||||
shouldCheck = shouldCheck || node.shouldCheckForTap()
|
||||
}
|
||||
|
||||
return shouldCheck
|
||||
return shouldCheck
|
||||
}
|
||||
|
||||
override func shouldCheckForTap() -> Bool {
|
||||
var shouldCheck = super.shouldCheckForTap()
|
||||
contents.forEach { node in
|
||||
shouldCheck = shouldCheck || node.shouldCheckForTap()
|
||||
}
|
||||
|
||||
override func shouldCheckForPan() -> Bool {
|
||||
var shouldCheck = super.shouldCheckForPan()
|
||||
contents.forEach { node in
|
||||
shouldCheck = shouldCheck || node.shouldCheckForPan()
|
||||
}
|
||||
|
||||
return shouldCheck
|
||||
return shouldCheck
|
||||
}
|
||||
|
||||
override func shouldCheckForPan() -> Bool {
|
||||
var shouldCheck = super.shouldCheckForPan()
|
||||
contents.forEach { node in
|
||||
shouldCheck = shouldCheck || node.shouldCheckForPan()
|
||||
}
|
||||
|
||||
override func shouldCheckForPinch() -> Bool {
|
||||
var shouldCheck = super.shouldCheckForPinch()
|
||||
contents.forEach { node in
|
||||
shouldCheck = shouldCheck || node.shouldCheckForPinch()
|
||||
}
|
||||
|
||||
return shouldCheck
|
||||
return shouldCheck
|
||||
}
|
||||
|
||||
override func shouldCheckForPinch() -> Bool {
|
||||
var shouldCheck = super.shouldCheckForPinch()
|
||||
contents.forEach { node in
|
||||
shouldCheck = shouldCheck || node.shouldCheckForPinch()
|
||||
}
|
||||
|
||||
override func shouldCheckForRotate() -> Bool {
|
||||
var shouldCheck = super.shouldCheckForRotate()
|
||||
contents.forEach { node in
|
||||
shouldCheck = shouldCheck || node.shouldCheckForRotate()
|
||||
}
|
||||
|
||||
return shouldCheck
|
||||
return shouldCheck
|
||||
}
|
||||
|
||||
override func shouldCheckForRotate() -> Bool {
|
||||
var shouldCheck = super.shouldCheckForRotate()
|
||||
contents.forEach { node in
|
||||
shouldCheck = shouldCheck || node.shouldCheckForRotate()
|
||||
}
|
||||
|
||||
return shouldCheck
|
||||
}
|
||||
}
|
||||
|
||||
public extension Array where Element: Node {
|
||||
public func group( place: Transform = Transform.identity, opaque: Bool = true, opacity: Double = 1, clip: Locus? = nil, effect: Effect? = nil, visible: Bool = true, tag: [String] = []) -> Group {
|
||||
return Group(contents: self, place: place, opaque: opaque, opacity: opacity, clip: clip, effect: effect, visible: visible, tag: tag)
|
||||
}
|
||||
public func group( place: Transform = Transform.identity, opaque: Bool = true, opacity: Double = 1, clip: Locus? = nil, effect: Effect? = nil, visible: Bool = true, tag: [String] = []) -> Group {
|
||||
return Group(contents: self, place: place, opaque: opaque, opacity: opacity, clip: clip, effect: effect, visible: visible, tag: tag)
|
||||
}
|
||||
}
|
||||
|
@ -1,133 +1,137 @@
|
||||
import UIKit
|
||||
import Foundation
|
||||
|
||||
#if os(iOS)
|
||||
import UIKit
|
||||
#endif
|
||||
|
||||
open class Image: Node {
|
||||
|
||||
open let srcVar: Variable<String>
|
||||
open var src: String {
|
||||
get { return srcVar.value }
|
||||
set(val) { srcVar.value = val }
|
||||
}
|
||||
|
||||
open let xAlignVar: Variable<Align>
|
||||
open var xAlign: Align {
|
||||
get { return xAlignVar.value }
|
||||
set(val) { xAlignVar.value = val }
|
||||
}
|
||||
|
||||
open let yAlignVar: Variable<Align>
|
||||
open var yAlign: Align {
|
||||
get { return yAlignVar.value }
|
||||
set(val) { yAlignVar.value = val }
|
||||
}
|
||||
|
||||
open let aspectRatioVar: Variable<AspectRatio>
|
||||
open var aspectRatio: AspectRatio {
|
||||
get { return aspectRatioVar.value }
|
||||
set(val) { aspectRatioVar.value = val }
|
||||
}
|
||||
|
||||
open let wVar: Variable<Int>
|
||||
open var w: Int {
|
||||
get { return wVar.value }
|
||||
set(val) { wVar.value = val }
|
||||
}
|
||||
|
||||
open let hVar: Variable<Int>
|
||||
open var h: Int {
|
||||
get { return hVar.value }
|
||||
set(val) { hVar.value = val }
|
||||
}
|
||||
|
||||
private var mImage: MImage?
|
||||
|
||||
public init(src: String, 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] = []) {
|
||||
self.srcVar = Variable<String>(src)
|
||||
self.xAlignVar = Variable<Align>(xAlign)
|
||||
self.yAlignVar = Variable<Align>(yAlign)
|
||||
self.aspectRatioVar = Variable<AspectRatio>(aspectRatio)
|
||||
self.wVar = Variable<Int>(w)
|
||||
self.hVar = Variable<Int>(h)
|
||||
super.init(
|
||||
place: place,
|
||||
opaque: opaque,
|
||||
opacity: opacity,
|
||||
clip: clip,
|
||||
effect: effect,
|
||||
visible: visible,
|
||||
tag: tag
|
||||
)
|
||||
}
|
||||
|
||||
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] = []) {
|
||||
|
||||
open let srcVar: Variable<String>
|
||||
open var src: String {
|
||||
get { return srcVar.value }
|
||||
set(val) { srcVar.value = val }
|
||||
var oldId: String?
|
||||
for key in imagesMap.keys {
|
||||
if image === imagesMap[key] {
|
||||
oldId = key
|
||||
}
|
||||
}
|
||||
|
||||
open let xAlignVar: Variable<Align>
|
||||
open var xAlign: Align {
|
||||
get { return xAlignVar.value }
|
||||
set(val) { xAlignVar.value = val }
|
||||
let id = oldId ?? UUID().uuidString
|
||||
imagesMap[id] = image
|
||||
|
||||
self.srcVar = Variable<String>("memory://\(id)")
|
||||
self.xAlignVar = Variable<Align>(xAlign)
|
||||
self.yAlignVar = Variable<Align>(yAlign)
|
||||
self.aspectRatioVar = Variable<AspectRatio>(aspectRatio)
|
||||
self.wVar = Variable<Int>(w)
|
||||
self.hVar = Variable<Int>(h)
|
||||
super.init(
|
||||
place: place,
|
||||
opaque: opaque,
|
||||
opacity: opacity,
|
||||
clip: clip,
|
||||
effect: effect,
|
||||
visible: visible,
|
||||
tag: tag
|
||||
)
|
||||
}
|
||||
|
||||
override func bounds() -> Rect? {
|
||||
if w != 0 && h != 0 {
|
||||
return Rect(x: 0.0, y: 0.0, w: Double(w), h: Double(h))
|
||||
}
|
||||
|
||||
open let yAlignVar: Variable<Align>
|
||||
open var yAlign: Align {
|
||||
get { return yAlignVar.value }
|
||||
set(val) { yAlignVar.value = val }
|
||||
mImage = image()
|
||||
|
||||
guard let mImage = mImage else {
|
||||
return .none
|
||||
}
|
||||
|
||||
open let aspectRatioVar: Variable<AspectRatio>
|
||||
open var aspectRatio: AspectRatio {
|
||||
get { return aspectRatioVar.value }
|
||||
set(val) { aspectRatioVar.value = val }
|
||||
return Rect(x: 0.0, y: 0.0,
|
||||
w: Double(mImage.size.width),
|
||||
h: Double(mImage.size.height))
|
||||
|
||||
}
|
||||
|
||||
func image() -> MImage? {
|
||||
|
||||
// image already loaded
|
||||
if let _ = mImage {
|
||||
return mImage
|
||||
}
|
||||
|
||||
open let wVar: Variable<Int>
|
||||
open var w: Int {
|
||||
get { return wVar.value }
|
||||
set(val) { wVar.value = val }
|
||||
// In-memory image
|
||||
if src.contains("memory") {
|
||||
let id = src.replacingOccurrences(of: "memory://", with: "")
|
||||
return imagesMap[id]
|
||||
}
|
||||
|
||||
open let hVar: Variable<Int>
|
||||
open var h: Int {
|
||||
get { return hVar.value }
|
||||
set(val) { hVar.value = val }
|
||||
// Base64 image
|
||||
if src.hasPrefix("data:image/png;base64,") {
|
||||
src = src.replacingOccurrences(of: "data:image/png;base64,", with: "")
|
||||
guard let decodedData = Data(base64Encoded: src, options: .ignoreUnknownCharacters) else {
|
||||
return .none
|
||||
}
|
||||
|
||||
return MImage(data: decodedData)
|
||||
}
|
||||
|
||||
private var uiImage: UIImage?
|
||||
|
||||
public init(src: String, 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] = []) {
|
||||
self.srcVar = Variable<String>(src)
|
||||
self.xAlignVar = Variable<Align>(xAlign)
|
||||
self.yAlignVar = Variable<Align>(yAlign)
|
||||
self.aspectRatioVar = Variable<AspectRatio>(aspectRatio)
|
||||
self.wVar = Variable<Int>(w)
|
||||
self.hVar = Variable<Int>(h)
|
||||
super.init(
|
||||
place: place,
|
||||
opaque: opaque,
|
||||
opacity: opacity,
|
||||
clip: clip,
|
||||
effect: effect,
|
||||
visible: visible,
|
||||
tag: tag
|
||||
)
|
||||
}
|
||||
|
||||
public init(image: UIImage, 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] {
|
||||
oldId = key
|
||||
}
|
||||
}
|
||||
|
||||
let id = oldId ?? UUID().uuidString
|
||||
imagesMap[id] = image
|
||||
|
||||
self.srcVar = Variable<String>("memory://\(id)")
|
||||
self.xAlignVar = Variable<Align>(xAlign)
|
||||
self.yAlignVar = Variable<Align>(yAlign)
|
||||
self.aspectRatioVar = Variable<AspectRatio>(aspectRatio)
|
||||
self.wVar = Variable<Int>(w)
|
||||
self.hVar = Variable<Int>(h)
|
||||
super.init(
|
||||
place: place,
|
||||
opaque: opaque,
|
||||
opacity: opacity,
|
||||
clip: clip,
|
||||
effect: effect,
|
||||
visible: visible,
|
||||
tag: tag
|
||||
)
|
||||
}
|
||||
|
||||
override func bounds() -> Rect? {
|
||||
if w != 0 && h != 0 {
|
||||
return Rect(x: 0.0, y: 0.0, w: Double(w), h: Double(h))
|
||||
}
|
||||
|
||||
uiImage = image()
|
||||
|
||||
guard let uiImage = uiImage else {
|
||||
return .none
|
||||
}
|
||||
|
||||
return Rect(x: 0.0, y: 0.0,
|
||||
w: Double(uiImage.size.width),
|
||||
h: Double(uiImage.size.height))
|
||||
|
||||
}
|
||||
|
||||
func image() -> UIImage? {
|
||||
|
||||
// image already loaded
|
||||
if let _ = uiImage {
|
||||
return uiImage
|
||||
}
|
||||
|
||||
// In-memory image
|
||||
if src.contains("memory") {
|
||||
let id = src.replacingOccurrences(of: "memory://", with: "")
|
||||
return imagesMap[id]
|
||||
}
|
||||
|
||||
// Base64 image
|
||||
if src.hasPrefix("data:image/png;base64,") {
|
||||
src = src.replacingOccurrences(of: "data:image/png;base64,", with: "")
|
||||
guard let decodedData = Data(base64Encoded: src, options: .ignoreUnknownCharacters) else {
|
||||
return .none
|
||||
}
|
||||
|
||||
return UIImage(data: decodedData)
|
||||
}
|
||||
|
||||
// General case
|
||||
return UIImage(named: src)
|
||||
}
|
||||
// General case
|
||||
return MImage(named: src)
|
||||
}
|
||||
}
|
||||
|
@ -7,16 +7,16 @@
|
||||
//
|
||||
|
||||
class SceneUtils {
|
||||
static func shapeCopy(from: Shape) -> Shape {
|
||||
return 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)
|
||||
}
|
||||
static func shapeCopy(from: Shape) -> Shape {
|
||||
return 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)
|
||||
}
|
||||
}
|
||||
|
@ -1,58 +1,57 @@
|
||||
import Foundation
|
||||
|
||||
open class Shape: Node {
|
||||
|
||||
open let formVar: AnimatableVariable<Locus>
|
||||
open var form: Locus {
|
||||
get { return formVar.value }
|
||||
set(val) { formVar.value = val }
|
||||
}
|
||||
|
||||
open let fillVar: AnimatableVariable<Fill?>
|
||||
open var fill: Fill? {
|
||||
get { return fillVar.value }
|
||||
set(val) { fillVar.value = val }
|
||||
}
|
||||
|
||||
open let strokeVar: AnimatableVariable<Stroke?>
|
||||
open var stroke: Stroke? {
|
||||
get { return strokeVar.value }
|
||||
set(val) { strokeVar.value = val }
|
||||
}
|
||||
|
||||
public init(form: Locus, fill: Fill? = nil, stroke: Stroke? = nil, place: Transform = Transform.identity, opaque: Bool = true, opacity: Double = 1, clip: Locus? = nil, effect: Effect? = nil, visible: Bool = true, tag: [String] = []) {
|
||||
self.formVar = AnimatableVariable<Locus>(form)
|
||||
self.fillVar = AnimatableVariable<Fill?>(fill)
|
||||
self.strokeVar = AnimatableVariable<Stroke?>(stroke)
|
||||
super.init(
|
||||
place: place,
|
||||
opaque: opaque,
|
||||
opacity: opacity,
|
||||
clip: clip,
|
||||
effect: effect,
|
||||
visible: visible,
|
||||
tag: tag
|
||||
)
|
||||
|
||||
open let formVar: AnimatableVariable<Locus>
|
||||
open var form: Locus {
|
||||
get { return formVar.value }
|
||||
set(val) { formVar.value = val }
|
||||
}
|
||||
|
||||
open let fillVar: AnimatableVariable<Fill?>
|
||||
open var fill: Fill? {
|
||||
get { return fillVar.value }
|
||||
set(val) { fillVar.value = val }
|
||||
}
|
||||
|
||||
open let strokeVar: AnimatableVariable<Stroke?>
|
||||
open var stroke: Stroke? {
|
||||
get { return strokeVar.value }
|
||||
set(val) { strokeVar.value = val }
|
||||
}
|
||||
|
||||
public init(form: Locus, fill: Fill? = nil, stroke: Stroke? = nil, place: Transform = Transform.identity, opaque: Bool = true, opacity: Double = 1, clip: Locus? = nil, effect: Effect? = nil, visible: Bool = true, tag: [String] = []) {
|
||||
self.formVar = AnimatableVariable<Locus>(form)
|
||||
self.fillVar = AnimatableVariable<Fill?>(fill)
|
||||
self.strokeVar = AnimatableVariable<Stroke?>(stroke)
|
||||
super.init(
|
||||
place: place,
|
||||
opaque: opaque,
|
||||
opacity: opacity,
|
||||
clip: clip,
|
||||
effect: effect,
|
||||
visible: visible,
|
||||
tag: tag
|
||||
)
|
||||
|
||||
self.formVar.node = self
|
||||
self.strokeVar.node = self
|
||||
self.fillVar.node = self
|
||||
}
|
||||
|
||||
// GENERATED NOT
|
||||
override internal func bounds() -> Rect? {
|
||||
var bounds = form.bounds()
|
||||
|
||||
if let shapeStroke = self.stroke {
|
||||
let r = shapeStroke.width / 2.0
|
||||
bounds = Rect(
|
||||
x: bounds.x - r,
|
||||
y: bounds.y - r,
|
||||
w: bounds.w + r * 2.0,
|
||||
h: bounds.h + r * 2.0)
|
||||
}
|
||||
|
||||
return bounds
|
||||
self.formVar.node = self
|
||||
self.strokeVar.node = self
|
||||
self.fillVar.node = self
|
||||
}
|
||||
|
||||
// GENERATED NOT
|
||||
override internal func bounds() -> Rect? {
|
||||
var bounds = form.bounds()
|
||||
|
||||
if let shapeStroke = self.stroke {
|
||||
let r = shapeStroke.width / 2.0
|
||||
bounds = Rect(
|
||||
x: bounds.x - r,
|
||||
y: bounds.y - r,
|
||||
w: bounds.w + r * 2.0,
|
||||
h: bounds.h + r * 2.0)
|
||||
}
|
||||
|
||||
return bounds
|
||||
}
|
||||
}
|
||||
|
@ -1,108 +1,115 @@
|
||||
import UIKit
|
||||
import Foundation
|
||||
|
||||
#if os(iOS)
|
||||
import UIKit
|
||||
#elseif os(OSX)
|
||||
import AppKit
|
||||
#endif
|
||||
|
||||
|
||||
open class Text: Node {
|
||||
|
||||
open let textVar: Variable<String>
|
||||
open var text: String {
|
||||
get { return textVar.value }
|
||||
set(val) { textVar.value = val }
|
||||
|
||||
open let textVar: Variable<String>
|
||||
open var text: String {
|
||||
get { return textVar.value }
|
||||
set(val) { textVar.value = val }
|
||||
}
|
||||
|
||||
open let fontVar: Variable<Font?>
|
||||
open var font: Font? {
|
||||
get { return fontVar.value }
|
||||
set(val) { fontVar.value = val }
|
||||
}
|
||||
|
||||
open let fillVar: Variable<Fill>
|
||||
open var fill: Fill {
|
||||
get { return fillVar.value }
|
||||
set(val) { fillVar.value = val }
|
||||
}
|
||||
|
||||
open let alignVar: Variable<Align>
|
||||
open var align: Align {
|
||||
get { return alignVar.value }
|
||||
set(val) { alignVar.value = val }
|
||||
}
|
||||
|
||||
open let baselineVar: Variable<Baseline>
|
||||
open var baseline: Baseline {
|
||||
get { return baselineVar.value }
|
||||
set(val) { baselineVar.value = val }
|
||||
}
|
||||
|
||||
public init(text: String, font: Font? = nil, fill: Fill = Color.black, align: Align = .min, baseline: Baseline = .top, place: Transform = Transform.identity, opaque: Bool = true, opacity: Double = 1, clip: Locus? = nil, effect: Effect? = nil, visible: Bool = true, tag: [String] = []) {
|
||||
self.textVar = Variable<String>(text)
|
||||
self.fontVar = Variable<Font?>(font)
|
||||
self.fillVar = Variable<Fill>(fill)
|
||||
self.alignVar = Variable<Align>(align)
|
||||
self.baselineVar = Variable<Baseline>(baseline)
|
||||
super.init(
|
||||
place: place,
|
||||
opaque: opaque,
|
||||
opacity: opacity,
|
||||
clip: clip,
|
||||
effect: effect,
|
||||
visible: visible,
|
||||
tag: tag
|
||||
)
|
||||
}
|
||||
|
||||
// GENERATED NOT
|
||||
override internal func bounds() -> Rect {
|
||||
let font: MFont
|
||||
if let f = self.font {
|
||||
|
||||
if let customFont = RenderUtils.loadFont(name: f.name, size:f.size) {
|
||||
font = customFont
|
||||
} else {
|
||||
font = MFont.systemFont(ofSize: CGFloat(f.size))
|
||||
}
|
||||
} else {
|
||||
font = MFont.systemFont(ofSize: MFont.mSystemFontSize)
|
||||
}
|
||||
|
||||
open let fontVar: Variable<Font?>
|
||||
open var font: Font? {
|
||||
get { return fontVar.value }
|
||||
set(val) { fontVar.value = val }
|
||||
var stringAttributes: [String: AnyObject] = [:]
|
||||
stringAttributes[NSFontAttributeName] = font
|
||||
let size = (text as NSString).size(attributes: stringAttributes)
|
||||
return Rect(
|
||||
x: calculateAlignmentOffset(font: font),
|
||||
y: calculateBaselineOffset(font: font),
|
||||
w: size.width.doubleValue,
|
||||
h: size.height.doubleValue
|
||||
)
|
||||
}
|
||||
|
||||
fileprivate func calculateBaselineOffset(font: MFont) -> Double {
|
||||
var baselineOffset = 0.0
|
||||
switch baseline {
|
||||
case .alphabetic:
|
||||
baselineOffset = font.ascender.doubleValue
|
||||
case .bottom:
|
||||
baselineOffset = (font.ascender - font.descender).doubleValue
|
||||
case .mid:
|
||||
baselineOffset = ((font.ascender - font.descender) / 2).doubleValue
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
open let fillVar: Variable<Fill>
|
||||
open var fill: Fill {
|
||||
get { return fillVar.value }
|
||||
set(val) { fillVar.value = val }
|
||||
return -baselineOffset
|
||||
}
|
||||
|
||||
fileprivate func calculateAlignmentOffset(font: MFont) -> Double {
|
||||
let textAttributes = [
|
||||
NSFontAttributeName: font
|
||||
]
|
||||
let textSize = NSString(string: text).size(attributes: textAttributes)
|
||||
var alignmentOffset = 0.0
|
||||
switch align {
|
||||
case .mid:
|
||||
alignmentOffset = (textSize.width / 2).doubleValue
|
||||
case .max:
|
||||
alignmentOffset = textSize.width.doubleValue
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
open let alignVar: Variable<Align>
|
||||
open var align: Align {
|
||||
get { return alignVar.value }
|
||||
set(val) { alignVar.value = val }
|
||||
}
|
||||
|
||||
open let baselineVar: Variable<Baseline>
|
||||
open var baseline: Baseline {
|
||||
get { return baselineVar.value }
|
||||
set(val) { baselineVar.value = val }
|
||||
}
|
||||
|
||||
public init(text: String, font: Font? = nil, fill: Fill = Color.black, align: Align = .min, baseline: Baseline = .top, place: Transform = Transform.identity, opaque: Bool = true, opacity: Double = 1, clip: Locus? = nil, effect: Effect? = nil, visible: Bool = true, tag: [String] = []) {
|
||||
self.textVar = Variable<String>(text)
|
||||
self.fontVar = Variable<Font?>(font)
|
||||
self.fillVar = Variable<Fill>(fill)
|
||||
self.alignVar = Variable<Align>(align)
|
||||
self.baselineVar = Variable<Baseline>(baseline)
|
||||
super.init(
|
||||
place: place,
|
||||
opaque: opaque,
|
||||
opacity: opacity,
|
||||
clip: clip,
|
||||
effect: effect,
|
||||
visible: visible,
|
||||
tag: tag
|
||||
)
|
||||
}
|
||||
|
||||
// GENERATED NOT
|
||||
override internal func bounds() -> Rect {
|
||||
let font: UIFont
|
||||
if let f = self.font {
|
||||
|
||||
if let customFont = RenderUtils.loadFont(name: f.name, size:f.size) {
|
||||
font = customFont
|
||||
} else {
|
||||
font = UIFont.systemFont(ofSize: CGFloat(f.size))
|
||||
}
|
||||
} else {
|
||||
font = UIFont.systemFont(ofSize: UIFont.systemFontSize)
|
||||
}
|
||||
var stringAttributes: [String: AnyObject] = [:]
|
||||
stringAttributes[NSFontAttributeName] = font
|
||||
let size = (text as NSString).size(attributes: stringAttributes)
|
||||
return Rect(
|
||||
x: calculateAlignmentOffset(font: font),
|
||||
y: calculateBaselineOffset(font: font),
|
||||
w: size.width.doubleValue,
|
||||
h: size.height.doubleValue
|
||||
)
|
||||
}
|
||||
|
||||
fileprivate func calculateBaselineOffset(font: UIFont) -> Double {
|
||||
var baselineOffset = 0.0
|
||||
switch baseline {
|
||||
case .alphabetic:
|
||||
baselineOffset = font.ascender.doubleValue
|
||||
case .bottom:
|
||||
baselineOffset = (font.ascender - font.descender).doubleValue
|
||||
case .mid:
|
||||
baselineOffset = ((font.ascender - font.descender) / 2).doubleValue
|
||||
default:
|
||||
break
|
||||
}
|
||||
return -baselineOffset
|
||||
}
|
||||
|
||||
fileprivate func calculateAlignmentOffset(font: UIFont) -> Double {
|
||||
let textAttributes = [
|
||||
NSFontAttributeName: font
|
||||
]
|
||||
let textSize = NSString(string: text).size(attributes: textAttributes)
|
||||
var alignmentOffset = 0.0
|
||||
switch align {
|
||||
case .mid:
|
||||
alignmentOffset = (textSize.width / 2).doubleValue
|
||||
case .max:
|
||||
alignmentOffset = textSize.width.doubleValue
|
||||
default:
|
||||
break
|
||||
}
|
||||
return -alignmentOffset
|
||||
}
|
||||
|
||||
return -alignmentOffset
|
||||
}
|
||||
|
||||
}
|
||||
|
89
Source/platform/iOS/Common_iOS.swift
Normal file
89
Source/platform/iOS/Common_iOS.swift
Normal file
@ -0,0 +1,89 @@
|
||||
//
|
||||
// Common_iOS.swift
|
||||
// Macaw
|
||||
//
|
||||
// Created by Daniil Manin on 8/10/17.
|
||||
// Copyright © 2017 Exyte. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
#if os(iOS)
|
||||
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 MPanGestureRecognizer = UIPanGestureRecognizer
|
||||
public typealias MPinchGestureRecognizer = UIPinchGestureRecognizer
|
||||
public typealias MRotationGestureRecognizer = UIRotationGestureRecognizer
|
||||
public typealias MScreen = UIScreen
|
||||
public typealias MDisplayLink = CADisplayLink
|
||||
public typealias MViewContentMode = UIViewContentMode
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
50
Source/platform/iOS/Graphics_iOS.swift
Normal file
50
Source/platform/iOS/Graphics_iOS.swift
Normal file
@ -0,0 +1,50 @@
|
||||
//
|
||||
// Graphics_iOS.swift
|
||||
// Macaw
|
||||
//
|
||||
// Created by Daniil Manin on 8/17/17.
|
||||
// Copyright © 2017 Exyte. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
#if os(iOS)
|
||||
import UIKit
|
||||
|
||||
func MGraphicsGetCurrentContext() -> CGContext? {
|
||||
return UIGraphicsGetCurrentContext()
|
||||
}
|
||||
|
||||
func MGraphicsGetImageFromCurrentImageContext() -> MImage! {
|
||||
return UIGraphicsGetImageFromCurrentImageContext()
|
||||
}
|
||||
|
||||
func MGraphicsPushContext(_ context: CGContext) {
|
||||
UIGraphicsPushContext(context)
|
||||
}
|
||||
|
||||
func MGraphicsPopContext() {
|
||||
UIGraphicsPopContext()
|
||||
}
|
||||
|
||||
func MGraphicsEndImageContext() {
|
||||
UIGraphicsEndImageContext()
|
||||
}
|
||||
|
||||
func MImagePNGRepresentation(_ image: MImage) -> Data? {
|
||||
return UIImagePNGRepresentation(image)
|
||||
}
|
||||
|
||||
func MImageJPEGRepresentation(_ image: MImage, _ quality: CGFloat = 0.8) -> Data? {
|
||||
return UIImageJPEGRepresentation(image, quality)
|
||||
}
|
||||
|
||||
func MMainScreen() -> MScreen? {
|
||||
return MScreen.main
|
||||
}
|
||||
|
||||
func MGraphicsBeginImageContextWithOptions(_ size: CGSize, _ opaque: Bool, _ scale: CGFloat) {
|
||||
UIGraphicsBeginImageContextWithOptions(size, opaque, scale)
|
||||
}
|
||||
|
||||
#endif
|
97
Source/platform/iOS/MView_iOS.swift
Normal file
97
Source/platform/iOS/MView_iOS.swift
Normal file
@ -0,0 +1,97 @@
|
||||
//
|
||||
// MView_iOS.swift
|
||||
// Macaw
|
||||
//
|
||||
// Created by Daniil Manin on 8/17/17.
|
||||
// Copyright © 2017 Exyte. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
#if os(iOS)
|
||||
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]) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
130
Source/platform/macOS/Common_macOS.swift
Normal file
130
Source/platform/macOS/Common_macOS.swift
Normal file
@ -0,0 +1,130 @@
|
||||
//
|
||||
// Common_macOS.swift
|
||||
// Macaw
|
||||
//
|
||||
// Created by Daniil Manin on 8/10/17.
|
||||
// Copyright © 2017 Exyte. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
#if os(OSX)
|
||||
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 = NSGestureRecognizerState
|
||||
public typealias MGestureRecognizerDelegate = NSGestureRecognizerDelegate
|
||||
public typealias MTapGestureRecognizer = NSClickGestureRecognizer
|
||||
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 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
|
||||
}
|
||||
}
|
||||
|
||||
func mLocationOfTouch(_ touch: Int, inView view: NSView?) -> NSPoint {
|
||||
return super.location(in: view)
|
||||
}
|
||||
}
|
||||
|
||||
extension NSFont {
|
||||
var lineHeight: CGFloat {
|
||||
return self.boundingRectForFont.size.height
|
||||
}
|
||||
|
||||
class var mSystemFontSize: CGFloat {
|
||||
return NSFont.systemFontSize()
|
||||
}
|
||||
}
|
||||
|
||||
extension NSScreen {
|
||||
var mScale: CGFloat {
|
||||
return self.backingScaleFactor
|
||||
}
|
||||
}
|
||||
|
||||
extension NSImage {
|
||||
var cgImage: CGImage? {
|
||||
return self.cgImage(forProposedRect: nil, context: nil, hints: nil)
|
||||
}
|
||||
}
|
||||
|
||||
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: [String : Any]? = nil) -> NSSize {
|
||||
return size(withAttributes: attrs)
|
||||
}
|
||||
}
|
||||
|
||||
func MMainScreen() -> MScreen? {
|
||||
return MScreen.main()
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
96
Source/platform/macOS/Graphics_macOS.swift
Normal file
96
Source/platform/macOS/Graphics_macOS.swift
Normal file
@ -0,0 +1,96 @@
|
||||
//
|
||||
// Graphics_macOS.swift
|
||||
// Macaw
|
||||
//
|
||||
// Created by Daniil Manin on 8/17/17.
|
||||
// Copyright © 2017 Exyte. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
#if os(OSX)
|
||||
import AppKit
|
||||
|
||||
private var imageContextStack: [CGFloat] = []
|
||||
|
||||
func MGraphicsGetCurrentContext() -> CGContext? {
|
||||
return NSGraphicsContext.current()?.cgContext
|
||||
}
|
||||
|
||||
func MGraphicsPushContext(_ context: CGContext) {
|
||||
let cx = NSGraphicsContext(cgContext: context, flipped: true)
|
||||
NSGraphicsContext.saveGraphicsState()
|
||||
NSGraphicsContext.setCurrent(cx)
|
||||
}
|
||||
|
||||
func MGraphicsPopContext() {
|
||||
NSGraphicsContext.restoreGraphicsState()
|
||||
}
|
||||
|
||||
func MImagePNGRepresentation(_ image: MImage) -> Data? {
|
||||
image.lockFocus()
|
||||
let rep = NSBitmapImageRep(focusedViewRect: NSMakeRect(0, 0, image.size.width, image.size.height))
|
||||
image.unlockFocus()
|
||||
|
||||
return rep?.representation(using: NSPNGFileType, properties: [:])
|
||||
}
|
||||
|
||||
func MImageJPEGRepresentation(_ image: MImage, _ quality: CGFloat = 0.9) -> Data? {
|
||||
image.lockFocus()
|
||||
let rep = NSBitmapImageRep(focusedViewRect: NSMakeRect(0, 0, image.size.width, image.size.height))
|
||||
image.unlockFocus()
|
||||
|
||||
return rep?.representation(using: NSJPEGFileType, properties: [NSImageCompressionFactor: quality])
|
||||
}
|
||||
|
||||
|
||||
func MGraphicsBeginImageContextWithOptions(_ size: CGSize, _ opaque: Bool, _ scale: CGFloat) {
|
||||
var scale = scale
|
||||
|
||||
if scale == 0.0 {
|
||||
scale = NSScreen.main()?.backingScaleFactor ?? 1.0
|
||||
}
|
||||
|
||||
let width = Int(size.width * scale)
|
||||
let height = Int(size.height * scale)
|
||||
|
||||
if width > 0 && height > 0 {
|
||||
imageContextStack.append(scale)
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
func MGraphicsGetImageFromCurrentImageContext() -> MImage? {
|
||||
if !imageContextStack.isEmpty {
|
||||
guard let ctx = MGraphicsGetCurrentContext() else {
|
||||
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()
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user