├── .gitignore ├── LICENSE.md ├── RangeSlider.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcuserdata │ │ ├── mahireusufzai.xcuserdatad │ │ └── UserInterfaceState.xcuserstate │ │ └── mal.xcuserdatad │ │ └── UserInterfaceState.xcuserstate └── xcuserdata │ └── mal.xcuserdatad │ ├── xcdebugger │ └── Breakpoints.xcbkptlist │ └── xcschemes │ ├── RangeSlider.xcscheme │ └── xcschememanagement.plist └── RangeSlider ├── DCIntrospect ├── DCCrossHairView.h ├── DCCrossHairView.m ├── DCFrameView.h ├── DCFrameView.m ├── DCIntrospect.h ├── DCIntrospect.m ├── DCIntrospectSettings.h ├── DCStatusBarOverlay.h └── DCStatusBarOverlay.m ├── Images ├── bar-background.png ├── bar-background@2x.png ├── bar-highlight.png ├── bar-highlight@2x.png ├── handle-hover.png ├── handle-hover@2x.png ├── handle.png └── handle@2x.png ├── RangeSlider-Info.plist ├── RangeSlider-Prefix.pch ├── RangeSlider.h ├── RangeSlider.m ├── RangeSliderAppDelegate.h ├── RangeSliderAppDelegate.m ├── RootViewController.h ├── RootViewController.m ├── en.lproj ├── InfoPlist.strings ├── MainWindow.xib └── RootViewController.xib └── main.m /.gitignore: -------------------------------------------------------------------------------- 1 | RangeSlider.xcodeproj/xcuserdata 2 | .DS_Store 3 | DerivedData/ 4 | RangeSlider.xcodeproj/project.xcworkspace/xcuserdata/ -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2012 SitePoint PTY LTD 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /RangeSlider.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 201FAEAA14087B2E00021322 /* DCCrossHairView.m in Sources */ = {isa = PBXBuildFile; fileRef = 201FAEA214087B2E00021322 /* DCCrossHairView.m */; }; 11 | 201FAEAB14087B2E00021322 /* DCFrameView.m in Sources */ = {isa = PBXBuildFile; fileRef = 201FAEA414087B2E00021322 /* DCFrameView.m */; }; 12 | 201FAEAC14087B2E00021322 /* DCIntrospect.m in Sources */ = {isa = PBXBuildFile; fileRef = 201FAEA614087B2E00021322 /* DCIntrospect.m */; }; 13 | 201FAEAD14087B2E00021322 /* DCStatusBarOverlay.m in Sources */ = {isa = PBXBuildFile; fileRef = 201FAEA914087B2E00021322 /* DCStatusBarOverlay.m */; }; 14 | 201FAEB014087B8F00021322 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 201FAEAF14087B8F00021322 /* QuartzCore.framework */; }; 15 | 206533B3140F5D8D00E7DD73 /* bar-background@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 206533AF140F5D8D00E7DD73 /* bar-background@2x.png */; }; 16 | 206533B4140F5D8D00E7DD73 /* bar-highlight@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 206533B0140F5D8D00E7DD73 /* bar-highlight@2x.png */; }; 17 | 206533B5140F5D8D00E7DD73 /* handle-hover@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 206533B1140F5D8D00E7DD73 /* handle-hover@2x.png */; }; 18 | 206533B6140F5D8D00E7DD73 /* handle@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 206533B2140F5D8D00E7DD73 /* handle@2x.png */; }; 19 | 20E0A25413EB77310074762C /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 20E0A25313EB77310074762C /* UIKit.framework */; }; 20 | 20E0A25613EB77310074762C /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 20E0A25513EB77310074762C /* Foundation.framework */; }; 21 | 20E0A25813EB77310074762C /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 20E0A25713EB77310074762C /* CoreGraphics.framework */; }; 22 | 20E0A25E13EB77310074762C /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 20E0A25C13EB77310074762C /* InfoPlist.strings */; }; 23 | 20E0A26013EB77310074762C /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 20E0A25F13EB77310074762C /* main.m */; }; 24 | 20E0A26413EB77310074762C /* RangeSliderAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 20E0A26313EB77310074762C /* RangeSliderAppDelegate.m */; }; 25 | 20E0A26713EB77310074762C /* MainWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 20E0A26513EB77310074762C /* MainWindow.xib */; }; 26 | 20E0A26A13EB77310074762C /* RootViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 20E0A26913EB77310074762C /* RootViewController.m */; }; 27 | 20E0A26D13EB77310074762C /* RootViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 20E0A26B13EB77310074762C /* RootViewController.xib */; }; 28 | 20E0A27813EB774C0074762C /* bar-background.png in Resources */ = {isa = PBXBuildFile; fileRef = 20E0A27413EB774C0074762C /* bar-background.png */; }; 29 | 20E0A27913EB774C0074762C /* bar-highlight.png in Resources */ = {isa = PBXBuildFile; fileRef = 20E0A27513EB774C0074762C /* bar-highlight.png */; }; 30 | 20E0A27A13EB774C0074762C /* handle-hover.png in Resources */ = {isa = PBXBuildFile; fileRef = 20E0A27613EB774C0074762C /* handle-hover.png */; }; 31 | 20E0A27B13EB774C0074762C /* handle.png in Resources */ = {isa = PBXBuildFile; fileRef = 20E0A27713EB774C0074762C /* handle.png */; }; 32 | 20E0A27E13EB78FE0074762C /* RangeSlider.m in Sources */ = {isa = PBXBuildFile; fileRef = 20E0A27D13EB78FE0074762C /* RangeSlider.m */; }; 33 | /* End PBXBuildFile section */ 34 | 35 | /* Begin PBXFileReference section */ 36 | 201FAEA114087B2E00021322 /* DCCrossHairView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DCCrossHairView.h; sourceTree = ""; }; 37 | 201FAEA214087B2E00021322 /* DCCrossHairView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DCCrossHairView.m; sourceTree = ""; }; 38 | 201FAEA314087B2E00021322 /* DCFrameView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DCFrameView.h; sourceTree = ""; }; 39 | 201FAEA414087B2E00021322 /* DCFrameView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DCFrameView.m; sourceTree = ""; }; 40 | 201FAEA514087B2E00021322 /* DCIntrospect.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DCIntrospect.h; sourceTree = ""; }; 41 | 201FAEA614087B2E00021322 /* DCIntrospect.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DCIntrospect.m; sourceTree = ""; }; 42 | 201FAEA714087B2E00021322 /* DCIntrospectSettings.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DCIntrospectSettings.h; sourceTree = ""; }; 43 | 201FAEA814087B2E00021322 /* DCStatusBarOverlay.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DCStatusBarOverlay.h; sourceTree = ""; }; 44 | 201FAEA914087B2E00021322 /* DCStatusBarOverlay.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DCStatusBarOverlay.m; sourceTree = ""; }; 45 | 201FAEAF14087B8F00021322 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; }; 46 | 206533AF140F5D8D00E7DD73 /* bar-background@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "bar-background@2x.png"; sourceTree = ""; }; 47 | 206533B0140F5D8D00E7DD73 /* bar-highlight@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "bar-highlight@2x.png"; sourceTree = ""; }; 48 | 206533B1140F5D8D00E7DD73 /* handle-hover@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "handle-hover@2x.png"; sourceTree = ""; }; 49 | 206533B2140F5D8D00E7DD73 /* handle@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "handle@2x.png"; sourceTree = ""; }; 50 | 20E0A24F13EB77310074762C /* RangeSlider.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = RangeSlider.app; sourceTree = BUILT_PRODUCTS_DIR; }; 51 | 20E0A25313EB77310074762C /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 52 | 20E0A25513EB77310074762C /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 53 | 20E0A25713EB77310074762C /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; 54 | 20E0A25B13EB77310074762C /* RangeSlider-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "RangeSlider-Info.plist"; sourceTree = ""; }; 55 | 20E0A25D13EB77310074762C /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 56 | 20E0A25F13EB77310074762C /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 57 | 20E0A26113EB77310074762C /* RangeSlider-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "RangeSlider-Prefix.pch"; sourceTree = ""; }; 58 | 20E0A26213EB77310074762C /* RangeSliderAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RangeSliderAppDelegate.h; sourceTree = ""; }; 59 | 20E0A26313EB77310074762C /* RangeSliderAppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RangeSliderAppDelegate.m; sourceTree = ""; }; 60 | 20E0A26613EB77310074762C /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/MainWindow.xib; sourceTree = ""; }; 61 | 20E0A26813EB77310074762C /* RootViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RootViewController.h; sourceTree = ""; }; 62 | 20E0A26913EB77310074762C /* RootViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RootViewController.m; sourceTree = ""; }; 63 | 20E0A26C13EB77310074762C /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/RootViewController.xib; sourceTree = ""; }; 64 | 20E0A27413EB774C0074762C /* bar-background.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "bar-background.png"; sourceTree = ""; }; 65 | 20E0A27513EB774C0074762C /* bar-highlight.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "bar-highlight.png"; sourceTree = ""; }; 66 | 20E0A27613EB774C0074762C /* handle-hover.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "handle-hover.png"; sourceTree = ""; }; 67 | 20E0A27713EB774C0074762C /* handle.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = handle.png; sourceTree = ""; }; 68 | 20E0A27C13EB78FE0074762C /* RangeSlider.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RangeSlider.h; sourceTree = ""; }; 69 | 20E0A27D13EB78FE0074762C /* RangeSlider.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RangeSlider.m; sourceTree = ""; }; 70 | /* End PBXFileReference section */ 71 | 72 | /* Begin PBXFrameworksBuildPhase section */ 73 | 20E0A24C13EB77310074762C /* Frameworks */ = { 74 | isa = PBXFrameworksBuildPhase; 75 | buildActionMask = 2147483647; 76 | files = ( 77 | 201FAEB014087B8F00021322 /* QuartzCore.framework in Frameworks */, 78 | 20E0A25413EB77310074762C /* UIKit.framework in Frameworks */, 79 | 20E0A25613EB77310074762C /* Foundation.framework in Frameworks */, 80 | 20E0A25813EB77310074762C /* CoreGraphics.framework in Frameworks */, 81 | ); 82 | runOnlyForDeploymentPostprocessing = 0; 83 | }; 84 | /* End PBXFrameworksBuildPhase section */ 85 | 86 | /* Begin PBXGroup section */ 87 | 201FAEA014087B2E00021322 /* DCIntrospect */ = { 88 | isa = PBXGroup; 89 | children = ( 90 | 201FAEA114087B2E00021322 /* DCCrossHairView.h */, 91 | 201FAEA214087B2E00021322 /* DCCrossHairView.m */, 92 | 201FAEA314087B2E00021322 /* DCFrameView.h */, 93 | 201FAEA414087B2E00021322 /* DCFrameView.m */, 94 | 201FAEA514087B2E00021322 /* DCIntrospect.h */, 95 | 201FAEA614087B2E00021322 /* DCIntrospect.m */, 96 | 201FAEA714087B2E00021322 /* DCIntrospectSettings.h */, 97 | 201FAEA814087B2E00021322 /* DCStatusBarOverlay.h */, 98 | 201FAEA914087B2E00021322 /* DCStatusBarOverlay.m */, 99 | ); 100 | path = DCIntrospect; 101 | sourceTree = ""; 102 | }; 103 | 20E0A24413EB77310074762C = { 104 | isa = PBXGroup; 105 | children = ( 106 | 201FAEAF14087B8F00021322 /* QuartzCore.framework */, 107 | 20E0A25913EB77310074762C /* RangeSlider */, 108 | 20E0A25213EB77310074762C /* Frameworks */, 109 | 20E0A25013EB77310074762C /* Products */, 110 | ); 111 | sourceTree = ""; 112 | }; 113 | 20E0A25013EB77310074762C /* Products */ = { 114 | isa = PBXGroup; 115 | children = ( 116 | 20E0A24F13EB77310074762C /* RangeSlider.app */, 117 | ); 118 | name = Products; 119 | sourceTree = ""; 120 | }; 121 | 20E0A25213EB77310074762C /* Frameworks */ = { 122 | isa = PBXGroup; 123 | children = ( 124 | 20E0A25313EB77310074762C /* UIKit.framework */, 125 | 20E0A25513EB77310074762C /* Foundation.framework */, 126 | 20E0A25713EB77310074762C /* CoreGraphics.framework */, 127 | ); 128 | name = Frameworks; 129 | sourceTree = ""; 130 | }; 131 | 20E0A25913EB77310074762C /* RangeSlider */ = { 132 | isa = PBXGroup; 133 | children = ( 134 | 201FAEA014087B2E00021322 /* DCIntrospect */, 135 | 20E0A27313EB774C0074762C /* Images */, 136 | 20E0A26213EB77310074762C /* RangeSliderAppDelegate.h */, 137 | 20E0A26313EB77310074762C /* RangeSliderAppDelegate.m */, 138 | 20E0A26513EB77310074762C /* MainWindow.xib */, 139 | 20E0A26813EB77310074762C /* RootViewController.h */, 140 | 20E0A26913EB77310074762C /* RootViewController.m */, 141 | 20E0A27C13EB78FE0074762C /* RangeSlider.h */, 142 | 20E0A27D13EB78FE0074762C /* RangeSlider.m */, 143 | 20E0A26B13EB77310074762C /* RootViewController.xib */, 144 | 20E0A25A13EB77310074762C /* Supporting Files */, 145 | ); 146 | path = RangeSlider; 147 | sourceTree = ""; 148 | }; 149 | 20E0A25A13EB77310074762C /* Supporting Files */ = { 150 | isa = PBXGroup; 151 | children = ( 152 | 20E0A25B13EB77310074762C /* RangeSlider-Info.plist */, 153 | 20E0A25C13EB77310074762C /* InfoPlist.strings */, 154 | 20E0A25F13EB77310074762C /* main.m */, 155 | 20E0A26113EB77310074762C /* RangeSlider-Prefix.pch */, 156 | ); 157 | name = "Supporting Files"; 158 | sourceTree = ""; 159 | }; 160 | 20E0A27313EB774C0074762C /* Images */ = { 161 | isa = PBXGroup; 162 | children = ( 163 | 206533AF140F5D8D00E7DD73 /* bar-background@2x.png */, 164 | 206533B0140F5D8D00E7DD73 /* bar-highlight@2x.png */, 165 | 206533B1140F5D8D00E7DD73 /* handle-hover@2x.png */, 166 | 206533B2140F5D8D00E7DD73 /* handle@2x.png */, 167 | 20E0A27413EB774C0074762C /* bar-background.png */, 168 | 20E0A27513EB774C0074762C /* bar-highlight.png */, 169 | 20E0A27613EB774C0074762C /* handle-hover.png */, 170 | 20E0A27713EB774C0074762C /* handle.png */, 171 | ); 172 | path = Images; 173 | sourceTree = ""; 174 | }; 175 | /* End PBXGroup section */ 176 | 177 | /* Begin PBXNativeTarget section */ 178 | 20E0A24E13EB77310074762C /* RangeSlider */ = { 179 | isa = PBXNativeTarget; 180 | buildConfigurationList = 20E0A27013EB77310074762C /* Build configuration list for PBXNativeTarget "RangeSlider" */; 181 | buildPhases = ( 182 | 20E0A24B13EB77310074762C /* Sources */, 183 | 20E0A24C13EB77310074762C /* Frameworks */, 184 | 20E0A24D13EB77310074762C /* Resources */, 185 | ); 186 | buildRules = ( 187 | ); 188 | dependencies = ( 189 | ); 190 | name = RangeSlider; 191 | productName = RangeSlider; 192 | productReference = 20E0A24F13EB77310074762C /* RangeSlider.app */; 193 | productType = "com.apple.product-type.application"; 194 | }; 195 | /* End PBXNativeTarget section */ 196 | 197 | /* Begin PBXProject section */ 198 | 20E0A24613EB77310074762C /* Project object */ = { 199 | isa = PBXProject; 200 | buildConfigurationList = 20E0A24913EB77310074762C /* Build configuration list for PBXProject "RangeSlider" */; 201 | compatibilityVersion = "Xcode 3.2"; 202 | developmentRegion = English; 203 | hasScannedForEncodings = 0; 204 | knownRegions = ( 205 | en, 206 | ); 207 | mainGroup = 20E0A24413EB77310074762C; 208 | productRefGroup = 20E0A25013EB77310074762C /* Products */; 209 | projectDirPath = ""; 210 | projectRoot = ""; 211 | targets = ( 212 | 20E0A24E13EB77310074762C /* RangeSlider */, 213 | ); 214 | }; 215 | /* End PBXProject section */ 216 | 217 | /* Begin PBXResourcesBuildPhase section */ 218 | 20E0A24D13EB77310074762C /* Resources */ = { 219 | isa = PBXResourcesBuildPhase; 220 | buildActionMask = 2147483647; 221 | files = ( 222 | 20E0A25E13EB77310074762C /* InfoPlist.strings in Resources */, 223 | 20E0A26713EB77310074762C /* MainWindow.xib in Resources */, 224 | 20E0A26D13EB77310074762C /* RootViewController.xib in Resources */, 225 | 20E0A27813EB774C0074762C /* bar-background.png in Resources */, 226 | 20E0A27913EB774C0074762C /* bar-highlight.png in Resources */, 227 | 20E0A27A13EB774C0074762C /* handle-hover.png in Resources */, 228 | 20E0A27B13EB774C0074762C /* handle.png in Resources */, 229 | 206533B3140F5D8D00E7DD73 /* bar-background@2x.png in Resources */, 230 | 206533B4140F5D8D00E7DD73 /* bar-highlight@2x.png in Resources */, 231 | 206533B5140F5D8D00E7DD73 /* handle-hover@2x.png in Resources */, 232 | 206533B6140F5D8D00E7DD73 /* handle@2x.png in Resources */, 233 | ); 234 | runOnlyForDeploymentPostprocessing = 0; 235 | }; 236 | /* End PBXResourcesBuildPhase section */ 237 | 238 | /* Begin PBXSourcesBuildPhase section */ 239 | 20E0A24B13EB77310074762C /* Sources */ = { 240 | isa = PBXSourcesBuildPhase; 241 | buildActionMask = 2147483647; 242 | files = ( 243 | 20E0A26013EB77310074762C /* main.m in Sources */, 244 | 20E0A26413EB77310074762C /* RangeSliderAppDelegate.m in Sources */, 245 | 20E0A26A13EB77310074762C /* RootViewController.m in Sources */, 246 | 20E0A27E13EB78FE0074762C /* RangeSlider.m in Sources */, 247 | 201FAEAA14087B2E00021322 /* DCCrossHairView.m in Sources */, 248 | 201FAEAB14087B2E00021322 /* DCFrameView.m in Sources */, 249 | 201FAEAC14087B2E00021322 /* DCIntrospect.m in Sources */, 250 | 201FAEAD14087B2E00021322 /* DCStatusBarOverlay.m in Sources */, 251 | ); 252 | runOnlyForDeploymentPostprocessing = 0; 253 | }; 254 | /* End PBXSourcesBuildPhase section */ 255 | 256 | /* Begin PBXVariantGroup section */ 257 | 20E0A25C13EB77310074762C /* InfoPlist.strings */ = { 258 | isa = PBXVariantGroup; 259 | children = ( 260 | 20E0A25D13EB77310074762C /* en */, 261 | ); 262 | name = InfoPlist.strings; 263 | sourceTree = ""; 264 | }; 265 | 20E0A26513EB77310074762C /* MainWindow.xib */ = { 266 | isa = PBXVariantGroup; 267 | children = ( 268 | 20E0A26613EB77310074762C /* en */, 269 | ); 270 | name = MainWindow.xib; 271 | sourceTree = ""; 272 | }; 273 | 20E0A26B13EB77310074762C /* RootViewController.xib */ = { 274 | isa = PBXVariantGroup; 275 | children = ( 276 | 20E0A26C13EB77310074762C /* en */, 277 | ); 278 | name = RootViewController.xib; 279 | sourceTree = ""; 280 | }; 281 | /* End PBXVariantGroup section */ 282 | 283 | /* Begin XCBuildConfiguration section */ 284 | 20E0A26E13EB77310074762C /* Debug */ = { 285 | isa = XCBuildConfiguration; 286 | buildSettings = { 287 | ALWAYS_SEARCH_USER_PATHS = NO; 288 | ARCHS = "$(ARCHS_STANDARD_32_BIT)"; 289 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 290 | COPY_PHASE_STRIP = NO; 291 | GCC_C_LANGUAGE_STANDARD = gnu99; 292 | GCC_DYNAMIC_NO_PIC = NO; 293 | GCC_OPTIMIZATION_LEVEL = 0; 294 | GCC_PREPROCESSOR_DEFINITIONS = ( 295 | "DEBUG=1", 296 | "$(inherited)", 297 | ); 298 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 299 | GCC_VERSION = com.apple.compilers.llvmgcc42; 300 | GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; 301 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 302 | GCC_WARN_UNUSED_VARIABLE = YES; 303 | IPHONEOS_DEPLOYMENT_TARGET = 4.3; 304 | SDKROOT = iphoneos; 305 | }; 306 | name = Debug; 307 | }; 308 | 20E0A26F13EB77310074762C /* Release */ = { 309 | isa = XCBuildConfiguration; 310 | buildSettings = { 311 | ALWAYS_SEARCH_USER_PATHS = NO; 312 | ARCHS = "$(ARCHS_STANDARD_32_BIT)"; 313 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 314 | COPY_PHASE_STRIP = YES; 315 | GCC_C_LANGUAGE_STANDARD = gnu99; 316 | GCC_VERSION = com.apple.compilers.llvmgcc42; 317 | GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; 318 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 319 | GCC_WARN_UNUSED_VARIABLE = YES; 320 | IPHONEOS_DEPLOYMENT_TARGET = 4.3; 321 | OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1"; 322 | SDKROOT = iphoneos; 323 | VALIDATE_PRODUCT = YES; 324 | }; 325 | name = Release; 326 | }; 327 | 20E0A27113EB77310074762C /* Debug */ = { 328 | isa = XCBuildConfiguration; 329 | buildSettings = { 330 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 331 | GCC_PREFIX_HEADER = "RangeSlider/RangeSlider-Prefix.pch"; 332 | INFOPLIST_FILE = "RangeSlider/RangeSlider-Info.plist"; 333 | PRODUCT_NAME = "$(TARGET_NAME)"; 334 | WRAPPER_EXTENSION = app; 335 | }; 336 | name = Debug; 337 | }; 338 | 20E0A27213EB77310074762C /* Release */ = { 339 | isa = XCBuildConfiguration; 340 | buildSettings = { 341 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 342 | GCC_PREFIX_HEADER = "RangeSlider/RangeSlider-Prefix.pch"; 343 | INFOPLIST_FILE = "RangeSlider/RangeSlider-Info.plist"; 344 | PRODUCT_NAME = "$(TARGET_NAME)"; 345 | WRAPPER_EXTENSION = app; 346 | }; 347 | name = Release; 348 | }; 349 | /* End XCBuildConfiguration section */ 350 | 351 | /* Begin XCConfigurationList section */ 352 | 20E0A24913EB77310074762C /* Build configuration list for PBXProject "RangeSlider" */ = { 353 | isa = XCConfigurationList; 354 | buildConfigurations = ( 355 | 20E0A26E13EB77310074762C /* Debug */, 356 | 20E0A26F13EB77310074762C /* Release */, 357 | ); 358 | defaultConfigurationIsVisible = 0; 359 | defaultConfigurationName = Release; 360 | }; 361 | 20E0A27013EB77310074762C /* Build configuration list for PBXNativeTarget "RangeSlider" */ = { 362 | isa = XCConfigurationList; 363 | buildConfigurations = ( 364 | 20E0A27113EB77310074762C /* Debug */, 365 | 20E0A27213EB77310074762C /* Release */, 366 | ); 367 | defaultConfigurationIsVisible = 0; 368 | defaultConfigurationName = Release; 369 | }; 370 | /* End XCConfigurationList section */ 371 | }; 372 | rootObject = 20E0A24613EB77310074762C /* Project object */; 373 | } 374 | -------------------------------------------------------------------------------- /RangeSlider.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /RangeSlider.xcodeproj/xcuserdata/mal.xcuserdatad/xcdebugger/Breakpoints.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /RangeSlider.xcodeproj/xcuserdata/mal.xcuserdatad/xcschemes/RangeSlider.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | 14 | 20 | 21 | 22 | 23 | 24 | 29 | 30 | 31 | 32 | 38 | 39 | 45 | 46 | 47 | 48 | 49 | 50 | 55 | 56 | 62 | 63 | 64 | 65 | 67 | 68 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /RangeSlider.xcodeproj/xcuserdata/mal.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | RangeSlider.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 20E0A24E13EB77310074762C 16 | 17 | primary 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /RangeSlider/DCIntrospect/DCCrossHairView.h: -------------------------------------------------------------------------------- 1 | // 2 | // DCCrossHairView.h 3 | // 4 | // Created by Domestic Cat on 3/05/11. 5 | // 6 | 7 | 8 | @interface DCCrossHairView : UIView 9 | { 10 | } 11 | 12 | @property (nonatomic, retain) UIColor *color; 13 | 14 | - (id)initWithFrame:(CGRect)frame color:(UIColor *)aColor; 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /RangeSlider/DCIntrospect/DCCrossHairView.m: -------------------------------------------------------------------------------- 1 | // 2 | // DCCrossHairView.m 3 | // 4 | // Created by Domestic Cat on 3/05/11. 5 | // 6 | 7 | #import "DCCrossHairView.h" 8 | 9 | @implementation DCCrossHairView 10 | @synthesize color; 11 | 12 | - (void)dealloc 13 | { 14 | [color release]; 15 | [super dealloc]; 16 | } 17 | 18 | - (id)initWithFrame:(CGRect)frame color:(UIColor *)aColor 19 | { 20 | if ((self = [super initWithFrame:frame])) 21 | { 22 | self.color = aColor; 23 | self.backgroundColor = [UIColor clearColor]; 24 | self.opaque = NO; 25 | } 26 | 27 | return self; 28 | } 29 | 30 | - (void)drawRect:(CGRect)rect 31 | { 32 | CGContextRef context = UIGraphicsGetCurrentContext(); 33 | [self.color set]; 34 | CGContextMoveToPoint(context, floorf(self.bounds.size.width / 2.0f) + 0.5f, 0.0f); 35 | CGContextAddLineToPoint(context, floorf(self.bounds.size.width / 2.0f) + 0.5f, self.bounds.size.height); 36 | CGContextStrokePath(context); 37 | 38 | CGContextMoveToPoint(context, 0, floorf(self.bounds.size.height / 2.0f) + 0.5f); 39 | CGContextAddLineToPoint(context, self.bounds.size.width, floorf(self.bounds.size.height / 2.0f) + 0.5f); 40 | CGContextStrokePath(context); 41 | } 42 | 43 | @end 44 | -------------------------------------------------------------------------------- /RangeSlider/DCIntrospect/DCFrameView.h: -------------------------------------------------------------------------------- 1 | // 2 | // DCFrameView.h 3 | // 4 | // Created by Domestic Cat on 29/04/11. 5 | // 6 | 7 | #import 8 | #import "DCCrossHairView.h" 9 | 10 | @protocol DCFrameViewDelegate 11 | 12 | @required 13 | 14 | - (void)touchAtPoint:(CGPoint)point; 15 | 16 | @end 17 | 18 | @interface DCFrameView : UIView 19 | { 20 | 21 | } 22 | 23 | @property (nonatomic, assign) id delegate; 24 | @property (nonatomic) CGRect mainRect; 25 | @property (nonatomic) CGRect superRect; 26 | @property (nonatomic, retain) UILabel *touchPointLabel; 27 | @property (nonatomic, retain) NSMutableArray *rectsToOutline; 28 | @property (nonatomic, retain) DCCrossHairView *touchPointView; 29 | 30 | /////////// 31 | // Setup // 32 | /////////// 33 | 34 | - (id)initWithFrame:(CGRect)frame delegate:(id)aDelegate; 35 | 36 | //////////////////// 37 | // Custom Setters // 38 | //////////////////// 39 | 40 | - (void)setMainRect:(CGRect)newMainRect; 41 | - (void)setSuperRect:(CGRect)newSuperRect; 42 | 43 | ///////////////////// 44 | // Drawing/Display // 45 | ///////////////////// 46 | 47 | - (void)drawRect:(CGRect)rect; 48 | 49 | //////////////////// 50 | // Touch Handling // 51 | //////////////////// 52 | 53 | - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event; 54 | 55 | @end 56 | -------------------------------------------------------------------------------- /RangeSlider/DCIntrospect/DCFrameView.m: -------------------------------------------------------------------------------- 1 | // 2 | // DCFrameView.m 3 | // 4 | // Created by Domestic Cat on 29/04/11. 5 | // 6 | 7 | #import "DCFrameView.h" 8 | 9 | @implementation DCFrameView 10 | @synthesize delegate; 11 | @synthesize mainRect, superRect; 12 | @synthesize touchPointLabel; 13 | @synthesize rectsToOutline; 14 | @synthesize touchPointView; 15 | 16 | - (void)dealloc 17 | { 18 | self.delegate = nil; 19 | [touchPointLabel release]; 20 | [touchPointView release]; 21 | 22 | [super dealloc]; 23 | } 24 | 25 | #pragma Setup 26 | 27 | - (id)initWithFrame:(CGRect)frame delegate:(id)aDelegate 28 | { 29 | self = [super initWithFrame:frame]; 30 | if (self) 31 | { 32 | self.delegate = aDelegate; 33 | self.backgroundColor = [UIColor clearColor]; 34 | self.opaque = NO; 35 | 36 | self.touchPointLabel = [[[UILabel alloc] initWithFrame:CGRectZero] autorelease]; 37 | self.touchPointLabel.text = @"X 320 Y 480"; 38 | self.touchPointLabel.font = [UIFont boldSystemFontOfSize:12.0f]; 39 | self.touchPointLabel.textAlignment = UITextAlignmentCenter; 40 | self.touchPointLabel.textColor = [UIColor whiteColor]; 41 | self.touchPointLabel.backgroundColor = [UIColor colorWithWhite:0.0f alpha:0.65f]; 42 | self.touchPointLabel.layer.cornerRadius = 5.5f; 43 | self.touchPointLabel.layer.masksToBounds = YES; 44 | self.touchPointLabel.alpha = 0.0f; 45 | [self addSubview:self.touchPointLabel]; 46 | 47 | self.rectsToOutline = [NSMutableArray array]; 48 | 49 | self.touchPointView = [[[DCCrossHairView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 17.0f, 17.0f) color:[UIColor blueColor]] autorelease]; 50 | self.touchPointView.alpha = 0.0f; 51 | [self addSubview:self.touchPointView]; 52 | } 53 | return self; 54 | } 55 | 56 | #pragma Custom Setters 57 | 58 | - (void)setMainRect:(CGRect)newMainRect 59 | { 60 | mainRect = newMainRect; 61 | [self setNeedsDisplay]; 62 | } 63 | 64 | - (void)setSuperRect:(CGRect)newSuperRect 65 | { 66 | superRect = newSuperRect; 67 | [self setNeedsDisplay]; 68 | } 69 | 70 | #pragma Drawing/Display 71 | 72 | - (void)drawRect:(CGRect)rect 73 | { 74 | CGContextRef context = UIGraphicsGetCurrentContext(); 75 | 76 | if (self.rectsToOutline.count > 0) 77 | { 78 | for (NSValue *value in self.rectsToOutline) 79 | { 80 | UIColor *randomColor = [UIColor colorWithRed:(arc4random() % 256) / 256.0f 81 | green:(arc4random() % 256) / 256.0f 82 | blue:(arc4random() % 256) / 256.0f 83 | alpha:1.0f]; 84 | [randomColor set]; 85 | CGRect valueRect = [value CGRectValue]; 86 | valueRect = CGRectMake(valueRect.origin.x + 0.5f, 87 | valueRect.origin.y + 0.5f, 88 | valueRect.size.width - 1.0f, 89 | valueRect.size.height - 1.0f); 90 | CGContextStrokeRect(context, valueRect); 91 | } 92 | return; 93 | } 94 | 95 | if (CGRectIsEmpty(self.mainRect)) 96 | return; 97 | 98 | CGRect mainRectOffset = CGRectOffset(mainRect, -superRect.origin.x, -superRect.origin.y); 99 | BOOL showAntialiasingWarning = NO; 100 | if (! CGRectIsEmpty(self.superRect)) 101 | { 102 | if ((mainRectOffset.origin.x != floorf(mainRectOffset.origin.x) && mainRect.origin.x != 0) || (mainRectOffset.origin.y != floor(mainRectOffset.origin.y) && mainRect.origin.y != 0)) 103 | showAntialiasingWarning = YES; 104 | } 105 | 106 | if (showAntialiasingWarning) 107 | { 108 | [[UIColor redColor] set]; 109 | NSLog(@"DCIntrospect: *** WARNING: One or more values of this view's frame are non-integer values. This view will likely look blurry. ***"); 110 | } 111 | else 112 | { 113 | [[UIColor blueColor] set]; 114 | } 115 | 116 | CGRect adjustedMainRect = CGRectMake(self.mainRect.origin.x + 0.5f, 117 | self.mainRect.origin.y + 0.5f, 118 | self.mainRect.size.width - 1.0f, 119 | self.mainRect.size.height - 1.0f); 120 | CGContextStrokeRect(context, adjustedMainRect); 121 | 122 | UIFont *font = [UIFont systemFontOfSize:10.0f]; 123 | 124 | float dash[2] = {3, 3}; 125 | CGContextSetLineDash(context, 0, dash, 2); 126 | 127 | // edge->left side 128 | CGContextMoveToPoint(context, CGRectGetMinX(self.superRect), floorf(CGRectGetMidY(adjustedMainRect)) + 0.5f); 129 | CGContextAddLineToPoint(context, CGRectGetMinX(adjustedMainRect), floorf(CGRectGetMidY(adjustedMainRect)) + 0.5f); 130 | CGContextStrokePath(context); 131 | 132 | NSString *leftDistanceString = (showAntialiasingWarning) ? [NSString stringWithFormat:@"%.1f", CGRectGetMinX(mainRectOffset)] : [NSString stringWithFormat:@"%.0f", CGRectGetMinX(mainRectOffset)]; 133 | CGSize leftDistanceStringSize = [leftDistanceString sizeWithFont:font]; 134 | [leftDistanceString drawInRect:CGRectMake(CGRectGetMinX(superRect) + 1.0f, 135 | floorf(CGRectGetMidY(adjustedMainRect)) - leftDistanceStringSize.height, 136 | leftDistanceStringSize.width, 137 | leftDistanceStringSize.height) 138 | withFont:font]; 139 | 140 | // right side->edge 141 | if (CGRectGetMaxX(self.mainRect) < CGRectGetMaxX(self.superRect)) 142 | { 143 | CGContextMoveToPoint(context, CGRectGetMaxX(adjustedMainRect), floorf(CGRectGetMidY(adjustedMainRect)) + 0.5f); 144 | CGContextAddLineToPoint(context, CGRectGetMaxX(self.superRect), floorf(CGRectGetMidY(adjustedMainRect)) + 0.5f); 145 | CGContextStrokePath(context); 146 | } 147 | NSString *rightDistanceString = (showAntialiasingWarning) ? [NSString stringWithFormat:@"%.1f", CGRectGetMaxX(self.superRect) - CGRectGetMaxX(adjustedMainRect) - 0.5] : [NSString stringWithFormat:@"%.0f", CGRectGetMaxX(self.superRect) - CGRectGetMaxX(adjustedMainRect) - 0.5]; 148 | CGSize rightDistanceStringSize = [rightDistanceString sizeWithFont:font]; 149 | [rightDistanceString drawInRect:CGRectMake(CGRectGetMaxX(self.superRect) - rightDistanceStringSize.width - 1.0f, 150 | floorf(CGRectGetMidY(adjustedMainRect)) - 0.5f - rightDistanceStringSize.height, 151 | rightDistanceStringSize.width, 152 | rightDistanceStringSize.height) 153 | withFont:font]; 154 | 155 | // edge->top side 156 | CGContextMoveToPoint(context, floorf(CGRectGetMidX(adjustedMainRect)) + 0.5f, self.superRect.origin.y); 157 | CGContextAddLineToPoint(context, floorf(CGRectGetMidX(adjustedMainRect)) + 0.5f, CGRectGetMinY(adjustedMainRect)); 158 | CGContextStrokePath(context); 159 | NSString *topDistanceString = (showAntialiasingWarning) ? [NSString stringWithFormat:@"%.1f", mainRectOffset.origin.y] : [NSString stringWithFormat:@"%.0f", mainRectOffset.origin.y]; 160 | CGSize topDistanceStringSize = [topDistanceString sizeWithFont:font]; 161 | [topDistanceString drawInRect:CGRectMake(floorf(CGRectGetMidX(adjustedMainRect)) + 3.0f, 162 | floorf(CGRectGetMinY(self.superRect)), 163 | topDistanceStringSize.width, 164 | topDistanceStringSize.height) 165 | withFont:font]; 166 | 167 | // bottom side->edge 168 | if (CGRectGetMaxY(self.mainRect) < CGRectGetMaxY(self.superRect)) 169 | { 170 | CGContextMoveToPoint(context, floorf(CGRectGetMidX(adjustedMainRect)) + 0.5f, CGRectGetMaxY(adjustedMainRect)); 171 | CGContextAddLineToPoint(context, floorf(CGRectGetMidX(adjustedMainRect)) + 0.5f, CGRectGetMaxY(self.superRect)); 172 | CGContextStrokePath(context); 173 | } 174 | NSString *bottomDistanceString = (showAntialiasingWarning) ? [NSString stringWithFormat:@"%.1f", CGRectGetMaxY(self.superRect) - CGRectGetMaxY(mainRectOffset)] : [NSString stringWithFormat:@"%.0f", self.superRect.size.height - mainRectOffset.origin.y - mainRectOffset.size.height]; 175 | CGSize bottomDistanceStringSize = [bottomDistanceString sizeWithFont:font]; 176 | [bottomDistanceString drawInRect:CGRectMake(floorf(CGRectGetMidX(adjustedMainRect)) + 3.0f, 177 | floorf(CGRectGetMaxY(self.superRect)) - bottomDistanceStringSize.height - 1.0f, 178 | bottomDistanceStringSize.width, 179 | bottomDistanceStringSize.height) 180 | withFont:font]; 181 | 182 | } 183 | 184 | #pragma Touch Handling 185 | 186 | - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event 187 | { 188 | CGFloat labelDistance = 16.0f; 189 | CGPoint touchPoint = [[touches anyObject] locationInView:self]; 190 | 191 | // adjust the point so it's exactly on the point of the mouse cursor 192 | touchPoint.x -= 1; 193 | touchPoint.y -= 2; 194 | 195 | NSString *touchPontLabelString = [NSString stringWithFormat:@"%.0f, %.0f", touchPoint.x, touchPoint.y]; 196 | self.touchPointLabel.text = touchPontLabelString; 197 | 198 | CGSize stringSize = [touchPontLabelString sizeWithFont:touchPointLabel.font]; 199 | CGRect frame = CGRectMake(touchPoint.x - floorf(stringSize.width / 2.0f) - 5.0f, 200 | touchPoint.y - stringSize.height - labelDistance, 201 | stringSize.width + 11.0f, 202 | stringSize.height + 4.0f); 203 | 204 | // make sure the label stays inside the frame 205 | UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation; 206 | CGFloat minY = UIInterfaceOrientationIsPortrait(orientation) ? [UIApplication sharedApplication].statusBarFrame.size.height : [UIApplication sharedApplication].statusBarFrame.size.width; 207 | minY += 2.0f; // to keep it touching the top bar 208 | if (frame.origin.x < 2.0f) 209 | frame.origin.x = 2.0f; 210 | else if (CGRectGetMaxX(frame) > self.bounds.size.width - 2.0f) 211 | frame.origin.x = self.bounds.size.width - frame.size.width - 2.0f; 212 | if (frame.origin.y < minY) 213 | frame.origin.y = touchPoint.y + stringSize.height + 4.0f; 214 | 215 | self.touchPointLabel.frame = frame; 216 | self.touchPointView.center = CGPointMake(touchPoint.x + 0.5f, touchPoint.y + 0.5f); 217 | self.touchPointView.alpha = self.touchPointLabel.alpha = 1.0f; 218 | 219 | [self.delegate touchAtPoint:touchPoint]; 220 | } 221 | 222 | - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event 223 | { 224 | [self touchesBegan:touches withEvent:event]; 225 | } 226 | 227 | - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event 228 | { 229 | [UIView animateWithDuration:0.08 animations:^{ 230 | self.touchPointView.alpha = self.touchPointLabel.alpha = 0.0f; 231 | }]; 232 | } 233 | 234 | @end 235 | -------------------------------------------------------------------------------- /RangeSlider/DCIntrospect/DCIntrospect.h: -------------------------------------------------------------------------------- 1 | // 2 | // DCIntrospect.h 3 | // 4 | // Created by Domestic Cat on 29/04/11. 5 | // 6 | 7 | #define kDCIntrospectNotificationIntrospectionDidStart @"kDCIntrospectNotificationIntrospectionDidStart" 8 | #define kDCIntrospectNotificationIntrospectionDidEnd @"kDCIntrospectNotificationIntrospectionDidEnd" 9 | #define kDCIntrospectAnimationDuration 0.08 10 | 11 | #import 12 | #include "TargetConditionals.h" 13 | 14 | #import "DCIntrospectSettings.h" 15 | #import "DCFrameView.h" 16 | #import "DCStatusBarOverlay.h" 17 | 18 | #ifdef DEBUG 19 | 20 | @interface UIView (debug) 21 | 22 | - (NSString *)recursiveDescription; 23 | 24 | @end 25 | 26 | #endif 27 | 28 | @interface DCIntrospect : NSObject 29 | { 30 | } 31 | 32 | @property (nonatomic) BOOL keyboardBindingsOn; // default: YES 33 | @property (nonatomic) BOOL showStatusBarOverlay; // default: YES 34 | @property (nonatomic, retain) UIGestureRecognizer *invokeGestureRecognizer; // default: nil 35 | 36 | @property (nonatomic) BOOL on; 37 | @property (nonatomic) BOOL handleArrowKeys; 38 | @property (nonatomic) BOOL viewOutlines; 39 | @property (nonatomic) BOOL highlightNonOpaqueViews; 40 | @property (nonatomic) BOOL flashOnRedraw; 41 | @property (nonatomic, retain) DCFrameView *frameView; 42 | @property (nonatomic, retain) UITextView *inputTextView; 43 | @property (nonatomic, retain) DCStatusBarOverlay *statusBarOverlay; 44 | 45 | @property (nonatomic, retain) NSMutableDictionary *objectNames; 46 | 47 | @property (nonatomic, assign) UIView *currentView; 48 | @property (nonatomic) CGRect originalFrame; 49 | @property (nonatomic) CGFloat originalAlpha; 50 | @property (nonatomic, retain) NSMutableArray *currentViewHistory; 51 | 52 | @property (nonatomic) BOOL showingHelp; 53 | 54 | /////////// 55 | // Setup // 56 | /////////// 57 | 58 | + (DCIntrospect *)sharedIntrospector; // this returns nil when NOT in DEGBUG mode 59 | - (void)start; // NOTE: call setup AFTER [window makeKeyAndVisible] so statusBarOrientation is reported correctly. 60 | 61 | //////////////////// 62 | // Custom Setters // 63 | //////////////////// 64 | 65 | - (void)setInvokeGestureRecognizer:(UIGestureRecognizer *)newGestureRecognizer; 66 | - (void)setKeyboardBindingsOn:(BOOL)keyboardBindingsOn; 67 | 68 | ////////////////// 69 | // Main Actions // 70 | ////////////////// 71 | 72 | - (void)invokeIntrospector; // can be called manually 73 | - (void)touchAtPoint:(CGPoint)point; // can be called manually 74 | - (void)selectView:(UIView *)view; 75 | - (void)statusBarTapped; 76 | 77 | ////////////////////// 78 | // Keyboard Capture // 79 | ////////////////////// 80 | 81 | - (void)textViewDidChangeSelection:(UITextView *)textView; 82 | - (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)string; 83 | 84 | ///////////////////////////////// 85 | // Logging Code & Object Names // 86 | ///////////////////////////////// 87 | 88 | - (void)logCodeForCurrentViewChanges; 89 | 90 | // make sure all names that are added are removed at dealloc or else they will be retained here! 91 | - (void)setName:(NSString *)name forObject:(id)object accessedWithSelf:(BOOL)accessedWithSelf; 92 | - (NSString *)nameForObject:(id)object; 93 | - (void)removeNamesForViewsInView:(UIView *)view; 94 | - (void)removeNameForObject:(id)object; 95 | 96 | //////////// 97 | // Layout // 98 | //////////// 99 | 100 | - (void)updateFrameView; 101 | - (void)updateStatusBar; 102 | - (void)updateViews; 103 | - (void)showTemporaryStringInStatusBar:(NSString *)string; 104 | 105 | ///////////// 106 | // Actions // 107 | ///////////// 108 | 109 | - (void)logRecursiveDescriptionForCurrentView; 110 | - (void)logRecursiveDescriptionForView:(UIView *)view; 111 | - (void)forceSetNeedsDisplay; 112 | - (void)forceSetNeedsLayout; 113 | - (void)forceReloadOfView; 114 | - (void)toggleOutlines; 115 | - (void)addOutlinesToFrameViewFromSubview:(UIView *)view; 116 | - (void)toggleNonOpaqueViews; 117 | - (void)setBackgroundColor:(UIColor *)color ofNonOpaqueViewsInSubview:(UIView *)view; 118 | - (void)toggleRedrawFlashing; 119 | - (void)callDrawRectOnViewsInSubview:(UIView *)subview; 120 | - (void)flashRect:(CGRect)rect inView:(UIView *)view; 121 | 122 | ///////////////////////////// 123 | // (Somewhat) Experimental // 124 | ///////////////////////////// 125 | 126 | - (void)logPropertiesForCurrentView; 127 | - (void)logPropertiesForObject:(id)object; 128 | - (void)logAccessabilityPropertiesForObject:(id)object; 129 | - (NSArray *)subclassesOfClass:(Class)parentClass; 130 | 131 | ///////////////////////// 132 | // Description Methods // 133 | ///////////////////////// 134 | 135 | - (NSString *)describeProperty:(NSString *)propertyName value:(id)value; 136 | - (NSString *)describeColor:(UIColor *)color; 137 | 138 | ///////////////////////// 139 | // DCIntrospector Help // 140 | ///////////////////////// 141 | 142 | - (void)toggleHelp; 143 | - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType; 144 | 145 | //////////////////// 146 | // Helper Methods // 147 | //////////////////// 148 | 149 | - (UIWindow *)mainWindow; 150 | - (NSMutableArray *)viewsAtPoint:(CGPoint)touchPoint inView:(UIView *)view; 151 | - (void)fadeView:(UIView *)view toAlpha:(CGFloat)alpha; 152 | - (BOOL)view:(UIView *)view containsSubview:(UIView *)subview; 153 | - (BOOL)shouldIgnoreView:(UIView *)view; 154 | 155 | @end 156 | -------------------------------------------------------------------------------- /RangeSlider/DCIntrospect/DCIntrospect.m: -------------------------------------------------------------------------------- 1 | // 2 | // DCIntrospect.m 3 | // 4 | // Created by Domestic Cat on 29/04/11. 5 | // 6 | 7 | #import "DCIntrospect.h" 8 | #import 9 | 10 | 11 | @interface DCIntrospect () 12 | 13 | - (void)takeFirstResponder; 14 | 15 | @end 16 | 17 | 18 | DCIntrospect *sharedInstance = nil; 19 | 20 | @implementation DCIntrospect 21 | @synthesize keyboardBindingsOn, showStatusBarOverlay, invokeGestureRecognizer; 22 | @synthesize on; 23 | @synthesize handleArrowKeys; 24 | @synthesize viewOutlines, highlightNonOpaqueViews, flashOnRedraw; 25 | @synthesize statusBarOverlay; 26 | @synthesize inputTextView; 27 | @synthesize frameView; 28 | @synthesize objectNames; 29 | @synthesize currentView, originalFrame, originalAlpha; 30 | @synthesize currentViewHistory; 31 | @synthesize showingHelp; 32 | 33 | #pragma mark Setup 34 | 35 | + (void)load 36 | { 37 | NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 38 | 39 | NSString *simulatorRoot = [[[NSProcessInfo processInfo] environment] objectForKey:@"IPHONE_SIMULATOR_ROOT"]; 40 | if (simulatorRoot) 41 | { 42 | void *AppSupport = dlopen([[simulatorRoot stringByAppendingPathComponent:@"/System/Library/PrivateFrameworks/AppSupport.framework/AppSupport"] fileSystemRepresentation], RTLD_LAZY); 43 | CFStringRef (*CPCopySharedResourcesPreferencesDomainForDomain)(CFStringRef domain) = dlsym(AppSupport, "CPCopySharedResourcesPreferencesDomainForDomain"); 44 | if (CPCopySharedResourcesPreferencesDomainForDomain) 45 | { 46 | CFStringRef accessibilityDomain = CPCopySharedResourcesPreferencesDomainForDomain(CFSTR("com.apple.Accessibility")); 47 | if (accessibilityDomain) 48 | { 49 | // This must be done *before* UIApplicationMain, hence +load 50 | CFPreferencesSetValue(CFSTR("ApplicationAccessibilityEnabled"), kCFBooleanTrue, accessibilityDomain, kCFPreferencesAnyUser, kCFPreferencesAnyHost); 51 | CFRelease(accessibilityDomain); 52 | } 53 | } 54 | } 55 | 56 | [pool drain]; 57 | } 58 | 59 | static void *originalValueForKeyIMPKey = &originalValueForKeyIMPKey; 60 | 61 | id UITextInputTraits_valueForKey(id self, SEL _cmd, NSString *key); 62 | id UITextInputTraits_valueForKey(id self, SEL _cmd, NSString *key) 63 | { 64 | static NSMutableSet *textInputTraitsProperties = nil; 65 | if (!textInputTraitsProperties) 66 | { 67 | textInputTraitsProperties = [[NSMutableSet alloc] init]; 68 | unsigned int count = 0; 69 | objc_property_t *properties = protocol_copyPropertyList(@protocol(UITextInputTraits), &count); 70 | for (unsigned int i = 0; i < count; i++) 71 | { 72 | objc_property_t property = properties[i]; 73 | NSString *propertyName = [NSString stringWithUTF8String:property_getName(property)]; 74 | [textInputTraitsProperties addObject:propertyName]; 75 | } 76 | free(properties); 77 | } 78 | 79 | IMP valueForKey = [objc_getAssociatedObject([self class], originalValueForKeyIMPKey) pointerValue]; 80 | if ([textInputTraitsProperties containsObject:key]) 81 | { 82 | id textInputTraits = valueForKey(self, _cmd, @"textInputTraits"); 83 | return valueForKey(textInputTraits, _cmd, key); 84 | } 85 | else 86 | { 87 | return valueForKey(self, _cmd, key); 88 | } 89 | } 90 | 91 | // See http://stackoverflow.com/questions/6617472/why-does-valueforkey-on-a-uitextfield-throws-an-exception-for-uitextinputtraits 92 | + (void)workaroundUITextInputTraitsPropertiesBug 93 | { 94 | Method valueForKey = class_getInstanceMethod([NSObject class], @selector(valueForKey:)); 95 | const char *valueForKeyTypeEncoding = method_getTypeEncoding(valueForKey); 96 | 97 | unsigned int count = 0; 98 | Class *classes = objc_copyClassList(&count); 99 | for (unsigned int i = 0; i < count; i++) 100 | { 101 | Class class = classes[i]; 102 | if (class_getInstanceMethod(class, NSSelectorFromString(@"textInputTraits"))) 103 | { 104 | IMP originalValueForKey = class_replaceMethod(class, @selector(valueForKey:), (IMP)UITextInputTraits_valueForKey, valueForKeyTypeEncoding); 105 | if (!originalValueForKey) 106 | originalValueForKey = class_getMethodImplementation([class superclass], @selector(valueForKey:)); 107 | 108 | objc_setAssociatedObject(class, originalValueForKeyIMPKey, [NSValue valueWithPointer:originalValueForKey], OBJC_ASSOCIATION_RETAIN_NONATOMIC); 109 | } 110 | } 111 | free(classes); 112 | } 113 | 114 | + (DCIntrospect *)sharedIntrospector 115 | { 116 | #ifdef DEBUG 117 | if (!sharedInstance) 118 | { 119 | sharedInstance = [[DCIntrospect alloc] init]; 120 | sharedInstance.keyboardBindingsOn = YES; 121 | sharedInstance.showStatusBarOverlay = ![UIApplication sharedApplication].statusBarHidden; 122 | [self workaroundUITextInputTraitsPropertiesBug]; 123 | } 124 | #endif 125 | return sharedInstance; 126 | } 127 | 128 | - (void)start 129 | { 130 | UIWindow *mainWindow = [self mainWindow]; 131 | if (!mainWindow) 132 | { 133 | NSLog(@"DCIntrospect: Couldn't setup. No main window?"); 134 | return; 135 | } 136 | 137 | if (!self.statusBarOverlay) 138 | { 139 | self.statusBarOverlay = [[[DCStatusBarOverlay alloc] init] autorelease]; 140 | } 141 | 142 | if (!self.inputTextView) 143 | { 144 | self.inputTextView = [[[UITextView alloc] initWithFrame:CGRectZero] autorelease]; 145 | self.inputTextView.delegate = self; 146 | self.inputTextView.autocorrectionType = UITextAutocorrectionTypeNo; 147 | self.inputTextView.autocapitalizationType = UITextAutocapitalizationTypeNone; 148 | self.inputTextView.inputView = [[[UIView alloc] init] autorelease]; 149 | [mainWindow addSubview:self.inputTextView]; 150 | } 151 | 152 | if (self.keyboardBindingsOn) 153 | { 154 | if (![self.inputTextView becomeFirstResponder]) 155 | { 156 | [self performSelector:@selector(takeFirstResponder) withObject:nil afterDelay:0.5]; 157 | } 158 | } 159 | 160 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(statusBarTapped) name:kDCIntrospectNotificationStatusBarTapped object:nil]; 161 | 162 | // reclaim the keyboard after dismissal if it is taken 163 | [[NSNotificationCenter defaultCenter] addObserverForName:UIKeyboardWillHideNotification 164 | object:nil 165 | queue:nil 166 | usingBlock:^(NSNotification *notification) { 167 | // needs to be done after a delay or else it doesn't work for some reason. 168 | if (self.keyboardBindingsOn) 169 | [self performSelector:@selector(takeFirstResponder) 170 | withObject:nil 171 | afterDelay:0.1]; 172 | }]; 173 | 174 | // listen for device orientation changes to adjust the status bar 175 | [[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications]; 176 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(updateViews) name:UIDeviceOrientationDidChangeNotification object:nil]; 177 | 178 | if (!self.currentViewHistory) 179 | self.currentViewHistory = [[[NSMutableArray alloc] init] autorelease]; 180 | 181 | NSLog(@"DCIntrospect is setup. %@ to start.", [kDCIntrospectKeysInvoke isEqualToString:@" "] ? @"Push the space bar" : [NSString stringWithFormat:@"Type '%@'", kDCIntrospectKeysInvoke]); 182 | } 183 | 184 | - (void)takeFirstResponder 185 | { 186 | if (![self.inputTextView becomeFirstResponder]) 187 | NSLog(@"DCIntrospect: Couldn't reclaim keyboard input. Is the keyboard used elsewhere?"); 188 | } 189 | 190 | - (void)resetInputTextView 191 | { 192 | self.inputTextView.text = @"\n2 4567 9\n"; 193 | self.handleArrowKeys = NO; 194 | self.inputTextView.selectedRange = NSMakeRange(5, 0); 195 | self.handleArrowKeys = YES; 196 | } 197 | 198 | #pragma mark Custom Setters 199 | - (void)setInvokeGestureRecognizer:(UIGestureRecognizer *)newGestureRecognizer 200 | { 201 | UIWindow *mainWindow = [self mainWindow]; 202 | [mainWindow removeGestureRecognizer:invokeGestureRecognizer]; 203 | 204 | [invokeGestureRecognizer release]; 205 | invokeGestureRecognizer = nil; 206 | invokeGestureRecognizer = [newGestureRecognizer retain]; 207 | [invokeGestureRecognizer addTarget:self action:@selector(invokeIntrospector)]; 208 | [mainWindow addGestureRecognizer:invokeGestureRecognizer]; 209 | } 210 | 211 | - (void)setKeyboardBindingsOn:(BOOL)newKeyboardBindingsOn 212 | { 213 | keyboardBindingsOn = newKeyboardBindingsOn; 214 | if (self.keyboardBindingsOn) 215 | [self.inputTextView becomeFirstResponder]; 216 | else 217 | [self.inputTextView resignFirstResponder]; 218 | } 219 | 220 | #pragma mark Main Actions 221 | 222 | - (void)invokeIntrospector 223 | { 224 | self.on = !self.on; 225 | 226 | if (self.on) 227 | { 228 | [self updateViews]; 229 | [self updateStatusBar]; 230 | [self updateFrameView]; 231 | 232 | if (keyboardBindingsOn) 233 | [self.inputTextView becomeFirstResponder]; 234 | else 235 | [self.inputTextView resignFirstResponder]; 236 | 237 | [self resetInputTextView]; 238 | 239 | [[NSNotificationCenter defaultCenter] postNotificationName:kDCIntrospectNotificationIntrospectionDidStart 240 | object:nil]; 241 | } 242 | else 243 | { 244 | if (self.viewOutlines) 245 | [self toggleOutlines]; 246 | if (self.highlightNonOpaqueViews) 247 | [self toggleNonOpaqueViews]; 248 | if (self.showingHelp) 249 | [self toggleHelp]; 250 | 251 | self.statusBarOverlay.hidden = YES; 252 | self.frameView.alpha = 0; 253 | self.currentView = nil; 254 | 255 | [[NSNotificationCenter defaultCenter] postNotificationName:kDCIntrospectNotificationIntrospectionDidEnd 256 | object:nil]; 257 | } 258 | } 259 | 260 | - (void)touchAtPoint:(CGPoint)point 261 | { 262 | // convert the point into the main window 263 | CGPoint convertedTouchPoint = [[self mainWindow] convertPoint:point fromView:self.frameView]; 264 | 265 | // find all the views under that point – will be added in order on screen, ie mainWindow will be index 0, main view controller at index 1 etc. 266 | NSMutableArray *views = [self viewsAtPoint:convertedTouchPoint inView:[self mainWindow]]; 267 | if (views.count == 0) 268 | return; 269 | 270 | // get the topmost view and setup the UI 271 | [self.currentViewHistory removeAllObjects]; 272 | UIView *newView = [views lastObject]; 273 | [self selectView:newView]; 274 | } 275 | 276 | - (void)selectView:(UIView *)view 277 | { 278 | self.currentView = view; 279 | self.originalFrame = self.currentView.frame; 280 | self.originalAlpha = self.currentView.alpha; 281 | 282 | if (self.frameView.rectsToOutline.count > 0) 283 | { 284 | [self.frameView.rectsToOutline removeAllObjects]; 285 | [self.frameView setNeedsDisplay]; 286 | self.viewOutlines = NO; 287 | } 288 | 289 | [self updateFrameView]; 290 | [self updateStatusBar]; 291 | 292 | if (![self.currentViewHistory containsObject:self.currentView]) 293 | [self.currentViewHistory addObject:self.currentView]; 294 | } 295 | 296 | - (void)statusBarTapped 297 | { 298 | if (self.showingHelp) 299 | { 300 | [self toggleHelp]; 301 | return; 302 | } 303 | } 304 | 305 | #pragma mark Keyboard Capture 306 | 307 | - (void)textViewDidChangeSelection:(UITextView *)textView 308 | { 309 | if (!(self.on && self.handleArrowKeys)) 310 | return; 311 | 312 | NSUInteger selectionLocation = textView.selectedRange.location; 313 | NSUInteger selectionLength = textView.selectedRange.length; 314 | BOOL shiftKey = selectionLength != 0; 315 | BOOL optionKey = selectionLocation % 2 == 1; 316 | 317 | CGRect frame = self.currentView.frame; 318 | if (shiftKey) 319 | { 320 | if (selectionLocation == 4 && selectionLength == 1) 321 | frame.origin.x -= 10.0f; 322 | else if (selectionLocation == 5 && selectionLength == 1) 323 | frame.origin.x += 10.0f; 324 | else if (selectionLocation == 0 && selectionLength == 5) 325 | frame.origin.y -= 10.0f; 326 | else if (selectionLocation == 5 && selectionLength == 5) 327 | frame.origin.y += 10.0f; 328 | } 329 | else if (optionKey) 330 | { 331 | if (selectionLocation == 7) 332 | frame.size.width += 1.0f; 333 | else if (selectionLocation == 3) 334 | frame.size.width -= 1.0f; 335 | else if (selectionLocation == 9) 336 | frame.size.height += 1.0f; 337 | else if (selectionLocation == 1) 338 | frame.size.height -= 1.0f; 339 | } 340 | else 341 | { 342 | if (selectionLocation == 4) 343 | frame.origin.x -= 1.0f; 344 | else if (selectionLocation == 6) 345 | frame.origin.x += 1.0f; 346 | else if (selectionLocation == 0) 347 | frame.origin.y -= 1.0f; 348 | else if (selectionLocation == 10) 349 | frame.origin.y += 1.0f; 350 | } 351 | 352 | self.currentView.frame = CGRectMake(floorf(frame.origin.x), 353 | floorf(frame.origin.y), 354 | floorf(frame.size.width), 355 | floorf(frame.size.height)); 356 | 357 | [self updateFrameView]; 358 | [self updateStatusBar]; 359 | 360 | [self resetInputTextView]; 361 | } 362 | 363 | - (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)string 364 | { 365 | if ([string isEqualToString:kDCIntrospectKeysInvoke]) 366 | { 367 | [self invokeIntrospector]; 368 | return NO; 369 | } 370 | 371 | if (!self.on) 372 | return NO; 373 | 374 | if (self.showingHelp) 375 | { 376 | [self toggleHelp]; 377 | return NO; 378 | } 379 | 380 | if ([string isEqualToString:kDCIntrospectKeysToggleViewOutlines]) 381 | { 382 | [self toggleOutlines]; 383 | return NO; 384 | } 385 | else if ([string isEqualToString:kDCIntrospectKeysToggleNonOpaqueViews]) 386 | { 387 | [self toggleNonOpaqueViews]; 388 | return NO; 389 | } 390 | else if ([string isEqualToString:kDCIntrospectKeysToggleFlashViewRedraws]) 391 | { 392 | [self toggleRedrawFlashing]; 393 | return NO; 394 | } 395 | else if ([string isEqualToString:kDCIntrospectKeysToggleShowCoordinates]) 396 | { 397 | [UIView animateWithDuration:0.15 398 | delay:0 399 | options:UIViewAnimationOptionAllowUserInteraction 400 | animations:^{ 401 | self.frameView.touchPointLabel.alpha = !self.frameView.touchPointLabel.alpha; 402 | } completion:^(BOOL finished) { 403 | NSString *coordinatesString = [NSString stringWithFormat:@"Coordinates are %@", (self.frameView.touchPointLabel.alpha) ? @"on" : @"off"]; 404 | if (self.showStatusBarOverlay) 405 | [self showTemporaryStringInStatusBar:coordinatesString]; 406 | else 407 | NSLog(@"DCIntrospect: %@", coordinatesString); 408 | }]; 409 | return NO; 410 | } 411 | else if ([string isEqualToString:kDCIntrospectKeysToggleHelp]) 412 | { 413 | [self toggleHelp]; 414 | return NO; 415 | } 416 | 417 | if (self.on && self.currentView) 418 | { 419 | if ([string isEqualToString:kDCIntrospectKeysLogProperties]) 420 | { 421 | [self logPropertiesForObject:self.currentView]; 422 | return NO; 423 | } 424 | else if ([string isEqualToString:kDCIntrospectKeysLogAccessibilityProperties]) 425 | { 426 | [self logAccessabilityPropertiesForObject:self.currentView]; 427 | return NO; 428 | } 429 | else if ([string isEqualToString:kDCIntrospectKeysLogViewRecursive]) 430 | { 431 | [self logRecursiveDescriptionForView:self.currentView]; 432 | return NO; 433 | } 434 | else if ([string isEqualToString:kDCIntrospectKeysSetNeedsDisplay]) 435 | { 436 | [self forceSetNeedsDisplay]; 437 | return NO; 438 | } 439 | else if ([string isEqualToString:kDCIntrospectKeysSetNeedsLayout]) 440 | { 441 | [self forceSetNeedsLayout]; 442 | return NO; 443 | } 444 | else if ([string isEqualToString:kDCIntrospectKeysReloadData]) 445 | { 446 | [self forceReloadOfView]; 447 | return NO; 448 | } 449 | else if ([string isEqualToString:kDCIntrospectKeysMoveUpInViewHierarchy]) 450 | { 451 | if (self.currentView.superview) 452 | { 453 | [self selectView:self.currentView.superview]; 454 | } 455 | else 456 | { 457 | NSLog(@"DCIntrospect: At top of view hierarchy."); 458 | return NO; 459 | } 460 | return NO; 461 | } 462 | else if ([string isEqualToString:kDCIntrospectKeysMoveBackInViewHierarchy]) 463 | { 464 | if (self.currentViewHistory.count == 0) 465 | return NO; 466 | 467 | int indexOfCurrentView = [self.currentViewHistory indexOfObject:self.currentView]; 468 | if (indexOfCurrentView == 0) 469 | { 470 | NSLog(@"DCIntrospect: At bottom of view history."); 471 | return NO; 472 | } 473 | 474 | [self selectView:[self.currentViewHistory objectAtIndex:indexOfCurrentView - 1]]; 475 | } 476 | else if ([string isEqualToString:kDCIntrospectKeysLogCodeForCurrentViewChanges]) 477 | { 478 | [self logCodeForCurrentViewChanges]; 479 | return NO; 480 | } 481 | 482 | CGRect frame = self.currentView.frame; 483 | if ([string isEqualToString:kDCIntrospectKeysNudgeViewLeft]) 484 | frame.origin.x -= 1.0f; 485 | else if ([string isEqualToString:kDCIntrospectKeysNudgeViewRight]) 486 | frame.origin.x += 1.0f; 487 | else if ([string isEqualToString:kDCIntrospectKeysNudgeViewUp]) 488 | frame.origin.y -= 1.0f; 489 | else if ([string isEqualToString:kDCIntrospectKeysNudgeViewDown]) 490 | frame.origin.y += 1.0f; 491 | else if ([string isEqualToString:kDCIntrospectKeysCenterInSuperview]) 492 | frame = CGRectMake(floorf((self.currentView.superview.frame.size.width - frame.size.width) / 2.0f), 493 | floorf((self.currentView.superview.frame.size.height - frame.size.height) / 2.0f), 494 | frame.size.width, 495 | frame.size.height); 496 | else if ([string isEqualToString:kDCIntrospectKeysIncreaseWidth]) 497 | frame.size.width += 1.0f; 498 | else if ([string isEqualToString:kDCIntrospectKeysDecreaseWidth]) 499 | frame.size.width -= 1.0f; 500 | else if ([string isEqualToString:kDCIntrospectKeysIncreaseHeight]) 501 | frame.size.height += 1.0f; 502 | else if ([string isEqualToString:kDCIntrospectKeysDecreaseHeight]) 503 | frame.size.height -= 1.0f; 504 | else if ([string isEqualToString:kDCIntrospectKeysIncreaseViewAlpha]) 505 | { 506 | if (self.currentView.alpha < 1.0f) 507 | self.currentView.alpha += 0.05f; 508 | } 509 | else if ([string isEqualToString:kDCIntrospectKeysDecreaseViewAlpha]) 510 | { 511 | if (self.currentView.alpha > 0.0f) 512 | self.currentView.alpha -= 0.05f; 513 | } 514 | 515 | self.currentView.frame = CGRectMake(floorf(frame.origin.x), 516 | floorf(frame.origin.y), 517 | floorf(frame.size.width), 518 | floorf(frame.size.height)); 519 | 520 | [self updateFrameView]; 521 | [self updateStatusBar]; 522 | } 523 | 524 | return NO; 525 | } 526 | 527 | #pragma mark Object Names 528 | 529 | - (void)logCodeForCurrentViewChanges 530 | { 531 | if (!self.currentView) 532 | return; 533 | 534 | NSString *varName = [self nameForObject:self.currentView]; 535 | if ([varName isEqualToString:[NSString stringWithFormat:@"%@", self.currentView.class]]) 536 | varName = @"<#view#>"; 537 | 538 | NSMutableString *outputString = [NSMutableString string]; 539 | if (!CGRectEqualToRect(self.originalFrame, self.currentView.frame)) 540 | { 541 | [outputString appendFormat:@"%@.frame = CGRectMake(%.1f, %.1f, %.1f, %.1f);\n", varName, self.currentView.frame.origin.x, self.currentView.frame.origin.y, self.currentView.frame.size.width, self.currentView.frame.size.height]; 542 | } 543 | 544 | if (self.originalAlpha != self.currentView.alpha) 545 | { 546 | [outputString appendFormat:@"%@.alpha = %.2f;\n", varName, self.currentView.alpha]; 547 | } 548 | 549 | if (outputString.length == 0) 550 | NSLog(@"DCIntrospect: No changes made to %@.", self.currentView.class); 551 | else 552 | printf("\n\n%s\n", [outputString UTF8String]); 553 | } 554 | 555 | - (void)setName:(NSString *)name forObject:(id)object accessedWithSelf:(BOOL)accessedWithSelf 556 | { 557 | if (!self.objectNames) 558 | self.objectNames = [NSMutableDictionary dictionary]; 559 | 560 | if (accessedWithSelf) 561 | name = [@"self." stringByAppendingString:name]; 562 | 563 | [self.objectNames setValue:object forKey:name]; 564 | } 565 | 566 | - (NSString *)nameForObject:(id)object 567 | { 568 | __block NSString *objectName = [NSString stringWithFormat:@"%@", [object class]]; 569 | if (!self.objectNames) 570 | return objectName; 571 | 572 | [self.objectNames enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { 573 | if (obj == object) 574 | { 575 | objectName = (NSString *)key; 576 | *stop = YES; 577 | } 578 | }]; 579 | 580 | return objectName; 581 | } 582 | 583 | - (void)removeNamesForViewsInView:(UIView *)view 584 | { 585 | if (!self.objectNames) 586 | return; 587 | 588 | NSMutableArray *objectsToRemove = [NSMutableArray array]; 589 | [self.objectNames enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { 590 | if ([[obj class] isSubclassOfClass:[UIView class]]) 591 | { 592 | UIView *subview = (UIView *)obj; 593 | if ([self view:view containsSubview:subview]) 594 | [objectsToRemove addObject:key]; 595 | } 596 | }]; 597 | 598 | [objectsToRemove enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { 599 | NSString *key = (NSString *)obj; 600 | [self.objectNames removeObjectForKey:key]; 601 | }]; 602 | } 603 | 604 | - (void)removeNameForObject:(id)object 605 | { 606 | if (!self.objectNames) 607 | return; 608 | 609 | NSString *objectName = [self nameForObject:object]; 610 | [self.objectNames removeObjectForKey:objectName]; 611 | } 612 | 613 | #pragma mark Layout 614 | 615 | - (void)updateFrameView 616 | { 617 | UIWindow *mainWindow = [self mainWindow]; 618 | if (!self.frameView) 619 | { 620 | self.frameView = [[[DCFrameView alloc] initWithFrame:(CGRect){ CGPointZero, mainWindow.frame.size } delegate:self] autorelease]; 621 | [mainWindow addSubview:self.frameView]; 622 | self.frameView.alpha = 0.0f; 623 | [self updateViews]; 624 | } 625 | 626 | [mainWindow bringSubviewToFront:self.frameView]; 627 | 628 | if (self.on) 629 | { 630 | if (self.currentView) 631 | { 632 | self.frameView.mainRect = [self.currentView.superview convertRect:self.currentView.frame toView:self.frameView]; 633 | if (self.currentView.superview == mainWindow) 634 | self.frameView.superRect = CGRectZero; 635 | else if (self.currentView.superview.superview) 636 | self.frameView.superRect = [self.currentView.superview.superview convertRect:self.currentView.superview.frame toView:self.frameView]; 637 | else 638 | self.frameView.superRect = CGRectZero; 639 | } 640 | else 641 | { 642 | self.frameView.mainRect = CGRectZero; 643 | } 644 | 645 | [self fadeView:self.frameView toAlpha:1.0f]; 646 | } 647 | else 648 | { 649 | [self fadeView:self.frameView toAlpha:0.0f]; 650 | } 651 | } 652 | 653 | - (void)updateStatusBar 654 | { 655 | if (self.currentView) 656 | { 657 | NSString *nameForObject = [self nameForObject:self.currentView]; 658 | 659 | // remove the 'self.' if it's there to save space 660 | if ([nameForObject hasPrefix:@"self."]) 661 | nameForObject = [nameForObject substringFromIndex:@"self.".length]; 662 | 663 | if (self.currentView.tag != 0) 664 | self.statusBarOverlay.leftLabel.text = [NSString stringWithFormat:@"%@ (tag: %i)", nameForObject, self.currentView.tag]; 665 | else 666 | self.statusBarOverlay.leftLabel.text = [NSString stringWithFormat:@"%@", nameForObject]; 667 | 668 | self.statusBarOverlay.rightLabel.text = NSStringFromCGRect(self.currentView.frame); 669 | } 670 | else 671 | { 672 | self.statusBarOverlay.leftLabel.text = @"DCIntrospect"; 673 | self.statusBarOverlay.rightLabel.text = [NSString stringWithFormat:@"'%@' for help", kDCIntrospectKeysToggleHelp]; 674 | } 675 | 676 | if (self.showStatusBarOverlay) 677 | self.statusBarOverlay.hidden = NO; 678 | else 679 | self.statusBarOverlay.hidden = YES; 680 | } 681 | 682 | - (void)updateViews 683 | { 684 | // current interface orientation 685 | UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation; 686 | CGFloat screenWidth = [UIScreen mainScreen].bounds.size.width; 687 | CGFloat screenHeight = [UIScreen mainScreen].bounds.size.height; 688 | 689 | CGFloat pi = (CGFloat)M_PI; 690 | if (orientation == UIDeviceOrientationPortrait) 691 | { 692 | self.frameView.transform = CGAffineTransformIdentity; 693 | self.frameView.frame = CGRectMake(0, 0, screenWidth, screenHeight); 694 | } 695 | else if (orientation == UIDeviceOrientationLandscapeLeft) 696 | { 697 | self.frameView.transform = CGAffineTransformMakeRotation(pi * (90) / 180.0f); 698 | self.frameView.frame = CGRectMake(screenWidth - screenHeight, 0, screenHeight, screenHeight); 699 | } 700 | else if (orientation == UIDeviceOrientationLandscapeRight) 701 | { 702 | self.frameView.transform = CGAffineTransformMakeRotation(pi * (-90) / 180.0f); 703 | self.frameView.frame = CGRectMake(0, 0, screenWidth, screenHeight); 704 | } 705 | else if (orientation == UIDeviceOrientationPortraitUpsideDown) 706 | { 707 | self.frameView.transform = CGAffineTransformMakeRotation(pi); 708 | self.frameView.frame = CGRectMake(0, 0, screenWidth, screenHeight); 709 | } 710 | 711 | self.currentView = nil; 712 | [self updateFrameView]; 713 | } 714 | 715 | - (void)showTemporaryStringInStatusBar:(NSString *)string 716 | { 717 | [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(updateStatusBar) object:nil]; 718 | 719 | self.statusBarOverlay.leftLabel.text = string; 720 | self.statusBarOverlay.rightLabel.text = nil; 721 | [self performSelector:@selector(updateStatusBar) withObject:nil afterDelay:0.75]; 722 | } 723 | 724 | #pragma mark Actions 725 | 726 | - (void)logRecursiveDescriptionForCurrentView 727 | { 728 | [self logRecursiveDescriptionForView:self.currentView]; 729 | } 730 | 731 | - (void)logRecursiveDescriptionForView:(UIView *)view 732 | { 733 | #ifdef DEBUG 734 | // [UIView recursiveDescription] is a private method. This should probably be re-written to avoid any potential problems. 735 | NSLog(@"DCIntrospect: %@", [view recursiveDescription]); 736 | #endif 737 | } 738 | 739 | - (void)forceSetNeedsDisplay 740 | { 741 | [self.currentView setNeedsDisplay]; 742 | } 743 | 744 | - (void)forceSetNeedsLayout 745 | { 746 | [self.currentView setNeedsLayout]; 747 | } 748 | 749 | - (void)forceReloadOfView 750 | { 751 | if ([self.currentView class] == [UITableView class]) 752 | [(UITableView *)self.currentView reloadData]; 753 | } 754 | 755 | - (void)toggleOutlines 756 | { 757 | UIWindow *mainWindow = [self mainWindow]; 758 | self.viewOutlines = !self.viewOutlines; 759 | 760 | if (self.viewOutlines) 761 | [self addOutlinesToFrameViewFromSubview:mainWindow]; 762 | else 763 | [self.frameView.rectsToOutline removeAllObjects]; 764 | 765 | [self.frameView setNeedsDisplay]; 766 | 767 | NSString *string = [NSString stringWithFormat:@"Showing view outlines is %@", (self.viewOutlines) ? @"on" : @"off"]; 768 | if (self.showStatusBarOverlay) 769 | [self showTemporaryStringInStatusBar:string]; 770 | else 771 | NSLog(@"DCIntrospect: %@", string); 772 | } 773 | 774 | - (void)addOutlinesToFrameViewFromSubview:(UIView *)view 775 | { 776 | for (UIView *subview in view.subviews) 777 | { 778 | if ([self shouldIgnoreView:subview]) 779 | continue; 780 | 781 | CGRect rect = [subview.superview convertRect:subview.frame toView:frameView]; 782 | 783 | NSValue *rectValue = [NSValue valueWithCGRect:rect]; 784 | [self.frameView.rectsToOutline addObject:rectValue]; 785 | [self addOutlinesToFrameViewFromSubview:subview]; 786 | } 787 | } 788 | 789 | - (void)toggleNonOpaqueViews 790 | { 791 | self.highlightNonOpaqueViews = !self.highlightNonOpaqueViews; 792 | 793 | UIWindow *mainWindow = [self mainWindow]; 794 | [self setBackgroundColor:(self.highlightNonOpaqueViews) ? kDCIntrospectOpaqueColor : [UIColor clearColor] 795 | ofNonOpaqueViewsInSubview:mainWindow]; 796 | 797 | NSString *string = [NSString stringWithFormat:@"Highlighting non-opaque views is %@", (self.highlightNonOpaqueViews) ? @"on" : @"off"]; 798 | if (self.showStatusBarOverlay) 799 | [self showTemporaryStringInStatusBar:string]; 800 | else 801 | NSLog(@"DCIntrospect: %@", string); 802 | } 803 | 804 | - (void)setBackgroundColor:(UIColor *)color ofNonOpaqueViewsInSubview:(UIView *)view 805 | { 806 | for (UIView *subview in view.subviews) 807 | { 808 | if ([self shouldIgnoreView:subview]) 809 | continue; 810 | 811 | if (!subview.opaque) 812 | subview.backgroundColor = color; 813 | 814 | [self setBackgroundColor:color ofNonOpaqueViewsInSubview:subview]; 815 | } 816 | } 817 | 818 | - (void)toggleRedrawFlashing 819 | { 820 | self.flashOnRedraw = !self.flashOnRedraw; 821 | NSString *string = [NSString stringWithFormat:@"Flashing on redraw is %@", (self.flashOnRedraw) ? @"on" : @"off"]; 822 | if (self.showStatusBarOverlay) 823 | [self showTemporaryStringInStatusBar:string]; 824 | else 825 | NSLog(@"DCIntrospect: %@", string); 826 | 827 | // flash all views to show what is working 828 | [self callDrawRectOnViewsInSubview:[self mainWindow]]; 829 | } 830 | 831 | - (void)callDrawRectOnViewsInSubview:(UIView *)subview 832 | { 833 | for (UIView *view in subview.subviews) 834 | { 835 | if (![self shouldIgnoreView:view]) 836 | { 837 | [view setNeedsDisplay]; 838 | [self callDrawRectOnViewsInSubview:view]; 839 | } 840 | } 841 | } 842 | 843 | - (void)flashRect:(CGRect)rect inView:(UIView *)view 844 | { 845 | if (self.flashOnRedraw) 846 | { 847 | CALayer *layer = [CALayer layer]; 848 | layer.frame = rect; 849 | layer.backgroundColor = kDCIntrospectFlashOnRedrawColor.CGColor; 850 | [view.layer addSublayer:layer]; 851 | [layer performSelector:@selector(removeFromSuperlayer) withObject:nil afterDelay:kDCIntrospectFlashOnRedrawFlashLength]; 852 | } 853 | } 854 | 855 | #pragma mark Description Methods 856 | 857 | - (NSString *)describeProperty:(NSString *)propertyName value:(id)value 858 | { 859 | if ([propertyName isEqualToString:@"contentMode"]) 860 | { 861 | switch ([value intValue]) 862 | { 863 | case 0: return @"UIViewContentModeScaleToFill"; 864 | case 1: return @"UIViewContentModeScaleAspectFit"; 865 | case 2: return @"UIViewContentModeScaleAspectFill"; 866 | case 3: return @"UIViewContentModeRedraw"; 867 | case 4: return @"UIViewContentModeCenter"; 868 | case 5: return @"UIViewContentModeTop"; 869 | case 6: return @"UIViewContentModeBottom"; 870 | case 7: return @"UIViewContentModeLeft"; 871 | case 8: return @"UIViewContentModeRight"; 872 | case 9: return @"UIViewContentModeTopLeft"; 873 | case 10: return @"UIViewContentModeTopRight"; 874 | case 11: return @"UIViewContentModeBottomLeft"; 875 | case 12: return @"UIViewContentModeBottomRight"; 876 | default: return nil; 877 | } 878 | } 879 | else if ([propertyName isEqualToString:@"textAlignment"]) 880 | { 881 | switch ([value intValue]) 882 | { 883 | case 0: return @"UITextAlignmentLeft"; 884 | case 1: return @"UITextAlignmentCenter"; 885 | case 2: return @"UITextAlignmentRight"; 886 | default: return nil; 887 | } 888 | } 889 | else if ([propertyName isEqualToString:@"lineBreakMode"]) 890 | { 891 | switch ([value intValue]) 892 | { 893 | case 0: return @"UILineBreakModeWordWrap"; 894 | case 1: return @"UILineBreakModeCharacterWrap"; 895 | case 2: return @"UILineBreakModeClip"; 896 | case 3: return @"UILineBreakModeHeadTruncation"; 897 | case 4: return @"UILineBreakModeTailTruncation"; 898 | case 5: return @"UILineBreakModeMiddleTruncation"; 899 | default: return nil; 900 | } 901 | } 902 | else if ([propertyName isEqualToString:@"activityIndicatorViewStyle"]) 903 | { 904 | switch ([value intValue]) 905 | { 906 | case 0: return @"UIActivityIndicatorViewStyleWhiteLarge"; 907 | case 1: return @"UIActivityIndicatorViewStyleWhite"; 908 | case 2: return @"UIActivityIndicatorViewStyleGray"; 909 | default: return nil; 910 | } 911 | } 912 | else if ([propertyName isEqualToString:@"returnKeyType"]) 913 | { 914 | switch ([value intValue]) 915 | { 916 | case 0: return @"UIReturnKeyDefault"; 917 | case 1: return @"UIReturnKeyGo"; 918 | case 2: return @"UIReturnKeyGoogle"; 919 | case 3: return @"UIReturnKeyJoin"; 920 | case 4: return @"UIReturnKeyNext"; 921 | case 5: return @"UIReturnKeyRoute"; 922 | case 6: return @"UIReturnKeySearch"; 923 | case 7: return @"UIReturnKeySend"; 924 | case 8: return @"UIReturnKeyYahoo"; 925 | case 9: return @"UIReturnKeyDone"; 926 | case 10: return @"UIReturnKeyEmergencyCall"; 927 | default: return nil; 928 | } 929 | } 930 | else if ([propertyName isEqualToString:@"keyboardAppearance"]) 931 | { 932 | switch ([value intValue]) 933 | { 934 | case 0: return @"UIKeyboardAppearanceDefault"; 935 | case 1: return @"UIKeyboardAppearanceAlert"; 936 | default: return nil; 937 | } 938 | } 939 | else if ([propertyName isEqualToString:@"keyboardType"]) 940 | { 941 | switch ([value intValue]) 942 | { 943 | case 0: return @"UIKeyboardTypeDefault"; 944 | case 1: return @"UIKeyboardTypeASCIICapable"; 945 | case 2: return @"UIKeyboardTypeNumbersAndPunctuation"; 946 | case 3: return @"UIKeyboardTypeURL"; 947 | case 4: return @"UIKeyboardTypeNumberPad"; 948 | case 5: return @"UIKeyboardTypePhonePad"; 949 | case 6: return @"UIKeyboardTypeNamePhonePad"; 950 | case 7: return @"UIKeyboardTypeEmailAddress"; 951 | case 8: return @"UIKeyboardTypeDecimalPad"; 952 | default: return nil; 953 | } 954 | } 955 | else if ([propertyName isEqualToString:@"autocorrectionType"]) 956 | { 957 | switch ([value intValue]) 958 | { 959 | case 0: return @"UIKeyboardTypeDefault"; 960 | case 1: return @"UITextAutocorrectionTypeDefault"; 961 | case 2: return @"UITextAutocorrectionTypeNo"; 962 | default: return nil; 963 | } 964 | } 965 | else if ([propertyName isEqualToString:@"autocapitalizationType"]) 966 | { 967 | switch ([value intValue]) 968 | { 969 | case 0: return @"UITextAutocapitalizationTypeNone"; 970 | case 1: return @"UITextAutocapitalizationTypeWords"; 971 | case 2: return @"UITextAutocapitalizationTypeSentences"; 972 | case 3: return @"UITextAutocapitalizationTypeAllCharacters"; 973 | default: return nil; 974 | } 975 | } 976 | else if ([propertyName isEqualToString:@"clearButtonMode"] || 977 | [propertyName isEqualToString:@"leftViewMode"] || 978 | [propertyName isEqualToString:@"rightViewMode"]) 979 | { 980 | switch ([value intValue]) 981 | { 982 | case 0: return @"UITextFieldViewModeNever"; 983 | case 1: return @"UITextFieldViewModeWhileEditing"; 984 | case 2: return @"UITextFieldViewModeUnlessEditing"; 985 | case 3: return @"UITextFieldViewModeAlways"; 986 | default: return nil; 987 | } 988 | } 989 | else if ([propertyName isEqualToString:@"borderStyle"]) 990 | { 991 | switch ([value intValue]) 992 | { 993 | case 0: return @"UITextBorderStyleNone"; 994 | case 1: return @"UITextBorderStyleLine"; 995 | case 2: return @"UITextBorderStyleBezel"; 996 | case 3: return @"UITextBorderStyleRoundedRect"; 997 | default: return nil; 998 | } 999 | } 1000 | else if ([propertyName isEqualToString:@"progressViewStyle"]) 1001 | { 1002 | switch ([value intValue]) 1003 | { 1004 | case 0: return @"UIProgressViewStyleBar"; 1005 | case 1: return @"UIProgressViewStyleDefault"; 1006 | default: return nil; 1007 | } 1008 | } 1009 | else if ([propertyName isEqualToString:@"separatorStyle"]) 1010 | { 1011 | switch ([value intValue]) 1012 | { 1013 | case 0: return @"UITableViewCellSeparatorStyleNone"; 1014 | case 1: return @"UITableViewCellSeparatorStyleSingleLine"; 1015 | case 2: return @"UITableViewCellSeparatorStyleSingleLineEtched"; 1016 | default: return nil; 1017 | } 1018 | } 1019 | else if ([propertyName isEqualToString:@"selectionStyle"]) 1020 | { 1021 | switch ([value intValue]) 1022 | { 1023 | case 0: return @"UITableViewCellSelectionStyleNone"; 1024 | case 1: return @"UITableViewCellSelectionStyleBlue"; 1025 | case 2: return @"UITableViewCellSelectionStyleGray"; 1026 | default: return nil; 1027 | } 1028 | } 1029 | else if ([propertyName isEqualToString:@"editingStyle"]) 1030 | { 1031 | switch ([value intValue]) 1032 | { 1033 | case 0: return @"UITableViewCellEditingStyleNone"; 1034 | case 1: return @"UITableViewCellEditingStyleDelete"; 1035 | case 2: return @"UITableViewCellEditingStyleInsert"; 1036 | default: return nil; 1037 | } 1038 | } 1039 | else if ([propertyName isEqualToString:@"accessoryType"] || [propertyName isEqualToString:@"editingAccessoryType"]) 1040 | { 1041 | switch ([value intValue]) 1042 | { 1043 | case 0: return @"UITableViewCellAccessoryNone"; 1044 | case 1: return @"UITableViewCellAccessoryDisclosureIndicator"; 1045 | case 2: return @"UITableViewCellAccessoryDetailDisclosureButton"; 1046 | case 3: return @"UITableViewCellAccessoryCheckmark"; 1047 | default: return nil; 1048 | } 1049 | } 1050 | else if ([propertyName isEqualToString:@"style"]) 1051 | { 1052 | switch ([value intValue]) 1053 | { 1054 | case 0: return @"UITableViewStylePlain"; 1055 | case 1: return @"UITableViewStyleGrouped"; 1056 | default: return nil; 1057 | } 1058 | 1059 | } 1060 | else if ([propertyName isEqualToString:@"autoresizingMask"]) 1061 | { 1062 | UIViewAutoresizing mask = [value intValue]; 1063 | NSMutableString *string = [NSMutableString string]; 1064 | if (mask & UIViewAutoresizingFlexibleLeftMargin) 1065 | [string appendString:@"UIViewAutoresizingFlexibleLeftMargin"]; 1066 | if (mask & UIViewAutoresizingFlexibleRightMargin) 1067 | [string appendString:@" | UIViewAutoresizingFlexibleRightMargin"]; 1068 | if (mask & UIViewAutoresizingFlexibleTopMargin) 1069 | [string appendString:@" | UIViewAutoresizingFlexibleTopMargin"]; 1070 | if (mask & UIViewAutoresizingFlexibleBottomMargin) 1071 | [string appendString:@" | UIViewAutoresizingFlexibleBottomMargin"]; 1072 | if (mask & UIViewAutoresizingFlexibleWidth) 1073 | [string appendString:@" | UIViewAutoresizingFlexibleWidthMargin"]; 1074 | if (mask & UIViewAutoresizingFlexibleHeight) 1075 | [string appendString:@" | UIViewAutoresizingFlexibleHeightMargin"]; 1076 | 1077 | if ([string hasPrefix:@" | "]) 1078 | [string replaceCharactersInRange:NSMakeRange(0, 3) withString:@""]; 1079 | 1080 | return ([string length] > 0) ? string : @"UIViewAutoresizingNone"; 1081 | } 1082 | else if ([propertyName isEqualToString:@"accessibilityTraits"]) 1083 | { 1084 | UIAccessibilityTraits traits = [value intValue]; 1085 | NSMutableString *string = [NSMutableString string]; 1086 | if (traits & UIAccessibilityTraitButton) 1087 | [string appendString:@"UIAccessibilityTraitButton"]; 1088 | if (traits & UIAccessibilityTraitLink) 1089 | [string appendString:@" | UIAccessibilityTraitLink"]; 1090 | if (traits & UIAccessibilityTraitSearchField) 1091 | [string appendString:@" | UIAccessibilityTraitSearchField"]; 1092 | if (traits & UIAccessibilityTraitImage) 1093 | [string appendString:@" | UIAccessibilityTraitImage"]; 1094 | if (traits & UIAccessibilityTraitSelected) 1095 | [string appendString:@" | UIAccessibilityTraitSelected"]; 1096 | if (traits & UIAccessibilityTraitPlaysSound) 1097 | [string appendString:@" | UIAccessibilityTraitPlaysSound"]; 1098 | if (traits & UIAccessibilityTraitKeyboardKey) 1099 | [string appendString:@" | UIAccessibilityTraitKeyboardKey"]; 1100 | if (traits & UIAccessibilityTraitStaticText) 1101 | [string appendString:@" | UIAccessibilityTraitStaticText"]; 1102 | if (traits & UIAccessibilityTraitSummaryElement) 1103 | [string appendString:@" | UIAccessibilityTraitSummaryElement"]; 1104 | if (traits & UIAccessibilityTraitNotEnabled) 1105 | [string appendString:@" | UIAccessibilityTraitNotEnabled"]; 1106 | if (traits & UIAccessibilityTraitUpdatesFrequently) 1107 | [string appendString:@" | UIAccessibilityTraitUpdatesFrequently"]; 1108 | if (traits & UIAccessibilityTraitStartsMediaSession) 1109 | [string appendString:@" | UIAccessibilityTraitStartsMediaSession"]; 1110 | if (traits & UIAccessibilityTraitAdjustable) 1111 | [string appendFormat:@" | UIAccessibilityTraitAdjustable"]; 1112 | if ([string hasPrefix:@" | "]) 1113 | [string replaceCharactersInRange:NSMakeRange(0, 3) withString:@""]; 1114 | 1115 | return ([string length] > 0) ? string : @"UIAccessibilityTraitNone"; 1116 | } 1117 | 1118 | if ([value isKindOfClass:[NSValue class]]) 1119 | { 1120 | // print out the return for each value depending on type 1121 | NSString *type = [NSString stringWithUTF8String:[value objCType]]; 1122 | if ([type isEqualToString:@"c"]) 1123 | { 1124 | return ([value boolValue]) ? @"YES" : @"NO"; 1125 | } 1126 | else if ([type isEqualToString:@"{CGSize=ff}"]) 1127 | { 1128 | CGSize size = [value CGSizeValue]; 1129 | return CGSizeEqualToSize(size, CGSizeZero) ? @"CGSizeZero" : NSStringFromCGSize(size); 1130 | } 1131 | else if ([type isEqualToString:@"{UIEdgeInsets=ffff}"]) 1132 | { 1133 | UIEdgeInsets edgeInsets = [value UIEdgeInsetsValue]; 1134 | return UIEdgeInsetsEqualToEdgeInsets(edgeInsets, UIEdgeInsetsZero) ? @"UIEdgeInsetsZero" : NSStringFromUIEdgeInsets(edgeInsets); 1135 | } 1136 | } 1137 | else if ([value isKindOfClass:[UIColor class]]) 1138 | { 1139 | UIColor *color = (UIColor *)value; 1140 | return [self describeColor:color]; 1141 | } 1142 | else if ([value isKindOfClass:[UIFont class]]) 1143 | { 1144 | UIFont *font = (UIFont *)value; 1145 | return [NSString stringWithFormat:@"%.0fpx %@", font.pointSize, font.fontName]; 1146 | } 1147 | 1148 | return value ? [value description] : @"nil"; 1149 | } 1150 | 1151 | - (NSString *)describeColor:(UIColor *)color 1152 | { 1153 | if (!color) 1154 | return @"nil"; 1155 | 1156 | NSString *returnString = nil; 1157 | if (CGColorSpaceGetModel(CGColorGetColorSpace(color.CGColor)) == kCGColorSpaceModelRGB) 1158 | { 1159 | const CGFloat *components = CGColorGetComponents(color.CGColor); 1160 | returnString = [NSString stringWithFormat:@"R: %.0f G: %.0f B: %.0f A: %.2f", 1161 | components[0] * 256, 1162 | components[1] * 256, 1163 | components[2] * 256, 1164 | components[3]]; 1165 | } 1166 | else 1167 | { 1168 | returnString = [NSString stringWithFormat:@"%@ (incompatible color space)", color]; 1169 | } 1170 | return returnString; 1171 | } 1172 | 1173 | #pragma mark DCIntrospector Help 1174 | 1175 | - (void)toggleHelp 1176 | { 1177 | UIWindow *mainWindow = [self mainWindow]; 1178 | self.showingHelp = !self.showingHelp; 1179 | 1180 | if (self.showingHelp) 1181 | { 1182 | self.statusBarOverlay.leftLabel.text = @"Help"; 1183 | self.statusBarOverlay.rightLabel.text = @"Any key to close"; 1184 | UIView *backingView = [[[UIView alloc] initWithFrame:CGRectMake(0, 0, mainWindow.frame.size.width, mainWindow.frame.size.height)] autorelease]; 1185 | backingView.tag = 1548; 1186 | backingView.alpha = 0; 1187 | backingView.backgroundColor = [UIColor colorWithRed:0.0f green:0.0f blue:0.0f alpha:0.85f]; 1188 | [mainWindow addSubview:backingView]; 1189 | 1190 | UIWebView *webView = [[[UIWebView alloc] initWithFrame:backingView.frame] autorelease]; 1191 | webView.opaque = NO; 1192 | webView.backgroundColor = [UIColor clearColor]; 1193 | webView.delegate = self; 1194 | [backingView addSubview:webView]; 1195 | 1196 | NSMutableString *helpString = [NSMutableString stringWithString:@""]; 1197 | [helpString appendString:@"

DCIntrospect

"]; 1204 | [helpString appendString:@"

Created by Domestic Cat Software 2011.

"]; 1205 | [helpString appendString:@"

Twitter: @patr

"]; 1206 | [helpString appendString:@"

More info and full documentation: domesticcat.com.au/projects/introspect

"]; 1207 | [helpString appendString:@"

GitHub project: github.com/domesticcatsoftware/dcintrospect/

"]; 1208 | 1209 | [helpString appendString:@"

Key Bindings

"]; 1210 | [helpString appendString:@"

Edit DCIntrospectSettings.h to change key bindings.

"]; 1211 | 1212 | [helpString appendString:@"

General

"]; 1213 | 1214 | [helpString appendFormat:@"
Invoke Introspector
%@
", ([kDCIntrospectKeysInvoke isEqualToString:@" "]) ? @"spacebar" : kDCIntrospectKeysInvoke]; 1215 | [helpString appendFormat:@"
Toggle View Outlines
%@
", kDCIntrospectKeysToggleViewOutlines]; 1216 | [helpString appendFormat:@"
Toggle Highlighting Non-Opaque Views
%@
", kDCIntrospectKeysToggleNonOpaqueViews]; 1217 | [helpString appendFormat:@"
Toggle Help
%@
", kDCIntrospectKeysToggleHelp]; 1218 | [helpString appendFormat:@"
Toggle flash on drawRect: (see below)
%@
", kDCIntrospectKeysToggleFlashViewRedraws]; 1219 | [helpString appendFormat:@"
Toggle coordinates
%@
", kDCIntrospectKeysToggleShowCoordinates]; 1220 | [helpString appendString:@"
"]; 1221 | 1222 | [helpString appendString:@"

When a view is selected

"]; 1223 | [helpString appendFormat:@"
Log Properties
%@
", kDCIntrospectKeysLogProperties]; 1224 | [helpString appendFormat:@"
Log Accessibility Properties
%@
", kDCIntrospectKeysLogAccessibilityProperties]; 1225 | [helpString appendFormat:@"
Log Recursive Description for View
%@
", kDCIntrospectKeysLogViewRecursive]; 1226 | [helpString appendFormat:@"
Move up in view hierarchy
%@
", ([kDCIntrospectKeysMoveUpInViewHierarchy isEqualToString:@""]) ? @"page up" : kDCIntrospectKeysMoveUpInViewHierarchy]; 1227 | [helpString appendFormat:@"
Move back down in view hierarchy
%@
", ([kDCIntrospectKeysMoveBackInViewHierarchy isEqualToString:@""]) ? @"page down" : kDCIntrospectKeysMoveBackInViewHierarchy]; 1228 | [helpString appendString:@"
"]; 1229 | 1230 | [helpString appendFormat:@"
Nudge Left
\uE235 / %@
", kDCIntrospectKeysNudgeViewLeft]; 1231 | [helpString appendFormat:@"
Nudge Right
\uE234 / %@
", kDCIntrospectKeysNudgeViewRight]; 1232 | [helpString appendFormat:@"
Nudge Up
\uE232 / %@
", kDCIntrospectKeysNudgeViewUp]; 1233 | [helpString appendFormat:@"
Nudge Down
\uE233 / %@
", kDCIntrospectKeysNudgeViewDown]; 1234 | [helpString appendFormat:@"
Center in Superview
%@
", kDCIntrospectKeysCenterInSuperview]; 1235 | [helpString appendFormat:@"
Increase Width
alt + \uE234 / %@
", kDCIntrospectKeysIncreaseWidth]; 1236 | [helpString appendFormat:@"
Decrease Width
alt + \uE235 / %@
", kDCIntrospectKeysDecreaseWidth]; 1237 | [helpString appendFormat:@"
Increase Height
alt + \uE233 / %@
", kDCIntrospectKeysIncreaseHeight]; 1238 | [helpString appendFormat:@"
Decrease Height
alt + \uE232 / %@
", kDCIntrospectKeysDecreaseHeight]; 1239 | [helpString appendFormat:@"
Increase Alpha
%@
", kDCIntrospectKeysIncreaseViewAlpha]; 1240 | [helpString appendFormat:@"
Decrease Alpha
%@
", kDCIntrospectKeysDecreaseViewAlpha]; 1241 | [helpString appendFormat:@"
Log view code
%@
", kDCIntrospectKeysLogCodeForCurrentViewChanges]; 1242 | [helpString appendString:@"
"]; 1243 | 1244 | [helpString appendFormat:@"
Call setNeedsDisplay
%@
", kDCIntrospectKeysSetNeedsDisplay]; 1245 | [helpString appendFormat:@"
Call setNeedsLayout
%@
", kDCIntrospectKeysSetNeedsLayout]; 1246 | [helpString appendFormat:@"
Call reloadData (UITableView only)
%@
", kDCIntrospectKeysReloadData]; 1247 | [helpString appendString:@"
"]; 1248 | 1249 | [helpString appendFormat:@"

Flash on drawRect: calls

To implement, call [[DCIntrospect sharedIntrospector] flashRect:inView:] inside the drawRect: method of any view you want to track.

When Flash on drawRect: is toggled on (binding: %@) the view will flash whenever drawRect: is called.

", kDCIntrospectKeysToggleFlashViewRedraws]; 1250 | 1251 | [helpString appendFormat:@"

Naming objects & logging code

By providing names for objects using setName:forObject:accessedWithSelf:, that name will be shown in the status bar instead of the class of the view.

This is also used when logging view code (binding: %@). Logging view code prints formatted code to the console for properties that have been changed.

For example, if you resize/move a view using the nudge keys, logging the view code will print view.frame = CGRectMake(50.0 ..etc); to the console. If a name is provided then view is replaced by the name.

", kDCIntrospectKeysLogCodeForCurrentViewChanges]; 1252 | 1253 | [helpString appendString:@"

License

DCIntrospect is made available under the MIT license.

"]; 1254 | 1255 | [helpString appendString:@"

Close Help

"]; 1256 | [helpString appendString:@"
"]; 1257 | 1258 | [UIView animateWithDuration:0.1 1259 | animations:^{ 1260 | backingView.alpha = 1.0f; 1261 | } completion:^(BOOL finished) { 1262 | [webView loadHTMLString:helpString baseURL:nil]; 1263 | }]; 1264 | } 1265 | else 1266 | { 1267 | UIView *backingView = (UIView *)[mainWindow viewWithTag:1548]; 1268 | [UIView animateWithDuration:0.1 1269 | animations:^{ 1270 | backingView.alpha = 0; 1271 | } completion:^(BOOL finished) { 1272 | [backingView removeFromSuperview]; 1273 | }]; 1274 | [self updateStatusBar]; 1275 | } 1276 | } 1277 | 1278 | - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType 1279 | { 1280 | NSString *requestString = [[request URL] absoluteString]; 1281 | if ([requestString isEqualToString:@"about:blank"]) 1282 | return YES; 1283 | else if ([requestString isEqualToString:@"http://close/"]) 1284 | [self toggleHelp]; 1285 | else 1286 | [[UIApplication sharedApplication] openURL:[request URL]]; 1287 | 1288 | return NO; 1289 | } 1290 | 1291 | #pragma mark Experimental 1292 | 1293 | - (void)logPropertiesForCurrentView 1294 | { 1295 | [self logPropertiesForObject:self.currentView]; 1296 | } 1297 | 1298 | - (void)logPropertiesForObject:(id)object 1299 | { 1300 | Class objectClass = [object class]; 1301 | NSString *className = [NSString stringWithFormat:@"%@", objectClass]; 1302 | 1303 | unsigned int count; 1304 | objc_property_t *properties = class_copyPropertyList(objectClass, &count); 1305 | size_t buf_size = 1024; 1306 | char *buffer = malloc(buf_size); 1307 | NSMutableString *outputString = [NSMutableString stringWithFormat:@"\n\n** %@", className]; 1308 | 1309 | // list the class heirachy 1310 | Class superClass = [objectClass superclass]; 1311 | while (superClass) 1312 | { 1313 | [outputString appendFormat:@" : %@", superClass]; 1314 | superClass = [superClass superclass]; 1315 | } 1316 | 1317 | [outputString appendString:@" ** \n\n"]; 1318 | 1319 | if ([objectClass isSubclassOfClass:UIView.class]) 1320 | { 1321 | UIView *view = (UIView *)object; 1322 | // print out generic uiview properties 1323 | [outputString appendString:@" ** UIView properties **\n"]; 1324 | [outputString appendFormat:@" tag: %i\n", view.tag]; 1325 | [outputString appendFormat:@" frame: %@ | ", NSStringFromCGRect(view.frame)]; 1326 | [outputString appendFormat:@"bounds: %@ | ", NSStringFromCGRect(view.bounds)]; 1327 | [outputString appendFormat:@"center: %@\n", NSStringFromCGPoint(view.center)]; 1328 | [outputString appendFormat:@" transform: %@\n", NSStringFromCGAffineTransform(view.transform)]; 1329 | [outputString appendFormat:@" autoresizingMask: %@\n", [self describeProperty:@"autoresizingMask" value:[NSNumber numberWithInt:view.autoresizingMask]]]; 1330 | [outputString appendFormat:@" autoresizesSubviews: %@\n", (view.autoresizesSubviews) ? @"YES" : @"NO"]; 1331 | [outputString appendFormat:@" contentMode: %@ | ", [self describeProperty:@"contentMode" value:[NSNumber numberWithInt:view.contentMode]]]; 1332 | [outputString appendFormat:@"contentStretch: %@\n", NSStringFromCGRect(view.contentStretch)]; 1333 | [outputString appendFormat:@" backgroundColor: %@\n", [self describeColor:view.backgroundColor]]; 1334 | [outputString appendFormat:@" alpha: %.2f | ", view.alpha]; 1335 | [outputString appendFormat:@"opaque: %@ | ", (view.opaque) ? @"YES" : @"NO"]; 1336 | [outputString appendFormat:@"hidden: %@ | ", (view.hidden) ? @"YES" : @"NO"]; 1337 | [outputString appendFormat:@"clips to bounds: %@ | ", (view.clipsToBounds) ? @"YES" : @"NO"]; 1338 | [outputString appendFormat:@"clearsContextBeforeDrawing: %@\n", (view.clearsContextBeforeDrawing) ? @"YES" : @"NO"]; 1339 | [outputString appendFormat:@" userInteractionEnabled: %@ | ", (view.userInteractionEnabled) ? @"YES" : @"NO"]; 1340 | [outputString appendFormat:@"multipleTouchEnabled: %@\n", (view.multipleTouchEnabled) ? @"YES" : @"NO"]; 1341 | [outputString appendFormat:@" gestureRecognizers: %@\n", (view.gestureRecognizers) ? [view.gestureRecognizers description] : @"nil"]; 1342 | 1343 | [outputString appendString:@"\n"]; 1344 | } 1345 | 1346 | [outputString appendFormat:@" ** %@ properties **\n", objectClass]; 1347 | 1348 | if (objectClass == UIScrollView.class || objectClass == UIButton.class) 1349 | { 1350 | [outputString appendString:@" Logging properties not currently supported for this view.\n"]; 1351 | } 1352 | else 1353 | { 1354 | 1355 | for (unsigned int i = 0; i < count; ++i) 1356 | { 1357 | // get the property name and selector name 1358 | NSString *propertyName = [NSString stringWithCString:property_getName(properties[i]) encoding:NSUTF8StringEncoding]; 1359 | 1360 | SEL sel = NSSelectorFromString(propertyName); 1361 | if ([object respondsToSelector:sel]) 1362 | { 1363 | NSString *propertyDescription; 1364 | @try 1365 | { 1366 | // get the return object and type for the selector 1367 | NSString *returnType = [NSString stringWithUTF8String:[[object methodSignatureForSelector:sel] methodReturnType]]; 1368 | id returnObject = [object valueForKey:propertyName]; 1369 | if ([returnType isEqualToString:@"c"]) 1370 | returnObject = [NSNumber numberWithBool:[returnObject intValue] != 0]; 1371 | 1372 | propertyDescription = [self describeProperty:propertyName value:returnObject]; 1373 | } 1374 | @catch (NSException *exception) 1375 | { 1376 | // Non KVC compliant properties, see also +workaroundUITextInputTraitsPropertiesBug 1377 | propertyDescription = @"N/A"; 1378 | } 1379 | [outputString appendFormat:@" %@: %@\n", propertyName, propertyDescription]; 1380 | } 1381 | } 1382 | } 1383 | 1384 | // list targets if there are any 1385 | if ([object respondsToSelector:@selector(allTargets)]) 1386 | { 1387 | [outputString appendString:@"\n ** Targets & Actions **\n"]; 1388 | UIControl *control = (UIControl *)object; 1389 | UIControlEvents controlEvents = [control allControlEvents]; 1390 | NSSet *allTargets = [control allTargets]; 1391 | [allTargets enumerateObjectsUsingBlock:^(id target, BOOL *stop) 1392 | { 1393 | NSArray *actions = [control actionsForTarget:target forControlEvent:controlEvents]; 1394 | [actions enumerateObjectsUsingBlock:^(id action, NSUInteger idx, BOOL *stop2) 1395 | { 1396 | [outputString appendFormat:@" target: %@ action: %@\n", target, action]; 1397 | }]; 1398 | }]; 1399 | } 1400 | 1401 | [outputString appendString:@"\n"]; 1402 | NSLog(@"DCIntrospect: %@", outputString); 1403 | 1404 | free(properties); 1405 | free(buffer); 1406 | } 1407 | 1408 | - (void)logAccessabilityPropertiesForObject:(id)object 1409 | { 1410 | Class objectClass = [object class]; 1411 | NSString *className = [NSString stringWithFormat:@"%@", objectClass]; 1412 | NSMutableString *outputString = [NSMutableString string]; 1413 | 1414 | // warn about accessibility inspector if the element count is zero 1415 | NSUInteger count = [object accessibilityElementCount]; 1416 | if (count == 0) 1417 | [outputString appendString:@"\n\n** Warning: Logging accessibility properties requires Accessibility Inspector: Settings.app -> General -> Accessibility\n"]; 1418 | 1419 | [outputString appendFormat:@"** %@ Accessibility Properties **\n", className]; 1420 | [outputString appendFormat:@" label: %@\n", [object accessibilityLabel]]; 1421 | [outputString appendFormat:@" hint: %@\n", [object accessibilityHint]]; 1422 | [outputString appendFormat:@" traits: %@\n", [self describeProperty:@"accessibilityTraits" value:[NSNumber numberWithUnsignedLongLong:[object accessibilityTraits]]]]; 1423 | [outputString appendFormat:@" value: %@\n", [object accessibilityValue]]; 1424 | [outputString appendFormat:@" frame: %@\n", NSStringFromCGRect([object accessibilityFrame])]; 1425 | [outputString appendString:@"\n"]; 1426 | 1427 | NSLog(@"DCIntrospect: %@", outputString); 1428 | } 1429 | 1430 | - (NSArray *)subclassesOfClass:(Class)parentClass 1431 | { 1432 | // thanks to Matt Gallagher: 1433 | int numClasses = objc_getClassList(NULL, 0); 1434 | Class *classes = NULL; 1435 | 1436 | classes = malloc(sizeof(Class) * numClasses); 1437 | numClasses = objc_getClassList(classes, numClasses); 1438 | 1439 | NSMutableArray *result = [NSMutableArray array]; 1440 | for (NSInteger i = 0; i < numClasses; i++) 1441 | { 1442 | Class superClass = classes[i]; 1443 | do 1444 | { 1445 | superClass = class_getSuperclass(superClass); 1446 | } while(superClass && superClass != parentClass); 1447 | 1448 | if (superClass == nil) 1449 | { 1450 | continue; 1451 | } 1452 | 1453 | [result addObject:classes[i]]; 1454 | } 1455 | 1456 | free(classes); 1457 | 1458 | return result; 1459 | } 1460 | 1461 | #pragma mark Helper Methods 1462 | 1463 | - (UIWindow *)mainWindow 1464 | { 1465 | NSArray *windows = [[UIApplication sharedApplication] windows]; 1466 | if (windows.count == 0) 1467 | return nil; 1468 | 1469 | return [windows objectAtIndex:0]; 1470 | } 1471 | 1472 | - (NSMutableArray *)viewsAtPoint:(CGPoint)touchPoint inView:(UIView *)view 1473 | { 1474 | NSMutableArray *views = [[NSMutableArray alloc] init]; 1475 | for (UIView *subview in view.subviews) 1476 | { 1477 | CGRect rect = subview.frame; 1478 | if ([self shouldIgnoreView:subview]) 1479 | continue; 1480 | 1481 | if (CGRectContainsPoint(rect, touchPoint)) 1482 | { 1483 | [views addObject:subview]; 1484 | 1485 | // convert the point to it's superview 1486 | CGPoint newTouchPoint = touchPoint; 1487 | newTouchPoint = [view convertPoint:newTouchPoint toView:subview]; 1488 | [views addObjectsFromArray:[self viewsAtPoint:newTouchPoint inView:subview]]; 1489 | } 1490 | } 1491 | 1492 | return [views autorelease]; 1493 | } 1494 | 1495 | - (void)fadeView:(UIView *)view toAlpha:(CGFloat)alpha 1496 | { 1497 | [UIView animateWithDuration:0.1 1498 | delay:0.0 1499 | options:UIViewAnimationOptionAllowUserInteraction 1500 | animations:^{ 1501 | view.alpha = alpha; 1502 | } 1503 | completion:nil]; 1504 | } 1505 | 1506 | - (BOOL)view:(UIView *)view containsSubview:(UIView *)subview 1507 | { 1508 | for (UIView *aView in view.subviews) 1509 | { 1510 | if (aView == subview) 1511 | return YES; 1512 | 1513 | if ([self view:aView containsSubview:subview]) 1514 | return YES; 1515 | } 1516 | 1517 | return NO; 1518 | } 1519 | 1520 | - (BOOL)shouldIgnoreView:(UIView *)view 1521 | { 1522 | if (view == self.frameView || view == self.inputTextView) 1523 | return YES; 1524 | return NO; 1525 | } 1526 | 1527 | @end 1528 | -------------------------------------------------------------------------------- /RangeSlider/DCIntrospect/DCIntrospectSettings.h: -------------------------------------------------------------------------------- 1 | ////////////// 2 | // Settings // 3 | ////////////// 4 | 5 | #define kDCIntrospectFlashOnRedrawColor [UIColor colorWithRed:1.0f green:0.0f blue:0.0f alpha:0.4f] // UIColor 6 | #define kDCIntrospectFlashOnRedrawFlashLength 0.03f // NSTimeInterval 7 | #define kDCIntrospectOpaqueColor [UIColor redColor] // UIColor 8 | 9 | ////////////////// 10 | // Key Bindings // 11 | ////////////////// 12 | 13 | // '' is equivalent to page up (copy and paste this character to use) 14 | // '' is equivalent to page down (copy and paste this character to use) 15 | 16 | // Global // 17 | #define kDCIntrospectKeysInvoke @" " // starts introspector 18 | #define kDCIntrospectKeysToggleViewOutlines @"o" // shows outlines for all views 19 | #define kDCIntrospectKeysToggleNonOpaqueViews @"O" // changes all non-opaque view background colours to red (destructive) 20 | #define kDCIntrospectKeysToggleHelp @"?" // shows help 21 | #define kDCIntrospectKeysToggleFlashViewRedraws @"f" // toggle flashing on redraw for all views that implement [[DCIntrospect sharedIntrospector] flashRect:inView:] in drawRect: 22 | #define kDCIntrospectKeysToggleShowCoordinates @"c" // toggles the coordinates display 23 | #define kDCIntrospectKeysEnterBlockMode @"b" // enters block action mode 24 | 25 | // When introspector is invoked and a view is selected // 26 | #define kDCIntrospectKeysNudgeViewLeft @"4" // nudges the selected view in given direction 27 | #define kDCIntrospectKeysNudgeViewRight @"6" // 28 | #define kDCIntrospectKeysNudgeViewUp @"8" // 29 | #define kDCIntrospectKeysNudgeViewDown @"2" // 30 | #define kDCIntrospectKeysCenterInSuperview @"5" // centers the selected view in it's superview 31 | #define kDCIntrospectKeysIncreaseWidth @"9" // increases/decreases the width/height of selected view 32 | #define kDCIntrospectKeysDecreaseWidth @"7" // 33 | #define kDCIntrospectKeysIncreaseHeight @"3" // 34 | #define kDCIntrospectKeysDecreaseHeight @"1" // 35 | #define kDCIntrospectKeysLogCodeForCurrentViewChanges @"0" // prints code to the console of the changes to the current view. If the view has not been changed nothing will be printed. For example, if you nudge a view or change it's rect with the nudge keys, this will log '<#view#>.frame = CGRectMake(50.0, ..etc);'. Or if you set it's name using setName:forObject:accessedWithSelf: it will use the name provided, for example 'myView.frame = CGRectMake(...);'. Setting accessedWithSelf to YES would output 'self.myView.frame = CGRectMake(...);'. 36 | 37 | #define kDCIntrospectKeysIncreaseViewAlpha @"+" // increases/decreases the selected views alpha value 38 | #define kDCIntrospectKeysDecreaseViewAlpha @"-" // 39 | 40 | #define kDCIntrospectKeysSetNeedsDisplay @"d" // calls setNeedsDisplay on selected view 41 | #define kDCIntrospectKeysSetNeedsLayout @"l" // calls setNeedsLayout on selected view 42 | #define kDCIntrospectKeysReloadData @"r" // calls reloadData on selected view if it's a UITableView 43 | #define kDCIntrospectKeysLogProperties @"p" // logs all properties of the selected view 44 | #define kDCIntrospectKeysLogAccessibilityProperties @"a" // logs accessibility info (useful for automated view tests - thanks to @samsoffes for the idea) 45 | #define kDCIntrospectKeysLogViewRecursive @"v" // calls private method recursiveDescription which logs selected view heirachy 46 | 47 | #define kDCIntrospectKeysMoveUpInViewHierarchy @"" // changes the selected view to it's superview 48 | #define kDCIntrospectKeysMoveBackInViewHierarchy @"" // changes the selected view back to the previous view selected (after using the above command) 49 | -------------------------------------------------------------------------------- /RangeSlider/DCIntrospect/DCStatusBarOverlay.h: -------------------------------------------------------------------------------- 1 | // 2 | // DCStatusBarOverlay.h 3 | // 4 | // Copyright 2011 Domestic Cat. All rights reserved. 5 | // 6 | 7 | // Based mainly on @myellow's excellent MTStatusBarOverlay: https://github.com/myell0w/MTStatusBarOverlay 8 | 9 | 10 | #import "DCIntrospectSettings.h" 11 | 12 | #define kDCIntrospectNotificationStatusBarTapped @"kDCIntrospectNotificationStatusBarTapped" 13 | 14 | @interface DCStatusBarOverlay : UIWindow 15 | { 16 | } 17 | 18 | @property (nonatomic, retain) UILabel *leftLabel; 19 | @property (nonatomic, retain) UILabel *rightLabel; 20 | 21 | /////////// 22 | // Setup // 23 | /////////// 24 | 25 | - (id)init; 26 | - (void)updateBarFrame; 27 | 28 | ///////////// 29 | // Actions // 30 | ///////////// 31 | 32 | - (void)tapped; 33 | 34 | @end 35 | -------------------------------------------------------------------------------- /RangeSlider/DCIntrospect/DCStatusBarOverlay.m: -------------------------------------------------------------------------------- 1 | // 2 | // DCStatusBarOverlay.m 3 | // 4 | // Copyright 2011 Domestic Cat. All rights reserved. 5 | // 6 | 7 | #import "DCStatusBarOverlay.h" 8 | 9 | @implementation DCStatusBarOverlay 10 | @synthesize leftLabel, rightLabel; 11 | 12 | - (void)dealloc 13 | { 14 | [[NSNotificationCenter defaultCenter] removeObserver:self name:UIDeviceOrientationDidChangeNotification object:nil]; 15 | 16 | [leftLabel release]; 17 | [rightLabel release]; 18 | 19 | [super dealloc]; 20 | } 21 | 22 | #pragma mark Setup 23 | 24 | - (id)init 25 | { 26 | if ((self = [super initWithFrame:CGRectZero])) 27 | { 28 | self.windowLevel = UIWindowLevelStatusBar + 1.0f; 29 | self.frame = [[UIApplication sharedApplication] statusBarFrame]; 30 | self.backgroundColor = [UIColor blackColor]; 31 | 32 | UIImageView *backgroundImageView = [[UIImageView alloc] initWithFrame:self.frame]; 33 | backgroundImageView.image = [[UIImage imageNamed:@"statusBarBackground.png"] stretchableImageWithLeftCapWidth:2.0f topCapHeight:0.0f]; 34 | [self addSubview:backgroundImageView]; 35 | [backgroundImageView release]; 36 | 37 | self.leftLabel = [[[UILabel alloc] initWithFrame:CGRectOffset(self.frame, 2.0f, 0.0f)] autorelease]; 38 | self.leftLabel.backgroundColor = [UIColor clearColor]; 39 | self.leftLabel.textAlignment = UITextAlignmentLeft; 40 | self.leftLabel.font = [UIFont boldSystemFontOfSize:12.0f]; 41 | self.leftLabel.textColor = [UIColor colorWithWhite:0.97f alpha:1.0f]; 42 | self.leftLabel.autoresizingMask = UIViewAutoresizingFlexibleWidth; 43 | [self addSubview:self.leftLabel]; 44 | 45 | self.rightLabel = [[[UILabel alloc] initWithFrame:CGRectOffset(self.frame, -2.0f, 0.0f)] autorelease]; 46 | self.rightLabel.backgroundColor = [UIColor clearColor]; 47 | self.rightLabel.font = [UIFont boldSystemFontOfSize:12.0f]; 48 | self.rightLabel.textAlignment = UITextAlignmentRight; 49 | self.rightLabel.textColor = [UIColor colorWithWhite:0.9f alpha:1.0f]; 50 | self.rightLabel.autoresizingMask = UIViewAutoresizingFlexibleWidth; 51 | [self addSubview:self.rightLabel]; 52 | 53 | UITapGestureRecognizer *gestureRecognizer = [[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapped)] autorelease]; 54 | [self addGestureRecognizer:gestureRecognizer]; 55 | 56 | [[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications]; 57 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(updateBarFrame) name:UIDeviceOrientationDidChangeNotification object:nil]; 58 | } 59 | 60 | return self; 61 | } 62 | 63 | - (void)updateBarFrame 64 | { 65 | // current interface orientation 66 | UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation; 67 | CGFloat screenWidth = [UIScreen mainScreen].bounds.size.width; 68 | CGFloat screenHeight = [UIScreen mainScreen].bounds.size.height; 69 | 70 | CGFloat pi = (CGFloat)M_PI; 71 | if (orientation == UIDeviceOrientationPortrait) 72 | { 73 | self.transform = CGAffineTransformIdentity; 74 | self.frame = CGRectMake(0, 0, screenWidth, self.frame.size.height); 75 | } 76 | else if (orientation == UIDeviceOrientationLandscapeLeft) 77 | { 78 | self.transform = CGAffineTransformMakeRotation(pi * (90) / 180.0f); 79 | self.frame = CGRectMake(screenWidth - self.frame.size.width, 0, self.frame.size.width, screenHeight); 80 | } 81 | else if (orientation == UIDeviceOrientationLandscapeRight) 82 | { 83 | self.transform = CGAffineTransformMakeRotation(pi * (-90) / 180.0f); 84 | self.frame = CGRectMake(0, 0, self.frame.size.width, screenHeight); 85 | } 86 | else if (orientation == UIDeviceOrientationPortraitUpsideDown) 87 | { 88 | self.transform = CGAffineTransformMakeRotation(pi); 89 | self.frame = CGRectMake(0, screenHeight - self.frame.size.height, screenWidth, self.frame.size.height); 90 | } 91 | } 92 | 93 | #pragma mark Actions 94 | 95 | - (void)tapped 96 | { 97 | [[NSNotificationCenter defaultCenter] postNotificationName:kDCIntrospectNotificationStatusBarTapped object:nil]; 98 | } 99 | 100 | @end 101 | -------------------------------------------------------------------------------- /RangeSlider/Images/bar-background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/buildmobile/iosrangeslider/84f2ecd9c817f781c258ebf9c6a7fff5f1f7b3a5/RangeSlider/Images/bar-background.png -------------------------------------------------------------------------------- /RangeSlider/Images/bar-background@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/buildmobile/iosrangeslider/84f2ecd9c817f781c258ebf9c6a7fff5f1f7b3a5/RangeSlider/Images/bar-background@2x.png -------------------------------------------------------------------------------- /RangeSlider/Images/bar-highlight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/buildmobile/iosrangeslider/84f2ecd9c817f781c258ebf9c6a7fff5f1f7b3a5/RangeSlider/Images/bar-highlight.png -------------------------------------------------------------------------------- /RangeSlider/Images/bar-highlight@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/buildmobile/iosrangeslider/84f2ecd9c817f781c258ebf9c6a7fff5f1f7b3a5/RangeSlider/Images/bar-highlight@2x.png -------------------------------------------------------------------------------- /RangeSlider/Images/handle-hover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/buildmobile/iosrangeslider/84f2ecd9c817f781c258ebf9c6a7fff5f1f7b3a5/RangeSlider/Images/handle-hover.png -------------------------------------------------------------------------------- /RangeSlider/Images/handle-hover@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/buildmobile/iosrangeslider/84f2ecd9c817f781c258ebf9c6a7fff5f1f7b3a5/RangeSlider/Images/handle-hover@2x.png -------------------------------------------------------------------------------- /RangeSlider/Images/handle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/buildmobile/iosrangeslider/84f2ecd9c817f781c258ebf9c6a7fff5f1f7b3a5/RangeSlider/Images/handle.png -------------------------------------------------------------------------------- /RangeSlider/Images/handle@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/buildmobile/iosrangeslider/84f2ecd9c817f781c258ebf9c6a7fff5f1f7b3a5/RangeSlider/Images/handle@2x.png -------------------------------------------------------------------------------- /RangeSlider/RangeSlider-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIconFile 12 | 13 | CFBundleIdentifier 14 | snikch.${PRODUCT_NAME:rfc1034identifier} 15 | CFBundleInfoDictionaryVersion 16 | 6.0 17 | CFBundleName 18 | ${PRODUCT_NAME} 19 | CFBundlePackageType 20 | APPL 21 | CFBundleShortVersionString 22 | 1.0 23 | CFBundleSignature 24 | ???? 25 | CFBundleVersion 26 | 1.0 27 | LSRequiresIPhoneOS 28 | 29 | NSMainNibFile 30 | MainWindow 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /RangeSlider/RangeSlider-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header for all source files of the 'RangeSlider' target in the 'RangeSlider' project 3 | // 4 | 5 | #import 6 | 7 | #ifndef __IPHONE_3_0 8 | #warning "This project uses features only available in iPhone SDK 3.0 and later." 9 | #endif 10 | 11 | #ifdef __OBJC__ 12 | #import 13 | #import 14 | #endif 15 | -------------------------------------------------------------------------------- /RangeSlider/RangeSlider.h: -------------------------------------------------------------------------------- 1 | // 2 | // RangeSlider.h 3 | // RangeSlider 4 | // 5 | // Created by Mal Curtis on 5/08/11. 6 | // Copyright 2011 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface RangeSlider : UIControl{ 12 | float minimumValue; 13 | float maximumValue; 14 | float minimumRange; 15 | float selectedMinimumValue; 16 | float selectedMaximumValue; 17 | float distanceFromCenter; 18 | 19 | float _padding; 20 | 21 | BOOL _maxThumbOn; 22 | BOOL _minThumbOn; 23 | 24 | UIImageView * _minThumb; 25 | UIImageView * _maxThumb; 26 | UIImageView * _track; 27 | UIImageView * _trackBackground; 28 | } 29 | 30 | @property(nonatomic) float minimumValue; 31 | @property(nonatomic) float maximumValue; 32 | @property(nonatomic) float minimumRange; 33 | @property(nonatomic) float selectedMinimumValue; 34 | @property(nonatomic) float selectedMaximumValue; 35 | 36 | @end 37 | -------------------------------------------------------------------------------- /RangeSlider/RangeSlider.m: -------------------------------------------------------------------------------- 1 | // 2 | // RangeSlider.m 3 | // RangeSlider 4 | // 5 | // Created by Mal Curtis on 5/08/11. 6 | // Copyright 2011 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import "RangeSlider.h" 10 | 11 | @interface RangeSlider (PrivateMethods) 12 | -(float)xForValue:(float)value; 13 | -(float)valueForX:(float)x; 14 | -(void)updateTrackHighlight; 15 | @end 16 | 17 | @implementation RangeSlider 18 | 19 | @synthesize minimumValue, maximumValue, minimumRange, selectedMinimumValue, selectedMaximumValue; 20 | 21 | - (id)initWithFrame:(CGRect)frame 22 | { 23 | self = [super initWithFrame:frame]; 24 | if (self) { 25 | _minThumbOn = false; 26 | _maxThumbOn = false; 27 | _padding = 20; 28 | 29 | _trackBackground = [[[UIImageView alloc] initWithImage:[UIImage imageNamed:@"bar-background.png"]] autorelease]; 30 | _trackBackground.center = self.center; 31 | [self addSubview:_trackBackground]; 32 | 33 | _track = [[[UIImageView alloc] initWithImage:[UIImage imageNamed:@"bar-highlight.png"]] autorelease]; 34 | _track.center = self.center; 35 | [self addSubview:_track]; 36 | 37 | _minThumb = [[[UIImageView alloc] initWithImage:[UIImage imageNamed:@"handle.png"] highlightedImage:[UIImage imageNamed:@"handle-hover.png"]] autorelease]; 38 | _minThumb.frame = CGRectMake(0,0, self.frame.size.height,self.frame.size.height); 39 | _minThumb.contentMode = UIViewContentModeCenter; 40 | [self addSubview:_minThumb]; 41 | 42 | _maxThumb = [[[UIImageView alloc] initWithImage:[UIImage imageNamed:@"handle.png"] highlightedImage:[UIImage imageNamed:@"handle-hover.png"]] autorelease]; 43 | _maxThumb.frame = CGRectMake(0,0, self.frame.size.height,self.frame.size.height); 44 | _maxThumb.contentMode = UIViewContentModeCenter; 45 | [self addSubview:_maxThumb]; 46 | } 47 | 48 | return self; 49 | } 50 | 51 | 52 | -(void)layoutSubviews 53 | { 54 | // Set the initial state 55 | _minThumb.center = CGPointMake([self xForValue:selectedMinimumValue], self.center.y); 56 | 57 | _maxThumb.center = CGPointMake([self xForValue:selectedMaximumValue], self.center.y); 58 | 59 | 60 | NSLog(@"Tapable size %f", _minThumb.bounds.size.width); 61 | [self updateTrackHighlight]; 62 | 63 | 64 | } 65 | 66 | -(float)xForValue:(float)value{ 67 | return (self.frame.size.width-(_padding*2))*((value - minimumValue) / (maximumValue - minimumValue))+_padding; 68 | } 69 | 70 | -(float) valueForX:(float)x{ 71 | return minimumValue + (x-_padding) / (self.frame.size.width-(_padding*2)) * (maximumValue - minimumValue); 72 | } 73 | 74 | -(BOOL)continueTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event{ 75 | if(!_minThumbOn && !_maxThumbOn){ 76 | return YES; 77 | } 78 | 79 | CGPoint touchPoint = [touch locationInView:self]; 80 | if(_minThumbOn){ 81 | _minThumb.center = CGPointMake(MAX([self xForValue:minimumValue],MIN(touchPoint.x - distanceFromCenter, [self xForValue:selectedMaximumValue - minimumRange])), _minThumb.center.y); 82 | selectedMinimumValue = [self valueForX:_minThumb.center.x]; 83 | 84 | } 85 | if(_maxThumbOn){ 86 | _maxThumb.center = CGPointMake(MIN([self xForValue:maximumValue], MAX(touchPoint.x - distanceFromCenter, [self xForValue:selectedMinimumValue + minimumRange])), _maxThumb.center.y); 87 | selectedMaximumValue = [self valueForX:_maxThumb.center.x]; 88 | } 89 | [self updateTrackHighlight]; 90 | [self setNeedsLayout]; 91 | 92 | [self sendActionsForControlEvents:UIControlEventValueChanged]; 93 | return YES; 94 | } 95 | 96 | -(BOOL) beginTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event{ 97 | CGPoint touchPoint = [touch locationInView:self]; 98 | 99 | if(CGRectContainsPoint(_minThumb.frame, touchPoint)){ 100 | _minThumbOn = true; 101 | distanceFromCenter = touchPoint.x - _minThumb.center.x; 102 | } 103 | else if(CGRectContainsPoint(_maxThumb.frame, touchPoint)){ 104 | _maxThumbOn = true; 105 | distanceFromCenter = touchPoint.x - _maxThumb.center.x; 106 | 107 | } 108 | return YES; 109 | } 110 | 111 | -(void)endTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event{ 112 | _minThumbOn = false; 113 | _maxThumbOn = false; 114 | } 115 | 116 | -(void)updateTrackHighlight{ 117 | _track.frame = CGRectMake( 118 | _minThumb.center.x, 119 | _track.center.y - (_track.frame.size.height/2), 120 | _maxThumb.center.x - _minThumb.center.x, 121 | _track.frame.size.height 122 | ); 123 | } 124 | 125 | /* 126 | // Only override drawRect: if you perform custom drawing. 127 | // An empty implementation adversely affects performance during animation. 128 | - (void)drawRect:(CGRect)rect 129 | { 130 | // Drawing code 131 | } 132 | */ 133 | 134 | @end 135 | -------------------------------------------------------------------------------- /RangeSlider/RangeSliderAppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // RangeSliderAppDelegate.h 3 | // RangeSlider 4 | // 5 | // Created by Mal Curtis on 5/08/11. 6 | // Copyright 2011 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface RangeSliderAppDelegate : NSObject 12 | 13 | @property (nonatomic, retain) IBOutlet UIWindow *window; 14 | 15 | @property (nonatomic, retain) IBOutlet UINavigationController *navigationController; 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /RangeSlider/RangeSliderAppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // RangeSliderAppDelegate.m 3 | // RangeSlider 4 | // 5 | // Created by Mal Curtis on 5/08/11. 6 | // Copyright 2011 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import "RangeSliderAppDelegate.h" 10 | #import "DCIntrospect.h" 11 | 12 | 13 | @implementation RangeSliderAppDelegate 14 | 15 | @synthesize window = _window; 16 | @synthesize navigationController = _navigationController; 17 | 18 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 19 | { 20 | // Override point for customization after application launch. 21 | // Add the navigation controller's view to the window and display. 22 | self.window.rootViewController = self.navigationController; 23 | [self.window makeKeyAndVisible]; 24 | // always call after makeKeyAndDisplay. 25 | #ifdef TARGET_IPHONE_SIMULATOR 26 | [[DCIntrospect sharedIntrospector] start]; 27 | #endif 28 | return YES; 29 | } 30 | 31 | - (void)applicationWillResignActive:(UIApplication *)application 32 | { 33 | /* 34 | Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 35 | Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 36 | */ 37 | } 38 | 39 | - (void)applicationDidEnterBackground:(UIApplication *)application 40 | { 41 | /* 42 | Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 43 | If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 44 | */ 45 | } 46 | 47 | - (void)applicationWillEnterForeground:(UIApplication *)application 48 | { 49 | /* 50 | Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 51 | */ 52 | } 53 | 54 | - (void)applicationDidBecomeActive:(UIApplication *)application 55 | { 56 | /* 57 | Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 58 | */ 59 | } 60 | 61 | - (void)applicationWillTerminate:(UIApplication *)application 62 | { 63 | /* 64 | Called when the application is about to terminate. 65 | Save data if appropriate. 66 | See also applicationDidEnterBackground:. 67 | */ 68 | } 69 | 70 | - (void)dealloc 71 | { 72 | [_window release]; 73 | [_navigationController release]; 74 | [super dealloc]; 75 | } 76 | 77 | @end 78 | -------------------------------------------------------------------------------- /RangeSlider/RootViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // RootViewController.h 3 | // RangeSlider 4 | // 5 | // Created by Mal Curtis on 5/08/11. 6 | // Copyright 2011 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "RangeSlider.h" 11 | 12 | @interface RootViewController : UITableViewController{ 13 | NSString * _sliderRangeText; 14 | } 15 | 16 | -(void)updateRangeLabel:(RangeSlider *)slider; 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /RangeSlider/RootViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // RootViewController.m 3 | // RangeSlider 4 | // 5 | // Created by Mal Curtis on 5/08/11. 6 | // Copyright 2011 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import "RootViewController.h" 10 | #import "RangeSlider.h" 11 | 12 | @implementation RootViewController 13 | 14 | 15 | - (void)viewDidLoad 16 | { 17 | [super viewDidLoad]; 18 | } 19 | 20 | - (void)viewWillAppear:(BOOL)animated 21 | { 22 | [super viewWillAppear:animated]; 23 | } 24 | 25 | - (void)viewDidAppear:(BOOL)animated 26 | { 27 | [super viewDidAppear:animated]; 28 | } 29 | 30 | - (void)viewWillDisappear:(BOOL)animated 31 | { 32 | [super viewWillDisappear:animated]; 33 | } 34 | 35 | - (void)viewDidDisappear:(BOOL)animated 36 | { 37 | [super viewDidDisappear:animated]; 38 | } 39 | 40 | 41 | // Override to allow orientations other than the default portrait orientation. 42 | - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { 43 | // Return YES for supported orientations. 44 | return YES; //(interfaceOrientation == UIInterfaceOrientationPortrait); 45 | } 46 | 47 | 48 | // Customize the number of sections in the table view. 49 | - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView 50 | { 51 | return 1; 52 | } 53 | 54 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 55 | { 56 | return 1; 57 | } 58 | 59 | // Customize the appearance of table view cells. 60 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 61 | { 62 | static NSString *CellIdentifier = @"Cell"; 63 | 64 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; 65 | if (cell == nil) { 66 | cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease]; 67 | } 68 | 69 | 70 | // Configure the cell. 71 | RangeSlider *slider= [[RangeSlider alloc] initWithFrame:cell.bounds]; 72 | slider.minimumValue = 1; 73 | slider.selectedMinimumValue = 2; 74 | slider.maximumValue = 10; 75 | slider.selectedMaximumValue = 8; 76 | slider.minimumRange = 2; 77 | [slider addTarget:self action:@selector(updateRangeLabel:) forControlEvents:UIControlEventValueChanged]; 78 | 79 | 80 | [cell addSubview:slider]; 81 | 82 | return cell; 83 | } 84 | 85 | -(void)updateRangeLabel:(RangeSlider *)slider{ 86 | NSLog(@"Slider Range: %f - %f", slider.selectedMinimumValue, slider.selectedMaximumValue); 87 | } 88 | 89 | /* 90 | // Override to support conditional editing of the table view. 91 | - (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath 92 | { 93 | // Return NO if you do not want the specified item to be editable. 94 | return YES; 95 | } 96 | */ 97 | 98 | /* 99 | // Override to support editing the table view. 100 | - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath 101 | { 102 | if (editingStyle == UITableViewCellEditingStyleDelete) 103 | { 104 | // Delete the row from the data source. 105 | [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade]; 106 | } 107 | else if (editingStyle == UITableViewCellEditingStyleInsert) 108 | { 109 | // Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view. 110 | } 111 | } 112 | */ 113 | 114 | /* 115 | // Override to support rearranging the table view. 116 | - (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath 117 | { 118 | } 119 | */ 120 | 121 | /* 122 | // Override to support conditional rearranging of the table view. 123 | - (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath 124 | { 125 | // Return NO if you do not want the item to be re-orderable. 126 | return YES; 127 | } 128 | */ 129 | 130 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath 131 | { 132 | /* 133 | <#DetailViewController#> *detailViewController = [[<#DetailViewController#> alloc] initWithNibName:@"<#Nib name#>" bundle:nil]; 134 | // ... 135 | // Pass the selected object to the new view controller. 136 | [self.navigationController pushViewController:detailViewController animated:YES]; 137 | [detailViewController release]; 138 | */ 139 | } 140 | 141 | - (void)didReceiveMemoryWarning 142 | { 143 | // Releases the view if it doesn't have a superview. 144 | [super didReceiveMemoryWarning]; 145 | 146 | // Relinquish ownership any cached data, images, etc that aren't in use. 147 | } 148 | 149 | - (void)viewDidUnload 150 | { 151 | [super viewDidUnload]; 152 | 153 | // Relinquish ownership of anything that can be recreated in viewDidLoad or on demand. 154 | // For example: self.myOutlet = nil; 155 | } 156 | 157 | - (void)dealloc 158 | { 159 | [super dealloc]; 160 | } 161 | 162 | @end 163 | -------------------------------------------------------------------------------- /RangeSlider/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /RangeSlider/en.lproj/MainWindow.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 1024 5 | 10D571 6 | 786 7 | 1038.29 8 | 460.00 9 | 10 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 11 | 112 12 | 13 | 14 | YES 15 | 16 | 17 | 18 | YES 19 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 20 | 21 | 22 | YES 23 | 24 | YES 25 | 26 | 27 | YES 28 | 29 | 30 | 31 | YES 32 | 33 | IBFilesOwner 34 | IBCocoaTouchFramework 35 | 36 | 37 | IBFirstResponder 38 | IBCocoaTouchFramework 39 | 40 | 41 | IBCocoaTouchFramework 42 | 43 | 44 | 45 | 1316 46 | 47 | {320, 480} 48 | 49 | 1 50 | MSAxIDEAA 51 | 52 | NO 53 | NO 54 | 55 | IBCocoaTouchFramework 56 | YES 57 | 58 | 59 | 60 | 61 | 1 62 | 63 | IBCocoaTouchFramework 64 | NO 65 | 66 | 67 | 256 68 | {0, 0} 69 | NO 70 | YES 71 | YES 72 | IBCocoaTouchFramework 73 | 74 | 75 | YES 76 | 77 | 78 | 79 | IBCocoaTouchFramework 80 | 81 | 82 | RootViewController 83 | 84 | 85 | 1 86 | 87 | IBCocoaTouchFramework 88 | NO 89 | 90 | 91 | 92 | 93 | 94 | 95 | YES 96 | 97 | 98 | delegate 99 | 100 | 101 | 102 | 4 103 | 104 | 105 | 106 | window 107 | 108 | 109 | 110 | 5 111 | 112 | 113 | 114 | navigationController 115 | 116 | 117 | 118 | 15 119 | 120 | 121 | 122 | 123 | YES 124 | 125 | 0 126 | 127 | 128 | 129 | 130 | 131 | 2 132 | 133 | 134 | YES 135 | 136 | 137 | 138 | 139 | -1 140 | 141 | 142 | File's Owner 143 | 144 | 145 | 3 146 | 147 | 148 | 149 | 150 | -2 151 | 152 | 153 | 154 | 155 | 9 156 | 157 | 158 | YES 159 | 160 | 161 | 162 | 163 | 164 | 165 | 11 166 | 167 | 168 | 169 | 170 | 13 171 | 172 | 173 | YES 174 | 175 | 176 | 177 | 178 | 179 | 14 180 | 181 | 182 | 183 | 184 | 185 | 186 | YES 187 | 188 | YES 189 | -1.CustomClassName 190 | -2.CustomClassName 191 | 11.IBPluginDependency 192 | 13.CustomClassName 193 | 13.IBPluginDependency 194 | 2.IBAttributePlaceholdersKey 195 | 2.IBEditorWindowLastContentRect 196 | 2.IBPluginDependency 197 | 3.CustomClassName 198 | 3.IBPluginDependency 199 | 9.IBEditorWindowLastContentRect 200 | 9.IBPluginDependency 201 | 202 | 203 | YES 204 | UIApplication 205 | UIResponder 206 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 207 | RootViewController 208 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 209 | 210 | YES 211 | 212 | 213 | YES 214 | 215 | 216 | {{673, 376}, {320, 480}} 217 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 218 | RangeSliderAppDelegate 219 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 220 | {{186, 376}, {320, 480}} 221 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 222 | 223 | 224 | 225 | YES 226 | 227 | 228 | YES 229 | 230 | 231 | 232 | 233 | YES 234 | 235 | 236 | YES 237 | 238 | 239 | 240 | 16 241 | 242 | 243 | 244 | YES 245 | 246 | RootViewController 247 | UITableViewController 248 | 249 | IBProjectSource 250 | RootViewController.h 251 | 252 | 253 | 254 | UIWindow 255 | UIView 256 | 257 | IBUserSource 258 | 259 | 260 | 261 | 262 | RangeSliderAppDelegate 263 | NSObject 264 | 265 | YES 266 | 267 | YES 268 | navigationController 269 | window 270 | 271 | 272 | YES 273 | UINavigationController 274 | UIWindow 275 | 276 | 277 | 278 | YES 279 | 280 | YES 281 | navigationController 282 | window 283 | 284 | 285 | YES 286 | 287 | navigationController 288 | UINavigationController 289 | 290 | 291 | window 292 | UIWindow 293 | 294 | 295 | 296 | 297 | IBProjectSource 298 | RangeSliderAppDelegate.h 299 | 300 | 301 | 302 | 303 | YES 304 | 305 | NSObject 306 | 307 | IBFrameworkSource 308 | Foundation.framework/Headers/NSError.h 309 | 310 | 311 | 312 | NSObject 313 | 314 | IBFrameworkSource 315 | Foundation.framework/Headers/NSFileManager.h 316 | 317 | 318 | 319 | NSObject 320 | 321 | IBFrameworkSource 322 | Foundation.framework/Headers/NSKeyValueCoding.h 323 | 324 | 325 | 326 | NSObject 327 | 328 | IBFrameworkSource 329 | Foundation.framework/Headers/NSKeyValueObserving.h 330 | 331 | 332 | 333 | NSObject 334 | 335 | IBFrameworkSource 336 | Foundation.framework/Headers/NSKeyedArchiver.h 337 | 338 | 339 | 340 | NSObject 341 | 342 | IBFrameworkSource 343 | Foundation.framework/Headers/NSObject.h 344 | 345 | 346 | 347 | NSObject 348 | 349 | IBFrameworkSource 350 | Foundation.framework/Headers/NSRunLoop.h 351 | 352 | 353 | 354 | NSObject 355 | 356 | IBFrameworkSource 357 | Foundation.framework/Headers/NSThread.h 358 | 359 | 360 | 361 | NSObject 362 | 363 | IBFrameworkSource 364 | Foundation.framework/Headers/NSURL.h 365 | 366 | 367 | 368 | NSObject 369 | 370 | IBFrameworkSource 371 | Foundation.framework/Headers/NSURLConnection.h 372 | 373 | 374 | 375 | NSObject 376 | 377 | IBFrameworkSource 378 | UIKit.framework/Headers/UIAccessibility.h 379 | 380 | 381 | 382 | NSObject 383 | 384 | IBFrameworkSource 385 | UIKit.framework/Headers/UINibLoading.h 386 | 387 | 388 | 389 | NSObject 390 | 391 | IBFrameworkSource 392 | UIKit.framework/Headers/UIResponder.h 393 | 394 | 395 | 396 | UIApplication 397 | UIResponder 398 | 399 | IBFrameworkSource 400 | UIKit.framework/Headers/UIApplication.h 401 | 402 | 403 | 404 | UIBarButtonItem 405 | UIBarItem 406 | 407 | IBFrameworkSource 408 | UIKit.framework/Headers/UIBarButtonItem.h 409 | 410 | 411 | 412 | UIBarItem 413 | NSObject 414 | 415 | IBFrameworkSource 416 | UIKit.framework/Headers/UIBarItem.h 417 | 418 | 419 | 420 | UINavigationBar 421 | UIView 422 | 423 | IBFrameworkSource 424 | UIKit.framework/Headers/UINavigationBar.h 425 | 426 | 427 | 428 | UINavigationController 429 | UIViewController 430 | 431 | IBFrameworkSource 432 | UIKit.framework/Headers/UINavigationController.h 433 | 434 | 435 | 436 | UINavigationItem 437 | NSObject 438 | 439 | 440 | 441 | UIResponder 442 | NSObject 443 | 444 | 445 | 446 | UISearchBar 447 | UIView 448 | 449 | IBFrameworkSource 450 | UIKit.framework/Headers/UISearchBar.h 451 | 452 | 453 | 454 | UISearchDisplayController 455 | NSObject 456 | 457 | IBFrameworkSource 458 | UIKit.framework/Headers/UISearchDisplayController.h 459 | 460 | 461 | 462 | UITableViewController 463 | UIViewController 464 | 465 | IBFrameworkSource 466 | UIKit.framework/Headers/UITableViewController.h 467 | 468 | 469 | 470 | UIView 471 | 472 | IBFrameworkSource 473 | UIKit.framework/Headers/UITextField.h 474 | 475 | 476 | 477 | UIView 478 | UIResponder 479 | 480 | IBFrameworkSource 481 | UIKit.framework/Headers/UIView.h 482 | 483 | 484 | 485 | UIViewController 486 | 487 | 488 | 489 | UIViewController 490 | 491 | IBFrameworkSource 492 | UIKit.framework/Headers/UIPopoverController.h 493 | 494 | 495 | 496 | UIViewController 497 | 498 | IBFrameworkSource 499 | UIKit.framework/Headers/UISplitViewController.h 500 | 501 | 502 | 503 | UIViewController 504 | 505 | IBFrameworkSource 506 | UIKit.framework/Headers/UITabBarController.h 507 | 508 | 509 | 510 | UIViewController 511 | UIResponder 512 | 513 | IBFrameworkSource 514 | UIKit.framework/Headers/UIViewController.h 515 | 516 | 517 | 518 | UIWindow 519 | UIView 520 | 521 | IBFrameworkSource 522 | UIKit.framework/Headers/UIWindow.h 523 | 524 | 525 | 526 | 527 | 0 528 | IBCocoaTouchFramework 529 | 530 | com.apple.InterfaceBuilder.CocoaTouchPlugin.iPhoneOS 531 | 532 | 533 | 534 | com.apple.InterfaceBuilder.CocoaTouchPlugin.InterfaceBuilder3 535 | 536 | 537 | YES 538 | RangeSlider.xcodeproj 539 | 3 540 | 112 541 | 542 | 543 | -------------------------------------------------------------------------------- /RangeSlider/en.lproj/RootViewController.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 784 5 | 10D541 6 | 760 7 | 1038.29 8 | 460.00 9 | 10 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 11 | 81 12 | 13 | 14 | YES 15 | 16 | 17 | 18 | YES 19 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 20 | 21 | 22 | YES 23 | 24 | YES 25 | 26 | 27 | YES 28 | 29 | 30 | 31 | YES 32 | 33 | IBFilesOwner 34 | IBCocoaTouchFramework 35 | 36 | 37 | IBFirstResponder 38 | IBCocoaTouchFramework 39 | 40 | 41 | 42 | 274 43 | {320, 247} 44 | 45 | 46 | 3 47 | MQA 48 | 49 | NO 50 | YES 51 | NO 52 | IBCocoaTouchFramework 53 | NO 54 | 1 55 | 0 56 | YES 57 | 44 58 | 22 59 | 22 60 | 61 | 62 | 63 | 64 | YES 65 | 66 | 67 | view 68 | 69 | 70 | 71 | 3 72 | 73 | 74 | 75 | dataSource 76 | 77 | 78 | 79 | 4 80 | 81 | 82 | 83 | delegate 84 | 85 | 86 | 87 | 5 88 | 89 | 90 | 91 | 92 | YES 93 | 94 | 0 95 | 96 | 97 | 98 | 99 | 100 | -1 101 | 102 | 103 | File's Owner 104 | 105 | 106 | -2 107 | 108 | 109 | 110 | 111 | 2 112 | 113 | 114 | 115 | 116 | 117 | 118 | YES 119 | 120 | YES 121 | -1.CustomClassName 122 | -2.CustomClassName 123 | 2.IBEditorWindowLastContentRect 124 | 2.IBPluginDependency 125 | 126 | 127 | YES 128 | RootViewController 129 | UIResponder 130 | {{144, 609}, {320, 247}} 131 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 132 | 133 | 134 | 135 | YES 136 | 137 | 138 | YES 139 | 140 | 141 | 142 | 143 | YES 144 | 145 | 146 | YES 147 | 148 | 149 | 150 | 5 151 | 152 | 153 | 154 | YES 155 | 156 | RootViewController 157 | UITableViewController 158 | 159 | IBProjectSource 160 | RootViewController.h 161 | 162 | 163 | 164 | 165 | YES 166 | 167 | NSObject 168 | 169 | IBFrameworkSource 170 | Foundation.framework/Headers/NSError.h 171 | 172 | 173 | 174 | NSObject 175 | 176 | IBFrameworkSource 177 | Foundation.framework/Headers/NSFileManager.h 178 | 179 | 180 | 181 | NSObject 182 | 183 | IBFrameworkSource 184 | Foundation.framework/Headers/NSKeyValueCoding.h 185 | 186 | 187 | 188 | NSObject 189 | 190 | IBFrameworkSource 191 | Foundation.framework/Headers/NSKeyValueObserving.h 192 | 193 | 194 | 195 | NSObject 196 | 197 | IBFrameworkSource 198 | Foundation.framework/Headers/NSKeyedArchiver.h 199 | 200 | 201 | 202 | NSObject 203 | 204 | IBFrameworkSource 205 | Foundation.framework/Headers/NSNetServices.h 206 | 207 | 208 | 209 | NSObject 210 | 211 | IBFrameworkSource 212 | Foundation.framework/Headers/NSObject.h 213 | 214 | 215 | 216 | NSObject 217 | 218 | IBFrameworkSource 219 | Foundation.framework/Headers/NSPort.h 220 | 221 | 222 | 223 | NSObject 224 | 225 | IBFrameworkSource 226 | Foundation.framework/Headers/NSRunLoop.h 227 | 228 | 229 | 230 | NSObject 231 | 232 | IBFrameworkSource 233 | Foundation.framework/Headers/NSStream.h 234 | 235 | 236 | 237 | NSObject 238 | 239 | IBFrameworkSource 240 | Foundation.framework/Headers/NSThread.h 241 | 242 | 243 | 244 | NSObject 245 | 246 | IBFrameworkSource 247 | Foundation.framework/Headers/NSURL.h 248 | 249 | 250 | 251 | NSObject 252 | 253 | IBFrameworkSource 254 | Foundation.framework/Headers/NSURLConnection.h 255 | 256 | 257 | 258 | NSObject 259 | 260 | IBFrameworkSource 261 | Foundation.framework/Headers/NSXMLParser.h 262 | 263 | 264 | 265 | NSObject 266 | 267 | IBFrameworkSource 268 | UIKit.framework/Headers/UIAccessibility.h 269 | 270 | 271 | 272 | NSObject 273 | 274 | IBFrameworkSource 275 | UIKit.framework/Headers/UINibLoading.h 276 | 277 | 278 | 279 | NSObject 280 | 281 | IBFrameworkSource 282 | UIKit.framework/Headers/UIResponder.h 283 | 284 | 285 | 286 | UIResponder 287 | NSObject 288 | 289 | 290 | 291 | UIScrollView 292 | UIView 293 | 294 | IBFrameworkSource 295 | UIKit.framework/Headers/UIScrollView.h 296 | 297 | 298 | 299 | UISearchBar 300 | UIView 301 | 302 | IBFrameworkSource 303 | UIKit.framework/Headers/UISearchBar.h 304 | 305 | 306 | 307 | UISearchDisplayController 308 | NSObject 309 | 310 | IBFrameworkSource 311 | UIKit.framework/Headers/UISearchDisplayController.h 312 | 313 | 314 | 315 | UITableView 316 | UIScrollView 317 | 318 | IBFrameworkSource 319 | UIKit.framework/Headers/UITableView.h 320 | 321 | 322 | 323 | UITableViewController 324 | UIViewController 325 | 326 | IBFrameworkSource 327 | UIKit.framework/Headers/UITableViewController.h 328 | 329 | 330 | 331 | UIView 332 | 333 | IBFrameworkSource 334 | UIKit.framework/Headers/UITextField.h 335 | 336 | 337 | 338 | UIView 339 | UIResponder 340 | 341 | IBFrameworkSource 342 | UIKit.framework/Headers/UIView.h 343 | 344 | 345 | 346 | UIViewController 347 | 348 | IBFrameworkSource 349 | UIKit.framework/Headers/UINavigationController.h 350 | 351 | 352 | 353 | UIViewController 354 | 355 | IBFrameworkSource 356 | UIKit.framework/Headers/UITabBarController.h 357 | 358 | 359 | 360 | UIViewController 361 | UIResponder 362 | 363 | IBFrameworkSource 364 | UIKit.framework/Headers/UIViewController.h 365 | 366 | 367 | 368 | 369 | 0 370 | IBCocoaTouchFramework 371 | 372 | com.apple.InterfaceBuilder.CocoaTouchPlugin.iPhoneOS 373 | 374 | 375 | 376 | com.apple.InterfaceBuilder.CocoaTouchPlugin.InterfaceBuilder3 377 | 378 | 379 | YES 380 | RangeSlider.xcodeproj 381 | 3 382 | 81 383 | 384 | 385 | -------------------------------------------------------------------------------- /RangeSlider/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // RangeSlider 4 | // 5 | // Created by Mal Curtis on 5/08/11. 6 | // Copyright 2011 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | int main(int argc, char *argv[]) 12 | { 13 | NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 14 | int retVal = UIApplicationMain(argc, argv, nil, nil); 15 | [pool release]; 16 | return retVal; 17 | } 18 | --------------------------------------------------------------------------------