diff options
| author | Ryan Houdek <Sonicadvance1@gmail.com> | 2016-01-23 12:40:05 -0500 |
|---|---|---|
| committer | Ryan Houdek <Sonicadvance1@gmail.com> | 2016-01-23 12:40:05 -0500 |
| commit | df5bdbe2797111846f6b5f32fc960934a4e299d9 (patch) | |
| tree | e83453ba5f8f68a77f1a2266bfa4ecbe10080ded /Source/Android/app/src/main/java | |
| parent | 3f5f52342a284887442c399249805283245cef4a (diff) | |
| parent | 2190496ce8d3e522f1510af9712bcb0d0b8f40f1 (diff) | |
Merge pull request #3547 from sigmabeta/android-config-rewrite
[Android] Rewrite settings UI.
Diffstat (limited to 'Source/Android/app/src/main/java')
37 files changed, 2438 insertions, 871 deletions
diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/SettingsActivity.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/SettingsActivity.java deleted file mode 100644 index d97eccb8e7..0000000000 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/SettingsActivity.java +++ /dev/null @@ -1,48 +0,0 @@ -package org.dolphinemu.dolphinemu.activities; - - -import android.content.Context; -import android.content.Intent; -import android.os.Bundle; -import android.support.v7.app.AppCompatActivity; - -import org.dolphinemu.dolphinemu.fragments.SettingsFragment; -import org.dolphinemu.dolphinemu.services.SettingsSaveService; -import org.dolphinemu.dolphinemu.utils.Log; - -public final class SettingsActivity extends AppCompatActivity -{ - @Override - protected void onCreate(Bundle savedInstanceState) - { - super.onCreate(savedInstanceState); - - // Display the fragment as the main content. - getFragmentManager().beginTransaction() - .replace(android.R.id.content, new SettingsFragment(), "settings_fragment") - .commit(); - } - - /** - * If this is called, the user has left the settings screen (potentially through the - * home button) and will expect their changes to be persisted. So we kick off an - * IntentService which will do so on a background thread. - */ - @Override - protected void onStop() - { - super.onStop(); - - Log.debug("[SettingsActivity] Settings activity stopping. Saving settings to INI..."); - - // Copy assets into appropriate locations. - Intent settingsSaver = new Intent(this, SettingsSaveService.class); - startService(settingsSaver); - } - - public static void launch(Context context) - { - Intent settings = new Intent(context, SettingsActivity.class); - context.startActivity(settings); - } -} diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/fragments/SettingsFragment.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/fragments/SettingsFragment.java deleted file mode 100644 index 0f549d470d..0000000000 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/fragments/SettingsFragment.java +++ /dev/null @@ -1,155 +0,0 @@ -package org.dolphinemu.dolphinemu.fragments; - -import android.app.AlertDialog; -import android.content.DialogInterface; -import android.content.SharedPreferences; -import android.os.Bundle; -import android.os.Environment; -import android.preference.ListPreference; -import android.preference.PreferenceFragment; -import android.preference.PreferenceManager; - -import org.dolphinemu.dolphinemu.R; -import org.dolphinemu.dolphinemu.utils.EGLHelper; - -import java.io.File; -import java.util.ArrayList; -import java.util.List; - -import javax.microedition.khronos.opengles.GL10; - -public final class SettingsFragment extends PreferenceFragment implements SharedPreferences.OnSharedPreferenceChangeListener -{ - private SharedPreferences mPreferences; - private ListPreference mVideoBackendPreference; - - private final EGLHelper mEglHelper = new EGLHelper(EGLHelper.EGL_OPENGL_ES2_BIT); - private final String mVendor = mEglHelper.getGL().glGetString(GL10.GL_VENDOR); - - private final String mVersion = mEglHelper.getGL().glGetString(GL10.GL_VERSION); - - @Override - public void onCreate(Bundle savedInstanceState) - { - super.onCreate(savedInstanceState); - - // Load the preferences from an XML resource - addPreferencesFromResource(R.xml.preferences); - - // TODO Below here is effectively ported from the old VideoSettingsFragment. There is - // TODO probably a simpler way to do this, but potentially could require UI discussion/feedback. - - // Setting valid video backends. - mVideoBackendPreference = (ListPreference) findPreference("gpuPref"); - final boolean deviceSupportsGL = mEglHelper.supportsOpenGL(); - final boolean deviceSupportsGLES3 = mEglHelper.supportsGLES3(); - - if (deviceSupportsGL) - { - mVideoBackendPreference.setEntries(R.array.videoBackendEntriesGL); - mVideoBackendPreference.setEntryValues(R.array.videoBackendValuesGL); - } - else if (deviceSupportsGLES3) - { - mVideoBackendPreference.setEntries(R.array.videoBackendEntriesGLES3); - mVideoBackendPreference.setEntryValues(R.array.videoBackendValuesGLES3); - } - else - { - mVideoBackendPreference.setEntries(R.array.videoBackendEntriesNoGLES3); - mVideoBackendPreference.setEntryValues(R.array.videoBackendValuesNoGLES3); - } - - // - // Set available post processing shaders - // - - List<CharSequence> shader_names = new ArrayList<CharSequence>(); - List<CharSequence> shader_values = new ArrayList<CharSequence>(); - - // Disabled option - shader_names.add("Disabled"); - shader_values.add(""); - - // TODO Since shaders are included with the APK, we know what they are at build-time. We should - // TODO be able to run this logic somehow at build-time and not rely on the device doing it. - - File shaders_folder = new File(Environment.getExternalStorageDirectory() + File.separator + "dolphin-emu" + File.separator + "Shaders"); - if (shaders_folder.exists()) - { - File[] shaders = shaders_folder.listFiles(); - for (File file : shaders) - { - if (file.isFile()) - { - String filename = file.getName(); - if (filename.endsWith(".glsl")) - { - // Strip the extension and put it in to the list - shader_names.add(filename.substring(0, filename.lastIndexOf('.'))); - shader_values.add(filename.substring(0, filename.lastIndexOf('.'))); - } - } - } - } - - final ListPreference shader_preference = (ListPreference) findPreference("postProcessingShader"); - shader_preference.setEntries(shader_names.toArray(new CharSequence[shader_names.size()])); - shader_preference.setEntryValues(shader_values.toArray(new CharSequence[shader_values.size()])); - - // - // Disable all options if Software Rendering is used. - // - // Note that the numeric value in 'getPreference()' - // denotes the placement on the UI. So if more elements are - // added to the video settings, these may need to change. - // - mPreferences = PreferenceManager.getDefaultSharedPreferences(getActivity()); - - if (mVideoBackendPreference.getValue().equals("Software Renderer")) - { - findPreference("enhancements").setEnabled(false); - findPreference("hacks").setEnabled(false); - findPreference("showFPS").setEnabled(false); - } - else if (mVideoBackendPreference.getValue().equals("OGL")) - { - findPreference("enhancements").setEnabled(true); - findPreference("hacks").setEnabled(true); - findPreference("showFPS").setEnabled(true); - - // Check if we support stereo - // If we support desktop GL then we must support at least OpenGL 3.2 - // If we only support OpenGLES then we need both OpenGLES 3.1 and AEP - if ((mEglHelper.supportsOpenGL() && mEglHelper.GetVersion() >= 320) || - (mEglHelper.supportsGLES3() && mEglHelper.GetVersion() >= 310 && mEglHelper.SupportsExtension("GL_ANDROID_extension_pack_es31a"))) - findPreference("StereoscopyScreen").setEnabled(true); - else - findPreference("StereoscopyScreen").setEnabled(false); - } - - // Also set a listener, so that if someone changes the video backend, it will disable - // the video settings, upon the user choosing "Software Rendering". - mPreferences.registerOnSharedPreferenceChangeListener(this); - } - - @Override - public void onSharedPreferenceChanged(SharedPreferences preferences, String key) - { - if (key.equals("gpuPref")) - { - if (preferences.getString(key, "Software Renderer").equals("Software Renderer")) - { - findPreference("enhancements").setEnabled(false); - findPreference("hacks").setEnabled(false); - findPreference("showFPS").setEnabled(false); - } - else if (preferences.getString(key, "Software Renderer").equals("OGL")) - { - findPreference("enhancements").setEnabled(true); - findPreference("hacks").setEnabled(true); - findPreference("showFPS").setEnabled(true); - } - } - } -} diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/model/settings/BooleanSetting.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/model/settings/BooleanSetting.java new file mode 100644 index 0000000000..478321bb8e --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/model/settings/BooleanSetting.java @@ -0,0 +1,28 @@ +package org.dolphinemu.dolphinemu.model.settings; + +public final class BooleanSetting extends Setting +{ + private boolean mValue; + + public BooleanSetting(String key, String section, boolean value) + { + super(key, section); + mValue = value; + } + + public boolean getValue() + { + return mValue; + } + + public void setValue(boolean value) + { + mValue = value; + } + + @Override + public String getValueAsString() + { + return mValue ? "True" : "False"; + } +} diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/model/settings/FloatSetting.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/model/settings/FloatSetting.java new file mode 100644 index 0000000000..af78fac15d --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/model/settings/FloatSetting.java @@ -0,0 +1,28 @@ +package org.dolphinemu.dolphinemu.model.settings; + +public final class FloatSetting extends Setting +{ + private float mValue; + + public FloatSetting(String key, String section, float value) + { + super(key, section); + mValue = value; + } + + public float getValue() + { + return mValue; + } + + public void setValue(float value) + { + mValue = value; + } + + @Override + public String getValueAsString() + { + return Float.toString(mValue); + } +} diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/model/settings/IntSetting.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/model/settings/IntSetting.java new file mode 100644 index 0000000000..334abc86b2 --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/model/settings/IntSetting.java @@ -0,0 +1,28 @@ +package org.dolphinemu.dolphinemu.model.settings; + +public final class IntSetting extends Setting +{ + private int mValue; + + public IntSetting(String key, String section, int value) + { + super(key, section); + mValue = value; + } + + public int getValue() + { + return mValue; + } + + public void setValue(int value) + { + mValue = value; + } + + @Override + public String getValueAsString() + { + return Integer.toString(mValue); + } +} diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/model/settings/Setting.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/model/settings/Setting.java new file mode 100644 index 0000000000..8ede2bbe07 --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/model/settings/Setting.java @@ -0,0 +1,48 @@ +package org.dolphinemu.dolphinemu.model.settings; + +/** + * Abstraction for a setting item as read from / written to Dolphin's configuration ini files. + * These files generally consist of a key/value pair, though the type of value is ambiguous and + * must be inferred at read-time. The type of value determines which child of this class is used + * to represent the Setting. + */ +public abstract class Setting +{ + private String mKey; + private String mSection; + + /** + * Base constructor. + * + * @param key Everything to the left of the = in a line from the ini file. + * @param section The corresponding recent section header; e.g. [Core] or [Enhancements] without the brackets. + */ + public Setting(String key, String section) + { + mKey = key; + mSection = section; + } + + /** + * + * @return The identifier used to write this setting to the ini file. + */ + public String getKey() + { + return mKey; + } + + /** + * + * @return The name of the header under which this Setting should be written in the ini file. + */ + public String getSection() + { + return mSection; + } + + /** + * @return A representation of this Setting's backing value converted to a String (e.g. for serialization). + */ + public abstract String getValueAsString(); +} diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/model/settings/SettingSection.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/model/settings/SettingSection.java new file mode 100644 index 0000000000..9f082f6e9d --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/model/settings/SettingSection.java @@ -0,0 +1,56 @@ +package org.dolphinemu.dolphinemu.model.settings; + +import java.util.HashMap; + +/** + * A semantically-related group of Settings objects. These Settings are + * internally stored as a Hashmap. + */ +public final class SettingSection +{ + private String mName; + + private HashMap<String, Setting> mSettings = new HashMap<>(); + + /** + * Create a new SettingSection with no Settings in it. + * + * @param name The header of this section; e.g. [Core] or [Enhancements] without the brackets. + */ + public SettingSection(String name) + { + mName = name; + } + + public String getName() + { + return mName; + } + + /** + * Convenience method; inserts a value directly into the backing Hashmap. + * + * @param key The key where the Setting will be inserted. + * @param setting The Setting to be inserted. + */ + public void putSetting(String key, Setting setting) + { + mSettings.put(key, setting); + } + + /** + * Convenience method; gets a value directly from the backing Hashmap. + * + * @param key Used to retrieve the Setting. + * @return A Setting object (you should probably cast this before using) + */ + public Setting getSetting(String key) + { + return mSettings.get(key); + } + + public HashMap<String, Setting> getSettings() + { + return mSettings; + } +} diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/model/settings/StringSetting.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/model/settings/StringSetting.java new file mode 100644 index 0000000000..257cb8a36d --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/model/settings/StringSetting.java @@ -0,0 +1,28 @@ +package org.dolphinemu.dolphinemu.model.settings; + +public final class StringSetting extends Setting +{ + private String mValue; + + public StringSetting(String key, String section, String value) + { + super(key, section); + mValue = value; + } + + public String getValue() + { + return mValue; + } + + public void setValue(String value) + { + mValue = value; + } + + @Override + public String getValueAsString() + { + return mValue; + } +} diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/model/settings/view/CheckBoxSetting.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/model/settings/view/CheckBoxSetting.java new file mode 100644 index 0000000000..adc19f8c30 --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/model/settings/view/CheckBoxSetting.java @@ -0,0 +1,56 @@ +package org.dolphinemu.dolphinemu.model.settings.view; + + +import org.dolphinemu.dolphinemu.model.settings.BooleanSetting; +import org.dolphinemu.dolphinemu.model.settings.Setting; + +public final class CheckBoxSetting extends SettingsItem +{ + private boolean mDefaultValue; + + public CheckBoxSetting(String key, String section, int titleId, int descriptionId, boolean defaultValue, Setting setting) + { + super(key, section, setting, titleId, descriptionId); + mDefaultValue = defaultValue; + } + + public boolean isChecked() + { + if (getSetting() == null) + { + return mDefaultValue; + } + + BooleanSetting setting = (BooleanSetting) getSetting(); + return setting.getValue(); + } + + /** + * Write a value to the backing boolean. If that boolean was previously null, + * initializes a new one and returns it, so it can be added to the Hashmap. + * + * @param checked Pretty self explanatory. + * @return null if overwritten successfully; otherwise, a newly created BooleanSetting. + */ + public BooleanSetting setChecked(boolean checked) + { + if (getSetting() == null) + { + BooleanSetting setting = new BooleanSetting(getKey(), getSection(), checked); + setSetting(setting); + return setting; + } + else + { + BooleanSetting setting = (BooleanSetting) getSetting(); + setting.setValue(checked); + return null; + } + } + + @Override + public int getType() + { + return TYPE_CHECKBOX; + } +} diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/model/settings/view/HeaderSetting.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/model/settings/view/HeaderSetting.java new file mode 100644 index 0000000000..2d5744c555 --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/model/settings/view/HeaderSetting.java @@ -0,0 +1,18 @@ +package org.dolphinemu.dolphinemu.model.settings.view; + + +import org.dolphinemu.dolphinemu.model.settings.Setting; + +public final class HeaderSetting extends SettingsItem +{ + public HeaderSetting(String key, Setting setting, int titleId, int descriptionId) + { + super(key, null, setting, titleId, descriptionId); + } + + @Override + public int getType() + { + return SettingsItem.TYPE_HEADER; + } +} diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/model/settings/view/SettingsItem.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/model/settings/view/SettingsItem.java new file mode 100644 index 0000000000..4ec62717b7 --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/model/settings/view/SettingsItem.java @@ -0,0 +1,106 @@ +package org.dolphinemu.dolphinemu.model.settings.view; + +import org.dolphinemu.dolphinemu.model.settings.Setting; + +/** + * ViewModel abstraction for an Item in the RecyclerView powering SettingsFragments. + * Each one corresponds to a {@link Setting} object, so this class's subclasses + * should vaguely correspond to those subclasses. There are a few with multiple analogues + * and a few with none (Headers, for example, do not correspond to anything in the ini + * file.) + */ +public abstract class SettingsItem +{ + public static final int TYPE_HEADER = 0; + public static final int TYPE_CHECKBOX = 1; + public static final int TYPE_SINGLE_CHOICE = 2; + public static final int TYPE_SLIDER = 3; + public static final int TYPE_SUBMENU = 4; + + private String mKey; + private String mSection; + + private Setting mSetting; + + private int mNameId; + private int mDescriptionId; + + /** + * Base constructor. Takes a key / section name in case the third parameter, the Setting, + * is null; in which case, one can be constructed and saved using the key / section. + * + * @param key Identifier for the Setting represented by this Item. + * @param section Section to which the Setting belongs. + * @param setting A possibly-null backing Setting, to be modified on UI events. + * @param nameId Resource ID for a text string to be displayed as this setting's name. + * @param descriptionId Resource ID for a text string to be displayed as this setting's description. + */ + public SettingsItem(String key, String section, Setting setting, int nameId, int descriptionId) + { + mKey = key; + mSection = section; + mSetting = setting; + mNameId = nameId; + mDescriptionId = descriptionId; + } + + /** + * + * @return The identifier for the backing Setting. + */ + public String getKey() + { + return mKey; + } + + /** + * + * @return The header under which the backing Setting belongs. + */ + public String getSection() + { + return mSection; + } + + /** + * + * @return The backing Setting, possibly null. + */ + public Setting getSetting() + { + return mSetting; + } + + /** + * Replace the backing setting with a new one. Generally used in cases where + * the backing setting is null. + * + * @param setting A non-null Setting. + */ + public void setSetting(Setting setting) + { + mSetting = setting; + } + + /** + * + * @return A resource ID for a text string representing this Setting's name. + */ + public int getNameId() + { + return mNameId; + } + + public int getDescriptionId() + { + return mDescriptionId; + } + + /** + * Used by {@link org.dolphinemu.dolphinemu.ui.settings.SettingsAdapter}'s onCreateViewHolder() + * method to determine which type of ViewHolder should be created. + * + * @return An integer (ideally, one of the constants defined in this file) + */ + public abstract int getType(); +} diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/model/settings/view/SingleChoiceSetting.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/model/settings/view/SingleChoiceSetting.java new file mode 100644 index 0000000000..07880587c2 --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/model/settings/view/SingleChoiceSetting.java @@ -0,0 +1,73 @@ +package org.dolphinemu.dolphinemu.model.settings.view; + + +import org.dolphinemu.dolphinemu.model.settings.IntSetting; +import org.dolphinemu.dolphinemu.model.settings.Setting; + +public final class SingleChoiceSetting extends SettingsItem +{ + private int mDefaultValue; + + private int mChoicesId; + private int mValuesId; + + public SingleChoiceSetting(String key, String section, int titleId, int descriptionId, int choicesId, int valuesId, int defaultValue, Setting setting) + { + super(key, section, setting, titleId, descriptionId); + mValuesId = valuesId; + mChoicesId = choicesId; + mDefaultValue = defaultValue; + } + + public int getChoicesId() + { + return mChoicesId; + } + + public int getValuesId() + { + return mValuesId; + } + + public int getSelectedValue() + { + if (getSetting() != null) + { + IntSetting setting = (IntSetting) getSetting(); + return setting.getValue(); + } + else + { + return mDefaultValue; + } + } + + /** + * Write a value to the backing int. If that int was previously null, + * initializes a new one and returns it, so it can be added to the Hashmap. + * + * @param selection New value of the int. + * @return null if overwritten successfully otherwise; a newly created IntSetting. + */ + public IntSetting setSelectedValue(int selection) + { + if (getSetting() == null) + { + IntSetting setting = new IntSetting(getKey(), getSection(), selection); + setSetting(setting); + return setting; + } + else + { + IntSetting setting = (IntSetting) getSetting(); + setting.setValue(selection); + return null; + } + } + + @Override + public int getType() + { + return TYPE_SINGLE_CHOICE; + } +} diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/model/settings/view/SliderSetting.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/model/settings/view/SliderSetting.java new file mode 100644 index 0000000000..0dbb39b521 --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/model/settings/view/SliderSetting.java @@ -0,0 +1,118 @@ +package org.dolphinemu.dolphinemu.model.settings.view; + +import org.dolphinemu.dolphinemu.model.settings.FloatSetting; +import org.dolphinemu.dolphinemu.model.settings.IntSetting; +import org.dolphinemu.dolphinemu.model.settings.Setting; +import org.dolphinemu.dolphinemu.utils.Log; +import org.dolphinemu.dolphinemu.utils.SettingsFile; + +public final class SliderSetting extends SettingsItem +{ + private int mMax; + private int mDefaultValue; + + private String mUnits; + + public SliderSetting(String key, String section, int titleId, int descriptionId, int max, String units, int defaultValue, Setting setting) + { + super(key, section, setting, titleId, descriptionId); + mMax = max; + mUnits = units; + mDefaultValue = defaultValue; + } + + public int getMax() + { + return mMax; + } + + public int getSelectedValue() + { + Setting setting = getSetting(); + + if (setting == null) + { + return mDefaultValue; + } + + if (setting instanceof IntSetting) + { + IntSetting intSetting = (IntSetting) setting; + return intSetting.getValue(); + } + else if (setting instanceof FloatSetting) + { + FloatSetting floatSetting = (FloatSetting) setting; + if (floatSetting.getKey().equals(SettingsFile.KEY_OVERCLOCK_PERCENT)) + { + return Math.round(floatSetting.getValue() * 100); + } + else + { + return Math.round(floatSetting.getValue()); + } + } + else + { + Log.error("[SliderSetting] Error casting setting type."); + return -1; + } + } + + /** + * Write a value to the backing int. If that int was previously null, + * initializes a new one and returns it, so it can be added to the Hashmap. + * + * @param selection New value of the int. + * @return null if overwritten successfully otherwise; a newly created IntSetting. + */ + public IntSetting setSelectedValue(int selection) + { + if (getSetting() == null) + { + IntSetting setting = new IntSetting(getKey(), getSection(), selection); + setSetting(setting); + return setting; + } + else + { + IntSetting setting = (IntSetting) getSetting(); + setting.setValue(selection); + return null; + } + } + + /** + * Write a value to the backing float. If that float was previously null, + * initializes a new one and returns it, so it can be added to the Hashmap. + * + * @param selection New value of the float. + * @return null if overwritten successfully otherwise; a newly created FloatSetting. + */ + public FloatSetting setSelectedValue(float selection) + { + if (getSetting() == null) + { + FloatSetting setting = new FloatSetting(getKey(), getSection(), selection); + setSetting(setting); + return setting; + } + else + { + FloatSetting setting = (FloatSetting) getSetting(); + setting.setValue(selection); + return null; + } + } + + public String getUnits() + { + return mUnits; + } + + @Override + public int getType() + { + return TYPE_SLIDER; + } +} diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/model/settings/view/SubmenuSetting.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/model/settings/view/SubmenuSetting.java new file mode 100644 index 0000000000..32db709b37 --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/model/settings/view/SubmenuSetting.java @@ -0,0 +1,25 @@ +package org.dolphinemu.dolphinemu.model.settings.view; + +import org.dolphinemu.dolphinemu.model.settings.Setting; + +public final class SubmenuSetting extends SettingsItem +{ + private String mMenuKey; + + public SubmenuSetting(String key, Setting setting, int titleId, int descriptionId, String menuKey) + { + super(key, null, setting, titleId, descriptionId); + mMenuKey = menuKey; + } + + public String getMenuKey() + { + return mMenuKey; + } + + @Override + public int getType() + { + return TYPE_SUBMENU; + } +} diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/services/AssetCopyService.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/services/AssetCopyService.java index 6004c88c5e..a93e9c501b 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/services/AssetCopyService.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/services/AssetCopyService.java @@ -13,7 +13,6 @@ import android.preference.PreferenceManager; import org.dolphinemu.dolphinemu.NativeLibrary; import org.dolphinemu.dolphinemu.utils.Log; -import org.dolphinemu.dolphinemu.utils.UserPreferences; import java.io.File; import java.io.FileOutputStream; @@ -61,10 +60,6 @@ public final class AssetCopyService extends IntentService copyAsset("GCPadNew.ini", ConfigDir + File.separator + "GCPadNew.ini"); copyAsset("WiimoteNew.ini", ConfigDir + File.separator + "WiimoteNew.ini"); - // Load the configuration keys set in the Dolphin ini and gfx ini files - // into the application's shared preferences. - UserPreferences.LoadIniToPrefs(this); - // Record the fact that we've done this before, so we don't do it on every launch. SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this); SharedPreferences.Editor editor = preferences.edit(); diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/services/SettingsSaveService.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/services/SettingsSaveService.java deleted file mode 100644 index 5be3f4d27c..0000000000 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/services/SettingsSaveService.java +++ /dev/null @@ -1,28 +0,0 @@ -package org.dolphinemu.dolphinemu.services; - -import android.app.IntentService; -import android.content.Intent; - -import org.dolphinemu.dolphinemu.utils.Log; -import org.dolphinemu.dolphinemu.utils.UserPreferences; - -/** - * IntentServices, unlike regular services, inherently run on a background thread. - * This IntentService saves all the options the user set in the Java-based UI into - * INI files the native code can read. - */ -public final class SettingsSaveService extends IntentService -{ - public SettingsSaveService() - { - super("SettingsSaveService"); - } - - @Override - protected void onHandleIntent(Intent intent) - { - Log.verbose("[SettingsSaveService] Saving settings to INI files..."); - UserPreferences.SavePrefsToIni(this); - Log.verbose("[SettingsSaveService] Save successful."); - } -} diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/DividerItemDecoration.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/DividerItemDecoration.java new file mode 100644 index 0000000000..fcd0befdc2 --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/DividerItemDecoration.java @@ -0,0 +1,157 @@ +package org.dolphinemu.dolphinemu.ui; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.Rect; +import android.graphics.drawable.Drawable; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.util.AttributeSet; +import android.view.View; + +/** + * Implementation from: + * https://gist.github.com/lapastillaroja/858caf1a82791b6c1a36 + */ +public final class DividerItemDecoration extends RecyclerView.ItemDecoration +{ + + private Drawable mDivider; + private boolean mShowFirstDivider = false; + private boolean mShowLastDivider = false; + + + public DividerItemDecoration(Context context, AttributeSet attrs) + { + final TypedArray a = context + .obtainStyledAttributes(attrs, new int[]{android.R.attr.listDivider}); + mDivider = a.getDrawable(0); + a.recycle(); + } + + public DividerItemDecoration(Context context, AttributeSet attrs, boolean showFirstDivider, + boolean showLastDivider) + { + this(context, attrs); + mShowFirstDivider = showFirstDivider; + mShowLastDivider = showLastDivider; + } + + public DividerItemDecoration(Drawable divider) + { + mDivider = divider; + } + + public DividerItemDecoration(Drawable divider, boolean showFirstDivider, + boolean showLastDivider) + { + this(divider); + mShowFirstDivider = showFirstDivider; + mShowLastDivider = showLastDivider; + } + + @Override + public void getItemOffsets(Rect outRect, View view, RecyclerView parent, + RecyclerView.State state) + { + super.getItemOffsets(outRect, view, parent, state); + if (mDivider == null) + { + return; + } + if (parent.getChildPosition(view) < 1) + { + return; + } + + if (getOrientation(parent) == LinearLayoutManager.VERTICAL) + { + outRect.top = mDivider.getIntrinsicHeight(); + } + else + { + outRect.left = mDivider.getIntrinsicWidth(); + } + } + + @Override + public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) + { + if (mDivider == null) + { + super.onDrawOver(c, parent, state); + return; + } + + // Initialization needed to avoid compiler warning + int left = 0, right = 0, top = 0, bottom = 0, size; + int orientation = getOrientation(parent); + int childCount = parent.getChildCount(); + + if (orientation == LinearLayoutManager.VERTICAL) + { + size = mDivider.getIntrinsicHeight(); + left = parent.getPaddingLeft(); + right = parent.getWidth() - parent.getPaddingRight(); + } + else + { //horizontal + size = mDivider.getIntrinsicWidth(); + top = parent.getPaddingTop(); + bottom = parent.getHeight() - parent.getPaddingBottom(); + } + + for (int i = mShowFirstDivider ? 0 : 1; i < childCount; i++) + { + View child = parent.getChildAt(i); + RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams(); + + if (orientation == LinearLayoutManager.VERTICAL) + { + top = child.getTop() - params.topMargin; + bottom = top + size; + } + else + { //horizontal + left = child.getLeft() - params.leftMargin; + right = left + size; + } + mDivider.setBounds(left, top, right, bottom); + mDivider.draw(c); + } + + // show last divider + if (mShowLastDivider && childCount > 0) + { + View child = parent.getChildAt(childCount - 1); + RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams(); + if (orientation == LinearLayoutManager.VERTICAL) + { + top = child.getBottom() + params.bottomMargin; + bottom = top + size; + } + else + { // horizontal + left = child.getRight() + params.rightMargin; + right = left + size; + } + mDivider.setBounds(left, top, right, bottom); + mDivider.draw(c); + } + } + + private int getOrientation(RecyclerView parent) + { + if (parent.getLayoutManager() instanceof LinearLayoutManager) + { + LinearLayoutManager layoutManager = (LinearLayoutManager) parent.getLayoutManager(); + return layoutManager.getOrientation(); + } + else + { + throw new IllegalStateException( + "DividerItemDecoration can only be used with a LinearLayoutManager."); + } + } +}
\ No newline at end of file diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainActivity.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainActivity.java index e112899201..57923e0e0e 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainActivity.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainActivity.java @@ -16,10 +16,10 @@ import android.view.View; import org.dolphinemu.dolphinemu.R; import org.dolphinemu.dolphinemu.activities.AddDirectoryActivity; -import org.dolphinemu.dolphinemu.activities.SettingsActivity; import org.dolphinemu.dolphinemu.adapters.PlatformPagerAdapter; import org.dolphinemu.dolphinemu.model.GameProvider; import org.dolphinemu.dolphinemu.ui.platform.PlatformGamesView; +import org.dolphinemu.dolphinemu.ui.settings.SettingsActivity; import org.dolphinemu.dolphinemu.utils.StartupHandler; /** @@ -115,9 +115,9 @@ public final class MainActivity extends AppCompatActivity implements MainView } @Override - public void launchSettingsActivity() + public void launchSettingsActivity(String menuTag) { - SettingsActivity.launch(this); + SettingsActivity.launch(this, menuTag); } @Override diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainPresenter.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainPresenter.java index 97b7a39f25..c1052fc42a 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainPresenter.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainPresenter.java @@ -7,6 +7,7 @@ import org.dolphinemu.dolphinemu.DolphinApplication; import org.dolphinemu.dolphinemu.NativeLibrary; import org.dolphinemu.dolphinemu.R; import org.dolphinemu.dolphinemu.model.GameDatabase; +import org.dolphinemu.dolphinemu.utils.SettingsFile; import rx.android.schedulers.AndroidSchedulers; import rx.functions.Action1; @@ -41,8 +42,12 @@ public final class MainPresenter { switch (itemId) { - case R.id.menu_settings: - mView.launchSettingsActivity(); + case R.id.menu_settings_core: + mView.launchSettingsActivity(SettingsFile.FILE_NAME_DOLPHIN); + return true; + + case R.id.menu_settings_video: + mView.launchSettingsActivity(SettingsFile.FILE_NAME_GFX); return true; case R.id.menu_refresh: diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainView.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainView.java index 1d286bebf3..12c8ae832c 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainView.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainView.java @@ -32,7 +32,7 @@ public interface MainView void refreshFragmentScreenshot(int fragmentPosition); - void launchSettingsActivity(); + void launchSettingsActivity(String menuTag); void launchFileListActivity(); diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/TvMainActivity.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/TvMainActivity.java index 38ab2eb4b4..95e4d04746 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/TvMainActivity.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/TvMainActivity.java @@ -20,11 +20,12 @@ import android.support.v17.leanback.widget.RowPresenter; import org.dolphinemu.dolphinemu.R; import org.dolphinemu.dolphinemu.activities.AddDirectoryActivity; import org.dolphinemu.dolphinemu.activities.EmulationActivity; -import org.dolphinemu.dolphinemu.activities.SettingsActivity; import org.dolphinemu.dolphinemu.adapters.GameRowPresenter; import org.dolphinemu.dolphinemu.adapters.SettingsRowPresenter; import org.dolphinemu.dolphinemu.model.Game; import org.dolphinemu.dolphinemu.model.TvSettingsItem; +import org.dolphinemu.dolphinemu.ui.settings.SettingsActivity; +import org.dolphinemu.dolphinemu.utils.SettingsFile; import org.dolphinemu.dolphinemu.utils.StartupHandler; import org.dolphinemu.dolphinemu.viewholders.TvGameViewHolder; @@ -112,9 +113,9 @@ public final class TvMainActivity extends Activity implements MainView } @Override - public void launchSettingsActivity() + public void launchSettingsActivity(String menuTag) { - SettingsActivity.launch(this); + SettingsActivity.launch(this, SettingsFile.FILE_NAME_DOLPHIN); } @Override @@ -229,9 +230,13 @@ public final class TvMainActivity extends Activity implements MainView R.drawable.ic_refresh_tv, R.string.grid_menu_refresh)); - rowItems.add(new TvSettingsItem(R.id.menu_settings, - R.drawable.ic_settings_tv, - R.string.grid_menu_settings)); + rowItems.add(new TvSettingsItem(R.id.menu_settings_core, + R.drawable.ic_settings_core_tv, + R.string.grid_menu_core_settings)); + + rowItems.add(new TvSettingsItem(R.id.menu_settings_video, + R.drawable.ic_settings_graphics_tv, + R.string.grid_menu_core_settings)); rowItems.add(new TvSettingsItem(R.id.button_add_directory, R.drawable.ic_add_tv, diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/settings/SettingsActivity.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/settings/SettingsActivity.java new file mode 100644 index 0000000000..7cd744aff2 --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/settings/SettingsActivity.java @@ -0,0 +1,106 @@ +package org.dolphinemu.dolphinemu.ui.settings; + + +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.support.v4.app.FragmentTransaction; +import android.support.v7.app.AppCompatActivity; +import android.widget.Toast; + +import org.dolphinemu.dolphinemu.BuildConfig; +import org.dolphinemu.dolphinemu.R; +import org.dolphinemu.dolphinemu.model.settings.SettingSection; + +import java.util.HashMap; + +public final class SettingsActivity extends AppCompatActivity implements SettingsActivityView +{ + private SettingsActivityPresenter mPresenter = new SettingsActivityPresenter(this); + + + @Override + protected void onCreate(Bundle savedInstanceState) + { + super.onCreate(savedInstanceState); + + setContentView(R.layout.activity_settings); + + Intent launcher = getIntent(); + String filename = launcher.getStringExtra(ARGUMENT_FILE_NAME); + + mPresenter.onCreate(savedInstanceState, filename); + } + + /** + * If this is called, the user has left the settings screen (potentially through the + * home button) and will expect their changes to be persisted. So we kick off an + * IntentService which will do so on a background thread. + */ + @Override + protected void onStop() + { + super.onStop(); + + mPresenter.onStop(isFinishing()); + } + + @Override + public void showSettingsFragment(String menuTag, boolean addToStack) + { + FragmentTransaction transaction = getSupportFragmentManager().beginTransaction() + .replace(R.id.frame_content, SettingsFragment.newInstance(menuTag), SettingsFragment.FRAGMENT_TAG); + + if (addToStack) + { + transaction.addToBackStack(null); + } + + transaction.commit(); + } + + @Override + public HashMap<String, SettingSection> getSettings() + { + return mPresenter.getSettings(); + } + + @Override + public void setSettings(HashMap<String, SettingSection> settings) + { + mPresenter.setSettings(settings); + } + + @Override + public void onSettingsFileLoaded(HashMap<String, SettingSection> settings) + { + SettingsFragmentView fragment = getFragment(); + + if (fragment != null) + { + fragment.onSettingsFileLoaded(settings); + } + } + + @Override + public void showToastMessage(String message) + { + Toast.makeText(this, message, Toast.LENGTH_SHORT).show(); + } + + private SettingsFragment getFragment() + { + return (SettingsFragment) getSupportFragmentManager().findFragmentByTag(SettingsFragment.FRAGMENT_TAG); + } + + public static final String ARGUMENT_FILE_NAME = BuildConfig.APPLICATION_ID + ".file_name"; + + public static void launch(Context context, String menuTag) + { + Intent settings = new Intent(context, SettingsActivity.class); + + settings.putExtra(ARGUMENT_FILE_NAME, menuTag); + + context.startActivity(settings); + } +} diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/settings/SettingsActivityPresenter.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/settings/SettingsActivityPresenter.java new file mode 100644 index 0000000000..aac7e8e2ed --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/settings/SettingsActivityPresenter.java @@ -0,0 +1,97 @@ +package org.dolphinemu.dolphinemu.ui.settings; + + +import android.os.Bundle; + +import org.dolphinemu.dolphinemu.model.settings.SettingSection; +import org.dolphinemu.dolphinemu.utils.Log; +import org.dolphinemu.dolphinemu.utils.SettingsFile; + +import java.util.HashMap; + +import rx.android.schedulers.AndroidSchedulers; +import rx.functions.Action1; +import rx.schedulers.Schedulers; + +public final class SettingsActivityPresenter +{ + private SettingsActivityView mView; + + private String mFileName; + private HashMap<String, SettingSection> mSettingsBySection; + + public SettingsActivityPresenter(SettingsActivityView view) + { + mView = view; + } + + public void onCreate(Bundle savedInstanceState, final String filename) + { + mFileName = filename; + + if (savedInstanceState == null) + { + SettingsFile.readFile(mFileName) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(new Action1<HashMap<String, SettingSection>>() + { + @Override + public void call(HashMap<String, SettingSection> settingsBySection) + { + mSettingsBySection = settingsBySection; + mView.onSettingsFileLoaded(settingsBySection); + } + }, + new Action1<Throwable>() + { + @Override + public void call(Throwable throwable) + { + Log.error("[SettingsActivityPresenter] Error reading file " + filename + ".ini: "+ throwable.getMessage()); + mView.onSettingsFileLoaded(null); + } + }); + + mView.showSettingsFragment(mFileName, false); + } + } + + public void setSettings(HashMap<String, SettingSection> settings) + { + mSettingsBySection = settings; + } + + public HashMap<String, SettingSection> getSettings() + { + return mSettingsBySection; + } + + public void onStop(boolean finishing) + { + if (mSettingsBySection != null && finishing) + { + Log.debug("[SettingsActivity] Settings activity stopping. Saving settings to INI..."); + SettingsFile.saveFile(mFileName, mSettingsBySection) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe( + new Action1<Boolean>() + { + @Override + public void call(Boolean aBoolean) + { + mView.showToastMessage("Saved successfully to " + mFileName + ".ini"); + } + }, + new Action1<Throwable>() + { + @Override + public void call(Throwable throwable) + { + mView.showToastMessage("Error saving " + mFileName + ".ini: " + throwable.getMessage()); + } + }); + } + } +} diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/settings/SettingsActivityView.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/settings/SettingsActivityView.java new file mode 100644 index 0000000000..2409ed1221 --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/settings/SettingsActivityView.java @@ -0,0 +1,51 @@ +package org.dolphinemu.dolphinemu.ui.settings; + +import org.dolphinemu.dolphinemu.model.settings.SettingSection; + +import java.util.HashMap; + +/** + * Abstraction for the Activity that manages SettingsFragments. + */ +public interface SettingsActivityView +{ + /** + * Show a new SettingsFragment. + * + * @param menuTag Identifier for the settings group that should be displayed. + * @param addToStack Whether or not this fragment should replace a previous one. + */ + void showSettingsFragment(String menuTag, boolean addToStack); + + /** + * Called by a contained Fragment to get access to the Setting Hashmap + * loaded from disk, so that each Fragment doesn't need to perform its own + * read operation. + * + * @return A possibly null Hashmap of Settings. + */ + HashMap<String, SettingSection> getSettings(); + + /** + * Used to provide the Activity with a Settings Hashmap if a Fragment already + * has one; for example, if a rotation occurs, the Fragment will not be killed, + * but the Activity will, so the Activity needs to have its Hashmap resupplied. + * + * @param settings The Fragment's Settings hashmap. + */ + void setSettings(HashMap<String, SettingSection> settings); + + /** + * Called when an asynchronous load operation completes. + * + * @param settings The (possibly null) result of the load operation. + */ + void onSettingsFileLoaded(HashMap<String, SettingSection> settings); + + /** + * Display a popup text message on screen. + * + * @param message The contents of the onscreen message. + */ + void showToastMessage(String message); +} diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/settings/SettingsAdapter.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/settings/SettingsAdapter.java new file mode 100644 index 0000000000..c83c578f06 --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/settings/SettingsAdapter.java @@ -0,0 +1,334 @@ +package org.dolphinemu.dolphinemu.ui.settings; + +import android.content.Context; +import android.content.DialogInterface; +import android.support.v7.app.AlertDialog; +import android.support.v7.widget.RecyclerView; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.SeekBar; +import android.widget.TextView; + +import org.dolphinemu.dolphinemu.R; +import org.dolphinemu.dolphinemu.model.settings.BooleanSetting; +import org.dolphinemu.dolphinemu.model.settings.FloatSetting; +import org.dolphinemu.dolphinemu.model.settings.IntSetting; +import org.dolphinemu.dolphinemu.model.settings.view.CheckBoxSetting; +import org.dolphinemu.dolphinemu.model.settings.view.SettingsItem; +import org.dolphinemu.dolphinemu.model.settings.view.SingleChoiceSetting; +import org.dolphinemu.dolphinemu.model.settings.view.SliderSetting; +import org.dolphinemu.dolphinemu.model.settings.view.SubmenuSetting; +import org.dolphinemu.dolphinemu.ui.settings.viewholder.CheckBoxSettingViewHolder; +import org.dolphinemu.dolphinemu.ui.settings.viewholder.HeaderViewHolder; +import org.dolphinemu.dolphinemu.ui.settings.viewholder.SettingViewHolder; +import org.dolphinemu.dolphinemu.ui.settings.viewholder.SingleChoiceViewHolder; +import org.dolphinemu.dolphinemu.ui.settings.viewholder.SliderViewHolder; +import org.dolphinemu.dolphinemu.ui.settings.viewholder.SubmenuViewHolder; +import org.dolphinemu.dolphinemu.utils.Log; +import org.dolphinemu.dolphinemu.utils.SettingsFile; + +import java.util.ArrayList; + +public final class SettingsAdapter extends RecyclerView.Adapter<SettingViewHolder> + implements DialogInterface.OnClickListener, SeekBar.OnSeekBarChangeListener +{ + private SettingsFragmentView mView; + private Context mContext; + private ArrayList<SettingsItem> mSettings; + + private SettingsItem mClickedItem; + private int mSeekbarProgress; + + private AlertDialog mDialog; + private TextView mTextSliderValue; + + public SettingsAdapter(SettingsFragmentView view, Context context) + { + mView = view; + mContext = context; + } + + @Override + public SettingViewHolder onCreateViewHolder(ViewGroup parent, int viewType) + { + View view; + LayoutInflater inflater = LayoutInflater.from(parent.getContext()); + + switch (viewType) + { + case SettingsItem.TYPE_HEADER: + view = inflater.inflate(R.layout.list_item_settings_header, parent, false); + return new HeaderViewHolder(view, this); + + case SettingsItem.TYPE_CHECKBOX: + view = inflater.inflate(R.layout.list_item_setting_checkbox, parent, false); + return new CheckBoxSettingViewHolder(view, this); + + case SettingsItem.TYPE_SINGLE_CHOICE: + view = inflater.inflate(R.layout.list_item_setting, parent, false); + return new SingleChoiceViewHolder(view, this); + + case SettingsItem.TYPE_SLIDER: + view = inflater.inflate(R.layout.list_item_setting, parent, false); + return new SliderViewHolder(view, this); + + case SettingsItem.TYPE_SUBMENU: + view = inflater.inflate(R.layout.list_item_setting, parent, false); + return new SubmenuViewHolder(view, this); + + default: + Log.error("[SettingsAdapter] Invalid view type: " + viewType); + return null; + } + } + + @Override + public void onBindViewHolder(SettingViewHolder holder, int position) + { + holder.bind(getItem(position)); + } + + private SettingsItem getItem(int position) + { + return mSettings.get(position); + } + + @Override + public int getItemCount() + { + if (mSettings != null) + { + return mSettings.size(); + } + else + { + return 0; + } + } + + @Override + public int getItemViewType(int position) + { + return getItem(position).getType(); + } + + public void setSettings(ArrayList<SettingsItem> settings) + { + mSettings = settings; + notifyDataSetChanged(); + } + + public void onBooleanClick(CheckBoxSetting item, int position, boolean checked) + { + BooleanSetting setting = item.setChecked(checked); + notifyItemChanged(position); + + if (setting != null) + { + mView.putSetting(setting); + } + } + + public void onSingleChoiceClick(SingleChoiceSetting item) + { + mClickedItem = item; + + int value = getSelectionForSingleChoiceValue(item); + + AlertDialog.Builder builder = new AlertDialog.Builder(mView.getActivity()); + + builder.setTitle(item.getNameId()); + builder.setSingleChoiceItems(item.getChoicesId(), value, this); + + mDialog = builder.show(); + } + + public void onSliderClick(SliderSetting item) + { + mClickedItem = item; + mSeekbarProgress = item.getSelectedValue(); + AlertDialog.Builder builder = new AlertDialog.Builder(mView.getActivity()); + + LayoutInflater inflater = LayoutInflater.from(mView.getActivity()); + View view = inflater.inflate(R.layout.dialog_seekbar, null); + + builder.setTitle(item.getNameId()); + builder.setView(view); + builder.setPositiveButton(R.string.dialog_seekbar_pos, this); + builder.setNegativeButton(R.string.dialog_seekbar_neg, this); + mDialog = builder.show(); + + mTextSliderValue = (TextView) view.findViewById(R.id.text_value); + mTextSliderValue.setText(String.valueOf(mSeekbarProgress)); + + TextView units = (TextView) view.findViewById(R.id.text_units); + units.setText(item.getUnits()); + + SeekBar seekbar = (SeekBar) view.findViewById(R.id.seekbar); + + seekbar.setMax(item.getMax()); + seekbar.setProgress(mSeekbarProgress); + + seekbar.setOnSeekBarChangeListener(this); + } + + public void onSubmenuClick(SubmenuSetting item) + { + mView.loadSubMenu(item.getMenuKey()); + } + + @Override + public void onClick(DialogInterface dialog, int which) + { + if (mClickedItem instanceof SingleChoiceSetting) + { + SingleChoiceSetting scSetting = (SingleChoiceSetting) mClickedItem; + + int value = getValueForSingleChoiceSelection(scSetting, which); + + // Get the backing Setting, which may be null (if for example it was missing from the file) + IntSetting setting = scSetting.setSelectedValue(value); + if (setting != null) + { + mView.putSetting(setting); + } + else + { + if (scSetting.getKey().equals(SettingsFile.KEY_XFB_METHOD)) + { + putXfbSetting(which); + } + } + + closeDialog(); + } + else if (mClickedItem instanceof SliderSetting) + { + SliderSetting sliderSetting = (SliderSetting) mClickedItem; + if (sliderSetting.getSetting() instanceof FloatSetting) + { + float value; + + if (sliderSetting.getKey().equals(SettingsFile.KEY_OVERCLOCK_PERCENT)) + { + value = mSeekbarProgress / 100.0f; + } + else + { + value = (float) mSeekbarProgress; + } + + FloatSetting setting = sliderSetting.setSelectedValue(value); + if (setting != null) + { + mView.putSetting(setting); + } + } + else + { + IntSetting setting = sliderSetting.setSelectedValue(mSeekbarProgress); + if (setting != null) + { + mView.putSetting(setting); + } + } + } + + mClickedItem = null; + mSeekbarProgress = -1; + } + + public void closeDialog() + { + if (mDialog != null) + { + mDialog.dismiss(); + mDialog = null; + } + } + + @Override + public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) + { + mSeekbarProgress = progress; + mTextSliderValue.setText(String.valueOf(mSeekbarProgress)); + } + + @Override + public void onStartTrackingTouch(SeekBar seekBar) + { + } + + @Override + public void onStopTrackingTouch(SeekBar seekBar) + { + } + + private int getValueForSingleChoiceSelection(SingleChoiceSetting item, int which) + { + int valuesId = item.getValuesId(); + + if (valuesId > 0) + { + int[] valuesArray = mContext.getResources().getIntArray(valuesId); + return valuesArray[which]; + } + else + { + return which; + } + } + + private int getSelectionForSingleChoiceValue(SingleChoiceSetting item) + { + int value = item.getSelectedValue(); + int valuesId = item.getValuesId(); + + if (valuesId > 0) + { + int[] valuesArray = mContext.getResources().getIntArray(valuesId); + for (int index = 0; index < valuesArray.length; index++) + { + int current = valuesArray[index]; + if (current == value) + { + return index; + } + } + } + else + { + return value; + } + + return -1; + } + + public void putXfbSetting(int which) + { + BooleanSetting xfbEnable = null; + BooleanSetting xfbReal = null; + + switch (which) + { + case 0: + xfbEnable = new BooleanSetting(SettingsFile.KEY_XFB, SettingsFile.SECTION_GFX_SETTINGS, false); + xfbReal = new BooleanSetting(SettingsFile.KEY_XFB_REAL, SettingsFile.SECTION_GFX_SETTINGS, false); + break; + + case 1: + xfbEnable = new BooleanSetting(SettingsFile.KEY_XFB, SettingsFile.SECTION_GFX_SETTINGS, true); + xfbReal = new BooleanSetting(SettingsFile.KEY_XFB_REAL, SettingsFile.SECTION_GFX_SETTINGS, false); + break; + + case 2: + xfbEnable = new BooleanSetting(SettingsFile.KEY_XFB, SettingsFile.SECTION_GFX_SETTINGS, true); + xfbReal = new BooleanSetting(SettingsFile.KEY_XFB_REAL, SettingsFile.SECTION_GFX_SETTINGS, true); + break; + } + + mView.putSetting(xfbEnable); + mView.putSetting(xfbReal); + } +} diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/settings/SettingsFragment.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/settings/SettingsFragment.java new file mode 100644 index 0000000000..89e5edb056 --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/settings/SettingsFragment.java @@ -0,0 +1,141 @@ +package org.dolphinemu.dolphinemu.ui.settings; + +import android.content.Context; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.support.v4.app.Fragment; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import org.dolphinemu.dolphinemu.BuildConfig; +import org.dolphinemu.dolphinemu.R; +import org.dolphinemu.dolphinemu.model.settings.Setting; +import org.dolphinemu.dolphinemu.model.settings.SettingSection; +import org.dolphinemu.dolphinemu.model.settings.view.SettingsItem; +import org.dolphinemu.dolphinemu.ui.DividerItemDecoration; + +import java.util.ArrayList; +import java.util.HashMap; + +public final class SettingsFragment extends Fragment implements SettingsFragmentView +{ + private SettingsFragmentPresenter mPresenter = new SettingsFragmentPresenter(this); + private SettingsActivityView mActivity; + + private SettingsAdapter mAdapter; + + @Override + public void onAttach(Context context) + { + super.onAttach(context); + + mActivity = (SettingsActivityView) context; + mPresenter.onAttach(); + } + + @Override + public void onCreate(Bundle savedInstanceState) + { + super.onCreate(savedInstanceState); + + setRetainInstance(true); + String menuTag = getArguments().getString(ARGUMENT_MENU_TAG); + + mAdapter = new SettingsAdapter(this, getActivity()); + + mPresenter.onCreate(menuTag); + } + + @Nullable + @Override + public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) + { + return inflater.inflate(R.layout.fragment_settings, container, false); + } + + @Override + public void onViewCreated(View view, @Nullable Bundle savedInstanceState) + { + LinearLayoutManager manager = new LinearLayoutManager(getActivity()); + + RecyclerView recyclerView = (RecyclerView) view.findViewById(R.id.list_settings); + + recyclerView.setAdapter(mAdapter); + recyclerView.setLayoutManager(manager); + recyclerView.addItemDecoration(new DividerItemDecoration(getActivity(), null)); + + SettingsActivityView activity = (SettingsActivityView) getActivity(); + HashMap<String, SettingSection> settings = activity.getSettings(); + + mPresenter.onViewCreated(settings); + } + + @Override + public void onDetach() + { + super.onDetach(); + mActivity = null; + + if (mAdapter != null) + { + mAdapter.closeDialog(); + } + } + + @Override + public void onSettingsFileLoaded(HashMap<String, SettingSection> settings) + { + mPresenter.setSettings(settings); + } + + @Override + public void passSettingsToActivity(HashMap<String, SettingSection> settings) + { + if (mActivity != null) + { + mActivity.setSettings(settings); + } + } + + @Override + public void showSettingsList(ArrayList<SettingsItem> settingsList) + { + mAdapter.setSettings(settingsList); + } + + @Override + public void loadSubMenu(String menuKey) + { + mActivity.showSettingsFragment(menuKey, true); + } + + @Override + public void showToastMessage(String message) + { + mActivity.showToastMessage(message); + } + + @Override + public void putSetting(Setting setting) + { + mPresenter.putSetting(setting); + } + + public static final String FRAGMENT_TAG = BuildConfig.APPLICATION_ID + ".fragment.settings"; + + public static final String ARGUMENT_MENU_TAG = FRAGMENT_TAG + ".menu_tag"; + + public static Fragment newInstance(String menuTag) + { + SettingsFragment fragment = new SettingsFragment(); + + Bundle arguments = new Bundle(); + arguments.putString(ARGUMENT_MENU_TAG, menuTag); + + fragment.setArguments(arguments); + return fragment; + } +} diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/settings/SettingsFragmentPresenter.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/settings/SettingsFragmentPresenter.java new file mode 100644 index 0000000000..c338ec22fd --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/settings/SettingsFragmentPresenter.java @@ -0,0 +1,257 @@ +package org.dolphinemu.dolphinemu.ui.settings; + +import org.dolphinemu.dolphinemu.R; +import org.dolphinemu.dolphinemu.model.settings.BooleanSetting; +import org.dolphinemu.dolphinemu.model.settings.IntSetting; +import org.dolphinemu.dolphinemu.model.settings.Setting; +import org.dolphinemu.dolphinemu.model.settings.SettingSection; +import org.dolphinemu.dolphinemu.model.settings.view.CheckBoxSetting; +import org.dolphinemu.dolphinemu.model.settings.view.HeaderSetting; +import org.dolphinemu.dolphinemu.model.settings.view.SettingsItem; +import org.dolphinemu.dolphinemu.model.settings.view.SingleChoiceSetting; +import org.dolphinemu.dolphinemu.model.settings.view.SliderSetting; +import org.dolphinemu.dolphinemu.model.settings.view.SubmenuSetting; +import org.dolphinemu.dolphinemu.utils.EGLHelper; +import org.dolphinemu.dolphinemu.utils.SettingsFile; + +import java.util.ArrayList; +import java.util.HashMap; + +public final class SettingsFragmentPresenter +{ + private SettingsFragmentView mView; + + private String mMenuTag; + + private HashMap<String, SettingSection> mSettings; + private ArrayList<SettingsItem> mSettingsList; + + public SettingsFragmentPresenter(SettingsFragmentView view) + { + mView = view; + } + + public void onCreate(String menuTag) + { + mMenuTag = menuTag; + } + + public void onViewCreated(HashMap<String, SettingSection> settings) + { + setSettings(settings); + } + + /** + * If the screen is rotated, the Activity will forget the settings map. This fragment + * won't, though; so rather than have the Activity reload from disk, have the fragment pass + * the settings map back to the Activity. + */ + public void onAttach() + { + if (mSettings != null) + { + mView.passSettingsToActivity(mSettings); + } + } + + public void putSetting(Setting setting) + { + mSettings.get(setting.getSection()).putSetting(setting.getKey(), setting); + } + + public void setSettings(HashMap<String, SettingSection> settings) + { + if (mSettingsList == null) + { + mSettings = settings; + + loadSettingsList(); + } + else + { + mView.showSettingsList(mSettingsList); + } + } + + private void loadSettingsList() + { + ArrayList<SettingsItem> sl = new ArrayList<>(); + + switch (mMenuTag) + { + case SettingsFile.FILE_NAME_DOLPHIN: + addCoreSettings(sl); + break; + + case SettingsFile.FILE_NAME_GFX: + addGraphicsSettings(sl); + break; + + case SettingsFile.SECTION_GFX_ENHANCEMENTS: + addEnhanceSettings(sl); + break; + + case SettingsFile.SECTION_GFX_HACKS: + addHackSettings(sl); + break; + + default: + mView.showToastMessage("Unimplemented menu."); + return; + } + + mSettingsList = sl; + mView.showSettingsList(mSettingsList); + } + + private void addCoreSettings(ArrayList<SettingsItem> sl) + { + Setting cpuCore = null; + Setting dualCore = null; + Setting overclockEnable = null; + Setting overclock = null; + + if (mSettings != null) + { + cpuCore = mSettings.get(SettingsFile.SECTION_CORE).getSetting(SettingsFile.KEY_CPU_CORE); + dualCore = mSettings.get(SettingsFile.SECTION_CORE).getSetting(SettingsFile.KEY_DUAL_CORE); + overclockEnable = mSettings.get(SettingsFile.SECTION_CORE).getSetting(SettingsFile.KEY_OVERCLOCK_ENABLE); + overclock = mSettings.get(SettingsFile.SECTION_CORE).getSetting(SettingsFile.KEY_OVERCLOCK_PERCENT); + } + else + { + mSettings = new HashMap<>(); + mSettings.put(SettingsFile.SECTION_CORE, new SettingSection(SettingsFile.SECTION_CORE)); + + mView.passSettingsToActivity(mSettings); + } + + // TODO Set default value for cpuCore based on arch. + sl.add(new SingleChoiceSetting(SettingsFile.KEY_CPU_CORE, SettingsFile.SECTION_CORE, R.string.cpu_core, 0, R.array.string_emu_cores, R.array.int_emu_cores, 4, cpuCore)); + sl.add(new CheckBoxSetting(SettingsFile.KEY_DUAL_CORE, SettingsFile.SECTION_CORE, R.string.dual_core, R.string.dual_core_descrip, true, dualCore)); + sl.add(new CheckBoxSetting(SettingsFile.KEY_OVERCLOCK_ENABLE, SettingsFile.SECTION_CORE, R.string.overclock_enable, R.string.overclock_enable_description, false, overclockEnable)); + sl.add(new SliderSetting(SettingsFile.KEY_OVERCLOCK_PERCENT, SettingsFile.SECTION_CORE, R.string.overclock_title, 0, 400, "%", 100, overclock)); + + } + + private void addGraphicsSettings(ArrayList<SettingsItem> sl) + { + Setting showFps = null; + + if (mSettings != null) + { + showFps = mSettings.get(SettingsFile.SECTION_GFX_SETTINGS).getSetting(SettingsFile.KEY_SHOW_FPS); + } + else + { + mSettings = new HashMap<>(); + + mSettings.put(SettingsFile.SECTION_GFX_SETTINGS, new SettingSection(SettingsFile.SECTION_GFX_SETTINGS)); + mSettings.put(SettingsFile.SECTION_GFX_ENHANCEMENTS, new SettingSection(SettingsFile.SECTION_GFX_ENHANCEMENTS)); + mSettings.put(SettingsFile.SECTION_GFX_HACKS, new SettingSection(SettingsFile.SECTION_GFX_HACKS)); + + mView.passSettingsToActivity(mSettings); + } + + sl.add(new CheckBoxSetting(SettingsFile.KEY_SHOW_FPS, SettingsFile.SECTION_GFX_SETTINGS, R.string.show_fps, 0, true, showFps)); + + sl.add(new SubmenuSetting(null, null, R.string.enhancements, 0, SettingsFile.SECTION_GFX_ENHANCEMENTS)); + sl.add(new SubmenuSetting(null, null, R.string.hacks, 0, SettingsFile.SECTION_GFX_HACKS)); + } + + private void addEnhanceSettings(ArrayList<SettingsItem> sl) + { + Setting resolution = mSettings.get(SettingsFile.SECTION_GFX_SETTINGS).getSetting(SettingsFile.KEY_INTERNAL_RES); + Setting fsaa = mSettings.get(SettingsFile.SECTION_GFX_SETTINGS).getSetting(SettingsFile.KEY_FSAA); + Setting anisotropic = mSettings.get(SettingsFile.SECTION_GFX_ENHANCEMENTS).getSetting(SettingsFile.KEY_ANISOTROPY); + Setting efbScaledCopy = mSettings.get(SettingsFile.SECTION_GFX_HACKS).getSetting(SettingsFile.KEY_SCALED_EFB); + Setting perPixel = mSettings.get(SettingsFile.SECTION_GFX_SETTINGS).getSetting(SettingsFile.KEY_PER_PIXEL); + Setting forceFilter = mSettings.get(SettingsFile.SECTION_GFX_ENHANCEMENTS).getSetting(SettingsFile.KEY_FORCE_FILTERING); + Setting disableFog = mSettings.get(SettingsFile.SECTION_GFX_SETTINGS).getSetting(SettingsFile.KEY_DISABLE_FOG); + + sl.add(new SingleChoiceSetting(SettingsFile.KEY_INTERNAL_RES, SettingsFile.SECTION_GFX_SETTINGS, R.string.internal_resolution, R.string.internal_resolution_descrip, R.array.internalResolutionEntries, R.array.internalResolutionValues, 0, resolution)); + sl.add(new SingleChoiceSetting(SettingsFile.KEY_FSAA, SettingsFile.SECTION_GFX_SETTINGS, R.string.FSAA, R.string.FSAA_descrip, R.array.FSAAEntries, R.array.FSAAValues, 0, fsaa)); + sl.add(new SingleChoiceSetting(SettingsFile.KEY_ANISOTROPY, SettingsFile.SECTION_GFX_ENHANCEMENTS, R.string.anisotropic_filtering, R.string.anisotropic_filtering_descrip, R.array.anisotropicFilteringEntries, R.array.anisotropicFilteringValues, 0, anisotropic)); + + // TODO +// Setting shader = mSettings.get(SettingsFile.SECTION_GFX_ENHANCEMENTS).getSetting(SettingsFile.KEY_POST_SHADER) +// sl.add(new SingleChoiceSetting(.getKey(), , R.string., R.string._descrip, R.array., R.array.)); + + sl.add(new CheckBoxSetting(SettingsFile.KEY_SCALED_EFB, SettingsFile.SECTION_GFX_HACKS, R.string.scaled_efb_copy, R.string.scaled_efb_copy_descrip, true, efbScaledCopy)); + sl.add(new CheckBoxSetting(SettingsFile.KEY_PER_PIXEL, SettingsFile.SECTION_GFX_SETTINGS, R.string.per_pixel_lighting, R.string.per_pixel_lighting_descrip, false, perPixel)); + sl.add(new CheckBoxSetting(SettingsFile.KEY_FORCE_FILTERING, SettingsFile.SECTION_GFX_ENHANCEMENTS, R.string.force_texture_filtering, R.string.force_texture_filtering_descrip, false, forceFilter)); + sl.add(new CheckBoxSetting(SettingsFile.KEY_DISABLE_FOG, SettingsFile.SECTION_GFX_SETTINGS, R.string.disable_fog, R.string.disable_fog_descrip, false, disableFog)); + + /* + Check if we support stereo + If we support desktop GL then we must support at least OpenGL 3.2 + If we only support OpenGLES then we need both OpenGLES 3.1 and AEP + */ + EGLHelper helper = new EGLHelper(EGLHelper.EGL_OPENGL_ES2_BIT); + + if ((helper.supportsOpenGL() && helper.GetVersion() >= 320) || + (helper.supportsGLES3() && helper.GetVersion() >= 310 && helper.SupportsExtension("GL_ANDROID_extension_pack_es31a"))) + { + sl.add(new SubmenuSetting(null, null, R.string.stereoscopy, 0, SettingsFile.SECTION_STEREOSCOPY)); + } + } + + private void addHackSettings(ArrayList<SettingsItem> sl) + { + int xfbValue = getXfbValue(); + + Setting skipEFB = mSettings.get(SettingsFile.SECTION_GFX_HACKS).getSetting(SettingsFile.KEY_SKIP_EFB); + Setting ignoreFormat = mSettings.get(SettingsFile.SECTION_GFX_HACKS).getSetting(SettingsFile.KEY_IGNORE_FORMAT); + Setting efbToTexture = mSettings.get(SettingsFile.SECTION_GFX_HACKS).getSetting(SettingsFile.KEY_EFB_TEXTURE); + Setting texCacheAccuracy = mSettings.get(SettingsFile.SECTION_GFX_HACKS).getSetting(SettingsFile.KEY_TEXCACHE_ACCURACY); + IntSetting xfb = new IntSetting(SettingsFile.KEY_XFB, SettingsFile.SECTION_GFX_HACKS, xfbValue); + Setting fastDepth = mSettings.get(SettingsFile.SECTION_GFX_HACKS).getSetting(SettingsFile.KEY_FAST_DEPTH); + Setting aspectRatio = mSettings.get(SettingsFile.SECTION_GFX_HACKS).getSetting(SettingsFile.KEY_ASPECT_RATIO); + + sl.add(new HeaderSetting(null, null, R.string.embedded_frame_buffer, 0)); + sl.add(new CheckBoxSetting(SettingsFile.KEY_SKIP_EFB, SettingsFile.SECTION_GFX_HACKS, R.string.skip_efb_access, R.string.skip_efb_access_descrip, false, skipEFB)); + sl.add(new CheckBoxSetting(SettingsFile.KEY_IGNORE_FORMAT, SettingsFile.SECTION_GFX_HACKS, R.string.ignore_format_changes, R.string.ignore_format_changes_descrip, false, ignoreFormat)); + sl.add(new CheckBoxSetting(SettingsFile.KEY_EFB_TEXTURE, SettingsFile.SECTION_GFX_HACKS, R.string.efb_copy_method, R.string.efb_copy_method_descrip, true, efbToTexture)); + + sl.add(new HeaderSetting(null, null, R.string.texture_cache, 0)); + sl.add(new SingleChoiceSetting(SettingsFile.KEY_TEXCACHE_ACCURACY, SettingsFile.SECTION_GFX_HACKS, R.string.texture_cache_accuracy, R.string.texture_cache_accuracy_descrip, R.array.textureCacheAccuracyEntries, R.array.textureCacheAccuracyValues, 128, texCacheAccuracy)); + + sl.add(new HeaderSetting(null, null, R.string.external_frame_buffer, 0)); + sl.add(new SingleChoiceSetting(SettingsFile.KEY_XFB_METHOD, SettingsFile.SECTION_GFX_HACKS, R.string.external_frame_buffer, R.string.external_frame_buffer_descrip, R.array.externalFrameBufferEntries, R.array.externalFrameBufferValues, 0, xfb)); + + sl.add(new HeaderSetting(null, null, R.string.other, 0)); + sl.add(new CheckBoxSetting(SettingsFile.KEY_FAST_DEPTH, SettingsFile.SECTION_GFX_HACKS, R.string.fast_depth_calculation, R.string.fast_depth_calculation_descrip, true, fastDepth)); + sl.add(new SingleChoiceSetting(SettingsFile.KEY_ASPECT_RATIO, SettingsFile.SECTION_GFX_HACKS, R.string.aspect_ratio, R.string.aspect_ratio_descrip, R.array.aspectRatioEntries, R.array.aspectRatioValues, 0, aspectRatio)); + } + + private int getXfbValue() + { + int xfbValue; + + try + { + boolean usingXFB = ((BooleanSetting) mSettings.get(SettingsFile.SECTION_GFX_SETTINGS).getSetting(SettingsFile.KEY_XFB)).getValue(); + boolean usingRealXFB = ((BooleanSetting) mSettings.get(SettingsFile.SECTION_GFX_SETTINGS).getSetting(SettingsFile.KEY_XFB_REAL)).getValue(); + + if (!usingXFB) + { + xfbValue = 0; + } + else if (!usingRealXFB) + { + xfbValue = 1; + } + else + { + xfbValue = 2; + } + } + catch (NullPointerException ex) + { + xfbValue = 0; + } + + return xfbValue; + } +} + diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/settings/SettingsFragmentView.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/settings/SettingsFragmentView.java new file mode 100644 index 0000000000..c437863c94 --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/settings/SettingsFragmentView.java @@ -0,0 +1,68 @@ +package org.dolphinemu.dolphinemu.ui.settings; + +import android.app.Activity; + +import org.dolphinemu.dolphinemu.model.settings.Setting; +import org.dolphinemu.dolphinemu.model.settings.SettingSection; +import org.dolphinemu.dolphinemu.model.settings.view.SettingsItem; + +import java.util.ArrayList; +import java.util.HashMap; + +/** + * Abstraction for a screen showing a list of settings. Instances of + * this type of view will each display a layer of the setting hierarchy. + */ +public interface SettingsFragmentView +{ + /** + * Called by the containing Activity to notify the Fragment that an + * asynchronous load operation completed. + * + * @param settings The potentially-null result of the load operation. + */ + void onSettingsFileLoaded(HashMap<String, SettingSection> settings); + + /** + * Pass a settings Hashmap to the containing activity, so that it can + * share the Hashmap with other SettingsFragments; useful so that rotations + * do not require an additional load operation. + * + * @param settings A Hashmap containing all the settings + */ + void passSettingsToActivity(HashMap<String, SettingSection> settings); + + /** + * Pass an ArrayList to the View so that it can be displayed on screen. + * + * @param settingsList The result of converting the Hashmap to an ArrayList + */ + void showSettingsList(ArrayList<SettingsItem> settingsList); + + /** + * @return The Fragment's containing activity. + */ + Activity getActivity(); + + /** + * Tell the Fragment to tell the containing Activity to show a new + * Fragment containing a submenu of settings. + * + * @param menuKey Identifier for the settings group that should be shown. + */ + void loadSubMenu(String menuKey); + + /** + * Tell the Fragment to tell the containing activity to display a toast message. + * + * @param message Text to be shown in the Toast + */ + void showToastMessage(String message); + + /** + * Have the fragment add a setting to the Hashmap. + * + * @param setting The (possibly previously missing) new setting. + */ + void putSetting(Setting setting); +} diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/settings/viewholder/CheckBoxSettingViewHolder.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/settings/viewholder/CheckBoxSettingViewHolder.java new file mode 100644 index 0000000000..c65fde1d66 --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/settings/viewholder/CheckBoxSettingViewHolder.java @@ -0,0 +1,57 @@ +package org.dolphinemu.dolphinemu.ui.settings.viewholder; + + +import android.view.View; +import android.widget.CheckBox; +import android.widget.TextView; + +import org.dolphinemu.dolphinemu.R; +import org.dolphinemu.dolphinemu.model.settings.view.CheckBoxSetting; +import org.dolphinemu.dolphinemu.model.settings.view.SettingsItem; +import org.dolphinemu.dolphinemu.ui.settings.SettingsAdapter; + +public final class CheckBoxSettingViewHolder extends SettingViewHolder +{ + private CheckBoxSetting mItem; + + private TextView mTextSettingName; + private TextView mTextSettingDescription; + + private CheckBox mCheckbox; + + public CheckBoxSettingViewHolder(View itemView, SettingsAdapter adapter) + { + super(itemView, adapter); + } + + @Override + protected void findViews(View root) + { + mTextSettingName = (TextView) root.findViewById(R.id.text_setting_name); + mTextSettingDescription = (TextView) root.findViewById(R.id.text_setting_description); + mCheckbox = (CheckBox) root.findViewById(R.id.checkbox); + } + + @Override + public void bind(SettingsItem item) + { + mItem = (CheckBoxSetting) item; + + mTextSettingName.setText(item.getNameId()); + + if (item.getDescriptionId() > 0) + { + mTextSettingDescription.setText(item.getDescriptionId()); + } + + mCheckbox.setChecked(mItem.isChecked()); + } + + @Override + public void onClick(View clicked) + { + mCheckbox.toggle(); + + getAdapter().onBooleanClick(mItem, getAdapterPosition(), mCheckbox.isChecked()); + } +} diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/settings/viewholder/HeaderViewHolder.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/settings/viewholder/HeaderViewHolder.java new file mode 100644 index 0000000000..6e3b53d4b3 --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/settings/viewholder/HeaderViewHolder.java @@ -0,0 +1,37 @@ +package org.dolphinemu.dolphinemu.ui.settings.viewholder; + +import android.view.View; +import android.widget.TextView; + +import org.dolphinemu.dolphinemu.R; +import org.dolphinemu.dolphinemu.model.settings.view.SettingsItem; +import org.dolphinemu.dolphinemu.ui.settings.SettingsAdapter; + +public final class HeaderViewHolder extends SettingViewHolder +{ + private TextView mHeaderName; + + public HeaderViewHolder(View itemView, SettingsAdapter adapter) + { + super(itemView, adapter); + itemView.setOnClickListener(null); + } + + @Override + protected void findViews(View root) + { + mHeaderName = (TextView) root.findViewById(R.id.text_header_name); + } + + @Override + public void bind(SettingsItem item) + { + mHeaderName.setText(item.getNameId()); + } + + @Override + public void onClick(View clicked) + { + // no-op + } +}
\ No newline at end of file diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/settings/viewholder/SettingViewHolder.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/settings/viewholder/SettingViewHolder.java new file mode 100644 index 0000000000..f57e9fc82c --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/settings/viewholder/SettingViewHolder.java @@ -0,0 +1,51 @@ +package org.dolphinemu.dolphinemu.ui.settings.viewholder; + +import android.support.v7.widget.RecyclerView; +import android.view.View; + +import org.dolphinemu.dolphinemu.model.settings.view.SettingsItem; +import org.dolphinemu.dolphinemu.ui.settings.SettingsAdapter; + +public abstract class SettingViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener +{ + private SettingsAdapter mAdapter; + + public SettingViewHolder(View itemView, SettingsAdapter adapter) + { + super(itemView); + + mAdapter = adapter; + + itemView.setOnClickListener(this); + + findViews(itemView); + } + + protected SettingsAdapter getAdapter() + { + return mAdapter; + } + + /** + * Gets handles to all this ViewHolder's child views using their XML-defined identifiers. + * + * @param root The newly inflated top-level view. + */ + protected abstract void findViews(View root); + + /** + * Called by the adapter to set this ViewHolder's child views to display the list item + * it must now represent. + * + * @param item The list item that should be represented by this ViewHolder. + */ + public abstract void bind(SettingsItem item); + + /** + * Called when this ViewHolder's view is clicked on. Implementations should usually pass + * this event up to the adapter. + * + * @param clicked The view that was clicked on. + */ + public abstract void onClick(View clicked); +} diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/settings/viewholder/SingleChoiceViewHolder.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/settings/viewholder/SingleChoiceViewHolder.java new file mode 100644 index 0000000000..add1b76637 --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/settings/viewholder/SingleChoiceViewHolder.java @@ -0,0 +1,48 @@ +package org.dolphinemu.dolphinemu.ui.settings.viewholder; + +import android.view.View; +import android.widget.TextView; + +import org.dolphinemu.dolphinemu.R; +import org.dolphinemu.dolphinemu.model.settings.view.SettingsItem; +import org.dolphinemu.dolphinemu.model.settings.view.SingleChoiceSetting; +import org.dolphinemu.dolphinemu.ui.settings.SettingsAdapter; + +public final class SingleChoiceViewHolder extends SettingViewHolder +{ + private SingleChoiceSetting mItem; + + private TextView mTextSettingName; + private TextView mTextSettingDescription; + + public SingleChoiceViewHolder(View itemView, SettingsAdapter adapter) + { + super(itemView, adapter); + } + + @Override + protected void findViews(View root) + { + mTextSettingName = (TextView) root.findViewById(R.id.text_setting_name); + mTextSettingDescription = (TextView) root.findViewById(R.id.text_setting_description); + } + + @Override + public void bind(SettingsItem item) + { + mItem = (SingleChoiceSetting) item; + + mTextSettingName.setText(item.getNameId()); + + if (item.getDescriptionId() > 0) + { + mTextSettingDescription.setText(item.getDescriptionId()); + } + } + + @Override + public void onClick(View clicked) + { + getAdapter().onSingleChoiceClick(mItem); + } +} diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/settings/viewholder/SliderViewHolder.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/settings/viewholder/SliderViewHolder.java new file mode 100644 index 0000000000..9615c720fb --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/settings/viewholder/SliderViewHolder.java @@ -0,0 +1,50 @@ +package org.dolphinemu.dolphinemu.ui.settings.viewholder; + + +import android.view.View; +import android.widget.TextView; + +import org.dolphinemu.dolphinemu.R; +import org.dolphinemu.dolphinemu.model.settings.view.SettingsItem; +import org.dolphinemu.dolphinemu.model.settings.view.SliderSetting; +import org.dolphinemu.dolphinemu.ui.settings.SettingsAdapter; + +public final class SliderViewHolder extends SettingViewHolder +{ + private SliderSetting mItem; + + private TextView mTextSettingName; + private TextView mTextSettingDescription; + + public SliderViewHolder(View itemView, SettingsAdapter adapter) + { + super(itemView, adapter); + } + + @Override + protected void findViews(View root) + { + mTextSettingName = (TextView) root.findViewById(R.id.text_setting_name); + mTextSettingDescription = (TextView) root.findViewById(R.id.text_setting_description); + } + + @Override + public void bind(SettingsItem item) + { + mItem = (SliderSetting) item; + + mTextSettingName.setText(item.getNameId()); + + if (item.getDescriptionId() > 0) + { + mTextSettingDescription.setText(item.getDescriptionId()); + } + } + + @Override + public void onClick(View clicked) + { + getAdapter().onSliderClick(mItem); + } +} + diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/settings/viewholder/SubmenuViewHolder.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/settings/viewholder/SubmenuViewHolder.java new file mode 100644 index 0000000000..4a8243cec7 --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/settings/viewholder/SubmenuViewHolder.java @@ -0,0 +1,48 @@ +package org.dolphinemu.dolphinemu.ui.settings.viewholder; + +import android.view.View; +import android.widget.TextView; + +import org.dolphinemu.dolphinemu.R; +import org.dolphinemu.dolphinemu.model.settings.view.SettingsItem; +import org.dolphinemu.dolphinemu.model.settings.view.SubmenuSetting; +import org.dolphinemu.dolphinemu.ui.settings.SettingsAdapter; + +public final class SubmenuViewHolder extends SettingViewHolder +{ + private SubmenuSetting mItem; + + private TextView mTextSettingName; + private TextView mTextSettingDescription; + + public SubmenuViewHolder(View itemView, SettingsAdapter adapter) + { + super(itemView, adapter); + } + + @Override + protected void findViews(View root) + { + mTextSettingName = (TextView) root.findViewById(R.id.text_setting_name); + mTextSettingDescription = (TextView) root.findViewById(R.id.text_setting_description); + } + + @Override + public void bind(SettingsItem item) + { + mItem = (SubmenuSetting) item; + + mTextSettingName.setText(item.getNameId()); + + if (item.getDescriptionId() > 0) + { + mTextSettingDescription.setText(item.getDescriptionId()); + } + } + + @Override + public void onClick(View clicked) + { + getAdapter().onSubmenuClick(mItem); + } +}
\ No newline at end of file diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/SettingsFile.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/SettingsFile.java new file mode 100644 index 0000000000..865e3371ae --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/SettingsFile.java @@ -0,0 +1,302 @@ +package org.dolphinemu.dolphinemu.utils; + +import android.os.Environment; +import android.support.annotation.NonNull; + +import org.dolphinemu.dolphinemu.model.settings.BooleanSetting; +import org.dolphinemu.dolphinemu.model.settings.FloatSetting; +import org.dolphinemu.dolphinemu.model.settings.IntSetting; +import org.dolphinemu.dolphinemu.model.settings.Setting; +import org.dolphinemu.dolphinemu.model.settings.SettingSection; +import org.dolphinemu.dolphinemu.model.settings.StringSetting; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.IOException; +import java.io.PrintWriter; +import java.io.UnsupportedEncodingException; +import java.util.HashMap; +import java.util.Set; + +import rx.Observable; +import rx.Subscriber; + +/** + * Contains static methods for interacting with .ini files in which settings are stored. + */ +public final class SettingsFile +{ + public static final String FILE_NAME_DOLPHIN = "Dolphin"; + public static final String FILE_NAME_GFX = "GFX"; + public static final String FILE_NAME_GCPAD = "GCPadNew"; + public static final String FILE_NAME_WIIMOTE = "WiimoteNew"; + + public static final String SECTION_CORE = "Core"; + + public static final String SECTION_GFX_SETTINGS = "Settings"; + public static final String SECTION_GFX_ENHANCEMENTS = "Enhancements"; + public static final String SECTION_GFX_HACKS = "Hacks"; + + public static final String SECTION_STEREOSCOPY = "Stereoscopy"; + + public static final String KEY_CPU_CORE = "CPUCore"; + public static final String KEY_DUAL_CORE = "CPUThread"; + public static final String KEY_OVERCLOCK_ENABLE = "OverclockEnable"; + public static final String KEY_OVERCLOCK_PERCENT = "Overclock"; + public static final String KEY_VIDEO_BACKEND = "GFXBackend"; + + public static final String KEY_SHOW_FPS = "ShowFPS"; + public static final String KEY_INTERNAL_RES = "EFBScale"; + public static final String KEY_FSAA = "MSAA"; + public static final String KEY_ANISOTROPY = "MaxAnisotropy"; + public static final String KEY_POST_SHADER = "PostProcessingShader"; + public static final String KEY_SCALED_EFB = "EFBScaledCopy"; + public static final String KEY_PER_PIXEL = "EnablePixelLighting"; + public static final String KEY_FORCE_FILTERING = "ForceFiltering"; + public static final String KEY_DISABLE_FOG = "DisableFog"; + + public static final String KEY_STEREO_MODE = "StereoMode"; + public static final String KEY_STEREO_DEPTH = "StereoDepth"; + public static final String KEY_STEREO_CONV = "StereoConvergencePercentage"; + public static final String KEY_STEREO_SWAP = "StereoSwapEyes"; + + public static final String KEY_SKIP_EFB = "EFBAccessEnable"; + public static final String KEY_IGNORE_FORMAT = "EFBEmulateFormatChanges"; + public static final String KEY_EFB_COPY = "EFBCopyEnable"; + public static final String KEY_EFB_TEXTURE = "EFBToTextureEnable"; + public static final String KEY_EFB_CACHE = "EFBCopyCacheEnable"; + public static final String KEY_TEXCACHE_ACCURACY = "SafeTextureCacheColorSamples"; + public static final String KEY_XFB = "UseXFB"; + public static final String KEY_XFB_REAL = "UseRealXFB"; + public static final String KEY_FAST_DEPTH= "FastDepthCalc"; + public static final String KEY_ASPECT_RATIO= "AspectRatio"; + + // Internal only, not actually found in settings file. + public static final String KEY_XFB_METHOD = "XFBMethod"; + + private SettingsFile() + { + } + + /** + * Reads a given .ini file from disk and returns it as an Rx Observable. If successful, + * this Observable emits a Hashmap of SettingSections, themselves effectively a Hashmap of + * key/value settings. If unsuccessful, the observer notifies the subscriber of why it failed. + * + * @param fileName The name of the settings file without a path or extension. + * @return An Observable that emits a Hashmap of the file's contents, then completes. + */ + public static Observable<HashMap<String, SettingSection>> readFile(final String fileName) + { + return Observable.create(new Observable.OnSubscribe<HashMap<String, SettingSection>>() + { + @Override + public void call(Subscriber<? super HashMap<String, SettingSection>> subscriber) + { + + HashMap<String, SettingSection> sections = new HashMap<>(); + + File ini = getSettingsFile(fileName); + + BufferedReader reader = null; + + try + { + reader = new BufferedReader(new FileReader(ini)); + + SettingSection current = null; + for (String line; (line = reader.readLine()) != null; ) + { + if (line.startsWith("[") && line.endsWith("]")) + { + current = sectionFromLine(line); + sections.put(current.getName(), current); + } + else if ((current != null) && line.contains("=")) + { + Setting setting = settingFromLine(current, line); + current.putSetting(setting.getKey(), setting); + } + } + } + catch (FileNotFoundException e) + { + Log.error("[SettingsFile] File not found: " + fileName + ".ini: " + e.getMessage()); + subscriber.onError(e); + } + catch (IOException e) + { + Log.error("[SettingsFile] Error reading from: " + fileName + ".ini: " + e.getMessage()); + subscriber.onError(e); + } finally + { + if (reader != null) + { + try + { + reader.close(); + } + catch (IOException e) + { + Log.error("[SettingsFile] Error closing: " + fileName + ".ini: " + e.getMessage()); + subscriber.onError(e); + } + } + } + + subscriber.onNext(sections); + subscriber.onCompleted(); + } + }); + } + + /** + * Saves a Settings Hashmap to a given .ini file on disk, returning the operation + * as an Rx Observable. If successful, this Observable emits an event to notify subscribers; + * if unsuccessful, the observer notifies the subscriber of why it failed. + * + * @param fileName The target filename without a path or extension. + * @param sections The hashmap containing the Settings we want to serialize. + * @return An Observable representing the operation. + */ + public static Observable<Boolean> saveFile(final String fileName, final HashMap<String, SettingSection> sections) + { + return Observable.create(new Observable.OnSubscribe<Boolean>() + { + @Override + public void call(Subscriber<? super Boolean> subscriber) + { + File ini = getSettingsFile(fileName); + + PrintWriter writer = null; + try + { + writer = new PrintWriter(ini, "UTF-8"); + + Set<String> keySet = sections.keySet(); + + for (String key : keySet) + { + SettingSection section = sections.get(key); + writeSection(writer, section); + } + } + catch (FileNotFoundException e) + { + Log.error("[SettingsFile] File not found: " + fileName + ".ini: " + e.getMessage()); + subscriber.onError(e); + } + catch (UnsupportedEncodingException e) + { + Log.error("[SettingsFile] Bad encoding; please file a bug report: " + fileName + ".ini: " + e.getMessage()); + subscriber.onError(e); + } finally + { + if (writer != null) + { + writer.close(); + } + } + + subscriber.onNext(true); + subscriber.onCompleted(); + } + }); + } + + @NonNull + private static File getSettingsFile(String fileName) + { + String storagePath = Environment.getExternalStorageDirectory().getAbsolutePath(); + return new File(storagePath + "/dolphin-emu/Config/" + fileName + ".ini"); + } + + private static SettingSection sectionFromLine(String line) + { + String sectionName = line.substring(1, line.length() - 1); + return new SettingSection(sectionName); + } + + /** + * For a line of text, determines what type of data is being represented, and returns + * a Setting object containing this data. + * + * @param current The section currently being parsed by the consuming method. + * @param line The line of text being parsed. + * @return A typed Setting containing the key/value contained in the line. + */ + private static Setting settingFromLine(SettingSection current, String line) + { + String[] splitLine = line.split("="); + + String key = splitLine[0].trim(); + String value = splitLine[1].trim(); + + try + { + int valueAsInt = Integer.valueOf(value); + + return new IntSetting(key, current.getName(), valueAsInt); + } + catch (NumberFormatException ex) + { + } + + try + { + float valueAsFloat = Float.valueOf(value); + + return new FloatSetting(key, current.getName(), valueAsFloat); + } + catch (NumberFormatException ex) + { + } + + switch (value) + { + case "True": + return new BooleanSetting(key, current.getName(), true); + case "False": + return new BooleanSetting(key, current.getName(), false); + default: + return new StringSetting(key, current.getName(), value); + } + } + + /** + * Writes the contents of a Section hashmap to disk. + * + * @param writer A PrintWriter pointed at a file on disk. + * @param section A section containing settings to be written to the file. + */ + private static void writeSection(PrintWriter writer, SettingSection section) + { + // Write the section header. + String header = sectionAsString(section); + writer.println(header); + + // Write this section's values. + HashMap<String, Setting> settings = section.getSettings(); + Set<String> keySet = settings.keySet(); + + for (String key : keySet) + { + Setting setting = settings.get(key); + String settingString = settingAsString(setting); + + writer.println(settingString); + } + } + + private static String sectionAsString(SettingSection section) + { + return "[" + section.getName() + "]"; + } + + private static String settingAsString(Setting setting) + { + return setting.getKey() + " = " + setting.getValueAsString(); + } +} diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/SliderPreference.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/SliderPreference.java deleted file mode 100644 index da896cf590..0000000000 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/SliderPreference.java +++ /dev/null @@ -1,128 +0,0 @@ -package org.dolphinemu.dolphinemu.utils; - -import android.app.AlertDialog; -import android.content.Context; -import android.os.Bundle; -import android.preference.DialogPreference; -import android.util.AttributeSet; -import android.view.LayoutInflater; -import android.view.View; -import android.widget.Button; -import android.widget.LinearLayout; -import android.widget.SeekBar; -import android.widget.TextView; -import android.widget.Toast; - -import org.dolphinemu.dolphinemu.R; - -public class SliderPreference extends DialogPreference implements SeekBar.OnSeekBarChangeListener, View.OnClickListener -{ - private static final String androidns = "http://schemas.android.com/apk/res/android"; - - // SeekBar - private int m_max, m_value; - private String m_key; - private SeekBar m_seekbar; - - // TextView - private TextView m_textview; - - public SliderPreference(Context context, AttributeSet attrs) - { - super(context, attrs); - - // Seekbar values - m_value = attrs.getAttributeIntValue(androidns, "defaultValue", 0); - m_max = attrs.getAttributeIntValue(androidns, "max", 100); - m_key = attrs.getAttributeValue(androidns, "key"); - } - - @Override - protected View onCreateDialogView() - { - LayoutInflater inflater = LayoutInflater.from(getContext()); - LinearLayout layout = (LinearLayout) inflater.inflate(R.layout.slider_layout, null, false); - - m_seekbar = (SeekBar) layout.findViewById(R.id.sliderSeekBar); - m_textview = (TextView) layout.findViewById(R.id.sliderTextView); - - if (shouldPersist()) - { - if (m_key != null && m_key.equals("Overclock")) - { - Toast.makeText(getContext(), getContext().getString(R.string.overclock_warning), - Toast.LENGTH_LONG).show(); - - float valueAsFloat = Float.valueOf(getPersistedString(Integer.toString(m_value))); - float valueAsPercent = valueAsFloat * 100; - - m_value = Math.round(valueAsPercent); - } - else - { - m_value = Integer.valueOf(getPersistedString(Integer.toString(m_value))); - } - } - - m_seekbar.setMax(m_max); - m_seekbar.setProgress(m_value); - setProgressText(m_value); - m_seekbar.setOnSeekBarChangeListener(this); - - return layout; - } - - // SeekBar overrides - @Override - public void onProgressChanged(SeekBar seek, int value, boolean fromTouch) - { - m_value = value; - setProgressText(value); - } - - @Override - public void onStartTrackingTouch(SeekBar seek) - { - } - - @Override - public void onStopTrackingTouch(SeekBar seek) - { - } - - void setProgressText(int value) - { - m_textview.setText(String.valueOf(value)); - } - - @Override - public void showDialog(Bundle state) - { - super.showDialog(state); - - Button positiveButton = ((AlertDialog) getDialog()).getButton(AlertDialog.BUTTON_POSITIVE); - positiveButton.setOnClickListener(this); - } - - @Override - public void onClick(View v) - { - if (shouldPersist()) - { - String valueToSave; - if (m_key != null && m_key.equals("Overclock")) - { - float valueAsFloat = m_value / 100.0f; - valueToSave = Float.toString(valueAsFloat); - } - else - { - valueToSave = Integer.toString(m_seekbar.getProgress()); - } - - persistString(valueToSave); - callChangeListener(m_seekbar.getProgress()); - } - ((AlertDialog) getDialog()).dismiss(); - } -} diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/UserPreferences.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/UserPreferences.java deleted file mode 100644 index a5d8883b95..0000000000 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/UserPreferences.java +++ /dev/null @@ -1,495 +0,0 @@ -/** - * Copyright 2013 Dolphin Emulator Project - * Licensed under GPLv2+ - * Refer to the license.txt file included. - */ - -package org.dolphinemu.dolphinemu.utils; - -import android.content.Context; -import android.content.SharedPreferences; -import android.os.Build; -import android.preference.PreferenceManager; - -import org.dolphinemu.dolphinemu.NativeLibrary; - -/** - * A class that retrieves all of the set user preferences in Android, in a safe way. - * <p> - * If any preferences are added to this emulator, an accessor for that preference - * should be added here. This way lengthy calls to getters from SharedPreferences - * aren't made necessary. - */ -public final class UserPreferences -{ - private UserPreferences() - { - // Disallows instantiation. - } - - /** - * Loads the settings stored in the Dolphin ini config files to the shared preferences of this front-end. - * - * @param ctx The context used to retrieve the SharedPreferences instance. - */ - public static void LoadIniToPrefs(Context ctx) - { - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ctx); - - // Get an editor. - SharedPreferences.Editor editor = prefs.edit(); - - // Add the settings. - if (Build.CPU_ABI.contains("arm64")) - editor.putString("cpuCorePref", getConfig("Dolphin.ini", "Core", "CPUCore", "4")); - else - editor.putString("cpuCorePref", getConfig("Dolphin.ini", "Core", "CPUCore", "3")); - - editor.putBoolean("dualCorePref", getConfig("Dolphin.ini", "Core", "CPUThread", "True").equals("True")); - editor.putBoolean("OverclockEnable", getConfig("Dolphin.ini", "Core", "OverclockEnable", "False").equals("True")); - editor.putString("Overclock", getConfig("Dolphin.ini", "Core", "Overclock", "100")); - - // Load analog ranges from GCPadNew.ini and WiimoteNew.ini - editor.putString("mainRadius0", getConfig("GCPadNew.ini", "GCPad1", "Main Stick/Radius", "100,000000")); - editor.putString("cStickRadius0", getConfig("GCPadNew.ini", "GCPad1", "C-Stick/Radius", "100,000000")); - editor.putString("inputThres0", getConfig("GCPadNew.ini", "GCPad1", "Triggers/Threshold", "90,000000")); - editor.putString("mainRadius1", getConfig("GCPadNew.ini", "GCPad2", "Main Stick/Radius", "100,000000")); - editor.putString("cStickRadius1", getConfig("GCPadNew.ini", "GCPad2", "C-Stick/Radius", "100,000000")); - editor.putString("inputThres1", getConfig("GCPadNew.ini", "GCPad2", "Triggers/Threshold", "90,000000")); - editor.putString("mainRadius2", getConfig("GCPadNew.ini", "GCPad3", "Main Stick/Radius", "100,000000")); - editor.putString("cStickRadius2", getConfig("GCPadNew.ini", "GCPad3", "C-Stick/Radius", "100,000000")); - editor.putString("inputThres2", getConfig("GCPadNew.ini", "GCPad3", "Triggers/Threshold", "90,000000")); - editor.putString("mainRadius3", getConfig("GCPadNew.ini", "GCPad4", "Main Stick/Radius", "100,000000")); - editor.putString("cStickRadius3", getConfig("GCPadNew.ini", "GCPad4", "C-Stick/Radius", "100,000000")); - editor.putString("inputThres3", getConfig("GCPadNew.ini", "GCPad4", "Triggers/Threshold", "90,000000")); - - editor.putString("tiltRange4", getConfig("WiimoteNew.ini", "Wiimote1", "Tilt/Modifier/Range", "50,00000")); - editor.putString("tiltRange5", getConfig("WiimoteNew.ini", "Wiimote2", "Tilt/Modifier/Range", "50,00000")); - editor.putString("tiltRange6", getConfig("WiimoteNew.ini", "Wiimote3", "Tilt/Modifier/Range", "50,00000")); - editor.putString("tiltRange7", getConfig("WiimoteNew.ini", "Wiimote4", "Tilt/Modifier/Range", "50,00000")); - - editor.putString("nunchukRadius4", getConfig("WiimoteNew.ini", "Wiimote1", "Nunchuk/Stick/Radius", "100,000000")); - editor.putString("nunchukRange4", getConfig("WiimoteNew.ini", "Wiimote1", "Nunchuk/Tilt/Modifier/Range", "50,00000")); - editor.putString("nunchukRadius5", getConfig("WiimoteNew.ini", "Wiimote2", "Nunchuk/Stick/Radius", "100,000000")); - editor.putString("nunchukRange5", getConfig("WiimoteNew.ini", "Wiimote2", "Nunchuk/Tilt/Modifier/Range", "50,00000")); - editor.putString("nunchukRadius6", getConfig("WiimoteNew.ini", "Wiimote3", "Nunchuk/Stick/Radius", "100,000000")); - editor.putString("nunchukRange6", getConfig("WiimoteNew.ini", "Wiimote3", "Nunchuk/Tilt/Modifier/Range", "50,00000")); - editor.putString("nunchukRadius7", getConfig("WiimoteNew.ini", "Wiimote4", "Nunchuk/Stick/Radius", "100,000000")); - editor.putString("nunchukRange7", getConfig("WiimoteNew.ini", "Wiimote4", "Nunchuk/Tilt/Modifier/Range", "50,00000")); - - editor.putString("classicLRadius4", getConfig("WiimoteNew.ini", "Wiimote1", "Classic/Left Stick/Radius", "100,000000")); - editor.putString("classicRRadius4", getConfig("WiimoteNew.ini", "Wiimote1", "Classic/Right Stick/Radius", "100,000000")); - editor.putString("classicThres4", getConfig("WiimoteNew.ini", "Wiimote1", "Classic/Triggers/Threshold", "90,000000")); - editor.putString("classicLRadius5", getConfig("WiimoteNew.ini", "Wiimote2", "Classic/Left Stick/Radius", "100,000000")); - editor.putString("classicRRadius5", getConfig("WiimoteNew.ini", "Wiimote2", "Classic/Right Stick/Radius", "100,000000")); - editor.putString("classicThres5", getConfig("WiimoteNew.ini", "Wiimote2", "Classic/Triggers/Threshold", "90,000000")); - editor.putString("classicLRadius6", getConfig("WiimoteNew.ini", "Wiimote3", "Classic/Left Stick/Radius", "100,000000")); - editor.putString("classicRRadius6", getConfig("WiimoteNew.ini", "Wiimote3", "Classic/Right Stick/Radius", "100,000000")); - editor.putString("classicThres6", getConfig("WiimoteNew.ini", "Wiimote3", "Classic/Triggers/Threshold", "90,000000")); - editor.putString("classicLRadius7", getConfig("WiimoteNew.ini", "Wiimote4", "Classic/Left Stick/Radius", "100,000000")); - editor.putString("classicRRadius7", getConfig("WiimoteNew.ini", "Wiimote4", "Classic/Right Stick/Radius", "100,000000")); - editor.putString("classicThres7", getConfig("WiimoteNew.ini", "Wiimote4", "Classic/Triggers/Threshold", "90,000000")); - - editor.putString("guitarRadius4", getConfig("WiimoteNew.ini", "Wiimote1", "Guitar/Stick/Radius", "100,000000")); - editor.putString("guitarRadius5", getConfig("WiimoteNew.ini", "Wiimote2", "Guitar/Stick/Radius", "100,000000")); - editor.putString("guitarRadius6", getConfig("WiimoteNew.ini", "Wiimote3", "Guitar/Stick/Radius", "100,000000")); - editor.putString("guitarRadius7", getConfig("WiimoteNew.ini", "Wiimote4", "Guitar/Stick/Radius", "100,000000")); - - editor.putString("drumsRadius4", getConfig("WiimoteNew.ini", "Wiimote1", "Drums/Stick/Radius", "100,000000")); - editor.putString("drumsRadius5", getConfig("WiimoteNew.ini", "Wiimote2", "Drums/Stick/Radius", "100,000000")); - editor.putString("drumsRadius6", getConfig("WiimoteNew.ini", "Wiimote3", "Drums/Stick/Radius", "100,000000")); - editor.putString("drumsRadius7", getConfig("WiimoteNew.ini", "Wiimote4", "Drums/Stick/Radius", "100,000000")); - - editor.putString("turntableRadius4", getConfig("WiimoteNew.ini", "Wiimote1", "Turntable/Stick/Radius", "100,000000")); - editor.putString("turntableRadius5", getConfig("WiimoteNew.ini", "Wiimote2", "Turntable/Stick/Radius", "100,000000")); - editor.putString("turntableRadius6", getConfig("WiimoteNew.ini", "Wiimote3", "Turntable/Stick/Radius", "100,000000")); - editor.putString("turntableRadius7", getConfig("WiimoteNew.ini", "Wiimote4", "Turntable/Stick/Radius", "100,000000")); - - // Load Wiimote Extension settings from WiimoteNew.ini - editor.putString("wiimoteExtension4", getConfig("WiimoteNew.ini", "Wiimote1", "Extension", "None")); - editor.putString("wiimoteExtension5", getConfig("WiimoteNew.ini", "Wiimote2", "Extension", "None")); - editor.putString("wiimoteExtension6", getConfig("WiimoteNew.ini", "Wiimote3", "Extension", "None")); - editor.putString("wiimoteExtension7", getConfig("WiimoteNew.ini", "Wiimote4", "Extension", "None")); - - editor.putString("gpuPref", getConfig("Dolphin.ini", "Core", "GFXBackend", "OGL")); - editor.putBoolean("showFPS", getConfig("GFX.ini", "Settings", "ShowFPS", "False").equals("True")); - editor.putBoolean("drawOnscreenControls", getConfig("Dolphin.ini", "Android", "ScreenControls", "True").equals("True")); - - editor.putString("internalResolution", getConfig("GFX.ini", "Settings", "EFBScale", "2")); - editor.putString("FSAA", getConfig("GFX.ini", "Settings", "MSAA", "0")); - editor.putString("anisotropicFiltering", getConfig("GFX.ini", "Enhancements", "MaxAnisotropy", "0")); - editor.putString("postProcessingShader", getConfig("GFX.ini", "Enhancements", "PostProcessingShader", "")); - editor.putBoolean("scaledEFBCopy", getConfig("GFX.ini", "Hacks", "EFBScaledCopy", "True").equals("True")); - editor.putBoolean("perPixelLighting", getConfig("GFX.ini", "Settings", "EnablePixelLighting", "False").equals("True")); - editor.putBoolean("forceTextureFiltering", getConfig("GFX.ini", "Enhancements", "ForceFiltering", "False").equals("True")); - editor.putBoolean("disableFog", getConfig("GFX.ini", "Settings", "DisableFog", "False").equals("True")); - editor.putBoolean("skipEFBAccess", getConfig("GFX.ini", "Hacks", "EFBAccessEnable", "False").equals("True")); - editor.putBoolean("ignoreFormatChanges", getConfig("GFX.ini", "Hacks", "EFBEmulateFormatChanges", "False").equals("True")); - editor.putString("stereoscopyMode", getConfig("GFX.ini", "Stereoscopy", "StereoMode", "0")); - editor.putBoolean("stereoSwapEyes", getConfig("GFX.ini", "Stereoscopy", "StereoSwapEyes", "False").equals("True")); - editor.putString("stereoDepth", getConfig("GFX.ini", "Stereoscopy", "StereoDepth", "20")); - editor.putString("stereoConvergencePercentage", getConfig("GFX.ini", "Stereoscopy", "StereoConvergencePercentage", "100")); - editor.putBoolean("enableController1", getConfig("Dolphin.ini", "Core", "SIDevice0", "6") == "6"); - editor.putBoolean("enableController2", getConfig("Dolphin.ini", "Core", "SIDevice1", "0") == "6"); - editor.putBoolean("enableController3", getConfig("Dolphin.ini", "Core", "SIDevice2", "0") == "6"); - editor.putBoolean("enableController4", getConfig("Dolphin.ini", "Core", "SIDevice3", "0") == "6"); - - String efbCopyOn = getConfig("GFX.ini", "Hacks", "EFBCopyEnable", "True"); - String efbToTexture = getConfig("GFX.ini", "Hacks", "EFBToTextureEnable", "True"); - String efbCopyCache = getConfig("GFX.ini", "Hacks", "EFBCopyCacheEnable", "False"); - - if (efbCopyOn.equals("False")) - { - editor.putString("efbCopyMethod", "Off"); - } - else if (efbCopyOn.equals("True") && efbToTexture.equals("True")) - { - editor.putString("efbCopyMethod", "Texture"); - } - else if(efbCopyOn.equals("True") && efbToTexture.equals("False") && efbCopyCache.equals("False")) - { - editor.putString("efbCopyMethod", "RAM (uncached)"); - } - else if(efbCopyOn.equals("True") && efbToTexture.equals("False") && efbCopyCache.equals("True")) - { - editor.putString("efbCopyMethod", "RAM (cached)"); - } - - editor.putString("textureCacheAccuracy", getConfig("GFX.ini", "Settings", "SafeTextureCacheColorSamples", "128")); - - String usingXFB = getConfig("GFX.ini", "Settings", "UseXFB", "False"); - String usingRealXFB = getConfig("GFX.ini", "Settings", "UseRealXFB", "False"); - - if (usingXFB.equals("False")) - { - editor.putString("externalFrameBuffer", "Disabled"); - } - else if (usingXFB.equals("True") && usingRealXFB.equals("False")) - { - editor.putString("externalFrameBuffer", "Virtual"); - } - else if (usingXFB.equals("True") && usingRealXFB.equals("True")) - { - editor.putString("externalFrameBuffer", "Real"); - } - - editor.putBoolean("fastDepthCalculation", getConfig("GFX.ini", "Settings", "FastDepthCalc", "True").equals("True")); - editor.putString("aspectRatio", getConfig("GFX.ini", "Settings", "AspectRatio", "0")); - - // Apply the changes. - editor.apply(); - } - - // Small utility method that shortens calls to NativeLibrary.GetConfig. - private static String getConfig(String ini, String section, String key, String defaultValue) - { - return NativeLibrary.GetConfig(ini, section, key, defaultValue); - } - - /** - * Writes the preferences set in the front-end to the Dolphin ini files. - * - * @param ctx The context used to retrieve the user settings. - * */ - public static void SavePrefsToIni(Context ctx) - { - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ctx); - - // Whether or not the user is using dual core. - boolean isUsingDualCore = prefs.getBoolean("dualCorePref", true); - - // Current CPU core being used. Falls back to interpreter upon error. - String currentEmuCore = prefs.getString("cpuCorePref", "0"); - - boolean overclockEnabled = prefs.getBoolean("OverclockEnable", false); - String overclockSetting = prefs.getString("Overclock", "100"); - - // Current GC analog range setup. Falls back to default upon error. - String currentMainRadius0 = prefs.getString("mainRadius0", "100,000000"); - String currentCStickRadius0 = prefs.getString("cStickRadius0", "100,000000"); - String currentInputThres0 = prefs.getString("inputThres0", "90,000000"); - String currentMainRadius1 = prefs.getString("mainRadius1", "100,000000"); - String currentCStickRadius1 = prefs.getString("cStickRadius1", "100,000000"); - String currentInputThres1 = prefs.getString("inputThres1", "90,000000"); - String currentMainRadius2 = prefs.getString("mainRadius2", "100,000000"); - String currentCStickRadius2 = prefs.getString("cStickRadius2", "100,000000"); - String currentInputThres2 = prefs.getString("inputThres2", "90,000000"); - String currentMainRadius3 = prefs.getString("mainRadius3", "100,000000"); - String currentCStickRadius3 = prefs.getString("cStickRadius3", "100,000000"); - String currentInputThres3 = prefs.getString("inputThres3", "90,000000"); - - // Current Wii analog range setup. Falls back to default on error. - String currentTiltRange4 = prefs.getString("tiltRange4", "50,000000"); - String currentTiltRange5 = prefs.getString("tiltRange5", "50,000000"); - String currentTiltRange6 = prefs.getString("tiltRange6", "50,000000"); - String currentTiltRange7 = prefs.getString("tiltRange7", "50,000000"); - - // Current Nunchuk analog range setup. Falls back to default upon error. - String currentNunchukRadius4 = prefs.getString("nunchukRadius4", "100,000000"); - String currentNunchukRange4 = prefs.getString("nunchukRange4", "50,000000"); - String currentNunchukRadius5 = prefs.getString("nunchukRadius5", "100,000000"); - String currentNunchukRange5 = prefs.getString("nunchukRange5", "50,000000"); - String currentNunchukRadius6 = prefs.getString("nunchukRadius6", "100,000000"); - String currentNunchukRange6 = prefs.getString("nunchukRange6", "50,000000"); - String currentNunchukRadius7 = prefs.getString("nunchukRadius7", "100,000000"); - String currentNunchukRange7 = prefs.getString("nunchukRange7", "50,000000"); - - // Current Classic analog range setup. Falls back to 100,000000 upon error. - String currentClassicLRadius4 = prefs.getString("classicLRadius4", "100,000000"); - String currentClassicRRadius4 = prefs.getString("classicRRadius4", "100,000000"); - String currentClassicThres4 = prefs.getString("classicThres4", "90,000000"); - String currentClassicLRadius5 = prefs.getString("classicLRadius5", "100,000000"); - String currentClassicRRadius5 = prefs.getString("classicRRadius5", "100,000000"); - String currentClassicThres5 = prefs.getString("classicThres5", "90,000000"); - String currentClassicLRadius6 = prefs.getString("classicLRadius6", "100,000000"); - String currentClassicRRadius6 = prefs.getString("classicRRadius6", "100,000000"); - String currentClassicThres6 = prefs.getString("classicThres6", "90,000000"); - String currentClassicLRadius7 = prefs.getString("classicLRadius7", "100,000000"); - String currentClassicRRadius7 = prefs.getString("classicRRadius7", "100,000000"); - String currentClassicThres7 = prefs.getString("classicThres7", "90,000000"); - - // Current Guitar analog range setup. Falls back to default upon error. - String currentGuitarRadius4 = prefs.getString("guitarRadius4", "100,000000"); - String currentGuitarRadius5 = prefs.getString("guitarRadius5", "100,000000"); - String currentGuitarRadius6 = prefs.getString("guitarRadius6", "100,000000"); - String currentGuitarRadius7 = prefs.getString("guitarRadius7", "100,000000"); - - // Current Drums modifier Radius setup. Falls back to default upon error. - String currentDrumsRadius4 = prefs.getString("drumsRadius4", "100,000000"); - String currentDrumsRadius5 = prefs.getString("drumsRadius5", "100,000000"); - String currentDrumsRadius6 = prefs.getString("drumsRadius6", "100,000000"); - String currentDrumsRadius7 = prefs.getString("drumsRadius7", "100,000000"); - - // Current Turntable analog range setup. Falls back to default upon error. - String currentTurntableRadius4 = prefs.getString("turntableRadius4", "100,000000"); - String currentTurntableRadius5 = prefs.getString("turntableRadius5", "100,000000"); - String currentTurntableRadius6 = prefs.getString("turntableRadius6", "100,000000"); - String currentTurntableRadius7 = prefs.getString("turntableRadius7", "100,000000"); - - // Current wiimote extension setup. Falls back to no extension upon error. - String currentWiimoteExtension4 = prefs.getString("wiimoteExtension4", "None"); - String currentWiimoteExtension5 = prefs.getString("wiimoteExtension5", "None"); - String currentWiimoteExtension6 = prefs.getString("wiimoteExtension6", "None"); - String currentWiimoteExtension7 = prefs.getString("wiimoteExtension7", "None"); - - // Current video backend being used. Falls back to software rendering upon error. - String currentVideoBackend = prefs.getString("gpuPref", "Software Rendering"); - - // Whether or not FPS will be displayed on-screen. - boolean showingFPS = prefs.getBoolean("showFPS", false); - - // Whether or not to draw on-screen controls. - boolean drawingOnscreenControls = prefs.getBoolean("drawOnscreenControls", true); - - // Whether or not to ignore all EFB access requests from the CPU. - boolean skipEFBAccess = prefs.getBoolean("skipEFBAccess", false); - - // Whether or not to ignore changes to the EFB format. - boolean ignoreFormatChanges = prefs.getBoolean("ignoreFormatChanges", false); - - // EFB copy method to use. - String efbCopyMethod = prefs.getString("efbCopyMethod", "Texture"); - - // Texture cache accuracy. Falls back to "Fast" up error. - String textureCacheAccuracy = prefs.getString("textureCacheAccuracy", "128"); - - // External frame buffer emulation. Falls back to disabled upon error. - String externalFrameBuffer = prefs.getString("externalFrameBuffer", "Disabled"); - - // Whether or not to use fast depth calculation. - boolean useFastDepthCalc = prefs.getBoolean("fastDepthCalculation", true); - - // Aspect ratio selection - String aspectRatio = prefs.getString("aspectRatio", "0"); - - // Internal resolution. Falls back to 1x Native upon error. - String internalResolution = prefs.getString("internalResolution", "2"); - - // FSAA Level. Falls back to 1x upon error. - String FSAALevel = prefs.getString("FSAA", "0"); - - // Anisotropic Filtering Level. Falls back to 1x upon error. - String anisotropicFiltLevel = prefs.getString("anisotropicFiltering", "0"); - - // Post processing shader setting - String postProcessing = prefs.getString("postProcessingShader", ""); - - // Whether or not Scaled EFB copies are used. - boolean usingScaledEFBCopy = prefs.getBoolean("scaledEFBCopy", true); - - // Whether or not per-pixel lighting is used. - boolean usingPerPixelLighting = prefs.getBoolean("perPixelLighting", false); - - // Whether or not texture filtering is being forced. - boolean isForcingTextureFiltering = prefs.getBoolean("forceTextureFiltering", false); - - // Whether or not fog is disabled. - boolean fogIsDisabled = prefs.getBoolean("disableFog", false); - - // Stereoscopy setting - String stereoscopyMode = prefs.getString("stereoscopyMode", "0"); - - // Stereoscopy swap eyes - boolean stereoscopyEyeSwap = prefs.getBoolean("stereoSwapEyes", false); - - // Stereoscopy separation - String stereoscopySeparation = prefs.getString("stereoDepth", "20"); - - // Stereoscopy convergence - String stereoConvergencePercentage = prefs.getString("stereoConvergencePercentage", "100"); - - // Controllers - // Controller 1 never gets disconnected due to touch screen - //boolean enableController1 = prefs.getBoolean("enableController1", true); - boolean enableController2 = prefs.getBoolean("enableController2", false); - boolean enableController3 = prefs.getBoolean("enableController3", false); - boolean enableController4 = prefs.getBoolean("enableController4", false); - - // CPU related Settings - NativeLibrary.SetConfig("Dolphin.ini", "Core", "CPUCore", currentEmuCore); - NativeLibrary.SetConfig("Dolphin.ini", "Core", "CPUThread", isUsingDualCore ? "True" : "False"); - - NativeLibrary.SetConfig("Dolphin.ini", "Core", "OverclockEnable", overclockEnabled ? "True" : "False"); - NativeLibrary.SetConfig("Dolphin.ini", "Core", "Overclock", overclockSetting); - - // GameCube analog ranges Setup - NativeLibrary.SetConfig("GCPadNew.ini", "GCPad1", "Main Stick/Radius", currentMainRadius0); - NativeLibrary.SetConfig("GCPadNew.ini", "GCPad1", "C-Stick/Radius", currentCStickRadius0); - NativeLibrary.SetConfig("GCPadNew.ini", "GCPad1", "Triggers/Threshold", currentInputThres0); - NativeLibrary.SetConfig("GCPadNew.ini", "GCPad2", "Main Stick/Radius", currentMainRadius1); - NativeLibrary.SetConfig("GCPadNew.ini", "GCPad2", "C-Stick/Radius", currentCStickRadius1); - NativeLibrary.SetConfig("GCPadNew.ini", "GCPad2", "Triggers/Threshold", currentInputThres1); - NativeLibrary.SetConfig("GCPadNew.ini", "GCPad3", "Main Stick/Radius", currentMainRadius2); - NativeLibrary.SetConfig("GCPadNew.ini", "GCPad3", "C-Stick/Radius", currentCStickRadius2); - NativeLibrary.SetConfig("GCPadNew.ini", "GCPad3", "Triggers/Threshold", currentInputThres2); - NativeLibrary.SetConfig("GCPadNew.ini", "GCPad4", "Main Stick/Radius", currentMainRadius3); - NativeLibrary.SetConfig("GCPadNew.ini", "GCPad4", "C-Stick/Radius", currentCStickRadius3); - NativeLibrary.SetConfig("GCPadNew.ini", "GCPad4", "Triggers/Threshold", currentInputThres3); - - // Wiimote analog ranges Setup - NativeLibrary.SetConfig("WiimoteNew.ini", "Wiimote1", "Tilt/Modifier/Range", currentTiltRange4); - NativeLibrary.SetConfig("WiimoteNew.ini", "Wiimote2", "Tilt/Modifier/Range", currentTiltRange5); - NativeLibrary.SetConfig("WiimoteNew.ini", "Wiimote3", "Tilt/Modifier/Range", currentTiltRange6); - NativeLibrary.SetConfig("WiimoteNew.ini", "Wiimote4", "Tilt/Modifier/Range", currentTiltRange7); - - // Nunchuk analog ranges Setup - NativeLibrary.SetConfig("WiimoteNew.ini", "Wiimote1", "Nunchuk/Stick/Radius", currentNunchukRadius4); - NativeLibrary.SetConfig("WiimoteNew.ini", "Wiimote1", "Nunchuk/Stick/Radius", currentNunchukRange4); - NativeLibrary.SetConfig("WiimoteNew.ini", "Wiimote2", "Nunchuk/Stick/Radius", currentNunchukRadius5); - NativeLibrary.SetConfig("WiimoteNew.ini", "Wiimote2", "Nunchuk/Stick/Radius", currentNunchukRange5); - NativeLibrary.SetConfig("WiimoteNew.ini", "Wiimote3", "Nunchuk/Stick/Radius", currentNunchukRadius6); - NativeLibrary.SetConfig("WiimoteNew.ini", "Wiimote3", "Nunchuk/Stick/Radius", currentNunchukRange6); - NativeLibrary.SetConfig("WiimoteNew.ini", "Wiimote4", "Nunchuk/Stick/Radius", currentNunchukRadius7); - NativeLibrary.SetConfig("WiimoteNew.ini", "Wiimote4", "Nunchuk/Stick/Radius", currentNunchukRange7); - - // Classic analog ranges Setup - NativeLibrary.SetConfig("WiimoteNew.ini", "Wiimote1", "Classic/Left Stick/Radius", currentClassicLRadius4); - NativeLibrary.SetConfig("WiimoteNew.ini", "Wiimote1", "Classic/Right Stick/Radius", currentClassicRRadius4); - NativeLibrary.SetConfig("WiimoteNew.ini", "Wiimote1", "Classic/Triggers/Threshold", currentClassicThres4); - NativeLibrary.SetConfig("WiimoteNew.ini", "Wiimote2", "Classic/Left Stick/Radius", currentClassicLRadius5); - NativeLibrary.SetConfig("WiimoteNew.ini", "Wiimote2", "Classic/Right Stick/Radius", currentClassicRRadius5); - NativeLibrary.SetConfig("WiimoteNew.ini", "Wiimote2", "Classic/Triggers/Threshold", currentClassicThres5); - NativeLibrary.SetConfig("WiimoteNew.ini", "Wiimote3", "Classic/Left Stick/Radius", currentClassicLRadius6); - NativeLibrary.SetConfig("WiimoteNew.ini", "Wiimote3", "Classic/Right Stick/Radius", currentClassicRRadius6); - NativeLibrary.SetConfig("WiimoteNew.ini", "Wiimote3", "Classic/Triggers/Threshold", currentClassicThres6); - NativeLibrary.SetConfig("WiimoteNew.ini", "Wiimote4", "Classic/Left Stick/Radius", currentClassicLRadius7); - NativeLibrary.SetConfig("WiimoteNew.ini", "Wiimote4", "Classic/Right Stick/Radius", currentClassicRRadius7); - NativeLibrary.SetConfig("WiimoteNew.ini", "Wiimote4", "Classic/Triggers/Threshold", currentClassicThres7); - - // Guitar analog ranges Setup - NativeLibrary.SetConfig("WiimoteNew.ini", "Wiimote1", "Guitar/Stick/Radius", currentGuitarRadius4); - NativeLibrary.SetConfig("WiimoteNew.ini", "Wiimote2", "Guitar/Stick/Radius", currentGuitarRadius5); - NativeLibrary.SetConfig("WiimoteNew.ini", "Wiimote3", "Guitar/Stick/Radius", currentGuitarRadius6); - NativeLibrary.SetConfig("WiimoteNew.ini", "Wiimote4", "Guitar/Stick/Radius", currentGuitarRadius7); - - // Drums analog ranges Setup - NativeLibrary.SetConfig("WiimoteNew.ini", "Wiimote1", "Drums/Stick/Radius", currentDrumsRadius4); - NativeLibrary.SetConfig("WiimoteNew.ini", "Wiimote2", "Drums/Stick/Radius", currentDrumsRadius5); - NativeLibrary.SetConfig("WiimoteNew.ini", "Wiimote3", "Drums/Stick/Radius", currentDrumsRadius6); - NativeLibrary.SetConfig("WiimoteNew.ini", "Wiimote4", "Drums/Stick/Radius", currentDrumsRadius7); - - // Turntable analog ranges Setup - NativeLibrary.SetConfig("WiimoteNew.ini", "Wiimote1", "Turntable/Stick/Radius", currentTurntableRadius4); - NativeLibrary.SetConfig("WiimoteNew.ini", "Wiimote2", "Turntable/Stick/Radius", currentTurntableRadius5); - NativeLibrary.SetConfig("WiimoteNew.ini", "Wiimote3", "Turntable/Stick/Radius", currentTurntableRadius6); - NativeLibrary.SetConfig("WiimoteNew.ini", "Wiimote4", "Turntable/Stick/Radius", currentTurntableRadius7); - - // Wiimote Extension Settings - NativeLibrary.SetConfig("WiimoteNew.ini", "Wiimote1", "Extension", currentWiimoteExtension4); - NativeLibrary.SetConfig("WiimoteNew.ini", "Wiimote2", "Extension", currentWiimoteExtension5); - NativeLibrary.SetConfig("WiimoteNew.ini", "Wiimote3", "Extension", currentWiimoteExtension6); - NativeLibrary.SetConfig("WiimoteNew.ini", "Wiimote4", "Extension", currentWiimoteExtension7); - - // General Video Settings - NativeLibrary.SetConfig("Dolphin.ini", "Core", "GFXBackend", currentVideoBackend); - NativeLibrary.SetConfig("GFX.ini", "Settings", "ShowFPS", showingFPS ? "True" : "False"); - NativeLibrary.SetConfig("Dolphin.ini", "Android", "ScreenControls", drawingOnscreenControls ? "True" : "False"); - - // Video Hack Settings - NativeLibrary.SetConfig("GFX.ini", "Hacks", "EFBAccessEnable", skipEFBAccess ? "False" : "True"); - NativeLibrary.SetConfig("GFX.ini", "Hacks", "EFBEmulateFormatChanges", ignoreFormatChanges ? "True" : "False"); - NativeLibrary.SetConfig("GFX.ini", "Settings", "AspectRatio", aspectRatio); - - // Set EFB Copy Method - if (efbCopyMethod.equals("Off")) - { - NativeLibrary.SetConfig("GFX.ini", "Hacks", "EFBCopyEnable", "False"); - } - else if (efbCopyMethod.equals("Texture")) - { - NativeLibrary.SetConfig("GFX.ini", "Hacks", "EFBCopyEnable", "True"); - NativeLibrary.SetConfig("GFX.ini", "Hacks", "EFBToTextureEnable", "True"); - } - else if (efbCopyMethod.equals("RAM (uncached)")) - { - NativeLibrary.SetConfig("GFX.ini", "Hacks", "EFBCopyEnable", "True"); - NativeLibrary.SetConfig("GFX.ini", "Hacks", "EFBToTextureEnable", "False"); - NativeLibrary.SetConfig("GFX.ini", "Hacks", "EFBCopyCacheEnable", "False"); - } - else if (efbCopyMethod.equals("RAM (cached)")) - { - NativeLibrary.SetConfig("GFX.ini", "Hacks", "EFBCopyEnable", "True"); - NativeLibrary.SetConfig("GFX.ini", "Hacks", "EFBToTextureEnable", "False"); - NativeLibrary.SetConfig("GFX.ini", "Hacks", "EFBCopyCacheEnable", "True"); - } - - // Set texture cache accuracy - NativeLibrary.SetConfig("GFX.ini", "Settings", "SafeTextureCacheColorSamples", textureCacheAccuracy); - - // Set external frame buffer. - if (externalFrameBuffer.equals("Disabled")) - { - NativeLibrary.SetConfig("GFX.ini", "Settings", "UseXFB", "False"); - } - else if (externalFrameBuffer.equals("Virtual")) - { - NativeLibrary.SetConfig("GFX.ini", "Settings", "UseXFB", "True"); - NativeLibrary.SetConfig("GFX.ini", "Settings", "UseRealXFB", "False"); - } - else if (externalFrameBuffer.equals("Real")) - { - NativeLibrary.SetConfig("GFX.ini", "Settings", "UseXFB", "True"); - NativeLibrary.SetConfig("GFX.ini", "Settings", "UseRealXFB", "True"); - } - - NativeLibrary.SetConfig("GFX.ini", "Settings", "FastDepthCalc", useFastDepthCalc ? "True" : "False"); - - //-- Enhancement Settings --// - NativeLibrary.SetConfig("GFX.ini", "Settings", "EFBScale", internalResolution); - NativeLibrary.SetConfig("GFX.ini", "Settings", "MSAA", FSAALevel); - NativeLibrary.SetConfig("GFX.ini", "Enhancements", "MaxAnisotropy", anisotropicFiltLevel); - NativeLibrary.SetConfig("GFX.ini", "Enhancements", "PostProcessingShader", postProcessing); - NativeLibrary.SetConfig("GFX.ini", "Hacks", "EFBScaledCopy", usingScaledEFBCopy ? "True" : "False"); - NativeLibrary.SetConfig("GFX.ini", "Settings", "EnablePixelLighting", usingPerPixelLighting ? "True" : "False"); - NativeLibrary.SetConfig("GFX.ini", "Enhancements", "ForceFiltering", isForcingTextureFiltering ? "True" : "False"); - NativeLibrary.SetConfig("GFX.ini", "Settings", "DisableFog", fogIsDisabled ? "True" : "False"); - NativeLibrary.SetConfig("GFX.ini", "Stereoscopy", "StereoMode", stereoscopyMode); - NativeLibrary.SetConfig("GFX.ini", "Stereoscopy", "StereoSwapEyes", stereoscopyEyeSwap ? "True" : "False"); - NativeLibrary.SetConfig("GFX.ini", "Stereoscopy", "StereoDepth", stereoscopySeparation); - NativeLibrary.SetConfig("GFX.ini", "Stereoscopy", "StereoConvergence", stereoConvergencePercentage); - NativeLibrary.SetConfig("Dolphin.ini", "Core", "SIDevice0", "6"); - NativeLibrary.SetConfig("Dolphin.ini", "Core", "SIDevice1", enableController2 ? "6" : "0"); - NativeLibrary.SetConfig("Dolphin.ini", "Core", "SIDevice2", enableController3 ? "6" : "0"); - NativeLibrary.SetConfig("Dolphin.ini", "Core", "SIDevice3", enableController4 ? "6" : "0"); - } -} |
