├── .gitignore ├── .swift-version ├── .swiftlint.yml ├── .travis.yml ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── ProcessingKit.podspec ├── ProcessingKit.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ ├── IDEWorkspaceChecks.plist │ │ └── WorkspaceSettings.xcsettings └── xcshareddata │ └── xcschemes │ ├── ProcessingKit OSX.xcscheme │ ├── ProcessingKit.xcscheme │ └── ProcessingKitTests.xcscheme ├── ProcessingKit.xctemplate ├── TemplateIcon.png ├── TemplateIcon@2x.png ├── TemplateInfo.plist └── ___FILEBASENAME___.swift ├── ProcessingKit ├── Core │ ├── Color │ │ └── Color.swift │ ├── Constants │ │ └── Constants.swift │ ├── Context │ │ └── Context.swift │ ├── Environment │ │ └── Frame.swift │ ├── Extensions │ │ ├── CGPoint.swift │ │ ├── NSImage.swift │ │ ├── NSView.swift │ │ ├── String.swift │ │ └── UIColor.swift │ ├── Image │ │ └── Image.swift │ ├── Input │ │ ├── Date.swift │ │ └── Gesture.swift │ ├── Shape │ │ ├── Shape.swift │ │ └── Vertex.swift │ ├── Structure │ │ └── Loop.swift │ ├── Transform │ │ └── Transform.swift │ └── Typography │ │ └── Text.swift ├── Demo.playground │ ├── Contents.swift │ └── contents.xcplayground ├── Info.plist ├── ProcessingKit.h ├── ProcessingView+Core │ ├── ProcessingView+Color.swift │ ├── ProcessingView+Constants.swift │ ├── ProcessingView+Date.swift │ ├── ProcessingView+Frame.swift │ ├── ProcessingView+Gesture.swift │ ├── ProcessingView+Image.swift │ ├── ProcessingView+Loop.swift │ ├── ProcessingView+Shape.swift │ ├── ProcessingView+Text.swift │ ├── ProcessingView+Transform.swift │ └── ProcessingView+Vertex.swift └── ProcessingView.swift ├── ProcessingKitExample ├── ProcessingKitExample.xcodeproj │ ├── project.pbxproj │ └── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist └── ProcessingKitExample │ ├── AppDelegate.swift │ ├── Assets.xcassets │ ├── AppIcon.appiconset │ │ ├── Contents.json │ │ ├── icon-20@2x.png │ │ ├── icon-20@3x.png │ │ ├── icon-29.png │ │ ├── icon-29@2x-1.png │ │ ├── icon-29@2x.png │ │ ├── icon-29@3x.png │ │ ├── icon-40.png │ │ ├── icon-40@2x-1.png │ │ ├── icon-40@2x.png │ │ ├── icon-40@3x.png │ │ ├── icon-60@2x.png │ │ ├── icon-60@3x.png │ │ ├── icon-76.png │ │ ├── icon-76@2x.png │ │ ├── icon-83.5@2x.png │ │ └── icon.png │ ├── Contents.json │ └── ProcessingKit-Logo.imageset │ │ ├── Contents.json │ │ └── ProcessingKit-Header.png │ ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard │ ├── BasicFunctions │ ├── ArcSampleView.swift │ ├── ArcSampleViewController.storyboard │ ├── ArcSampleViewController.swift │ ├── CurveSampleView.swift │ ├── CurveSampleViewController.storyboard │ ├── CurveSampleViewController.swift │ ├── EllipseSampleView.swift │ ├── EllipseSampleViewController.storyboard │ ├── EllipseSampleViewController.swift │ ├── ImageSampleView.swift │ ├── ImageSampleViewController.storyboard │ ├── ImageSampleViewController.swift │ ├── QuadSampleView.swift │ ├── QuadSampleViewController.storyboard │ ├── QuadSampleViewController.swift │ ├── RectSampleView.swift │ ├── RectSampleViewController.storyboard │ ├── RectSampleViewController.swift │ ├── TextSampleView.swift │ ├── TextSampleViewController.storyboard │ ├── TextSampleViewController.swift │ ├── TriangleSampleView.swift │ ├── TriangleSampleViewController.storyboard │ └── TriangleSampleViewController.swift │ ├── Extensions │ └── ViewController.swift │ ├── Info.plist │ ├── MainTableViewController.swift │ ├── OthersSample │ ├── ClockSampleView.swift │ ├── ClockSampleViewController.storyboard │ ├── ClockSampleViewController.swift │ ├── ParticlesSampleView.swift │ ├── ParticlesSampleViewController.storyboard │ └── ParticlesSampleViewController.swift │ └── TouchSample │ ├── TouchSampleView.swift │ ├── TouchSampleViewController.storyboard │ └── TouchSampleViewController.swift ├── ProcessingKitOSXExample ├── ProcessingKitOSXExample.xcodeproj │ ├── project.pbxproj │ └── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist ├── ProcessingKitOSXExample │ ├── AppDelegate.swift │ ├── Assets.xcassets │ │ └── AppIcon.appiconset │ │ │ └── Contents.json │ ├── Base.lproj │ │ └── Main.storyboard │ ├── CustomView.swift │ ├── Info.plist │ ├── ProcessingKitOSXExample.entitlements │ └── ViewController.swift └── ProcessingKitOSXExampleTests │ ├── Info.plist │ └── ProcessingKitOSXExampleTests.swift ├── ProcessingKitTests ├── CGPath+Extension │ └── CGPath+Extension.swift ├── GestureTests.swift ├── Info.plist ├── Input │ └── DateTests.swift ├── ProcessingViewDelegateSpy.swift ├── ProcessingViewTests.swift ├── ShapeTests.swift └── TransformTests.swift ├── README.md └── Resources ├── OSX_Example.gif ├── OSX_ExampleCode.png ├── ProcessingKit-Header.png ├── Storyboard-Usage.png ├── demo.gif ├── iOS_Example.gif └── iOS_ExampleCode.png /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## Build generated 6 | build/ 7 | DerivedData/ 8 | 9 | ## Various settings 10 | *.pbxuser 11 | !default.pbxuser 12 | *.mode1v3 13 | !default.mode1v3 14 | *.mode2v3 15 | !default.mode2v3 16 | *.perspectivev3 17 | !default.perspectivev3 18 | xcuserdata/ 19 | 20 | ## Other 21 | *.moved-aside 22 | *.xccheckout 23 | *.xcscmblueprint 24 | 25 | ## Obj-C/Swift specific 26 | *.hmap 27 | *.ipa 28 | *.dSYM.zip 29 | *.dSYM 30 | 31 | ## Playgrounds 32 | timeline.xctimeline 33 | playground.xcworkspace 34 | 35 | # Swift Package Manager 36 | # 37 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 38 | # Packages/ 39 | # Package.pins 40 | .build/ 41 | 42 | # CocoaPods 43 | # 44 | # We recommend against adding the Pods directory to your .gitignore. However 45 | # you should judge for yourself, the pros and cons are mentioned at: 46 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 47 | # 48 | # Pods/ 49 | 50 | # Carthage 51 | # 52 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 53 | # Carthage/Checkouts 54 | 55 | Carthage/Build 56 | 57 | # fastlane 58 | # 59 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 60 | # screenshots whenever they are needed. 61 | # For more information about the recommended setup visit: 62 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 63 | 64 | fastlane/report.xml 65 | fastlane/Preview.html 66 | fastlane/screenshots 67 | fastlane/test_output 68 | -------------------------------------------------------------------------------- /.swift-version: -------------------------------------------------------------------------------- 1 | 4.2.1 2 | -------------------------------------------------------------------------------- /.swiftlint.yml: -------------------------------------------------------------------------------- 1 | disabled_rules: # rule identifiers to exclude from running 2 | - force_cast 3 | - force_try 4 | - function_parameter_count 5 | - line_length 6 | - todo 7 | - trailing_comma 8 | - valid_docs 9 | - variable_name 10 | included: 11 | - ProcessingKit/ 12 | excluded: # paths to ignore during linting. 13 | type_body_length: 14 | - 400 # warning 15 | - 500 # error 16 | function_body_length: 17 | - 150 # warning 18 | - 200 # error 19 | file_length: 20 | warning: 600 # warning 21 | error: 1000 # error 22 | type_name: 23 | max_length: 24 | warning: 60 # warning 25 | error: 80 # error 26 | vertical_whitespace: 27 | severity: error 28 | trailing_newline: 29 | severity: error 30 | variable_name: 31 | min_length: # not possible to disable this partial rule, so set it to zero 32 | warning: 0 33 | error: 0 34 | max_length: 35 | warning: 60 # warning 36 | error: 80 # error 37 | excluded: 38 | - id 39 | - e 40 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | osx_image: xcode10.1 2 | language: objective-c 3 | branches: 4 | only: 5 | - master 6 | before_install: 7 | - gem install xcpretty 8 | before_script: 9 | - set -o pipefail 10 | script: 11 | - swiftlint 12 | - xcodebuild test -project ./ProcessingKit.xcodeproj -scheme ProcessingKitTests -configuration Debug -sdk iphonesimulator -destination 'platform=iOS Simulator,OS=12.0,name=iPhone X' | xcpretty -c 13 | - xcodebuild -project ./ProcessingKit.xcodeproj -scheme 'ProcessingKit OSX' -configuration Debug | xcpretty -c 14 | after_success: 15 | - bash <(curl -s https://codecov.io/bash) 16 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. 6 | 7 | ## Our Standards 8 | 9 | Examples of behavior that contributes to creating a positive environment include: 10 | 11 | * Using welcoming and inclusive language 12 | * Being respectful of differing viewpoints and experiences 13 | * Gracefully accepting constructive criticism 14 | * Focusing on what is best for the community 15 | * Showing empathy towards other community members 16 | 17 | Examples of unacceptable behavior by participants include: 18 | 19 | * The use of sexualized language or imagery and unwelcome sexual attention or advances 20 | * Trolling, insulting/derogatory comments, and personal or political attacks 21 | * Public or private harassment 22 | * Publishing others' private information, such as a physical or electronic address, without explicit permission 23 | * Other conduct which could reasonably be considered inappropriate in a professional setting 24 | 25 | ## Our Responsibilities 26 | 27 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. 28 | 29 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. 30 | 31 | ## Scope 32 | 33 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. 34 | 35 | ## Enforcement 36 | 37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at natmark0918@gmail.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. 38 | 39 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. 40 | 41 | ## Attribution 42 | 43 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] 44 | 45 | [homepage]: http://contributor-covenant.org 46 | [version]: http://contributor-covenant.org/version/1/4/ 47 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | When contributing to this repository, please first discuss the change you wish to make via issue, 4 | email, or any other method with the owners of this repository before making a change. 5 | 6 | Please note we have a code of conduct, please follow it in all your interactions with the project. 7 | 8 | ## Pull Request Process 9 | 10 | 1. Ensure any install or build dependencies are removed before the end of the layer when doing a 11 | build. 12 | 2. Update the README.md with details of changes to the interface, this includes new environment 13 | variables, exposed ports, useful file locations and container parameters. 14 | 3. Increase the version numbers in any examples files and the README.md to the new version that this 15 | Pull Request would represent. The versioning scheme we use is [SemVer](http://semver.org/). 16 | 4. You may merge the Pull Request in once you have the sign-off of two other developers, or if you 17 | do not have permission to do that, you may request the second reviewer to merge it for you. 18 | 19 | ## Code of Conduct 20 | 21 | ### Our Pledge 22 | 23 | In the interest of fostering an open and welcoming environment, we as 24 | contributors and maintainers pledge to making participation in our project and 25 | our community a harassment-free experience for everyone, regardless of age, body 26 | size, disability, ethnicity, gender identity and expression, level of experience, 27 | nationality, personal appearance, race, religion, or sexual identity and 28 | orientation. 29 | 30 | ### Our Standards 31 | 32 | Examples of behavior that contributes to creating a positive environment 33 | include: 34 | 35 | * Using welcoming and inclusive language 36 | * Being respectful of differing viewpoints and experiences 37 | * Gracefully accepting constructive criticism 38 | * Focusing on what is best for the community 39 | * Showing empathy towards other community members 40 | 41 | Examples of unacceptable behavior by participants include: 42 | 43 | * The use of sexualized language or imagery and unwelcome sexual attention or 44 | advances 45 | * Trolling, insulting/derogatory comments, and personal or political attacks 46 | * Public or private harassment 47 | * Publishing others' private information, such as a physical or electronic 48 | address, without explicit permission 49 | * Other conduct which could reasonably be considered inappropriate in a 50 | professional setting 51 | 52 | ### Our Responsibilities 53 | 54 | Project maintainers are responsible for clarifying the standards of acceptable 55 | behavior and are expected to take appropriate and fair corrective action in 56 | response to any instances of unacceptable behavior. 57 | 58 | Project maintainers have the right and responsibility to remove, edit, or 59 | reject comments, commits, code, wiki edits, issues, and other contributions 60 | that are not aligned to this Code of Conduct, or to ban temporarily or 61 | permanently any contributor for other behaviors that they deem inappropriate, 62 | threatening, offensive, or harmful. 63 | 64 | ### Scope 65 | 66 | This Code of Conduct applies both within project spaces and in public spaces 67 | when an individual is representing the project or its community. Examples of 68 | representing a project or community include using an official project e-mail 69 | address, posting via an official social media account, or acting as an appointed 70 | representative at an online or offline event. Representation of a project may be 71 | further defined and clarified by project maintainers. 72 | 73 | ### Enforcement 74 | 75 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 76 | reported by contacting the project team at natmark0918@gmail.com . All 77 | complaints will be reviewed and investigated and will result in a response that 78 | is deemed necessary and appropriate to the circumstances. The project team is 79 | obligated to maintain confidentiality with regard to the reporter of an incident. 80 | Further details of specific enforcement policies may be posted separately. 81 | 82 | Project maintainers who do not follow or enforce the Code of Conduct in good 83 | faith may face temporary or permanent repercussions as determined by other 84 | members of the project's leadership. 85 | 86 | ### Attribution 87 | 88 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 89 | available at [http://contributor-covenant.org/version/1/4][version] 90 | 91 | [homepage]: http://contributor-covenant.org 92 | [version]: http://contributor-covenant.org/version/1/4/ 93 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Atsuya Sato 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /ProcessingKit.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = "ProcessingKit" 3 | s.version = "1.5.0" 4 | s.summary = "Visual Designing library for iOS." 5 | s.description = <<-DESC 6 | ProcessingKit is a Visual Designing library for iOS. 7 | ProcessingKit written in Swift🐧 and you can write like processing. 8 | DESC 9 | s.homepage = "https://github.com/natmark/ProcessingKit" 10 | s.screenshots = "https://github.com/natmark/ProcessingKit/raw/master/Resources/ProcessingKit-Header.png?raw=true" 11 | s.license = { :type => "MIT", :file => "LICENSE" } 12 | s.author = { "Atsuya Sato" => "natmark0918@gmail.com" } 13 | s.osx.deployment_target = "10.11" 14 | s.ios.deployment_target = "10.0" 15 | s.source = { :git => "https://github.com/natmark/ProcessingKit.git", :tag => "#{s.version}" } 16 | s.source_files = "ProcessingKit/**/*.swift" 17 | s.exclude_files = "ProcessingKit/Demo.playground/*" 18 | s.ios.exclude_files = "ProcessingKit/Core/Extensions/NSImage.swift", "ProcessingKit/Core/Extensions/NSView.swift" 19 | s.requires_arc = true 20 | 21 | s.subspec "Core" do |subspec| 22 | subspec.source_files = "ProcessingKit/Core/**/*.swift" 23 | subspec.ios.exclude_files = "ProcessingKit/Core/Extensions/NSImage.swift", "ProcessingKit/Core/Extensions/NSView.swift" 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /ProcessingKit.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ProcessingKit.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ProcessingKit.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /ProcessingKit.xcodeproj/xcshareddata/xcschemes/ProcessingKit OSX.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 49 | 50 | 51 | 52 | 53 | 54 | 64 | 65 | 71 | 72 | 73 | 74 | 75 | 76 | 82 | 83 | 89 | 90 | 91 | 92 | 94 | 95 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /ProcessingKit.xcodeproj/xcshareddata/xcschemes/ProcessingKit.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 49 | 50 | 51 | 52 | 53 | 54 | 64 | 65 | 71 | 72 | 73 | 74 | 75 | 76 | 82 | 83 | 89 | 90 | 91 | 92 | 94 | 95 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /ProcessingKit.xcodeproj/xcshareddata/xcschemes/ProcessingKitTests.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 16 | 18 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 40 | 41 | 42 | 43 | 49 | 50 | 52 | 53 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /ProcessingKit.xctemplate/TemplateIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/natmark/ProcessingKit/0cc2a6fa90c69ba218df96644b0b496bf399b36a/ProcessingKit.xctemplate/TemplateIcon.png -------------------------------------------------------------------------------- /ProcessingKit.xctemplate/TemplateIcon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/natmark/ProcessingKit/0cc2a6fa90c69ba218df96644b0b496bf399b36a/ProcessingKit.xctemplate/TemplateIcon@2x.png -------------------------------------------------------------------------------- /ProcessingKit.xctemplate/TemplateInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | DefaultCompletionName 6 | SketchView 7 | Description 8 | A ProcessingKit sketch view class, with implementation and header files. 9 | Kind 10 | Xcode.IDEKit.TextSubstitutionFileTemplateKind 11 | MainTemplateFile 12 | ___FILEBASENAME___.swift 13 | Options 14 | 15 | 16 | Description 17 | The name of the class to create 18 | Identifier 19 | productName 20 | Default 21 | SketchView 22 | Name 23 | ProcessingKit sketch view class 24 | NotPersisted 25 | 26 | Required 27 | 28 | Type 29 | text 30 | 31 | 32 | Platforms 33 | 34 | com.apple.platform.iphoneos 35 | com.apple.platform.macosx 36 | 37 | Summary 38 | A ProcessingKit sketch view 39 | 40 | 41 | -------------------------------------------------------------------------------- /ProcessingKit.xctemplate/___FILEBASENAME___.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ___FILENAME___ 3 | // ___PROJECTNAME___ 4 | // 5 | // Created by ___FULLUSERNAME___ on ___DATE___. 6 | //___COPYRIGHT___ 7 | // 8 | 9 | #if os(iOS) 10 | import UIKit 11 | #elseif os(OSX) 12 | import Cocoa 13 | #endif 14 | 15 | import ProcessingKit 16 | 17 | class ___FILEBASENAMEASIDENTIFIER___: ProcessingView { 18 | func setup() { 19 | 20 | } 21 | 22 | func draw() { 23 | 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /ProcessingKit/Core/Color/Color.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Color.swift 3 | // ProcessingKit 4 | // 5 | // Created by AtsuyaSato on 2017/08/13. 6 | // Copyright © 2017年 Atsuya Sato. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | #if os(iOS) 12 | import UIKit 13 | #elseif os(OSX) 14 | import Cocoa 15 | #endif 16 | 17 | public protocol ColorComponentsContract { 18 | var fill: UIColor { get set } 19 | var stroke: UIColor { get set } 20 | var strokeWeight: CGFloat { get set } 21 | } 22 | 23 | public protocol ColorModelContract { 24 | func background(_ color: UIColor) 25 | func background(_ r: CGFloat, _ g: CGFloat, _ b: CGFloat, _ a: CGFloat) 26 | func clear() 27 | mutating func fill(_ color: UIColor) 28 | mutating func fill(_ r: CGFloat, _ g: CGFloat, _ b: CGFloat, _ a: CGFloat) 29 | mutating func stroke(_ color: UIColor) 30 | mutating func stroke(_ r: CGFloat, _ g: CGFloat, _ b: CGFloat, _ a: CGFloat) 31 | mutating func strokeWeight(_ weight: CGFloat) 32 | mutating func noFill() 33 | mutating func noStroke() 34 | } 35 | 36 | public class ColorComponents: ColorComponentsContract { 37 | public var fill: UIColor = UIColor.white 38 | public var stroke: UIColor = UIColor.clear 39 | public var strokeWeight: CGFloat = 1.0 40 | 41 | public init() {} 42 | } 43 | 44 | public struct ColorModel: ColorModelContract { 45 | private var contextComponents: ContextComponenetsContract 46 | private var colorComponents: ColorComponentsContract 47 | private var frameComponents: FrameComponentsContract 48 | 49 | public init(contextComponents: ContextComponenetsContract, colorComponents: ColorComponentsContract, frameComponents: FrameComponentsContract) { 50 | self.contextComponents = contextComponents 51 | self.colorComponents = colorComponents 52 | self.frameComponents = frameComponents 53 | } 54 | 55 | public func background(_ color: UIColor) { 56 | let context = self.contextComponents.context 57 | context?.clear(self.frameComponents.bounds) 58 | } 59 | 60 | public func background(_ r: CGFloat, _ g: CGFloat, _ b: CGFloat, _ a: CGFloat) { 61 | self.background(UIColor(red: r / 255.0, green: g / 255.0, blue: b / 255.0, alpha: a / 255.0)) 62 | } 63 | 64 | public func clear() { 65 | let context = self.contextComponents.context 66 | context?.clear(self.frameComponents.bounds) 67 | } 68 | 69 | public mutating func fill(_ color: UIColor) { 70 | self.colorComponents.fill = color 71 | } 72 | 73 | public mutating func fill(_ r: CGFloat, _ g: CGFloat, _ b: CGFloat, _ a: CGFloat) { 74 | self.fill(UIColor(red: r / 255.0, green: g / 255.0, blue: b / 255.0, alpha: a / 255.0)) 75 | } 76 | 77 | public mutating func stroke(_ color: UIColor) { 78 | self.colorComponents.stroke = color 79 | } 80 | 81 | public mutating func stroke(_ r: CGFloat, _ g: CGFloat, _ b: CGFloat, _ a: CGFloat) { 82 | self.stroke(UIColor(red: r / 255.0, green: g / 255.0, blue: b / 255.0, alpha: a / 255.0)) 83 | } 84 | 85 | public mutating func strokeWeight(_ weight: CGFloat) { 86 | self.colorComponents.strokeWeight = weight 87 | } 88 | 89 | public mutating func noFill() { 90 | self.colorComponents.fill = UIColor.clear 91 | } 92 | 93 | public mutating func noStroke() { 94 | self.colorComponents.stroke = UIColor.clear 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /ProcessingKit/Core/Constants/Constants.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Constants.swift 3 | // ProcessingKit 4 | // 5 | // Created by AtsuyaSato on 2017/08/13. 6 | // Copyright © 2017年 Atsuya Sato. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | #if os(iOS) 12 | import UIKit 13 | #elseif os(OSX) 14 | import Cocoa 15 | #endif 16 | 17 | public protocol Constants { 18 | var HALF_PI: CGFloat { get } 19 | var PI: CGFloat { get } 20 | var QUARTER_PI: CGFloat { get } 21 | var TAU: CGFloat { get } 22 | var TWO_PI: CGFloat { get } 23 | } 24 | -------------------------------------------------------------------------------- /ProcessingKit/Core/Context/Context.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Context.swift 3 | // ProcessingKit 4 | // 5 | // Created by AtsuyaSato on 2017/12/31. 6 | // Copyright © 2017年 Atsuya Sato. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | #if os(iOS) 12 | import UIKit 13 | #elseif os(OSX) 14 | import Cocoa 15 | public typealias UIColor = NSColor 16 | public typealias UIImageView = NSImageView 17 | public typealias UIImage = NSImage 18 | public typealias UIViewController = NSViewController 19 | public typealias UITouch = NSTouch 20 | public typealias UIFont = NSFont 21 | public typealias UIEvent = NSEvent 22 | public typealias UIView = NSView 23 | public typealias UIResponder = NSResponder 24 | public typealias CGRect = NSRect 25 | public typealias CGPoint = NSPoint 26 | #endif 27 | 28 | public protocol ContextComponenetsContract { 29 | var context: CGContext? { get } 30 | } 31 | 32 | public class ContextComponents: ContextComponenetsContract { 33 | public init() { 34 | } 35 | 36 | public var context: CGContext? { 37 | #if os(iOS) 38 | return UIGraphicsGetCurrentContext() 39 | #elseif os(OSX) 40 | return NSGraphicsContext.current?.cgContext 41 | #endif 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /ProcessingKit/Core/Environment/Frame.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Frame.swift 3 | // ProcessingKit 4 | // 5 | // Created by AtsuyaSato on 2017/08/13. 6 | // Copyright © 2017年 Atsuya Sato. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | #if os(iOS) 12 | import UIKit 13 | #elseif os(OSX) 14 | import Cocoa 15 | #endif 16 | 17 | public protocol FrameComponentsContract { 18 | var bounds: CGRect { get set } 19 | var frame: CGRect { get set } 20 | var frameRate: CGFloat { get set } 21 | var frameCount: UInt64 { get set } 22 | } 23 | 24 | public protocol FrameModelContract { 25 | var width: CGFloat { get } 26 | var height: CGFloat { get } 27 | var frameRate: CGFloat { get } 28 | mutating func frameRate(_ fps: CGFloat) 29 | } 30 | 31 | public class FrameComponents: FrameComponentsContract { 32 | public var bounds: CGRect = CGRect.zero 33 | public var frame: CGRect = CGRect.zero 34 | public var frameRate: CGFloat = 60.0 35 | public var frameCount: UInt64 = 0 36 | 37 | public init() {} 38 | } 39 | 40 | public struct FrameModel: FrameModelContract { 41 | private var frameComponents: FrameComponentsContract 42 | private var timer: Timer? 43 | 44 | public init(frameComponents: FrameComponentsContract, timer: Timer?) { 45 | self.frameComponents = frameComponents 46 | self.timer = timer 47 | } 48 | 49 | public var width: CGFloat { 50 | return self.frameComponents.bounds.size.width 51 | } 52 | 53 | public var height: CGFloat { 54 | return self.frameComponents.bounds.size.height 55 | } 56 | 57 | public var frameRate: CGFloat { 58 | return self.frameComponents.frameRate 59 | } 60 | 61 | public mutating func frameRate(_ fps: CGFloat) { 62 | self.frameComponents.frameRate = fps 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /ProcessingKit/Core/Extensions/CGPoint.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CGPoint.swift 3 | // ProcessingKit 4 | // 5 | // Created by AtsuyaSato on 2017/12/30. 6 | // Copyright © 2017年 Atsuya Sato. All rights reserved. 7 | // 8 | 9 | #if os(iOS) 10 | import UIKit 11 | #elseif os(OSX) 12 | import Cocoa 13 | #endif 14 | 15 | extension CGPoint: Hashable { 16 | func distance(point: CGPoint) -> Float { 17 | let dx = Float(x - point.x) 18 | let dy = Float(y - point.y) 19 | return sqrt((dx * dx) + (dy * dy)) 20 | } 21 | public var hashValue: Int { 22 | return x.hashValue << 32 ^ y.hashValue 23 | } 24 | } 25 | 26 | func == (lhs: CGPoint, rhs: CGPoint) -> Bool { 27 | return lhs.distance(point: rhs) < 0.000001 28 | } 29 | 30 | extension CGPoint { 31 | func addTo(_ a: CGPoint) -> CGPoint { 32 | return CGPoint(x: self.x + a.x, y: self.y + a.y) 33 | } 34 | 35 | func deltaTo(_ a: CGPoint) -> CGPoint { 36 | return CGPoint(x: self.x - a.x, y: self.y - a.y) 37 | } 38 | 39 | func multiplyBy(_ value: CGFloat) -> CGPoint { 40 | return CGPoint(x: self.x * value, y: self.y * value) 41 | } 42 | 43 | func length() -> CGFloat { 44 | return CGFloat(sqrt(CDouble( 45 | self.x*self.x + self.y*self.y 46 | ))) 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /ProcessingKit/Core/Extensions/NSImage.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NSImage.swift 3 | // ProcessingKit 4 | // 5 | // Created by AtsuyaSato on 2017/12/31. 6 | // Copyright © 2017年 Atsuya Sato. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | #if os(OSX) 12 | import Cocoa 13 | #endif 14 | 15 | extension NSImage { 16 | var cgImage: CGImage? { 17 | var imageRect = NSRect(x: 0, y: 0, width: size.width, height: size.height) 18 | #if swift(>=3.0) 19 | guard let image = cgImage(forProposedRect: &imageRect, context: nil, hints: nil) else { 20 | return nil 21 | } 22 | #else 23 | guard let image = CGImageForProposedRect(&imageRect, context: nil, hints: nil) else { 24 | return nil 25 | } 26 | #endif 27 | return image 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /ProcessingKit/Core/Extensions/NSView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NSView.swift 3 | // ProcessingKit 4 | // 5 | // Created by AtsuyaSato on 2017/12/31. 6 | // Copyright © 2017年 Atsuya Sato. All rights reserved. 7 | // 8 | 9 | #if os(OSX) 10 | import Cocoa 11 | #endif 12 | 13 | extension NSView { 14 | var backgroundColor: NSColor? { 15 | get { 16 | guard let layer = layer, let backgroundColor = layer.backgroundColor else {return nil} 17 | return NSColor(cgColor: backgroundColor) 18 | } 19 | set { 20 | wantsLayer = true 21 | layer?.backgroundColor = newValue?.cgColor 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /ProcessingKit/Core/Extensions/String.swift: -------------------------------------------------------------------------------- 1 | // 2 | // String.swift 3 | // ProcessingKit 4 | // 5 | // Created by AtsuyaSato on 2017/08/16. 6 | // Copyright © 2017年 Atsuya Sato. All rights reserved. 7 | // 8 | 9 | #if os(iOS) 10 | import UIKit 11 | #else 12 | import Cocoa 13 | #endif 14 | 15 | extension String { 16 | func height(withConstrainedWidth width: CGFloat, font: UIFont) -> CGFloat { 17 | let constraintRect = CGSize(width: width, height: .greatestFiniteMagnitude) 18 | let boundingBox = self.boundingRect(with: constraintRect, options: .usesLineFragmentOrigin, attributes: [NSAttributedString.Key.font: font], context: nil) 19 | 20 | return ceil(boundingBox.height) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /ProcessingKit/Core/Extensions/UIColor.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIColor.swift 3 | // ProcessingKit 4 | // 5 | // Created by AtsuyaSato on 2017/08/16. 6 | // Copyright © 2017年 Atsuya Sato. All rights reserved. 7 | // 8 | 9 | #if os(iOS) 10 | import UIKit 11 | #elseif os(OSX) 12 | import Cocoa 13 | #endif 14 | 15 | extension UIColor { 16 | class func hexStr (hexStr: NSString, alpha: CGFloat) -> UIColor { 17 | let alpha = alpha 18 | var hexStr = hexStr 19 | hexStr = hexStr.replacingOccurrences(of: "#", with: "") as NSString 20 | let scanner = Scanner(string: hexStr as String) 21 | var color: UInt32 = 0 22 | if scanner.scanHexInt32(&color) { 23 | let r = CGFloat((color & 0xFF0000) >> 16) / 255.0 24 | let g = CGFloat((color & 0x00FF00) >> 8) / 255.0 25 | let b = CGFloat(color & 0x0000FF) / 255.0 26 | return UIColor(red: r, green: g, blue: b, alpha: alpha) 27 | } else { 28 | print("invalid hex string") 29 | return UIColor.white 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /ProcessingKit/Core/Image/Image.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Image.swift 3 | // ProcessingKit 4 | // 5 | // Created by AtsuyaSato on 2017/08/16. 6 | // Copyright © 2017年 Atsuya Sato. All rights reserved. 7 | // 8 | 9 | #if os(iOS) 10 | import UIKit 11 | #elseif os(OSX) 12 | import Cocoa 13 | #endif 14 | 15 | public protocol ImageModelContract { 16 | #if os(iOS) 17 | func image(_ img: UIImage, _ x: CGFloat, _ y: CGFloat) 18 | func image(_ img: UIImage, _ x: CGFloat, _ y: CGFloat, _ width: CGFloat, _ height: CGFloat) 19 | #elseif os(OSX) 20 | func drawImage(_ img: NSImage, _ x: CGFloat, _ y: CGFloat) 21 | func drawImage(_ img: NSImage, _ x: CGFloat, _ y: CGFloat, _ width: CGFloat, _ height: CGFloat) 22 | #endif 23 | } 24 | 25 | public struct ImageModel: ImageModelContract { 26 | private var contextComponents: ContextComponenetsContract 27 | 28 | public init(contextComponents: ContextComponenetsContract) { 29 | self.contextComponents = contextComponents 30 | } 31 | 32 | #if os(iOS) 33 | public func image(_ img: UIImage, _ x: CGFloat, _ y: CGFloat) { 34 | let context = self.contextComponents.context 35 | context?.saveGState() 36 | context?.translateBy(x: 0.0, y: img.size.height) 37 | context?.scaleBy(x: 1.0, y: -1.0) 38 | if let cgImg = img.cgImage { 39 | context?.draw(cgImg, in: CGRect(x: x, y: y, width: img.size.width, height: img.size.height)) 40 | } 41 | context?.restoreGState() 42 | } 43 | 44 | public func image(_ img: UIImage, _ x: CGFloat, _ y: CGFloat, _ width: CGFloat, _ height: CGFloat) { 45 | let context = self.contextComponents.context 46 | context?.saveGState() 47 | context?.translateBy(x: 0.0, y: height) 48 | context?.scaleBy(x: 1.0, y: -1.0) 49 | if let cgImg = img.cgImage { 50 | context?.draw(cgImg, in: CGRect(x: x, y: -y, width: width, height: height)) 51 | } 52 | context?.restoreGState() 53 | } 54 | #elseif os(OSX) 55 | public func drawImage(_ img: NSImage, _ x: CGFloat, _ y: CGFloat) { 56 | let context = self.contextComponents.context 57 | context?.saveGState() 58 | context?.translateBy(x: 0.0, y: img.size.height) 59 | context?.scaleBy(x: 1.0, y: -1.0) 60 | if let cgImg = img.cgImage { 61 | context?.draw(cgImg, in: CGRect(x: x, y: y, width: img.size.width, height: img.size.height)) 62 | } 63 | context?.restoreGState() 64 | } 65 | 66 | public func drawImage(_ img: NSImage, _ x: CGFloat, _ y: CGFloat, _ width: CGFloat, _ height: CGFloat) { 67 | let context = self.contextComponents.context 68 | context?.saveGState() 69 | context?.translateBy(x: 0.0, y: height) 70 | context?.scaleBy(x: 1.0, y: -1.0) 71 | if let cgImg = img.cgImage { 72 | context?.draw(cgImg, in: CGRect(x: x, y: -y, width: width, height: height)) 73 | } 74 | context?.restoreGState() 75 | } 76 | #endif 77 | } 78 | -------------------------------------------------------------------------------- /ProcessingKit/Core/Input/Date.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Date.swift 3 | // ProcessingKit 4 | // 5 | // Created by AtsuyaSato on 2017/09/27. 6 | // Copyright © 2017年 Atsuya Sato. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public protocol DateModelContract { 12 | func millis() -> Int 13 | func second() -> Int 14 | func minute() -> Int 15 | func hour() -> Int 16 | func day() -> Int 17 | func month() -> Int 18 | func year() -> Int 19 | } 20 | 21 | public struct DateModel: DateModelContract { 22 | private var currentDate: Date? 23 | private var startDate: Date 24 | 25 | // for test 26 | public init(startDate: Date, currentDate: Date) { 27 | self.startDate = startDate 28 | self.currentDate = currentDate 29 | } 30 | 31 | public init(startDate: Date) { 32 | self.startDate = startDate 33 | } 34 | 35 | public func millis() -> Int { 36 | return self.getMillis() 37 | } 38 | 39 | public func second() -> Int { 40 | return self.getComponents().second ?? 0 41 | } 42 | 43 | public func minute() -> Int { 44 | return self.getComponents().minute ?? 0 45 | } 46 | 47 | public func hour() -> Int { 48 | return self.getComponents().hour ?? 0 49 | } 50 | 51 | public func day() -> Int { 52 | return self.getComponents().day ?? 0 53 | } 54 | 55 | public func month() -> Int { 56 | return self.getComponents().month ?? 0 57 | } 58 | 59 | public func year() -> Int { 60 | return self.getComponents().year ?? 0 61 | } 62 | 63 | private func getMillis() -> Int { 64 | let date = Date().timeIntervalSince(startDate) 65 | 66 | let intMax = Double(Int.max) 67 | if intMax <= date * 1000 { 68 | return -1 69 | } 70 | return Int(date * 1000) 71 | } 72 | 73 | private func getComponents() -> DateComponents { 74 | let calendar = Calendar.current 75 | let components = calendar.dateComponents([.year, .month, .day, .hour, .minute, .second], from: currentDate ?? Date()) 76 | return components 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /ProcessingKit/Core/Input/Gesture.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Gesture.swift 3 | // ProcessingKit 4 | // 5 | // Created by AtsuyaSato on 2018/10/07. 6 | // Copyright © 2018 Atsuya Sato. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | #if os(iOS) 12 | import UIKit 13 | #elseif os(OSX) 14 | import Cocoa 15 | #endif 16 | 17 | public enum GestureEvent { 18 | #if os(iOS) 19 | case didTap 20 | case didRelease 21 | case didDrag 22 | case didSwipe(direction: UISwipeGestureRecognizer.Direction) 23 | case didPinch(scale: CGFloat, velocity: CGFloat) 24 | case didRotate(rotation: CGFloat, velocity: CGFloat) 25 | case didLongPress 26 | #elseif os(OSX) 27 | case didClick 28 | case didRelease 29 | case didDrag 30 | case didMove 31 | case didMagnify(magnification: CGFloat) 32 | case didRotate(rotation: CGFloat, inDegrees: CGFloat) 33 | case didPress 34 | case didScroll(x: CGFloat, y: CGFloat) 35 | #endif 36 | } 37 | 38 | public protocol GestureComponentsContract { 39 | var delegateEvents: [GestureEvent] { get set } 40 | #if os(iOS) 41 | var isPressed: Bool { get set } 42 | var touchX: CGFloat { get set } 43 | var touchY: CGFloat { get set } 44 | var touches: Set { get set } 45 | #elseif os(OSX) 46 | var isPressed: Bool { get set } 47 | var mouseX: CGFloat { get set } 48 | var mouseY: CGFloat { get set } 49 | #endif 50 | } 51 | 52 | public protocol GestureModelContract { 53 | #if os(iOS) 54 | var fingerPressed: Bool { get } 55 | var touchX: CGFloat { get } 56 | var touchY: CGFloat { get } 57 | var touches: Set { get } 58 | 59 | mutating func didTap(recognizer: UITapGestureRecognizer) 60 | mutating func didTapExit(recognizer: UITapGestureRecognizer) 61 | mutating func didPan(recognizer: UIPanGestureRecognizer) 62 | 63 | mutating func didSwipe(recognizer: UISwipeGestureRecognizer) 64 | mutating func didPinch(recognizer: UIPinchGestureRecognizer) 65 | mutating func didRotate(recognizer: UIRotationGestureRecognizer) 66 | mutating func didLongPress(recognizer: UILongPressGestureRecognizer) 67 | 68 | mutating func touchesBegan(_ touches: Set) 69 | mutating func touchesMoved(_ touches: Set) 70 | mutating func touchesEnded(_ touches: Set) 71 | #elseif os(OSX) 72 | var mousePressed: Bool { get } 73 | var mouseX: CGFloat { get } 74 | var mouseY: CGFloat { get } 75 | 76 | mutating func didClick(recognizer: NSClickGestureRecognizer) 77 | mutating func didClickExit(recognizer: NSClickGestureRecognizer) 78 | mutating func didMagnify(recognizer: NSMagnificationGestureRecognizer) 79 | mutating func didPan(recognizer: NSPanGestureRecognizer) 80 | mutating func didPress(recognizer: NSPressGestureRecognizer) 81 | mutating func didRotate(recognizer: NSRotationGestureRecognizer) 82 | 83 | mutating func scrollWheel(with event: NSEvent) 84 | mutating func mouseMoved(with event: NSEvent) 85 | 86 | mutating func mouseDown(_ location: NSPoint) 87 | mutating func mouseDragged(_ location: NSPoint) 88 | mutating func mouseUp(_ location: NSPoint) 89 | mutating func mouseMoved(_ location: NSPoint) 90 | #endif 91 | } 92 | 93 | public class GestureComponents: GestureComponentsContract { 94 | public var delegateEvents: [GestureEvent] = [] 95 | 96 | #if os(iOS) 97 | public var isPressed = false 98 | public var touchX: CGFloat = 0.0 99 | public var touchY: CGFloat = 0.0 100 | public var touches: Set = [] 101 | #elseif os(OSX) 102 | public var isPressed: Bool = false 103 | public var mouseX: CGFloat = 0.0 104 | public var mouseY: CGFloat = 0.0 105 | #endif 106 | 107 | public init() {} 108 | } 109 | 110 | public struct GestureModel: GestureModelContract { 111 | private var gestureComponents: GestureComponentsContract 112 | private var frameComponents: FrameComponentsContract 113 | 114 | public init(gestureComponents: GestureComponentsContract, 115 | frameComponents: FrameComponentsContract) { 116 | self.gestureComponents = gestureComponents 117 | self.frameComponents = frameComponents 118 | } 119 | 120 | #if os(iOS) 121 | public var fingerPressed: Bool { 122 | return self.gestureComponents.isPressed 123 | } 124 | 125 | public var touchX: CGFloat { 126 | return self.gestureComponents.touches.first?.x ?? 0.0 127 | } 128 | 129 | public var touchY: CGFloat { 130 | return self.gestureComponents.touches.first?.y ?? 0.0 131 | } 132 | 133 | public var touches: Set { 134 | return self.gestureComponents.touches 135 | } 136 | #elseif os(OSX) 137 | public var mousePressed: Bool { 138 | return self.gestureComponents.isPressed 139 | } 140 | 141 | public var mouseX: CGFloat { 142 | return self.gestureComponents.mouseX 143 | } 144 | 145 | public var mouseY: CGFloat { 146 | return self.gestureComponents.mouseY 147 | } 148 | #endif 149 | 150 | #if os(iOS) 151 | public mutating func touchesBegan(_ touches: Set) { 152 | self.gestureComponents.touches = touches 153 | self.gestureComponents.isPressed = true 154 | } 155 | 156 | public mutating func touchesMoved(_ touches: Set) { 157 | self.gestureComponents.touches = touches 158 | } 159 | 160 | public mutating func touchesEnded(_ touches: Set) { 161 | self.gestureComponents.touches.removeAll() 162 | self.gestureComponents.isPressed = false 163 | } 164 | 165 | public mutating func didTap(recognizer: UITapGestureRecognizer) { 166 | self.touchesBegan(self.touchesFrom(recognizer: recognizer)) 167 | self.gestureComponents.delegateEvents.append(.didTap) 168 | } 169 | public mutating func didTapExit(recognizer: UITapGestureRecognizer) { 170 | self.touchesEnded(self.touchesFrom(recognizer: recognizer)) 171 | } 172 | public mutating func didPan(recognizer: UIPanGestureRecognizer) { 173 | self.handleTap(recognizer: recognizer) 174 | self.gestureComponents.delegateEvents.append(.didDrag) 175 | } 176 | public mutating func didSwipe(recognizer: UISwipeGestureRecognizer) { 177 | self.gestureComponents.delegateEvents.append(.didSwipe(direction: recognizer.direction)) 178 | } 179 | public mutating func didPinch(recognizer: UIPinchGestureRecognizer) { 180 | self.handleTap(recognizer: recognizer) 181 | self.gestureComponents.delegateEvents.append(.didPinch(scale: recognizer.scale, velocity: recognizer.velocity)) 182 | } 183 | public mutating func didRotate(recognizer: UIRotationGestureRecognizer) { 184 | self.handleTap(recognizer: recognizer) 185 | self.gestureComponents.delegateEvents.append(.didRotate(rotation: recognizer.rotation, velocity: recognizer.velocity)) 186 | } 187 | public mutating func didLongPress(recognizer: UILongPressGestureRecognizer) { 188 | self.handleTap(recognizer: recognizer) 189 | self.gestureComponents.delegateEvents.append(.didLongPress) 190 | } 191 | 192 | private mutating func handleTap(recognizer: UIGestureRecognizer) { 193 | switch recognizer.state { 194 | case .possible: return 195 | case .began: 196 | self.touchesBegan(touchesFrom(recognizer: recognizer)) 197 | case .changed: 198 | self.touchesMoved(touchesFrom(recognizer: recognizer)) 199 | case .ended: 200 | self.touchesEnded(touchesFrom(recognizer: recognizer)) 201 | case .cancelled: 202 | self.touchesEnded(touchesFrom(recognizer: recognizer)) 203 | case .failed: 204 | self.touchesEnded(touchesFrom(recognizer: recognizer)) 205 | } 206 | } 207 | 208 | private func touchesFrom(recognizer: UIGestureRecognizer) -> Set { 209 | var touches = Set() 210 | for i in 0.. NSPoint { 286 | return recognizer.location(in: recognizer.view) 287 | } 288 | 289 | private func convertCoordinateSystem(location: NSPoint) -> NSPoint { 290 | let height = frameComponents.frame.size.height 291 | // MARK: Coordinate systems are different between iOS and OS X 292 | return NSPoint(x: location.x, y: height - location.y) 293 | } 294 | #endif 295 | } 296 | -------------------------------------------------------------------------------- /ProcessingKit/Core/Shape/Shape.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Graphics.swift 3 | // ProcessingKit 4 | // 5 | // Created by AtsuyaSato on 2017/08/09. 6 | // Copyright © 2017年 Atsuya Sato. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | #if os(iOS) 12 | import UIKit 13 | #elseif os(OSX) 14 | import Cocoa 15 | #endif 16 | 17 | public protocol ShapeModelContract { 18 | func point(_ x: CGFloat, _ y: CGFloat) 19 | func line(_ x1: CGFloat, _ y1: CGFloat, _ x2: CGFloat, _ y2: CGFloat) 20 | func rect(_ x: CGFloat, _ y: CGFloat, _ width: CGFloat, _ height: CGFloat) 21 | func rect(_ x: CGFloat, _ y: CGFloat, _ width: CGFloat, _ height: CGFloat, _ radius: CGFloat) 22 | func rect(_ x: CGFloat, _ y: CGFloat, _ width: CGFloat, _ height: CGFloat, _ topLeftRadius: CGFloat, _ topRightRadius: CGFloat, _ bottomLeftRadius: CGFloat, _ bottomRightRadius: CGFloat) 23 | func ellipse(_ x: CGFloat, _ y: CGFloat, _ width: CGFloat, _ height: CGFloat) 24 | func arc(_ x: CGFloat, _ y: CGFloat, _ radius: CGFloat, _ start: CGFloat, _ stop: CGFloat) 25 | func triangle(_ x1: CGFloat, _ y1: CGFloat, _ x2: CGFloat, _ y2: CGFloat, _ x3: CGFloat, _ y3: CGFloat) 26 | func quad(_ x1: CGFloat, _ y1: CGFloat, _ x2: CGFloat, _ y2: CGFloat, _ x3: CGFloat, _ y3: CGFloat, _ x4: CGFloat, _ y4: CGFloat) 27 | func curve(_ cpx1: CGFloat, _ cpy1: CGFloat, _ x1: CGFloat, _ y1: CGFloat, _ x2: CGFloat, _ y2: CGFloat, _ cpx2: CGFloat, _ cpy2: CGFloat) 28 | func bezier(_ x1: CGFloat, _ y1: CGFloat, _ cpx1: CGFloat, _ cpy1: CGFloat, _ cpx2: CGFloat, _ cpy2: CGFloat, _ x2: CGFloat, _ y2: CGFloat) 29 | func radians(_ degrees: CGFloat) -> CGFloat 30 | } 31 | 32 | public struct ShapeModel: ShapeModelContract { 33 | private var colorComponents: ColorComponentsContract 34 | private var contextComponents: ContextComponenetsContract 35 | 36 | public init(contextComponents: ContextComponenetsContract, colorComponents: ColorComponentsContract) { 37 | self.contextComponents = contextComponents 38 | self.colorComponents = colorComponents 39 | } 40 | 41 | public func point(_ x: CGFloat, _ y: CGFloat) { 42 | let context = self.contextComponents.context 43 | context?.setFillColor(self.colorComponents.stroke.cgColor) 44 | 45 | drawing(mode: .fill) { 46 | let width = self.colorComponents.strokeWeight 47 | let height = self.colorComponents.strokeWeight 48 | context?.addEllipse(in: CGRect(x: x - width / 2, y: y - height / 2, width: width, height: height)) 49 | } 50 | } 51 | 52 | public func line(_ x1: CGFloat, _ y1: CGFloat, _ x2: CGFloat, _ y2: CGFloat) { 53 | let context = self.contextComponents.context 54 | setGraphicsConfiguration(context: context) 55 | 56 | drawing(mode: .stroke) { 57 | context?.move(to: CGPoint(x: x1, y: y1)) 58 | context?.addLine(to: CGPoint(x: x2, y: y2)) 59 | } 60 | } 61 | 62 | public func rect(_ x: CGFloat, _ y: CGFloat, _ width: CGFloat, _ height: CGFloat) { 63 | let context = self.contextComponents.context 64 | setGraphicsConfiguration(context: context) 65 | 66 | drawing(mode: .fillStroke) { 67 | context?.addRect(CGRect(x: x, y: y, width: width, height: height)) 68 | } 69 | } 70 | 71 | public func rect(_ x: CGFloat, _ y: CGFloat, _ width: CGFloat, _ height: CGFloat, _ radius: CGFloat) { 72 | self.rect(x, y, width, height, radius, radius, radius, radius) 73 | } 74 | 75 | public func rect(_ x: CGFloat, _ y: CGFloat, _ width: CGFloat, _ height: CGFloat, _ topLeftRadius: CGFloat, _ topRightRadius: CGFloat, _ bottomLeftRadius: CGFloat, _ bottomRightRadius: CGFloat) { 76 | let context = self.contextComponents.context 77 | setGraphicsConfiguration(context: context) 78 | 79 | var topLeftRadius = topLeftRadius 80 | var topRightRadius = topRightRadius 81 | var bottomLeftRadius = bottomLeftRadius 82 | var bottomRightRadius = bottomRightRadius 83 | if topLeftRadius > min(width, height) / 2 { 84 | topLeftRadius = min(width, height) / 2 85 | } 86 | if topRightRadius > min(width, height) / 2 { 87 | topRightRadius = min(width, height) / 2 88 | } 89 | if bottomLeftRadius > min(width, height) / 2 { 90 | bottomLeftRadius = min(width, height) / 2 91 | } 92 | if bottomRightRadius > min(width, height) / 2 { 93 | bottomRightRadius = min(width, height) / 2 94 | } 95 | 96 | drawing(mode: .fillStroke) { 97 | context?.beginPath() 98 | context?.move(to: CGPoint(x: x + topLeftRadius, y: y)) 99 | 100 | context?.addLine(to: CGPoint(x: x + width - topRightRadius, y: y)) 101 | context?.addArc(center: CGPoint(x: x + width - topRightRadius, y: y + topRightRadius), radius: topRightRadius, startAngle: radians(-90), endAngle: radians(0), clockwise: false) 102 | 103 | context?.addLine(to: CGPoint(x: x + width, y: y + height - bottomRightRadius)) 104 | context?.addArc(center: CGPoint(x: x + width - bottomRightRadius, y: y + height - bottomRightRadius), radius: bottomRightRadius, startAngle: radians(0), endAngle: radians(90), clockwise: false) 105 | 106 | context?.addLine(to: CGPoint(x: x + bottomLeftRadius, y: y + height)) 107 | context?.addArc(center: CGPoint(x: x + bottomLeftRadius, y: y + height - bottomLeftRadius), radius: bottomLeftRadius, startAngle: radians(90), endAngle: radians(180), clockwise: false) 108 | 109 | context?.addLine(to: CGPoint(x: x, y: y + topLeftRadius)) 110 | context?.addArc(center: CGPoint(x: x + topLeftRadius, y: y + topLeftRadius), radius: topLeftRadius, startAngle: radians(180), endAngle: radians(270), clockwise: false) 111 | 112 | context?.closePath() 113 | } 114 | } 115 | 116 | public func ellipse(_ x: CGFloat, _ y: CGFloat, _ width: CGFloat, _ height: CGFloat) { 117 | let context = self.contextComponents.context 118 | setGraphicsConfiguration(context: context) 119 | 120 | drawing(mode: .fillStroke) { 121 | context?.addEllipse(in: CGRect(x: x - width / 2, y: y - height / 2, width: width, height: height)) 122 | } 123 | } 124 | 125 | public func arc(_ x: CGFloat, _ y: CGFloat, _ radius: CGFloat, _ start: CGFloat, _ stop: CGFloat) { 126 | let context = self.contextComponents.context 127 | setGraphicsConfiguration(context: context) 128 | 129 | drawing(mode: .fillStroke) { 130 | context?.addArc(center: CGPoint(x: x, y: y), radius: radius, startAngle: start, endAngle: stop, clockwise: false) 131 | } 132 | } 133 | 134 | public func triangle(_ x1: CGFloat, _ y1: CGFloat, _ x2: CGFloat, _ y2: CGFloat, _ x3: CGFloat, _ y3: CGFloat) { 135 | let context = self.contextComponents.context 136 | setGraphicsConfiguration(context: context) 137 | 138 | drawing(mode: .fillStroke) { 139 | context?.beginPath() 140 | context?.move(to: CGPoint(x: x1, y: y1)) 141 | context?.addLine(to: CGPoint(x: x2, y: y2)) 142 | context?.addLine(to: CGPoint(x: x3, y: y3)) 143 | context?.closePath() 144 | } 145 | } 146 | 147 | public func quad(_ x1: CGFloat, _ y1: CGFloat, _ x2: CGFloat, _ y2: CGFloat, _ x3: CGFloat, _ y3: CGFloat, _ x4: CGFloat, _ y4: CGFloat) { 148 | let context = self.contextComponents.context 149 | setGraphicsConfiguration(context: context) 150 | 151 | drawing(mode: .fillStroke) { 152 | context?.beginPath() 153 | context?.move(to: CGPoint(x: x1, y: y1)) 154 | context?.addLine(to: CGPoint(x: x2, y: y2)) 155 | context?.addLine(to: CGPoint(x: x3, y: y3)) 156 | context?.addLine(to: CGPoint(x: x4, y: y4)) 157 | context?.closePath() 158 | } 159 | } 160 | 161 | public func curve(_ cpx1: CGFloat, _ cpy1: CGFloat, _ x1: CGFloat, _ y1: CGFloat, _ x2: CGFloat, _ y2: CGFloat, _ cpx2: CGFloat, _ cpy2: CGFloat) { 162 | let context = self.contextComponents.context 163 | setGraphicsConfiguration(context: context) 164 | 165 | let (b1, b2) = ShapeModel.convertCurvePoint(cpx1, cpy1, x1, y1, x2, y2, cpx2, cpy2) 166 | 167 | drawing(mode: .fillStroke) { 168 | context?.move(to: CGPoint(x: x1, y: y1)) 169 | context?.addCurve(to: CGPoint(x: x2, y: y2), control1: CGPoint(x: b1.x, y: b1.y), control2: CGPoint(x: b2.x, y: b2.y)) 170 | } 171 | } 172 | 173 | public func bezier(_ x1: CGFloat, _ y1: CGFloat, _ cpx1: CGFloat, _ cpy1: CGFloat, _ cpx2: CGFloat, _ cpy2: CGFloat, _ x2: CGFloat, _ y2: CGFloat) { 174 | let context = self.contextComponents.context 175 | setGraphicsConfiguration(context: context) 176 | 177 | drawing(mode: .fillStroke) { 178 | context?.move(to: CGPoint(x: x1, y: y1)) 179 | context?.addCurve(to: CGPoint(x: x2, y: y2), control1: CGPoint(x: cpx1, y: cpy1), control2: CGPoint(x: cpx2, y: cpy2)) 180 | } 181 | } 182 | 183 | public func radians(_ degrees: CGFloat) -> CGFloat { 184 | let radian = (CGFloat.pi * 2) * (degrees / 360.0) 185 | return radian 186 | } 187 | 188 | // For testing 189 | static func convertCurvePoint(_ cpx1: CGFloat, _ cpy1: CGFloat, _ x1: CGFloat, _ y1: CGFloat, _ x2: CGFloat, _ y2: CGFloat, _ cpx2: CGFloat, _ cpy2: CGFloat) -> (CGPoint, CGPoint) { 190 | let alpha: CGFloat = 1.0 191 | let p0 = CGPoint(x: cpx1, y: cpy1) 192 | let p1 = CGPoint(x: x1, y: y1) 193 | let p2 = CGPoint(x: x2, y: y2) 194 | let p3 = CGPoint(x: cpx2, y: cpy2) 195 | 196 | let d1 = p1.deltaTo(p0).length() 197 | let d2 = p2.deltaTo(p1).length() 198 | let d3 = p3.deltaTo(p2).length() 199 | 200 | var b1 = p2.multiplyBy(pow(d1, 2 * alpha)) 201 | b1 = b1.deltaTo(p0.multiplyBy(pow(d2, 2 * alpha))) 202 | b1 = b1.addTo(p1.multiplyBy(2 * pow(d1, 2 * alpha) + 3 * pow(d1, alpha) * pow(d2, alpha) + pow(d2, 2 * alpha))) 203 | b1 = b1.multiplyBy(1.0 / (3 * pow(d1, alpha) * (pow(d1, alpha) + pow(d2, alpha)))) 204 | 205 | var b2 = p1.multiplyBy(pow(d3, 2 * alpha)) 206 | b2 = b2.deltaTo(p3.multiplyBy(pow(d2, 2 * alpha))) 207 | b2 = b2.addTo(p2.multiplyBy(2 * pow(d3, 2 * alpha) + 3 * pow(d3, alpha) * pow(d2, alpha) + pow(d2, 2 * alpha))) 208 | b2 = b2.multiplyBy(1.0 / (3 * pow(d3, alpha) * (pow(d3, alpha) + pow(d2, alpha)))) 209 | 210 | return (b1, b2) 211 | } 212 | 213 | private func setGraphicsConfiguration(context: CGContext?) { 214 | context?.setFillColor(self.colorComponents.fill.cgColor) 215 | context?.setStrokeColor(self.colorComponents.stroke.cgColor) 216 | context?.setLineWidth(self.colorComponents.strokeWeight) 217 | } 218 | 219 | private func drawing(mode: CGPathDrawingMode, closure:() -> Void) { 220 | let context = self.contextComponents.context 221 | context?.saveGState() 222 | closure() 223 | 224 | // do not execute this line when testing to protect path infomation 225 | if !isTesting() { 226 | context?.drawPath(using: mode) 227 | } 228 | 229 | context?.restoreGState() 230 | } 231 | 232 | private func isTesting() -> Bool { 233 | return ProcessInfo.processInfo.environment["XCTestConfigurationFilePath"] != nil 234 | } 235 | } 236 | -------------------------------------------------------------------------------- /ProcessingKit/Core/Shape/Vertex.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Vertex.swift 3 | // ProcessingKit 4 | // 5 | // Created by AtsuyaSato on 2017/09/27. 6 | // Copyright © 2017年 Atsuya Sato. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | #if os(iOS) 12 | import UIKit 13 | #elseif os(OSX) 14 | import Cocoa 15 | #endif 16 | 17 | public enum BeginShapeKind { 18 | case points 19 | case lines 20 | case triangles 21 | case quads 22 | case none 23 | } 24 | 25 | public enum EndShapeMode { 26 | case close 27 | case none 28 | } 29 | 30 | public protocol VertexComponentsContract { 31 | var vertexes: [CGPoint] { get set } 32 | var kind: BeginShapeKind { get set } 33 | } 34 | 35 | public protocol VertexModelContract { 36 | mutating func beginShape(_ kind: BeginShapeKind) 37 | mutating func endShape(_ mode: EndShapeMode) 38 | mutating func vertex(_ x: CGFloat, _ y: CGFloat) 39 | } 40 | 41 | public class VertexComponents: VertexComponentsContract { 42 | public var vertexes: [CGPoint] = [] 43 | public var kind: BeginShapeKind = .none 44 | 45 | public init() {} 46 | } 47 | 48 | public struct VertexModel: VertexModelContract { 49 | private var contextComponents: ContextComponenetsContract 50 | private var vertexComponents: VertexComponentsContract 51 | private var colorComponents: ColorComponentsContract 52 | 53 | public init(contextComponents: ContextComponenetsContract, vertexComponents: VertexComponentsContract, colorComponents: ColorComponentsContract) { 54 | self.contextComponents = contextComponents 55 | self.vertexComponents = vertexComponents 56 | self.colorComponents = colorComponents 57 | } 58 | 59 | public mutating func beginShape(_ kind: BeginShapeKind) { 60 | self.vertexComponents.kind = kind 61 | self.vertexComponents.vertexes.removeAll() 62 | } 63 | 64 | public mutating func endShape(_ mode: EndShapeMode) { 65 | guard self.vertexComponents.vertexes.count > 0 else { 66 | return 67 | } 68 | 69 | switch self.vertexComponents.kind { 70 | case .points: 71 | let context = self.contextComponents.context 72 | context?.setFillColor(self.colorComponents.stroke.cgColor) 73 | for vertex in self.vertexComponents.vertexes { 74 | context?.fill(CGRect(x: vertex.x, y: vertex.y, width: self.colorComponents.strokeWeight, height: self.colorComponents.strokeWeight)) 75 | } 76 | case .lines: 77 | while self.vertexComponents.vertexes.count >= 2 { 78 | let arrSlice: ArraySlice = self.vertexComponents.vertexes.prefix(2) 79 | let vertexes = arrSlice.map { $0 } 80 | addLineToPoints(vertexes: vertexes, isClosed: false) 81 | self.vertexComponents.vertexes.removeFirst(2) 82 | } 83 | case .triangles: 84 | while self.vertexComponents.vertexes.count >= 3 { 85 | let arrSlice: ArraySlice = self.vertexComponents.vertexes.prefix(3) 86 | let vertexes = arrSlice.map { $0 } 87 | addLineToPoints(vertexes: vertexes, isClosed: true) 88 | self.vertexComponents.vertexes.removeFirst(3) 89 | } 90 | case .quads: 91 | while self.vertexComponents.vertexes.count >= 4 { 92 | let arrSlice: ArraySlice = self.vertexComponents.vertexes.prefix(4) 93 | let vertexes = arrSlice.map { $0 } 94 | addLineToPoints(vertexes: vertexes, isClosed: true) 95 | self.vertexComponents.vertexes.removeFirst(4) 96 | } 97 | case .none: 98 | self.addLineToPoints(vertexes: self.vertexComponents.vertexes, isClosed: mode == .close) 99 | } 100 | 101 | self.vertexComponents.vertexes.removeAll() 102 | } 103 | 104 | public mutating func vertex(_ x: CGFloat, _ y: CGFloat) { 105 | self.vertexComponents.vertexes.append(CGPoint(x: x, y: y)) 106 | } 107 | 108 | private func addLineToPoints(vertexes: [CGPoint], isClosed: Bool) { 109 | let context = self.contextComponents.context 110 | setGraphicsConfiguration(context: context) 111 | 112 | for (index, vertex) in vertexes.enumerated() { 113 | if index == 0 { 114 | context?.move(to: vertex) 115 | } else { 116 | context?.addLine(to: vertex) 117 | } 118 | } 119 | if isClosed { 120 | context?.addLine(to: vertexes.first!) 121 | } 122 | context?.drawPath(using: .fillStroke) 123 | } 124 | 125 | private func setGraphicsConfiguration(context: CGContext?) { 126 | context?.setFillColor(self.colorComponents.fill.cgColor) 127 | context?.setStrokeColor(self.colorComponents.stroke.cgColor) 128 | context?.setLineWidth(self.colorComponents.strokeWeight) 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /ProcessingKit/Core/Structure/Loop.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Structure.swift 3 | // ProcessingKit 4 | // 5 | // Created by AtsuyaSato on 2017/08/13. 6 | // Copyright © 2017年 Atsuya Sato. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public protocol LoopModelContract { 12 | func loop() 13 | func noLoop() 14 | } 15 | -------------------------------------------------------------------------------- /ProcessingKit/Core/Transform/Transform.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Transform.swift 3 | // ProcessingKit 4 | // 5 | // Created by AtsuyaSato on 2017/09/27. 6 | // Copyright © 2017年 Atsuya Sato. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | #if os(iOS) 12 | import UIKit 13 | #elseif os(OSX) 14 | import Cocoa 15 | #endif 16 | 17 | public protocol TransformModelContract { 18 | func pushMatrix() 19 | func popMatrix() 20 | func scale(_ s: CGFloat) 21 | func scale(_ x: CGFloat, _ y: CGFloat) 22 | func shear(_ angleX: CGFloat, _ angleY: CGFloat) 23 | func rotate(_ angle: CGFloat) 24 | func translate(_ x: CGFloat, _ y: CGFloat) 25 | } 26 | 27 | public struct TransformModel: TransformModelContract { 28 | private var contextComponents: ContextComponenetsContract 29 | 30 | public init(contextComponents: ContextComponenetsContract) { 31 | self.contextComponents = contextComponents 32 | } 33 | 34 | public func pushMatrix() { 35 | let context = self.contextComponents.context 36 | context?.saveGState() 37 | } 38 | 39 | public func popMatrix() { 40 | let context = self.contextComponents.context 41 | context?.restoreGState() 42 | } 43 | 44 | public func scale(_ s: CGFloat) { 45 | let context = self.contextComponents.context 46 | context?.scaleBy(x: s, y: s) 47 | 48 | } 49 | 50 | public func scale(_ x: CGFloat, _ y: CGFloat) { 51 | let context = self.contextComponents.context 52 | context?.scaleBy(x: x, y: y) 53 | } 54 | 55 | public func shear(_ angleX: CGFloat, _ angleY: CGFloat) { 56 | let context = self.contextComponents.context 57 | context?.concatenate(CGAffineTransform(a: 1, b: tan(angleY), c: tan(angleX), d: 1, tx: 0, ty: 0)) 58 | } 59 | 60 | public func rotate(_ angle: CGFloat) { 61 | let context = self.contextComponents.context 62 | context?.rotate(by: angle) 63 | } 64 | 65 | public func translate(_ x: CGFloat, _ y: CGFloat) { 66 | let context = self.contextComponents.context 67 | context?.translateBy(x: x, y: y) 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /ProcessingKit/Core/Typography/Text.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Text.swift 3 | // ProcessingKit 4 | // 5 | // Created by AtsuyaSato on 2017/08/13. 6 | // Copyright © 2017年 Atsuya Sato. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | #if os(iOS) 12 | import UIKit 13 | #elseif os(OSX) 14 | import Cocoa 15 | #endif 16 | 17 | public protocol TextComponentsContract { 18 | var textSize: CGFloat { get set } 19 | var textFont: UIFont { get set } 20 | var textAlignX: NSTextAlignment { get set } 21 | } 22 | 23 | public protocol TextModelContract { 24 | func text(_ str: String, _ x: CGFloat, _ y: CGFloat) 25 | func text(_ str: String, _ x: CGFloat, _ y: CGFloat, _ width: CGFloat, _ height: CGFloat) 26 | func textWidth(_ str: String) -> CGFloat 27 | mutating func textSize(_ size: CGFloat) 28 | mutating func textFont(_ font: UIFont) 29 | mutating func textAlign(_ allignX: NSTextAlignment) 30 | } 31 | 32 | public class TextComponents: TextComponentsContract { 33 | public var textSize: CGFloat = 20.0 34 | public var textFont: UIFont = UIFont.systemFont(ofSize: 20.0) 35 | public var textAlignX: NSTextAlignment = .left 36 | 37 | public init() {} 38 | } 39 | 40 | public struct TextModel: TextModelContract { 41 | private var contextComponents: ContextComponenetsContract 42 | private var textComponents: TextComponentsContract 43 | private var colorComponents: ColorComponentsContract 44 | private var frameComponents: FrameComponentsContract 45 | 46 | public init(contextComponents: ContextComponenetsContract, frameComponents: FrameComponentsContract, textComponents: TextComponentsContract, colorComponents: ColorComponentsContract) { 47 | self.contextComponents = contextComponents 48 | self.frameComponents = frameComponents 49 | self.textComponents = textComponents 50 | self.colorComponents = colorComponents 51 | } 52 | 53 | public func text(_ str: String, _ x: CGFloat, _ y: CGFloat) { 54 | let width = self.textWidth(str) 55 | let height = str.height(withConstrainedWidth: width, font: self.textComponents.textFont) 56 | if self.textComponents.textAlignX == .center { 57 | self.text(str, x - width / 2, y, width, height) 58 | return 59 | } else if self.textComponents.textAlignX == .right { 60 | self.text(str, x - width, y, width, height) 61 | return 62 | } 63 | 64 | self.text(str, x, y, width, height) 65 | } 66 | 67 | public func text(_ str: String, _ x: CGFloat, _ y: CGFloat, _ width: CGFloat, _ height: CGFloat) { 68 | let context = self.contextComponents.context 69 | 70 | context?.saveGState() 71 | 72 | context?.translateBy(x: 0, y: frameComponents.bounds.size.height) 73 | context?.scaleBy(x: 1.0, y: -1.0) 74 | context?.textMatrix = CGAffineTransform.identity 75 | 76 | let path: CGMutablePath = CGMutablePath() 77 | let bounds: CGRect = CGRect(x: x, y: -y + frameComponents.bounds.size.height, width: width, height: height) 78 | path.addRect(bounds) 79 | 80 | let paragraph = NSMutableParagraphStyle() 81 | paragraph.alignment = self.textComponents.textAlignX 82 | 83 | let attributes: [NSAttributedString.Key: Any] = [NSAttributedString.Key.paragraphStyle: paragraph] 84 | 85 | let attrString = NSMutableAttributedString(string: str, attributes: attributes) 86 | 87 | // set font 88 | CFAttributedStringSetAttribute(attrString, CFRangeMake(0, attrString.length), kCTFontAttributeName, self.textComponents.textFont) 89 | 90 | CFAttributedStringSetAttribute(attrString, CFRangeMake(0, attrString.length), kCTForegroundColorAttributeName, self.colorComponents.fill.cgColor) 91 | 92 | let framesetter: CTFramesetter = CTFramesetterCreateWithAttributedString(attrString) 93 | 94 | let frame: CTFrame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, 0), path, nil) 95 | 96 | // 上記の内容を描画します。 97 | CTFrameDraw(frame, context!) 98 | 99 | context?.restoreGState() 100 | } 101 | 102 | public func textWidth(_ str: String) -> CGFloat { 103 | let size = str.size(withAttributes: [NSAttributedString.Key.font: self.textComponents.textFont]) 104 | return size.width 105 | } 106 | 107 | public mutating func textSize(_ size: CGFloat) { 108 | self.textComponents.textSize = size 109 | self.textComponents.textFont = UIFont.systemFont(ofSize: size) 110 | } 111 | 112 | public mutating func textFont(_ font: UIFont) { 113 | self.textComponents.textFont = font 114 | self.textComponents.textSize = font.pointSize 115 | } 116 | 117 | public mutating func textAlign(_ allignX: NSTextAlignment) { 118 | self.textComponents.textAlignX = allignX 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /ProcessingKit/Demo.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | //: Playground - noun: a place where people can play 2 | 3 | import UIKit 4 | import PlaygroundSupport 5 | import ProcessingKit 6 | 7 | //: Step 1: Create custom view class for drawing 8 | class SampleView: ProcessingView { 9 | var i: CGFloat = 0 10 | var dx: CGFloat = 0 11 | 12 | //: The setup() function is run once, when the program starts. 13 | func setup() { 14 | dx = 10 15 | } 16 | 17 | //: Called directly after setup(), the draw() function continuously executes the lines of code contained inside its block until the program is stopped or noLoop() is called. 18 | func draw() { 19 | background(UIColor.white) 20 | fill(UIColor.red) 21 | ellipse(i, 100, 100, 100) 22 | i+=dx 23 | if i > width { 24 | i = 0 25 | } 26 | } 27 | } 28 | 29 | //: Step 2: Create custom view instance 30 | let sampleView = SampleView(frame: CGRect(x: 0, y: 0, width: 360, height: 480)) 31 | 32 | //: Option for playground 33 | sampleView.isPlayground = true 34 | 35 | PlaygroundPage.current.needsIndefiniteExecution = true 36 | PlaygroundPage.current.liveView = sampleView 37 | -------------------------------------------------------------------------------- /ProcessingKit/Demo.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /ProcessingKit/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | $(CURRENT_PROJECT_VERSION) 21 | NSPrincipalClass 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /ProcessingKit/ProcessingKit.h: -------------------------------------------------------------------------------- 1 | // 2 | // ProcessingKit.h 3 | // ProcessingKit 4 | // 5 | // Created by AtsuyaSato on 2017/08/04. 6 | // Copyright © 2017年 Atsuya Sato. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for ProcessingKit. 12 | FOUNDATION_EXPORT double ProcessingKitVersionNumber; 13 | 14 | //! Project version string for ProcessingKit. 15 | FOUNDATION_EXPORT const unsigned char ProcessingKitVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import 18 | 19 | 20 | -------------------------------------------------------------------------------- /ProcessingKit/ProcessingView+Core/ProcessingView+Color.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ProcessingView+Color.swift 3 | // ProcessingKit 4 | // 5 | // Created by AtsuyaSato on 2018/09/09. 6 | // Copyright © 2018年 Atsuya Sato. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | #if os(iOS) 12 | import UIKit 13 | #elseif os(OSX) 14 | import Cocoa 15 | #endif 16 | 17 | extension ProcessingView: ColorModelContract { 18 | public func background(_ color: UIColor) { 19 | self.colorModel.background(color) 20 | self.backgroundColor = color 21 | } 22 | 23 | public func background(_ r: CGFloat, _ g: CGFloat, _ b: CGFloat, _ a: CGFloat = 255) { 24 | self.colorModel.background(r, g, b, a) 25 | self.backgroundColor = UIColor(red: r / 255.0, green: g / 255.0, blue: b / 255.0, alpha: a / 255.0) 26 | 27 | } 28 | 29 | public func clear() { 30 | self.colorModel.clear() 31 | self.background(UIColor.white) 32 | } 33 | 34 | public func fill(_ color: UIColor) { 35 | self.colorModel.fill(color) 36 | } 37 | 38 | public func fill(_ r: CGFloat, _ g: CGFloat, _ b: CGFloat, _ a: CGFloat = 255) { 39 | self.colorModel.fill(r, g, b, a) 40 | } 41 | 42 | public func stroke(_ color: UIColor) { 43 | self.colorModel.stroke(color) 44 | } 45 | 46 | public func stroke(_ r: CGFloat, _ g: CGFloat, _ b: CGFloat, _ a: CGFloat = 255) { 47 | self.colorModel.stroke(r, g, b, a) 48 | } 49 | 50 | public func strokeWeight(_ weight: CGFloat) { 51 | self.colorModel.strokeWeight(weight) 52 | } 53 | 54 | public func noFill() { 55 | self.colorModel.noFill() 56 | } 57 | 58 | public func noStroke() { 59 | self.colorModel.noStroke() 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /ProcessingKit/ProcessingView+Core/ProcessingView+Constants.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ProcessingView+Constants.swift 3 | // ProcessingKit 4 | // 5 | // Created by AtsuyaSato on 2018/09/09. 6 | // Copyright © 2018年 Atsuya Sato. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | #if os(iOS) 12 | import UIKit 13 | #elseif os(OSX) 14 | import Cocoa 15 | #endif 16 | 17 | extension ProcessingView: Constants { 18 | public var HALF_PI: CGFloat { 19 | return .pi / 2 20 | } 21 | 22 | public var PI: CGFloat { 23 | return .pi 24 | } 25 | 26 | public var QUARTER_PI: CGFloat { 27 | return .pi / 4 28 | } 29 | 30 | public var TAU: CGFloat { 31 | return self.TWO_PI 32 | } 33 | 34 | public var TWO_PI: CGFloat { 35 | return .pi * 2 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /ProcessingKit/ProcessingView+Core/ProcessingView+Date.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ProcessingView+Date.swift 3 | // ProcessingKit 4 | // 5 | // Created by AtsuyaSato on 2018/09/09. 6 | // Copyright © 2018年 Atsuya Sato. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | #if os(iOS) 12 | import UIKit 13 | #elseif os(OSX) 14 | import Cocoa 15 | #endif 16 | 17 | extension ProcessingView: DateModelContract { 18 | public func millis() -> Int { 19 | return self.dateModel.millis() 20 | } 21 | 22 | public func second() -> Int { 23 | return self.dateModel.second() 24 | } 25 | 26 | public func minute() -> Int { 27 | return self.dateModel.minute() 28 | } 29 | 30 | public func hour() -> Int { 31 | return self.dateModel.hour() 32 | } 33 | 34 | public func day() -> Int { 35 | return self.dateModel.day() 36 | } 37 | 38 | public func month() -> Int { 39 | return self.dateModel.month() 40 | } 41 | 42 | public func year() -> Int { 43 | return self.dateModel.year() 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /ProcessingKit/ProcessingView+Core/ProcessingView+Frame.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ProcessingView+Frame.swift 3 | // ProcessingKit 4 | // 5 | // Created by AtsuyaSato on 2018/09/09. 6 | // Copyright © 2018年 Atsuya Sato. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | #if os(iOS) 12 | import UIKit 13 | #elseif os(OSX) 14 | import Cocoa 15 | #endif 16 | 17 | extension ProcessingView: FrameModelContract { 18 | public var frameRate: CGFloat { 19 | return self.frameModel.frameRate 20 | } 21 | 22 | public var width: CGFloat { 23 | return self.frameModel.width 24 | } 25 | 26 | public var height: CGFloat { 27 | return self.frameModel.height 28 | } 29 | 30 | public func frameRate(_ fps: CGFloat) { 31 | self.frameModel.frameRate(fps) 32 | 33 | self.timer?.invalidate() 34 | self.timer = nil 35 | self.timer = Timer.scheduledTimer(timeInterval: TimeInterval(1.0 / fps), target: self, selector: #selector(update(timer:)), userInfo: nil, repeats: true) 36 | } 37 | 38 | public func delay(napTime: Int) { 39 | let delayInSeconds = Double(napTime) / 1000.0 40 | self.timer?.invalidate() 41 | DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + delayInSeconds) { 42 | self.timer?.fire() 43 | } 44 | } 45 | 46 | @objc private func update(timer: Timer) { 47 | self.draw(self.frame) 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /ProcessingKit/ProcessingView+Core/ProcessingView+Gesture.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ProcessingView+Gesture.swift 3 | // ProcessingKit 4 | // 5 | // Created by AtsuyaSato on 2018/10/07. 6 | // Copyright © 2018 Atsuya Sato. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | #if os(iOS) 12 | import UIKit 13 | #elseif os(OSX) 14 | import Cocoa 15 | #endif 16 | 17 | extension ProcessingView { 18 | #if os(iOS) 19 | public var fingerPressed: Bool { 20 | return self.gestureModel.fingerPressed 21 | } 22 | 23 | public var touchX: CGFloat { 24 | return self.gestureModel.touchX 25 | } 26 | 27 | public var touchY: CGFloat { 28 | return self.gestureModel.touchY 29 | } 30 | 31 | public var touches: Set { 32 | return self.gestureModel.touches 33 | } 34 | #elseif os(OSX) 35 | public var mousePressed: Bool { 36 | return self.gestureModel.mousePressed 37 | } 38 | 39 | public var mouseX: CGFloat { 40 | return self.gestureModel.mouseX 41 | } 42 | 43 | public var mouseY: CGFloat { 44 | return self.gestureModel.mouseY 45 | } 46 | #endif 47 | 48 | #if os(iOS) 49 | @objc func didTap(recognizer: UITapGestureRecognizer) { 50 | self.gestureModel.didTap(recognizer: recognizer) 51 | 52 | let dispatchTime = DispatchTime.now() + Double(1.0 / self.frameRate) 53 | DispatchQueue.main.asyncAfter(deadline: dispatchTime) { 54 | self.didTapExit(recognizer: recognizer) 55 | } 56 | } 57 | func didTapExit(recognizer: UITapGestureRecognizer) { 58 | self.gestureModel.didTapExit(recognizer: recognizer) 59 | } 60 | @objc func didSwipe(recognizer: UISwipeGestureRecognizer) { 61 | self.gestureModel.didSwipe(recognizer: recognizer) 62 | } 63 | @objc func didPinch(recognizer: UIPinchGestureRecognizer) { 64 | self.gestureModel.didPinch(recognizer: recognizer) 65 | } 66 | @objc func didRotate(recognizer: UIRotationGestureRecognizer) { 67 | self.gestureModel.didRotate(recognizer: recognizer) 68 | } 69 | @objc func didPan(recognizer: UIPanGestureRecognizer) { 70 | self.gestureModel.didPan(recognizer: recognizer) 71 | } 72 | @objc func didLongPress(recognizer: UILongPressGestureRecognizer) { 73 | self.gestureModel.didLongPress(recognizer: recognizer) 74 | } 75 | #elseif os(OSX) 76 | @objc func didClick(recognizer: NSClickGestureRecognizer) { 77 | self.gestureModel.didClick(recognizer: recognizer) 78 | 79 | let dispatchTime = DispatchTime.now() + Double(1.0 / self.frameRate) 80 | DispatchQueue.main.asyncAfter(deadline: dispatchTime) { 81 | self.didClickExit(recognizer: recognizer) 82 | } 83 | } 84 | @objc func didClickExit(recognizer: NSClickGestureRecognizer) { 85 | self.gestureModel.didClickExit(recognizer: recognizer) 86 | } 87 | @objc func didMagnify(recognizer: NSMagnificationGestureRecognizer) { 88 | self.gestureModel.didMagnify(recognizer: recognizer) 89 | } 90 | @objc func didPan(recognizer: NSPanGestureRecognizer) { 91 | self.gestureModel.didPan(recognizer: recognizer) 92 | } 93 | @objc func didPress(recognizer: NSPressGestureRecognizer) { 94 | self.gestureModel.didPress(recognizer: recognizer) 95 | } 96 | @objc func didRotate(recognizer: NSRotationGestureRecognizer) { 97 | self.gestureModel.didRotate(recognizer: recognizer) 98 | } 99 | open override func scrollWheel(with event: NSEvent) { 100 | self.gestureModel.scrollWheel(with: event) 101 | } 102 | open override func mouseMoved(with event: NSEvent) { 103 | self.gestureModel.mouseMoved(with: event) 104 | } 105 | #endif 106 | } 107 | -------------------------------------------------------------------------------- /ProcessingKit/ProcessingView+Core/ProcessingView+Image.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ProcessingView+Image.swift 3 | // ProcessingKit 4 | // 5 | // Created by AtsuyaSato on 2018/09/09. 6 | // Copyright © 2018年 Atsuya Sato. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | #if os(iOS) 12 | import UIKit 13 | #elseif os(OSX) 14 | import Cocoa 15 | #endif 16 | 17 | extension ProcessingView: ImageModelContract { 18 | #if os(iOS) 19 | public func image(_ img: UIImage, _ x: CGFloat, _ y: CGFloat) { 20 | self.imageModel.image(img, x, y) 21 | } 22 | 23 | public func image(_ img: UIImage, _ x: CGFloat, _ y: CGFloat, _ width: CGFloat, _ height: CGFloat) { 24 | self.imageModel.image(img, x, y, width, height) 25 | } 26 | #elseif os(OSX) 27 | public func drawImage(_ img: NSImage, _ x: CGFloat, _ y: CGFloat) { 28 | self.imageModel.drawImage(img, x, y) 29 | } 30 | 31 | public func drawImage(_ img: NSImage, _ x: CGFloat, _ y: CGFloat, _ width: CGFloat, _ height: CGFloat) { 32 | self.imageModel.drawImage(img, x, y, width, height) 33 | } 34 | #endif 35 | } 36 | -------------------------------------------------------------------------------- /ProcessingKit/ProcessingView+Core/ProcessingView+Loop.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ProcessingView+Loop.swift 3 | // ProcessingKit 4 | // 5 | // Created by AtsuyaSato on 2018/09/09. 6 | // Copyright © 2018年 Atsuya Sato. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | #if os(iOS) 12 | import UIKit 13 | #elseif os(OSX) 14 | import Cocoa 15 | #endif 16 | 17 | extension ProcessingView: LoopModelContract { 18 | public func loop() { 19 | self.timer?.fire() 20 | } 21 | 22 | public func noLoop() { 23 | self.timer?.invalidate() 24 | self.timer = nil 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /ProcessingKit/ProcessingView+Core/ProcessingView+Shape.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ProcessingView+Shape.swift 3 | // ProcessingKit 4 | // 5 | // Created by AtsuyaSato on 2018/09/09. 6 | // Copyright © 2018年 Atsuya Sato. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | #if os(iOS) 12 | import UIKit 13 | #elseif os(OSX) 14 | import Cocoa 15 | #endif 16 | 17 | extension ProcessingView: ShapeModelContract { 18 | public func point(_ x: CGFloat, _ y: CGFloat) { 19 | self.shapeModel.point(x, y) 20 | } 21 | 22 | public func line(_ x1: CGFloat, _ y1: CGFloat, _ x2: CGFloat, _ y2: CGFloat) { 23 | self.shapeModel.line(x1, y1, x2, y2) 24 | } 25 | 26 | public func rect(_ x: CGFloat, _ y: CGFloat, _ width: CGFloat, _ height: CGFloat) { 27 | self.shapeModel.rect(x, y, width, height) 28 | } 29 | 30 | public func rect(_ x: CGFloat, _ y: CGFloat, _ width: CGFloat, _ height: CGFloat, _ radius: CGFloat) { 31 | self.shapeModel.rect(x, y, width, height, radius) 32 | } 33 | 34 | public func rect(_ x: CGFloat, _ y: CGFloat, _ width: CGFloat, _ height: CGFloat, _ topLeftRadius: CGFloat, _ topRightRadius: CGFloat, _ bottomLeftRadius: CGFloat, _ bottomRightRadius: CGFloat) { 35 | self.shapeModel.rect(x, y, width, height, topLeftRadius, topRightRadius, bottomLeftRadius, bottomRightRadius) 36 | } 37 | 38 | public func ellipse(_ x: CGFloat, _ y: CGFloat, _ width: CGFloat, _ height: CGFloat) { 39 | self.shapeModel.ellipse(x, y, width, height) 40 | } 41 | 42 | public func arc(_ x: CGFloat, _ y: CGFloat, _ radius: CGFloat, _ start: CGFloat, _ stop: CGFloat) { 43 | self.shapeModel.arc(x, y, radius, start, stop) 44 | } 45 | 46 | public func triangle(_ x1: CGFloat, _ y1: CGFloat, _ x2: CGFloat, _ y2: CGFloat, _ x3: CGFloat, _ y3: CGFloat) { 47 | self.shapeModel.triangle(x1, y1, x2, y2, x3, y3) 48 | } 49 | 50 | public func quad(_ x1: CGFloat, _ y1: CGFloat, _ x2: CGFloat, _ y2: CGFloat, _ x3: CGFloat, _ y3: CGFloat, _ x4: CGFloat, _ y4: CGFloat) { 51 | self.shapeModel.quad(x1, y1, x2, y2, x3, y3, x4, y4) 52 | } 53 | 54 | public func curve(_ cpx1: CGFloat, _ cpy1: CGFloat, _ x1: CGFloat, _ y1: CGFloat, _ x2: CGFloat, _ y2: CGFloat, _ cpx2: CGFloat, _ cpy2: CGFloat) { 55 | self.shapeModel.curve(cpx1, cpy1, x1, y1, x2, y2, cpx2, cpy2) 56 | } 57 | 58 | public func bezier(_ x1: CGFloat, _ y1: CGFloat, _ cpx1: CGFloat, _ cpy1: CGFloat, _ cpx2: CGFloat, _ cpy2: CGFloat, _ x2: CGFloat, _ y2: CGFloat) { 59 | self.shapeModel.bezier(x1, y1, cpx1, cpy1, cpx2, cpy2, x2, y2) 60 | } 61 | 62 | public func radians(_ degrees: CGFloat) -> CGFloat { 63 | return self.shapeModel.radians(degrees) 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /ProcessingKit/ProcessingView+Core/ProcessingView+Text.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ProcessingView+Text.swift 3 | // ProcessingKit 4 | // 5 | // Created by AtsuyaSato on 2018/09/09. 6 | // Copyright © 2018年 Atsuya Sato. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | #if os(iOS) 12 | import UIKit 13 | #elseif os(OSX) 14 | import Cocoa 15 | #endif 16 | 17 | extension ProcessingView: TextModelContract { 18 | public func text(_ str: String, _ x: CGFloat, _ y: CGFloat) { 19 | self.textModel.text(str, x, y) 20 | } 21 | 22 | public func text(_ str: String, _ x: CGFloat, _ y: CGFloat, _ width: CGFloat, _ height: CGFloat) { 23 | self.textModel.text(str, x, y, width, height) 24 | } 25 | 26 | public func textWidth(_ str: String) -> CGFloat { 27 | return self.textModel.textWidth(str) 28 | } 29 | 30 | public func textSize(_ size: CGFloat) { 31 | self.textModel.textSize(size) 32 | } 33 | 34 | public func textFont(_ font: UIFont) { 35 | self.textModel.textFont(font) 36 | } 37 | 38 | public func textAlign(_ allignX: NSTextAlignment) { 39 | self.textModel.textAlign(allignX) 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /ProcessingKit/ProcessingView+Core/ProcessingView+Transform.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ProcessingView+Transform.swift 3 | // ProcessingKit 4 | // 5 | // Created by AtsuyaSato on 2018/09/09. 6 | // Copyright © 2018年 Atsuya Sato. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | #if os(iOS) 12 | import UIKit 13 | #elseif os(OSX) 14 | import Cocoa 15 | #endif 16 | 17 | extension ProcessingView: TransformModelContract { 18 | public func pushMatrix() { 19 | self.transformModel.pushMatrix() 20 | } 21 | 22 | public func popMatrix() { 23 | self.transformModel.popMatrix() 24 | } 25 | 26 | public func scale(_ s: CGFloat) { 27 | self.transformModel.scale(s) 28 | } 29 | 30 | public func scale(_ x: CGFloat, _ y: CGFloat) { 31 | self.transformModel.scale(x, y) 32 | } 33 | 34 | public func shear(_ angleX: CGFloat, _ angleY: CGFloat) { 35 | self.transformModel.shear(angleX, angleY) 36 | } 37 | 38 | public func rotate(_ angle: CGFloat) { 39 | self.transformModel.rotate(angle) 40 | } 41 | 42 | public func translate(_ x: CGFloat, _ y: CGFloat) { 43 | self.transformModel.translate(x, y) 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /ProcessingKit/ProcessingView+Core/ProcessingView+Vertex.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ProcessingView+Vertex.swift 3 | // ProcessingKit 4 | // 5 | // Created by AtsuyaSato on 2018/09/09. 6 | // Copyright © 2018年 Atsuya Sato. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | #if os(iOS) 12 | import UIKit 13 | #elseif os(OSX) 14 | import Cocoa 15 | #endif 16 | 17 | extension ProcessingView: VertexModelContract { 18 | public func beginShape(_ kind: BeginShapeKind = .none) { 19 | self.vertexModel.beginShape(kind) 20 | } 21 | 22 | public func endShape(_ mode: EndShapeMode = .none) { 23 | self.vertexModel.endShape(mode) 24 | } 25 | 26 | public func vertex(_ x: CGFloat, _ y: CGFloat) { 27 | self.vertexModel.vertex(x, y) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /ProcessingKitExample/ProcessingKitExample.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ProcessingKitExample/ProcessingKitExample.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ProcessingKitExample/ProcessingKitExample/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // ProcessingKitExample 4 | // 5 | // Created by AtsuyaSato on 2017/08/05. 6 | // Copyright © 2017年 Atsuya Sato. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | var window: UIWindow? 15 | 16 | 17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 18 | // Override point for customization after application launch. 19 | return true 20 | } 21 | 22 | func applicationWillResignActive(_ application: UIApplication) { 23 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 24 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 25 | } 26 | 27 | func applicationDidEnterBackground(_ application: UIApplication) { 28 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 29 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 30 | } 31 | 32 | func applicationWillEnterForeground(_ application: UIApplication) { 33 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 34 | } 35 | 36 | func applicationDidBecomeActive(_ application: UIApplication) { 37 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 38 | } 39 | 40 | func applicationWillTerminate(_ application: UIApplication) { 41 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 42 | } 43 | 44 | 45 | } 46 | 47 | -------------------------------------------------------------------------------- /ProcessingKitExample/ProcessingKitExample/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "20x20", 5 | "idiom" : "iphone", 6 | "filename" : "icon-20@2x.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "20x20", 11 | "idiom" : "iphone", 12 | "filename" : "icon-20@3x.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "29x29", 17 | "idiom" : "iphone", 18 | "filename" : "icon-29@2x.png", 19 | "scale" : "2x" 20 | }, 21 | { 22 | "size" : "29x29", 23 | "idiom" : "iphone", 24 | "filename" : "icon-29@3x.png", 25 | "scale" : "3x" 26 | }, 27 | { 28 | "size" : "40x40", 29 | "idiom" : "iphone", 30 | "filename" : "icon-40@2x.png", 31 | "scale" : "2x" 32 | }, 33 | { 34 | "size" : "40x40", 35 | "idiom" : "iphone", 36 | "filename" : "icon-40@3x.png", 37 | "scale" : "3x" 38 | }, 39 | { 40 | "size" : "60x60", 41 | "idiom" : "iphone", 42 | "filename" : "icon-60@2x.png", 43 | "scale" : "2x" 44 | }, 45 | { 46 | "size" : "60x60", 47 | "idiom" : "iphone", 48 | "filename" : "icon-60@3x.png", 49 | "scale" : "3x" 50 | }, 51 | { 52 | "idiom" : "ipad", 53 | "size" : "20x20", 54 | "scale" : "1x" 55 | }, 56 | { 57 | "idiom" : "ipad", 58 | "size" : "20x20", 59 | "scale" : "2x" 60 | }, 61 | { 62 | "size" : "29x29", 63 | "idiom" : "ipad", 64 | "filename" : "icon-29.png", 65 | "scale" : "1x" 66 | }, 67 | { 68 | "size" : "29x29", 69 | "idiom" : "ipad", 70 | "filename" : "icon-29@2x-1.png", 71 | "scale" : "2x" 72 | }, 73 | { 74 | "size" : "40x40", 75 | "idiom" : "ipad", 76 | "filename" : "icon-40.png", 77 | "scale" : "1x" 78 | }, 79 | { 80 | "size" : "40x40", 81 | "idiom" : "ipad", 82 | "filename" : "icon-40@2x-1.png", 83 | "scale" : "2x" 84 | }, 85 | { 86 | "size" : "76x76", 87 | "idiom" : "ipad", 88 | "filename" : "icon-76.png", 89 | "scale" : "1x" 90 | }, 91 | { 92 | "size" : "76x76", 93 | "idiom" : "ipad", 94 | "filename" : "icon-76@2x.png", 95 | "scale" : "2x" 96 | }, 97 | { 98 | "size" : "83.5x83.5", 99 | "idiom" : "ipad", 100 | "filename" : "icon-83.5@2x.png", 101 | "scale" : "2x" 102 | }, 103 | { 104 | "size" : "1024x1024", 105 | "idiom" : "ios-marketing", 106 | "filename" : "icon.png", 107 | "scale" : "1x" 108 | } 109 | ], 110 | "info" : { 111 | "version" : 1, 112 | "author" : "xcode" 113 | } 114 | } -------------------------------------------------------------------------------- /ProcessingKitExample/ProcessingKitExample/Assets.xcassets/AppIcon.appiconset/icon-20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/natmark/ProcessingKit/0cc2a6fa90c69ba218df96644b0b496bf399b36a/ProcessingKitExample/ProcessingKitExample/Assets.xcassets/AppIcon.appiconset/icon-20@2x.png -------------------------------------------------------------------------------- /ProcessingKitExample/ProcessingKitExample/Assets.xcassets/AppIcon.appiconset/icon-20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/natmark/ProcessingKit/0cc2a6fa90c69ba218df96644b0b496bf399b36a/ProcessingKitExample/ProcessingKitExample/Assets.xcassets/AppIcon.appiconset/icon-20@3x.png -------------------------------------------------------------------------------- /ProcessingKitExample/ProcessingKitExample/Assets.xcassets/AppIcon.appiconset/icon-29.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/natmark/ProcessingKit/0cc2a6fa90c69ba218df96644b0b496bf399b36a/ProcessingKitExample/ProcessingKitExample/Assets.xcassets/AppIcon.appiconset/icon-29.png -------------------------------------------------------------------------------- /ProcessingKitExample/ProcessingKitExample/Assets.xcassets/AppIcon.appiconset/icon-29@2x-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/natmark/ProcessingKit/0cc2a6fa90c69ba218df96644b0b496bf399b36a/ProcessingKitExample/ProcessingKitExample/Assets.xcassets/AppIcon.appiconset/icon-29@2x-1.png -------------------------------------------------------------------------------- /ProcessingKitExample/ProcessingKitExample/Assets.xcassets/AppIcon.appiconset/icon-29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/natmark/ProcessingKit/0cc2a6fa90c69ba218df96644b0b496bf399b36a/ProcessingKitExample/ProcessingKitExample/Assets.xcassets/AppIcon.appiconset/icon-29@2x.png -------------------------------------------------------------------------------- /ProcessingKitExample/ProcessingKitExample/Assets.xcassets/AppIcon.appiconset/icon-29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/natmark/ProcessingKit/0cc2a6fa90c69ba218df96644b0b496bf399b36a/ProcessingKitExample/ProcessingKitExample/Assets.xcassets/AppIcon.appiconset/icon-29@3x.png -------------------------------------------------------------------------------- /ProcessingKitExample/ProcessingKitExample/Assets.xcassets/AppIcon.appiconset/icon-40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/natmark/ProcessingKit/0cc2a6fa90c69ba218df96644b0b496bf399b36a/ProcessingKitExample/ProcessingKitExample/Assets.xcassets/AppIcon.appiconset/icon-40.png -------------------------------------------------------------------------------- /ProcessingKitExample/ProcessingKitExample/Assets.xcassets/AppIcon.appiconset/icon-40@2x-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/natmark/ProcessingKit/0cc2a6fa90c69ba218df96644b0b496bf399b36a/ProcessingKitExample/ProcessingKitExample/Assets.xcassets/AppIcon.appiconset/icon-40@2x-1.png -------------------------------------------------------------------------------- /ProcessingKitExample/ProcessingKitExample/Assets.xcassets/AppIcon.appiconset/icon-40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/natmark/ProcessingKit/0cc2a6fa90c69ba218df96644b0b496bf399b36a/ProcessingKitExample/ProcessingKitExample/Assets.xcassets/AppIcon.appiconset/icon-40@2x.png -------------------------------------------------------------------------------- /ProcessingKitExample/ProcessingKitExample/Assets.xcassets/AppIcon.appiconset/icon-40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/natmark/ProcessingKit/0cc2a6fa90c69ba218df96644b0b496bf399b36a/ProcessingKitExample/ProcessingKitExample/Assets.xcassets/AppIcon.appiconset/icon-40@3x.png -------------------------------------------------------------------------------- /ProcessingKitExample/ProcessingKitExample/Assets.xcassets/AppIcon.appiconset/icon-60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/natmark/ProcessingKit/0cc2a6fa90c69ba218df96644b0b496bf399b36a/ProcessingKitExample/ProcessingKitExample/Assets.xcassets/AppIcon.appiconset/icon-60@2x.png -------------------------------------------------------------------------------- /ProcessingKitExample/ProcessingKitExample/Assets.xcassets/AppIcon.appiconset/icon-60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/natmark/ProcessingKit/0cc2a6fa90c69ba218df96644b0b496bf399b36a/ProcessingKitExample/ProcessingKitExample/Assets.xcassets/AppIcon.appiconset/icon-60@3x.png -------------------------------------------------------------------------------- /ProcessingKitExample/ProcessingKitExample/Assets.xcassets/AppIcon.appiconset/icon-76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/natmark/ProcessingKit/0cc2a6fa90c69ba218df96644b0b496bf399b36a/ProcessingKitExample/ProcessingKitExample/Assets.xcassets/AppIcon.appiconset/icon-76.png -------------------------------------------------------------------------------- /ProcessingKitExample/ProcessingKitExample/Assets.xcassets/AppIcon.appiconset/icon-76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/natmark/ProcessingKit/0cc2a6fa90c69ba218df96644b0b496bf399b36a/ProcessingKitExample/ProcessingKitExample/Assets.xcassets/AppIcon.appiconset/icon-76@2x.png -------------------------------------------------------------------------------- /ProcessingKitExample/ProcessingKitExample/Assets.xcassets/AppIcon.appiconset/icon-83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/natmark/ProcessingKit/0cc2a6fa90c69ba218df96644b0b496bf399b36a/ProcessingKitExample/ProcessingKitExample/Assets.xcassets/AppIcon.appiconset/icon-83.5@2x.png -------------------------------------------------------------------------------- /ProcessingKitExample/ProcessingKitExample/Assets.xcassets/AppIcon.appiconset/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/natmark/ProcessingKit/0cc2a6fa90c69ba218df96644b0b496bf399b36a/ProcessingKitExample/ProcessingKitExample/Assets.xcassets/AppIcon.appiconset/icon.png -------------------------------------------------------------------------------- /ProcessingKitExample/ProcessingKitExample/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /ProcessingKitExample/ProcessingKitExample/Assets.xcassets/ProcessingKit-Logo.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "ProcessingKit-Header.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /ProcessingKitExample/ProcessingKitExample/Assets.xcassets/ProcessingKit-Logo.imageset/ProcessingKit-Header.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/natmark/ProcessingKit/0cc2a6fa90c69ba218df96644b0b496bf399b36a/ProcessingKitExample/ProcessingKitExample/Assets.xcassets/ProcessingKit-Logo.imageset/ProcessingKit-Header.png -------------------------------------------------------------------------------- /ProcessingKitExample/ProcessingKitExample/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /ProcessingKitExample/ProcessingKitExample/BasicFunctions/ArcSampleView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ArcSampleView.swift 3 | // ProcessingKitExample 4 | // 5 | // Created by AtsuyaSato on 2017/09/26. 6 | // Copyright © 2017年 Atsuya Sato. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import ProcessingKit 11 | 12 | class ArcSampleView : ProcessingView { 13 | func setup() { 14 | background(UIColor.white) 15 | fill(UIColor.red) 16 | strokeWeight(5.0) 17 | stroke(UIColor.blue) 18 | arc(200, 200, 100, radians(0), radians(90.0)) 19 | } 20 | } 21 | 22 | -------------------------------------------------------------------------------- /ProcessingKitExample/ProcessingKitExample/BasicFunctions/ArcSampleViewController.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /ProcessingKitExample/ProcessingKitExample/BasicFunctions/ArcSampleViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ArcSampleViewController.swift 3 | // ProcessingKitExample 4 | // 5 | // Created by AtsuyaSato on 2017/09/26. 6 | // Copyright © 2017年 Atsuya Sato. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class ArcSampleViewController: UIViewController { 12 | 13 | @IBOutlet weak var arcSampleView: ArcSampleView! 14 | 15 | override func viewDidLoad() { 16 | super.viewDidLoad() 17 | // Do any additional setup after loading the view. 18 | } 19 | 20 | override func didReceiveMemoryWarning() { 21 | super.didReceiveMemoryWarning() 22 | // Dispose of any resources that can be recreated. 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /ProcessingKitExample/ProcessingKitExample/BasicFunctions/CurveSampleView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CurveSampleView.swift 3 | // ProcessingKitExample 4 | // 5 | // Created by AtsuyaSato on 2017/12/30. 6 | // Copyright © 2017年 Atsuya Sato. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import ProcessingKit 11 | 12 | class CurveSampleView : ProcessingView { 13 | func setup() { 14 | background(UIColor.white) 15 | stroke(UIColor.black) 16 | curve(40, 40, 80, 60, 100, 100, 60, 120) 17 | noStroke() 18 | fill(255, 0, 0) 19 | ellipse(40, 40, 3, 3) 20 | fill(0, 0, 255, 192) 21 | ellipse(100, 100, 3, 3) 22 | ellipse(80, 60, 3, 3) 23 | fill(255, 0, 0) 24 | ellipse(60, 120, 3, 3) 25 | } 26 | } 27 | 28 | -------------------------------------------------------------------------------- /ProcessingKitExample/ProcessingKitExample/BasicFunctions/CurveSampleViewController.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /ProcessingKitExample/ProcessingKitExample/BasicFunctions/CurveSampleViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CurveSampleViewController.swift 3 | // ProcessingKitExample 4 | // 5 | // Created by AtsuyaSato on 2017/12/30. 6 | // Copyright © 2017年 Atsuya Sato. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class CurveSampleViewController: UIViewController { 12 | 13 | @IBOutlet weak var curveSampleView: CurveSampleView! 14 | 15 | override func viewDidLoad() { 16 | super.viewDidLoad() 17 | 18 | // Do any additional setup after loading the view. 19 | } 20 | 21 | override func didReceiveMemoryWarning() { 22 | super.didReceiveMemoryWarning() 23 | // Dispose of any resources that can be recreated. 24 | } 25 | 26 | 27 | /* 28 | // MARK: - Navigation 29 | 30 | // In a storyboard-based application, you will often want to do a little preparation before navigation 31 | override func prepare(for segue: UIStoryboardSegue, sender: Any?) { 32 | // Get the new view controller using segue.destinationViewController. 33 | // Pass the selected object to the new view controller. 34 | } 35 | */ 36 | 37 | } 38 | -------------------------------------------------------------------------------- /ProcessingKitExample/ProcessingKitExample/BasicFunctions/EllipseSampleView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // EllipseSampleView.swift 3 | // ProcessingKitExample 4 | // 5 | // Created by AtsuyaSato on 2017/08/16. 6 | // Copyright © 2017年 Atsuya Sato. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import ProcessingKit 11 | 12 | class EllipseSampleView : ProcessingView { 13 | func setup() { 14 | background(UIColor.white) 15 | fill(UIColor.red) 16 | ellipse(200, 100, 100, 100) 17 | fill(UIColor.blue) 18 | ellipse(250, 150, 100, 100) 19 | noFill() 20 | stroke(UIColor.black) 21 | ellipse(150, 200, 100, 100) 22 | } 23 | } 24 | 25 | -------------------------------------------------------------------------------- /ProcessingKitExample/ProcessingKitExample/BasicFunctions/EllipseSampleViewController.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /ProcessingKitExample/ProcessingKitExample/BasicFunctions/EllipseSampleViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // EllipseSampleViewController.swift 3 | // ProcessingKitExample 4 | // 5 | // Created by AtsuyaSato on 2017/08/16. 6 | // Copyright © 2017年 Atsuya Sato. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class EllipseSampleViewController: UIViewController { 12 | 13 | @IBOutlet weak var ellipseSampleView: EllipseSampleView! 14 | 15 | override func viewDidLoad() { 16 | super.viewDidLoad() 17 | // Do any additional setup after loading the view. 18 | } 19 | 20 | override func didReceiveMemoryWarning() { 21 | super.didReceiveMemoryWarning() 22 | // Dispose of any resources that can be recreated. 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /ProcessingKitExample/ProcessingKitExample/BasicFunctions/ImageSampleView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ImageSampleView.swift 3 | // ProcessingKitExample 4 | // 5 | // Created by AtsuyaSato on 2017/09/27. 6 | // Copyright © 2017年 Atsuya Sato. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import ProcessingKit 11 | 12 | class ImageSampleView : ProcessingView { 13 | func setup() { 14 | image(UIImage(named: "ProcessingKit-Logo")!, 0, 100, width, 100) 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /ProcessingKitExample/ProcessingKitExample/BasicFunctions/ImageSampleViewController.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /ProcessingKitExample/ProcessingKitExample/BasicFunctions/ImageSampleViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ImageSampleViewController.swift 3 | // ProcessingKitExample 4 | // 5 | // Created by AtsuyaSato on 2017/09/27. 6 | // Copyright © 2017年 Atsuya Sato. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class ImageSampleViewController: UIViewController { 12 | 13 | @IBOutlet var imageSampleView: ImageSampleView! 14 | override func viewDidLoad() { 15 | super.viewDidLoad() 16 | // Do any additional setup after loading the view. 17 | } 18 | 19 | override func didReceiveMemoryWarning() { 20 | super.didReceiveMemoryWarning() 21 | // Dispose of any resources that can be recreated. 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /ProcessingKitExample/ProcessingKitExample/BasicFunctions/QuadSampleView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // QuadSampleView.swift 3 | // ProcessingKitExample 4 | // 5 | // Created by AtsuyaSato on 2017/12/29. 6 | // Copyright © 2017年 Atsuya Sato. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import ProcessingKit 11 | 12 | class QuadSampleView : ProcessingView { 13 | func setup() { 14 | background(UIColor.white) 15 | fill(UIColor.red) 16 | strokeWeight(5.0) 17 | stroke(UIColor.blue) 18 | quad(30, 30, 20, 150, 200, 200, 400, 100) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /ProcessingKitExample/ProcessingKitExample/BasicFunctions/QuadSampleViewController.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /ProcessingKitExample/ProcessingKitExample/BasicFunctions/QuadSampleViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // QuadSampleViewController.swift 3 | // ProcessingKitExample 4 | // 5 | // Created by AtsuyaSato on 2017/12/29. 6 | // Copyright © 2017年 Atsuya Sato. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class QuadSampleViewController: UIViewController { 12 | 13 | @IBOutlet weak var quadSampleView: QuadSampleView! 14 | 15 | override func viewDidLoad() { 16 | super.viewDidLoad() 17 | 18 | // Do any additional setup after loading the view. 19 | } 20 | 21 | override func didReceiveMemoryWarning() { 22 | super.didReceiveMemoryWarning() 23 | // Dispose of any resources that can be recreated. 24 | } 25 | 26 | 27 | /* 28 | // MARK: - Navigation 29 | 30 | // In a storyboard-based application, you will often want to do a little preparation before navigation 31 | override func prepare(for segue: UIStoryboardSegue, sender: Any?) { 32 | // Get the new view controller using segue.destinationViewController. 33 | // Pass the selected object to the new view controller. 34 | } 35 | */ 36 | 37 | } 38 | -------------------------------------------------------------------------------- /ProcessingKitExample/ProcessingKitExample/BasicFunctions/RectSampleView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RectSampleView.swift 3 | // ProcessingKitExample 4 | // 5 | // Created by AtsuyaSato on 2017/08/16. 6 | // Copyright © 2017年 Atsuya Sato. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import ProcessingKit 11 | 12 | class RectSampleView : ProcessingView { 13 | func setup() { 14 | background(UIColor.white) 15 | fill(UIColor.red) 16 | rect(200, 100, 100, 100) 17 | fill(UIColor.blue) 18 | rect(250, 150, 100, 100) 19 | noFill() 20 | stroke(UIColor.black) 21 | rect(150, 200, 100, 100) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /ProcessingKitExample/ProcessingKitExample/BasicFunctions/RectSampleViewController.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /ProcessingKitExample/ProcessingKitExample/BasicFunctions/RectSampleViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RectSampleViewController.swift 3 | // ProcessingKitExample 4 | // 5 | // Created by AtsuyaSato on 2017/08/16. 6 | // Copyright © 2017年 Atsuya Sato. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class RectSampleViewController: UIViewController { 12 | 13 | @IBOutlet weak var rectSampleView: RectSampleView! 14 | 15 | override func viewDidLoad() { 16 | super.viewDidLoad() 17 | // Do any additional setup after loading the view. 18 | } 19 | 20 | override func didReceiveMemoryWarning() { 21 | super.didReceiveMemoryWarning() 22 | // Dispose of any resources that can be recreated. 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /ProcessingKitExample/ProcessingKitExample/BasicFunctions/TextSampleView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LineSampleView.swift 3 | // ProcessingKitExample 4 | // 5 | // Created by AtsuyaSato on 2017/08/16. 6 | // Copyright © 2017年 Atsuya Sato. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import ProcessingKit 11 | 12 | class TextSampleView : ProcessingView { 13 | func setup() { 14 | background(UIColor.white) 15 | fill(UIColor.black) 16 | textSize(64.0) 17 | textAlign(.center) 18 | text("Hello World", self.frame.size.width / 2, self.frame.size.height / 2) 19 | 20 | textFont(UIFont(name: "AmericanTypewriter", size: 40.0)!) 21 | fill(UIColor(red: 4 / 255.0, green: 39 / 255.0, blue: 69 / 255.0, alpha: 255.0 / 255.0)) 22 | text("Processing Kit", self.frame.size.width / 2, self.frame.size.height / 2 + 50) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /ProcessingKitExample/ProcessingKitExample/BasicFunctions/TextSampleViewController.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /ProcessingKitExample/ProcessingKitExample/BasicFunctions/TextSampleViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LineSampleViewController.swift 3 | // ProcessingKitExample 4 | // 5 | // Created by AtsuyaSato on 2017/08/16. 6 | // Copyright © 2017年 Atsuya Sato. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class TextSampleViewController: UIViewController { 12 | 13 | @IBOutlet weak var textSampleView: TextSampleView! 14 | 15 | override func viewDidLoad() { 16 | super.viewDidLoad() 17 | // Do any additional setup after loading the view. 18 | } 19 | 20 | override func didReceiveMemoryWarning() { 21 | super.didReceiveMemoryWarning() 22 | // Dispose of any resources that can be recreated. 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /ProcessingKitExample/ProcessingKitExample/BasicFunctions/TriangleSampleView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TriangleSampleView.swift 3 | // ProcessingKitExample 4 | // 5 | // Created by AtsuyaSato on 2017/12/29. 6 | // Copyright © 2017年 Atsuya Sato. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import ProcessingKit 11 | 12 | class TriangleSampleView : ProcessingView { 13 | func setup() { 14 | background(UIColor.white) 15 | fill(UIColor.red) 16 | strokeWeight(5.0) 17 | stroke(UIColor.blue) 18 | triangle(width/2, 100, 0, height/2, width, height/2) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /ProcessingKitExample/ProcessingKitExample/BasicFunctions/TriangleSampleViewController.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /ProcessingKitExample/ProcessingKitExample/BasicFunctions/TriangleSampleViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TriangleSampleViewController.swift 3 | // ProcessingKitExample 4 | // 5 | // Created by AtsuyaSato on 2017/12/29. 6 | // Copyright © 2017年 Atsuya Sato. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class TriangleSampleViewController: UIViewController { 12 | 13 | @IBOutlet weak var triangleSampleView: TriangleSampleView! 14 | 15 | override func viewDidLoad() { 16 | super.viewDidLoad() 17 | 18 | // Do any additional setup after loading the view. 19 | } 20 | 21 | override func didReceiveMemoryWarning() { 22 | super.didReceiveMemoryWarning() 23 | // Dispose of any resources that can be recreated. 24 | } 25 | 26 | 27 | /* 28 | // MARK: - Navigation 29 | 30 | // In a storyboard-based application, you will often want to do a little preparation before navigation 31 | override func prepare(for segue: UIStoryboardSegue, sender: Any?) { 32 | // Get the new view controller using segue.destinationViewController. 33 | // Pass the selected object to the new view controller. 34 | } 35 | */ 36 | 37 | } 38 | -------------------------------------------------------------------------------- /ProcessingKitExample/ProcessingKitExample/Extensions/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // ProcessingKitExample 4 | // 5 | // Created by AtsuyaSato on 2017/08/16. 6 | // Copyright © 2017年 Atsuya Sato. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | public extension UIViewController { 12 | 13 | static func create() -> Self { 14 | let name: String = "\(type(of: self))".components(separatedBy: ".").first! 15 | return instantiate(storyboardName: name) 16 | } 17 | 18 | private static func instantiate(storyboardName: String) -> T { 19 | let storyboard: UIStoryboard = UIStoryboard(name: storyboardName, bundle: nil) 20 | let vc: UIViewController? = storyboard.instantiateInitialViewController() 21 | return vc as! T 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /ProcessingKitExample/ProcessingKitExample/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UILaunchStoryboardName 24 | LaunchScreen 25 | UIMainStoryboardFile 26 | Main 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /ProcessingKitExample/ProcessingKitExample/MainTableViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MainTableViewController.swift 3 | // ProcessingKitExample 4 | // 5 | // Created by AtsuyaSato on 2017/08/16. 6 | // Copyright © 2017年 Atsuya Sato. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class MainTableViewController: UITableViewController { 12 | 13 | override func viewDidLoad() { 14 | super.viewDidLoad() 15 | } 16 | 17 | override func didReceiveMemoryWarning() { 18 | super.didReceiveMemoryWarning() 19 | // Dispose of any resources that can be recreated. 20 | } 21 | 22 | override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { 23 | tableView.deselectRow(at: indexPath, animated: true) 24 | switch indexPath { 25 | case IndexPath(row: 0, section: 0): //Text 26 | transition(viewController: TextSampleViewController.create()) 27 | return 28 | case IndexPath(row: 1, section: 0): //Rect 29 | transition(viewController: RectSampleViewController.create()) 30 | return 31 | case IndexPath(row: 2, section: 0): //Ellipse 32 | transition(viewController: EllipseSampleViewController.create()) 33 | return 34 | case IndexPath(row: 3, section: 0): //Arc 35 | transition(viewController: ArcSampleViewController.create()) 36 | return 37 | case IndexPath(row: 4, section: 0): //Triangle 38 | transition(viewController: TriangleSampleViewController.create()) 39 | return 40 | case IndexPath(row: 5, section: 0): //Quad 41 | transition(viewController: QuadSampleViewController.create()) 42 | return 43 | case IndexPath(row: 6, section: 0): //Curve 44 | transition(viewController: CurveSampleViewController.create()) 45 | return 46 | case IndexPath(row: 7, section: 0): //Image 47 | transition(viewController: ImageSampleViewController.create()) 48 | return 49 | case IndexPath(row: 0, section: 1): //Simple Tap 50 | transition(viewController: TouchSampleViewController.create()) 51 | case IndexPath(row: 0, section: 2): //Particles 52 | transition(viewController: ParticlesSampleViewController.create()) 53 | case IndexPath(row: 1, section: 2): //Clock Sample 54 | transition(viewController: ClockSampleViewController.create()) 55 | return 56 | default: 57 | return 58 | } 59 | } 60 | func transition(viewController: UIViewController){ 61 | self.navigationController?.pushViewController(viewController, animated: true) 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /ProcessingKitExample/ProcessingKitExample/OthersSample/ClockSampleView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ClockSampleView.swift 3 | // ProcessingKitExample 4 | // 5 | // Created by AtsuyaSato on 2017/09/30. 6 | // Copyright © 2017年 Atsuya Sato. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import ProcessingKit 11 | 12 | class ClockSampleView : ProcessingView { 13 | func setup() { 14 | stroke(UIColor.black) 15 | } 16 | 17 | func draw() { 18 | background(UIColor.white) 19 | let s = second() 20 | let m = minute() 21 | let h = hour() % 12 22 | translate(width/2, width/2) 23 | 24 | noFill() 25 | stroke(UIColor.black) 26 | 27 | // 秒針 28 | pushMatrix() 29 | rotate(radians(CGFloat(s)*(360/60))) 30 | strokeWeight(1) 31 | line(0, 0, 0, -width/2) 32 | popMatrix() 33 | 34 | // 分針 35 | pushMatrix() 36 | rotate(radians(CGFloat(m)*(360/60))) 37 | strokeWeight(2) 38 | line(0, 0, 0, -width/2) 39 | popMatrix() 40 | 41 | // 時針 42 | pushMatrix() 43 | rotate(radians(CGFloat(h)*(360/12))) 44 | strokeWeight(4) 45 | line(0, 0, 0, -width/3) 46 | popMatrix() 47 | 48 | strokeWeight(2); 49 | beginShape(.points); 50 | stride(from: 0, to: 360, by: 6).forEach { 51 | let angle = radians(CGFloat($0)) 52 | let x = cos(angle) * width / 2 53 | let y = sin(angle) * width / 2 54 | vertex(x, y) 55 | } 56 | endShape() 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /ProcessingKitExample/ProcessingKitExample/OthersSample/ClockSampleViewController.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /ProcessingKitExample/ProcessingKitExample/OthersSample/ClockSampleViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ClockSampleViewController.swift 3 | // ProcessingKitExample 4 | // 5 | // Created by AtsuyaSato on 2017/09/30. 6 | // Copyright © 2017年 Atsuya Sato. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class ClockSampleViewController: UIViewController { 12 | @IBOutlet weak var clockSampleView: ClockSampleView! 13 | 14 | override func viewDidLoad() { 15 | super.viewDidLoad() 16 | // Do any additional setup after loading the view. 17 | } 18 | 19 | override func didReceiveMemoryWarning() { 20 | super.didReceiveMemoryWarning() 21 | // Dispose of any resources that can be recreated. 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /ProcessingKitExample/ProcessingKitExample/OthersSample/ParticlesSampleView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ParticlesSampleView.swift 3 | // ProcessingKitExample 4 | // 5 | // Created by AtsuyaSato on 2017/08/17. 6 | // Copyright © 2017年 Atsuya Sato. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import ProcessingKit 11 | 12 | class ParticlesSampleView : ProcessingView { 13 | let totalDots = 50 14 | var dots: [Dot] = [] 15 | let diameter: CGFloat = 12.0 16 | 17 | func setup() { 18 | // initial fill colour 19 | fill(UIColor(red: 1.0, green: 0.0, blue: 0.0, alpha: 1.0)) 20 | noStroke(); 21 | // array of dots 22 | for _ in 0..Float { 50 | return ( Float(arc4random_uniform(UINT32_MAX)) / Float(UINT32_MAX) ) * (_Max - _Min) + _Min 51 | } 52 | } 53 | 54 | class Dot { 55 | var x: CGFloat = 0.0 56 | var y: CGFloat = 0.0 57 | var vx: CGFloat = 0.0 58 | var vy: CGFloat = 0.0 59 | var width: CGFloat = 0.0 60 | var height: CGFloat = 0.0 61 | 62 | init(width: CGFloat, height: CGFloat){ 63 | self.width = width 64 | self.height = height 65 | } 66 | func update(){ 67 | // update the velocity 68 | self.vx = self.vx + CGFloat(getRandomNumber(Min: 0.0, Max: 2.0) - 1.0) 69 | self.vx = self.vx * 0.96 70 | self.vy = self.vy + CGFloat(getRandomNumber(Min: 0.0, Max: 2.0) - 1.0) 71 | self.vy = self.vy * 0.96 72 | // update the position 73 | self.x = self.x + self.vx 74 | self.y = self.y + self.vy 75 | // handle boundary collision 76 | if (self.x > self.width) { self.x = self.width; self.vx = self.vx * -1.0 } 77 | if (self.x < 0) { self.x = 0; self.vx = self.vx * -1.0 } 78 | if (self.y > self.height) { self.y = self.height; self.vy = self.vy * -1.0 } 79 | if (self.y < 0) { self.y = 0; self.vy = self.vy * -1.0 } 80 | } 81 | private func getRandomNumber(Min _Min : Float, Max _Max : Float)->Float { 82 | return ( Float(arc4random_uniform(UINT32_MAX)) / Float(UINT32_MAX) ) * (_Max - _Min) + _Min 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /ProcessingKitExample/ProcessingKitExample/OthersSample/ParticlesSampleViewController.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /ProcessingKitExample/ProcessingKitExample/OthersSample/ParticlesSampleViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ParticlesSampleViewController.swift 3 | // ProcessingKitExample 4 | // 5 | // Created by AtsuyaSato on 2017/08/17. 6 | // Copyright © 2017年 Atsuya Sato. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class ParticlesSampleViewController: UIViewController { 12 | 13 | @IBOutlet weak var particlesSampleView: ParticlesSampleView! 14 | 15 | override func viewDidLoad() { 16 | super.viewDidLoad() 17 | // Do any additional setup after loading the view. 18 | } 19 | 20 | override func didReceiveMemoryWarning() { 21 | super.didReceiveMemoryWarning() 22 | // Dispose of any resources that can be recreated. 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /ProcessingKitExample/ProcessingKitExample/TouchSample/TouchSampleView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TouchSampleView.swift 3 | // ProcessingKitExample 4 | // 5 | // Created by AtsuyaSato on 2017/08/05. 6 | // Copyright © 2017年 Atsuya Sato. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import ProcessingKit 11 | 12 | class TouchSampleView : ProcessingView { 13 | func setup() { 14 | background(UIColor.white) 15 | textAlign(.center) 16 | textSize(20.0) 17 | stroke(UIColor.black) 18 | fill(UIColor.black) 19 | text("Touch me!", self.frame.size.width / 2, self.frame.size.height / 2) 20 | 21 | noStroke() 22 | fill(UIColor.red) 23 | } 24 | func draw() { 25 | if fingerPressed { 26 | ellipse(touchX, touchY, 30, 30) 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /ProcessingKitExample/ProcessingKitExample/TouchSample/TouchSampleViewController.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /ProcessingKitExample/ProcessingKitExample/TouchSample/TouchSampleViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TouchSampleViewController.swift 3 | // ProcessingKitExample 4 | // 5 | // Created by AtsuyaSato on 2017/08/16. 6 | // Copyright © 2017年 Atsuya Sato. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class TouchSampleViewController: UIViewController { 12 | 13 | @IBOutlet weak var touchSampleView: TouchSampleView! 14 | 15 | override func viewDidLoad() { 16 | super.viewDidLoad() 17 | // Do any additional setup after loading the view. 18 | } 19 | 20 | override func didReceiveMemoryWarning() { 21 | super.didReceiveMemoryWarning() 22 | // Dispose of any resources that can be recreated. 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /ProcessingKitOSXExample/ProcessingKitOSXExample.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ProcessingKitOSXExample/ProcessingKitOSXExample.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ProcessingKitOSXExample/ProcessingKitOSXExample/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // ProcessingKitOSXExample 4 | // 5 | // Created by AtsuyaSato on 2017/12/31. 6 | // Copyright © 2017年 Atsuya Sato. All rights reserved. 7 | // 8 | 9 | import Cocoa 10 | 11 | @NSApplicationMain 12 | class AppDelegate: NSObject, NSApplicationDelegate { 13 | 14 | 15 | 16 | func applicationDidFinishLaunching(_ aNotification: Notification) { 17 | // Insert code here to initialize your application 18 | } 19 | 20 | func applicationWillTerminate(_ aNotification: Notification) { 21 | // Insert code here to tear down your application 22 | } 23 | 24 | 25 | } 26 | 27 | -------------------------------------------------------------------------------- /ProcessingKitOSXExample/ProcessingKitOSXExample/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "size" : "16x16", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "mac", 10 | "size" : "16x16", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "mac", 15 | "size" : "32x32", 16 | "scale" : "1x" 17 | }, 18 | { 19 | "idiom" : "mac", 20 | "size" : "32x32", 21 | "scale" : "2x" 22 | }, 23 | { 24 | "idiom" : "mac", 25 | "size" : "128x128", 26 | "scale" : "1x" 27 | }, 28 | { 29 | "idiom" : "mac", 30 | "size" : "128x128", 31 | "scale" : "2x" 32 | }, 33 | { 34 | "idiom" : "mac", 35 | "size" : "256x256", 36 | "scale" : "1x" 37 | }, 38 | { 39 | "idiom" : "mac", 40 | "size" : "256x256", 41 | "scale" : "2x" 42 | }, 43 | { 44 | "idiom" : "mac", 45 | "size" : "512x512", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "mac", 50 | "size" : "512x512", 51 | "scale" : "2x" 52 | } 53 | ], 54 | "info" : { 55 | "version" : 1, 56 | "author" : "xcode" 57 | } 58 | } -------------------------------------------------------------------------------- /ProcessingKitOSXExample/ProcessingKitOSXExample/CustomView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CustomView.swift 3 | // ProcessingKitOSXExample 4 | // 5 | // Created by AtsuyaSato on 2017/12/31. 6 | // Copyright © 2017年 Atsuya Sato. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import ProcessingKit 11 | import Cocoa 12 | 13 | class CustomView: ProcessingView { 14 | func draw() { 15 | background(NSColor.white) 16 | fill(NSColor.blue) 17 | ellipse(mouseX, mouseY, 100, 100) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /ProcessingKitOSXExample/ProcessingKitOSXExample/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleVersion 22 | 1 23 | LSMinimumSystemVersion 24 | $(MACOSX_DEPLOYMENT_TARGET) 25 | NSHumanReadableCopyright 26 | Copyright © 2017年 Atsuya Sato. All rights reserved. 27 | NSMainStoryboardFile 28 | Main 29 | NSPrincipalClass 30 | NSApplication 31 | 32 | 33 | -------------------------------------------------------------------------------- /ProcessingKitOSXExample/ProcessingKitOSXExample/ProcessingKitOSXExample.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | com.apple.security.files.user-selected.read-only 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /ProcessingKitOSXExample/ProcessingKitOSXExample/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // ProcessingKitOSXExample 4 | // 5 | // Created by AtsuyaSato on 2017/12/31. 6 | // Copyright © 2017年 Atsuya Sato. All rights reserved. 7 | // 8 | 9 | import Cocoa 10 | 11 | class ViewController: NSViewController { 12 | 13 | @IBOutlet weak var customView: CustomView! 14 | override func viewDidLoad() { 15 | super.viewDidLoad() 16 | // Do any additional setup after loading the view. 17 | } 18 | 19 | override var representedObject: Any? { 20 | didSet { 21 | // Update the view, if already loaded. 22 | } 23 | } 24 | 25 | 26 | } 27 | 28 | -------------------------------------------------------------------------------- /ProcessingKitOSXExample/ProcessingKitOSXExampleTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /ProcessingKitOSXExample/ProcessingKitOSXExampleTests/ProcessingKitOSXExampleTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ProcessingKitOSXExampleTests.swift 3 | // ProcessingKitOSXExampleTests 4 | // 5 | // Created by AtsuyaSato on 2017/12/31. 6 | // Copyright © 2017年 Atsuya Sato. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import ProcessingKitOSXExample 11 | 12 | class ProcessingKitOSXExampleTests: XCTestCase { 13 | 14 | override func setUp() { 15 | super.setUp() 16 | // Put setup code here. This method is called before the invocation of each test method in the class. 17 | } 18 | 19 | override func tearDown() { 20 | // Put teardown code here. This method is called after the invocation of each test method in the class. 21 | super.tearDown() 22 | } 23 | 24 | func testExample() { 25 | // This is an example of a functional test case. 26 | // Use XCTAssert and related functions to verify your tests produce the correct results. 27 | } 28 | 29 | func testPerformanceExample() { 30 | // This is an example of a performance test case. 31 | self.measure { 32 | // Put the code you want to measure the time of here. 33 | } 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /ProcessingKitTests/CGPath+Extension/CGPath+Extension.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CGPath+Extension.swift 3 | // ProcessingKitTests 4 | // 5 | // Created by AtsuyaSato on 2019/01/31. 6 | // Copyright © 2019 Atsuya Sato. All rights reserved. 7 | // 8 | import CoreGraphics 9 | 10 | extension CGPath: Equatable { 11 | public static func ==(lhs: CGPath, rhs: CGPath) -> Bool { 12 | if lhs.getPathElementsPoints().count != rhs.getPathElementsPoints().count { 13 | return false 14 | } 15 | if lhs.firstPoint != rhs.firstPoint { 16 | return false 17 | } 18 | if lhs.currentPoint != rhs.currentPoint { 19 | return false 20 | } 21 | 22 | for i in 0.. Void) { 56 | typealias Body = @convention(block) (CGPathElement) -> Void 57 | let callback: @convention(c) (UnsafeMutableRawPointer, UnsafePointer) -> Void = { (info, element) in 58 | let body = unsafeBitCast(info, to: Body.self) 59 | body(element.pointee) 60 | } 61 | //print(MemoryLayout.size(ofValue: body)) 62 | let unsafeBody = unsafeBitCast(body, to: UnsafeMutableRawPointer.self) 63 | self.apply(info: unsafeBody, function: unsafeBitCast(callback, to: CGPathApplierFunction.self)) 64 | } 65 | func getPathElementsPoints() -> [CGPoint] { 66 | var arrayPoints : [CGPoint]! = [CGPoint]() 67 | self.forEach { element in 68 | switch (element.type) { 69 | case CGPathElementType.moveToPoint: 70 | arrayPoints.append(element.points[0]) 71 | case .addLineToPoint: 72 | arrayPoints.append(element.points[0]) 73 | case .addQuadCurveToPoint: 74 | arrayPoints.append(element.points[0]) 75 | arrayPoints.append(element.points[1]) 76 | case .addCurveToPoint: 77 | arrayPoints.append(element.points[0]) 78 | arrayPoints.append(element.points[1]) 79 | arrayPoints.append(element.points[2]) 80 | default: break 81 | } 82 | } 83 | return arrayPoints 84 | } 85 | func getPathElementsPointsAndTypes() -> ([CGPoint],[CGPathElementType]) { 86 | var arrayPoints : [CGPoint]! = [CGPoint]() 87 | var arrayTypes : [CGPathElementType]! = [CGPathElementType]() 88 | self.forEach { element in 89 | switch (element.type) { 90 | case CGPathElementType.moveToPoint: 91 | arrayPoints.append(element.points[0]) 92 | arrayTypes.append(element.type) 93 | case .addLineToPoint: 94 | arrayPoints.append(element.points[0]) 95 | arrayTypes.append(element.type) 96 | case .addQuadCurveToPoint: 97 | arrayPoints.append(element.points[0]) 98 | arrayPoints.append(element.points[1]) 99 | arrayTypes.append(element.type) 100 | arrayTypes.append(element.type) 101 | case .addCurveToPoint: 102 | arrayPoints.append(element.points[0]) 103 | arrayPoints.append(element.points[1]) 104 | arrayPoints.append(element.points[2]) 105 | arrayTypes.append(element.type) 106 | arrayTypes.append(element.type) 107 | arrayTypes.append(element.type) 108 | default: break 109 | } 110 | } 111 | return (arrayPoints,arrayTypes) 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /ProcessingKitTests/GestureTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // EventTests.swift 3 | // ProcessingKitTests 4 | // 5 | // Created by AtsuyaSato on 2018/07/04. 6 | // Copyright © 2018年 Atsuya Sato. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import ProcessingKit 11 | 12 | class GestureTests: XCTestCase { 13 | func testFingerPressed() { 14 | let view = ProcessingView(frame: CGRect(x: 0, y: 0, width: 100, height: 100)) 15 | XCTAssertEqual(view.fingerPressed, false) 16 | 17 | view.didTap(recognizer: view.tapGestureWithSingleTouch) 18 | XCTAssertEqual(view.fingerPressed, true) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /ProcessingKitTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /ProcessingKitTests/Input/DateTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DateTests.swift 3 | // ProcessingKitTests 4 | // 5 | // Created by AtsuyaSato on 2017/09/27. 6 | // Copyright © 2017年 Atsuya Sato. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import ProcessingKit 11 | 12 | class DateTests: XCTestCase { 13 | 14 | override func setUp() { 15 | super.setUp() 16 | } 17 | 18 | override func tearDown() { 19 | super.tearDown() 20 | } 21 | 22 | func testDateValue() { 23 | var components = DateComponents() 24 | components.year = 2017 25 | components.month = 5 26 | components.day = 20 27 | components.hour = 22 28 | components.minute = 50 29 | components.second = 10 30 | 31 | let calendar = Calendar(identifier: .gregorian) 32 | let date = calendar.date(from: components) 33 | 34 | guard let currentDate = date else { 35 | XCTFail() 36 | return 37 | } 38 | 39 | let dateModel = DateModel(startDate: Date(), currentDate: currentDate) 40 | 41 | XCTAssertEqual(dateModel.year(), 2017) 42 | XCTAssertEqual(dateModel.month(), 5) 43 | XCTAssertEqual(dateModel.day(), 20) 44 | XCTAssertEqual(dateModel.hour(), 22) 45 | XCTAssertEqual(dateModel.minute(), 50) 46 | XCTAssertEqual(dateModel.second(), 10) 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /ProcessingKitTests/ProcessingViewDelegateSpy.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ProcessingViewDelegateSpy.swift 3 | // ProcessingKitTests 4 | // 5 | // Created by AtsuyaSato on 2017/09/26. 6 | // Copyright © 2017年 Atsuya Sato. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import ProcessingKit 11 | 12 | class ProcessingViewDelegateSetupSpy: ProcessingViewDelegate { 13 | private let exception: XCTestExpectation 14 | private(set) var spyHistory: [Any] = [] 15 | 16 | init(exception: XCTestExpectation) { 17 | self.exception = exception 18 | } 19 | 20 | func setup() { 21 | self.record(()) 22 | exception.fulfill() 23 | } 24 | 25 | private func record(_ args: Void) { 26 | self.spyHistory += [args] 27 | } 28 | } 29 | 30 | class ProcessingViewDelegateDrawSpy: ProcessingViewDelegate { 31 | private let exception: XCTestExpectation 32 | private(set) var spyHistory: [Any] = [] 33 | 34 | init(exception: XCTestExpectation) { 35 | self.exception = exception 36 | } 37 | 38 | func setup() { 39 | self.record(()) 40 | } 41 | 42 | func draw() { 43 | self.record(()) 44 | exception.fulfill() 45 | } 46 | private func record(_ args: Void) { 47 | self.spyHistory += [args] 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /ProcessingKitTests/ProcessingViewTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ProcessingViewTests.swift 3 | // ProcessingViewTests 4 | // 5 | // Created by AtsuyaSato on 2017/08/04. 6 | // Copyright © 2017年 Atsuya Sato. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import ProcessingKit 11 | 12 | class ProcessingViewTests: XCTestCase { 13 | 14 | override func setUp() { 15 | super.setUp() 16 | } 17 | 18 | override func tearDown() { 19 | super.tearDown() 20 | } 21 | 22 | func testCallSetup() { 23 | let view = ProcessingView(frame: CGRect.zero) 24 | 25 | let processingViewDelegateSpy = ProcessingViewDelegateSetupSpy(exception: 26 | expectation(description: "Setup") 27 | ) 28 | view.delegate = processingViewDelegateSpy 29 | waitForExpectations(timeout: 100) 30 | XCTAssertEqual(processingViewDelegateSpy.spyHistory.count, 1) 31 | } 32 | 33 | func testCallDraw() { 34 | let view = ProcessingView(frame: CGRect.zero) 35 | 36 | let processingViewDelegateSpy = ProcessingViewDelegateDrawSpy(exception: 37 | expectation(description: "Draw") 38 | ) 39 | view.delegate = processingViewDelegateSpy 40 | waitForExpectations(timeout: 100) 41 | print(processingViewDelegateSpy.spyHistory.count) 42 | XCTAssertEqual(processingViewDelegateSpy.spyHistory.count, 2) 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /ProcessingKitTests/TransformTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TransformTests.swift 3 | // ProcessingKitTests 4 | // 5 | // Created by AtsuyaSato on 2018/01/14. 6 | // Copyright © 2018年 Atsuya Sato. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import ProcessingKit 11 | 12 | /* Quartz 2D 13 | https://developer.apple.com/library/content/documentation/GraphicsImaging/Conceptual/drawingwithquartz2d/dq_affine/dq_affine.html 14 | 15 | | a b 0 | 16 | [x' y' 1] = [x y 1] × | c d 0 | 17 | | tx ty 1 | 18 | 19 | y 20 | ^ 21 | | 22 | | 23 | 0ーーーー> x 24 | */ 25 | 26 | enum Transform { 27 | case translate(x: CGFloat, y: CGFloat) 28 | case rotate(angle: CGFloat) 29 | case shear(angleX: CGFloat, angleY: CGFloat) 30 | case scale(x: CGFloat, y: CGFloat) 31 | } 32 | 33 | class ProcessingViewDelegateTransformSpy: ProcessingViewDelegate { 34 | private let exception: XCTestExpectation 35 | private let view: ProcessingView 36 | private let transform: Transform 37 | private(set) var context: CGContext? 38 | 39 | init(exception: XCTestExpectation, view: ProcessingView, transform: Transform) { 40 | self.exception = exception 41 | self.view = view 42 | self.transform = transform 43 | } 44 | 45 | func setup() { 46 | switch transform { 47 | case .translate(let x, let y): 48 | self.view.translate(x, y) 49 | case .rotate(let angle): 50 | self.view.rotate(angle) 51 | case .shear(let x, let y): 52 | self.view.shear(x, y) 53 | case .scale(let x, let y): 54 | self.view.scale(x, y) 55 | } 56 | self.record(UIGraphicsGetCurrentContext()) 57 | exception.fulfill() 58 | } 59 | 60 | private func record(_ arg: CGContext?) { 61 | self.context = arg 62 | } 63 | } 64 | 65 | class TransformTests: XCTestCase { 66 | let radians = { (angle: CGFloat) -> CGFloat in 67 | return .pi * angle / 360 68 | } 69 | 70 | override func setUp() { 71 | super.setUp() 72 | } 73 | 74 | override func tearDown() { 75 | super.tearDown() 76 | } 77 | 78 | func testTranslate() { 79 | let testCases: [UInt: TestCase] = [ 80 | #line: TestCase( 81 | description: "Move 100pt to the right", 82 | transform: .translate(x: 100.0, y: 0.0), 83 | expect: CGAffineTransform(a: 1.0, b: 0.0, c: 0.0, d: 1.0, tx: 100.0, ty: 0.0) 84 | ), 85 | #line: TestCase( 86 | description: "Move 50pt to the bottom", 87 | transform: .translate(x: 0.0, y: 50.0), 88 | expect: CGAffineTransform(a: 1.0, b: 0.0, c: 0.0, d: 1.0, tx: 0.0, ty: -50.0) 89 | ), 90 | #line: TestCase( 91 | description: "Move 40pt to the left, 20pt to the top", 92 | transform: .translate(x: -40.0, y: -20.0), 93 | expect: CGAffineTransform(a: 1.0, b: 0.0, c: 0.0, d: 1.0, tx: -40.0, ty: 20.0) 94 | ), 95 | ] 96 | 97 | check(testCases: testCases) 98 | } 99 | 100 | func testRotate() { 101 | let testCases: [UInt: TestCase] = [ 102 | #line: TestCase( 103 | description: "Rotate by 90 degrees", 104 | transform: .rotate(angle: radians(90)), 105 | expect: CGAffineTransform(a: cos(radians(90)), b: -sin(radians(90)), c: sin(radians(90)), d: cos(radians(90)), tx: 0.0, ty: 0.0) 106 | ), 107 | #line: TestCase( 108 | description: "Rotate by 360 degrees", 109 | transform: .rotate(angle: radians(360)), 110 | expect: CGAffineTransform(a: cos(radians(360)), b: -sin(radians(360)), c: sin(radians(360)), d: cos(radians(360)), tx: 0.0, ty: 0.0) 111 | ), 112 | #line: TestCase( 113 | description: "Rotate by -90 degrees", 114 | transform: .rotate(angle: radians(-90)), 115 | expect: CGAffineTransform(a: cos(radians(-90)), b: -sin(radians(-90)), c: sin(radians(-90)), d: cos(radians(-90)), tx: 0.0, ty: 0.0) 116 | ), 117 | ] 118 | 119 | check(testCases: testCases) 120 | } 121 | 122 | func testShear() { 123 | let testCases: [UInt: TestCase] = [ 124 | #line: TestCase( 125 | description: "x-shear angle to 30°", 126 | transform: .shear(angleX: radians(30), angleY: radians(0)), 127 | expect: CGAffineTransform(a: 1.0, b: tan(radians(-0)), c: tan(radians(-30)), d: 1.0, tx: 0.0, ty: 0.0) 128 | ), 129 | #line: TestCase( 130 | description: "y-shear angle to 60°", 131 | transform: .shear(angleX: radians(0), angleY: radians(60)), 132 | expect: CGAffineTransform(a: 1.0, b: tan(radians(-60)), c: tan(radians(-0)), d: 1.0, tx: 0.0, ty: 0.0) 133 | ), 134 | #line: TestCase( 135 | description: "x-shear angle to 45° & y-shear angle to 45°", 136 | transform: .shear(angleX: radians(45), angleY: radians(45)), 137 | expect: CGAffineTransform(a: 1.0, b: tan(radians(-45)), c: tan(radians(-45)), d: 1.0, tx: 0.0, ty: 0.0) 138 | ), 139 | ] 140 | check(testCases: testCases) 141 | } 142 | 143 | func testScale() { 144 | let testCases: [UInt: TestCase] = [ 145 | #line: TestCase( 146 | description: "Scale width by 2.0 times", 147 | transform: .scale(x: 2.0, y: 1.0), 148 | expect: CGAffineTransform(a: 2.0, b: 0.0, c: 0.0, d: 1.0, tx: 0.0, ty: 0.0) 149 | ), 150 | #line: TestCase( 151 | description: "Scale width by 0.5 times, height by 2.0 times", 152 | transform: .scale(x: 0.5, y: 2.0), 153 | expect: CGAffineTransform(a: 0.5, b: 0.0, c: 0.0, d: 2.0, tx: 0.0, ty: 0.0) 154 | ), 155 | #line: TestCase( 156 | description: "Scale width by -2.0 times", 157 | transform: .scale(x: -2.0, y: 1.0), 158 | expect: CGAffineTransform(a: -2.0, b: 0.0, c: 0.0, d: 1.0, tx: 0.0, ty: 0.0) 159 | ), 160 | ] 161 | check(testCases: testCases) 162 | } 163 | 164 | func check(testCases: [UInt: TestCase]) { 165 | _ = testCases.map { (line, testCase) in 166 | let view = ProcessingView(frame: CGRect(x: 0, y: 0, width: 100, height: 100)) 167 | 168 | let transformDelegateSpy = ProcessingViewDelegateTransformSpy( 169 | exception: expectation(description: testCase.description), 170 | view: view, 171 | transform: testCase.transform 172 | ) 173 | 174 | view.delegate = transformDelegateSpy 175 | waitForExpectations(timeout: 100) 176 | 177 | let actual = transformDelegateSpy.context?.ctm 178 | // Multiply scale(1.0, -1.0), translate(0.0, 100.0) and expect together for coordinate system 179 | let expected = CGAffineTransform(a: 1.0, b: 0.0, c: -0.0, d: -1.0, tx: 0.0, ty: 0.0).concatenating(testCase.expect.concatenating(CGAffineTransform(a: 1.0, b: 0.0, c: 0.0, d: 1.0, tx: 0.0, ty: 100.0))) 180 | 181 | XCTAssertEqual(actual, expected, String(line)) 182 | } 183 | } 184 | 185 | struct TestCase { 186 | let description: String 187 | let transform: Transform 188 | let expect: CGAffineTransform 189 | } 190 | } 191 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![Header](https://github.com/natmark/ProcessingKit/blob/master/Resources/ProcessingKit-Header.png?raw=true) 2 | 3 |

4 | 5 | Build Status 7 | 8 | 9 | Pods Version 11 | 12 | 13 | Platforms 15 | 16 | 17 | Swift 18 | 19 | 20 | Carthage Compatible 22 | 23 | 24 | codecov 25 | 26 |

27 | 28 | ---------------- 29 | 30 | # ProcessingKit 31 | ProcessingKit is a Visual designing library for iOS & OSX. 32 | ProcessingKit written in Swift🐧 and you can write like [processing](https://github.com/processing/processing). 33 | 34 | ## Demo 35 | ![Demo](https://github.com/natmark/ProcessingKit/blob/master/Resources/demo.gif?raw=true) 36 | 37 | ### Demo Apps 38 | - [iOS Official Demo](https://github.com/natmark/ProcessingKit/tree/master/ProcessingKitExample) 39 | - [OSX Official Demo](https://github.com/natmark/ProcessingKit/tree/master/ProcessingKitOSXExample) 40 | 41 | 42 | #### [iPad Demo App (Developed for Open Source Conference)](https://github.com/natmark/OSCProcessingKitDemo) 43 | 44 | |Sketch Runner|Code Comparison (between Processing and ProcessingKit)| 45 | |:------------:|:----------------------------------------------------:| 46 | |![](https://raw.githubusercontent.com/natmark/OSCProcessingKitDemo/master/Resources/screenshot1.png)|![](https://raw.githubusercontent.com/natmark/OSCProcessingKitDemo/master/Resources/screenshot2.png)| 47 | 48 | ## Example 49 | |OS|gif|code| 50 | |:---:|:------:|:------:| 51 | |iOS| gif | ![code](https://raw.githubusercontent.com/natmark/ProcessingKit/master/Resources/iOS_ExampleCode.png)| 52 | |OSX| ![gif](https://raw.githubusercontent.com/natmark/ProcessingKit/master/Resources/OSX_Example.gif) | ![code](https://raw.githubusercontent.com/natmark/ProcessingKit/master/Resources/OSX_ExampleCode.png)| 53 | 54 | ## Requirements 55 | - Swift 3.0 or later 56 | - iOS 10.0 or later 57 | - OSX 10.11 or later 58 | 59 | If you use Swift 3.x, try [ProcessingKit 0.6.0](https://github.com/natmark/ProcessingKit/releases/tag/0.6.0). 60 | 61 | ## Usage 62 | 1. Create custom class that inherits from ProcessingView 63 | 64 | ```Swift 65 | import ProcessingKit 66 | 67 | class SampleView: ProcessingView { 68 | func setup() { 69 | // The setup() function is run once, when the view instantiated. 70 | } 71 | func draw() { 72 | // Called directly after setup(), the draw() function continuously executes the lines of code contained inside its block until the program is stopped or noLoop() is called. 73 | } 74 | } 75 | ``` 76 | 77 | 2. Create a SampleView instance 78 | ### Create programmatically 79 | ```Swift 80 | lazy var sampleView: SampleView = { 81 | let sampleView = SampleView(frame: frame) 82 | sampleView.isUserInteractionEnabled = true // If you want to use touch events (default true) 83 | return sampleView 84 | }() 85 | ``` 86 | 87 | ### Use InterfaceBuilder 88 | 89 | 1. Add UIView to ViewController 90 | 2. Select UIView & Open Identity inspector 91 | 3. Set SampleView to Custom class field 92 | 4. Add outlet connection 93 | 94 | ```Swift 95 | @IBOutlet weak var sampleView: SampleView! 96 | 97 | override func viewDidLoad() { 98 | super.viewDidLoad() 99 | sampleView.isUserInteractionEnabled = true // If you want to use touch events (default true) 100 | } 101 | ``` 102 | 103 | ## Installation 104 | 105 | ### [CocoaPods](http://cocoadocs.org/docsets/ProcessingKit/) 106 | Add the following to your `Podfile`: 107 | ``` 108 | pod "ProcessingKit" 109 | ``` 110 | 111 | - (Example project here: [PKPodsExample](https://github.com/natmark/PKPodsExample)) 112 | 113 | ### [Carthage](https://github.com/Carthage/Carthage) 114 | Add the following to your `Cartfile`: 115 | ``` 116 | github "natmark/ProcessingKit" 117 | ``` 118 | 119 | - (Example project here: [PKExample](https://github.com/natmark/PKExample)) 120 | 121 | ## Xcode File Template 122 | - `ProcessingKit.xctemplate` is available. 123 | - Use [Donut](https://github.com/natmark/Donut)(Xcode file template manager) to install. 124 | 125 | `$ donut install https://github.com/natmark/ProcessingKit` 126 | 127 | ## Documentation 128 | - [ProcessingKit/wiki](https://github.com/natmark/ProcessingKit/wiki) 129 | 130 | ## License 131 | ProcessingKit is available under the MIT license. See the LICENSE file for more info. 132 | -------------------------------------------------------------------------------- /Resources/OSX_Example.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/natmark/ProcessingKit/0cc2a6fa90c69ba218df96644b0b496bf399b36a/Resources/OSX_Example.gif -------------------------------------------------------------------------------- /Resources/OSX_ExampleCode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/natmark/ProcessingKit/0cc2a6fa90c69ba218df96644b0b496bf399b36a/Resources/OSX_ExampleCode.png -------------------------------------------------------------------------------- /Resources/ProcessingKit-Header.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/natmark/ProcessingKit/0cc2a6fa90c69ba218df96644b0b496bf399b36a/Resources/ProcessingKit-Header.png -------------------------------------------------------------------------------- /Resources/Storyboard-Usage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/natmark/ProcessingKit/0cc2a6fa90c69ba218df96644b0b496bf399b36a/Resources/Storyboard-Usage.png -------------------------------------------------------------------------------- /Resources/demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/natmark/ProcessingKit/0cc2a6fa90c69ba218df96644b0b496bf399b36a/Resources/demo.gif -------------------------------------------------------------------------------- /Resources/iOS_Example.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/natmark/ProcessingKit/0cc2a6fa90c69ba218df96644b0b496bf399b36a/Resources/iOS_Example.gif -------------------------------------------------------------------------------- /Resources/iOS_ExampleCode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/natmark/ProcessingKit/0cc2a6fa90c69ba218df96644b0b496bf399b36a/Resources/iOS_ExampleCode.png --------------------------------------------------------------------------------