├── Cartfile ├── Cartfile.resolved ├── Images ├── screen1.png ├── screen2.png ├── screen3.png └── pencilcup.png ├── Example ├── PencilCup.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── PencilCup.xcscmblueprint ├── PencilCup.xcodeproj │ ├── project.xcworkspace │ │ └── contents.xcworkspacedata │ ├── xcshareddata │ │ └── xcschemes │ │ │ └── PencilCup-Example.xcscheme │ └── project.pbxproj └── PencilCup │ ├── Drawable.swift │ ├── Images.xcassets │ └── AppIcon.appiconset │ │ └── Contents.json │ ├── Info.plist │ ├── ColorViewController.swift │ ├── AppDelegate.swift │ ├── PencilCupView.swift │ ├── DrawView.swift │ ├── Base.lproj │ ├── LaunchScreen.xib │ └── Main.storyboard │ ├── CoreGraphicsView.swift │ └── InkWell.swift ├── .travis.yml ├── Sources ├── ContextRect.swift ├── ContextPoint.swift ├── ContextMisc.swift ├── ContextPath.swift └── ContextRef.swift ├── .gitignore ├── XcodeSnippets ├── PencilCup_Dot.codesnippet ├── PencilCup_FillPath.codesnippet ├── PencilCup_StrokePath.codesnippet ├── PencilCup_MoveToPoint.codesnippet ├── PencilCup_AddLineToPoint.codesnippet └── PencilCup_AddCurveToPoint.codesnippet ├── LICENSE └── README.md /Cartfile: -------------------------------------------------------------------------------- 1 | github "joalbright/Inlinit" 2 | -------------------------------------------------------------------------------- /Cartfile.resolved: -------------------------------------------------------------------------------- 1 | github "joalbright/Inlinit" "0.1.3" 2 | -------------------------------------------------------------------------------- /Images/screen1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joalbright/PencilCup/HEAD/Images/screen1.png -------------------------------------------------------------------------------- /Images/screen2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joalbright/PencilCup/HEAD/Images/screen2.png -------------------------------------------------------------------------------- /Images/screen3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joalbright/PencilCup/HEAD/Images/screen3.png -------------------------------------------------------------------------------- /Images/pencilcup.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joalbright/PencilCup/HEAD/Images/pencilcup.png -------------------------------------------------------------------------------- /Example/PencilCup.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Example/PencilCup.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # references: 2 | # * http://www.objc.io/issue-6/travis-ci.html 3 | # * https://github.com/supermarin/xcpretty#usage 4 | 5 | language: objective-c 6 | # cache: cocoapods 7 | # podfile: Example/Podfile 8 | # before_install: 9 | # - gem install cocoapods # Since Travis is not always on latest version 10 | # - pod install --project-directory=Example 11 | script: 12 | - set -o pipefail && xcodebuild test -workspace Example/PencilCup.xcworkspace -scheme PencilCup-Example -sdk iphonesimulator ONLY_ACTIVE_ARCH=NO | xcpretty 13 | - pod lib lint 14 | -------------------------------------------------------------------------------- /Example/PencilCup/Drawable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Drawable.swift 3 | // PencilCup 4 | // 5 | // Created by Jo Albright on 1/6/16. 6 | // Copyright © 2016 Jo Albright. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | public protocol Drawable { 12 | 13 | } 14 | 15 | extension Drawable { 16 | 17 | public func drawLines(_ context: CGContext?, lines: [CGLine]) { 18 | 19 | _ = context?.round() 20 | 21 | for line in lines { 22 | 23 | _ = line.drawPoints(context?.color(line.fill))?.fill() 24 | _ = line.drawPoints(context?.color(line.stroke))?.line(line.strokeWidth)?.stroke() 25 | 26 | } 27 | 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /Example/PencilCup/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | } 33 | ], 34 | "info" : { 35 | "version" : 1, 36 | "author" : "xcode" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Sources/ContextRect.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ContextRect.swift 3 | // PencilCup 4 | // 5 | // Created by Jo Albright on 1/4/16. 6 | // Copyright © 2016 Jo Albright. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | extension CGRect { 12 | 13 | var center: CGPoint { return CGPoint(x: midX, y: midY) } 14 | 15 | /// Inset all four sides with d 16 | func inset(_ d: CGFloat) -> CGRect { 17 | 18 | return insetBy(dx: d, dy: d) 19 | 20 | } 21 | 22 | func pointOnCircleInRect(_ degree: CGFloat) -> CGPoint { 23 | 24 | return CGPoint { 25 | 26 | $0.x = (width) * cos(degree * CGFloat(M_PI / 180)) / 2 + center.x 27 | $0.y = (height) * sin(degree * CGFloat(M_PI / 180)) / 2 + center.y 28 | 29 | } 30 | 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # OS X 2 | .DS_Store 3 | 4 | # Xcode 5 | build/ 6 | *.pbxuser 7 | !default.pbxuser 8 | *.mode1v3 9 | !default.mode1v3 10 | *.mode2v3 11 | !default.mode2v3 12 | *.perspectivev3 13 | !default.perspectivev3 14 | xcuserdata 15 | *.xccheckout 16 | profile 17 | *.moved-aside 18 | DerivedData 19 | *.hmap 20 | *.ipa 21 | 22 | # Bundler 23 | .bundle 24 | 25 | Carthage 26 | # We recommend against adding the Pods directory to your .gitignore. However 27 | # you should judge for yourself, the pros and cons are mentioned at: 28 | # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control 29 | # 30 | # Note: if you ignore the Pods directory, make sure to uncomment 31 | # `pod install` in .travis.yml 32 | # 33 | # Pods/ 34 | 35 | .build/ 36 | Packages/ 37 | 38 | _Pods.xcodeproj 39 | 40 | PencilCup.podspec 41 | -------------------------------------------------------------------------------- /XcodeSnippets/PencilCup_Dot.codesnippet: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDECodeSnippetCompletionPrefix 6 | dot 7 | IDECodeSnippetCompletionScopes 8 | 9 | CodeBlock 10 | 11 | IDECodeSnippetContents 12 | -•- <# Point #> 13 | IDECodeSnippetIdentifier 14 | 5A77FBC3-7A17-4E47-A204-AB9EA87A42F9 15 | IDECodeSnippetLanguage 16 | Xcode.SourceCodeLanguage.Swift 17 | IDECodeSnippetTitle 18 | CGContext Dot 19 | IDECodeSnippetUserSnippet 20 | 21 | IDECodeSnippetVersion 22 | 2 23 | 24 | 25 | -------------------------------------------------------------------------------- /XcodeSnippets/PencilCup_FillPath.codesnippet: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDECodeSnippetCompletionPrefix 6 | fill 7 | IDECodeSnippetCompletionScopes 8 | 9 | All 10 | 11 | IDECodeSnippetContents 12 | -■ <# Next #> 13 | IDECodeSnippetIdentifier 14 | B285393C-2754-449F-9C7B-3CA7E97C99AC 15 | IDECodeSnippetLanguage 16 | Xcode.SourceCodeLanguage.Swift 17 | IDECodeSnippetTitle 18 | CGContext Fill Path 19 | IDECodeSnippetUserSnippet 20 | 21 | IDECodeSnippetVersion 22 | 2 23 | 24 | 25 | -------------------------------------------------------------------------------- /XcodeSnippets/PencilCup_StrokePath.codesnippet: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDECodeSnippetCompletionPrefix 6 | stroke 7 | IDECodeSnippetCompletionScopes 8 | 9 | All 10 | 11 | IDECodeSnippetContents 12 | -□ <# Next #> 13 | IDECodeSnippetIdentifier 14 | 6B13E7EA-064D-42B8-9E95-32755C14433C 15 | IDECodeSnippetLanguage 16 | Xcode.SourceCodeLanguage.Swift 17 | IDECodeSnippetTitle 18 | CGContext Stroke Path 19 | IDECodeSnippetUserSnippet 20 | 21 | IDECodeSnippetVersion 22 | 2 23 | 24 | 25 | -------------------------------------------------------------------------------- /Sources/ContextPoint.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ContexCGPoint.swift 3 | // PencilCup 4 | // 5 | // Created by Jo Albright on 1/6/16. 6 | // Copyright © 2016 Jo Albright. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | extension CGPoint: Inlinit { } 12 | 13 | public struct CGLine: Inlinit { 14 | 15 | public var points: [CGPoint] = [] 16 | public var strokeWidth: CGFloat = 0 17 | 18 | public var fill: CGColor? 19 | public var stroke: CGColor? 20 | 21 | public init() { } 22 | 23 | public func drawPoints(_ context: CGContext?) -> CGContext? { 24 | 25 | for (p,point) in points.enumerated() { 26 | 27 | if point == .zero { continue } 28 | _ = p == 0 ? { context ->- point }() : { context -+- point }() 29 | 30 | } 31 | 32 | return context 33 | 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /XcodeSnippets/PencilCup_MoveToPoint.codesnippet: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDECodeSnippetCompletionPrefix 6 | move 7 | IDECodeSnippetCompletionScopes 8 | 9 | All 10 | 11 | IDECodeSnippetContents 12 | ->- <# Move to Point #> 13 | IDECodeSnippetIdentifier 14 | FE81D6E4-A12B-485E-869F-650D96FD9DA1 15 | IDECodeSnippetLanguage 16 | Xcode.SourceCodeLanguage.Swift 17 | IDECodeSnippetTitle 18 | CGContext Move to Point 19 | IDECodeSnippetUserSnippet 20 | 21 | IDECodeSnippetVersion 22 | 2 23 | 24 | 25 | -------------------------------------------------------------------------------- /XcodeSnippets/PencilCup_AddLineToPoint.codesnippet: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDECodeSnippetCompletionPrefix 6 | add 7 | IDECodeSnippetCompletionScopes 8 | 9 | All 10 | 11 | IDECodeSnippetContents 12 | -+- <# Add Line to Point #> 13 | IDECodeSnippetIdentifier 14 | 7D6F57D2-BC92-4ECE-B768-C33E0DD73607 15 | IDECodeSnippetLanguage 16 | Xcode.SourceCodeLanguage.Swift 17 | IDECodeSnippetTitle 18 | CGContext Add Line to Point 19 | IDECodeSnippetUserSnippet 20 | 21 | IDECodeSnippetVersion 22 | 2 23 | 24 | 25 | -------------------------------------------------------------------------------- /XcodeSnippets/PencilCup_AddCurveToPoint.codesnippet: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDECodeSnippetCompletionPrefix 6 | add 7 | IDECodeSnippetCompletionScopes 8 | 9 | All 10 | 11 | IDECodeSnippetContents 12 | -~- <# Add Curve to Point #> 13 | IDECodeSnippetIdentifier 14 | 168A4F19-B263-433B-B33D-F653800E8AA7 15 | IDECodeSnippetLanguage 16 | Xcode.SourceCodeLanguage.Swift 17 | IDECodeSnippetTitle 18 | CGContext Add Curve to Point 19 | IDECodeSnippetUserSnippet 20 | 21 | IDECodeSnippetVersion 22 | 2 23 | 24 | 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016 Jo Albright 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /Example/PencilCup/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 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /Example/PencilCup/ColorViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ColorViewController.swift 3 | // PencilCup 4 | // 5 | // Created by Jo Albright on 1/8/16. 6 | // Copyright © 2016 CocoaPods. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class ColorViewController: UIViewController { 12 | 13 | @IBOutlet weak var wheel: ColorWheel! 14 | 15 | @IBOutlet weak var hueBar: ColorBar! 16 | 17 | @IBOutlet weak var saturationBar: ColorBar! 18 | 19 | @IBOutlet weak var brightnessBar: ColorBar! 20 | 21 | @IBOutlet weak var alphaBar: ColorBar! 22 | 23 | override func viewDidLoad() { 24 | super.viewDidLoad() 25 | 26 | // Do any additional setup after loading the view. 27 | } 28 | 29 | @IBAction func hueChanged(_ bar: ColorBar) { 30 | 31 | print(bar.value) 32 | 33 | saturationBar.h = bar.value / 360 34 | brightnessBar.h = bar.value / 360 35 | alphaBar.h = bar.value / 360 36 | 37 | } 38 | 39 | @IBAction func brightnessChanged(_ bar: ColorBar) { 40 | 41 | saturationBar.b = bar.value 42 | alphaBar.b = bar.value 43 | 44 | 45 | } 46 | 47 | @IBAction func saturationChanged(_ bar: ColorBar) { 48 | 49 | brightnessBar.s = bar.value 50 | alphaBar.s = bar.value 51 | 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /Example/PencilCup.xcworkspace/xcshareddata/PencilCup.xcscmblueprint: -------------------------------------------------------------------------------- 1 | { 2 | "DVTSourceControlWorkspaceBlueprintPrimaryRemoteRepositoryKey" : "F423E37263D1CD1B20A383A95421A3124300B2D8", 3 | "DVTSourceControlWorkspaceBlueprintWorkingCopyRepositoryLocationsKey" : { 4 | 5 | }, 6 | "DVTSourceControlWorkspaceBlueprintWorkingCopyStatesKey" : { 7 | "F423E37263D1CD1B20A383A95421A3124300B2D8" : 9223372036854775807, 8 | "BC7D22AD9EBFA3958907C65E8D59AF07B67456E4" : 9223372036854775807 9 | }, 10 | "DVTSourceControlWorkspaceBlueprintIdentifierKey" : "F90C44F9-36AD-4600-B650-8C2148F32A71", 11 | "DVTSourceControlWorkspaceBlueprintWorkingCopyPathsKey" : { 12 | "F423E37263D1CD1B20A383A95421A3124300B2D8" : "PencilCup\/", 13 | "BC7D22AD9EBFA3958907C65E8D59AF07B67456E4" : "Relax\/" 14 | }, 15 | "DVTSourceControlWorkspaceBlueprintNameKey" : "PencilCup", 16 | "DVTSourceControlWorkspaceBlueprintVersion" : 204, 17 | "DVTSourceControlWorkspaceBlueprintRelativePathToProjectKey" : "Example\/PencilCup.xcworkspace", 18 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoriesKey" : [ 19 | { 20 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/joalbright\/Relax.git", 21 | "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git", 22 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "BC7D22AD9EBFA3958907C65E8D59AF07B67456E4" 23 | }, 24 | { 25 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/joalbright\/PencilCup.git", 26 | "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git", 27 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "F423E37263D1CD1B20A383A95421A3124300B2D8" 28 | } 29 | ] 30 | } -------------------------------------------------------------------------------- /Sources/ContextMisc.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ContextMisc.swift 3 | // PencilCup 4 | // 5 | // Created by Jo Albright on 10/28/15. 6 | // Copyright © 2015 Jo Albright. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | typealias TPoint = (x: CGFloat, y: CGFloat) 12 | public typealias TCurve = (a1: CGPoint, a2: CGPoint, p: CGPoint) 13 | public typealias TSize = (width: CGFloat, height: CGFloat) 14 | public typealias TScale = (x: CGFloat, y: CGFloat) 15 | public typealias TDelta = (dx: CGFloat, dy: CGFloat) 16 | 17 | /// Update left CGPoint with offset of right CGPoint 18 | public func += (lhs: inout CGPoint, rhs: CGPoint) { 19 | 20 | lhs.x += rhs.x; lhs.y += rhs.y 21 | 22 | } 23 | 24 | /// Add right point to left point 25 | /// - returns: CGPoint 26 | public func + (lhs: CGPoint, rhs: CGPoint) -> CGPoint { 27 | 28 | return CGPoint(x: lhs.x + rhs.x, y: lhs.y + rhs.y) 29 | 30 | } 31 | 32 | /// Subtract right point from left point 33 | /// - returns: CGPoint 34 | public func - (lhs: CGPoint, rhs: CGPoint) -> CGPoint { 35 | 36 | return CGPoint(x: lhs.x - rhs.x, y: lhs.y - rhs.y) 37 | 38 | } 39 | 40 | /// Multiple right to left (x&&y) 41 | public func * (lhs: CGPoint, rhs: CGFloat) -> CGPoint { 42 | 43 | return CGPoint(x: lhs.x * rhs, y: lhs.y * rhs) 44 | 45 | } 46 | 47 | // MARK: - CGSize Operators 48 | 49 | /// Scale a CGSize by CGFloat value 50 | /// - returns: CGSize 51 | public func * (lhs: CGSize, rhs: CGFloat) -> CGSize { 52 | 53 | return CGSize(width: lhs.width * rhs, height: lhs.height * rhs) 54 | 55 | } 56 | 57 | /// Scale a CGSize by CGFloat value 58 | /// - returns: CGSize 59 | public func * (lhs: TSize, rhs: CGFloat) -> TSize { 60 | 61 | return (width: lhs.width * rhs, height: lhs.height * rhs) 62 | 63 | } 64 | 65 | 66 | extension CGFloat { 67 | 68 | init(_ n: CGFloat, min: CGFloat, max: CGFloat) { 69 | 70 | self = n 71 | if n < min { self = min } 72 | if n > max { self = max } 73 | 74 | } 75 | 76 | init(_ n: CGFloat, range: Range) { 77 | 78 | self = n 79 | if n < CGFloat(range.lowerBound) { self = CGFloat(range.lowerBound) } 80 | if n > CGFloat(range.upperBound) { self = CGFloat(range.upperBound) } 81 | 82 | } 83 | 84 | } 85 | -------------------------------------------------------------------------------- /Example/PencilCup/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // PencilCup 4 | // 5 | // Created by Jo Albright on 01/05/2016. 6 | // Copyright (c) 2016 Jo Albright. 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: [UIApplicationLaunchOptionsKey: 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 throttle down OpenGL ES frame rates. 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 inactive 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 | -------------------------------------------------------------------------------- /Sources/ContextPath.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ContextPath.swift 3 | // PencilCup 4 | // 5 | // Created by Jo Albright on 1/4/16. 6 | // Copyright © 2016 Jo Albright. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | 12 | /// Move To Point Operator 13 | infix operator ->- : AdditionPrecedence 14 | 15 | /// CGContext Move To Point 16 | func ->- (lhs: CGContext?, rhs: CGPoint) -> CGContext? { 17 | 18 | lhs?.move(to: rhs); return lhs 19 | 20 | } 21 | 22 | func ->- (lhs: CGContext?, rhs: TPoint) -> CGContext? { 23 | 24 | lhs?.move(to: CGPoint(x: rhs.x, y: rhs.y)); return lhs 25 | 26 | } 27 | 28 | 29 | /// Add Line To Point Operator 30 | infix operator -+- : AdditionPrecedence 31 | 32 | /// CGContext Add Line To Point 33 | func -+- (lhs: CGContext?, rhs: CGPoint) -> CGContext? { 34 | 35 | lhs?.addLine(to: rhs); return lhs 36 | 37 | } 38 | 39 | func -+- (lhs: CGContext?, rhs: TPoint) -> CGContext? { 40 | 41 | lhs?.addLine(to: CGPoint(x: rhs.x, y: rhs.y)); return lhs 42 | 43 | } 44 | 45 | 46 | /// Add Curve To Point Operator 47 | infix operator -~- : AdditionPrecedence 48 | 49 | /// Add Curve To Point 50 | func -~- (lhs: CGContext?, rhs: (CGPoint,CGPoint,CGPoint)) -> CGContext? { 51 | 52 | lhs?.addCurve(to: rhs.2, control1: rhs.0, control2: rhs.1); return lhs 53 | 54 | } 55 | 56 | func -~- (lhs: CGContext?, rhs: (TPoint,TPoint,TPoint)) -> CGContext? { 57 | 58 | lhs?.addCurve(to: CGPoint(x: rhs.2.x, y: rhs.2.y), control1: CGPoint(x: rhs.0.x, y: rhs.0.y), control2: CGPoint(x: rhs.1.x, y: rhs.1.y)); return lhs 59 | 60 | } 61 | 62 | func -~- (lhs: CGContext?, rhs: (CGFloat,CGFloat,CGFloat,CGFloat,CGFloat,CGFloat)) -> CGContext? { 63 | 64 | lhs?.addCurve(to: CGPoint(x: rhs.4, y: rhs.5), control1: CGPoint(x: rhs.0, y: rhs.1), control2: CGPoint(x: rhs.2, y: rhs.3)); return lhs 65 | 66 | } 67 | 68 | 69 | /// Dot Operator 70 | /// - description : Line with start and end points that are equal with a stroke width and round cap. 71 | infix operator -•- : AdditionPrecedence 72 | 73 | /// CGContext Create Dot : Diameter = Stroke Width 74 | func -•- (lhs: CGContext?, rhs: CGPoint) -> CGContext? { 75 | 76 | return lhs ->- rhs -+- rhs -□ nil 77 | 78 | } 79 | 80 | 81 | /// Fill Path Operator 82 | infix operator -■ : AdditionPrecedence 83 | 84 | /// CGContext Fill Path 85 | /// - discussion : rhs gets set before fill 86 | func -■ (lhs: CGContext?, rhs: CGColor?) -> CGContext? { 87 | 88 | if let rhs = rhs { lhs?.setFillColor(rhs) } 89 | lhs?.fillPath(); return lhs 90 | 91 | } 92 | 93 | 94 | /// Stroke Path Operator 95 | infix operator -□ : AdditionPrecedence 96 | 97 | /// CGContext Stroke Path 98 | /// - discussion : rhs gets set before stroke 99 | func -□ (lhs: CGContext?, rhs: CGColor?) -> CGContext? { 100 | 101 | if let rhs = rhs { lhs?.setStrokeColor(rhs) } 102 | lhs?.strokePath(); return lhs 103 | 104 | } 105 | 106 | 107 | 108 | -------------------------------------------------------------------------------- /Example/PencilCup/PencilCupView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PencilCupView.swift 3 | // PencilCup 4 | // 5 | // Created by Jo Albright on 1/4/16. 6 | // Copyright © 2016 Jo Albright. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @IBDesignable class PencilCupView: UIView { 12 | 13 | override func draw(_ rect: CGRect) { 14 | 15 | let (bgColor,cupColor) = (UIColor(white: 0.9, alpha: 1).cgColor, UIColor(white: 0.2, alpha: 1).cgColor) 16 | 17 | let context = UIGraphicsGetCurrentContext()?.round()?.color(bgColor)?.rect(rect)?.fill() 18 | _ = context?.color(cupColor)?.round()?.line(1)?.offset((rect.width - 188) / 2, (rect.height - 300) / 2) 19 | 20 | _ = context ->- (126.01,89.44) -~- (116.37,89.19,105.65,89.06,94.35,89.06) -~- (52.35,89.06,18.3,90.8,18.3,94.24) 21 | _ = context -~- (18.3,97.68,52.35,101.51,94.35,101.51) -~- (104.7,101.51,114.57,101.28,123.57,100.87) -+- (126.01,89.44) -■ nil 22 | 23 | _ = context ->- (140,99.75) -+- (150.28,49.72) -~- (150.5,48.64,151.56,47.94,152.64,48.17) -+- (162.37,50.18) 24 | _ = context -~- (163.46,50.4,164.15,51.46,163.93,52.54) -+- (154.43,98.52) -□ nil 25 | 26 | _ = context ->- (159.39,13.91) -~- (160.85,14.62,162.41,15.16,164.07,15.5) -~- (165.71,15.84,167.36,15.97,168.96,15.9) 27 | _ = context -~- (170.55,15.83,171.69,14.33,171.39,12.77) -+- (169.3,2.12) -~- (168.85,-0.16,165.88,-0.78,164.56,1.14) 28 | _ = context -+- (158.41,10.08) -~- (157.51,11.39,157.96,13.22,159.39,13.91) -■ nil 29 | 30 | _ = context ->- (159.39,13.91) -~- (160.85,14.62,162.41,15.16,164.07,15.5) -~- (165.71,15.84,167.36,15.97,168.96,15.9) 31 | _ = context -~- (170.55,15.83,171.69,14.33,171.39,12.77) -+- (169.3,2.12) -~- (168.85,-0.16,165.88,-0.78,164.56,1.14) 32 | _ = context -+- (158.41,10.08) -~- (157.51,11.39,157.96,13.22,159.39,13.91) -□ nil 33 | 34 | _ = context ->- (137.79,100.12) -+- (148.47,48.45) -~- (148.64,47.62,148.27,46.77,147.54,46.33) -+- (141.06,42.43) 35 | _ = context -~- (139.87,41.72,138.35,42.39,138.07,43.74) -+- (126.28,100.81) -□ nil 36 | 37 | _ = context ->- (158.41,10.08) -+- (140.27,38.9) ->- (176.92,46.09) -+- (171.39,12.77) -□ nil 38 | 39 | _ = context ->- (167.6,96.07) -+- (176.74,51.79) -~- (177.02,50.42,175.86,49.2,174.48,49.4) -+- (167.77,50.43) 40 | _ = context -~- (166.94,50.55,166.28,51.18,166.11,52) -+- (156.58,98.15) -□ nil 41 | 42 | _ = context ->- (30.06,218.44) -~- (30.06,221.19,27.83,223.42,25.08,223.42) -+- (24.83,223.42) 43 | _ = context -~- (22.08,223.42,19.84,221.19,19.84,218.44) -+- (19.84,138.67) -~- (19.84,135.92,22.08,133.69,24.83,133.69) 44 | _ = context -+- (25.08,133.69) -~- (27.83,133.69,30.06,135.92,30.06,138.67) -+- (30.06,218.44) 45 | 46 | _ = context ->- (174.9,100.03) -~- (161.84,103.04,137.31,106.55,94,106.55) -~- (50.69,106.55,26.17,103.04,13.1,100.03) 47 | _ = context -~- (6.38,98.48,-0.04,103.61,-0.04,110.51) -+- (-0.04,274.38) -~- (-0.04,281.03,4.04,286.99,10.23,289.4) 48 | _ = context -~- (22.22,294.07,46.74,300,94,300) -~- (141.26,300,165.78,294.07,177.77,289.4) 49 | _ = context -~- (183.96,286.99,188.04,281.03,188.04,274.38) -+- (188.04,110.51) -~- (188.04,103.61,181.62,98.48,174.9,100.03) -■ nil 50 | 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /Example/PencilCup/DrawView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DrawView.swift 3 | // PencilCup 4 | // 5 | // Created by Jo Albright on 1/6/16. 6 | // Copyright © 2016 CocoaPods. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class DrawView: UIView, Drawable { 12 | 13 | var lines: [CGLine] = [] { didSet { setNeedsDisplay() } } 14 | 15 | override func draw(_ rect: CGRect) { 16 | 17 | drawLines(UIGraphicsGetCurrentContext(), lines: lines) 18 | 19 | } 20 | 21 | override func layoutSubviews() { 22 | 23 | /// Placeholder demo lines ... uncomment to test 24 | // lines = [CGLine] { 25 | // 26 | // for _ in 0...3 { 27 | // 28 | // $0.append(CGLine { 29 | // 30 | // $0.strokeWidth = CGFloat(drand48()) * 20 31 | // 32 | // for _ in 0...10 { 33 | // 34 | // $0.points.append(CGPoint { 35 | // 36 | // $0.x = CGFloat(drand48()) * UIScreen.mainScreen().bounds.width 37 | // $0.y = CGFloat(drand48()) * UIScreen.mainScreen().bounds.height 38 | // 39 | // }) 40 | // 41 | // } 42 | // 43 | // print($0.points) 44 | // 45 | // }) 46 | // 47 | // } 48 | // 49 | // } 50 | 51 | } 52 | 53 | override func prepareForInterfaceBuilder() { 54 | 55 | lines = [CGLine] { 56 | 57 | for _ in 0...3 { 58 | 59 | $0.append(CGLine { 60 | 61 | $0.strokeWidth = CGFloat(drand48()) * 20 62 | 63 | for _ in 0...10 { 64 | 65 | $0.points.append(CGPoint { 66 | 67 | $0.x = CGFloat(drand48()) * UIScreen.main.bounds.width 68 | $0.y = CGFloat(drand48()) * UIScreen.main.bounds.height 69 | 70 | }) 71 | 72 | } 73 | 74 | }) 75 | 76 | } 77 | 78 | } 79 | 80 | } 81 | 82 | override func touchesBegan(_ touches: Set, with event: UIEvent?) { 83 | 84 | guard let touch = touches.first else { return } 85 | 86 | lines.append(CGLine { 87 | 88 | $0.stroke = UIColor.darkGray.cgColor 89 | $0.fill = UIColor.clear.cgColor 90 | $0.strokeWidth = 1 91 | $0.points.append(touch.location(in: self)) 92 | 93 | }) 94 | 95 | } 96 | 97 | override func touchesMoved(_ touches: Set, with event: UIEvent?) { 98 | 99 | guard let touch = touches.first, lines.count > 0 else { return } 100 | 101 | lines[lines.count - 1].points.append(touch.location(in: self)) 102 | 103 | } 104 | 105 | override func touchesEnded(_ touches: Set, with event: UIEvent?) { 106 | 107 | guard let touch = touches.first, lines.count > 0 else { return } 108 | 109 | lines[lines.count - 1].points.append(touch.location(in: self)) 110 | 111 | } 112 | 113 | } 114 | -------------------------------------------------------------------------------- /Example/PencilCup/Base.lproj/LaunchScreen.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 21 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /Example/PencilCup.xcodeproj/xcshareddata/xcschemes/PencilCup-Example.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 38 | 39 | 44 | 45 | 47 | 53 | 54 | 55 | 56 | 57 | 63 | 64 | 65 | 66 | 67 | 68 | 78 | 80 | 86 | 87 | 88 | 89 | 90 | 91 | 97 | 99 | 105 | 106 | 107 | 108 | 110 | 111 | 114 | 115 | 116 | -------------------------------------------------------------------------------- /Sources/ContextRef.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ContextRef.swift 3 | // PencilCup 4 | // 5 | // Created by Jo Albright on 1/4/16. 6 | // Copyright © 2016 Jo Albright. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | 12 | // MARK: - Context : Settings 13 | 14 | public extension CGContext { 15 | 16 | var boundingBox: CGRect { return boundingBoxOfPath } 17 | var currenCGPoint: CGPoint { return currentPointOfPath } 18 | 19 | /// Sets lineCap and lineJoin to .Round 20 | func round() -> CGContext? { 21 | 22 | setLineCap(.round); setLineJoin(.round); return self 23 | 24 | } 25 | 26 | /// Sets stroke and fill color 27 | func color(_ color: CGColor?) -> CGContext? { 28 | 29 | guard let color = color else { return self } 30 | setFillColor(color) 31 | setStrokeColor(color) 32 | return self 33 | 34 | } 35 | 36 | /// Sets lineWidth 37 | func line(_ width: CGFloat) -> CGContext? { setLineWidth(width); return self } 38 | 39 | /// Sets blendMode 40 | func blend(_ mode: CGBlendMode) -> CGContext? { setBlendMode(mode); return self } 41 | 42 | /// Sets alpha 43 | func alpha(_ alpha: CGFloat) -> CGContext? { setAlpha(alpha); return self } 44 | 45 | /// Sets flatness 46 | func flatness(_ flatness: CGFloat) -> CGContext? { setFlatness(flatness); return self } 47 | 48 | func containsPoint(_ x: CGFloat, _ y: CGFloat) -> Bool { return pathContains(CGPoint(x: x, y: y), mode: .fill) } 49 | 50 | func containsPoint(_ point: CGPoint) -> Bool { return pathContains(point, mode: .fill) } 51 | 52 | } 53 | 54 | 55 | // MARK: - Context : Scale, Rotate, & Offset 56 | 57 | public extension CGContext { 58 | 59 | /// Rotates by angle 60 | func rotate(_ angle: CGFloat) -> CGContext? { rotate(by: angle); return self } 61 | 62 | /// Translates origin by x,y 63 | func offset(_ x: CGFloat, _ y: CGFloat) -> CGContext? { translateBy(x: x, y: y); return self } 64 | 65 | /// Translates origin by point 66 | func offset(_ point: CGPoint) -> CGContext? { translateBy(x: point.x, y: point.y); return self } 67 | 68 | /// Scales both x & y by xy 69 | func scale(_ xy: CGFloat = 1) -> CGContext? { scaleBy(x: xy, y: xy); return self } 70 | 71 | /// Scales by x & y 72 | func scale(_ x: CGFloat, _ y: CGFloat) -> CGContext? { scaleBy(x: x, y: y); return self } 73 | 74 | /// Scales x & y by scale 75 | func scale(_ scale: TScale) -> CGContext? { scaleBy(x: scale.x, y: scale.y); return self } 76 | 77 | } 78 | 79 | // MARK: - Context : Fill, Stroke, & Clear 80 | 81 | public extension CGContext { 82 | 83 | /// Clears with rect 84 | func clear(_ rect: CGRect? = nil) -> CGContext? { 85 | 86 | clear(rect ?? CGRect(x: 0, y: 0, width: 2048, height: 2048)); return self 87 | 88 | } 89 | 90 | /// Strokes available path 91 | func stroke() -> CGContext? { strokePath(); return self } 92 | 93 | /// Fills available path 94 | func fill() -> CGContext? { fillPath(); return self } 95 | 96 | } 97 | 98 | // MARK: - Context : Add to Path 99 | 100 | public extension CGContext { 101 | 102 | /// Add rect(s) to path 103 | func rect(_ rects: CGRect...) -> CGContext? { 104 | 105 | for rect in rects { addRect(rect) }; return self 106 | 107 | } 108 | 109 | /// Add ellipse(s) in rect to path 110 | func ellipse(_ rects: CGRect...) -> CGContext? { 111 | 112 | for rect in rects { addEllipse(in: rect) }; return self 113 | 114 | } 115 | 116 | /// Add circle with center as c and radius of r to path 117 | func circle(_ c: CGPoint, r: CGFloat) -> CGContext? { 118 | 119 | addEllipse(in: CGRect(origin: c - CGPoint(x: r, y: r), size: CGSize(width: r, height: r) * 2)); return self 120 | 121 | } 122 | 123 | /// Move path to x,y 124 | func m(_ x: CGFloat, _ y: CGFloat) -> CGContext? { 125 | 126 | move(to: CGPoint(x: x, y: y)); return self 127 | 128 | } 129 | 130 | /// Move to point 131 | func m(_ point: CGPoint) -> CGContext? { 132 | 133 | move(to: point); return self 134 | 135 | } 136 | 137 | /// Add line to x,y 138 | func l(_ x: CGFloat, _ y: CGFloat) -> CGContext? { 139 | 140 | addLine(to: CGPoint(x: x, y: y)); return self 141 | 142 | } 143 | 144 | /// Add line(s) to point(s) 145 | func l(_ points: CGPoint...) -> CGContext? { 146 | 147 | for point in points { addLine(to: point) }; return self 148 | 149 | } 150 | 151 | /// Add curve to curve point with curve anchors 152 | func c(_ curve: (CGPoint,CGPoint,CGPoint)) -> CGContext? { 153 | 154 | addCurve(to: curve.2, control1: curve.0, control2: curve.1); return self 155 | 156 | } 157 | 158 | /// Dot with center of x,y and diameter of strokeWidth 159 | func d(_ x: CGFloat, _ y: CGFloat) -> CGContext? { 160 | 161 | return m(x,y)?.l(x,y)?.stroke() 162 | 163 | } 164 | 165 | /// Dot(s) with center of point(s) and diameter of strokeWidth 166 | func d(_ points: CGPoint...) -> CGContext? { 167 | 168 | for point in points { _ = m(point)?.l(point)?.stroke() }; return self 169 | 170 | } 171 | 172 | } 173 | 174 | 175 | 176 | -------------------------------------------------------------------------------- /Example/PencilCup/CoreGraphicsView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CoreGraphicsView.swift 3 | // PencilCup 4 | // 5 | // Created by Jo Albright on 1/5/16. 6 | // Copyright © 2016 Jo Albright. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @IBDesignable class CoreGraphicsView: UIView { 12 | 13 | override func draw(_ rect: CGRect) { 14 | 15 | let context = UIGraphicsGetCurrentContext() 16 | 17 | UIColor(white: 0.9, alpha: 1).set() 18 | 19 | context?.fill(rect) 20 | 21 | UIColor(white: 0.2, alpha: 1).set() 22 | 23 | context?.setLineCap(.round) 24 | context?.setLineJoin(.round) 25 | context?.setLineWidth(1) 26 | context?.translateBy(x: (rect.width - 188) / 2, y: (rect.height - 300) / 2) 27 | 28 | // context?.move(to: CGPoint(x: 126.01, y: 89.44)) 29 | // context?.addCurve(to: CGPoint(x: 94.35, y: 89.06), control1: CGPoint(x: 116.37, y: 89.19), control2: CGPoint(x: 105.65, y: 89.06)) 30 | // CGContextAddCurveToPoint(context,52.35,89.06,18.3,90.8,18.3,94.24) 31 | // CGContextAddCurveToPoint(context,18.3,97.68,52.35,101.51,94.35,101.51) 32 | // CGContextAddCurveToPoint(context,104.7,101.51,114.57,101.28,123.57,100.87) 33 | // context?.addLine(to: CGPoint(x: 126.01, y: 89.44)) 34 | // context?.fillPath() 35 | // 36 | // context?.move(to: CGPoint(x: 140, y: 99.75)) 37 | // context?.addLine(to: CGPoint(x: 150.28, y: 49.72)) 38 | // CGContextAddCurveToPoint(context,150.5,48.64,151.56,47.94,152.64,48.17) 39 | // context?.addLine(to: CGPoint(x: 162.37, y: 50.18)) 40 | // CGContextAddCurveToPoint(context,163.46,50.4,164.15,51.46,163.93,52.54) 41 | // context?.addLine(to: CGPoint(x: 154.43, y: 98.52)) 42 | // context?.strokePath() 43 | // 44 | // context?.move(to: CGPoint(x: 159.39, y: 13.91)) 45 | // CGContextAddCurveToPoint(context,160.85,14.62,162.41,15.16,164.07,15.5) 46 | // CGContextAddCurveToPoint(context,165.71,15.84,167.36,15.97,168.96,15.9) 47 | // CGContextAddCurveToPoint(context,170.55,15.83,171.69,14.33,171.39,12.77) 48 | // context?.addLine(to: CGPoint(x: 169.3, y: 2.12)) 49 | // CGContextAddCurveToPoint(context,168.85,-0.16,165.88,-0.78,164.56,1.14) 50 | // context?.addLine(to: CGPoint(x: 158.41, y: 10.08)) 51 | // CGContextAddCurveToPoint(context,157.51,11.39,157.96,13.22,159.39,13.91) 52 | // context?.fillPath() 53 | // 54 | // context?.move(to: CGPoint(x: 159.39, y: 13.91)) 55 | // CGContextAddCurveToPoint(context,160.85,14.62,162.41,15.16,164.07,15.5) 56 | // CGContextAddCurveToPoint(context,165.71,15.84,167.36,15.97,168.96,15.9) 57 | // CGContextAddCurveToPoint(context,170.55,15.83,171.69,14.33,171.39,12.77) 58 | // context?.addLine(to: CGPoint(x: 169.3, y: 2.12)) 59 | // CGContextAddCurveToPoint(context,168.85,-0.16,165.88,-0.78,164.56,1.14) 60 | // context?.addLine(to: CGPoint(x: 158.41, y: 10.08)) 61 | // CGContextAddCurveToPoint(context,157.51,11.39,157.96,13.22,159.39,13.91) 62 | // context?.strokePath() 63 | // 64 | // context?.move(to: CGPoint(x: 137.79, y: 100.12)) 65 | // context?.addLine(to: CGPoint(x: 148.47, y: 48.45)) 66 | // CGContextAddCurveToPoint(context,148.64,47.62,148.27,46.77,147.54,46.33) 67 | // context?.addLine(to: CGPoint(x: 141.06, y: 42.43)) 68 | // CGContextAddCurveToPoint(context,139.87,41.72,138.35,42.39,138.07,43.74) 69 | // context?.addLine(to: CGPoint(x: 126.28, y: 100.81)) 70 | // context?.strokePath() 71 | // 72 | // context?.move(to: CGPoint(x: 158.41, y: 10.08)) 73 | // context?.addLine(to: CGPoint(x: 140.27, y: 38.9)) 74 | // context?.strokePath() 75 | // 76 | // context?.move(to: CGPoint(x: 176.92, y: 46.09)) 77 | // context?.addLine(to: CGPoint(x: 171.39, y: 12.77)) 78 | // context?.strokePath() 79 | // 80 | // context?.move(to: CGPoint(x: 167.6, y: 96.07)) 81 | // context?.addLine(to: CGPoint(x: 176.74, y: 51.79)) 82 | // CGContextAddCurveToPoint(context,177.02,50.42,175.86,49.2,174.48,49.4) 83 | // context?.addLine(to: CGPoint(x: 167.77, y: 50.43)) 84 | // CGContextAddCurveToPoint(context,166.94,50.55,166.28,51.18,166.11,52) 85 | // context?.addLine(to: CGPoint(x: 156.58, y: 98.15)) 86 | // context?.strokePath() 87 | // 88 | // context?.move(to: CGPoint(x: 30.06, y: 218.44)) 89 | // CGContextAddCurveToPoint(context,30.06,221.19,27.83,223.42,25.08,223.42) 90 | // context?.addLine(to: CGPoint(x: 24.83, y: 223.42)) 91 | // CGContextAddCurveToPoint(context,22.08,223.42,19.84,221.19,19.84,218.44) 92 | // context?.addLine(to: CGPoint(x: 19.84, y: 138.67)) 93 | // CGContextAddCurveToPoint(context,19.84,135.92,22.08,133.69,24.83,133.69) 94 | // context?.addLine(to: CGPoint(x: 25.08, y: 133.69)) 95 | // CGContextAddCurveToPoint(context,27.83,133.69,30.06,135.92,30.06,138.67) 96 | // context?.addLine(to: CGPoint(x: 30.06, y: 218.44)) 97 | // 98 | // context?.move(to: CGPoint(x: 174.9, y: 100.03)) 99 | // CGContextAddCurveToPoint(context,161.84,103.04,137.31,106.55,94,106.55) 100 | // CGContextAddCurveToPoint(context,50.69,106.55,26.17,103.04,13.1,100.03) 101 | // CGContextAddCurveToPoint(context,6.38,98.48,-0.04,103.61,-0.04,110.51) 102 | // context?.addLine(to: CGPoint(x: -0.04, y: 274.38)) 103 | // CGContextAddCurveToPoint(context,-0.04,281.03,4.04,286.99,10.23,289.4) 104 | // CGContextAddCurveToPoint(context,22.22,294.07,46.74,300,94,300) 105 | // CGContextAddCurveToPoint(context,141.26,300,165.78,294.07,177.77,289.4) 106 | // CGContextAddCurveToPoint(context,183.96,286.99,188.04,281.03,188.04,274.38) 107 | // context?.addLine(to: CGPoint(x: 188.04, y: 110.51)) 108 | // CGContextAddCurveToPoint(context,188.04,103.61,181.62,98.48,174.9,100.03) 109 | // context?.fillPath() 110 | 111 | } 112 | 113 | } 114 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PencilCup 2 | Tools built to help use CoreGraphics more Swiftly 3 | 4 | 5 | 6 | [![Version](https://img.shields.io/cocoapods/v/PencilCup.svg?style=flat)](http://cocoapods.org/pods/PencilCup) 7 | [![License](https://img.shields.io/cocoapods/l/PencilCup.svg?style=flat)](http://cocoapods.org/pods/PencilCup) 8 | [![Platform](https://img.shields.io/cocoapods/p/PencilCup.svg?style=flat)](http://cocoapods.org/pods/PencilCup) 9 | 10 | ![Pencil Cup](./Images/pencilcup.png) 11 | 12 | ## Usage 13 | 14 | To run the example project, clone the repo, and run `pod install` from the Example directory first. 15 | 16 | Add these [Code Snippets](./XcodeSnippets) into Xcode to help with using the new operators. 17 | 18 | Code Snippet Directory : **~/Library/Developer/Xcode/UserData/CodeSnippets/** 19 | 20 | ### Motivation 21 | 22 | > Core Graphics is an amazingly useful library that I work with in every app I build. But I also have spent a lot of time writing lines of code to draw things that are very simple. 23 | 24 | **Main Problems** 25 | 26 | - each point on a path uses a new line of code 27 | - you must pass "context" with every CGContext function 28 | - CGContext options set using functions instead of methods 29 | 30 | ```swift 31 | let context = UIGraphicsGetCurrentContext() 32 | UIColor(white: 0.9, alpha: 1).set() 33 | CGContextFillRect(context, rect) 34 | UIColor(white: 0.2, alpha: 1).set() 35 | 36 | CGContextSetLineCap(context, .Round) 37 | CGContextSetLineJoin(context, .Round) 38 | CGContextSetLineWidth(context, 1) 39 | CGContextTranslateCTM(context, (rect.width - 188) / 2, (rect.height - 300) / 2) 40 | 41 | CGContextMoveToPoint(context,126.01,89.44) 42 | CGContextAddCurveToPoint(context,116.37, 89.19, 105.65, 89.06, 94.35, 89.06) 43 | CGContextAddCurveToPoint(context, 52.35, 89.06, 18.3, 90.8, 18.3, 94.24) 44 | CGContextAddCurveToPoint(context, 18.3, 97.68, 52.35, 101.51, 94.35, 101.51) 45 | CGContextAddCurveToPoint(context, 104.7, 101.51, 114.57, 101.28, 123.57, 100.87) 46 | CGContextAddLineToPoint(context,126.01,89.44) 47 | CGContextFillPath(context) 48 | 49 | CGContextMoveToPoint(context,140, 99.75) 50 | CGContextAddLineToPoint(context, 150.28, 49.72) 51 | CGContextAddCurveToPoint(context, 150.5, 48.64, 151.56, 47.94, 152.64, 48.17) 52 | CGContextAddLineToPoint(context, 162.37, 50.18) 53 | CGContextAddCurveToPoint(context, 163.46, 50.4, 164.15, 51.46, 163.93, 52.54) 54 | CGContextAddLineToPoint(context, 154.43, 98.52) 55 | CGContextStrokePath(context) 56 | ``` 57 | *22 lines of code* 58 | 59 | --- 60 | 61 | ### New Patterns 62 | 63 | > You now have the ability to set context options using extension methods. Infix operators open up the ability to build a multi point path on a single line of code. 64 | 65 | **New Features** 66 | 67 | - typealiases PCPoint, PCSize, PCScale, PCDelta 68 | - CGRect extended with inset methods and global initializer functions 69 | - CGContext extended with methods that simplify setup 70 | - infix operators for points and paths 71 | 72 | #### Operator Pattern 73 | 74 | ```swift 75 | let (bgColor,cupColor) = (UIColor(white: 0.9, alpha: 1).CGColor, UIColor(white: 0.2, alpha: 1).CGColor) 76 | 77 | let context = UIGraphicsGetCurrentContext()?.round()?.color(bgColor)?.rect(rect)?.fill() 78 | context?.color(cupColor)?.round()?.line(1)?.offset((rect.width - 188) / 2, (rect.height - 300) / 2) 79 | 80 | context ->- (126.01,89.44) -~- (116.37,89.19,105.65,89.06,94.35,89.06) -~- (52.35,89.06,18.3,90.8,18.3,94.24) 81 | context -~- (18.3,97.68,52.35,101.51,94.35,101.51) -~- (104.7,101.51,114.57,101.28,123.57,100.87) -+- (126.01,89.44) -■ nil 82 | 83 | context ->- (140,99.75) -+- (150.28,49.72) -~- (150.5,48.64,151.56,47.94,152.64,48.17) -+- (162.37,50.18) 84 | context -~- (163.46,50.4,164.15,51.46,163.93,52.54) -+- (154.43,98.52) -□ nil 85 | ``` 86 | *7 lines of code* 87 | 88 | #### Function Pattern 89 | 90 | ```swift 91 | let (bgColor,cupColor) = (UIColor(white: 0.9, alpha: 1).CGColor, UIColor(white: 0.2, alpha: 1).CGColor) 92 | 93 | let context = UIGraphicsGetCurrentContext()?.round()?.color(bgColor)?.rect(rect)?.fill() 94 | context?.color(cupColor)?.round()?.line(1)?.offset((rect.width - 188) / 2, (rect.height - 300) / 2) 95 | 96 | context?.m(126.01,89.44)?.c(116.37,89.19,105.65,89.06,94.35,89.06)?.c(52.35,89.06,18.3,90.8,18.3,94.24) 97 | context?.c(18.3,97.68,52.35,101.51,94.35,101.51)?.c(104.7,101.51,114.57,101.28,123.57,100.87)?.l(126.01,89.44)?.fill() 98 | 99 | context?.m(140,99.75)?.l(150.28,49.72)?.c(150.5,48.64,151.56,47.94,152.64,48.17)?.l(162.37,50.18) 100 | context?.c(163.46,50.4,164.15,51.46,163.93,52.54)?.l(154.43,98.52)?.stroke() 101 | ``` 102 | *7 lines of code* 103 | 104 | > I personally enjoy the operator pattern, because the visuals of the operators make it more readable for me. But both are great patterns. 105 | 106 | 107 | 108 | --- 109 | 110 | ### Screens 111 | 112 | - CoreGraphics Drawn PencilCup Logo 113 | - ColorWheel and ColorBar Classes in Example Project 114 | - gradient steps are changlable 115 | - bars have values to change hue, saturation, brightness, alpha 116 | 117 | 118 | 119 | ![Pencil Cup](./Images/screen1.png) ![Pencil Cup](./Images/screen2.png) ![Pencil Cup](./Images/screen3.png) 120 | 121 | 122 | ## Installation 123 | 124 | PencilCup is available through [CocoaPods](http://cocoapods.org). To install 125 | it, simply add the following line to your Podfile: 126 | 127 | ```ruby 128 | pod "PencilCup" 129 | ``` 130 | 131 | PencilCup is also available through [Swift Package Manager](https://swift.org/package-manager/). Please take a look at the link to learn more about how to use SwiftPM. 132 | 133 | ```swift 134 | import PackageDescription 135 | 136 | let package = Package( 137 | name: "YOUR_PACKAGE_NAME", 138 | dependencies: [ 139 | .Package(url: "https://github.com/joalbright/PencilCup.git", majorVersion: 0) 140 | ] 141 | ) 142 | ``` 143 | 144 | ## Author 145 | 146 | [Jo Albright](http://github.com/joalbright) 147 | 148 | ## License 149 | 150 | PencilCup is available under the MIT license. See the LICENSE file for more info. 151 | -------------------------------------------------------------------------------- /Example/PencilCup/InkWell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DrawableInkWell.swift 3 | // PencilCup 4 | // 5 | // Created by Jo Albright on 1/6/16. 6 | // Copyright © 2016 Jo Albright. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @IBDesignable class ColorBar: UIControl { 12 | 13 | @IBInspectable var steps: CGFloat = 360 14 | @IBInspectable var reverse: Bool = false 15 | 16 | enum BarType: String { case Hue, Saturation, Brightness, Alpha } 17 | var type: BarType = .Hue 18 | @IBInspectable var typeString: String = "Hue" { didSet { type = BarType(rawValue: typeString) ?? .Hue } } 19 | 20 | @IBInspectable var isHorizontal: Bool = false 21 | 22 | @IBInspectable var handleColor: UIColor = UIColor.black 23 | 24 | @IBInspectable var h: CGFloat = 0 { didSet { setNeedsDisplay() } } 25 | @IBInspectable var s: CGFloat = 1 { didSet { setNeedsDisplay() } } 26 | @IBInspectable var b: CGFloat = 1 { didSet { setNeedsDisplay() } } 27 | @IBInspectable var a: CGFloat = 1 { didSet { setNeedsDisplay() } } 28 | 29 | @IBInspectable var value: CGFloat = 0 { didSet { setNeedsDisplay() } } 30 | @IBInspectable var minValue: CGFloat = 0 31 | @IBInspectable var maxValue: CGFloat = 100 32 | 33 | var locked: Bool = true 34 | 35 | override func touchesBegan(_ touches: Set, with event: UIEvent?) { 36 | 37 | guard let touch = touches.first else { return } 38 | let location = touch.location(in: self) 39 | 40 | let wh = frame.width < frame.height ? frame.width : frame.height 41 | 42 | let percent = 1 - (value - minValue) / (maxValue - minValue) 43 | 44 | let x = isHorizontal ? frame.height / 2 + ((frame.width - frame.height) * percent) : frame.width / 2 45 | let y = isHorizontal ? frame.height / 2 : frame.width / 2 + ((frame.height - frame.width) * percent) 46 | 47 | locked = !(fabs(location.x - x) < wh / 2 && fabs(location.y - y) < wh / 2) 48 | 49 | } 50 | 51 | override func touchesMoved(_ touches: Set, with event: UIEvent?) { 52 | 53 | guard let touch = touches.first, !locked else { return } 54 | let location = touch.location(in: self) 55 | 56 | let percent = isHorizontal ? (location.x - frame.height / 2) / (frame.width - frame.height) : (location.y - frame.width / 2) / (frame.height - frame.width) 57 | 58 | let rP = reverse ? 1 - percent : percent 59 | 60 | value = rP * (maxValue - minValue) + minValue 61 | 62 | if value < minValue { value = minValue } 63 | if value > maxValue { value = maxValue } 64 | 65 | switch type { 66 | 67 | case .Hue: h = (value - minValue) / (maxValue - minValue) 68 | case .Saturation: s = (value - minValue) / (maxValue - minValue) 69 | case .Brightness: b = (value - minValue) / (maxValue - minValue) 70 | case .Alpha : a = (value - minValue) / (maxValue - minValue) 71 | 72 | } 73 | 74 | sendActions(for: .valueChanged) 75 | 76 | } 77 | 78 | override func draw(_ rect: CGRect) { 79 | 80 | steps = steps == 0 ? isHorizontal ? rect.width : rect.height : steps 81 | 82 | layer.cornerRadius = rect.width < rect.height ? rect.width / 2 : rect.height / 2 83 | layer.masksToBounds = true 84 | 85 | let sD: CGFloat = isHorizontal ? rect.width != steps ? 2 : 0 : rect.height != steps ? 2 : 0 86 | 87 | let context = UIGraphicsGetCurrentContext() 88 | 89 | var rW = reverse ? isHorizontal ? rect.width : 0 : 0 90 | var rH = reverse ? isHorizontal ? 0 : rect.height : 0 91 | let r: CGFloat = reverse ? 1 : -1 92 | 93 | let xM = isHorizontal ? rect.width / steps : 0 94 | let yM = isHorizontal ? 0 : rect.height / steps 95 | 96 | let width = isHorizontal ? rect.width / steps + sD : rect.width 97 | let height = isHorizontal ? rect.height : rect.height / steps + sD 98 | 99 | for i in 0...Int(steps) { 100 | 101 | switch type { 102 | 103 | case .Hue : UIColor(hue: CGFloat(i) / steps, saturation: 1, brightness: 1, alpha: 1).set() 104 | case .Saturation : UIColor(hue: h, saturation: CGFloat(i) / steps, brightness: b, alpha: 1).set() 105 | case .Brightness : UIColor(hue: h, saturation: s, brightness: CGFloat(i) / steps, alpha: 1).set() 106 | case .Alpha : UIColor(hue: h, saturation: s, brightness: b, alpha: CGFloat(i) / steps).set() 107 | 108 | } 109 | 110 | _ = context?.rect(CGRect(x: rW - (CGFloat(i) * xM * r), y: rH - (CGFloat(i) * yM * r), width: width, height: height))?.fill() 111 | 112 | } 113 | 114 | _ = context?.blend(.clear)?.line(6.5) 115 | 116 | rW = rW > 0 ? rW - rect.height : 0 117 | rH = rH > 0 ? rH - rect.width : 0 118 | 119 | let percent = (value - minValue) / (maxValue - minValue) 120 | let x = isHorizontal ? rW - (rect.width - rect.height) * percent * r : 0 121 | let y = isHorizontal ? 0 : rH - (rect.height - rect.width) * percent * r 122 | 123 | let handleWH = rect.width < rect.height ? rect.width : rect.height 124 | let handleRect = CGRect(x: x, y: y, width: handleWH, height: handleWH).inset(3) 125 | 126 | _ = context?.ellipse(handleRect)?.stroke()?.blend(.normal)?.color(handleColor.cgColor)?.line(1) 127 | 128 | if percent == 0 && type == .Alpha { 129 | 130 | let (l1,l2) = (handleRect.pointOnCircleInRect(-45),handleRect.pointOnCircleInRect(-225)) 131 | 132 | _ = context?.line(2)?.color(UIColor.red.cgColor) ->- l1 -+- l2 133 | 134 | } 135 | 136 | _ = context?.ellipse(CGRect(x: x, y: y, width: handleWH, height: handleWH).inset(3))?.stroke() 137 | 138 | } 139 | 140 | } 141 | 142 | @IBDesignable class ColorWheel: UIControl { 143 | 144 | @IBInspectable var steps: CGFloat = 360 145 | 146 | @IBInspectable var hueStart: CGFloat = 0 147 | @IBInspectable var hueEnd: CGFloat = 360 148 | 149 | @IBInspectable var saturation: CGFloat = 1 150 | @IBInspectable var brightness: CGFloat = 1 151 | 152 | override func draw(_ rect: CGRect) { 153 | 154 | layer.cornerRadius = rect.width > rect.height ? rect.width / 2 : rect.width / 2 155 | layer.masksToBounds = true 156 | 157 | let context = UIGraphicsGetCurrentContext() 158 | 159 | let degrees: CGFloat = 360 160 | 161 | for d in 0...Int(steps) { 162 | 163 | let hueRange = hueEnd - hueStart 164 | let distance = degrees / steps 165 | let degree = CGFloat(d) * distance 166 | let percent = CGFloat(d) / steps 167 | 168 | var hue = percent * (hueRange / degrees) + hueStart / degrees 169 | 170 | if hue < 0 { hue += 1 } else if hue > 1 { hue -= 1 } 171 | 172 | UIColor(hue: hue, saturation: saturation, brightness: brightness, alpha: 1).set() 173 | 174 | let a1 = rect.inset(-100).pointOnCircleInRect(degree - distance / 2 - 0.25) 175 | let a2 = rect.inset(-100).pointOnCircleInRect(degree + distance / 2 + 0.25) 176 | 177 | _ = context ->- rect.center -+- a1 -+- a2 -■ nil 178 | 179 | } 180 | 181 | } 182 | 183 | // TODO: Add value functionality 184 | 185 | override func touchesBegan(_ touches: Set, with event: UIEvent?) { 186 | 187 | 188 | 189 | } 190 | 191 | override func touchesMoved(_ touches: Set, with event: UIEvent?) { 192 | 193 | 194 | sendActions(for: .valueChanged) 195 | 196 | } 197 | 198 | } 199 | 200 | -------------------------------------------------------------------------------- /Example/PencilCup/Base.lproj/Main.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 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | -------------------------------------------------------------------------------- /Example/PencilCup.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 607FACD61AFB9204008FA782 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 607FACD51AFB9204008FA782 /* AppDelegate.swift */; }; 11 | 607FACDB1AFB9204008FA782 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 607FACD91AFB9204008FA782 /* Main.storyboard */; }; 12 | 607FACDD1AFB9204008FA782 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 607FACDC1AFB9204008FA782 /* Images.xcassets */; }; 13 | 607FACE01AFB9204008FA782 /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 607FACDE1AFB9204008FA782 /* LaunchScreen.xib */; }; 14 | A914C70E1E933C790027D1FB /* ContextMisc.swift in Sources */ = {isa = PBXBuildFile; fileRef = A914C7091E933C790027D1FB /* ContextMisc.swift */; }; 15 | A914C70F1E933C790027D1FB /* ContextPath.swift in Sources */ = {isa = PBXBuildFile; fileRef = A914C70A1E933C790027D1FB /* ContextPath.swift */; }; 16 | A914C7101E933C790027D1FB /* ContextPoint.swift in Sources */ = {isa = PBXBuildFile; fileRef = A914C70B1E933C790027D1FB /* ContextPoint.swift */; }; 17 | A914C7111E933C790027D1FB /* ContextRect.swift in Sources */ = {isa = PBXBuildFile; fileRef = A914C70C1E933C790027D1FB /* ContextRect.swift */; }; 18 | A914C7121E933C790027D1FB /* ContextRef.swift in Sources */ = {isa = PBXBuildFile; fileRef = A914C70D1E933C790027D1FB /* ContextRef.swift */; }; 19 | A914C7151E933CF10027D1FB /* Inlinit.swift in Sources */ = {isa = PBXBuildFile; fileRef = A914C7141E933CF10027D1FB /* Inlinit.swift */; }; 20 | A939C7151C3E007F001EC587 /* DrawView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A939C7141C3E007F001EC587 /* DrawView.swift */; }; 21 | A945D6711C3F0B92006CDF25 /* InkWell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A945D6701C3F0B92006CDF25 /* InkWell.swift */; }; 22 | A945D6731C3F0BAF006CDF25 /* Drawable.swift in Sources */ = {isa = PBXBuildFile; fileRef = A945D6721C3F0BAF006CDF25 /* Drawable.swift */; }; 23 | A945D67B1C40BC01006CDF25 /* ColorViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A945D67A1C40BC01006CDF25 /* ColorViewController.swift */; }; 24 | A9B091581C3CCC48004E26D0 /* PencilCupView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9B091561C3CCC48004E26D0 /* PencilCupView.swift */; }; 25 | A9B091591C3CCC48004E26D0 /* CoreGraphicsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9B091571C3CCC48004E26D0 /* CoreGraphicsView.swift */; }; 26 | /* End PBXBuildFile section */ 27 | 28 | /* Begin PBXFileReference section */ 29 | 3A317D8797530C3299CF00DE /* README.md */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = net.daringfireball.markdown; name = README.md; path = ../../README.md; sourceTree = ""; }; 30 | 607FACD01AFB9204008FA782 /* PencilCup_Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = PencilCup_Example.app; sourceTree = BUILT_PRODUCTS_DIR; }; 31 | 607FACD41AFB9204008FA782 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 32 | 607FACD51AFB9204008FA782 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 33 | 607FACDA1AFB9204008FA782 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 34 | 607FACDC1AFB9204008FA782 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 35 | 607FACDF1AFB9204008FA782 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; }; 36 | 984567C7765F410F76D66991 /* LICENSE */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; name = LICENSE; path = ../../LICENSE; sourceTree = ""; }; 37 | A914C7091E933C790027D1FB /* ContextMisc.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ContextMisc.swift; path = ../../Sources/ContextMisc.swift; sourceTree = ""; }; 38 | A914C70A1E933C790027D1FB /* ContextPath.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ContextPath.swift; path = ../../Sources/ContextPath.swift; sourceTree = ""; }; 39 | A914C70B1E933C790027D1FB /* ContextPoint.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ContextPoint.swift; path = ../../Sources/ContextPoint.swift; sourceTree = ""; }; 40 | A914C70C1E933C790027D1FB /* ContextRect.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ContextRect.swift; path = ../../Sources/ContextRect.swift; sourceTree = ""; }; 41 | A914C70D1E933C790027D1FB /* ContextRef.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ContextRef.swift; path = ../../Sources/ContextRef.swift; sourceTree = ""; }; 42 | A914C7141E933CF10027D1FB /* Inlinit.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Inlinit.swift; path = ../../Carthage/Checkouts/Inlinit/Sources/Inlinit.swift; sourceTree = ""; }; 43 | A939C7141C3E007F001EC587 /* DrawView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DrawView.swift; sourceTree = ""; }; 44 | A945D6701C3F0B92006CDF25 /* InkWell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = InkWell.swift; path = /Users/RedLeader/_github/PencilCup/Example/PencilCup/InkWell.swift; sourceTree = ""; }; 45 | A945D6721C3F0BAF006CDF25 /* Drawable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Drawable.swift; path = /Users/RedLeader/_github/PencilCup/Example/PencilCup/Drawable.swift; sourceTree = ""; }; 46 | A945D67A1C40BC01006CDF25 /* ColorViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ColorViewController.swift; sourceTree = ""; }; 47 | A9B091561C3CCC48004E26D0 /* PencilCupView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PencilCupView.swift; sourceTree = ""; }; 48 | A9B091571C3CCC48004E26D0 /* CoreGraphicsView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CoreGraphicsView.swift; sourceTree = ""; }; 49 | /* End PBXFileReference section */ 50 | 51 | /* Begin PBXFrameworksBuildPhase section */ 52 | 607FACCD1AFB9204008FA782 /* Frameworks */ = { 53 | isa = PBXFrameworksBuildPhase; 54 | buildActionMask = 2147483647; 55 | files = ( 56 | ); 57 | runOnlyForDeploymentPostprocessing = 0; 58 | }; 59 | /* End PBXFrameworksBuildPhase section */ 60 | 61 | /* Begin PBXGroup section */ 62 | 607FACC71AFB9204008FA782 = { 63 | isa = PBXGroup; 64 | children = ( 65 | 607FACD21AFB9204008FA782 /* Example for PencilCup */, 66 | 607FACD11AFB9204008FA782 /* Products */, 67 | ); 68 | sourceTree = ""; 69 | }; 70 | 607FACD11AFB9204008FA782 /* Products */ = { 71 | isa = PBXGroup; 72 | children = ( 73 | 607FACD01AFB9204008FA782 /* PencilCup_Example.app */, 74 | ); 75 | name = Products; 76 | sourceTree = ""; 77 | }; 78 | 607FACD21AFB9204008FA782 /* Example for PencilCup */ = { 79 | isa = PBXGroup; 80 | children = ( 81 | A914C7131E933CA60027D1FB /* Carthage */, 82 | A914C6FC1E933C2B0027D1FB /* PencilCup */, 83 | 607FACD91AFB9204008FA782 /* Main.storyboard */, 84 | A945D6771C40BBC7006CDF25 /* PencilCup Logo */, 85 | A945D6781C40BBE0006CDF25 /* DrawView */, 86 | A945D6791C40BBEA006CDF25 /* ColorPicker */, 87 | 607FACD31AFB9204008FA782 /* Supporting Files */, 88 | ); 89 | name = "Example for PencilCup"; 90 | path = PencilCup; 91 | sourceTree = ""; 92 | }; 93 | 607FACD31AFB9204008FA782 /* Supporting Files */ = { 94 | isa = PBXGroup; 95 | children = ( 96 | 3A317D8797530C3299CF00DE /* README.md */, 97 | 984567C7765F410F76D66991 /* LICENSE */, 98 | 607FACD51AFB9204008FA782 /* AppDelegate.swift */, 99 | 607FACDC1AFB9204008FA782 /* Images.xcassets */, 100 | 607FACDE1AFB9204008FA782 /* LaunchScreen.xib */, 101 | 607FACD41AFB9204008FA782 /* Info.plist */, 102 | ); 103 | name = "Supporting Files"; 104 | sourceTree = ""; 105 | }; 106 | A914C6FC1E933C2B0027D1FB /* PencilCup */ = { 107 | isa = PBXGroup; 108 | children = ( 109 | A914C7091E933C790027D1FB /* ContextMisc.swift */, 110 | A914C70A1E933C790027D1FB /* ContextPath.swift */, 111 | A914C70B1E933C790027D1FB /* ContextPoint.swift */, 112 | A914C70C1E933C790027D1FB /* ContextRect.swift */, 113 | A914C70D1E933C790027D1FB /* ContextRef.swift */, 114 | ); 115 | name = PencilCup; 116 | sourceTree = ""; 117 | }; 118 | A914C7131E933CA60027D1FB /* Carthage */ = { 119 | isa = PBXGroup; 120 | children = ( 121 | A914C7141E933CF10027D1FB /* Inlinit.swift */, 122 | ); 123 | name = Carthage; 124 | sourceTree = ""; 125 | }; 126 | A945D6771C40BBC7006CDF25 /* PencilCup Logo */ = { 127 | isa = PBXGroup; 128 | children = ( 129 | A9B091561C3CCC48004E26D0 /* PencilCupView.swift */, 130 | A9B091571C3CCC48004E26D0 /* CoreGraphicsView.swift */, 131 | ); 132 | name = "PencilCup Logo"; 133 | sourceTree = ""; 134 | }; 135 | A945D6781C40BBE0006CDF25 /* DrawView */ = { 136 | isa = PBXGroup; 137 | children = ( 138 | A939C7141C3E007F001EC587 /* DrawView.swift */, 139 | A945D6721C3F0BAF006CDF25 /* Drawable.swift */, 140 | ); 141 | name = DrawView; 142 | sourceTree = ""; 143 | }; 144 | A945D6791C40BBEA006CDF25 /* ColorPicker */ = { 145 | isa = PBXGroup; 146 | children = ( 147 | A945D67A1C40BC01006CDF25 /* ColorViewController.swift */, 148 | A945D6701C3F0B92006CDF25 /* InkWell.swift */, 149 | ); 150 | name = ColorPicker; 151 | sourceTree = ""; 152 | }; 153 | /* End PBXGroup section */ 154 | 155 | /* Begin PBXNativeTarget section */ 156 | 607FACCF1AFB9204008FA782 /* PencilCup_Example */ = { 157 | isa = PBXNativeTarget; 158 | buildConfigurationList = 607FACEF1AFB9204008FA782 /* Build configuration list for PBXNativeTarget "PencilCup_Example" */; 159 | buildPhases = ( 160 | 607FACCC1AFB9204008FA782 /* Sources */, 161 | 607FACCD1AFB9204008FA782 /* Frameworks */, 162 | 607FACCE1AFB9204008FA782 /* Resources */, 163 | ); 164 | buildRules = ( 165 | ); 166 | dependencies = ( 167 | ); 168 | name = PencilCup_Example; 169 | productName = PencilCup; 170 | productReference = 607FACD01AFB9204008FA782 /* PencilCup_Example.app */; 171 | productType = "com.apple.product-type.application"; 172 | }; 173 | /* End PBXNativeTarget section */ 174 | 175 | /* Begin PBXProject section */ 176 | 607FACC81AFB9204008FA782 /* Project object */ = { 177 | isa = PBXProject; 178 | attributes = { 179 | LastSwiftUpdateCheck = 0720; 180 | LastUpgradeCheck = 0720; 181 | ORGANIZATIONNAME = CocoaPods; 182 | TargetAttributes = { 183 | 607FACCF1AFB9204008FA782 = { 184 | CreatedOnToolsVersion = 6.3.1; 185 | LastSwiftMigration = 0820; 186 | }; 187 | }; 188 | }; 189 | buildConfigurationList = 607FACCB1AFB9204008FA782 /* Build configuration list for PBXProject "PencilCup" */; 190 | compatibilityVersion = "Xcode 3.2"; 191 | developmentRegion = English; 192 | hasScannedForEncodings = 0; 193 | knownRegions = ( 194 | en, 195 | Base, 196 | ); 197 | mainGroup = 607FACC71AFB9204008FA782; 198 | productRefGroup = 607FACD11AFB9204008FA782 /* Products */; 199 | projectDirPath = ""; 200 | projectRoot = ""; 201 | targets = ( 202 | 607FACCF1AFB9204008FA782 /* PencilCup_Example */, 203 | ); 204 | }; 205 | /* End PBXProject section */ 206 | 207 | /* Begin PBXResourcesBuildPhase section */ 208 | 607FACCE1AFB9204008FA782 /* Resources */ = { 209 | isa = PBXResourcesBuildPhase; 210 | buildActionMask = 2147483647; 211 | files = ( 212 | 607FACDB1AFB9204008FA782 /* Main.storyboard in Resources */, 213 | 607FACE01AFB9204008FA782 /* LaunchScreen.xib in Resources */, 214 | 607FACDD1AFB9204008FA782 /* Images.xcassets in Resources */, 215 | ); 216 | runOnlyForDeploymentPostprocessing = 0; 217 | }; 218 | /* End PBXResourcesBuildPhase section */ 219 | 220 | /* Begin PBXSourcesBuildPhase section */ 221 | 607FACCC1AFB9204008FA782 /* Sources */ = { 222 | isa = PBXSourcesBuildPhase; 223 | buildActionMask = 2147483647; 224 | files = ( 225 | A914C7101E933C790027D1FB /* ContextPoint.swift in Sources */, 226 | A914C7121E933C790027D1FB /* ContextRef.swift in Sources */, 227 | A9B091581C3CCC48004E26D0 /* PencilCupView.swift in Sources */, 228 | A914C7111E933C790027D1FB /* ContextRect.swift in Sources */, 229 | 607FACD61AFB9204008FA782 /* AppDelegate.swift in Sources */, 230 | A939C7151C3E007F001EC587 /* DrawView.swift in Sources */, 231 | A945D6731C3F0BAF006CDF25 /* Drawable.swift in Sources */, 232 | A914C70F1E933C790027D1FB /* ContextPath.swift in Sources */, 233 | A945D67B1C40BC01006CDF25 /* ColorViewController.swift in Sources */, 234 | A914C70E1E933C790027D1FB /* ContextMisc.swift in Sources */, 235 | A9B091591C3CCC48004E26D0 /* CoreGraphicsView.swift in Sources */, 236 | A914C7151E933CF10027D1FB /* Inlinit.swift in Sources */, 237 | A945D6711C3F0B92006CDF25 /* InkWell.swift in Sources */, 238 | ); 239 | runOnlyForDeploymentPostprocessing = 0; 240 | }; 241 | /* End PBXSourcesBuildPhase section */ 242 | 243 | /* Begin PBXVariantGroup section */ 244 | 607FACD91AFB9204008FA782 /* Main.storyboard */ = { 245 | isa = PBXVariantGroup; 246 | children = ( 247 | 607FACDA1AFB9204008FA782 /* Base */, 248 | ); 249 | name = Main.storyboard; 250 | sourceTree = ""; 251 | }; 252 | 607FACDE1AFB9204008FA782 /* LaunchScreen.xib */ = { 253 | isa = PBXVariantGroup; 254 | children = ( 255 | 607FACDF1AFB9204008FA782 /* Base */, 256 | ); 257 | name = LaunchScreen.xib; 258 | sourceTree = ""; 259 | }; 260 | /* End PBXVariantGroup section */ 261 | 262 | /* Begin XCBuildConfiguration section */ 263 | 607FACED1AFB9204008FA782 /* Debug */ = { 264 | isa = XCBuildConfiguration; 265 | buildSettings = { 266 | ALWAYS_SEARCH_USER_PATHS = NO; 267 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 268 | CLANG_CXX_LIBRARY = "libc++"; 269 | CLANG_ENABLE_MODULES = YES; 270 | CLANG_ENABLE_OBJC_ARC = YES; 271 | CLANG_WARN_BOOL_CONVERSION = YES; 272 | CLANG_WARN_CONSTANT_CONVERSION = YES; 273 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 274 | CLANG_WARN_EMPTY_BODY = YES; 275 | CLANG_WARN_ENUM_CONVERSION = YES; 276 | CLANG_WARN_INT_CONVERSION = YES; 277 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 278 | CLANG_WARN_UNREACHABLE_CODE = YES; 279 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 280 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 281 | COPY_PHASE_STRIP = NO; 282 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 283 | ENABLE_STRICT_OBJC_MSGSEND = YES; 284 | ENABLE_TESTABILITY = YES; 285 | GCC_C_LANGUAGE_STANDARD = gnu99; 286 | GCC_DYNAMIC_NO_PIC = NO; 287 | GCC_NO_COMMON_BLOCKS = YES; 288 | GCC_OPTIMIZATION_LEVEL = 0; 289 | GCC_PREPROCESSOR_DEFINITIONS = ( 290 | "DEBUG=1", 291 | "$(inherited)", 292 | ); 293 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 294 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 295 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 296 | GCC_WARN_UNDECLARED_SELECTOR = YES; 297 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 298 | GCC_WARN_UNUSED_FUNCTION = YES; 299 | GCC_WARN_UNUSED_VARIABLE = YES; 300 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 301 | MTL_ENABLE_DEBUG_INFO = YES; 302 | ONLY_ACTIVE_ARCH = YES; 303 | SDKROOT = iphoneos; 304 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 305 | }; 306 | name = Debug; 307 | }; 308 | 607FACEE1AFB9204008FA782 /* Release */ = { 309 | isa = XCBuildConfiguration; 310 | buildSettings = { 311 | ALWAYS_SEARCH_USER_PATHS = NO; 312 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 313 | CLANG_CXX_LIBRARY = "libc++"; 314 | CLANG_ENABLE_MODULES = YES; 315 | CLANG_ENABLE_OBJC_ARC = YES; 316 | CLANG_WARN_BOOL_CONVERSION = YES; 317 | CLANG_WARN_CONSTANT_CONVERSION = YES; 318 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 319 | CLANG_WARN_EMPTY_BODY = YES; 320 | CLANG_WARN_ENUM_CONVERSION = YES; 321 | CLANG_WARN_INT_CONVERSION = YES; 322 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 323 | CLANG_WARN_UNREACHABLE_CODE = YES; 324 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 325 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 326 | COPY_PHASE_STRIP = NO; 327 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 328 | ENABLE_NS_ASSERTIONS = NO; 329 | ENABLE_STRICT_OBJC_MSGSEND = YES; 330 | GCC_C_LANGUAGE_STANDARD = gnu99; 331 | GCC_NO_COMMON_BLOCKS = YES; 332 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 333 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 334 | GCC_WARN_UNDECLARED_SELECTOR = YES; 335 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 336 | GCC_WARN_UNUSED_FUNCTION = YES; 337 | GCC_WARN_UNUSED_VARIABLE = YES; 338 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 339 | MTL_ENABLE_DEBUG_INFO = NO; 340 | SDKROOT = iphoneos; 341 | VALIDATE_PRODUCT = YES; 342 | }; 343 | name = Release; 344 | }; 345 | 607FACF01AFB9204008FA782 /* Debug */ = { 346 | isa = XCBuildConfiguration; 347 | buildSettings = { 348 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 349 | INFOPLIST_FILE = PencilCup/Info.plist; 350 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 351 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 352 | MODULE_NAME = ExampleApp; 353 | PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.demo.$(PRODUCT_NAME:rfc1034identifier)"; 354 | PRODUCT_NAME = "$(TARGET_NAME)"; 355 | SWIFT_VERSION = 3.0; 356 | }; 357 | name = Debug; 358 | }; 359 | 607FACF11AFB9204008FA782 /* Release */ = { 360 | isa = XCBuildConfiguration; 361 | buildSettings = { 362 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 363 | INFOPLIST_FILE = PencilCup/Info.plist; 364 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 365 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 366 | MODULE_NAME = ExampleApp; 367 | PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.demo.$(PRODUCT_NAME:rfc1034identifier)"; 368 | PRODUCT_NAME = "$(TARGET_NAME)"; 369 | SWIFT_VERSION = 3.0; 370 | }; 371 | name = Release; 372 | }; 373 | /* End XCBuildConfiguration section */ 374 | 375 | /* Begin XCConfigurationList section */ 376 | 607FACCB1AFB9204008FA782 /* Build configuration list for PBXProject "PencilCup" */ = { 377 | isa = XCConfigurationList; 378 | buildConfigurations = ( 379 | 607FACED1AFB9204008FA782 /* Debug */, 380 | 607FACEE1AFB9204008FA782 /* Release */, 381 | ); 382 | defaultConfigurationIsVisible = 0; 383 | defaultConfigurationName = Release; 384 | }; 385 | 607FACEF1AFB9204008FA782 /* Build configuration list for PBXNativeTarget "PencilCup_Example" */ = { 386 | isa = XCConfigurationList; 387 | buildConfigurations = ( 388 | 607FACF01AFB9204008FA782 /* Debug */, 389 | 607FACF11AFB9204008FA782 /* Release */, 390 | ); 391 | defaultConfigurationIsVisible = 0; 392 | defaultConfigurationName = Release; 393 | }; 394 | /* End XCConfigurationList section */ 395 | }; 396 | rootObject = 607FACC81AFB9204008FA782 /* Project object */; 397 | } 398 | --------------------------------------------------------------------------------