mirror of
https://github.com/Lime3DS/Lime3DS.git
synced 2025-01-09 00:20:39 +01:00
android: Implemented custom layout customization GUI
This commit also changes the name of the 'Portrait' landscape layout to 'Original' Co-authored-by: OpenSauce04 <opensauce04@gmail.com>
This commit is contained in:
parent
7e5b83f126
commit
862fda4332
@ -156,11 +156,10 @@ object NativeLibrary {
|
||||
external fun getPerfStats(): DoubleArray
|
||||
|
||||
/**
|
||||
* Notifies the core emulation that the orientation has changed.
|
||||
* Notifies the core emulation that the layout should be updated
|
||||
*/
|
||||
external fun notifyOrientationChange(layoutOption: Int, rotation: Int, isPortrait: Boolean)
|
||||
external fun updateFramebuffer(isPortrait: Boolean)
|
||||
|
||||
external fun notifyPortraitLayoutChange(layoutOption: Int, rotation: Int, isPortrait: Boolean)
|
||||
/**
|
||||
* Swaps the top and bottom screens.
|
||||
*/
|
||||
@ -263,14 +262,6 @@ object NativeLibrary {
|
||||
get() = LimeApplication.appContext.resources.configuration.orientation ==
|
||||
Configuration.ORIENTATION_PORTRAIT
|
||||
|
||||
@Keep
|
||||
@JvmStatic
|
||||
fun landscapeScreenLayout(): Int = EmulationMenuSettings.landscapeScreenLayout
|
||||
|
||||
@Keep
|
||||
@JvmStatic
|
||||
fun portraitScreenLayout(): Int = EmulationMenuSettings.portraitScreenLayout
|
||||
|
||||
@Keep
|
||||
@JvmStatic
|
||||
fun displayAlertMsg(title: String, message: String, yesNo: Boolean): Boolean {
|
||||
|
@ -1,17 +0,0 @@
|
||||
// Copyright 2023 Citra Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
package io.github.lime3ds.android.display
|
||||
|
||||
enum class PortraitScreenLayout(val int: Int) {
|
||||
// These must match what is defined in src/common/settings.h
|
||||
TOP_FULL_WIDTH(0),
|
||||
CUSTOM_PORTRAIT_LAYOUT(1);
|
||||
|
||||
companion object {
|
||||
fun from(int: Int): PortraitScreenLayout {
|
||||
return entries.firstOrNull { it.int == int } ?: TOP_FULL_WIDTH;
|
||||
}
|
||||
}
|
||||
}
|
@ -3,7 +3,6 @@
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
package io.github.lime3ds.android.display
|
||||
|
||||
import android.view.WindowManager
|
||||
import io.github.lime3ds.android.NativeLibrary
|
||||
import io.github.lime3ds.android.features.settings.model.BooleanSetting
|
||||
@ -26,40 +25,35 @@ class ScreenAdjustmentUtil(
|
||||
BooleanSetting.SWAP_SCREEN.boolean = isEnabled
|
||||
settings.saveSetting(BooleanSetting.SWAP_SCREEN, SettingsFile.FILE_NAME_CONFIG)
|
||||
}
|
||||
|
||||
// TODO: Consider how cycling should handle custom layout
|
||||
// right now it simply skips it
|
||||
fun cycleLayouts() {
|
||||
val nextLayout = if (NativeLibrary.isPortraitMode) {
|
||||
(EmulationMenuSettings.portraitScreenLayout + 1) % (PortraitScreenLayout.entries.size - 1)
|
||||
// TODO: figure out how to pull these from R.array
|
||||
val landscape_values = intArrayOf(6,1,3,4,0,5);
|
||||
val portrait_values = intArrayOf(0,1);
|
||||
if (NativeLibrary.isPortraitMode) {
|
||||
val current_layout = IntSetting.PORTRAIT_SCREEN_LAYOUT.int
|
||||
val pos = portrait_values.indexOf(current_layout)
|
||||
val layout_option = portrait_values[(pos + 1) % portrait_values.size]
|
||||
changePortraitOrientation(layout_option)
|
||||
} else {
|
||||
(EmulationMenuSettings.landscapeScreenLayout + 1) % (ScreenLayout.entries.size - 1)
|
||||
val current_layout = IntSetting.SCREEN_LAYOUT.int
|
||||
val pos = landscape_values.indexOf(current_layout)
|
||||
val layout_option = landscape_values[(pos + 1) % landscape_values.size]
|
||||
changeScreenOrientation(layout_option)
|
||||
}
|
||||
settings.loadSettings()
|
||||
|
||||
changeScreenOrientation(nextLayout)
|
||||
}
|
||||
|
||||
fun changePortraitOrientation(layoutOption: Int) {
|
||||
EmulationMenuSettings.portraitScreenLayout = layoutOption
|
||||
NativeLibrary.notifyPortraitLayoutChange(
|
||||
EmulationMenuSettings.portraitScreenLayout,
|
||||
windowManager.defaultDisplay.rotation,
|
||||
NativeLibrary::isPortraitMode.get()
|
||||
)
|
||||
IntSetting.PORTRAIT_SCREEN_LAYOUT.int = layoutOption
|
||||
settings.saveSetting(IntSetting.PORTRAIT_SCREEN_LAYOUT, SettingsFile.FILE_NAME_CONFIG)
|
||||
NativeLibrary.reloadSettings()
|
||||
NativeLibrary.updateFramebuffer(NativeLibrary.isPortraitMode)
|
||||
}
|
||||
|
||||
fun changeScreenOrientation(layoutOption: Int) {
|
||||
EmulationMenuSettings.landscapeScreenLayout = layoutOption
|
||||
NativeLibrary.notifyOrientationChange(
|
||||
EmulationMenuSettings.landscapeScreenLayout,
|
||||
windowManager.defaultDisplay.rotation,
|
||||
NativeLibrary::isPortraitMode.get()
|
||||
)
|
||||
IntSetting.SCREEN_LAYOUT.int = layoutOption
|
||||
settings.saveSetting(IntSetting.SCREEN_LAYOUT, SettingsFile.FILE_NAME_CONFIG)
|
||||
|
||||
NativeLibrary.reloadSettings()
|
||||
NativeLibrary.updateFramebuffer(NativeLibrary.isPortraitMode)
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ package io.github.lime3ds.android.display
|
||||
|
||||
enum class ScreenLayout(val int: Int) {
|
||||
// These must match what is defined in src/common/settings.h
|
||||
TOP_BOTTOM(0),
|
||||
ORIGINAL(0),
|
||||
SINGLE_SCREEN(1),
|
||||
LARGE_SCREEN(2),
|
||||
SIDE_SCREEN(3),
|
||||
@ -21,3 +21,15 @@ enum class ScreenLayout(val int: Int) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum class PortraitScreenLayout(val int: Int) {
|
||||
// These must match what is defined in src/common/settings.h
|
||||
TOP_FULL_WIDTH(0),
|
||||
CUSTOM_PORTRAIT_LAYOUT(1);
|
||||
|
||||
companion object {
|
||||
fun from(int: Int): PortraitScreenLayout {
|
||||
return entries.firstOrNull { it.int == int } ?: TOP_FULL_WIDTH;
|
||||
}
|
||||
}
|
||||
}
|
@ -23,7 +23,23 @@ enum class IntSetting(
|
||||
CARDBOARD_X_SHIFT("cardboard_x_shift", Settings.SECTION_LAYOUT, 0),
|
||||
CARDBOARD_Y_SHIFT("cardboard_y_shift", Settings.SECTION_LAYOUT, 0),
|
||||
SCREEN_LAYOUT("layout_option", Settings.SECTION_LAYOUT, 0),
|
||||
LANDSCAPE_TOP_X("custom_top_x",Settings.SECTION_LAYOUT,0),
|
||||
LANDSCAPE_TOP_Y("custom_top_y",Settings.SECTION_LAYOUT,0),
|
||||
LANDSCAPE_TOP_WIDTH("custom_top_width",Settings.SECTION_LAYOUT,800),
|
||||
LANDSCAPE_TOP_HEIGHT("custom_top_height",Settings.SECTION_LAYOUT,480),
|
||||
LANDSCAPE_BOTTOM_X("custom_bottom_x",Settings.SECTION_LAYOUT,80),
|
||||
LANDSCAPE_BOTTOM_Y("custom_bottom_y",Settings.SECTION_LAYOUT,480),
|
||||
LANDSCAPE_BOTTOM_WIDTH("custom_bottom_width",Settings.SECTION_LAYOUT,640),
|
||||
LANDSCAPE_BOTTOM_HEIGHT("custom_bottom_height",Settings.SECTION_LAYOUT,480),
|
||||
PORTRAIT_SCREEN_LAYOUT("portrait_layout_option",Settings.SECTION_LAYOUT,0),
|
||||
PORTRAIT_TOP_X("custom_portrait_top_x",Settings.SECTION_LAYOUT,0),
|
||||
PORTRAIT_TOP_Y("custom_portrait_top_y",Settings.SECTION_LAYOUT,0),
|
||||
PORTRAIT_TOP_WIDTH("custom_portrait_top_width",Settings.SECTION_LAYOUT,800),
|
||||
PORTRAIT_TOP_HEIGHT("custom_portrait_top_height",Settings.SECTION_LAYOUT,480),
|
||||
PORTRAIT_BOTTOM_X("custom_portrait_bottom_x",Settings.SECTION_LAYOUT,80),
|
||||
PORTRAIT_BOTTOM_Y("custom_portrait_bottom_y",Settings.SECTION_LAYOUT,480),
|
||||
PORTRAIT_BOTTOM_WIDTH("custom_portrait_bottom_width",Settings.SECTION_LAYOUT,640),
|
||||
PORTRAIT_BOTTOM_HEIGHT("custom_portrait_bottom_height",Settings.SECTION_LAYOUT,480),
|
||||
AUDIO_INPUT_TYPE("output_type", Settings.SECTION_AUDIO, 0),
|
||||
NEW_3DS("is_new_3ds", Settings.SECTION_SYSTEM, 1),
|
||||
LLE_APPLETS("lle_applets", Settings.SECTION_SYSTEM, 0),
|
||||
|
@ -109,6 +109,8 @@ class Settings {
|
||||
const val SECTION_AUDIO = "Audio"
|
||||
const val SECTION_DEBUG = "Debugging"
|
||||
const val SECTION_THEME = "Theme"
|
||||
const val SECTION_CUSTOM_LANDSCAPE = "Custom Landscape Layout"
|
||||
const val SECTION_CUSTOM_PORTRAIT = "Custom Portrait Layout"
|
||||
|
||||
const val KEY_BUTTON_A = "button_a"
|
||||
const val KEY_BUTTON_B = "button_b"
|
||||
|
@ -7,6 +7,7 @@ package io.github.lime3ds.android.features.settings.ui
|
||||
import android.os.Bundle
|
||||
import android.text.TextUtils
|
||||
import io.github.lime3ds.android.NativeLibrary
|
||||
import io.github.lime3ds.android.features.settings.model.IntSetting
|
||||
import io.github.lime3ds.android.features.settings.model.Settings
|
||||
import io.github.lime3ds.android.utils.SystemSaveGame
|
||||
import io.github.lime3ds.android.utils.DirectoryInitialization
|
||||
@ -56,6 +57,9 @@ class SettingsActivityPresenter(private val activityView: SettingsActivityView)
|
||||
Log.debug("[SettingsActivity] Settings activity stopping. Saving settings to INI...")
|
||||
settings.saveSettings(activityView)
|
||||
SystemSaveGame.save()
|
||||
//added to ensure that layout changes take effect as soon as settings window closes
|
||||
NativeLibrary.reloadSettings()
|
||||
NativeLibrary.updateFramebuffer(NativeLibrary.isPortraitMode)
|
||||
}
|
||||
NativeLibrary.reloadSettings()
|
||||
}
|
||||
|
@ -7,13 +7,16 @@ package io.github.lime3ds.android.features.settings.ui
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.content.DialogInterface
|
||||
import android.graphics.Color
|
||||
import android.icu.util.Calendar
|
||||
import android.icu.util.TimeZone
|
||||
import android.text.Editable
|
||||
import android.text.InputFilter
|
||||
import android.text.TextWatcher
|
||||
import android.text.format.DateFormat
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import android.widget.TextView
|
||||
import android.widget.EditText
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.widget.doOnTextChanged
|
||||
@ -22,6 +25,8 @@ import androidx.recyclerview.widget.RecyclerView
|
||||
import com.google.android.material.datepicker.MaterialDatePicker
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import com.google.android.material.slider.Slider
|
||||
import com.google.android.material.textfield.TextInputEditText
|
||||
import com.google.android.material.textfield.TextInputLayout
|
||||
import com.google.android.material.timepicker.MaterialTimePicker
|
||||
import com.google.android.material.timepicker.TimeFormat
|
||||
import io.github.lime3ds.android.R
|
||||
@ -73,7 +78,8 @@ class SettingsAdapter(
|
||||
private var clickedPosition: Int
|
||||
private var dialog: AlertDialog? = null
|
||||
private var sliderProgress = 0
|
||||
private var textSliderValue: TextView? = null
|
||||
private var textSliderValue: TextInputEditText? = null
|
||||
private var textInputLayout: TextInputLayout? = null
|
||||
private var textInputValue: String = ""
|
||||
|
||||
private var defaultCancelListener =
|
||||
@ -256,18 +262,36 @@ class SettingsAdapter(
|
||||
|
||||
val inflater = LayoutInflater.from(context)
|
||||
val sliderBinding = DialogSliderBinding.inflate(inflater)
|
||||
|
||||
textInputLayout = sliderBinding.textInput
|
||||
textSliderValue = sliderBinding.textValue
|
||||
textSliderValue!!.text = sliderProgress.toString()
|
||||
sliderBinding.textUnits.text = item.units
|
||||
textSliderValue!!.setText(sliderProgress.toString())
|
||||
//sliderBinding.textUnits.text = item.units
|
||||
textInputLayout!!.suffixText = item.units
|
||||
|
||||
sliderBinding.slider.apply {
|
||||
valueFrom = item.min.toFloat()
|
||||
valueTo = item.max.toFloat()
|
||||
value = sliderProgress.toFloat()
|
||||
textSliderValue!!.addTextChangedListener( object : TextWatcher {
|
||||
override fun afterTextChanged(s: Editable) {
|
||||
val textValue = s.toString().toIntOrNull();
|
||||
if (textValue == null || textValue < valueFrom || textValue > valueTo) {
|
||||
textInputLayout!!.error ="Inappropriate value"
|
||||
} else {
|
||||
textInputLayout!!.error = null
|
||||
value = textValue.toFloat();
|
||||
}
|
||||
}
|
||||
override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {}
|
||||
override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {}
|
||||
})
|
||||
|
||||
addOnChangeListener { _: Slider, value: Float, _: Boolean ->
|
||||
sliderProgress = value.toInt()
|
||||
textSliderValue!!.text = sliderProgress.toString()
|
||||
if (textSliderValue!!.text.toString() != value.toInt().toString()) {
|
||||
textSliderValue!!.setText(value.toInt().toString())
|
||||
textSliderValue!!.setSelection(textSliderValue!!.length())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6,6 +6,7 @@ package io.github.lime3ds.android.features.settings.ui
|
||||
|
||||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
import android.content.res.Resources
|
||||
import android.hardware.camera2.CameraAccessException
|
||||
import android.hardware.camera2.CameraCharacteristics
|
||||
import android.hardware.camera2.CameraManager
|
||||
@ -42,6 +43,7 @@ import io.github.lime3ds.android.utils.GpuDriverHelper
|
||||
import io.github.lime3ds.android.utils.Log
|
||||
import io.github.lime3ds.android.utils.SystemSaveGame
|
||||
import io.github.lime3ds.android.utils.ThemeUtil
|
||||
import kotlin.math.min
|
||||
|
||||
class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView) {
|
||||
private var menuTag: String? = null
|
||||
@ -91,9 +93,12 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView)
|
||||
Settings.SECTION_CAMERA -> addCameraSettings(sl)
|
||||
Settings.SECTION_CONTROLS -> addControlsSettings(sl)
|
||||
Settings.SECTION_RENDERER -> addGraphicsSettings(sl)
|
||||
Settings.SECTION_LAYOUT -> addLayoutSettings(sl)
|
||||
Settings.SECTION_AUDIO -> addAudioSettings(sl)
|
||||
Settings.SECTION_DEBUG -> addDebugSettings(sl)
|
||||
Settings.SECTION_THEME -> addThemeSettings(sl)
|
||||
Settings.SECTION_CUSTOM_LANDSCAPE -> addCustomLandscapeSettings(sl)
|
||||
Settings.SECTION_CUSTOM_PORTRAIT -> addCustomPortraitSettings(sl)
|
||||
else -> {
|
||||
fragmentView.showToastMessage("Unimplemented menu", false)
|
||||
return
|
||||
@ -103,6 +108,23 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView)
|
||||
fragmentView.showSettingsList(settingsList!!)
|
||||
}
|
||||
|
||||
/** Returns the portrait mode width */
|
||||
private fun getWidth(): Int {
|
||||
val dm = Resources.getSystem().displayMetrics;
|
||||
return if (dm.widthPixels < dm.heightPixels)
|
||||
dm.widthPixels
|
||||
else
|
||||
dm.heightPixels
|
||||
}
|
||||
|
||||
private fun getHeight(): Int {
|
||||
val dm = Resources.getSystem().displayMetrics;
|
||||
return if (dm.widthPixels < dm.heightPixels)
|
||||
dm.heightPixels
|
||||
else
|
||||
dm.widthPixels
|
||||
}
|
||||
|
||||
private fun addConfigSettings(sl: ArrayList<SettingsItem>) {
|
||||
settingsActivity.setToolbarTitle(settingsActivity.getString(R.string.preferences_settings))
|
||||
sl.apply {
|
||||
@ -146,6 +168,14 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView)
|
||||
Settings.SECTION_RENDERER
|
||||
)
|
||||
)
|
||||
add(
|
||||
SubmenuSetting(
|
||||
R.string.preferences_layout,
|
||||
0,
|
||||
R.drawable.ic_fit_screen,
|
||||
Settings.SECTION_LAYOUT
|
||||
)
|
||||
)
|
||||
add(
|
||||
SubmenuSetting(
|
||||
R.string.preferences_audio,
|
||||
@ -162,6 +192,7 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView)
|
||||
Settings.SECTION_DEBUG
|
||||
)
|
||||
)
|
||||
|
||||
add(
|
||||
RunnableSetting(
|
||||
R.string.reset_to_default,
|
||||
@ -873,6 +904,262 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView)
|
||||
}
|
||||
}
|
||||
|
||||
private fun addLayoutSettings(sl: ArrayList<SettingsItem>) {
|
||||
settingsActivity.setToolbarTitle("Layout")
|
||||
sl.apply {
|
||||
add(
|
||||
SingleChoiceSetting(
|
||||
IntSetting.SCREEN_LAYOUT,
|
||||
R.string.emulation_switch_screen_layout,
|
||||
0,
|
||||
R.array.landscapeLayouts,
|
||||
R.array.landscapeLayoutValues,
|
||||
IntSetting.SCREEN_LAYOUT.key,
|
||||
IntSetting.SCREEN_LAYOUT.defaultValue
|
||||
)
|
||||
)
|
||||
add(
|
||||
SingleChoiceSetting(
|
||||
IntSetting.PORTRAIT_SCREEN_LAYOUT,
|
||||
R.string.emulation_switch_portrait_layout,
|
||||
0,
|
||||
R.array.portraitLayouts,
|
||||
R.array.portraitLayoutValues,
|
||||
IntSetting.PORTRAIT_SCREEN_LAYOUT.key,
|
||||
IntSetting.PORTRAIT_SCREEN_LAYOUT.defaultValue
|
||||
)
|
||||
)
|
||||
add(
|
||||
SubmenuSetting(
|
||||
R.string.emulation_landscape_custom_layout,
|
||||
0,
|
||||
R.drawable.ic_fit_screen,
|
||||
Settings.SECTION_CUSTOM_LANDSCAPE
|
||||
)
|
||||
)
|
||||
add(
|
||||
SubmenuSetting(
|
||||
R.string.emulation_portrait_custom_layout,
|
||||
0,
|
||||
R.drawable.ic_portrait_fit_screen,
|
||||
Settings.SECTION_CUSTOM_PORTRAIT
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private fun addCustomLandscapeSettings(sl: ArrayList<SettingsItem>) {
|
||||
settingsActivity.setToolbarTitle(settingsActivity.getString(R.string.emulation_landscape_custom_layout))
|
||||
sl.apply {
|
||||
add(HeaderSetting(R.string.emulation_top_screen))
|
||||
add(
|
||||
SliderSetting(
|
||||
IntSetting.LANDSCAPE_TOP_X,
|
||||
R.string.emulation_custom_layout_x,
|
||||
0,
|
||||
0,
|
||||
getHeight(),
|
||||
"px",
|
||||
IntSetting.LANDSCAPE_TOP_X.key,
|
||||
IntSetting.LANDSCAPE_TOP_X.defaultValue.toFloat()
|
||||
)
|
||||
)
|
||||
add(
|
||||
SliderSetting(
|
||||
IntSetting.LANDSCAPE_TOP_Y,
|
||||
R.string.emulation_custom_layout_y,
|
||||
0,
|
||||
0,
|
||||
getWidth(),
|
||||
"px",
|
||||
IntSetting.LANDSCAPE_TOP_Y.key,
|
||||
IntSetting.LANDSCAPE_TOP_Y.defaultValue.toFloat()
|
||||
)
|
||||
)
|
||||
add(
|
||||
SliderSetting(
|
||||
IntSetting.LANDSCAPE_TOP_WIDTH,
|
||||
R.string.emulation_custom_layout_width,
|
||||
0,
|
||||
0,
|
||||
getHeight(),
|
||||
"px",
|
||||
IntSetting.LANDSCAPE_TOP_WIDTH.key,
|
||||
IntSetting.LANDSCAPE_TOP_WIDTH.defaultValue.toFloat()
|
||||
)
|
||||
)
|
||||
add(
|
||||
SliderSetting(
|
||||
IntSetting.LANDSCAPE_TOP_HEIGHT,
|
||||
R.string.emulation_custom_layout_height,
|
||||
0,
|
||||
0,
|
||||
getWidth(),
|
||||
"px",
|
||||
IntSetting.LANDSCAPE_TOP_HEIGHT.key,
|
||||
IntSetting.LANDSCAPE_TOP_HEIGHT.defaultValue.toFloat()
|
||||
)
|
||||
)
|
||||
add(HeaderSetting(R.string.emulation_bottom_screen))
|
||||
add(
|
||||
SliderSetting(
|
||||
IntSetting.LANDSCAPE_BOTTOM_X,
|
||||
R.string.emulation_custom_layout_x,
|
||||
0,
|
||||
0,
|
||||
getHeight(),
|
||||
"px",
|
||||
IntSetting.LANDSCAPE_BOTTOM_X.key,
|
||||
IntSetting.LANDSCAPE_BOTTOM_X.defaultValue.toFloat()
|
||||
)
|
||||
)
|
||||
add(
|
||||
SliderSetting(
|
||||
IntSetting.LANDSCAPE_BOTTOM_Y,
|
||||
R.string.emulation_custom_layout_y,
|
||||
0,
|
||||
0,
|
||||
getWidth(),
|
||||
"px",
|
||||
IntSetting.LANDSCAPE_BOTTOM_Y.key,
|
||||
IntSetting.LANDSCAPE_BOTTOM_Y.defaultValue.toFloat()
|
||||
)
|
||||
)
|
||||
add(
|
||||
SliderSetting(
|
||||
IntSetting.LANDSCAPE_BOTTOM_WIDTH,
|
||||
R.string.emulation_custom_layout_width,
|
||||
0,
|
||||
0,
|
||||
getHeight(),
|
||||
"px",
|
||||
IntSetting.LANDSCAPE_BOTTOM_WIDTH.key,
|
||||
IntSetting.LANDSCAPE_BOTTOM_WIDTH.defaultValue.toFloat()
|
||||
)
|
||||
)
|
||||
add(
|
||||
SliderSetting(
|
||||
IntSetting.LANDSCAPE_BOTTOM_HEIGHT,
|
||||
R.string.emulation_custom_layout_height,
|
||||
0,
|
||||
0,
|
||||
getWidth(),
|
||||
"px",
|
||||
IntSetting.LANDSCAPE_BOTTOM_HEIGHT.key,
|
||||
IntSetting.LANDSCAPE_BOTTOM_HEIGHT.defaultValue.toFloat()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun addCustomPortraitSettings(sl: ArrayList<SettingsItem>) {
|
||||
settingsActivity.setToolbarTitle(settingsActivity.getString(R.string.emulation_portrait_custom_layout))
|
||||
sl.apply {
|
||||
add(HeaderSetting(R.string.emulation_top_screen))
|
||||
add(
|
||||
SliderSetting(
|
||||
IntSetting.PORTRAIT_TOP_X,
|
||||
R.string.emulation_custom_layout_x,
|
||||
0,
|
||||
0,
|
||||
getWidth(),
|
||||
"px",
|
||||
IntSetting.PORTRAIT_TOP_X.key,
|
||||
IntSetting.PORTRAIT_TOP_X.defaultValue.toFloat()
|
||||
)
|
||||
)
|
||||
add(
|
||||
SliderSetting(
|
||||
IntSetting.PORTRAIT_TOP_Y,
|
||||
R.string.emulation_custom_layout_y,
|
||||
0,
|
||||
0,
|
||||
getHeight(),
|
||||
"px",
|
||||
IntSetting.PORTRAIT_TOP_Y.key,
|
||||
IntSetting.PORTRAIT_TOP_Y.defaultValue.toFloat()
|
||||
)
|
||||
)
|
||||
add(
|
||||
SliderSetting(
|
||||
IntSetting.PORTRAIT_TOP_WIDTH,
|
||||
R.string.emulation_custom_layout_width,
|
||||
0,
|
||||
0,
|
||||
getWidth(),
|
||||
"px",
|
||||
IntSetting.PORTRAIT_TOP_WIDTH.key,
|
||||
IntSetting.PORTRAIT_TOP_WIDTH.defaultValue.toFloat()
|
||||
)
|
||||
)
|
||||
add(
|
||||
SliderSetting(
|
||||
IntSetting.PORTRAIT_TOP_HEIGHT,
|
||||
R.string.emulation_custom_layout_height,
|
||||
0,
|
||||
0,
|
||||
getHeight(),
|
||||
"px",
|
||||
IntSetting.PORTRAIT_TOP_HEIGHT.key,
|
||||
IntSetting.PORTRAIT_TOP_HEIGHT.defaultValue.toFloat()
|
||||
)
|
||||
)
|
||||
add(HeaderSetting(R.string.emulation_bottom_screen))
|
||||
add(
|
||||
SliderSetting(
|
||||
IntSetting.PORTRAIT_BOTTOM_X,
|
||||
R.string.emulation_custom_layout_x,
|
||||
0,
|
||||
0,
|
||||
getWidth(),
|
||||
"px",
|
||||
IntSetting.PORTRAIT_BOTTOM_X.key,
|
||||
IntSetting.PORTRAIT_BOTTOM_X.defaultValue.toFloat()
|
||||
)
|
||||
)
|
||||
add(
|
||||
SliderSetting(
|
||||
IntSetting.PORTRAIT_BOTTOM_Y,
|
||||
R.string.emulation_custom_layout_y,
|
||||
0,
|
||||
0,
|
||||
getHeight(),
|
||||
"px",
|
||||
IntSetting.PORTRAIT_BOTTOM_Y.key,
|
||||
IntSetting.PORTRAIT_BOTTOM_Y.defaultValue.toFloat()
|
||||
)
|
||||
)
|
||||
add(
|
||||
SliderSetting(
|
||||
IntSetting.PORTRAIT_BOTTOM_WIDTH,
|
||||
R.string.emulation_custom_layout_width,
|
||||
0,
|
||||
0,
|
||||
getWidth(),
|
||||
"px",
|
||||
IntSetting.PORTRAIT_BOTTOM_WIDTH.key,
|
||||
IntSetting.PORTRAIT_BOTTOM_WIDTH.defaultValue.toFloat()
|
||||
)
|
||||
)
|
||||
add(
|
||||
SliderSetting(
|
||||
IntSetting.PORTRAIT_BOTTOM_HEIGHT,
|
||||
R.string.emulation_custom_layout_height,
|
||||
0,
|
||||
0,
|
||||
getHeight(),
|
||||
"px",
|
||||
IntSetting.PORTRAIT_BOTTOM_HEIGHT.key,
|
||||
IntSetting.PORTRAIT_BOTTOM_HEIGHT.defaultValue.toFloat()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun addAudioSettings(sl: ArrayList<SettingsItem>) {
|
||||
settingsActivity.setToolbarTitle(settingsActivity.getString(R.string.preferences_audio))
|
||||
sl.apply {
|
||||
|
@ -13,6 +13,8 @@ import android.os.Bundle
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.os.SystemClock
|
||||
import android.text.Editable
|
||||
import android.text.TextWatcher
|
||||
import android.view.Choreographer
|
||||
import android.view.LayoutInflater
|
||||
import android.view.MotionEvent
|
||||
@ -54,6 +56,7 @@ import io.github.lime3ds.android.databinding.FragmentEmulationBinding
|
||||
import io.github.lime3ds.android.display.PortraitScreenLayout
|
||||
import io.github.lime3ds.android.display.ScreenAdjustmentUtil
|
||||
import io.github.lime3ds.android.display.ScreenLayout
|
||||
import io.github.lime3ds.android.features.settings.model.IntSetting
|
||||
import io.github.lime3ds.android.features.settings.model.SettingsViewModel
|
||||
import io.github.lime3ds.android.features.settings.ui.SettingsActivity
|
||||
import io.github.lime3ds.android.features.settings.utils.SettingsFile
|
||||
@ -324,6 +327,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram
|
||||
SettingsFile.FILE_NAME_CONFIG,
|
||||
""
|
||||
)
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
@ -786,7 +790,10 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram
|
||||
|
||||
popupMenu.menuInflater.inflate(R.menu.menu_landscape_screen_layout, popupMenu.menu)
|
||||
|
||||
val layoutOptionMenuItem = when (EmulationMenuSettings.landscapeScreenLayout) {
|
||||
val layoutOptionMenuItem = when (IntSetting.SCREEN_LAYOUT.int) {
|
||||
ScreenLayout.ORIGINAL.int ->
|
||||
R.id.menu_screen_layout_original
|
||||
|
||||
ScreenLayout.SINGLE_SCREEN.int ->
|
||||
R.id.menu_screen_layout_single
|
||||
|
||||
@ -825,7 +832,17 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram
|
||||
true
|
||||
}
|
||||
|
||||
R.id.menu_screen_layout_original -> {
|
||||
screenAdjustmentUtil.changeScreenOrientation(ScreenLayout.ORIGINAL.int)
|
||||
true
|
||||
}
|
||||
|
||||
R.id.menu_screen_layout_custom -> {
|
||||
Toast.makeText(
|
||||
requireContext(),
|
||||
R.string.emulation_adjust_custom_layout,
|
||||
Toast.LENGTH_LONG
|
||||
).show()
|
||||
screenAdjustmentUtil.changeScreenOrientation(ScreenLayout.CUSTOM_LAYOUT.int)
|
||||
true
|
||||
}
|
||||
@ -845,7 +862,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram
|
||||
|
||||
popupMenu.menuInflater.inflate(R.menu.menu_portrait_screen_layout, popupMenu.menu)
|
||||
|
||||
val layoutOptionMenuItem = when (EmulationMenuSettings.portraitScreenLayout) {
|
||||
val layoutOptionMenuItem = when (IntSetting.PORTRAIT_SCREEN_LAYOUT.int) {
|
||||
PortraitScreenLayout.TOP_FULL_WIDTH.int ->
|
||||
R.id.menu_portrait_layout_top_full
|
||||
|
||||
@ -867,6 +884,11 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram
|
||||
}
|
||||
|
||||
R.id.menu_portrait_layout_custom -> {
|
||||
Toast.makeText(
|
||||
requireContext(),
|
||||
R.string.emulation_adjust_custom_layout,
|
||||
Toast.LENGTH_LONG
|
||||
).show()
|
||||
screenAdjustmentUtil.changePortraitOrientation(PortraitScreenLayout.CUSTOM_PORTRAIT_LAYOUT.int)
|
||||
true
|
||||
}
|
||||
@ -919,14 +941,32 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram
|
||||
|
||||
sliderBinding.apply {
|
||||
slider.valueTo = 150f
|
||||
slider.valueFrom = 0f
|
||||
slider.value = preferences.getInt(target, 50).toFloat()
|
||||
textValue.setText((slider.value + 50).toInt().toString())
|
||||
textValue.addTextChangedListener( object : TextWatcher {
|
||||
override fun afterTextChanged(s: Editable) {
|
||||
val value = s.toString().toIntOrNull()
|
||||
if (value == null || value < 50 || value > 150) {
|
||||
textInput.error = "Inappropriate Value"
|
||||
} else {
|
||||
textInput.error = null
|
||||
slider.value = value.toFloat() - 50
|
||||
}
|
||||
}
|
||||
override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {}
|
||||
override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {}
|
||||
})
|
||||
slider.addOnChangeListener(
|
||||
Slider.OnChangeListener { slider: Slider, progress: Float, _: Boolean ->
|
||||
textValue.text = (progress.toInt() + 50).toString()
|
||||
setControlScale(slider.value.toInt(), target)
|
||||
if (textValue.text.toString() != (slider.value + 50).toInt().toString()) {
|
||||
textValue.setText((slider.value + 50).toInt().toString())
|
||||
textValue.setSelection(textValue.length())
|
||||
setControlScale(slider.value.toInt(), target)
|
||||
}
|
||||
|
||||
})
|
||||
textValue.text = (sliderBinding.slider.value.toInt() + 50).toString()
|
||||
textUnits.text = "%"
|
||||
textInput.suffixText = "%"
|
||||
}
|
||||
val previousProgress = sliderBinding.slider.value.toInt()
|
||||
|
||||
@ -949,15 +989,36 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram
|
||||
val sliderBinding = DialogSliderBinding.inflate(layoutInflater)
|
||||
|
||||
sliderBinding.apply {
|
||||
slider.valueFrom = 0f
|
||||
slider.valueTo = 100f
|
||||
slider.value = preferences.getInt("controlOpacity", 50).toFloat()
|
||||
slider.addOnChangeListener(
|
||||
Slider.OnChangeListener { slider: Slider, progress: Float, _: Boolean ->
|
||||
textValue.text = (progress.toInt()).toString()
|
||||
setControlOpacity(slider.value.toInt())
|
||||
})
|
||||
textValue.text = (sliderBinding.slider.value.toInt()).toString()
|
||||
textUnits.text = "%"
|
||||
textValue.setText(slider.value.toInt().toString())
|
||||
|
||||
textValue.addTextChangedListener( object : TextWatcher {
|
||||
override fun afterTextChanged(s: Editable) {
|
||||
val value = s.toString().toIntOrNull()
|
||||
if (value == null || value < slider.valueFrom || value > slider.valueTo) {
|
||||
textInput.error = "Inappropriate Value"
|
||||
} else {
|
||||
textInput.error = null
|
||||
slider.value = value.toFloat()
|
||||
}
|
||||
}
|
||||
override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {}
|
||||
override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {}
|
||||
})
|
||||
|
||||
|
||||
slider.addOnChangeListener { _: Slider, value: Float, _: Boolean ->
|
||||
|
||||
if (textValue.text.toString() != slider.value.toInt().toString()) {
|
||||
textValue.setText(slider.value.toInt().toString())
|
||||
textValue.setSelection(textValue.length())
|
||||
setControlOpacity(slider.value.toInt())
|
||||
}
|
||||
}
|
||||
|
||||
textInput.suffixText = "%"
|
||||
}
|
||||
val previousProgress = sliderBinding.slider.value.toInt()
|
||||
|
||||
@ -986,7 +1047,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram
|
||||
private fun resetScale(target: String) {
|
||||
preferences.edit().putInt(
|
||||
target,
|
||||
50
|
||||
100
|
||||
).apply()
|
||||
}
|
||||
|
||||
|
@ -7,8 +7,6 @@ package io.github.lime3ds.android.utils
|
||||
import androidx.drawerlayout.widget.DrawerLayout
|
||||
import androidx.preference.PreferenceManager
|
||||
import io.github.lime3ds.android.LimeApplication
|
||||
import io.github.lime3ds.android.display.PortraitScreenLayout
|
||||
import io.github.lime3ds.android.display.ScreenLayout
|
||||
|
||||
object EmulationMenuSettings {
|
||||
private val preferences =
|
||||
@ -28,26 +26,7 @@ object EmulationMenuSettings {
|
||||
.putBoolean("EmulationMenuSettings_DpadSlideEnable", value)
|
||||
.apply()
|
||||
}
|
||||
var landscapeScreenLayout: Int
|
||||
get() = preferences.getInt(
|
||||
"EmulationMenuSettings_LandscapeScreenLayout",
|
||||
ScreenLayout.LARGE_SCREEN.int
|
||||
)
|
||||
set(value) {
|
||||
preferences.edit()
|
||||
.putInt("EmulationMenuSettings_LandscapeScreenLayout", value)
|
||||
.apply()
|
||||
}
|
||||
var portraitScreenLayout: Int
|
||||
get() = preferences.getInt(
|
||||
"EmulationMenuSettings_PortraitScreenLayout",
|
||||
PortraitScreenLayout.TOP_FULL_WIDTH.int
|
||||
)
|
||||
set(value) {
|
||||
preferences.edit()
|
||||
.putInt("EmulationMenuSettings_PortraitScreenLayout", value)
|
||||
.apply()
|
||||
}
|
||||
|
||||
var showFps: Boolean
|
||||
get() = preferences.getBoolean("EmulationMenuSettings_ShowFps", false)
|
||||
set(value) {
|
||||
|
@ -175,7 +175,6 @@ void Config::ReadValues() {
|
||||
// Layout
|
||||
Settings::values.layout_option = static_cast<Settings::LayoutOption>(sdl2_config->GetInteger(
|
||||
"Layout", "layout_option", static_cast<int>(Settings::LayoutOption::LargeScreen)));
|
||||
ReadSetting("Layout", Settings::values.custom_layout);
|
||||
ReadSetting("Layout", Settings::values.custom_top_x);
|
||||
ReadSetting("Layout", Settings::values.custom_top_y);
|
||||
ReadSetting("Layout", Settings::values.custom_top_width);
|
||||
|
@ -180,16 +180,19 @@ filter_mode =
|
||||
|
||||
[Layout]
|
||||
# Layout for the screen inside the render window, landscape mode
|
||||
# 0 (default): Default Top Bottom Screen,
|
||||
# 0: Top/Bottom *currently unsupported on android*
|
||||
# 1: Single Screen Only,
|
||||
# 2: Large Screen Small Screen
|
||||
# 2: *currently unsupported on android*
|
||||
# 3: Side by Side
|
||||
# 4: Hybrid
|
||||
# 5: Custom Layout
|
||||
# 6: (default) Large screen / small screen
|
||||
layout_option =
|
||||
|
||||
# Screen placement when using Custom layout option
|
||||
# 0x, 0y is the top left corner of the render window.
|
||||
# suggested aspect ratio for top screen is 5:3
|
||||
# suggested aspect ratio for bottom screen is 4:3
|
||||
custom_top_x =
|
||||
custom_top_y =
|
||||
custom_top_width =
|
||||
|
@ -21,18 +21,6 @@ static bool IsPortraitMode() {
|
||||
IDCache::GetNativeLibraryClass(), IDCache::GetIsPortraitMode());
|
||||
}
|
||||
|
||||
static void UpdateLandscapeScreenLayout() {
|
||||
Settings::values.layout_option =
|
||||
static_cast<Settings::LayoutOption>(IDCache::GetEnvForThread()->CallStaticIntMethod(
|
||||
IDCache::GetNativeLibraryClass(), IDCache::GetLandscapeScreenLayout()));
|
||||
}
|
||||
|
||||
static void UpdatePortraitScreenLayout() {
|
||||
Settings::values.portrait_layout_option =
|
||||
static_cast<Settings::PortraitLayoutOption>(IDCache::GetEnvForThread()->CallStaticIntMethod(
|
||||
IDCache::GetNativeLibraryClass(), IDCache::GetPortraitScreenLayout()));
|
||||
}
|
||||
|
||||
bool EmuWindow_Android::OnSurfaceChanged(ANativeWindow* surface) {
|
||||
if (render_window == surface) {
|
||||
return false;
|
||||
@ -63,8 +51,6 @@ void EmuWindow_Android::OnTouchMoved(int x, int y) {
|
||||
}
|
||||
|
||||
void EmuWindow_Android::OnFramebufferSizeChanged() {
|
||||
UpdateLandscapeScreenLayout();
|
||||
UpdatePortraitScreenLayout();
|
||||
const bool is_portrait_mode{IsPortraitMode()};
|
||||
|
||||
const int bigger{window_width > window_height ? window_width : window_height};
|
||||
|
@ -177,10 +177,6 @@ jint JNI_OnLoad(JavaVM* vm, void* reserved) {
|
||||
s_native_library_class, "onCoreError",
|
||||
"(Lio/github/lime3ds/android/NativeLibrary$CoreError;Ljava/lang/String;)Z");
|
||||
s_is_portrait_mode = env->GetStaticMethodID(s_native_library_class, "isPortraitMode", "()Z");
|
||||
s_landscape_screen_layout =
|
||||
env->GetStaticMethodID(s_native_library_class, "landscapeScreenLayout", "()I");
|
||||
s_portrait_screen_layout =
|
||||
env->GetStaticMethodID(s_native_library_class, "portraitScreenLayout", "()I");
|
||||
s_exit_emulation_activity =
|
||||
env->GetStaticMethodID(s_native_library_class, "exitEmulationActivity", "(I)V");
|
||||
s_request_camera_permission =
|
||||
|
@ -346,29 +346,13 @@ void JNICALL Java_io_github_lime3ds_android_NativeLibrary_enableAdrenoTurboMode(
|
||||
EnableAdrenoTurboMode(enable);
|
||||
}
|
||||
|
||||
void Java_io_github_lime3ds_android_NativeLibrary_notifyOrientationChange(
|
||||
[[maybe_unused]] JNIEnv* env, [[maybe_unused]] jobject obj, jint layout_option, jint rotation,
|
||||
jboolean portrait) {
|
||||
Settings::values.layout_option = static_cast<Settings::LayoutOption>(layout_option);
|
||||
void Java_io_github_lime3ds_android_NativeLibrary_updateFramebuffer([[maybe_unused]] JNIEnv* env,
|
||||
[[maybe_unused]] jobject obj,
|
||||
jboolean is_portrait_mode) {
|
||||
auto& system = Core::System::GetInstance();
|
||||
if (system.IsPoweredOn()) {
|
||||
|
||||
system.GPU().Renderer().UpdateCurrentFramebufferLayout(portrait);
|
||||
system.GPU().Renderer().UpdateCurrentFramebufferLayout(is_portrait_mode);
|
||||
}
|
||||
InputManager::screen_rotation = rotation;
|
||||
Camera::NDK::g_rotation = rotation;
|
||||
}
|
||||
|
||||
void Java_io_github_lime3ds_android_NativeLibrary_notifyPortraitLayoutChange(
|
||||
[[maybe_unused]] JNIEnv* env, [[maybe_unused]] jobject obj, jint layout_option, jint rotation) {
|
||||
Settings::values.portrait_layout_option =
|
||||
static_cast<Settings::PortraitLayoutOption>(layout_option);
|
||||
auto& system = Core::System::GetInstance();
|
||||
if (system.IsPoweredOn()) {
|
||||
system.GPU().Renderer().UpdateCurrentFramebufferLayout(!(rotation % 2));
|
||||
}
|
||||
InputManager::screen_rotation = rotation;
|
||||
Camera::NDK::g_rotation = rotation;
|
||||
}
|
||||
|
||||
void Java_io_github_lime3ds_android_NativeLibrary_swapScreens([[maybe_unused]] JNIEnv* env,
|
||||
|
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:fromDegrees="90"
|
||||
android:toDegrees="0"
|
||||
android:drawable="@drawable/ic_fit_screen">
|
||||
</rotate>
|
@ -1,6 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
@ -13,25 +14,30 @@
|
||||
android:layout_marginRight="@dimen/spacing_large"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_below="@+id/text_value"
|
||||
android:layout_below="@+id/text_input"
|
||||
android:layout_marginBottom="@dimen/spacing_medlarge" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_marginLeft="@dimen/spacing_large"
|
||||
android:layout_marginRight="@dimen/spacing_large"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/text_input"
|
||||
app:suffixText="%">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:layout_width="match_parent"
|
||||
android:inputType="number"
|
||||
android:layout_height="wrap_content"
|
||||
tools:text="75"
|
||||
android:id="@+id/text_value"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:layout_marginTop="@dimen/spacing_medlarge"
|
||||
android:layout_marginBottom="@dimen/spacing_medlarge" />
|
||||
android:id="@+id/text_value"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:layout_marginTop="@dimen/spacing_medlarge"
|
||||
android:layout_marginBottom="@dimen/spacing_medlarge" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
tools:text="%"
|
||||
android:id="@+id/text_units"
|
||||
android:layout_alignTop="@+id/text_value"
|
||||
android:layout_toEndOf="@+id/text_value" />
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
</RelativeLayout>
|
||||
|
@ -1,127 +0,0 @@
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
tools:context="io.github.lime3ds.android.activities.EmulationActivity">
|
||||
|
||||
<item
|
||||
android:id="@+id/menu_emulation_save_state"
|
||||
android:title="@string/emulation_save_state">
|
||||
<menu/>
|
||||
</item>
|
||||
|
||||
<item
|
||||
android:id="@+id/menu_emulation_load_state"
|
||||
android:title="@string/emulation_load_state">
|
||||
<menu/>
|
||||
</item>
|
||||
|
||||
<item
|
||||
android:id="@+id/menu_emulation_configure_controls"
|
||||
android:title="@string/emulation_configure_controls">
|
||||
<menu>
|
||||
<item
|
||||
android:id="@+id/menu_emulation_edit_layout"
|
||||
android:title="@string/emulation_edit_layout" />
|
||||
|
||||
<item
|
||||
android:id="@+id/menu_emulation_toggle_controls"
|
||||
android:title="@string/emulation_toggle_controls" />
|
||||
|
||||
<item
|
||||
android:id="@+id/menu_emulation_adjust_scale"
|
||||
android:title="@string/emulation_control_scale" />
|
||||
|
||||
<group android:checkableBehavior="all">
|
||||
<item
|
||||
android:id="@+id/menu_emulation_joystick_rel_center"
|
||||
android:checkable="true"
|
||||
android:title="@string/emulation_control_joystick_rel_center"/>
|
||||
<item
|
||||
android:id="@+id/menu_emulation_dpad_slide_enable"
|
||||
android:checkable="true"
|
||||
android:title="@string/emulation_control_dpad_slide_enable" />
|
||||
</group>
|
||||
|
||||
<item
|
||||
android:id="@+id/menu_emulation_reset_overlay"
|
||||
android:title="@string/emulation_touch_overlay_reset" />
|
||||
</menu>
|
||||
</item>
|
||||
|
||||
<item
|
||||
android:id="@+id/menu_emulation_amiibo"
|
||||
android:title="@string/menu_emulation_amiibo">
|
||||
<menu>
|
||||
<item
|
||||
android:id="@+id/menu_emulation_amiibo_load"
|
||||
android:title="@string/menu_emulation_amiibo_load" />
|
||||
|
||||
<item
|
||||
android:id="@+id/menu_emulation_amiibo_remove"
|
||||
android:title="@string/menu_emulation_amiibo_remove" />
|
||||
</menu>
|
||||
</item>
|
||||
|
||||
<item
|
||||
android:id="@+id/menu_emulation_switch_screen_layout"
|
||||
app:showAsAction="never"
|
||||
android:title="@string/emulation_switch_screen_layout">
|
||||
<menu>
|
||||
<group android:checkableBehavior="single">
|
||||
<item
|
||||
android:id="@+id/menu_portrait_layout_top_full"
|
||||
android:title="@string/emulation_screen_layout_landscape" />
|
||||
|
||||
<item
|
||||
android:id="@+id/menu_screen_layout_portrait"
|
||||
android:title="@string/emulation_screen_layout_portrait" />
|
||||
|
||||
<item
|
||||
android:id="@+id/menu_screen_layout_single"
|
||||
android:title="@string/emulation_screen_layout_single" />
|
||||
|
||||
<item
|
||||
android:id="@+id/menu_screen_layout_sidebyside"
|
||||
android:title="@string/emulation_screen_layout_sidebyside" />
|
||||
|
||||
<item
|
||||
android:id="@+id/menu_screen_layout_hybrid"
|
||||
android:title="@string/emulation_screen_layout_hybrid" />
|
||||
</group>
|
||||
</menu>
|
||||
</item>
|
||||
|
||||
<item
|
||||
android:id="@+id/menu_emulation_swap_screens"
|
||||
app:showAsAction="never"
|
||||
android:title="@string/emulation_swap_screens"
|
||||
android:checkable="true" />
|
||||
|
||||
<item
|
||||
android:id="@+id/menu_emulation_show_fps"
|
||||
app:showAsAction="never"
|
||||
android:title="@string/emulation_show_fps"
|
||||
android:checkable="true" />
|
||||
|
||||
<item
|
||||
android:id="@+id/menu_emulation_show_overlay"
|
||||
app:showAsAction="never"
|
||||
android:title="@string/emulation_show_overlay"
|
||||
android:checkable="true" />
|
||||
|
||||
<item
|
||||
android:id="@+id/menu_emulation_open_cheats"
|
||||
app:showAsAction="never"
|
||||
android:title="@string/emulation_open_cheats" />
|
||||
|
||||
<item
|
||||
android:id="@+id/menu_emulation_open_settings"
|
||||
app:showAsAction="never"
|
||||
android:title="@string/emulation_open_settings" />
|
||||
|
||||
<item
|
||||
android:id="@+id/menu_emulation_close_game"
|
||||
app:showAsAction="never"
|
||||
android:title="@string/emulation_close_game" />
|
||||
|
||||
</menu>
|
@ -29,12 +29,13 @@
|
||||
|
||||
<item
|
||||
android:id="@+id/menu_portrait_screen_layout"
|
||||
android:icon="@drawable/ic_fit_screen"
|
||||
android:icon="@drawable/ic_portrait_fit_screen"
|
||||
android:title="@string/emulation_switch_portrait_layout" />
|
||||
|
||||
<item
|
||||
android:id="@+id/menu_swap_screens"
|
||||
android:icon="@drawable/ic_splitscreen"
|
||||
|
||||
android:title="@string/emulation_swap_screens" />
|
||||
|
||||
<item
|
||||
|
@ -19,9 +19,14 @@
|
||||
android:id="@+id/menu_screen_layout_hybrid"
|
||||
android:title="@string/emulation_screen_layout_hybrid" />
|
||||
|
||||
<item
|
||||
android:id="@+id/menu_screen_layout_original"
|
||||
android:title="@string/emulation_screen_layout_original" />
|
||||
|
||||
<item
|
||||
android:id="@+id/menu_screen_layout_custom"
|
||||
android:title="@string/emulation_screen_layout_custom" />
|
||||
|
||||
</group>
|
||||
|
||||
</menu>
|
||||
|
@ -10,6 +10,7 @@
|
||||
<item
|
||||
android:id="@+id/menu_portrait_layout_custom"
|
||||
android:title="@string/emulation_screen_layout_custom" />
|
||||
|
||||
</group>
|
||||
|
||||
</menu>
|
||||
|
@ -11,6 +11,37 @@
|
||||
<item>1</item>
|
||||
</integer-array>
|
||||
|
||||
<string-array name="landscapeLayouts">
|
||||
<item>@string/emulation_screen_layout_landscape</item>
|
||||
<item>@string/emulation_screen_layout_single</item>
|
||||
<item>@string/emulation_screen_layout_sidebyside</item>
|
||||
<item>@string/emulation_screen_layout_hybrid</item>
|
||||
<item>@string/emulation_screen_layout_original</item>
|
||||
<item>@string/emulation_screen_layout_custom</item>
|
||||
</string-array>
|
||||
<!-- start with 6 because that is the MobileLandscape layout in cpp files
|
||||
- skip 0 because top/bottom rarely makes sense in landscape
|
||||
- skip 2 because that is "Large Screen" which the default replaces in mobile
|
||||
-->
|
||||
<integer-array name="landscapeLayoutValues">
|
||||
<item>6</item>
|
||||
<item>1</item>
|
||||
<item>3</item>
|
||||
<item>4</item>
|
||||
<item>0</item>
|
||||
<item>5</item>
|
||||
</integer-array>
|
||||
|
||||
<string-array name="portraitLayouts">
|
||||
<item>@string/emulation_portrait_layout_top_full</item>
|
||||
<item>@string/emulation_screen_layout_custom</item>
|
||||
</string-array>
|
||||
|
||||
<integer-array name="portraitLayoutValues">
|
||||
<item>0</item>
|
||||
<item>1</item>
|
||||
</integer-array>
|
||||
|
||||
<string-array name="regionNames">
|
||||
<item>@string/auto_select</item>
|
||||
<item>@string/system_region_jpn</item>
|
||||
|
@ -330,7 +330,7 @@
|
||||
<string name="preferences_audio">Audio</string>
|
||||
<string name="preferences_debug">Debug</string>
|
||||
<string name="preferences_theme">Theme and Color</string>
|
||||
|
||||
<string name="preferences_layout">Layout</string>
|
||||
<!-- ROM loading errors -->
|
||||
<string name="loader_error_encrypted">Your ROM is Encrypted</string>
|
||||
<string name="loader_error_invalid_format">Invalid ROM format</string>
|
||||
@ -365,8 +365,18 @@
|
||||
<string name="emulation_screen_layout_single">Single Screen</string>
|
||||
<string name="emulation_screen_layout_sidebyside">Side by Side Screens</string>
|
||||
<string name="emulation_screen_layout_hybrid">Hybrid Screens</string>
|
||||
<string name="emulation_screen_layout_original">Original</string>
|
||||
<string name="emulation_portrait_layout_top_full">Default</string>
|
||||
<string name="emulation_screen_layout_custom">Custom Layout</string>
|
||||
<string name="emulation_adjust_custom_layout">Adjust Custom Layout in Settings</string>
|
||||
<string name="emulation_landscape_custom_layout">Landscape Custom Layout</string>
|
||||
<string name="emulation_portrait_custom_layout">Portrait Custom Layout</string>
|
||||
<string name="emulation_top_screen">Top Screen</string>
|
||||
<string name="emulation_bottom_screen">Bottom Screen</string>
|
||||
<string name="emulation_custom_layout_x">X-Position</string>
|
||||
<string name="emulation_custom_layout_y">Y-Position</string>
|
||||
<string name="emulation_custom_layout_width">Width</string>
|
||||
<string name="emulation_custom_layout_height">Height</string>
|
||||
<string name="emulation_cycle_landscape_layouts">Cycle Layouts</string>
|
||||
<string name="emulation_swap_screens">Swap Screens</string>
|
||||
<string name="emulation_touch_overlay_reset">Reset Overlay</string>
|
||||
|
@ -490,9 +490,6 @@ struct Values {
|
||||
SwitchableSetting<bool> upright_screen{false, "upright_screen"};
|
||||
SwitchableSetting<float, true> large_screen_proportion{4.f, 1.f, 16.f,
|
||||
"large_screen_proportion"};
|
||||
// I think the custom_layout setting below is no longer needed
|
||||
// since custom layout is now just part of the layout option above?
|
||||
Setting<bool> custom_layout{false, "custom_layout"};
|
||||
Setting<u16> custom_top_x{0, "custom_top_x"};
|
||||
Setting<u16> custom_top_y{0, "custom_top_y"};
|
||||
Setting<u16> custom_top_width{800, "custom_top_width"};
|
||||
|
@ -121,7 +121,7 @@ FramebufferLayout PortraitTopFullFrameLayout(u32 width, u32 height, bool swapped
|
||||
ASSERT(width > 0);
|
||||
ASSERT(height > 0);
|
||||
|
||||
FramebufferLayout res{width, height, true, true, {}, {}};
|
||||
FramebufferLayout res{width, height, true, true, {}, {}, true, true};
|
||||
// Default layout gives equal screen sizes to the top and bottom screen
|
||||
Common::Rectangle<u32> screen_window_area{0, 0, width, height / 2};
|
||||
Common::Rectangle<u32> top_screen = MaxRectangle(screen_window_area, TOP_SCREEN_ASPECT_RATIO);
|
||||
@ -305,7 +305,7 @@ FramebufferLayout HybridScreenLayout(u32 width, u32 height, bool swapped, bool u
|
||||
ASSERT(width > 0);
|
||||
ASSERT(height > 0);
|
||||
|
||||
FramebufferLayout res{width, height, true, true, {}, {}, !upright, true, {}};
|
||||
FramebufferLayout res{width, height, true, true, {}, {}, !upright, false, true, {}};
|
||||
|
||||
// Split the window into two parts. Give 2.25x width to the main screen,
|
||||
// and make a bar on the right side with 1x width top screen and 1.25x width bottom screen
|
||||
@ -386,7 +386,8 @@ FramebufferLayout CustomFrameLayout(u32 width, u32 height, bool is_swapped, bool
|
||||
ASSERT(width > 0);
|
||||
ASSERT(height > 0);
|
||||
|
||||
FramebufferLayout res{width, height, true, true, {}, {}, !Settings::values.upright_screen};
|
||||
FramebufferLayout res{
|
||||
width, height, true, true, {}, {}, !Settings::values.upright_screen, is_portrait_mode};
|
||||
u16 top_x = is_portrait_mode ? Settings::values.custom_portrait_top_x.GetValue()
|
||||
: Settings::values.custom_top_x.GetValue();
|
||||
u16 top_width = is_portrait_mode ? Settings::values.custom_portrait_top_width.GetValue()
|
||||
@ -629,9 +630,7 @@ FramebufferLayout GetCardboardSettings(const FramebufferLayout& layout) {
|
||||
|
||||
return new_layout;
|
||||
}
|
||||
/*f
|
||||
* TODO: remove this?
|
||||
*/
|
||||
|
||||
std::pair<unsigned, unsigned> GetMinimumSizeFromPortraitLayout() {
|
||||
u32 min_width, min_height;
|
||||
min_width = Core::kScreenTopWidth;
|
||||
|
@ -61,7 +61,7 @@ struct FramebufferLayout {
|
||||
Common::Rectangle<u32> top_screen;
|
||||
Common::Rectangle<u32> bottom_screen;
|
||||
bool is_rotated = true;
|
||||
|
||||
bool is_portrait = false;
|
||||
bool additional_screen_enabled;
|
||||
Common::Rectangle<u32> additional_screen;
|
||||
|
||||
|
@ -164,8 +164,6 @@ void Config::ReadValues() {
|
||||
ReadSetting("Layout", Settings::values.swap_screen);
|
||||
ReadSetting("Layout", Settings::values.upright_screen);
|
||||
ReadSetting("Layout", Settings::values.large_screen_proportion);
|
||||
|
||||
ReadSetting("Layout", Settings::values.custom_layout);
|
||||
ReadSetting("Layout", Settings::values.custom_top_x);
|
||||
ReadSetting("Layout", Settings::values.custom_top_y);
|
||||
ReadSetting("Layout", Settings::values.custom_top_width);
|
||||
|
@ -182,7 +182,7 @@ filter_mode =
|
||||
|
||||
[Layout]
|
||||
# Layout for the screen inside the render window.
|
||||
# 0 (default): Default Top Bottom Screen
|
||||
# 0 (default): Default Above/Below Screen
|
||||
# 1: Single Screen Only
|
||||
# 2: Large Screen Small Screen
|
||||
# 3: Side by Side
|
||||
@ -191,10 +191,6 @@ filter_mode =
|
||||
# 6: Custom Layout
|
||||
layout_option =
|
||||
|
||||
# Toggle custom layout (using the settings below) on or off.
|
||||
# 0 (default): Off, 1: On
|
||||
custom_layout =
|
||||
|
||||
# Screen placement when using Custom layout option
|
||||
# 0x, 0y is the top left corner of the render window.
|
||||
custom_top_x =
|
||||
|
@ -520,8 +520,6 @@ void Config::ReadLayoutValues() {
|
||||
|
||||
if (global) {
|
||||
ReadBasicSetting(Settings::values.mono_render_option);
|
||||
|
||||
ReadBasicSetting(Settings::values.custom_layout);
|
||||
ReadBasicSetting(Settings::values.custom_top_x);
|
||||
ReadBasicSetting(Settings::values.custom_top_y);
|
||||
ReadBasicSetting(Settings::values.custom_top_width);
|
||||
@ -1081,8 +1079,6 @@ void Config::SaveLayoutValues() {
|
||||
|
||||
if (global) {
|
||||
WriteBasicSetting(Settings::values.mono_render_option);
|
||||
|
||||
WriteBasicSetting(Settings::values.custom_layout);
|
||||
WriteBasicSetting(Settings::values.custom_top_x);
|
||||
WriteBasicSetting(Settings::values.custom_top_y);
|
||||
WriteBasicSetting(Settings::values.custom_top_width);
|
||||
|
@ -634,10 +634,6 @@ void RendererOpenGL::DrawSingleScreenStereo(const ScreenInfo& screen_info_l,
|
||||
* Draws the emulated screens to the emulator window.
|
||||
*/
|
||||
void RendererOpenGL::DrawScreens(const Layout::FramebufferLayout& layout, bool flipped) {
|
||||
bool isPortrait = false;
|
||||
#ifdef ANDROID
|
||||
isPortrait = layout.height > layout.width;
|
||||
#endif
|
||||
if (settings.bg_color_update_requested.exchange(false)) {
|
||||
// Update background color before drawing
|
||||
glClearColor(Settings::values.bg_red.GetValue(), Settings::values.bg_green.GetValue(),
|
||||
@ -679,12 +675,12 @@ void RendererOpenGL::DrawScreens(const Layout::FramebufferLayout& layout, bool f
|
||||
if (!Settings::values.swap_screen.GetValue()) {
|
||||
DrawTopScreen(layout, top_screen);
|
||||
glUniform1i(uniform_layer, 0);
|
||||
ApplySecondLayerOpacity(isPortrait);
|
||||
ApplySecondLayerOpacity(layout.is_portrait);
|
||||
DrawBottomScreen(layout, bottom_screen);
|
||||
} else {
|
||||
DrawBottomScreen(layout, bottom_screen);
|
||||
glUniform1i(uniform_layer, 0);
|
||||
ApplySecondLayerOpacity(isPortrait);
|
||||
ApplySecondLayerOpacity(layout.is_portrait);
|
||||
DrawTopScreen(layout, top_screen);
|
||||
}
|
||||
|
||||
@ -696,19 +692,14 @@ void RendererOpenGL::DrawScreens(const Layout::FramebufferLayout& layout, bool f
|
||||
DrawBottomScreen(layout, additional_screen);
|
||||
}
|
||||
}
|
||||
ResetSecondLayerOpacity(isPortrait);
|
||||
ResetSecondLayerOpacity(layout.is_portrait);
|
||||
}
|
||||
|
||||
void RendererOpenGL::ApplySecondLayerOpacity(bool isPortrait) {
|
||||
#ifdef ANDROID
|
||||
// TODO: Allow for second layer opacity in portrait mode android
|
||||
if (isPortrait) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
if ((Settings::values.layout_option.GetValue() == Settings::LayoutOption::CustomLayout ||
|
||||
Settings::values.custom_layout) &&
|
||||
if (!isPortrait &&
|
||||
(Settings::values.layout_option.GetValue() == Settings::LayoutOption::CustomLayout) &&
|
||||
Settings::values.custom_second_layer_opacity.GetValue() < 100) {
|
||||
state.blend.src_rgb_func = GL_CONSTANT_ALPHA;
|
||||
state.blend.src_a_func = GL_CONSTANT_ALPHA;
|
||||
@ -719,15 +710,8 @@ void RendererOpenGL::ApplySecondLayerOpacity(bool isPortrait) {
|
||||
}
|
||||
|
||||
void RendererOpenGL::ResetSecondLayerOpacity(bool isPortrait) {
|
||||
#ifdef ANDROID
|
||||
// TODO: Allow for second layer opacity in portrait mode android
|
||||
if (isPortrait) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
if ((Settings::values.layout_option.GetValue() == Settings::LayoutOption::CustomLayout ||
|
||||
Settings::values.custom_layout) &&
|
||||
if (!isPortrait &&
|
||||
(Settings::values.layout_option.GetValue() == Settings::LayoutOption::CustomLayout) &&
|
||||
Settings::values.custom_second_layer_opacity.GetValue() < 100) {
|
||||
state.blend.src_rgb_func = GL_ONE;
|
||||
state.blend.dst_rgb_func = GL_ZERO;
|
||||
|
Loading…
x
Reference in New Issue
Block a user