diff --git a/apple/Assets/PauseView.xib b/apple/Assets/PauseView.xib deleted file mode 100644 index 4136ceee9c..0000000000 --- a/apple/Assets/PauseView.xib +++ /dev/null @@ -1,553 +0,0 @@ - - - - 1552 - 12D78 - 3084 - 1187.37 - 626.00 - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - 2083 - - - IBProxyObject - IBUIButton - IBUISegmentedControl - IBUIView - - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - PluginDependencyRecalculationVersion - - - - - IBFilesOwner - IBIPadFramework - - - IBFirstResponder - IBIPadFramework - - - - 274 - - - - 292 - {{160, 237}, {120, 44}} - - - - _NS:9 - NO - 4 - IBIPadFramework - 0 - 0 - 1 - Exit - - 3 - MQA - - - 1 - MC4xOTYwNzg0MzQ2IDAuMzA5ODAzOTMyOSAwLjUyMTU2ODY1NgA - - - 3 - MC41AA - - - 2 - 15 - - - Helvetica-Bold - 15 - 16 - - - - - 292 - {{20, 20}, {120, 44}} - - - - _NS:9 - NO - IBIPadFramework - 0 - 0 - 1 - Resume Game - - - 1 - MC4xOTYwNzg0MzQ2IDAuMzA5ODAzOTMyOSAwLjUyMTU2ODY1NgA - - - - - - - - 292 - {{160, 20}, {120, 44}} - - - - _NS:9 - NO - IBIPadFramework - 0 - 0 - 1 - Toggle RGUI - - - 1 - MC4xOTYwNzg0MzQ2IDAuMzA5ODAzOTMyOSAwLjUyMTU2ODY1NgA - - - - - - - - 292 - {{20, 237}, {120, 44}} - - - - _NS:9 - NO - 1 - IBIPadFramework - 0 - 0 - 1 - Reset - - - 1 - MC4xOTYwNzg0MzQ2IDAuMzA5ODAzOTMyOSAwLjUyMTU2ODY1NgA - - - - - - - - 292 - {{20, 186}, {120, 44}} - - - - _NS:9 - NO - 3 - IBIPadFramework - 0 - 0 - 1 - Save State - - - 1 - MC4xOTYwNzg0MzQ2IDAuMzA5ODAzOTMyOSAwLjUyMTU2ODY1NgA - - - - - - - - 292 - {{160, 186}, {120, 44}} - - - - _NS:9 - NO - 2 - IBIPadFramework - 0 - 0 - 1 - Load State - - - 1 - MC4xOTYwNzg0MzQ2IDAuMzA5ODAzOTMyOSAwLjUyMTU2ODY1NgA - - - - - - - - 292 - {{20, 135}, {260, 44}} - - - - _NS:9 - NO - 10 - IBIPadFramework - 10 - 0 - - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - - - - - - - - - - - - - - - - - - - - - - - - - - - {0, 0} - {0, 0} - {0, 0} - {0, 0} - {0, 0} - {0, 0} - {0, 0} - {0, 0} - {0, 0} - {0, 0} - - - - - - - - - - - - - - - - - 292 - {{20, 71}, {120, 44}} - - - - _NS:9 - NO - IBIPadFramework - 0 - 0 - 1 - System Config - - - 1 - MC4xOTYwNzg0MzQ2IDAuMzA5ODAzOTMyOSAwLjUyMTU2ODY1NgA - - - - - - - - 292 - {{160, 71}, {120, 44}} - - - - _NS:9 - NO - IBIPadFramework - 0 - 0 - 1 - Core Config - - - 1 - MC4xOTYwNzg0MzQ2IDAuMzA5ODAzOTMyOSAwLjUyMTU2ODY1NgA - - - - - - - {{0, 20}, {300, 300}} - - - - - 3 - MQA - - 2 - - - NO - 0.0 - - 2 - - - IBUISimulatedFreeformSizeMetricsSentinel - Freeform - - IBIPadFramework - - - - - - - basicEvent: - - - 7 - - 215 - - - - closePauseMenu: - - - 7 - - 25 - - - - basicEvent: - - - 7 - - 214 - - - - basicEvent: - - - 7 - - 212 - - - - basicEvent: - - - 7 - - 213 - - - - chooseState: - - - 13 - - 139 - - - - showSystemSettings - - - 7 - - 166 - - - - showSettings - - - 7 - - 154 - - - - showRGUI: - - - 7 - - 179 - - - - - - 0 - - - - - - 1 - - - - - - - - - - - - - - - - -1 - - - File's Owner - - - -2 - - - - - 12 - - - - - - 17 - - - - - - 30 - - - - - - 86 - - - - - - 122 - - - - - - 131 - - - - - 140 - - - - - - 152 - - - - - - 170 - - - - - - - - RetroArch_iOS - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - UIResponder - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - - - - 215 - - - - - RetroArch_iOS - UINavigationController - - IBProjectSource - ./Classes/RetroArch_iOS.h - - - - - 0 - IBIPadFramework - YES - 3 - 2083 - - diff --git a/apple/Assets/ic_pause.png b/apple/Assets/ic_pause.png deleted file mode 100644 index b024ca8713..0000000000 Binary files a/apple/Assets/ic_pause.png and /dev/null differ diff --git a/apple/OSX/platform.h b/apple/OSX/platform.h index cb33fb8629..80243aaa8e 100644 --- a/apple/OSX/platform.h +++ b/apple/OSX/platform.h @@ -34,8 +34,8 @@ + (RetroArch_OSX*)get; -- (void)loadingCore:(RAModuleInfo*)core withFile:(const char*)file; -- (void)unloadingCore:(RAModuleInfo*)core; +- (void)loadingCore:(NSString*)core withFile:(const char*)file; +- (void)unloadingCore:(NSString*)core; @property (nonatomic) NSString* configDirectory; // e.g. /var/mobile/Documents/.RetroArch @property (nonatomic) NSString* globalConfigFile; // e.g. /var/mobile/Documents/.RetroArch/retroarch.cfg diff --git a/apple/OSX/platform.m b/apple/OSX/platform.m index f911432227..f96b806565 100644 --- a/apple/OSX/platform.m +++ b/apple/OSX/platform.m @@ -16,12 +16,16 @@ #include #include +#include + #import "RetroArch_Apple.h" #include "rarch_wrapper.h" #include "apple/common/apple_input.h" #include "file.h" +static const void* const associated_core_key = &associated_core_key; + @interface RApplication : NSApplication @end @@ -45,7 +49,7 @@ bool _loaded; bool _wantReload; NSString* _file; - RAModuleInfo* _core; + NSString* _core; } + (RetroArch_OSX*)get @@ -72,15 +76,22 @@ // Create core select list NSComboBox* cb = (NSComboBox*)[_coreSelectSheet.contentView viewWithTag:1]; - - for (RAModuleInfo* i in apple_get_modules()) - [cb addItemWithObjectValue:i]; + + apple_core_info_set_core_path(self.coreDirectory.UTF8String); + apple_core_info_set_config_path(self.configDirectory.UTF8String); + const core_info_list_t* cores = apple_core_info_list_get(); + for (int i = 0; cores && i != cores->count; i ++) + { + NSString* desc = @(cores->list[i].display_name); + objc_setAssociatedObject(desc, associated_core_key, apple_get_core_id(&cores->list[i]), OBJC_ASSOCIATION_RETAIN_NONATOMIC); + [cb addItemWithObjectValue:desc]; + } if (cb.numberOfItems) [cb selectItemAtIndex:0]; else apple_display_alert(@"No libretro cores were found.\nSelect \"Go->Cores Directory\" from the menu and place libretro dylib files there.", @"RetroArch"); - + // Run RGUI if needed if (!_wantReload || apple_argv) apple_run_core(nil, 0); @@ -173,19 +184,19 @@ return; NSComboBox* cb = (NSComboBox*)[_coreSelectSheet.contentView viewWithTag:1]; - _core = (RAModuleInfo*)cb.objectValueOfSelectedItem; + _core = objc_getAssociatedObject(cb.objectValueOfSelectedItem, associated_core_key); [self runCore]; } #pragma mark RetroArch_Platform -- (void)loadingCore:(RAModuleInfo*)core withFile:(const char*)file +- (void)loadingCore:(const NSString*)core withFile:(const char*)file { if (file) [NSDocumentController.sharedDocumentController noteNewRecentDocumentURL:[NSURL fileURLWithPath:@(file)]]; } -- (void)unloadingCore:(RAModuleInfo*)core +- (void)unloadingCore:(const NSString*)core { if (_isTerminating) [NSApplication.sharedApplication terminate:nil]; diff --git a/apple/OSX/settings.m b/apple/OSX/settings.m index efb197ab1d..232cc5d686 100644 --- a/apple/OSX/settings.m +++ b/apple/OSX/settings.m @@ -21,112 +21,8 @@ #include "driver.h" #include "input/input_common.h" -struct settings fake_settings; -struct global fake_extern; - static const void* associated_name_tag = (void*)&associated_name_tag; -#define BINDFOR(s) (*(struct retro_keybind*)(&s)->value) - -static const char* key_name_for_id(uint32_t hidkey) -{ - for (int i = 0; apple_key_name_map[i].hid_id; i ++) - if (apple_key_name_map[i].hid_id == hidkey) - return apple_key_name_map[i].keyname; - - return "nul"; -} - -static uint32_t key_id_for_name(const char* name) -{ - for (int i = 0; apple_key_name_map[i].hid_id; i ++) - if (strcmp(name, apple_key_name_map[i].keyname) == 0) - return apple_key_name_map[i].hid_id; - - return 0; -} - -#define key_name_for_rk(X) key_name_for_id(input_translate_rk_to_keysym(X)) -#define key_rk_for_name(X) input_translate_keysym_to_rk(key_id_for_name(X)) - -static const char* get_input_config_key(const rarch_setting_t* setting, const char* type) -{ - static char buffer[32]; - if (setting->input_player) - snprintf(buffer, 32, "input_player%d_%s%c%s", setting->input_player, setting->name, type ? '_' : '\0', type); - else - snprintf(buffer, 32, "input_%s%c%s", setting->name, type ? '_' : '\0', type); - return buffer; -} - -static const char* get_button_name(const rarch_setting_t* setting) -{ - static char buffer[32]; - - if (BINDFOR(*setting).joykey == NO_BTN) - return "nul"; - - snprintf(buffer, 32, "%lld", BINDFOR(*setting).joykey); - return buffer; -} - -static const char* get_axis_name(const rarch_setting_t* setting) -{ - static char buffer[32]; - - uint32_t joyaxis = BINDFOR(*setting).joyaxis; - - if (AXIS_NEG_GET(joyaxis) != AXIS_DIR_NONE) - snprintf(buffer, 8, "-%d", AXIS_NEG_GET(joyaxis)); - else if (AXIS_POS_GET(joyaxis) != AXIS_DIR_NONE) - snprintf(buffer, 8, "+%d", AXIS_POS_GET(joyaxis)); - else - return "nul"; - - return buffer; -} - -@interface RANumberFormatter : NSNumberFormatter -@end - -@implementation RANumberFormatter -- (id)initWithFloatSupport:(bool)allowFloat minimum:(double)min maximum:(double)max -{ - self = [super init]; - self.allowsFloats = allowFloat; - self.maximumFractionDigits = 10; - - if (min || max) - { - self.minimum = [NSNumber numberWithInt:min]; - self.maximum = [NSNumber numberWithInt:max]; - } - - return self; -} - -- (BOOL)isPartialStringValid:(NSString*)partialString newEditingString:(NSString**)newString errorDescription:(NSString**)error -{ - bool hasDot = false; - - if (partialString.length) - for (int i = 0; i != partialString.length; i ++) - { - unichar ch = [partialString characterAtIndex:i]; - - if (i == 0 && (!self.minimum || self.minimum.intValue < 0) && ch == '-') - continue; - else if (self.allowsFloats && !hasDot && ch == '.') - hasDot = true; - else if (!isdigit(ch)) - return NO; - } - - return YES; -} -@end - - @interface RAInputBinder : NSWindow @end @@ -163,11 +59,9 @@ static const char* get_axis_name(const rarch_setting_t* setting) if (!_setting) return; - if (aSetting->type == ST_INT || aSetting->type == ST_FLOAT) + if (aSetting->type == ST_INT || aSetting->type == ST_UINT || aSetting->type == ST_FLOAT) { - self.textField.formatter = [[RANumberFormatter alloc] initWithFloatSupport:aSetting->type == ST_FLOAT - minimum:aSetting->min - maximum:aSetting->max]; + self.textField.formatter = [[RANumberFormatter alloc] initWithSetting:aSetting]; } else self.textField.formatter = nil; @@ -175,11 +69,12 @@ static const char* get_axis_name(const rarch_setting_t* setting) // Set value switch (aSetting->type) { - case ST_INT: self.numericValue = @(*(int*)aSetting->value); break; - case ST_FLOAT: self.numericValue = @(*(float*)aSetting->value); break; - case ST_STRING: self.stringValue = @((const char*)aSetting->value); break; - case ST_PATH: self.stringValue = @((const char*)aSetting->value); break; - case ST_BOOL: self.booleanValue = *(bool*)aSetting->value; break; + case ST_INT: self.numericValue = @(*aSetting->value.integer); break; + case ST_UINT: self.numericValue = @(*aSetting->value.unsigned_integer); break; + case ST_FLOAT: self.numericValue = @(*aSetting->value.fraction); break; + case ST_STRING: self.stringValue = @( aSetting->value.string); break; + case ST_PATH: self.stringValue = @( aSetting->value.string); break; + case ST_BOOL: self.booleanValue = *aSetting->value.boolean; break; case ST_BIND: [self updateInputString]; break; default: break; } @@ -199,9 +94,11 @@ static const char* get_axis_name(const rarch_setting_t* setting) _numericValue = numericValue; if (_setting && _setting->type == ST_INT) - *(int*)_setting->value = _numericValue.intValue; + *_setting->value.integer = _numericValue.intValue; + else if (_setting && _setting->type == ST_UINT) + *_setting->value.unsigned_integer = _numericValue.intValue; else if (_setting && _setting->type == ST_FLOAT) - *(float*)_setting->value = _numericValue.floatValue; + *_setting->value.fraction = _numericValue.floatValue; } - (void)setBooleanValue:(bool)booleanValue @@ -209,7 +106,7 @@ static const char* get_axis_name(const rarch_setting_t* setting) _booleanValue = booleanValue; if (_setting && _setting->type == ST_BOOL) - *(bool*)_setting->value = _booleanValue; + *_setting->value.boolean= _booleanValue; } - (void)setStringValue:(NSString *)stringValue @@ -217,15 +114,14 @@ static const char* get_axis_name(const rarch_setting_t* setting) _stringValue = stringValue ? stringValue : @""; if (_setting && (_setting->type == ST_STRING || _setting->type == ST_PATH)) - strlcpy(_setting->value, _stringValue.UTF8String, _setting->size); + strlcpy(_setting->value.string, _stringValue.UTF8String, _setting->size); } // Input Binding - (void)updateInputString { - self.stringValue = [NSString stringWithFormat:@"[KB:%s] [JS:%s] [AX:%s]", key_name_for_rk(BINDFOR(*_setting).key), - get_button_name(_setting), - get_axis_name(_setting)]; + char buffer[256]; + self.stringValue = @(setting_data_get_string_representation(_setting, buffer, sizeof(buffer))); } - (void)dismissBinder @@ -291,8 +187,9 @@ static const char* get_axis_name(const rarch_setting_t* setting) NSMutableArray* thisSubGroup = nil; _settings = [NSMutableArray array]; - memcpy(&fake_settings, &g_settings, sizeof(struct settings)); - memcpy(&fake_extern, &g_extern, sizeof(struct global)); + setting_data_load_current(); + + const rarch_setting_t* setting_data = setting_data_get_list(); for (int i = 0; setting_data[i].type; i ++) { @@ -334,67 +231,12 @@ static const char* get_axis_name(const rarch_setting_t* setting) } } - [self load]; -} - -- (void)load -{ - config_file_t* conf = config_file_new(apple_platform.globalConfigFile.UTF8String); - - for (int i = 0; setting_data[i].type; i ++) - { - switch (setting_data[i].type) - { - case ST_BOOL: config_get_bool (conf, setting_data[i].name, (bool*)setting_data[i].value); break; - case ST_INT: config_get_int (conf, setting_data[i].name, (int*)setting_data[i].value); break; - case ST_FLOAT: config_get_float (conf, setting_data[i].name, (float*)setting_data[i].value); break; - case ST_PATH: config_get_array (conf, setting_data[i].name, (char*)setting_data[i].value, setting_data[i].size); break; - case ST_STRING: config_get_array (conf, setting_data[i].name, (char*)setting_data[i].value, setting_data[i].size); break; - - case ST_BIND: - { - input_config_parse_key (conf, "input_player1", setting_data[i].name, setting_data[i].value); - input_config_parse_joy_button(conf, "input_player1", setting_data[i].name, setting_data[i].value); - input_config_parse_joy_axis (conf, "input_player1", setting_data[i].name, setting_data[i].value); - break; - } - - case ST_HEX: break; - default: break; - } - } - config_file_free(conf); + setting_data_load_config_path(setting_data_get_list(), apple_platform.globalConfigFile.UTF8String); } - (void)windowWillClose:(NSNotification *)notification { - config_file_t* conf = config_file_new(apple_platform.globalConfigFile.UTF8String); - conf = conf ? conf : config_file_new(0); - - for (int i = 0; setting_data[i].type; i ++) - { - switch (setting_data[i].type) - { - case ST_BOOL: config_set_bool (conf, setting_data[i].name, * (bool*)setting_data[i].value); break; - case ST_INT: config_set_int (conf, setting_data[i].name, * (int*)setting_data[i].value); break; - case ST_FLOAT: config_set_float (conf, setting_data[i].name, *(float*)setting_data[i].value); break; - case ST_PATH: config_set_string(conf, setting_data[i].name, (char*)setting_data[i].value); break; - case ST_STRING: config_set_string(conf, setting_data[i].name, (char*)setting_data[i].value); break; - - case ST_BIND: - { - config_set_string(conf, get_input_config_key(&setting_data[i], 0 ), key_name_for_rk(BINDFOR(setting_data[i]).key)); - config_set_string(conf, get_input_config_key(&setting_data[i], "btn" ), get_button_name(&setting_data[i])); - config_set_string(conf, get_input_config_key(&setting_data[i], "axis"), get_axis_name(&setting_data[i])); - break; - } - - case ST_HEX: break; - default: break; - } - } - config_file_write(conf, apple_platform.globalConfigFile.UTF8String); - config_file_free(conf); + setting_data_save_config_path(setting_data_get_list(), apple_platform.globalConfigFile.UTF8String); apple_exit_stasis(true); @@ -457,6 +299,7 @@ static const char* get_axis_name(const rarch_setting_t* setting) } else { + const rarch_setting_t* setting_data = setting_data_get_list(); const rarch_setting_t* setting = &setting_data[[item intValue]]; if ([tableColumn.identifier isEqualToString:@"title"]) @@ -466,13 +309,29 @@ static const char* get_axis_name(const rarch_setting_t* setting) RASettingCell* s = nil; switch (setting->type) { - case ST_BOOL: s = [outlineView makeViewWithIdentifier:@"RABooleanSetting" owner:nil]; break; - case ST_INT: s = [outlineView makeViewWithIdentifier:@"RANumericSetting" owner:nil]; break; - case ST_FLOAT: s = [outlineView makeViewWithIdentifier:@"RANumericSetting" owner:nil]; break; - case ST_PATH: s = [outlineView makeViewWithIdentifier:@"RAPathSetting" owner:nil]; break; - case ST_STRING: s = [outlineView makeViewWithIdentifier:@"RAStringSetting" owner:nil]; break; - case ST_BIND: s = [outlineView makeViewWithIdentifier:@"RABindSetting" owner:nil]; break; - default: break; + case ST_BOOL: + s = [outlineView makeViewWithIdentifier:@"RABooleanSetting" owner:nil]; + break; + case ST_INT: + s = [outlineView makeViewWithIdentifier:@"RANumericSetting" owner:nil]; + break; + case ST_UINT: + s = [outlineView makeViewWithIdentifier:@"RANumericSetting" owner:nil]; + break; + case ST_FLOAT: + s = [outlineView makeViewWithIdentifier:@"RANumericSetting" owner:nil]; + break; + case ST_PATH: + s = [outlineView makeViewWithIdentifier:@"RAPathSetting" owner:nil]; + break; + case ST_STRING: + s = [outlineView makeViewWithIdentifier:@"RAStringSetting" owner:nil]; + break; + case ST_BIND: + s = [outlineView makeViewWithIdentifier:@"RABindSetting" owner:nil]; + break; + default: + break; } s.setting = setting; return s; diff --git a/apple/RetroArch_OSX.xcodeproj/project.pbxproj b/apple/RetroArch_OSX.xcodeproj/project.pbxproj index 70d60caf1b..c05be1a65f 100644 --- a/apple/RetroArch_OSX.xcodeproj/project.pbxproj +++ b/apple/RetroArch_OSX.xcodeproj/project.pbxproj @@ -17,7 +17,6 @@ 967894941788ECDB00D6CA69 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 967894911788ECDB00D6CA69 /* MainMenu.xib */; }; 967894961788ED1100D6CA69 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 967894951788ED1100D6CA69 /* main.m */; }; 9678949D1788F02600D6CA69 /* RAGameView.m in Sources */ = {isa = PBXBuildFile; fileRef = 967894971788F02600D6CA69 /* RAGameView.m */; }; - 9678949E1788F02600D6CA69 /* RAModuleInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 967894991788F02600D6CA69 /* RAModuleInfo.m */; }; 9678949F1788F02600D6CA69 /* utility.m in Sources */ = {isa = PBXBuildFile; fileRef = 9678949C1788F02600D6CA69 /* utility.m */; }; 967894A11788F07D00D6CA69 /* griffin.c in Sources */ = {isa = PBXBuildFile; fileRef = 967894A01788F07D00D6CA69 /* griffin.c */; }; 967894A41788F0C200D6CA69 /* CoreAudio.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 967894A21788F0C200D6CA69 /* CoreAudio.framework */; }; @@ -45,8 +44,6 @@ 967894921788ECDB00D6CA69 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = OSX/en.lproj/MainMenu.xib; sourceTree = SOURCE_ROOT; }; 967894951788ED1100D6CA69 /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 967894971788F02600D6CA69 /* RAGameView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RAGameView.m; sourceTree = ""; }; - 967894981788F02600D6CA69 /* RAModuleInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RAModuleInfo.h; sourceTree = ""; }; - 967894991788F02600D6CA69 /* RAModuleInfo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RAModuleInfo.m; sourceTree = ""; }; 9678949A1788F02600D6CA69 /* rarch_wrapper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = rarch_wrapper.h; sourceTree = ""; }; 9678949B1788F02600D6CA69 /* RetroArch_Apple.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RetroArch_Apple.h; sourceTree = ""; }; 9678949C1788F02600D6CA69 /* utility.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = utility.m; sourceTree = ""; }; @@ -119,8 +116,6 @@ 9620F662178FD4D3001B3B81 /* settings.m */, 967894A01788F07D00D6CA69 /* griffin.c */, 967894971788F02600D6CA69 /* RAGameView.m */, - 967894981788F02600D6CA69 /* RAModuleInfo.h */, - 967894991788F02600D6CA69 /* RAModuleInfo.m */, 9678949A1788F02600D6CA69 /* rarch_wrapper.h */, 9678949B1788F02600D6CA69 /* RetroArch_Apple.h */, 9678949C1788F02600D6CA69 /* utility.m */, @@ -219,7 +214,6 @@ files = ( 967894961788ED1100D6CA69 /* main.m in Sources */, 9678949D1788F02600D6CA69 /* RAGameView.m in Sources */, - 9678949E1788F02600D6CA69 /* RAModuleInfo.m in Sources */, 9678949F1788F02600D6CA69 /* utility.m in Sources */, 967894A11788F07D00D6CA69 /* griffin.c in Sources */, 9620F663178FD4D3001B3B81 /* settings.m in Sources */, diff --git a/apple/RetroArch_iOS.xcodeproj/project.pbxproj b/apple/RetroArch_iOS.xcodeproj/project.pbxproj index 4511385729..9b9d50cce5 100644 --- a/apple/RetroArch_iOS.xcodeproj/project.pbxproj +++ b/apple/RetroArch_iOS.xcodeproj/project.pbxproj @@ -7,7 +7,7 @@ objects = { /* Begin PBXBuildFile section */ - 9605EA9B170288EA001D47B0 /* RAModuleInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 9605EA9A170288EA001D47B0 /* RAModuleInfo.m */; }; + 509FC979183F9F18007A5A30 /* menu.m in Sources */ = {isa = PBXBuildFile; fileRef = 509FC978183F9F18007A5A30 /* menu.m */; }; 962979F616C43B9500E6DCE0 /* ic_dir.png in Resources */ = {isa = PBXBuildFile; fileRef = 962979F416C43B9500E6DCE0 /* ic_dir.png */; }; 962979F716C43B9500E6DCE0 /* ic_file.png in Resources */ = {isa = PBXBuildFile; fileRef = 962979F516C43B9500E6DCE0 /* ic_file.png */; }; 96297A0F16C5AEA100E6DCE0 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 96297A0E16C5AEA100E6DCE0 /* main.m */; }; @@ -22,13 +22,9 @@ 966B9CC116E41E7A005B61E1 /* Default@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 966B9CBA16E41E7A005B61E1 /* Default@2x.png */; }; 966B9CC316E41E7A005B61E1 /* Icon-72.png in Resources */ = {isa = PBXBuildFile; fileRef = 966B9CBB16E41E7A005B61E1 /* Icon-72.png */; }; 966B9CC516E41E7A005B61E1 /* Icon.png in Resources */ = {isa = PBXBuildFile; fileRef = 966B9CBC16E41E7A005B61E1 /* Icon.png */; }; - 966B9CC916E41EC1005B61E1 /* PauseView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 966B9CC716E41EC1005B61E1 /* PauseView.xib */; }; 966B9CCB16E41EC1005B61E1 /* PauseIndicatorView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 966B9CC816E41EC1005B61E1 /* PauseIndicatorView.xib */; }; 9678945B1788EAAE00D6CA69 /* browser.m in Sources */ = {isa = PBXBuildFile; fileRef = 967894571788EAAE00D6CA69 /* browser.m */; }; - 9678945C1788EAAE00D6CA69 /* RALogView.m in Sources */ = {isa = PBXBuildFile; fileRef = 967894581788EAAE00D6CA69 /* RALogView.m */; }; - 9678945D1788EAAE00D6CA69 /* settings.m in Sources */ = {isa = PBXBuildFile; fileRef = 967894591788EAAE00D6CA69 /* settings.m */; }; 967894631788EBD800D6CA69 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 967894611788EBD800D6CA69 /* InfoPlist.strings */; }; - 967D646F16E45428006BA1F2 /* ic_pause.png in Resources */ = {isa = PBXBuildFile; fileRef = 967D646E16E45428006BA1F2 /* ic_pause.png */; }; 967D647516E6EA04006BA1F2 /* modules in Resources */ = {isa = PBXBuildFile; fileRef = 967D647416E6EA04006BA1F2 /* modules */; }; 96AFAE2A16C1D4EA009DE44C /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 96AFAE2916C1D4EA009DE44C /* UIKit.framework */; }; 96AFAE2C16C1D4EA009DE44C /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 96AFAE2B16C1D4EA009DE44C /* Foundation.framework */; }; @@ -39,8 +35,7 @@ /* End PBXBuildFile section */ /* Begin PBXFileReference section */ - 9605EA99170288EA001D47B0 /* RAModuleInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RAModuleInfo.h; sourceTree = ""; }; - 9605EA9A170288EA001D47B0 /* RAModuleInfo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RAModuleInfo.m; sourceTree = ""; }; + 509FC978183F9F18007A5A30 /* menu.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = menu.m; path = iOS/menu.m; sourceTree = SOURCE_ROOT; }; 962979F416C43B9500E6DCE0 /* ic_dir.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = ic_dir.png; path = "../../android/phoenix/res/drawable-xhdpi/ic_dir.png"; sourceTree = ""; }; 962979F516C43B9500E6DCE0 /* ic_file.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = ic_file.png; path = "../../android/phoenix/res/drawable-xhdpi/ic_file.png"; sourceTree = ""; }; 96297A0E16C5AEA100E6DCE0 /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; @@ -56,15 +51,11 @@ 966B9CBA16E41E7A005B61E1 /* Default@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default@2x.png"; sourceTree = ""; }; 966B9CBB16E41E7A005B61E1 /* Icon-72.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Icon-72.png"; sourceTree = ""; }; 966B9CBC16E41E7A005B61E1 /* Icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Icon.png; sourceTree = ""; }; - 966B9CC716E41EC1005B61E1 /* PauseView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = PauseView.xib; sourceTree = ""; }; 966B9CC816E41EC1005B61E1 /* PauseIndicatorView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = PauseIndicatorView.xib; sourceTree = ""; }; 967894571788EAAE00D6CA69 /* browser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = browser.m; path = iOS/browser.m; sourceTree = SOURCE_ROOT; }; - 967894581788EAAE00D6CA69 /* RALogView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RALogView.m; path = iOS/RALogView.m; sourceTree = SOURCE_ROOT; }; - 967894591788EAAE00D6CA69 /* settings.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = settings.m; path = iOS/settings.m; sourceTree = SOURCE_ROOT; }; 9678945A1788EAAE00D6CA69 /* views.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = views.h; path = iOS/views.h; sourceTree = SOURCE_ROOT; }; 9678945F1788EBD000D6CA69 /* RetroArch-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = "RetroArch-Info.plist"; path = "iOS/RetroArch-Info.plist"; sourceTree = SOURCE_ROOT; }; 967894621788EBD800D6CA69 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = iOS/en.lproj/InfoPlist.strings; sourceTree = SOURCE_ROOT; }; - 967D646E16E45428006BA1F2 /* ic_pause.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = ic_pause.png; sourceTree = ""; }; 967D647416E6EA04006BA1F2 /* modules */ = {isa = PBXFileReference; lastKnownFileType = folder; path = modules; sourceTree = SOURCE_ROOT; }; 96AFAE2516C1D4EA009DE44C /* RetroArch.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = RetroArch.app; sourceTree = BUILT_PRODUCTS_DIR; }; 96AFAE2916C1D4EA009DE44C /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; @@ -108,10 +99,8 @@ 966B9CBA16E41E7A005B61E1 /* Default@2x.png */, 962979F416C43B9500E6DCE0 /* ic_dir.png */, 962979F516C43B9500E6DCE0 /* ic_file.png */, - 967D646E16E45428006BA1F2 /* ic_pause.png */, 966B9CBB16E41E7A005B61E1 /* Icon-72.png */, 966B9CBC16E41E7A005B61E1 /* Icon.png */, - 966B9CC716E41EC1005B61E1 /* PauseView.xib */, 966B9CC816E41EC1005B61E1 /* PauseIndicatorView.xib */, ); path = Assets; @@ -154,15 +143,12 @@ 96AFAE3316C1D4EA009DE44C /* common */ = { isa = PBXGroup; children = ( + 509FC978183F9F18007A5A30 /* menu.m */, 9646869417BBBEAE00C5EA69 /* platform.m */, 967894571788EAAE00D6CA69 /* browser.m */, - 967894581788EAAE00D6CA69 /* RALogView.m */, - 967894591788EAAE00D6CA69 /* settings.m */, 9678945A1788EAAE00D6CA69 /* views.h */, 96297A0E16C5AEA100E6DCE0 /* main.m */, 963F5AC516CC523B009BBD19 /* RAGameView.m */, - 9605EA9A170288EA001D47B0 /* RAModuleInfo.m */, - 9605EA99170288EA001D47B0 /* RAModuleInfo.h */, 96C19C2616D455BE00FE8D5A /* rarch_wrapper.h */, 96355CD11788CF190010DBFA /* RetroArch_Apple.h */, 96337E81176AC6E5004685F3 /* utility.m */, @@ -285,9 +271,7 @@ 966B9CC116E41E7A005B61E1 /* Default@2x.png in Resources */, 966B9CC316E41E7A005B61E1 /* Icon-72.png in Resources */, 966B9CC516E41E7A005B61E1 /* Icon.png in Resources */, - 966B9CC916E41EC1005B61E1 /* PauseView.xib in Resources */, 966B9CCB16E41EC1005B61E1 /* PauseIndicatorView.xib in Resources */, - 967D646F16E45428006BA1F2 /* ic_pause.png in Resources */, 967D647516E6EA04006BA1F2 /* modules in Resources */, 967894631788EBD800D6CA69 /* InfoPlist.strings in Resources */, ); @@ -303,11 +287,9 @@ 96297A0F16C5AEA100E6DCE0 /* main.m in Sources */, 963F5AC816CC523B009BBD19 /* RAGameView.m in Sources */, D48581DE16F823F9004BEB17 /* griffin.c in Sources */, - 9605EA9B170288EA001D47B0 /* RAModuleInfo.m in Sources */, 96337E82176AC6E5004685F3 /* utility.m in Sources */, + 509FC979183F9F18007A5A30 /* menu.m in Sources */, 9678945B1788EAAE00D6CA69 /* browser.m in Sources */, - 9678945C1788EAAE00D6CA69 /* RALogView.m in Sources */, - 9678945D1788EAAE00D6CA69 /* settings.m in Sources */, 9646869517BBBEAE00C5EA69 /* platform.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/apple/common/RAGameView.m b/apple/common/RAGameView.m index 1682cb828c..60dc293189 100644 --- a/apple/common/RAGameView.m +++ b/apple/common/RAGameView.m @@ -16,7 +16,7 @@ #import "RetroArch_Apple.h" #include "rarch_wrapper.h" -#include "general.h" +#include "../../general.h" #include "gfx/gfx_common.h" #include "gfx/gfx_context.h" @@ -60,10 +60,10 @@ #ifdef IOS +#include #import "views.h" static const float ALMOST_INVISIBLE = .021f; static GLKView* g_view; -static UIView* g_pause_view; static UIView* g_pause_indicator_view; static UITextField* g_text_hide; @@ -154,16 +154,12 @@ static bool g_is_syncing = true; { self = [super init]; - UINib* xib = [UINib nibWithNibName:@"PauseView" bundle:nil]; - g_pause_view = [[xib instantiateWithOwner:[RetroArch_iOS get] options:nil] lastObject]; - - xib = [UINib nibWithNibName:@"PauseIndicatorView" bundle:nil]; + UINib *xib = [UINib nibWithNibName:@"PauseIndicatorView" bundle:nil]; g_pause_indicator_view = [[xib instantiateWithOwner:[RetroArch_iOS get] options:nil] lastObject]; g_view = [GLKView new]; g_view.multipleTouchEnabled = YES; g_view.enableSetNeedsDisplay = NO; - [g_view addSubview:g_pause_view]; [g_view addSubview:g_pause_indicator_view]; if (is_ios_7()) @@ -190,7 +186,6 @@ static bool g_is_syncing = true; float tenpctw = width / 10.0f; float tenpcth = height / 10.0f; - g_pause_view.frame = CGRectMake(width / 2.0f - 150.0f, height / 2.0f - 150.0f, 300.0f, 300.0f); g_pause_indicator_view.frame = CGRectMake(tenpctw * 4.0f, 0.0f, tenpctw * 2.0f, tenpcth); [g_pause_indicator_view viewWithTag:1].frame = CGRectMake(0, 0, tenpctw * 2.0f, tenpcth); @@ -198,30 +193,6 @@ static bool g_is_syncing = true; [g_text_hide becomeFirstResponder]; } -- (void)openPauseMenu -{ - // Setup save state selector - UISegmentedControl* stateSelect = (UISegmentedControl*)[g_pause_view viewWithTag:10]; - stateSelect.selectedSegmentIndex = (g_extern.state_slot < 10) ? g_extern.state_slot : -1; - - g_extern.is_paused = true; - - // - [UIView animateWithDuration:0.2 - animations:^{ g_pause_view.alpha = 1.0f; } - completion:^(BOOL finished) { }]; -} - -- (void)closePauseMenu -{ - [UIView animateWithDuration:0.2 - animations:^{ g_pause_view.alpha = 0.0f; } - completion:^(BOOL finished) { } - ]; - - g_extern.is_paused = false; -} - - (void)hidePauseButton { [UIView animateWithDuration:0.2 @@ -271,7 +242,7 @@ static RAScreen* get_chosen_screen() #endif } -bool apple_gfx_ctx_init() +bool apple_gfx_ctx_init(void) { dispatch_sync(dispatch_get_main_queue(), ^{ @@ -290,7 +261,7 @@ bool apple_gfx_ctx_init() return true; } -void apple_gfx_ctx_destroy() +void apple_gfx_ctx_destroy(void) { g_initialized = false; diff --git a/apple/common/RAModuleInfo.h b/apple/common/RAModuleInfo.h deleted file mode 100644 index 65c4553156..0000000000 --- a/apple/common/RAModuleInfo.h +++ /dev/null @@ -1,45 +0,0 @@ -/* RetroArch - A frontend for libretro. - * Copyright (C) 2013 - Jason Fetters - * - * RetroArch is free software: you can redistribute it and/or modify it under the terms - * of the GNU General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with RetroArch. - * If not, see . - */ - -#ifndef _RA_MODULE_INFO_H -#define _RA_MODULE_INFO_H - -#import -#include "compat/apple_compat.h" - -#include "conf/config_file.h" -#include "core_info.h" - -extern NSArray* apple_get_modules(); - -@interface RAModuleInfo : NSObject -@property (nonatomic) NSString* path; // e.g. /path/to/corename_libretro.dylib -@property (nonatomic) NSString* baseName; // e.g. corename_libretro -@property (nonatomic) core_info_t* info; -@property (nonatomic) config_file_t* data; -@property (nonatomic) NSString* description; // Friendly name from config file, else just the filename -@property (nonatomic) NSString* customConfigFile; // Path where custom config file would reside -@property (nonatomic) NSString* configFile; // Path to effective config file - -- (bool)supportsFileAtPath:(NSString*)path; - -- (void)createCustomConfig; -- (void)deleteCustomConfig; -- (bool)hasCustomConfig; - -@end - -#endif - diff --git a/apple/common/RAModuleInfo.m b/apple/common/RAModuleInfo.m deleted file mode 100644 index 348d4901a6..0000000000 --- a/apple/common/RAModuleInfo.m +++ /dev/null @@ -1,185 +0,0 @@ -/* RetroArch - A frontend for libretro. - * Copyright (C) 2013 - Jason Fetters - * - * RetroArch is free software: you can redistribute it and/or modify it under the terms - * of the GNU General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with RetroArch. - * If not, see . - */ - -#import "RetroArch_Apple.h" -#import "RAModuleInfo.h" - -#include "file.h" -#include "core_info.h" - -static NSMutableArray* moduleList; -static core_info_list_t* coreList; - -NSArray* apple_get_modules() -{ - if (!moduleList) - { - coreList = core_info_list_new(apple_platform.coreDirectory.UTF8String); - - if (!coreList) - return nil; - - moduleList = [NSMutableArray arrayWithCapacity:coreList->count]; - - for (int i = 0; coreList && i < coreList->count; i ++) - { - core_info_t* core = &coreList->list[i]; - - RAModuleInfo* newInfo = [RAModuleInfo new]; - newInfo.path = [NSString stringWithCString:core->path encoding:NSUTF8StringEncoding]; - newInfo.baseName = newInfo.path.lastPathComponent.stringByDeletingPathExtension; - newInfo.info = core; - newInfo.data = core->data; - newInfo.description = [NSString stringWithCString:core->display_name encoding:NSUTF8StringEncoding]; - newInfo.customConfigFile = [NSString stringWithFormat:@"%@/%@.cfg", apple_platform.configDirectory, newInfo.baseName]; - newInfo.configFile = newInfo.hasCustomConfig ? newInfo.customConfigFile : apple_platform.globalConfigFile; - - [moduleList addObject:newInfo]; - } - - [moduleList sortUsingComparator:^(RAModuleInfo* left, RAModuleInfo* right) - { - return [left.description caseInsensitiveCompare:right.description]; - }]; - } - - return moduleList; -} - -@implementation RAModuleInfo - -- (id)copyWithZone:(NSZone *)zone -{ - return self; -} - -- (bool)supportsFileAtPath:(NSString*)path -{ - return core_info_does_support_file(self.info, path.UTF8String); -} - -- (void)createCustomConfig -{ - if (!self.hasCustomConfig) - [NSFileManager.defaultManager copyItemAtPath:apple_platform.globalConfigFile toPath:self.customConfigFile error:nil]; -} - -- (void)deleteCustomConfig -{ - if (self.hasCustomConfig) - [NSFileManager.defaultManager removeItemAtPath:self.customConfigFile error:nil]; -} - -- (bool)hasCustomConfig -{ - return path_file_exists(self.customConfigFile.UTF8String); -} - -@end - -#ifdef IOS -#import "../iOS/views.h" - -static const void* const associated_string_key = &associated_string_key; - -// Build a string with a second associated string -static NSString* build_string_pair(NSString* stringA, NSString* stringB) -{ - NSString* string_pair = [NSString stringWithString:stringA]; - objc_setAssociatedObject(string_pair, associated_string_key, stringB, OBJC_ASSOCIATION_RETAIN_NONATOMIC); - return string_pair; -} - -@implementation RAModuleInfoList -{ - RAModuleInfo* _data; - uint32_t _firmwareSectionIndex; -} - -- (id)initWithModuleInfo:(RAModuleInfo*)info -{ - self = [super initWithStyle:UITableViewStyleGrouped]; - - _data = info; - - [self.sections addObject: [NSArray arrayWithObjects:@"Core", - build_string_pair(@"Core Name", objc_get_value_from_config(_data.data, @"corename", @"Unspecified")), - nil]]; - - [self.sections addObject: [NSArray arrayWithObjects:@"Hardware/Software", - build_string_pair(@"Developer", objc_get_value_from_config(_data.data, @"manufacturer", @"Unspecified")), - build_string_pair(@"Name", objc_get_value_from_config(_data.data, @"systemname", @"Unspecified")), - nil]]; - - // Firmware - _firmwareSectionIndex = 1000; - uint32_t firmwareCount = 0; - if (_data.data && config_get_uint(_data.data, "firmware_count", &firmwareCount) && firmwareCount) - { - NSMutableArray* firmwareSection = [NSMutableArray arrayWithObject:@"Firmware"]; - - for (int i = 0; i < firmwareCount; i ++) - { - NSString* path = objc_get_value_from_config(_data.data, [NSString stringWithFormat:@"firmware%d_path", i], @"Unspecified"); - path = [path stringByReplacingOccurrencesOfString:@"%sysdir%" withString:[RetroArch_iOS get].systemDirectory]; - [firmwareSection addObject:build_string_pair(objc_get_value_from_config(_data.data, [NSString stringWithFormat:@"firmware%d_desc", i], @"Unspecified"), path)]; - } - - _firmwareSectionIndex = self.sections.count; - [self.sections addObject:firmwareSection]; - } - - return self; -} - -- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath -{ - if (indexPath.section == _firmwareSectionIndex) - { - NSString* item = (NSString*)[self itemForIndexPath:indexPath]; - apple_display_alert(objc_getAssociatedObject(item, associated_string_key), item); - } -} - -- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath -{ - static NSString* const cell_id = @"datacell"; - - UITableViewCell* cell = [self.tableView dequeueReusableCellWithIdentifier:cell_id]; - - if (!cell) - { - cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:cell_id]; - cell.selectionStyle = UITableViewCellSelectionStyleNone; - cell.detailTextLabel.adjustsFontSizeToFitWidth = YES; - } - - NSString* item = (NSString*)[self itemForIndexPath:indexPath]; - NSString* value = (NSString*)objc_getAssociatedObject(item, associated_string_key); - - cell.textLabel.text = item; - cell.detailTextLabel.text = value; - - if (indexPath.section == _firmwareSectionIndex) - cell.backgroundColor = path_file_exists(value.UTF8String) ? [UIColor blueColor] : [UIColor redColor]; - else - cell.backgroundColor = [UIColor whiteColor]; - - return cell; -} - -@end - -#endif diff --git a/apple/common/RetroArch_Apple.h b/apple/common/RetroArch_Apple.h index ef74ae22ea..b3c233b46a 100644 --- a/apple/common/RetroArch_Apple.h +++ b/apple/common/RetroArch_Apple.h @@ -19,15 +19,18 @@ #include #import -#import "RAModuleInfo.h" + +#include "core_info.h" +#include "core_info_ext.h" +#include "setting_data.h" #include "apple_export.h" #define GSEVENT_TYPE_KEYDOWN 10 #define GSEVENT_TYPE_KEYUP 11 @protocol RetroArch_Platform -- (void)loadingCore:(RAModuleInfo*)core withFile:(const char*)file; -- (void)unloadingCore:(RAModuleInfo*)core; +- (void)loadingCore:(NSString*)core withFile:(const char*)file; +- (void)unloadingCore:(NSString*)core; - (NSString*)configDirectory; // < This returns the directory that contains retroarch.cfg and other custom configs - (NSString*)globalConfigFile; // < This is the full path to retroarch.cfg @@ -35,6 +38,7 @@ @end #ifdef IOS +#include #import "../iOS/platform.h" #elif defined(OSX) #import "../OSX/platform.h" @@ -44,16 +48,26 @@ extern char** apple_argv; extern bool apple_is_paused; extern bool apple_is_running; extern bool apple_use_tv_mode; -extern RAModuleInfo* apple_core; +extern NSString* apple_core; extern id apple_platform; // main.m -extern void apple_run_core(RAModuleInfo* core, const char* file); +extern void apple_run_core(NSString* core, const char* file); // utility.m extern void apple_display_alert(NSString* message, NSString* title); -extern NSString* objc_get_value_from_config(config_file_t* config, NSString* name, NSString* defaultValue); +extern NSString *objc_get_value_from_config(config_file_t* config, NSString* name, NSString* defaultValue); +extern NSString *apple_get_core_id(const core_info_t *core); +extern NSString *apple_get_core_display_name(NSString *core_id); + +@interface RANumberFormatter : NSNumberFormatter +#ifdef IOS + +#endif + +- (id)initWithSetting:(const rarch_setting_t*)setting; +@end // frontend/platform/platform_apple.c extern void apple_frontend_post_event(void (*fn)(void*), void* userdata); diff --git a/apple/common/apple_input.c b/apple/common/apple_input.c index 2230d46eed..6031cd5a4b 100644 --- a/apple/common/apple_input.c +++ b/apple/common/apple_input.c @@ -86,12 +86,12 @@ void apple_input_enable_icade(bool on) icade_buttons = 0; } -uint32_t apple_input_get_icade_buttons() +uint32_t apple_input_get_icade_buttons(void) { return icade_enabled ? icade_buttons : 0; } -void apple_input_reset_icade_buttons() +void apple_input_reset_icade_buttons(void) { icade_buttons = 0; } @@ -107,8 +107,10 @@ void apple_input_handle_key_event(unsigned keycode, bool down) } -int32_t apple_input_find_any_key() +int32_t apple_input_find_any_key(void) { + input_init_keyboard_lut(apple_key_map_hidusage); + for (int i = 0; apple_key_name_map[i].hid_id; i++) if (g_current_input_data.keys[apple_key_name_map[i].hid_id]) return apple_key_name_map[i].hid_id; diff --git a/apple/common/apple_input.h b/apple/common/apple_input.h index 67c4525617..08c3f0c256 100644 --- a/apple/common/apple_input.h +++ b/apple/common/apple_input.h @@ -67,11 +67,11 @@ extern apple_input_data_t g_polled_input_data; // Main thread only void apple_input_enable_icade(bool on); -uint32_t apple_input_get_icade_buttons(); -void apple_input_reset_icade_buttons(); +uint32_t apple_input_get_icade_buttons(void); +void apple_input_reset_icade_buttons(void); void apple_input_handle_key_event(unsigned keycode, bool down); -extern int32_t apple_input_find_any_key(); +extern int32_t apple_input_find_any_key(void); extern int32_t apple_input_find_any_button(uint32_t port); extern int32_t apple_input_find_any_axis(uint32_t port); diff --git a/apple/common/core_info_ext.c b/apple/common/core_info_ext.c new file mode 100644 index 0000000000..2d16512391 --- /dev/null +++ b/apple/common/core_info_ext.c @@ -0,0 +1,112 @@ +/* RetroArch - A frontend for libretro. + * Copyright (C) 2013 - Jason Fetters + * + * RetroArch is free software: you can redistribute it and/or modify it under the terms + * of the GNU General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with RetroArch. + * If not, see . + */ + +#include "core_info_ext.h" + +static core_info_list_t* global_core_list = 0; +static char core_config_path[PATH_MAX]; + +void apple_core_info_set_core_path(const char* core_path) +{ + if (global_core_list) + core_info_list_free(global_core_list); + + global_core_list = core_path ? core_info_list_new(core_path) : 0; + + if (!global_core_list) + RARCH_WARN("No cores were found at %s", core_path ? core_path : "(null"); +} + +void apple_core_info_set_config_path(const char* config_path) +{ + if (!config_path || strlcpy(core_config_path, config_path, sizeof(core_config_path)) >= PATH_MAX) + *core_config_path = '\0'; +} + +core_info_list_t* apple_core_info_list_get(void) +{ + if (!global_core_list) + RARCH_WARN("apple_core_info_list_get() called before apple_core_info_set_core_path()"); + + return global_core_list; +} + +const core_info_t* apple_core_info_list_get_by_id(const char* core_id) +{ + if (core_id) + { + const core_info_list_t* cores = apple_core_info_list_get(); + + for (int i = 0; i != cores->count; i ++) + if (cores->list[i].path && strcmp(core_id, cores->list[i].path) == 0) + return &cores->list[i]; + } + + return 0; +} + +const char* apple_core_info_get_id(const core_info_t* info, char* buffer, size_t buffer_length) +{ + if (!buffer || !buffer_length) + return ""; + + if (info && info->path && strlcpy(buffer, info->path, buffer_length) < buffer_length) + return buffer; + + *buffer = 0; + return buffer; +} + +const char* apple_core_info_get_custom_config(const char* core_id, char* buffer, size_t buffer_length) +{ + if (!core_id || !buffer || !buffer_length) + return 0; + + snprintf(buffer, buffer_length, "%s/%s", core_config_path, path_basename(core_id)); + fill_pathname(buffer, buffer, ".cfg", buffer_length); + return buffer; +} + +bool apple_core_info_has_custom_config(const char* core_id) +{ + if (!core_id) + return false; + + char path[PATH_MAX]; + apple_core_info_get_custom_config(core_id, path, sizeof(path)); + return path_file_exists(path); +} + +// ROM HISTORY EXTENSIONS +const char* apple_rom_history_get_path(rom_history_t* history, uint32_t index) +{ + const char *path, *core_path, *core_name; + rom_history_get_index(history, index, &path, &core_path, &core_name); + return path ? path : ""; +} + +const char* apple_rom_history_get_core_path(rom_history_t* history, uint32_t index) +{ + const char *path, *core_path, *core_name; + rom_history_get_index(history, index, &path, &core_path, &core_name); + return core_path ? core_path : ""; +} + +const char* apple_rom_history_get_core_name(rom_history_t* history, uint32_t index) +{ + const char *path, *core_path, *core_name; + rom_history_get_index(history, index, &path, &core_path, &core_name); + return core_name ? core_name : ""; +} diff --git a/apple/common/core_info_ext.h b/apple/common/core_info_ext.h new file mode 100644 index 0000000000..a406ec883d --- /dev/null +++ b/apple/common/core_info_ext.h @@ -0,0 +1,38 @@ +/* RetroArch - A frontend for libretro. + * Copyright (C) 2013 - Jason Fetters + * + * RetroArch is free software: you can redistribute it and/or modify it under the terms + * of the GNU General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with RetroArch. + * If not, see . + */ + +#ifndef __APPLE_RARCH_CORE_INFO_EXT_H__ +#define __APPLE_RARCH_CORE_INFO_EXT_H__ + +#include "core_info.h" +#include "frontend/menu/history.h" + +void apple_core_info_set_core_path(const char* core_path); +void apple_core_info_set_config_path(const char* config_path); + +core_info_list_t* apple_core_info_list_get(void); +const core_info_t* apple_core_info_list_get_by_id(const char* core_id); +const char* apple_core_info_get_id(const core_info_t* info, char* buffer, size_t buffer_length); + +const char* apple_core_info_get_custom_config(const char* core_id, char* buffer, size_t buffer_length); +bool apple_core_info_has_custom_config(const char* core_id); + + +// ROM HISTORY EXTENSIONS +const char* apple_rom_history_get_path(rom_history_t* history, uint32_t index); +const char* apple_rom_history_get_core_path(rom_history_t* history, uint32_t index); +const char* apple_rom_history_get_core_name(rom_history_t* history, uint32_t index); + +#endif diff --git a/apple/common/main.m b/apple/common/main.m index 1339728cf8..94e4183667 100644 --- a/apple/common/main.m +++ b/apple/common/main.m @@ -1,5 +1,6 @@ /* RetroArch - A frontend for libretro. * Copyright (C) 2013 - Jason Fetters + * Copyright (C) 2011-2013 - Daniel De Matteis * * RetroArch is free software: you can redistribute it and/or modify it under the terms * of the GNU General Public License as published by the Free Software Found- @@ -29,15 +30,18 @@ id apple_platform; #pragma mark EMULATION static pthread_t apple_retro_thread; -bool apple_is_paused; bool apple_is_running; bool apple_use_tv_mode; -RAModuleInfo* apple_core; +NSString* apple_core; -void apple_run_core(RAModuleInfo* core, const char* file) +void apple_run_core(NSString* core, const char* file) { if (!apple_is_running) { + if (file && access([@(file) stringByDeletingLastPathComponent].UTF8String, R_OK | W_OK | X_OK)) + apple_display_alert(@"The directory containing the selected file has limited permissions. This may " + "prevent zipped games from loading, and will cause some cores to not function.", 0); + [apple_platform loadingCore:core withFile:file]; apple_core = core; @@ -49,15 +53,17 @@ void apple_run_core(RAModuleInfo* core, const char* file) if (!apple_argv) { - NSString* config_to_use = apple_core ? apple_core.configFile : apple_platform.globalConfigFile; - strlcpy(config_path, config_to_use.UTF8String, sizeof(config_path)); + if (apple_core_info_has_custom_config(apple_core.UTF8String)) + apple_core_info_get_custom_config(apple_core.UTF8String, config_path, sizeof(config_path)); + else + strlcpy(config_path, apple_platform.globalConfigFile.UTF8String, sizeof(config_path)); static const char* const argv_game[] = { "retroarch", "-c", config_path, "-L", core_path, file_path, 0 }; static const char* const argv_menu[] = { "retroarch", "-c", config_path, "--menu", 0 }; if (file && core) { - strlcpy(core_path, apple_core.path.UTF8String, sizeof(core_path)); + strlcpy(core_path, apple_core.UTF8String, sizeof(core_path)); strlcpy(file_path, file, sizeof(file_path)); } @@ -83,8 +89,8 @@ void apple_rarch_exited(void* result) if (result) apple_display_alert(@"Failed to load game.", 0); - RAModuleInfo* used_core = apple_core; - apple_core = nil; + NSString* used_core = apple_core; + apple_core = 0; if (apple_is_running) { diff --git a/apple/common/rarch_wrapper.h b/apple/common/rarch_wrapper.h index 593f2f4543..471f56bcf4 100644 --- a/apple/common/rarch_wrapper.h +++ b/apple/common/rarch_wrapper.h @@ -23,21 +23,21 @@ void apple_rarch_exited (void* result); // These functions must only be called in gfx/context/apple_gl_context.c -bool apple_gfx_ctx_init(); -void apple_gfx_ctx_destroy(); +bool apple_gfx_ctx_init(void); +void apple_gfx_ctx_destroy(void); bool apple_gfx_ctx_bind_api(enum gfx_ctx_api api, unsigned major, unsigned minor); void apple_gfx_ctx_swap_interval(unsigned interval); bool apple_gfx_ctx_set_video_mode(unsigned width, unsigned height, bool fullscreen); void apple_gfx_ctx_get_video_size(unsigned* width, unsigned* height); void apple_gfx_ctx_update_window_title(void); bool apple_gfx_ctx_has_focus(void); -void apple_gfx_ctx_swap_buffers(); +void apple_gfx_ctx_swap_buffers(void); gfx_ctx_proc_t apple_gfx_ctx_get_proc_address(const char *symbol_name); #ifdef IOS void apple_bind_game_view_fbo(void); #endif -void ios_add_log_message(const char* format, ...); +#define ios_add_log_message(...) printf(__VA_ARGS__) #endif diff --git a/apple/common/setting_data.c b/apple/common/setting_data.c new file mode 100644 index 0000000000..97fab8f967 --- /dev/null +++ b/apple/common/setting_data.c @@ -0,0 +1,585 @@ +/* RetroArch - A frontend for libretro. + * Copyright (C) 2013 - Jason Fetters + * + * RetroArch is free software: you can redistribute it and/or modify it under the terms + * of the GNU General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with RetroArch. + * If not, see . + */ + +#include "setting_data.h" +#include "config.def.h" + +// Input +static const char* get_input_config_prefix(const rarch_setting_t* setting) +{ + static char buffer[32]; + snprintf(buffer, 32, "input%cplayer%d", setting->index ? '_' : '\0', setting->index); + return buffer; +} + +static const char* get_input_config_key(const rarch_setting_t* setting, const char* type) +{ + static char buffer[64]; + snprintf(buffer, 64, "%s_%s%c%s", get_input_config_prefix(setting), setting->name, type ? '_' : '\0', type); + return buffer; +} + +static const char* get_key_name(const rarch_setting_t* setting) +{ + if (BINDFOR(*setting).key == RETROK_UNKNOWN) + return "nul"; + + uint32_t hidkey = input_translate_rk_to_keysym(BINDFOR(*setting).key); + + for (int i = 0; apple_key_name_map[i].hid_id; i ++) + if (apple_key_name_map[i].hid_id == hidkey) + return apple_key_name_map[i].keyname; + + return "nul"; +} + + +static const char* get_button_name(const rarch_setting_t* setting) +{ + static char buffer[32]; + + if (BINDFOR(*setting).joykey == NO_BTN) + return "nul"; + + snprintf(buffer, 32, "%lld", BINDFOR(*setting).joykey); + return buffer; +} + +static const char* get_axis_name(const rarch_setting_t* setting) +{ + static char buffer[32]; + + uint32_t joyaxis = BINDFOR(*setting).joyaxis; + + if (AXIS_NEG_GET(joyaxis) != AXIS_DIR_NONE) + snprintf(buffer, 8, "-%d", AXIS_NEG_GET(joyaxis)); + else if (AXIS_POS_GET(joyaxis) != AXIS_DIR_NONE) + snprintf(buffer, 8, "+%d", AXIS_POS_GET(joyaxis)); + else + return "nul"; + + return buffer; +} + +// +void setting_data_reset(const rarch_setting_t* settings) +{ + for (const rarch_setting_t* i = settings; i->type != ST_NONE; i ++) + { + switch (i->type) + { + case ST_BOOL: *i->value.boolean = i->default_value.boolean; break; + case ST_INT: *i->value.integer = i->default_value.integer; break; + case ST_UINT: *i->value.unsigned_integer = i->default_value.unsigned_integer; break; + case ST_FLOAT: *i->value.fraction = i->default_value.fraction; break; + case ST_BIND: *i->value.keybind = *i->default_value.keybind; break; + default: break; + } + } +} + +bool setting_data_load_config_path(const rarch_setting_t* settings, const char* path) +{ + config_file_t* config = config_file_new(path); + + if (config) + { + setting_data_load_config(settings, config); + config_file_free(config); + } + + return config; +} + +bool setting_data_load_config(const rarch_setting_t* settings, config_file_t* config) +{ + if (!config) + return false; + + for (const rarch_setting_t* i = settings; i->type != ST_NONE; i ++) + { + switch (i->type) + { + case ST_BOOL: config_get_bool (config, i->name, i->value.boolean); break; + case ST_INT: config_get_int (config, i->name, i->value.integer); break; + case ST_UINT: config_get_uint (config, i->name, i->value.unsigned_integer); break; + case ST_FLOAT: config_get_float (config, i->name, i->value.fraction); break; + case ST_PATH: config_get_array (config, i->name, i->value.string, i->size); break; + case ST_STRING: config_get_array (config, i->name, i->value.string, i->size); break; + + case ST_BIND: + { + const char* prefix = get_input_config_prefix(i); + input_config_parse_key (config, prefix, i->name, i->value.keybind); + input_config_parse_joy_button(config, prefix, i->name, i->value.keybind); + input_config_parse_joy_axis (config, prefix, i->name, i->value.keybind); + break; + } + + case ST_HEX: break; + default: break; + } + } + + return true; +} + +bool setting_data_save_config_path(const rarch_setting_t* settings, const char* path) +{ + config_file_t* config = config_file_new(path); + + if (!config) + config = config_file_new(0); + + setting_data_save_config(settings, config); + bool result = config_file_write(config, path); + config_file_free(config); + + return result; +} + +bool setting_data_save_config(const rarch_setting_t* settings, config_file_t* config) +{ + if (!config) + return false; + + for (const rarch_setting_t* i = settings; i->type != ST_NONE; i ++) + { + switch (i->type) + { + case ST_BOOL: config_set_bool (config, i->name, *i->value.boolean); break; + case ST_INT: config_set_int (config, i->name, *i->value.integer); break; + case ST_UINT: config_set_uint64(config, i->name, *i->value.unsigned_integer); break; + case ST_FLOAT: config_set_float (config, i->name, *i->value.fraction); break; + case ST_PATH: config_set_string(config, i->name, i->value.string); break; + case ST_STRING: config_set_string(config, i->name, i->value.string); break; + + case ST_BIND: + { + config_set_string(config, get_input_config_key(i, 0 ), get_key_name(i)); + config_set_string(config, get_input_config_key(i, "btn" ), get_button_name(i)); + config_set_string(config, get_input_config_key(i, "axis"), get_axis_name(i)); + break; + } + + case ST_HEX: break; + default: break; + } + } + + return true; +} + +const rarch_setting_t* setting_data_find_setting(const rarch_setting_t* settings, const char* name) +{ + if (!name) + return 0; + + for (const rarch_setting_t* i = settings; i->type != ST_NONE; i ++) + if (i->type <= ST_GROUP && strcmp(i->name, name) == 0) + return i; + + return 0; +} + +void setting_data_set_with_string_representation(const rarch_setting_t* setting, const char* value) +{ + if (!setting || !value) + return; + + switch (setting->type) + { + case ST_INT: sscanf(value, "%d", setting->value.integer); break; + case ST_UINT: sscanf(value, "%u", setting->value.unsigned_integer); break; + case ST_FLOAT: sscanf(value, "%f", setting->value.fraction); break; + case ST_PATH: strlcpy(setting->value.string, value, setting->size); break; + case ST_STRING: strlcpy(setting->value.string, value, setting->size); break; + + default: return; + } +} + +const char* setting_data_get_string_representation(const rarch_setting_t* setting, char* buffer, size_t length) +{ + if (!setting || !buffer || !length) + return ""; + + switch (setting->type) + { + case ST_BOOL: snprintf(buffer, length, "%s", *setting->value.boolean ? "True" : "False"); break; + case ST_INT: snprintf(buffer, length, "%d", *setting->value.integer); break; + case ST_UINT: snprintf(buffer, length, "%u", *setting->value.unsigned_integer); break; + case ST_FLOAT: snprintf(buffer, length, "%f", *setting->value.fraction); break; + case ST_PATH: strlcpy(buffer, setting->value.string, length); break; + case ST_STRING: strlcpy(buffer, setting->value.string, length); break; + + case ST_BIND: + { + snprintf(buffer, length, "[KB:%s] [JS:%s] [AX:%s]", get_key_name(setting), get_button_name(setting), get_axis_name(setting)); + break; + } + + default: return ""; + } + + return buffer; +} + +rarch_setting_t setting_data_group_setting(enum setting_type type, const char* name) +{ + rarch_setting_t result = { type, name }; + return result; +} + +rarch_setting_t setting_data_bool_setting(const char* name, const char* description, bool* target, bool default_value) +{ + rarch_setting_t result = { ST_BOOL, name, sizeof(bool), description }; + result.value.boolean = target; + result.default_value.boolean = default_value; + return result; +} + +rarch_setting_t setting_data_int_setting(const char* name, const char* description, int* target, int default_value) +{ + rarch_setting_t result = { ST_INT, name, sizeof(bool), description }; + result.value.integer = target; + result.default_value.integer = default_value; + return result; +} + +rarch_setting_t setting_data_uint_setting(const char* name, const char* description, unsigned int* target, unsigned int default_value) +{ + rarch_setting_t result = { ST_UINT, name, sizeof(bool), description }; + result.value.unsigned_integer = target; + result.default_value.unsigned_integer = default_value; + return result; +} + +rarch_setting_t setting_data_float_setting(const char* name, const char* description, float* target, float default_value) +{ + rarch_setting_t result = { ST_FLOAT, name, sizeof(bool), description }; + result.value.fraction = target; + result.default_value.fraction = default_value; + return result; +} + +rarch_setting_t setting_data_path_setting(const char* name, const char* description, char* target, unsigned size, char* default_value) +{ + rarch_setting_t result = { ST_PATH, name, size, description }; + result.value.string = target; + result.default_value.string = default_value; + return result; +} + +rarch_setting_t setting_data_string_setting(const char* name, const char* description, char* target, unsigned size, char* default_value) +{ + rarch_setting_t result = { ST_STRING, name, size, description }; + result.value.string = target; + result.default_value.string = default_value; + return result; +} + +rarch_setting_t setting_data_bind_setting(const char* name, const char* description, struct retro_keybind* target, uint32_t index, + const struct retro_keybind* default_value) +{ + rarch_setting_t result = { ST_BIND, name, 0, description }; + result.value.keybind = target; + result.default_value.keybind = default_value; + result.index = index; + return result; +} + + +// HACK +struct settings fake_settings; +struct global fake_extern; + +void setting_data_load_current() +{ + memcpy(&fake_settings, &g_settings, sizeof(struct settings)); + memcpy(&fake_extern, &g_extern, sizeof(struct global)); +} + +#define g_settings fake_settings +#define g_extern fake_extern + + +#define DEFAULT_ME_YO 0 +#define NEXT (list[index++]) +#define START_GROUP(NAME) NEXT = setting_data_group_setting (ST_GROUP, NAME); +#define END_GROUP() NEXT = setting_data_group_setting (ST_END_GROUP, 0); +#define START_SUB_GROUP(NAME) NEXT = setting_data_group_setting (ST_SUB_GROUP, NAME); +#define END_SUB_GROUP() NEXT = setting_data_group_setting (ST_END_SUB_GROUP, 0); +#define CONFIG_BOOL(TARGET, NAME, SHORT, DEF) NEXT = setting_data_bool_setting (NAME, SHORT, &TARGET, DEF); +#define CONFIG_INT(TARGET, NAME, SHORT, DEF) NEXT = setting_data_int_setting (NAME, SHORT, &TARGET, DEF); +#define CONFIG_UINT(TARGET, NAME, SHORT, DEF) NEXT = setting_data_uint_setting (NAME, SHORT, &TARGET, DEF); +#define CONFIG_FLOAT(TARGET, NAME, SHORT, DEF) NEXT = setting_data_float_setting (NAME, SHORT, &TARGET, DEF); +#define CONFIG_PATH(TARGET, NAME, SHORT, DEF) NEXT = setting_data_path_setting (NAME, SHORT, TARGET, sizeof(TARGET), DEF); +#define CONFIG_STRING(TARGET, NAME, SHORT, DEF) NEXT = setting_data_string_setting(NAME, SHORT, TARGET, sizeof(TARGET), DEF); +#define CONFIG_HEX(TARGET, NAME, SHORT) +#define CONFIG_BIND(TARGET, PLAYER, NAME, SHORT, DEF) \ + NEXT = setting_data_bind_setting (NAME, SHORT, &TARGET, PLAYER, DEF); + +// TODO: Add black_frame_insertion, swap_interval msg_color video.rotation audio.block_frames audio.in_rate fast_forward_ratio +// rgui_show_start_screen + +const rarch_setting_t* setting_data_get_list() +{ + static rarch_setting_t list[512] = { 0 }; + + if (list[0].type == ST_NONE) + { + unsigned index = 0; + + /***********/ + /* DRIVERS */ + /***********/ +#if 0 + START_GROUP("Drivers") + START_SUB_GROUP("Drivers") + CONFIG_STRING(g_settings.video.driver, "video_driver", "Video Driver", "") + CONFIG_STRING(g_settings.video.gl_context, "video_gl_context", "OpenGL Driver", "") + CONFIG_STRING(g_settings.audio.driver, "audio_driver", "Audio Driver", "") + CONFIG_STRING(g_settings.input.driver, "input_driver", "Input Driver", "") + CONFIG_STRING(g_settings.input.joypad_driver, "input_joypad_driver", "Joypad Driver", "") + END_SUB_GROUP() + END_GROUP() +#endif + + /*********/ + /* PATHS */ + /*********/ + START_GROUP("Paths") + START_SUB_GROUP("Paths") + CONFIG_PATH(g_settings.libretro, "libretro_path", "libretro Path", "") + CONFIG_PATH(g_settings.core_options_path, "core_options_path", "Core Options Path", DEFAULT_ME_YO) + CONFIG_PATH(g_settings.screenshot_directory, "screenshot_directory", "Screenshot Directory", DEFAULT_ME_YO) + CONFIG_PATH(g_settings.cheat_database, "cheat_database_path", "Cheat Database", DEFAULT_ME_YO) + CONFIG_PATH(g_settings.cheat_settings_path, "cheat_settings_path", "Cheat Settings", DEFAULT_ME_YO) + CONFIG_PATH(g_settings.game_history_path, "game_history_path", "Game History Path", DEFAULT_ME_YO) + CONFIG_UINT(g_settings.game_history_size, "game_history_size", "Game History Size", game_history_size) + + #ifdef HAVE_RGUI + CONFIG_PATH(g_settings.rgui_browser_directory, "rgui_browser_directory", "Browser Directory", DEFAULT_ME_YO) + #endif + + #ifdef HAVE_OVERLAY + CONFIG_PATH(g_extern.overlay_dir, "overlay_directory", "Overlay Directory", DEFAULT_ME_YO) + #endif + END_SUB_GROUP() + END_GROUP() + + + /*************/ + /* EMULATION */ + /*************/ + START_GROUP("Emulation") + START_SUB_GROUP("Emulation") + CONFIG_BOOL(g_settings.pause_nonactive, "pause_nonactive", "Pause when inactive", pause_nonactive) + CONFIG_BOOL(g_settings.rewind_enable, "rewind_enable", "Enable Rewind", rewind_enable) +// CONFIG_INT(g_settings.rewind_buffer_size, "rewind_buffer_size", "Rewind Buffer Size", rewind_buffer_size) /* *= 1000000 */ + CONFIG_UINT(g_settings.rewind_granularity, "rewind_granularity", "Rewind Granularity", rewind_granularity) + CONFIG_FLOAT(g_settings.slowmotion_ratio, "slowmotion_ratio", "Slow motion ratio", slowmotion_ratio) /* >= 1.0f */ + + /* Saves */ + CONFIG_UINT(g_settings.autosave_interval, "autosave_interval", "Autosave Interval", autosave_interval) + CONFIG_BOOL(g_settings.block_sram_overwrite, "block_sram_overwrite", "Block SRAM overwrite", block_sram_overwrite) + CONFIG_BOOL(g_settings.savestate_auto_index, "savestate_auto_index", "Save State Auto Index", savestate_auto_index) + CONFIG_BOOL(g_settings.savestate_auto_save, "savestate_auto_save", "Auto Save State", savestate_auto_save) + CONFIG_BOOL(g_settings.savestate_auto_load, "savestate_auto_load", "Auto Load State", savestate_auto_load) + END_SUB_GROUP() + END_GROUP() + + /*********/ + /* VIDEO */ + /*********/ + START_GROUP("Video") + START_SUB_GROUP("Monitor") + CONFIG_UINT(g_settings.video.monitor_index, "video_monitor_index", "Monitor Index", monitor_index) + CONFIG_BOOL(g_settings.video.fullscreen, "video_fullscreen", "Use Fullscreen mode", g_extern.force_fullscreen ? true : fullscreen) // if (!g_extern.force_fullscreen) + CONFIG_BOOL(g_settings.video.windowed_fullscreen, "video_windowed_fullscreen", "Windowed Fullscreen Mode", windowed_fullscreen) + CONFIG_UINT(g_settings.video.fullscreen_x, "video_fullscreen_x", "Fullscreen Width", fullscreen_x) + CONFIG_UINT(g_settings.video.fullscreen_y, "video_fullscreen_y", "Fullscreen Height", fullscreen_y) + CONFIG_FLOAT(g_settings.video.refresh_rate, "video_refresh_rate", "Refresh Rate", refresh_rate) + END_SUB_GROUP() + +#if 0 + /* Video: Window Manager */ + START_SUB_GROUP("Window Manager") + CONFIG_BOOL(g_settings.video.disable_composition, "video_disable_composition", "Disable WM Composition", disable_composition) + END_SUB_GROUP() +#endif + + START_SUB_GROUP("Aspect") + CONFIG_BOOL(g_settings.video.force_aspect, "video_force_aspect", "Force aspect ratio", force_aspect) + CONFIG_FLOAT(g_settings.video.aspect_ratio, "video_aspect_ratio", "Aspect Ratio", aspect_ratio) + CONFIG_BOOL(g_settings.video.aspect_ratio_auto, "video_aspect_ratio_auto", "Use Auto Aspect Ratio", aspect_ratio_auto) + CONFIG_UINT(g_settings.video.aspect_ratio_idx, "aspect_ratio_index", "Aspect Ratio Index", aspect_ratio_idx) + END_SUB_GROUP() + + START_SUB_GROUP("Scaling") + CONFIG_FLOAT(g_settings.video.xscale, "video_xscale", "X Scale", xscale) + CONFIG_FLOAT(g_settings.video.yscale, "video_yscale", "Y Scale", yscale) + CONFIG_BOOL(g_settings.video.scale_integer, "video_scale_integer", "Force integer scaling", scale_integer) + + CONFIG_INT(g_extern.console.screen.viewports.custom_vp.x, "custom_viewport_x", "Custom Viewport X", 0) + CONFIG_INT(g_extern.console.screen.viewports.custom_vp.y, "custom_viewport_y", "Custom Viewport Y", 0) + CONFIG_UINT(g_extern.console.screen.viewports.custom_vp.width, "custom_viewport_width", "Custom Viewport Width", 0) + CONFIG_UINT(g_extern.console.screen.viewports.custom_vp.height, "custom_viewport_height", "Custom Viewport Height", 0) + + CONFIG_BOOL(g_settings.video.smooth, "video_smooth", "Use bilinear filtering", video_smooth) + END_SUB_GROUP() + + START_SUB_GROUP("Shader") + CONFIG_BOOL(g_settings.video.shader_enable, "video_shader_enable", "Enable Shaders", shader_enable) + CONFIG_PATH(g_settings.video.shader_dir, "video_shader_dir", "Shader Directory", DEFAULT_ME_YO) + CONFIG_PATH(g_settings.video.shader_path, "video_shader", "Shader", DEFAULT_ME_YO) + END_SUB_GROUP() + + START_SUB_GROUP("Sync") + CONFIG_BOOL(g_settings.video.threaded, "video_threaded", "Use threaded video", video_threaded) + CONFIG_BOOL(g_settings.video.vsync, "video_vsync", "Use VSync", vsync) + CONFIG_BOOL(g_settings.video.hard_sync, "video_hard_sync", "Use OpenGL Hard Sync", hard_sync) + CONFIG_UINT(g_settings.video.hard_sync_frames, "video_hard_sync_frames", "Number of Hard Sync frames", hard_sync_frames) // 0 - 3 + END_SUB_GROUP() + + START_SUB_GROUP("Misc") + CONFIG_BOOL(g_settings.video.post_filter_record, "video_post_filter_record", "Post filter record", post_filter_record) + CONFIG_BOOL(g_settings.video.gpu_record, "video_gpu_record", "GPU Record", gpu_record) + CONFIG_BOOL(g_settings.video.gpu_screenshot, "video_gpu_screenshot", "GPU Screenshot", gpu_screenshot) + CONFIG_BOOL(g_settings.video.allow_rotate, "video_allow_rotate", "Allow rotation", allow_rotate) + CONFIG_BOOL(g_settings.video.crop_overscan, "video_crop_overscan", "Crop Overscan", crop_overscan) + + #ifdef HAVE_DYLIB + CONFIG_PATH(g_settings.video.filter_path, "video_filter", "Software filter"), + #endif + END_SUB_GROUP() + + START_SUB_GROUP("Messages") + CONFIG_PATH(g_settings.video.font_path, "video_font_path", "Font Path", DEFAULT_ME_YO) + CONFIG_FLOAT(g_settings.video.font_size, "video_font_size", "Font Size", font_size) + CONFIG_BOOL(g_settings.video.font_enable, "video_font_enable", "Font Enable", font_enable) + CONFIG_BOOL(g_settings.video.font_scale, "video_font_scale", "Font Scale", font_scale) + CONFIG_FLOAT(g_settings.video.msg_pos_x, "video_message_pos_x", "Message X Position", message_pos_offset_x) + CONFIG_FLOAT(g_settings.video.msg_pos_y, "video_message_pos_y", "Message Y Position", message_pos_offset_y) + /* message color */ + END_SUB_GROUP() + END_GROUP() + + /*********/ + /* AUDIO */ + /*********/ + START_GROUP("Audio") + START_SUB_GROUP("State") + CONFIG_BOOL(g_settings.audio.enable, "audio_enable", "Enable", audio_enable) + CONFIG_FLOAT(g_settings.audio.volume, "audio_volume", "Volume", audio_volume) + END_SUB_GROUP() + + START_SUB_GROUP("Sync") + CONFIG_BOOL(g_settings.audio.sync, "audio_sync", "Enable Sync", audio_sync) + CONFIG_UINT(g_settings.audio.latency, "audio_latency", "Latency", out_latency) + CONFIG_BOOL(g_settings.audio.rate_control, "audio_rate_control", "Enable Rate Control", rate_control) + CONFIG_FLOAT(g_settings.audio.rate_control_delta, "audio_rate_control_delta", "Rate Control Delta", rate_control_delta) + END_SUB_GROUP() + + START_SUB_GROUP("Misc") + CONFIG_STRING(g_settings.audio.device, "audio_device", "Device", DEFAULT_ME_YO) + CONFIG_UINT(g_settings.audio.out_rate, "audio_out_rate", "Ouput Rate", out_rate) + CONFIG_PATH(g_settings.audio.dsp_plugin, "audio_dsp_plugin", "DSP Plugin", DEFAULT_ME_YO) + END_SUB_GROUP() + END_GROUP() + + /*********/ + /* INPUT */ + /*********/ + START_GROUP("Input") + START_SUB_GROUP("Input") + /* Input: Autoconfig */ + CONFIG_BOOL(g_settings.input.autodetect_enable, "input_autodetect_enable", "Use joypad autodetection", input_autodetect_enable) + CONFIG_PATH(g_settings.input.autoconfig_dir, "joypad_autoconfig_dir", "Joypad Autoconfig Directory", DEFAULT_ME_YO) + END_SUB_GROUP() + + START_SUB_GROUP("Joypad Mapping") + CONFIG_INT(g_settings.input.joypad_map[0], "input_player1_joypad_index", "Player 1 Pad Index", 0) + CONFIG_INT(g_settings.input.joypad_map[1], "input_player2_joypad_index", "Player 2 Pad Index", 1) + CONFIG_INT(g_settings.input.joypad_map[2], "input_player3_joypad_index", "Player 3 Pad Index", 2) + CONFIG_INT(g_settings.input.joypad_map[3], "input_player4_joypad_index", "Player 4 Pad Index", 3) + CONFIG_INT(g_settings.input.joypad_map[4], "input_player5_joypad_index", "Player 5 Pad Index", 4) + END_SUB_GROUP() + + START_SUB_GROUP("Turbo/Deadzone") + CONFIG_FLOAT(g_settings.input.axis_threshold, "input_axis_threshold", "Axis Deadzone", axis_threshold) + CONFIG_UINT(g_settings.input.turbo_period, "input_turbo_period", "Turbo Period", turbo_period) + CONFIG_UINT(g_settings.input.turbo_duty_cycle, "input_duty_cycle", "Duty Cycle", turbo_duty_cycle) + END_SUB_GROUP() + + START_SUB_GROUP("Misc") + CONFIG_BOOL(g_settings.input.netplay_client_swap_input, "netplay_client_swap_input", "Swap Netplay Input", netplay_client_swap_input) + CONFIG_BOOL(g_settings.input.debug_enable, "input_debug_enable", "Enable Input Debugging", input_debug_enable) + END_SUB_GROUP() + + #ifdef HAVE_OVERLAY + START_SUB_GROUP("Overlay") + CONFIG_PATH(g_settings.input.overlay, "input_overlay", "Input Overlay", DEFAULT_ME_YO) + CONFIG_FLOAT(g_settings.input.overlay_opacity, "input_overlay_opacity", "Overlay Opacity", 1.0f) + CONFIG_FLOAT(g_settings.input.overlay_scale, "input_overlay_scale", "Overlay Scale", 1.0f) + END_SUB_GROUP() + #endif + + /* Input: Android */ + #ifdef ANDROID + START_SUB_GROUP("Android") + CONFIG_INT(g_settings.input.back_behavior, "input_back_behavior", "Back Behavior", BACK_BUTTON_QUIT) + CONFIG_INT(g_settings.input.icade_profile[0], "input_autodetect_icade_profile_pad1", "iCade 1", DEFAULT_ME_YO) + CONFIG_INT(g_settings.input.icade_profile[1], "input_autodetect_icade_profile_pad2", "iCade 2", DEFAULT_ME_YO) + CONFIG_INT(g_settings.input.icade_profile[2], "input_autodetect_icade_profile_pad3", "iCade 3", DEFAULT_ME_YO) + CONFIG_INT(g_settings.input.icade_profile[3], "input_autodetect_icade_profile_pad4", "iCade 4", DEFAULT_ME_YO) + END_SUB_GROUP() + #endif + + START_SUB_GROUP("Meta Keys") + for (int i = 0; i != RARCH_BIND_LIST_END; i ++) + if (input_config_bind_map[i].meta) + { + const struct input_bind_map* bind = &input_config_bind_map[i]; + CONFIG_BIND(g_settings.input.binds[0][i], 0, bind->base, bind->desc, &retro_keybinds_1[i]) + } + END_SUB_GROUP() + + START_SUB_GROUP("Player 1") + for (int i = 0; i != RARCH_BIND_LIST_END; i ++) + if (!input_config_bind_map[i].meta) + { + const struct input_bind_map* bind = &input_config_bind_map[i]; + CONFIG_BIND(g_settings.input.binds[0][i], 0, bind->base, bind->desc, &retro_keybinds_1[i]) + } + END_SUB_GROUP() + END_GROUP() + + /********/ + /* Misc */ + /********/ + START_GROUP("Misc") + START_SUB_GROUP("Misc") + CONFIG_BOOL(g_extern.config_save_on_exit, "config_save_on_exit", "Save Config On Exit", config_save_on_exit) + CONFIG_BOOL(g_settings.network_cmd_enable, "network_cmd_enable", "Network Commands", network_cmd_enable) +// CONFIG_INT(g_settings.network_cmd_port, "network_cmd_port", "Network Command Port", network_cmd_port) + CONFIG_BOOL(g_settings.stdin_cmd_enable, "stdin_cmd_enable", "stdin command", stdin_cmd_enable) + END_SUB_GROUP() + END_GROUP() + } + + return list; +} diff --git a/apple/common/setting_data.h b/apple/common/setting_data.h index dc5fa2c39e..8d39970962 100644 --- a/apple/common/setting_data.h +++ b/apple/common/setting_data.h @@ -18,7 +18,7 @@ #include "general.h" -enum setting_type { ST_NONE, ST_BOOL, ST_INT, ST_FLOAT, ST_PATH, ST_STRING, ST_HEX, ST_BIND, +enum setting_type { ST_NONE, ST_BOOL, ST_INT, ST_UINT, ST_FLOAT, ST_PATH, ST_STRING, ST_HEX, ST_BIND, ST_GROUP, ST_SUB_GROUP, ST_END_GROUP, ST_END_SUB_GROUP }; typedef struct @@ -26,322 +26,68 @@ typedef struct enum setting_type type; const char* name; - - void* value; uint32_t size; const char* short_description; - uint32_t input_player; + uint32_t index; double min; double max; bool allow_blank; + + union + { + bool boolean; + int integer; + unsigned int unsigned_integer; + float fraction; + const char* string; + const struct retro_keybind* keybind; + } default_value; + + union + { + bool* boolean; + int* integer; + unsigned int* unsigned_integer; + float* fraction; + char* string; + struct retro_keybind* keybind; + } value; } rarch_setting_t; -extern struct settings fake_settings; -extern struct global fake_extern; - -// HACK -#define g_settings fake_settings -#define g_extern fake_extern - -#define START_GROUP(NAME) { ST_GROUP, NAME }, -#define END_GROUP() { ST_END_GROUP }, -#define START_SUB_GROUP(NAME) { ST_SUB_GROUP, NAME }, -#define END_SUB_GROUP() { ST_END_SUB_GROUP }, -#define CONFIG_BOOL(TARGET, NAME, SHORT) { ST_BOOL, NAME, &TARGET, sizeof(TARGET), SHORT }, -#define CONFIG_INT(TARGET, NAME, SHORT) { ST_INT, NAME, &TARGET, sizeof(TARGET), SHORT }, -#define CONFIG_FLOAT(TARGET, NAME, SHORT) { ST_FLOAT, NAME, &TARGET, sizeof(TARGET), SHORT }, -#define CONFIG_PATH(TARGET, NAME, SHORT) { ST_PATH, NAME, &TARGET, sizeof(TARGET), SHORT }, -#define CONFIG_STRING(TARGET, NAME, SHORT) { ST_STRING, NAME, &TARGET, sizeof(TARGET), SHORT }, -#define CONFIG_HEX(TARGET, NAME, SHORT) { ST_HEX, NAME, &TARGET, sizeof(TARGET), SHORT }, - -#define CONFIG_BIND(TARGET, PLAYER, NAME, SHORT) { ST_BIND, NAME, &TARGET, sizeof(TARGET), SHORT, PLAYER }, - -const rarch_setting_t setting_data[] = -{ - /***********/ - /* DRIVERS */ - /***********/ -#if 0 - START_GROUP("Drivers") - START_SUB_GROUP("Drivers") - CONFIG_STRING(g_settings.video.driver, "video_driver", "Video Driver") - CONFIG_STRING(g_settings.video.gl_context, "video_gl_context", "OpenGL Driver") - CONFIG_STRING(g_settings.audio.driver, "audio_driver", "Audio Driver") - CONFIG_STRING(g_settings.input.driver, "input_driver", "Input Driver") - CONFIG_STRING(g_settings.input.joypad_driver, "input_joypad_driver", "Joypad Driver") - END_SUB_GROUP() - END_GROUP() -#endif - - /*********/ - /* PATHS */ - /*********/ - START_GROUP("Paths") - START_SUB_GROUP("Paths") - CONFIG_PATH(g_settings.libretro, "libretro_path", "libretro Path") - CONFIG_PATH(g_settings.core_options_path, "core_options_path", "Core Options Path") - CONFIG_PATH(g_settings.screenshot_directory, "screenshot_directory", "Screenshot Directory") - CONFIG_PATH(g_settings.cheat_database, "cheat_database_path", "Cheat Database") - CONFIG_PATH(g_settings.cheat_settings_path, "cheat_settings_path", "Cheat Settings") - CONFIG_PATH(g_settings.game_history_path, "game_history_path", "Game History Path") - CONFIG_INT(g_settings.game_history_size, "game_history_size", "Game History Size") - - #ifdef HAVE_RGUI - CONFIG_PATH(g_settings.rgui_browser_directory, "rgui_browser_directory", "Browser Directory") - #endif - - #ifdef HAVE_OVERLAY - CONFIG_PATH(g_extern.overlay_dir, "overlay_directory", "Overlay Directory") - #endif - END_SUB_GROUP() - END_GROUP() +#define BINDFOR(s) (*(&s)->value.keybind) - /*************/ - /* EMULATION */ - /*************/ - START_GROUP("Emulation") - START_SUB_GROUP("Emulation") - CONFIG_BOOL(g_settings.pause_nonactive, "pause_nonactive", "Pause when inactive") - CONFIG_BOOL(g_settings.rewind_enable, "rewind_enable", "Enable Rewind") - CONFIG_INT(g_settings.rewind_buffer_size, "rewind_buffer_size", "Rewind Buffer Size") /* *= 1000000 */ - CONFIG_INT(g_settings.rewind_granularity, "rewind_granularity", "Rewind Granularity") - CONFIG_FLOAT(g_settings.slowmotion_ratio, "slowmotion_ratio", "Slow motion ratio") /* >= 1.0f */ +void setting_data_reset(const rarch_setting_t* settings); - /* Saves */ - CONFIG_INT(g_settings.autosave_interval, "autosave_interval", "Autosave Interval") - CONFIG_BOOL(g_settings.block_sram_overwrite, "block_sram_overwrite", "Block SRAM overwrite") - CONFIG_BOOL(g_settings.savestate_auto_index, "savestate_auto_index", "Save State Auto Index") - CONFIG_BOOL(g_settings.savestate_auto_save, "savestate_auto_save", "Auto Save State") - CONFIG_BOOL(g_settings.savestate_auto_load, "savestate_auto_load", "Auto Load State") - END_SUB_GROUP() - END_GROUP() +bool setting_data_load_config_path(const rarch_setting_t* settings, const char* path); +bool setting_data_load_config(const rarch_setting_t* settings, config_file_t* config); +bool setting_data_save_config_path(const rarch_setting_t* settings, const char* path); +bool setting_data_save_config(const rarch_setting_t* settings, config_file_t* config); - /*********/ - /* VIDEO */ - /*********/ - START_GROUP("Video") - START_SUB_GROUP("Monitor") - CONFIG_INT(g_settings.video.monitor_index, "video_monitor_index", "Monitor Index") - CONFIG_BOOL(g_settings.video.fullscreen, "video_fullscreen", "Use Fullscreen mode") // if (!g_extern.force_fullscreen) - CONFIG_BOOL(g_settings.video.windowed_fullscreen, "video_windowed_fullscreen", "Windowed Fullscreen Mode") - CONFIG_INT(g_settings.video.fullscreen_x, "video_fullscreen_x", "Fullscreen Width") - CONFIG_INT(g_settings.video.fullscreen_y, "video_fullscreen_y", "Fullscreen Height") - CONFIG_FLOAT(g_settings.video.refresh_rate, "video_refresh_rate", "Refresh Rate") - END_SUB_GROUP() +const rarch_setting_t* setting_data_find_setting(const rarch_setting_t* settings, const char* name); -#if 0 - /* Video: Window Manager */ - START_SUB_GROUP("Window Manager") - CONFIG_BOOL(g_settings.video.disable_composition, "video_disable_composition", "Disable WM Composition") - END_SUB_GROUP() -#endif +void setting_data_set_with_string_representation(const rarch_setting_t* setting, const char* value); +const char* setting_data_get_string_representation(const rarch_setting_t* setting, char* buffer, size_t length); - START_SUB_GROUP("Aspect") - CONFIG_BOOL(g_settings.video.force_aspect, "video_force_aspect", "Force aspect ratio") - CONFIG_FLOAT(g_settings.video.aspect_ratio, "video_aspect_ratio", "Aspect Ratio") - CONFIG_BOOL(g_settings.video.aspect_ratio_auto, "video_aspect_ratio_auto", "Use Auto Aspect Ratio") - CONFIG_INT(g_settings.video.aspect_ratio_idx, "aspect_ratio_index", "Aspect Ratio Index") - END_SUB_GROUP() +// List building helper functions +rarch_setting_t setting_data_group_setting(enum setting_type type, const char* name); +rarch_setting_t setting_data_bool_setting(const char* name, const char* description, bool* target, bool default_value); +rarch_setting_t setting_data_int_setting(const char* name, const char* description, int* target, int default_value); +rarch_setting_t setting_data_uint_setting(const char* name, const char* description, unsigned int* target, unsigned int default_value); +rarch_setting_t setting_data_float_setting(const char* name, const char* description, float* target, float default_value); +rarch_setting_t setting_data_path_setting(const char* name, const char* description, char* target, unsigned size, char* default_value); +rarch_setting_t setting_data_string_setting(const char* name, const char* description, char* target, unsigned size, char* default_value); +rarch_setting_t setting_data_bind_setting(const char* name, const char* description, struct retro_keybind* target, uint32_t index, + const struct retro_keybind* default_value); - START_SUB_GROUP("Scaling") - CONFIG_FLOAT(g_settings.video.xscale, "video_xscale", "X Scale") - CONFIG_FLOAT(g_settings.video.yscale, "video_yscale", "Y Scale") - CONFIG_BOOL(g_settings.video.scale_integer, "video_scale_integer", "Force integer scaling") - - CONFIG_INT(g_extern.console.screen.viewports.custom_vp.x, "custom_viewport_x", "Custom Viewport X") - CONFIG_INT(g_extern.console.screen.viewports.custom_vp.y, "custom_viewport_y", "Custom Viewport Y") - CONFIG_INT(g_extern.console.screen.viewports.custom_vp.width, "custom_viewport_width", "Custom Viewport Width") - CONFIG_INT(g_extern.console.screen.viewports.custom_vp.height, "custom_viewport_height", "Custom Viewport Height") - - CONFIG_BOOL(g_settings.video.smooth, "video_smooth", "Use bilinear filtering") - END_SUB_GROUP() - - START_SUB_GROUP("Shader") - CONFIG_BOOL(g_settings.video.shader_enable, "video_shader_enable", "Enable Shaders") - CONFIG_PATH(g_settings.video.shader_dir, "video_shader_dir", "Shader Directory") - CONFIG_PATH(g_settings.video.shader_path, "video_shader", "Shader") - END_SUB_GROUP() - - START_SUB_GROUP("Sync") - CONFIG_BOOL(g_settings.video.threaded, "video_threaded", "Use threaded video") - CONFIG_BOOL(g_settings.video.vsync, "video_vsync", "Use VSync") - CONFIG_BOOL(g_settings.video.hard_sync, "video_hard_sync", "Use OpenGL Hard Sync") - CONFIG_INT(g_settings.video.hard_sync_frames, "video_hard_sync_frames", "Number of Hard Sync frames") // 0 - 3 - END_SUB_GROUP() - - START_SUB_GROUP("Misc") - CONFIG_BOOL(g_settings.video.post_filter_record, "video_post_filter_record", "Post filter record") - CONFIG_BOOL(g_settings.video.gpu_record, "video_gpu_record", "GPU Record") - CONFIG_BOOL(g_settings.video.gpu_screenshot, "video_gpu_screenshot", "GPU Screenshot") - CONFIG_BOOL(g_settings.video.allow_rotate, "video_allow_rotate", "Allow rotation") - CONFIG_BOOL(g_settings.video.crop_overscan, "video_crop_overscan", "Crop Overscan") - - #ifdef HAVE_DYLIB - CONFIG_PATH(g_settings.video.filter_path, "video_filter", "Software filter"), - #endif - END_SUB_GROUP() - - START_SUB_GROUP("Messages") - CONFIG_PATH(g_settings.video.font_path, "video_font_path", "Font Path") - CONFIG_FLOAT(g_settings.video.font_size, "video_font_size", "Font Size") - CONFIG_BOOL(g_settings.video.font_enable, "video_font_enable", "Font Enable") - CONFIG_BOOL(g_settings.video.font_scale, "video_font_scale", "Font Scale") - CONFIG_FLOAT(g_settings.video.msg_pos_x, "video_message_pos_x", "Message X Position") - CONFIG_FLOAT(g_settings.video.msg_pos_y, "video_message_pos_y", "Message Y Position") - /* message color */ - END_SUB_GROUP() - END_GROUP() - - /*********/ - /* AUDIO */ - /*********/ - START_GROUP("Audio") - START_SUB_GROUP("Audio") - CONFIG_BOOL(g_settings.audio.enable, "audio_enable", "Enable") - CONFIG_FLOAT(g_settings.audio.volume, "audio_volume", "Volume") - - /* Audio: Sync */ - CONFIG_BOOL(g_settings.audio.sync, "audio_sync", "Enable Sync") - CONFIG_INT(g_settings.audio.latency, "audio_latency", "Latency") - CONFIG_BOOL(g_settings.audio.rate_control, "audio_rate_control", "Enable Rate Control") - CONFIG_FLOAT(g_settings.audio.rate_control_delta, "audio_rate_control_delta", "Rate Control Delta") - - /* Audio: Other */ - CONFIG_STRING(g_settings.audio.device, "audio_device", "Device") - CONFIG_INT(g_settings.audio.out_rate, "audio_out_rate", "Ouput Rate") - CONFIG_PATH(g_settings.audio.dsp_plugin, "audio_dsp_plugin", "DSP Plugin") - END_SUB_GROUP() - END_GROUP() - - /*********/ - /* INPUT */ - /*********/ - START_GROUP("Input") - START_SUB_GROUP("Input") - /* Input: Autoconfig */ - CONFIG_BOOL(g_settings.input.autodetect_enable, "input_autodetect_enable", "Use joypad autodetection") - CONFIG_PATH(g_settings.input.autoconfig_dir, "joypad_autoconfig_dir", "Joypad Autoconfig Directory") - - /* Input: Joypad mapping */ - CONFIG_INT(g_settings.input.joypad_map[0], "input_player1_joypad_index", "Player 1 Pad Index") - CONFIG_INT(g_settings.input.joypad_map[1], "input_player2_joypad_index", "Player 2 Pad Index") - CONFIG_INT(g_settings.input.joypad_map[2], "input_player3_joypad_index", "Player 3 Pad Index") - CONFIG_INT(g_settings.input.joypad_map[3], "input_player4_joypad_index", "Player 4 Pad Index") - CONFIG_INT(g_settings.input.joypad_map[4], "input_player5_joypad_index", "Player 5 Pad Index") - - /* Input: Turbo/Axis options */ - CONFIG_FLOAT(g_settings.input.axis_threshold, "input_axis_threshold", "Axis Deadzone") - CONFIG_INT(g_settings.input.turbo_period, "input_turbo_period", "Turbo Period") - CONFIG_INT(g_settings.input.turbo_duty_cycle, "input_duty_cycle", "Duty Cycle") - - /* Input: Misc */ - CONFIG_BOOL(g_settings.input.netplay_client_swap_input, "netplay_client_swap_input", "Swap Netplay Input") - CONFIG_BOOL(g_settings.input.debug_enable, "input_debug_enable", "Enable Input Debugging") - - /* Input: Overlay */ - #ifdef HAVE_OVERLAY - CONFIG_PATH(g_settings.input.overlay, "input_overlay", "Input Overlay") - CONFIG_FLOAT(g_settings.input.overlay_opacity, "input_overlay_opacity", "Overlay Opacity") - CONFIG_FLOAT(g_settings.input.overlay_scale, "input_overlay_scale", "Overlay Scale") - #endif - - /* Input: Android */ - #ifdef ANDROID - CONFIG_INT(g_settings.input.back_behavior, "input_back_behavior", "Back Behavior") - CONFIG_INT(g_settings.input.icade_profile[0], "input_autodetect_icade_profile_pad1", "iCade 1") - CONFIG_INT(g_settings.input.icade_profile[1], "input_autodetect_icade_profile_pad2", "iCade 2") - CONFIG_INT(g_settings.input.icade_profile[2], "input_autodetect_icade_profile_pad3", "iCade 3") - CONFIG_INT(g_settings.input.icade_profile[3], "input_autodetect_icade_profile_pad4", "iCade 4") - #endif - END_SUB_GROUP() - - START_SUB_GROUP("Meta Keys") - CONFIG_BIND(g_settings.input.binds[0][RARCH_FAST_FORWARD_KEY], 0, "toggle_fast_forward", "Fast forward toggle") - CONFIG_BIND(g_settings.input.binds[0][RARCH_FAST_FORWARD_HOLD_KEY], 0, "hold_fast_forward", "Fast forward hold") - CONFIG_BIND(g_settings.input.binds[0][RARCH_LOAD_STATE_KEY], 0, "load_state", "Load state") - CONFIG_BIND(g_settings.input.binds[0][RARCH_SAVE_STATE_KEY], 0, "save_state", "Save state") - CONFIG_BIND(g_settings.input.binds[0][RARCH_FULLSCREEN_TOGGLE_KEY], 0, "toggle_fullscreen", "Fullscreen toggle") - CONFIG_BIND(g_settings.input.binds[0][RARCH_QUIT_KEY], 0, "exit_emulator", "Quit RetroArch") - CONFIG_BIND(g_settings.input.binds[0][RARCH_STATE_SLOT_PLUS], 0, "state_slot_increase", "Savestate slot +") - CONFIG_BIND(g_settings.input.binds[0][RARCH_STATE_SLOT_MINUS], 0, "state_slot_decrease", "Savestate slot -") - CONFIG_BIND(g_settings.input.binds[0][RARCH_REWIND], 0, "rewind", "Rewind") - CONFIG_BIND(g_settings.input.binds[0][RARCH_MOVIE_RECORD_TOGGLE], 0, "movie_record_toggle", "Movie record toggle") - CONFIG_BIND(g_settings.input.binds[0][RARCH_PAUSE_TOGGLE], 0, "pause_toggle", "Pause toggle") - CONFIG_BIND(g_settings.input.binds[0][RARCH_FRAMEADVANCE], 0, "frame_advance", "Frameadvance") - CONFIG_BIND(g_settings.input.binds[0][RARCH_RESET], 0, "reset", "Reset game") - CONFIG_BIND(g_settings.input.binds[0][RARCH_SHADER_NEXT], 0, "shader_next", "Next shader") - CONFIG_BIND(g_settings.input.binds[0][RARCH_SHADER_PREV], 0, "shader_prev", "Previous shader") - CONFIG_BIND(g_settings.input.binds[0][RARCH_CHEAT_INDEX_PLUS], 0, "cheat_index_plus", "Cheat index +") - CONFIG_BIND(g_settings.input.binds[0][RARCH_CHEAT_INDEX_MINUS], 0, "cheat_index_minus", "Cheat index -") - CONFIG_BIND(g_settings.input.binds[0][RARCH_CHEAT_TOGGLE], 0, "cheat_toggle", "Cheat toggle") - CONFIG_BIND(g_settings.input.binds[0][RARCH_SCREENSHOT], 0, "screenshot", "Take screenshot") - CONFIG_BIND(g_settings.input.binds[0][RARCH_DSP_CONFIG], 0, "dsp_config", "DSP config") - CONFIG_BIND(g_settings.input.binds[0][RARCH_MUTE], 0, "audio_mute", "Audio mute toggle") - CONFIG_BIND(g_settings.input.binds[0][RARCH_NETPLAY_FLIP], 0, "netplay_flip_players", "Netplay flip players") - CONFIG_BIND(g_settings.input.binds[0][RARCH_SLOWMOTION], 0, "slowmotion", "Slow motion") - CONFIG_BIND(g_settings.input.binds[0][RARCH_ENABLE_HOTKEY], 0, "enable_hotkey", "Enable hotkeys") - CONFIG_BIND(g_settings.input.binds[0][RARCH_VOLUME_UP], 0, "volume_up", "Volume +") - CONFIG_BIND(g_settings.input.binds[0][RARCH_VOLUME_DOWN], 0, "volume_down", "Volume -") - CONFIG_BIND(g_settings.input.binds[0][RARCH_OVERLAY_NEXT], 0, "overlay_next", "Overlay next") - CONFIG_BIND(g_settings.input.binds[0][RARCH_DISK_EJECT_TOGGLE], 0, "disk_eject_toggle", "Disk eject toggle") - CONFIG_BIND(g_settings.input.binds[0][RARCH_DISK_NEXT], 0, "disk_next", "Disk next") - CONFIG_BIND(g_settings.input.binds[0][RARCH_GRAB_MOUSE_TOGGLE], 0, "grab_mouse_toggle", "Grab mouse toggle") - CONFIG_BIND(g_settings.input.binds[0][RARCH_MENU_TOGGLE], 0, "menu_toggle", "RGUI menu toggle") - END_SUB_GROUP() - - START_SUB_GROUP("Player 1") - CONFIG_BIND(g_settings.input.binds[0][RETRO_DEVICE_ID_JOYPAD_UP], 1, "up", "Up D-pad") - CONFIG_BIND(g_settings.input.binds[0][RETRO_DEVICE_ID_JOYPAD_DOWN], 1, "down", "Down D-pad") - CONFIG_BIND(g_settings.input.binds[0][RETRO_DEVICE_ID_JOYPAD_LEFT], 1, "left", "Left D-pad") - CONFIG_BIND(g_settings.input.binds[0][RETRO_DEVICE_ID_JOYPAD_RIGHT], 1, "right", "Right D-pad") - CONFIG_BIND(g_settings.input.binds[0][RETRO_DEVICE_ID_JOYPAD_SELECT],1, "select", "Select button") - CONFIG_BIND(g_settings.input.binds[0][RETRO_DEVICE_ID_JOYPAD_START], 1, "start", "Start button") - CONFIG_BIND(g_settings.input.binds[0][RETRO_DEVICE_ID_JOYPAD_B], 1, "b", "B button (down)") - CONFIG_BIND(g_settings.input.binds[0][RETRO_DEVICE_ID_JOYPAD_A], 1, "a", "A button (right)") - CONFIG_BIND(g_settings.input.binds[0][RETRO_DEVICE_ID_JOYPAD_X], 1, "x", "X button (top)") - CONFIG_BIND(g_settings.input.binds[0][RETRO_DEVICE_ID_JOYPAD_Y], 1, "y", "Y button (left)") - CONFIG_BIND(g_settings.input.binds[0][RETRO_DEVICE_ID_JOYPAD_L], 1, "l", "L button (left shoulder)") - CONFIG_BIND(g_settings.input.binds[0][RETRO_DEVICE_ID_JOYPAD_R], 1, "r", "R button (right shoulder)") - CONFIG_BIND(g_settings.input.binds[0][RETRO_DEVICE_ID_JOYPAD_L2], 1, "l2", "L2 button (left shoulder #2)") - CONFIG_BIND(g_settings.input.binds[0][RETRO_DEVICE_ID_JOYPAD_R2], 1, "r2", "R2 button (right shoulder #2)") - CONFIG_BIND(g_settings.input.binds[0][RETRO_DEVICE_ID_JOYPAD_L3], 1, "l3", "L3 button (left analog button)") - CONFIG_BIND(g_settings.input.binds[0][RETRO_DEVICE_ID_JOYPAD_R3], 1, "r3", "R3 button (right analog button)") - CONFIG_BIND(g_settings.input.binds[0][RARCH_ANALOG_LEFT_Y_MINUS], 1, "l_y_minus", "Left analog Y- (up)") - CONFIG_BIND(g_settings.input.binds[0][RARCH_ANALOG_LEFT_Y_PLUS], 1, "l_y_plus", "Left analog Y+ (down)") - CONFIG_BIND(g_settings.input.binds[0][RARCH_ANALOG_LEFT_X_MINUS], 1, "l_x_minus", "Left analog X- (left)") - CONFIG_BIND(g_settings.input.binds[0][RARCH_ANALOG_LEFT_X_PLUS], 1, "l_x_plus", "Left analog X+ (right)") - CONFIG_BIND(g_settings.input.binds[0][RARCH_ANALOG_RIGHT_Y_MINUS], 1, "r_y_minus", "Right analog Y- (up)") - CONFIG_BIND(g_settings.input.binds[0][RARCH_ANALOG_RIGHT_Y_PLUS], 1, "r_y_plus", "Right analog Y+ (down)") - CONFIG_BIND(g_settings.input.binds[0][RARCH_ANALOG_RIGHT_X_MINUS], 1, "r_x_minus", "Right analog X- (left)") - CONFIG_BIND(g_settings.input.binds[0][RARCH_ANALOG_RIGHT_X_PLUS], 1, "r_x_plus", "Right analog X+ (right)") - CONFIG_BIND(g_settings.input.binds[0][RARCH_TURBO_ENABLE], 1, "turbo", "Turbo enable") - END_SUB_GROUP() - END_GROUP() - - /********/ - /* Misc */ - /********/ - START_GROUP("Misc") - START_SUB_GROUP("Misc") - CONFIG_BOOL(g_extern.config_save_on_exit, "config_save_on_exit", "Save Config On Exit") - CONFIG_BOOL(g_settings.network_cmd_enable, "network_cmd_enable", "Network Commands") - CONFIG_INT(g_settings.network_cmd_port, "network_cmd_port", "Network Command Port") - CONFIG_BOOL(g_settings.stdin_cmd_enable, "stdin_cmd_enable", "stdin command") - END_SUB_GROUP() - END_GROUP() - - { 0 } -}; - -// HACK -#undef g_settings -#undef g_extern +// These functions operate only on RetroArch's main settings list +void setting_data_load_current(); +const rarch_setting_t* setting_data_get_list(); // Keyboard #include "keycode.h" -#endif \ No newline at end of file +#endif diff --git a/apple/common/utility.m b/apple/common/utility.m index c0425423e5..a7e026d899 100644 --- a/apple/common/utility.m +++ b/apple/common/utility.m @@ -16,6 +16,7 @@ #include #include "RetroArch_Apple.h" +#include "setting_data.h" #include "general.h" #include "file.h" @@ -54,56 +55,81 @@ NSString* objc_get_value_from_config(config_file_t* config, NSString* name, NSSt return result; } -#ifdef IOS -#include "../iOS/views.h" - -// Simple class to reduce code duplication for fixed table views -@implementation RATableViewController - -- (id)initWithStyle:(UITableViewStyle)style +// Get a core ID as an NSString +NSString *apple_get_core_id(const core_info_t *core) { - self = [super initWithStyle:style]; - self.sections = [NSMutableArray array]; + char buf[PATH_MAX]; + return @(apple_core_info_get_id(core, buf, sizeof(buf))); +} + +NSString *apple_get_core_display_name(NSString *core_id) +{ + const core_info_t *core = apple_core_info_list_get_by_id(core_id.UTF8String); + return core ? @(core->display_name) : core_id; +} + +// Number formatter class for setting strings +@implementation RANumberFormatter +- (id)initWithSetting:(const rarch_setting_t*)setting +{ + if ((self = [super init])) + { + self.allowsFloats = (setting->type == ST_FLOAT); + + if (setting->min != setting->max) + { + self.minimum = @(setting->min); + self.maximum = @(setting->max); + } + else + { + if (setting->type == ST_INT) + { + self.minimum = @(INT_MIN); + self.maximum = @(INT_MAX); + } + else if (setting->type == ST_UINT) + { + self.minimum = @(0); + self.maximum = @(UINT_MAX); + } + else if (setting->type == ST_FLOAT) + { + self.minimum = @(FLT_MIN); + self.maximum = @(FLT_MAX); + } + } + } + return self; } -- (bool)getCellFor:(NSString*)reuseID withStyle:(UITableViewCellStyle)style result:(UITableViewCell**)output +- (BOOL)isPartialStringValid:(NSString*)partialString newEditingString:(NSString**)newString errorDescription:(NSString**)error { - UITableViewCell* result = [self.tableView dequeueReusableCellWithIdentifier:reuseID]; - - if (result) - *output = result; - else - *output = [[UITableViewCell alloc] initWithStyle:style reuseIdentifier:reuseID]; - - return !result; + bool hasDot = false; + + if (partialString.length) + for (int i = 0; i != partialString.length; i ++) + { + unichar ch = [partialString characterAtIndex:i]; + + if (i == 0 && (!self.minimum || self.minimum.intValue < 0) && ch == '-') + continue; + else if (self.allowsFloats && !hasDot && ch == '.') + hasDot = true; + else if (!isdigit(ch)) + return NO; + } + + return YES; } -- (NSInteger)numberOfSectionsInTableView:(UITableView*)tableView +#ifdef IOS +- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string { - return self.sections.count; + NSString* text = [textField.text stringByReplacingCharactersInRange:range withString:string]; + return [self isPartialStringValid:text newEditingString:nil errorDescription:nil]; } - -- (NSString*)tableView:(UITableView*)tableView titleForHeaderInSection:(NSInteger)section -{ - return self.hidesHeaders ? nil : self.sections[section][0]; -} - -- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section -{ - return [self.sections[section] count] - 1; -} - -- (id)itemForIndexPath:(NSIndexPath*)indexPath -{ - return self.sections[indexPath.section][indexPath.row + 1]; -} - -- (void)reset -{ - self.sections = [NSMutableArray array]; - [self.tableView reloadData]; -} -@end - #endif + +@end diff --git a/apple/iOS/RALogView.m b/apple/iOS/RALogView.m deleted file mode 100644 index d81608a0fc..0000000000 --- a/apple/iOS/RALogView.m +++ /dev/null @@ -1,84 +0,0 @@ -/* RetroArch - A frontend for libretro. - * Copyright (C) 2013 - Jason Fetters - * - * RetroArch is free software: you can redistribute it and/or modify it under the terms - * of the GNU General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with RetroArch. - * If not, see . - */ - -#include -#include -#include - -#import "views.h" - -static NSMutableArray* g_messages; -static pthread_mutex_t g_lock = PTHREAD_MUTEX_INITIALIZER; - -void ios_add_log_message(const char* format, ...) -{ - pthread_mutex_lock(&g_lock); - - g_messages = g_messages ? g_messages : [NSMutableArray array]; - - char buffer[512]; - - va_list args; - va_start(args, format); - vsnprintf(buffer, 512, format, args); - va_end(args); - [g_messages addObject:@(buffer)]; - - pthread_mutex_unlock(&g_lock); -} - -@implementation RALogView - -- (RALogView*)init -{ - self = [super initWithStyle:UITableViewStyleGrouped]; - [self setTitle:@"RetroArch Diagnostic Log"]; - return self; -} - -- (NSInteger)numberOfSectionsInTableView:(UITableView*)tableView -{ - return 1; -} - -- (NSString*)tableView:(UITableView*)tableView titleForHeaderInSection:(NSInteger)section -{ - return @"Messages"; -} - -- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section -{ - pthread_mutex_lock(&g_lock); - NSInteger count = g_messages ? g_messages.count : 0; - pthread_mutex_unlock(&g_lock); - - return count; -} - -- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath -{ - static NSString* const cell_id = @"message"; - - UITableViewCell* cell = [self.tableView dequeueReusableCellWithIdentifier:cell_id]; - cell = cell ? cell : [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cell_id]; - - pthread_mutex_lock(&g_lock); - cell.textLabel.text = g_messages[indexPath.row]; - pthread_mutex_unlock(&g_lock); - - return cell; -} - -@end diff --git a/apple/iOS/browser.m b/apple/iOS/browser.m index 3766126834..0f9b100fa5 100644 --- a/apple/iOS/browser.m +++ b/apple/iOS/browser.m @@ -24,16 +24,6 @@ static const void* const associated_module_key = &associated_module_key; -@implementation RADirectoryItem -+ (RADirectoryItem*)directoryItemFromElement:(struct string_list_elem*)element -{ - RADirectoryItem* item = [RADirectoryItem new]; - item.path = @(element->data); - item.isDirectory = element->attr.b; - return item; -} -@end - enum file_action { FA_DELETE = 10000, FA_CREATE, FA_MOVE }; static void file_action(enum file_action action, NSString* source, NSString* target) { @@ -54,6 +44,50 @@ static void file_action(enum file_action action, NSString* source, NSString* tar apple_display_alert(error.localizedDescription, @"Action failed"); } +@implementation RADirectoryItem ++ (RADirectoryItem*)directoryItemFromPath:(NSString*)path +{ + RADirectoryItem* item = [RADirectoryItem new]; + item.path = path; + item.isDirectory = path_is_absolute(path.UTF8String); + return item; +} + ++ (RADirectoryItem*)directoryItemFromElement:(struct string_list_elem*)element +{ + RADirectoryItem* item = [RADirectoryItem new]; + item.path = @(element->data); + item.isDirectory = element->attr.b; + return item; +} + +- (UITableViewCell*)cellForTableView:(UITableView *)tableView +{ + static NSString* const cell_id = @"path_item"; + static NSString* const icon_types[2] = { @"ic_file", @"ic_dir" }; + + uint32_t type_id = self.isDirectory ? 1 : 0; + + UITableViewCell* result = [tableView dequeueReusableCellWithIdentifier:cell_id]; + if (!result) + result = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cell_id]; + + result.textLabel.text = [self.path lastPathComponent]; + result.imageView.image = [UIImage imageNamed:icon_types[type_id]]; + + return result; +} + +- (void)wasSelectedOnTableView:(UITableView *)tableView ofController:(UIViewController *)controller +{ + if (self.isDirectory) + [(id)controller browseTo:self.path]; + else + [[(id)controller directoryDelegate] directoryList:controller itemWasSelected:self]; +} + +@end + @implementation RADirectoryList { NSString* _path; @@ -61,15 +95,12 @@ static void file_action(enum file_action action, NSString* source, NSString* tar - (id)initWithPath:(NSString*)path delegate:(id)delegate { - self = [super initWithStyle:UITableViewStylePlain]; - - if (self) + if ((self = [super initWithStyle:UITableViewStylePlain])) { _path = path; _directoryDelegate = delegate; self = [super initWithStyle:UITableViewStylePlain]; - self.title = path.lastPathComponent; self.hidesHeaders = YES; self.toolbarItems = @@ -84,34 +115,19 @@ static void file_action(enum file_action action, NSString* source, NSString* tar [self.tableView addGestureRecognizer:[[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(fileAction:)]]; + + self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"Up" + style:UIBarButtonItemStyleBordered target:self action:@selector(gotoParent)]; } return self; } -- (void)viewWillAppear:(BOOL)animated +- (void)browseTo:(NSString*)path { - [self refresh]; -} - -- (void)viewDidDisappear:(BOOL)animated -{ - [self reset]; -} + _path = path; + self.title = _path.lastPathComponent; -- (NSArray*)sectionIndexTitlesForTableView:(UITableView*)tableView -{ - static NSArray* names = nil; - - if (!names) - names = @[@"/", @"#", @"A", @"B", @"C", @"D", @"E", @"F", @"G", @"H", @"I", @"J", @"K", @"L", - @"M", @"N", @"O", @"P", @"Q", @"R", @"S", @"T", @"U", @"V", @"W", @"X", @"Y", @"Z"]; - - return names; -} - -- (void)refresh -{ // Need one array per section self.sections = [NSMutableArray array]; @@ -139,34 +155,36 @@ static void file_action(enum file_action action, NSString* source, NSString* tar } else apple_display_alert([NSString stringWithFormat:@"Browsed path is not a directory: %@", _path], 0); - - [self.tableView reloadData]; + + [self.tableView scrollRectToVisible:CGRectMake(0, 0, 1, 1) animated:NO]; + [UIView transitionWithView:self.tableView duration:.25f options:UIViewAnimationOptionTransitionCrossDissolve + animations: + ^{ + [self.tableView reloadData]; + } completion:nil]; } -- (void)tableView:(UITableView*)tableView didSelectRowAtIndexPath:(NSIndexPath*)indexPath +- (void)gotoParent { - [self.directoryDelegate directoryList:self itemWasSelected:[self itemForIndexPath:indexPath]]; + [self browseTo:[_path stringByDeletingLastPathComponent]]; } -- (UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath +- (void)viewWillAppear:(BOOL)animated { - RADirectoryItem* path = [self itemForIndexPath:indexPath]; - uint32_t type_id = path.isDirectory ? 1 : 0; - - UITableViewCell* cell = nil; - - static NSString* const cell_types[2] = { @"file", @"folder" }; - if ([self getCellFor:cell_types[type_id] withStyle:UITableViewCellStyleDefault result:&cell]) - { - static NSString* const icon_types[2] = { @"ic_file", @"ic_dir" }; - cell.imageView.image = [UIImage imageNamed:icon_types[type_id]]; - } - - cell.textLabel.text = [path.path lastPathComponent]; - - return cell; + [super viewWillAppear:animated]; + [self browseTo:_path]; } +- (NSArray*)sectionIndexTitlesForTableView:(UITableView*)tableView +{ + static NSArray* names = nil; + + if (!names) + names = @[@"/", @"#", @"A", @"B", @"C", @"D", @"E", @"F", @"G", @"H", @"I", @"J", @"K", @"L", + @"M", @"N", @"O", @"P", @"Q", @"R", @"S", @"T", @"U", @"V", @"W", @"X", @"Y", @"Z"]; + + return names; +} // File management // Called as a selector from a toolbar button @@ -245,95 +263,35 @@ static void file_action(enum file_action action, NSString* source, NSString* tar file_action(alertView.tag, self.selectedItem.path, [_path stringByAppendingPathComponent:text]); } - [self refresh]; + [self browseTo:_path]; } - @end -@implementation RAModuleList -- (id)initWithGame:(NSString*)path delegate:(id)delegate -{ - self = [super initWithStyle:UITableViewStyleGrouped]; - - if (self) - { - [self setTitle:path ? [path lastPathComponent] : @"Cores"]; - _moduleDelegate = delegate; - - // Load the modules with their data - NSArray* moduleList = apple_get_modules(); - - NSMutableArray* supported = [NSMutableArray arrayWithObject:@"Suggested Cores"]; - NSMutableArray* other = [NSMutableArray arrayWithObject:@"Other Cores"]; - - for (RAModuleInfo* i in moduleList) - { - if (path && [i supportsFileAtPath:path]) [supported addObject:i]; - else [other addObject:i]; - } - - if (supported.count > 1) - [self.sections addObject:supported]; - - if (other.count > 1) - [self.sections addObject:other]; - } - - return self; -} - -- (void)tableView:(UITableView*)tableView didSelectRowAtIndexPath:(NSIndexPath*)indexPath -{ - [self.moduleDelegate moduleList:self itemWasSelected:[self itemForIndexPath:indexPath]]; -} - -- (void)infoButtonTapped:(id)sender -{ - RAModuleInfo* info = objc_getAssociatedObject(sender, associated_module_key); - if (info && info.data) - [self.navigationController pushViewController:[[RAModuleInfoList alloc] initWithModuleInfo:info] animated:YES]; - else - apple_display_alert(@"No information available.", 0); -} - -- (UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath -{ - static NSString* const cell_id = @"module"; - - UITableViewCell* cell = nil; - if ([self getCellFor:cell_id withStyle:UITableViewCellStyleDefault result:&cell]) - { - UIButton* infoButton = [UIButton buttonWithType:UIButtonTypeInfoDark]; - [infoButton addTarget:self action:@selector(infoButtonTapped:) forControlEvents:UIControlEventTouchUpInside]; - cell.accessoryView = infoButton; - } - - RAModuleInfo* info = (RAModuleInfo*)[self itemForIndexPath:indexPath]; - cell.textLabel.text = info.description; - objc_setAssociatedObject(cell.accessoryView, associated_module_key, info, OBJC_ASSOCIATION_RETAIN_NONATOMIC); - - return cell; -} +@interface RAFoldersList() +@property (nonatomic) NSString* path; @end @implementation RAFoldersList -{ - NSString* _path; -} - (id)initWithFilePath:(NSString*)path { - self = [super initWithStyle:UITableViewStyleGrouped]; - - if (self) + if ((self = [super initWithStyle:UITableViewStyleGrouped])) { + RAFoldersList* __weak weakSelf = self; _path = path; + // Parent item + NSString* sourceItem = _path.stringByDeletingLastPathComponent; + + RAMenuItemBasic* parentItem = [RAMenuItemBasic itemWithDescription:@"" association:sourceItem.stringByDeletingLastPathComponent + action:^(id userdata){ [weakSelf moveInto:userdata]; } detail:NULL]; + [self.sections addObject:@[@"", parentItem]]; + + // List contents struct string_list* contents = dir_list_new([_path stringByDeletingLastPathComponent].UTF8String, 0, true); NSMutableArray* items = [NSMutableArray arrayWithObject:@""]; - NSString* sourceDirectory = _path.stringByDeletingLastPathComponent; if (contents) { @@ -344,7 +302,10 @@ static void file_action(enum file_action action, NSString* source, NSString* tar if (contents->elems[i].attr.b) { const char* basename = path_basename(contents->elems[i].data); - [items addObject:[sourceDirectory stringByAppendingPathComponent:@(basename)]]; + + RAMenuItemBasic* item = [RAMenuItemBasic itemWithDescription:@(basename) association:@(contents->elems[i].data) + action:^(id userdata){ [weakSelf moveInto:userdata]; } detail:NULL]; + [items addObject:item]; } } @@ -352,29 +313,17 @@ static void file_action(enum file_action action, NSString* source, NSString* tar } [self setTitle:[@"Move " stringByAppendingString:_path.lastPathComponent]]; - [self.sections addObject:@[@"", [sourceDirectory stringByDeletingLastPathComponent]]]; + [self.sections addObject:items]; } return self; } -- (UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath +- (void)moveInto:(NSString*)path { - static NSString* const cell_id = @"Directory"; - - UITableViewCell* cell = nil; - [self getCellFor:cell_id withStyle:UITableViewCellStyleDefault result:&cell]; - - cell.textLabel.text = [[self itemForIndexPath:indexPath] lastPathComponent]; - - return cell; -} - -- (void)tableView:(UITableView*)tableView didSelectRowAtIndexPath:(NSIndexPath*)indexPath -{ - NSString* targetPath = [[self itemForIndexPath:indexPath] stringByAppendingPathComponent:_path.lastPathComponent]; - file_action(FA_MOVE, _path, targetPath); + NSString* targetPath = [path stringByAppendingPathComponent:self.path.lastPathComponent]; + file_action(FA_MOVE, self.path, targetPath); [self.navigationController popViewControllerAnimated:YES]; } diff --git a/apple/iOS/menu.h b/apple/iOS/menu.h new file mode 100644 index 0000000000..0a77754afc --- /dev/null +++ b/apple/iOS/menu.h @@ -0,0 +1,197 @@ +/* RetroArch - A frontend for libretro. + * Copyright (C) 2013 - Jason Fetters + * + * RetroArch is free software: you can redistribute it and/or modify it under the terms + * of the GNU General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with RetroArch. + * If not, see . + */ + +#ifndef __APPLE_RARCH_IOS_MENU_H__ +#define __APPLE_RARCH_IOS_MENU_H__ + +#include "frontend/menu/history.h" +#include "views.h" +#include "apple/common/setting_data.h" + +@protocol RAMenuItemBase +- (UITableViewCell*)cellForTableView:(UITableView*)tableView; +- (void)wasSelectedOnTableView:(UITableView*)tableView ofController:(UIViewController*)controller; +@end + +/*********************************************/ +/* RAMenuBase */ +/* A menu class that displays RAMenuItemBase */ +/* objects. */ +/*********************************************/ +@interface RAMenuBase : UITableViewController +@property (nonatomic) NSMutableArray* sections; +@property (nonatomic) BOOL hidesHeaders; + +- (id)initWithStyle:(UITableViewStyle)style; +- (id)itemForIndexPath:(NSIndexPath*)indexPath; +@end + +/*********************************************/ +/* RAMenuItemBasic */ +/* A simple menu item that displays a text */ +/* description and calls a block object when */ +/* selected. */ +/*********************************************/ +@interface RAMenuItemBasic : NSObject +@property (nonatomic) NSString* description; +@property (nonatomic) id userdata; +@property (copy) void (^action)(id userdata); +@property (copy) NSString* (^detail)(id userdata); + ++ (RAMenuItemBasic*)itemWithDescription:(NSString*)description association:(id)userdata action:(void (^)())action detail:(NSString* (^)())detail; +@end + +/*********************************************/ +/* RAMenuItemBooleanSetting */ +/* A simple menu item that displays the */ +/* state, and allows editing, of a boolean */ +/* setting. */ +/*********************************************/ +@interface RAMenuItemBooleanSetting : NSObject +@property (nonatomic) const rarch_setting_t* setting; +@end + +/*********************************************/ +/* RAMenuItemGeneralSetting */ +/* A simple menu item that displays the */ +/* state, and allows editing, of a string or */ +/* numeric setting. */ +/*********************************************/ +@interface RAMenuItemGeneralSetting : NSObject +@property (nonatomic) const rarch_setting_t* setting; +@property (nonatomic, weak) UITableView* parentTable; +@end + +/*********************************************/ +/* RAMenuItemPathSetting */ +/* A menu item that displays and allows */ +/* browsing for a path setting. */ +/*********************************************/ +@interface RAMenuItemPathSetting : RAMenuItemGeneralSetting @end + +/*********************************************/ +/* RAMenuItemBindSetting */ +/* A menu item that displays and allows */ +/* mapping of a keybinding. */ +/*********************************************/ +@interface RAMenuItemBindSetting : RAMenuItemGeneralSetting @end + +/*********************************************/ +/* RAMainMenu */ +/* Menu object that is displayed immediately */ +/* after startup. */ +/*********************************************/ +@interface RAMainMenu : RAMenuBase +@property (nonatomic) NSString* core; +@end + +/*********************************************/ +/* RAHistoryMenu */ +/* Menu object that displays and allows */ +/* launching a file from the ROM history. */ +/*********************************************/ +@interface RAHistoryMenu : RAMenuBase +@property (nonatomic) rom_history_t* history; +- (id)initWithHistoryPath:(NSString*)historyPath; +@end + +/*********************************************/ +/* RASettingsGroupMenu */ +/* Menu object that displays and allows */ +/* editing of the a group of */ +/* rarch_setting_t structures. */ +/*********************************************/ +@interface RASettingsGroupMenu : RAMenuBase +- (id)initWithGroup:(const rarch_setting_t*)settings; +@end + +/*********************************************/ +/* RACoreSettingsMenu */ +/* Menu object that displays and allows */ +/* editing of the setting_data list. */ +/*********************************************/ +@interface RACoreSettingsMenu : RAMenuBase +@property (nonatomic) NSString* core; +- (id)initWithCore:(NSString*)core; +@end + +/*********************************************/ +/* RAFrontendSettingsMenu */ +/* Menu object that displays and allows */ +/* editing of cocoa frontend related */ +/* settings. */ +/*********************************************/ +@interface RAFrontendSettingsMenu : RASettingsGroupMenu @end + +/*********************************************/ +/* RACoreOptionsMenu */ +/* Menu object that allows editing of */ +/* options specific to the running core. */ +/*********************************************/ +@interface RACoreOptionsMenu : RAMenuBase @end + +/*********************************************/ +/* RAMenuItemCoreList */ +/* Menu item that handles display and */ +/* selection of an item in RAMenuCoreList. */ +/* This item will not function on anything */ +/* but an RAMenuCoreList type menu. */ +/*********************************************/ +@class RAMenuCoreList; +@interface RAMenuItemCoreList : NSObject +@property (nonatomic, weak) RAMenuCoreList* parent; +@property (nonatomic) NSString* core; +@end + +/*********************************************/ +/* RAMenuCoreList */ +/* Menu object that displays and allows */ +/* selection from a list of cores. */ +/* If the path is not nil, only cores that */ +/* may support the file is listed. */ +/* If the path is nil, an 'Auto Detect' */ +/* entry is added to the menu, when tapped */ +/* the action function will be called with */ +/* nil as the argument. */ +/*********************************************/ +@interface RAMenuCoreList : RAMenuBase +@property (nonatomic) NSString* path; +@property (copy) void (^action)(NSString* coreID); +- (id)initWithPath:(NSString*)path action:(void (^)(NSString*))action; +@end + +/*********************************************/ +/* RALogMenu */ +/* Displays a text file line-by-line. */ +/*********************************************/ +@interface RALogMenu : RAMenuBase +- (id)initWithFile:(const char*)path; +@end + +/*********************************************/ +/* RAMenuItemStateSelect */ +/* Menu item that allows save state slots */ +/* 0-9 to be selected. */ +/*********************************************/ +@interface RAMenuItemStateSelect : NSObject @end + +/*********************************************/ +/* RAPauseMenu */ +/* Menu which provides options for the */ +/* currently running game. */ +/*********************************************/ +@interface RAPauseMenu : RAMenuBase @end + +#endif diff --git a/apple/iOS/menu.m b/apple/iOS/menu.m new file mode 100644 index 0000000000..ea0ba573a6 --- /dev/null +++ b/apple/iOS/menu.m @@ -0,0 +1,952 @@ +/* RetroArch - A frontend for libretro. + * Copyright (C) 2013 - Jason Fetters + * + * RetroArch is free software: you can redistribute it and/or modify it under the terms + * of the GNU General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with RetroArch. + * If not, see . + */ + +#include +#include "apple/common/RetroArch_Apple.h" +#include "apple/common/apple_input.h" +#include "menu.h" + +/*********************************************/ +/* RAMenuBase */ +/* A menu class that displays RAMenuItemBase */ +/* objects. */ +/*********************************************/ +@implementation RAMenuBase + +- (id)initWithStyle:(UITableViewStyle)style +{ + if ((self = [super initWithStyle:style])) + self.sections = [NSMutableArray array]; + return self; +} + +- (NSInteger)numberOfSectionsInTableView:(UITableView*)tableView +{ + return self.sections.count; +} + +- (NSString*)tableView:(UITableView*)tableView titleForHeaderInSection:(NSInteger)section +{ + return self.hidesHeaders ? nil : self.sections[section][0]; +} + +- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section +{ + return [self.sections[section] count] - 1; +} + +- (id)itemForIndexPath:(NSIndexPath*)indexPath +{ + return self.sections[indexPath.section][indexPath.row + 1]; +} + +- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath +{ + return [[self itemForIndexPath:indexPath] cellForTableView:tableView]; +} + +- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath +{ + [[self itemForIndexPath:indexPath] wasSelectedOnTableView:tableView ofController:self]; +} + +@end + +/*********************************************/ +/* RAMenuItemBasic */ +/* A simple menu item that displays a text */ +/* description and calls a block object when */ +/* selected. */ +/*********************************************/ +@implementation RAMenuItemBasic + ++ (RAMenuItemBasic*)itemWithDescription:(NSString*)description action:(void (^)())action +{ + return [self itemWithDescription:description action:action detail:Nil]; +} + ++ (RAMenuItemBasic*)itemWithDescription:(NSString*)description action:(void (^)())action detail:(NSString* (^)())detail +{ + return [self itemWithDescription:description association:nil action:action detail:detail]; +} + ++ (RAMenuItemBasic*)itemWithDescription:(NSString*)description association:(id)userdata action:(void (^)())action detail:(NSString* (^)())detail +{ + RAMenuItemBasic* item = [RAMenuItemBasic new]; + item.description = description; + item.userdata = userdata; + item.action = action; + item.detail = detail; + return item; +} + +- (UITableViewCell*)cellForTableView:(UITableView*)tableView +{ + static NSString* const cell_id = @"text"; + + UITableViewCell* result = [tableView dequeueReusableCellWithIdentifier:cell_id]; + if (!result) + result = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:cell_id]; + + result.selectionStyle = UITableViewCellSelectionStyleNone; + result.textLabel.text = self.description; + result.detailTextLabel.text = self.detail ? self.detail(self.userdata) : nil; + return result; +} + +- (void)wasSelectedOnTableView:(UITableView*)tableView ofController:(UIViewController*)controller +{ + if (self.action) + self.action(self.userdata); +} + +@end + +/*********************************************/ +/* RAMenuItemBooleanSetting */ +/* A simple menu item that displays the */ +/* state, and allows editing, of a boolean */ +/* setting. */ +/*********************************************/ +@implementation RAMenuItemBooleanSetting + ++ (RAMenuItemBooleanSetting*)itemForSetting:(const rarch_setting_t*)setting +{ + RAMenuItemBooleanSetting* item = [RAMenuItemBooleanSetting new]; + item.setting = setting; + return item; +} + +- (UITableViewCell*)cellForTableView:(UITableView*)tableView +{ + static NSString* const cell_id = @"boolean_setting"; + + UITableViewCell* result = [tableView dequeueReusableCellWithIdentifier:cell_id]; + if (!result) + { + result = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:cell_id]; + result.selectionStyle = UITableViewCellSelectionStyleNone; + result.accessoryView = [UISwitch new]; + } + + result.textLabel.text = @(self.setting->short_description); + [(id)result.accessoryView removeTarget:nil action:NULL forControlEvents:UIControlEventValueChanged]; + [(id)result.accessoryView addTarget:self action:@selector(handleBooleanSwitch:) forControlEvents:UIControlEventValueChanged]; + + if (self.setting) + [(id)result.accessoryView setOn:*self.setting->value.boolean]; + return result; +} + +- (void)handleBooleanSwitch:(UISwitch*)swt +{ + if (self.setting) + *self.setting->value.boolean = swt.on ? true : false; +} + +- (void)wasSelectedOnTableView:(UITableView*)tableView ofController:(UIViewController*)controller +{ +} + +@end + +/*********************************************/ +/* RAMenuItemGeneralSetting */ +/* A simple menu item that displays the */ +/* state, and allows editing, of a string or */ +/* numeric setting. */ +/*********************************************/ +@interface RAMenuItemGeneralSetting() +@property (nonatomic) RANumberFormatter* formatter; +@end + +@implementation RAMenuItemGeneralSetting + ++ (RAMenuItemGeneralSetting*)itemForSetting:(const rarch_setting_t*)setting +{ + RAMenuItemGeneralSetting* item = [RAMenuItemGeneralSetting new]; + item.setting = setting; + + if (item.setting->type == ST_INT || item.setting->type == ST_UINT || item.setting->type == ST_FLOAT) + item.formatter = [[RANumberFormatter alloc] initWithSetting:item.setting]; + + return item; +} + +- (UITableViewCell*)cellForTableView:(UITableView*)tableView +{ + static NSString* const cell_id = @"string_setting"; + + self.parentTable = tableView; + + UITableViewCell* result = [tableView dequeueReusableCellWithIdentifier:cell_id]; + if (!result) + { + result = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:cell_id]; + result.selectionStyle = UITableViewCellSelectionStyleNone; + } + + char buffer[256]; + result.textLabel.text = @(self.setting->short_description); + + if (self.setting) + result.detailTextLabel.text = @(setting_data_get_string_representation(self.setting, buffer, sizeof(buffer))); + return result; +} + +- (void)wasSelectedOnTableView:(UITableView*)tableView ofController:(UIViewController*)controller +{ + UIAlertView* alertView = [[UIAlertView alloc] initWithTitle:@"Enter new value" message:@(self.setting->short_description) delegate:self + cancelButtonTitle:@"Cancel" otherButtonTitles:@"OK", nil]; + alertView.alertViewStyle = UIAlertViewStylePlainTextInput; + + UITextField* field = [alertView textFieldAtIndex:0]; + char buffer[256]; + + field.delegate = self.formatter; + field.placeholder = @(setting_data_get_string_representation(self.setting, buffer, sizeof(buffer))); + + [alertView show]; +} + +- (void)alertView:(UIAlertView*)alertView clickedButtonAtIndex:(NSInteger)buttonIndex +{ + NSString* text = [alertView textFieldAtIndex:0].text; + + if (buttonIndex == alertView.firstOtherButtonIndex && text.length) + { + setting_data_set_with_string_representation(self.setting, text.UTF8String); + [self.parentTable reloadData]; + } +} + +@end + +/*********************************************/ +/* RAMenuItemPathSetting */ +/* A menu item that displays and allows */ +/* browsing for a path setting. */ +/*********************************************/ +@interface RAMenuItemPathSetting() @end +@implementation RAMenuItemPathSetting + ++ (RAMenuItemPathSetting*)itemForSetting:(const rarch_setting_t*)setting +{ + RAMenuItemPathSetting* item = [RAMenuItemPathSetting new]; + item.setting = setting; + return item; +} + +- (void)wasSelectedOnTableView:(UITableView*)tableView ofController:(UIViewController*)controller +{ + RADirectoryList* list = [[RADirectoryList alloc] initWithPath:@"/" delegate:self]; + [controller.navigationController pushViewController:list animated:YES]; +} + +- (bool)directoryList:(id)list itemWasSelected:(RADirectoryItem *)path +{ + setting_data_set_with_string_representation(self.setting, path.path.UTF8String); + [[list navigationController] popViewControllerAnimated:YES]; + + [self.parentTable reloadData]; + + return true; +} + +@end + +/*********************************************/ +/* RAMenuItemBindSetting */ +/* A menu item that displays and allows */ +/* mapping of a keybinding. */ +/*********************************************/ +@interface RAMenuItemBindSetting() +@property (nonatomic) NSTimer* bindTimer; +@property (nonatomic) UIAlertView* alert; +@end + +@implementation RAMenuItemBindSetting + ++ (RAMenuItemBindSetting*)itemForSetting:(const rarch_setting_t*)setting +{ + RAMenuItemBindSetting* item = [RAMenuItemBindSetting new]; + item.setting = setting; + return item; +} + +- (void)wasSelectedOnTableView:(UITableView *)tableView ofController:(UIViewController *)controller +{ + self.alert = [[UIAlertView alloc] initWithTitle:@"RetroArch" + message:@(self.setting->short_description) + delegate:self + cancelButtonTitle:@"Cancel" + otherButtonTitles:@"Clear Keyboard", @"Clear Joystick", @"Clear Axis", nil]; + [self.alert show]; + + [self.parentTable reloadData]; + + self.bindTimer = [NSTimer scheduledTimerWithTimeInterval:.1f target:self selector:@selector(checkBind:) + userInfo:nil repeats:YES]; +} + +- (void)finishWithClickedButton:(bool)clicked +{ + if (!clicked) + [self.alert dismissWithClickedButtonIndex:self.alert.cancelButtonIndex animated:YES]; + self.alert = nil; + + + [self.parentTable reloadData]; + + [self.bindTimer invalidate]; + self.bindTimer = nil; +} + +- (void)alertView:(UIAlertView*)alertView clickedButtonAtIndex:(NSInteger)buttonIndex +{ + if (buttonIndex == alertView.firstOtherButtonIndex) + BINDFOR(*self.setting).key = RETROK_UNKNOWN; + else if(buttonIndex == alertView.firstOtherButtonIndex + 1) + BINDFOR(*self.setting).joykey = NO_BTN; + else if(buttonIndex == alertView.firstOtherButtonIndex + 2) + BINDFOR(*self.setting).joyaxis = AXIS_NONE; + + [self finishWithClickedButton:true]; +} + +- (void)checkBind:(NSTimer*)send +{ + int32_t value = 0; + + if ((value = apple_input_find_any_key())) + BINDFOR(*self.setting).key = input_translate_keysym_to_rk(value); + else if ((value = apple_input_find_any_button(0)) >= 0) + BINDFOR(*self.setting).joykey = value; + else if ((value = apple_input_find_any_axis(0))) + BINDFOR(*self.setting).joyaxis = (value > 0) ? AXIS_POS(value - 1) : AXIS_NEG(value - 1); + else + return; + + [self finishWithClickedButton:false]; +} + +@end + + +/*********************************************/ +/* RAMainMenu */ +/* Menu object that is displayed immediately */ +/* after startup. */ +/*********************************************/ +@implementation RAMainMenu + +- (id)init +{ + if ((self = [super initWithStyle:UITableViewStylePlain])) + { + RAMainMenu* __weak weakSelf = self; + + self.title = @"RetroArch"; + + self.sections = + (id)@[ + @[ @"", + [RAMenuItemBasic itemWithDescription:@"Choose Core" + action:^{ [weakSelf chooseCoreWithPath:nil]; } + detail:^{ return weakSelf.core ? apple_get_core_display_name(weakSelf.core) : @"Auto Detect"; }], + [RAMenuItemBasic itemWithDescription:@"Load Game" action:^{ [weakSelf loadGame]; }], + [RAMenuItemBasic itemWithDescription:@"Load Game (History)" action:^{ [weakSelf loadHistory]; }], + [RAMenuItemBasic itemWithDescription:@"Frontend Settings" action:^{ [[RetroArch_iOS get] showSystemSettings]; }] + ] + ]; + } + + return self; +} + +- (void)chooseCoreWithPath:(NSString*)path +{ + RAMainMenu* __weak weakSelf = self; + + RAMenuCoreList* list = [[RAMenuCoreList alloc] initWithPath:path + action: ^(NSString* core) + { + if (path) + apple_run_core(weakSelf.core, path.UTF8String); + else + { + weakSelf.core = core; + [weakSelf.tableView reloadData]; + [weakSelf.navigationController popViewControllerAnimated:YES]; + } + }]; + [self.navigationController pushViewController:list animated:YES]; +} + +- (void)loadGame +{ + NSString* rootPath = RetroArch_iOS.get.documentsDirectory; + NSString* ragPath = [rootPath stringByAppendingPathComponent:@"RetroArchGames"]; + NSString* target = path_is_directory(ragPath.UTF8String) ? ragPath : rootPath; + + [self.navigationController pushViewController:[[RADirectoryList alloc] initWithPath:target delegate:self] animated:YES]; +} + +- (void)loadHistory +{ + NSString* history_path = [NSString stringWithFormat:@"%@/%s", RetroArch_iOS.get.systemDirectory, ".retroarch-game-history.txt"]; + [self.navigationController pushViewController:[[RAHistoryMenu alloc] initWithHistoryPath:history_path] animated:YES]; +} + +- (bool)directoryList:(id)list itemWasSelected:(RADirectoryItem*)path +{ + if (!path.isDirectory) + { + if (self.core) + apple_run_core(self.core, path.path.UTF8String); + else + [self chooseCoreWithPath:path.path]; + } + + return true; +} + +@end + +/*********************************************/ +/* RAHistoryMenu */ +/* Menu object that displays and allows */ +/* launching a file from the ROM history. */ +/*********************************************/ +@implementation RAHistoryMenu + +- (id)initWithHistoryPath:(NSString *)historyPath +{ + if ((self = [super initWithStyle:UITableViewStylePlain])) + { + RAHistoryMenu* __weak weakSelf = self; + + _history = rom_history_init(historyPath.UTF8String, 100); + + NSMutableArray* section = [NSMutableArray arrayWithObject:@""]; + [self.sections addObject:section]; + + for (int i = 0; _history && i != rom_history_size(_history); i ++) + { + RAMenuItemBasic* item = [RAMenuItemBasic itemWithDescription:@(path_basename(apple_rom_history_get_path(weakSelf.history, i))) + action:^{ apple_run_core(@(apple_rom_history_get_core_path(weakSelf.history, i)), + apple_rom_history_get_path(weakSelf.history, i)); } + detail:^{ return @(apple_rom_history_get_core_name(weakSelf.history, i)); }]; + [section addObject:item]; + } + } + + return self; +} + +- (void)dealloc +{ + rom_history_free(self.history); +} + +@end + +/*********************************************/ +/* RASettingsGroupMenu */ +/* Menu object that displays and allows */ +/* editing of the a group of */ +/* rarch_setting_t structures. */ +/*********************************************/ +@implementation RASettingsGroupMenu + +- (id)initWithGroup:(const rarch_setting_t*)group +{ + if ((self = [super initWithStyle:UITableViewStyleGrouped])) + { + self.title = @(group->name); + + NSMutableArray* settings = nil; + + for (const rarch_setting_t* i = group + 1; i->type != ST_END_GROUP; i ++) + { + if (i->type == ST_SUB_GROUP) + settings = [NSMutableArray arrayWithObjects:@(i->name), nil]; + else if (i->type == ST_END_SUB_GROUP) + { + if (settings.count) + [self.sections addObject:settings]; + } + else if (i->type == ST_BOOL) + [settings addObject:[RAMenuItemBooleanSetting itemForSetting:i]]; + else if (i->type == ST_INT || i->type == ST_UINT || i->type == ST_FLOAT || i->type == ST_STRING) + [settings addObject:[RAMenuItemGeneralSetting itemForSetting:i]]; + else if (i->type == ST_PATH) + [settings addObject:[RAMenuItemPathSetting itemForSetting:i]]; + else if (i->type == ST_BIND) + [settings addObject:[RAMenuItemBindSetting itemForSetting:i]]; + } + } + + return self; +} + +@end + + +/*********************************************/ +/* RACoreSettingsMenu */ +/* Menu object that displays and allows */ +/* editing of the setting_data list. */ +/*********************************************/ +@interface RACoreSettingsMenu() +@property (nonatomic) NSString* pathToSave; // < Leave nil to not save +@end + +@implementation RACoreSettingsMenu + +- (id)initWithCore:(NSString*)core +{ + char buffer[PATH_MAX]; + + RACoreSettingsMenu* __weak weakSelf = self; + + if ((self = [super initWithStyle:UITableViewStyleGrouped])) + { + if (apple_core_info_has_custom_config(core.UTF8String)) + _pathToSave = @(apple_core_info_get_custom_config(core.UTF8String, buffer, sizeof(buffer))); + else + _pathToSave = apple_platform.globalConfigFile; + + const rarch_setting_t* setting_data = setting_data_get_list(); + + setting_data_reset(setting_data); + setting_data_load_config_path(setting_data, _pathToSave.UTF8String); + + // HACK: Load the key mapping table + apple_input_find_any_key(); + + self.core = core; + self.title = self.core ? apple_get_core_display_name(core) : @"Global Core Config"; + + NSMutableArray* settings = [NSMutableArray arrayWithObjects:@"", nil]; + [self.sections addObject:settings]; + + for (const rarch_setting_t* i = setting_data; i->type != ST_NONE; i ++) + if (i->type == ST_GROUP) + [settings addObject:[RAMenuItemBasic itemWithDescription:@(i->name) action: + ^{ + [weakSelf.navigationController pushViewController:[[RASettingsGroupMenu alloc] initWithGroup:i] animated:YES]; + }]]; + + [settings addObject:[RAMenuItemBasic itemWithDescription:@"Core Options" + action:^{ [weakSelf.navigationController pushViewController:[RACoreOptionsMenu new] animated:YES]; }]]; + } + + return self; +} + +- (void)dealloc +{ + if (self.pathToSave) + { + config_file_t* config = config_file_new(self.pathToSave.UTF8String); + if (!config) + config = config_file_new(0); + + setting_data_save_config(setting_data_get_list(), config); + + config_set_string(config, "system_directory", [[RetroArch_iOS get].systemDirectory UTF8String]); + config_set_string(config, "savefile_directory", [[RetroArch_iOS get].systemDirectory UTF8String]); + config_set_string(config, "savestate_directory", [[RetroArch_iOS get].systemDirectory UTF8String]); + config_file_write(config, self.pathToSave.UTF8String); + config_file_free(config); + } +} + +@end + +/*********************************************/ +/* RAFrontendSettingsMenu */ +/* Menu object that displays and allows */ +/* editing of cocoa frontend related */ +/* settings. */ +/*********************************************/ +static const void* const associated_core_key = &associated_core_key; + +@interface RAFrontendSettingsMenu() @end +@implementation RAFrontendSettingsMenu + +- (id)init +{ + const rarch_setting_t* apple_get_frontend_settings(); + const rarch_setting_t* frontend_setting_data = apple_get_frontend_settings(); + + if ((self = [super initWithGroup:frontend_setting_data])) + { + RAFrontendSettingsMenu* __weak weakSelf = self; + + self.title = @"Frontend Settings"; + + RAMenuItemBasic* diagnostic_item = [RAMenuItemBasic itemWithDescription:@"Diagnostic Log" + action:^{ [weakSelf.navigationController pushViewController:[[RALogMenu alloc] initWithFile:RetroArch_iOS.get.logPath.UTF8String] animated:YES]; }]; + [self.sections insertObject:@[@"", diagnostic_item] atIndex:0]; + + // Core items to load core settings + NSMutableArray* cores = [NSMutableArray arrayWithObject:@"Cores"]; + + [cores addObject:[RAMenuItemBasic itemWithDescription:@"Global Core Config" + action: ^{ [weakSelf showCoreConfigFor:nil]; }]]; + + const core_info_list_t* core_list = apple_core_info_list_get(); + for (int i = 0; i < core_list->count; i ++) + [cores addObject:[RAMenuItemBasic itemWithDescription:@(core_list->list[i].display_name) + association:apple_get_core_id(&core_list->list[i]) + action: ^(id userdata) { [weakSelf showCoreConfigFor:userdata]; } + detail: ^(id userdata) { return apple_core_info_has_custom_config([userdata UTF8String]) ? @"[Custom]" : @"[Global]"; }]]; + [self.sections addObject:cores]; + } + + return self; +} + +- (void)dealloc +{ + const rarch_setting_t* apple_get_frontend_settings(); + setting_data_save_config_path(apple_get_frontend_settings(), [RetroArch_iOS get].systemConfigPath.UTF8String); + [[RetroArch_iOS get] refreshSystemConfig]; +} + +- (void)showCoreConfigFor:(NSString*)core +{ + if (core && !apple_core_info_has_custom_config(core.UTF8String)) + { + UIAlertView* alert = [[UIAlertView alloc] initWithTitle:@"RetroArch" + message:@"No custom configuration for this core exists, " + "would you like to create one?" + delegate:self + cancelButtonTitle:@"No" + otherButtonTitles:@"Yes", nil]; + objc_setAssociatedObject(alert, associated_core_key, core, OBJC_ASSOCIATION_RETAIN_NONATOMIC); + [alert show]; + } + else + [self.navigationController pushViewController:[[RACoreSettingsMenu alloc] initWithCore:core] animated:YES]; +} + +- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex +{ + NSString* core_id = objc_getAssociatedObject(alertView, associated_core_key); + + if (buttonIndex == alertView.firstOtherButtonIndex && core_id) + { + char path[PATH_MAX]; + apple_core_info_get_custom_config(core_id.UTF8String, path, sizeof(path)); + + if (![[NSFileManager defaultManager] copyItemAtPath:apple_platform.globalConfigFile toPath:@(path) error:nil]) + RARCH_WARN("Could not create custom config at %s", path); + [self.tableView reloadData]; + } + + [self.navigationController pushViewController:[[RACoreSettingsMenu alloc] initWithCore:core_id] animated:YES]; +} + +@end + +/*********************************************/ +/* RACoreOptionsMenu */ +/* Menu object that allows editing of */ +/* options specific to the running core. */ +/*********************************************/ +@interface RACoreOptionsMenu() +@property (nonatomic) uint32_t currentIndex; +@end + +@implementation RACoreOptionsMenu + +- (id)init +{ + if ((self = [super initWithStyle:UITableViewStyleGrouped])) + { + RACoreOptionsMenu* __weak weakSelf = self; + core_option_manager_t* options = g_extern.system.core_options; + + NSMutableArray* section = [NSMutableArray arrayWithObject:@""]; + [self.sections addObject:section]; + + if (options) + { + for (int i = 0; i != core_option_size(options); i ++) + [section addObject:[RAMenuItemBasic itemWithDescription:@(core_option_get_desc(options, i)) association:nil + action:^{ [weakSelf editValue:i]; } + detail:^{ return @(core_option_get_val(options, i)); }]]; + } + else + [section addObject:[RAMenuItemBasic itemWithDescription:@"The running core has no options." action:NULL]]; + } + + return self; +} + +- (void)editValue:(uint32_t)index +{ + self.currentIndex = index; + + UIActionSheet* sheet = [UIActionSheet new]; + sheet.title = @(core_option_get_desc(g_extern.system.core_options, index)); + sheet.delegate = self; + + struct string_list* values = core_option_get_vals(g_extern.system.core_options, index); + + for (int i = 0; i != values->size; i ++) + [sheet addButtonWithTitle:@(values->elems[i].data)]; + + [sheet addButtonWithTitle:@"Cancel"]; + sheet.cancelButtonIndex = sheet.numberOfButtons - 1; + + [sheet showInView:self.tableView]; +} + +- (void)actionSheet:(UIActionSheet*)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex +{ + if (buttonIndex != actionSheet.cancelButtonIndex) + core_option_set_val(g_extern.system.core_options, self.currentIndex, buttonIndex); + + [self.tableView reloadData]; +} + +@end + +/*********************************************/ +/* RAMenuItemCoreList */ +/* Menu item that handles display and */ +/* selection of an item in RAMenuCoreList. */ +/* This item will not function on anything */ +/* but an RAMenuCoreList type menu. */ +/*********************************************/ +@implementation RAMenuItemCoreList + +- (id)initWithCore:(NSString*)core parent:(RAMenuCoreList* __weak)parent +{ + if ((self = [super init])) + { + _core = core; + _parent = parent; + } + + return self; +} + +- (UITableViewCell*)cellForTableView:(UITableView*)tableView +{ + static NSString* const cell_id = @"RAMenuItemCoreList"; + + UITableViewCell* result = [tableView dequeueReusableCellWithIdentifier:cell_id]; + if (!result) + { + result = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:cell_id]; +// UIButton* infoButton = [UIButton buttonWithType:UIButtonTypeInfoDark]; +// [infoButton addTarget:self action:@selector(infoButtonTapped:) forControlEvents:UIControlEventTouchUpInside]; +// result.accessoryView = infoButton; + } + + result.textLabel.text = apple_get_core_display_name(self.core); + return result; +} + +- (void)wasSelectedOnTableView:(UITableView*)tableView ofController:(UIViewController*)controller +{ + if (self.parent.action) + self.parent.action(self.core); +} + +@end + +/*********************************************/ +/* RAMenuCoreList */ +/* Menu object that displays and allows */ +/* selection from a list of cores. */ +/* If the path is not nil, only cores that */ +/* may support the file is listed. */ +/* If the path is nil, an 'Auto Detect' */ +/* entry is added to the menu, when tapped */ +/* the action function will be called with */ +/* nil as the argument. */ +/*********************************************/ +@implementation RAMenuCoreList + +- (id)initWithPath:(NSString*)path action:(void (^)(NSString *))action +{ + if ((self = [super initWithStyle:UITableViewStyleGrouped])) + { + self.title = @"Choose Core"; + _action = action; + _path = path; + + if (!_path) + { + RAMenuCoreList* __weak weakSelf = self; + [self.sections addObject: @[@"", [RAMenuItemBasic itemWithDescription:@"Auto Detect" + action: ^{ if(weakSelf.action) weakSelf.action(nil); }]]]; + } + + NSMutableArray* core_section = [NSMutableArray arrayWithObject:@"Cores"]; + [self.sections addObject:core_section]; + + core_info_list_t* core_list = apple_core_info_list_get(); + if (core_list) + { + if (!_path) + [self load:core_list->count coresFromList:core_list->list toSection:core_section]; + else + { + const core_info_t* core_support = 0; + size_t core_count = 0; + core_info_list_get_supported_cores(core_list, _path.UTF8String, &core_support, &core_count); + + if (core_count == 1 && _action) + _action(apple_get_core_id(&core_support[0])); + else if (core_count > 1) + [self load:core_count coresFromList:core_support toSection:core_section]; + } + } + } + + return self; +} + +- (void)load:(uint32_t)count coresFromList:(const core_info_t*)list toSection:(NSMutableArray*)array +{ + for (int i = 0; i < count; i ++) + [array addObject:[[RAMenuItemCoreList alloc] initWithCore:apple_get_core_id(&list[i]) parent:self]]; +} + +@end + +/*********************************************/ +/* RALogMenu */ +/* Displays a text file line-by-line. */ +/*********************************************/ +@implementation RALogMenu + +- (id)initWithFile:(const char*)path +{ + if ((self = [super initWithStyle:UITableViewStylePlain])) + { + NSMutableArray* data = [NSMutableArray arrayWithObject:@""]; + + fflush(stdout); + fflush(stderr); + FILE* file = fopen(path, "r"); + if (file) + { + char buffer[1024]; + while (fgets(buffer, 1024, file)) + [data addObject:[RAMenuItemBasic itemWithDescription:@(buffer) action:NULL]]; + fclose(file); + } + else + [data addObject:[RAMenuItemBasic itemWithDescription:@"Logging not enabled" action:NULL]]; + + [self.sections addObject:data]; + + } + + return self; +} + +@end + +/*********************************************/ +/* RAMenuItemStateSelect */ +/* Menu item that allows save state slots */ +/* 0-9 to be selected. */ +/*********************************************/ +@implementation RAMenuItemStateSelect + +- (UITableViewCell*)cellForTableView:(UITableView*)tableView +{ + static NSString* const cell_id = @"state_slot_setting"; + + UITableViewCell* result = [tableView dequeueReusableCellWithIdentifier:cell_id]; + if (!result) + { + result = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:cell_id]; + result.selectionStyle = UITableViewCellSelectionStyleNone; + + result.textLabel.text = @"Slot"; + + UISegmentedControl* accessory = [[UISegmentedControl alloc] initWithItems:@[@"0", @"1", @"2", @"3", @"4", @"5", @"6", @"7", @"8", @"9"]]; + [accessory addTarget:self action:@selector(changed:) forControlEvents:UIControlEventValueChanged]; + accessory.segmentedControlStyle = UISegmentedControlStyleBar; + result.accessoryView = accessory; + } + + [(id)result.accessoryView setSelectedSegmentIndex:(g_extern.state_slot < 10) ? g_extern.state_slot : -1]; + + return result; +} + +- (void)changed:(UISegmentedControl*)sender +{ + g_extern.state_slot = sender.selectedSegmentIndex; +} + +- (void)wasSelectedOnTableView:(UITableView *)tableView ofController:(UIViewController *)controller +{ + +} + +@end + +/*********************************************/ +/* RAPauseMenu */ +/* Menu which provides options for the */ +/* currently running game. */ +/*********************************************/ +@implementation RAPauseMenu + +- (id)init +{ + if ((self = [super initWithStyle:UITableViewStyleGrouped])) + { + RAPauseMenu* __weak weakSelf = self; + + [self.sections addObject:@[@"Actions", + [RAMenuItemBasic itemWithDescription:@"Reset Game" action:^{ [weakSelf performBasicAction:RESET]; }], + [RAMenuItemBasic itemWithDescription:@"Close Game" action:^{ [weakSelf performBasicAction:QUIT]; }] + ]]; + + [self.sections addObject:@[@"States", + [RAMenuItemStateSelect new], + [RAMenuItemBasic itemWithDescription:@"Load State" action:^{ [weakSelf performBasicAction:LOAD_STATE]; }], + [RAMenuItemBasic itemWithDescription:@"Save State" action:^{ [weakSelf performBasicAction:SAVE_STATE]; }] + ]]; + + [self.sections addObject:@[@"Settings", + [RAMenuItemBasic itemWithDescription:@"System Config" action:^{ [[RetroArch_iOS get] showSystemSettings]; }], + [RAMenuItemBasic itemWithDescription:@"Core Config" action:^{ [[RetroArch_iOS get] showSettings]; }] + ]]; + } + + return self; +} + +- (void)performBasicAction:(enum basic_event_t)action +{ + [self.navigationController popViewControllerAnimated:(action != QUIT)]; + apple_frontend_post_event(apple_event_basic_command, action); +} + +@end diff --git a/apple/iOS/platform.h b/apple/iOS/platform.h index 4282656126..00850d0add 100644 --- a/apple/iOS/platform.h +++ b/apple/iOS/platform.h @@ -21,21 +21,21 @@ @interface RAGameView : UIViewController + (RAGameView*)get; -- (void)openPauseMenu; -- (void)closePauseMenu; - (void)iOS7SetiCadeMode:(bool)on; @end -@interface RetroArch_iOS : UINavigationController +@interface RetroArch_iOS : UINavigationController + (RetroArch_iOS*)get; -- (void)loadingCore:(RAModuleInfo*)core withFile:(const char*)file; -- (void)unloadingCore:(RAModuleInfo*)core; +- (void)loadingCore:(NSString*)core withFile:(const char*)file; +- (void)unloadingCore:(NSString*)core; - (void)refreshSystemConfig; +- (IBAction)showSettings; +- (IBAction)showSystemSettings; + @property (nonatomic) NSString* configDirectory; // e.g. /var/mobile/Documents/.RetroArch @property (nonatomic) NSString* globalConfigFile; // e.g. /var/mobile/Documents/.RetroArch/retroarch.cfg @property (nonatomic) NSString* coreDirectory; // e.g. /Applications/RetroArch.app/modules @@ -43,6 +43,7 @@ @property (nonatomic) NSString* documentsDirectory; // e.g. /var/mobile/Documents @property (nonatomic) NSString* systemDirectory; // e.g. /var/mobile/Documents/.RetroArch @property (nonatomic) NSString* systemConfigPath; // e.g. /var/mobile/Documents/.RetroArch/frontend.cfg +@property (nonatomic) NSString* logPath; @end diff --git a/apple/iOS/platform.m b/apple/iOS/platform.m index ed19a3a299..d77bd71092 100644 --- a/apple/iOS/platform.m +++ b/apple/iOS/platform.m @@ -20,6 +20,8 @@ #include "rarch_wrapper.h" #include "apple/common/apple_input.h" +#include "apple/common/setting_data.h" +#include "menu.h" #import "views.h" #include "bluetooth/btpad.h" @@ -28,6 +30,57 @@ #include "file.h" +static struct +{ + bool portrait; + bool portrait_upside_down; + bool landscape_left; + bool landscape_right; + + bool logging_enabled; + + char bluetooth_mode[64]; + + struct + { + int stdout; + int stderr; + + FILE* file; + } logging; +} apple_frontend_settings; + +const rarch_setting_t* apple_get_frontend_settings() +{ + static rarch_setting_t settings[16]; + + settings[0] = setting_data_group_setting(ST_GROUP, "Frontend Settings"); + settings[1] = setting_data_group_setting(ST_SUB_GROUP, "Frontend"); + settings[2] = setting_data_bool_setting("ios_use_file_log", "Enable File Logging", + &apple_frontend_settings.logging_enabled, false); + settings[3] = setting_data_bool_setting("ios_tv_mode", "TV Mode", &apple_use_tv_mode, false); + settings[4] = setting_data_group_setting(ST_END_SUB_GROUP, 0); + + settings[5] = setting_data_group_setting(ST_SUB_GROUP, "Bluetooth"); + settings[6] = setting_data_string_setting("ios_btmode", "Mode", apple_frontend_settings.bluetooth_mode, + sizeof(apple_frontend_settings.bluetooth_mode), "keyboard"); + settings[7] = setting_data_group_setting(ST_END_SUB_GROUP, 0); + + settings[8] = setting_data_group_setting(ST_SUB_GROUP, "Orientations"); + settings[9] = setting_data_bool_setting("ios_allow_portrait", "Portrait", + &apple_frontend_settings.portrait, true); + settings[10] = setting_data_bool_setting("ios_allow_portrait_upside_down", "Portrait Upside Down", + &apple_frontend_settings.portrait_upside_down, true); + settings[11] = setting_data_bool_setting("ios_allow_landscape_left", "Landscape Left", + &apple_frontend_settings.landscape_left, true); + settings[12] = setting_data_bool_setting("ios_allow_landscape_right", "Landscape Right", + &apple_frontend_settings.landscape_right, true); + settings[13] = setting_data_group_setting(ST_END_SUB_GROUP, 0); + settings[14] = setting_data_group_setting(ST_END_GROUP, 0); + + return settings; +} + //#define HAVE_DEBUG_FILELOG bool is_ios_7() { @@ -51,6 +104,29 @@ void ios_set_bluetooth_mode(NSString* mode) #endif } +void ios_set_logging_state(bool on) +{ + fflush(stdout); + fflush(stderr); + + if (on && !apple_frontend_settings.logging.file) + { + apple_frontend_settings.logging.file = fopen([RetroArch_iOS get].logPath.UTF8String, "a"); + apple_frontend_settings.logging.stdout = dup(1); + apple_frontend_settings.logging.stderr = dup(2); + dup2(fileno(apple_frontend_settings.logging.file), 1); + dup2(fileno(apple_frontend_settings.logging.file), 2); + } + else if (!on && apple_frontend_settings.logging.file) + { + dup2(apple_frontend_settings.logging.stdout, 1); + dup2(apple_frontend_settings.logging.stderr, 2); + + fclose(apple_frontend_settings.logging.file); + apple_frontend_settings.logging.file = 0; + } +} + // Input helpers: This is kept here because it needs objective-c static void handle_touch_event(NSArray* touches) { @@ -106,7 +182,7 @@ static void handle_touch_event(NSArray* touches) { key_commands = [NSMutableArray array]; - for (int i = 0; i != 26; i ++) + for (int i = 0; i < 26; i ++) { [key_commands addObject:[UIKeyCommand keyCommandWithInput:[NSString stringWithFormat:@"%c", 'a' + i] modifierFlags:0 action:@selector(keyGotten:)]]; @@ -130,8 +206,7 @@ static void handle_touch_event(NSArray* touches) UIWindow* _window; NSString* _path; - bool _isGameTop, _isRomList; - uint32_t _settingMenusInBackStack; + bool _isGameTop; uint32_t _enabledOrientations; } @@ -159,6 +234,7 @@ static void handle_touch_event(NSArray* touches) self.configDirectory = self.systemDirectory; self.globalConfigFile = [NSString stringWithFormat:@"%@/retroarch.cfg", self.configDirectory]; self.coreDirectory = [NSBundle.mainBundle.bundlePath stringByAppendingPathComponent:@"modules"]; + self.logPath = [self.systemDirectory stringByAppendingPathComponent:@"stdout.log"]; const char *path = self.documentsDirectory.UTF8String; path_mkdir(path); @@ -171,11 +247,15 @@ static void handle_touch_event(NSArray* touches) if (access(path, 0755) != 0) apple_display_alert([NSString stringWithFormat:@"Failed to create or access system directory: %@", self.systemDirectory], 0); else - [self beginBrowsingForFile]; + [self pushViewController:[RAMainMenu new] animated:YES]; } // Warn if there are no cores present - if (apple_get_modules().count == 0) + apple_core_info_set_core_path(self.coreDirectory.UTF8String); + apple_core_info_set_config_path(self.configDirectory.UTF8String); + const core_info_list_t* core_list = apple_core_info_list_get(); + + if (!core_list || core_list->count == 0) apple_display_alert(@"No libretro cores were found. You will not be able to play any games.", 0); } @@ -203,77 +283,19 @@ static void handle_touch_event(NSArray* touches) return true; } -- (void)beginBrowsingForFile -{ - NSString* rootPath = RetroArch_iOS.get.documentsDirectory; - NSString* ragPath = [rootPath stringByAppendingPathComponent:@"RetroArchGames"]; - NSString* target = path_is_directory(ragPath.UTF8String) ? ragPath : rootPath; - - [self pushViewController:[[RADirectoryList alloc] initWithPath:target delegate:self] animated:YES]; - - [self refreshSystemConfig]; - if (apple_use_tv_mode) - apple_run_core(nil, 0); - -} - -- (bool)directoryList:(id)list itemWasSelected:(RADirectoryItem*)path -{ - if(path.isDirectory) - [self pushViewController:[[RADirectoryList alloc] initWithPath:path.path delegate:self] animated:YES]; - else - { - _path = path.path; - - if (access([path.path stringByDeletingLastPathComponent].UTF8String, R_OK | W_OK | X_OK)) - apple_display_alert(@"The directory containing the selected file has limited permissions. This may " - "prevent zipped games from loading, and will cause some cores to not function.", 0); - - [self pushViewController:[[RAModuleList alloc] initWithGame:path.path delegate:self] animated:YES]; - } - - return true; -} - -- (bool)moduleList:(id)list itemWasSelected:(RAModuleInfo*)module -{ - apple_run_core(module, _path.UTF8String); - return true; -} - // UINavigationControllerDelegate - (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated { + apple_input_reset_icade_buttons(); _isGameTop = [viewController isKindOfClass:[RAGameView class]]; - _isRomList = [viewController isKindOfClass:[RADirectoryList class]]; + g_extern.is_paused = !_isGameTop; + [[UIApplication sharedApplication] setStatusBarHidden:_isGameTop withAnimation:UIStatusBarAnimationNone]; [[UIApplication sharedApplication] setIdleTimerDisabled:_isGameTop]; - self.navigationBarHidden = _isGameTop; - [self setToolbarHidden:!_isRomList animated:YES]; - self.topViewController.navigationItem.rightBarButtonItem = [self createSettingsButton]; -} - -// UINavigationController: Never animate when pushing onto, or popping, an RAGameView -- (void)pushViewController:(UIViewController*)theView animated:(BOOL)animated -{ - apple_input_reset_icade_buttons(); - - if ([theView respondsToSelector:@selector(isSettingsView)] && [(id)theView isSettingsView]) - _settingMenusInBackStack ++; - - [super pushViewController:theView animated:animated && !_isGameTop]; -} - -- (UIViewController*)popViewControllerAnimated:(BOOL)animated -{ - apple_input_reset_icade_buttons(); - - if ([self.topViewController respondsToSelector:@selector(isSettingsView)] && [(id)self.topViewController isSettingsView]) - _settingMenusInBackStack --; - - return [super popViewControllerAnimated:animated && !_isGameTop]; + [self setNavigationBarHidden:_isGameTop animated:!_isGameTop]; + [self setToolbarHidden:!viewController.toolbarItems.count animated:YES]; } // NOTE: This version only runs on iOS6 @@ -304,17 +326,17 @@ static void handle_touch_event(NSArray* touches) #pragma mark RetroArch_Platform -- (void)loadingCore:(RAModuleInfo*)core withFile:(const char*)file +- (void)loadingCore:(NSString*)core withFile:(const char*)file { [self pushViewController:RAGameView.get animated:NO]; - [RASettingsList refreshModuleConfig:core]; + (void)[[RACoreSettingsMenu alloc] initWithCore:core]; btpad_set_inquiry_state(false); [self refreshSystemConfig]; } -- (void)unloadingCore:(RAModuleInfo*)core +- (void)unloadingCore:(NSString*)core { [self popToViewController:[RAGameView get] animated:NO]; [self popViewControllerAnimated:NO]; @@ -325,104 +347,46 @@ static void handle_touch_event(NSArray* touches) #pragma mark FRONTEND CONFIG - (void)refreshSystemConfig { - // Read load time settings - config_file_t* conf = config_file_new([self.systemConfigPath UTF8String]); + const rarch_setting_t* frontend_settings = apple_get_frontend_settings(); + + setting_data_reset(frontend_settings); + setting_data_load_config_path(frontend_settings, self.systemConfigPath.UTF8String); // Get enabled orientations - static const struct { const char* setting; uint32_t orientation; } orientationSettings[4] = + static const struct { const bool* value; uint32_t orientation; } orientationSettings[4] = { - { "ios_allow_portrait", UIInterfaceOrientationMaskPortrait }, - { "ios_allow_portrait_upside_down", UIInterfaceOrientationMaskPortraitUpsideDown }, - { "ios_allow_landscape_left", UIInterfaceOrientationMaskLandscapeLeft }, - { "ios_allow_landscape_right", UIInterfaceOrientationMaskLandscapeRight } + { &apple_frontend_settings.portrait, UIInterfaceOrientationMaskPortrait }, + { &apple_frontend_settings.portrait_upside_down, UIInterfaceOrientationMaskPortraitUpsideDown }, + { &apple_frontend_settings.landscape_left, UIInterfaceOrientationMaskLandscapeLeft }, + { &apple_frontend_settings.landscape_right, UIInterfaceOrientationMaskLandscapeRight } }; _enabledOrientations = 0; for (int i = 0; i < 4; i ++) - { - bool enabled = false; - bool found = conf && config_get_bool(conf, orientationSettings[i].setting, &enabled); - - if (!found || enabled) - _enabledOrientations |= orientationSettings[i].orientation; - } + _enabledOrientations |= (*orientationSettings[i].value) ? orientationSettings[i].orientation : 0; - if (conf) - { - // Setup bluetooth mode - ios_set_bluetooth_mode(objc_get_value_from_config(conf, @"ios_btmode", @"keyboard")); - - bool val; - apple_use_tv_mode = config_get_bool(conf, "ios_tv_mode", &val) && val; - - config_file_free(conf); - } + // Set bluetooth mode + ios_set_bluetooth_mode(@(apple_frontend_settings.bluetooth_mode)); + ios_set_logging_state(apple_frontend_settings.logging_enabled); + + } #pragma mark PAUSE MENU -- (UIBarButtonItem*)createSettingsButton -{ - if (_settingMenusInBackStack == 0) - return [[UIBarButtonItem alloc] - initWithTitle:@"Settings" - style:UIBarButtonItemStyleBordered - target:[RetroArch_iOS get] - action:@selector(showSystemSettings)]; - - else - return nil; -} - - (IBAction)showPauseMenu:(id)sender { - if (apple_is_running && !apple_is_paused && _isGameTop) - { - apple_is_paused = true; - [[RAGameView get] openPauseMenu]; - - btpad_set_inquiry_state(true); - } -} - -- (IBAction)basicEvent:(id)sender -{ - if (apple_is_running) - apple_frontend_post_event(&apple_event_basic_command, ((UIView*)sender).tag); - - [self closePauseMenu:sender]; -} - -- (IBAction)chooseState:(id)sender -{ - if (apple_is_running) - apple_frontend_post_event(apple_event_set_state_slot, (void*)((UISegmentedControl*)sender).selectedSegmentIndex); -} - -- (IBAction)showRGUI:(id)sender -{ - if (apple_is_running) - apple_frontend_post_event(apple_event_show_rgui, 0); - - [self closePauseMenu:sender]; -} - -- (IBAction)closePauseMenu:(id)sender -{ - [[RAGameView get] closePauseMenu]; - apple_is_paused = false; - - btpad_set_inquiry_state(false); + [self pushViewController:[RAPauseMenu new] animated:YES]; } - (IBAction)showSettings { - [self pushViewController:[[RASettingsList alloc] initWithModule:apple_core] animated:YES]; + [self pushViewController:[[RACoreSettingsMenu alloc] initWithCore:apple_core] animated:YES]; } - (IBAction)showSystemSettings { - [self pushViewController:[RASystemSettingsList new] animated:YES]; + [self pushViewController:[RAFrontendSettingsMenu new] animated:YES]; } @end @@ -430,13 +394,7 @@ static void handle_touch_event(NSArray* touches) int main(int argc, char *argv[]) { @autoreleasepool { -#if defined(HAVE_DEBUG_FILELOG) && (TARGET_IPHONE_SIMULATOR == 0) - NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); - NSString *documentsDirectory = [paths objectAtIndex:0]; - NSString *logPath = [documentsDirectory stringByAppendingPathComponent:@"console_stdout.log"]; - freopen([logPath cStringUsingEncoding:NSASCIIStringEncoding], "a", stdout); - freopen([logPath cStringUsingEncoding:NSASCIIStringEncoding], "a", stderr); -#endif return UIApplicationMain(argc, argv, NSStringFromClass([RApplication class]), NSStringFromClass([RetroArch_iOS class])); } } + diff --git a/apple/iOS/settings.m b/apple/iOS/settings.m deleted file mode 100644 index a7b88ce337..0000000000 --- a/apple/iOS/settings.m +++ /dev/null @@ -1,890 +0,0 @@ -/* RetroArch - A frontend for libretro. - * Copyright (C) 2013 - Jason Fetters - * - * RetroArch is free software: you can redistribute it and/or modify it under the terms - * of the GNU General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with RetroArch. - * If not, see . - */ - -#import "apple/common/RetroArch_Apple.h" -#import "views.h" - -#include "apple/common/apple_input.h" -#include "apple/common/keycode.h" -#include "bluetooth/btdynamic.h" -#include "bluetooth/btpad.h" - -static const void* const associated_userdata_key = &associated_userdata_key; -static const void* const associated_module_key = &associated_module_key; -static const void* const associated_setting_key = &associated_setting_key; - -enum SettingTypes -{ - BooleanSetting, ButtonSetting, EnumerationSetting, FileListSetting, - GroupSetting, AspectSetting, RangeSetting, CustomAction -}; - -@interface RASettingData : NSObject -{ - @public - enum SettingTypes type; - - NSString* label; // < The label displayed in the settings menu - NSString* name; // < The key name of the value in the config file - NSString* value; // < The current state of the setting - - uint32_t player; // < The player that a ButtonSetting represents - NSString* button_bind; // < The Gamepad button binding string - NSString* axis_bind; // < The Gamepad axis binding string - - NSString* path; // < The base path for FileListSettings - NSArray* subValues; // < The available options for EnumerationSettings and FileListSettings - bool haveNoneOption; // < Determines if a 'None' option is added to an Enumeration or FileList - bool haveDescriptions; // < Determines if subValues containts friendly descriptions for each value - - double rangeMin; // < The mininum value of a range setting - double rangeMax; // < The maximum value of a range setting - - void (*changed)(RASettingData* action); - void (*reload)(RASettingData* action, id userdata); -} - -- (void)setValue:(NSString*)aValue; - -@end - -@implementation RASettingData -- (id)initWithType:(enum SettingTypes)aType label:(NSString*)aLabel name:(NSString*)aName -{ - type = aType; - label = aLabel; - name = aName; - return self; -} - -- (void)setValue:(NSString*)aValue; -{ - value = aValue; - - if (changed) - changed(self); -} - -- (uint32_t)enumerationCount -{ - return subValues.count / (haveDescriptions ? 2 : 1); -} - -- (NSString*)valueForEnumerationIndex:(uint32_t)index -{ - return subValues[index * (haveDescriptions ? 2 : 1)]; -} - -- (NSString*)labelForEnumerationIndex:(uint32_t)index -{ - return subValues[index * (haveDescriptions ? 2 : 1) + (haveDescriptions ? 1 : 0)]; -} - -- (NSString*)labelForEnumerationValue -{ - const uint32_t count = self.enumerationCount; - - for (int i = 0; haveDescriptions && i < count; i ++) - { - if ([value isEqualToString:subValues[i * 2]]) - return subValues[i * 2 + 1]; - } - - return value; -} - -@end - -// Helper view definitions -@interface RAButtonGetter : NSObject -- (id)initFromTable:(UITableView*)table; -- (void)runForSetting:(RASettingData*)setting; -@end - -@interface RASettingEnumerationList : UITableViewController -- (id)initWithSetting:(RASettingData*)setting fromTable:(UITableView*)table; -@end - - -static RASettingData* boolean_setting(config_file_t* config, NSString* name, NSString* label, NSString* defaultValue) -{ - RASettingData* result = [[RASettingData alloc] initWithType:BooleanSetting label:label name:name]; - result->value = objc_get_value_from_config(config, name, defaultValue); - return result; -} - -static RASettingData* button_setting(config_file_t* config, uint32_t player, NSString* name, NSString* label, NSString* defaultValue) -{ - NSString* realname = player ? [NSString stringWithFormat:@"input_player%d_%@", player, name] : name; - - RASettingData* result = [[RASettingData alloc] initWithType:ButtonSetting label:label name:realname]; - result->player = player ? player - 1 : 0; - result->value = objc_get_value_from_config(config, realname, defaultValue); - result->button_bind = objc_get_value_from_config(config, [realname stringByAppendingString:@"_btn"], @"nul"); - result->axis_bind = objc_get_value_from_config(config, [realname stringByAppendingString:@"_axis"], @"nul"); - return result; -} - -static RASettingData* group_setting(NSString* label, NSArray* settings) -{ - RASettingData* result = [[RASettingData alloc] initWithType:GroupSetting label:label name:nil]; - result->subValues = settings; - return result; -} - -static RASettingData* enumeration_setting(config_file_t* config, NSString* name, NSString* label, NSString* defaultValue, NSArray* values, bool haveDescriptions) -{ - RASettingData* result = [[RASettingData alloc] initWithType:EnumerationSetting label:label name:name]; - result->value = objc_get_value_from_config(config, name, defaultValue); - result->subValues = values; - result->haveDescriptions = haveDescriptions; - return result; -} - -static RASettingData* subpath_setting(config_file_t* config, NSString* name, NSString* label, NSString* defaultValue, NSString* path, NSString* extension) -{ - NSString* value = objc_get_value_from_config(config, name, defaultValue); - value = [value stringByReplacingOccurrencesOfString:path withString:@""]; - - NSArray* values = [[NSFileManager defaultManager] subpathsOfDirectoryAtPath:path error:nil]; - values = [values pathsMatchingExtensions:[NSArray arrayWithObject:extension]]; - - RASettingData* result = [[RASettingData alloc] initWithType:FileListSetting label:label name:name]; - result->value = value; - result->subValues = values; - result->path = path; - result->haveNoneOption = true; - return result; -} - -static RASettingData* range_setting(config_file_t* config, NSString* name, NSString* label, NSString* defaultValue, double minValue, double maxValue) -{ - RASettingData* result = [[RASettingData alloc] initWithType:RangeSetting label:label name:name]; - result->value = objc_get_value_from_config(config, name, defaultValue); - result->rangeMin = minValue; - result->rangeMax = maxValue; - return result; -} - -static RASettingData* aspect_setting(config_file_t* config, NSString* label) -{ - // Why does this need to be so difficult? - - RASettingData* result = [[RASettingData alloc] initWithType:AspectSetting label:label name:@""]; - result->subValues = [NSArray arrayWithObjects:@"Fill Screen", @"Game Aspect", @"Pixel Aspect", @"4:3", @"16:9", nil]; - - bool videoForceAspect = true; - bool videoAspectAuto = false; - double videoAspect = -1.0; - - if (config) - { - config_get_bool(config, "video_force_aspect", &videoForceAspect); - config_get_bool(config, "video_aspect_auto", &videoAspectAuto); - config_get_double(config, "video_aspect_ratio", &videoAspect); - } - - if (!videoForceAspect) - result->value = @"Fill Screen"; - else if (videoAspect < 0.0) - result->value = videoAspectAuto ? @"Game Aspect" : @"Pixel Aspect"; - else - result->value = (videoAspect < 1.5) ? @"4:3" : @"16:9"; - - return result; -} - -static RASettingData* custom_action(NSString* action, NSString* value, id data, void (*reload_func)(RASettingData* action, id userdata)) -{ - RASettingData* result = [[RASettingData alloc] initWithType:CustomAction label:action name:nil]; - result->value = value; - result->reload = reload_func; - - if (data != nil) - objc_setAssociatedObject(result, associated_userdata_key, data, OBJC_ASSOCIATION_RETAIN_NONATOMIC); - - return result; -} - -// This adds a change notify function to a setting and returns it; done this way so it can be used in NSArray -// init lists. -static RASettingData* change_notify(RASettingData* setting, void (*change_func)(RASettingData* setting)) -{ - setting->changed = change_func; - return setting; -} - -static NSArray* build_input_port_group(config_file_t* config, uint32_t player) -{ - // Only player 1 should have default key bindings - #define DEFKEY(val) (player == 1) ? val : @"nul" - - return [NSArray arrayWithObjects: - [NSArray arrayWithObjects:[NSString stringWithFormat:@"Player %d", player], - button_setting(config, player, @"up", @"Up", DEFKEY(@"up")), - button_setting(config, player, @"down", @"Down", DEFKEY(@"down")), - button_setting(config, player, @"left", @"Left", DEFKEY(@"left")), - button_setting(config, player, @"right", @"Right", DEFKEY(@"right")), - - button_setting(config, player, @"start", @"Start", DEFKEY(@"enter")), - button_setting(config, player, @"select", @"Select", DEFKEY(@"rshift")), - - button_setting(config, player, @"b", @"B", DEFKEY(@"z")), - button_setting(config, player, @"a", @"A", DEFKEY(@"x")), - button_setting(config, player, @"x", @"X", DEFKEY(@"s")), - button_setting(config, player, @"y", @"Y", DEFKEY(@"a")), - - button_setting(config, player, @"l", @"L", DEFKEY(@"q")), - button_setting(config, player, @"r", @"R", DEFKEY(@"w")), - button_setting(config, player, @"l2", @"L2", @"nul"), - button_setting(config, player, @"r2", @"R2", @"nul"), - button_setting(config, player, @"l3", @"L3", @"nul"), - button_setting(config, player, @"r3", @"R3", @"nul"), - - button_setting(config, player, @"l_y_minus", @"Left Stick Up", @"nul"), - button_setting(config, player, @"l_y_plus", @"Left Stick Down", @"nul"), - button_setting(config, player, @"l_x_minus", @"Left Stick Left", @"nul"), - button_setting(config, player, @"l_x_plus", @"Left Stick Right", @"nul"), - button_setting(config, player, @"r_y_minus", @"Right Stick Up", @"nul"), - button_setting(config, player, @"r_y_plus", @"Right Stick Down", @"nul"), - button_setting(config, player, @"r_x_minus", @"Right Stick Left", @"nul"), - button_setting(config, player, @"r_x_plus", @"Right Stick Right", @"nul"), - nil], - nil]; -} - -@implementation RASettingsList -{ - RAModuleInfo* _module; - NSString* _configPath; - bool _cancelSave; // Set to prevent dealloc from writing to disk -} - -+ (void)refreshModuleConfig:(RAModuleInfo*)module; -{ - (void)[[RASettingsList alloc] initWithModule:module]; -} - -- (id)initWithModule:(RAModuleInfo*)module -{ - _module = module; - _configPath = _module ? _module.configFile : apple_platform.globalConfigFile; - - config_file_t* config = config_file_new([_configPath UTF8String]); - - NSString* overlay_path = [[[NSBundle mainBundle] bundlePath] stringByAppendingString:@"/overlays/"]; - NSString* shader_path = [[[NSBundle mainBundle] bundlePath] stringByAppendingString:@"/shaders_glsl/"]; - - NSArray* settings = [NSArray arrayWithObjects: - [NSArray arrayWithObjects:@"Core", - custom_action(@"Core Info", nil, nil, 0), - _module.hasCustomConfig ? custom_action(@"Delete Custom Config", nil, nil, 0) : nil, - nil], - - [NSArray arrayWithObjects:@"Video", - boolean_setting(config, @"video_smooth", @"Bilinear filtering", @"true"), - boolean_setting(config, @"video_crop_overscan", @"Crop Overscan", @"true"), - boolean_setting(config, @"video_scale_integer", @"Integer Scaling", @"false"), - aspect_setting(config, @"Aspect Ratio"), - nil], - - [NSArray arrayWithObjects:@"GPU Shader", - boolean_setting(config, @"video_shader_enable", @"Enable Shader", @"false"), - subpath_setting(config, @"video_shader", @"Shader", @"", shader_path, @"glsl"), - nil], - - [NSArray arrayWithObjects:@"Audio", - boolean_setting(config, @"audio_enable", @"Enable Output", @"true"), - boolean_setting(config, @"audio_sync", @"Sync on Audio", @"true"), - boolean_setting(config, @"audio_rate_control", @"Rate Control", @"true"), - nil], - - [NSArray arrayWithObjects:@"Input", - subpath_setting(config, @"input_overlay", @"Input Overlay", @"", overlay_path, @"cfg"), - range_setting(config, @"input_overlay_opacity", @"Overlay Opacity", @"1.0", 0.0, 1.0), - group_setting(@"System Keys", [NSArray arrayWithObjects: - // TODO: Many of these strings will be cut off on an iPhone - [NSArray arrayWithObjects:@"System Keys", - button_setting(config, 0, @"input_menu_toggle", @"Show RGUI", @"f1"), - button_setting(config, 0, @"input_disk_eject_toggle", @"Insert/Eject Disk", @"nul"), - button_setting(config, 0, @"input_disk_next", @"Cycle Disks", @"nul"), - button_setting(config, 0, @"input_save_state", @"Save State", @"f2"), - button_setting(config, 0, @"input_load_state", @"Load State", @"f4"), - button_setting(config, 0, @"input_state_slot_increase", @"Next State Slot", @"f7"), - button_setting(config, 0, @"input_state_slot_decrease", @"Previous State Slot", @"f6"), - button_setting(config, 0, @"input_toggle_fast_forward", @"Toggle Fast Forward", @"space"), - button_setting(config, 0, @"input_hold_fast_forward", @"Hold Fast Forward", @"l"), - button_setting(config, 0, @"input_rewind", @"Rewind", @"r"), - button_setting(config, 0, @"input_slowmotion", @"Slow Motion", @"e"), - button_setting(config, 0, @"input_reset", @"Reset", @"h"), - button_setting(config, 0, @"input_exit_emulator", @"Close Game", @"escape"), - button_setting(config, 0, @"input_enable_hotkey", @"Hotkey Enable (Always on if not set)", @"nul"), - nil], - nil]), - group_setting(@"Player 1 Keys", build_input_port_group(config, 1)), - group_setting(@"Player 2 Keys", build_input_port_group(config, 2)), - group_setting(@"Player 3 Keys", build_input_port_group(config, 3)), - group_setting(@"Player 4 Keys", build_input_port_group(config, 4)), - nil], - - [NSArray arrayWithObjects:@"Save States", - boolean_setting(config, @"rewind_enable", @"Enable Rewinding", @"false"), - boolean_setting(config, @"block_sram_overwrite", @"Disable SRAM on Load", @"false"), - boolean_setting(config, @"savestate_auto_save", @"Auto Save on Exit", @"false"), - boolean_setting(config, @"savestate_auto_load", @"Auto Load on Startup", @"true"), - nil], - nil - ]; - - if (config) - config_file_free(config); - - self = [super initWithSettings:settings title:_module ? _module.description : @"Global Core Config"]; - return self; -} - -- (void)dealloc -{ - if (!_cancelSave) - { - config_file_t* config = config_file_new([_configPath UTF8String]); - - if (!config) - config = config_file_new(0); - - if (config) - { - config_set_string(config, "system_directory", [[RetroArch_iOS get].systemDirectory UTF8String]); - config_set_string(config, "savefile_directory", [[RetroArch_iOS get].systemDirectory UTF8String]); - config_set_string(config, "savestate_directory", [[RetroArch_iOS get].systemDirectory UTF8String]); - [self writeSettings:nil toConfig:config]; - config_file_write(config, [_configPath UTF8String]); - config_file_free(config); - } - - apple_refresh_config(); - } -} - -- (void)handleCustomAction:(RASettingData*)setting -{ - if ([@"Core Info" isEqualToString:setting->label]) - [self.navigationController pushViewController:[[RAModuleInfoList alloc] initWithModuleInfo:_module] animated:YES]; - else if([@"Delete Custom Config" isEqualToString:setting->label]) - { - [_module deleteCustomConfig]; - _cancelSave = true; - [self.navigationController popViewControllerAnimated:YES]; - } -} - -@end - -#pragma mark System Settings - -static void reload_core_config_state(RASettingData* action, RAModuleInfo* userdata) -{ - [action setValue:userdata.hasCustomConfig ? @"[Custom]" : @"[Global]"]; -} - -static void bluetooth_option_changed(RASettingData* setting) -{ - ios_set_bluetooth_mode(setting->value); -} - -@implementation RASystemSettingsList -- (id)init -{ - config_file_t* config = config_file_new([[RetroArch_iOS get].systemConfigPath UTF8String]); - - NSMutableArray* modules = [NSMutableArray array]; - [modules addObject:@"Cores"]; - [modules addObject:custom_action(@"Global Core Config", nil, nil, 0)]; - - NSArray* moduleList = apple_get_modules(); - for (RAModuleInfo* i in moduleList) - { - [modules addObject:custom_action(i.description, nil, i, reload_core_config_state)]; - } - - - NSArray* bluetoothOptions = nil; - - if (!is_ios_7() && btstack_try_load()) - bluetoothOptions = @[@"keyboard", @"Keyboard", @"icade", @"iCade Device", @"btstack", @"WiiMote/SixAxis (BTstack)"]; - else if (!is_ios_7()) - bluetoothOptions = @[@"keyboard", @"Keyboard", @"icade", @"iCade Device"]; - else // if (is_ios_7()) - bluetoothOptions = @[@"none", @"None", @"icade", @"iCade Device"]; - - NSArray* settings = [NSArray arrayWithObjects: - [NSArray arrayWithObjects:@"Frontend", - custom_action(@"Diagnostic Log", nil, nil, 0), - boolean_setting(config, @"ios_tv_mode", @"TV Mode", @"false"), - nil], - [NSArray arrayWithObjects:@"Bluetooth", - change_notify(enumeration_setting(config, @"ios_btmode", @"Mode", @"keyboard", bluetoothOptions, true), bluetooth_option_changed), - nil], - [NSArray arrayWithObjects:@"Orientations", - boolean_setting(config, @"ios_allow_portrait", @"Portrait", @"true"), - boolean_setting(config, @"ios_allow_portrait_upside_down", @"Portrait Upside Down", @"true"), - boolean_setting(config, @"ios_allow_landscape_left", @"Landscape Left", @"true"), - boolean_setting(config, @"ios_allow_landscape_right", @"Landscape Right", @"true"), - nil], - modules, - nil - ]; - - if (config) - config_file_free(config); - - self = [super initWithSettings:settings title:@"RetroArch Settings"]; - return self; -} - -- (void)viewDidAppear:(BOOL)animated -{ - [self.tableView reloadData]; - [super viewDidAppear:animated]; -} - -- (void)dealloc -{ - config_file_t* config = config_file_new([[RetroArch_iOS get].systemConfigPath UTF8String]); - - if (!config) - config = config_file_new(0); - - if (config) - { - [self writeSettings:nil toConfig:config]; - config_file_write(config, [[RetroArch_iOS get].systemConfigPath UTF8String]); - config_file_free(config); - } - - [[RetroArch_iOS get] refreshSystemConfig]; -} - -- (void)handleCustomAction:(RASettingData*)setting -{ - if ([@"Diagnostic Log" isEqualToString:setting->label]) - [self.navigationController pushViewController:[RALogView new] animated:YES]; - else if ([@"Enable BTstack" isEqualToString:setting->label]) - btstack_set_poweron([setting->value isEqualToString:@"true"]); - else if([@"Global Core Config" isEqualToString:setting->label]) - [self.navigationController pushViewController:[[RASettingsList alloc] initWithModule:nil] animated:YES]; - else - { - RAModuleInfo* data = (RAModuleInfo*)objc_getAssociatedObject(setting, associated_userdata_key); - if (data) - { - if (!data.hasCustomConfig) - { - UIAlertView* alert = [[UIAlertView alloc] initWithTitle:@"RetroArch" - message:@"No custom configuration for this core exists, " - "would you like to create one?" - delegate:self - cancelButtonTitle:@"No" - otherButtonTitles:@"Yes", nil]; - objc_setAssociatedObject(alert, associated_module_key, data, OBJC_ASSOCIATION_RETAIN_NONATOMIC); - [alert show]; - } - else - [self.navigationController pushViewController:[[RASettingsList alloc] initWithModule:data] animated:YES]; - } - } -} - -- (void)alertView:(UIAlertView*)alertView willDismissWithButtonIndex:(NSInteger)buttonIndex -{ - RAModuleInfo* data = (RAModuleInfo*)objc_getAssociatedObject(alertView, associated_module_key); - - if (data) - { - if (buttonIndex == alertView.firstOtherButtonIndex) - { - [data createCustomConfig]; - [self.tableView reloadData]; - } - - [self.navigationController pushViewController:[[RASettingsList alloc] initWithModule:data] animated:YES]; - } - -} - -@end - -@implementation RASettingsSubList -{ - RAButtonGetter* _binder; -} - -- (id)initWithSettings:(NSMutableArray*)values title:(NSString*)title -{ - self = [super initWithStyle:UITableViewStyleGrouped]; - [self setTitle:title]; - - self.sections = values; - _binder = [[RAButtonGetter alloc] initFromTable:self.tableView]; - return self; -} - -- (bool)isSettingsView -{ - return true; -} - -- (void)handleCustomAction:(RASettingData*)setting -{ - -} - -- (void)writeSettings:(NSArray*)settingList toConfig:(config_file_t*)config -{ - if (!config) - return; - - NSArray* list = settingList ? settingList : self.sections; - - for (int i = 0; i < [list count]; i++) - { - NSArray* group = [list objectAtIndex:i]; - - for (int j = 1; j < [group count]; j ++) - { - RASettingData* setting = [group objectAtIndex:j]; - - switch (setting->type) - { - case GroupSetting: - [self writeSettings:setting->subValues toConfig:config]; - break; - - case FileListSetting: - if ([setting->value length] > 0) - config_set_string(config, [setting->name UTF8String], [[setting->path stringByAppendingPathComponent:setting->value] UTF8String]); - else - config_set_string(config, [setting->name UTF8String], ""); - break; - - case ButtonSetting: - if (setting->value) - config_set_string(config, [setting->name UTF8String], [setting->value UTF8String]); - if (setting->button_bind) - config_set_string(config, [[setting->name stringByAppendingString:@"_btn"] UTF8String], [setting->button_bind UTF8String]); - if (setting->axis_bind) - config_set_string(config, [[setting->name stringByAppendingString:@"_axis"] UTF8String], [setting->axis_bind UTF8String]); - break; - - case AspectSetting: - config_set_string(config, "video_force_aspect", [@"Fill Screen" isEqualToString:setting->value] ? "false" : "true"); - config_set_string(config, "video_aspect_ratio_auto", [@"Game Aspect" isEqualToString:setting->value] ? "true" : "false"); - config_set_string(config, "video_aspect_ratio", "-1.0"); - if([@"4:3" isEqualToString:setting->value]) - config_set_string(config, "video_aspect_ratio", "1.33333333"); - else if([@"16:9" isEqualToString:setting->value]) - config_set_string(config, "video_aspect_ratio", "1.77777777"); - break; - - case CustomAction: - break; - - default: - config_set_string(config, [setting->name UTF8String], [setting->value UTF8String]); - break; - } - } - } -} - -- (void)tableView:(UITableView*)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath -{ - RASettingData* setting = (RASettingData*)[self itemForIndexPath:indexPath]; - - switch (setting->type) - { - case EnumerationSetting: - case FileListSetting: - case AspectSetting: - [self.navigationController pushViewController:[[RASettingEnumerationList alloc] initWithSetting:setting fromTable:(UITableView*)self.view] animated:YES]; - break; - - case ButtonSetting: - [_binder runForSetting:setting]; - break; - - case GroupSetting: - [self.navigationController pushViewController:[[RASettingsSubList alloc] initWithSettings:setting->subValues title:setting->label] animated:YES]; - break; - - default: - break; - } - - [self handleCustomAction:setting]; -} - -- (void)handleBooleanSwitch:(UISwitch*)swt -{ - RASettingData* setting = objc_getAssociatedObject(swt, associated_setting_key); - [setting setValue:swt.on ? @"true" : @"false"]; - - [self handleCustomAction:setting]; -} - -- (void)handleSlider:(UISlider*)sld -{ - RASettingData* setting = objc_getAssociatedObject(sld, associated_setting_key); - [setting setValue:[NSString stringWithFormat:@"%f", sld.value]]; - - [self handleCustomAction:setting]; -} - -- (UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath -{ - RASettingData* setting = (RASettingData*)[self itemForIndexPath:indexPath]; - - UITableViewCell* cell = nil; - - switch (setting->type) - { - case BooleanSetting: - { - static NSString* const cell_id = @"boolean"; - cell = [self.tableView dequeueReusableCellWithIdentifier:cell_id]; - - if (cell == nil) - { - cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cell_id]; - - UISwitch* accessory = [[UISwitch alloc] init]; - [accessory addTarget:self action:@selector(handleBooleanSwitch:) forControlEvents:UIControlEventValueChanged]; - cell.accessoryView = accessory; - - [cell setSelectionStyle:UITableViewCellSelectionStyleNone]; - } - - cell.textLabel.text = setting->label; - - UISwitch* swt = (UISwitch*)cell.accessoryView; - swt.on = [setting->value isEqualToString:@"true"]; - objc_setAssociatedObject(swt, associated_setting_key, setting, OBJC_ASSOCIATION_RETAIN_NONATOMIC); - - return cell; - } - - case RangeSetting: - { - static NSString* const cell_id = @"range"; - cell = [self.tableView dequeueReusableCellWithIdentifier:cell_id]; - - if (cell == nil) - { - cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cell_id]; - - UISlider* accessory = [UISlider new]; - [accessory addTarget:self action:@selector(handleSlider:) forControlEvents:UIControlEventValueChanged]; - accessory.continuous = NO; - cell.accessoryView = accessory; - - [cell setSelectionStyle:UITableViewCellSelectionStyleNone]; - } - - cell.textLabel.text = setting->label; - - UISlider* sld = (UISlider*)cell.accessoryView; - sld.minimumValue = setting->rangeMin; - sld.maximumValue = setting->rangeMax; - sld.value = [setting->value doubleValue]; - objc_setAssociatedObject(sld, associated_setting_key, setting, OBJC_ASSOCIATION_RETAIN_NONATOMIC); - - return cell; - } - break; - - default: - { - static NSString* const cell_id = @"default"; - cell = [self.tableView dequeueReusableCellWithIdentifier:cell_id]; - - if (!cell) - { - cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:cell_id]; - cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; - } - - if (setting->reload) - setting->reload(setting, objc_getAssociatedObject(setting, associated_userdata_key)); - - cell.textLabel.text = setting->label; - - if (setting->type == ButtonSetting) - cell.detailTextLabel.text = [NSString stringWithFormat:@"[KB:%@] [JS:%@] [AX:%@]", - [setting->value length] ? setting->value : @"nul", - [setting->button_bind length] ? setting->button_bind : @"nul", - [setting->axis_bind length] ? setting->axis_bind : @"nul"]; - else if(setting->type == EnumerationSetting) - cell.detailTextLabel.text = setting.labelForEnumerationValue; - else - cell.detailTextLabel.text = setting->value; - - return cell; - } - } -} - -@end - -@implementation RASettingEnumerationList -{ - RASettingData* _value; - UITableView* _view; - unsigned _mainSection; -}; - -- (id)initWithSetting:(RASettingData*)setting fromTable:(UITableView*)table -{ - self = [super initWithStyle:UITableViewStyleGrouped]; - - _value = setting; - _view = table; - _mainSection = _value->haveNoneOption ? 1 : 0; - - [self setTitle: _value->label]; - return self; -} - -- (NSInteger)numberOfSectionsInTableView:(UITableView*)tableView -{ - return _value->haveNoneOption ? 2 : 1; -} - -- (NSInteger)tableView:(UITableView*)tableView numberOfRowsInSection:(NSInteger)section -{ - return (section == _mainSection) ? _value.enumerationCount : 1; -} - -- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath -{ - static NSString* const cell_id = @"option"; - - UITableViewCell* cell = [self.tableView dequeueReusableCellWithIdentifier:cell_id]; - cell = cell ? cell : [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cell_id]; - - if (indexPath.section == _mainSection) - cell.textLabel.text = [_value labelForEnumerationIndex:indexPath.row]; - else - cell.textLabel.text = @"None"; - - return cell; -} - -- (void)tableView:(UITableView*)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath -{ - [_value setValue: (indexPath.section == _mainSection) ? [_value valueForEnumerationIndex:indexPath.row] : @""]; - - [_view reloadData]; - [self.navigationController popViewControllerAnimated:YES]; -} - -@end - -@implementation RAButtonGetter -{ - RASettingData* _value; - UIAlertView* _alert; - UITableView* _view; - bool _finished; - NSTimer* _btTimer; -} - -- (id)initFromTable:(UITableView*)table -{ - self = [super init]; - - _view = table; - - _alert = [[UIAlertView alloc] initWithTitle:@"RetroArch" - message:@"" - delegate:self - cancelButtonTitle:@"Cancel" - otherButtonTitles:@"Clear Keyboard", @"Clear Joystick", @"Clear Axis", nil]; - - if (is_ios_7()) - _alert.alertViewStyle = UIAlertViewStylePlainTextInput; - - return self; -} - -- (void)runForSetting:(RASettingData*)setting -{ - apple_input_reset_icade_buttons(); - - _value = setting; - - _alert.message = _value->name; - [_alert show]; - - _btTimer = [NSTimer scheduledTimerWithTimeInterval:.05f target:self selector:@selector(checkInput) userInfo:nil repeats:YES]; - - _finished = false; -} - -- (void)finish -{ - if (!_finished) - { - _finished = true; - - apple_input_reset_icade_buttons(); - - [_btTimer invalidate]; - _btTimer = nil; - - [_alert dismissWithClickedButtonIndex:_alert.cancelButtonIndex animated:YES]; - [_view reloadData]; - } -} - -- (void)alertView:(UIAlertView*)alertView willDismissWithButtonIndex:(NSInteger)buttonIndex -{ - if (buttonIndex == _alert.firstOtherButtonIndex) - _value->value = @"nul"; - else if(buttonIndex == _alert.firstOtherButtonIndex + 1) - _value->button_bind = @"nul"; - else if(buttonIndex == _alert.firstOtherButtonIndex + 2) - _value->axis_bind = @"nul"; - - [self finish]; -} - -- (void)checkInput -{ - int32_t value = 0; - - if ((value = apple_input_find_any_key())) - _value->value = @(apple_keycode_hidusage_to_name(value)); - else if ((value = apple_input_find_any_button(0)) >= 0) - _value->button_bind = [NSString stringWithFormat:@"%d", value]; - else if ((value = apple_input_find_any_axis(0))) - _value->axis_bind = [NSString stringWithFormat:@"%s%d", (value > 0) ? "+" : "-", value - 1]; - else - return; - - [self finish]; -} - -@end - diff --git a/apple/iOS/views.h b/apple/iOS/views.h index 5a0cd530d1..8a294804e8 100644 --- a/apple/iOS/views.h +++ b/apple/iOS/views.h @@ -16,76 +16,34 @@ #ifndef _RARCH_APPLE_VIEWS_H #define _RARCH_APPLE_VIEWS_H -#import "RAModuleInfo.h" +#include +#include "core_info.h" -// RALogView.m -@interface RALogView : UITableViewController -@end - -// utility.m -@interface RATableViewController : UITableViewController -@property (nonatomic) NSMutableArray* sections; -@property (nonatomic) BOOL hidesHeaders; - -- (id)initWithStyle:(UITableViewStyle)style; -- (bool)getCellFor:(NSString*)reuseID withStyle:(UITableViewCellStyle)style result:(UITableViewCell**)output; -- (id)itemForIndexPath:(NSIndexPath*)indexPath; -- (void)reset; -@end - -// browser.m -@interface RADirectoryItem : NSObject -@property (nonatomic) NSString* path; -@property (nonatomic) bool isDirectory; -@end // browser.m +@class RADirectoryItem; @protocol RADirectoryListDelegate - (bool)directoryList:(id)list itemWasSelected:(RADirectoryItem*)path; @end -@interface RADirectoryList : RATableViewController +#include "menu.h" + +// browser.m +@interface RADirectoryItem : NSObject +@property (nonatomic) NSString* path; +@property (nonatomic) bool isDirectory; +@end + +@interface RADirectoryList : RAMenuBase @property (nonatomic, weak) id directoryDelegate; @property (nonatomic, weak) RADirectoryItem* selectedItem; - (id)initWithPath:(NSString*)path delegate:(id)delegate; +- (void)browseTo:(NSString*)path; @end // browser.m -@protocol RAModuleListDelegate -- (bool)moduleList:(id)list itemWasSelected:(RAModuleInfo*)module; -@end - -@interface RAModuleList : RATableViewController -@property (nonatomic, weak) id moduleDelegate; -- (id)initWithGame:(NSString*)path delegate:(id)delegate; -@end - -// browser.m -@interface RAFoldersList : RATableViewController +@interface RAFoldersList : RAMenuBase - (id) initWithFilePath:(NSString*)path; @end -// RAModuleInfo.m -@interface RAModuleInfoList : RATableViewController -- (id)initWithModuleInfo:(RAModuleInfo*)info; -@end - -// settings.m -@interface RASettingsSubList : RATableViewController -- (id)initWithSettings:(NSArray*)values title:(NSString*)title; -- (void)writeSettings:(NSArray*)settingList toConfig:(config_file_t*)config; - -- (bool)isSettingsView; -@end - -// settings.m -@interface RASettingsList : RASettingsSubList -+ (void)refreshModuleConfig:(RAModuleInfo*)module; -- (id)initWithModule:(RAModuleInfo*)module; -@end - -// settings.m -@interface RASystemSettingsList : RASettingsSubList -@end - #endif diff --git a/core_options.c b/core_options.c index f2145423c5..67834db694 100644 --- a/core_options.c +++ b/core_options.c @@ -200,6 +200,18 @@ const char *core_option_get_val(core_option_manager_t *opt, size_t index) return option->vals->elems[option->index].data; } +struct string_list *core_option_get_vals(core_option_manager_t *opt, size_t index) +{ + return opt->opts[index].vals; +} + +void core_option_set_val(core_option_manager_t *opt, size_t index, size_t val_index) +{ + struct core_option *option= (struct core_option*)&opt->opts[index]; + option->index = val_index % option->vals->size; + opt->updated = true; +} + void core_option_next(core_option_manager_t *opt, size_t index) { struct core_option *option = &opt->opts[index]; diff --git a/core_options.h b/core_options.h index 42f408497f..ba4a0da612 100644 --- a/core_options.h +++ b/core_options.h @@ -40,6 +40,10 @@ size_t core_option_size(core_option_manager_t *opt); const char *core_option_get_desc(core_option_manager_t *opt, size_t index); const char *core_option_get_val(core_option_manager_t *opt, size_t index); +// Helpers to present a list of options +struct string_list *core_option_get_vals(core_option_manager_t *opt, size_t index); +void core_option_set_val(core_option_manager_t *opt, size_t index, size_t val_index); + // Cycles through options for an option. Options wrap around. void core_option_next(core_option_manager_t *opt, size_t index); void core_option_prev(core_option_manager_t *opt, size_t index); diff --git a/griffin/griffin.c b/griffin/griffin.c index 104bfe9e6c..0225ff40a0 100644 --- a/griffin/griffin.c +++ b/griffin/griffin.c @@ -22,6 +22,7 @@ #include "../ps3/altivec_mem.c" #endif + /*============================================================ CONSOLE EXTENSIONS ============================================================ */ @@ -43,6 +44,8 @@ CONSOLE EXTENSIONS #include "../file_extract.c" #endif + + /*============================================================ RLAUNCH ============================================================ */ @@ -579,6 +582,15 @@ XML ============================================================ */ #define RXML_LIBXML2_COMPAT #include "../compat/rxml/rxml.c" + +/*============================================================ + APPLE EXTENSIONS +============================================================ */ + +#if defined(IOS) || defined(OSX) +#include "../apple/common/setting_data.c" +#include "../apple/common/core_info_ext.c" +#endif #ifdef __cplusplus }