Android: Allow editing settings during emulation
This commit is contained in:
parent
736505f020
commit
9c19309a03
|
@ -34,6 +34,8 @@ import androidx.fragment.app.FragmentManager;
|
|||
import org.dolphinemu.dolphinemu.NativeLibrary;
|
||||
import org.dolphinemu.dolphinemu.R;
|
||||
import org.dolphinemu.dolphinemu.features.settings.model.Settings;
|
||||
import org.dolphinemu.dolphinemu.features.settings.ui.MenuTag;
|
||||
import org.dolphinemu.dolphinemu.features.settings.ui.SettingsActivity;
|
||||
import org.dolphinemu.dolphinemu.features.settings.utils.SettingsFile;
|
||||
import org.dolphinemu.dolphinemu.fragments.EmulationFragment;
|
||||
import org.dolphinemu.dolphinemu.fragments.MenuFragment;
|
||||
|
@ -101,7 +103,8 @@ public final class EmulationActivity extends AppCompatActivity
|
|||
MENU_ACTION_LOAD_SLOT6, MENU_ACTION_EXIT, MENU_ACTION_CHANGE_DISC,
|
||||
MENU_ACTION_RESET_OVERLAY, MENU_SET_IR_SENSITIVITY, MENU_ACTION_CHOOSE_DOUBLETAP,
|
||||
MENU_ACTION_SCREEN_ORIENTATION, MENU_ACTION_MOTION_CONTROLS, MENU_ACTION_PAUSE_EMULATION,
|
||||
MENU_ACTION_UNPAUSE_EMULATION, MENU_ACTION_OVERLAY_CONTROLS})
|
||||
MENU_ACTION_UNPAUSE_EMULATION, MENU_ACTION_OVERLAY_CONTROLS, MENU_ACTION_SETTINGS_CORE,
|
||||
MENU_ACTION_SETTINGS_GRAPHICS})
|
||||
public @interface MenuAction
|
||||
{
|
||||
}
|
||||
|
@ -140,6 +143,8 @@ public final class EmulationActivity extends AppCompatActivity
|
|||
public static final int MENU_ACTION_PAUSE_EMULATION = 31;
|
||||
public static final int MENU_ACTION_UNPAUSE_EMULATION = 32;
|
||||
public static final int MENU_ACTION_OVERLAY_CONTROLS = 33;
|
||||
public static final int MENU_ACTION_SETTINGS_CORE = 34;
|
||||
public static final int MENU_ACTION_SETTINGS_GRAPHICS = 35;
|
||||
|
||||
private static SparseIntArray buttonsActionsMap = new SparseIntArray();
|
||||
|
||||
|
@ -648,6 +653,14 @@ public final class EmulationActivity extends AppCompatActivity
|
|||
showMotionControlsOptions();
|
||||
return;
|
||||
|
||||
case MENU_ACTION_SETTINGS_CORE:
|
||||
SettingsActivity.launch(this, MenuTag.CONFIG);
|
||||
return;
|
||||
|
||||
case MENU_ACTION_SETTINGS_GRAPHICS:
|
||||
SettingsActivity.launch(this, MenuTag.GRAPHICS);
|
||||
return;
|
||||
|
||||
case MENU_ACTION_EXIT:
|
||||
mEmulationFragment.stopEmulation();
|
||||
finish();
|
||||
|
|
|
@ -19,6 +19,12 @@ public class AbstractLegacySetting implements AbstractSetting
|
|||
return settings.isGameSpecific() && settings.getSection(mFile, mSection).exists(mKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRuntimeEditable()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean delete(Settings settings)
|
||||
{
|
||||
|
|
|
@ -4,5 +4,7 @@ public interface AbstractSetting
|
|||
{
|
||||
boolean isOverridden(Settings settings);
|
||||
|
||||
boolean isRuntimeEditable();
|
||||
|
||||
boolean delete(Settings settings);
|
||||
}
|
||||
|
|
|
@ -26,6 +26,12 @@ public class AdHocBooleanSetting implements AbstractBooleanSetting
|
|||
return NativeConfig.isOverridden(mFile, mSection, mKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRuntimeEditable()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean delete(Settings settings)
|
||||
{
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
package org.dolphinemu.dolphinemu.features.settings.model;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public enum BooleanSetting implements AbstractBooleanSetting
|
||||
{
|
||||
// These entries have the same names and order as in C++, just for consistency.
|
||||
|
@ -94,6 +98,17 @@ public enum BooleanSetting implements AbstractBooleanSetting
|
|||
MAIN_JIT_REGISTER_CACHE_OFF(Settings.FILE_DOLPHIN, Settings.SECTION_DEBUG, "JitRegisterCacheOff",
|
||||
false);
|
||||
|
||||
private static final BooleanSetting[] NOT_RUNTIME_EDITABLE_ARRAY = new BooleanSetting[]{
|
||||
MAIN_DSP_HLE,
|
||||
MAIN_CPU_THREAD,
|
||||
MAIN_OVERRIDE_REGION_SETTINGS,
|
||||
MAIN_WII_SD_CARD, // Can actually be changed, but specific code is required
|
||||
MAIN_DSP_JIT
|
||||
};
|
||||
|
||||
private static final Set<BooleanSetting> NOT_RUNTIME_EDITABLE =
|
||||
new HashSet<>(Arrays.asList(NOT_RUNTIME_EDITABLE_ARRAY));
|
||||
|
||||
private final String mFile;
|
||||
private final String mSection;
|
||||
private final String mKey;
|
||||
|
@ -116,6 +131,18 @@ public enum BooleanSetting implements AbstractBooleanSetting
|
|||
return NativeConfig.isOverridden(mFile, mSection, mKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRuntimeEditable()
|
||||
{
|
||||
for (BooleanSetting setting : NOT_RUNTIME_EDITABLE)
|
||||
{
|
||||
if (setting == this)
|
||||
return false;
|
||||
}
|
||||
|
||||
return NativeConfig.isSettingSaveable(mFile, mSection, mKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean delete(Settings settings)
|
||||
{
|
||||
|
|
|
@ -29,6 +29,12 @@ public enum FloatSetting implements AbstractFloatSetting
|
|||
return NativeConfig.isOverridden(mFile, mSection, mKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRuntimeEditable()
|
||||
{
|
||||
return NativeConfig.isSettingSaveable(mFile, mSection, mKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean delete(Settings settings)
|
||||
{
|
||||
|
|
|
@ -2,6 +2,10 @@ package org.dolphinemu.dolphinemu.features.settings.model;
|
|||
|
||||
import org.dolphinemu.dolphinemu.NativeLibrary;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public enum IntSetting implements AbstractIntSetting
|
||||
{
|
||||
// These entries have the same names and order as in C++, just for consistency.
|
||||
|
@ -34,6 +38,16 @@ public enum IntSetting implements AbstractIntSetting
|
|||
|
||||
LOGGER_VERBOSITY(Settings.FILE_LOGGER, Settings.SECTION_LOGGER_OPTIONS, "Verbosity", 1);
|
||||
|
||||
private static final IntSetting[] NOT_RUNTIME_EDITABLE_ARRAY = new IntSetting[]{
|
||||
MAIN_CPU_CORE,
|
||||
MAIN_GC_LANGUAGE,
|
||||
MAIN_SLOT_A, // Can actually be changed, but specific code is required
|
||||
MAIN_SLOT_B, // Can actually be changed, but specific code is required
|
||||
};
|
||||
|
||||
private static final Set<IntSetting> NOT_RUNTIME_EDITABLE =
|
||||
new HashSet<>(Arrays.asList(NOT_RUNTIME_EDITABLE_ARRAY));
|
||||
|
||||
private final String mFile;
|
||||
private final String mSection;
|
||||
private final String mKey;
|
||||
|
@ -56,6 +70,18 @@ public enum IntSetting implements AbstractIntSetting
|
|||
return NativeConfig.isOverridden(mFile, mSection, mKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRuntimeEditable()
|
||||
{
|
||||
for (IntSetting setting : NOT_RUNTIME_EDITABLE)
|
||||
{
|
||||
if (setting == this)
|
||||
return false;
|
||||
}
|
||||
|
||||
return NativeConfig.isSettingSaveable(mFile, mSection, mKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean delete(Settings settings)
|
||||
{
|
||||
|
|
|
@ -105,6 +105,10 @@ public class Settings implements Closeable
|
|||
}
|
||||
else
|
||||
{
|
||||
// Loading game INIs while the core is running will mess with the game INIs loaded by the core
|
||||
if (NativeLibrary.IsRunning())
|
||||
throw new IllegalStateException("Attempted to load game INI while emulating");
|
||||
|
||||
NativeConfig.loadGameInis(mGameId, mRevision);
|
||||
loadCustomGameSettings(mGameId, view);
|
||||
}
|
||||
|
@ -155,9 +159,14 @@ public class Settings implements Closeable
|
|||
|
||||
NativeConfig.save(NativeConfig.LAYER_BASE_OR_CURRENT);
|
||||
|
||||
// Notify the native code of the changes
|
||||
NativeLibrary.ReloadConfig();
|
||||
NativeLibrary.ReloadWiimoteConfig();
|
||||
if (!NativeLibrary.IsRunning())
|
||||
{
|
||||
// Notify the native code of the changes to legacy settings
|
||||
NativeLibrary.ReloadConfig();
|
||||
NativeLibrary.ReloadWiimoteConfig();
|
||||
}
|
||||
|
||||
// LogManager does use the new config system, but doesn't pick up on changes automatically
|
||||
NativeLibrary.ReloadLoggerConfig();
|
||||
NativeLibrary.UpdateGCAdapterScanThread();
|
||||
|
||||
|
|
|
@ -2,6 +2,10 @@ package org.dolphinemu.dolphinemu.features.settings.model;
|
|||
|
||||
import org.dolphinemu.dolphinemu.NativeLibrary;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public enum StringSetting implements AbstractStringSetting
|
||||
{
|
||||
// These entries have the same names and order as in C++, just for consistency.
|
||||
|
@ -20,6 +24,13 @@ public enum StringSetting implements AbstractStringSetting
|
|||
GFX_ENHANCE_POST_SHADER(Settings.FILE_GFX, Settings.SECTION_GFX_ENHANCEMENTS,
|
||||
"PostProcessingShader", "");
|
||||
|
||||
private static final StringSetting[] NOT_RUNTIME_EDITABLE_ARRAY = new StringSetting[]{
|
||||
MAIN_GFX_BACKEND,
|
||||
};
|
||||
|
||||
private static final Set<StringSetting> NOT_RUNTIME_EDITABLE =
|
||||
new HashSet<>(Arrays.asList(NOT_RUNTIME_EDITABLE_ARRAY));
|
||||
|
||||
private final String mFile;
|
||||
private final String mSection;
|
||||
private final String mKey;
|
||||
|
@ -42,6 +53,18 @@ public enum StringSetting implements AbstractStringSetting
|
|||
return NativeConfig.isOverridden(mFile, mSection, mKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRuntimeEditable()
|
||||
{
|
||||
for (StringSetting setting : NOT_RUNTIME_EDITABLE)
|
||||
{
|
||||
if (setting == this)
|
||||
return false;
|
||||
}
|
||||
|
||||
return NativeConfig.isSettingSaveable(mFile, mSection, mKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean delete(Settings settings)
|
||||
{
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package org.dolphinemu.dolphinemu.features.settings.model.view;
|
||||
|
||||
import org.dolphinemu.dolphinemu.NativeLibrary;
|
||||
import org.dolphinemu.dolphinemu.features.settings.model.AbstractSetting;
|
||||
import org.dolphinemu.dolphinemu.features.settings.model.Settings;
|
||||
import org.dolphinemu.dolphinemu.features.settings.ui.SettingsAdapter;
|
||||
|
@ -67,4 +68,13 @@ public abstract class SettingsItem
|
|||
AbstractSetting setting = getSetting();
|
||||
return setting != null && setting.isOverridden(settings);
|
||||
}
|
||||
|
||||
public boolean isEditable()
|
||||
{
|
||||
if (!NativeLibrary.IsRunning())
|
||||
return true;
|
||||
|
||||
AbstractSetting setting = getSetting();
|
||||
return setting != null && setting.isRuntimeEditable();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -300,6 +300,13 @@ public final class SettingsFragmentPresenter
|
|||
BooleanSetting.MAIN_DSP_JIT.isOverridden(settings);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRuntimeEditable()
|
||||
{
|
||||
return BooleanSetting.MAIN_DSP_HLE.isRuntimeEditable() &&
|
||||
BooleanSetting.MAIN_DSP_JIT.isRuntimeEditable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean delete(Settings settings)
|
||||
{
|
||||
|
|
|
@ -66,6 +66,12 @@ public final class CheckBoxSettingViewHolder extends SettingViewHolder
|
|||
@Override
|
||||
public void onClick(View clicked)
|
||||
{
|
||||
if (!mItem.isEditable())
|
||||
{
|
||||
showNotRuntimeEditableError();
|
||||
return;
|
||||
}
|
||||
|
||||
mCheckbox.toggle();
|
||||
|
||||
getAdapter().onBooleanClick(mItem, getAdapterPosition(), mCheckbox.isChecked());
|
||||
|
|
|
@ -52,6 +52,12 @@ public final class FilePickerViewHolder extends SettingViewHolder
|
|||
@Override
|
||||
public void onClick(View clicked)
|
||||
{
|
||||
if (!mItem.isEditable())
|
||||
{
|
||||
showNotRuntimeEditableError();
|
||||
return;
|
||||
}
|
||||
|
||||
if (mFilePicker.getRequestType() == MainPresenter.REQUEST_DIRECTORY)
|
||||
{
|
||||
getAdapter().onFilePickerDirectoryClick(mItem);
|
||||
|
|
|
@ -51,6 +51,12 @@ public final class InputBindingSettingViewHolder extends SettingViewHolder
|
|||
@Override
|
||||
public void onClick(View clicked)
|
||||
{
|
||||
if (!mItem.isEditable())
|
||||
{
|
||||
showNotRuntimeEditableError();
|
||||
return;
|
||||
}
|
||||
|
||||
getAdapter().onInputBindingClick(mItem, getAdapterPosition());
|
||||
|
||||
setStyle(mTextSettingName, mItem);
|
||||
|
|
|
@ -51,6 +51,12 @@ public class RumbleBindingViewHolder extends SettingViewHolder
|
|||
@Override
|
||||
public void onClick(View clicked)
|
||||
{
|
||||
if (!mItem.isEditable())
|
||||
{
|
||||
showNotRuntimeEditableError();
|
||||
return;
|
||||
}
|
||||
|
||||
getAdapter().onInputBindingClick(mItem, getAdapterPosition());
|
||||
|
||||
setStyle(mTextSettingName, mItem);
|
||||
|
|
|
@ -1,11 +1,16 @@
|
|||
package org.dolphinemu.dolphinemu.features.settings.ui.viewholder;
|
||||
|
||||
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Typeface;
|
||||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import org.dolphinemu.dolphinemu.DolphinApplication;
|
||||
import org.dolphinemu.dolphinemu.R;
|
||||
import org.dolphinemu.dolphinemu.features.settings.model.view.SettingsItem;
|
||||
import org.dolphinemu.dolphinemu.features.settings.ui.SettingsAdapter;
|
||||
|
||||
|
@ -34,6 +39,15 @@ public abstract class SettingViewHolder extends RecyclerView.ViewHolder
|
|||
{
|
||||
boolean overridden = settingsItem.isOverridden(mAdapter.getSettings());
|
||||
textView.setTypeface(null, overridden ? Typeface.BOLD : Typeface.NORMAL);
|
||||
|
||||
if (!settingsItem.isEditable())
|
||||
textView.setPaintFlags(textView.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);
|
||||
}
|
||||
|
||||
protected static void showNotRuntimeEditableError()
|
||||
{
|
||||
Toast.makeText(DolphinApplication.getAppContext(), R.string.setting_not_runtime_editable,
|
||||
Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -87,6 +87,12 @@ public final class SingleChoiceViewHolder extends SettingViewHolder
|
|||
@Override
|
||||
public void onClick(View clicked)
|
||||
{
|
||||
if (!mItem.isEditable())
|
||||
{
|
||||
showNotRuntimeEditableError();
|
||||
return;
|
||||
}
|
||||
|
||||
int position = getAdapterPosition();
|
||||
if (mItem instanceof SingleChoiceSetting)
|
||||
{
|
||||
|
|
|
@ -56,6 +56,12 @@ public final class SliderViewHolder extends SettingViewHolder
|
|||
@Override
|
||||
public void onClick(View clicked)
|
||||
{
|
||||
if (!mItem.isEditable())
|
||||
{
|
||||
showNotRuntimeEditableError();
|
||||
return;
|
||||
}
|
||||
|
||||
getAdapter().onSliderClick(mItem, getAdapterPosition());
|
||||
|
||||
setStyle(mTextSettingName, mItem);
|
||||
|
|
|
@ -50,6 +50,9 @@ public final class MenuFragment extends Fragment implements View.OnClickListener
|
|||
.append(R.id.menu_screen_orientation, EmulationActivity.MENU_ACTION_SCREEN_ORIENTATION);
|
||||
buttonsActionsMap.append(R.id.menu_change_disc, EmulationActivity.MENU_ACTION_CHANGE_DISC);
|
||||
buttonsActionsMap.append(R.id.menu_exit, EmulationActivity.MENU_ACTION_EXIT);
|
||||
buttonsActionsMap.append(R.id.menu_settings_core, EmulationActivity.MENU_ACTION_SETTINGS_CORE);
|
||||
buttonsActionsMap.append(R.id.menu_settings_graphics,
|
||||
EmulationActivity.MENU_ACTION_SETTINGS_GRAPHICS);
|
||||
}
|
||||
|
||||
public static MenuFragment newInstance(String title)
|
||||
|
@ -83,15 +86,6 @@ public final class MenuFragment extends Fragment implements View.OnClickListener
|
|||
|
||||
updatePauseUnpauseVisibility();
|
||||
|
||||
Settings settings = ((EmulationActivity) getActivity()).getSettings();
|
||||
if (BooleanSetting.MAIN_ENABLE_SAVESTATES.getBoolean(settings))
|
||||
{
|
||||
options.findViewById(R.id.menu_quicksave).setVisibility(View.VISIBLE);
|
||||
options.findViewById(R.id.menu_quickload).setVisibility(View.VISIBLE);
|
||||
options.findViewById(R.id.menu_emulation_save_root).setVisibility(View.VISIBLE);
|
||||
options.findViewById(R.id.menu_emulation_load_root).setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
PackageManager packageManager = requireActivity().getPackageManager();
|
||||
|
||||
if (!packageManager.hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN))
|
||||
|
@ -146,6 +140,22 @@ public final class MenuFragment extends Fragment implements View.OnClickListener
|
|||
return rootView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume()
|
||||
{
|
||||
super.onResume();
|
||||
|
||||
LinearLayout options = requireView().findViewById(R.id.layout_options);
|
||||
|
||||
Settings settings = ((EmulationActivity) requireActivity()).getSettings();
|
||||
boolean savestatesEnabled = BooleanSetting.MAIN_ENABLE_SAVESTATES.getBoolean(settings);
|
||||
int savestateVisibility = savestatesEnabled ? View.VISIBLE : View.GONE;
|
||||
options.findViewById(R.id.menu_quicksave).setVisibility(savestateVisibility);
|
||||
options.findViewById(R.id.menu_quickload).setVisibility(savestateVisibility);
|
||||
options.findViewById(R.id.menu_emulation_save_root).setVisibility(savestateVisibility);
|
||||
options.findViewById(R.id.menu_emulation_load_root).setVisibility(savestateVisibility);
|
||||
}
|
||||
|
||||
private void updatePauseUnpauseVisibility()
|
||||
{
|
||||
boolean paused = EmulationActivity.getHasUserPausedEmulation();
|
||||
|
|
|
@ -30,6 +30,16 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<Button
|
||||
android:id="@+id/menu_settings_core"
|
||||
android:text="@string/grid_menu_config"
|
||||
style="@style/InGameMenuOption"/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/menu_settings_graphics"
|
||||
android:text="@string/grid_menu_graphics_settings"
|
||||
style="@style/InGameMenuOption"/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/menu_pause_emulation"
|
||||
android:text="@string/pause_emulation"
|
||||
|
|
|
@ -378,6 +378,7 @@
|
|||
|
||||
<string name="write_permission_needed">You need to allow write access to external storage for the emulator to work</string>
|
||||
<string name="load_settings">Loading Settings...</string>
|
||||
<string name="setting_not_runtime_editable">This setting can\'t be changed while a game is running.</string>
|
||||
<string name="emulation_change_disc">Change Disc</string>
|
||||
|
||||
<string name="external_storage_not_mounted">The external storage needs to be available in order to use Dolphin</string>
|
||||
|
|
Loading…
Reference in New Issue