├── .swift-version ├── CustomSegue.podspec ├── CustomSegue.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcuserdata │ │ └── wouter.xcuserdatad │ │ └── UserInterfaceState.xcuserstate └── xcshareddata │ └── xcschemes │ └── CustomSegue.xcscheme ├── CustomSegue ├── CustomSegue.h └── Info.plist ├── Example ├── Example.xcodeproj │ ├── project.pbxproj │ └── project.xcworkspace │ │ └── contents.xcworkspacedata ├── Example.xcworkspace │ └── contents.xcworkspacedata ├── Example │ ├── AppDelegate.swift │ ├── Assets.xcassets │ │ └── AppIcon.appiconset │ │ │ └── Contents.json │ ├── Base.lproj │ │ └── Main.storyboard │ ├── CustomAnimator.swift │ ├── DestinationViewController.swift │ ├── FromViewController.swift │ ├── Info.plist │ ├── SplitViewController.swift │ └── Storyboards.swift ├── Podfile └── Podfile.lock ├── LICENSE ├── Package.swift ├── README.md ├── SB_H_set_segue_identifier_2x.png ├── Sources ├── ChildWindowSegue.swift ├── DismissSegue.swift ├── NSViewController+CustomSegue.swift ├── PresentWithAnimatorSegue.swift ├── ReplaceWindowContentSegue.swift ├── SplitViewSegue.swift ├── TablePopoverSegue.swift ├── TransitionAnimator.swift └── TransitionFromViewSegue.swift ├── logo.png └── screen.gif /.swift-version: -------------------------------------------------------------------------------- 1 | 5.0 2 | -------------------------------------------------------------------------------- /CustomSegue.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | 3 | # ――― Spec Metadata ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 4 | s.name = "CustomSegue" 5 | s.version = "4.0.0" 6 | s.summary = "Custom segue for OSX Storyboards with slide and cross fade effects" 7 | s.homepage = "https://github.com/phimage/CustomSegue" 8 | 9 | # ――― Spec License ――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 10 | s.license = "MIT" 11 | 12 | # ――― Author Metadata ――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 13 | s.author = { "phimage" => "eric.marchand.n7@gmail.com" } 14 | 15 | # ――― Platform Specifics ――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 16 | s.osx.deployment_target = '10.11' 17 | 18 | # ――― Source Location ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 19 | s.source = { :git => "https://github.com/phimage/CustomSegue.git", :tag => s.version } 20 | 21 | # ――― Source Code ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 22 | 23 | s.source_files = "Sources/*.swift" 24 | # s.swift_version = '5.0' 25 | 26 | end 27 | -------------------------------------------------------------------------------- /CustomSegue.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | C40299DA1D44AC0A007477E4 /* CustomSegue.h in Headers */ = {isa = PBXBuildFile; fileRef = C40299D91D44AC0A007477E4 /* CustomSegue.h */; settings = {ATTRIBUTES = (Public, ); }; }; 11 | C4BC15B11D84524D00D10F10 /* ChildWindowSegue.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4BC15A81D84524D00D10F10 /* ChildWindowSegue.swift */; }; 12 | C4BC15B21D84524D00D10F10 /* DismissSegue.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4BC15A91D84524D00D10F10 /* DismissSegue.swift */; }; 13 | C4BC15B31D84524D00D10F10 /* NSViewController+CustomSegue.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4BC15AA1D84524D00D10F10 /* NSViewController+CustomSegue.swift */; }; 14 | C4BC15B41D84524D00D10F10 /* PresentWithAnimatorSegue.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4BC15AB1D84524D00D10F10 /* PresentWithAnimatorSegue.swift */; }; 15 | C4BC15B51D84524D00D10F10 /* ReplaceWindowContentSegue.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4BC15AC1D84524D00D10F10 /* ReplaceWindowContentSegue.swift */; }; 16 | C4BC15B61D84524D00D10F10 /* SplitViewSegue.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4BC15AD1D84524D00D10F10 /* SplitViewSegue.swift */; }; 17 | C4BC15B71D84524D00D10F10 /* TablePopoverSegue.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4BC15AE1D84524D00D10F10 /* TablePopoverSegue.swift */; }; 18 | C4BC15B81D84524D00D10F10 /* TransitionAnimator.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4BC15AF1D84524D00D10F10 /* TransitionAnimator.swift */; }; 19 | C4BC15B91D84524D00D10F10 /* TransitionFromViewSegue.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4BC15B01D84524D00D10F10 /* TransitionFromViewSegue.swift */; }; 20 | /* End PBXBuildFile section */ 21 | 22 | /* Begin PBXFileReference section */ 23 | C40299D61D44AC0A007477E4 /* CustomSegue.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = CustomSegue.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 24 | C40299D91D44AC0A007477E4 /* CustomSegue.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CustomSegue.h; sourceTree = ""; }; 25 | C40299DB1D44AC0A007477E4 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 26 | C4BC15A81D84524D00D10F10 /* ChildWindowSegue.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChildWindowSegue.swift; sourceTree = ""; }; 27 | C4BC15A91D84524D00D10F10 /* DismissSegue.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DismissSegue.swift; sourceTree = ""; }; 28 | C4BC15AA1D84524D00D10F10 /* NSViewController+CustomSegue.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSViewController+CustomSegue.swift"; sourceTree = ""; }; 29 | C4BC15AB1D84524D00D10F10 /* PresentWithAnimatorSegue.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PresentWithAnimatorSegue.swift; sourceTree = ""; }; 30 | C4BC15AC1D84524D00D10F10 /* ReplaceWindowContentSegue.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReplaceWindowContentSegue.swift; sourceTree = ""; }; 31 | C4BC15AD1D84524D00D10F10 /* SplitViewSegue.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SplitViewSegue.swift; sourceTree = ""; }; 32 | C4BC15AE1D84524D00D10F10 /* TablePopoverSegue.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TablePopoverSegue.swift; sourceTree = ""; }; 33 | C4BC15AF1D84524D00D10F10 /* TransitionAnimator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TransitionAnimator.swift; sourceTree = ""; }; 34 | C4BC15B01D84524D00D10F10 /* TransitionFromViewSegue.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TransitionFromViewSegue.swift; sourceTree = ""; }; 35 | /* End PBXFileReference section */ 36 | 37 | /* Begin PBXFrameworksBuildPhase section */ 38 | C40299D21D44AC0A007477E4 /* Frameworks */ = { 39 | isa = PBXFrameworksBuildPhase; 40 | buildActionMask = 2147483647; 41 | files = ( 42 | ); 43 | runOnlyForDeploymentPostprocessing = 0; 44 | }; 45 | /* End PBXFrameworksBuildPhase section */ 46 | 47 | /* Begin PBXGroup section */ 48 | C40299CC1D44AC0A007477E4 = { 49 | isa = PBXGroup; 50 | children = ( 51 | C4BC15A71D84524D00D10F10 /* Sources */, 52 | C40299D81D44AC0A007477E4 /* CustomSegue */, 53 | C40299D71D44AC0A007477E4 /* Products */, 54 | ); 55 | sourceTree = ""; 56 | }; 57 | C40299D71D44AC0A007477E4 /* Products */ = { 58 | isa = PBXGroup; 59 | children = ( 60 | C40299D61D44AC0A007477E4 /* CustomSegue.framework */, 61 | ); 62 | name = Products; 63 | sourceTree = ""; 64 | }; 65 | C40299D81D44AC0A007477E4 /* CustomSegue */ = { 66 | isa = PBXGroup; 67 | children = ( 68 | C40299D91D44AC0A007477E4 /* CustomSegue.h */, 69 | C40299DB1D44AC0A007477E4 /* Info.plist */, 70 | ); 71 | path = CustomSegue; 72 | sourceTree = ""; 73 | }; 74 | C4BC15A71D84524D00D10F10 /* Sources */ = { 75 | isa = PBXGroup; 76 | children = ( 77 | C4BC15A81D84524D00D10F10 /* ChildWindowSegue.swift */, 78 | C4BC15A91D84524D00D10F10 /* DismissSegue.swift */, 79 | C4BC15AA1D84524D00D10F10 /* NSViewController+CustomSegue.swift */, 80 | C4BC15AB1D84524D00D10F10 /* PresentWithAnimatorSegue.swift */, 81 | C4BC15AC1D84524D00D10F10 /* ReplaceWindowContentSegue.swift */, 82 | C4BC15AD1D84524D00D10F10 /* SplitViewSegue.swift */, 83 | C4BC15AE1D84524D00D10F10 /* TablePopoverSegue.swift */, 84 | C4BC15AF1D84524D00D10F10 /* TransitionAnimator.swift */, 85 | C4BC15B01D84524D00D10F10 /* TransitionFromViewSegue.swift */, 86 | ); 87 | path = Sources; 88 | sourceTree = ""; 89 | }; 90 | /* End PBXGroup section */ 91 | 92 | /* Begin PBXHeadersBuildPhase section */ 93 | C40299D31D44AC0A007477E4 /* Headers */ = { 94 | isa = PBXHeadersBuildPhase; 95 | buildActionMask = 2147483647; 96 | files = ( 97 | C40299DA1D44AC0A007477E4 /* CustomSegue.h in Headers */, 98 | ); 99 | runOnlyForDeploymentPostprocessing = 0; 100 | }; 101 | /* End PBXHeadersBuildPhase section */ 102 | 103 | /* Begin PBXNativeTarget section */ 104 | C40299D51D44AC0A007477E4 /* CustomSegue */ = { 105 | isa = PBXNativeTarget; 106 | buildConfigurationList = C40299DE1D44AC0A007477E4 /* Build configuration list for PBXNativeTarget "CustomSegue" */; 107 | buildPhases = ( 108 | C40299D11D44AC0A007477E4 /* Sources */, 109 | C40299D21D44AC0A007477E4 /* Frameworks */, 110 | C40299D31D44AC0A007477E4 /* Headers */, 111 | C40299D41D44AC0A007477E4 /* Resources */, 112 | ); 113 | buildRules = ( 114 | ); 115 | dependencies = ( 116 | ); 117 | name = CustomSegue; 118 | productName = CustomSegue; 119 | productReference = C40299D61D44AC0A007477E4 /* CustomSegue.framework */; 120 | productType = "com.apple.product-type.framework"; 121 | }; 122 | /* End PBXNativeTarget section */ 123 | 124 | /* Begin PBXProject section */ 125 | C40299CD1D44AC0A007477E4 /* Project object */ = { 126 | isa = PBXProject; 127 | attributes = { 128 | LastUpgradeCheck = 1020; 129 | ORGANIZATIONNAME = phimage; 130 | TargetAttributes = { 131 | C40299D51D44AC0A007477E4 = { 132 | CreatedOnToolsVersion = 7.3.1; 133 | LastSwiftMigration = 1020; 134 | }; 135 | }; 136 | }; 137 | buildConfigurationList = C40299D01D44AC0A007477E4 /* Build configuration list for PBXProject "CustomSegue" */; 138 | compatibilityVersion = "Xcode 3.2"; 139 | developmentRegion = en; 140 | hasScannedForEncodings = 0; 141 | knownRegions = ( 142 | en, 143 | Base, 144 | ); 145 | mainGroup = C40299CC1D44AC0A007477E4; 146 | productRefGroup = C40299D71D44AC0A007477E4 /* Products */; 147 | projectDirPath = ""; 148 | projectRoot = ""; 149 | targets = ( 150 | C40299D51D44AC0A007477E4 /* CustomSegue */, 151 | ); 152 | }; 153 | /* End PBXProject section */ 154 | 155 | /* Begin PBXResourcesBuildPhase section */ 156 | C40299D41D44AC0A007477E4 /* Resources */ = { 157 | isa = PBXResourcesBuildPhase; 158 | buildActionMask = 2147483647; 159 | files = ( 160 | ); 161 | runOnlyForDeploymentPostprocessing = 0; 162 | }; 163 | /* End PBXResourcesBuildPhase section */ 164 | 165 | /* Begin PBXSourcesBuildPhase section */ 166 | C40299D11D44AC0A007477E4 /* Sources */ = { 167 | isa = PBXSourcesBuildPhase; 168 | buildActionMask = 2147483647; 169 | files = ( 170 | C4BC15B51D84524D00D10F10 /* ReplaceWindowContentSegue.swift in Sources */, 171 | C4BC15B31D84524D00D10F10 /* NSViewController+CustomSegue.swift in Sources */, 172 | C4BC15B41D84524D00D10F10 /* PresentWithAnimatorSegue.swift in Sources */, 173 | C4BC15B21D84524D00D10F10 /* DismissSegue.swift in Sources */, 174 | C4BC15B81D84524D00D10F10 /* TransitionAnimator.swift in Sources */, 175 | C4BC15B11D84524D00D10F10 /* ChildWindowSegue.swift in Sources */, 176 | C4BC15B91D84524D00D10F10 /* TransitionFromViewSegue.swift in Sources */, 177 | C4BC15B61D84524D00D10F10 /* SplitViewSegue.swift in Sources */, 178 | C4BC15B71D84524D00D10F10 /* TablePopoverSegue.swift in Sources */, 179 | ); 180 | runOnlyForDeploymentPostprocessing = 0; 181 | }; 182 | /* End PBXSourcesBuildPhase section */ 183 | 184 | /* Begin XCBuildConfiguration section */ 185 | C40299DC1D44AC0A007477E4 /* Debug */ = { 186 | isa = XCBuildConfiguration; 187 | buildSettings = { 188 | ALWAYS_SEARCH_USER_PATHS = NO; 189 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 190 | CLANG_ANALYZER_NONNULL = YES; 191 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 192 | CLANG_CXX_LIBRARY = "libc++"; 193 | CLANG_ENABLE_MODULES = YES; 194 | CLANG_ENABLE_OBJC_ARC = YES; 195 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 196 | CLANG_WARN_BOOL_CONVERSION = YES; 197 | CLANG_WARN_COMMA = YES; 198 | CLANG_WARN_CONSTANT_CONVERSION = YES; 199 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 200 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 201 | CLANG_WARN_EMPTY_BODY = YES; 202 | CLANG_WARN_ENUM_CONVERSION = YES; 203 | CLANG_WARN_INFINITE_RECURSION = YES; 204 | CLANG_WARN_INT_CONVERSION = YES; 205 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 206 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 207 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 208 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 209 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 210 | CLANG_WARN_STRICT_PROTOTYPES = YES; 211 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 212 | CLANG_WARN_UNREACHABLE_CODE = YES; 213 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 214 | CODE_SIGN_IDENTITY = "-"; 215 | COPY_PHASE_STRIP = NO; 216 | CURRENT_PROJECT_VERSION = 1; 217 | DEBUG_INFORMATION_FORMAT = dwarf; 218 | ENABLE_STRICT_OBJC_MSGSEND = YES; 219 | ENABLE_TESTABILITY = YES; 220 | GCC_C_LANGUAGE_STANDARD = gnu99; 221 | GCC_DYNAMIC_NO_PIC = NO; 222 | GCC_NO_COMMON_BLOCKS = YES; 223 | GCC_OPTIMIZATION_LEVEL = 0; 224 | GCC_PREPROCESSOR_DEFINITIONS = ( 225 | "DEBUG=1", 226 | "$(inherited)", 227 | ); 228 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 229 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 230 | GCC_WARN_UNDECLARED_SELECTOR = YES; 231 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 232 | GCC_WARN_UNUSED_FUNCTION = YES; 233 | GCC_WARN_UNUSED_VARIABLE = YES; 234 | MACOSX_DEPLOYMENT_TARGET = 10.13; 235 | MTL_ENABLE_DEBUG_INFO = YES; 236 | ONLY_ACTIVE_ARCH = YES; 237 | SDKROOT = macosx; 238 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 239 | SWIFT_SWIFT3_OBJC_INFERENCE = Off; 240 | SWIFT_VERSION = 4.0; 241 | VERSIONING_SYSTEM = "apple-generic"; 242 | VERSION_INFO_PREFIX = ""; 243 | }; 244 | name = Debug; 245 | }; 246 | C40299DD1D44AC0A007477E4 /* Release */ = { 247 | isa = XCBuildConfiguration; 248 | buildSettings = { 249 | ALWAYS_SEARCH_USER_PATHS = NO; 250 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 251 | CLANG_ANALYZER_NONNULL = YES; 252 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 253 | CLANG_CXX_LIBRARY = "libc++"; 254 | CLANG_ENABLE_MODULES = YES; 255 | CLANG_ENABLE_OBJC_ARC = YES; 256 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 257 | CLANG_WARN_BOOL_CONVERSION = YES; 258 | CLANG_WARN_COMMA = YES; 259 | CLANG_WARN_CONSTANT_CONVERSION = YES; 260 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 261 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 262 | CLANG_WARN_EMPTY_BODY = YES; 263 | CLANG_WARN_ENUM_CONVERSION = YES; 264 | CLANG_WARN_INFINITE_RECURSION = YES; 265 | CLANG_WARN_INT_CONVERSION = YES; 266 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 267 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 268 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 269 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 270 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 271 | CLANG_WARN_STRICT_PROTOTYPES = YES; 272 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 273 | CLANG_WARN_UNREACHABLE_CODE = YES; 274 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 275 | CODE_SIGN_IDENTITY = "-"; 276 | COPY_PHASE_STRIP = NO; 277 | CURRENT_PROJECT_VERSION = 1; 278 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 279 | ENABLE_NS_ASSERTIONS = NO; 280 | ENABLE_STRICT_OBJC_MSGSEND = YES; 281 | GCC_C_LANGUAGE_STANDARD = gnu99; 282 | GCC_NO_COMMON_BLOCKS = YES; 283 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 284 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 285 | GCC_WARN_UNDECLARED_SELECTOR = YES; 286 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 287 | GCC_WARN_UNUSED_FUNCTION = YES; 288 | GCC_WARN_UNUSED_VARIABLE = YES; 289 | MACOSX_DEPLOYMENT_TARGET = 10.13; 290 | MTL_ENABLE_DEBUG_INFO = NO; 291 | SDKROOT = macosx; 292 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 293 | SWIFT_SWIFT3_OBJC_INFERENCE = Off; 294 | SWIFT_VERSION = 4.0; 295 | VERSIONING_SYSTEM = "apple-generic"; 296 | VERSION_INFO_PREFIX = ""; 297 | }; 298 | name = Release; 299 | }; 300 | C40299DF1D44AC0A007477E4 /* Debug */ = { 301 | isa = XCBuildConfiguration; 302 | buildSettings = { 303 | CLANG_ENABLE_MODULES = YES; 304 | CODE_SIGN_IDENTITY = ""; 305 | COMBINE_HIDPI_IMAGES = YES; 306 | DEFINES_MODULE = YES; 307 | DYLIB_COMPATIBILITY_VERSION = 1; 308 | DYLIB_CURRENT_VERSION = 1; 309 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 310 | FRAMEWORK_VERSION = A; 311 | INFOPLIST_FILE = CustomSegue/Info.plist; 312 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 313 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; 314 | MACOSX_DEPLOYMENT_TARGET = 10.10; 315 | PRODUCT_BUNDLE_IDENTIFIER = fr.phimage.CustomSegue; 316 | PRODUCT_NAME = "$(TARGET_NAME)"; 317 | SKIP_INSTALL = YES; 318 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 319 | SWIFT_VERSION = 5.0; 320 | }; 321 | name = Debug; 322 | }; 323 | C40299E01D44AC0A007477E4 /* Release */ = { 324 | isa = XCBuildConfiguration; 325 | buildSettings = { 326 | CLANG_ENABLE_MODULES = YES; 327 | CODE_SIGN_IDENTITY = ""; 328 | COMBINE_HIDPI_IMAGES = YES; 329 | DEFINES_MODULE = YES; 330 | DYLIB_COMPATIBILITY_VERSION = 1; 331 | DYLIB_CURRENT_VERSION = 1; 332 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 333 | FRAMEWORK_VERSION = A; 334 | INFOPLIST_FILE = CustomSegue/Info.plist; 335 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 336 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; 337 | MACOSX_DEPLOYMENT_TARGET = 10.10; 338 | PRODUCT_BUNDLE_IDENTIFIER = fr.phimage.CustomSegue; 339 | PRODUCT_NAME = "$(TARGET_NAME)"; 340 | SKIP_INSTALL = YES; 341 | SWIFT_VERSION = 5.0; 342 | }; 343 | name = Release; 344 | }; 345 | /* End XCBuildConfiguration section */ 346 | 347 | /* Begin XCConfigurationList section */ 348 | C40299D01D44AC0A007477E4 /* Build configuration list for PBXProject "CustomSegue" */ = { 349 | isa = XCConfigurationList; 350 | buildConfigurations = ( 351 | C40299DC1D44AC0A007477E4 /* Debug */, 352 | C40299DD1D44AC0A007477E4 /* Release */, 353 | ); 354 | defaultConfigurationIsVisible = 0; 355 | defaultConfigurationName = Release; 356 | }; 357 | C40299DE1D44AC0A007477E4 /* Build configuration list for PBXNativeTarget "CustomSegue" */ = { 358 | isa = XCConfigurationList; 359 | buildConfigurations = ( 360 | C40299DF1D44AC0A007477E4 /* Debug */, 361 | C40299E01D44AC0A007477E4 /* Release */, 362 | ); 363 | defaultConfigurationIsVisible = 0; 364 | defaultConfigurationName = Release; 365 | }; 366 | /* End XCConfigurationList section */ 367 | }; 368 | rootObject = C40299CD1D44AC0A007477E4 /* Project object */; 369 | } 370 | -------------------------------------------------------------------------------- /CustomSegue.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /CustomSegue.xcodeproj/project.xcworkspace/xcuserdata/wouter.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phimage/CustomSegue/daccb44e1e5f10098421aaee5ac129a3746aa1cd/CustomSegue.xcodeproj/project.xcworkspace/xcuserdata/wouter.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /CustomSegue.xcodeproj/xcshareddata/xcschemes/CustomSegue.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 34 | 35 | 45 | 46 | 52 | 53 | 54 | 55 | 56 | 57 | 63 | 64 | 70 | 71 | 72 | 73 | 75 | 76 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /CustomSegue/CustomSegue.h: -------------------------------------------------------------------------------- 1 | // 2 | // CustomSegue.h 3 | // CustomSegue 4 | // 5 | // Created by phimage on 24/07/16. 6 | // Copyright © 2016 phimage. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for CustomSegue. 12 | FOUNDATION_EXPORT double CustomSegueVersionNumber; 13 | 14 | //! Project version string for CustomSegue. 15 | FOUNDATION_EXPORT const unsigned char CustomSegueVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import 18 | 19 | 20 | -------------------------------------------------------------------------------- /CustomSegue/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | NSHumanReadableCopyright 24 | Copyright © 2016 phimage. All rights reserved. 25 | NSPrincipalClass 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /Example/Example.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 48CAFC9D1F971C4800BCF23F /* Storyboards.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48CAFC9C1F971C4800BCF23F /* Storyboards.swift */; }; 11 | 4DE0661F08D4BC1D30069EFC /* Pods_Example.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 71F6941F96991F59FB9D2FAB /* Pods_Example.framework */; }; 12 | C40299F41D44AF23007477E4 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C40299F31D44AF23007477E4 /* AppDelegate.swift */; }; 13 | C40299F61D44AF23007477E4 /* FromViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C40299F51D44AF23007477E4 /* FromViewController.swift */; }; 14 | C40299F81D44AF23007477E4 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C40299F71D44AF23007477E4 /* Assets.xcassets */; }; 15 | C40299FB1D44AF23007477E4 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = C40299F91D44AF23007477E4 /* Main.storyboard */; }; 16 | C4029A051D44B45D007477E4 /* DestinationViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4029A041D44B45D007477E4 /* DestinationViewController.swift */; }; 17 | C49FCF841D69871000C2674C /* CustomAnimator.swift in Sources */ = {isa = PBXBuildFile; fileRef = C49FCF831D69871000C2674C /* CustomAnimator.swift */; }; 18 | C49FCF8A1D6994E900C2674C /* SplitViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C49FCF891D6994E900C2674C /* SplitViewController.swift */; }; 19 | /* End PBXBuildFile section */ 20 | 21 | /* Begin PBXFileReference section */ 22 | 1ECFB563A014A59E4C159F2B /* Pods-Example.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Example.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Example/Pods-Example.debug.xcconfig"; sourceTree = ""; }; 23 | 48CAFC9C1F971C4800BCF23F /* Storyboards.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Storyboards.swift; sourceTree = ""; }; 24 | 71F6941F96991F59FB9D2FAB /* Pods_Example.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Example.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 25 | 9B1B3522AC1F8FB3170A61D1 /* Pods-Example.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Example.release.xcconfig"; path = "Pods/Target Support Files/Pods-Example/Pods-Example.release.xcconfig"; sourceTree = ""; }; 26 | C40299F01D44AF23007477E4 /* Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Example.app; sourceTree = BUILT_PRODUCTS_DIR; }; 27 | C40299F31D44AF23007477E4 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 28 | C40299F51D44AF23007477E4 /* FromViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FromViewController.swift; sourceTree = ""; }; 29 | C40299F71D44AF23007477E4 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 30 | C40299FA1D44AF23007477E4 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 31 | C40299FC1D44AF23007477E4 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 32 | C4029A041D44B45D007477E4 /* DestinationViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DestinationViewController.swift; sourceTree = ""; }; 33 | C49FCF831D69871000C2674C /* CustomAnimator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomAnimator.swift; sourceTree = ""; }; 34 | C49FCF891D6994E900C2674C /* SplitViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SplitViewController.swift; sourceTree = ""; }; 35 | /* End PBXFileReference section */ 36 | 37 | /* Begin PBXFrameworksBuildPhase section */ 38 | C40299ED1D44AF23007477E4 /* Frameworks */ = { 39 | isa = PBXFrameworksBuildPhase; 40 | buildActionMask = 2147483647; 41 | files = ( 42 | 4DE0661F08D4BC1D30069EFC /* Pods_Example.framework in Frameworks */, 43 | ); 44 | runOnlyForDeploymentPostprocessing = 0; 45 | }; 46 | /* End PBXFrameworksBuildPhase section */ 47 | 48 | /* Begin PBXGroup section */ 49 | B1573A813610991DA5D5AB49 /* Pods */ = { 50 | isa = PBXGroup; 51 | children = ( 52 | 1ECFB563A014A59E4C159F2B /* Pods-Example.debug.xcconfig */, 53 | 9B1B3522AC1F8FB3170A61D1 /* Pods-Example.release.xcconfig */, 54 | ); 55 | name = Pods; 56 | sourceTree = ""; 57 | }; 58 | C40299E71D44AF23007477E4 = { 59 | isa = PBXGroup; 60 | children = ( 61 | C40299F21D44AF23007477E4 /* Example */, 62 | C40299F11D44AF23007477E4 /* Products */, 63 | B1573A813610991DA5D5AB49 /* Pods */, 64 | C5CFB55A30F29B0EC9686E7E /* Frameworks */, 65 | ); 66 | sourceTree = ""; 67 | }; 68 | C40299F11D44AF23007477E4 /* Products */ = { 69 | isa = PBXGroup; 70 | children = ( 71 | C40299F01D44AF23007477E4 /* Example.app */, 72 | ); 73 | name = Products; 74 | sourceTree = ""; 75 | }; 76 | C40299F21D44AF23007477E4 /* Example */ = { 77 | isa = PBXGroup; 78 | children = ( 79 | C40299F31D44AF23007477E4 /* AppDelegate.swift */, 80 | C40299F51D44AF23007477E4 /* FromViewController.swift */, 81 | C4029A041D44B45D007477E4 /* DestinationViewController.swift */, 82 | C49FCF891D6994E900C2674C /* SplitViewController.swift */, 83 | C49FCF831D69871000C2674C /* CustomAnimator.swift */, 84 | 48CAFC9C1F971C4800BCF23F /* Storyboards.swift */, 85 | C40299F71D44AF23007477E4 /* Assets.xcassets */, 86 | C40299F91D44AF23007477E4 /* Main.storyboard */, 87 | C40299FC1D44AF23007477E4 /* Info.plist */, 88 | ); 89 | path = Example; 90 | sourceTree = ""; 91 | }; 92 | C5CFB55A30F29B0EC9686E7E /* Frameworks */ = { 93 | isa = PBXGroup; 94 | children = ( 95 | 71F6941F96991F59FB9D2FAB /* Pods_Example.framework */, 96 | ); 97 | name = Frameworks; 98 | sourceTree = ""; 99 | }; 100 | /* End PBXGroup section */ 101 | 102 | /* Begin PBXNativeTarget section */ 103 | C40299EF1D44AF23007477E4 /* Example */ = { 104 | isa = PBXNativeTarget; 105 | buildConfigurationList = C40299FF1D44AF23007477E4 /* Build configuration list for PBXNativeTarget "Example" */; 106 | buildPhases = ( 107 | C372FB2FDE291BD20DD6A63E /* [CP] Check Pods Manifest.lock */, 108 | C40299EC1D44AF23007477E4 /* Sources */, 109 | C40299ED1D44AF23007477E4 /* Frameworks */, 110 | C40299EE1D44AF23007477E4 /* Resources */, 111 | 16C39006B594E72F399AD840 /* [CP] Embed Pods Frameworks */, 112 | ); 113 | buildRules = ( 114 | ); 115 | dependencies = ( 116 | ); 117 | name = Example; 118 | productName = Example; 119 | productReference = C40299F01D44AF23007477E4 /* Example.app */; 120 | productType = "com.apple.product-type.application"; 121 | }; 122 | /* End PBXNativeTarget section */ 123 | 124 | /* Begin PBXProject section */ 125 | C40299E81D44AF23007477E4 /* Project object */ = { 126 | isa = PBXProject; 127 | attributes = { 128 | LastSwiftUpdateCheck = 0730; 129 | LastUpgradeCheck = 1020; 130 | ORGANIZATIONNAME = phimage; 131 | TargetAttributes = { 132 | C40299EF1D44AF23007477E4 = { 133 | CreatedOnToolsVersion = 7.3.1; 134 | LastSwiftMigration = 1020; 135 | }; 136 | }; 137 | }; 138 | buildConfigurationList = C40299EB1D44AF23007477E4 /* Build configuration list for PBXProject "Example" */; 139 | compatibilityVersion = "Xcode 3.2"; 140 | developmentRegion = en; 141 | hasScannedForEncodings = 0; 142 | knownRegions = ( 143 | en, 144 | Base, 145 | ); 146 | mainGroup = C40299E71D44AF23007477E4; 147 | productRefGroup = C40299F11D44AF23007477E4 /* Products */; 148 | projectDirPath = ""; 149 | projectRoot = ""; 150 | targets = ( 151 | C40299EF1D44AF23007477E4 /* Example */, 152 | ); 153 | }; 154 | /* End PBXProject section */ 155 | 156 | /* Begin PBXResourcesBuildPhase section */ 157 | C40299EE1D44AF23007477E4 /* Resources */ = { 158 | isa = PBXResourcesBuildPhase; 159 | buildActionMask = 2147483647; 160 | files = ( 161 | C40299F81D44AF23007477E4 /* Assets.xcassets in Resources */, 162 | C40299FB1D44AF23007477E4 /* Main.storyboard in Resources */, 163 | ); 164 | runOnlyForDeploymentPostprocessing = 0; 165 | }; 166 | /* End PBXResourcesBuildPhase section */ 167 | 168 | /* Begin PBXShellScriptBuildPhase section */ 169 | 16C39006B594E72F399AD840 /* [CP] Embed Pods Frameworks */ = { 170 | isa = PBXShellScriptBuildPhase; 171 | buildActionMask = 2147483647; 172 | files = ( 173 | ); 174 | inputPaths = ( 175 | "${PODS_ROOT}/Target Support Files/Pods-Example/Pods-Example-frameworks.sh", 176 | "${BUILT_PRODUCTS_DIR}/CustomSegue/CustomSegue.framework", 177 | ); 178 | name = "[CP] Embed Pods Frameworks"; 179 | outputPaths = ( 180 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/CustomSegue.framework", 181 | ); 182 | runOnlyForDeploymentPostprocessing = 0; 183 | shellPath = /bin/sh; 184 | shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Example/Pods-Example-frameworks.sh\"\n"; 185 | showEnvVarsInLog = 0; 186 | }; 187 | C372FB2FDE291BD20DD6A63E /* [CP] Check Pods Manifest.lock */ = { 188 | isa = PBXShellScriptBuildPhase; 189 | buildActionMask = 2147483647; 190 | files = ( 191 | ); 192 | inputPaths = ( 193 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock", 194 | "${PODS_ROOT}/Manifest.lock", 195 | ); 196 | name = "[CP] Check Pods Manifest.lock"; 197 | outputPaths = ( 198 | "$(DERIVED_FILE_DIR)/Pods-Example-checkManifestLockResult.txt", 199 | ); 200 | runOnlyForDeploymentPostprocessing = 0; 201 | shellPath = /bin/sh; 202 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; 203 | showEnvVarsInLog = 0; 204 | }; 205 | /* End PBXShellScriptBuildPhase section */ 206 | 207 | /* Begin PBXSourcesBuildPhase section */ 208 | C40299EC1D44AF23007477E4 /* Sources */ = { 209 | isa = PBXSourcesBuildPhase; 210 | buildActionMask = 2147483647; 211 | files = ( 212 | 48CAFC9D1F971C4800BCF23F /* Storyboards.swift in Sources */, 213 | C49FCF8A1D6994E900C2674C /* SplitViewController.swift in Sources */, 214 | C40299F61D44AF23007477E4 /* FromViewController.swift in Sources */, 215 | C49FCF841D69871000C2674C /* CustomAnimator.swift in Sources */, 216 | C40299F41D44AF23007477E4 /* AppDelegate.swift in Sources */, 217 | C4029A051D44B45D007477E4 /* DestinationViewController.swift in Sources */, 218 | ); 219 | runOnlyForDeploymentPostprocessing = 0; 220 | }; 221 | /* End PBXSourcesBuildPhase section */ 222 | 223 | /* Begin PBXVariantGroup section */ 224 | C40299F91D44AF23007477E4 /* Main.storyboard */ = { 225 | isa = PBXVariantGroup; 226 | children = ( 227 | C40299FA1D44AF23007477E4 /* Base */, 228 | ); 229 | name = Main.storyboard; 230 | sourceTree = ""; 231 | }; 232 | /* End PBXVariantGroup section */ 233 | 234 | /* Begin XCBuildConfiguration section */ 235 | C40299FD1D44AF23007477E4 /* Debug */ = { 236 | isa = XCBuildConfiguration; 237 | buildSettings = { 238 | ALWAYS_SEARCH_USER_PATHS = NO; 239 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 240 | CLANG_ANALYZER_NONNULL = YES; 241 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 242 | CLANG_CXX_LIBRARY = "libc++"; 243 | CLANG_ENABLE_MODULES = YES; 244 | CLANG_ENABLE_OBJC_ARC = YES; 245 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 246 | CLANG_WARN_BOOL_CONVERSION = YES; 247 | CLANG_WARN_COMMA = YES; 248 | CLANG_WARN_CONSTANT_CONVERSION = YES; 249 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 250 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 251 | CLANG_WARN_EMPTY_BODY = YES; 252 | CLANG_WARN_ENUM_CONVERSION = YES; 253 | CLANG_WARN_INFINITE_RECURSION = YES; 254 | CLANG_WARN_INT_CONVERSION = YES; 255 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 256 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 257 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 258 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 259 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 260 | CLANG_WARN_STRICT_PROTOTYPES = YES; 261 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 262 | CLANG_WARN_UNREACHABLE_CODE = YES; 263 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 264 | CODE_SIGN_IDENTITY = "-"; 265 | COPY_PHASE_STRIP = NO; 266 | DEBUG_INFORMATION_FORMAT = dwarf; 267 | ENABLE_STRICT_OBJC_MSGSEND = YES; 268 | ENABLE_TESTABILITY = YES; 269 | GCC_C_LANGUAGE_STANDARD = gnu99; 270 | GCC_DYNAMIC_NO_PIC = NO; 271 | GCC_NO_COMMON_BLOCKS = YES; 272 | GCC_OPTIMIZATION_LEVEL = 0; 273 | GCC_PREPROCESSOR_DEFINITIONS = ( 274 | "DEBUG=1", 275 | "$(inherited)", 276 | ); 277 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 278 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 279 | GCC_WARN_UNDECLARED_SELECTOR = YES; 280 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 281 | GCC_WARN_UNUSED_FUNCTION = YES; 282 | GCC_WARN_UNUSED_VARIABLE = YES; 283 | MACOSX_DEPLOYMENT_TARGET = 10.11; 284 | MTL_ENABLE_DEBUG_INFO = YES; 285 | ONLY_ACTIVE_ARCH = YES; 286 | SDKROOT = macosx; 287 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 288 | }; 289 | name = Debug; 290 | }; 291 | C40299FE1D44AF23007477E4 /* Release */ = { 292 | isa = XCBuildConfiguration; 293 | buildSettings = { 294 | ALWAYS_SEARCH_USER_PATHS = NO; 295 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 296 | CLANG_ANALYZER_NONNULL = YES; 297 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 298 | CLANG_CXX_LIBRARY = "libc++"; 299 | CLANG_ENABLE_MODULES = YES; 300 | CLANG_ENABLE_OBJC_ARC = YES; 301 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 302 | CLANG_WARN_BOOL_CONVERSION = YES; 303 | CLANG_WARN_COMMA = YES; 304 | CLANG_WARN_CONSTANT_CONVERSION = YES; 305 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 306 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 307 | CLANG_WARN_EMPTY_BODY = YES; 308 | CLANG_WARN_ENUM_CONVERSION = YES; 309 | CLANG_WARN_INFINITE_RECURSION = YES; 310 | CLANG_WARN_INT_CONVERSION = YES; 311 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 312 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 313 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 314 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 315 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 316 | CLANG_WARN_STRICT_PROTOTYPES = YES; 317 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 318 | CLANG_WARN_UNREACHABLE_CODE = YES; 319 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 320 | CODE_SIGN_IDENTITY = "-"; 321 | COPY_PHASE_STRIP = NO; 322 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 323 | ENABLE_NS_ASSERTIONS = NO; 324 | ENABLE_STRICT_OBJC_MSGSEND = YES; 325 | GCC_C_LANGUAGE_STANDARD = gnu99; 326 | GCC_NO_COMMON_BLOCKS = YES; 327 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 328 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 329 | GCC_WARN_UNDECLARED_SELECTOR = YES; 330 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 331 | GCC_WARN_UNUSED_FUNCTION = YES; 332 | GCC_WARN_UNUSED_VARIABLE = YES; 333 | MACOSX_DEPLOYMENT_TARGET = 10.11; 334 | MTL_ENABLE_DEBUG_INFO = NO; 335 | SDKROOT = macosx; 336 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 337 | }; 338 | name = Release; 339 | }; 340 | C4029A001D44AF23007477E4 /* Debug */ = { 341 | isa = XCBuildConfiguration; 342 | baseConfigurationReference = 1ECFB563A014A59E4C159F2B /* Pods-Example.debug.xcconfig */; 343 | buildSettings = { 344 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 345 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 346 | COMBINE_HIDPI_IMAGES = YES; 347 | INFOPLIST_FILE = Example/Info.plist; 348 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; 349 | PRODUCT_BUNDLE_IDENTIFIER = fr.phimage.Example; 350 | PRODUCT_NAME = "$(TARGET_NAME)"; 351 | SWIFT_VERSION = 5.0; 352 | }; 353 | name = Debug; 354 | }; 355 | C4029A011D44AF23007477E4 /* Release */ = { 356 | isa = XCBuildConfiguration; 357 | baseConfigurationReference = 9B1B3522AC1F8FB3170A61D1 /* Pods-Example.release.xcconfig */; 358 | buildSettings = { 359 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 360 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 361 | COMBINE_HIDPI_IMAGES = YES; 362 | INFOPLIST_FILE = Example/Info.plist; 363 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; 364 | PRODUCT_BUNDLE_IDENTIFIER = fr.phimage.Example; 365 | PRODUCT_NAME = "$(TARGET_NAME)"; 366 | SWIFT_VERSION = 5.0; 367 | }; 368 | name = Release; 369 | }; 370 | /* End XCBuildConfiguration section */ 371 | 372 | /* Begin XCConfigurationList section */ 373 | C40299EB1D44AF23007477E4 /* Build configuration list for PBXProject "Example" */ = { 374 | isa = XCConfigurationList; 375 | buildConfigurations = ( 376 | C40299FD1D44AF23007477E4 /* Debug */, 377 | C40299FE1D44AF23007477E4 /* Release */, 378 | ); 379 | defaultConfigurationIsVisible = 0; 380 | defaultConfigurationName = Release; 381 | }; 382 | C40299FF1D44AF23007477E4 /* Build configuration list for PBXNativeTarget "Example" */ = { 383 | isa = XCConfigurationList; 384 | buildConfigurations = ( 385 | C4029A001D44AF23007477E4 /* Debug */, 386 | C4029A011D44AF23007477E4 /* Release */, 387 | ); 388 | defaultConfigurationIsVisible = 0; 389 | defaultConfigurationName = Release; 390 | }; 391 | /* End XCConfigurationList section */ 392 | }; 393 | rootObject = C40299E81D44AF23007477E4 /* Project object */; 394 | } 395 | -------------------------------------------------------------------------------- /Example/Example.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Example/Example.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Example/Example/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // Example 4 | // 5 | // Created by phimage on 24/07/16. 6 | // Copyright © 2016 phimage. All rights reserved. 7 | // 8 | 9 | import Cocoa 10 | 11 | @NSApplicationMain 12 | class AppDelegate: NSObject, NSApplicationDelegate { 13 | 14 | 15 | 16 | func applicationDidFinishLaunching(_ aNotification: Notification) { 17 | // Insert code here to initialize your application 18 | } 19 | 20 | func applicationWillTerminate(_ aNotification: Notification) { 21 | // Insert code here to tear down your application 22 | } 23 | 24 | 25 | } 26 | -------------------------------------------------------------------------------- /Example/Example/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "size" : "16x16", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "mac", 10 | "size" : "16x16", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "mac", 15 | "size" : "32x32", 16 | "scale" : "1x" 17 | }, 18 | { 19 | "idiom" : "mac", 20 | "size" : "32x32", 21 | "scale" : "2x" 22 | }, 23 | { 24 | "idiom" : "mac", 25 | "size" : "128x128", 26 | "scale" : "1x" 27 | }, 28 | { 29 | "idiom" : "mac", 30 | "size" : "128x128", 31 | "scale" : "2x" 32 | }, 33 | { 34 | "idiom" : "mac", 35 | "size" : "256x256", 36 | "scale" : "1x" 37 | }, 38 | { 39 | "idiom" : "mac", 40 | "size" : "256x256", 41 | "scale" : "2x" 42 | }, 43 | { 44 | "idiom" : "mac", 45 | "size" : "512x512", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "mac", 50 | "size" : "512x512", 51 | "scale" : "2x" 52 | } 53 | ], 54 | "info" : { 55 | "version" : 1, 56 | "author" : "xcode" 57 | } 58 | } -------------------------------------------------------------------------------- /Example/Example/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | 449 | 450 | 451 | 452 | 453 | 454 | 455 | 456 | 457 | 458 | 459 | 460 | 461 | 462 | 463 | 464 | 465 | 466 | 467 | 468 | 469 | 470 | 471 | 472 | 473 | 474 | 475 | 476 | 477 | 478 | 479 | 480 | 481 | 482 | 483 | 484 | 485 | 486 | 487 | 488 | 489 | 490 | 491 | 492 | 493 | 494 | 495 | 496 | 497 | 498 | 499 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 509 | 510 | Default 511 | 512 | 513 | 514 | 515 | 516 | 517 | Left to Right 518 | 519 | 520 | 521 | 522 | 523 | 524 | Right to Left 525 | 526 | 527 | 528 | 529 | 530 | 531 | 532 | 533 | 534 | 535 | Default 536 | 537 | 538 | 539 | 540 | 541 | 542 | Left to Right 543 | 544 | 545 | 546 | 547 | 548 | 549 | Right to Left 550 | 551 | 552 | 553 | 554 | 555 | 556 | 557 | 558 | 559 | 560 | 561 | 562 | 563 | 564 | 565 | 566 | 567 | 568 | 569 | 570 | 571 | 572 | 573 | 574 | 575 | 576 | 577 | 578 | 579 | 580 | 581 | 582 | 583 | 584 | 585 | 586 | 587 | 588 | 589 | 590 | 591 | 592 | 593 | 594 | 595 | 596 | 597 | 598 | 599 | 600 | 601 | 602 | 603 | 604 | 605 | 606 | 607 | 608 | 609 | 610 | 611 | 612 | 613 | 614 | 615 | 616 | 617 | 618 | 619 | 620 | 621 | 622 | 623 | 624 | 625 | 626 | 627 | 628 | 629 | 630 | 631 | 632 | 633 | 634 | 635 | 636 | 637 | 638 | 639 | 640 | 641 | 642 | 643 | 644 | 645 | 646 | 647 | 648 | 649 | 650 | 651 | 652 | 653 | 654 | 655 | 656 | 657 | 658 | 659 | 660 | 661 | 662 | 663 | 664 | 665 | 666 | 667 | 668 | 669 | 670 | 671 | 672 | 673 | 674 | 675 | 676 | 686 | 687 | 688 | 689 | 690 | 691 | 692 | 693 | 694 | 695 | 696 | 697 | 698 | 699 | 700 | 701 | 702 | 703 | 704 | 705 | 706 | 707 | 708 | 709 | 710 | 711 | 712 | 713 | 714 | 715 | 716 | 717 | 718 | 719 | 729 | 730 | 731 | 732 | 733 | 734 | 735 | 736 | 737 | 738 | 739 | 740 | 741 | 742 | 743 | 744 | 745 | 746 | 747 | 748 | 749 | 750 | 760 | 770 | 780 | 790 | 800 | 810 | 820 | 830 | 840 | 850 | 851 | 852 | 853 | 854 | 855 | 856 | 857 | 858 | 859 | 860 | 861 | 862 | 863 | 864 | 865 | 866 | 867 | 868 | 869 | 870 | 871 | 872 | 873 | 874 | 875 | 876 | 877 | 878 | 879 | 880 | 881 | 882 | 883 | 884 | 885 | 886 | 887 | 888 | 889 | 890 | 891 | 892 | 893 | 894 | 895 | 896 | 897 | 898 | 899 | 900 | 901 | 902 | 903 | 904 | 905 | 906 | 907 | 908 | 909 | 910 | 911 | 912 | 913 | 914 | 915 | 916 | 917 | 918 | 919 | 920 | 921 | 922 | 923 | 924 | 925 | 926 | 927 | 928 | 929 | 930 | 931 | 932 | 933 | 934 | 935 | 945 | 946 | 947 | 948 | 949 | 950 | 951 | 952 | 953 | 954 | 955 | 956 | 957 | 958 | 959 | 960 | 961 | 962 | 963 | 964 | 965 | 966 | 967 | 968 | 969 | 970 | 971 | 972 | 973 | 974 | 975 | 976 | 977 | 978 | 979 | 980 | 981 | 982 | 983 | 984 | 985 | 986 | 987 | 988 | 989 | 990 | 991 | 992 | 993 | 994 | 995 | 996 | 997 | 998 | 999 | 1000 | 1001 | 1002 | 1006 | 1010 | 1011 | 1012 | 1013 | 1014 | 1015 | 1016 | 1017 | 1018 | 1019 | 1020 | 1021 | 1022 | 1023 | 1024 | 1025 | 1026 | 1027 | 1028 | 1029 | 1030 | 1031 | 1032 | 1033 | 1034 | 1035 | 1036 | 1037 | 1038 | 1039 | 1040 | 1041 | 1042 | 1043 | 1044 | 1045 | 1046 | 1047 | 1048 | 1049 | 1050 | 1051 | 1052 | 1053 | 1054 | 1055 | 1056 | 1057 | 1058 | 1059 | 1060 | 1061 | 1062 | 1063 | 1064 | 1065 | 1066 | 1067 | 1068 | 1069 | 1070 | 1071 | 1072 | 1073 | 1074 | 1075 | 1076 | 1077 | 1078 | 1079 | 1080 | 1090 | 1097 | 1098 | 1099 | 1100 | 1101 | 1102 | 1103 | 1104 | 1105 | 1106 | 1107 | 1108 | 1109 | 1110 | 1111 | 1112 | 1113 | 1114 | 1115 | 1116 | 1117 | 1118 | 1119 | 1120 | 1121 | 1122 | 1123 | 1124 | -------------------------------------------------------------------------------- /Example/Example/CustomAnimator.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CustomAnimator.swift 3 | // Example 4 | 5 | import Cocoa 6 | 7 | class CustomAnimator: NSObject, NSViewControllerPresentationAnimator { 8 | 9 | fileprivate let duration: TimeInterval 10 | fileprivate let rect: NSRect 11 | 12 | init(duration: TimeInterval, rect: NSRect) { 13 | self.duration = duration 14 | self.rect = rect 15 | super.init() 16 | } 17 | 18 | @objc func animatePresentation(of viewController: NSViewController, from fromViewController: NSViewController) { 19 | let parentVC = fromViewController 20 | let childVC = viewController 21 | childVC.view.wantsLayer = true 22 | childVC.view.layerContentsRedrawPolicy = .onSetNeedsDisplay 23 | childVC.view.translatesAutoresizingMaskIntoConstraints = true 24 | childVC.view.alphaValue = 0 25 | let anotherRect = NSMakeRect(rect.minX, parentVC.view.frame.height - rect.minY, rect.width, rect.height) 26 | childVC.view.frame = anotherRect 27 | parentVC.view.addSubview(childVC.view) 28 | NSAnimationContext.runAnimationGroup({ (context) -> Void in 29 | context.duration = self.duration 30 | childVC.view.animator().alphaValue = 1 31 | childVC.view.animator().frame = parentVC.view.frame 32 | }, completionHandler: { 33 | childVC.view.translatesAutoresizingMaskIntoConstraints = false 34 | let views = ["view" : childVC.view] 35 | let horizontalConstraints = NSLayoutConstraint.constraints(withVisualFormat: "H:|[view]|", options: [], metrics: nil, views: views) 36 | let verticalConstraints = NSLayoutConstraint.constraints(withVisualFormat: "V:|[view]|", options: [], metrics: nil, views: views) 37 | parentVC.view.addConstraints(horizontalConstraints) 38 | parentVC.view.addConstraints(verticalConstraints) 39 | }) 40 | } 41 | 42 | @objc func animateDismissal(of viewController: NSViewController, from fromViewController: NSViewController) { 43 | let childVC = viewController 44 | childVC.view.wantsLayer = true 45 | childVC.view.layerContentsRedrawPolicy = .onSetNeedsDisplay 46 | NSAnimationContext.runAnimationGroup({ (context) -> Void in 47 | context.duration = self.duration 48 | childVC.view.animator().alphaValue = 0 49 | }, completionHandler: { 50 | childVC.view.removeFromSuperview() 51 | }) 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /Example/Example/DestinationViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DestinationViewController.swift 3 | // Example 4 | // 5 | // Created by phimage on 24/07/16. 6 | // Copyright © 2016 phimage. All rights reserved. 7 | // 8 | 9 | import Cocoa 10 | import CustomSegue 11 | 12 | class DestinationViewController: NSViewController { 13 | 14 | override func viewDidLoad() { 15 | super.viewDidLoad() 16 | 17 | // Dismiss after defined time interval 18 | Timer.scheduledTimer(timeInterval: 2.0, target: self, selector: #selector(DestinationViewController.dismissNotAmbigous(_:)), userInfo: nil, repeats: false) 19 | } 20 | 21 | 22 | @objc func dismissNotAmbigous(_ sender: AnyObject?) { 23 | self.dismiss(sender) 24 | } 25 | 26 | 27 | var segue: ReplaceWindowContentSegue? 28 | @IBAction func dismissSegue(_ sender: AnyObject?) { 29 | segue?.unperform() 30 | } 31 | } 32 | 33 | // We could prevent to pass event to source controller views by doing nothing here 34 | /* 35 | class DestinationView: NSView { 36 | override func mouseDown(theEvent: NSEvent) { 37 | } 38 | 39 | override func acceptsFirstMouse(theEvent: NSEvent?) -> Bool { 40 | return true 41 | } 42 | } 43 | */ 44 | -------------------------------------------------------------------------------- /Example/Example/FromViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FromViewControllerswift 3 | // Example 4 | // 5 | // Created by phimage on 24/07/16. 6 | // Copyright © 2016 phimage. All rights reserved. 7 | // 8 | 9 | import Cocoa 10 | import CustomSegue 11 | 12 | extension NSStoryboardSegue { 13 | var source: NSViewController? { 14 | return self.sourceController as? NSViewController 15 | } 16 | var destination: NSViewController? { 17 | return self.destinationController as? NSViewController 18 | } 19 | } 20 | 21 | class FromViewController: NSViewController { 22 | 23 | override func prepare(for segue: NSStoryboardSegue, sender: Any?) { 24 | if segue == FromViewController.Segue.configured { 25 | if let segue = segue as? PresentWithAnimatorSegue, let animator = segue.animator as? TransitionAnimator { 26 | animator.duration = 1 27 | animator.transition = [.slideDown/*, .crossfade*/] 28 | animator.backgroundColor = NSColor(calibratedRed: 1, green: 0, blue: 0, alpha: 0.5) 29 | animator.keepOriginalSize = true 30 | animator.removeFromView = false 31 | 32 | } 33 | } 34 | else if segue.identifier == "chidwindow" { 35 | if let segue = segue as? ChildWindowSegue, let animator = segue.animator as? ChildWindowAnimator { 36 | animator.windowCustomizer = { window in 37 | window.styleMask = .borderless 38 | 39 | if let frame = segue.source?.view.window?.frame { 40 | // Open window near current one 41 | let origin = NSPoint(x: frame.origin.x + frame.width, y: frame.origin.y) 42 | window.setFrameOrigin(origin) 43 | } 44 | } 45 | } 46 | } 47 | else if segue.identifier == "splitview" { 48 | if let segue = segue as? ChildWindowSegue, let animator = segue.animator as? ChildWindowAnimator { 49 | animator.windowCustomizer = { window in 50 | 51 | if let frame = segue.source?.view.window?.frame { 52 | 53 | var newFrame = NSRect() 54 | newFrame.origin = NSPoint(x: frame.origin.x + frame.width, y: frame.origin.y) 55 | newFrame.size = NSSize(width: frame.width * 2, height: frame.height) 56 | window.setFrame(newFrame, display: false) 57 | 58 | if let splitC = segue.destinationController as? NSSplitViewController { 59 | splitC.splitView.setPosition(frame.width / 2, ofDividerAt: 0) 60 | } 61 | } 62 | } 63 | 64 | 65 | } 66 | } 67 | else if segue.identifier == "customanimator" { 68 | if let segue = segue as? PresentWithAnimatorSegue { 69 | if let frame = segue.source?.view.window?.frame { 70 | segue.animator = CustomAnimator(duration: 1.0, rect: frame) 71 | } 72 | 73 | } 74 | } else if segue.identifier == "replace" { 75 | if let segue = segue as? ReplaceWindowContentSegue, let destinationController = segue.destinationController as? DestinationViewController { 76 | destinationController.segue = segue 77 | } 78 | } 79 | } 80 | 81 | } 82 | 83 | 84 | -------------------------------------------------------------------------------- /Example/Example/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1 25 | LSMinimumSystemVersion 26 | $(MACOSX_DEPLOYMENT_TARGET) 27 | NSHumanReadableCopyright 28 | Copyright © 2016 phimage. All rights reserved. 29 | NSMainStoryboardFile 30 | Main 31 | NSPrincipalClass 32 | NSApplication 33 | 34 | 35 | -------------------------------------------------------------------------------- /Example/Example/SplitViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SplitViewController.swift 3 | // Example 4 | // 5 | // Created by phimage on 21/08/16. 6 | // Copyright © 2016 phimage. All rights reserved. 7 | // 8 | 9 | import Cocoa 10 | import CustomSegue 11 | 12 | class SplitViewController: NSViewController { 13 | 14 | @IBOutlet weak var checkbox: NSButton! 15 | override func viewDidLoad() { 16 | super.viewDidLoad() 17 | 18 | // Do any additional setup after loading the view. 19 | } 20 | 21 | override func prepare(for segue: NSStoryboardSegue, sender: Any?) { 22 | if let segue = segue as? SplitViewSegue { 23 | segue.replace = checkbox.state == .on 24 | if let d = segue.destinationController as? DestinationSplitViewController { 25 | d.segue = segue 26 | } 27 | } 28 | } 29 | } 30 | 31 | 32 | 33 | class DestinationSplitViewController: NSViewController { 34 | 35 | @IBOutlet weak var tableView: NSTableView! 36 | 37 | var segue: SplitViewSegue? 38 | 39 | @IBAction func dismissSegue(_ sender: AnyObject?) { 40 | segue?.unperform() 41 | } 42 | 43 | 44 | override func prepare(for segue: NSStoryboardSegue, sender: Any?) { 45 | if let segue = segue as? TablePopoverSegue , segue.identifier == "rowdetail" { 46 | segue.popoverBehavior = .transient 47 | segue.tableView = tableView 48 | 49 | // TIPS get selected object and pass info to the destination controller 50 | let selectedRow = tableView.selectedRow 51 | if (selectedRow >= 0) { 52 | 53 | 54 | } 55 | } 56 | } 57 | 58 | } 59 | 60 | 61 | extension DestinationSplitViewController: NSTableViewDataSource, NSTableViewDelegate { 62 | 63 | func numberOfRows(in tableView: NSTableView) -> Int { 64 | return 2 65 | } 66 | 67 | func tableView(_ tableView: NSTableView, objectValueFor tableColumn: NSTableColumn?, row: Int) -> Any? { 68 | return "\(row)" 69 | } 70 | 71 | func tableViewSelectionDidChange(_ notification: Notification) { 72 | self.performSegue(withIdentifier: "rowdetail", sender: notification.object) 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /Example/Example/Storyboards.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Autogenerated by Natalie - Storyboard Generator 3 | // by Marcin Krzyzanowski http://krzyzanowskim.com 4 | // 5 | import Cocoa 6 | 7 | // MARK: - Storyboards 8 | 9 | extension NSStoryboard { 10 | func instantiateViewController(ofType type: T.Type) -> T? where T: IdentifiableProtocol { 11 | let instance = type.init() 12 | if let identifier = instance.storyboardIdentifier { 13 | return self.instantiateController(withIdentifier: identifier) as? T 14 | } 15 | return nil 16 | } 17 | 18 | func instantiateViewController(ofType type: T.Type) -> T? where T: IdentifiableProtocol { 19 | let instance = type.init() 20 | if let identifier = instance.storyboardIdentifier { 21 | return self.instantiateController(withIdentifier: identifier) as? T 22 | } 23 | return nil 24 | } 25 | 26 | } 27 | 28 | protocol Storyboard { 29 | static var storyboard: NSStoryboard { get } 30 | static var identifier: NSStoryboard.Name { get } 31 | } 32 | 33 | struct Storyboards { 34 | 35 | struct Main: Storyboard { 36 | 37 | static let identifier = "Main" 38 | 39 | static var storyboard: NSStoryboard { 40 | return NSStoryboard(name: self.identifier, bundle: nil) 41 | } 42 | 43 | static func instantiateInitialController() -> NSWindowController { 44 | return self.storyboard.instantiateInitialController() as! NSWindowController 45 | } 46 | 47 | static func instantiateController(withIdentifier identifier: NSStoryboard.SceneIdentifier) -> NSWindowController { 48 | return self.storyboard.instantiateController(withIdentifier: identifier) as! NSWindowController 49 | } 50 | 51 | static func instantiateViewController(ofType type: T.Type) -> T? where T: IdentifiableProtocol { 52 | return self.storyboard.instantiateViewController(ofType: type) 53 | } 54 | 55 | static func instantiateController(withIdentifier identifier: NSStoryboard.SceneIdentifier) -> NSViewController { 56 | return self.storyboard.instantiateController(withIdentifier: identifier) as! NSViewController 57 | } 58 | 59 | static func instantiateViewController(ofType type: T.Type) -> T? where T: IdentifiableProtocol { 60 | return self.storyboard.instantiateViewController(ofType: type) 61 | } 62 | } 63 | } 64 | 65 | // MARK: - ReusableKind 66 | enum ReusableKind: String, CustomStringConvertible { 67 | case tableViewCell = "tableViewCell" 68 | case collectionViewCell = "collectionViewCell" 69 | 70 | var description: String { return self.rawValue } 71 | } 72 | 73 | // MARK: - SegueKind 74 | enum SegueKind: String, CustomStringConvertible { 75 | case relationship = "relationship" 76 | case show = "show" 77 | case presentation = "presentation" 78 | case embed = "embed" 79 | case unwind = "unwind" 80 | case push = "push" 81 | case modal = "modal" 82 | case popover = "popover" 83 | case replace = "replace" 84 | case custom = "custom" 85 | 86 | var description: String { return self.rawValue } 87 | } 88 | 89 | // MARK: - IdentifiableProtocol 90 | 91 | public protocol IdentifiableProtocol: Equatable { 92 | var storyboardIdentifier: NSStoryboard.SceneIdentifier? { get } 93 | } 94 | 95 | // MARK: - SegueProtocol 96 | 97 | public protocol SegueProtocol { 98 | var identifier: NSStoryboardSegue.Identifier? { get } 99 | } 100 | 101 | public func ==(lhs: T, rhs: U) -> Bool { 102 | return lhs.identifier == rhs.identifier 103 | } 104 | 105 | public func ~=(lhs: T, rhs: U) -> Bool { 106 | return lhs.identifier == rhs.identifier 107 | } 108 | 109 | public func ==(lhs: T, rhs: NSStoryboardSegue.Identifier) -> Bool { 110 | return lhs.identifier == rhs 111 | } 112 | 113 | public func ~=(lhs: T, rhs: NSStoryboardSegue.Identifier) -> Bool { 114 | return lhs.identifier == rhs 115 | } 116 | 117 | public func ==(lhs: NSStoryboardSegue.Identifier, rhs: T) -> Bool { 118 | return lhs == rhs.identifier 119 | } 120 | 121 | public func ~=(lhs: NSStoryboardSegue.Identifier, rhs: T) -> Bool { 122 | return lhs == rhs.identifier 123 | } 124 | 125 | /*extension NSStoryboardSegue.Identifier: ExpressibleByStringLiteral { 126 | public typealias StringLiteralType = String 127 | public init(stringLiteral value: StringLiteralType) { 128 | self.init(rawValue: value) 129 | } 130 | } 131 | 132 | public func ==(lhs: T, rhs: String) -> Bool { 133 | return lhs.identifier? == rhs 134 | } 135 | 136 | public func ~=(lhs: T, rhs: String) -> Bool { 137 | return lhs.identifier? == rhs 138 | } 139 | 140 | public func ==(lhs: String, rhs: T) -> Bool { 141 | return lhs == rhs.identifier? 142 | } 143 | 144 | public func ~=(lhs: String, rhs: T) -> Bool { 145 | return lhs == rhs.identifier? 146 | }*/ 147 | 148 | // MARK: - ReusableViewProtocol 149 | public protocol ReusableViewProtocol: IdentifiableProtocol { 150 | var viewType: NSView.Type? { get } 151 | } 152 | 153 | public func ==(lhs: T, rhs: U) -> Bool { 154 | return lhs.storyboardIdentifier == rhs.storyboardIdentifier 155 | } 156 | 157 | // MARK: - Protocol Implementation 158 | extension NSStoryboardSegue: SegueProtocol { 159 | } 160 | 161 | // MARK: - NSViewController extension 162 | extension NSViewController { 163 | func perform(segue: T, sender: Any?) { 164 | if let identifier = segue.identifier { 165 | performSegue(withIdentifier: identifier, sender: sender) 166 | } 167 | } 168 | 169 | func perform(segue: T) { 170 | perform(segue: segue, sender: nil) 171 | } 172 | } 173 | // MARK: - NSWindowController extension 174 | extension NSWindowController { 175 | func perform(segue: T, sender: Any?) { 176 | if let identifier = segue.identifier { 177 | performSegue(withIdentifier: identifier, sender: sender) 178 | } 179 | } 180 | 181 | func perform(segue: T) { 182 | perform(segue: segue, sender: nil) 183 | } 184 | } 185 | 186 | // MARK: - DestinationViewController 187 | 188 | // MARK: - DestinationViewController 189 | 190 | // MARK: - FromViewController 191 | extension NSStoryboardSegue { 192 | func selection() -> FromViewController.Segue? { 193 | if let identifier = self.identifier { 194 | return FromViewController.Segue(rawValue: identifier) 195 | } 196 | return nil 197 | } 198 | } 199 | extension FromViewController { 200 | 201 | enum Segue: NSStoryboardSegue.Identifier, CustomStringConvertible, SegueProtocol { 202 | case configured = "configured" 203 | case chidwindow = "chidwindow" 204 | case splitview = "splitview" 205 | case customanimator = "customanimator" 206 | case replace = "replace" 207 | 208 | var kind: SegueKind? { 209 | switch self { 210 | case .configured: 211 | return SegueKind(rawValue: "custom") 212 | case .chidwindow: 213 | return SegueKind(rawValue: "custom") 214 | case .splitview: 215 | return SegueKind(rawValue: "custom") 216 | case .customanimator: 217 | return SegueKind(rawValue: "custom") 218 | case .replace: 219 | return SegueKind(rawValue: "custom") 220 | } 221 | } 222 | 223 | var destination: AnyObject.Type? { 224 | switch self { 225 | case .configured: 226 | return DestinationViewController.self 227 | case .chidwindow: 228 | return DestinationViewController.self 229 | case .splitview: 230 | return NSSplitViewController.self 231 | case .customanimator: 232 | return DestinationViewController.self 233 | case .replace: 234 | return DestinationViewController.self 235 | } 236 | } 237 | 238 | var identifier: NSStoryboardSegue.Identifier? { return self.rawValue } 239 | var description: String { return "\(self.rawValue)" } 240 | } 241 | 242 | } 243 | 244 | // MARK: - DestinationSplitViewController 245 | extension NSStoryboardSegue { 246 | func selection() -> DestinationSplitViewController.Segue? { 247 | if let identifier = self.identifier { 248 | return DestinationSplitViewController.Segue(rawValue: identifier) 249 | } 250 | return nil 251 | } 252 | } 253 | extension DestinationSplitViewController { 254 | 255 | enum Segue: NSStoryboardSegue.Identifier, CustomStringConvertible, SegueProtocol { 256 | case rowdetail = "rowdetail" 257 | 258 | var kind: SegueKind? { 259 | switch self { 260 | case .rowdetail: 261 | return SegueKind(rawValue: "custom") 262 | } 263 | } 264 | 265 | var destination: AnyObject.Type? { 266 | switch self { 267 | case .rowdetail: 268 | return NSViewController.self 269 | } 270 | } 271 | 272 | var identifier: NSStoryboardSegue.Identifier? { return self.rawValue } 273 | var description: String { return "\(self.rawValue)" } 274 | } 275 | 276 | } 277 | 278 | // MARK: - SplitViewController 279 | 280 | -------------------------------------------------------------------------------- /Example/Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment this line to define a global platform for your project 2 | platform :osx, '10.11' 3 | use_frameworks! 4 | 5 | target 'Example' do 6 | pod 'CustomSegue', :path => '../CustomSegue.podspec' 7 | end 8 | -------------------------------------------------------------------------------- /Example/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - CustomSegue (4.0.0) 3 | 4 | DEPENDENCIES: 5 | - CustomSegue (from `../CustomSegue.podspec`) 6 | 7 | EXTERNAL SOURCES: 8 | CustomSegue: 9 | :path: "../CustomSegue.podspec" 10 | 11 | SPEC CHECKSUMS: 12 | CustomSegue: debd954fd08cc7e101a1d8df330c22ded6a412ec 13 | 14 | PODFILE CHECKSUM: de97afe579430568ffbb32e1dcc73e6eb62f35aa 15 | 16 | COCOAPODS: 1.6.0 17 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Eric Marchand 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 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // Package.swift 2 | /* 3 | The MIT License (MIT) 4 | Copyright (c) 2016 Eric Marchand (phimage) 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 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | */ 21 | 22 | import PackageDescription 23 | 24 | let package = Package( 25 | name: "CustomSegue" 26 | ) 27 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CustomSegue 2 | 3 | [![License](https://img.shields.io/badge/license-MIT-blue.svg?style=flat 4 | )](http://mit-license.org) 5 | [![Platform](http://img.shields.io/badge/platform-osx-lightgrey.svg?style=flat 6 | )](https://developer.apple.com/resources/) 7 | [![Language](http://img.shields.io/badge/language-swift-orange.svg?style=flat 8 | )](https://developer.apple.com/swift) 9 | [![Issues](https://img.shields.io/github/issues/phimage/CustomSegue.svg?style=flat 10 | )](https://github.com/phimage/CustomSegue/issues) 11 | [![Cocoapod](http://img.shields.io/cocoapods/v/CustomSegue.svg?style=flat)](http://cocoadocs.org/docsets/CustomSegue/) 12 | 13 | [](#logo) 14 | Custom segue for OSX Storyboards. Slide and cross fade effects, new customized window. 15 | 16 | ```swift 17 | class MyViewController: NSViewController { 18 | 19 | override func prepareForSegue(segue: NSStoryboardSegue, sender: AnyObject?) 20 | if segue.identifier == "configured" { 21 | if let segue = segue as? PresentWithAnimatorSegue, animator = segue.animator as? TransitionAnimator { 22 | animator.duration = 1 23 | animator.transition = [.SlideDown, .Crossfade] 24 | } 25 | } 26 | } 27 | ``` 28 | 29 | `TransitionAnimator` transition is configured via [NSViewControllerTransitionOptions](https://developer.apple.com/reference/appkit/nsviewcontrollertransitionoptions), and suppress the need to use a parent controller with `transitionFromViewController` function. 30 | 31 | ## Demo 32 | In [Example](Example) folder you can launch `pod install` and open `Example.xcworkspace` 33 | 34 | 35 | 36 | ## How to use 37 | Use `PresentWithAnimatorSegue` in your storyboard or use one of already configured segue: `SlideDownSegue`, `SlideUpSegue`, `SlideLeftSegue`, `SlideRightSegue`, `ChildWindowSegue`, ... 38 | 39 | 40 | ### Configure segue 41 | In your storyboard add an storyboard identifier to the segue. 42 | 43 | 44 | 45 | Then in your source view controller, you can configure the segue in `prepare(for segue` function. 46 | 47 | ```swift 48 | class MyViewController: NSViewController { 49 | override func prepare(for segue: NSStoryboardSegue, sender: AnyObject?) { 50 | if segue.identifier?.rawValue == "PetDetail" { 51 | ... 52 | ``` 53 | 54 | You can use [Natalie](https://github.com/krzyzanowskim/Natalie) to generate code about segue for your controller. 55 | With this generate code you can do 56 | ```swift 57 | override func prepare(for segue: NSStoryboardSegue, sender: AnyObject?) { 58 | if segue.identifier == "PetDetail" { 59 | // or better the constant generated 60 | if segue == MyViewController.Segue.petDetail { 61 | ``` 62 | 63 | You can change the duration, the transition type, ... on `animator` object of type `TransitionAnimator` 64 | ```swift 65 | if let segue = segue as? PresentWithAnimatorSegue, animator = segue.animator as? TransitionAnimator { 66 | animator.duration = 1 67 | animator.transition = [.SlideDown, .Crossfade] 68 | } 69 | ``` 70 | 71 | For `ChildWindowSegue` you can customize the `NSWindow`, which display the destination controller 72 | ```swift 73 | if let segue = segue as? ChildWindowSegue, animator = segue.animator as? ChildWindowAnimator { 74 | animator.windowCustomizer = { window in 75 | window.styleMask = NSBorderlessWindowMask 76 | window.setFrameOrigin(NSPoint(...)) 77 | } 78 | } 79 | ``` 80 | 81 | 82 | :bulb: You can also put your own custom animator. 83 | ```swift 84 | if let segue = segue as? PresentWithAnimatorSegue { 85 | segue.animator = MyAnimator() 86 | } 87 | ``` 88 | 89 | ## Others segues 90 | ### ReplaceWindowContentSegue 91 | Replace `contentViewController` of `sourceController` parent `NSWindow` by `destinationController` 92 | 93 | :bulb: You can store this segue into `destinationController` and call `unperform` on it to restore `sourceController` 94 | 95 | ### SplitViewSegue 96 | Segue that replace the last split view item or add a new one into the `sourceController` parent (`NSSplitViewController`) 97 | 98 | Set `replace` to `false` on segue, to add a new split view item. 99 | 100 | ### DismissSegue 101 | Segue to dismiss current from controller 102 | 103 | Allow to display in storyboard the action as segue instead of simple `IBAction` 104 | 105 | ### TransitionFromViewSegue 106 | Segue using parent controller of source and `transitionFromViewController` function 107 | 108 | :warning: `parentViewController` must be set and the same for the `sourceController` and `destinationController` 109 | 110 | ### TablePopoverSegue 111 | Show `destinationController` in a popover with a position relative to the selected table row 112 | 113 | :warning: You must set the `tableView` into segue object (do it in `prepareForSegue`) 114 | 115 | :bulb: You can display detail about selected row in a nice way. So in `prepareForSegue` get table view selected row and pass data to `destinationController` 116 | 117 | ## Present view controller utility method 118 | Little utility method added to `NSViewController` using new enum `PresentationMode`. 119 | ```swift 120 | viewController.present(.asSheet) 121 | viewController.present(.asModalWindow) 122 | viewController.present(.segue(segueIdentifier: "id")) 123 | viewController.present(.animator(animator: MyAnimator())) 124 | viewController.present(.asPopover(... 125 | 126 | ``` 127 | :warning: `parentViewController` must be set 128 | 129 | ## Installation 130 | 131 | ## Using CocoaPods ## 132 | [CocoaPods](https://cocoapods.org/) is a centralized dependency manager for 133 | Objective-C and Swift. Go [here](https://guides.cocoapods.org/using/index.html) 134 | to learn more. 135 | 136 | 1. Add the project to your [Podfile](https://guides.cocoapods.org/using/the-podfile.html). 137 | 138 | ```ruby 139 | use_frameworks! 140 | 141 | pod 'CustomSegue' 142 | ``` 143 | 144 | 2. Run `pod install` and open the `.xcworkspace` file to launch Xcode. 145 | 146 | 147 | ## Using Carthage ## 148 | [Carthage](https://github.com/Carthage/Carthage) is a decentralized dependency manager for Objective-C and Swift. 149 | 150 | 1. Add the project to your [Cartfile](https://github.com/Carthage/Carthage/blob/master/Documentation/Artifacts.md#cartfile). 151 | 152 | ``` 153 | github "phimage/CustomSegue" 154 | ``` 155 | 156 | 2. Run `carthage update` and follow [the additional steps](https://github.com/Carthage/Carthage#getting-started) 157 | in order to add Prephirences to your project. 158 | -------------------------------------------------------------------------------- /SB_H_set_segue_identifier_2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phimage/CustomSegue/daccb44e1e5f10098421aaee5ac129a3746aa1cd/SB_H_set_segue_identifier_2x.png -------------------------------------------------------------------------------- /Sources/ChildWindowSegue.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ChildWindowSegue.swift 3 | // CustomSegue 4 | /* 5 | The MIT License (MIT) 6 | Copyright (c) 2016 Eric Marchand (phimage) 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 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 | */ 23 | 24 | import AppKit 25 | 26 | // Segue to present controller in a new NSWindow 27 | public final class ChildWindowSegue: PresentWithAnimatorSegue { 28 | override init(identifier: NSStoryboardSegue.Identifier, source sourceController: Any, destination destinationController: Any) { 29 | super.init(identifier: identifier, source: sourceController, destination: destinationController) 30 | animator = ChildWindowAnimator() 31 | } 32 | } 33 | 34 | // Animator for ChildWindowSegue 35 | open class ChildWindowAnimator: NSObject, NSViewControllerPresentationAnimator { 36 | 37 | // Customize created NSWindow 38 | open var windowCustomizer: ((NSWindow) -> Void)? = nil 39 | // Place when adding child window 40 | open var place: NSWindow.OrderingMode = .above 41 | 42 | // Create the NSWindow 43 | open var windowFactory: ((_ contentViewController: NSViewController) -> NSWindow) = { contentViewController in 44 | return NSWindow(contentViewController: contentViewController) 45 | } 46 | 47 | open func animatePresentation(of viewController: NSViewController, from fromViewController: NSViewController) { 48 | if viewController.view.window == nil { 49 | let window = windowFactory(viewController) 50 | window.appearance = fromViewController.view.window?.appearance 51 | self.windowCustomizer?(window) 52 | fromViewController.view.window?.addChildWindow(window, ordered: place) 53 | } 54 | } 55 | 56 | open func animateDismissal(of viewController: NSViewController, from fromViewController: NSViewController) { 57 | if let window = viewController.view.window { 58 | DispatchQueue.main.async { 59 | fromViewController.view.window?.removeChildWindow(window) 60 | window.orderOut(self) 61 | } 62 | } 63 | } 64 | 65 | } 66 | -------------------------------------------------------------------------------- /Sources/DismissSegue.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DismissSegue.swift 3 | // CustomSegue 4 | /* 5 | The MIT License (MIT) 6 | Copyright (c) 2016 Eric Marchand (phimage) 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 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 | */ 23 | 24 | import AppKit 25 | 26 | // Segue to dismiss current from controller. Allow to display in storyboard the action instead of simple IBAction 27 | open class DismissSegue: NSStoryboardSegue { 28 | 29 | open override func perform() { 30 | guard let fromController = self.sourceController as? NSViewController 31 | else { return } 32 | 33 | if let presentingViewController = fromController.presentingViewController { 34 | // assert(self.destinationController as? NSViewController == presentingViewController) 35 | presentingViewController.dismiss(fromController) 36 | } else { 37 | fromController.dismiss(nil) 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /Sources/NSViewController+CustomSegue.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NSViewController+CustomSegue.swift 3 | // CustomSegue 4 | /* 5 | The MIT License (MIT) 6 | Copyright (c) 2016 Eric Marchand (phimage) 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 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 | */ 23 | 24 | import Foundation 25 | 26 | public extension NSViewController { 27 | 28 | // How to present this view controller 29 | enum PresentationMode { 30 | case asModalWindow 31 | case asSheet 32 | case asPopover(relativeToRect: NSRect, ofView : NSView, preferredEdge: NSRectEdge, behavior: NSPopover.Behavior) 33 | case transitionFrom(fromViewController: NSViewController, options: NSViewController.TransitionOptions) 34 | case animator(animator: NSViewControllerPresentationAnimator) 35 | case segue(segueIdentifier: String) 36 | } 37 | 38 | // Present this view controller using parent controller. 39 | func present(_ mode: PresentationMode) { 40 | assert(self.parent != nil) 41 | if let p = self.parent { 42 | switch mode { 43 | case .asSheet: 44 | p.presentAsSheet(self) 45 | case .asModalWindow: 46 | p.presentAsModalWindow(self) 47 | case .asPopover(let positioningRect, let positioningView, let preferredEdge, let behavior): 48 | p.present(self, asPopoverRelativeTo: positioningRect, of : positioningView, preferredEdge: preferredEdge, behavior: behavior) 49 | case .transitionFrom(let fromViewController, let options): 50 | p.transition(from: fromViewController, to: self, options: options, completionHandler: nil) 51 | case .animator(let animator): 52 | p.present(self, animator: animator) 53 | case .segue(let segueIdentifier): 54 | p.performSegue(withIdentifier: segueIdentifier, sender: self) 55 | } 56 | } 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /Sources/PresentWithAnimatorSegue.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PresentWithAnimatorSegue.swift 3 | // CustomSegue 4 | /* 5 | The MIT License (MIT) 6 | Copyright (c) 2016 Eric Marchand (phimage) 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 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 | */ 23 | 24 | import AppKit 25 | 26 | // A segue with custom animator. 27 | // You can configure the animator in `prepareForSegue` 28 | open class PresentWithAnimatorSegue: NSStoryboardSegue { 29 | 30 | // An animator used to present the view controller. (by default an TransitionAnimator) 31 | open var animator: NSViewControllerPresentationAnimator = TransitionAnimator() 32 | // Add destination controller as child to source controller 33 | open var addAsChild = false 34 | 35 | override open func perform() { 36 | guard let fromController = self.sourceController as? NSViewController, 37 | let toController = self.destinationController as? NSViewController 38 | else { return } 39 | 40 | if toController.parent == nil && addAsChild { 41 | fromController.addChild(toController) 42 | } 43 | fromController.present(toController, animator: animator) 44 | } 45 | 46 | } 47 | 48 | // MARK: Utility class with transition type configured 49 | 50 | // Slide down segue 51 | open class SlideDownSegue: PresentWithAnimatorSegue { 52 | 53 | override init(identifier: NSStoryboardSegue.Identifier, source sourceController: Any, destination destinationController: Any) { 54 | super.init(identifier: identifier, source: sourceController, destination: destinationController) 55 | (animator as? TransitionAnimator)?.transition = [.slideDown, .crossfade] 56 | } 57 | 58 | } 59 | 60 | // Slide up segue 61 | open class SlideUpSegue: PresentWithAnimatorSegue { 62 | 63 | override init(identifier: NSStoryboardSegue.Identifier, source sourceController: Any, destination destinationController: Any) { 64 | super.init(identifier: identifier, source: sourceController, destination: destinationController) 65 | (animator as? TransitionAnimator)?.transition = [.slideUp, .crossfade] 66 | } 67 | 68 | } 69 | 70 | // Slide left segue 71 | open class SlideLeftSegue: PresentWithAnimatorSegue { 72 | 73 | override init(identifier: NSStoryboardSegue.Identifier, source sourceController: Any, destination destinationController: Any) { 74 | super.init(identifier: identifier, source: sourceController, destination: destinationController) 75 | (animator as? TransitionAnimator)?.transition = [.slideLeft, .crossfade] 76 | } 77 | 78 | } 79 | 80 | // Slide right segue 81 | open class SlideRightSegue: PresentWithAnimatorSegue { 82 | 83 | override init(identifier: NSStoryboardSegue.Identifier, source sourceController: Any, destination destinationController: Any) { 84 | super.init(identifier: identifier, source: sourceController, destination: destinationController) 85 | (animator as? TransitionAnimator)?.transition = [.slideRight, .crossfade] 86 | } 87 | 88 | } 89 | 90 | // Crossfade segue 91 | open class CrossfadeSegue: PresentWithAnimatorSegue { 92 | 93 | override init(identifier: NSStoryboardSegue.Identifier, source sourceController: Any, destination destinationController: Any) { 94 | super.init(identifier: identifier, source: sourceController, destination: destinationController) 95 | (animator as? TransitionAnimator)?.transition = .crossfade 96 | } 97 | 98 | } 99 | -------------------------------------------------------------------------------- /Sources/ReplaceWindowContentSegue.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ReplaceWindowContentSegue.swift 3 | // CustomSegue 4 | /* 5 | The MIT License (MIT) 6 | Copyright (c) 2016 Eric Marchand (phimage) 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 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 | */ 23 | 24 | import AppKit 25 | 26 | // Replace contentViewController of sourceController parent NSWindow by destinationController 27 | open class ReplaceWindowContentSegue: NSStoryboardSegue { 28 | 29 | open var copyFrame = false 30 | 31 | open override func perform() { 32 | guard let fromController = self.sourceController as? NSViewController, 33 | let toController = self.destinationController as? NSViewController, 34 | let window = fromController.view.window 35 | else { return } 36 | if copyFrame { 37 | toController.view.frame = fromController.view.frame 38 | } 39 | window.contentViewController = toController 40 | } 41 | 42 | // In prepareForSegue of sourceController, store this segue into destinationController 43 | // Then you can call this method to dismiss the destinationController 44 | open func unperform() { 45 | guard let fromController = self.sourceController as? NSViewController, 46 | let toController = self.destinationController as? NSViewController, 47 | let window = toController.view.window 48 | else { return } 49 | 50 | if copyFrame { 51 | fromController.view.frame = toController.view.frame 52 | } 53 | window.contentViewController = fromController 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /Sources/SplitViewSegue.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SplitViewSegue.swift 3 | // CustomSegue 4 | /* 5 | The MIT License (MIT) 6 | Copyright (c) 2016 Eric Marchand (phimage) 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 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 | */ 23 | 24 | import AppKit 25 | 26 | // Segue that replace the last split view item if sourceController is in NSSplitViewController 27 | open class SplitViewSegue: NSStoryboardSegue { 28 | 29 | open var splitViewType: NSSplitViewItem.InitType = .standard 30 | 31 | // If true replace the source controller or last split view item 32 | // otherwise just append a new item 33 | open var replace = true 34 | 35 | open override func perform() { 36 | guard let fromController = self.sourceController as? NSViewController, 37 | let toController = self.destinationController as? NSViewController 38 | else { return } 39 | 40 | if let splitViewController = fromController.parent as? NSSplitViewController { 41 | if replace { 42 | if let splitViewItem = splitViewController.splitViewItem(for: fromController) { 43 | splitViewController.removeSplitViewItem(splitViewItem) 44 | } else { 45 | splitViewController.removeLastSplitViewItem() 46 | } 47 | } 48 | splitViewController.addViewController(toController, type: splitViewType) 49 | } 50 | } 51 | 52 | // In prepareForSegue of sourceController, store this segue into destinationController 53 | // Then you can call this method to dismiss the destinationController 54 | open func unperform() { 55 | guard let fromController = self.sourceController as? NSViewController, 56 | let toController = self.destinationController as? NSViewController 57 | else { return } 58 | 59 | if let splitViewController = toController.parent as? NSSplitViewController { 60 | if let splitViewItem = splitViewController.splitViewItem(for: toController) { 61 | splitViewController.removeSplitViewItem(splitViewItem) 62 | } else { 63 | splitViewController.removeLastSplitViewItem() 64 | } 65 | if replace { 66 | splitViewController.addViewController(fromController, type: splitViewType) 67 | } 68 | } 69 | } 70 | 71 | } 72 | 73 | // MARK: extension 74 | public extension NSSplitViewController { 75 | 76 | func addViewController(_ viewController: NSViewController, type: NSSplitViewItem.InitType = .standard) { 77 | self.addSplitViewItem(NSSplitViewItem(viewController: viewController, type: type)) 78 | } 79 | 80 | func removeLastSplitViewItem() { 81 | if let last = self.splitViewItems.last { 82 | self.removeSplitViewItem(last) 83 | } 84 | } 85 | 86 | } 87 | 88 | public extension NSSplitViewItem { 89 | 90 | convenience init(viewController: NSViewController, type: NSSplitViewItem.InitType) { 91 | switch type { 92 | case .standard: 93 | self.init(viewController: viewController) 94 | case .sidebar: 95 | if #available(OSX 10.11, *) { 96 | self.init(sidebarWithViewController: viewController) 97 | } else { 98 | self.init(viewController: viewController) 99 | } 100 | case .contentList: 101 | if #available(OSX 10.11, *) { 102 | self.init(contentListWithViewController: viewController) 103 | } else { 104 | self.init(viewController: viewController) 105 | } 106 | } 107 | } 108 | 109 | enum InitType { 110 | case standard 111 | @available(OSX 10.11, *) 112 | case sidebar 113 | @available(OSX 10.11, *) 114 | case contentList 115 | } 116 | } 117 | 118 | -------------------------------------------------------------------------------- /Sources/TablePopoverSegue.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TablePopoverSegue.swift 3 | // CustomSegue 4 | /* 5 | The MIT License (MIT) 6 | Copyright (c) 2016 Eric Marchand (phimage) 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 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 | */ 23 | 24 | import AppKit 25 | 26 | // show popover near selected table view raw 27 | open class TablePopoverSegue: NSStoryboardSegue { 28 | 29 | open weak var tableView: NSTableView? 30 | open var preferredEdge: NSRectEdge = NSRectEdge.maxX 31 | open var popoverBehavior: NSPopover.Behavior = .transient 32 | 33 | open override func perform() { 34 | guard let fromController = self.sourceController as? NSViewController, 35 | let toController = self.destinationController as? NSViewController, 36 | let tableView = self.tableView 37 | else { return } 38 | 39 | let selectedColumn = tableView.selectedColumn 40 | let selectedRow = tableView.selectedRow 41 | var selectedView = tableView as NSView 42 | if (selectedRow >= 0) { 43 | if let view = tableView.view(atColumn: selectedColumn, row: selectedRow, makeIfNecessary: false) { 44 | selectedView = view 45 | } 46 | } 47 | fromController.present(toController, asPopoverRelativeTo: selectedView.bounds, of: selectedView, preferredEdge: preferredEdge, behavior: popoverBehavior) 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /Sources/TransitionAnimator.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TransitionAnimator.swift 3 | // CustomSegue 4 | /* 5 | The MIT License (MIT) 6 | Copyright (c) 2016 Eric Marchand (phimage) 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 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 | */ 23 | 24 | import AppKit 25 | 26 | // Simple enum for transition type. 27 | public enum TransitionType { 28 | case present, dismiss 29 | } 30 | 31 | // Protocol that view controllers can implement to receive notification of transition. 32 | // This could be used to change controller behaviours. 33 | public protocol TransitionAnimatorNotifiable { 34 | 35 | // Notify the transition completion 36 | func notifyTransitionCompletion(_ transition: TransitionType) 37 | } 38 | 39 | // An animator to present view controller using NSViewControllerTransitionOptions 40 | open class TransitionAnimator: NSObject, NSViewControllerPresentationAnimator { 41 | 42 | // Duration of animation (default: 0.3) 43 | open var duration: TimeInterval 44 | // Animation options for view transitions 45 | open var transition: NSViewController.TransitionOptions 46 | // Background color used on destination controller if not already defined 47 | open var backgroundColor = NSColor.windowBackgroundColor 48 | // If false, destination controller take the size of the source controller 49 | // If true, when sliding the destination controller keep one of its size element.(ex: for slide down and up, the height is kept) 50 | // (default: false) 51 | open var keepOriginalSize = false 52 | // Remove view of fromViewController from view hierarchy. Best use with crossfade effect. 53 | open var removeFromView = false 54 | // Optional origin point for displayed view 55 | open var origin: NSPoint? = nil { 56 | didSet { 57 | assert(keepOriginalSize) 58 | } 59 | } 60 | 61 | fileprivate var fromView: NSView? = nil 62 | 63 | // Init 64 | public init(duration: TimeInterval = 0.3, transition: NSViewController.TransitionOptions = [NSViewController.TransitionOptions.crossfade, NSViewController.TransitionOptions.slideDown]) { 65 | self.duration = duration 66 | self.transition = transition 67 | } 68 | 69 | // MARK: NSViewControllerPresentationAnimator 70 | 71 | 72 | @objc open func animatePresentation(of viewController: NSViewController, from fromViewController: NSViewController) { 73 | let fromFrame = fromViewController.view.frame 74 | 75 | let originalFrame = viewController.view.frame 76 | let startFrame = transition.slideStartFrame(fromFrame: fromFrame, keepOriginalSize: keepOriginalSize, originalFrame: originalFrame) 77 | var destinationFrame = transition.slideStopFrame(fromFrame: fromFrame, keepOriginalSize: keepOriginalSize, originalFrame: originalFrame) 78 | 79 | if let origin = self.origin { 80 | destinationFrame.origin = origin 81 | } 82 | 83 | viewController.view.frame = startFrame 84 | viewController.view.autoresizingMask = [NSView.AutoresizingMask.width, NSView.AutoresizingMask.height] 85 | 86 | if transition.contains(NSViewController.TransitionOptions.crossfade) { 87 | viewController.view.alphaValue = 0 88 | } 89 | 90 | if !viewController.view.wantsLayer { // remove potential transparency 91 | viewController.view.wantsLayer = true 92 | viewController.view.layer?.backgroundColor = backgroundColor.cgColor 93 | viewController.view.layer?.isOpaque = true 94 | } 95 | // maybe create an intermediate container view to remove from controller view from hierarchy 96 | if removeFromView { 97 | fromView = fromViewController.view 98 | fromViewController.view = NSView(frame: fromViewController.view.frame) 99 | fromViewController.view.addSubview(fromView!) 100 | } 101 | fromViewController.view.addSubview(viewController.view) 102 | 103 | NSAnimationContext.runAnimationGroup( 104 | { [unowned self] context in 105 | context.duration = self.duration 106 | context.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeOut) 107 | 108 | viewController.view.animator().frame = destinationFrame 109 | if self.transition.contains(NSViewController.TransitionOptions.crossfade) { 110 | viewController.view.animator().alphaValue = 1 111 | self.fromView?.animator().alphaValue = 0 112 | } 113 | 114 | }, completionHandler: { [unowned self] in 115 | if self.removeFromView { 116 | self.fromView?.removeFromSuperview() 117 | } 118 | if let src = viewController as? TransitionAnimatorNotifiable { 119 | src.notifyTransitionCompletion(.present) 120 | } 121 | if let dst = viewController as? TransitionAnimatorNotifiable { 122 | dst.notifyTransitionCompletion(.present) 123 | } 124 | }) 125 | } 126 | 127 | @objc open func animateDismissal(of viewController: NSViewController, from fromViewController: NSViewController) { 128 | let fromFrame = fromViewController.view.frame 129 | let originalFrame = viewController.view.frame 130 | let destinationFrame = transition.slideStartFrame(fromFrame: fromFrame, keepOriginalSize: keepOriginalSize, originalFrame: originalFrame) 131 | 132 | if self.removeFromView { 133 | fromViewController.view.addSubview(self.fromView!) 134 | } 135 | 136 | NSAnimationContext.runAnimationGroup( 137 | { [unowned self] context in 138 | context.duration = self.duration 139 | context.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeIn) 140 | 141 | viewController.view.animator().frame = destinationFrame 142 | if self.transition.contains(NSViewController.TransitionOptions.crossfade) { 143 | viewController.view.animator().alphaValue = 0 144 | self.fromView?.animator().alphaValue = 1 145 | } 146 | 147 | }, completionHandler: { 148 | viewController.view.removeFromSuperview() 149 | if self.removeFromView { 150 | if let view = self.fromView { 151 | fromViewController.view = view 152 | } 153 | } 154 | 155 | if let src = viewController as? TransitionAnimatorNotifiable { 156 | src.notifyTransitionCompletion(.dismiss) 157 | } 158 | if let dst = viewController as? TransitionAnimatorNotifiable { 159 | dst.notifyTransitionCompletion(.dismiss) 160 | } 161 | }) 162 | } 163 | } 164 | 165 | 166 | // MARK: NSViewControllerTransitionOptions 167 | 168 | extension NSViewController.TransitionOptions { 169 | 170 | func slideStartFrame(fromFrame: NSRect, keepOriginalSize: Bool, originalFrame: NSRect) -> NSRect { 171 | if self.contains(NSViewController.TransitionOptions.slideLeft) { 172 | let width = keepOriginalSize ? originalFrame.width : fromFrame.width 173 | return NSRect(x: fromFrame.width, y: 0, width: width, height: fromFrame.height) 174 | } 175 | if self.contains(NSViewController.TransitionOptions.slideRight) { 176 | let width = keepOriginalSize ? originalFrame.width : fromFrame.width 177 | return NSRect(x: -width, y: 0, width: width, height: fromFrame.height) 178 | } 179 | if self.contains(NSViewController.TransitionOptions.slideDown) { 180 | let height = keepOriginalSize ? originalFrame.height : fromFrame.height 181 | return NSRect(x: 0, y: fromFrame.height, width: fromFrame.width, height: height) 182 | } 183 | if self.contains(NSViewController.TransitionOptions.slideUp) { 184 | let height = keepOriginalSize ? originalFrame.height : fromFrame.height 185 | return NSRect(x: 0, y: -height, width: fromFrame.width, height: height) 186 | } 187 | if self.contains(NSViewController.TransitionOptions.slideForward) { 188 | switch NSApp.userInterfaceLayoutDirection { 189 | case .leftToRight: 190 | return NSViewController.TransitionOptions.slideLeft.slideStartFrame(fromFrame: fromFrame, keepOriginalSize: keepOriginalSize, originalFrame: originalFrame) 191 | case .rightToLeft: 192 | return NSViewController.TransitionOptions.slideRight.slideStartFrame(fromFrame: fromFrame, keepOriginalSize: keepOriginalSize, originalFrame: originalFrame) 193 | @unknown default: 194 | fatalError("Unknown \(NSApp.userInterfaceLayoutDirection)") 195 | } 196 | } 197 | if self.contains(NSViewController.TransitionOptions.slideBackward) { 198 | switch NSApp.userInterfaceLayoutDirection { 199 | case .leftToRight: 200 | return NSViewController.TransitionOptions.slideRight.slideStartFrame(fromFrame: fromFrame, keepOriginalSize: keepOriginalSize, originalFrame: originalFrame) 201 | case .rightToLeft: 202 | return NSViewController.TransitionOptions.slideLeft.slideStartFrame(fromFrame: fromFrame, keepOriginalSize: keepOriginalSize, originalFrame: originalFrame) 203 | @unknown default: 204 | fatalError("Unknown \(NSApp.userInterfaceLayoutDirection)") 205 | } 206 | } 207 | return fromFrame 208 | } 209 | 210 | func slideStopFrame(fromFrame: NSRect, keepOriginalSize: Bool, originalFrame: NSRect) -> NSRect { 211 | if !keepOriginalSize { 212 | return fromFrame 213 | } 214 | if self.contains(NSViewController.TransitionOptions.slideLeft) { 215 | return NSRect(x: fromFrame.width - originalFrame.width , y: 0, width: originalFrame.width , height: fromFrame.height) 216 | } 217 | if self.contains(NSViewController.TransitionOptions.slideRight) { 218 | return NSRect(x: 0, y: 0, width: originalFrame.width , height: fromFrame.height) 219 | } 220 | if self.contains(NSViewController.TransitionOptions.slideUp) { 221 | return NSRect(x: 0, y: 0, width: fromFrame.width, height: originalFrame.height ) 222 | } 223 | if self.contains(NSViewController.TransitionOptions.slideDown) { 224 | return NSRect(x: 0, y: fromFrame.height - originalFrame.height , width: fromFrame.width, height: originalFrame.height) 225 | } 226 | if self.contains(NSViewController.TransitionOptions.slideForward) { 227 | switch NSApp.userInterfaceLayoutDirection { 228 | case .leftToRight: 229 | return NSViewController.TransitionOptions.slideLeft.slideStopFrame(fromFrame: fromFrame, keepOriginalSize: keepOriginalSize, originalFrame: originalFrame) 230 | case .rightToLeft: 231 | return NSViewController.TransitionOptions.slideRight.slideStopFrame(fromFrame: fromFrame, keepOriginalSize: keepOriginalSize, originalFrame: originalFrame) 232 | @unknown default: 233 | fatalError("Unknown \(NSApp.userInterfaceLayoutDirection)") 234 | } 235 | } 236 | if self.contains(NSViewController.TransitionOptions.slideBackward) { 237 | switch NSApp.userInterfaceLayoutDirection { 238 | case .leftToRight: 239 | return NSViewController.TransitionOptions.slideRight.slideStopFrame(fromFrame: fromFrame, keepOriginalSize: keepOriginalSize, originalFrame: originalFrame) 240 | case .rightToLeft: 241 | return NSViewController.TransitionOptions.slideLeft.slideStopFrame(fromFrame: fromFrame, keepOriginalSize: keepOriginalSize, originalFrame: originalFrame) 242 | @unknown default: 243 | fatalError("Unknown \(NSApp.userInterfaceLayoutDirection)") 244 | } 245 | } 246 | return fromFrame 247 | } 248 | 249 | } 250 | -------------------------------------------------------------------------------- /Sources/TransitionFromViewSegue.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TransitionFromViewSegue.swift 3 | // CustomSegue 4 | /* 5 | The MIT License (MIT) 6 | Copyright (c) 2016 Eric Marchand (phimage) 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 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 | */ 23 | 24 | import AppKit 25 | 26 | // Segue using parent controller of source and `transitionFromViewController` 27 | open class TransitionFromViewSegue: NSStoryboardSegue { 28 | 29 | // Animation options for view transitions 30 | open var transition: NSViewController.TransitionOptions = [.crossfade, .slideDown] 31 | // Handler for transition completion 32 | open var completionHandler: (() -> Void)? 33 | // Set wants layer or not for all controller main view 34 | open var wantsLayer = true 35 | 36 | override open func perform() { 37 | guard let fromController = self.sourceController as? NSViewController, 38 | let toController = self.destinationController as? NSViewController 39 | else { return } 40 | 41 | if let parentViewController = fromController.parent { 42 | parentViewController.addChild(toController) 43 | 44 | if wantsLayer { 45 | parentViewController.view.wantsLayer = true 46 | fromController.view.wantsLayer = true 47 | toController.view.wantsLayer = true 48 | } 49 | 50 | parentViewController.transition(from: fromController, to: toController, options: transition, completionHandler: completionHandler) 51 | } 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phimage/CustomSegue/daccb44e1e5f10098421aaee5ac129a3746aa1cd/logo.png -------------------------------------------------------------------------------- /screen.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phimage/CustomSegue/daccb44e1e5f10098421aaee5ac129a3746aa1cd/screen.gif --------------------------------------------------------------------------------