├── android ├── .gitignore ├── dist │ ├── android.jar │ └── de.marcelpociot.circularslider-android-1.0.zip ├── hooks │ ├── README │ ├── uninstall.py │ ├── install.py │ ├── add.py │ └── remove.py ├── images │ └── demo.gif ├── CHANGELOG.txt ├── libs │ ├── x86 │ │ └── libde.marcelpociot.circularslider.so │ ├── armeabi │ │ └── libde.marcelpociot.circularslider.so │ └── armeabi-v7a │ │ └── libde.marcelpociot.circularslider.so ├── platform │ └── android │ │ └── res │ │ ├── drawable-hdpi │ │ ├── ic_launcher.png │ │ ├── scrubber_control_normal_holo.png │ │ └── scrubber_control_pressed_holo.png │ │ ├── drawable-mdpi │ │ ├── ic_launcher.png │ │ ├── scrubber_control_normal_holo.png │ │ └── scrubber_control_pressed_holo.png │ │ └── drawable-xhdpi │ │ ├── ic_launcher.png │ │ ├── scrubber_control_normal_holo.png │ │ └── scrubber_control_pressed_holo.png ├── build.properties ├── assets │ └── README ├── build.xml ├── timodule.xml ├── manifest ├── example │ └── app.js ├── src │ └── de │ │ └── marcelpociot │ │ └── circularslider │ │ ├── TiCircularSliderModule.java │ │ ├── ViewProxy.java │ │ ├── View.java │ │ └── CircularSeekBar.java ├── .classpath ├── README.md └── documentation │ └── index.md ├── ios ├── Classes │ ├── .gitignore │ ├── DeMarcelpociotCircularsliderModuleAssets.h │ ├── DeMarcelpociotCircularsliderModule.h │ ├── DeMarcelpociotCircularsliderView.h │ ├── DeMarcelpociotCircularsliderViewProxy.h │ ├── DeMarcelpociotCircularsliderModuleAssets.m │ ├── DeMarcelpociotCircularsliderViewProxy.m │ ├── DeMarcelpociotCircularsliderModule.m │ └── DeMarcelpociotCircularsliderView.m ├── LICENSE ├── images │ └── demo.gif ├── LICENSE.txt ├── hooks │ ├── README │ ├── uninstall.py │ ├── install.py │ ├── add.py │ └── remove.py ├── CHANGELOG.txt ├── DeMarcelpociotCircularslider_Prefix.pch ├── dist │ ├── de.marcelpociot.circularslider-iphone-1.0.zip │ ├── de.marcelpociot.circularslider-iphone-1.1.0.zip │ └── de.marcelpociot.circularslider-iphone-1.2.0.zip ├── TiCircularSlide.xcodeproj │ ├── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ ├── xcuserdata │ │ │ ├── hans.xcuserdatad │ │ │ │ └── UserInterfaceState.xcuserstate │ │ │ └── marcelpociot.xcuserdatad │ │ │ │ ├── UserInterfaceState.xcuserstate │ │ │ │ └── WorkspaceSettings.xcsettings │ │ └── xcshareddata │ │ │ └── TiCircularSlide.xccheckout │ ├── xcuserdata │ │ ├── hans.xcuserdatad │ │ │ └── xcschemes │ │ │ │ ├── xcschememanagement.plist │ │ │ │ ├── Build & Test.xcscheme │ │ │ │ └── TiCircularSlide.xcscheme │ │ └── marcelpociot.xcuserdatad │ │ │ └── xcschemes │ │ │ ├── xcschememanagement.plist │ │ │ ├── Build & Test.xcscheme │ │ │ └── TiCircularSlide.xcscheme │ └── project.pbxproj ├── assets │ └── README ├── timodule.xml ├── platform │ └── README ├── manifest ├── titanium.xcconfig ├── module.xcconfig ├── example │ └── app.js ├── README.md ├── documentation │ └── index.md ├── EFCircularSlider │ ├── EFCircularSlider.h │ ├── EFCircularTrig.h │ ├── EFCircularTrig.m │ └── EFCircularSlider.m └── build.py ├── .gitignore └── README.md /android/.gitignore: -------------------------------------------------------------------------------- 1 | tmp 2 | bin 3 | build 4 | .apt_generated 5 | -------------------------------------------------------------------------------- /ios/Classes/.gitignore: -------------------------------------------------------------------------------- 1 | DeMarcelpociotCircularslider.h 2 | DeMarcelpociotCircularslider.m 3 | -------------------------------------------------------------------------------- /ios/LICENSE: -------------------------------------------------------------------------------- 1 | TODO: place your license here and we'll include it in the module distribution 2 | -------------------------------------------------------------------------------- /ios/images/demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpociot/TiCircularSlider/HEAD/ios/images/demo.gif -------------------------------------------------------------------------------- /android/dist/android.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpociot/TiCircularSlider/HEAD/android/dist/android.jar -------------------------------------------------------------------------------- /android/hooks/README: -------------------------------------------------------------------------------- 1 | These files are not yet supported as of 1.4.0 but will be in a near future release. 2 | -------------------------------------------------------------------------------- /android/images/demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpociot/TiCircularSlider/HEAD/android/images/demo.gif -------------------------------------------------------------------------------- /ios/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Place your license text here. This file will be incorporated with your app at package time. -------------------------------------------------------------------------------- /ios/hooks/README: -------------------------------------------------------------------------------- 1 | These files are not yet supported as of 1.4.0 but will be in a near future release. 2 | -------------------------------------------------------------------------------- /ios/CHANGELOG.txt: -------------------------------------------------------------------------------- 1 | Place your change log text here. This file will be incorporated with your app at package time. -------------------------------------------------------------------------------- /android/CHANGELOG.txt: -------------------------------------------------------------------------------- 1 | Place your change log text here. This file will be incorporated with your app at package time. -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | tmp 2 | bin 3 | build 4 | *.class 5 | *.pyc 6 | *.pyo 7 | .DS_Store 8 | .settings 9 | .project 10 | -------------------------------------------------------------------------------- /ios/DeMarcelpociotCircularslider_Prefix.pch: -------------------------------------------------------------------------------- 1 | 2 | #ifdef __OBJC__ 3 | #import 4 | #endif 5 | -------------------------------------------------------------------------------- /android/libs/x86/libde.marcelpociot.circularslider.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpociot/TiCircularSlider/HEAD/android/libs/x86/libde.marcelpociot.circularslider.so -------------------------------------------------------------------------------- /ios/dist/de.marcelpociot.circularslider-iphone-1.0.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpociot/TiCircularSlider/HEAD/ios/dist/de.marcelpociot.circularslider-iphone-1.0.zip -------------------------------------------------------------------------------- /ios/dist/de.marcelpociot.circularslider-iphone-1.1.0.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpociot/TiCircularSlider/HEAD/ios/dist/de.marcelpociot.circularslider-iphone-1.1.0.zip -------------------------------------------------------------------------------- /ios/dist/de.marcelpociot.circularslider-iphone-1.2.0.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpociot/TiCircularSlider/HEAD/ios/dist/de.marcelpociot.circularslider-iphone-1.2.0.zip -------------------------------------------------------------------------------- /android/dist/de.marcelpociot.circularslider-android-1.0.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpociot/TiCircularSlider/HEAD/android/dist/de.marcelpociot.circularslider-android-1.0.zip -------------------------------------------------------------------------------- /android/libs/armeabi/libde.marcelpociot.circularslider.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpociot/TiCircularSlider/HEAD/android/libs/armeabi/libde.marcelpociot.circularslider.so -------------------------------------------------------------------------------- /android/platform/android/res/drawable-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpociot/TiCircularSlider/HEAD/android/platform/android/res/drawable-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/platform/android/res/drawable-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpociot/TiCircularSlider/HEAD/android/platform/android/res/drawable-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/platform/android/res/drawable-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpociot/TiCircularSlider/HEAD/android/platform/android/res/drawable-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/libs/armeabi-v7a/libde.marcelpociot.circularslider.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpociot/TiCircularSlider/HEAD/android/libs/armeabi-v7a/libde.marcelpociot.circularslider.so -------------------------------------------------------------------------------- /android/platform/android/res/drawable-hdpi/scrubber_control_normal_holo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpociot/TiCircularSlider/HEAD/android/platform/android/res/drawable-hdpi/scrubber_control_normal_holo.png -------------------------------------------------------------------------------- /android/platform/android/res/drawable-hdpi/scrubber_control_pressed_holo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpociot/TiCircularSlider/HEAD/android/platform/android/res/drawable-hdpi/scrubber_control_pressed_holo.png -------------------------------------------------------------------------------- /android/platform/android/res/drawable-mdpi/scrubber_control_normal_holo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpociot/TiCircularSlider/HEAD/android/platform/android/res/drawable-mdpi/scrubber_control_normal_holo.png -------------------------------------------------------------------------------- /android/platform/android/res/drawable-mdpi/scrubber_control_pressed_holo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpociot/TiCircularSlider/HEAD/android/platform/android/res/drawable-mdpi/scrubber_control_pressed_holo.png -------------------------------------------------------------------------------- /android/platform/android/res/drawable-xhdpi/scrubber_control_normal_holo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpociot/TiCircularSlider/HEAD/android/platform/android/res/drawable-xhdpi/scrubber_control_normal_holo.png -------------------------------------------------------------------------------- /android/platform/android/res/drawable-xhdpi/scrubber_control_pressed_holo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpociot/TiCircularSlider/HEAD/android/platform/android/res/drawable-xhdpi/scrubber_control_pressed_holo.png -------------------------------------------------------------------------------- /ios/TiCircularSlide.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ios/TiCircularSlide.xcodeproj/project.xcworkspace/xcuserdata/hans.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpociot/TiCircularSlider/HEAD/ios/TiCircularSlide.xcodeproj/project.xcworkspace/xcuserdata/hans.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /android/build.properties: -------------------------------------------------------------------------------- 1 | titanium.platform=/Users/manu/Library/Application Support/Titanium/mobilesdk/osx/3.2.2.GA/android 2 | android.platform=/Users/manu/Development/android/sdk/platforms/android-19 3 | google.apis=/Users/manu/Development/android/sdk/add-ons/addon-google_apis-google-19 -------------------------------------------------------------------------------- /ios/TiCircularSlide.xcodeproj/project.xcworkspace/xcuserdata/marcelpociot.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpociot/TiCircularSlider/HEAD/ios/TiCircularSlide.xcodeproj/project.xcworkspace/xcuserdata/marcelpociot.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /ios/Classes/DeMarcelpociotCircularsliderModuleAssets.h: -------------------------------------------------------------------------------- 1 | /** 2 | * This is a generated file. Do not edit or your changes will be lost 3 | */ 4 | 5 | @interface DeMarcelpociotCircularsliderModuleAssets : NSObject 6 | { 7 | } 8 | - (NSData*) moduleAsset; 9 | - (NSData*) resolveModuleAsset:(NSString*)path; 10 | 11 | @end 12 | -------------------------------------------------------------------------------- /ios/assets/README: -------------------------------------------------------------------------------- 1 | Place your assets like PNG files in this directory and they will be packaged with your module. 2 | 3 | If you create a file named de.marcelpociot.circularslider.js in this directory, it will be 4 | compiled and used as your module. This allows you to run pure Javascript 5 | modules that are pre-compiled. 6 | 7 | -------------------------------------------------------------------------------- /android/assets/README: -------------------------------------------------------------------------------- 1 | Place your assets like PNG files in this directory and they will be packaged with your module. 2 | 3 | If you create a file named de.marcelpociot.circularslider.js in this directory, it will be 4 | compiled and used as your module. This allows you to run pure Javascript 5 | modules that are pre-compiled. 6 | 7 | -------------------------------------------------------------------------------- /android/build.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Ant build script for Titanium Android module android 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /ios/Classes/DeMarcelpociotCircularsliderModule.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Your Copyright Here 3 | * 4 | * Appcelerator Titanium is Copyright (c) 2009-2010 by Appcelerator, Inc. 5 | * and licensed under the Apache Public License (version 2) 6 | */ 7 | #import "TiModule.h" 8 | 9 | @interface DeMarcelpociotCircularsliderModule : TiModule 10 | { 11 | } 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /ios/hooks/uninstall.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # This is the module uninstall hook that will be 4 | # called when your module is uninstalled 5 | # 6 | import os, sys 7 | 8 | def main(args,argc): 9 | 10 | # TODO: write your uninstall hook here (optional) 11 | 12 | # exit 13 | sys.exit(0) 14 | 15 | 16 | if __name__ == '__main__': 17 | main(sys.argv,len(sys.argv)) 18 | 19 | -------------------------------------------------------------------------------- /android/hooks/uninstall.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # This is the module uninstall hook that will be 4 | # called when your module is uninstalled 5 | # 6 | import os, sys 7 | 8 | def main(args,argc): 9 | 10 | # TODO: write your uninstall hook here (optional) 11 | 12 | # exit 13 | sys.exit(0) 14 | 15 | 16 | if __name__ == '__main__': 17 | main(sys.argv,len(sys.argv)) 18 | 19 | -------------------------------------------------------------------------------- /ios/hooks/install.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # This is the module install hook that will be 4 | # called when your module is first installed 5 | # 6 | import os, sys 7 | 8 | def main(args,argc): 9 | 10 | # TODO: write your install hook here (optional) 11 | 12 | # exit 13 | sys.exit(0) 14 | 15 | 16 | 17 | if __name__ == '__main__': 18 | main(sys.argv,len(sys.argv)) 19 | 20 | -------------------------------------------------------------------------------- /android/hooks/install.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # This is the module install hook that will be 4 | # called when your module is first installed 5 | # 6 | import os, sys 7 | 8 | def main(args,argc): 9 | 10 | # TODO: write your install hook here (optional) 11 | 12 | # exit 13 | sys.exit(0) 14 | 15 | 16 | 17 | if __name__ == '__main__': 18 | main(sys.argv,len(sys.argv)) 19 | 20 | -------------------------------------------------------------------------------- /ios/TiCircularSlide.xcodeproj/project.xcworkspace/xcuserdata/marcelpociot.xcuserdatad/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | HasAskedToTakeAutomaticSnapshotBeforeSignificantChanges 6 | 7 | SnapshotAutomaticallyBeforeSignificantChanges 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /ios/timodule.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /android/timodule.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /ios/platform/README: -------------------------------------------------------------------------------- 1 | You can place platform-specific files here in sub-folders named "android" and/or "iphone", just as you can with normal Titanium Mobile SDK projects. Any folders and files you place here will be merged with the platform-specific files in a Titanium Mobile project that uses this module. 2 | 3 | When a Titanium Mobile project that uses this module is built, the files from this platform/ folder will be treated the same as files (if any) from the Titanium Mobile project's platform/ folder. 4 | -------------------------------------------------------------------------------- /android/manifest: -------------------------------------------------------------------------------- 1 | # 2 | # this is your module manifest and used by Titanium 3 | # during compilation, packaging, distribution, etc. 4 | # 5 | version: 1.0.1 6 | apiversion: 2 7 | description: Circular slider with many customizations 8 | author: Manuel Lehner 9 | license: MIT 10 | copyright: 2014 11 | 12 | 13 | # these should not be edited 14 | name: TiCircularSlider 15 | moduleid: de.marcelpociot.circularslider 16 | guid: 92ea5ecb-d462-433c-9967-90275ff0e99f 17 | platform: android 18 | minsdk: 3.2.0.GA 19 | -------------------------------------------------------------------------------- /android/example/app.js: -------------------------------------------------------------------------------- 1 | var win = Ti.UI.createWindow({ 2 | backgroundColor:'white' 3 | }); 4 | var TiCircularSlider = require('de.marcelpociot.circularslider'); 5 | 6 | var sliderView = TiCircularSlider.createView({ 7 | height: 250, 8 | width: 250, 9 | lineWidth: 5, 10 | filledColor: 'blue', 11 | unfilledColor: 'grey' 12 | }); 13 | sliderView.addEventListener('change',function(e) 14 | { 15 | Ti.API.info( "Value is: ", e.value ); 16 | }); 17 | win.add( sliderView ); 18 | win.open(); 19 | -------------------------------------------------------------------------------- /ios/Classes/DeMarcelpociotCircularsliderView.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Appcelerator Titanium Mobile 3 | * Copyright (c) 2009-2013 by Appcelerator, Inc. All Rights Reserved. 4 | * Licensed under the terms of the Apache Public License 5 | * Please see the LICENSE included with this distribution for details. 6 | */ 7 | #import "TiBase.h" 8 | #import "TiUIView.h" 9 | #import "EFCircularSlider.h" 10 | 11 | @interface DeMarcelpociotCircularsliderView : TiUIView { 12 | EFCircularSlider* sliderView; 13 | } 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /ios/manifest: -------------------------------------------------------------------------------- 1 | # 2 | # this is your module manifest and used by Titanium 3 | # during compilation, packaging, distribution, etc. 4 | # 5 | version: 1.2.0 6 | apiversion: 2 7 | description: Circular slider with many customizations 8 | author: Marcel Pociot 9 | license: MIT 10 | copyright: Marcel Pociot 11 | 12 | 13 | # these should not be edited 14 | name: TiCircularSlider 15 | moduleid: de.marcelpociot.circularslider 16 | guid: ecae907d-2ade-46aa-9cc5-346d32c5b0f3 17 | platform: iphone 18 | minsdk: 3.1.3.GA 19 | architectures: armv7 arm64 i386 x86_64 20 | -------------------------------------------------------------------------------- /ios/titanium.xcconfig: -------------------------------------------------------------------------------- 1 | // 2 | // 3 | // CHANGE THESE VALUES TO REFLECT THE VERSION (AND LOCATION IF DIFFERENT) 4 | // OF YOUR TITANIUM SDK YOU'RE BUILDING FOR 5 | // 6 | // 7 | TITANIUM_SDK_VERSION = 5.1.2.GA 8 | 9 | 10 | // 11 | // THESE SHOULD BE OK GENERALLY AS-IS 12 | // 13 | TITANIUM_SDK = ~/Library/Application Support/Titanium/mobilesdk/osx/$(TITANIUM_SDK_VERSION) 14 | TITANIUM_BASE_SDK = "$(TITANIUM_SDK)/iphone/include" 15 | TITANIUM_BASE_SDK2 = "$(TITANIUM_SDK)/iphone/include/TiCore" 16 | HEADER_SEARCH_PATHS= $(TITANIUM_BASE_SDK) $(TITANIUM_BASE_SDK2) 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /ios/TiCircularSlide.xcodeproj/xcuserdata/hans.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SuppressBuildableAutocreation 6 | 7 | 24416B8111C4CA220047AFDD 8 | 9 | primary 10 | 11 | 12 | D2AAC07D0554694100DB518D 13 | 14 | primary 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /ios/Classes/DeMarcelpociotCircularsliderViewProxy.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Appcelerator Titanium Mobile 3 | * Copyright (c) 2009-2013 by Appcelerator, Inc. All Rights Reserved. 4 | * Licensed under the terms of the Apache Public License 5 | * Please see the LICENSE included with this distribution for details. 6 | */ 7 | #import "TiViewProxy.h" 8 | #import "EFCircularSlider.h" 9 | 10 | @interface DeMarcelpociotCircularsliderViewProxy : TiViewProxy { 11 | 12 | } 13 | 14 | -(void)valueChanged:(EFCircularSlider*)slider; 15 | -(void)touchStarted:(EFCircularSlider*)slider; 16 | -(void)touchEnded:(EFCircularSlider*)slider; 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /ios/Classes/DeMarcelpociotCircularsliderModuleAssets.m: -------------------------------------------------------------------------------- 1 | /** 2 | * This is a generated file. Do not edit or your changes will be lost 3 | */ 4 | #import "DeMarcelpociotCircularsliderModuleAssets.h" 5 | 6 | extern NSData* filterDataInRange(NSData* thedata, NSRange range); 7 | 8 | @implementation DeMarcelpociotCircularsliderModuleAssets 9 | 10 | - (NSData*) moduleAsset 11 | { 12 | //##TI_AUTOGEN_BEGIN asset 13 | //Compiler generates code for asset here 14 | return nil; // DEFAULT BEHAVIOR 15 | //##TI_AUTOGEN_END asset 16 | } 17 | 18 | - (NSData*) resolveModuleAsset:(NSString*)path 19 | { 20 | //##TI_AUTOGEN_BEGIN resolve_asset 21 | //Compiler generates code for asset resolution here 22 | return nil; // DEFAULT BEHAVIOR 23 | //##TI_AUTOGEN_END resolve_asset 24 | } 25 | 26 | @end 27 | -------------------------------------------------------------------------------- /android/src/de/marcelpociot/circularslider/TiCircularSliderModule.java: -------------------------------------------------------------------------------- 1 | package de.marcelpociot.circularslider; 2 | 3 | import org.appcelerator.kroll.KrollModule; 4 | import org.appcelerator.kroll.annotations.Kroll; 5 | 6 | import org.appcelerator.titanium.TiApplication; 7 | import org.appcelerator.kroll.common.Log; 8 | 9 | @Kroll.module(name="TiCircularSlider", id="de.marcelpociot.circularslider") 10 | public class TiCircularSliderModule extends KrollModule 11 | { 12 | private static final String TAG = "TiCircularSliderModule"; 13 | 14 | public TiCircularSliderModule() 15 | { 16 | super(); 17 | } 18 | 19 | @Kroll.onAppCreate 20 | public static void onAppCreate(TiApplication app) 21 | { 22 | Log.d(TAG, "inside onAppCreate"); 23 | // put module init code that needs to run when the application is created 24 | } 25 | 26 | 27 | } 28 | 29 | -------------------------------------------------------------------------------- /ios/TiCircularSlide.xcodeproj/xcuserdata/marcelpociot.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | Build & Test.xcscheme 8 | 9 | orderHint 10 | 1 11 | 12 | TiCircularSlide.xcscheme 13 | 14 | orderHint 15 | 0 16 | 17 | 18 | SuppressBuildableAutocreation 19 | 20 | 24416B8111C4CA220047AFDD 21 | 22 | primary 23 | 24 | 25 | D2AAC07D0554694100DB518D 26 | 27 | primary 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /ios/hooks/add.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # This is the module project add hook that will be 4 | # called when your module is added to a project 5 | # 6 | import os, sys 7 | 8 | def dequote(s): 9 | if s[0:1] == '"': 10 | return s[1:-1] 11 | return s 12 | 13 | def main(args,argc): 14 | # You will get the following command line arguments 15 | # in the following order: 16 | # 17 | # project_dir = the full path to the project root directory 18 | # project_type = the type of project (desktop, mobile, ipad) 19 | # project_name = the name of the project 20 | # 21 | project_dir = dequote(os.path.expanduser(args[1])) 22 | project_type = dequote(args[2]) 23 | project_name = dequote(args[3]) 24 | 25 | # TODO: write your add hook here (optional) 26 | 27 | 28 | # exit 29 | sys.exit(0) 30 | 31 | 32 | 33 | if __name__ == '__main__': 34 | main(sys.argv,len(sys.argv)) 35 | 36 | -------------------------------------------------------------------------------- /android/hooks/add.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # This is the module project add hook that will be 4 | # called when your module is added to a project 5 | # 6 | import os, sys 7 | 8 | def dequote(s): 9 | if s[0:1] == '"': 10 | return s[1:-1] 11 | return s 12 | 13 | def main(args,argc): 14 | # You will get the following command line arguments 15 | # in the following order: 16 | # 17 | # project_dir = the full path to the project root directory 18 | # project_type = the type of project (desktop, mobile, ipad) 19 | # project_name = the name of the project 20 | # 21 | project_dir = dequote(os.path.expanduser(args[1])) 22 | project_type = dequote(args[2]) 23 | project_name = dequote(args[3]) 24 | 25 | # TODO: write your add hook here (optional) 26 | 27 | 28 | # exit 29 | sys.exit(0) 30 | 31 | 32 | 33 | if __name__ == '__main__': 34 | main(sys.argv,len(sys.argv)) 35 | 36 | -------------------------------------------------------------------------------- /ios/hooks/remove.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # This is the module project remove hook that will be 4 | # called when your module is remove from a project 5 | # 6 | import os, sys 7 | 8 | def dequote(s): 9 | if s[0:1] == '"': 10 | return s[1:-1] 11 | return s 12 | 13 | def main(args,argc): 14 | # You will get the following command line arguments 15 | # in the following order: 16 | # 17 | # project_dir = the full path to the project root directory 18 | # project_type = the type of project (desktop, mobile, ipad) 19 | # project_name = the name of the project 20 | # 21 | project_dir = dequote(os.path.expanduser(args[1])) 22 | project_type = dequote(args[2]) 23 | project_name = dequote(args[3]) 24 | 25 | # TODO: write your remove hook here (optional) 26 | 27 | # exit 28 | sys.exit(0) 29 | 30 | 31 | 32 | if __name__ == '__main__': 33 | main(sys.argv,len(sys.argv)) 34 | 35 | -------------------------------------------------------------------------------- /android/.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /android/hooks/remove.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # This is the module project remove hook that will be 4 | # called when your module is remove from a project 5 | # 6 | import os, sys 7 | 8 | def dequote(s): 9 | if s[0:1] == '"': 10 | return s[1:-1] 11 | return s 12 | 13 | def main(args,argc): 14 | # You will get the following command line arguments 15 | # in the following order: 16 | # 17 | # project_dir = the full path to the project root directory 18 | # project_type = the type of project (desktop, mobile, ipad) 19 | # project_name = the name of the project 20 | # 21 | project_dir = dequote(os.path.expanduser(args[1])) 22 | project_type = dequote(args[2]) 23 | project_name = dequote(args[3]) 24 | 25 | # TODO: write your remove hook here (optional) 26 | 27 | # exit 28 | sys.exit(0) 29 | 30 | 31 | 32 | if __name__ == '__main__': 33 | main(sys.argv,len(sys.argv)) 34 | 35 | -------------------------------------------------------------------------------- /ios/module.xcconfig: -------------------------------------------------------------------------------- 1 | // 2 | // PLACE ANY BUILD DEFINITIONS IN THIS FILE AND THEY WILL BE 3 | // PICKED UP DURING THE APP BUILD FOR YOUR MODULE 4 | // 5 | // see the following webpage for instructions on the settings 6 | // for this file: 7 | // http://developer.apple.com/mac/library/documentation/DeveloperTools/Conceptual/XcodeBuildSystem/400-Build_Configurations/build_configs.html 8 | // 9 | 10 | // 11 | // How to add a Framework (example) 12 | // 13 | OTHER_LDFLAGS=$(inherited) -framework QuartzCore -framework CoreImage 14 | // 15 | // Adding a framework for a specific version(s) of iPhone: 16 | // 17 | // OTHER_LDFLAGS[sdk=iphoneos4*]=$(inherited) -framework Foo 18 | // OTHER_LDFLAGS[sdk=iphonesimulator4*]=$(inherited) -framework Foo 19 | // 20 | // 21 | // How to add a compiler define: 22 | // 23 | // OTHER_CFLAGS=$(inherited) -DFOO=1 24 | // 25 | // 26 | // IMPORTANT NOTE: always use $(inherited) in your overrides 27 | // 28 | -------------------------------------------------------------------------------- /ios/Classes/DeMarcelpociotCircularsliderViewProxy.m: -------------------------------------------------------------------------------- 1 | /** 2 | * Appcelerator Titanium Mobile 3 | * Copyright (c) 2009-2013 by Appcelerator, Inc. All Rights Reserved. 4 | * Licensed under the terms of the Apache Public License 5 | * Please see the LICENSE included with this distribution for details. 6 | */ 7 | 8 | #import "DeMarcelpociotCircularsliderViewProxy.h" 9 | #import "TiUtils.h" 10 | 11 | @implementation DeMarcelpociotCircularsliderViewProxy 12 | 13 | -(void)valueChanged:(EFCircularSlider*)slider { 14 | [self fireEvent:@"change" withObject:@{ 15 | @"value": NUMFLOAT([slider currentValue]) 16 | }]; 17 | } 18 | 19 | -(void)touchStarted:(EFCircularSlider*)slider { 20 | [self fireEvent:@"touchstart" withObject:@{ 21 | @"value": NUMFLOAT([slider currentValue]) 22 | }]; 23 | } 24 | 25 | -(void)touchEnded:(EFCircularSlider*)slider { 26 | [self fireEvent:@"touchend" withObject:@{ 27 | @"value": NUMFLOAT([slider currentValue]) 28 | }]; 29 | } 30 | 31 | @end 32 | -------------------------------------------------------------------------------- /ios/example/app.js: -------------------------------------------------------------------------------- 1 | var win = Ti.UI.createWindow({ 2 | backgroundColor:'white' 3 | }); 4 | 5 | var TiCircularSlider = require('de.marcelpociot.circularslider'); 6 | var sliderView = TiCircularSlider.createView({ 7 | top: 200, 8 | left: 50, 9 | height: 250, 10 | width: 250, 11 | lineWidth: 15, 12 | handleColor: 'red', 13 | filledColor: '#d7d7d7', 14 | unfilledColor: '#black' 15 | }); 16 | 17 | sliderView.addEventListener('change',function(e) { 18 | Ti.API.warn("change"); 19 | sliderValue.text = Math.round( e.value ); 20 | }); 21 | 22 | sliderView.addEventListener('touchstart',function(e) { 23 | Ti.API.warn("touchstart"); 24 | sliderValue.text = Math.round( e.value ); 25 | }); 26 | 27 | sliderView.addEventListener('touchend',function(e) { 28 | Ti.API.warn("touchend"); 29 | sliderValue.text = Math.round( e.value ); 30 | }); 31 | 32 | win.add( sliderView ); 33 | 34 | win.addEventListener("open", function() { 35 | sliderView.setValue(50); 36 | }); 37 | 38 | var sliderValue = Ti.UI.createLabel({ 39 | top: 40, 40 | layout: 'horizontal', 41 | }); 42 | win.add( sliderValue ); 43 | 44 | win.open(); 45 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TiCircularSlider [![Titanium](http://www-static.appcelerator.com/badges/titanium-git-badge-sq.png)](http://www.appcelerator.com/titanium/) 2 | 3 | ## About 4 | TiCircularSlider is a native module for Titanium for iOS and Android. It uses [EFCircularSlider](https://github.com/eliotfowler/EFCircularSlider) on iOS and [CircularSeekBar](https://github.com/RaghavSood/AndroidCircularSeekBar) on Android. Within this module they share the same API. 5 | 6 | ## Quick Start 7 | 8 | ### Installation [![gitTio](http://gitt.io/badge.png)](http://gitt.io/component/de.marcelpociot.circularslider) 9 | Download the latest distribution ZIP-file and consult the [Titanium Documentation](http://docs.appcelerator.com/titanium/latest/#!/guide/Using_a_Module) on how install it, or simply use the [gitTio CLI](http://gitt.io/cli): 10 | 11 | `$ gittio install de.marcelpociot.circularslider` 12 | 13 | ### Usage 14 | ```javascript 15 | var TiCircularSlider = require('de.marcelpociot.circularslider'); 16 | 17 | var sliderView = TiCircularSlider.createView({ 18 | height: 250, 19 | width: 250, 20 | lineWidth: 5, 21 | filledColor: 'blue', 22 | unfilledColor: 'grey' 23 | }); 24 | sliderView.addEventListener('change',function(e){ 25 | Ti.API.info( "Value is: ", e.value ); 26 | }); 27 | win.add( sliderView ); 28 | ``` 29 | 30 | ### [iOS](ios) 31 | Author: Marcel Pociot ([mpociot](https://github.com/mpociot/)) 32 | 33 | ### [Android](android) 34 | Author: Manuel Lehner ([manumaticx](https://github.com/manumaticx/)) 35 | 36 | ## License: MIT 37 | 38 | [![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/mpociot/ticircularslider/trend.png)](https://bitdeli.com/free "Bitdeli Badge") 39 | -------------------------------------------------------------------------------- /ios/TiCircularSlide.xcodeproj/project.xcworkspace/xcshareddata/TiCircularSlide.xccheckout: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDESourceControlProjectFavoriteDictionaryKey 6 | 7 | IDESourceControlProjectIdentifier 8 | C0D386F6-22E3-4C0E-995E-095B9514E20D 9 | IDESourceControlProjectName 10 | TiCircularSlide 11 | IDESourceControlProjectOriginsDictionary 12 | 13 | D95FEB8EA29486930BDDFF666F72E9F476E33FEC 14 | github.com:mpociot/TiCircularSlider.git 15 | 16 | IDESourceControlProjectPath 17 | ios/TiCircularSlide.xcodeproj 18 | IDESourceControlProjectRelativeInstallPathDictionary 19 | 20 | D95FEB8EA29486930BDDFF666F72E9F476E33FEC 21 | ../../.. 22 | 23 | IDESourceControlProjectURL 24 | github.com:mpociot/TiCircularSlider.git 25 | IDESourceControlProjectVersion 26 | 111 27 | IDESourceControlProjectWCCIdentifier 28 | D95FEB8EA29486930BDDFF666F72E9F476E33FEC 29 | IDESourceControlProjectWCConfigurations 30 | 31 | 32 | IDESourceControlRepositoryExtensionIdentifierKey 33 | public.vcs.git 34 | IDESourceControlWCCIdentifierKey 35 | D95FEB8EA29486930BDDFF666F72E9F476E33FEC 36 | IDESourceControlWCCName 37 | TiCircularSlider 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /android/README.md: -------------------------------------------------------------------------------- 1 | TiCircularSlider 2 | =========================================== 3 | 4 | 5 | Circular slider with many customizations. 6 | Wrapper module for AndroidCircularSeekBar. 7 | 8 | ![demo](images/demo.gif) 9 | 10 | ### Usage 11 | 12 | ```javascript 13 | var TiCircularSlider = require('de.marcelpociot.circularslider'); 14 | 15 | var sliderView = TiCircularSlider.createView({ 16 | height: 250, 17 | width: 250, 18 | lineWidth: 5, 19 | filledColor: 'blue', 20 | unfilledColor: 'grey' 21 | }); 22 | sliderView.addEventListener('change',function(e) 23 | { 24 | Ti.API.info( "Value is: ", e.value ); 25 | }); 26 | win.add( sliderView ); 27 | ``` 28 | 29 | ### License 30 | 31 | The MIT License (MIT) 32 | 33 | Copyright (c) 2014 Manuel Lehner 34 | 35 | Permission is hereby granted, free of charge, to any person obtaining a copy 36 | of this software and associated documentation files (the "Software"), to deal 37 | in the Software without restriction, including without limitation the rights 38 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 39 | copies of the Software, and to permit persons to whom the Software is 40 | furnished to do so, subject to the following conditions: 41 | 42 | The above copyright notice and this permission notice shall be included in 43 | all copies or substantial portions of the Software. 44 | 45 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 46 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 47 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 48 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 49 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 50 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 51 | THE SOFTWARE. 52 | -------------------------------------------------------------------------------- /android/documentation/index.md: -------------------------------------------------------------------------------- 1 | TiCircularSlider 2 | =========================================== 3 | 4 | 5 | Circular slider with many customizations. 6 | Wrapper module for AndroidCircularSeekBar. 7 | 8 | ![demo](images/demo.gif) 9 | 10 | ### Usage 11 | 12 | ```javascript 13 | var TiCircularSlider = require('de.marcelpociot.circularslider'); 14 | 15 | var sliderView = TiCircularSlider.createView({ 16 | height: 250, 17 | width: 250, 18 | lineWidth: 5, 19 | filledColor: 'blue', 20 | unfilledColor: 'grey' 21 | }); 22 | sliderView.addEventListener('change',function(e) 23 | { 24 | Ti.API.info( "Value is: ", e.value ); 25 | }); 26 | win.add( sliderView ); 27 | ``` 28 | 29 | ### License 30 | 31 | The MIT License (MIT) 32 | 33 | Copyright (c) 2014 Manuel Lehner 34 | 35 | Permission is hereby granted, free of charge, to any person obtaining a copy 36 | of this software and associated documentation files (the "Software"), to deal 37 | in the Software without restriction, including without limitation the rights 38 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 39 | copies of the Software, and to permit persons to whom the Software is 40 | furnished to do so, subject to the following conditions: 41 | 42 | The above copyright notice and this permission notice shall be included in 43 | all copies or substantial portions of the Software. 44 | 45 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 46 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 47 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 48 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 49 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 50 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 51 | THE SOFTWARE. 52 | -------------------------------------------------------------------------------- /ios/README.md: -------------------------------------------------------------------------------- 1 | TiCircularSlider 2 | =========================================== 3 | 4 | 5 | Circular slider with many customizations. 6 | Wrapper module for EFCircularSlider. 7 | 8 | 9 | 10 | ### Usage 11 | 12 | TiCircularProgress is pretty much a ProgressView replacement. 13 | 14 | var TiCircularSlider = require('de.marcelpociot.circularslider'); 15 | 16 | var sliderView = TiCircularSlider.createView({ 17 | top: 200, 18 | left: 50, 19 | height: 250, 20 | width: 250, 21 | lineWidth: 5, 22 | handleColor: 'red', 23 | filledColor: '#d7d7d7', 24 | unfilledColor: '#black' 25 | }); 26 | sliderView.addEventListener('change',function(e) 27 | { 28 | Ti.API.info( "Value is: ", e.value ); 29 | }); 30 | win.add( sliderView ); 31 | 32 | 33 | ## Options 34 | 35 | 36 | #### lineWidth 37 | 38 | Type: `Float` 39 | Default: `5` 40 | 41 | The circle's line width. 42 | 43 | 44 | #### minimumValue 45 | 46 | Type: `Float` 47 | Default: `0.0` 48 | 49 | 50 | #### maximumValue 51 | 52 | Type: `Float` 53 | Default: `100.0` 54 | 55 | #### handleColor 56 | 57 | Type: `Color` 58 | Default: `red` 59 | 60 | Color for the slider handle. 61 | 62 | 63 | #### filledColor 64 | 65 | Type: `Color` 66 | Default: `red` 67 | 68 | Color for the filled (selected) area of the slider. 69 | 70 | #### unfilledColor 71 | 72 | Type: `Color` 73 | Default: `black` 74 | 75 | Color for the unfilled (unselected) area of the slider. 76 | 77 | ## Events 78 | 79 | ### change 80 | Fired everytime the selection changes. 81 | 82 | ##### value 83 | Type: `Float` 84 | The current selected value 85 | 86 | 87 | ABOUT THE AUTHOR 88 | ======================== 89 | I'm a web enthusiast located in Germany and in charge of http://www.titaniumcontrols.com 90 | 91 | Follow me on twitter: @marcelpociot / @TitaniumCTRLs 92 | 93 | [![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/mpociot/ticircularslider/trend.png)](https://bitdeli.com/free "Bitdeli Badge") 94 | 95 | -------------------------------------------------------------------------------- /ios/Classes/DeMarcelpociotCircularsliderModule.m: -------------------------------------------------------------------------------- 1 | /** 2 | * Your Copyright Here 3 | * 4 | * Appcelerator Titanium is Copyright (c) 2009-2010 by Appcelerator, Inc. 5 | * and licensed under the Apache Public License (version 2) 6 | */ 7 | #import "DeMarcelpociotCircularsliderModule.h" 8 | #import "TiBase.h" 9 | #import "TiHost.h" 10 | #import "TiUtils.h" 11 | 12 | @implementation DeMarcelpociotCircularsliderModule 13 | 14 | #pragma mark Internal 15 | 16 | // this is generated for your module, please do not change it 17 | -(id)moduleGUID 18 | { 19 | return @"ecae907d-2ade-46aa-9cc5-346d32c5b0f3"; 20 | } 21 | 22 | // this is generated for your module, please do not change it 23 | -(NSString*)moduleId 24 | { 25 | return @"de.marcelpociot.circularslider"; 26 | } 27 | 28 | #pragma mark Lifecycle 29 | 30 | -(void)startup 31 | { 32 | // this method is called when the module is first loaded 33 | // you *must* call the superclass 34 | [super startup]; 35 | 36 | NSLog(@"[INFO] %@ loaded",self); 37 | } 38 | 39 | -(void)shutdown:(id)sender 40 | { 41 | // this method is called when the module is being unloaded 42 | // typically this is during shutdown. make sure you don't do too 43 | // much processing here or the app will be quit forceably 44 | 45 | // you *must* call the superclass 46 | [super shutdown:sender]; 47 | } 48 | 49 | #pragma mark Internal Memory Management 50 | 51 | -(void)didReceiveMemoryWarning:(NSNotification*)notification 52 | { 53 | // optionally release any resources that can be dynamically 54 | // reloaded once memory is available - such as caches 55 | [super didReceiveMemoryWarning:notification]; 56 | } 57 | 58 | #pragma mark Listener Notifications 59 | 60 | -(void)_listenerAdded:(NSString *)type count:(int)count 61 | { 62 | if (count == 1 && [type isEqualToString:@"my_event"]) 63 | { 64 | // the first (of potentially many) listener is being added 65 | // for event named 'my_event' 66 | } 67 | } 68 | 69 | -(void)_listenerRemoved:(NSString *)type count:(int)count 70 | { 71 | if (count == 0 && [type isEqualToString:@"my_event"]) 72 | { 73 | // the last listener called for event named 'my_event' has 74 | // been removed, we can optionally clean up any resources 75 | // since no body is listening at this point for that event 76 | } 77 | } 78 | 79 | #pragma Public APIs 80 | 81 | @end 82 | -------------------------------------------------------------------------------- /android/src/de/marcelpociot/circularslider/ViewProxy.java: -------------------------------------------------------------------------------- 1 | package de.marcelpociot.circularslider; 2 | 3 | import org.appcelerator.kroll.KrollDict; 4 | import org.appcelerator.kroll.KrollModule; 5 | import org.appcelerator.kroll.annotations.Kroll; 6 | import org.appcelerator.kroll.common.Log; 7 | import org.appcelerator.titanium.proxy.TiViewProxy; 8 | import org.appcelerator.titanium.view.TiUIView; 9 | 10 | import android.app.Activity; 11 | 12 | @Kroll.proxy(creatableInModule = TiCircularSliderModule.class) 13 | public class ViewProxy extends TiViewProxy { 14 | private static final String LCAT = "TiCircularSliderModule"; 15 | 16 | de.marcelpociot.circularslider.View view; 17 | 18 | public ViewProxy() { 19 | super(); 20 | 21 | Log.d(LCAT, "[VIEWPROXY LIFECYCLE EVENT] init"); 22 | } 23 | 24 | @Override 25 | public TiUIView createView(Activity activity) { 26 | // This method is called when the view needs to be created. This is 27 | // a required method for a TiViewProxy subclass. 28 | 29 | view = new View(this); 30 | view.getLayoutParams().autoFillsHeight = true; 31 | view.getLayoutParams().autoFillsWidth = true; 32 | 33 | return view; 34 | } 35 | 36 | // Handle creation options 37 | @Override 38 | public void handleCreationDict(KrollDict options) { 39 | // This method is called from handleCreationArgs if there is at least 40 | // argument specified for the proxy creation call and the first argument 41 | // is a KrollDict object. 42 | 43 | Log.d(LCAT, "VIEWPROXY LIFECYCLE EVENT] handleCreationDict " + options); 44 | 45 | // Calling the superclass method ensures that the properties specified 46 | // in the dictionary are properly set on the proxy object. 47 | super.handleCreationDict(options); 48 | } 49 | 50 | public void handleCreationArgs(KrollModule createdInModule, Object[] args) { 51 | // This method is one of the initializers for the proxy class. The 52 | // arguments 53 | // for the create call are passed as an array of objects. If your proxy 54 | // simply needs to handle a single KrollDict argument, use 55 | // handleCreationDict. 56 | // The superclass method calls the handleCreationDict if the first 57 | // argument 58 | // to the create method is a dictionary object. 59 | 60 | Log.d(LCAT, "VIEWPROXY LIFECYCLE EVENT] handleCreationArgs "); 61 | 62 | for (int i = 0; i < args.length; i++) { 63 | Log.d(LCAT, "VIEWPROXY LIFECYCLE EVENT] args[" + i + "] " + args[i]); 64 | } 65 | 66 | super.handleCreationArgs(createdInModule, args); 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /ios/TiCircularSlide.xcodeproj/xcuserdata/marcelpociot.xcuserdatad/xcschemes/Build & Test.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 42 | 43 | 49 | 50 | 51 | 52 | 53 | 54 | 60 | 61 | 63 | 64 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /ios/TiCircularSlide.xcodeproj/xcuserdata/marcelpociot.xcuserdatad/xcschemes/TiCircularSlide.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 42 | 43 | 49 | 50 | 51 | 52 | 53 | 54 | 60 | 61 | 63 | 64 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /ios/documentation/index.md: -------------------------------------------------------------------------------- 1 | TiCircularSlider 2 | =========================================== 3 | 4 | 5 | Circular slider with many customizations. 6 | Wrapper module for EFCircularSlider. 7 | 8 | 9 | 10 | ### Usage 11 | 12 | TiCircularProgress is pretty much a ProgressView replacement. 13 | 14 | var TiCircularSlider = require('de.marcelpociot.circularslider'); 15 | 16 | var sliderView = TiCircularSlider.createView({ 17 | top: 200, 18 | left: 50, 19 | height: 250, 20 | width: 250, 21 | lineWidth: 5, 22 | handleColor: 'red', 23 | filledColor: '#d7d7d7', 24 | unfilledColor: '#black' 25 | }); 26 | sliderView.addEventListener('change',function(e) 27 | { 28 | Ti.API.info( "Value is: ", e.value ); 29 | }); 30 | win.add( sliderView ); 31 | 32 | 33 | ## Options 34 | 35 | 36 | #### lineWidth 37 | 38 | Type: `Float` 39 | Default: `5` 40 | 41 | The circle's line width. 42 | 43 | 44 | #### minimumValue 45 | 46 | Type: `Float` 47 | Default: `0.0` 48 | 49 | 50 | #### maximumValue 51 | 52 | Type: `Float` 53 | Default: `100.0` 54 | 55 | #### handleColor 56 | 57 | Type: `Color` 58 | Default: `red` 59 | 60 | Color for the slider handle. 61 | 62 | #### filledColor 63 | 64 | Type: `Color` 65 | Default: `red` 66 | 67 | Color for the filled (selected) area of the slider. 68 | 69 | #### unfilledColor 70 | 71 | Type: `Color` 72 | Default: `black` 73 | 74 | Color for the unfilled (unselected) area of the slider. 75 | 76 | #### labelFont 77 | 78 | Type: `String` 79 | Default: (system-provided font-family) 80 | 81 | Font of the inner marking labels within the circle. 82 | 83 | #### labelColor 84 | 85 | Type: `Color` 86 | Default: `Black` 87 | 88 | Color of the inner marking labels within the circle. 89 | 90 | #### labelDisplacement 91 | 92 | Type: `Float` 93 | Default: `0` 94 | 95 | Value with which to displace all labels along radial line from center to slider circumference. 96 | Note: A negative value will move the label closer to the center. A positive value will move the 97 | label closer to the circumference 98 | 99 | ## Events 100 | 101 | ### change 102 | Fired everytime the selection changes. 103 | 104 | ##### value 105 | Type: `Float` 106 | The current selected value 107 | 108 | ### touchstart 109 | Fired everytime the selection starts. 110 | 111 | ##### value 112 | Type: `Float` 113 | The current selected value 114 | 115 | ### touchend 116 | Fired everytime the selection stops. 117 | 118 | ##### value 119 | Type: `Float` 120 | The current selected value 121 | 122 | 123 | ABOUT THE AUTHOR 124 | ======================== 125 | I'm a web enthusiast located in Germany and in charge of http://www.titaniumcontrols.com 126 | 127 | Follow me on twitter: @marcelpociot / @TitaniumCTRLs 128 | 129 | [![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/mpociot/ticircularslider/trend.png)](https://bitdeli.com/free "Bitdeli Badge") 130 | 131 | -------------------------------------------------------------------------------- /ios/TiCircularSlide.xcodeproj/xcuserdata/hans.xcuserdatad/xcschemes/Build & Test.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 16 | 22 | 23 | 24 | 25 | 26 | 31 | 32 | 33 | 34 | 35 | 36 | 46 | 47 | 53 | 54 | 55 | 56 | 57 | 58 | 64 | 65 | 71 | 72 | 73 | 74 | 76 | 77 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /ios/TiCircularSlide.xcodeproj/xcuserdata/hans.xcuserdatad/xcschemes/TiCircularSlide.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 16 | 22 | 23 | 24 | 25 | 26 | 31 | 32 | 33 | 34 | 35 | 36 | 46 | 47 | 53 | 54 | 55 | 56 | 57 | 58 | 64 | 65 | 71 | 72 | 73 | 74 | 76 | 77 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /ios/EFCircularSlider/EFCircularSlider.h: -------------------------------------------------------------------------------- 1 | // 2 | // EFCircularSlider.h 3 | // Awake 4 | // 5 | // Created by Eliot Fowler on 12/3/13. 6 | // Copyright (c) 2013 Eliot Fowler. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | /** 12 | * Class used to define a circular control with a handle that can be moved around the circumference to represent a value 13 | */ 14 | @interface EFCircularSlider : UIControl 15 | 16 | typedef enum : NSUInteger { 17 | CircularSliderHandleTypeSemiTransparentWhiteCircle, 18 | CircularSliderHandleTypeSemiTransparentBlackCircle, 19 | CircularSliderHandleTypeDoubleCircleWithOpenCenter, 20 | CircularSliderHandleTypeDoubleCircleWithClosedCenter, 21 | CircularSliderHandleTypeBigCircle 22 | } CircularSliderHandleType; 23 | 24 | #pragma mark - Default Autolayout initialiser 25 | /** 26 | * Initialise the class with a desired radius 27 | * This initialiser should be used for autolayout - use initWithFrame otherwise 28 | * Note: Intrinsice content size will be based on this parameter, lineWidth and handleType 29 | * 30 | * @param radius Desired radius of circular slider 31 | * 32 | * @return Allocated instance of this class 33 | */ 34 | -(id)initWithRadius:(CGFloat)radius; 35 | 36 | 37 | #pragma mark - Values 38 | /** 39 | * @property Value at North/midnight (start) 40 | */ 41 | @property (nonatomic) float minimumValue; 42 | /** 43 | * @property Value at North/midnight (end) 44 | */ 45 | @property (nonatomic) float maximumValue; 46 | /** 47 | * @property Current value between North/midnight (start) and North/midnight (end) - clockwise direction 48 | */ 49 | @property (nonatomic) float currentValue; 50 | 51 | 52 | #pragma mark - Labels 53 | /** 54 | * @property BOOL indicating whether values snap to nearest label 55 | */ 56 | @property (nonatomic) BOOL snapToLabels; 57 | /** 58 | * Note: The LAST label will appear at North/midnight 59 | * The FIRST label will appear at the first interval after North/midnight 60 | * 61 | * @property NSArray of strings used to render labels at regular intervals within the circle 62 | */ 63 | @property (nonatomic, strong) NSArray *innerMarkingLabels; 64 | 65 | 66 | #pragma mark - Visual Customisation 67 | /** 68 | * @property Width of the line to draw for slider 69 | */ 70 | @property (nonatomic) int lineWidth; 71 | /** 72 | * @property Color of filled portion of line (from North/midnight start to currentValue) 73 | */ 74 | @property (nonatomic, strong) UIColor* filledColor; 75 | /** 76 | * @property Color of unfilled portion of line (from currentValue to North/midnight end) 77 | */ 78 | @property (nonatomic, strong) UIColor* unfilledColor; 79 | /** 80 | * Note: If this property is not set, filledColor will be used. 81 | * If handleType is semiTransparent*, specified color will override this property. 82 | * 83 | * @property Color of the handle 84 | */ 85 | @property (nonatomic, strong) UIColor* handleColor; 86 | /** 87 | * @property Font of the inner marking labels within the circle 88 | */ 89 | @property (nonatomic, strong) UIFont* labelFont; 90 | /** 91 | * @property Color of the inner marking labels within the circle 92 | */ 93 | @property (nonatomic, strong) UIColor* labelColor; 94 | /** 95 | * Note: A negative value will move the label closer to the center. A positive value will move the label closer to the circumference 96 | * @property Value with which to displace all labels along radial line from center to slider circumference. 97 | */ 98 | @property (nonatomic) CGFloat labelDisplacement; 99 | /** 100 | * @property Type of the handle to display to represent draggable current value 101 | */ 102 | @property (nonatomic) CircularSliderHandleType handleType; 103 | 104 | @end 105 | -------------------------------------------------------------------------------- /ios/EFCircularSlider/EFCircularTrig.h: -------------------------------------------------------------------------------- 1 | // 2 | // EFCircularTrig.h 3 | // 4 | // 5 | // Created by Eliot Fowler on 12/3/13. 6 | // Copyright (c) 2013 Eliot Fowler. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | /** 13 | * Helper class that provides interfaces for calculations involving trigonometry. 14 | * Also includes function for drawing arcs. 15 | */ 16 | @interface EFCircularTrig : NSObject 17 | 18 | /** 19 | * Determines the angle between two points on a circle 20 | * 21 | * @param fromPoint Point on the circle circumference 22 | * @param toPoint Point on the circle circumference 23 | * 24 | * @return Angle in degrees between the two points, relative to North as 0 degrees (clockwise) 25 | */ 26 | +(CGFloat) angleRelativeToNorthFromPoint:(CGPoint)fromPoint 27 | toPoint:(CGPoint)toPoint; 28 | 29 | /** 30 | * Determine the coordinates of a point on a circle at a given angle 31 | * 32 | * @param radius Radius of the circle 33 | * @param angleFromNorth Angle from North as 0 degrees (clockwise) 34 | * 35 | * @return Point on the circle circumference 36 | */ 37 | +(CGPoint)pointOnRadius:(CGFloat)radius 38 | atAngleFromNorth:(CGFloat)angleFromNorth; 39 | 40 | /** 41 | * Draw a filled circle using current context settings 42 | * 43 | * @param ctx Graphics context within which to fill a circle 44 | * @param center Center of the circle to draw 45 | * @param radius Radius of the circle to draw 46 | */ 47 | +(void) drawFilledCircleInContext:(CGContextRef)ctx 48 | center:(CGPoint)center 49 | radius:(CGFloat)radius; 50 | 51 | /** 52 | * Draw an empty circle with a variable line width using current context settings 53 | * 54 | * @param ctx Graphics context within which to fill a circle 55 | * @param center Center of the circle to draw 56 | * @param radius Radius of the circle to draw 57 | * @param lineWidth Width of line to draw around circle (centered on radius) 58 | */ 59 | +(void) drawUnfilledCircleInContext:(CGContextRef)ctx 60 | center:(CGPoint)center 61 | radius:(CGFloat)radius 62 | lineWidth:(CGFloat)lineWidth; 63 | 64 | /** 65 | * Draw an unfilled arc (ie partial circle) with a variable line width using current context settings 66 | * 67 | * @param ctx Graphics context within which to fill a circle 68 | * @param center Center of the circle to draw 69 | * @param radius Radius of the circle to draw 70 | * @param lineWidth Width of line to draw around circle (centered on radius) 71 | * @param fromAngleFromNorth Angle in degrees to draw arc from (clockwise) 72 | * @param toAngleFromNorth Angle in degrees to draw arc to (clockwise) 73 | */ 74 | +(void) drawUnfilledArcInContext:(CGContextRef)ctx 75 | center:(CGPoint)center 76 | radius:(CGFloat)radius 77 | lineWidth:(CGFloat)lineWidth 78 | fromAngleFromNorth:(CGFloat)fromAngleFromNorth 79 | toAngleFromNorth:(CGFloat)toAngleFromNorth; 80 | 81 | /** 82 | * Calculates how many degrees an arc spans along the circumference of a circle 83 | * 84 | * @param arcLength Length of arc segment along circle circumference 85 | * @param radius Radius of circle whose circumference arc sits upon 86 | * 87 | * @return Degrees from start of arc to end of arc along circle's circumference 88 | */ 89 | +(CGFloat) degreesForArcLength:(CGFloat)arcLength 90 | onCircleWithRadius:(CGFloat)radius; 91 | 92 | /** 93 | * Given an unfilled arc or circle, determine width from arc center to outside edge of line 94 | * 95 | * @param radius Radius of the arc 96 | * @param lineWidth Width of line drawn around arc 97 | * 98 | * @return Distance from center to outer edge of unfilled arc 99 | */ 100 | +(CGFloat) outerRadiuOfUnfilledArcWithRadius:(CGFloat)radius 101 | lineWidth:(CGFloat)lineWidth; 102 | 103 | /** 104 | * Given an unfilled arc or circle, determine width from arc center to inside edge of line 105 | * 106 | * @param radius Radius of the arc 107 | * @param lineWidth Width of line drawn around arc 108 | * 109 | * @return Distance from center to inner edge of unfilled arc 110 | */ 111 | +(CGFloat)innerRadiusOfUnfilledArcWithRadius:(CGFloat)radius 112 | lineWidth:(CGFloat)lineWidth; 113 | 114 | @end 115 | -------------------------------------------------------------------------------- /android/src/de/marcelpociot/circularslider/View.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Appcelerator Titanium Mobile 3 | * Copyright (c) 2009-2012 by Appcelerator, Inc. All Rights Reserved. 4 | * Licensed under the terms of the Apache Public License 5 | * Please see the LICENSE included with this distribution for details. 6 | * 7 | */ 8 | 9 | package de.marcelpociot.circularslider; 10 | 11 | import java.util.HashMap; 12 | 13 | import org.appcelerator.kroll.KrollDict; 14 | import org.appcelerator.kroll.KrollProxy; 15 | import org.appcelerator.kroll.common.Log; 16 | import org.appcelerator.titanium.proxy.TiViewProxy; 17 | import org.appcelerator.titanium.util.TiConvert; 18 | import org.appcelerator.titanium.view.TiUIView; 19 | 20 | import de.marcelpociot.circularslider.CircularSeekBar.OnSeekChangeListener; 21 | 22 | public class View extends TiUIView { 23 | // Standard Debugging variables 24 | private static final String LCAT = "TiCircularSliderModule"; 25 | 26 | private static final String PROPERTY_VALUE = "value"; 27 | private static final String PROPERTY_MIN_VALUE = "minimumValue"; 28 | private static final String PROPERTY_MAX_VALUE = "maximumValue"; 29 | private static final String PROPERTY_LINE_WIDTH = "lineWidth"; 30 | private static final String PROPERTY_COLOR_FILLED = "filledColor"; 31 | private static final String PROPERTY_COLOR_UNFILLED = "unfilledColor"; 32 | 33 | public View(TiViewProxy proxy) { 34 | super(proxy); 35 | 36 | Log.d(LCAT, "[VIEW LIFECYCLE EVENT] view"); 37 | 38 | CircularSeekBar csb = new CircularSeekBar(proxy.getActivity()); 39 | 40 | csb.setSeekBarChangeListener(new OnSeekChangeListener() { 41 | 42 | @Override 43 | public void onProgressChange(CircularSeekBar view, int newProgress) { 44 | Log.d(LCAT, 45 | "Progress:" + view.getProgress() + "/" 46 | + view.getMaxProgress()); 47 | notifyOfChange(view.getProgress()); 48 | } 49 | }); 50 | 51 | setNativeView(csb); 52 | 53 | } 54 | 55 | // The view is automatically registered as a model listener when the view 56 | // is realized by the view proxy. That means that the processProperties 57 | // method will be called during creation and that propertiesChanged and 58 | // propertyChanged will be called when properties are changed on the proxy. 59 | 60 | @Override 61 | public void processProperties(KrollDict props) { 62 | super.processProperties(props); 63 | 64 | CircularSeekBar csb = (CircularSeekBar) getNativeView(); 65 | 66 | if (props.containsKey(PROPERTY_MIN_VALUE)) { 67 | int min = TiConvert.toInt(props.get(PROPERTY_MIN_VALUE)); 68 | csb.setMinProgress(min); 69 | } 70 | 71 | if (props.containsKey(PROPERTY_MAX_VALUE)) { 72 | int max = TiConvert.toInt(props.getInt(PROPERTY_MAX_VALUE)); 73 | if (max >= csb.getMinProgress()) { 74 | csb.setMaxProgress(max); 75 | } else { 76 | Log.e(LCAT, "Maximum value must be greater than minimum value."); 77 | if (csb.getMaxProgress() < csb.getMinProgress()) { 78 | csb.setMaxProgress(csb.getMinProgress() + 1); 79 | } 80 | } 81 | } 82 | 83 | if (props.containsKey(PROPERTY_VALUE)) { 84 | csb.setProgress(TiConvert.toInt(props.get(PROPERTY_VALUE))); 85 | } 86 | 87 | if (props.containsKey(PROPERTY_LINE_WIDTH)) { 88 | csb.setBarWidth(TiConvert.toInt(props.get(PROPERTY_LINE_WIDTH))); 89 | } 90 | 91 | if (props.containsKey(PROPERTY_COLOR_FILLED)) { 92 | csb.setProgressColor(TiConvert.toColor(props 93 | .getString(PROPERTY_COLOR_FILLED))); 94 | } 95 | 96 | if (props.containsKey(PROPERTY_COLOR_UNFILLED)) { 97 | csb.setRingBackgroundColor(TiConvert.toColor(props 98 | .getString(PROPERTY_COLOR_UNFILLED))); 99 | } 100 | 101 | Log.d(LCAT, "[VIEW LIFECYCLE EVENT] processProperties " + props); 102 | 103 | } 104 | 105 | @Override 106 | public void propertyChanged(String key, Object oldValue, Object newValue, 107 | KrollProxy proxy) { 108 | // This method is called whenever a proxy property value is updated. 109 | // Note that this 110 | // method is only called if the new value is different than the current 111 | // value. 112 | 113 | super.propertyChanged(key, oldValue, newValue, proxy); 114 | 115 | Log.d(LCAT, "[VIEW LIFECYCLE EVENT] propertyChanged: " + key + ' ' 116 | + oldValue + ' ' + newValue); 117 | } 118 | 119 | private void notifyOfChange(int newValue) { 120 | // The event listeners for a view are actually attached to the view 121 | // proxy. 122 | // You must reference 'proxy' to get the proxy for this view. 123 | 124 | Log.d(LCAT, "[VIEW LIFECYCLE EVENT] notifyOfValueChange"); 125 | 126 | if (proxy.hasListeners("change")) { 127 | HashMap hm = new HashMap(); 128 | hm.put("value", newValue); 129 | proxy.fireEvent("change", hm); 130 | } 131 | } 132 | 133 | } 134 | -------------------------------------------------------------------------------- /ios/Classes/DeMarcelpociotCircularsliderView.m: -------------------------------------------------------------------------------- 1 | /** 2 | * Appcelerator Titanium Mobile 3 | * Copyright (c) 2009-2013 by Appcelerator, Inc. All Rights Reserved. 4 | * Licensed under the terms of the Apache Public License 5 | * Please see the LICENSE included with this distribution for details. 6 | */ 7 | 8 | #import "DeMarcelpociotCircularsliderView.h" 9 | 10 | @implementation DeMarcelpociotCircularsliderView 11 | 12 | -(EFCircularSlider*)sliderView 13 | { 14 | if( sliderView == nil ) 15 | { 16 | NSLog(@"INITIALIZING VIEW %@",[self frame]); 17 | sliderView = [[EFCircularSlider alloc] initWithFrame:[self frame]]; 18 | [self addSubview:sliderView]; 19 | [sliderView addTarget:self.proxy action:@selector(valueChanged:) forControlEvents:UIControlEventValueChanged]; 20 | [sliderView addTarget:self.proxy action:@selector(touchStarted:) forControlEvents:UIControlEventTouchDown]; 21 | [sliderView addTarget:self.proxy action:@selector(touchEnded:) forControlEvents:UIControlEventTouchUpInside]; 22 | } 23 | return sliderView; 24 | } 25 | 26 | -(void)frameSizeChanged:(CGRect)frame bounds:(CGRect)bounds 27 | { 28 | NSLog(@"[VIEW LIFECYCLE EVENT] frameSizeChanged"); 29 | 30 | if (sliderView != nil) { 31 | 32 | // You must call the special method 'setView:positionRect' against 33 | // the TiUtils helper class. This method will correctly layout your 34 | // child view within the correct layout boundaries of the new bounds 35 | // of your view. 36 | [TiUtils setView:sliderView positionRect:bounds]; 37 | EFCircularSlider *oldSlider = sliderView; 38 | [sliderView removeFromSuperview]; 39 | sliderView = [[EFCircularSlider alloc] initWithFrame:bounds]; 40 | [self addSubview:sliderView]; 41 | [sliderView setMinimumValue:oldSlider.minimumValue]; 42 | [sliderView setMaximumValue:oldSlider.maximumValue]; 43 | [sliderView setLineWidth:oldSlider.lineWidth]; 44 | [sliderView setHandleColor:oldSlider.handleColor]; 45 | [sliderView setUnfilledColor:oldSlider.unfilledColor]; 46 | [sliderView setFilledColor:oldSlider.filledColor]; 47 | 48 | [sliderView setLabelFont:oldSlider.labelFont]; 49 | [sliderView setLabelColor:oldSlider.labelColor]; 50 | [sliderView setLabelDisplacement:oldSlider.labelDisplacement]; 51 | 52 | // Event: "change" 53 | [sliderView addTarget:self.proxy action:@selector(valueChanged:) forControlEvents:UIControlEventValueChanged]; 54 | 55 | // Event: "touchstart" 56 | [sliderView addTarget:self.proxy action:@selector(touchStarted:) forControlEvents:UIControlEventTouchDown]; 57 | 58 | // Event: "touchend" 59 | [sliderView addTarget:self.proxy action:@selector(touchEnded:) forControlEvents:UIControlEventTouchUpInside]; 60 | } 61 | } 62 | 63 | -(void)setMinimumValue_:(id)minimum 64 | { 65 | [[self sliderView] setMinimumValue:[TiUtils floatValue:minimum def:0.0f]]; 66 | } 67 | 68 | -(void)setMaximumValue_:(id)maximum 69 | { 70 | [[self sliderView] setMaximumValue:[TiUtils floatValue:maximum def:100.0f]]; 71 | } 72 | 73 | -(void)setValue_:(id)value 74 | { 75 | [[self sliderView] setCurrentValue:[TiUtils floatValue:value def:0.0f]]; 76 | } 77 | 78 | -(void)setLineWidth_:(id)value 79 | { 80 | [[self sliderView] setLineWidth:[TiUtils floatValue:value def:0.0f]]; 81 | } 82 | 83 | -(void)setHandleColor_:(id)value 84 | { 85 | [[self sliderView] setHandleColor:[TiUtils colorValue:value].color]; 86 | } 87 | 88 | -(void)setUnfilledColor_:(id)value 89 | { 90 | [[self sliderView] setUnfilledColor:[TiUtils colorValue:value].color]; 91 | } 92 | 93 | -(void)setFilledColor_:(id)value 94 | { 95 | [[self sliderView] setFilledColor:[TiUtils colorValue:value].color]; 96 | } 97 | 98 | -(void)setInnerMarkingLabels_:(NSArray *)value 99 | { 100 | [[self sliderView] setInnerMarkingLabels:value]; 101 | } 102 | 103 | -(void)setLabelFont_:(id)value 104 | { 105 | [[self sliderView] setLabelFont:[TiUtils fontValue:value].font]; 106 | } 107 | 108 | -(void)setLabelColor_:(id)value 109 | { 110 | [[self sliderView] setLabelColor:[TiUtils colorValue:value].color]; 111 | } 112 | 113 | -(void)setLabelDisplacement_:(id)value 114 | { 115 | [[self sliderView] setLabelDisplacement:[TiUtils floatValue:value]]; 116 | } 117 | 118 | MAKE_SYSTEM_PROP(BIG_CIRCLE, CircularSliderHandleTypeBigCircle); 119 | MAKE_SYSTEM_PROP(SEMI_TRANSPARENT_WHITE_CIRCLE, CircularSliderHandleTypeSemiTransparentWhiteCircle); 120 | MAKE_SYSTEM_PROP(SEMI_TRANSPARENT_BLACK_CIRCLE, CircularSliderHandleTypeSemiTransparentBlackCircle); 121 | MAKE_SYSTEM_PROP(DOUBLE_CIRCLE_OPEN_CENTER, CircularSliderHandleTypeDoubleCircleWithOpenCenter); 122 | MAKE_SYSTEM_PROP(DOUBLE_CIRCLE_CLOSED_CENTER, CircularSliderHandleTypeDoubleCircleWithClosedCenter); 123 | 124 | -(void)setHandleType_:(id)value 125 | { 126 | NSLog(@"Handle Type: %@",value); 127 | [[self sliderView] setHandleType:value]; 128 | } 129 | 130 | 131 | @end 132 | -------------------------------------------------------------------------------- /ios/EFCircularSlider/EFCircularTrig.m: -------------------------------------------------------------------------------- 1 | // 2 | // EFCircularTrig.m 3 | // 4 | // 5 | // Created by Eliot Fowler on 12/3/13. 6 | // Copyright (c) 2013 Eliot Fowler. All rights reserved. 7 | // 8 | 9 | #import "EFCircularTrig.h" 10 | 11 | /** 12 | * Macro for converting radian degrees from cartesian reference (0 radians is along X axis) 13 | * to 'compass style' reference (0 radians is along Y axis (ie North on a compass)). 14 | * 15 | * @param rad Radian degrees to convert from Cartesian reference 16 | * 17 | * @return Radian Degrees in 'Compass' reference 18 | */ 19 | #define CartesianToCompass(rad) ( rad + M_PI/2 ) 20 | /** 21 | * Macro for converting radian degrees from 'compass style' reference (0 radians is along Y axis (ie North on a compass)) 22 | * to cartesian reference (0 radians is along X axis). 23 | * 24 | * @param rad Radian degrees to convert from 'Compass' reference 25 | * 26 | * @return Radian Degrees in Cartesian reference 27 | */ 28 | #define CompassToCartesian(rad) ( rad - M_PI/2 ) 29 | #define ToRad(deg) ( (M_PI * (deg)) / 180.0 ) 30 | #define ToDeg(rad) ( (180.0 * (rad)) / M_PI ) 31 | #define SQR(x) ( (x) * (x) ) 32 | 33 | @implementation EFCircularTrig 34 | 35 | +(CGFloat) angleRelativeToNorthFromPoint:(CGPoint)fromPoint 36 | toPoint:(CGPoint)toPoint 37 | { 38 | CGPoint v = CGPointMake(toPoint.x-fromPoint.x,toPoint.y-fromPoint.y); 39 | float vmag = sqrt(SQR(v.x) + SQR(v.y)); 40 | v.x /= vmag; 41 | v.y /= vmag; 42 | double cartesianRadians = atan2(v.y,v.x); 43 | // Need to convert from cartesian style radians to compass style 44 | double compassRadians = CartesianToCompass(cartesianRadians); 45 | if (compassRadians < 0) 46 | { 47 | compassRadians += (2 * M_PI); 48 | } 49 | NSAssert(compassRadians >= 0 && compassRadians <= 2 * M_PI, @"angleRelativeToNorth should be always positive"); 50 | return ToDeg(compassRadians); 51 | } 52 | 53 | +(CGPoint)pointOnRadius:(CGFloat)radius 54 | atAngleFromNorth:(CGFloat)angleFromNorth 55 | { 56 | //Get the point on the circle for this angle 57 | CGPoint result; 58 | // Need to adjust from 'compass' style angle to cartesian angle 59 | float cartesianAngle = CompassToCartesian(ToRad(angleFromNorth)); 60 | result.y = round(radius * sin(cartesianAngle)) ; 61 | result.x = round(radius * cos(cartesianAngle)); 62 | 63 | return result; 64 | } 65 | 66 | #pragma mark - Draw arcs 67 | 68 | +(void) drawFilledCircleInContext:(CGContextRef)ctx 69 | center:(CGPoint)center 70 | radius:(CGFloat)radius 71 | { 72 | CGContextFillEllipseInRect(ctx, CGRectMake(center.x - (radius), 73 | center.y - (radius), 74 | 2 * radius, 75 | 2 * radius)); 76 | } 77 | 78 | +(void) drawUnfilledCircleInContext:(CGContextRef)ctx 79 | center:(CGPoint)center 80 | radius:(CGFloat)radius 81 | lineWidth:(CGFloat)lineWidth 82 | { 83 | [self drawUnfilledArcInContext:ctx center:center radius:radius lineWidth:lineWidth fromAngleFromNorth:0 toAngleFromNorth:360]; // 0 - 360 is full circle 84 | } 85 | 86 | +(void) drawUnfilledArcInContext:(CGContextRef)ctx 87 | center:(CGPoint)center 88 | radius:(CGFloat)radius 89 | lineWidth:(CGFloat)lineWidth 90 | fromAngleFromNorth:(CGFloat)fromAngleFromNorth 91 | toAngleFromNorth:(CGFloat)toAngleFromNorth 92 | { 93 | float cartesianFromAngle = CompassToCartesian(ToRad(fromAngleFromNorth)); 94 | float cartesianToAngle = CompassToCartesian(ToRad(toAngleFromNorth)); 95 | 96 | CGContextAddArc(ctx, 97 | center.x, // arc start point x 98 | center.y, // arc start point y 99 | radius, // arc radius from center 100 | cartesianFromAngle, cartesianToAngle, 101 | 0); // iOS flips the y coordinate so anti-clockwise (specified here by 0) becomes clockwise (desired)! 102 | 103 | CGContextSetLineWidth(ctx, lineWidth); 104 | CGContextSetLineCap(ctx, kCGLineCapButt); 105 | CGContextDrawPath(ctx, kCGPathStroke); 106 | } 107 | 108 | +(CGFloat) degreesForArcLength:(CGFloat)arcLength 109 | onCircleWithRadius:(CGFloat)radius 110 | { 111 | float totalCircumference = 2 * M_PI * radius; 112 | 113 | float arcRatioToCircumference = arcLength / totalCircumference; 114 | 115 | return 360 * arcRatioToCircumference; // If arcLength is exactly half circumference, that is exactly half a circle in degrees 116 | } 117 | 118 | 119 | #pragma mark - Calculate radii of arcs with line widths 120 | /* 121 | * For an unfilled arc. 122 | * 123 | * Radius of outer arc (center to outside edge) | --------- 124 | * = radius + 0.5 * lineWidth | +++++++++++++++ 125 | * | /++/++++ --- ++++\++\ 126 | * Radius of inner arc (center to inside edge) | /++/++/ \++\++\ 127 | * = radius - (0.5 * lineWidth) | |++|++| . |++|++| 128 | * outer edge^ ^-radius-^ ^inner edge 129 | * 130 | */ 131 | +(CGFloat) outerRadiuOfUnfilledArcWithRadius:(CGFloat)radius 132 | lineWidth:(CGFloat)lineWidth 133 | { 134 | return radius + 0.5 * lineWidth; 135 | } 136 | 137 | +(CGFloat)innerRadiusOfUnfilledArcWithRadius:(CGFloat)radius 138 | lineWidth:(CGFloat)lineWidth 139 | { 140 | return radius - 0.5 * lineWidth; 141 | } 142 | 143 | @end 144 | -------------------------------------------------------------------------------- /ios/build.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # Appcelerator Titanium Module Packager 4 | # 5 | # 6 | import os, subprocess, sys, glob, string 7 | import zipfile 8 | from datetime import date 9 | 10 | cwd = os.path.abspath(os.path.dirname(sys._getframe(0).f_code.co_filename)) 11 | os.chdir(cwd) 12 | required_module_keys = ['name','version','moduleid','description','copyright','license','copyright','platform','minsdk'] 13 | module_defaults = { 14 | 'description':'My module', 15 | 'author': 'Your Name', 16 | 'license' : 'Specify your license', 17 | 'copyright' : 'Copyright (c) %s by Your Company' % str(date.today().year), 18 | } 19 | module_license_default = "TODO: place your license here and we'll include it in the module distribution" 20 | 21 | def find_sdk(config): 22 | sdk = config['TITANIUM_SDK'] 23 | return os.path.expandvars(os.path.expanduser(sdk)) 24 | 25 | def replace_vars(config,token): 26 | idx = token.find('$(') 27 | while idx != -1: 28 | idx2 = token.find(')',idx+2) 29 | if idx2 == -1: break 30 | key = token[idx+2:idx2] 31 | if not config.has_key(key): break 32 | token = token.replace('$(%s)' % key, config[key]) 33 | idx = token.find('$(') 34 | return token 35 | 36 | 37 | def read_ti_xcconfig(): 38 | contents = open(os.path.join(cwd,'titanium.xcconfig')).read() 39 | config = {} 40 | for line in contents.splitlines(False): 41 | line = line.strip() 42 | if line[0:2]=='//': continue 43 | idx = line.find('=') 44 | if idx > 0: 45 | key = line[0:idx].strip() 46 | value = line[idx+1:].strip() 47 | config[key] = replace_vars(config,value) 48 | return config 49 | 50 | def generate_doc(config): 51 | docdir = os.path.join(cwd,'documentation') 52 | if not os.path.exists(docdir): 53 | print "Couldn't find documentation file at: %s" % docdir 54 | return None 55 | 56 | try: 57 | import markdown2 as markdown 58 | except ImportError: 59 | import markdown 60 | documentation = [] 61 | for file in os.listdir(docdir): 62 | if file in ignoreFiles or os.path.isdir(os.path.join(docdir, file)): 63 | continue 64 | md = open(os.path.join(docdir,file)).read() 65 | html = markdown.markdown(md) 66 | documentation.append({file:html}); 67 | return documentation 68 | 69 | def compile_js(manifest,config): 70 | js_file = os.path.join(cwd,'assets','de.marcelpociot.circularslider.js') 71 | if not os.path.exists(js_file): return 72 | 73 | from compiler import Compiler 74 | try: 75 | import json 76 | except: 77 | import simplejson as json 78 | 79 | compiler = Compiler(cwd, manifest['moduleid'], manifest['name'], 'commonjs') 80 | root_asset, module_assets = compiler.compile_module() 81 | 82 | root_asset_content = """ 83 | %s 84 | 85 | return filterDataInRange([NSData dataWithBytesNoCopy:data length:sizeof(data) freeWhenDone:NO], ranges[0]); 86 | """ % root_asset 87 | 88 | module_asset_content = """ 89 | %s 90 | 91 | NSNumber *index = [map objectForKey:path]; 92 | if (index == nil) { 93 | return nil; 94 | } 95 | return filterDataInRange([NSData dataWithBytesNoCopy:data length:sizeof(data) freeWhenDone:NO], ranges[index.integerValue]); 96 | """ % module_assets 97 | 98 | from tools import splice_code 99 | 100 | assets_router = os.path.join(cwd,'Classes','DeMarcelpociotCircularsliderModuleAssets.m') 101 | splice_code(assets_router, 'asset', root_asset_content) 102 | splice_code(assets_router, 'resolve_asset', module_asset_content) 103 | 104 | # Generate the exports after crawling all of the available JS source 105 | exports = open('metadata.json','w') 106 | json.dump({'exports':compiler.exports }, exports) 107 | exports.close() 108 | 109 | def die(msg): 110 | print msg 111 | sys.exit(1) 112 | 113 | def warn(msg): 114 | print "[WARN] %s" % msg 115 | 116 | def validate_license(): 117 | c = open(os.path.join(cwd,'LICENSE')).read() 118 | if c.find(module_license_default)!=-1: 119 | warn('please update the LICENSE file with your license text before distributing') 120 | 121 | def validate_manifest(): 122 | path = os.path.join(cwd,'manifest') 123 | f = open(path) 124 | if not os.path.exists(path): die("missing %s" % path) 125 | manifest = {} 126 | for line in f.readlines(): 127 | line = line.strip() 128 | if line[0:1]=='#': continue 129 | if line.find(':') < 0: continue 130 | key,value = line.split(':') 131 | manifest[key.strip()]=value.strip() 132 | for key in required_module_keys: 133 | if not manifest.has_key(key): die("missing required manifest key '%s'" % key) 134 | if module_defaults.has_key(key): 135 | defvalue = module_defaults[key] 136 | curvalue = manifest[key] 137 | if curvalue==defvalue: warn("please update the manifest key: '%s' to a non-default value" % key) 138 | return manifest,path 139 | 140 | ignoreFiles = ['.DS_Store','.gitignore','libTitanium.a','titanium.jar','README'] 141 | ignoreDirs = ['.DS_Store','.svn','.git','CVSROOT'] 142 | 143 | def zip_dir(zf,dir,basepath,ignoreExt=[]): 144 | if not os.path.exists(dir): return 145 | for root, dirs, files in os.walk(dir): 146 | for name in ignoreDirs: 147 | if name in dirs: 148 | dirs.remove(name) # don't visit ignored directories 149 | for file in files: 150 | if file in ignoreFiles: continue 151 | e = os.path.splitext(file) 152 | if len(e) == 2 and e[1] in ignoreExt: continue 153 | from_ = os.path.join(root, file) 154 | to_ = from_.replace(dir, '%s/%s'%(basepath,dir), 1) 155 | zf.write(from_, to_) 156 | 157 | def glob_libfiles(): 158 | files = [] 159 | for libfile in glob.glob('build/**/*.a'): 160 | if libfile.find('Release-')!=-1: 161 | files.append(libfile) 162 | return files 163 | 164 | def build_module(manifest,config): 165 | from tools import ensure_dev_path 166 | ensure_dev_path() 167 | 168 | rc = os.system("xcodebuild -sdk iphoneos -configuration Release") 169 | if rc != 0: 170 | die("xcodebuild failed") 171 | rc = os.system("xcodebuild -sdk iphonesimulator -configuration Release") 172 | if rc != 0: 173 | die("xcodebuild failed") 174 | # build the merged library using lipo 175 | moduleid = manifest['moduleid'] 176 | libpaths = '' 177 | for libfile in glob_libfiles(): 178 | libpaths+='%s ' % libfile 179 | 180 | os.system("lipo %s -create -output build/lib%s.a" %(libpaths,moduleid)) 181 | 182 | def package_module(manifest,mf,config): 183 | name = manifest['name'].lower() 184 | moduleid = manifest['moduleid'].lower() 185 | version = manifest['version'] 186 | modulezip = '%s-iphone-%s.zip' % (moduleid,version) 187 | if os.path.exists(modulezip): os.remove(modulezip) 188 | zf = zipfile.ZipFile(modulezip, 'w', zipfile.ZIP_DEFLATED) 189 | modulepath = 'modules/iphone/%s/%s' % (moduleid,version) 190 | zf.write(mf,'%s/manifest' % modulepath) 191 | libname = 'lib%s.a' % moduleid 192 | zf.write('build/%s' % libname, '%s/%s' % (modulepath,libname)) 193 | docs = generate_doc(config) 194 | if docs!=None: 195 | for doc in docs: 196 | for file, html in doc.iteritems(): 197 | filename = string.replace(file,'.md','.html') 198 | zf.writestr('%s/documentation/%s'%(modulepath,filename),html) 199 | zip_dir(zf,'assets',modulepath,['.pyc','.js']) 200 | zip_dir(zf,'example',modulepath,['.pyc']) 201 | zip_dir(zf,'platform',modulepath,['.pyc','.js']) 202 | zf.write('LICENSE','%s/LICENSE' % modulepath) 203 | zf.write('module.xcconfig','%s/module.xcconfig' % modulepath) 204 | exports_file = 'metadata.json' 205 | if os.path.exists(exports_file): 206 | zf.write(exports_file, '%s/%s' % (modulepath, exports_file)) 207 | zf.close() 208 | 209 | 210 | if __name__ == '__main__': 211 | manifest,mf = validate_manifest() 212 | validate_license() 213 | config = read_ti_xcconfig() 214 | 215 | sdk = find_sdk(config) 216 | sys.path.insert(0,os.path.join(sdk,'iphone')) 217 | sys.path.append(os.path.join(sdk, "common")) 218 | 219 | compile_js(manifest,config) 220 | build_module(manifest,config) 221 | package_module(manifest,mf,config) 222 | sys.exit(0) 223 | 224 | -------------------------------------------------------------------------------- /android/src/de/marcelpociot/circularslider/CircularSeekBar.java: -------------------------------------------------------------------------------- 1 | package de.marcelpociot.circularslider; 2 | 3 | /** 4 | * @author Raghav Sood 5 | * @version 1 6 | * @date 26 January, 2013 7 | */ 8 | 9 | import android.content.Context; 10 | import android.graphics.Bitmap; 11 | import android.graphics.BitmapFactory; 12 | import android.graphics.Canvas; 13 | import android.graphics.Color; 14 | import android.graphics.Paint; 15 | import android.graphics.RectF; 16 | import android.util.AttributeSet; 17 | import android.view.MotionEvent; 18 | import android.view.View; 19 | 20 | /** 21 | * The Class CircularSeekBar. 22 | */ 23 | public class CircularSeekBar extends View { 24 | 25 | /** The context */ 26 | private Context mContext; 27 | 28 | /** The listener to listen for changes */ 29 | private OnSeekChangeListener mListener; 30 | 31 | /** The color of the progress ring */ 32 | private Paint circleColor; 33 | 34 | /** the color of the inside circle. Acts as background color */ 35 | private Paint innerColor; 36 | 37 | /** The progress circle ring background */ 38 | private Paint circleRing; 39 | 40 | /** The angle of progress */ 41 | private int angle = 0; 42 | 43 | /** The start angle (12 O'clock */ 44 | private int startAngle = 270; 45 | 46 | /** The width of the progress ring */ 47 | private int barWidth = 5; 48 | 49 | /** The width of the view */ 50 | private int width; 51 | 52 | /** The height of the view */ 53 | private int height; 54 | 55 | /** The padding for the view */ 56 | private int padding; 57 | 58 | /** The minimum progress amount */ 59 | private int minProgress = 0; 60 | 61 | /** The maximum progress amount */ 62 | private int maxProgress = 100; 63 | 64 | /** The current progress */ 65 | private int progress; 66 | 67 | /** The progress percent */ 68 | private int progressPercent; 69 | 70 | /** The radius of the inner circle */ 71 | private float innerRadius; 72 | 73 | /** The radius of the outer circle */ 74 | private float outerRadius; 75 | 76 | /** The circle's center X coordinate */ 77 | private float cx; 78 | 79 | /** The circle's center Y coordinate */ 80 | private float cy; 81 | 82 | /** The left bound for the circle RectF */ 83 | private float left; 84 | 85 | /** The right bound for the circle RectF */ 86 | private float right; 87 | 88 | /** The top bound for the circle RectF */ 89 | private float top; 90 | 91 | /** The bottom bound for the circle RectF */ 92 | private float bottom; 93 | 94 | /** The X coordinate for the top left corner of the marking drawable */ 95 | private float dx; 96 | 97 | /** The Y coordinate for the top left corner of the marking drawable */ 98 | private float dy; 99 | 100 | /** The X coordinate for 12 O'Clock */ 101 | private float startPointX; 102 | 103 | /** The Y coordinate for 12 O'Clock */ 104 | private float startPointY; 105 | 106 | /** 107 | * The X coordinate for the current position of the marker, pre adjustment 108 | * to center 109 | */ 110 | private float markPointX; 111 | 112 | /** 113 | * The Y coordinate for the current position of the marker, pre adjustment 114 | * to center 115 | */ 116 | private float markPointY; 117 | 118 | /** 119 | * The adjustment factor. This adds an adjustment of the specified size to 120 | * both sides of the progress bar, allowing touch events to be processed 121 | * more user friendlily (yes, I know that's not a word) 122 | */ 123 | private float adjustmentFactor = 100; 124 | 125 | /** The progress mark when the view isn't being progress modified */ 126 | private Bitmap progressMark; 127 | 128 | /** The progress mark when the view is being progress modified. */ 129 | private Bitmap progressMarkPressed; 130 | 131 | /** The flag to see if view is pressed */ 132 | private boolean IS_PRESSED = false; 133 | 134 | /** 135 | * The flag to see if the setProgress() method was called from our own 136 | * View's setAngle() method, or externally by a user. 137 | */ 138 | private boolean CALLED_FROM_ANGLE = false; 139 | 140 | /** The rectangle containing our circles and arcs. */ 141 | private RectF rect = new RectF(); 142 | 143 | { 144 | mListener = new OnSeekChangeListener() { 145 | 146 | @Override 147 | public void onProgressChange(CircularSeekBar view, int newProgress) { 148 | 149 | } 150 | }; 151 | 152 | circleColor = new Paint(); 153 | innerColor = new Paint(); 154 | circleRing = new Paint(); 155 | 156 | circleColor.setColor(Color.parseColor("#ff33b5e5")); // Set default 157 | // progress 158 | // color to holo 159 | // blue. 160 | innerColor.setColor(Color.WHITE); 161 | circleRing.setColor(Color.GRAY); 162 | 163 | circleColor.setAntiAlias(true); 164 | innerColor.setAntiAlias(true); 165 | circleRing.setAntiAlias(true); 166 | 167 | circleColor.setStrokeWidth(5); 168 | innerColor.setStrokeWidth(5); 169 | circleRing.setStrokeWidth(5); 170 | 171 | circleColor.setStyle(Paint.Style.FILL); 172 | } 173 | 174 | /** 175 | * Instantiates a new circular seek bar. 176 | * 177 | * @param context 178 | * the context 179 | * @param attrs 180 | * the attrs 181 | * @param defStyle 182 | * the def style 183 | */ 184 | public CircularSeekBar(Context context, AttributeSet attrs, int defStyle) { 185 | super(context, attrs, defStyle); 186 | mContext = context; 187 | initDrawable(); 188 | } 189 | 190 | /** 191 | * Instantiates a new circular seek bar. 192 | * 193 | * @param context 194 | * the context 195 | * @param attrs 196 | * the attrs 197 | */ 198 | public CircularSeekBar(Context context, AttributeSet attrs) { 199 | super(context, attrs); 200 | mContext = context; 201 | initDrawable(); 202 | } 203 | 204 | /** 205 | * Instantiates a new circular seek bar. 206 | * 207 | * @param context 208 | * the context 209 | */ 210 | public CircularSeekBar(Context context) { 211 | super(context); 212 | mContext = context; 213 | initDrawable(); 214 | } 215 | 216 | /** 217 | * Inits the drawable. 218 | */ 219 | public void initDrawable() { 220 | 221 | progressMark = BitmapFactory.decodeResource( 222 | mContext.getResources(), 223 | mContext.getResources().getIdentifier( 224 | "scrubber_control_normal_holo", "drawable", 225 | mContext.getPackageName())); 226 | 227 | progressMarkPressed = BitmapFactory.decodeResource( 228 | mContext.getResources(), 229 | mContext.getResources().getIdentifier( 230 | "scrubber_control_pressed_holo", "drawable", 231 | mContext.getPackageName())); 232 | 233 | padding = progressMark.getHeight(); 234 | } 235 | 236 | /* 237 | * (non-Javadoc) 238 | * 239 | * @see android.view.View#onMeasure(int, int) 240 | */ 241 | @Override 242 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 243 | super.onMeasure(widthMeasureSpec, heightMeasureSpec); 244 | 245 | width = getWidth(); // Get View Width 246 | height = getHeight();// Get View Height 247 | 248 | int size = ((width > height) ? height : width) - 25; 249 | 250 | cx = width / 2; // Center X for circle 251 | cy = height / 2; // Center Y for circle 252 | outerRadius = (size - padding) / 2; // Radius of the outer circle 253 | 254 | innerRadius = outerRadius - barWidth; // Radius of the inner circle 255 | 256 | left = cx - outerRadius; // Calculate left bound of our rect 257 | right = cx + outerRadius;// Calculate right bound of our rect 258 | top = cy - outerRadius;// Calculate top bound of our rect 259 | bottom = cy + outerRadius;// Calculate bottom bound of our rect 260 | 261 | startPointX = cx; // 12 O'clock X coordinate 262 | startPointY = cy - outerRadius;// 12 O'clock Y coordinate 263 | markPointX = startPointX;// Initial locatino of the marker X coordinate 264 | markPointY = startPointY;// Initial locatino of the marker Y coordinate 265 | 266 | rect.set(left, top, right, bottom); // assign size to rect 267 | } 268 | 269 | /* 270 | * (non-Javadoc) 271 | * 272 | * @see android.view.View#onDraw(android.graphics.Canvas) 273 | */ 274 | @Override 275 | protected void onDraw(Canvas canvas) { 276 | dx = getXFromAngle(); 277 | dy = getYFromAngle(); 278 | 279 | canvas.drawCircle(cx, cy, outerRadius, circleRing); 280 | canvas.drawArc(rect, startAngle, angle, true, circleColor); 281 | canvas.drawCircle(cx, cy, innerRadius, innerColor); 282 | drawMarkerAtProgress(canvas); 283 | 284 | super.onDraw(canvas); 285 | } 286 | 287 | /** 288 | * Draw marker at the current progress point onto the given canvas. 289 | * 290 | * @param canvas 291 | * the canvas 292 | */ 293 | public void drawMarkerAtProgress(Canvas canvas) { 294 | if (IS_PRESSED) { 295 | canvas.drawBitmap(progressMarkPressed, dx, dy, null); 296 | } else { 297 | canvas.drawBitmap(progressMark, dx, dy, null); 298 | } 299 | } 300 | 301 | /** 302 | * Gets the X coordinate of the arc's end arm's point of intersection with 303 | * the circle 304 | * 305 | * @return the X coordinate 306 | */ 307 | public float getXFromAngle() { 308 | int size1 = progressMark.getWidth(); 309 | int size2 = progressMarkPressed.getWidth(); 310 | int adjust = (size1 > size2) ? size1 : size2; 311 | float x = markPointX - (adjust / 2); 312 | return x; 313 | } 314 | 315 | /** 316 | * Gets the Y coordinate of the arc's end arm's point of intersection with 317 | * the circle 318 | * 319 | * @return the Y coordinate 320 | */ 321 | public float getYFromAngle() { 322 | int size1 = progressMark.getHeight(); 323 | int size2 = progressMarkPressed.getHeight(); 324 | int adjust = (size1 > size2) ? size1 : size2; 325 | float y = markPointY - (adjust / 2); 326 | return y; 327 | } 328 | 329 | /** 330 | * Get the angle. 331 | * 332 | * @return the angle 333 | */ 334 | public int getAngle() { 335 | return angle; 336 | } 337 | 338 | /** 339 | * Set the angle. 340 | * 341 | * @param angle 342 | * the new angle 343 | */ 344 | public void setAngle(int angle) { 345 | this.angle = angle; 346 | float donePercent = (((float) this.angle) / 360) * 100; 347 | float progress = (donePercent / 100) 348 | * (getMaxProgress() - getMinProgress()) + getMinProgress(); 349 | setProgressPercent(Math.round(donePercent)); 350 | CALLED_FROM_ANGLE = true; 351 | setProgress(Math.round(progress)); 352 | } 353 | 354 | /** 355 | * Sets the seek bar change listener. 356 | * 357 | * @param listener 358 | * the new seek bar change listener 359 | */ 360 | public void setSeekBarChangeListener(OnSeekChangeListener listener) { 361 | mListener = listener; 362 | } 363 | 364 | /** 365 | * Gets the seek bar change listener. 366 | * 367 | * @return the seek bar change listener 368 | */ 369 | public OnSeekChangeListener getSeekBarChangeListener() { 370 | return mListener; 371 | } 372 | 373 | /** 374 | * Gets the bar width. 375 | * 376 | * @return the bar width 377 | */ 378 | public int getBarWidth() { 379 | return barWidth; 380 | } 381 | 382 | /** 383 | * Sets the bar width. 384 | * 385 | * @param barWidth 386 | * the new bar width 387 | */ 388 | public void setBarWidth(int barWidth) { 389 | this.barWidth = barWidth; 390 | } 391 | 392 | /** 393 | * The listener interface for receiving onSeekChange events. The class that 394 | * is interested in processing a onSeekChange event implements this 395 | * interface, and the object created with that class is registered with a 396 | * component using the component's 397 | * setSeekBarChangeListener(OnSeekChangeListener) method. When 398 | * the onSeekChange event occurs, that object's appropriate 399 | * method is invoked. 400 | * 401 | * @see OnSeekChangeEvent 402 | */ 403 | public interface OnSeekChangeListener { 404 | 405 | /** 406 | * On progress change. 407 | * 408 | * @param view 409 | * the view 410 | * @param newProgress 411 | * the new progress 412 | */ 413 | public void onProgressChange(CircularSeekBar view, int newProgress); 414 | } 415 | 416 | /** 417 | * Gets the max progress. 418 | * 419 | * @return the max progress 420 | */ 421 | public int getMaxProgress() { 422 | return maxProgress; 423 | } 424 | 425 | /** 426 | * Sets the max progress. 427 | * 428 | * @param maxProgress 429 | * the new max progress 430 | */ 431 | public void setMaxProgress(int maxProgress) { 432 | this.maxProgress = maxProgress; 433 | } 434 | 435 | /** 436 | * Gets the min progress. 437 | * 438 | * @return the min progress 439 | */ 440 | public int getMinProgress() { 441 | return minProgress; 442 | } 443 | 444 | /** 445 | * Sets the min progress. 446 | * 447 | * @param minProgress 448 | * the new min progress 449 | */ 450 | public void setMinProgress(int minProgress) { 451 | this.minProgress = minProgress; 452 | } 453 | 454 | /** 455 | * Gets the progress. 456 | * 457 | * @return the progress 458 | */ 459 | public int getProgress() { 460 | return progress; 461 | } 462 | 463 | /** 464 | * Sets the progress. 465 | * 466 | * @param progress 467 | * the new progress 468 | */ 469 | public void setProgress(int progress) { 470 | if (this.progress != progress) { 471 | this.progress = progress; 472 | if (!CALLED_FROM_ANGLE) { 473 | int newPercent = (this.progress * 100) 474 | / (this.maxProgress - this.minProgress); 475 | int newAngle = (newPercent * 360) / 100; 476 | this.setAngle(newAngle); 477 | this.setProgressPercent(newPercent); 478 | } 479 | this.invalidate(); 480 | mListener.onProgressChange(this, this.getProgress()); 481 | CALLED_FROM_ANGLE = false; 482 | } 483 | 484 | } 485 | 486 | /** 487 | * Gets the progress percent. 488 | * 489 | * @return the progress percent 490 | */ 491 | public int getProgressPercent() { 492 | return progressPercent; 493 | } 494 | 495 | /** 496 | * Sets the progress percent. 497 | * 498 | * @param progressPercent 499 | * the new progress percent 500 | */ 501 | public void setProgressPercent(int progressPercent) { 502 | this.progressPercent = progressPercent; 503 | } 504 | 505 | /** 506 | * Sets the ring background color. 507 | * 508 | * @param color 509 | * the new ring background color 510 | */ 511 | public void setRingBackgroundColor(int color) { 512 | circleRing.setColor(color); 513 | } 514 | 515 | /** 516 | * Sets the back ground color. 517 | * 518 | * @param color 519 | * the new back ground color 520 | */ 521 | public void setBackGroundColor(int color) { 522 | innerColor.setColor(color); 523 | } 524 | 525 | /** 526 | * Sets the progress color. 527 | * 528 | * @param color 529 | * the new progress color 530 | */ 531 | public void setProgressColor(int color) { 532 | circleColor.setColor(color); 533 | } 534 | 535 | /* 536 | * (non-Javadoc) 537 | * 538 | * @see android.view.View#onTouchEvent(android.view.MotionEvent) 539 | */ 540 | @Override 541 | public boolean onTouchEvent(MotionEvent event) { 542 | float x = event.getX(); 543 | float y = event.getY(); 544 | boolean up = false; 545 | switch (event.getAction()) { 546 | case MotionEvent.ACTION_DOWN: 547 | moved(x, y, up); 548 | break; 549 | case MotionEvent.ACTION_MOVE: 550 | moved(x, y, up); 551 | break; 552 | case MotionEvent.ACTION_UP: 553 | up = true; 554 | moved(x, y, up); 555 | break; 556 | } 557 | return true; 558 | } 559 | 560 | /** 561 | * Moved. 562 | * 563 | * @param x 564 | * the x 565 | * @param y 566 | * the y 567 | * @param up 568 | * the up 569 | */ 570 | private void moved(float x, float y, boolean up) { 571 | float distance = (float) Math.sqrt(Math.pow((x - cx), 2) 572 | + Math.pow((y - cy), 2)); 573 | if (distance < outerRadius + adjustmentFactor 574 | && distance > innerRadius - adjustmentFactor && !up) { 575 | IS_PRESSED = true; 576 | 577 | markPointX = (float) (cx + outerRadius 578 | * Math.cos(Math.atan2(x - cx, cy - y) - (Math.PI / 2))); 579 | markPointY = (float) (cy + outerRadius 580 | * Math.sin(Math.atan2(x - cx, cy - y) - (Math.PI / 2))); 581 | 582 | float degrees = (float) ((float) ((Math.toDegrees(Math.atan2( 583 | x - cx, cy - y)) + 360.0)) % 360.0); 584 | // and to make it count 0-360 585 | if (degrees < 0) { 586 | degrees += 2 * Math.PI; 587 | } 588 | 589 | setAngle(Math.round(degrees)); 590 | invalidate(); 591 | 592 | } else { 593 | IS_PRESSED = false; 594 | invalidate(); 595 | } 596 | 597 | } 598 | 599 | /** 600 | * Gets the adjustment factor. 601 | * 602 | * @return the adjustment factor 603 | */ 604 | public float getAdjustmentFactor() { 605 | return adjustmentFactor; 606 | } 607 | 608 | /** 609 | * Sets the adjustment factor. 610 | * 611 | * @param adjustmentFactor 612 | * the new adjustment factor 613 | */ 614 | public void setAdjustmentFactor(float adjustmentFactor) { 615 | this.adjustmentFactor = adjustmentFactor; 616 | } 617 | } -------------------------------------------------------------------------------- /ios/EFCircularSlider/EFCircularSlider.m: -------------------------------------------------------------------------------- 1 | // 2 | // EFCircularSlider.m 3 | // Awake 4 | // 5 | // Created by Eliot Fowler on 12/3/13. 6 | // Copyright (c) 2013 Eliot Fowler. All rights reserved. 7 | // 8 | 9 | #import "EFCircularSlider.h" 10 | #import 11 | #import "EFCircularTrig.h" 12 | 13 | 14 | @interface EFCircularSlider () 15 | 16 | @property (nonatomic) CGFloat radius; 17 | @property (nonatomic) int angleFromNorth; 18 | @property (nonatomic) BOOL moving; 19 | @property (nonatomic, strong) NSMutableDictionary *labelsWithPercents; 20 | 21 | @property (nonatomic, readonly) CGFloat handleWidth; 22 | @property (nonatomic, readonly) CGFloat innerLabelRadialDistanceFromCircumference; 23 | @property (nonatomic, readonly) CGPoint centerPoint; 24 | 25 | @property (nonatomic, readonly) CGFloat radiusForDoubleCircleOuterCircle; 26 | @property (nonatomic, readonly) CGFloat lineWidthForDoubleCircleOuterCircle; 27 | @property (nonatomic, readonly) CGFloat radiusForDoubleCircleInnerCircle; 28 | @property (nonatomic, readonly) CGFloat lineWidthForDoubleCircleInnerCircle; 29 | 30 | @end 31 | 32 | static const CGFloat kFitFrameRadius = -1.0; 33 | 34 | @implementation EFCircularSlider 35 | 36 | @synthesize radius = _radius; 37 | 38 | #pragma mark - Initialisation 39 | - (id)init 40 | { 41 | return [self initWithRadius:kFitFrameRadius]; 42 | } 43 | 44 | - (id)initWithFrame:(CGRect)frame 45 | { 46 | self = [super initWithFrame:frame]; 47 | if (self) { 48 | [self initDefaultValuesWithRadius:kFitFrameRadius]; 49 | } 50 | return self; 51 | } 52 | 53 | - (id)initWithRadius:(CGFloat)radius 54 | { 55 | self = [super init]; 56 | if (self) 57 | { 58 | [self initDefaultValuesWithRadius:radius]; 59 | } 60 | return self; 61 | } 62 | 63 | -(void) initDefaultValuesWithRadius:(CGFloat)radius 64 | { 65 | _radius = radius; 66 | _maximumValue = 100.0f; 67 | _minimumValue = 0.0f; 68 | _lineWidth = 5; 69 | _unfilledColor = [UIColor blackColor]; 70 | _filledColor = [UIColor redColor]; 71 | _labelFont = [UIFont systemFontOfSize:10.0f]; 72 | _snapToLabels = NO; 73 | _handleType = CircularSliderHandleTypeSemiTransparentWhiteCircle; 74 | _labelColor = [UIColor redColor]; 75 | _labelDisplacement = 0; 76 | 77 | _angleFromNorth = 0; 78 | 79 | self.backgroundColor = [UIColor clearColor]; 80 | } 81 | 82 | #pragma mark - Public setter overrides 83 | -(void) setLineWidth:(int)lineWidth 84 | { 85 | _lineWidth = lineWidth; 86 | [self setNeedsUpdateConstraints]; // This could affect intrinsic content size 87 | [self invalidateIntrinsicContentSize]; // Need to update intrinsice content size 88 | [self setNeedsDisplay]; // Need to redraw with new line width 89 | } 90 | 91 | -(void) setHandleType:(CircularSliderHandleType)handleType 92 | { 93 | _handleType = handleType; 94 | [self setNeedsUpdateConstraints]; // This could affect intrinsic content size 95 | [self setNeedsDisplay]; // Need to redraw with new handle type 96 | } 97 | 98 | -(void) setFilledColor:(UIColor*)filledColor 99 | { 100 | _filledColor = filledColor; 101 | [self setNeedsDisplay]; // Need to redraw with new filled color 102 | } 103 | 104 | -(void) setUnfilledColor:(UIColor*)unfilledColor 105 | { 106 | _unfilledColor = unfilledColor; 107 | [self setNeedsDisplay]; // Need to redraw with new unfilled color 108 | } 109 | 110 | -(void) setHandlerColor:(UIColor *)handleColor 111 | { 112 | _handleColor = handleColor; 113 | [self setNeedsDisplay]; // Need to redraw with new handle color 114 | } 115 | 116 | -(void) setLabelFont:(UIFont*)labelFont 117 | { 118 | _labelFont = labelFont; 119 | [self setNeedsDisplay]; // Need to redraw with new label font 120 | } 121 | 122 | -(void) setLabelColor:(UIColor*)labelColor 123 | { 124 | _labelColor = labelColor; 125 | [self setNeedsDisplay]; // Need to redraw with new label color 126 | } 127 | 128 | -(void)setInnerMarkingLabels:(NSArray*)innerMarkingLabels 129 | { 130 | _innerMarkingLabels = innerMarkingLabels; 131 | [self setNeedsUpdateConstraints]; // This could affect intrinsic content size 132 | [self setNeedsDisplay]; // Need to redraw with new label texts 133 | } 134 | 135 | -(void)setMinimumValue:(float)minimumValue 136 | { 137 | _minimumValue = minimumValue; 138 | [self setNeedsDisplay]; // Need to redraw with updated value range 139 | } 140 | 141 | -(void)setMaximumValue:(float)maximumValue 142 | { 143 | _maximumValue = maximumValue; 144 | [self setNeedsDisplay]; // Need to redraw with updated value range 145 | } 146 | 147 | /** 148 | * There is no local variable currentValue - it is always calculated based on angleFromNorth 149 | * 150 | * @param currentValue Value used to update angleFromNorth between minimumValue & maximumValue 151 | */ 152 | -(void) setCurrentValue:(float)currentValue 153 | { 154 | NSAssert(currentValue <= self.maximumValue && currentValue >= self.minimumValue, 155 | @"currentValue (%.2f) must be between self.minimuValue (%.2f) and self.maximumValue (%.2f)", 156 | currentValue, self.minimumValue, self.maximumValue); 157 | 158 | // Update the angleFromNorth to match this newly set value 159 | self.angleFromNorth = (currentValue * 360)/(self.maximumValue - self.minimumValue); 160 | [self setNeedsDisplay]; 161 | [self sendActionsForControlEvents:UIControlEventValueChanged]; 162 | } 163 | 164 | -(void)setAngleFromNorth:(int)angleFromNorth 165 | { 166 | _angleFromNorth = angleFromNorth; 167 | NSAssert(_angleFromNorth >= 0, @"_angleFromNorth %d must be greater than 0", angleFromNorth); 168 | } 169 | 170 | -(void) setRadius:(CGFloat)radius 171 | { 172 | _radius = radius; 173 | [self invalidateIntrinsicContentSize]; // Need to update intrinsice content size 174 | [self setNeedsDisplay]; // Need to redraw with new radius 175 | } 176 | 177 | #pragma mark - Public getter overrides 178 | 179 | /** 180 | * There is no local variable currentValue - it is always calculated based on angleFromNorth 181 | * 182 | * @return currentValue Value between minimumValue & maximumValue derived from angleFromNorth 183 | */ 184 | -(float) currentValue 185 | { 186 | return (self.angleFromNorth * (self.maximumValue - self.minimumValue))/360.0f; 187 | } 188 | 189 | -(CGFloat) radius 190 | { 191 | if (_radius == kFitFrameRadius) 192 | { 193 | // Slider is being used in frames - calculate the max radius based on the frame 194 | // (constrained by smallest dimension so it fits within view) 195 | CGFloat minimumDimension = MIN(self.bounds.size.height, self.bounds.size.width); 196 | int halfLineWidth = ceilf(self.lineWidth / 2.0); 197 | int halfHandleWidth = ceilf(self.handleWidth / 2.0); 198 | return minimumDimension * 0.5 - MAX(halfHandleWidth, halfLineWidth); 199 | } 200 | return _radius; 201 | } 202 | 203 | -(UIColor*)handleColor 204 | { 205 | UIColor *newHandleColor = _handleColor; 206 | switch (self.handleType) { 207 | case CircularSliderHandleTypeSemiTransparentWhiteCircle: 208 | { 209 | newHandleColor = [UIColor colorWithWhite:1.0 alpha:0.7]; 210 | break; 211 | } 212 | case CircularSliderHandleTypeSemiTransparentBlackCircle: 213 | { 214 | newHandleColor = [UIColor colorWithWhite:0.0 alpha:0.7]; 215 | break; 216 | } 217 | case CircularSliderHandleTypeDoubleCircleWithClosedCenter: 218 | case CircularSliderHandleTypeDoubleCircleWithOpenCenter: 219 | case CircularSliderHandleTypeBigCircle: 220 | { 221 | if (!newHandleColor) 222 | { 223 | // handleColor public property hasn't been set - use filledColor 224 | newHandleColor = self.filledColor; 225 | } 226 | break; 227 | } 228 | } 229 | 230 | return newHandleColor; 231 | } 232 | 233 | #pragma mark - Private getter overrides 234 | 235 | -(CGFloat) handleWidth 236 | { 237 | switch (self.handleType) { 238 | case CircularSliderHandleTypeSemiTransparentWhiteCircle: 239 | case CircularSliderHandleTypeSemiTransparentBlackCircle: 240 | { 241 | return self.lineWidth; 242 | } 243 | case CircularSliderHandleTypeBigCircle: 244 | { 245 | return self.lineWidth + 5; // 5 points bigger than standard handles 246 | } 247 | case CircularSliderHandleTypeDoubleCircleWithClosedCenter: 248 | case CircularSliderHandleTypeDoubleCircleWithOpenCenter: 249 | { 250 | return 2 * [EFCircularTrig outerRadiuOfUnfilledArcWithRadius:self.radiusForDoubleCircleOuterCircle 251 | lineWidth:self.lineWidthForDoubleCircleOuterCircle]; 252 | } 253 | } 254 | } 255 | 256 | -(CGFloat)radiusForDoubleCircleOuterCircle 257 | { 258 | return 0.5 * self.lineWidth + 5; 259 | } 260 | -(CGFloat)lineWidthForDoubleCircleOuterCircle 261 | { 262 | return 4.0; 263 | } 264 | 265 | -(CGFloat)radiusForDoubleCircleInnerCircle 266 | { 267 | return 0.5 * self.lineWidth; 268 | } 269 | -(CGFloat)lineWidthForDoubleCircleInnerCircle 270 | { 271 | return 2.0; 272 | } 273 | 274 | -(CGFloat)innerLabelRadialDistanceFromCircumference 275 | { 276 | // Labels should be moved far enough to clear the line itself plus a fixed offset (relative to radius). 277 | int distanceToMoveInwards = 0.1 * -(self.radius) - 0.5 * self.lineWidth; 278 | distanceToMoveInwards -= 0.5 * self.labelFont.pointSize; // Also account for variable font size. 279 | return distanceToMoveInwards; 280 | } 281 | 282 | -(CGPoint)centerPoint 283 | { 284 | return CGPointMake(self.bounds.size.width * 0.5, self.bounds.size.height * 0.5); 285 | } 286 | 287 | #pragma mark - Method overrides 288 | -(CGSize)intrinsicContentSize 289 | { 290 | // Total width is: diameter + (2 * MAX(halfLineWidth, halfHandleWidth)) 291 | int diameter = self.radius * 2; 292 | int halfLineWidth = ceilf(self.lineWidth / 2.0); 293 | int halfHandleWidth = ceilf(self.handleWidth / 2.0); 294 | 295 | int widthWithHandle = diameter + (2 * MAX(halfHandleWidth, halfLineWidth)); 296 | 297 | return CGSizeMake(widthWithHandle, widthWithHandle); 298 | } 299 | 300 | - (void)drawRect:(CGRect)rect 301 | { 302 | [super drawRect:rect]; 303 | 304 | CGContextRef ctx = UIGraphicsGetCurrentContext(); 305 | 306 | // Draw the circular lines that slider handle moves along 307 | [self drawLine:ctx]; 308 | 309 | // Draw the draggable 'handle' 310 | [self drawHandle:ctx]; 311 | 312 | // Add the labels 313 | [self drawInnerLabels:ctx]; 314 | } 315 | 316 | 317 | - (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event { 318 | if ([self pointInsideHandle:point withEvent:event]) 319 | { 320 | return YES; // Point is indeed within handle bounds 321 | } 322 | else 323 | { 324 | return [self pointInsideCircle:point withEvent:event]; // Return YES if point is inside slider's circle 325 | } 326 | } 327 | 328 | - (BOOL)pointInsideCircle:(CGPoint)point withEvent:(UIEvent *)event { 329 | CGPoint p1 = [self centerPoint]; 330 | CGPoint p2 = point; 331 | CGFloat xDist = (p2.x - p1.x); 332 | CGFloat yDist = (p2.y - p1.y); 333 | double distance = sqrt((xDist * xDist) + (yDist * yDist)); 334 | return distance < self.radius + self.lineWidth * 0.5; 335 | } 336 | 337 | - (BOOL)pointInsideHandle:(CGPoint)point withEvent:(UIEvent *)event { 338 | CGPoint handleCenter = [self pointOnCircleAtAngleFromNorth:self.angleFromNorth]; 339 | CGFloat handleRadius = MAX(self.handleWidth, 44.0) * 0.5; 340 | // Adhere to apple's design guidelines - avoid making touch targets smaller than 44 points 341 | 342 | // Treat handle as a box around it's center 343 | BOOL pointInsideHorzontalHandleBounds = (point.x >= handleCenter.x - handleRadius 344 | && point.x <= handleCenter.x + handleRadius); 345 | BOOL pointInsideVerticalHandleBounds = (point.y >= handleCenter.y - handleRadius 346 | && point.y <= handleCenter.y + handleRadius); 347 | return pointInsideHorzontalHandleBounds && pointInsideVerticalHandleBounds; 348 | } 349 | 350 | #pragma mark - Drawing methods 351 | 352 | -(void) drawLine:(CGContextRef)ctx 353 | { 354 | // Draw an unfilled circle (this shows what can be filled) 355 | [self.unfilledColor set]; 356 | [EFCircularTrig drawUnfilledCircleInContext:ctx 357 | center:self.centerPoint 358 | radius:self.radius 359 | lineWidth:self.lineWidth]; 360 | 361 | // Draw an unfilled arc up to the currently filled point 362 | [self.filledColor set]; 363 | 364 | [EFCircularTrig drawUnfilledArcInContext:ctx 365 | center:self.centerPoint 366 | radius:self.radius 367 | lineWidth:self.lineWidth 368 | fromAngleFromNorth:0 369 | toAngleFromNorth:self.angleFromNorth]; 370 | } 371 | 372 | -(void) drawHandle:(CGContextRef)ctx{ 373 | CGContextSaveGState(ctx); 374 | CGPoint handleCenter = [self pointOnCircleAtAngleFromNorth:self.angleFromNorth]; 375 | 376 | // Ensure that handle is drawn in the correct color 377 | [self.handleColor set]; 378 | 379 | switch (self.handleType) { 380 | case CircularSliderHandleTypeSemiTransparentWhiteCircle: 381 | case CircularSliderHandleTypeSemiTransparentBlackCircle: 382 | case CircularSliderHandleTypeBigCircle: 383 | { 384 | [EFCircularTrig drawFilledCircleInContext:ctx 385 | center:handleCenter 386 | radius:0.5 * self.handleWidth]; 387 | break; 388 | } 389 | case CircularSliderHandleTypeDoubleCircleWithClosedCenter: 390 | case CircularSliderHandleTypeDoubleCircleWithOpenCenter: 391 | { 392 | [self drawUnfilledLineBehindDoubleCircleHandle:ctx]; 393 | 394 | // Draw unfilled outer circle 395 | [EFCircularTrig drawUnfilledCircleInContext:ctx 396 | center:CGPointMake(handleCenter.x, 397 | handleCenter.y) 398 | radius:self.radiusForDoubleCircleOuterCircle 399 | lineWidth:self.lineWidthForDoubleCircleOuterCircle]; 400 | 401 | if (self.handleType == CircularSliderHandleTypeDoubleCircleWithClosedCenter) 402 | { 403 | // Draw filled inner circle 404 | [EFCircularTrig drawFilledCircleInContext:ctx 405 | center:handleCenter 406 | radius:[EFCircularTrig outerRadiuOfUnfilledArcWithRadius:self.radiusForDoubleCircleInnerCircle 407 | lineWidth:self.lineWidthForDoubleCircleInnerCircle]]; 408 | } 409 | else if (self.handleType == CircularSliderHandleTypeDoubleCircleWithOpenCenter) 410 | { 411 | // Draw unfilled inner circle 412 | [EFCircularTrig drawUnfilledCircleInContext:ctx 413 | center:CGPointMake(handleCenter.x, 414 | handleCenter.y) 415 | radius:self.radiusForDoubleCircleInnerCircle 416 | lineWidth:self.lineWidthForDoubleCircleInnerCircle]; 417 | } 418 | 419 | break; 420 | } 421 | } 422 | 423 | CGContextRestoreGState(ctx); 424 | } 425 | 426 | /** 427 | * Draw unfilled line from left edge of handle to right edge of handle 428 | * This is to ensure that the filled portion of the line doesn't show inside the double circle 429 | * @param ctx Graphics Context within which to draw unfilled line behind handle 430 | */ 431 | -(void) drawUnfilledLineBehindDoubleCircleHandle:(CGContextRef)ctx 432 | { 433 | CGFloat degreesToHandleCenter = self.angleFromNorth; 434 | // To determine where handle intersects the filledCircle, make approximation that arcLength ~ radius of handle outer circle. 435 | // This is a fine approximation whenever self.radius is sufficiently large (which it must be for this control to be usable) 436 | CGFloat degreesDifference = [EFCircularTrig degreesForArcLength:self.radiusForDoubleCircleOuterCircle 437 | onCircleWithRadius:self.radius]; 438 | CGFloat degreesToHandleLeftEdge = degreesToHandleCenter - degreesDifference; 439 | CGFloat degreesToHandleRightEdge = degreesToHandleCenter + degreesDifference; 440 | 441 | CGContextSaveGState(ctx); 442 | [self.unfilledColor set]; 443 | [EFCircularTrig drawUnfilledArcInContext:ctx 444 | center:self.centerPoint 445 | radius:self.radius 446 | lineWidth:self.lineWidth 447 | fromAngleFromNorth:degreesToHandleLeftEdge 448 | toAngleFromNorth:degreesToHandleRightEdge]; 449 | CGContextRestoreGState(ctx); 450 | } 451 | 452 | -(void) drawInnerLabels:(CGContextRef)ctx 453 | { 454 | // Only draw labels if they have been set 455 | NSInteger labelsCount = self.innerMarkingLabels.count; 456 | if(labelsCount) 457 | { 458 | #if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_7_0 459 | NSDictionary *attributes = @{ NSFontAttributeName: self.labelFont, 460 | NSForegroundColorAttributeName: self.labelColor}; 461 | #endif 462 | for (int i = 0; i < labelsCount; i++) 463 | { 464 | // Enumerate through labels clockwise 465 | NSString* label = self.innerMarkingLabels[i]; 466 | 467 | CGRect labelFrame = [self contextCoordinatesForLabelAtIndex:i]; 468 | 469 | #if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_7_0 470 | [label drawInRect:labelFrame withAttributes:attributes]; 471 | #else 472 | [self.labelColor setFill]; 473 | [label drawInRect:labelFrame withFont:self.labelFont]; 474 | #endif 475 | } 476 | } 477 | } 478 | 479 | -(CGRect)contextCoordinatesForLabelAtIndex:(NSInteger)index 480 | { 481 | NSString *label = self.innerMarkingLabels[index]; 482 | 483 | // Determine how many degrees around the full circle this label should go 484 | CGFloat percentageAlongCircle = (index + 1) / (float)self.innerMarkingLabels.count; 485 | CGFloat degreesFromNorthForLabel = percentageAlongCircle * 360; 486 | CGPoint pointOnCircle = [self pointOnCircleAtAngleFromNorth:degreesFromNorthForLabel]; 487 | 488 | CGSize labelSize = [self sizeOfString:label withFont:self.labelFont]; 489 | CGPoint offsetFromCircle = [self offsetFromCircleForLabelAtIndex:index withSize:labelSize]; 490 | 491 | return CGRectMake(pointOnCircle.x + offsetFromCircle.x, pointOnCircle.y + offsetFromCircle.y, labelSize.width, labelSize.height); 492 | } 493 | 494 | -(CGPoint) offsetFromCircleForLabelAtIndex:(NSInteger)index withSize:(CGSize)labelSize 495 | { 496 | // Determine how many degrees around the full circle this label should go 497 | CGFloat percentageAlongCircle = (index + 1) / (float)self.innerMarkingLabels.count; 498 | CGFloat degreesFromNorthForLabel = percentageAlongCircle * 360; 499 | 500 | CGFloat radialDistance = self.innerLabelRadialDistanceFromCircumference + self.labelDisplacement; 501 | CGPoint inwardOffset = [EFCircularTrig pointOnRadius:radialDistance 502 | atAngleFromNorth:degreesFromNorthForLabel]; 503 | 504 | return CGPointMake(-labelSize.width * 0.5 + inwardOffset.x, -labelSize.height * 0.5 + inwardOffset.y); 505 | } 506 | 507 | #pragma mark - UIControl functions 508 | 509 | -(BOOL)beginTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event 510 | { 511 | [super beginTrackingWithTouch:touch withEvent:event]; 512 | 513 | if (![self moving]) { 514 | [self sendActionsForControlEvents:UIControlEventTouchDown]; 515 | } 516 | 517 | return YES; 518 | } 519 | 520 | -(BOOL) continueTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event 521 | { 522 | [super continueTrackingWithTouch:touch withEvent:event]; 523 | 524 | CGPoint lastPoint = [touch locationInView:self]; 525 | [self setMoving:YES]; 526 | [self moveHandle:lastPoint]; 527 | [self sendActionsForControlEvents:UIControlEventValueChanged]; 528 | 529 | return YES; 530 | } 531 | 532 | -(void)endTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event 533 | { 534 | [super endTrackingWithTouch:touch withEvent:event]; 535 | if(self.snapToLabels && self.innerMarkingLabels != nil) 536 | { 537 | CGPoint bestGuessPoint = CGPointZero; 538 | float minDist = 360; 539 | NSUInteger labelsCount = self.innerMarkingLabels.count; 540 | 541 | for (int i = 0; i < labelsCount; i++) 542 | { 543 | CGFloat percentageAlongCircle = i/(float)labelsCount; 544 | CGFloat degreesForLabel = percentageAlongCircle * 360; 545 | if(abs(self.angleFromNorth - degreesForLabel) < minDist) 546 | { 547 | minDist = abs(self.angleFromNorth - degreesForLabel); 548 | bestGuessPoint = [self pointOnCircleAtAngleFromNorth:degreesForLabel]; 549 | } 550 | } 551 | self.angleFromNorth = floor([EFCircularTrig angleRelativeToNorthFromPoint:self.centerPoint 552 | toPoint:bestGuessPoint]); 553 | [self setNeedsDisplay]; 554 | } 555 | [self setMoving:NO]; 556 | [self sendActionsForControlEvents:UIControlEventTouchUpInside]; 557 | } 558 | 559 | -(void)moveHandle:(CGPoint)point 560 | { 561 | self.angleFromNorth = floor([EFCircularTrig angleRelativeToNorthFromPoint:self.centerPoint 562 | toPoint:point]);; 563 | [self setNeedsDisplay]; 564 | } 565 | 566 | #pragma mark - Helper functions 567 | - (BOOL) isDoubleCircleHandle 568 | { 569 | return self.handleType == CircularSliderHandleTypeDoubleCircleWithClosedCenter || self.handleType == CircularSliderHandleTypeDoubleCircleWithOpenCenter; 570 | } 571 | 572 | - (CGSize) sizeOfString:(NSString *)string withFont:(UIFont*)font 573 | { 574 | NSDictionary *attributes = [NSDictionary dictionaryWithObjectsAndKeys:font, NSFontAttributeName, nil]; 575 | return [[NSAttributedString alloc] initWithString:string attributes:attributes].size; 576 | } 577 | 578 | -(CGPoint)pointOnCircleAtAngleFromNorth:(int)angleFromNorth 579 | { 580 | CGPoint offset = [EFCircularTrig pointOnRadius:self.radius atAngleFromNorth:angleFromNorth]; 581 | return CGPointMake(self.centerPoint.x + offset.x, self.centerPoint.y + offset.y); 582 | } 583 | 584 | @end 585 | -------------------------------------------------------------------------------- /ios/TiCircularSlide.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXAggregateTarget section */ 10 | 24416B8111C4CA220047AFDD /* Build & Test */ = { 11 | isa = PBXAggregateTarget; 12 | buildConfigurationList = 24416B8A11C4CA520047AFDD /* Build configuration list for PBXAggregateTarget "Build & Test" */; 13 | buildPhases = ( 14 | 24416B8011C4CA220047AFDD /* ShellScript */, 15 | ); 16 | dependencies = ( 17 | 24416B8511C4CA280047AFDD /* PBXTargetDependency */, 18 | ); 19 | name = "Build & Test"; 20 | productName = "Build & test"; 21 | }; 22 | /* End PBXAggregateTarget section */ 23 | 24 | /* Begin PBXBuildFile section */ 25 | 1EE76995185FB1F300E46898 /* EFCircularSlider.h in Headers */ = {isa = PBXBuildFile; fileRef = 1EE76993185FB1F300E46898 /* EFCircularSlider.h */; }; 26 | 1EE76996185FB1F300E46898 /* EFCircularSlider.m in Sources */ = {isa = PBXBuildFile; fileRef = 1EE76994185FB1F300E46898 /* EFCircularSlider.m */; }; 27 | 1EE76999185FB23100E46898 /* DeMarcelpociotCircularsliderView.h in Headers */ = {isa = PBXBuildFile; fileRef = 1EE76997185FB23100E46898 /* DeMarcelpociotCircularsliderView.h */; }; 28 | 1EE7699A185FB23100E46898 /* DeMarcelpociotCircularsliderView.m in Sources */ = {isa = PBXBuildFile; fileRef = 1EE76998185FB23100E46898 /* DeMarcelpociotCircularsliderView.m */; }; 29 | 1EE7699D185FB23F00E46898 /* DeMarcelpociotCircularsliderViewProxy.h in Headers */ = {isa = PBXBuildFile; fileRef = 1EE7699B185FB23F00E46898 /* DeMarcelpociotCircularsliderViewProxy.h */; }; 30 | 1EE7699E185FB23F00E46898 /* DeMarcelpociotCircularsliderViewProxy.m in Sources */ = {isa = PBXBuildFile; fileRef = 1EE7699C185FB23F00E46898 /* DeMarcelpociotCircularsliderViewProxy.m */; }; 31 | 1EE769A0185FB58A00E46898 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1EE7699F185FB58A00E46898 /* QuartzCore.framework */; }; 32 | 1EE769A2185FB59000E46898 /* CoreImage.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1EE769A1185FB59000E46898 /* CoreImage.framework */; }; 33 | 24DD6CF91134B3F500162E58 /* DeMarcelpociotCircularsliderModule.h in Headers */ = {isa = PBXBuildFile; fileRef = 24DD6CF71134B3F500162E58 /* DeMarcelpociotCircularsliderModule.h */; }; 34 | 24DD6CFA1134B3F500162E58 /* DeMarcelpociotCircularsliderModule.m in Sources */ = {isa = PBXBuildFile; fileRef = 24DD6CF81134B3F500162E58 /* DeMarcelpociotCircularsliderModule.m */; }; 35 | 24DE9E1111C5FE74003F90F6 /* DeMarcelpociotCircularsliderModuleAssets.h in Headers */ = {isa = PBXBuildFile; fileRef = 24DE9E0F11C5FE74003F90F6 /* DeMarcelpociotCircularsliderModuleAssets.h */; }; 36 | 24DE9E1211C5FE74003F90F6 /* DeMarcelpociotCircularsliderModuleAssets.m in Sources */ = {isa = PBXBuildFile; fileRef = 24DE9E1011C5FE74003F90F6 /* DeMarcelpociotCircularsliderModuleAssets.m */; }; 37 | 3AD6468A1C7B68F9002B069E /* EFCircularTrig.h in Headers */ = {isa = PBXBuildFile; fileRef = 3AD646881C7B68F9002B069E /* EFCircularTrig.h */; }; 38 | 3AD6468B1C7B68F9002B069E /* EFCircularTrig.m in Sources */ = {isa = PBXBuildFile; fileRef = 3AD646891C7B68F9002B069E /* EFCircularTrig.m */; }; 39 | AA747D9F0F9514B9006C5449 /* DeMarcelpociotCircularslider_Prefix.pch in Headers */ = {isa = PBXBuildFile; fileRef = AA747D9E0F9514B9006C5449 /* DeMarcelpociotCircularslider_Prefix.pch */; }; 40 | AACBBE4A0F95108600F1A2B1 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AACBBE490F95108600F1A2B1 /* Foundation.framework */; }; 41 | /* End PBXBuildFile section */ 42 | 43 | /* Begin PBXContainerItemProxy section */ 44 | 24416B8411C4CA280047AFDD /* PBXContainerItemProxy */ = { 45 | isa = PBXContainerItemProxy; 46 | containerPortal = 0867D690FE84028FC02AAC07 /* Project object */; 47 | proxyType = 1; 48 | remoteGlobalIDString = D2AAC07D0554694100DB518D; 49 | remoteInfo = TiCircularSlide; 50 | }; 51 | /* End PBXContainerItemProxy section */ 52 | 53 | /* Begin PBXFileReference section */ 54 | 1EE76993185FB1F300E46898 /* EFCircularSlider.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EFCircularSlider.h; sourceTree = ""; }; 55 | 1EE76994185FB1F300E46898 /* EFCircularSlider.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = EFCircularSlider.m; sourceTree = ""; }; 56 | 1EE76997185FB23100E46898 /* DeMarcelpociotCircularsliderView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DeMarcelpociotCircularsliderView.h; path = Classes/DeMarcelpociotCircularsliderView.h; sourceTree = ""; }; 57 | 1EE76998185FB23100E46898 /* DeMarcelpociotCircularsliderView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DeMarcelpociotCircularsliderView.m; path = Classes/DeMarcelpociotCircularsliderView.m; sourceTree = ""; }; 58 | 1EE7699B185FB23F00E46898 /* DeMarcelpociotCircularsliderViewProxy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DeMarcelpociotCircularsliderViewProxy.h; path = Classes/DeMarcelpociotCircularsliderViewProxy.h; sourceTree = ""; }; 59 | 1EE7699C185FB23F00E46898 /* DeMarcelpociotCircularsliderViewProxy.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DeMarcelpociotCircularsliderViewProxy.m; path = Classes/DeMarcelpociotCircularsliderViewProxy.m; sourceTree = ""; }; 60 | 1EE7699F185FB58A00E46898 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; }; 61 | 1EE769A1185FB59000E46898 /* CoreImage.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreImage.framework; path = System/Library/Frameworks/CoreImage.framework; sourceTree = SDKROOT; }; 62 | 24DD6CF71134B3F500162E58 /* DeMarcelpociotCircularsliderModule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DeMarcelpociotCircularsliderModule.h; path = Classes/DeMarcelpociotCircularsliderModule.h; sourceTree = ""; }; 63 | 24DD6CF81134B3F500162E58 /* DeMarcelpociotCircularsliderModule.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DeMarcelpociotCircularsliderModule.m; path = Classes/DeMarcelpociotCircularsliderModule.m; sourceTree = ""; }; 64 | 24DD6D1B1134B66800162E58 /* titanium.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = titanium.xcconfig; sourceTree = ""; }; 65 | 24DE9E0F11C5FE74003F90F6 /* DeMarcelpociotCircularsliderModuleAssets.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DeMarcelpociotCircularsliderModuleAssets.h; path = Classes/DeMarcelpociotCircularsliderModuleAssets.h; sourceTree = ""; }; 66 | 24DE9E1011C5FE74003F90F6 /* DeMarcelpociotCircularsliderModuleAssets.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DeMarcelpociotCircularsliderModuleAssets.m; path = Classes/DeMarcelpociotCircularsliderModuleAssets.m; sourceTree = ""; }; 67 | 3AD646881C7B68F9002B069E /* EFCircularTrig.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EFCircularTrig.h; sourceTree = ""; }; 68 | 3AD646891C7B68F9002B069E /* EFCircularTrig.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = EFCircularTrig.m; sourceTree = ""; }; 69 | AA747D9E0F9514B9006C5449 /* DeMarcelpociotCircularslider_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DeMarcelpociotCircularslider_Prefix.pch; sourceTree = SOURCE_ROOT; }; 70 | AACBBE490F95108600F1A2B1 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 71 | D2AAC07E0554694100DB518D /* libDeMarcelpociotCircularslider.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libDeMarcelpociotCircularslider.a; sourceTree = BUILT_PRODUCTS_DIR; }; 72 | /* End PBXFileReference section */ 73 | 74 | /* Begin PBXFrameworksBuildPhase section */ 75 | D2AAC07C0554694100DB518D /* Frameworks */ = { 76 | isa = PBXFrameworksBuildPhase; 77 | buildActionMask = 2147483647; 78 | files = ( 79 | 1EE769A2185FB59000E46898 /* CoreImage.framework in Frameworks */, 80 | 1EE769A0185FB58A00E46898 /* QuartzCore.framework in Frameworks */, 81 | AACBBE4A0F95108600F1A2B1 /* Foundation.framework in Frameworks */, 82 | ); 83 | runOnlyForDeploymentPostprocessing = 0; 84 | }; 85 | /* End PBXFrameworksBuildPhase section */ 86 | 87 | /* Begin PBXGroup section */ 88 | 034768DFFF38A50411DB9C8B /* Products */ = { 89 | isa = PBXGroup; 90 | children = ( 91 | D2AAC07E0554694100DB518D /* libDeMarcelpociotCircularslider.a */, 92 | ); 93 | name = Products; 94 | sourceTree = ""; 95 | }; 96 | 0867D691FE84028FC02AAC07 /* TiCircularSlide */ = { 97 | isa = PBXGroup; 98 | children = ( 99 | 08FB77AEFE84172EC02AAC07 /* Classes */, 100 | 32C88DFF0371C24200C91783 /* Other Sources */, 101 | 0867D69AFE84028FC02AAC07 /* Frameworks */, 102 | 034768DFFF38A50411DB9C8B /* Products */, 103 | ); 104 | name = TiCircularSlide; 105 | sourceTree = ""; 106 | }; 107 | 0867D69AFE84028FC02AAC07 /* Frameworks */ = { 108 | isa = PBXGroup; 109 | children = ( 110 | 1EE769A1185FB59000E46898 /* CoreImage.framework */, 111 | 1EE7699F185FB58A00E46898 /* QuartzCore.framework */, 112 | AACBBE490F95108600F1A2B1 /* Foundation.framework */, 113 | ); 114 | name = Frameworks; 115 | sourceTree = ""; 116 | }; 117 | 08FB77AEFE84172EC02AAC07 /* Classes */ = { 118 | isa = PBXGroup; 119 | children = ( 120 | 1EE76992185FB1F300E46898 /* EFCircularSlider */, 121 | 24DE9E0F11C5FE74003F90F6 /* DeMarcelpociotCircularsliderModuleAssets.h */, 122 | 24DE9E1011C5FE74003F90F6 /* DeMarcelpociotCircularsliderModuleAssets.m */, 123 | 24DD6CF71134B3F500162E58 /* DeMarcelpociotCircularsliderModule.h */, 124 | 24DD6CF81134B3F500162E58 /* DeMarcelpociotCircularsliderModule.m */, 125 | 1EE76997185FB23100E46898 /* DeMarcelpociotCircularsliderView.h */, 126 | 1EE76998185FB23100E46898 /* DeMarcelpociotCircularsliderView.m */, 127 | 1EE7699B185FB23F00E46898 /* DeMarcelpociotCircularsliderViewProxy.h */, 128 | 1EE7699C185FB23F00E46898 /* DeMarcelpociotCircularsliderViewProxy.m */, 129 | ); 130 | name = Classes; 131 | sourceTree = ""; 132 | }; 133 | 1EE76992185FB1F300E46898 /* EFCircularSlider */ = { 134 | isa = PBXGroup; 135 | children = ( 136 | 3AD646881C7B68F9002B069E /* EFCircularTrig.h */, 137 | 3AD646891C7B68F9002B069E /* EFCircularTrig.m */, 138 | 1EE76993185FB1F300E46898 /* EFCircularSlider.h */, 139 | 1EE76994185FB1F300E46898 /* EFCircularSlider.m */, 140 | ); 141 | path = EFCircularSlider; 142 | sourceTree = ""; 143 | }; 144 | 32C88DFF0371C24200C91783 /* Other Sources */ = { 145 | isa = PBXGroup; 146 | children = ( 147 | AA747D9E0F9514B9006C5449 /* DeMarcelpociotCircularslider_Prefix.pch */, 148 | 24DD6D1B1134B66800162E58 /* titanium.xcconfig */, 149 | ); 150 | name = "Other Sources"; 151 | sourceTree = ""; 152 | }; 153 | /* End PBXGroup section */ 154 | 155 | /* Begin PBXHeadersBuildPhase section */ 156 | D2AAC07A0554694100DB518D /* Headers */ = { 157 | isa = PBXHeadersBuildPhase; 158 | buildActionMask = 2147483647; 159 | files = ( 160 | AA747D9F0F9514B9006C5449 /* DeMarcelpociotCircularslider_Prefix.pch in Headers */, 161 | 1EE76999185FB23100E46898 /* DeMarcelpociotCircularsliderView.h in Headers */, 162 | 24DD6CF91134B3F500162E58 /* DeMarcelpociotCircularsliderModule.h in Headers */, 163 | 1EE7699D185FB23F00E46898 /* DeMarcelpociotCircularsliderViewProxy.h in Headers */, 164 | 24DE9E1111C5FE74003F90F6 /* DeMarcelpociotCircularsliderModuleAssets.h in Headers */, 165 | 3AD6468A1C7B68F9002B069E /* EFCircularTrig.h in Headers */, 166 | 1EE76995185FB1F300E46898 /* EFCircularSlider.h in Headers */, 167 | ); 168 | runOnlyForDeploymentPostprocessing = 0; 169 | }; 170 | /* End PBXHeadersBuildPhase section */ 171 | 172 | /* Begin PBXNativeTarget section */ 173 | D2AAC07D0554694100DB518D /* TiCircularSlide */ = { 174 | isa = PBXNativeTarget; 175 | buildConfigurationList = 1DEB921E08733DC00010E9CD /* Build configuration list for PBXNativeTarget "TiCircularSlide" */; 176 | buildPhases = ( 177 | D2AAC07A0554694100DB518D /* Headers */, 178 | D2AAC07B0554694100DB518D /* Sources */, 179 | D2AAC07C0554694100DB518D /* Frameworks */, 180 | ); 181 | buildRules = ( 182 | ); 183 | dependencies = ( 184 | ); 185 | name = TiCircularSlide; 186 | productName = TiCircularSlide; 187 | productReference = D2AAC07E0554694100DB518D /* libDeMarcelpociotCircularslider.a */; 188 | productType = "com.apple.product-type.library.static"; 189 | }; 190 | /* End PBXNativeTarget section */ 191 | 192 | /* Begin PBXProject section */ 193 | 0867D690FE84028FC02AAC07 /* Project object */ = { 194 | isa = PBXProject; 195 | attributes = { 196 | LastUpgradeCheck = 0730; 197 | }; 198 | buildConfigurationList = 1DEB922208733DC00010E9CD /* Build configuration list for PBXProject "TiCircularSlide" */; 199 | compatibilityVersion = "Xcode 3.2"; 200 | developmentRegion = English; 201 | hasScannedForEncodings = 1; 202 | knownRegions = ( 203 | English, 204 | Japanese, 205 | French, 206 | German, 207 | ); 208 | mainGroup = 0867D691FE84028FC02AAC07 /* TiCircularSlide */; 209 | productRefGroup = 034768DFFF38A50411DB9C8B /* Products */; 210 | projectDirPath = ""; 211 | projectRoot = ""; 212 | targets = ( 213 | D2AAC07D0554694100DB518D /* TiCircularSlide */, 214 | 24416B8111C4CA220047AFDD /* Build & Test */, 215 | ); 216 | }; 217 | /* End PBXProject section */ 218 | 219 | /* Begin PBXShellScriptBuildPhase section */ 220 | 24416B8011C4CA220047AFDD /* ShellScript */ = { 221 | isa = PBXShellScriptBuildPhase; 222 | buildActionMask = 2147483647; 223 | files = ( 224 | ); 225 | inputPaths = ( 226 | ); 227 | outputPaths = ( 228 | ); 229 | runOnlyForDeploymentPostprocessing = 0; 230 | shellPath = /bin/sh; 231 | shellScript = "# shell script goes here\n\npython \"${TITANIUM_SDK}/titanium.py\" run --dir=\"${PROJECT_DIR}\"\nexit $?\n"; 232 | }; 233 | /* End PBXShellScriptBuildPhase section */ 234 | 235 | /* Begin PBXSourcesBuildPhase section */ 236 | D2AAC07B0554694100DB518D /* Sources */ = { 237 | isa = PBXSourcesBuildPhase; 238 | buildActionMask = 2147483647; 239 | files = ( 240 | 3AD6468B1C7B68F9002B069E /* EFCircularTrig.m in Sources */, 241 | 1EE76996185FB1F300E46898 /* EFCircularSlider.m in Sources */, 242 | 24DD6CFA1134B3F500162E58 /* DeMarcelpociotCircularsliderModule.m in Sources */, 243 | 24DE9E1211C5FE74003F90F6 /* DeMarcelpociotCircularsliderModuleAssets.m in Sources */, 244 | 1EE7699A185FB23100E46898 /* DeMarcelpociotCircularsliderView.m in Sources */, 245 | 1EE7699E185FB23F00E46898 /* DeMarcelpociotCircularsliderViewProxy.m in Sources */, 246 | ); 247 | runOnlyForDeploymentPostprocessing = 0; 248 | }; 249 | /* End PBXSourcesBuildPhase section */ 250 | 251 | /* Begin PBXTargetDependency section */ 252 | 24416B8511C4CA280047AFDD /* PBXTargetDependency */ = { 253 | isa = PBXTargetDependency; 254 | target = D2AAC07D0554694100DB518D /* TiCircularSlide */; 255 | targetProxy = 24416B8411C4CA280047AFDD /* PBXContainerItemProxy */; 256 | }; 257 | /* End PBXTargetDependency section */ 258 | 259 | /* Begin XCBuildConfiguration section */ 260 | 1DEB921F08733DC00010E9CD /* Debug */ = { 261 | isa = XCBuildConfiguration; 262 | baseConfigurationReference = 24DD6D1B1134B66800162E58 /* titanium.xcconfig */; 263 | buildSettings = { 264 | CLANG_ENABLE_OBJC_ARC = YES; 265 | CODE_SIGN_IDENTITY = "iPhone Developer"; 266 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 267 | DSTROOT = /tmp/DeMarcelpociotCircularslider.dst; 268 | GCC_C_LANGUAGE_STANDARD = c99; 269 | GCC_OPTIMIZATION_LEVEL = 0; 270 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 271 | GCC_PREFIX_HEADER = DeMarcelpociotCircularslider_Prefix.pch; 272 | GCC_PREPROCESSOR_DEFINITIONS = "TI_VERSION=$(TI_VERSION)"; 273 | GCC_TREAT_WARNINGS_AS_ERRORS = NO; 274 | GCC_VERSION = ""; 275 | GCC_WARN_ABOUT_RETURN_TYPE = NO; 276 | GCC_WARN_MISSING_PARENTHESES = NO; 277 | GCC_WARN_SHADOW = NO; 278 | GCC_WARN_STRICT_SELECTOR_MATCH = NO; 279 | GCC_WARN_UNUSED_FUNCTION = YES; 280 | GCC_WARN_UNUSED_PARAMETER = NO; 281 | GCC_WARN_UNUSED_VALUE = NO; 282 | GCC_WARN_UNUSED_VARIABLE = NO; 283 | INSTALL_PATH = /usr/local/lib; 284 | LIBRARY_SEARCH_PATHS = ""; 285 | OTHER_CFLAGS = ( 286 | "-DDEBUG", 287 | "-DTI_POST_1_2", 288 | ); 289 | OTHER_LDFLAGS = "-ObjC"; 290 | PRODUCT_NAME = DeMarcelpociotCircularslider; 291 | PROVISIONING_PROFILE = ""; 292 | "PROVISIONING_PROFILE[sdk=iphoneos*]" = ""; 293 | RUN_CLANG_STATIC_ANALYZER = NO; 294 | SDKROOT = iphoneos; 295 | USER_HEADER_SEARCH_PATHS = ""; 296 | }; 297 | name = Debug; 298 | }; 299 | 1DEB922008733DC00010E9CD /* Release */ = { 300 | isa = XCBuildConfiguration; 301 | baseConfigurationReference = 24DD6D1B1134B66800162E58 /* titanium.xcconfig */; 302 | buildSettings = { 303 | ALWAYS_SEARCH_USER_PATHS = NO; 304 | CLANG_ENABLE_OBJC_ARC = YES; 305 | DSTROOT = /tmp/DeMarcelpociotCircularslider.dst; 306 | GCC_C_LANGUAGE_STANDARD = c99; 307 | GCC_MODEL_TUNING = G5; 308 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 309 | GCC_PREFIX_HEADER = DeMarcelpociotCircularslider_Prefix.pch; 310 | GCC_PREPROCESSOR_DEFINITIONS = "TI_VERSION=$(TI_VERSION)"; 311 | GCC_TREAT_WARNINGS_AS_ERRORS = NO; 312 | GCC_VERSION = ""; 313 | GCC_WARN_ABOUT_RETURN_TYPE = NO; 314 | GCC_WARN_MISSING_PARENTHESES = NO; 315 | GCC_WARN_SHADOW = NO; 316 | GCC_WARN_STRICT_SELECTOR_MATCH = NO; 317 | GCC_WARN_UNUSED_FUNCTION = YES; 318 | GCC_WARN_UNUSED_PARAMETER = NO; 319 | GCC_WARN_UNUSED_VALUE = NO; 320 | GCC_WARN_UNUSED_VARIABLE = NO; 321 | INSTALL_PATH = /usr/local/lib; 322 | IPHONEOS_DEPLOYMENT_TARGET = 6.1; 323 | LIBRARY_SEARCH_PATHS = ""; 324 | OTHER_CFLAGS = "-DTI_POST_1_2"; 325 | OTHER_LDFLAGS = "-ObjC"; 326 | PRODUCT_NAME = DeMarcelpociotCircularslider; 327 | RUN_CLANG_STATIC_ANALYZER = NO; 328 | SDKROOT = iphoneos; 329 | USER_HEADER_SEARCH_PATHS = ""; 330 | }; 331 | name = Release; 332 | }; 333 | 1DEB922308733DC00010E9CD /* Debug */ = { 334 | isa = XCBuildConfiguration; 335 | baseConfigurationReference = 24DD6D1B1134B66800162E58 /* titanium.xcconfig */; 336 | buildSettings = { 337 | CODE_SIGN_IDENTITY = "iPhone Developer"; 338 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 339 | DSTROOT = /tmp/DeMarcelpociotCircularslider.dst; 340 | ENABLE_TESTABILITY = YES; 341 | GCC_C_LANGUAGE_STANDARD = c99; 342 | GCC_OPTIMIZATION_LEVEL = 0; 343 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 344 | GCC_PREFIX_HEADER = DeMarcelpociotCircularslider_Prefix.pch; 345 | GCC_PREPROCESSOR_DEFINITIONS = "TI_VERSION=$(TI_VERSION)"; 346 | GCC_TREAT_WARNINGS_AS_ERRORS = NO; 347 | GCC_VERSION = ""; 348 | GCC_WARN_ABOUT_RETURN_TYPE = NO; 349 | GCC_WARN_MISSING_PARENTHESES = NO; 350 | GCC_WARN_SHADOW = NO; 351 | GCC_WARN_STRICT_SELECTOR_MATCH = NO; 352 | GCC_WARN_UNUSED_FUNCTION = YES; 353 | GCC_WARN_UNUSED_PARAMETER = NO; 354 | GCC_WARN_UNUSED_VALUE = NO; 355 | GCC_WARN_UNUSED_VARIABLE = NO; 356 | INSTALL_PATH = /usr/local/lib; 357 | ONLY_ACTIVE_ARCH = YES; 358 | OTHER_CFLAGS = ( 359 | "-DDEBUG", 360 | "-DTI_POST_1_2", 361 | ); 362 | OTHER_LDFLAGS = "-ObjC"; 363 | PRODUCT_NAME = DeMarcelpociotCircularslider; 364 | PROVISIONING_PROFILE = ""; 365 | "PROVISIONING_PROFILE[sdk=iphoneos*]" = ""; 366 | RUN_CLANG_STATIC_ANALYZER = NO; 367 | SDKROOT = iphoneos; 368 | USER_HEADER_SEARCH_PATHS = ""; 369 | }; 370 | name = Debug; 371 | }; 372 | 1DEB922408733DC00010E9CD /* Release */ = { 373 | isa = XCBuildConfiguration; 374 | baseConfigurationReference = 24DD6D1B1134B66800162E58 /* titanium.xcconfig */; 375 | buildSettings = { 376 | ALWAYS_SEARCH_USER_PATHS = NO; 377 | DSTROOT = /tmp/DeMarcelpociotCircularslider.dst; 378 | GCC_C_LANGUAGE_STANDARD = c99; 379 | GCC_MODEL_TUNING = G5; 380 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 381 | GCC_PREFIX_HEADER = DeMarcelpociotCircularslider_Prefix.pch; 382 | GCC_PREPROCESSOR_DEFINITIONS = "TI_VERSION=$(TI_VERSION)"; 383 | GCC_TREAT_WARNINGS_AS_ERRORS = NO; 384 | GCC_VERSION = ""; 385 | GCC_WARN_ABOUT_RETURN_TYPE = NO; 386 | GCC_WARN_MISSING_PARENTHESES = NO; 387 | GCC_WARN_SHADOW = NO; 388 | GCC_WARN_STRICT_SELECTOR_MATCH = NO; 389 | GCC_WARN_UNUSED_FUNCTION = YES; 390 | GCC_WARN_UNUSED_PARAMETER = NO; 391 | GCC_WARN_UNUSED_VALUE = NO; 392 | GCC_WARN_UNUSED_VARIABLE = NO; 393 | INSTALL_PATH = /usr/local/lib; 394 | IPHONEOS_DEPLOYMENT_TARGET = 6.0; 395 | OTHER_CFLAGS = "-DTI_POST_1_2"; 396 | OTHER_LDFLAGS = "-ObjC"; 397 | PRODUCT_NAME = DeMarcelpociotCircularslider; 398 | RUN_CLANG_STATIC_ANALYZER = NO; 399 | SDKROOT = iphoneos; 400 | USER_HEADER_SEARCH_PATHS = ""; 401 | }; 402 | name = Release; 403 | }; 404 | 24416B8211C4CA220047AFDD /* Debug */ = { 405 | isa = XCBuildConfiguration; 406 | baseConfigurationReference = 24DD6D1B1134B66800162E58 /* titanium.xcconfig */; 407 | buildSettings = { 408 | COPY_PHASE_STRIP = NO; 409 | GCC_DYNAMIC_NO_PIC = NO; 410 | GCC_OPTIMIZATION_LEVEL = 0; 411 | PRODUCT_NAME = "Build & test"; 412 | }; 413 | name = Debug; 414 | }; 415 | 24416B8311C4CA220047AFDD /* Release */ = { 416 | isa = XCBuildConfiguration; 417 | baseConfigurationReference = 24DD6D1B1134B66800162E58 /* titanium.xcconfig */; 418 | buildSettings = { 419 | COPY_PHASE_STRIP = YES; 420 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 421 | GCC_ENABLE_FIX_AND_CONTINUE = NO; 422 | IPHONEOS_DEPLOYMENT_TARGET = 6.1; 423 | PRODUCT_NAME = "Build & test"; 424 | ZERO_LINK = NO; 425 | }; 426 | name = Release; 427 | }; 428 | /* End XCBuildConfiguration section */ 429 | 430 | /* Begin XCConfigurationList section */ 431 | 1DEB921E08733DC00010E9CD /* Build configuration list for PBXNativeTarget "TiCircularSlide" */ = { 432 | isa = XCConfigurationList; 433 | buildConfigurations = ( 434 | 1DEB921F08733DC00010E9CD /* Debug */, 435 | 1DEB922008733DC00010E9CD /* Release */, 436 | ); 437 | defaultConfigurationIsVisible = 0; 438 | defaultConfigurationName = Release; 439 | }; 440 | 1DEB922208733DC00010E9CD /* Build configuration list for PBXProject "TiCircularSlide" */ = { 441 | isa = XCConfigurationList; 442 | buildConfigurations = ( 443 | 1DEB922308733DC00010E9CD /* Debug */, 444 | 1DEB922408733DC00010E9CD /* Release */, 445 | ); 446 | defaultConfigurationIsVisible = 0; 447 | defaultConfigurationName = Release; 448 | }; 449 | 24416B8A11C4CA520047AFDD /* Build configuration list for PBXAggregateTarget "Build & Test" */ = { 450 | isa = XCConfigurationList; 451 | buildConfigurations = ( 452 | 24416B8211C4CA220047AFDD /* Debug */, 453 | 24416B8311C4CA220047AFDD /* Release */, 454 | ); 455 | defaultConfigurationIsVisible = 0; 456 | defaultConfigurationName = Release; 457 | }; 458 | /* End XCConfigurationList section */ 459 | }; 460 | rootObject = 0867D690FE84028FC02AAC07 /* Project object */; 461 | } 462 | --------------------------------------------------------------------------------