enable/disable media based on slots.

This commit is contained in:
Kelvin Sherlock 2020-08-25 00:35:40 -04:00
parent 9cce33ffe9
commit 259b5f31a7
7 changed files with 161 additions and 58 deletions

View File

@ -91,6 +91,9 @@ static NSString *kMyContext = @"kMyContext";
[self addObserver: self forKeyPath: @"mameNoThrottle" options:0 context: (__bridge void * _Nullable)(kMyContext)]; [self addObserver: self forKeyPath: @"mameNoThrottle" options:0 context: (__bridge void * _Nullable)(kMyContext)];
[_slotController addObserver: self forKeyPath: @"args" options: 0 context: (__bridge void * _Nullable)(kMyContext)]; [_slotController addObserver: self forKeyPath: @"args" options: 0 context: (__bridge void * _Nullable)(kMyContext)];
[_mediaController bind: @"media" toObject: _slotController withKeyPath: @"media" options: 0];
[self buildCommandLine]; [self buildCommandLine];
} }

View File

@ -736,7 +736,7 @@
<button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="ug9-kz-ZSS"> <button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="ug9-kz-ZSS">
<rect key="frame" x="621" y="53" width="85" height="32"/> <rect key="frame" x="621" y="53" width="85" height="32"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxY="YES"/> <autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxY="YES"/>
<buttonCell key="cell" type="push" title="Launch" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="evD-kp-H2u"> <buttonCell key="cell" type="push" title="Launch" bezelStyle="rounded" image="NSAppleMenuImage" imagePosition="leading" alignment="center" borderStyle="border" inset="2" id="evD-kp-H2u">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/> <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/> <font key="font" metaFont="system"/>
</buttonCell> </buttonCell>
@ -778,4 +778,7 @@
<viewController title="Slot View" nibName="SlotView" id="CYF-Xd-EdF" customClass="SlotViewController"/> <viewController title="Slot View" nibName="SlotView" id="CYF-Xd-EdF" customClass="SlotViewController"/>
<viewController title="Media View" nibName="MediaView" id="kiU-IX-LTW" customClass="MediaViewController"/> <viewController title="Media View" nibName="MediaView" id="kiU-IX-LTW" customClass="MediaViewController"/>
</objects> </objects>
<resources>
<image name="NSAppleMenuImage" width="128" height="128"/>
</resources>
</document> </document>

View File

@ -14,7 +14,7 @@
</customObject> </customObject>
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/> <customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
<customObject id="-3" userLabel="Application" customClass="NSObject"/> <customObject id="-3" userLabel="Application" customClass="NSObject"/>
<scrollView borderType="none" autohidesScrollers="YES" horizontalLineScroll="20" horizontalPageScroll="10" verticalLineScroll="20" verticalPageScroll="10" usesPredominantAxisScrolling="NO" id="nVT-kT-bWl"> <scrollView borderType="none" autohidesScrollers="YES" horizontalLineScroll="20" horizontalPageScroll="10" verticalLineScroll="20" verticalPageScroll="10" hasHorizontalScroller="NO" usesPredominantAxisScrolling="NO" id="nVT-kT-bWl">
<rect key="frame" x="0.0" y="0.0" width="306" height="500"/> <rect key="frame" x="0.0" y="0.0" width="306" height="500"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<clipView key="contentView" drawsBackground="NO" copiesOnScroll="NO" id="IBD-wb-pch"> <clipView key="contentView" drawsBackground="NO" copiesOnScroll="NO" id="IBD-wb-pch">
@ -81,17 +81,17 @@
<rect key="frame" x="1" y="41" width="304" height="27"/> <rect key="frame" x="1" y="41" width="304" height="27"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews> <subviews>
<pathControl verticalHuggingPriority="750" fixedFrame="YES" allowsExpansionToolTips="YES" translatesAutoresizingMaskIntoConstraints="NO" id="f7R-TO-fmF"> <pathControl focusRingType="none" verticalHuggingPriority="750" fixedFrame="YES" allowsExpansionToolTips="YES" translatesAutoresizingMaskIntoConstraints="NO" id="f7R-TO-fmF">
<rect key="frame" x="0.0" y="1" width="251" height="22"/> <rect key="frame" x="0.0" y="1" width="251" height="22"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES" flexibleMaxY="YES"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
<pathCell key="cell" controlSize="small" selectable="YES" editable="YES" alignment="left" pathStyle="popUp" id="dcz-8y-tKb"> <pathCell key="cell" controlSize="small" selectable="YES" editable="YES" focusRingType="none" alignment="left" pathStyle="popUp" id="dcz-8y-tKb">
<font key="font" metaFont="smallSystem"/> <font key="font" metaFont="smallSystem"/>
</pathCell> </pathCell>
</pathControl> </pathControl>
<button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="zNo-ij-mUl"> <button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="zNo-ij-mUl">
<rect key="frame" x="278" y="4" width="23" height="18"/> <rect key="frame" x="256" y="5" width="23" height="18"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMinY="YES" flexibleMaxY="YES"/> <autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
<buttonCell key="cell" type="bevel" bezelStyle="rounded" image="NSStopProgressFreestandingTemplate" imagePosition="overlaps" alignment="center" controlSize="small" imageScaling="proportionallyDown" inset="2" id="IZA-Tu-olu"> <buttonCell key="cell" type="bevel" bezelStyle="rounded" image="NSNavEjectButton.normalSelected" imagePosition="overlaps" alignment="center" controlSize="small" imageScaling="proportionallyDown" inset="2" id="IZA-Tu-olu">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/> <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="smallSystem"/> <font key="font" metaFont="smallSystem"/>
</buttonCell> </buttonCell>
@ -99,14 +99,9 @@
<action selector="buttonDelete:" target="-2" id="f30-YS-1UK"/> <action selector="buttonDelete:" target="-2" id="f30-YS-1UK"/>
</connections> </connections>
</button> </button>
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" id="jeU-0Q-Eps">
<rect key="frame" x="256" y="6" width="14" height="14"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<imageCell key="cell" enabled="NO" refusesFirstResponder="YES" alignment="left" image="NSStatusUnavailable" id="dtr-VF-lvn"/>
</imageView>
</subviews> </subviews>
<connections> <connections>
<outlet property="imageView" destination="jeU-0Q-Eps" id="Cjz-C6-w1l"/> <outlet property="deleteButton" destination="zNo-ij-mUl" id="9br-3c-ddI"/>
<outlet property="pathControl" destination="f7R-TO-fmF" id="oH7-N3-JC7"/> <outlet property="pathControl" destination="f7R-TO-fmF" id="oH7-N3-JC7"/>
</connections> </connections>
</tableCellView> </tableCellView>
@ -122,7 +117,7 @@
<nil key="backgroundColor"/> <nil key="backgroundColor"/>
</clipView> </clipView>
<scroller key="horizontalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" horizontal="YES" id="9Vz-lW-4GG"> <scroller key="horizontalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" horizontal="YES" id="9Vz-lW-4GG">
<rect key="frame" x="0.0" y="485" width="306" height="15"/> <rect key="frame" x="-100" y="-100" width="306" height="15"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
</scroller> </scroller>
<scroller key="verticalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" horizontal="NO" id="f8l-nC-KhG"> <scroller key="verticalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" horizontal="NO" id="f8l-nC-KhG">
@ -133,7 +128,6 @@
</scrollView> </scrollView>
</objects> </objects>
<resources> <resources>
<image name="NSStatusUnavailable" width="16" height="16"/> <image name="NSNavEjectButton.normalSelected" width="128" height="128"/>
<image name="NSStopProgressFreestandingTemplate" width="14" height="14"/>
</resources> </resources>
</document> </document>

View File

@ -13,11 +13,11 @@ NS_ASSUME_NONNULL_BEGIN
@interface MediaViewController : NSViewController <NSOutlineViewDelegate, NSOutlineViewDataSource> @interface MediaViewController : NSViewController <NSOutlineViewDelegate, NSOutlineViewDataSource>
@property (weak) IBOutlet NSOutlineView *outlineView; @property (weak) IBOutlet NSOutlineView *outlineView;
@property (nonatomic) NSDictionary *media;
- (IBAction)buttonDelete:(id)sender; - (IBAction)buttonDelete:(id)sender;
-(void)setMedia: (NSDictionary *)media; //-(void)setMedia: (NSDictionary *)media;
@end @end

View File

@ -86,25 +86,26 @@
-(BOOL)setItemCount: (unsigned)newCount { -(BOOL)setItemCount: (unsigned)newCount {
unsigned count = (unsigned)[_children count];
if (count == newCount) return NO;
if (newCount == _validCount) {
return NO;
}
unsigned count = (unsigned)[_children count];
NSMutableArray *tmp = [NSMutableArray arrayWithArray: _children]; NSMutableArray *tmp = [NSMutableArray arrayWithArray: _children];
_validCount = newCount; _validCount = newCount;
while (newCount > count) { for (unsigned i = count; i < newCount; ++i) {
[tmp addObject: [MediaItem new]]; [tmp addObject: [MediaItem new]];
++count;
} }
// delete excess items, if blank. otherwise, mark invalid. // delete excess items, if blank. otherwise, mark invalid.
unsigned ix = 0; unsigned ix = 0;
for(MediaItem *item in tmp) { for(MediaItem *item in tmp) {
[item setValid: ix < newCount]; [item setValid: ix++ < newCount];
} }
while (newCount > count) { for (unsigned i = newCount; i < count; ++i) {
--newCount;
MediaItem *item = [tmp lastObject]; MediaItem *item = [tmp lastObject];
if ([item url]) break; if ([item url]) break;
@ -115,6 +116,25 @@
return YES; return YES;
} }
-(BOOL)pruneChildren {
NSUInteger count = [_children count];
BOOL delta = NO;
if (_validCount == count) return NO;
NSMutableArray *tmp = [NSMutableArray arrayWithArray: _children];
for (NSInteger i = _validCount; i < count; ++i) {
MediaItem *item = [tmp lastObject];
if ([item url]) break;
[tmp removeLastObject];
delta = YES;
}
if (delta) {
[self setChildren: tmp];
return YES;
}
return NO;
}
@end @end
@ -152,6 +172,10 @@
[pc setURL: _url]; //??? will binding take care of it? [pc setURL: _url]; //??? will binding take care of it?
[pc unbind: @"value"]; [pc unbind: @"value"];
[pc bind: @"value" toObject: self withKeyPath: @"url" options: nil]; [pc bind: @"value" toObject: self withKeyPath: @"url" options: nil];
NSColor *tintColor = nil;
if (!_valid) tintColor = [NSColor redColor];
[[view deleteButton] setContentTintColor: tintColor];
} }
-(CGFloat)height { -(CGFloat)height {
@ -167,8 +191,8 @@
MediaCategory *_data[5]; MediaCategory *_data[5];
NSArray *_root; NSArray *_root;
NSDictionary *_media;
} }
@property (weak) IBOutlet NSPathControl *_hacky_hack;
@end @end
@ -196,28 +220,8 @@
_data[3] = d; _data[3] = d;
_data[4] = e; _data[4] = e;
_root = @[a,b,c,d,e]; _root = @[];
[a setChildren: @[
[MediaItem new],
[MediaItem new],
]];
[b setChildren: @[
[MediaItem new],
[MediaItem new],
]];
[c setChildren: @[
[MediaItem new],
[MediaItem new],
]];
[d setChildren: @[
[MediaItem new],
[MediaItem new],
]];
} }
@ -228,6 +232,20 @@ enum {
kIndexCDROM, kIndexCDROM,
kIndexCassette kIndexCassette
}; };
-(void)rebuildRoot {
NSMutableArray *tmp = [NSMutableArray new];
for (unsigned j = 0 ; j < 5; ++j) {
MediaCategory *cat = _data[j];
if ([cat count]) [tmp addObject: cat];
}
_root = tmp;
//[_outlineView reloadItem: nil reloadChildren: YES];
[_outlineView reloadData];
[_outlineView expandItem: nil expandChildren: YES];
}
-(void)setMedia: (NSDictionary *)media { -(void)setMedia: (NSDictionary *)media {
static NSString *Keys[] = { static NSString *Keys[] = {
@ -237,11 +255,16 @@ enum {
@"cdrm", @"cdrm",
@"cass" @"cass"
}; };
NSNumber *o; NSNumber *o;
MediaCategory *cat; MediaCategory *cat;
unsigned i; unsigned i;
BOOL delta = NO; BOOL delta = NO;
if (_media == media) return;
_media = media;
for (unsigned j = 0; j < 5; ++j) { for (unsigned j = 0; j < 5; ++j) {
o = [media objectForKey: Keys[j]]; o = [media objectForKey: Keys[j]];
@ -251,15 +274,7 @@ enum {
} }
if (delta) { if (delta) [self rebuildRoot];
NSMutableArray *tmp = [NSMutableArray new];
for (unsigned j = 0 ; j < 5; ++j) {
MediaCategory *cat = _data[j];
if ([cat count]) [tmp addObject: cat];
}
_root = tmp;
[_outlineView reloadData];
}
} }
- (void)viewDidLoad { - (void)viewDidLoad {
@ -269,6 +284,7 @@ enum {
//NSOutlineView *view = [self view]; //NSOutlineView *view = [self view];
//[view expandItem: nil expandChildren: YES]; //[view expandItem: nil expandChildren: YES];
// Do view setup here. // Do view setup here.
[_outlineView reloadData];
[_outlineView expandItem: nil expandChildren: YES]; [_outlineView expandItem: nil expandChildren: YES];
} }
@ -364,5 +380,11 @@ enum {
MediaItem *item = [_outlineView itemAtRow: row]; MediaItem *item = [_outlineView itemAtRow: row];
[item setUrl: nil]; [item setUrl: nil];
//[[pv pathControl] setURL: nil]; //[[pv pathControl] setURL: nil];
// if item is invalid, should attempt to remove...
if (![item valid]) {
MediaCategory *cat = [_outlineView parentForItem: item];
if ([cat pruneChildren]) [self rebuildRoot];
}
} }
@end @end

View File

@ -37,6 +37,7 @@ NS_ASSUME_NONNULL_BEGIN
@property NSSize resolution; @property NSSize resolution;
@property NSArray *args; @property NSArray *args;
@property NSDictionary *media;
//-(void)setMachine: (NSDictionary *)machine; //-(void)setMachine: (NSDictionary *)machine;

View File

@ -15,6 +15,10 @@ const unsigned kMemoryMask = 1 << 16;
unsigned _slots_explicit; unsigned _slots_explicit;
unsigned _slots_valid; unsigned _slots_valid;
unsigned _slots_default; unsigned _slots_default;
NSDictionary *_slot_object[14];
NSDictionary *_slot_media[14];
NSDictionary *_machine_media;
} }
@property (weak) IBOutlet NSPopUpButton *ram_menu; @property (weak) IBOutlet NSPopUpButton *ram_menu;
@ -89,7 +93,19 @@ const unsigned kMemoryMask = 1 << 16;
_slots_explicit = 0; _slots_explicit = 0;
_slots_valid = 0; _slots_valid = 0;
_machine_media = nil;
[self setArgs: @[]]; [self setArgs: @[]];
[self setMedia: @{}];
#if 0
// retain for later?
for (unsigned i = 0; i < 14; ++i) {
_slot_media[i] = nil;
_slot_object[i] = nil;
}
#endif
} }
static NSFont *ItalicMenuFont(void) { static NSFont *ItalicMenuFont(void) {
@ -212,20 +228,26 @@ static void DeactivateMenus(NSArray *items, NSPopUpButton *button) {
if ([value isEqualToString: [d objectForKey: @"value"]]) { if ([value isEqualToString: [d objectForKey: @"value"]]) {
[button selectItemAtIndex: ix]; [button selectItemAtIndex: ix];
_slot_object[index] = d;
_slot_media[index] = [d objectForKey: @"media"];
return; return;
} }
++ix; ++ix;
} }
} }
_slots_explicit &= ~mask; _slots_explicit &= ~mask;
if (default_index) { if (default_index) {
NSDictionary *d = [items objectAtIndex: default_index]; NSDictionary *d = [items objectAtIndex: default_index];
[button selectItemAtIndex: default_index]; [button selectItemAtIndex: default_index];
[self setValue: [d objectForKey: @"value"] forKey: slot]; [self setValue: [d objectForKey: @"value"] forKey: slot];
_slot_object[index] = d;
_slot_media[index] = [d objectForKey: @"media"];
} else { } else {
[self setValue: @"" forKey: slot];
[button selectItemAtIndex: 0]; [button selectItemAtIndex: 0];
[self setValue: @"" forKey: slot];
_slot_object[index] = nil;
_slot_media[index] = nil;
} }
} }
@ -267,11 +289,14 @@ static void DeactivateMenus(NSArray *items, NSPopUpButton *button) {
res.height = [(NSNumber *)[r objectAtIndex: 1 /*@"height"*/] doubleValue]; res.height = [(NSNumber *)[r objectAtIndex: 1 /*@"height"*/] doubleValue];
} }
[self setResolution: res]; [self setResolution: res];
_machine_media = [d objectForKey: @"media"];
// n.b. - does content binding propogate immediately? // n.b. - does content binding propogate immediately?
[self setMachine: d]; [self setMachine: d];
[self syncSlots]; [self syncSlots];
[self rebuildArgs]; [self rebuildArgs];
[self rebuildMedia];
} }
@ -297,6 +322,16 @@ static void DeactivateMenus(NSArray *items, NSPopUpButton *button) {
[self setValue: [o objectForKey: @"value"] forKey: key]; [self setValue: [o objectForKey: @"value"] forKey: key];
_slot_object[tag] = o;
NSDictionary *newMedia = [o objectForKey: @"media"];
NSDictionary *oldMedia = _slot_media[tag];
if (newMedia != oldMedia) {
_slot_media[tag] = newMedia;
[self rebuildMedia];
}
[self rebuildArgs]; [self rebuildArgs];
} }
@ -359,8 +394,53 @@ static BOOL should_add_arg(unsigned slot, unsigned valid_slots, unsigned explici
_(11, _gameio, @"-gameio") _(11, _gameio, @"-gameio")
_(12, _printer, @"-printer") _(12, _printer, @"-printer")
_(13, _modem, @"-modem") _(13, _modem, @"-modem")
#undef _
[self setArgs: args]; [self setArgs: args];
} }
-(void)rebuildMedia {
#define _(var, o) var += [[o objectForKey: @ # var ] unsignedIntValue]
unsigned cass = 0;
unsigned cdrm = 0;
unsigned hard = 0;
unsigned flop_5_25 = 0;
unsigned flop_3_5 = 0;
unsigned mask = 1;
for (unsigned i = 0; i < 14; ++i, mask <<= 1) {
if (_slots_valid & mask) {
NSDictionary *tmp = _slot_media[i];
if (tmp) {
_(cass, tmp);
_(cdrm, tmp);
_(hard, tmp);
_(flop_5_25, tmp);
_(flop_3_5, tmp);
}
}
}
NSDictionary *tmp = _machine_media;
if (tmp) {
_(cass, tmp);
_(cdrm, tmp);
_(hard, tmp);
_(flop_5_25, tmp);
_(flop_3_5, tmp);
}
[self setMedia: @{
@"cass": @(cass),
@"cdrm": @(cdrm),
@"hard": @(hard),
@"flop_5_25": @(flop_5_25),
@"flop_3_5": @(flop_3_5),
}];
}
@end @end