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)];
[_slotController addObserver: self forKeyPath: @"args" options: 0 context: (__bridge void * _Nullable)(kMyContext)];
[_mediaController bind: @"media" toObject: _slotController withKeyPath: @"media" options: 0];
[self buildCommandLine];
}

View File

@ -736,7 +736,7 @@
<button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="ug9-kz-ZSS">
<rect key="frame" x="621" y="53" width="85" height="32"/>
<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"/>
<font key="font" metaFont="system"/>
</buttonCell>
@ -778,4 +778,7 @@
<viewController title="Slot View" nibName="SlotView" id="CYF-Xd-EdF" customClass="SlotViewController"/>
<viewController title="Media View" nibName="MediaView" id="kiU-IX-LTW" customClass="MediaViewController"/>
</objects>
<resources>
<image name="NSAppleMenuImage" width="128" height="128"/>
</resources>
</document>

View File

@ -14,7 +14,7 @@
</customObject>
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
<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"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<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"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<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"/>
<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"/>
</pathCell>
</pathControl>
<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"/>
<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"/>
<font key="font" metaFont="smallSystem"/>
</buttonCell>
@ -99,14 +99,9 @@
<action selector="buttonDelete:" target="-2" id="f30-YS-1UK"/>
</connections>
</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>
<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"/>
</connections>
</tableCellView>
@ -122,7 +117,7 @@
<nil key="backgroundColor"/>
</clipView>
<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"/>
</scroller>
<scroller key="verticalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" horizontal="NO" id="f8l-nC-KhG">
@ -133,7 +128,6 @@
</scrollView>
</objects>
<resources>
<image name="NSStatusUnavailable" width="16" height="16"/>
<image name="NSStopProgressFreestandingTemplate" width="14" height="14"/>
<image name="NSNavEjectButton.normalSelected" width="128" height="128"/>
</resources>
</document>

View File

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

View File

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

View File

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

View File

@ -15,6 +15,10 @@ const unsigned kMemoryMask = 1 << 16;
unsigned _slots_explicit;
unsigned _slots_valid;
unsigned _slots_default;
NSDictionary *_slot_object[14];
NSDictionary *_slot_media[14];
NSDictionary *_machine_media;
}
@property (weak) IBOutlet NSPopUpButton *ram_menu;
@ -89,7 +93,19 @@ const unsigned kMemoryMask = 1 << 16;
_slots_explicit = 0;
_slots_valid = 0;
_machine_media = nil;
[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) {
@ -212,20 +228,26 @@ static void DeactivateMenus(NSArray *items, NSPopUpButton *button) {
if ([value isEqualToString: [d objectForKey: @"value"]]) {
[button selectItemAtIndex: ix];
_slot_object[index] = d;
_slot_media[index] = [d objectForKey: @"media"];
return;
}
++ix;
}
}
_slots_explicit &= ~mask;
if (default_index) {
NSDictionary *d = [items objectAtIndex: default_index];
[button selectItemAtIndex: default_index];
[self setValue: [d objectForKey: @"value"] forKey: slot];
_slot_object[index] = d;
_slot_media[index] = [d objectForKey: @"media"];
} else {
[self setValue: @"" forKey: slot];
[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];
}
[self setResolution: res];
_machine_media = [d objectForKey: @"media"];
// n.b. - does content binding propogate immediately?
[self setMachine: d];
[self syncSlots];
[self rebuildArgs];
[self rebuildMedia];
}
@ -297,6 +322,16 @@ static void DeactivateMenus(NSArray *items, NSPopUpButton *button) {
[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];
}
@ -359,8 +394,53 @@ static BOOL should_add_arg(unsigned slot, unsigned valid_slots, unsigned explici
_(11, _gameio, @"-gameio")
_(12, _printer, @"-printer")
_(13, _modem, @"-modem")
#undef _
[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