├── .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 |
13 |
20 |
24 |
28 |
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 |
--------------------------------------------------------------------------------