Android: Add graphical save/load state selector
This commit is contained in:
parent
b560142015
commit
6ad2b72c2e
|
@ -51,6 +51,8 @@ static jclass s_PatchCode_class;
|
|||
static jmethodID s_PatchCode_constructor;
|
||||
static jclass s_GameListEntry_class;
|
||||
static jmethodID s_GameListEntry_constructor;
|
||||
static jclass s_SaveStateInfo_class;
|
||||
static jmethodID s_SaveStateInfo_constructor;
|
||||
|
||||
namespace AndroidHelpers {
|
||||
// helper for retrieving the current per-thread jni environment
|
||||
|
@ -350,7 +352,7 @@ void AndroidHostInterface::RunOnEmulationThread(std::function<void()> function,
|
|||
m_mutex.unlock();
|
||||
}
|
||||
|
||||
void AndroidHostInterface::RunLater(std::function<void ()> func)
|
||||
void AndroidHostInterface::RunLater(std::function<void()> func)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
m_callback_queue.push_back(std::move(func));
|
||||
|
@ -887,7 +889,7 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* reserved)
|
|||
|
||||
// Create global reference so it doesn't get cleaned up.
|
||||
JNIEnv* env = AndroidHelpers::GetJNIEnv();
|
||||
jclass string_class, host_interface_class, patch_code_class, game_list_entry_class;
|
||||
jclass string_class, host_interface_class, patch_code_class, game_list_entry_class, save_state_info_class;
|
||||
if ((string_class = env->FindClass("java/lang/String")) == nullptr ||
|
||||
(s_String_class = static_cast<jclass>(env->NewGlobalRef(string_class))) == nullptr ||
|
||||
(host_interface_class = env->FindClass("com/github/stenzek/duckstation/AndroidHostInterface")) == nullptr ||
|
||||
|
@ -895,7 +897,9 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* reserved)
|
|||
(patch_code_class = env->FindClass("com/github/stenzek/duckstation/PatchCode")) == nullptr ||
|
||||
(s_PatchCode_class = static_cast<jclass>(env->NewGlobalRef(patch_code_class))) == nullptr ||
|
||||
(game_list_entry_class = env->FindClass("com/github/stenzek/duckstation/GameListEntry")) == nullptr ||
|
||||
(s_GameListEntry_class = static_cast<jclass>(env->NewGlobalRef(game_list_entry_class))) == nullptr)
|
||||
(s_GameListEntry_class = static_cast<jclass>(env->NewGlobalRef(game_list_entry_class))) == nullptr ||
|
||||
(save_state_info_class = env->FindClass("com/github/stenzek/duckstation/SaveStateInfo")) == nullptr ||
|
||||
(s_SaveStateInfo_class = static_cast<jclass>(env->NewGlobalRef(save_state_info_class))) == nullptr)
|
||||
{
|
||||
Log_ErrorPrint("AndroidHostInterface class lookup failed");
|
||||
return -1;
|
||||
|
@ -937,7 +941,11 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* reserved)
|
|||
(s_GameListEntry_constructor = env->GetMethodID(
|
||||
s_GameListEntry_class, "<init>",
|
||||
"(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;JLjava/lang/String;Ljava/lang/"
|
||||
"String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V")) == nullptr)
|
||||
"String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V")) == nullptr ||
|
||||
(s_SaveStateInfo_constructor = env->GetMethodID(
|
||||
s_SaveStateInfo_class, "<init>",
|
||||
"(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;IZII[B)V")) ==
|
||||
nullptr)
|
||||
{
|
||||
Log_ErrorPrint("AndroidHostInterface lookups failed");
|
||||
return -1;
|
||||
|
@ -1574,3 +1582,96 @@ DEFINE_JNI_ARGS_METHOD(jboolean, AndroidHostInterface_setMediaFilename, jstring
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
static jobject CreateSaveStateInfo(JNIEnv* env, const CommonHostInterface::ExtendedSaveStateInfo& ssi)
|
||||
{
|
||||
LocalRefHolder<jstring> path(env, env->NewStringUTF(ssi.path.c_str()));
|
||||
LocalRefHolder<jstring> title(env, env->NewStringUTF(ssi.title.c_str()));
|
||||
LocalRefHolder<jstring> code(env, env->NewStringUTF(ssi.game_code.c_str()));
|
||||
LocalRefHolder<jstring> media_path(env, env->NewStringUTF(ssi.media_path.c_str()));
|
||||
LocalRefHolder<jstring> timestamp(env, env->NewStringUTF(Timestamp::FromUnixTimestamp(ssi.timestamp).ToString("%c")));
|
||||
LocalRefHolder<jbyteArray> screenshot_data;
|
||||
if (!ssi.screenshot_data.empty())
|
||||
{
|
||||
const jsize data_size = static_cast<jsize>(ssi.screenshot_data.size() * sizeof(u32));
|
||||
screenshot_data = LocalRefHolder<jbyteArray>(env, env->NewByteArray(data_size));
|
||||
env->SetByteArrayRegion(screenshot_data.Get(), 0, data_size,
|
||||
reinterpret_cast<const jbyte*>(ssi.screenshot_data.data()));
|
||||
}
|
||||
|
||||
return env->NewObject(s_SaveStateInfo_class, s_SaveStateInfo_constructor, path.Get(), title.Get(), code.Get(),
|
||||
media_path.Get(), timestamp.Get(), static_cast<jint>(ssi.slot),
|
||||
static_cast<jboolean>(ssi.global), static_cast<jint>(ssi.screenshot_width),
|
||||
static_cast<jint>(ssi.screenshot_height), screenshot_data.Get());
|
||||
}
|
||||
|
||||
static jobject CreateEmptySaveStateInfo(JNIEnv* env, s32 slot, bool global)
|
||||
{
|
||||
return env->NewObject(s_SaveStateInfo_class, s_SaveStateInfo_constructor, nullptr, nullptr, nullptr, nullptr, nullptr,
|
||||
static_cast<jint>(slot), static_cast<jboolean>(global), static_cast<jint>(0),
|
||||
static_cast<jint>(0), nullptr);
|
||||
}
|
||||
|
||||
DEFINE_JNI_ARGS_METHOD(jobjectArray, AndroidHostInterface_getSaveStateInfo, jobject obj, jboolean includeEmpty)
|
||||
{
|
||||
if (!System::IsValid())
|
||||
return nullptr;
|
||||
|
||||
AndroidHostInterface* hi = AndroidHelpers::GetNativeClass(env, obj);
|
||||
std::vector<jobject> infos;
|
||||
|
||||
// +1 for the quick save only in android.
|
||||
infos.reserve(1 + CommonHostInterface::PER_GAME_SAVE_STATE_SLOTS + CommonHostInterface::GLOBAL_SAVE_STATE_SLOTS);
|
||||
|
||||
const std::string& game_code = System::GetRunningCode();
|
||||
if (!game_code.empty())
|
||||
{
|
||||
for (u32 i = 0; i <= CommonHostInterface::PER_GAME_SAVE_STATE_SLOTS; i++)
|
||||
{
|
||||
std::optional<CommonHostInterface::ExtendedSaveStateInfo> esi =
|
||||
hi->GetExtendedSaveStateInfo(game_code.c_str(), static_cast<s32>(i));
|
||||
if (esi.has_value())
|
||||
{
|
||||
jobject obj = CreateSaveStateInfo(env, esi.value());
|
||||
if (obj)
|
||||
infos.push_back(obj);
|
||||
}
|
||||
else if (includeEmpty)
|
||||
{
|
||||
jobject obj = CreateEmptySaveStateInfo(env, static_cast<s32>(i), false);
|
||||
if (obj)
|
||||
infos.push_back(obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (u32 i = 1; i <= CommonHostInterface::GLOBAL_SAVE_STATE_SLOTS; i++)
|
||||
{
|
||||
std::optional<CommonHostInterface::ExtendedSaveStateInfo> esi =
|
||||
hi->GetExtendedSaveStateInfo(nullptr, static_cast<s32>(i));
|
||||
if (esi.has_value())
|
||||
{
|
||||
jobject obj = CreateSaveStateInfo(env, esi.value());
|
||||
if (obj)
|
||||
infos.push_back(obj);
|
||||
}
|
||||
else if (includeEmpty)
|
||||
{
|
||||
jobject obj = CreateEmptySaveStateInfo(env, static_cast<s32>(i), true);
|
||||
if (obj)
|
||||
infos.push_back(obj);
|
||||
}
|
||||
}
|
||||
|
||||
if (infos.empty())
|
||||
return nullptr;
|
||||
|
||||
jobjectArray ret = env->NewObjectArray(static_cast<jsize>(infos.size()), s_SaveStateInfo_class, nullptr);
|
||||
for (size_t i = 0; i < infos.size(); i++)
|
||||
{
|
||||
env->SetObjectArrayElement(ret, static_cast<jsize>(i), infos[i]);
|
||||
env->DeleteLocalRef(infos[i]);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -136,6 +136,8 @@ public class AndroidHostInterface {
|
|||
|
||||
public native boolean setMediaFilename(String filename);
|
||||
|
||||
public native SaveStateInfo[] getSaveStateInfo(boolean includeEmpty);
|
||||
|
||||
static {
|
||||
System.loadLibrary("duckstation-native");
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ import android.view.View;
|
|||
import android.view.Window;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.ListView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
@ -41,7 +42,6 @@ public class EmulationActivity extends AppCompatActivity implements SurfaceHolde
|
|||
private boolean mApplySettingsOnSurfaceRestored = false;
|
||||
private String mGameTitle = null;
|
||||
private EmulationSurfaceView mContentView;
|
||||
private int mSaveStateSlot = 0;
|
||||
|
||||
private boolean getBooleanSetting(String key, boolean defaultValue) {
|
||||
return mPreferences.getBoolean(key, defaultValue);
|
||||
|
@ -398,42 +398,36 @@ public class EmulationActivity extends AppCompatActivity implements SurfaceHolde
|
|||
}
|
||||
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
||||
if (mGameTitle != null && !mGameTitle.isEmpty())
|
||||
builder.setTitle(mGameTitle);
|
||||
builder.setItems(R.array.emulation_menu, (dialogInterface, i) -> {
|
||||
switch (i) {
|
||||
case 0: // Quick Load
|
||||
case 0: // Load State
|
||||
{
|
||||
AndroidHostInterface.getInstance().loadState(false, mSaveStateSlot);
|
||||
onMenuClosed();
|
||||
showSaveStateMenu(false);
|
||||
return;
|
||||
}
|
||||
|
||||
case 1: // Quick Save
|
||||
case 1: // Save State
|
||||
{
|
||||
AndroidHostInterface.getInstance().saveState(false, mSaveStateSlot);
|
||||
onMenuClosed();
|
||||
showSaveStateMenu(true);
|
||||
return;
|
||||
}
|
||||
|
||||
case 2: // Save State Slot
|
||||
{
|
||||
showSaveStateSlotMenu();
|
||||
return;
|
||||
}
|
||||
|
||||
case 3: // Toggle Fast Forward
|
||||
case 2: // Toggle Fast Forward
|
||||
{
|
||||
AndroidHostInterface.getInstance().setFastForwardEnabled(!AndroidHostInterface.getInstance().isFastForwardEnabled());
|
||||
onMenuClosed();
|
||||
return;
|
||||
}
|
||||
|
||||
case 4: // More Options
|
||||
case 3: // More Options
|
||||
{
|
||||
showMoreMenu();
|
||||
return;
|
||||
}
|
||||
|
||||
case 5: // Quit
|
||||
case 4: // Quit
|
||||
{
|
||||
mStopRequested = true;
|
||||
finish();
|
||||
|
@ -445,15 +439,34 @@ public class EmulationActivity extends AppCompatActivity implements SurfaceHolde
|
|||
builder.create().show();
|
||||
}
|
||||
|
||||
private void showSaveStateSlotMenu() {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
||||
builder.setSingleChoiceItems(R.array.emulation_save_state_slot_menu, mSaveStateSlot, (dialogInterface, i) -> {
|
||||
mSaveStateSlot = i;
|
||||
dialogInterface.dismiss();
|
||||
private void showSaveStateMenu(boolean saving) {
|
||||
final SaveStateInfo[] infos = AndroidHostInterface.getInstance().getSaveStateInfo(true);
|
||||
if (infos == null) {
|
||||
onMenuClosed();
|
||||
return;
|
||||
}
|
||||
|
||||
final AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
||||
final ListView listView = new ListView(this);
|
||||
listView.setAdapter(new SaveStateInfo.ListAdapter(this, infos));
|
||||
builder.setView(listView);
|
||||
builder.setOnDismissListener((dialog) -> {
|
||||
onMenuClosed();
|
||||
});
|
||||
builder.setOnCancelListener(dialogInterface -> onMenuClosed());
|
||||
builder.create().show();
|
||||
|
||||
final AlertDialog dialog = builder.create();
|
||||
|
||||
listView.setOnItemClickListener((parent, view, position, id) -> {
|
||||
SaveStateInfo info = infos[position];
|
||||
if (saving) {
|
||||
AndroidHostInterface.getInstance().saveState(info.isGlobal(), info.getSlot());
|
||||
} else {
|
||||
AndroidHostInterface.getInstance().loadState(info.isGlobal(), info.getSlot());
|
||||
}
|
||||
dialog.dismiss();
|
||||
});
|
||||
|
||||
dialog.show();
|
||||
}
|
||||
|
||||
private void showMoreMenu() {
|
||||
|
|
|
@ -298,7 +298,7 @@ public class GameDirectoriesActivity extends AppCompatActivity {
|
|||
.setTitle(R.string.edit_game_directories_add_path)
|
||||
.setMessage(R.string.edit_game_directories_add_path_summary)
|
||||
.setView(text)
|
||||
.setPositiveButton("Add", (dialog, which) -> {
|
||||
.setPositiveButton("Add", (dialog, which) -> {
|
||||
final String path = text.getText().toString();
|
||||
if (!path.isEmpty()) {
|
||||
addSearchDirectory(GameDirectoriesActivity.this, path, true);
|
||||
|
|
|
@ -0,0 +1,151 @@
|
|||
package com.github.stenzek.duckstation;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.BaseAdapter;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
public class SaveStateInfo {
|
||||
private String mPath;
|
||||
private String mGameTitle;
|
||||
private String mGameCode;
|
||||
private String mMediaPath;
|
||||
private String mTimestamp;
|
||||
private int mSlot;
|
||||
private boolean mGlobal;
|
||||
private Bitmap mScreenshot;
|
||||
|
||||
public SaveStateInfo(String path, String gameTitle, String gameCode, String mediaPath, String timestamp, int slot, boolean global,
|
||||
int screenshotWidth, int screenshotHeight, byte[] screenshotData) {
|
||||
mPath = path;
|
||||
mGameTitle = gameTitle;
|
||||
mGameCode = gameCode;
|
||||
mMediaPath = mediaPath;
|
||||
mTimestamp = timestamp;
|
||||
mSlot = slot;
|
||||
mGlobal = global;
|
||||
|
||||
if (screenshotData != null) {
|
||||
try {
|
||||
mScreenshot = Bitmap.createBitmap(screenshotWidth, screenshotHeight, Bitmap.Config.ARGB_8888);
|
||||
mScreenshot.copyPixelsFromBuffer(ByteBuffer.wrap(screenshotData));
|
||||
} catch (Exception e) {
|
||||
mScreenshot = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean exists() {
|
||||
return mPath != null;
|
||||
}
|
||||
|
||||
public String getPath() {
|
||||
return mPath;
|
||||
}
|
||||
|
||||
public String getGameTitle() {
|
||||
return mGameTitle;
|
||||
}
|
||||
|
||||
public String getGameCode() {
|
||||
return mGameCode;
|
||||
}
|
||||
|
||||
public String getMediaPath() {
|
||||
return mMediaPath;
|
||||
}
|
||||
|
||||
public String getTimestamp() {
|
||||
return mTimestamp;
|
||||
}
|
||||
|
||||
public int getSlot() {
|
||||
return mSlot;
|
||||
}
|
||||
|
||||
public boolean isGlobal() {
|
||||
return mGlobal;
|
||||
}
|
||||
|
||||
public Bitmap getScreenshot() {
|
||||
return mScreenshot;
|
||||
}
|
||||
|
||||
private void fillView(Context context, View view) {
|
||||
ImageView imageView = (ImageView) view.findViewById(R.id.image);
|
||||
TextView summaryView = (TextView) view.findViewById(R.id.summary);
|
||||
TextView gameView = (TextView) view.findViewById(R.id.game);
|
||||
TextView pathView = (TextView) view.findViewById(R.id.path);
|
||||
TextView timestampView = (TextView) view.findViewById(R.id.timestamp);
|
||||
|
||||
if (mScreenshot != null)
|
||||
imageView.setImageBitmap(mScreenshot);
|
||||
else
|
||||
imageView.setImageDrawable(context.getDrawable(R.drawable.ic_baseline_not_interested_60));
|
||||
|
||||
String summaryText;
|
||||
if (mGlobal)
|
||||
summaryView.setText(String.format(context.getString(R.string.save_state_info_global_save_n), mSlot));
|
||||
else if (mSlot == 0)
|
||||
summaryView.setText(R.string.save_state_info_quick_save);
|
||||
else
|
||||
summaryView.setText(String.format(context.getString(R.string.save_state_info_game_save_n), mSlot));
|
||||
|
||||
if (exists()) {
|
||||
gameView.setText(String.format("%s - %s", mGameCode, mGameTitle));
|
||||
|
||||
int lastSlashPosition = mMediaPath.lastIndexOf('/');
|
||||
if (lastSlashPosition >= 0)
|
||||
pathView.setText(mMediaPath.substring(lastSlashPosition + 1));
|
||||
else
|
||||
pathView.setText(mMediaPath);
|
||||
|
||||
timestampView.setText(mTimestamp);
|
||||
} else {
|
||||
gameView.setText(R.string.save_state_info_slot_is_empty);
|
||||
pathView.setText("");
|
||||
timestampView.setText("");
|
||||
}
|
||||
}
|
||||
|
||||
public static class ListAdapter extends BaseAdapter {
|
||||
private final Context mContext;
|
||||
private final SaveStateInfo[] mInfos;
|
||||
|
||||
public ListAdapter(Context context, SaveStateInfo[] infos) {
|
||||
mContext = context;
|
||||
mInfos = infos;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return mInfos.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getItem(int position) {
|
||||
return mInfos[position];
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getItemId(int position) {
|
||||
return position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
if (convertView == null) {
|
||||
convertView = LayoutInflater.from(mContext).inflate(R.layout.save_state_view_entry, parent, false);
|
||||
}
|
||||
|
||||
mInfos[position].fillView(mContext, convertView);
|
||||
return convertView;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
<vector android:height="60dp" android:tint="?attr/colorControlNormal"
|
||||
android:viewportHeight="24" android:viewportWidth="24"
|
||||
android:width="60dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="@android:color/white" android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.42,0 -8,-3.58 -8,-8 0,-1.85 0.63,-3.55 1.69,-4.9L16.9,18.31C15.55,19.37 13.85,20 12,20zM18.31,16.9L7.1,5.69C8.45,4.63 10.15,4 12,4c4.42,0 8,3.58 8,8 0,1.85 -0.63,3.55 -1.69,4.9z"/>
|
||||
</vector>
|
|
@ -0,0 +1,66 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/linearLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/image"
|
||||
android:layout_width="80dp"
|
||||
android:layout_height="60dp"
|
||||
android:layout_marginTop="20dp"
|
||||
android:layout_marginBottom="4dp"
|
||||
android:layout_marginLeft="15dp"
|
||||
android:layout_alignParentTop="true"
|
||||
android:scaleType="fitXY"
|
||||
tools:srcCompat="@drawable/ic_media_cdrom" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/summary"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="15dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:text="Game Slot 1"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_toRightOf="@id/image" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/game"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="15dp"
|
||||
android:layout_marginTop="0dp"
|
||||
android:text="SCES-0000 - Game Name"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||
android:layout_below="@id/summary"
|
||||
android:layout_toRightOf="@id/image" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/path"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="15dp"
|
||||
android:layout_marginTop="0dp"
|
||||
android:text="Dump Name.chd"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||
android:layout_below="@id/game"
|
||||
android:layout_toRightOf="@id/image" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/timestamp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="15dp"
|
||||
android:layout_marginTop="0dp"
|
||||
android:layout_marginBottom="14dp"
|
||||
android:text="Saved at Timestamp"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||
android:layout_below="@id/path"
|
||||
android:layout_toRightOf="@id/image" />
|
||||
|
||||
</RelativeLayout>
|
|
@ -81,7 +81,6 @@
|
|||
<string-array name="emulation_menu">
|
||||
<item>Cargar Estado</item>
|
||||
<item>Guardar Estado</item>
|
||||
<item>Guardar Estado en Ranura</item>
|
||||
<item>Activar Avance Rápido</item>
|
||||
<item>Más Opciones</item>
|
||||
<item>Salir</item>
|
||||
|
@ -94,19 +93,6 @@
|
|||
<item>Cambiar Control de Pantalla Tactil</item>
|
||||
<item>Editar Diseño del Control de Pantalla Tactil</item>
|
||||
</string-array>
|
||||
<string-array name="emulation_save_state_slot_menu">
|
||||
<item>Ranura Rápida</item>
|
||||
<item>Ranura 1</item>
|
||||
<item>Ranura 2</item>
|
||||
<item>Ranura 3</item>
|
||||
<item>Ranura 4</item>
|
||||
<item>Ranura 5</item>
|
||||
<item>Ranura 6</item>
|
||||
<item>Ranura 7</item>
|
||||
<item>Ranura 8</item>
|
||||
<item>Ranura 9</item>
|
||||
<item>Ranura 10</item>
|
||||
</string-array>
|
||||
<string-array name="settings_cdrom_read_speedup_entries">
|
||||
<item>Ninguno (Velocidad Doble)</item>
|
||||
<item>2x (Velocidad Cuádruple)</item>
|
||||
|
|
|
@ -81,7 +81,6 @@
|
|||
<string-array name="emulation_menu">
|
||||
<item>Carica Stato</item>
|
||||
<item>Salva Stato</item>
|
||||
<item>Slot Salvataggio Stato</item>
|
||||
<item>Abilita/Disabilita Avanti Veloce</item>
|
||||
<item>Altre Opzioni</item>
|
||||
<item>Esci</item>
|
||||
|
@ -94,19 +93,6 @@
|
|||
<item>Cambia Controller Touchscreen</item>
|
||||
<item>Edit Touchscreen Controller Layout</item>
|
||||
</string-array>
|
||||
<string-array name="emulation_save_state_slot_menu">
|
||||
<item>Slot Veloce</item>
|
||||
<item>Slot Gioco 1</item>
|
||||
<item>Slot Gioco 2</item>
|
||||
<item>Slot Gioco 3</item>
|
||||
<item>Slot Gioco 4</item>
|
||||
<item>Slot Gioco 5</item>
|
||||
<item>Slot Gioco 6</item>
|
||||
<item>Slot Gioco 7</item>
|
||||
<item>Slot Gioco 8</item>
|
||||
<item>Slot Gioco 9</item>
|
||||
<item>Slot Gioco 10</item>
|
||||
</string-array>
|
||||
<string-array name="settings_cdrom_read_speedup_entries">
|
||||
<item>Nessuna Velocità Doppia)</item>
|
||||
<item>2x (Velocità Quadrupla</item>
|
||||
|
|
|
@ -81,7 +81,6 @@
|
|||
<string-array name="emulation_menu">
|
||||
<item>Staat Laden</item>
|
||||
<item>Staat Opslaan</item>
|
||||
<item>Staat Nummer</item>
|
||||
<item>Doorspoelen aan/uitzetten</item>
|
||||
<item>Meer Opties</item>
|
||||
<item>Afsluiten</item>
|
||||
|
@ -94,19 +93,6 @@
|
|||
<item>Touchscreen Controller Aanpassen</item>
|
||||
<item>Edit Touchscreen Controller Layout</item>
|
||||
</string-array>
|
||||
<string-array name="emulation_save_state_slot_menu">
|
||||
<item>Snel Slot</item>
|
||||
<item>Game Slot 1</item>
|
||||
<item>Game Slot 2</item>
|
||||
<item>Game Slot 3</item>
|
||||
<item>Game Slot 4</item>
|
||||
<item>Game Slot 5</item>
|
||||
<item>Game Slot 6</item>
|
||||
<item>Game Slot 7</item>
|
||||
<item>Game Slot 8</item>
|
||||
<item>Game Slot 9</item>
|
||||
<item>Game Slot 10</item>
|
||||
</string-array>
|
||||
<string-array name="settings_cdrom_read_speedup_entries">
|
||||
<item>Geen (Dubbele Snelheid)</item>
|
||||
<item>2x (Vierdubbele Snelheid)</item>
|
||||
|
|
|
@ -81,7 +81,6 @@
|
|||
<string-array name="emulation_menu">
|
||||
<item>Carregar Estado</item>
|
||||
<item>Salvar Estado</item>
|
||||
<item>Salvar para Compartimento</item>
|
||||
<item>Avanço (Fixo)</item>
|
||||
<item>Mais Opções</item>
|
||||
<item>Sair</item>
|
||||
|
@ -94,19 +93,6 @@
|
|||
<item>Mudar controle em Tela</item>
|
||||
<item>Editar Posição dos Controles (Tela)</item>
|
||||
</string-array>
|
||||
<string-array name="emulation_save_state_slot_menu">
|
||||
<item>Armazenamento Rápido</item>
|
||||
<item>Armazenamento 1</item>
|
||||
<item>Armazenamento 2</item>
|
||||
<item>Armazenamento 3</item>
|
||||
<item>Armazenamento 4</item>
|
||||
<item>Armazenamento 5</item>
|
||||
<item>Armazenamento 6</item>
|
||||
<item>Armazenamento 7</item>
|
||||
<item>Armazenamento 8</item>
|
||||
<item>Armazenamento 9</item>
|
||||
<item>Armazenamento 10</item>
|
||||
</string-array>
|
||||
<string-array name="settings_cdrom_read_speedup_entries">
|
||||
<item>Nenhum</item>
|
||||
<item>2x (4x Veloz)</item>
|
||||
|
|
|
@ -81,7 +81,6 @@
|
|||
<string-array name="emulation_menu">
|
||||
<item>Загрузить состояние</item>
|
||||
<item>Сохранить состояние</item>
|
||||
<item>Слот сохранения</item>
|
||||
<item>Включить ускорение</item>
|
||||
<item>Другие опции</item>
|
||||
<item>Выход</item>
|
||||
|
|
|
@ -160,7 +160,6 @@
|
|||
<string-array name="emulation_menu">
|
||||
<item>Load State</item>
|
||||
<item>Save State</item>
|
||||
<item>Save State Slot</item>
|
||||
<item>Toggle Fast Forward</item>
|
||||
<item>More Options</item>
|
||||
<item>Quit</item>
|
||||
|
@ -173,19 +172,6 @@
|
|||
<item>Change Touchscreen Controller</item>
|
||||
<item>Edit Touchscreen Controller Layout</item>
|
||||
</string-array>
|
||||
<string-array name="emulation_save_state_slot_menu">
|
||||
<item>Quick Slot</item>
|
||||
<item>Game Slot 1</item>
|
||||
<item>Game Slot 2</item>
|
||||
<item>Game Slot 3</item>
|
||||
<item>Game Slot 4</item>
|
||||
<item>Game Slot 5</item>
|
||||
<item>Game Slot 6</item>
|
||||
<item>Game Slot 7</item>
|
||||
<item>Game Slot 8</item>
|
||||
<item>Game Slot 9</item>
|
||||
<item>Game Slot 10</item>
|
||||
</string-array>
|
||||
<string-array name="settings_cdrom_read_speedup_entries">
|
||||
<item>None (Double Speed)</item>
|
||||
<item>2x (Quad Speed)</item>
|
||||
|
|
|
@ -206,4 +206,8 @@
|
|||
<string name="menu_edit_game_directories_add_path">Add Path</string>
|
||||
<string name="edit_game_directories_add_path">Add Path</string>
|
||||
<string name="edit_game_directories_add_path_summary">Enter the full path to the directory with games.\n\nYou can get this from a file manager app.\n\nExample: /storage/emulated/0/games</string>
|
||||
<string name="save_state_info_slot_is_empty">Slot Is Empty</string>
|
||||
<string name="save_state_info_game_save_n">Game Save %d</string>
|
||||
<string name="save_state_info_global_save_n">Global Save %d</string>
|
||||
<string name="save_state_info_quick_save">Quick Save</string>
|
||||
</resources>
|
||||
|
|
Loading…
Reference in New Issue