├── .gitignore ├── Demos └── DSFDragSlider Demo │ ├── DSFDragSlider Demo │ ├── Assets.xcassets │ │ ├── Contents.json │ │ ├── AccentColor.colorset │ │ │ └── Contents.json │ │ └── AppIcon.appiconset │ │ │ └── Contents.json │ ├── DSFDragSlider_Demo.entitlements │ ├── Info.plist │ ├── AppDelegate.swift │ └── Base.lproj │ │ └── MainMenu.xib │ ├── DSFDragSlider Objc Demo │ ├── Assets.xcassets │ │ ├── Contents.json │ │ ├── AccentColor.colorset │ │ │ └── Contents.json │ │ └── AppIcon.appiconset │ │ │ └── Contents.json │ ├── AppDelegate.h │ ├── main.m │ ├── DSFDragSlider_Objc_Demo.entitlements │ ├── Info.plist │ └── AppDelegate.m │ ├── DSFDragSlider SwiftUI Demo │ ├── Assets.xcassets │ │ ├── Contents.json │ │ ├── AccentColor.colorset │ │ │ └── Contents.json │ │ └── AppIcon.appiconset │ │ │ └── Contents.json │ ├── Preview Content │ │ └── Preview Assets.xcassets │ │ │ └── Contents.json │ ├── DSFDragSlider_SwiftUI_Demo.entitlements │ ├── Info.plist │ ├── AppDelegate.swift │ ├── ContentView.swift │ └── Base.lproj │ │ └── Main.storyboard │ └── DSFDragSlider Demo.xcodeproj │ ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist │ ├── xcshareddata │ └── xcschemes │ │ └── DSFDragSlider Objc Demo.xcscheme │ └── project.pbxproj ├── Tests ├── LinuxMain.swift └── DSFDragSliderTests │ ├── XCTestManifests.swift │ └── DSFDragSliderTests.swift ├── .swiftpm └── xcode │ └── package.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ └── IDEWorkspaceChecks.plist ├── Package.swift ├── LICENSE ├── Sources └── DSFDragSlider │ ├── private │ ├── NSGraphicsContext+extensions.swift │ ├── DSFKeyedPanGestureRecognizer.swift │ └── DSFDragSlider+private.swift │ ├── DSFDragSliderProtocol.swift │ ├── DSFDragSlider.swift │ └── DSFDragSlider+SwiftUI.swift └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | /.build 3 | /Packages 4 | /*.xcodeproj 5 | xcuserdata/ 6 | Package.resolved 7 | -------------------------------------------------------------------------------- /Demos/DSFDragSlider Demo/DSFDragSlider Demo/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Demos/DSFDragSlider Demo/DSFDragSlider Objc Demo/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Demos/DSFDragSlider Demo/DSFDragSlider SwiftUI Demo/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Tests/LinuxMain.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | 3 | import DSFDragSliderTests 4 | 5 | var tests = [XCTestCaseEntry]() 6 | tests += DSFDragSliderTests.allTests() 7 | XCTMain(tests) 8 | -------------------------------------------------------------------------------- /Demos/DSFDragSlider Demo/DSFDragSlider SwiftUI Demo/Preview Content/Preview Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Tests/DSFDragSliderTests/XCTestManifests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | 3 | #if !canImport(ObjectiveC) 4 | public func allTests() -> [XCTestCaseEntry] { 5 | return [ 6 | testCase(DSFDragSliderTests.allTests), 7 | ] 8 | } 9 | #endif 10 | -------------------------------------------------------------------------------- /Demos/DSFDragSlider Demo/DSFDragSlider Demo.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Demos/DSFDragSlider Demo/DSFDragSlider Demo/Assets.xcassets/AccentColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "idiom" : "universal" 5 | } 6 | ], 7 | "info" : { 8 | "author" : "xcode", 9 | "version" : 1 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Demos/DSFDragSlider Demo/DSFDragSlider Objc Demo/Assets.xcassets/AccentColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "idiom" : "universal" 5 | } 6 | ], 7 | "info" : { 8 | "author" : "xcode", 9 | "version" : 1 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Demos/DSFDragSlider Demo/DSFDragSlider SwiftUI Demo/Assets.xcassets/AccentColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "idiom" : "universal" 5 | } 6 | ], 7 | "info" : { 8 | "author" : "xcode", 9 | "version" : 1 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Demos/DSFDragSlider Demo/DSFDragSlider Objc Demo/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // DSFDragSlider Objc Demo 4 | // 5 | // Created by Darren Ford on 21/9/20. 6 | // 7 | 8 | #import 9 | 10 | @interface AppDelegate : NSObject 11 | 12 | 13 | @end 14 | 15 | -------------------------------------------------------------------------------- /.swiftpm/xcode/package.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Demos/DSFDragSlider Demo/DSFDragSlider Demo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Demos/DSFDragSlider Demo/DSFDragSlider Objc Demo/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // DSFDragSlider Objc Demo 4 | // 5 | // Created by Darren Ford on 21/9/20. 6 | // 7 | 8 | #import 9 | 10 | int main(int argc, const char * argv[]) { 11 | @autoreleasepool { 12 | // Setup code that might create autoreleased objects goes here. 13 | } 14 | return NSApplicationMain(argc, argv); 15 | } 16 | -------------------------------------------------------------------------------- /Demos/DSFDragSlider Demo/DSFDragSlider Demo/DSFDragSlider_Demo.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 | -------------------------------------------------------------------------------- /Demos/DSFDragSlider Demo/DSFDragSlider Objc Demo/DSFDragSlider_Objc_Demo.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 | -------------------------------------------------------------------------------- /Demos/DSFDragSlider Demo/DSFDragSlider SwiftUI Demo/DSFDragSlider_SwiftUI_Demo.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 | -------------------------------------------------------------------------------- /Tests/DSFDragSliderTests/DSFDragSliderTests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | @testable import DSFDragSlider 3 | 4 | final class DSFDragSliderTests: XCTestCase { 5 | func testExample() { 6 | // This is an example of a functional test case. 7 | // Use XCTAssert and related functions to verify your tests produce the correct 8 | // results. 9 | //XCTAssertEqual(DSFDragSlider().text, "Hello, World!") 10 | } 11 | 12 | static var allTests = [ 13 | ("testExample", testExample), 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:5.3 2 | 3 | import PackageDescription 4 | 5 | let package = Package( 6 | name: "DSFDragSlider", 7 | platforms: [ 8 | .macOS(.v10_11) 9 | ], 10 | products: [ 11 | .library(name: "DSFDragSlider", targets: ["DSFDragSlider"]), 12 | .library(name: "DSFDragSlider-static", type: .static, targets: ["DSFDragSlider"]), 13 | .library(name: "DSFDragSlider-shared", type: .dynamic, targets: ["DSFDragSlider"]), 14 | ], 15 | dependencies: [ 16 | .package(url: "https://github.com/dagronf/DSFAppearanceManager", from: "3.3.0") 17 | ], 18 | targets: [ 19 | .target( 20 | name: "DSFDragSlider", 21 | dependencies: ["DSFAppearanceManager"]), 22 | .testTarget( 23 | name: "DSFDragSliderTests", 24 | dependencies: ["DSFDragSlider"]), 25 | ] 26 | ) 27 | -------------------------------------------------------------------------------- /Demos/DSFDragSlider Demo/DSFDragSlider Demo/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 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleVersion 22 | 1 23 | LSMinimumSystemVersion 24 | $(MACOSX_DEPLOYMENT_TARGET) 25 | NSMainNibFile 26 | MainMenu 27 | NSPrincipalClass 28 | NSApplication 29 | 30 | 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Darren Ford 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. -------------------------------------------------------------------------------- /Demos/DSFDragSlider Demo/DSFDragSlider Objc Demo/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 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleVersion 22 | 1 23 | LSMinimumSystemVersion 24 | $(MACOSX_DEPLOYMENT_TARGET) 25 | NSMainNibFile 26 | MainMenu 27 | NSPrincipalClass 28 | NSApplication 29 | 30 | 31 | -------------------------------------------------------------------------------- /Demos/DSFDragSlider Demo/DSFDragSlider SwiftUI Demo/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 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleVersion 22 | 1 23 | LSMinimumSystemVersion 24 | $(MACOSX_DEPLOYMENT_TARGET) 25 | NSMainStoryboardFile 26 | Main 27 | NSPrincipalClass 28 | NSApplication 29 | 30 | 31 | -------------------------------------------------------------------------------- /Demos/DSFDragSlider Demo/DSFDragSlider Demo/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "scale" : "1x", 6 | "size" : "16x16" 7 | }, 8 | { 9 | "idiom" : "mac", 10 | "scale" : "2x", 11 | "size" : "16x16" 12 | }, 13 | { 14 | "idiom" : "mac", 15 | "scale" : "1x", 16 | "size" : "32x32" 17 | }, 18 | { 19 | "idiom" : "mac", 20 | "scale" : "2x", 21 | "size" : "32x32" 22 | }, 23 | { 24 | "idiom" : "mac", 25 | "scale" : "1x", 26 | "size" : "128x128" 27 | }, 28 | { 29 | "idiom" : "mac", 30 | "scale" : "2x", 31 | "size" : "128x128" 32 | }, 33 | { 34 | "idiom" : "mac", 35 | "scale" : "1x", 36 | "size" : "256x256" 37 | }, 38 | { 39 | "idiom" : "mac", 40 | "scale" : "2x", 41 | "size" : "256x256" 42 | }, 43 | { 44 | "idiom" : "mac", 45 | "scale" : "1x", 46 | "size" : "512x512" 47 | }, 48 | { 49 | "idiom" : "mac", 50 | "scale" : "2x", 51 | "size" : "512x512" 52 | } 53 | ], 54 | "info" : { 55 | "author" : "xcode", 56 | "version" : 1 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /Demos/DSFDragSlider Demo/DSFDragSlider Objc Demo/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "scale" : "1x", 6 | "size" : "16x16" 7 | }, 8 | { 9 | "idiom" : "mac", 10 | "scale" : "2x", 11 | "size" : "16x16" 12 | }, 13 | { 14 | "idiom" : "mac", 15 | "scale" : "1x", 16 | "size" : "32x32" 17 | }, 18 | { 19 | "idiom" : "mac", 20 | "scale" : "2x", 21 | "size" : "32x32" 22 | }, 23 | { 24 | "idiom" : "mac", 25 | "scale" : "1x", 26 | "size" : "128x128" 27 | }, 28 | { 29 | "idiom" : "mac", 30 | "scale" : "2x", 31 | "size" : "128x128" 32 | }, 33 | { 34 | "idiom" : "mac", 35 | "scale" : "1x", 36 | "size" : "256x256" 37 | }, 38 | { 39 | "idiom" : "mac", 40 | "scale" : "2x", 41 | "size" : "256x256" 42 | }, 43 | { 44 | "idiom" : "mac", 45 | "scale" : "1x", 46 | "size" : "512x512" 47 | }, 48 | { 49 | "idiom" : "mac", 50 | "scale" : "2x", 51 | "size" : "512x512" 52 | } 53 | ], 54 | "info" : { 55 | "author" : "xcode", 56 | "version" : 1 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /Demos/DSFDragSlider Demo/DSFDragSlider SwiftUI Demo/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // DSFDragSlider SwiftUI Demo 4 | // 5 | // Created by Darren Ford on 21/9/20. 6 | // 7 | 8 | import Cocoa 9 | import SwiftUI 10 | 11 | @main 12 | class AppDelegate: NSObject, NSApplicationDelegate { 13 | 14 | var window: NSWindow! 15 | 16 | 17 | func applicationDidFinishLaunching(_ aNotification: Notification) { 18 | // Create the SwiftUI view that provides the window contents. 19 | let contentView = ContentView() 20 | 21 | // Create the window and set the content view. 22 | window = NSWindow( 23 | contentRect: NSRect(x: 0, y: 0, width: 480, height: 300), 24 | styleMask: [.titled, .closable, .miniaturizable, .resizable, .fullSizeContentView], 25 | backing: .buffered, defer: false) 26 | window.isReleasedWhenClosed = false 27 | window.center() 28 | window.setFrameAutosaveName("Main Window") 29 | window.contentView = NSHostingView(rootView: contentView) 30 | window.makeKeyAndOrderFront(nil) 31 | 32 | window.autorecalculatesKeyViewLoop = true 33 | } 34 | 35 | func applicationWillTerminate(_ aNotification: Notification) { 36 | // Insert code here to tear down your application 37 | } 38 | 39 | 40 | } 41 | 42 | -------------------------------------------------------------------------------- /Demos/DSFDragSlider Demo/DSFDragSlider SwiftUI Demo/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "scale" : "1x", 6 | "size" : "16x16" 7 | }, 8 | { 9 | "idiom" : "mac", 10 | "scale" : "2x", 11 | "size" : "16x16" 12 | }, 13 | { 14 | "idiom" : "mac", 15 | "scale" : "1x", 16 | "size" : "32x32" 17 | }, 18 | { 19 | "idiom" : "mac", 20 | "scale" : "2x", 21 | "size" : "32x32" 22 | }, 23 | { 24 | "idiom" : "mac", 25 | "scale" : "1x", 26 | "size" : "128x128" 27 | }, 28 | { 29 | "idiom" : "mac", 30 | "scale" : "2x", 31 | "size" : "128x128" 32 | }, 33 | { 34 | "idiom" : "mac", 35 | "scale" : "1x", 36 | "size" : "256x256" 37 | }, 38 | { 39 | "idiom" : "mac", 40 | "scale" : "2x", 41 | "size" : "256x256" 42 | }, 43 | { 44 | "idiom" : "mac", 45 | "scale" : "1x", 46 | "size" : "512x512" 47 | }, 48 | { 49 | "idiom" : "mac", 50 | "scale" : "2x", 51 | "size" : "512x512" 52 | } 53 | ], 54 | "info" : { 55 | "author" : "xcode", 56 | "version" : 1 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /Demos/DSFDragSlider Demo/DSFDragSlider Objc Demo/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // DSFDragSlider Objc Demo 4 | // 5 | // Created by Darren Ford on 21/9/20. 6 | // 7 | 8 | #import "AppDelegate.h" 9 | 10 | @import DSFDragSlider; 11 | 12 | @interface AppDelegate () 13 | 14 | @property (strong) IBOutlet NSWindow *window; 15 | 16 | @property (weak) IBOutlet DSFDragSlider *dragSlider1; 17 | @property (weak) IBOutlet DSFDragSlider *dragSlider2; 18 | @property (weak) IBOutlet DSFDragSlider *dragSlider3; 19 | 20 | @end 21 | 22 | @implementation AppDelegate 23 | 24 | - (void)applicationDidFinishLaunching:(NSNotification *)aNotification { 25 | // Insert code here to initialize your application 26 | 27 | self.dragSlider1.position = CGPointMake(200, 400); 28 | } 29 | 30 | 31 | - (void)applicationWillTerminate:(NSNotification *)aNotification { 32 | // Insert code here to tear down your application 33 | } 34 | 35 | - (IBAction)randomPressed:(id)sender { 36 | 37 | CGFloat rx = arc4random_uniform(1000.0) - 500.0; 38 | CGFloat ry = arc4random_uniform(1000.0) - 500.0; 39 | 40 | self.dragSlider1.position = CGPointMake(rx, ry); 41 | } 42 | 43 | - (IBAction)resetPressed:(id)sender { 44 | self.dragSlider1.position = CGPointMake(0, 0); 45 | } 46 | 47 | @end 48 | -------------------------------------------------------------------------------- /Sources/DSFDragSlider/private/NSGraphicsContext+extensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NSGraphicsContext+extensions.swift 3 | // 4 | // Copyright © 2022 Darren Ford. All rights reserved. 5 | // 6 | // MIT License 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in all 16 | // copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | // SOFTWARE. 25 | 26 | #if os(macOS) 27 | 28 | import AppKit 29 | 30 | internal extension NSGraphicsContext { 31 | static func enterState(block: () -> Void) { 32 | NSGraphicsContext.saveGraphicsState() 33 | defer { NSGraphicsContext.restoreGraphicsState() } 34 | block() 35 | } 36 | } 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /Demos/DSFDragSlider Demo/DSFDragSlider Demo/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // DSFDragSlider Demo 4 | // 5 | // Created by Darren Ford on 20/9/20. 6 | // 7 | 8 | import Cocoa 9 | 10 | import DSFDragSlider 11 | 12 | @main 13 | class AppDelegate: NSObject, NSApplicationDelegate { 14 | 15 | @IBOutlet var window: NSWindow! 16 | 17 | @IBOutlet weak var dragSlider: DSFDragSlider! 18 | 19 | @IBOutlet weak var dragSlider2: DSFDragSlider! 20 | @IBOutlet weak var xValue: NSTextField! 21 | @IBOutlet weak var yValue: NSTextField! 22 | 23 | func applicationDidFinishLaunching(_ aNotification: Notification) { 24 | // Insert code here to initialize your application 25 | 26 | dragSlider2.delegate = self 27 | self.xValue.doubleValue = Double(dragSlider2.x) 28 | self.yValue.doubleValue = Double(dragSlider2.y) 29 | } 30 | 31 | func applicationWillTerminate(_ aNotification: Notification) { 32 | // Insert code here to tear down your application 33 | } 34 | } 35 | 36 | extension AppDelegate: DSFDragSliderProtocol { 37 | func dragSlider(_ dragSlide: DSFDragSlider, didStartDragAtPoint point: CGPoint) { 38 | Swift.print("Start Drag (\(point))") 39 | } 40 | 41 | func dragSlider(_ dragSlide: DSFDragSlider, didChangePosition point: CGPoint) { 42 | self.xValue.doubleValue = Double(point.x) 43 | self.yValue.doubleValue = Double(point.y) 44 | } 45 | 46 | func dragSlider(_ dragSlide: DSFDragSlider, didCancelDragAtPoint point: CGPoint) { 47 | Swift.print("Drag cancelled (\(point))") 48 | } 49 | 50 | func dragSlider(_ dragSlide: DSFDragSlider, didEndDragAtPoint point: CGPoint) { 51 | Swift.print("Drag ended (\(point))") 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /Sources/DSFDragSlider/DSFDragSliderProtocol.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DSFDragSliderProtocol.swift 3 | // 4 | // Copyright © 2022 Darren Ford. All rights reserved. 5 | // 6 | // MIT License 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in all 16 | // copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | // SOFTWARE. 25 | 26 | #if os(macOS) 27 | 28 | import Foundation 29 | import AppKit 30 | 31 | /// Protocol for handling drag slider events 32 | @objc public protocol DSFDragSliderProtocol: AnyObject { 33 | /// The position changed for the specified drag slider 34 | @objc func dragSlider(_ dragSlide: DSFDragSlider, didChangePosition point: CGPoint) 35 | 36 | /// The user cancelled an active drag (using the ESC key) 37 | @objc func dragSlider(_ dragSlide: DSFDragSlider, didCancelDragAtPoint point: CGPoint) 38 | 39 | /// A drag was completed 40 | @objc func dragSlider(_ dragSlide: DSFDragSlider, didEndDragAtPoint point: CGPoint) 41 | } 42 | 43 | #endif 44 | -------------------------------------------------------------------------------- /Sources/DSFDragSlider/private/DSFKeyedPanGestureRecognizer.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DSFKeyedPanGestureRecognizer.swift 3 | // 4 | // Copyright © 2022 Darren Ford. All rights reserved. 5 | // 6 | // MIT License 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in all 16 | // copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | // SOFTWARE. 25 | 26 | #if os(macOS) 27 | 28 | import AppKit 29 | import Foundation 30 | 31 | /// Pan gesture recognizer that passes key events to its containing view 32 | internal class DSFKeyedPanGestureRecognizer: NSPanGestureRecognizer { 33 | override func keyDown(with event: NSEvent) { 34 | super.keyDown(with: event) 35 | self.view?.keyDown(with: event) 36 | } 37 | 38 | override func keyUp(with event: NSEvent) { 39 | super.keyUp(with: event) 40 | self.view?.keyUp(with: event) 41 | } 42 | 43 | override func mouseDown(with event: NSEvent) { 44 | super.mouseDown(with: event) 45 | self.view?.mouseDown(with: event) 46 | } 47 | 48 | override func mouseUp(with event: NSEvent) { 49 | super.mouseUp(with: event) 50 | self.view?.mouseUp(with: event) 51 | } 52 | } 53 | 54 | #endif 55 | -------------------------------------------------------------------------------- /Demos/DSFDragSlider Demo/DSFDragSlider Demo.xcodeproj/xcshareddata/xcschemes/DSFDragSlider Objc Demo.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 45 | 51 | 52 | 53 | 54 | 60 | 62 | 68 | 69 | 70 | 71 | 73 | 74 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /Demos/DSFDragSlider Demo/DSFDragSlider SwiftUI Demo/ContentView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ContentView.swift 3 | // DSFDragSlider SwiftUI Demo 4 | // 5 | // Created by Darren Ford on 21/9/20. 6 | // 7 | 8 | import SwiftUI 9 | import DSFDragSlider 10 | 11 | struct ContentView: View { 12 | 13 | @State private var isState1 = true 14 | private static let state1 = DSFDragSliderUI.Configuration( 15 | range: CGRect(x: -1000, y: -1000, width: 2000, height: 2000), 16 | deltaX: 1, 17 | deltaY: 1 18 | ) 19 | private static let state2 = DSFDragSliderUI.Configuration( 20 | range: CGRect(x: 0, y: 0, width: 100, height: 100), 21 | deltaX: 0.5, 22 | deltaY: 0.5 23 | ) 24 | 25 | //// 26 | 27 | @State var config = state1 28 | @State private var position = CGPoint(x: 0, y: 0) 29 | 30 | var config2 = DSFDragSliderUI.Configuration( 31 | range: CGRect(x: 0, y: 0, width: 512, height: 512), 32 | deltaX: 1, 33 | deltaY: 1 34 | ) 35 | @State private var position2 = CGPoint(x: 200, y: 350) 36 | 37 | @State private var xValue: String = "200.00" 38 | @State private var yValue: String = "350.00" 39 | 40 | @State private var isEnabled: Bool = true 41 | 42 | var body: some View { 43 | VStack { 44 | DSFDragSliderUI( 45 | configuration: $config, 46 | currentPosition: $position, 47 | dragChangedBlock: { point in 48 | Swift.print("changed point = \(point)") 49 | }, 50 | dragEndedBlock: { point in 51 | Swift.print("ended point = \(point)") 52 | } 53 | ) 54 | .padding() 55 | 56 | Text("\(String(format: "X = %.02f, Y = %.02f", self.position.x, self.position.y))") 57 | 58 | HStack { 59 | Button("Reset") { 60 | self.position = CGPoint(x: 0, y: 0) 61 | } 62 | 63 | Button("Change") { 64 | if isState1 { 65 | self.config = ContentView.state2 66 | } 67 | else { 68 | self.config = ContentView.state1 69 | } 70 | self.position = CGPoint(x: 0, y: 0) 71 | isState1.toggle() 72 | } 73 | } 74 | 75 | Divider() 76 | .frame(maxWidth: .infinity) 77 | 78 | VStack(alignment: .leading, spacing: 16) { 79 | 80 | Toggle(isOn: $isEnabled, label: { 81 | Text("Is Enabled") 82 | }) 83 | .toggleStyle(CheckboxToggleStyle()) 84 | 85 | HStack { 86 | DSFDragSliderUI( 87 | configuration: .constant(config2), 88 | currentPosition: $position2, 89 | dragChangedBlock: { point in 90 | xValue = String(format: "%.02f", point.x) 91 | yValue = String(format: "%.02f", point.y) 92 | }, 93 | dragEndedBlock: { point in 94 | Swift.print("ended point = \(point)") 95 | } 96 | ) 97 | .disabled(!self.isEnabled) 98 | .frame(width: 51, height: 51, alignment: .center) 99 | 100 | VStack { 101 | TextField( 102 | "X Value", text: $xValue, 103 | onCommit: { 104 | let v = Float(xValue) 105 | position2.x = CGFloat(v ?? 0) 106 | } 107 | ) 108 | .disabled(!self.isEnabled) 109 | 110 | TextField( 111 | "Y Value", text: $yValue, 112 | onCommit: { 113 | let v = Float(xValue) 114 | position2.x = CGFloat(v ?? 0) 115 | } 116 | ) 117 | .disabled(!self.isEnabled) 118 | } 119 | } 120 | } 121 | .padding() 122 | } 123 | } 124 | } 125 | 126 | struct ContentView_Previews: PreviewProvider { 127 | static var previews: some View { 128 | ContentView() 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /Sources/DSFDragSlider/DSFDragSlider.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DSFDragSlider.swift 3 | // 4 | // Copyright © 2022 Darren Ford. All rights reserved. 5 | // 6 | // MIT License 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in all 16 | // copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | // SOFTWARE. 25 | 26 | #if os(macOS) 27 | 28 | import AppKit 29 | 30 | /// A 2d-position selector 31 | @IBDesignable 32 | public class DSFDragSlider: NSView, NSGestureRecognizerDelegate { 33 | /// The delegate receives callbacks as the control is dragged 34 | @objc public weak var delegate: DSFDragSliderProtocol? 35 | 36 | /// Is the control enabled? 37 | @IBInspectable var isEnabled: Bool = true { 38 | didSet { 39 | self.needsDisplay = true 40 | self.recognizer?.isEnabled = self.isEnabled 41 | } 42 | } 43 | 44 | /// Minimum allowed X value 45 | @IBInspectable var minX: CGFloat = 0 46 | /// Maximum allowed X value 47 | @IBInspectable var maxX: CGFloat = 1000 48 | 49 | /// Minimum allowed Y value 50 | @IBInspectable var minY: CGFloat = 0 51 | /// Maximum allowed Y value 52 | @IBInspectable var maxY: CGFloat = 1000 53 | 54 | /// Convenience for getting/setting the range via a rect 55 | @objc public var range: CGRect { 56 | get { 57 | return CGRect(x: self.minX, y: self.minY, width: self.maxX - self.minX, height: self.maxY - self.minY) 58 | } 59 | set { 60 | self.minX = newValue.minX 61 | self.maxX = newValue.maxX 62 | self.minY = newValue.minY 63 | self.maxY = newValue.maxY 64 | 65 | self.needsDisplay = true 66 | } 67 | } 68 | 69 | /// The delta recorded per horizontal pixel move 70 | @IBInspectable var deltaX: CGFloat = 1.0 71 | /// The delta recorded per vertical pixel move 72 | @IBInspectable var deltaY: CGFloat = 1.0 73 | 74 | /// The current position 75 | @objc public dynamic var position = CGPoint(x: 500, y: 500) { 76 | willSet { 77 | self.willChangeValue(for: \.x) 78 | self.willChangeValue(for: \.y) 79 | } 80 | 81 | didSet { 82 | self.didChangeValue(for: \.x) 83 | self.didChangeValue(for: \.y) 84 | self.needsDisplay = true 85 | } 86 | } 87 | 88 | /// The current X value for the control 89 | @objc public dynamic var x: CGFloat { 90 | get { 91 | self.position.x 92 | } 93 | set { 94 | self.willChangeValue(for: \.position) 95 | let nv = min(max(minX, newValue), maxX) 96 | self.position.x = nv 97 | self.didChangeValue(for: \.position) 98 | self.needsDisplay = true 99 | } 100 | } 101 | 102 | /// The current Y value for the control 103 | @objc public dynamic var y: CGFloat { 104 | get { 105 | self.position.y 106 | } 107 | set { 108 | self.willChangeValue(for: \.position) 109 | let nv = min(max(minY, newValue), maxY) 110 | self.position.y = nv 111 | self.didChangeValue(for: \.position) 112 | } 113 | } 114 | 115 | @objc override public init(frame frameRect: NSRect) { 116 | super.init(frame: frameRect) 117 | self.setup() 118 | } 119 | 120 | @objc public required init?(coder: NSCoder) { 121 | super.init(coder: coder) 122 | self.setup() 123 | } 124 | 125 | // Private 126 | 127 | deinit { 128 | if let r = self.recognizer { 129 | self.removeGestureRecognizer(r) 130 | self.recognizer = nil 131 | } 132 | } 133 | 134 | // Drag/Key recognizer 135 | internal var recognizer: DSFKeyedPanGestureRecognizer? 136 | 137 | // Mouse tracker 138 | internal var tracker: NSTrackingArea? 139 | 140 | // Are we currently panning on the control? 141 | internal var isPanning = false 142 | 143 | internal var isHover = false 144 | 145 | // The previous position for the drag 146 | internal var lastPosition: CGPoint? 147 | 148 | // The position before the user started interacting with the control 149 | internal var originalPosition: CGPoint? 150 | } 151 | 152 | #endif 153 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DSFDragSlider 2 | 3 | ![](https://img.shields.io/github/v/tag/dagronf/DSFDragSlider) ![](https://img.shields.io/badge/macOS-10.11+-red) ![](https://img.shields.io/badge/Swift-5.0-orange.svg) 4 | ![](https://img.shields.io/badge/License-MIT-lightgrey) [![](https://img.shields.io/badge/spm-compatible-brightgreen.svg?style=flat)](https://swift.org/package-manager) 5 | 6 | A virtual trackpad macOS control. 7 | 8 | ![](https://github.com/dagronf/dagronf.github.io/raw/master/art/projects/DSFDragSlider/dsfdragslider.gif) 9 | 10 | ## Why 11 | 12 | I have a project that needs the ability to change 2-dimension values (x:y or width:height for example). The project has limited UI space so I wanted a control that acted like a trackpad for tweaking a positional value. 13 | 14 | ## Features 15 | 16 | * Dark mode support, high contrast support 17 | * Keyboard support (use the arrow keys when the field is focussed) 18 | * Cancelable drags (hit the ESC key during drag) 19 | * shift-drag to temporarily increase the delta values by 10 during the drag (faster tracking) 20 | * option-drag to temporarily decrease the delta values by 10 during the drag (slower tracking) 21 | 22 | 23 | ## Properties 24 | 25 | All properties support Cocoa Bindings. 26 | 27 | * `isEnabled` : Whether the control is enabled (Bool) 28 | 29 | ### Dimensions 30 | 31 | * `minX` : The minimum x-value represented (CGFloat) 32 | * `minY` : The minimum y-value represented (CGFloat) 33 | * `maxX` : The maximum x-value represented (CGFloat) 34 | * `maxY` : The maximum y-value represented (CGFloat) 35 | * `deltaX` : The dragging x scale factor (CGFloat). The higher the value, the faster the tracking. 36 | * `deltaY` : The dragging y scale factor (CGFloat). The higher the value, the faster the tracking. 37 | 38 | * `range` : The rectangle representing the draggable range. 39 | 40 | #### Positions 41 | 42 | * `position` : The current position (CGPoint) 43 | * `x` : The current x position (CGFloat) 44 | * `y` : The current y position (CGFloat) 45 | 46 | ## Delegate 47 | 48 | The control can report updates via a supplied delegate (DSFDragSliderProtocol) 49 | 50 | ```swift 51 | /// A drag was started at a particular point 52 | @objc func dragSlider(_ dragSlide: DSFDragSlider, didStartDragAtPoint: CGPoint) 53 | 54 | /// The position changed for the specified drag slider 55 | @objc func dragSlider(_ dragSlide: DSFDragSlider, didChangePosition: CGPoint) 56 | 57 | /// The user cancelled an active drag (using the ESC key) 58 | @objc func dragSlider(_ dragSlide: DSFDragSlider, didCancelDragAtPoint: CGPoint) 59 | ``` 60 | 61 | ## SwiftUI 62 | 63 | There is also a SwiftUI wrapper for DSFDragSlider, called `DSFDragSliderUI` 64 | 65 | ```swift 66 | struct ContentView: View { 67 | // The configuration for the drag slider 68 | var configuration = DragSlider.Configuration( 69 | range: CGRect(x: -100, y: -100, width: 200, height: 200), 70 | deltaX: 1, 71 | deltaY: 1 72 | ) 73 | 74 | // A dynamically updated position as the user drags the control 75 | @State private var currentPosition = CGPoint(x: 50, y: 50) 76 | 77 | @State private var isDisabled = false 78 | 79 | var body: some View { 80 | DSFDragSliderUI( 81 | configuration: .constant(configuration), 82 | currentPosition: $position 83 | ) 84 | .disabled(self.isDisabled) 85 | } 86 | } 87 | ``` 88 | 89 | 90 | ## Screenshots 91 | 92 | drawing 93 | 94 | ![](https://github.com/dagronf/dagronf.github.io/raw/master/art/projects/DSFDragSlider/dsfdragslider_demo.gif) 95 | 96 | 97 | ## License 98 | 99 | ``` 100 | MIT License 101 | 102 | Copyright (c) 2020 Darren Ford 103 | 104 | Permission is hereby granted, free of charge, to any person obtaining a copy 105 | of this software and associated documentation files (the "Software"), to deal 106 | in the Software without restriction, including without limitation the rights 107 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 108 | copies of the Software, and to permit persons to whom the Software is 109 | furnished to do so, subject to the following conditions: 110 | 111 | The above copyright notice and this permission notice shall be included in all 112 | copies or substantial portions of the Software. 113 | 114 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 115 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 116 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 117 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 118 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 119 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 120 | SOFTWARE. 121 | ``` 122 | -------------------------------------------------------------------------------- /Sources/DSFDragSlider/DSFDragSlider+SwiftUI.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DSFDragSlider+SwiftUI.swift 3 | // 4 | // Copyright © 2022 Darren Ford. All rights reserved. 5 | // 6 | // MIT License 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in all 16 | // copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | // SOFTWARE. 25 | 26 | #if canImport(SwiftUI) && os(macOS) 27 | 28 | import AppKit 29 | import SwiftUI 30 | 31 | @available(macOS 10.15, *) 32 | public struct DSFDragSliderUI: NSViewRepresentable { 33 | 34 | public typealias NSViewType = DSFDragSlider 35 | 36 | public struct Configuration { 37 | let range: CGRect 38 | let deltaX: CGFloat 39 | let deltaY: CGFloat 40 | 41 | public init(range: CGRect, deltaX: CGFloat, deltaY: CGFloat) { 42 | self.range = range 43 | self.deltaX = deltaX 44 | self.deltaY = deltaY 45 | } 46 | } 47 | 48 | @Binding var configuration: Configuration 49 | @Binding var currentPosition: CGPoint 50 | let isEnabled: Bool 51 | 52 | private var dragChangedBlock: ((CGPoint) -> Void)? = nil 53 | private var dragEndedBlock: ((CGPoint) -> Void)? = nil 54 | 55 | public init( 56 | configuration: Binding, 57 | currentPosition: Binding, 58 | dragChangedBlock: ((CGPoint) -> Void)? = nil, 59 | dragEndedBlock: ((CGPoint) -> Void)? = nil 60 | ) { 61 | self.isEnabled = true 62 | self._configuration = configuration 63 | self._currentPosition = currentPosition 64 | self.dragChangedBlock = dragChangedBlock 65 | self.dragEndedBlock = dragEndedBlock 66 | } 67 | 68 | // Modifier for enabling/disabling the control 69 | public func disabled(_ disabled: Bool) -> some View { 70 | return DSFDragSliderUI( 71 | isEnabled: !disabled, 72 | configuration: self.$configuration, 73 | currentPosition: self.$currentPosition, 74 | dragChangedBlock: self.dragChangedBlock, 75 | dragEndedBlock: self.dragEndedBlock 76 | ) 77 | } 78 | } 79 | 80 | @available(macOS 10.15, *) 81 | extension DSFDragSliderUI { 82 | internal init( 83 | isEnabled: Bool, 84 | configuration: Binding, 85 | currentPosition: Binding, 86 | dragChangedBlock: ((CGPoint) -> Void)? = nil, 87 | dragEndedBlock: ((CGPoint) -> Void)? = nil 88 | ) { 89 | self.isEnabled = isEnabled 90 | self._configuration = configuration 91 | self._currentPosition = currentPosition 92 | self.dragChangedBlock = dragChangedBlock 93 | self.dragEndedBlock = dragEndedBlock 94 | } 95 | } 96 | 97 | @available(macOS 10.15, *) 98 | extension DSFDragSliderUI { 99 | public func makeCoordinator() -> Coordinator { 100 | Coordinator(self) 101 | } 102 | 103 | public func makeNSView(context: Context) -> DSFDragSlider { 104 | let dragSlider = DSFDragSlider() 105 | dragSlider.isEnabled = self.isEnabled 106 | dragSlider.range = configuration.range 107 | dragSlider.deltaX = configuration.deltaX 108 | dragSlider.deltaY = configuration.deltaY 109 | dragSlider.delegate = context.coordinator 110 | return dragSlider 111 | } 112 | 113 | public func updateNSView(_ nsView: DSFDragSlider, context: Context) { 114 | nsView.isEnabled = self.isEnabled 115 | nsView.position = self.currentPosition 116 | nsView.range = configuration.range 117 | nsView.deltaX = configuration.deltaX 118 | nsView.deltaY = configuration.deltaY 119 | } 120 | 121 | public class Coordinator: NSObject, DSFDragSliderProtocol { 122 | let parent: DSFDragSliderUI 123 | init(_ slider: DSFDragSliderUI) { 124 | self.parent = slider 125 | } 126 | 127 | public func dragSlider(_ dragSlide: DSFDragSlider, didChangePosition point: CGPoint) { 128 | parent.currentPosition = point 129 | parent.dragChangedBlock?(point) 130 | } 131 | 132 | public func dragSlider(_ dragSlide: DSFDragSlider, didCancelDragAtPoint point: CGPoint) { 133 | Swift.print("drag cancelled...") 134 | } 135 | 136 | public func dragSlider(_ dragSlide: DSFDragSlider, didEndDragAtPoint point: CGPoint) { 137 | parent.currentPosition = point 138 | parent.dragEndedBlock?(point) 139 | } 140 | } 141 | } 142 | 143 | ////////// 144 | @available(macOS 10.15, *) 145 | let DemoPosition = CGPoint(x: 0, y: 0) 146 | 147 | @available(macOS 10.15, *) 148 | let DemoConfig = DSFDragSliderUI.Configuration( 149 | range: CGRect(x: -1000, y: -1000, width: 2000, height: 2000), 150 | deltaX: 1, 151 | deltaY: 1) 152 | 153 | @available(macOS 10.15, *) 154 | struct DragSlider_Previews: PreviewProvider { 155 | static var previews: some View { 156 | DSFDragSliderUI( 157 | configuration: .constant(DemoConfig), 158 | currentPosition: .constant(DemoPosition) 159 | ) 160 | DSFDragSliderUI( 161 | configuration: .constant(DemoConfig), 162 | currentPosition: .constant(DemoPosition) 163 | ) 164 | .disabled(true) 165 | } 166 | } 167 | 168 | #endif 169 | -------------------------------------------------------------------------------- /Sources/DSFDragSlider/private/DSFDragSlider+private.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DSFDragSlider+private.swift 3 | // 4 | // Copyright © 2022 Darren Ford. All rights reserved. 5 | // 6 | // MIT License 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in all 16 | // copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | // SOFTWARE. 25 | 26 | #if os(macOS) 27 | 28 | import AppKit 29 | import Carbon.HIToolbox 30 | import Foundation 31 | 32 | import DSFAppearanceManager 33 | 34 | // MARK: - Configuration 35 | 36 | internal extension DSFDragSlider { 37 | func setup() { 38 | let r = DSFKeyedPanGestureRecognizer(target: self, action: #selector(self.userDidPan(_:))) 39 | if #available(OSX 10.12.2, *) { 40 | r.numberOfTouchesRequired = 1 41 | } 42 | r.delegate = self 43 | self.addGestureRecognizer(r) 44 | self.recognizer = r 45 | } 46 | } 47 | 48 | // MARK: - Drawing and layout 49 | 50 | extension DSFDragSlider { 51 | override public var focusRingMaskBounds: NSRect { 52 | return self.bounds 53 | } 54 | 55 | override public func drawFocusRingMask() { 56 | let pth = NSBezierPath(roundedRect: self.bounds, xRadius: 4.5, yRadius: 4.5) 57 | pth.fill() 58 | } 59 | 60 | override public func layout() { 61 | super.layout() 62 | 63 | if let t = self.tracker { 64 | self.removeTrackingArea(t) 65 | } 66 | 67 | self.tracker = NSTrackingArea( 68 | rect: self.bounds, 69 | options: [.mouseEnteredAndExited, .activeInKeyWindow], 70 | owner: self, 71 | userInfo: nil 72 | ) 73 | self.addTrackingArea(self.tracker!) 74 | } 75 | 76 | override public func draw(_ dirtyRect: NSRect) { 77 | self.alphaValue = self.isEnabled ? 1.0 : 0.4 78 | 79 | super.draw(dirtyRect) 80 | 81 | let rect = self.bounds.insetBy(dx: 1, dy: 1) 82 | 83 | // Drawing code here. 84 | 85 | let rectanglePath = NSBezierPath(roundedRect: rect, xRadius: 4, yRadius: 4) 86 | 87 | // Trackpad area 88 | 89 | NSGraphicsContext.enterState { 90 | rectanglePath.setClip() 91 | 92 | if DSFAppearanceManager.IncreaseContrast { 93 | NSColor.textColor.setStroke() 94 | } 95 | else if self.isDarkMode { 96 | NSColor(calibratedWhite: 0.5, alpha: 1.0).setStroke() 97 | } 98 | else { 99 | NSColor.white.setStroke() 100 | } 101 | rectanglePath.lineWidth = 2 102 | 103 | if self.isPanning { 104 | NSColor.windowBackgroundColor.setFill() 105 | } 106 | else if self.isHover { 107 | if self.isDarkMode { 108 | NSColor.disabledControlTextColor.setFill() 109 | } 110 | else { 111 | NSColor.windowBackgroundColor.setFill() 112 | } 113 | } 114 | else { 115 | if self.isDarkMode { 116 | NSColor(calibratedWhite: 0.2, alpha: 1.0).setFill() 117 | } 118 | else { 119 | NSColor(calibratedWhite: 0.85, alpha: 1.0).setFill() 120 | } 121 | } 122 | 123 | if !DSFAppearanceManager.IncreaseContrast { 124 | let shadow = NSShadow() 125 | shadow.shadowColor = NSColor.black.withAlphaComponent(0.3) 126 | shadow.shadowOffset = NSSize(width: 0.5, height: -0.5) 127 | shadow.shadowBlurRadius = 2 128 | shadow.set() 129 | } 130 | 131 | rectanglePath.fill() 132 | rectanglePath.stroke() 133 | } 134 | 135 | // Arrow Badge 136 | 137 | if self.isEnabled, !self.isPanning { 138 | NSGraphicsContext.enterState { 139 | let b = DragSliderBadgePath() 140 | b.transform(using: AffineTransform(translationByX: self.bounds.width - 15.5, byY: 3.5)) 141 | 142 | if self.isDarkMode { 143 | NSColor(calibratedWhite: 0.4, alpha: 1.0).setStroke() 144 | } 145 | else { 146 | NSColor(calibratedWhite: 0.7, alpha: 1.0).setStroke() 147 | } 148 | b.stroke() 149 | } 150 | } 151 | 152 | // Crosshair and button 153 | 154 | NSGraphicsContext.enterState { 155 | let inset = rect.insetBy(dx: 5, dy: 5) 156 | 157 | let xperc = inset.width / (maxX - minX) 158 | let yperc = inset.height / (maxY - minY) 159 | let xpos = (self.x - minX) * xperc + inset.minX 160 | let ypos = (self.y - minY) * yperc + inset.minY 161 | 162 | if self.isDarkMode { 163 | NSColor(calibratedWhite: 0.7, alpha: 1.0).setFill() 164 | NSColor(calibratedWhite: 1, alpha: 1.0).setStroke() 165 | } 166 | else { 167 | NSColor(calibratedWhite: 1.0, alpha: 1.0).setFill() 168 | if DSFAppearanceManager.IncreaseContrast { 169 | NSColor.textColor.setStroke() 170 | } 171 | else { 172 | NSColor(calibratedWhite: 0.1, alpha: 1.0).setStroke() 173 | } 174 | } 175 | 176 | let c = NSBezierPath() 177 | c.lineWidth = DSFAppearanceManager.IncreaseContrast ? 1.0 : 0.5 178 | c.move(to: NSPoint(x: inset.minX, y: ypos)) 179 | c.line(to: NSPoint(x: inset.maxX, y: ypos)) 180 | c.move(to: NSPoint(x: xpos, y: inset.minY)) 181 | c.line(to: NSPoint(x: xpos, y: inset.maxY)) 182 | c.setLineDash([1, 1], count: 2, phase: 0) 183 | c.stroke() 184 | 185 | let r = NSRect(x: xpos - 3, y: ypos - 3, width: 6, height: 6) 186 | let b = NSBezierPath(ovalIn: r) 187 | b.fill() 188 | 189 | if self.isDarkMode { 190 | NSColor.white.setStroke() 191 | } 192 | else { 193 | NSColor.systemGray.setStroke() 194 | } 195 | b.lineWidth = DSFAppearanceManager.IncreaseContrast ? 1.0 : 0.5 196 | b.stroke() 197 | } 198 | } 199 | 200 | private func DragSliderBadgePath() -> NSBezierPath { 201 | let result = NSBezierPath() 202 | 203 | //// Bezier Drawing 204 | let bezierPath = NSBezierPath() 205 | bezierPath.move(to: NSPoint(x: 4, y: 3)) 206 | bezierPath.line(to: NSPoint(x: 6, y: 1)) 207 | bezierPath.line(to: NSPoint(x: 8, y: 3)) 208 | bezierPath.lineWidth = 1 209 | result.append(bezierPath) 210 | 211 | //// Bezier 5 Drawing 212 | let bezier5Path = NSBezierPath() 213 | bezier5Path.move(to: NSPoint(x: 6, y: 10)) 214 | bezier5Path.line(to: NSPoint(x: 6, y: 1)) 215 | bezier5Path.lineWidth = 1 216 | result.append(bezier5Path) 217 | 218 | //// Bezier 6 Drawing 219 | let bezier6Path = NSBezierPath() 220 | bezier6Path.move(to: NSPoint(x: 1, y: 6)) 221 | bezier6Path.line(to: NSPoint(x: 11, y: 6)) 222 | bezier6Path.lineWidth = 1 223 | result.append(bezier6Path) 224 | 225 | //// Bezier 7 Drawing 226 | let bezier7Path = NSBezierPath() 227 | bezier7Path.move(to: NSPoint(x: 3, y: 8)) 228 | bezier7Path.line(to: NSPoint(x: 1, y: 6)) 229 | bezier7Path.line(to: NSPoint(x: 3, y: 4)) 230 | bezier7Path.lineWidth = 1 231 | result.append(bezier7Path) 232 | 233 | //// Bezier 4 Drawing 234 | let bezier4Path = NSBezierPath() 235 | bezier4Path.move(to: NSPoint(x: 4, y: 9)) 236 | bezier4Path.line(to: NSPoint(x: 6, y: 11)) 237 | bezier4Path.line(to: NSPoint(x: 8, y: 9)) 238 | bezier4Path.lineWidth = 1 239 | result.append(bezier4Path) 240 | 241 | //// Bezier 3 Drawing 242 | let bezier3Path = NSBezierPath() 243 | bezier3Path.move(to: NSPoint(x: 9, y: 8)) 244 | bezier3Path.line(to: NSPoint(x: 11, y: 6)) 245 | bezier3Path.line(to: NSPoint(x: 9, y: 4)) 246 | bezier3Path.lineWidth = 1 247 | result.append(bezier3Path) 248 | 249 | return result 250 | } 251 | } 252 | 253 | 254 | // MARK: - User interaction 255 | 256 | extension DSFDragSlider { 257 | 258 | internal var canChangeX: Bool { 259 | return (self.maxX - self.minX) > 0.0 260 | } 261 | 262 | internal var canChangeY: Bool { 263 | return (self.maxY - self.minY) > 0.0 264 | } 265 | 266 | override public var acceptsFirstResponder: Bool { 267 | return self.isEnabled 268 | } 269 | 270 | override public func acceptsFirstMouse(for event: NSEvent?) -> Bool { 271 | return self.isEnabled 272 | } 273 | 274 | @objc func userDidPan(_ sender: NSPanGestureRecognizer) { 275 | var scaleX: CGFloat = self.deltaX 276 | var scaleY: CGFloat = self.deltaY 277 | 278 | if !self.isPanning { 279 | return 280 | } 281 | 282 | if let event = NSApp.currentEvent { 283 | if event.modifierFlags.contains(.shift) { scaleX *= 10; scaleY *= 10 } 284 | else if event.modifierFlags.contains(.option) { scaleX /= 10; scaleY /= 10 } 285 | } 286 | 287 | let translation = sender.translation(in: self) 288 | if let last = lastPosition { 289 | let xDiff = (translation.x - last.x) * scaleX 290 | let yDiff = (translation.y - last.y) * scaleY 291 | 292 | let nx = min(max(self.minX, self.position.x + xDiff), self.maxX) 293 | let ny = min(max(self.minY, self.position.y + yDiff), self.maxY) 294 | self.position = CGPoint(x: nx, y: ny) 295 | 296 | self.delegate?.dragSlider(self, didChangePosition: self.position) 297 | } 298 | 299 | self.lastPosition = translation 300 | 301 | self.needsDisplay = true 302 | } 303 | 304 | // MARK: Mouse handling 305 | 306 | override public func mouseEntered(with event: NSEvent) { 307 | guard self.isEnabled else { return } 308 | self.isHover = true 309 | NSCursor.openHand.push() 310 | 311 | self.needsDisplay = true 312 | } 313 | 314 | override public func mouseExited(with event: NSEvent) { 315 | guard self.isEnabled else { return } 316 | self.isHover = false 317 | if self.isPanning == false { 318 | NSCursor.pop() 319 | } 320 | 321 | self.needsDisplay = true 322 | } 323 | 324 | override public func mouseDown(with event: NSEvent) { 325 | guard self.isEnabled else { return } 326 | self.isPanning = true 327 | self.needsDisplay = true 328 | 329 | self.lastPosition = nil 330 | self.originalPosition = self.position // Save so we can cancel using esc 331 | self.isPanning = true 332 | NSCursor.closedHand.push() 333 | 334 | self.needsDisplay = true 335 | } 336 | 337 | override public func mouseUp(with event: NSEvent) { 338 | guard self.isEnabled else { return } 339 | 340 | NSCursor.pop() 341 | 342 | if !self.isPanning { 343 | return 344 | } 345 | 346 | self.isPanning = false 347 | 348 | self.needsDisplay = true 349 | 350 | self.delegate?.dragSlider(self, didEndDragAtPoint: self.position) 351 | } 352 | 353 | // MARK: key handling 354 | 355 | override public func keyDown(with event: NSEvent) { 356 | var incr: CGFloat = 1 357 | if event.modifierFlags.contains(.shift) { incr *= 10 } 358 | else if event.modifierFlags.contains(.option) { incr /= 10 } 359 | 360 | if event.keyCode == kVK_LeftArrow { 361 | if self.canChangeX { 362 | let nx = min(max(self.minX, self.position.x - incr), self.maxX) 363 | self.position.x = nx 364 | self.delegate?.dragSlider(self, didChangePosition: self.position) 365 | } 366 | else { 367 | NSSound.beep() 368 | } 369 | } 370 | else if event.keyCode == kVK_RightArrow { 371 | if self.canChangeX { 372 | let nx = min(max(self.minX, self.position.x + incr), self.maxX) 373 | self.position.x = nx 374 | self.delegate?.dragSlider(self, didChangePosition: self.position) 375 | } 376 | else { 377 | NSSound.beep() 378 | } 379 | } 380 | else if event.keyCode == kVK_UpArrow { 381 | if self.canChangeY { 382 | let ny = min(max(self.minY, self.position.y + incr), self.maxY) 383 | self.position.y = ny 384 | self.delegate?.dragSlider(self, didChangePosition: self.position) 385 | } 386 | else { 387 | NSSound.beep() 388 | } 389 | } 390 | else if event.keyCode == kVK_DownArrow { 391 | if self.canChangeY { 392 | let ny = min(max(self.minY, self.position.y - incr), self.maxY) 393 | self.position.y = ny 394 | self.delegate?.dragSlider(self, didChangePosition: self.position) 395 | } 396 | else { 397 | NSSound.beep() 398 | } 399 | } 400 | else { 401 | super.keyDown(with: event) 402 | // self.interpretKeyEvents([event]) 403 | } 404 | self.needsDisplay = true 405 | } 406 | 407 | override public func cancelOperation(_ sender: Any?) { 408 | self.recognizer?.state = .cancelled 409 | self.isPanning = false 410 | if let orig = self.originalPosition { 411 | self.position = orig 412 | } 413 | 414 | // Tell the delegate we've reverted back to our original value 415 | self.delegate?.dragSlider(self, didCancelDragAtPoint: self.position) 416 | 417 | self.needsDisplay = true 418 | } 419 | 420 | } 421 | 422 | // MARK: - Accessibility 423 | 424 | extension DSFDragSlider { 425 | override public func isAccessibilityEnabled() -> Bool { 426 | return true 427 | } 428 | 429 | override public func isAccessibilityElement() -> Bool { 430 | return true 431 | } 432 | 433 | override public func accessibilityRole() -> NSAccessibility.Role? { 434 | return NSAccessibility.Role.incrementor 435 | } 436 | 437 | override public func accessibilityLabel() -> String? { 438 | return NSLocalizedString("Infinite Scroller", comment: "") 439 | } 440 | } 441 | 442 | #endif 443 | -------------------------------------------------------------------------------- /Demos/DSFDragSlider Demo/DSFDragSlider Demo.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 52; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 2310303B2517486C005EF645 /* DSFLabelledTextField in Frameworks */ = {isa = PBXBuildFile; productRef = 2310303A2517486C005EF645 /* DSFLabelledTextField */; }; 11 | 231519B525184E8400D40833 /* DSFDragSlider in Frameworks */ = {isa = PBXBuildFile; productRef = 231519B425184E8400D40833 /* DSFDragSlider */; }; 12 | 2331A78E25184CCB0053FBF0 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 2331A78D25184CCB0053FBF0 /* AppDelegate.m */; }; 13 | 2331A79025184CCC0053FBF0 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 2331A78F25184CCC0053FBF0 /* Assets.xcassets */; }; 14 | 2331A79325184CCC0053FBF0 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 2331A79125184CCC0053FBF0 /* MainMenu.xib */; }; 15 | 2331A79625184CCC0053FBF0 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 2331A79525184CCC0053FBF0 /* main.m */; }; 16 | 2331A7AC25184F5A0053FBF0 /* DSFLabelledTextField in Frameworks */ = {isa = PBXBuildFile; productRef = 2331A7AB25184F5A0053FBF0 /* DSFLabelledTextField */; }; 17 | 2331A7B625185AD00053FBF0 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2331A7B525185AD00053FBF0 /* AppDelegate.swift */; }; 18 | 2331A7B825185AD00053FBF0 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2331A7B725185AD00053FBF0 /* ContentView.swift */; }; 19 | 2331A7BA25185AD10053FBF0 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 2331A7B925185AD10053FBF0 /* Assets.xcassets */; }; 20 | 2331A7BD25185AD10053FBF0 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 2331A7BC25185AD10053FBF0 /* Preview Assets.xcassets */; }; 21 | 2331A7C025185AD10053FBF0 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 2331A7BE25185AD10053FBF0 /* Main.storyboard */; }; 22 | 2383E1DF251713200006803E /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2383E1DE251713200006803E /* AppDelegate.swift */; }; 23 | 2383E1E1251713210006803E /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 2383E1E0251713210006803E /* Assets.xcassets */; }; 24 | 2383E1E4251713210006803E /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 2383E1E2251713210006803E /* MainMenu.xib */; }; 25 | 23B7711228B603BD00389426 /* DSFDragSlider in Frameworks */ = {isa = PBXBuildFile; productRef = 23B7711128B603BD00389426 /* DSFDragSlider */; }; 26 | 23F1167C28B5FF22005A4126 /* DSFDragSlider in Frameworks */ = {isa = PBXBuildFile; productRef = 23F1167B28B5FF22005A4126 /* DSFDragSlider */; }; 27 | /* End PBXBuildFile section */ 28 | 29 | /* Begin PBXCopyFilesBuildPhase section */ 30 | 23B7710F28B602AF00389426 /* Embed Frameworks */ = { 31 | isa = PBXCopyFilesBuildPhase; 32 | buildActionMask = 2147483647; 33 | dstPath = ""; 34 | dstSubfolderSpec = 10; 35 | files = ( 36 | ); 37 | name = "Embed Frameworks"; 38 | runOnlyForDeploymentPostprocessing = 0; 39 | }; 40 | /* End PBXCopyFilesBuildPhase section */ 41 | 42 | /* Begin PBXFileReference section */ 43 | 2331A78A25184CCB0053FBF0 /* DSFDragSlider Objc Demo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "DSFDragSlider Objc Demo.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 44 | 2331A78C25184CCB0053FBF0 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 45 | 2331A78D25184CCB0053FBF0 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 46 | 2331A78F25184CCC0053FBF0 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 47 | 2331A79225184CCC0053FBF0 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; 48 | 2331A79425184CCC0053FBF0 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 49 | 2331A79525184CCC0053FBF0 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 50 | 2331A79725184CCC0053FBF0 /* DSFDragSlider_Objc_Demo.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DSFDragSlider_Objc_Demo.entitlements; sourceTree = ""; }; 51 | 2331A7B325185AD00053FBF0 /* DSFDragSlider SwiftUI Demo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "DSFDragSlider SwiftUI Demo.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 52 | 2331A7B525185AD00053FBF0 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 53 | 2331A7B725185AD00053FBF0 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; 54 | 2331A7B925185AD10053FBF0 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 55 | 2331A7BC25185AD10053FBF0 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; 56 | 2331A7BF25185AD10053FBF0 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 57 | 2331A7C125185AD10053FBF0 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 58 | 2331A7C225185AD10053FBF0 /* DSFDragSlider_SwiftUI_Demo.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DSFDragSlider_SwiftUI_Demo.entitlements; sourceTree = ""; }; 59 | 2383E1DB251713200006803E /* DSFDragSlider Demo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "DSFDragSlider Demo.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 60 | 2383E1DE251713200006803E /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 61 | 2383E1E0251713210006803E /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 62 | 2383E1E3251713210006803E /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; 63 | 2383E1E5251713210006803E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 64 | 2383E1E6251713210006803E /* DSFDragSlider_Demo.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DSFDragSlider_Demo.entitlements; sourceTree = ""; }; 65 | 23F1167428B5F792005A4126 /* DSFDragSlider */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = DSFDragSlider; path = ../..; sourceTree = ""; }; 66 | /* End PBXFileReference section */ 67 | 68 | /* Begin PBXFrameworksBuildPhase section */ 69 | 2331A78725184CCB0053FBF0 /* Frameworks */ = { 70 | isa = PBXFrameworksBuildPhase; 71 | buildActionMask = 2147483647; 72 | files = ( 73 | 231519B525184E8400D40833 /* DSFDragSlider in Frameworks */, 74 | 2331A7AC25184F5A0053FBF0 /* DSFLabelledTextField in Frameworks */, 75 | ); 76 | runOnlyForDeploymentPostprocessing = 0; 77 | }; 78 | 2331A7B025185AD00053FBF0 /* Frameworks */ = { 79 | isa = PBXFrameworksBuildPhase; 80 | buildActionMask = 2147483647; 81 | files = ( 82 | 23B7711228B603BD00389426 /* DSFDragSlider in Frameworks */, 83 | ); 84 | runOnlyForDeploymentPostprocessing = 0; 85 | }; 86 | 2383E1D8251713200006803E /* Frameworks */ = { 87 | isa = PBXFrameworksBuildPhase; 88 | buildActionMask = 2147483647; 89 | files = ( 90 | 2310303B2517486C005EF645 /* DSFLabelledTextField in Frameworks */, 91 | 23F1167C28B5FF22005A4126 /* DSFDragSlider in Frameworks */, 92 | ); 93 | runOnlyForDeploymentPostprocessing = 0; 94 | }; 95 | /* End PBXFrameworksBuildPhase section */ 96 | 97 | /* Begin PBXGroup section */ 98 | 2331A78B25184CCB0053FBF0 /* DSFDragSlider Objc Demo */ = { 99 | isa = PBXGroup; 100 | children = ( 101 | 2331A78C25184CCB0053FBF0 /* AppDelegate.h */, 102 | 2331A78D25184CCB0053FBF0 /* AppDelegate.m */, 103 | 2331A78F25184CCC0053FBF0 /* Assets.xcassets */, 104 | 2331A79125184CCC0053FBF0 /* MainMenu.xib */, 105 | 2331A79425184CCC0053FBF0 /* Info.plist */, 106 | 2331A79525184CCC0053FBF0 /* main.m */, 107 | 2331A79725184CCC0053FBF0 /* DSFDragSlider_Objc_Demo.entitlements */, 108 | ); 109 | path = "DSFDragSlider Objc Demo"; 110 | sourceTree = ""; 111 | }; 112 | 2331A7AA25184F5A0053FBF0 /* Frameworks */ = { 113 | isa = PBXGroup; 114 | children = ( 115 | ); 116 | name = Frameworks; 117 | sourceTree = ""; 118 | }; 119 | 2331A7B425185AD00053FBF0 /* DSFDragSlider SwiftUI Demo */ = { 120 | isa = PBXGroup; 121 | children = ( 122 | 2331A7B525185AD00053FBF0 /* AppDelegate.swift */, 123 | 2331A7B725185AD00053FBF0 /* ContentView.swift */, 124 | 2331A7B925185AD10053FBF0 /* Assets.xcassets */, 125 | 2331A7BE25185AD10053FBF0 /* Main.storyboard */, 126 | 2331A7C125185AD10053FBF0 /* Info.plist */, 127 | 2331A7C225185AD10053FBF0 /* DSFDragSlider_SwiftUI_Demo.entitlements */, 128 | 2331A7BB25185AD10053FBF0 /* Preview Content */, 129 | ); 130 | path = "DSFDragSlider SwiftUI Demo"; 131 | sourceTree = ""; 132 | }; 133 | 2331A7BB25185AD10053FBF0 /* Preview Content */ = { 134 | isa = PBXGroup; 135 | children = ( 136 | 2331A7BC25185AD10053FBF0 /* Preview Assets.xcassets */, 137 | ); 138 | path = "Preview Content"; 139 | sourceTree = ""; 140 | }; 141 | 2383E1D2251713200006803E = { 142 | isa = PBXGroup; 143 | children = ( 144 | 23F1167428B5F792005A4126 /* DSFDragSlider */, 145 | 2383E1DD251713200006803E /* DSFDragSlider Demo */, 146 | 2331A78B25184CCB0053FBF0 /* DSFDragSlider Objc Demo */, 147 | 2331A7B425185AD00053FBF0 /* DSFDragSlider SwiftUI Demo */, 148 | 2383E1DC251713200006803E /* Products */, 149 | 2331A7AA25184F5A0053FBF0 /* Frameworks */, 150 | ); 151 | sourceTree = ""; 152 | }; 153 | 2383E1DC251713200006803E /* Products */ = { 154 | isa = PBXGroup; 155 | children = ( 156 | 2383E1DB251713200006803E /* DSFDragSlider Demo.app */, 157 | 2331A78A25184CCB0053FBF0 /* DSFDragSlider Objc Demo.app */, 158 | 2331A7B325185AD00053FBF0 /* DSFDragSlider SwiftUI Demo.app */, 159 | ); 160 | name = Products; 161 | sourceTree = ""; 162 | }; 163 | 2383E1DD251713200006803E /* DSFDragSlider Demo */ = { 164 | isa = PBXGroup; 165 | children = ( 166 | 2383E1DE251713200006803E /* AppDelegate.swift */, 167 | 2383E1E0251713210006803E /* Assets.xcassets */, 168 | 2383E1E2251713210006803E /* MainMenu.xib */, 169 | 2383E1E5251713210006803E /* Info.plist */, 170 | 2383E1E6251713210006803E /* DSFDragSlider_Demo.entitlements */, 171 | ); 172 | path = "DSFDragSlider Demo"; 173 | sourceTree = ""; 174 | }; 175 | /* End PBXGroup section */ 176 | 177 | /* Begin PBXNativeTarget section */ 178 | 2331A78925184CCB0053FBF0 /* DSFDragSlider Objc Demo */ = { 179 | isa = PBXNativeTarget; 180 | buildConfigurationList = 2331A79A25184CCC0053FBF0 /* Build configuration list for PBXNativeTarget "DSFDragSlider Objc Demo" */; 181 | buildPhases = ( 182 | 2331A78625184CCB0053FBF0 /* Sources */, 183 | 2331A78725184CCB0053FBF0 /* Frameworks */, 184 | 2331A78825184CCB0053FBF0 /* Resources */, 185 | ); 186 | buildRules = ( 187 | ); 188 | dependencies = ( 189 | ); 190 | name = "DSFDragSlider Objc Demo"; 191 | packageProductDependencies = ( 192 | 231519B425184E8400D40833 /* DSFDragSlider */, 193 | 2331A7AB25184F5A0053FBF0 /* DSFLabelledTextField */, 194 | ); 195 | productName = "DSFDragSlider Objc Demo"; 196 | productReference = 2331A78A25184CCB0053FBF0 /* DSFDragSlider Objc Demo.app */; 197 | productType = "com.apple.product-type.application"; 198 | }; 199 | 2331A7B225185AD00053FBF0 /* DSFDragSlider SwiftUI Demo */ = { 200 | isa = PBXNativeTarget; 201 | buildConfigurationList = 2331A7C525185AD10053FBF0 /* Build configuration list for PBXNativeTarget "DSFDragSlider SwiftUI Demo" */; 202 | buildPhases = ( 203 | 2331A7AF25185AD00053FBF0 /* Sources */, 204 | 2331A7B025185AD00053FBF0 /* Frameworks */, 205 | 2331A7B125185AD00053FBF0 /* Resources */, 206 | 23B7710F28B602AF00389426 /* Embed Frameworks */, 207 | ); 208 | buildRules = ( 209 | ); 210 | dependencies = ( 211 | ); 212 | name = "DSFDragSlider SwiftUI Demo"; 213 | packageProductDependencies = ( 214 | 23B7711128B603BD00389426 /* DSFDragSlider */, 215 | ); 216 | productName = "DSFDragSlider SwiftUI Demo"; 217 | productReference = 2331A7B325185AD00053FBF0 /* DSFDragSlider SwiftUI Demo.app */; 218 | productType = "com.apple.product-type.application"; 219 | }; 220 | 2383E1DA251713200006803E /* DSFDragSlider Demo */ = { 221 | isa = PBXNativeTarget; 222 | buildConfigurationList = 2383E1E9251713210006803E /* Build configuration list for PBXNativeTarget "DSFDragSlider Demo" */; 223 | buildPhases = ( 224 | 2383E1D7251713200006803E /* Sources */, 225 | 2383E1D8251713200006803E /* Frameworks */, 226 | 2383E1D9251713200006803E /* Resources */, 227 | ); 228 | buildRules = ( 229 | ); 230 | dependencies = ( 231 | ); 232 | name = "DSFDragSlider Demo"; 233 | packageProductDependencies = ( 234 | 2310303A2517486C005EF645 /* DSFLabelledTextField */, 235 | 23F1167B28B5FF22005A4126 /* DSFDragSlider */, 236 | ); 237 | productName = "DSFDragSlider Demo"; 238 | productReference = 2383E1DB251713200006803E /* DSFDragSlider Demo.app */; 239 | productType = "com.apple.product-type.application"; 240 | }; 241 | /* End PBXNativeTarget section */ 242 | 243 | /* Begin PBXProject section */ 244 | 2383E1D3251713200006803E /* Project object */ = { 245 | isa = PBXProject; 246 | attributes = { 247 | LastSwiftUpdateCheck = 1220; 248 | LastUpgradeCheck = 1220; 249 | TargetAttributes = { 250 | 2331A78925184CCB0053FBF0 = { 251 | CreatedOnToolsVersion = 12.2; 252 | }; 253 | 2331A7B225185AD00053FBF0 = { 254 | CreatedOnToolsVersion = 12.2; 255 | }; 256 | 2383E1DA251713200006803E = { 257 | CreatedOnToolsVersion = 12.2; 258 | }; 259 | }; 260 | }; 261 | buildConfigurationList = 2383E1D6251713200006803E /* Build configuration list for PBXProject "DSFDragSlider Demo" */; 262 | compatibilityVersion = "Xcode 9.3"; 263 | developmentRegion = en; 264 | hasScannedForEncodings = 0; 265 | knownRegions = ( 266 | en, 267 | Base, 268 | ); 269 | mainGroup = 2383E1D2251713200006803E; 270 | packageReferences = ( 271 | 231030392517486C005EF645 /* XCRemoteSwiftPackageReference "DSFLabelledTextField" */, 272 | 231519B325184E8400D40833 /* XCRemoteSwiftPackageReference "DSFDragSlider" */, 273 | ); 274 | productRefGroup = 2383E1DC251713200006803E /* Products */; 275 | projectDirPath = ""; 276 | projectRoot = ""; 277 | targets = ( 278 | 2383E1DA251713200006803E /* DSFDragSlider Demo */, 279 | 2331A78925184CCB0053FBF0 /* DSFDragSlider Objc Demo */, 280 | 2331A7B225185AD00053FBF0 /* DSFDragSlider SwiftUI Demo */, 281 | ); 282 | }; 283 | /* End PBXProject section */ 284 | 285 | /* Begin PBXResourcesBuildPhase section */ 286 | 2331A78825184CCB0053FBF0 /* Resources */ = { 287 | isa = PBXResourcesBuildPhase; 288 | buildActionMask = 2147483647; 289 | files = ( 290 | 2331A79025184CCC0053FBF0 /* Assets.xcassets in Resources */, 291 | 2331A79325184CCC0053FBF0 /* MainMenu.xib in Resources */, 292 | ); 293 | runOnlyForDeploymentPostprocessing = 0; 294 | }; 295 | 2331A7B125185AD00053FBF0 /* Resources */ = { 296 | isa = PBXResourcesBuildPhase; 297 | buildActionMask = 2147483647; 298 | files = ( 299 | 2331A7C025185AD10053FBF0 /* Main.storyboard in Resources */, 300 | 2331A7BD25185AD10053FBF0 /* Preview Assets.xcassets in Resources */, 301 | 2331A7BA25185AD10053FBF0 /* Assets.xcassets in Resources */, 302 | ); 303 | runOnlyForDeploymentPostprocessing = 0; 304 | }; 305 | 2383E1D9251713200006803E /* Resources */ = { 306 | isa = PBXResourcesBuildPhase; 307 | buildActionMask = 2147483647; 308 | files = ( 309 | 2383E1E1251713210006803E /* Assets.xcassets in Resources */, 310 | 2383E1E4251713210006803E /* MainMenu.xib in Resources */, 311 | ); 312 | runOnlyForDeploymentPostprocessing = 0; 313 | }; 314 | /* End PBXResourcesBuildPhase section */ 315 | 316 | /* Begin PBXSourcesBuildPhase section */ 317 | 2331A78625184CCB0053FBF0 /* Sources */ = { 318 | isa = PBXSourcesBuildPhase; 319 | buildActionMask = 2147483647; 320 | files = ( 321 | 2331A79625184CCC0053FBF0 /* main.m in Sources */, 322 | 2331A78E25184CCB0053FBF0 /* AppDelegate.m in Sources */, 323 | ); 324 | runOnlyForDeploymentPostprocessing = 0; 325 | }; 326 | 2331A7AF25185AD00053FBF0 /* Sources */ = { 327 | isa = PBXSourcesBuildPhase; 328 | buildActionMask = 2147483647; 329 | files = ( 330 | 2331A7B825185AD00053FBF0 /* ContentView.swift in Sources */, 331 | 2331A7B625185AD00053FBF0 /* AppDelegate.swift in Sources */, 332 | ); 333 | runOnlyForDeploymentPostprocessing = 0; 334 | }; 335 | 2383E1D7251713200006803E /* Sources */ = { 336 | isa = PBXSourcesBuildPhase; 337 | buildActionMask = 2147483647; 338 | files = ( 339 | 2383E1DF251713200006803E /* AppDelegate.swift in Sources */, 340 | ); 341 | runOnlyForDeploymentPostprocessing = 0; 342 | }; 343 | /* End PBXSourcesBuildPhase section */ 344 | 345 | /* Begin PBXVariantGroup section */ 346 | 2331A79125184CCC0053FBF0 /* MainMenu.xib */ = { 347 | isa = PBXVariantGroup; 348 | children = ( 349 | 2331A79225184CCC0053FBF0 /* Base */, 350 | ); 351 | name = MainMenu.xib; 352 | sourceTree = ""; 353 | }; 354 | 2331A7BE25185AD10053FBF0 /* Main.storyboard */ = { 355 | isa = PBXVariantGroup; 356 | children = ( 357 | 2331A7BF25185AD10053FBF0 /* Base */, 358 | ); 359 | name = Main.storyboard; 360 | sourceTree = ""; 361 | }; 362 | 2383E1E2251713210006803E /* MainMenu.xib */ = { 363 | isa = PBXVariantGroup; 364 | children = ( 365 | 2383E1E3251713210006803E /* Base */, 366 | ); 367 | name = MainMenu.xib; 368 | sourceTree = ""; 369 | }; 370 | /* End PBXVariantGroup section */ 371 | 372 | /* Begin XCBuildConfiguration section */ 373 | 2331A79825184CCC0053FBF0 /* Debug */ = { 374 | isa = XCBuildConfiguration; 375 | buildSettings = { 376 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 377 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 378 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 379 | CODE_SIGN_ENTITLEMENTS = "DSFDragSlider Objc Demo/DSFDragSlider_Objc_Demo.entitlements"; 380 | CODE_SIGN_STYLE = Automatic; 381 | COMBINE_HIDPI_IMAGES = YES; 382 | DEVELOPMENT_TEAM = 3L6RK3LGGW; 383 | ENABLE_HARDENED_RUNTIME = YES; 384 | INFOPLIST_FILE = "DSFDragSlider Objc Demo/Info.plist"; 385 | LD_RUNPATH_SEARCH_PATHS = ( 386 | "$(inherited)", 387 | "@executable_path/../Frameworks", 388 | ); 389 | MACOSX_DEPLOYMENT_TARGET = 10.11; 390 | PRODUCT_BUNDLE_IDENTIFIER = "com.darrenford.DSFDragSlider-Objc-Demo"; 391 | PRODUCT_NAME = "$(TARGET_NAME)"; 392 | SWIFT_VERSION = 5.0; 393 | }; 394 | name = Debug; 395 | }; 396 | 2331A79925184CCC0053FBF0 /* Release */ = { 397 | isa = XCBuildConfiguration; 398 | buildSettings = { 399 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 400 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 401 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 402 | CODE_SIGN_ENTITLEMENTS = "DSFDragSlider Objc Demo/DSFDragSlider_Objc_Demo.entitlements"; 403 | CODE_SIGN_STYLE = Automatic; 404 | COMBINE_HIDPI_IMAGES = YES; 405 | DEVELOPMENT_TEAM = 3L6RK3LGGW; 406 | ENABLE_HARDENED_RUNTIME = YES; 407 | INFOPLIST_FILE = "DSFDragSlider Objc Demo/Info.plist"; 408 | LD_RUNPATH_SEARCH_PATHS = ( 409 | "$(inherited)", 410 | "@executable_path/../Frameworks", 411 | ); 412 | MACOSX_DEPLOYMENT_TARGET = 10.11; 413 | PRODUCT_BUNDLE_IDENTIFIER = "com.darrenford.DSFDragSlider-Objc-Demo"; 414 | PRODUCT_NAME = "$(TARGET_NAME)"; 415 | SWIFT_VERSION = 5.0; 416 | }; 417 | name = Release; 418 | }; 419 | 2331A7C325185AD10053FBF0 /* Debug */ = { 420 | isa = XCBuildConfiguration; 421 | buildSettings = { 422 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 423 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 424 | CODE_SIGN_ENTITLEMENTS = "DSFDragSlider SwiftUI Demo/DSFDragSlider_SwiftUI_Demo.entitlements"; 425 | CODE_SIGN_STYLE = Automatic; 426 | COMBINE_HIDPI_IMAGES = YES; 427 | DEVELOPMENT_ASSET_PATHS = "\"DSFDragSlider SwiftUI Demo/Preview Content\""; 428 | DEVELOPMENT_TEAM = 3L6RK3LGGW; 429 | ENABLE_HARDENED_RUNTIME = YES; 430 | ENABLE_PREVIEWS = YES; 431 | INFOPLIST_FILE = "DSFDragSlider SwiftUI Demo/Info.plist"; 432 | LD_RUNPATH_SEARCH_PATHS = ( 433 | "$(inherited)", 434 | "@executable_path/../Frameworks", 435 | ); 436 | MACOSX_DEPLOYMENT_TARGET = 10.15; 437 | PRODUCT_BUNDLE_IDENTIFIER = "com.darrenford.DSFDragSlider-SwiftUI-Demo"; 438 | PRODUCT_NAME = "$(TARGET_NAME)"; 439 | SWIFT_VERSION = 5.0; 440 | }; 441 | name = Debug; 442 | }; 443 | 2331A7C425185AD10053FBF0 /* Release */ = { 444 | isa = XCBuildConfiguration; 445 | buildSettings = { 446 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 447 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 448 | CODE_SIGN_ENTITLEMENTS = "DSFDragSlider SwiftUI Demo/DSFDragSlider_SwiftUI_Demo.entitlements"; 449 | CODE_SIGN_STYLE = Automatic; 450 | COMBINE_HIDPI_IMAGES = YES; 451 | DEVELOPMENT_ASSET_PATHS = "\"DSFDragSlider SwiftUI Demo/Preview Content\""; 452 | DEVELOPMENT_TEAM = 3L6RK3LGGW; 453 | ENABLE_HARDENED_RUNTIME = YES; 454 | ENABLE_PREVIEWS = YES; 455 | INFOPLIST_FILE = "DSFDragSlider SwiftUI Demo/Info.plist"; 456 | LD_RUNPATH_SEARCH_PATHS = ( 457 | "$(inherited)", 458 | "@executable_path/../Frameworks", 459 | ); 460 | MACOSX_DEPLOYMENT_TARGET = 10.15; 461 | PRODUCT_BUNDLE_IDENTIFIER = "com.darrenford.DSFDragSlider-SwiftUI-Demo"; 462 | PRODUCT_NAME = "$(TARGET_NAME)"; 463 | SWIFT_VERSION = 5.0; 464 | }; 465 | name = Release; 466 | }; 467 | 2383E1E7251713210006803E /* Debug */ = { 468 | isa = XCBuildConfiguration; 469 | buildSettings = { 470 | ALWAYS_SEARCH_USER_PATHS = NO; 471 | CLANG_ANALYZER_NONNULL = YES; 472 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 473 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 474 | CLANG_CXX_LIBRARY = "libc++"; 475 | CLANG_ENABLE_MODULES = YES; 476 | CLANG_ENABLE_OBJC_ARC = YES; 477 | CLANG_ENABLE_OBJC_WEAK = YES; 478 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 479 | CLANG_WARN_BOOL_CONVERSION = YES; 480 | CLANG_WARN_COMMA = YES; 481 | CLANG_WARN_CONSTANT_CONVERSION = YES; 482 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 483 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 484 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 485 | CLANG_WARN_EMPTY_BODY = YES; 486 | CLANG_WARN_ENUM_CONVERSION = YES; 487 | CLANG_WARN_INFINITE_RECURSION = YES; 488 | CLANG_WARN_INT_CONVERSION = YES; 489 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 490 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 491 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 492 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 493 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 494 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 495 | CLANG_WARN_STRICT_PROTOTYPES = YES; 496 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 497 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 498 | CLANG_WARN_UNREACHABLE_CODE = YES; 499 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 500 | COPY_PHASE_STRIP = NO; 501 | DEBUG_INFORMATION_FORMAT = dwarf; 502 | ENABLE_STRICT_OBJC_MSGSEND = YES; 503 | ENABLE_TESTABILITY = YES; 504 | GCC_C_LANGUAGE_STANDARD = gnu11; 505 | GCC_DYNAMIC_NO_PIC = NO; 506 | GCC_NO_COMMON_BLOCKS = YES; 507 | GCC_OPTIMIZATION_LEVEL = 0; 508 | GCC_PREPROCESSOR_DEFINITIONS = ( 509 | "DEBUG=1", 510 | "$(inherited)", 511 | ); 512 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 513 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 514 | GCC_WARN_UNDECLARED_SELECTOR = YES; 515 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 516 | GCC_WARN_UNUSED_FUNCTION = YES; 517 | GCC_WARN_UNUSED_VARIABLE = YES; 518 | MACOSX_DEPLOYMENT_TARGET = 10.11; 519 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 520 | MTL_FAST_MATH = YES; 521 | ONLY_ACTIVE_ARCH = YES; 522 | SDKROOT = macosx; 523 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 524 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 525 | }; 526 | name = Debug; 527 | }; 528 | 2383E1E8251713210006803E /* Release */ = { 529 | isa = XCBuildConfiguration; 530 | buildSettings = { 531 | ALWAYS_SEARCH_USER_PATHS = NO; 532 | CLANG_ANALYZER_NONNULL = YES; 533 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 534 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 535 | CLANG_CXX_LIBRARY = "libc++"; 536 | CLANG_ENABLE_MODULES = YES; 537 | CLANG_ENABLE_OBJC_ARC = YES; 538 | CLANG_ENABLE_OBJC_WEAK = YES; 539 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 540 | CLANG_WARN_BOOL_CONVERSION = YES; 541 | CLANG_WARN_COMMA = YES; 542 | CLANG_WARN_CONSTANT_CONVERSION = YES; 543 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 544 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 545 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 546 | CLANG_WARN_EMPTY_BODY = YES; 547 | CLANG_WARN_ENUM_CONVERSION = YES; 548 | CLANG_WARN_INFINITE_RECURSION = YES; 549 | CLANG_WARN_INT_CONVERSION = YES; 550 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 551 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 552 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 553 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 554 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 555 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 556 | CLANG_WARN_STRICT_PROTOTYPES = YES; 557 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 558 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 559 | CLANG_WARN_UNREACHABLE_CODE = YES; 560 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 561 | COPY_PHASE_STRIP = NO; 562 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 563 | ENABLE_NS_ASSERTIONS = NO; 564 | ENABLE_STRICT_OBJC_MSGSEND = YES; 565 | GCC_C_LANGUAGE_STANDARD = gnu11; 566 | GCC_NO_COMMON_BLOCKS = YES; 567 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 568 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 569 | GCC_WARN_UNDECLARED_SELECTOR = YES; 570 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 571 | GCC_WARN_UNUSED_FUNCTION = YES; 572 | GCC_WARN_UNUSED_VARIABLE = YES; 573 | MACOSX_DEPLOYMENT_TARGET = 10.11; 574 | MTL_ENABLE_DEBUG_INFO = NO; 575 | MTL_FAST_MATH = YES; 576 | SDKROOT = macosx; 577 | SWIFT_COMPILATION_MODE = wholemodule; 578 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 579 | }; 580 | name = Release; 581 | }; 582 | 2383E1EA251713210006803E /* Debug */ = { 583 | isa = XCBuildConfiguration; 584 | buildSettings = { 585 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 586 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 587 | CODE_SIGN_ENTITLEMENTS = "DSFDragSlider Demo/DSFDragSlider_Demo.entitlements"; 588 | CODE_SIGN_STYLE = Automatic; 589 | COMBINE_HIDPI_IMAGES = YES; 590 | DEVELOPMENT_TEAM = 3L6RK3LGGW; 591 | ENABLE_HARDENED_RUNTIME = YES; 592 | INFOPLIST_FILE = "DSFDragSlider Demo/Info.plist"; 593 | LD_RUNPATH_SEARCH_PATHS = ( 594 | "$(inherited)", 595 | "@executable_path/../Frameworks", 596 | ); 597 | MACOSX_DEPLOYMENT_TARGET = 10.11; 598 | PRODUCT_BUNDLE_IDENTIFIER = "com.darrenford.DSFDragSlider-Demo"; 599 | PRODUCT_NAME = "$(TARGET_NAME)"; 600 | SWIFT_VERSION = 5.0; 601 | }; 602 | name = Debug; 603 | }; 604 | 2383E1EB251713210006803E /* Release */ = { 605 | isa = XCBuildConfiguration; 606 | buildSettings = { 607 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 608 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 609 | CODE_SIGN_ENTITLEMENTS = "DSFDragSlider Demo/DSFDragSlider_Demo.entitlements"; 610 | CODE_SIGN_STYLE = Automatic; 611 | COMBINE_HIDPI_IMAGES = YES; 612 | DEVELOPMENT_TEAM = 3L6RK3LGGW; 613 | ENABLE_HARDENED_RUNTIME = YES; 614 | INFOPLIST_FILE = "DSFDragSlider Demo/Info.plist"; 615 | LD_RUNPATH_SEARCH_PATHS = ( 616 | "$(inherited)", 617 | "@executable_path/../Frameworks", 618 | ); 619 | MACOSX_DEPLOYMENT_TARGET = 10.11; 620 | PRODUCT_BUNDLE_IDENTIFIER = "com.darrenford.DSFDragSlider-Demo"; 621 | PRODUCT_NAME = "$(TARGET_NAME)"; 622 | SWIFT_VERSION = 5.0; 623 | }; 624 | name = Release; 625 | }; 626 | /* End XCBuildConfiguration section */ 627 | 628 | /* Begin XCConfigurationList section */ 629 | 2331A79A25184CCC0053FBF0 /* Build configuration list for PBXNativeTarget "DSFDragSlider Objc Demo" */ = { 630 | isa = XCConfigurationList; 631 | buildConfigurations = ( 632 | 2331A79825184CCC0053FBF0 /* Debug */, 633 | 2331A79925184CCC0053FBF0 /* Release */, 634 | ); 635 | defaultConfigurationIsVisible = 0; 636 | defaultConfigurationName = Release; 637 | }; 638 | 2331A7C525185AD10053FBF0 /* Build configuration list for PBXNativeTarget "DSFDragSlider SwiftUI Demo" */ = { 639 | isa = XCConfigurationList; 640 | buildConfigurations = ( 641 | 2331A7C325185AD10053FBF0 /* Debug */, 642 | 2331A7C425185AD10053FBF0 /* Release */, 643 | ); 644 | defaultConfigurationIsVisible = 0; 645 | defaultConfigurationName = Release; 646 | }; 647 | 2383E1D6251713200006803E /* Build configuration list for PBXProject "DSFDragSlider Demo" */ = { 648 | isa = XCConfigurationList; 649 | buildConfigurations = ( 650 | 2383E1E7251713210006803E /* Debug */, 651 | 2383E1E8251713210006803E /* Release */, 652 | ); 653 | defaultConfigurationIsVisible = 0; 654 | defaultConfigurationName = Release; 655 | }; 656 | 2383E1E9251713210006803E /* Build configuration list for PBXNativeTarget "DSFDragSlider Demo" */ = { 657 | isa = XCConfigurationList; 658 | buildConfigurations = ( 659 | 2383E1EA251713210006803E /* Debug */, 660 | 2383E1EB251713210006803E /* Release */, 661 | ); 662 | defaultConfigurationIsVisible = 0; 663 | defaultConfigurationName = Release; 664 | }; 665 | /* End XCConfigurationList section */ 666 | 667 | /* Begin XCRemoteSwiftPackageReference section */ 668 | 231030392517486C005EF645 /* XCRemoteSwiftPackageReference "DSFLabelledTextField" */ = { 669 | isa = XCRemoteSwiftPackageReference; 670 | repositoryURL = "https://github.com/dagronf/DSFLabelledTextField.git"; 671 | requirement = { 672 | kind = upToNextMajorVersion; 673 | minimumVersion = 1.0.1; 674 | }; 675 | }; 676 | 231519B325184E8400D40833 /* XCRemoteSwiftPackageReference "DSFDragSlider" */ = { 677 | isa = XCRemoteSwiftPackageReference; 678 | repositoryURL = "https://github.com/dagronf/DSFDragSlider.git"; 679 | requirement = { 680 | kind = upToNextMajorVersion; 681 | minimumVersion = 0.9.4; 682 | }; 683 | }; 684 | /* End XCRemoteSwiftPackageReference section */ 685 | 686 | /* Begin XCSwiftPackageProductDependency section */ 687 | 2310303A2517486C005EF645 /* DSFLabelledTextField */ = { 688 | isa = XCSwiftPackageProductDependency; 689 | package = 231030392517486C005EF645 /* XCRemoteSwiftPackageReference "DSFLabelledTextField" */; 690 | productName = DSFLabelledTextField; 691 | }; 692 | 231519B425184E8400D40833 /* DSFDragSlider */ = { 693 | isa = XCSwiftPackageProductDependency; 694 | package = 231519B325184E8400D40833 /* XCRemoteSwiftPackageReference "DSFDragSlider" */; 695 | productName = DSFDragSlider; 696 | }; 697 | 2331A7AB25184F5A0053FBF0 /* DSFLabelledTextField */ = { 698 | isa = XCSwiftPackageProductDependency; 699 | package = 231030392517486C005EF645 /* XCRemoteSwiftPackageReference "DSFLabelledTextField" */; 700 | productName = DSFLabelledTextField; 701 | }; 702 | 23B7711128B603BD00389426 /* DSFDragSlider */ = { 703 | isa = XCSwiftPackageProductDependency; 704 | package = 231519B325184E8400D40833 /* XCRemoteSwiftPackageReference "DSFDragSlider" */; 705 | productName = DSFDragSlider; 706 | }; 707 | 23F1167B28B5FF22005A4126 /* DSFDragSlider */ = { 708 | isa = XCSwiftPackageProductDependency; 709 | productName = DSFDragSlider; 710 | }; 711 | /* End XCSwiftPackageProductDependency section */ 712 | }; 713 | rootObject = 2383E1D3251713200006803E /* Project object */; 714 | } 715 | -------------------------------------------------------------------------------- /Demos/DSFDragSlider Demo/DSFDragSlider SwiftUI Demo/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 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | 449 | 450 | 451 | 452 | 453 | 454 | 455 | 456 | 457 | 458 | 459 | 460 | 461 | 462 | 463 | 464 | 465 | 466 | 467 | 468 | 469 | 470 | 471 | 472 | 473 | 474 | 475 | 476 | 477 | 478 | 479 | 480 | 481 | 482 | 483 | 484 | 485 | 486 | 487 | 488 | 489 | 490 | 491 | 492 | 493 | 494 | 495 | 496 | 497 | 498 | 499 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 509 | 510 | 511 | 512 | 513 | 514 | 515 | 516 | 517 | 518 | 519 | 520 | 521 | 522 | 523 | 524 | 525 | 526 | 527 | 528 | Default 529 | 530 | 531 | 532 | 533 | 534 | 535 | Left to Right 536 | 537 | 538 | 539 | 540 | 541 | 542 | Right to Left 543 | 544 | 545 | 546 | 547 | 548 | 549 | 550 | 551 | 552 | 553 | Default 554 | 555 | 556 | 557 | 558 | 559 | 560 | Left to Right 561 | 562 | 563 | 564 | 565 | 566 | 567 | Right to Left 568 | 569 | 570 | 571 | 572 | 573 | 574 | 575 | 576 | 577 | 578 | 579 | 580 | 581 | 582 | 583 | 584 | 585 | 586 | 587 | 588 | 589 | 590 | 591 | 592 | 593 | 594 | 595 | 596 | 597 | 598 | 599 | 600 | 601 | 602 | 603 | 604 | 605 | 606 | 607 | 608 | 609 | 610 | 611 | 612 | 613 | 614 | 615 | 616 | 617 | 618 | 619 | 620 | 621 | 622 | 623 | 624 | 625 | 626 | 627 | 628 | 629 | 630 | 631 | 632 | 633 | 634 | 635 | 636 | 637 | 638 | 639 | 640 | 641 | 642 | 643 | 644 | 645 | 646 | 647 | 648 | 649 | 650 | 651 | 652 | 653 | 654 | 655 | 656 | 657 | 658 | 659 | 660 | 661 | 662 | 663 | 664 | 665 | 666 | 667 | 668 | 669 | 670 | 671 | 672 | 673 | 674 | 675 | 676 | 677 | 678 | 679 | 680 | 681 | 682 | 683 | 684 | -------------------------------------------------------------------------------- /Demos/DSFDragSlider Demo/DSFDragSlider Demo/Base.lproj/MainMenu.xib: -------------------------------------------------------------------------------- 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 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | 449 | 450 | 451 | 452 | 453 | 454 | 455 | 456 | 457 | 458 | 459 | 460 | 461 | 462 | 463 | 464 | 465 | 466 | 467 | 468 | 469 | 470 | 471 | 472 | 473 | 474 | 475 | 476 | 477 | 478 | 479 | 480 | 481 | 482 | 483 | 484 | 485 | 486 | 487 | 488 | 489 | 490 | 491 | 492 | 493 | 494 | 495 | 496 | 497 | 498 | 499 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 509 | 510 | 511 | 512 | 513 | 514 | 515 | 516 | 517 | 518 | 519 | 520 | 521 | 522 | 523 | 524 | 525 | 526 | 527 | 528 | 529 | 530 | 531 | 532 | 533 | 534 | 535 | 536 | 537 | 538 | 539 | 540 | 541 | 542 | 543 | Default 544 | 545 | 546 | 547 | 548 | 549 | 550 | Left to Right 551 | 552 | 553 | 554 | 555 | 556 | 557 | Right to Left 558 | 559 | 560 | 561 | 562 | 563 | 564 | 565 | 566 | 567 | 568 | Default 569 | 570 | 571 | 572 | 573 | 574 | 575 | Left to Right 576 | 577 | 578 | 579 | 580 | 581 | 582 | Right to Left 583 | 584 | 585 | 586 | 587 | 588 | 589 | 590 | 591 | 592 | 593 | 594 | 595 | 596 | 597 | 598 | 599 | 600 | 601 | 602 | 603 | 604 | 605 | 606 | 607 | 608 | 609 | 610 | 611 | 612 | 613 | 614 | 615 | 616 | 617 | 618 | 619 | 620 | 621 | 622 | 623 | 624 | 625 | 626 | 627 | 628 | 629 | 630 | 631 | 632 | 633 | 634 | 635 | 636 | 637 | 638 | 639 | 640 | 641 | 642 | 643 | 644 | 645 | 646 | 647 | 648 | 649 | 650 | 651 | 652 | 653 | 654 | 655 | 656 | 657 | 658 | 659 | 660 | 661 | 662 | 663 | 664 | 665 | 666 | 667 | 668 | 669 | 670 | 671 | 672 | 673 | 674 | 675 | 676 | 677 | 678 | 679 | 680 | 681 | 682 | 683 | 684 | 685 | 686 | 687 | 688 | 689 | 690 | 691 | 692 | 693 | 694 | 695 | 696 | 697 | 698 | 699 | 700 | 701 | 702 | 703 | 704 | 705 | 706 | 707 | 708 | 709 | 710 | 711 | 712 | 713 | 714 | 715 | 716 | 717 | 718 | 719 | 720 | 721 | 722 | 723 | 724 | 725 | 726 | 727 | 728 | 729 | 730 | 731 | 732 | 733 | 734 | 735 | 736 | 737 | 738 | 739 | 740 | 741 | 742 | 743 | 744 | 745 | 746 | 747 | 748 | 749 | 750 | 751 | 752 | 753 | 754 | 755 | 756 | 757 | 758 | 759 | 760 | 761 | 762 | 763 | 764 | 765 | 766 | 767 | 768 | 769 | 770 | 771 | 772 | 773 | 774 | 775 | 776 | 777 | 778 | 779 | 780 | 781 | 782 | 783 | 784 | 785 | 786 | 787 | 788 | 789 | 790 | 791 | 792 | 793 | 794 | 795 | 796 | 797 | 798 | 799 | 800 | 801 | 802 | 803 | 804 | 805 | 806 | 807 | 808 | 809 | 810 | 811 | 812 | 813 | 814 | 815 | 816 | 817 | 818 | 819 | 820 | 821 | 822 | 823 | 824 | 825 | 826 | 827 | 828 | 829 | 830 | 831 | 832 | 833 | 834 | 835 | 836 | 837 | 838 | 839 | 840 | 841 | 842 | 843 | 844 | 845 | 846 | 847 | 848 | 849 | 850 | 851 | 852 | 853 | 854 | 855 | 856 | 857 | 858 | 859 | 860 | 861 | 862 | 863 | 864 | 865 | 866 | 867 | 868 | 869 | 870 | 871 | 872 | 873 | 874 | 875 | 876 | 877 | 878 | 879 | 880 | 881 | 882 | 883 | 884 | 885 | 886 | 887 | 888 | 889 | 890 | 891 | 892 | 893 | 894 | 895 | 896 | 897 | 898 | 899 | 900 | 901 | --------------------------------------------------------------------------------