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
-
-
- IBProxyObject
- IBUIButton
- IBUISegmentedControl
- IBUIView
-
-
- com.apple.InterfaceBuilder.IBCocoaTouchPlugin
-
-
-
-
-
-
-
-
-
-
-
- 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
}