RetroArch/ios/RetroArch/settings/RASettingsList.m

259 lines
12 KiB
Objective-C

/* 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 <http://www.gnu.org/licenses/>.
*/
#import <objc/runtime.h>
#import "settings.h"
@implementation RASettingData
- (id)initWithType:(enum SettingTypes)aType label:(NSString*)aLabel name:(NSString*)aName
{
self.type = aType;
self.label = aLabel;
self.name = aName;
return self;
}
@end
static NSString* get_value_from_config(config_file_t* config, NSString* name, NSString* defaultValue)
{
char* data = 0;
if (config)
config_get_string(config, [name UTF8String], &data);
NSString* result = data ? [NSString stringWithUTF8String:data] : defaultValue;
free(data);
return result;
}
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 = get_value_from_config(config, name, defaultValue);
return result;
}
static RASettingData* button_setting(config_file_t* config, NSString* name, NSString* label, NSString* defaultValue)
{
RASettingData* result = [[RASettingData alloc] initWithType:ButtonSetting label:label name:name];
result.msubValues = [NSMutableArray arrayWithObjects:
get_value_from_config(config, name, defaultValue),
get_value_from_config(config, [name stringByAppendingString:@"_btn"], @""),
get_value_from_config(config, [name stringByAppendingString:@"_axis"], @""),
nil];
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)
{
RASettingData* result = [[RASettingData alloc] initWithType:EnumerationSetting label:label name:name];
result.value = get_value_from_config(config, name, defaultValue);
result.subValues = values;
return result;
}
static RASettingData* subpath_setting(config_file_t* config, NSString* name, NSString* label, NSString* defaultValue, NSString* path, NSString* extension)
{
NSString* value = 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 = 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:@"fram"];
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)
{
return [[RASettingData alloc] initWithType:CustomAction label:action name:nil];
}
@implementation RASettingsList
+ (void)refreshConfigFile
{
(void)[[RASettingsList alloc] init];
}
- (id)init
{
config_file_t* config = config_file_new([[RetroArch_iOS get].moduleInfo.configPath UTF8String]);
NSString* overlay_path = [[[NSBundle mainBundle] bundlePath] stringByAppendingString:@"/overlays/"];
NSString* shader_path = [[[NSBundle mainBundle] bundlePath] stringByAppendingString:@"/shaders/"];
NSArray* settings = [NSArray arrayWithObjects:
[NSArray arrayWithObjects:@"Frontend",
custom_action(@"Module Info"),
custom_action(@"Diagnostic Log"),
boolean_setting(config, @"ios_auto_bluetooth", @"Auto Enable Bluetooth", @"false"),
nil],
[NSArray arrayWithObjects:@"Video",
boolean_setting(config, @"video_smooth", @"Smooth Video", @"true"),
boolean_setting(config, @"video_crop_overscan", @"Crop Overscan", @"true"),
boolean_setting(config, @"video_scale_integer", @"Integer Scaling", @"false"),
aspect_setting(config, @"Aspect Ratio"),
subpath_setting(config, @"video_xml_shader", @"Shader", @"", shader_path, @"shader"),
nil],
[NSArray arrayWithObjects:@"Audio",
boolean_setting(config, @"audio_enable", @"Enable Output", @"true"),
boolean_setting(config, @"audio_sync", @"Sync on Audio Stream", @"true"),
boolean_setting(config, @"audio_rate_control", @"Adjust for Better Sync", @"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(@"Player 1 Keys", [NSArray arrayWithObjects:
[NSArray arrayWithObjects:@"Player 1",
button_setting(config, @"input_player1_up", @"Up", @"up"),
button_setting(config, @"input_player1_down", @"Down", @"down"),
button_setting(config, @"input_player1_left", @"Left", @"left"),
button_setting(config, @"input_player1_right", @"Right", @"right"),
button_setting(config, @"input_player1_start", @"Start", @"enter"),
button_setting(config, @"input_player1_select", @"Select", @"rshift"),
button_setting(config, @"input_player1_b", @"B", @"z"),
button_setting(config, @"input_player1_a", @"A", @"x"),
button_setting(config, @"input_player1_x", @"X", @"s"),
button_setting(config, @"input_player1_y", @"Y", @"a"),
button_setting(config, @"input_player1_l", @"L", @"q"),
button_setting(config, @"input_player1_r", @"R", @"w"),
button_setting(config, @"input_player1_l2", @"L2", @""),
button_setting(config, @"input_player1_r2", @"R2", @""),
button_setting(config, @"input_player1_l3", @"L3", @""),
button_setting(config, @"input_player1_r3", @"R3", @""),
button_setting(config, @"input_player1_l_y_minus", @"Left Stick Up", @""),
button_setting(config, @"input_player1_l_y_plus", @"Left Stick Down", @""),
button_setting(config, @"input_player1_l_x_minus", @"Left Stick Left", @""),
button_setting(config, @"input_player1_l_x_plus", @"Left Stick Right", @""),
button_setting(config, @"input_player1_r_y_minus", @"Right Stick Up", @""),
button_setting(config, @"input_player1_r_y_plus", @"Right Stick Down", @""),
button_setting(config, @"input_player1_r_x_minus", @"Right Stick Left", @""),
button_setting(config, @"input_player1_r_x_plus", @"Right Stick Right", @""),
nil],
nil]),
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, @"input_menu_toggle", @"Show Menu", @"F1"),
button_setting(config, @"input_disk_eject_toggle", @"Insert/Eject Disk", @""),
button_setting(config, @"input_disk_next", @"Cycle Disks", @""),
button_setting(config, @"input_save_state", @"Save State", @"f2"),
button_setting(config, @"input_load_state", @"Load State", @"f4"),
button_setting(config, @"input_state_slot_increase", @"Next State Slot", @"f7"),
button_setting(config, @"input_state_slot_decrease", @"Previous State Slot", @"f6"),
button_setting(config, @"input_toggle_fast_forward", @"Toggle Fast Forward", @"space"),
button_setting(config, @"input_hold_fast_forward", @"Hold Fast Forward", @"l"),
button_setting(config, @"input_rewind", @"Rewind", @"r"),
button_setting(config, @"input_slowmotion", @"Slow Motion", @"e"),
button_setting(config, @"input_reset", @"Reset", @"h"),
button_setting(config, @"input_exit_emulator", @"Close Game", @"escape"),
button_setting(config, @"input_enable_hotkey", @"Hotkey Enable (Always on if not set)", @""),
nil],
nil]),
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
];
self = [super initWithSettings:settings title:@"RetroArch Settings"];
return self;
}
- (void)dealloc
{
config_file_t* config = config_file_new([[RetroArch_iOS get].moduleInfo.configPath UTF8String]);
if (!config)
config = config_file_new(0);
config_set_string(config, "system_directory", [[RetroArch_iOS get].system_directory UTF8String]);
[self writeSettings:nil toConfig:config];
if (config)
config_file_write(config, [[RetroArch_iOS get].moduleInfo.configPath UTF8String]);
config_file_free(config);
[[RetroArch_iOS get] refreshConfig];
}
- (void)handleCustomAction:(NSString*)action
{
if ([@"Module Info" isEqualToString:action])
[[RetroArch_iOS get] pushViewController:[[RAModuleInfoList alloc] initWithModuleInfo:[RetroArch_iOS get].moduleInfo] animated:YES];
else if ([@"Diagnostic Log" isEqualToString:action])
[[RetroArch_iOS get] pushViewController:[RALogView new] animated:YES];
}
@end