├── .gitignore ├── Framework ├── Headers │ ├── MASPreferences.h │ ├── MASPreferences.modulemap │ ├── MASPreferencesViewController.h │ └── MASPreferencesWindowController.h ├── Info.plist ├── MASPreferences.h ├── MASPreferences.modulemap ├── MASPreferencesViewController.h ├── MASPreferencesWindowController.h ├── MASPreferencesWindowController.m └── en.lproj │ └── MASPreferencesWindow.xib ├── LICENSE.md ├── MASPreferences.podspec ├── MASPreferences.xcodeproj ├── project.pbxproj └── xcshareddata │ └── xcschemes │ └── MASPreferences.xcscheme ├── Package.swift └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | build/* 3 | *.pbxuser 4 | !default.pbxuser 5 | *.mode1v3 6 | !default.mode1v3 7 | *.mode2v3 8 | !default.mode2v3 9 | *.perspectivev3 10 | !default.perspectivev3 11 | *.xcworkspace 12 | !default.xcworkspace 13 | xcuserdata 14 | profile 15 | *.moved-aside 16 | # Finder 17 | .DS_Store 18 | # Carthage 19 | Carthage/Build 20 | # Swift Package Manager 21 | .swiftpm 22 | -------------------------------------------------------------------------------- /Framework/Headers/MASPreferences.h: -------------------------------------------------------------------------------- 1 | ../MASPreferences.h -------------------------------------------------------------------------------- /Framework/Headers/MASPreferences.modulemap: -------------------------------------------------------------------------------- 1 | ../MASPreferences.modulemap -------------------------------------------------------------------------------- /Framework/Headers/MASPreferencesViewController.h: -------------------------------------------------------------------------------- 1 | ../MASPreferencesViewController.h -------------------------------------------------------------------------------- /Framework/Headers/MASPreferencesWindowController.h: -------------------------------------------------------------------------------- 1 | ../MASPreferencesWindowController.h -------------------------------------------------------------------------------- /Framework/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | com.github.shpakovski.${PRODUCT_NAME:rfc1034identifier} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | ${PRODUCT_NAME} 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.2 19 | CFBundleVersion 20 | 120 21 | NSHumanReadableCopyright 22 | Copyright © 2016 Vadim Shpakovski. All rights reserved. 23 | 24 | 25 | -------------------------------------------------------------------------------- /Framework/MASPreferences.h: -------------------------------------------------------------------------------- 1 | #import "MASPreferencesViewController.h" 2 | #import "MASPreferencesWindowController.h" 3 | -------------------------------------------------------------------------------- /Framework/MASPreferences.modulemap: -------------------------------------------------------------------------------- 1 | framework module MASPreferences { 2 | umbrella header "MASPreferences.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Framework/MASPreferencesViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // Any controller providing preference pane view must support this protocol 3 | // 4 | 5 | #import 6 | 7 | NS_ASSUME_NONNULL_BEGIN 8 | 9 | /*! 10 | * Requirements for the Preferences panel 11 | */ 12 | @protocol MASPreferencesViewController 13 | 14 | /*! 15 | * Unique identifier of the Panel represented by the view controller. 16 | */ 17 | @property (nonatomic, readonly) NSString* viewIdentifier; 18 | 19 | /*! 20 | * Toolbar item label for the Panel represented by the view controller. 21 | * 22 | * This label may be used as a Preferences window title. 23 | */ 24 | @property (nonatomic, readonly, nullable) NSString *toolbarItemLabel; 25 | 26 | @optional 27 | 28 | /*! 29 | * Toolbar icon for the Panel represented by the view controller. 30 | * 31 | * If you do not implement this then the toolbar will only use labels 32 | */ 33 | @property (nonatomic, readonly, nullable) NSImage *toolbarItemImage; 34 | 35 | /*! 36 | * Called when selection goes to the Panel represented by the view controller. 37 | */ 38 | - (void)viewWillAppear; 39 | 40 | /*! 41 | * Called when selection goes to another Panel. 42 | */ 43 | - (void)viewDidDisappear; 44 | 45 | /*! 46 | * Returns initial control in the key view loop. 47 | * 48 | * @return The view to focus on automatically when the panel is open. 49 | */ 50 | - (__kindof NSView *)initialKeyView; 51 | 52 | /*! 53 | * The flag used to detect if the Prerences window can be resized horizontally. 54 | */ 55 | @property (nonatomic, readonly) BOOL hasResizableWidth; 56 | 57 | /*! 58 | * The flag used to detect if the Prerences window can be resized vertically. 59 | */ 60 | @property (nonatomic, readonly) BOOL hasResizableHeight; 61 | 62 | @end 63 | 64 | NS_ASSUME_NONNULL_END 65 | -------------------------------------------------------------------------------- /Framework/MASPreferencesWindowController.h: -------------------------------------------------------------------------------- 1 | // 2 | // You create an application Preferences window using code like this: 3 | // _preferencesWindowController = [[MASPreferencesWindowController alloc] initWithViewControllers:controllers title:title] 4 | // 5 | // To open the Preferences window: 6 | // [_preferencesWindowController showWindow:sender] 7 | // 8 | 9 | #import 10 | 11 | @protocol MASPreferencesViewController; 12 | 13 | NS_ASSUME_NONNULL_BEGIN 14 | 15 | /*! 16 | * Notification posted when you switch selected panel in Preferences. 17 | */ 18 | extern NSString * const kMASPreferencesWindowControllerDidChangeViewNotification; 19 | 20 | /*! 21 | * Window controller for managing Preference view controllers. 22 | */ 23 | __attribute__((__visibility__("default"))) 24 | @interface MASPreferencesWindowController : NSWindowController 25 | { 26 | @private 27 | NSMutableArray *_viewControllers; 28 | NSMutableDictionary *_minimumViewRects; 29 | NSString *_title; 30 | NSViewController *_selectedViewController; 31 | NSToolbar * __unsafe_unretained _toolbar; 32 | } 33 | 34 | /*! 35 | * Child view controllers in the Preferences window. 36 | */ 37 | @property (nonatomic, readonly) NSMutableArray *viewControllers; 38 | 39 | /*! 40 | * Index of selected panel in the Preferences window. 41 | */ 42 | @property (nonatomic, readonly) NSUInteger indexOfSelectedController; 43 | 44 | /*! 45 | * View controller representing selected panel in the Preferences window. 46 | */ 47 | @property (nonatomic, readonly) NSViewController *selectedViewController; 48 | 49 | /*! 50 | * Optional window title provided in the initializer. 51 | */ 52 | @property (nonatomic, copy, readonly, nullable) NSString *title; 53 | 54 | /*! 55 | * The toolbar managed by the Preferences window. 56 | */ 57 | @property (nonatomic, unsafe_unretained) IBOutlet NSToolbar *toolbar; 58 | 59 | /*! 60 | * Creates new a window controller for Preferences with custom title. 61 | * 62 | * @param viewControllers Non-empty list of view controllers representing Preference panels. 63 | * @param title Optional title for the Preferneces window. Pass `nil` to show the title provided by selected view controller. 64 | * 65 | * @return A new controller with the given title. 66 | */ 67 | - (instancetype)initWithViewControllers:(NSArray *)viewControllers title:(NSString * _Nullable)title; 68 | - (instancetype)init __attribute((unavailable("Please use initWithViewControllers:title:"))); 69 | 70 | /*! 71 | * Creates new a window controller for Preferences with a flexible title. 72 | * 73 | * @param viewControllers Non-empty list of view controllers representing Preference panels. 74 | * 75 | * @return A new controller with title depending on selected view controller. 76 | */ 77 | - (instancetype)initWithViewControllers:(NSArray *)viewControllers; 78 | 79 | /*! 80 | * Appends new panel to the Preferences window. 81 | * 82 | * @param viewController View controller representing new panel. 83 | */ 84 | - (void)addViewController:(NSViewController *)viewController; 85 | 86 | /*! 87 | * Changes selection in the Preferences toolbar. 88 | * 89 | * @param controllerIndex Position of the new panel to select in the toolbar. 90 | */ 91 | - (void)selectControllerAtIndex:(NSUInteger)controllerIndex; 92 | 93 | /*! 94 | * Changes selection in the Preferences toolbar using panel identifier. 95 | * 96 | * @param identifier String identifier of the view controller to select. 97 | */ 98 | - (void)selectControllerWithIdentifier:(NSString *)identifier; 99 | 100 | /*! 101 | * Useful action for switching to the next panel. 102 | * 103 | * For example, you may connect it to the main menu. 104 | * 105 | * @param sender Menu or toolbar item. 106 | */ 107 | - (IBAction)goNextTab:(id _Nullable)sender; 108 | 109 | /*! 110 | * Useful action for switching to the previous panel. 111 | * 112 | * For example, you may connect it to the main menu. 113 | * 114 | * @param sender Menu or toolbar item. 115 | */ 116 | - (IBAction)goPreviousTab:(id _Nullable)sender; 117 | 118 | @end 119 | 120 | NS_ASSUME_NONNULL_END 121 | -------------------------------------------------------------------------------- /Framework/MASPreferencesWindowController.m: -------------------------------------------------------------------------------- 1 | #import "MASPreferencesWindowController.h" 2 | #import "MASPreferencesViewController.h" 3 | 4 | NSString *const kMASPreferencesWindowControllerDidChangeViewNotification = @"MASPreferencesWindowControllerDidChangeViewNotification"; 5 | 6 | static NSString *const kMASPreferencesFrameTopLeftKey = @"MASPreferences Frame Top Left"; 7 | static NSString *const kMASPreferencesSelectedViewKey = @"MASPreferences Selected Identifier View"; 8 | 9 | static NSString * PreferencesKeyForViewBounds (NSString *identifier) 10 | { 11 | return [NSString stringWithFormat:@"MASPreferences %@ Frame", identifier]; 12 | } 13 | 14 | @interface MASPreferencesWindowController () // Private 15 | 16 | - (NSViewController *)viewControllerForIdentifier:(NSString *)identifier; 17 | 18 | @property (readonly) NSArray *toolbarItemIdentifiers; 19 | @property (nonatomic, retain) NSViewController *selectedViewController; 20 | 21 | @end 22 | 23 | #pragma mark - 24 | 25 | @implementation MASPreferencesWindowController 26 | 27 | @synthesize viewControllers = _viewControllers; 28 | @synthesize selectedViewController = _selectedViewController; 29 | @synthesize title = _title; 30 | @synthesize toolbar = _toolbar; 31 | 32 | #pragma mark - 33 | 34 | - (instancetype)initWithViewControllers:(NSArray *)viewControllers 35 | { 36 | return [self initWithViewControllers:viewControllers title:nil]; 37 | } 38 | 39 | - (instancetype)initWithViewControllers:(NSArray *)viewControllers title:(NSString *)title 40 | { 41 | NSParameterAssert(viewControllers.count > 0); 42 | NSString *nibPath = [[MASPreferencesWindowController resourceBundle] pathForResource:@"MASPreferencesWindow" ofType:@"nib"]; 43 | if ((self = [super initWithWindowNibPath:nibPath owner:self])) 44 | { 45 | _viewControllers = [viewControllers mutableCopy]; 46 | _minimumViewRects = [[NSMutableDictionary alloc] init]; 47 | _title = [title copy]; 48 | } 49 | return self; 50 | } 51 | 52 | - (void)dealloc 53 | { 54 | [[NSNotificationCenter defaultCenter] removeObserver:self]; 55 | [[self window] setDelegate:nil]; 56 | for (NSToolbarItem *item in [self.toolbar items]) { 57 | item.target = nil; 58 | item.action = nil; 59 | } 60 | self.toolbar.delegate = nil; 61 | } 62 | 63 | - (void)addViewController:(NSViewController *)viewController 64 | { 65 | NSParameterAssert(viewController); 66 | [_viewControllers addObject: viewController]; 67 | [_toolbar insertItemWithItemIdentifier: viewController.viewIdentifier atIndex: ([_viewControllers count] - 1)]; 68 | [_toolbar validateVisibleItems]; 69 | } 70 | 71 | #pragma mark - 72 | 73 | - (void)windowDidLoad 74 | { 75 | BOOL hasImages = NO; 76 | for (id viewController in self.viewControllers) 77 | if ([viewController respondsToSelector:@selector(toolbarItemImage)]) 78 | hasImages = YES; 79 | 80 | if(hasImages == NO) 81 | [[[self window] toolbar] setDisplayMode:NSToolbarDisplayModeLabelOnly]; 82 | 83 | if ([self.title length] > 0) 84 | [[self window] setTitle:self.title]; 85 | 86 | if ([self.viewControllers count]) 87 | self.selectedViewController = [self viewControllerForIdentifier:[[NSUserDefaults standardUserDefaults] stringForKey:kMASPreferencesSelectedViewKey]] ?: [self firstViewController]; 88 | 89 | NSString *origin = [[NSUserDefaults standardUserDefaults] stringForKey:kMASPreferencesFrameTopLeftKey]; 90 | if (origin) 91 | { 92 | [self.window layoutIfNeeded]; 93 | [self.window setFrameTopLeftPoint:NSPointFromString(origin)]; 94 | } 95 | 96 | #ifdef MAC_OS_VERSION_11_0 97 | if (@available(macOS 11.0, *)) { 98 | [self.window setToolbarStyle:NSWindowToolbarStylePreference]; 99 | } 100 | #endif 101 | 102 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(windowDidMove:) name:NSWindowDidMoveNotification object:self.window]; 103 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(windowDidResize:) name:NSWindowDidResizeNotification object:self.window]; 104 | } 105 | 106 | - (NSViewController *)firstViewController { 107 | for (id viewController in self.viewControllers) 108 | if ([viewController isKindOfClass:[NSViewController class]]) 109 | return viewController; 110 | 111 | return nil; 112 | } 113 | 114 | #pragma mark - 115 | #pragma mark NSWindowDelegate 116 | 117 | - (BOOL)windowShouldClose:(id __unused)sender 118 | { 119 | return !self.selectedViewController || [self.selectedViewController commitEditing]; 120 | } 121 | 122 | - (void)windowDidMove:(NSNotification* __unused)aNotification 123 | { 124 | [[NSUserDefaults standardUserDefaults] setObject:NSStringFromPoint(NSMakePoint(NSMinX([self.window frame]), NSMaxY([self.window frame]))) forKey:kMASPreferencesFrameTopLeftKey]; 125 | } 126 | 127 | - (void)windowDidResize:(NSNotification* __unused)aNotification 128 | { 129 | NSViewController *viewController = self.selectedViewController; 130 | if (viewController) 131 | [[NSUserDefaults standardUserDefaults] setObject:NSStringFromRect([viewController.view bounds]) forKey:PreferencesKeyForViewBounds(viewController.viewIdentifier)]; 132 | } 133 | 134 | #pragma mark - 135 | #pragma mark Accessors 136 | 137 | - (NSArray *)toolbarItemIdentifiers 138 | { 139 | NSMutableArray *identifiers = [NSMutableArray arrayWithCapacity:_viewControllers.count]; 140 | for (id viewController in _viewControllers) 141 | if (viewController == [NSNull null]) 142 | [identifiers addObject:NSToolbarFlexibleSpaceItemIdentifier]; 143 | else 144 | [identifiers addObject:[viewController viewIdentifier]]; 145 | return identifiers; 146 | } 147 | 148 | #pragma mark - 149 | 150 | - (NSUInteger)indexOfSelectedController 151 | { 152 | NSUInteger index = [self.toolbarItemIdentifiers indexOfObject:self.selectedViewController.viewIdentifier]; 153 | return index; 154 | } 155 | 156 | #pragma mark - 157 | #pragma mark NSToolbarDelegate 158 | 159 | - (NSArray *)toolbarAllowedItemIdentifiers:(NSToolbar * __unused)toolbar 160 | { 161 | NSArray *identifiers = self.toolbarItemIdentifiers; 162 | return identifiers; 163 | } 164 | 165 | - (NSArray *)toolbarDefaultItemIdentifiers:(NSToolbar * __unused)toolbar 166 | { 167 | NSArray *identifiers = self.toolbarItemIdentifiers; 168 | return identifiers; 169 | } 170 | 171 | - (NSArray *)toolbarSelectableItemIdentifiers:(NSToolbar * __unused)toolbar 172 | { 173 | NSArray *identifiers = self.toolbarItemIdentifiers; 174 | return identifiers; 175 | } 176 | 177 | - (NSToolbarItem *)toolbar:(NSToolbar * __unused)toolbar itemForItemIdentifier:(NSString *)itemIdentifier willBeInsertedIntoToolbar:(BOOL __unused)flag 178 | { 179 | NSToolbarItem *toolbarItem = [[NSToolbarItem alloc] initWithItemIdentifier:itemIdentifier]; 180 | NSArray *identifiers = self.toolbarItemIdentifiers; 181 | NSUInteger controllerIndex = [identifiers indexOfObject:itemIdentifier]; 182 | if (controllerIndex != NSNotFound) 183 | { 184 | id controller = [_viewControllers objectAtIndex:controllerIndex]; 185 | if ([controller respondsToSelector:@selector(toolbarItemImage)]) 186 | toolbarItem.image = controller.toolbarItemImage; 187 | toolbarItem.label = controller.toolbarItemLabel; 188 | toolbarItem.target = self; 189 | toolbarItem.action = @selector(toolbarItemDidClick:); 190 | } 191 | return toolbarItem; 192 | } 193 | 194 | #pragma mark - 195 | #pragma mark Private methods 196 | 197 | - (NSViewController *)viewControllerForIdentifier:(NSString *)identifier 198 | { 199 | for (id viewController in self.viewControllers) { 200 | if (viewController == [NSNull null]) continue; 201 | if ([[viewController viewIdentifier] isEqualToString:identifier]) 202 | return viewController; 203 | } 204 | return nil; 205 | } 206 | 207 | #pragma mark - 208 | 209 | - (void)setSelectedViewController:(NSViewController *)controller 210 | { 211 | if (_selectedViewController == controller) 212 | return; 213 | 214 | if (_selectedViewController) 215 | { 216 | // Check if we can commit changes for old controller 217 | if (![_selectedViewController commitEditing]) 218 | { 219 | [[self.window toolbar] setSelectedItemIdentifier:_selectedViewController.viewIdentifier]; 220 | return; 221 | } 222 | [self.window setContentView:[[NSView alloc] init]]; 223 | [_selectedViewController setNextResponder:nil]; 224 | // With 10.10 and later AppKit will invoke viewDidDisappear so we need to prevent it from being called twice. 225 | if (![NSViewController instancesRespondToSelector:@selector(viewDidDisappear)]) 226 | if ([_selectedViewController respondsToSelector:@selector(viewDidDisappear)]) 227 | [_selectedViewController viewDidDisappear]; 228 | _selectedViewController = nil; 229 | } 230 | 231 | if (!controller) 232 | return; 233 | 234 | // Retrieve the new window tile from the controller view 235 | if ([self.title length] == 0) 236 | { 237 | NSString *label = controller.toolbarItemLabel; 238 | self.window.title = label; 239 | } 240 | 241 | [[self.window toolbar] setSelectedItemIdentifier:controller.viewIdentifier]; 242 | 243 | // Record new selected controller in user defaults 244 | [[NSUserDefaults standardUserDefaults] setObject:controller.viewIdentifier forKey:kMASPreferencesSelectedViewKey]; 245 | 246 | NSView *controllerView = controller.view; 247 | 248 | // Retrieve current and minimum frame size for the view 249 | NSString *oldViewRectString = [[NSUserDefaults standardUserDefaults] stringForKey:PreferencesKeyForViewBounds(controller.viewIdentifier)]; 250 | NSString *minViewRectString = [_minimumViewRects objectForKey:controller.viewIdentifier]; 251 | if (!minViewRectString) 252 | [_minimumViewRects setObject:NSStringFromRect(controllerView.bounds) forKey:controller.viewIdentifier]; 253 | 254 | BOOL sizableWidth = ([controller respondsToSelector:@selector(hasResizableWidth)] 255 | ? controller.hasResizableWidth 256 | : controllerView.autoresizingMask & NSViewWidthSizable); 257 | BOOL sizableHeight = ([controller respondsToSelector:@selector(hasResizableHeight)] 258 | ? controller.hasResizableHeight 259 | : controllerView.autoresizingMask & NSViewHeightSizable); 260 | 261 | NSRect oldViewRect = oldViewRectString ? NSRectFromString(oldViewRectString) : controllerView.bounds; 262 | NSRect minViewRect = minViewRectString ? NSRectFromString(minViewRectString) : controllerView.bounds; 263 | oldViewRect.size.width = NSWidth(oldViewRect) < NSWidth(minViewRect) || !sizableWidth ? NSWidth(minViewRect) : NSWidth(oldViewRect); 264 | oldViewRect.size.height = NSHeight(oldViewRect) < NSHeight(minViewRect) || !sizableHeight ? NSHeight(minViewRect) : NSHeight(oldViewRect); 265 | 266 | [controllerView setFrame:oldViewRect]; 267 | 268 | // Calculate new window size and position 269 | NSRect oldFrame = [self.window frame]; 270 | NSRect newFrame = [self.window frameRectForContentRect:oldViewRect]; 271 | newFrame = NSOffsetRect(newFrame, NSMinX(oldFrame), NSMaxY(oldFrame) - NSMaxY(newFrame)); 272 | 273 | // Setup min/max sizes and show/hide resize indicator 274 | [self.window setContentMinSize:minViewRect.size]; 275 | [self.window setContentMaxSize:NSMakeSize(sizableWidth ? CGFLOAT_MAX : NSWidth(oldViewRect), sizableHeight ? CGFLOAT_MAX : NSHeight(oldViewRect))]; 276 | [self.window setShowsResizeIndicator:sizableWidth || sizableHeight]; 277 | [[self.window standardWindowButton:NSWindowZoomButton] setEnabled:sizableWidth || sizableHeight]; 278 | 279 | [self.window setFrame:newFrame display:YES animate:[self.window isVisible]]; 280 | 281 | _selectedViewController = controller; 282 | 283 | // In OSX 10.10, setContentView below calls viewWillAppear. We still want to call viewWillAppear on < 10.10, 284 | // so the check below avoids calling viewWillAppear twice on 10.10. 285 | // See https://github.com/shpakovski/MASPreferences/issues/32 for more info. 286 | if (![NSViewController instancesRespondToSelector:@selector(viewWillAppear)]) 287 | if ([controller respondsToSelector:@selector(viewWillAppear)]) 288 | [controller viewWillAppear]; 289 | 290 | [self.window setContentView:controllerView]; 291 | [self.window recalculateKeyViewLoop]; 292 | if ([self.window firstResponder] == self.window) { 293 | if ([controller respondsToSelector:@selector(initialKeyView)]) 294 | [self.window makeFirstResponder:[controller initialKeyView]]; 295 | else 296 | [self.window selectKeyViewFollowingView:controllerView]; 297 | } 298 | 299 | // Insert view controller into responder chain on 10.9 and earlier 300 | if (controllerView.nextResponder != controller) { 301 | controller.nextResponder = controllerView.nextResponder; 302 | controllerView.nextResponder = controller; 303 | } 304 | 305 | [[NSNotificationCenter defaultCenter] postNotificationName:kMASPreferencesWindowControllerDidChangeViewNotification object:self]; 306 | } 307 | 308 | - (void)toolbarItemDidClick:(id)sender 309 | { 310 | if ([sender respondsToSelector:@selector(itemIdentifier)]) 311 | self.selectedViewController = [self viewControllerForIdentifier:[sender itemIdentifier]]; 312 | } 313 | 314 | #pragma mark - 315 | #pragma mark Public methods 316 | 317 | - (void)selectControllerAtIndex:(NSUInteger)controllerIndex 318 | { 319 | if (NSLocationInRange(controllerIndex, NSMakeRange(0, _viewControllers.count))) 320 | self.selectedViewController = [self.viewControllers objectAtIndex:controllerIndex]; 321 | } 322 | 323 | - (void)selectControllerWithIdentifier:(NSString *)identifier 324 | { 325 | NSParameterAssert(identifier.length > 0); 326 | self.selectedViewController = [self viewControllerForIdentifier:identifier]; 327 | } 328 | 329 | #pragma mark - 330 | #pragma mark Actions 331 | 332 | - (IBAction)goNextTab:(id __unused)sender 333 | { 334 | NSUInteger selectedIndex = self.indexOfSelectedController; 335 | NSUInteger numberOfControllers = [_viewControllers count]; 336 | 337 | do { selectedIndex = (selectedIndex + 1) % numberOfControllers; } 338 | while ([_viewControllers objectAtIndex:selectedIndex] == [NSNull null]); 339 | 340 | [self selectControllerAtIndex:selectedIndex]; 341 | } 342 | 343 | - (IBAction)goPreviousTab:(id __unused)sender 344 | { 345 | NSUInteger selectedIndex = self.indexOfSelectedController; 346 | NSUInteger numberOfControllers = [_viewControllers count]; 347 | 348 | do { selectedIndex = (selectedIndex + numberOfControllers - 1) % numberOfControllers; } 349 | while ([_viewControllers objectAtIndex:selectedIndex] == [NSNull null]); 350 | 351 | [self selectControllerAtIndex:selectedIndex]; 352 | } 353 | 354 | #pragma mark - 355 | #pragma mark Helper Functions 356 | 357 | + (NSBundle *)resourceBundle { 358 | #ifdef SWIFT_PACKAGE 359 | return SWIFTPM_MODULE_BUNDLE; 360 | #else 361 | NSBundle *moduleBundle = [NSBundle bundleForClass:MASPreferencesWindowController.class]; 362 | 363 | // Lookup for MASPreferences.bundle, which usually comes with CocoaPods's `:linkage => :static`. 364 | NSString *resourceBundlePath = [moduleBundle pathForResource:@"MASPreferences" ofType:@"bundle"]; 365 | if ([resourceBundlePath length]) { 366 | NSBundle *resourceBundle = [NSBundle bundleWithURL:[NSURL fileURLWithPath:resourceBundlePath]]; 367 | if (resourceBundle) { 368 | return resourceBundle; 369 | } 370 | } 371 | 372 | return moduleBundle; 373 | #endif 374 | } 375 | 376 | @end 377 | -------------------------------------------------------------------------------- /Framework/en.lproj/MASPreferencesWindow.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 1080 5 | 12E55 6 | 3084 7 | 1187.39 8 | 626.00 9 | 10 | com.apple.InterfaceBuilder.CocoaPlugin 11 | 3084 12 | 13 | 14 | YES 15 | NSCustomObject 16 | NSToolbar 17 | NSView 18 | NSWindowTemplate 19 | 20 | 21 | YES 22 | com.apple.InterfaceBuilder.CocoaPlugin 23 | 24 | 25 | PluginDependencyRecalculationVersion 26 | 27 | 28 | 29 | YES 30 | 31 | MASPreferencesWindowController 32 | 33 | 34 | FirstResponder 35 | 36 | 37 | NSApplication 38 | 39 | 40 | 11 41 | 2 42 | {{540, 400}, {360, 270}} 43 | 1618478080 44 | 45 | NSWindow 46 | 47 | 48 | A3419266-C6CB-4FAA-AB63-B91B70C196EA 49 | 50 | 51 | YES 52 | YES 53 | NO 54 | NO 55 | 1 56 | 1 57 | 58 | YES 59 | 60 | YES 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 256 72 | {360, 270} 73 | 74 | 75 | 76 | 77 | {{0, 0}, {2560, 1418}} 78 | {10000000000000, 10000000000000} 79 | 80 | YES 81 | 82 | 83 | 84 | 85 | YES 86 | 87 | 88 | window 89 | 90 | 91 | 92 | 3 93 | 94 | 95 | 96 | toolbar 97 | 98 | 99 | 100 | 23 101 | 102 | 103 | 104 | delegate 105 | 106 | 107 | 108 | 20 109 | 110 | 111 | 112 | delegate 113 | 114 | 115 | 116 | 22 117 | 118 | 119 | 120 | 121 | YES 122 | 123 | 0 124 | 125 | 126 | 127 | 128 | 129 | -2 130 | 131 | 132 | File's Owner 133 | 134 | 135 | -1 136 | 137 | 138 | First Responder 139 | 140 | 141 | -3 142 | 143 | 144 | Application 145 | 146 | 147 | 1 148 | 149 | 150 | YES 151 | 152 | 153 | 154 | 155 | 156 | 157 | 2 158 | 159 | 160 | 161 | 162 | 4 163 | 164 | 165 | YES 166 | 167 | 168 | 169 | 170 | 171 | 172 | YES 173 | 174 | YES 175 | -1.IBPluginDependency 176 | -2.IBPluginDependency 177 | -3.IBPluginDependency 178 | 1.IBNSWindowAutoPositionCentersHorizontal 179 | 1.IBNSWindowAutoPositionCentersVertical 180 | 1.IBPluginDependency 181 | 1.IBWindowTemplateEditedContentRect 182 | 1.NSWindowTemplate.visibleAtLaunch 183 | 2.IBPluginDependency 184 | 4.IBPluginDependency 185 | 186 | 187 | YES 188 | com.apple.InterfaceBuilder.CocoaPlugin 189 | com.apple.InterfaceBuilder.CocoaPlugin 190 | com.apple.InterfaceBuilder.CocoaPlugin 191 | 192 | 193 | com.apple.InterfaceBuilder.CocoaPlugin 194 | {{484, 402}, {360, 270}} 195 | 196 | com.apple.InterfaceBuilder.CocoaPlugin 197 | com.apple.InterfaceBuilder.CocoaPlugin 198 | 199 | 200 | 201 | YES 202 | 203 | 204 | 205 | 206 | 207 | YES 208 | 209 | 210 | 211 | 212 | 23 213 | 214 | 215 | 216 | YES 217 | 218 | MASPreferencesWindowController 219 | NSWindowController 220 | 221 | YES 222 | 223 | YES 224 | goNextTab: 225 | goPreviousTab: 226 | 227 | 228 | YES 229 | id 230 | id 231 | 232 | 233 | 234 | YES 235 | 236 | YES 237 | goNextTab: 238 | goPreviousTab: 239 | 240 | 241 | YES 242 | 243 | goNextTab: 244 | id 245 | 246 | 247 | goPreviousTab: 248 | id 249 | 250 | 251 | 252 | 253 | IBProjectSource 254 | ./Classes/MASPreferencesWindowController.h 255 | 256 | 257 | 258 | 259 | 0 260 | IBCocoaFramework 261 | 262 | com.apple.InterfaceBuilder.CocoaPlugin.InterfaceBuilder3 263 | 264 | 265 | YES 266 | 3 267 | 268 | 269 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MASPreferences is licensed under the 2-clause BSD license. 2 | 3 | Copyright (c) 2016 Vadim Shpakovski. All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | 2. Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 19 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 22 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | -------------------------------------------------------------------------------- /MASPreferences.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.platform = :osx, '10.10' 3 | s.name = "MASPreferences" 4 | s.version = "1.4.1" 5 | s.summary = "Modern implementation of the Preferences window for OS X apps, used in TextMate, GitBox and Mou." 6 | s.homepage = "https://github.com/shpakovski/MASPreferences" 7 | s.license = { :type => 'BSD', :file => 'LICENSE.md' } 8 | s.author = { "Vadim Shpakovski" => "vadim@shpakovski.com" } 9 | s.source = { :git => 'https://github.com/shpakovski/MASPreferences.git', :tag => '1.4.1' } 10 | s.source_files = 'Framework/*.{h,m}' 11 | s.resource_bundles = { 12 | 'MASPreferences' => ['Framework/en.lproj/*.xib'] 13 | } 14 | s.exclude_files = 'README.md', 'LICENSE.md', 'MASPreferences.podspec' 15 | s.requires_arc = true 16 | end 17 | -------------------------------------------------------------------------------- /MASPreferences.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | F16AF8081BA27AFD0022155C /* MASPreferencesWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = F16AF8001BA27AFD0022155C /* MASPreferencesWindow.xib */; }; 11 | F16AF80A1BA27AFD0022155C /* MASPreferences.h in Headers */ = {isa = PBXBuildFile; fileRef = F16AF8031BA27AFD0022155C /* MASPreferences.h */; settings = {ATTRIBUTES = (Public, ); }; }; 12 | F16AF80B1BA27AFD0022155C /* MASPreferencesViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = F16AF8051BA27AFD0022155C /* MASPreferencesViewController.h */; settings = {ATTRIBUTES = (Public, ); }; }; 13 | F16AF80C1BA27AFD0022155C /* MASPreferencesWindowController.h in Headers */ = {isa = PBXBuildFile; fileRef = F16AF8061BA27AFD0022155C /* MASPreferencesWindowController.h */; settings = {ATTRIBUTES = (Public, ); }; }; 14 | F16AF80D1BA27AFD0022155C /* MASPreferencesWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = F16AF8071BA27AFD0022155C /* MASPreferencesWindowController.m */; }; 15 | /* End PBXBuildFile section */ 16 | 17 | /* Begin PBXFileReference section */ 18 | F16AF7F41BA279F10022155C /* MASPreferences.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = MASPreferences.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 19 | F16AF8011BA27AFD0022155C /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/MASPreferencesWindow.xib; sourceTree = ""; }; 20 | F16AF8021BA27AFD0022155C /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 21 | F16AF8031BA27AFD0022155C /* MASPreferences.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MASPreferences.h; sourceTree = ""; }; 22 | F16AF8041BA27AFD0022155C /* MASPreferences.modulemap */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = "sourcecode.module-map"; path = MASPreferences.modulemap; sourceTree = ""; }; 23 | F16AF8051BA27AFD0022155C /* MASPreferencesViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MASPreferencesViewController.h; sourceTree = ""; }; 24 | F16AF8061BA27AFD0022155C /* MASPreferencesWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MASPreferencesWindowController.h; sourceTree = ""; }; 25 | F16AF8071BA27AFD0022155C /* MASPreferencesWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MASPreferencesWindowController.m; sourceTree = ""; }; 26 | /* End PBXFileReference section */ 27 | 28 | /* Begin PBXFrameworksBuildPhase section */ 29 | F16AF7F01BA279F10022155C /* Frameworks */ = { 30 | isa = PBXFrameworksBuildPhase; 31 | buildActionMask = 2147483647; 32 | files = ( 33 | ); 34 | runOnlyForDeploymentPostprocessing = 0; 35 | }; 36 | /* End PBXFrameworksBuildPhase section */ 37 | 38 | /* Begin PBXGroup section */ 39 | F16AF7EA1BA279F10022155C = { 40 | isa = PBXGroup; 41 | children = ( 42 | F16AF7FF1BA27AFD0022155C /* Framework */, 43 | F16AF7F51BA279F10022155C /* Products */, 44 | ); 45 | sourceTree = ""; 46 | }; 47 | F16AF7F51BA279F10022155C /* Products */ = { 48 | isa = PBXGroup; 49 | children = ( 50 | F16AF7F41BA279F10022155C /* MASPreferences.framework */, 51 | ); 52 | name = Products; 53 | sourceTree = ""; 54 | }; 55 | F16AF7FF1BA27AFD0022155C /* Framework */ = { 56 | isa = PBXGroup; 57 | children = ( 58 | F16AF8051BA27AFD0022155C /* MASPreferencesViewController.h */, 59 | F16AF8061BA27AFD0022155C /* MASPreferencesWindowController.h */, 60 | F16AF8071BA27AFD0022155C /* MASPreferencesWindowController.m */, 61 | F16AF8001BA27AFD0022155C /* MASPreferencesWindow.xib */, 62 | F16AF8021BA27AFD0022155C /* Info.plist */, 63 | F16AF8041BA27AFD0022155C /* MASPreferences.modulemap */, 64 | F16AF8031BA27AFD0022155C /* MASPreferences.h */, 65 | ); 66 | path = Framework; 67 | sourceTree = ""; 68 | }; 69 | /* End PBXGroup section */ 70 | 71 | /* Begin PBXHeadersBuildPhase section */ 72 | F16AF7F11BA279F10022155C /* Headers */ = { 73 | isa = PBXHeadersBuildPhase; 74 | buildActionMask = 2147483647; 75 | files = ( 76 | F16AF80A1BA27AFD0022155C /* MASPreferences.h in Headers */, 77 | F16AF80C1BA27AFD0022155C /* MASPreferencesWindowController.h in Headers */, 78 | F16AF80B1BA27AFD0022155C /* MASPreferencesViewController.h in Headers */, 79 | ); 80 | runOnlyForDeploymentPostprocessing = 0; 81 | }; 82 | /* End PBXHeadersBuildPhase section */ 83 | 84 | /* Begin PBXNativeTarget section */ 85 | F16AF7F31BA279F10022155C /* MASPreferences */ = { 86 | isa = PBXNativeTarget; 87 | buildConfigurationList = F16AF7FC1BA279F10022155C /* Build configuration list for PBXNativeTarget "MASPreferences" */; 88 | buildPhases = ( 89 | F16AF7EF1BA279F10022155C /* Sources */, 90 | F16AF7F01BA279F10022155C /* Frameworks */, 91 | F16AF7F11BA279F10022155C /* Headers */, 92 | F16AF7F21BA279F10022155C /* Resources */, 93 | ); 94 | buildRules = ( 95 | ); 96 | dependencies = ( 97 | ); 98 | name = MASPreferences; 99 | productName = MASPreferences; 100 | productReference = F16AF7F41BA279F10022155C /* MASPreferences.framework */; 101 | productType = "com.apple.product-type.framework"; 102 | }; 103 | /* End PBXNativeTarget section */ 104 | 105 | /* Begin PBXProject section */ 106 | F16AF7EB1BA279F10022155C /* Project object */ = { 107 | isa = PBXProject; 108 | attributes = { 109 | LastUpgradeCheck = 0900; 110 | ORGANIZATIONNAME = "Vadim Shpakovski"; 111 | TargetAttributes = { 112 | F16AF7F31BA279F10022155C = { 113 | CreatedOnToolsVersion = 7.0; 114 | }; 115 | }; 116 | }; 117 | buildConfigurationList = F16AF7EE1BA279F10022155C /* Build configuration list for PBXProject "MASPreferences" */; 118 | compatibilityVersion = "Xcode 3.2"; 119 | developmentRegion = English; 120 | hasScannedForEncodings = 0; 121 | knownRegions = ( 122 | en, 123 | ); 124 | mainGroup = F16AF7EA1BA279F10022155C; 125 | productRefGroup = F16AF7F51BA279F10022155C /* Products */; 126 | projectDirPath = ""; 127 | projectRoot = ""; 128 | targets = ( 129 | F16AF7F31BA279F10022155C /* MASPreferences */, 130 | ); 131 | }; 132 | /* End PBXProject section */ 133 | 134 | /* Begin PBXResourcesBuildPhase section */ 135 | F16AF7F21BA279F10022155C /* Resources */ = { 136 | isa = PBXResourcesBuildPhase; 137 | buildActionMask = 2147483647; 138 | files = ( 139 | F16AF8081BA27AFD0022155C /* MASPreferencesWindow.xib in Resources */, 140 | ); 141 | runOnlyForDeploymentPostprocessing = 0; 142 | }; 143 | /* End PBXResourcesBuildPhase section */ 144 | 145 | /* Begin PBXSourcesBuildPhase section */ 146 | F16AF7EF1BA279F10022155C /* Sources */ = { 147 | isa = PBXSourcesBuildPhase; 148 | buildActionMask = 2147483647; 149 | files = ( 150 | F16AF80D1BA27AFD0022155C /* MASPreferencesWindowController.m in Sources */, 151 | ); 152 | runOnlyForDeploymentPostprocessing = 0; 153 | }; 154 | /* End PBXSourcesBuildPhase section */ 155 | 156 | /* Begin PBXVariantGroup section */ 157 | F16AF8001BA27AFD0022155C /* MASPreferencesWindow.xib */ = { 158 | isa = PBXVariantGroup; 159 | children = ( 160 | F16AF8011BA27AFD0022155C /* en */, 161 | ); 162 | name = MASPreferencesWindow.xib; 163 | sourceTree = ""; 164 | }; 165 | /* End PBXVariantGroup section */ 166 | 167 | /* Begin XCBuildConfiguration section */ 168 | F16AF7FA1BA279F10022155C /* Debug */ = { 169 | isa = XCBuildConfiguration; 170 | buildSettings = { 171 | ALWAYS_SEARCH_USER_PATHS = NO; 172 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 173 | CLANG_CXX_LIBRARY = "libc++"; 174 | CLANG_ENABLE_MODULES = YES; 175 | CLANG_ENABLE_OBJC_ARC = YES; 176 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 177 | CLANG_WARN_BOOL_CONVERSION = YES; 178 | CLANG_WARN_COMMA = YES; 179 | CLANG_WARN_CONSTANT_CONVERSION = YES; 180 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 181 | CLANG_WARN_EMPTY_BODY = YES; 182 | CLANG_WARN_ENUM_CONVERSION = YES; 183 | CLANG_WARN_INFINITE_RECURSION = YES; 184 | CLANG_WARN_INT_CONVERSION = YES; 185 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 186 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 187 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 188 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 189 | CLANG_WARN_STRICT_PROTOTYPES = YES; 190 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 191 | CLANG_WARN_UNREACHABLE_CODE = YES; 192 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 193 | COPY_PHASE_STRIP = NO; 194 | DEBUG_INFORMATION_FORMAT = dwarf; 195 | ENABLE_STRICT_OBJC_MSGSEND = YES; 196 | ENABLE_TESTABILITY = YES; 197 | GCC_C_LANGUAGE_STANDARD = gnu99; 198 | GCC_DYNAMIC_NO_PIC = NO; 199 | GCC_NO_COMMON_BLOCKS = YES; 200 | GCC_OPTIMIZATION_LEVEL = 0; 201 | GCC_PREPROCESSOR_DEFINITIONS = ( 202 | "DEBUG=1", 203 | "$(inherited)", 204 | ); 205 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 206 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 207 | GCC_WARN_UNDECLARED_SELECTOR = YES; 208 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 209 | GCC_WARN_UNUSED_FUNCTION = YES; 210 | GCC_WARN_UNUSED_VARIABLE = YES; 211 | MACOSX_DEPLOYMENT_TARGET = 10.6; 212 | MTL_ENABLE_DEBUG_INFO = YES; 213 | ONLY_ACTIVE_ARCH = YES; 214 | SDKROOT = macosx; 215 | }; 216 | name = Debug; 217 | }; 218 | F16AF7FB1BA279F10022155C /* Release */ = { 219 | isa = XCBuildConfiguration; 220 | buildSettings = { 221 | ALWAYS_SEARCH_USER_PATHS = NO; 222 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 223 | CLANG_CXX_LIBRARY = "libc++"; 224 | CLANG_ENABLE_MODULES = YES; 225 | CLANG_ENABLE_OBJC_ARC = YES; 226 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 227 | CLANG_WARN_BOOL_CONVERSION = YES; 228 | CLANG_WARN_COMMA = YES; 229 | CLANG_WARN_CONSTANT_CONVERSION = YES; 230 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 231 | CLANG_WARN_EMPTY_BODY = YES; 232 | CLANG_WARN_ENUM_CONVERSION = YES; 233 | CLANG_WARN_INFINITE_RECURSION = YES; 234 | CLANG_WARN_INT_CONVERSION = YES; 235 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 236 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 237 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 238 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 239 | CLANG_WARN_STRICT_PROTOTYPES = YES; 240 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 241 | CLANG_WARN_UNREACHABLE_CODE = YES; 242 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 243 | COPY_PHASE_STRIP = NO; 244 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 245 | ENABLE_NS_ASSERTIONS = NO; 246 | ENABLE_STRICT_OBJC_MSGSEND = YES; 247 | GCC_C_LANGUAGE_STANDARD = gnu99; 248 | GCC_NO_COMMON_BLOCKS = YES; 249 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 250 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 251 | GCC_WARN_UNDECLARED_SELECTOR = YES; 252 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 253 | GCC_WARN_UNUSED_FUNCTION = YES; 254 | GCC_WARN_UNUSED_VARIABLE = YES; 255 | MACOSX_DEPLOYMENT_TARGET = 10.6; 256 | MTL_ENABLE_DEBUG_INFO = NO; 257 | SDKROOT = macosx; 258 | }; 259 | name = Release; 260 | }; 261 | F16AF7FD1BA279F10022155C /* Debug */ = { 262 | isa = XCBuildConfiguration; 263 | buildSettings = { 264 | COMBINE_HIDPI_IMAGES = YES; 265 | DEFINES_MODULE = YES; 266 | DYLIB_COMPATIBILITY_VERSION = 1; 267 | DYLIB_CURRENT_VERSION = 1; 268 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 269 | FRAMEWORK_VERSION = A; 270 | INFOPLIST_FILE = Framework/Info.plist; 271 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 272 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; 273 | MODULEMAP_FILE = Framework/MASPreferences.modulemap; 274 | PRODUCT_BUNDLE_IDENTIFIER = com.github.shpakovski.MASPreferences; 275 | PRODUCT_NAME = "$(TARGET_NAME)"; 276 | SKIP_INSTALL = YES; 277 | }; 278 | name = Debug; 279 | }; 280 | F16AF7FE1BA279F10022155C /* Release */ = { 281 | isa = XCBuildConfiguration; 282 | buildSettings = { 283 | COMBINE_HIDPI_IMAGES = YES; 284 | DEFINES_MODULE = YES; 285 | DYLIB_COMPATIBILITY_VERSION = 1; 286 | DYLIB_CURRENT_VERSION = 1; 287 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 288 | FRAMEWORK_VERSION = A; 289 | INFOPLIST_FILE = Framework/Info.plist; 290 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 291 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; 292 | MODULEMAP_FILE = Framework/MASPreferences.modulemap; 293 | PRODUCT_BUNDLE_IDENTIFIER = com.github.shpakovski.MASPreferences; 294 | PRODUCT_NAME = "$(TARGET_NAME)"; 295 | SKIP_INSTALL = YES; 296 | }; 297 | name = Release; 298 | }; 299 | /* End XCBuildConfiguration section */ 300 | 301 | /* Begin XCConfigurationList section */ 302 | F16AF7EE1BA279F10022155C /* Build configuration list for PBXProject "MASPreferences" */ = { 303 | isa = XCConfigurationList; 304 | buildConfigurations = ( 305 | F16AF7FA1BA279F10022155C /* Debug */, 306 | F16AF7FB1BA279F10022155C /* Release */, 307 | ); 308 | defaultConfigurationIsVisible = 0; 309 | defaultConfigurationName = Release; 310 | }; 311 | F16AF7FC1BA279F10022155C /* Build configuration list for PBXNativeTarget "MASPreferences" */ = { 312 | isa = XCConfigurationList; 313 | buildConfigurations = ( 314 | F16AF7FD1BA279F10022155C /* Debug */, 315 | F16AF7FE1BA279F10022155C /* Release */, 316 | ); 317 | defaultConfigurationIsVisible = 0; 318 | defaultConfigurationName = Release; 319 | }; 320 | /* End XCConfigurationList section */ 321 | }; 322 | rootObject = F16AF7EB1BA279F10022155C /* Project object */; 323 | } 324 | -------------------------------------------------------------------------------- /MASPreferences.xcodeproj/xcshareddata/xcschemes/MASPreferences.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 33 | 34 | 35 | 36 | 47 | 48 | 54 | 55 | 56 | 57 | 58 | 59 | 65 | 66 | 72 | 73 | 74 | 75 | 77 | 78 | 81 | 82 | 83 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:5.3 2 | import PackageDescription 3 | 4 | let package = Package( 5 | name: "MASPreferences", 6 | defaultLocalization: "en", 7 | platforms: [ 8 | .macOS(.v10_10), 9 | ], 10 | products: [ 11 | .library(name: "MASPreferences", 12 | targets: ["MASPreferences"]) 13 | ], 14 | targets: [ 15 | .target( 16 | name: "MASPreferences", 17 | path: "./Framework", 18 | exclude: [ 19 | "Info.plist", 20 | "MASPreferences.modulemap", 21 | ], 22 | resources: [], 23 | publicHeadersPath: "./Headers" 24 | ) 25 | ] 26 | ) 27 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MASPreferences 2 | 3 | This component is intended as a replacement for SS_PrefsController by Matt Legend Gemmell and Selectable Toolbar by Brandon Walkin. It is designed to use NSViewController subclasses for preference panes. 4 | 5 | # How to use 6 | 7 | You can find a Demo project at [MASPreferencesDemo](https://github.com/shpakovski/MASPreferencesDemo). 8 | 9 | # Install 10 | 11 | #### [Carthage](https://github.com/Carthage/Carthage) 12 | 13 | - Add `github "shpakovski/MASPreferences"` to your Cartfile. 14 | 15 | #### [CocoaPods](https://github.com/cocoapods/cocoapods) 16 | 17 | - Add `pod 'MASPreferences'` to your Podfile. 18 | 19 | #### [Swift Package Manager](https://www.swift.org/package-manager/) 20 | 21 | - Add `.package(url: "https://github.com/shpakovski/MASPreferences.git", .upToNextMajor(from: "1.4.1"))` to your Package.swift. 22 | --------------------------------------------------------------------------------