Eliminate the hard-coded slot values and use the slot name + dictionary for saving between machines.

This commit is contained in:
Kelvin Sherlock 2023-11-02 22:16:03 -04:00
parent 2198467def
commit 9b3223478c
3 changed files with 72 additions and 164 deletions

View File

@ -10,16 +10,6 @@
#import <Cocoa/Cocoa.h> #import <Cocoa/Cocoa.h>
#import "Media.h" #import "Media.h"
/* number of slot types. bitmask used so should be < sizeof(unsigned *8) */
#define SLOT_COUNT 28
static_assert(SLOT_COUNT <= sizeof(unsigned) * 8, "too many slot types");
#define kSMARTPORT_SLOT 1
#define kBIOS_SLOT 2
#ifndef SIZEOF
#define SIZEOF(x) (sizeof(x) / sizeof(x[0]))
#endif
//NS_ASSUME_NONNULL_BEGIN //NS_ASSUME_NONNULL_BEGIN
@class Slot, SlotOption, SlotTableCellView; @class Slot, SlotOption, SlotTableCellView;
@ -36,6 +26,7 @@ static_assert(SLOT_COUNT <= sizeof(unsigned) * 8, "too many slot types");
@property (readonly) NSArray *menuItems; @property (readonly) NSArray *menuItems;
@property (readonly) SlotOption *selectedItem; @property (readonly) SlotOption *selectedItem;
@property (readonly) NSString *selectedValue;
-(NSArray *)args; -(NSArray *)args;
-(NSDictionary *)serialize; -(NSDictionary *)serialize;

View File

@ -72,48 +72,6 @@ static NSArray *DeepCopyArray(NSArray *src) {
@implementation Slot @implementation Slot
static NSDictionary *IndexMap = nil;
+(void)load {
IndexMap = @{
@"ramsize": @0,
@"smartport": @1,
@"bios": @2,
@"sl0": @3,
@"sl1": @4,
@"sl2": @5,
@"sl3": @6,
@"sl4": @7,
@"sl5": @8,
@"sl6": @9,
@"sl7": @10,
@"exp": @11,
@"aux": @12,
@"rs232": @13,
@"gameio": @14,
@"modem": @15,
@"printer": @16,
//nubus mac
@"nb9": @17,
@"nba": @18,
@"nbb": @19,
@"nbc": @20,
@"nbd": @21,
@"nbe": @22,
@"pds": @23,
@"pds030": @24,
@"centronics": @25,
@"mdin": @26,
@"mdout": @27
};
static_assert(kSMARTPORT_SLOT == 1, "Smartport != 1");
static_assert(kBIOS_SLOT == 2, "Bios != 2");
}
-(void)reset { -(void)reset {
[self setSelectedIndex: _defaultIndex >= 0 ? _defaultIndex : 0]; [self setSelectedIndex: _defaultIndex >= 0 ? _defaultIndex : 0];
@ -171,7 +129,7 @@ static NSDictionary *IndexMap = nil;
// { 'sl3' : 'uthernet' } // { 'sl3' : 'uthernet' }
// special case for smartport since the name isn't used. // special case for smartport since the name isn't used.
if (_index == kSMARTPORT_SLOT) { if ([_name isEqualToString: @"-smartport"]) {
SlotOption *option = [_options objectAtIndex: _selectedIndex]; SlotOption *option = [_options objectAtIndex: _selectedIndex];
[option reserialize: dict]; [option reserialize: dict];
return; return;
@ -230,9 +188,14 @@ static NSDictionary *IndexMap = nil;
[option buildMedia: &media]; [option buildMedia: &media];
return media; return media;
} }
-(NSString *)selectedValue {
if (_selectedIndex < 0) return nil;
if (_selectedIndex >= [_options count]) return nil;
return [[_options objectAtIndex: _selectedIndex] value];
}
-(NSArray *)selectedChildren { -(NSArray *)selectedChildren {
if (_selectedIndex < 0) return nil; if (_selectedIndex < 0) return nil;
@ -288,21 +251,22 @@ static NSDictionary *IndexMap = nil;
if (c != '-') _name = p; if (c != '-') _name = p;
} }
-(instancetype)initWithDictionary: (NSDictionary *)data devices: (NSDictionary *)devices { -(instancetype)initWithDictionary: (NSDictionary *)data devices: (NSDictionary *)devices {
return [self initWithDictionary: data devices: devices index: 0];
}
-(instancetype)initWithDictionary: (NSDictionary *)data devices: (NSDictionary *)devices index: (NSInteger)index {
BOOL topLevel = NO; BOOL topLevel = NO;
_selectedIndex = -1; _selectedIndex = -1;
_defaultIndex = -1; _defaultIndex = -1;
_index = -1; _index = index;
_name = [data objectForKey: @"name"]; _name = [data objectForKey: @"name"];
_title = [data objectForKey: @"description"]; _title = [data objectForKey: @"description"];
NSNumber *x = [IndexMap objectForKey: _name]; if (index < 0x10000) {
if (x) {
topLevel = YES; topLevel = YES;
_index = [x integerValue];
_name = [@"-" stringByAppendingString: _name]; _name = [@"-" stringByAppendingString: _name];
_title = [_title stringByAppendingString: @":"]; _title = [_title stringByAppendingString: @":"];
} }
@ -310,14 +274,13 @@ static NSDictionary *IndexMap = nil;
NSArray *op = [data objectForKey: @"options"]; NSArray *op = [data objectForKey: @"options"];
NSMutableArray *options = [NSMutableArray arrayWithCapacity: [op count]]; NSMutableArray *options = [NSMutableArray arrayWithCapacity: [op count]];
NSInteger ix = 0;
NSInteger index = 0;
for (NSDictionary *d in op) { for (NSDictionary *d in op) {
SlotOption *o = [[SlotOption alloc] initWithDictionary: d devices: devices]; SlotOption *o = [[SlotOption alloc] initWithDictionary: d devices: devices];
if ([o isDefault]) { if ([o isDefault]) {
_defaultIndex = index; _defaultIndex = ix;
} }
++index; ++ix;
if (topLevel) { if (topLevel) {
[o setKeyPath: _name]; [o setKeyPath: _name];
NSArray *tmp = [o children]; NSArray *tmp = [o children];
@ -338,36 +301,6 @@ static NSDictionary *IndexMap = nil;
return self; return self;
} }
#if 0
-(instancetype)initWithName: (NSString *)name title: (NSString *)title data: (NSArray *)data {
_name = [name copy];
_title = [title copy];
_selectedIndex = -1;
_defaultIndex = -1;
_index = -1;
NSMutableArray *options = [NSMutableArray arrayWithCapacity: [data count]];
//NSMutableArray *menuItems = [NSMutableArray arrayWithCapacity: [data count]];
NSInteger index = 0;
for (NSDictionary *d in data) {
SlotOption *o = [[SlotOption alloc] initWithDictionary: d];
if ([o isDefault]) {
_defaultIndex = index;
}
++index;
[options addObject: o];
}
_options = options;
//_menuItems = menuItems;
_selectedIndex = _defaultIndex;
if (_selectedIndex < 0) _selectedIndex = 0;
return self;
}
#endif
-(NSArray *)menuItems { -(NSArray *)menuItems {
//if (_menuItems) return _menuItems; //if (_menuItems) return _menuItems;
@ -406,7 +339,8 @@ static NSDictionary *IndexMap = nil;
// [menu setItemArray: ] doesn't work prior to 10.14, apparently. // [menu setItemArray: ] doesn't work prior to 10.14, apparently.
[menu removeAllItems]; [menu removeAllItems];
if (_index == kSMARTPORT_SLOT) {
if ([_name isEqualToString: @"-smartport"]) {
//[menu setItemArray: @[]]; //[menu setItemArray: @[]];
[button setHidden: YES]; [button setHidden: YES];
} else { } else {
@ -630,7 +564,7 @@ NSDictionary *BuildDevices(NSArray *array) {
NSArray *data = MapArray(slots, ^(id o){ NSArray *data = MapArray(slots, ^(id o){
Slot *s = [[Slot alloc] initWithDictionary: o devices: nil]; Slot *s = [[Slot alloc] initWithDictionary: o devices: nil index: 0];
return s; return s;
}); });
@ -658,9 +592,11 @@ NSArray *BuildSlots(NSString *name, NSDictionary *data) {
NSMutableArray *rv = [NSMutableArray arrayWithCapacity: [slots count]]; NSMutableArray *rv = [NSMutableArray arrayWithCapacity: [slots count]];
NSDictionary *devices = BuildDevices([data objectForKey: @"devices"]); NSDictionary *devices = BuildDevices([data objectForKey: @"devices"]);
unsigned ix = 0;
for (NSDictionary *d in slots) { for (NSDictionary *d in slots) {
Slot *s = [[Slot alloc] initWithDictionary: d devices: devices]; Slot *s = [[Slot alloc] initWithDictionary: d devices: devices index: ++ix];
[rv addObject: s]; [rv addObject: s];
} }

View File

@ -16,7 +16,7 @@
#import <objc/runtime.h> #import <objc/runtime.h>
#define MAX_SLOTS 32
static unsigned RootKey = 0; static unsigned RootKey = 0;
@ -31,18 +31,13 @@ static unsigned RootKey = 0;
@implementation SlotViewController { @implementation SlotViewController {
NSArray *_root; NSArray *_root;
unsigned _slots_explicit; Media _slot_media[MAX_SLOTS];
unsigned _slots_valid;
unsigned _slots_default;
Slot *_slot_object[SLOT_COUNT];
NSString *_slot_value[SLOT_COUNT]; // when explicitely set.
Media _slot_media[SLOT_COUNT];
Media _machine_media; Media _machine_media;
NSDictionary *_machine_data; NSDictionary *_machine_data;
NSMutableDictionary *_slotValues;
IBOutlet NSPopover *_popover; IBOutlet NSPopover *_popover;
BOOL _loadingBookmark; BOOL _loadingBookmark;
@ -55,6 +50,7 @@ static unsigned RootKey = 0;
_root = @[]; _root = @[];
objc_setAssociatedObject(_outlineView, &RootKey, _root, OBJC_ASSOCIATION_RETAIN); objc_setAssociatedObject(_outlineView, &RootKey, _root, OBJC_ASSOCIATION_RETAIN);
_slotValues = [NSMutableDictionary new];
//[_outlineView setIndentationPerLevel: 2.0]; //[_outlineView setIndentationPerLevel: 2.0];
} }
@ -66,16 +62,13 @@ static unsigned RootKey = 0;
[_outlineView reloadData]; [_outlineView reloadData];
_slots_valid = 0; [_slotValues removeAllObjects];
_slots_explicit = 0;
_slots_default = 0;
_machine_media = EmptyMedia; _machine_media = EmptyMedia;
_machine_data = nil; _machine_data = nil;
for (unsigned i = 0; i < SLOT_COUNT; ++i) { for (unsigned i = 0; i < MAX_SLOTS; ++i) {
_slot_media[i] = EmptyMedia; _slot_media[i] = EmptyMedia;
_slot_object[i] = nil;
_slot_value[i] = nil;
} }
[self setResolution: NSMakeSize(0, 0)]; [self setResolution: NSMakeSize(0, 0)];
@ -86,10 +79,8 @@ static unsigned RootKey = 0;
-(void)loadMachine { -(void)loadMachine {
NSDictionary *d = MameMachine(_machine); NSDictionary *d = MameMachine(_machine);
if (!d) { if (!d) {
[self resetMachine]; [self resetMachine];
return; return;
@ -103,39 +94,33 @@ static unsigned RootKey = 0;
} }
[self setResolution: res]; [self setResolution: res];
_slots_valid = 0;
//_slots_explicit = 0;
_slots_default = 0;
_machine_media = MediaFromDictionary([d objectForKey: @"media"]); _machine_media = MediaFromDictionary([d objectForKey: @"media"]);
_machine_data = d; _machine_data = d;
for (unsigned i = 0; i < SLOT_COUNT; ++i) { for (unsigned i = 0; i < MAX_SLOTS; ++i) {
_slot_media[i] = EmptyMedia; _slot_media[i] = EmptyMedia;
_slot_object[i] = nil;
} }
_slot_value[kBIOS_SLOT] = nil; // don't copy over to other machines.
extern NSArray *BuildSlots(NSString *name, NSDictionary *data); extern NSArray *BuildSlots(NSString *name, NSDictionary *data);
_root = BuildSlots(_machine, d); _root = BuildSlots(_machine, d);
objc_setAssociatedObject(_outlineView, &RootKey, _root, OBJC_ASSOCIATION_RETAIN); objc_setAssociatedObject(_outlineView, &RootKey, _root, OBJC_ASSOCIATION_RETAIN);
for (Slot *item in _root) { for (Slot *item in _root) {
NSInteger index = [item index]; NSString *name = [item name];
if (index < 0) continue; NSInteger index = [item index] - 1;
unsigned mask = 1 << index; if (index < 0 || index >= MAX_SLOTS) continue;
_slots_valid |= mask; if ([name isEqualToString: @"-bios"]) continue;
if ([item defaultIndex] >= 0)
_slots_default |= mask;
if (_slot_value[index])
[item selectValue: _slot_value[index]];
NSString *v = [_slotValues objectForKey: name];
if (v) {
[item selectValue: v];
}
// TODO -- reset to default index???
_slot_media[index] = [item selectedMedia]; _slot_media[index] = [item selectedMedia];
_slot_object[index] = item;
} }
@ -165,12 +150,9 @@ static unsigned RootKey = 0;
Media media = EmptyMedia; Media media = EmptyMedia;
unsigned mask = 1; for (unsigned i = 0; i < MAX_SLOTS; ++i) {
for (unsigned i = 0; i < SLOT_COUNT; ++i, mask <<= 1) {
if (_slots_valid & mask) { MediaAdd(&media, &_slot_media[i]);
MediaAdd(&media, &_slot_media[i]);
}
} }
// machine media last. // machine media last.
MediaAdd(&media, &_machine_media); MediaAdd(&media, &_machine_media);
@ -196,34 +178,29 @@ static unsigned RootKey = 0;
BOOL direct = YES; BOOL direct = YES;
NSInteger index = [sender tag]; NSInteger index = [sender tag];
if (index < 0) return; //
if (index >= 0 && index < SLOT_COUNT) { if (index < 0x10000) {
direct = YES; direct = YES;
} else { } else {
direct = NO; direct = NO;
index &= ~0x10000; index &= ~0x10000;
} }
if (index >= SLOT_COUNT) return; // index--;
unsigned mask = 1 << index; if (index < 0 || index >= MAX_SLOTS) return; //
// index 0 = ram = special case...
SlotOption *o = [[sender selectedItem] representedObject]; SlotOption *o = [[sender selectedItem] representedObject];
Slot *item = _slot_object[index]; Slot *item = [_root objectAtIndex: index];
if (direct) { if (direct) {
_slots_explicit |= mask; NSString *name = [item name];
_slot_value[index] = [o value]; NSString *value = [o value];
//_slots_default &= ~mask; [_slotValues setObject: value forKey: name];
} }
Media media = [item selectedMedia]; Media media = [item selectedMedia];
if (!MediaEqual(&media, &_slot_media[index])) { if (!MediaEqual(&media, &_slot_media[index])) {
_slot_media[index] = media; _slot_media[index] = media;
[self rebuildMedia]; [self rebuildMedia];
} }
// needs to reload children if expanded. // needs to reload children if expanded.
@ -244,9 +221,9 @@ static unsigned RootKey = 0;
#endif #endif
NSInteger index = [sender tag]; NSInteger index = [sender tag];
if (index < 0 || index >= SLOT_COUNT) return; if (index <= 0 || index >= 0x10000) return;
index--;
Slot *item = _slot_object[index]; Slot *item = [_root objectAtIndex: index];
NSArray *children = [item selectedChildren]; NSArray *children = [item selectedChildren];
objc_setAssociatedObject(_childOutlineView, &RootKey, children, OBJC_ASSOCIATION_RETAIN); objc_setAssociatedObject(_childOutlineView, &RootKey, children, OBJC_ASSOCIATION_RETAIN);
@ -266,15 +243,19 @@ static unsigned RootKey = 0;
-(IBAction)resetSlots:(id)sender { -(IBAction)resetSlots:(id)sender {
_slots_explicit = 0;
for (unsigned i = 0; i < SLOT_COUNT; ++i) { //_slots_explicit = 0;
for (unsigned i = 0; i < MAX_SLOTS; ++i) {
_slot_media[i] = EmptyMedia; _slot_media[i] = EmptyMedia;
_slot_value[i] = nil;
} }
for (Slot *item in _root) { for (Slot *item in _root) {
NSString *name = [item name];
[_slotValues removeObjectForKey: name];
[item reset]; [item reset];
// if children, reset them too... // if children, reset them too...
NSInteger index = [item index]; NSInteger index = [item index] - 1;
if (index < 0) continue; if (index < 0) continue;
_slot_media[index] = [item selectedMedia]; _slot_media[index] = [item selectedMedia];
} }
@ -367,19 +348,19 @@ static unsigned RootKey = 0;
for (Slot *item in _root) { for (Slot *item in _root) {
[item reserialize: dict]; [item reserialize: dict];
NSInteger index = [item index]; NSInteger index = [item index] - 1;
if (index >= 0 && index < SLOT_COUNT) { if (index >= 0 && index < MAX_SLOTS) {
unsigned mask = 1 << index;
NSString *name = [item name];
[_slotValues removeObjectForKey: name];
if ([item defaultIndex] != [item selectedIndex]) { if ([item defaultIndex] != [item selectedIndex]) {
_slots_explicit |= mask; // grrr. NSString *v = [item selectedValue];
_slot_value[index] = [[item selectedItem] value]; if (v) [_slotValues setObject: v forKey: name];
} }
_slot_media[index] = [item selectedMedia]; _slot_media[index] = [item selectedMedia];
} }
++index;
} }
// need to do it here so it propogate to media view. // need to do it here so it propogate to media view.