mirror of
https://github.com/ksherlock/ample.git
synced 2026-04-23 19:19:24 +00:00
Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f628d99e4a | |||
| 0b248e6aad | |||
| 94aac38af4 | |||
| 6215a0df12 | |||
| d348c15dc5 | |||
| e14336a009 | |||
| 4baf545245 | |||
| 0f3e6c8307 | |||
| 8fdb149eb3 | |||
| 787eac87f6 |
@@ -64,6 +64,8 @@
|
||||
B6152B5B25F5B57E00605E6E /* Media.m in Sources */ = {isa = PBXBuildFile; fileRef = B6152B5925F5B57E00605E6E /* Media.m */; };
|
||||
B615A99F26640940001FBF99 /* SlotView.xib in Resources */ = {isa = PBXBuildFile; fileRef = B6E9A18125088B36005E7525 /* SlotView.xib */; };
|
||||
B615A9A026640A70001FBF99 /* SlotViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = B6E9A17F25088B1B005E7525 /* SlotViewController.m */; };
|
||||
B63005332666D6940014C381 /* BookmarkManager.m in Sources */ = {isa = PBXBuildFile; fileRef = B63005322666D6940014C381 /* BookmarkManager.m */; };
|
||||
B63005342666D6940014C381 /* BookmarkManager.m in Sources */ = {isa = PBXBuildFile; fileRef = B63005322666D6940014C381 /* BookmarkManager.m */; };
|
||||
B6374AC4260EBBCF0045CA16 /* pty_shell.c in Sources */ = {isa = PBXBuildFile; fileRef = B6374AB6260EBB970045CA16 /* pty_shell.c */; };
|
||||
B6374AC5260EBC5A0045CA16 /* pty_shell in CopyFiles */ = {isa = PBXBuildFile; fileRef = B6374ABD260EBBC90045CA16 /* pty_shell */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
|
||||
B6374AD1260ECB400045CA16 /* macclas2.plist in Resources */ = {isa = PBXBuildFile; fileRef = B6374AC9260ECB3F0045CA16 /* macclas2.plist */; };
|
||||
@@ -375,6 +377,8 @@
|
||||
B6152B5525F4549F00605E6E /* Slot.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Slot.m; sourceTree = "<group>"; };
|
||||
B6152B5825F5B4F100605E6E /* Media.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Media.h; sourceTree = "<group>"; };
|
||||
B6152B5925F5B57E00605E6E /* Media.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Media.m; sourceTree = "<group>"; };
|
||||
B63005312666D6940014C381 /* BookmarkManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BookmarkManager.h; sourceTree = "<group>"; };
|
||||
B63005322666D6940014C381 /* BookmarkManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = BookmarkManager.m; sourceTree = "<group>"; };
|
||||
B6374AB6260EBB970045CA16 /* pty_shell.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = pty_shell.c; sourceTree = "<group>"; };
|
||||
B6374ABD260EBBC90045CA16 /* pty_shell */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = pty_shell; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
B6374AC9260ECB3F0045CA16 /* macclas2.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = macclas2.plist; sourceTree = "<group>"; };
|
||||
@@ -690,6 +694,8 @@
|
||||
B608E17E2502FE0C00D53465 /* TransparentScroller.m */,
|
||||
B66D0FE62611386B000902F1 /* SoftwareList.m */,
|
||||
B66D0FE926113AA8000902F1 /* SoftwareList.h */,
|
||||
B63005312666D6940014C381 /* BookmarkManager.h */,
|
||||
B63005322666D6940014C381 /* BookmarkManager.m */,
|
||||
B6BA563A251685DA00B0C47D /* Window Controllers */,
|
||||
B6B9EA652506A5550080E70D /* EjectButton.h */,
|
||||
B6B9EA642506A5550080E70D /* EjectButton.m */,
|
||||
@@ -1154,6 +1160,7 @@
|
||||
B60A6E1424EE0AE2004B7EEF /* FlippedView.m in Sources */,
|
||||
B6BA258024E99BE9005FB8FF /* AppDelegate.m in Sources */,
|
||||
B6004DF024FB05D600D38596 /* LogWindowController.m in Sources */,
|
||||
B63005332666D6940014C381 /* BookmarkManager.m in Sources */,
|
||||
B66236A924FD9A34006CABD7 /* PreferencesWindowController.m in Sources */,
|
||||
B63C1F0F25B1447C0016A611 /* CheatSheetWindowController.m in Sources */,
|
||||
B64AF1F2250ECB2E00A09B9B /* DiskImagesWindowController.m in Sources */,
|
||||
@@ -1183,6 +1190,7 @@
|
||||
B6E4B5B324FDE2670094A35C /* MediaViewController.m in Sources */,
|
||||
B64AF1F7250ED5E400A09B9B /* TableCellView.m in Sources */,
|
||||
B6E4B5B424FDE2670094A35C /* FlippedView.m in Sources */,
|
||||
B63005342666D6940014C381 /* BookmarkManager.m in Sources */,
|
||||
B615A9A026640A70001FBF99 /* SlotViewController.m in Sources */,
|
||||
B6665C15265A0E3E00254939 /* AutocompleteControl.m in Sources */,
|
||||
B6E4B5B524FDE2670094A35C /* AppDelegate.m in Sources */,
|
||||
|
||||
@@ -40,4 +40,13 @@ extern NSString *kDownloadExtension;
|
||||
extern NSString *kDefaultDownloadURL;
|
||||
extern NSString *kDefaultDownloadExtension;
|
||||
|
||||
|
||||
@protocol Bookmark <NSObject>
|
||||
-(BOOL)loadBookmark: (NSDictionary *)bookmark;
|
||||
-(BOOL)saveBookmark: (NSMutableDictionary *)bookmark;
|
||||
|
||||
-(void)willLoadBookmark: (NSDictionary *)bookmark;
|
||||
-(void)didLoadBookmark: (NSDictionary *)bookmark;
|
||||
@end
|
||||
|
||||
#endif /* Ample_h */
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#import "DiskImagesWindowController.h"
|
||||
#import "CheatSheetWindowController.h"
|
||||
#import "Transformers.h"
|
||||
#import "BookmarkManager.h"
|
||||
|
||||
#import "LogWindowController.h"
|
||||
|
||||
@@ -40,6 +41,10 @@
|
||||
|
||||
RegisterTransformers();
|
||||
|
||||
BookmarkManager *bm = [BookmarkManager sharedManager];
|
||||
[bm loadBookmarks];
|
||||
[bm updateMenu];
|
||||
|
||||
path = [bundle pathForResource: @"Defaults" ofType: @"plist"];
|
||||
dict = [NSDictionary dictionaryWithContentsOfFile: path];
|
||||
|
||||
|
||||
@@ -96,7 +96,7 @@ Todo --
|
||||
}
|
||||
|
||||
-(void)setStringValue:(NSString *)stringValue {
|
||||
[super setStringValue: stringValue];
|
||||
[super setStringValue: stringValue ? stringValue : @""];
|
||||
if (_value && [[_value menuTitle] isEqualToString: stringValue] == NO)
|
||||
_value = nil;
|
||||
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
<objects>
|
||||
<customObject id="-2" userLabel="File's Owner" customClass="LaunchWindowController">
|
||||
<connections>
|
||||
<outlet property="addBookmarkWindow" destination="yIt-hP-HBq" id="Qhx-WV-cg4"/>
|
||||
<outlet property="bookmarkTextField" destination="fAl-Vn-x1w" id="GNr-j6-BiQ"/>
|
||||
<outlet property="machineView" destination="oVt-eD-aaj" id="Q9V-Kr-6GN"/>
|
||||
<outlet property="machineViewController" destination="RgH-d9-xl8" id="DIa-h0-6y2"/>
|
||||
<outlet property="mediaController" destination="t7c-zy-czN" id="a7d-HC-TWx"/>
|
||||
@@ -123,7 +125,7 @@ DQ
|
||||
</connections>
|
||||
</button>
|
||||
<popUpButton verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="hM8-FM-Agh">
|
||||
<rect key="frame" x="382" y="87" width="172" height="25"/>
|
||||
<rect key="frame" x="382" y="87" width="174" height="25"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<popUpButtonCell key="cell" type="push" title="Default" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" selectedItem="Dsm-bi-Txy" id="mBS-h4-BWC">
|
||||
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
|
||||
@@ -239,7 +241,7 @@ DQ
|
||||
</button>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="PGK-yK-2ZK">
|
||||
<rect key="frame" x="15" y="91" width="43" height="16"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" lineBreakMode="clipping" title="Speed" id="D9w-Mz-PXs">
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
@@ -247,7 +249,7 @@ DQ
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<popUpButton verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="FE4-gG-fPb">
|
||||
<rect key="frame" x="62" y="86" width="107" height="25"/>
|
||||
<rect key="frame" x="62" y="86" width="109" height="25"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<popUpButtonCell key="cell" type="push" title="100%" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="borderAndBezel" tag="1" imageScaling="proportionallyDown" inset="2" selectedItem="yoI-Ra-evu" id="M40-f0-awc">
|
||||
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
|
||||
@@ -487,6 +489,78 @@ DQ
|
||||
<viewController title="Media View" nibName="MediaView" id="t7c-zy-czN" customClass="MediaViewController"/>
|
||||
<viewController title="Slot View" nibName="SlotView" id="lyS-mc-3Tf" customClass="SlotViewController"/>
|
||||
<customObject id="RgH-d9-xl8" customClass="MachineViewController"/>
|
||||
<window title="Add Bookmark" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" restorable="NO" releasedWhenClosed="NO" visibleAtLaunch="NO" animationBehavior="default" id="yIt-hP-HBq">
|
||||
<windowStyleMask key="styleMask" titled="YES"/>
|
||||
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
|
||||
<rect key="contentRect" x="196" y="240" width="462" height="116"/>
|
||||
<rect key="screenRect" x="0.0" y="0.0" width="2560" height="1417"/>
|
||||
<view key="contentView" wantsLayer="YES" id="WVd-g4-Tbl">
|
||||
<rect key="frame" x="0.0" y="0.0" width="462" height="116"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Gho-Xy-rn4">
|
||||
<rect key="frame" x="358" y="13" width="90" height="32"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMinY="YES"/>
|
||||
<buttonCell key="cell" type="push" title="Add" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="Vxo-rD-aMe">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
<string key="keyEquivalent" base64-UTF8="YES">
|
||||
DQ
|
||||
</string>
|
||||
</buttonCell>
|
||||
<connections>
|
||||
<action selector="bookmarkSave:" target="-2" id="wLF-LE-5RO"/>
|
||||
<binding destination="-2" name="enabled" keyPath="bookmarkName" id="U5R-gU-1bE">
|
||||
<dictionary key="options">
|
||||
<string key="NSValueTransformerName">StringNotEmptyTransformer</string>
|
||||
</dictionary>
|
||||
</binding>
|
||||
</connections>
|
||||
</button>
|
||||
<button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="3sv-Kd-Ep5">
|
||||
<rect key="frame" x="268" y="13" width="90" height="32"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMinY="YES"/>
|
||||
<buttonCell key="cell" type="push" title="Cancel" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="jaa-RY-PAg">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
<string key="keyEquivalent" base64-UTF8="YES">
|
||||
Gw
|
||||
</string>
|
||||
</buttonCell>
|
||||
<connections>
|
||||
<action selector="bookmarkCancel:" target="-2" id="uWM-vs-hz7"/>
|
||||
</connections>
|
||||
</button>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="1fO-x7-Gft">
|
||||
<rect key="frame" x="18" y="80" width="103" height="16"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" lineBreakMode="clipping" title="Add Bookmark…" id="AZS-JR-SNt">
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<textField verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="fAl-Vn-x1w">
|
||||
<rect key="frame" x="20" y="49" width="422" height="23"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" borderStyle="bezel" placeholderString="bookmark name" drawsBackground="YES" id="Enq-2z-cle">
|
||||
<font key="font" usesAppearanceFont="YES"/>
|
||||
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
<connections>
|
||||
<binding destination="-2" name="value" keyPath="bookmarkName" id="84v-el-4Uk">
|
||||
<dictionary key="options">
|
||||
<bool key="NSContinuouslyUpdatesValue" value="YES"/>
|
||||
<string key="NSNullPlaceholder">bookmark name</string>
|
||||
</dictionary>
|
||||
</binding>
|
||||
</connections>
|
||||
</textField>
|
||||
</subviews>
|
||||
</view>
|
||||
<point key="canvasLocation" x="130" y="70"/>
|
||||
</window>
|
||||
</objects>
|
||||
<resources>
|
||||
<image name="NSAppleMenuImage" width="11" height="14"/>
|
||||
|
||||
@@ -19,6 +19,11 @@
|
||||
</connections>
|
||||
</customObject>
|
||||
<customObject id="YLy-65-1bz" customClass="NSFontManager"/>
|
||||
<customObject id="sJn-ug-xF3" customClass="BookmarkManager">
|
||||
<connections>
|
||||
<outlet property="menu" destination="ha0-nx-PIl" id="vTa-TU-DS1"/>
|
||||
</connections>
|
||||
</customObject>
|
||||
<menu title="Main Menu" systemMenu="main" id="AYu-sK-qS6">
|
||||
<items>
|
||||
<menuItem title="Ample" id="1Xt-HY-uBw">
|
||||
@@ -389,6 +394,22 @@
|
||||
</items>
|
||||
</menu>
|
||||
</menuItem>
|
||||
<menuItem title="Bookmarks" id="vHO-2e-qJc">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<menu key="submenu" title="Bookmarks" id="ha0-nx-PIl">
|
||||
<items>
|
||||
<menuItem title="Add Bookmark…" keyEquivalent="d" id="1JF-xV-zmG">
|
||||
<connections>
|
||||
<action selector="addBookmark:" target="-1" id="cqp-ko-BfQ"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Manage Bookmarks…" id="isI-q6-b1V">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
</menuItem>
|
||||
<menuItem isSeparatorItem="YES" id="gWR-Yl-mg6"/>
|
||||
</items>
|
||||
</menu>
|
||||
</menuItem>
|
||||
<menuItem title="Window" id="aUF-d1-5bR">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<menu key="submenu" title="Window" systemMenu="window" id="Td7-aD-5lo">
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
//
|
||||
// BookmarkManager.h
|
||||
// Ample
|
||||
//
|
||||
// Created by Kelvin Sherlock on 6/1/2021.
|
||||
// Copyright © 2021 Kelvin Sherlock. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@class NSMenu;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface BookmarkManager : NSObject
|
||||
|
||||
@property (weak) IBOutlet NSMenu *menu;
|
||||
|
||||
+(instancetype)sharedManager;
|
||||
|
||||
-(void)loadBookmarks;
|
||||
-(void)updateMenu;
|
||||
|
||||
-(BOOL)validateName: (NSString *)name;
|
||||
|
||||
-(BOOL)saveBookmark: (NSDictionary *)bookmark name: (NSString *)name;
|
||||
-(NSDictionary *)loadBookmarkFromURL: (NSURL *)url;
|
||||
|
||||
-(BOOL)saveDefault: (NSDictionary *)bookmark;
|
||||
-(NSDictionary *)loadDefault;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,214 @@
|
||||
//
|
||||
// BookmarkManager.m
|
||||
// Ample
|
||||
//
|
||||
// Created by Kelvin Sherlock on 6/1/2021.
|
||||
// Copyright © 2021 Kelvin Sherlock. All rights reserved.
|
||||
//
|
||||
|
||||
#import "BookmarkManager.h"
|
||||
#import "Ample.h"
|
||||
|
||||
@interface BookmarkManager () {
|
||||
NSArray<NSURL *> *_urls;
|
||||
NSURL *_bookmarkDirectory;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation BookmarkManager
|
||||
|
||||
static BookmarkManager *singleton = nil;
|
||||
|
||||
-(void)awakeFromNib {
|
||||
if (!singleton) singleton = self;
|
||||
}
|
||||
|
||||
+(instancetype)sharedManager {
|
||||
if (!singleton) singleton = [BookmarkManager new];
|
||||
return singleton;
|
||||
}
|
||||
|
||||
-(instancetype)init {
|
||||
if (singleton) return singleton;
|
||||
return [super init];
|
||||
}
|
||||
|
||||
-(NSURL *)bookmarkDirectory {
|
||||
|
||||
if (_bookmarkDirectory) return _bookmarkDirectory;
|
||||
NSFileManager *fm = [NSFileManager defaultManager];
|
||||
|
||||
NSURL *url = SupportDirectory();
|
||||
url = [url URLByAppendingPathComponent: @"Bookmarks"];
|
||||
NSError *error = nil;
|
||||
[fm createDirectoryAtURL: url withIntermediateDirectories: YES attributes: nil error: &error];
|
||||
if (error) NSLog(@"%@", error);
|
||||
_bookmarkDirectory = url;
|
||||
return url;
|
||||
}
|
||||
|
||||
/* disallow leading .
|
||||
* disallow : or / characters.
|
||||
*/
|
||||
-(BOOL)validateName: (NSString *)name {
|
||||
|
||||
enum { kMaxLength = 128 };
|
||||
unichar buffer[kMaxLength];
|
||||
NSUInteger length = [name length];
|
||||
if (length == 0 || length > kMaxLength) return NO;
|
||||
[name getCharacters: buffer range: NSMakeRange(0, length)];
|
||||
if (buffer[0] == '.') return NO;
|
||||
for (unsigned i = 0; i < length; ++i) {
|
||||
unichar c = buffer[i];
|
||||
if (c == ':' || c == '/') return NO;
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
|
||||
-(NSDictionary *)loadDefault {
|
||||
NSURL *url = [self bookmarkDirectory];
|
||||
url = [url URLByAppendingPathComponent: @".Default"];
|
||||
|
||||
NSDictionary *d;
|
||||
|
||||
if (@available(macOS 10.13, *)) {
|
||||
NSError *error = nil;
|
||||
d = [NSDictionary dictionaryWithContentsOfURL: url error: &error];
|
||||
if (!d) NSLog(@"Error loading %@: %@", url, error);
|
||||
} else {
|
||||
d = [NSDictionary dictionaryWithContentsOfURL: url];
|
||||
if (!d) NSLog(@"Error loading %@", url);
|
||||
}
|
||||
return d;
|
||||
}
|
||||
|
||||
/* save as .Default */
|
||||
-(BOOL)saveDefault: (NSDictionary *)bookmark {
|
||||
|
||||
NSURL *url = [self bookmarkDirectory];
|
||||
url = [url URLByAppendingPathComponent: @".Default"];
|
||||
|
||||
NSError *error = nil;
|
||||
BOOL ok = NO;
|
||||
if (@available(macOS 10.13, *)) {
|
||||
ok = [bookmark writeToURL: url error: &error];
|
||||
if (!ok) NSLog(@"%@", error);
|
||||
} else {
|
||||
ok = [bookmark writeToURL: url atomically: YES];
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
-(BOOL)saveBookmark: (NSDictionary *)bookmark name: (NSString *)name {
|
||||
|
||||
NSError *error;
|
||||
NSData *data = [NSPropertyListSerialization dataWithPropertyList: bookmark
|
||||
format: NSPropertyListXMLFormat_v1_0
|
||||
options: 0
|
||||
error: &error];
|
||||
|
||||
|
||||
|
||||
NSURL *base = [self bookmarkDirectory];
|
||||
|
||||
NSURL *url = [base URLByAppendingPathComponent: name];
|
||||
|
||||
BOOL ok = [data writeToURL: url options: NSDataWritingWithoutOverwriting error: &error];
|
||||
|
||||
if (!ok) {
|
||||
for (unsigned i = 1 ; i < 100; ++i) {
|
||||
NSString *tmp = [name stringByAppendingFormat: @"(%d)", i];
|
||||
[base URLByAppendingPathComponent: tmp];
|
||||
|
||||
ok = [data writeToURL: url options: NSDataWritingWithoutOverwriting error: &error];
|
||||
if (ok) {
|
||||
name = tmp;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!ok) return NO;
|
||||
|
||||
if (!_menu) return YES; // ?
|
||||
|
||||
NSUInteger ix = [_urls indexOfObjectPassingTest: ^BOOL(NSURL *object, NSUInteger index, BOOL *stop){
|
||||
NSString *path = [object lastPathComponent];
|
||||
return [name caseInsensitiveCompare: path] == NSOrderedAscending;
|
||||
}];
|
||||
|
||||
NSMenuItem *item = [[NSMenuItem alloc] initWithTitle: name action: @selector(loadBookmark:) keyEquivalent: @""];
|
||||
[item setRepresentedObject: url];
|
||||
|
||||
if (ix == NSNotFound) {
|
||||
_urls = [_urls arrayByAddingObject: url];
|
||||
[_menu addItem: item];
|
||||
} else {
|
||||
|
||||
NSInteger n = [_menu numberOfItems];
|
||||
[_menu insertItem: item atIndex: n - [_urls count] + ix];
|
||||
NSMutableArray *tmp = [_urls mutableCopy];
|
||||
|
||||
[tmp insertObject: url atIndex: ix];
|
||||
}
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
-(NSDictionary *)loadBookmarkFromURL: (NSURL *)url {
|
||||
|
||||
NSDictionary *d;
|
||||
|
||||
if (@available(macOS 10.13, *)) {
|
||||
NSError *error = nil;
|
||||
d = [NSDictionary dictionaryWithContentsOfURL: url error: &error];
|
||||
if (!d) NSLog(@"Error loading %@: %@", url, error);
|
||||
} else {
|
||||
d = [NSDictionary dictionaryWithContentsOfURL: url];
|
||||
if (!d) NSLog(@"Error loading %@", url);
|
||||
}
|
||||
return d;
|
||||
}
|
||||
|
||||
|
||||
-(void)loadBookmarks {
|
||||
|
||||
NSURL *url = [self bookmarkDirectory];
|
||||
|
||||
NSFileManager *fm = [NSFileManager defaultManager];
|
||||
|
||||
NSError *error = nil;
|
||||
|
||||
NSArray *files = [fm contentsOfDirectoryAtURL: url
|
||||
includingPropertiesForKeys: nil
|
||||
options: NSDirectoryEnumerationSkipsHiddenFiles
|
||||
error: &error];
|
||||
|
||||
// bleh, has to create 2 new NSStrings for every comparison
|
||||
files = [files sortedArrayUsingComparator: ^(NSURL *a, NSURL *b){
|
||||
NSString *aa = [a lastPathComponent];
|
||||
NSString *bb = [b lastPathComponent];
|
||||
return [aa caseInsensitiveCompare: bb];
|
||||
}];
|
||||
|
||||
|
||||
_urls = files;
|
||||
}
|
||||
|
||||
-(void)updateMenu {
|
||||
|
||||
NSArray *menus = [_menu itemArray];
|
||||
for (NSMenuItem *item in [menus reverseObjectEnumerator]) {
|
||||
if ([item tag] == 0xdeadbeef) [_menu removeItem: item];
|
||||
}
|
||||
for (NSURL *url in _urls) {
|
||||
NSString *title = [url lastPathComponent]; // [[url lastPathComponent] stringByDeletingPathExtension];
|
||||
|
||||
NSMenuItem *item = [_menu addItemWithTitle: title action: @selector(loadBookmark:) keyEquivalent: @""];
|
||||
[item setRepresentedObject: url];
|
||||
[item setTag: 0xdeadbeef];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
+182
-20
@@ -15,6 +15,7 @@
|
||||
|
||||
#import "AutocompleteControl.h"
|
||||
#import "SoftwareList.h"
|
||||
#import "BookmarkManager.h"
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <wctype.h>
|
||||
@@ -23,7 +24,9 @@ static NSString *kMyContext = @"kMyContext";
|
||||
static NSString *kContextMachine = @"kContextMachine";
|
||||
|
||||
|
||||
@interface LaunchWindowController ()
|
||||
@interface LaunchWindowController () {
|
||||
BOOL _loadingBookmark;
|
||||
}
|
||||
@property (strong) IBOutlet MediaViewController *mediaController;
|
||||
@property (strong) IBOutlet SlotViewController *slotController;
|
||||
@property (strong) IBOutlet MachineViewController *machineViewController;
|
||||
@@ -41,6 +44,7 @@ static NSString *kContextMachine = @"kContextMachine";
|
||||
@property BOOL mameSquarePixels;
|
||||
@property BOOL mameMouse;
|
||||
@property BOOL mameSamples;
|
||||
@property BOOL mameBGFX;
|
||||
|
||||
@property BOOL mameAVI;
|
||||
@property BOOL mameWAV;
|
||||
@@ -54,7 +58,6 @@ static NSString *kContextMachine = @"kContextMachine";
|
||||
|
||||
@property NSInteger mameSpeed;
|
||||
|
||||
@property BOOL mameBGFX;
|
||||
@property NSInteger mameBackend;
|
||||
@property NSInteger mameEffects;
|
||||
|
||||
@@ -64,6 +67,12 @@ static NSString *kContextMachine = @"kContextMachine";
|
||||
@property (weak) IBOutlet AutocompleteControl *softwareListControl;
|
||||
@property SoftwareSet *softwareSet;
|
||||
@property Software *software;
|
||||
|
||||
|
||||
|
||||
@property (strong) IBOutlet NSWindow *addBookmarkWindow;
|
||||
@property (strong) NSString *bookmarkName;
|
||||
@property (weak) IBOutlet NSTextField *bookmarkTextField;
|
||||
@end
|
||||
|
||||
@interface LaunchWindowController (SoftwareList)
|
||||
@@ -72,6 +81,30 @@ static NSString *kContextMachine = @"kContextMachine";
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@interface LaunchWindowController (Bookmark)
|
||||
|
||||
-(IBAction)addBookmark:(id)sender;
|
||||
|
||||
@end
|
||||
|
||||
static NSString *BackendStrings[] = {
|
||||
@"",
|
||||
@"metal",
|
||||
@"opengl",
|
||||
};
|
||||
|
||||
static NSString *EffectsStrings[] = {
|
||||
@"-",
|
||||
@"unfiltered",
|
||||
@"hlsl",
|
||||
@"crt-geom",
|
||||
@"crt-geom-deluxe",
|
||||
@"lcd-grid",
|
||||
};
|
||||
|
||||
|
||||
|
||||
@implementation LaunchWindowController
|
||||
|
||||
-(NSString *)windowNibName {
|
||||
@@ -97,7 +130,8 @@ static NSString *kContextMachine = @"kContextMachine";
|
||||
|
||||
|
||||
NSArray *keys = @[
|
||||
@"mameMachine", @"mameSquarePixels", @"mameWindowMode",
|
||||
//@"mameMachine", // - handled
|
||||
@"mameSquarePixels", @"mameWindowMode",
|
||||
@"mameMouse", @"mameSamples",
|
||||
@"mameDebug",
|
||||
@"mameSpeed",
|
||||
@@ -132,8 +166,11 @@ static NSString *kContextMachine = @"kContextMachine";
|
||||
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
|
||||
|
||||
if (context == (__bridge void *)kMyContext) {
|
||||
if (_loadingBookmark) return;
|
||||
[self buildCommandLine];
|
||||
} else if (context == (__bridge void *)kContextMachine) {
|
||||
if (_loadingBookmark) return;
|
||||
|
||||
NSString *machine = [_machineViewController machine];
|
||||
[self setMameMachine: machine];
|
||||
[_slotController setMachine: machine];
|
||||
@@ -298,7 +335,6 @@ static NSString *ShellQuote(NSString *s) {
|
||||
[argv addObject: _mameMachine];
|
||||
|
||||
if (_software) {
|
||||
// todo -- need to include source as well.
|
||||
NSString *name = [_software name];
|
||||
if (![_softwareSet nameIsUnique: name])
|
||||
name = [_software fullName];
|
||||
@@ -365,25 +401,12 @@ static NSString *ShellQuote(NSString *s) {
|
||||
|
||||
if (_mameBGFX) {
|
||||
if (_mameBackend) {
|
||||
static NSString *Names[] = {
|
||||
@"-",
|
||||
@"metal",
|
||||
@"opengl",
|
||||
};
|
||||
[argv addObject: @"-bgfx_backend"];
|
||||
[argv addObject: Names[_mameBackend]];
|
||||
[argv addObject: BackendStrings[_mameBackend]];
|
||||
}
|
||||
if (_mameEffects) {
|
||||
static NSString *Names[] = {
|
||||
@"-",
|
||||
@"unfiltered",
|
||||
@"hlsl",
|
||||
@"crt-geom",
|
||||
@"crt-geom-deluxe",
|
||||
@"lcd-grid",
|
||||
};
|
||||
[argv addObject: @"-bgfx_screen_chains"];
|
||||
[argv addObject: Names[_mameEffects]];
|
||||
[argv addObject: EffectsStrings[_mameEffects]];
|
||||
}
|
||||
|
||||
} else {
|
||||
@@ -453,7 +476,12 @@ static NSString *ShellQuote(NSString *s) {
|
||||
if (cmd == @selector(exportShellScript:)) {
|
||||
return [_args count] ? YES : NO;
|
||||
}
|
||||
return [super validateMenuItem: menuItem];
|
||||
if (cmd == @selector(addBookmark:)) {
|
||||
return _mameMachine ? YES : NO;
|
||||
}
|
||||
|
||||
return YES;
|
||||
//return [super validateMenuItem: menuItem]; // not implemented?
|
||||
}
|
||||
|
||||
# pragma mark - IBActions
|
||||
@@ -541,3 +569,137 @@ static NSString *ShellQuote(NSString *s) {
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation LaunchWindowController (Bookmark)
|
||||
|
||||
-(IBAction)addBookmark:(id)sender {
|
||||
|
||||
if (!_mameMachine) return;
|
||||
|
||||
NSString *name = _mameMachine;
|
||||
if (_software) {
|
||||
name = [name stringByAppendingFormat: @" - %@", [_software title]];
|
||||
}
|
||||
[self setBookmarkName: name];
|
||||
[_bookmarkTextField selectText: nil];
|
||||
[[self window] beginSheet: _addBookmarkWindow completionHandler: nil];
|
||||
}
|
||||
|
||||
-(IBAction)bookmarkCancel:(id)sender {
|
||||
[[self window] endSheet: _addBookmarkWindow];
|
||||
[_addBookmarkWindow orderOut: nil];
|
||||
}
|
||||
|
||||
-(IBAction)bookmarkSave:(id)sender {
|
||||
|
||||
|
||||
BookmarkManager *bm = [BookmarkManager sharedManager];
|
||||
|
||||
if (![bm validateName: _bookmarkName]) {
|
||||
[_bookmarkTextField selectText: nil];
|
||||
NSBeep();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
//NSLog(@"%@", _bookmarkName);
|
||||
NSDictionary *d = [self makeBookmark];
|
||||
//NSLog(@"%@", d);
|
||||
|
||||
[bm saveBookmark: d name: _bookmarkName];
|
||||
|
||||
[[self window] endSheet: _addBookmarkWindow];
|
||||
[_addBookmarkWindow orderOut: nil];
|
||||
[self setBookmarkName: nil];
|
||||
}
|
||||
|
||||
|
||||
-(IBAction)loadBookmark:(id)sender {
|
||||
NSURL *url = [sender representedObject];
|
||||
if (!url) return;
|
||||
|
||||
NSDictionary *d = [NSDictionary dictionaryWithContentsOfURL: url];
|
||||
if (!d) return; // oops...
|
||||
|
||||
NSString *machine = [d objectForKey: @"machine"];
|
||||
if (!machine) return;
|
||||
|
||||
_loadingBookmark = YES;
|
||||
[_machineViewController willLoadBookmark: d];
|
||||
[_slotController willLoadBookmark: d];
|
||||
[_mediaController willLoadBookmark: d];
|
||||
|
||||
|
||||
[self setMameMachine: machine];
|
||||
[self updateSoftwareList];
|
||||
[_softwareListControl setStringValue: [d objectForKey: @"software"]];
|
||||
|
||||
[_machineViewController loadBookmark: d];
|
||||
[_slotController loadBookmark: d];
|
||||
[_mediaController loadBookmark: d];
|
||||
|
||||
[_machineViewController didLoadBookmark: d];
|
||||
[_slotController didLoadBookmark: d];
|
||||
[_mediaController didLoadBookmark: d];
|
||||
|
||||
_loadingBookmark = NO;
|
||||
|
||||
[self buildCommandLine];
|
||||
}
|
||||
|
||||
-(NSDictionary *)makeBookmark {
|
||||
|
||||
[[self window] makeFirstResponder: nil];
|
||||
|
||||
NSMutableDictionary *dict = [NSMutableDictionary new];
|
||||
|
||||
[dict setObject: _mameMachine forKey: @"machine"];
|
||||
[dict setObject: @232 forKey: @"version"];
|
||||
[_machineViewController saveBookmark: dict];
|
||||
[_slotController saveBookmark: dict];
|
||||
[_mediaController saveBookmark: dict];
|
||||
|
||||
|
||||
// Boolean values
|
||||
#undef _
|
||||
#define _(v,k) [dict setObject: v ? (NSObject *)kCFBooleanTrue : (NSObject *)kCFBooleanFalse forKey: k]
|
||||
|
||||
_(_mameDebug, @"debug");
|
||||
_(_mameSquarePixels, @"squarePixels");
|
||||
_(_mameMouse, @"mouse");
|
||||
_(_mameSamples, @"samples");
|
||||
_(_mameBGFX, @"bgfx");
|
||||
|
||||
// numeric values
|
||||
#undef _
|
||||
#define _(v,k) [dict setObject: @(v) forKey: k]
|
||||
_(_mameWindowMode, @"windowMode");
|
||||
_(_mameSpeed, @"speed");
|
||||
|
||||
// String values
|
||||
#undef _
|
||||
#define _(v,k) [dict setObject: v forKey: k]
|
||||
|
||||
if (_mameAVI && [_mameAVIPath length]) _(_mameAVIPath, @"AVIPath");
|
||||
if (_mameWAV && [_mameWAVPath length]) _(_mameWAVPath, @"WAVPath");
|
||||
if (_mameVGM && [_mameVGMPath length]) _(_mameVGMPath, @"VGMPath");
|
||||
|
||||
if ([_mameShareDirectory length]) _(_mameShareDirectory, @"shareDirectory");
|
||||
if ([_mameBitBanger length]) _(_mameBitBanger, @"shareDirectory");
|
||||
|
||||
|
||||
if (_software) _([_software fullName], @"software");
|
||||
|
||||
|
||||
if (_mameBackend) _(BackendStrings[_mameBackend], @"backend");
|
||||
if (_mameEffects) _(EffectsStrings[_mameEffects], @"effects");
|
||||
|
||||
|
||||
return dict;
|
||||
|
||||
#undef _
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import "Ample.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@@ -17,4 +18,8 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@end
|
||||
|
||||
@interface MachineViewController (Bookmark) <Bookmark>
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
@@ -110,5 +110,67 @@
|
||||
return [data count];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation MachineViewController (Bookmark)
|
||||
|
||||
-(BOOL)loadBookmark: (NSDictionary *)bookmark {
|
||||
|
||||
NSBrowser *browser = (NSBrowser *)[self view];
|
||||
NSString *machine = [bookmark objectForKey: @"machine"];
|
||||
|
||||
NSIndexPath *path = nil;
|
||||
NSUInteger ix[2] = {0, 0 };
|
||||
for (NSDictionary *d in _data) {
|
||||
|
||||
NSArray *children = [d objectForKey: @"children"];
|
||||
|
||||
for (NSDictionary *dd in children) {
|
||||
NSString *value = [dd objectForKey: @"value"];
|
||||
|
||||
if ([machine isEqualToString: value]) {
|
||||
path = [NSIndexPath indexPathWithIndexes: ix length: 2];
|
||||
[browser selectRow: ix[0] inColumn: 0];
|
||||
[browser selectRow: ix[1] inColumn: 1];
|
||||
|
||||
//[browser setSelectionIndexPath: path];
|
||||
return YES;
|
||||
}
|
||||
++ix[1];
|
||||
}
|
||||
ix[1] = 0;
|
||||
|
||||
|
||||
// check parent after.
|
||||
NSString *value = [d objectForKey: @"value"];
|
||||
if ([machine isEqualToString: value]) {
|
||||
path = [NSIndexPath indexPathWithIndexes: ix length: 1];
|
||||
[browser selectRow: ix[0] inColumn: 0];
|
||||
// "setSelectionIndexPath: is not supported for browsers with matrix delegates."
|
||||
//[browser setSelectionIndexPath: path];
|
||||
return YES;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
++ix[0];
|
||||
|
||||
}
|
||||
NSLog(@"MachineViewController: Unable to find %@", machine);
|
||||
return NO;
|
||||
}
|
||||
|
||||
-(BOOL)saveBookmark: (NSMutableDictionary *)bookmark {
|
||||
// machine saved in parent.
|
||||
return YES;
|
||||
}
|
||||
|
||||
-(void)willLoadBookmark:(NSDictionary *)bookmark {
|
||||
}
|
||||
|
||||
-(void)didLoadBookmark:(NSDictionary *)bookmark {
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import "Media.h"
|
||||
#import "Ample.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@@ -20,8 +21,9 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
- (IBAction)ejectAction:(id)sender;
|
||||
- (IBAction)pathAction:(id)sender;
|
||||
|
||||
@end
|
||||
|
||||
//-(void)setMedia: (NSDictionary *)media;
|
||||
@interface MediaViewController (Bookmark) <Bookmark>
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@@ -262,6 +262,8 @@
|
||||
MediaCategory *_data[CATEGORY_COUNT];
|
||||
NSArray *_root;
|
||||
Media _media;
|
||||
|
||||
BOOL _loadingBookmark;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -376,6 +378,28 @@ x = media.name; cat = _data[index]; delta |= [cat setItemCount: x]
|
||||
}
|
||||
}
|
||||
|
||||
-(void)resetDiskImages {
|
||||
|
||||
BOOL delta = NO;
|
||||
for (unsigned j = 0; j < CATEGORY_COUNT; ++j) {
|
||||
|
||||
MediaCategory *cat = _data[j];
|
||||
NSInteger count = [cat count];
|
||||
for (NSInteger i = 0; i < count; ++i) {
|
||||
|
||||
MediaItem *item = [cat objectAtIndex: i];
|
||||
NSURL *url = [item url];
|
||||
if (!url) continue;
|
||||
[item setUrl: nil];
|
||||
delta = YES;
|
||||
}
|
||||
}
|
||||
if (delta) {
|
||||
[self rebuildRoot];
|
||||
[self rebuildArgs];
|
||||
}
|
||||
}
|
||||
|
||||
static NSString *kDragType = @"private.ample.media";
|
||||
- (void)viewDidLoad {
|
||||
|
||||
@@ -641,4 +665,92 @@ static NSString *kDragType = @"private.ample.media";
|
||||
|
||||
[self rebuildArgs];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation MediaViewController (Bookmark)
|
||||
|
||||
-(BOOL)loadBookmark: (NSDictionary *)bookmark {
|
||||
|
||||
#if 0
|
||||
// hmmm... should rely on machine/slots to set media
|
||||
// so it doesn't go out of sync after an update.
|
||||
NSDictionary *d = [bookmark objectForKey: @"media"];
|
||||
Media m = EmptyMedia;
|
||||
|
||||
if (d) m = MediaFromDictionary(d);
|
||||
[self setMedia: m];
|
||||
#endif
|
||||
|
||||
// reset all media
|
||||
[self resetDiskImages];
|
||||
|
||||
// if order of indexes change, would need to do a version check.
|
||||
|
||||
NSArray *media = [bookmark objectForKey: @"media"];
|
||||
unsigned ix = 0;
|
||||
for (NSArray *a in media) {
|
||||
if (ix >= CATEGORY_COUNT) {
|
||||
NSLog(@"MediaViewController: too many categories.");
|
||||
break;
|
||||
}
|
||||
MediaCategory *cat = _data[ix++];
|
||||
NSInteger count = [cat count];
|
||||
unsigned i = 0;
|
||||
for (NSString *path in a) {
|
||||
if (i >= count) {
|
||||
NSLog(@"MediaViewController: too many files.");
|
||||
break; //
|
||||
}
|
||||
MediaItem *item = [cat objectAtIndex: i++];
|
||||
NSURL *url = nil;
|
||||
if ([path length])
|
||||
url = [NSURL fileURLWithPath: path];
|
||||
|
||||
[item setUrl: url];
|
||||
}
|
||||
}
|
||||
|
||||
// add will load bookmark / did load bookmark to block all the rebuilding ?
|
||||
[self rebuildRoot];
|
||||
[self rebuildArgs];
|
||||
return YES;
|
||||
|
||||
}
|
||||
|
||||
-(BOOL)saveBookmark: (NSMutableDictionary *)bookmark {
|
||||
|
||||
NSMutableArray *media = [NSMutableArray arrayWithCapacity: CATEGORY_COUNT];
|
||||
|
||||
for (unsigned ix = 0; ix < CATEGORY_COUNT; ++ix) {
|
||||
|
||||
MediaCategory *cat = _data[ix];
|
||||
NSInteger count = [cat validCount];
|
||||
|
||||
NSMutableArray *array = [NSMutableArray new];
|
||||
for (NSInteger i = 0; i < count; ++i) {
|
||||
|
||||
MediaItem *item = [cat objectAtIndex: i];
|
||||
NSURL *url = [item url];
|
||||
NSString *s = @"";
|
||||
if (url)
|
||||
s = [NSString stringWithCString: [url fileSystemRepresentation] encoding: NSUTF8StringEncoding];
|
||||
|
||||
[array addObject: s];
|
||||
}
|
||||
[media addObject: array];
|
||||
}
|
||||
|
||||
[bookmark setObject: media forKey: @"media"];
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
-(void)willLoadBookmark:(NSDictionary *)bookmark {
|
||||
_loadingBookmark = YES;
|
||||
}
|
||||
-(void)didLoadBookmark:(NSDictionary *)bookmark {
|
||||
_loadingBookmark = NO;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
+2
-1
@@ -27,7 +27,8 @@
|
||||
@property (readonly) SlotOption *selectedItem;
|
||||
|
||||
-(NSArray *)args;
|
||||
-(NSArray *)serialize;
|
||||
-(NSDictionary *)serialize;
|
||||
-(void)reserialize: (NSDictionary *)dict;
|
||||
|
||||
-(void)reset;
|
||||
-(void)prepareView: (SlotTableCellView *)view;
|
||||
|
||||
+55
-8
@@ -60,7 +60,10 @@ static NSArray *DeepCopyArray(NSArray *src) {
|
||||
-(void)setKeyPath: (NSString *)path;
|
||||
-(void)buildArgs: (NSMutableArray *)args;
|
||||
-(void)buildMedia: (Media *)media;
|
||||
-(void)buildSerial: (NSMutableArray *)array;
|
||||
-(void)buildSerial: (NSMutableDictionary *)array;
|
||||
|
||||
|
||||
-(void)reserialize: (NSDictionary *)dict;
|
||||
|
||||
//-(BOOL)loadDeviceSlots: (NSDictionary *)devices;
|
||||
|
||||
@@ -138,15 +141,47 @@ static NSDictionary *IndexMap = nil;
|
||||
return rv;
|
||||
}
|
||||
|
||||
-(NSArray *)serialize {
|
||||
-(NSDictionary *)serialize {
|
||||
if (_selectedIndex < 0) return nil;
|
||||
|
||||
NSMutableArray *array = [NSMutableArray new];
|
||||
NSMutableDictionary *d = [NSMutableDictionary new];
|
||||
SlotOption *option = [_options objectAtIndex: _selectedIndex];
|
||||
[option buildSerial: array];
|
||||
return array;
|
||||
[option buildSerial: d];
|
||||
//if (![d count]) return nil; //?
|
||||
return d;
|
||||
}
|
||||
|
||||
-(void)reserialize: (NSDictionary *)dict {
|
||||
// { 'sl3' : 'uthernet' }
|
||||
|
||||
// special case for smartport since the name isn't used.
|
||||
if (_index == kSMARTPORT) {
|
||||
SlotOption *option = [_options objectAtIndex: _selectedIndex];
|
||||
[option reserialize: dict];
|
||||
return;
|
||||
}
|
||||
NSString *value = [dict objectForKey: _name];
|
||||
if (!value) {
|
||||
//[self reset];
|
||||
return;
|
||||
}
|
||||
// find it...
|
||||
BOOL found = NO;
|
||||
unsigned ix = 0;
|
||||
for (SlotOption *option in _options) {
|
||||
if ([value isEqualToString: [option value]]) {
|
||||
|
||||
[self setSelectedIndex: ix];
|
||||
[option reserialize: dict];
|
||||
found = YES;
|
||||
break;
|
||||
}
|
||||
++ix;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
-(Media)selectedMedia {
|
||||
|
||||
if (_selectedIndex < 0) return EmptyMedia;
|
||||
@@ -457,14 +492,26 @@ https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/KeyVa
|
||||
}
|
||||
}
|
||||
|
||||
-(void)reserialize: (NSDictionary *)dict {
|
||||
|
||||
#if 0
|
||||
NSString *value = [dict objectForKey: _keyPath];
|
||||
if (value) {
|
||||
// don't need to do anything since set by slot.
|
||||
}
|
||||
#endif
|
||||
for (Slot *s in _children) {
|
||||
[s reserialize: dict];
|
||||
}
|
||||
}
|
||||
|
||||
-(void)buildSerial: (NSMutableArray *)array {
|
||||
-(void)buildSerial: (NSMutableDictionary *)dict {
|
||||
|
||||
if (!_default)
|
||||
[array addObject: _keyPath];
|
||||
[dict setObject: _value forKey: _keyPath];
|
||||
|
||||
for (Slot *s in _children)
|
||||
[[s selectedItem] buildSerial: array];
|
||||
[[s selectedItem] buildSerial: dict];
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import "Media.h"
|
||||
#import "Ample.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@@ -17,13 +18,16 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
@property Media media;
|
||||
@property NSSize resolution;
|
||||
@property (nonatomic) NSString *machine;
|
||||
|
||||
@end
|
||||
|
||||
@interface SlotViewController (OutlineView) <NSOutlineViewDelegate, NSOutlineViewDataSource>
|
||||
|
||||
@end
|
||||
|
||||
@interface SlotViewController (Bookmark) <Bookmark>
|
||||
|
||||
@end
|
||||
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
@@ -49,6 +49,7 @@ static unsigned RootKey = 0;
|
||||
|
||||
IBOutlet NSPopover *_popover;
|
||||
|
||||
BOOL _loadingBookmark;
|
||||
}
|
||||
|
||||
- (void)viewDidLoad {
|
||||
@@ -142,8 +143,10 @@ static unsigned RootKey = 0;
|
||||
|
||||
|
||||
[_outlineView reloadData];
|
||||
[self rebuildMedia];
|
||||
[self rebuildArgs];
|
||||
if (!_loadingBookmark) {
|
||||
[self rebuildMedia];
|
||||
[self rebuildArgs];
|
||||
}
|
||||
}
|
||||
|
||||
-(void)setMachine: (NSString *)machine {
|
||||
@@ -281,8 +284,10 @@ static unsigned RootKey = 0;
|
||||
#ifdef SLOT_TREE
|
||||
[_outlineView reloadData];
|
||||
#endif
|
||||
[self rebuildMedia];
|
||||
[self rebuildArgs];
|
||||
if (!_loadingBookmark) {
|
||||
[self rebuildMedia];
|
||||
[self rebuildArgs];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -338,5 +343,57 @@ static unsigned RootKey = 0;
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation SlotViewController (Bookmark)
|
||||
|
||||
-(BOOL)loadBookmark: (NSDictionary *)bookmark {
|
||||
|
||||
NSDictionary *dict = [bookmark objectForKey: @"slots"];
|
||||
|
||||
[self setMachine: [bookmark objectForKey: @"machine"]];
|
||||
|
||||
[self resetSlots: nil];
|
||||
for (Slot *item in _root) {
|
||||
[item reserialize: dict];
|
||||
|
||||
NSInteger index = [item index];
|
||||
if (index >= 0 && index < SLOT_COUNT) {
|
||||
unsigned mask = 1 << index;
|
||||
|
||||
if ([item defaultIndex] != [item selectedIndex])
|
||||
_slots_explicit |= mask; // grrr.
|
||||
|
||||
_slot_media[index] = [item selectedMedia];
|
||||
_slot_value[index] = [[item selectedItem] value];
|
||||
}
|
||||
|
||||
++index;
|
||||
}
|
||||
|
||||
[self rebuildMedia];
|
||||
[self rebuildArgs];
|
||||
return YES;
|
||||
}
|
||||
-(BOOL)saveBookmark: (NSMutableDictionary *)bookmark {
|
||||
|
||||
NSMutableDictionary *slots = [NSMutableDictionary new];
|
||||
for (Slot *item in _root) {
|
||||
NSDictionary *d = [item serialize];
|
||||
[slots addEntriesFromDictionary: d];
|
||||
}
|
||||
|
||||
[bookmark setObject: slots forKey: @"slots"];
|
||||
return YES;
|
||||
}
|
||||
|
||||
|
||||
-(void)willLoadBookmark:(NSDictionary *)bookmark {
|
||||
_loadingBookmark = YES;
|
||||
}
|
||||
-(void)didLoadBookmark:(NSDictionary *)bookmark {
|
||||
_loadingBookmark = NO;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -28,11 +28,13 @@
|
||||
|
||||
-(void)viewDidMoveToSuperview {
|
||||
return;
|
||||
#if 0
|
||||
if (_trackingRect) {
|
||||
[self removeTrackingRect: _trackingRect];
|
||||
}
|
||||
NSRect rect = [_dragHandle frame];
|
||||
_trackingRect = [self addTrackingRect: rect owner: self userData: NULL assumeInside:NO];
|
||||
#endif
|
||||
}
|
||||
|
||||
-(void)mouseEntered:(NSEvent *)event {
|
||||
|
||||
@@ -21,5 +21,8 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
@interface ValidColorTransformer : NSValueTransformer
|
||||
@end
|
||||
|
||||
@interface StringNotEmptyTransformer : NSValueTransformer
|
||||
@end
|
||||
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
@@ -73,6 +73,21 @@
|
||||
@end
|
||||
|
||||
|
||||
@implementation StringNotEmptyTransformer
|
||||
+ (BOOL)allowsReverseTransformation {
|
||||
return NO;
|
||||
}
|
||||
+ (Class)transformedValueClass {
|
||||
return [NSNumber class];
|
||||
}
|
||||
|
||||
- (id)transformedValue:(id)value {
|
||||
NSUInteger length = [(NSString *)value length];
|
||||
return [NSNumber numberWithBool: length ? YES : NO];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
void RegisterTransformers(void) {
|
||||
|
||||
@@ -85,4 +100,8 @@ void RegisterTransformers(void) {
|
||||
|
||||
t = [ValidColorTransformer new];
|
||||
[NSValueTransformer setValueTransformer: t forName: @"ValidColorTransformer"];
|
||||
|
||||
t = [StringNotEmptyTransformer new];
|
||||
[NSValueTransformer setValueTransformer: t forName: @"StringNotEmptyTransformer"];
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user