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:
David Griswold 2024-08-11 16:18:59 +01:00 committed by OpenSauce
parent 7e5b83f126
commit 862fda4332
31 changed files with 546 additions and 322 deletions

View File

@ -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 {

View File

@ -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;
}
}
}

View File

@ -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)
}
}

View File

@ -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;
}
}
}

View File

@ -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),

View File

@ -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"

View File

@ -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()
}

View File

@ -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())
}
}
}

View File

@ -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 {

View File

@ -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()
}

View File

@ -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) {

View File

@ -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);

View File

@ -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 =

View File

@ -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};

View File

@ -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 =

View File

@ -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,

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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

View File

@ -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>

View File

@ -10,6 +10,7 @@
<item
android:id="@+id/menu_portrait_layout_custom"
android:title="@string/emulation_screen_layout_custom" />
</group>
</menu>

View File

@ -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>

View File

@ -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>

View File

@ -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"};

View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

@ -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 =

View File

@ -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);

View File

@ -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;