mirror of
https://github.com/Lime3DS/Lime3DS.git
synced 2024-11-26 11:34:18 +01:00
Merge branch 'master' into global-hotkeys
This commit is contained in:
commit
7b569b70d8
@ -19,7 +19,6 @@ cmake .. -G Ninja \
|
||||
-DCMAKE_C_COMPILER=clang-18 \
|
||||
"${EXTRA_CMAKE_FLAGS[@]}" \
|
||||
-DENABLE_QT_TRANSLATION=ON \
|
||||
-DCITRA_ENABLE_COMPATIBILITY_REPORTING=ON \
|
||||
-DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON \
|
||||
-DUSE_DISCORD_PRESENCE=ON
|
||||
ninja
|
||||
|
@ -7,7 +7,6 @@ cmake .. -GNinja \
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||
-DENABLE_QT_TRANSLATION=ON \
|
||||
-DCITRA_ENABLE_COMPATIBILITY_REPORTING=ON \
|
||||
-DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON \
|
||||
-DUSE_DISCORD_PRESENCE=ON
|
||||
ninja
|
||||
|
@ -6,7 +6,6 @@ cmake .. -G Ninja \
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||
-DENABLE_QT_TRANSLATION=ON \
|
||||
-DCITRA_ENABLE_COMPATIBILITY_REPORTING=ON \
|
||||
-DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON \
|
||||
-DUSE_DISCORD_PRESENCE=ON
|
||||
ninja
|
||||
|
2
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
2
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
@ -4,7 +4,7 @@ labels: ["bug"]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: Tech support does not belong here. You should only file an issue here if you think you have experienced an actual bug with Lime.
|
||||
value: Tech support does not belong here. You should only file an issue here if you think you have experienced an actual bug with Lime3DS.
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: Is there an existing issue for this?
|
||||
|
2
.github/workflows/build.yml
vendored
2
.github/workflows/build.yml
vendored
@ -256,4 +256,4 @@ jobs:
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
asset_paths: '["./**/*.tar.*","./**/*.AppImage","./**/*.zip","./**/*.apk"]'
|
||||
asset_paths: '["./**/*.tar.*","./**/*.AppImage","./**/*.zip","./**/*.apk","./**/*.aab",]'
|
||||
|
@ -268,6 +268,11 @@ android.applicationVariants.configureEach {
|
||||
include("*.apk")
|
||||
into(layout.buildDirectory.dir("bundle"))
|
||||
}
|
||||
project.copy {
|
||||
from(layout.buildDirectory.dir("outputs/bundle/${variant.name}"))
|
||||
include("*.aab")
|
||||
into(layout.buildDirectory.dir("bundle"))
|
||||
}
|
||||
}
|
||||
}
|
||||
tasks.named("bundle${capitalizedName}").configure { finalizedBy(copyTask) }
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright 2023 Citra Emulator Project
|
||||
// Copyright Citra Emulator Project / Lime3DS Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
@ -156,9 +156,9 @@ 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)
|
||||
external fun updateFramebuffer(isPortrait: Boolean)
|
||||
|
||||
/**
|
||||
* Swaps the top and bottom screens.
|
||||
@ -262,10 +262,6 @@ object NativeLibrary {
|
||||
get() = LimeApplication.appContext.resources.configuration.orientation ==
|
||||
Configuration.ORIENTATION_PORTRAIT
|
||||
|
||||
@Keep
|
||||
@JvmStatic
|
||||
fun landscapeScreenLayout(): Int = EmulationMenuSettings.landscapeScreenLayout
|
||||
|
||||
@Keep
|
||||
@JvmStatic
|
||||
fun displayAlertMsg(title: String, message: String, yesNo: Boolean): Boolean {
|
||||
|
@ -1,9 +1,8 @@
|
||||
// Copyright 2023 Citra Emulator Project
|
||||
// Copyright Citra Emulator Project / Lime3DS Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// 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
|
||||
@ -12,8 +11,10 @@ import io.github.lime3ds.android.features.settings.model.Settings
|
||||
import io.github.lime3ds.android.features.settings.utils.SettingsFile
|
||||
import io.github.lime3ds.android.utils.EmulationMenuSettings
|
||||
|
||||
class ScreenAdjustmentUtil(private val windowManager: WindowManager,
|
||||
private val settings: Settings) {
|
||||
class ScreenAdjustmentUtil(
|
||||
private val windowManager: WindowManager,
|
||||
private val settings: Settings
|
||||
) {
|
||||
fun swapScreen() {
|
||||
val isEnabled = !EmulationMenuSettings.swapScreens
|
||||
EmulationMenuSettings.swapScreens = isEnabled
|
||||
@ -24,19 +25,35 @@ class ScreenAdjustmentUtil(private val windowManager: WindowManager,
|
||||
BooleanSetting.SWAP_SCREEN.boolean = isEnabled
|
||||
settings.saveSetting(BooleanSetting.SWAP_SCREEN, SettingsFile.FILE_NAME_CONFIG)
|
||||
}
|
||||
|
||||
fun cycleLayouts() {
|
||||
val nextLayout = (EmulationMenuSettings.landscapeScreenLayout + 1) % ScreenLayout.entries.size
|
||||
changeScreenOrientation(ScreenLayout.from(nextLayout))
|
||||
// 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 {
|
||||
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)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun changeScreenOrientation(layoutOption: ScreenLayout) {
|
||||
EmulationMenuSettings.landscapeScreenLayout = layoutOption.int
|
||||
NativeLibrary.notifyOrientationChange(
|
||||
EmulationMenuSettings.landscapeScreenLayout,
|
||||
windowManager.defaultDisplay.rotation
|
||||
)
|
||||
IntSetting.SCREEN_LAYOUT.int = layoutOption.int
|
||||
fun changePortraitOrientation(layoutOption: Int) {
|
||||
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) {
|
||||
IntSetting.SCREEN_LAYOUT.int = layoutOption
|
||||
settings.saveSetting(IntSetting.SCREEN_LAYOUT, SettingsFile.FILE_NAME_CONFIG)
|
||||
NativeLibrary.reloadSettings()
|
||||
NativeLibrary.updateFramebuffer(NativeLibrary.isPortraitMode)
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright 2023 Citra Emulator Project
|
||||
// Copyright Citra Emulator Project / Lime3DS Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
@ -6,17 +6,30 @@ package io.github.lime3ds.android.display
|
||||
|
||||
enum class ScreenLayout(val int: Int) {
|
||||
// These must match what is defined in src/common/settings.h
|
||||
DEFAULT(0),
|
||||
ORIGINAL(0),
|
||||
SINGLE_SCREEN(1),
|
||||
LARGE_SCREEN(2),
|
||||
SIDE_SCREEN(3),
|
||||
HYBRID_SCREEN(4),
|
||||
MOBILE_PORTRAIT(5),
|
||||
CUSTOM_LAYOUT(5),
|
||||
MOBILE_LANDSCAPE(6);
|
||||
|
||||
|
||||
companion object {
|
||||
fun from(int: Int): ScreenLayout {
|
||||
return entries.firstOrNull { it.int == int } ?: DEFAULT
|
||||
return entries.firstOrNull { it.int == int } ?: MOBILE_LANDSCAPE
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
// Copyright 2023 Citra Emulator Project
|
||||
// Copyright Citra Emulator Project / Lime3DS Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
@ -14,6 +14,7 @@ enum class BooleanSetting(
|
||||
PLUGIN_LOADER("plugin_loader", Settings.SECTION_SYSTEM, false),
|
||||
ALLOW_PLUGIN_LOADER("allow_plugin_loader", Settings.SECTION_SYSTEM, true),
|
||||
SWAP_SCREEN("swap_screen", Settings.SECTION_LAYOUT, false),
|
||||
CUSTOM_LAYOUT("custom_layout",Settings.SECTION_LAYOUT,false),
|
||||
ADRENO_GPU_BOOST("adreno_gpu_boost", Settings.SECTION_RENDERER, false);
|
||||
|
||||
override var boolean: Boolean = defaultValue
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright 2023 Citra Emulator Project
|
||||
// Copyright Citra Emulator Project / Lime3DS Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
@ -23,6 +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),
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright 2023 Citra Emulator Project
|
||||
// Copyright Citra Emulator Project / Lime3DS Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
@ -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"
|
||||
@ -131,7 +133,6 @@ class Settings {
|
||||
const val KEY_CSTICK_AXIS_HORIZONTAL = "cstick_axis_horizontal"
|
||||
const val KEY_DPAD_AXIS_VERTICAL = "dpad_axis_vertical"
|
||||
const val KEY_DPAD_AXIS_HORIZONTAL = "dpad_axis_horizontal"
|
||||
|
||||
const val HOTKEY_SCREEN_SWAP = "hotkey_screen_swap"
|
||||
const val HOTKEY_CYCLE_LAYOUT = "hotkey_toggle_layout"
|
||||
const val HOTKEY_CLOSE_GAME = "hotkey_close_game"
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright 2023 Citra Emulator Project
|
||||
// Copyright Citra Emulator Project / Lime3DS Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
@ -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()
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright 2023 Citra Emulator Project
|
||||
// Copyright Citra Emulator Project / Lime3DS Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
@ -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,35 @@ 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())
|
||||
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())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright 2023 Citra Emulator Project
|
||||
// Copyright Citra Emulator Project / Lime3DS Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
@ -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(settingsActivity.getString(R.string.preferences_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 {
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright 2023 Citra Emulator Project
|
||||
// Copyright Citra Emulator Project / Lime3DS Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
@ -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
|
||||
@ -51,8 +53,10 @@ import io.github.lime3ds.android.activities.EmulationActivity
|
||||
import io.github.lime3ds.android.databinding.DialogCheckboxBinding
|
||||
import io.github.lime3ds.android.databinding.DialogSliderBinding
|
||||
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
|
||||
@ -142,7 +146,8 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram
|
||||
retainInstance = true
|
||||
emulationState = EmulationState(game.path)
|
||||
emulationActivity = requireActivity() as EmulationActivity
|
||||
screenAdjustmentUtil = ScreenAdjustmentUtil(emulationActivity.windowManager, settingsViewModel.settings)
|
||||
screenAdjustmentUtil =
|
||||
ScreenAdjustmentUtil(emulationActivity.windowManager, settingsViewModel.settings)
|
||||
EmulationLifecycleUtil.addShutdownHook(hook = { emulationState.stop() })
|
||||
EmulationLifecycleUtil.addPauseResumeHook(hook = { togglePause() })
|
||||
}
|
||||
@ -207,16 +212,18 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram
|
||||
}
|
||||
})
|
||||
binding.inGameMenu.menu.findItem(R.id.menu_lock_drawer).apply {
|
||||
val titleId = if (EmulationMenuSettings.drawerLockMode == DrawerLayout.LOCK_MODE_LOCKED_CLOSED) {
|
||||
R.string.unlock_drawer
|
||||
} else {
|
||||
R.string.lock_drawer
|
||||
}
|
||||
val iconId = if (EmulationMenuSettings.drawerLockMode == DrawerLayout.LOCK_MODE_UNLOCKED) {
|
||||
R.drawable.ic_unlocked
|
||||
} else {
|
||||
R.drawable.ic_lock
|
||||
}
|
||||
val titleId =
|
||||
if (EmulationMenuSettings.drawerLockMode == DrawerLayout.LOCK_MODE_LOCKED_CLOSED) {
|
||||
R.string.unlock_drawer
|
||||
} else {
|
||||
R.string.lock_drawer
|
||||
}
|
||||
val iconId =
|
||||
if (EmulationMenuSettings.drawerLockMode == DrawerLayout.LOCK_MODE_UNLOCKED) {
|
||||
R.drawable.ic_unlocked
|
||||
} else {
|
||||
R.drawable.ic_lock
|
||||
}
|
||||
|
||||
title = getString(titleId)
|
||||
icon = ResourcesCompat.getDrawable(
|
||||
@ -267,7 +274,12 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram
|
||||
}
|
||||
|
||||
R.id.menu_landscape_screen_layout -> {
|
||||
showScreenLayoutMenu()
|
||||
showLandscapeScreenLayoutMenu()
|
||||
true
|
||||
}
|
||||
|
||||
R.id.menu_portrait_screen_layout -> {
|
||||
showPortraitScreenLayoutMenu()
|
||||
true
|
||||
}
|
||||
|
||||
@ -315,6 +327,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram
|
||||
SettingsFile.FILE_NAME_CONFIG,
|
||||
""
|
||||
)
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
@ -423,7 +436,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram
|
||||
}
|
||||
|
||||
private fun togglePause() {
|
||||
if(emulationState.isPaused) {
|
||||
if (emulationState.isPaused) {
|
||||
emulationState.unpause()
|
||||
} else {
|
||||
emulationState.pause()
|
||||
@ -769,7 +782,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram
|
||||
popupMenu.show()
|
||||
}
|
||||
|
||||
private fun showScreenLayoutMenu() {
|
||||
private fun showLandscapeScreenLayoutMenu() {
|
||||
val popupMenu = PopupMenu(
|
||||
requireContext(),
|
||||
binding.inGameMenu.findViewById(R.id.menu_landscape_screen_layout)
|
||||
@ -777,19 +790,22 @@ 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
|
||||
|
||||
ScreenLayout.SIDE_SCREEN.int ->
|
||||
R.id.menu_screen_layout_sidebyside
|
||||
|
||||
ScreenLayout.MOBILE_PORTRAIT.int ->
|
||||
R.id.menu_screen_layout_portrait
|
||||
|
||||
ScreenLayout.HYBRID_SCREEN.int ->
|
||||
R.id.menu_screen_layout_hybrid
|
||||
|
||||
ScreenLayout.CUSTOM_LAYOUT.int ->
|
||||
R.id.menu_screen_layout_custom
|
||||
|
||||
else -> R.id.menu_screen_layout_landscape
|
||||
}
|
||||
popupMenu.menu.findItem(layoutOptionMenuItem).setChecked(true)
|
||||
@ -797,27 +813,83 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram
|
||||
popupMenu.setOnMenuItemClickListener {
|
||||
when (it.itemId) {
|
||||
R.id.menu_screen_layout_landscape -> {
|
||||
screenAdjustmentUtil.changeScreenOrientation(ScreenLayout.MOBILE_LANDSCAPE)
|
||||
true
|
||||
}
|
||||
|
||||
R.id.menu_screen_layout_portrait -> {
|
||||
screenAdjustmentUtil.changeScreenOrientation(ScreenLayout.MOBILE_PORTRAIT)
|
||||
screenAdjustmentUtil.changeScreenOrientation(ScreenLayout.MOBILE_LANDSCAPE.int)
|
||||
true
|
||||
}
|
||||
|
||||
R.id.menu_screen_layout_single -> {
|
||||
screenAdjustmentUtil.changeScreenOrientation(ScreenLayout.SINGLE_SCREEN)
|
||||
screenAdjustmentUtil.changeScreenOrientation(ScreenLayout.SINGLE_SCREEN.int)
|
||||
true
|
||||
}
|
||||
|
||||
R.id.menu_screen_layout_sidebyside -> {
|
||||
screenAdjustmentUtil.changeScreenOrientation(ScreenLayout.SIDE_SCREEN)
|
||||
screenAdjustmentUtil.changeScreenOrientation(ScreenLayout.SIDE_SCREEN.int)
|
||||
true
|
||||
}
|
||||
|
||||
R.id.menu_screen_layout_hybrid -> {
|
||||
screenAdjustmentUtil.changeScreenOrientation(ScreenLayout.HYBRID_SCREEN)
|
||||
screenAdjustmentUtil.changeScreenOrientation(ScreenLayout.HYBRID_SCREEN.int)
|
||||
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
|
||||
}
|
||||
|
||||
else -> true
|
||||
}
|
||||
}
|
||||
|
||||
popupMenu.show()
|
||||
}
|
||||
|
||||
private fun showPortraitScreenLayoutMenu() {
|
||||
val popupMenu = PopupMenu(
|
||||
requireContext(),
|
||||
binding.inGameMenu.findViewById(R.id.menu_portrait_screen_layout)
|
||||
)
|
||||
|
||||
popupMenu.menuInflater.inflate(R.menu.menu_portrait_screen_layout, popupMenu.menu)
|
||||
|
||||
val layoutOptionMenuItem = when (IntSetting.PORTRAIT_SCREEN_LAYOUT.int) {
|
||||
PortraitScreenLayout.TOP_FULL_WIDTH.int ->
|
||||
R.id.menu_portrait_layout_top_full
|
||||
|
||||
PortraitScreenLayout.CUSTOM_PORTRAIT_LAYOUT.int ->
|
||||
R.id.menu_portrait_layout_custom
|
||||
|
||||
else ->
|
||||
R.id.menu_portrait_layout_top_full
|
||||
|
||||
}
|
||||
|
||||
popupMenu.menu.findItem(layoutOptionMenuItem).setChecked(true)
|
||||
|
||||
popupMenu.setOnMenuItemClickListener {
|
||||
when (it.itemId) {
|
||||
R.id.menu_portrait_layout_top_full -> {
|
||||
screenAdjustmentUtil.changePortraitOrientation(PortraitScreenLayout.TOP_FULL_WIDTH.int)
|
||||
true
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
@ -869,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()
|
||||
|
||||
@ -899,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()
|
||||
|
||||
@ -959,7 +1070,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram
|
||||
resetScale("controlScale-" + NativeLibrary.ButtonType.BUTTON_SWAP)
|
||||
binding.surfaceInputOverlay.refreshControls()
|
||||
}
|
||||
|
||||
|
||||
private fun setControlOpacity(opacity: Int) {
|
||||
preferences.edit()
|
||||
.putInt("controlOpacity", opacity)
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright 2023 Citra Emulator Project
|
||||
// Copyright Citra Emulator Project / Lime3DS Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
@ -7,7 +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.ScreenLayout
|
||||
|
||||
object EmulationMenuSettings {
|
||||
private val preferences =
|
||||
@ -27,16 +26,7 @@ object EmulationMenuSettings {
|
||||
.putBoolean("EmulationMenuSettings_DpadSlideEnable", value)
|
||||
.apply()
|
||||
}
|
||||
var landscapeScreenLayout: Int
|
||||
get() = preferences.getInt(
|
||||
"EmulationMenuSettings_LandscapeScreenLayout",
|
||||
ScreenLayout.MOBILE_LANDSCAPE.int
|
||||
)
|
||||
set(value) {
|
||||
preferences.edit()
|
||||
.putInt("EmulationMenuSettings_LandscapeScreenLayout", value)
|
||||
.apply()
|
||||
}
|
||||
|
||||
var showFps: Boolean
|
||||
get() = preferences.getBoolean("EmulationMenuSettings_ShowFps", false)
|
||||
set(value) {
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright 2014 Citra Emulator Project
|
||||
// Copyright Citra Emulator Project / Lime3DS Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
@ -174,8 +174,7 @@ void Config::ReadValues() {
|
||||
|
||||
// Layout
|
||||
Settings::values.layout_option = static_cast<Settings::LayoutOption>(sdl2_config->GetInteger(
|
||||
"Layout", "layout_option", static_cast<int>(Settings::LayoutOption::MobileLandscape)));
|
||||
ReadSetting("Layout", Settings::values.custom_layout);
|
||||
"Layout", "layout_option", static_cast<int>(Settings::LayoutOption::LargeScreen)));
|
||||
ReadSetting("Layout", Settings::values.custom_top_x);
|
||||
ReadSetting("Layout", Settings::values.custom_top_y);
|
||||
ReadSetting("Layout", Settings::values.custom_top_width);
|
||||
@ -188,6 +187,19 @@ void Config::ReadValues() {
|
||||
ReadSetting("Layout", Settings::values.cardboard_x_shift);
|
||||
ReadSetting("Layout", Settings::values.cardboard_y_shift);
|
||||
|
||||
Settings::values.portrait_layout_option =
|
||||
static_cast<Settings::PortraitLayoutOption>(sdl2_config->GetInteger(
|
||||
"Layout", "portrait_layout_option",
|
||||
static_cast<int>(Settings::PortraitLayoutOption::PortraitTopFullWidth)));
|
||||
ReadSetting("Layout", Settings::values.custom_portrait_top_x);
|
||||
ReadSetting("Layout", Settings::values.custom_portrait_top_y);
|
||||
ReadSetting("Layout", Settings::values.custom_portrait_top_width);
|
||||
ReadSetting("Layout", Settings::values.custom_portrait_top_height);
|
||||
ReadSetting("Layout", Settings::values.custom_portrait_bottom_x);
|
||||
ReadSetting("Layout", Settings::values.custom_portrait_bottom_y);
|
||||
ReadSetting("Layout", Settings::values.custom_portrait_bottom_width);
|
||||
ReadSetting("Layout", Settings::values.custom_portrait_bottom_height);
|
||||
|
||||
// Utility
|
||||
ReadSetting("Utility", Settings::values.dump_textures);
|
||||
ReadSetting("Utility", Settings::values.custom_textures);
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright 2014 Citra Emulator Project
|
||||
// Copyright Citra Emulator Project / Lime3DS Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
@ -179,16 +179,20 @@ anaglyph_shader_name =
|
||||
filter_mode =
|
||||
|
||||
[Layout]
|
||||
# Layout for the screen inside the render window.
|
||||
# 0 (default): Default Top Bottom Screen, 1: Single Screen Only, 2: Large Screen Small Screen, 3: Side by Side
|
||||
# Layout for the screen inside the render window, landscape mode
|
||||
# 0: Top/Bottom *currently unsupported on android*
|
||||
# 1: Single Screen Only,
|
||||
# 2: *currently unsupported on android*
|
||||
# 3: Side by Side
|
||||
# 4: Hybrid
|
||||
# 5: Custom Layout
|
||||
# 6: (default) Large screen / small screen
|
||||
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.
|
||||
# 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 =
|
||||
@ -198,6 +202,22 @@ custom_bottom_y =
|
||||
custom_bottom_width =
|
||||
custom_bottom_height =
|
||||
|
||||
# Layout for the portrait mode
|
||||
# 0 (default): Top and bottom screens at top, full width
|
||||
# 1: Custom Layout
|
||||
portrait_layout_option =
|
||||
|
||||
# Screen placement when using Portrait Custom layout option
|
||||
# 0x, 0y is the top left corner of the render window.
|
||||
custom_portrait_top_x =
|
||||
custom_portrait_top_y =
|
||||
custom_portrait_top_width =
|
||||
custom_portrait_top_height =
|
||||
custom_portrait_bottom_x =
|
||||
custom_portrait_bottom_y =
|
||||
custom_portrait_bottom_width =
|
||||
custom_portrait_bottom_height =
|
||||
|
||||
# Swaps the prominent screen with the other screen.
|
||||
# For example, if Single Screen is chosen, setting this to 1 will display the bottom screen instead of the top screen.
|
||||
# 0 (default): Top Screen is prominent, 1: Bottom Screen is prominent
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright 2019 Citra Emulator Project
|
||||
// Copyright Citra Emulator Project / Lime3DS Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
@ -21,12 +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()));
|
||||
}
|
||||
|
||||
bool EmuWindow_Android::OnSurfaceChanged(ANativeWindow* surface) {
|
||||
if (render_window == surface) {
|
||||
return false;
|
||||
@ -57,7 +51,6 @@ void EmuWindow_Android::OnTouchMoved(int x, int y) {
|
||||
}
|
||||
|
||||
void EmuWindow_Android::OnFramebufferSizeChanged() {
|
||||
UpdateLandscapeScreenLayout();
|
||||
const bool is_portrait_mode{IsPortraitMode()};
|
||||
|
||||
const int bigger{window_width > window_height ? window_width : window_height};
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright 2019 Citra Emulator Project
|
||||
// Copyright Citra Emulator Project / Lime3DS Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
@ -27,6 +27,7 @@ static jclass s_native_library_class;
|
||||
static jmethodID s_on_core_error;
|
||||
static jmethodID s_is_portrait_mode;
|
||||
static jmethodID s_landscape_screen_layout;
|
||||
static jmethodID s_portrait_screen_layout;
|
||||
static jmethodID s_exit_emulation_activity;
|
||||
static jmethodID s_request_camera_permission;
|
||||
static jmethodID s_request_mic_permission;
|
||||
@ -90,6 +91,10 @@ jmethodID GetLandscapeScreenLayout() {
|
||||
return s_landscape_screen_layout;
|
||||
}
|
||||
|
||||
jmethodID GetPortraitScreenLayout() {
|
||||
return s_portrait_screen_layout;
|
||||
}
|
||||
|
||||
jmethodID GetExitEmulationActivity() {
|
||||
return s_exit_emulation_activity;
|
||||
}
|
||||
@ -172,8 +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_exit_emulation_activity =
|
||||
env->GetStaticMethodID(s_native_library_class, "exitEmulationActivity", "(I)V");
|
||||
s_request_camera_permission =
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright 2019 Citra Emulator Project
|
||||
// Copyright Citra Emulator Project / Lime3DS Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
@ -27,6 +27,7 @@ jmethodID GetDisplayAlertPrompt();
|
||||
jmethodID GetAlertPromptButton();
|
||||
jmethodID GetIsPortraitMode();
|
||||
jmethodID GetLandscapeScreenLayout();
|
||||
jmethodID GetPortraitScreenLayout();
|
||||
jmethodID GetExitEmulationActivity();
|
||||
jmethodID GetRequestCameraPermission();
|
||||
jmethodID GetRequestMicPermission();
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright 2019 Citra Emulator Project
|
||||
// Copyright Citra Emulator Project / Lime3DS Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
@ -346,15 +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) {
|
||||
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(!(rotation % 2));
|
||||
system.GPU().Renderer().UpdateCurrentFramebufferLayout(is_portrait_mode);
|
||||
}
|
||||
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_screen_layout_landscape"
|
||||
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>
|
@ -27,9 +27,15 @@
|
||||
android:icon="@drawable/ic_fit_screen"
|
||||
android:title="@string/emulation_switch_screen_layout" />
|
||||
|
||||
<item
|
||||
android:id="@+id/menu_portrait_screen_layout"
|
||||
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
|
||||
|
@ -7,10 +7,6 @@
|
||||
android:id="@+id/menu_screen_layout_landscape"
|
||||
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" />
|
||||
@ -23,6 +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>
|
||||
|
@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<group android:checkableBehavior="single">
|
||||
|
||||
<item
|
||||
android:id="@+id/menu_portrait_layout_top_full"
|
||||
android:title="@string/emulation_portrait_layout_top_full" />
|
||||
|
||||
<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>
|
||||
@ -359,12 +359,25 @@
|
||||
<string name="emulation_open_settings">Open Settings</string>
|
||||
<string name="emulation_open_cheats">Open Cheats</string>
|
||||
<string name="emulation_switch_screen_layout">Landscape Screen Layout</string>
|
||||
<string name="emulation_switch_portrait_layout">Portrait Screen Layout</string>
|
||||
<string name="emulation_screen_layout_landscape">Default</string>
|
||||
<string name="emulation_screen_layout_portrait">Portrait</string>
|
||||
<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_cycle_landscape_layouts">Cycle Landscape Layouts</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>
|
||||
<string name="emulation_show_overlay">Show Overlay</string>
|
||||
|
@ -1,7 +1,10 @@
|
||||
// Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project
|
||||
// Copyright Citra Emulator Project / Lime3DS Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
// Copyright Dolphin Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
|
||||
#include <array>
|
||||
#include <fstream>
|
||||
#include <limits>
|
||||
@ -707,8 +710,8 @@ std::string AppDataRoamingDirectory() {
|
||||
/**
|
||||
* @return The user’s home directory on POSIX systems
|
||||
*/
|
||||
static const std::string& GetHomeDirectory() {
|
||||
static std::string home_path;
|
||||
const std::string GetHomeDirectory() {
|
||||
std::string home_path;
|
||||
if (home_path.empty()) {
|
||||
const char* envvar = getenv("HOME");
|
||||
if (envvar) {
|
||||
|
@ -1,7 +1,10 @@
|
||||
// Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project
|
||||
// Copyright Citra Emulator Project / Lime3DS Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
// Copyright Dolphin Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
@ -207,6 +210,7 @@ void UpdateUserPath(UserPath path, const std::string& filename);
|
||||
[[nodiscard]] const std::string& GetExeDirectory();
|
||||
[[nodiscard]] std::string AppDataRoamingDirectory();
|
||||
#else
|
||||
[[nodiscard]] const std::string GetHomeDirectory();
|
||||
[[nodiscard]] const std::string GetUserDirectory(const std::string& envvar);
|
||||
#endif
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright 2014 Citra Emulator Project
|
||||
// Copyright Citra Emulator Project / Lime3DS Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
@ -108,6 +108,7 @@ void LogSettings() {
|
||||
log_setting("Renderer_AnaglyphShader", values.anaglyph_shader_name.GetValue());
|
||||
}
|
||||
log_setting("Layout_LayoutOption", values.layout_option.GetValue());
|
||||
log_setting("Layout_PortraitLayoutOption", values.portrait_layout_option.GetValue());
|
||||
log_setting("Layout_SwapScreen", values.swap_screen.GetValue());
|
||||
log_setting("Layout_UprightScreen", values.upright_screen.GetValue());
|
||||
log_setting("Layout_LargeScreenProportion", values.large_screen_proportion.GetValue());
|
||||
@ -196,6 +197,7 @@ void RestoreGlobalState(bool is_powered_on) {
|
||||
values.texture_filter.SetGlobal(true);
|
||||
values.texture_sampling.SetGlobal(true);
|
||||
values.layout_option.SetGlobal(true);
|
||||
values.portrait_layout_option.SetGlobal(true);
|
||||
values.swap_screen.SetGlobal(true);
|
||||
values.upright_screen.SetGlobal(true);
|
||||
values.large_screen_proportion.SetGlobal(true);
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright 2014 Citra Emulator Project
|
||||
// Copyright Citra Emulator Project / Lime3DS Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
@ -33,6 +33,7 @@ enum class InitTicks : u32 {
|
||||
Fixed = 1,
|
||||
};
|
||||
|
||||
/** Defines the layout option for desktop and mobile landscape */
|
||||
enum class LayoutOption : u32 {
|
||||
Default,
|
||||
SingleScreen,
|
||||
@ -42,18 +43,20 @@ enum class LayoutOption : u32 {
|
||||
SeparateWindows,
|
||||
#endif
|
||||
HybridScreen,
|
||||
#ifndef ANDROID // TODO: Implement custom layouts on Android
|
||||
CustomLayout,
|
||||
#endif
|
||||
// Similiar to default, but better for mobile devices in portrait mode. Top screen in clamped to
|
||||
// the top of the frame, and the bottom screen is enlarged to match the top screen.
|
||||
MobilePortrait,
|
||||
|
||||
// Similiar to LargeScreen, but better for mobile devices in landscape mode. The screens are
|
||||
// clamped to the top of the frame, and the bottom screen is a bit bigger.
|
||||
MobileLandscape,
|
||||
};
|
||||
|
||||
/** Defines the layout option for mobile portrait */
|
||||
enum class PortraitLayoutOption : u32 {
|
||||
// formerly mobile portrait
|
||||
PortraitTopFullWidth,
|
||||
PortraitCustomLayout,
|
||||
};
|
||||
|
||||
enum class StereoRenderOption : u32 {
|
||||
Off = 0,
|
||||
SideBySide = 1,
|
||||
@ -482,21 +485,19 @@ struct Values {
|
||||
SwitchableSetting<TextureFilter> texture_filter{TextureFilter::None, "texture_filter"};
|
||||
SwitchableSetting<TextureSampling> texture_sampling{TextureSampling::GameControlled,
|
||||
"texture_sampling"};
|
||||
|
||||
SwitchableSetting<LayoutOption> layout_option{LayoutOption::Default, "layout_option"};
|
||||
SwitchableSetting<bool> swap_screen{false, "swap_screen"};
|
||||
SwitchableSetting<bool> upright_screen{false, "upright_screen"};
|
||||
SwitchableSetting<float, true> large_screen_proportion{4.f, 1.f, 16.f,
|
||||
"large_screen_proportion"};
|
||||
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{400, "custom_top_width"};
|
||||
Setting<u16> custom_top_height{240, "custom_top_height"};
|
||||
Setting<u16> custom_bottom_x{40, "custom_bottom_x"};
|
||||
Setting<u16> custom_bottom_y{240, "custom_bottom_y"};
|
||||
Setting<u16> custom_bottom_width{320, "custom_bottom_width"};
|
||||
Setting<u16> custom_bottom_height{240, "custom_bottom_height"};
|
||||
Setting<u16> custom_top_width{800, "custom_top_width"};
|
||||
Setting<u16> custom_top_height{480, "custom_top_height"};
|
||||
Setting<u16> custom_bottom_x{80, "custom_bottom_x"};
|
||||
Setting<u16> custom_bottom_y{500, "custom_bottom_y"};
|
||||
Setting<u16> custom_bottom_width{640, "custom_bottom_width"};
|
||||
Setting<u16> custom_bottom_height{480, "custom_bottom_height"};
|
||||
Setting<u16> custom_second_layer_opacity{100, "custom_second_layer_opacity"};
|
||||
|
||||
SwitchableSetting<bool> screen_top_stretch{false, "screen_top_stretch"};
|
||||
@ -506,6 +507,17 @@ struct Values {
|
||||
Setting<u16> screen_bottom_leftright_padding{0, "screen_bottom_leftright_padding"};
|
||||
Setting<u16> screen_bottom_topbottom_padding{0, "screen_bottom_topbottom_padding"};
|
||||
|
||||
SwitchableSetting<PortraitLayoutOption> portrait_layout_option{
|
||||
PortraitLayoutOption::PortraitTopFullWidth, "portrait_layout_option"};
|
||||
Setting<u16> custom_portrait_top_x{0, "custom_portrait_top_x"};
|
||||
Setting<u16> custom_portrait_top_y{0, "custom_portrait_top_y"};
|
||||
Setting<u16> custom_portrait_top_width{800, "custom_portrait_top_width"};
|
||||
Setting<u16> custom_portrait_top_height{480, "custom_portrait_top_height"};
|
||||
Setting<u16> custom_portrait_bottom_x{80, "custom_portrait_bottom_x"};
|
||||
Setting<u16> custom_portrait_bottom_y{500, "custom_portrait_bottom_y"};
|
||||
Setting<u16> custom_portrait_bottom_width{640, "custom_portrait_bottom_width"};
|
||||
Setting<u16> custom_portrait_bottom_height{480, "custom_portrait_bottom_height"};
|
||||
|
||||
SwitchableSetting<float> bg_red{0.f, "bg_red"};
|
||||
SwitchableSetting<float> bg_green{0.f, "bg_green"};
|
||||
SwitchableSetting<float> bg_blue{0.f, "bg_blue"};
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright 2014 Citra Emulator Project
|
||||
// Copyright Citra Emulator Project / Lime3DS Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
@ -176,20 +176,33 @@ void EmuWindow::TouchMoved(unsigned framebuffer_x, unsigned framebuffer_y) {
|
||||
void EmuWindow::UpdateCurrentFramebufferLayout(u32 width, u32 height, bool is_portrait_mode) {
|
||||
Layout::FramebufferLayout layout;
|
||||
|
||||
// If in portrait mode, only the MobilePortrait option really makes sense
|
||||
const Settings::LayoutOption layout_option = is_portrait_mode
|
||||
? Settings::LayoutOption::MobilePortrait
|
||||
: Settings::values.layout_option.GetValue();
|
||||
const auto min_size =
|
||||
Layout::GetMinimumSizeFromLayout(layout_option, Settings::values.upright_screen.GetValue());
|
||||
const Settings::LayoutOption layout_option = Settings::values.layout_option.GetValue();
|
||||
const Settings::PortraitLayoutOption portrait_layout_option =
|
||||
Settings::values.portrait_layout_option.GetValue();
|
||||
const auto min_size = is_portrait_mode
|
||||
? Layout::GetMinimumSizeFromPortraitLayout()
|
||||
: Layout::GetMinimumSizeFromLayout(
|
||||
layout_option, Settings::values.upright_screen.GetValue());
|
||||
|
||||
if (Settings::values.custom_layout.GetValue() == true) {
|
||||
layout = Layout::CustomFrameLayout(width, height, Settings::values.swap_screen.GetValue());
|
||||
width = std::max(width, min_size.first);
|
||||
height = std::max(height, min_size.second);
|
||||
if (is_portrait_mode) {
|
||||
switch (portrait_layout_option) {
|
||||
case Settings::PortraitLayoutOption::PortraitTopFullWidth:
|
||||
layout = Layout::PortraitTopFullFrameLayout(width, height,
|
||||
Settings::values.swap_screen.GetValue());
|
||||
break;
|
||||
case Settings::PortraitLayoutOption::PortraitCustomLayout:
|
||||
layout = Layout::CustomFrameLayout(
|
||||
width, height, Settings::values.swap_screen.GetValue(), is_portrait_mode);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
width = std::max(width, min_size.first);
|
||||
height = std::max(height, min_size.second);
|
||||
|
||||
switch (layout_option) {
|
||||
case Settings::LayoutOption::CustomLayout:
|
||||
layout = Layout::CustomFrameLayout(
|
||||
width, height, Settings::values.swap_screen.GetValue(), is_portrait_mode);
|
||||
break;
|
||||
case Settings::LayoutOption::SingleScreen:
|
||||
layout =
|
||||
Layout::SingleFrameLayout(width, height, Settings::values.swap_screen.GetValue(),
|
||||
@ -219,21 +232,12 @@ void EmuWindow::UpdateCurrentFramebufferLayout(u32 width, u32 height, bool is_po
|
||||
Settings::values.upright_screen.GetValue());
|
||||
break;
|
||||
#endif
|
||||
case Settings::LayoutOption::MobilePortrait:
|
||||
layout = Layout::MobilePortraitFrameLayout(width, height,
|
||||
Settings::values.swap_screen.GetValue());
|
||||
break;
|
||||
case Settings::LayoutOption::MobileLandscape:
|
||||
layout =
|
||||
Layout::LargeFrameLayout(width, height, Settings::values.swap_screen.GetValue(),
|
||||
false, 2.25f, Layout::VerticalAlignment::Top);
|
||||
break;
|
||||
#ifndef ANDROID // TODO: Implement custom layouts on Android
|
||||
case Settings::LayoutOption::CustomLayout:
|
||||
layout =
|
||||
Layout::CustomFrameLayout(width, height, Settings::values.swap_screen.GetValue());
|
||||
break;
|
||||
#endif
|
||||
|
||||
case Settings::LayoutOption::Default:
|
||||
default:
|
||||
layout =
|
||||
@ -241,8 +245,9 @@ void EmuWindow::UpdateCurrentFramebufferLayout(u32 width, u32 height, bool is_po
|
||||
Settings::values.upright_screen.GetValue());
|
||||
break;
|
||||
}
|
||||
UpdateMinimumWindowSize(min_size);
|
||||
}
|
||||
UpdateMinimumWindowSize(min_size);
|
||||
|
||||
if (Settings::values.render_3d.GetValue() == Settings::StereoRenderOption::CardboardVR) {
|
||||
layout = Layout::GetCardboardSettings(layout);
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright 2016 Citra Emulator Project
|
||||
// Copyright Citra Emulator Project / Lime3DS Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
@ -117,11 +117,11 @@ FramebufferLayout DefaultFrameLayout(u32 width, u32 height, bool swapped, bool u
|
||||
return res;
|
||||
}
|
||||
|
||||
FramebufferLayout MobilePortraitFrameLayout(u32 width, u32 height, bool swapped) {
|
||||
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
|
||||
@ -382,24 +382,33 @@ FramebufferLayout SeparateWindowsLayout(u32 width, u32 height, bool is_secondary
|
||||
return SingleFrameLayout(width, height, is_secondary, upright);
|
||||
}
|
||||
|
||||
FramebufferLayout CustomFrameLayout(u32 width, u32 height, bool is_swapped) {
|
||||
FramebufferLayout CustomFrameLayout(u32 width, u32 height, bool is_swapped, bool is_portrait_mode) {
|
||||
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()
|
||||
: Settings::values.custom_top_width.GetValue();
|
||||
u16 top_y = is_portrait_mode ? Settings::values.custom_portrait_top_y.GetValue()
|
||||
: Settings::values.custom_top_y.GetValue();
|
||||
u16 top_height = is_portrait_mode ? Settings::values.custom_portrait_top_height.GetValue()
|
||||
: Settings::values.custom_top_height.GetValue();
|
||||
u16 bottom_x = is_portrait_mode ? Settings::values.custom_portrait_bottom_x.GetValue()
|
||||
: Settings::values.custom_bottom_x.GetValue();
|
||||
u16 bottom_width = is_portrait_mode ? Settings::values.custom_portrait_bottom_width.GetValue()
|
||||
: Settings::values.custom_bottom_width.GetValue();
|
||||
u16 bottom_y = is_portrait_mode ? Settings::values.custom_portrait_bottom_y.GetValue()
|
||||
: Settings::values.custom_bottom_y.GetValue();
|
||||
u16 bottom_height = is_portrait_mode ? Settings::values.custom_portrait_bottom_height.GetValue()
|
||||
: Settings::values.custom_bottom_height.GetValue();
|
||||
|
||||
Common::Rectangle<u32> top_screen{Settings::values.custom_top_x.GetValue(),
|
||||
Settings::values.custom_top_y.GetValue(),
|
||||
(u32)(Settings::values.custom_top_x.GetValue() +
|
||||
Settings::values.custom_top_width.GetValue()),
|
||||
(u32)(Settings::values.custom_top_y.GetValue() +
|
||||
Settings::values.custom_top_height.GetValue())};
|
||||
Common::Rectangle<u32> bot_screen{Settings::values.custom_bottom_x.GetValue(),
|
||||
Settings::values.custom_bottom_y.GetValue(),
|
||||
(u32)(Settings::values.custom_bottom_x.GetValue() +
|
||||
Settings::values.custom_bottom_width.GetValue()),
|
||||
(u32)(Settings::values.custom_bottom_y.GetValue() +
|
||||
Settings::values.custom_bottom_height.GetValue())};
|
||||
Common::Rectangle<u32> top_screen{top_x, top_y, (u32)(top_x + top_width),
|
||||
(u32)(top_y + top_height)};
|
||||
Common::Rectangle<u32> bot_screen{bottom_x, bottom_y, (u32)(bottom_x + bottom_width),
|
||||
(u32)(bottom_y + bottom_height)};
|
||||
|
||||
if (is_swapped) {
|
||||
res.top_screen = bot_screen;
|
||||
@ -411,102 +420,126 @@ FramebufferLayout CustomFrameLayout(u32 width, u32 height, bool is_swapped) {
|
||||
return res;
|
||||
}
|
||||
|
||||
FramebufferLayout FrameLayoutFromResolutionScale(u32 res_scale, bool is_secondary) {
|
||||
if (Settings::values.custom_layout.GetValue() == true) {
|
||||
return CustomFrameLayout(std::max(Settings::values.custom_top_width.GetValue(),
|
||||
Settings::values.custom_bottom_width.GetValue()),
|
||||
std::max(Settings::values.custom_top_height.GetValue(),
|
||||
Settings::values.custom_bottom_height.GetValue()),
|
||||
Settings::values.swap_screen.GetValue());
|
||||
}
|
||||
|
||||
FramebufferLayout FrameLayoutFromResolutionScale(u32 res_scale, bool is_secondary,
|
||||
bool is_portrait) {
|
||||
int width, height;
|
||||
switch (Settings::values.layout_option.GetValue()) {
|
||||
case Settings::LayoutOption::SingleScreen:
|
||||
#ifndef ANDROID
|
||||
case Settings::LayoutOption::SeparateWindows:
|
||||
#endif
|
||||
{
|
||||
const bool swap_screens = is_secondary || Settings::values.swap_screen.GetValue();
|
||||
if (swap_screens) {
|
||||
width = Core::kScreenBottomWidth * res_scale;
|
||||
height = Core::kScreenBottomHeight * res_scale;
|
||||
} else {
|
||||
if (is_portrait) {
|
||||
auto layout_option = Settings::values.portrait_layout_option.GetValue();
|
||||
switch (layout_option) {
|
||||
case Settings::PortraitLayoutOption::PortraitCustomLayout:
|
||||
return CustomFrameLayout(
|
||||
std::max(Settings::values.custom_portrait_top_x.GetValue() +
|
||||
Settings::values.custom_portrait_top_width.GetValue(),
|
||||
Settings::values.custom_portrait_bottom_x.GetValue() +
|
||||
Settings::values.custom_portrait_bottom_width.GetValue()),
|
||||
std::max(Settings::values.custom_portrait_top_y.GetValue() +
|
||||
Settings::values.custom_portrait_top_height.GetValue(),
|
||||
Settings::values.custom_portrait_bottom_y.GetValue() +
|
||||
Settings::values.custom_portrait_bottom_height.GetValue()),
|
||||
Settings::values.swap_screen.GetValue(), is_portrait);
|
||||
case Settings::PortraitLayoutOption::PortraitTopFullWidth:
|
||||
width = Core::kScreenTopWidth * res_scale;
|
||||
height = Core::kScreenTopHeight * res_scale;
|
||||
height = (Core::kScreenTopHeight + Core::kScreenBottomHeight) * res_scale;
|
||||
return PortraitTopFullFrameLayout(width, height,
|
||||
Settings::values.swap_screen.GetValue());
|
||||
}
|
||||
if (Settings::values.upright_screen.GetValue()) {
|
||||
std::swap(width, height);
|
||||
}
|
||||
return SingleFrameLayout(width, height, swap_screens,
|
||||
Settings::values.upright_screen.GetValue());
|
||||
}
|
||||
} else {
|
||||
auto layout_option = Settings::values.layout_option.GetValue();
|
||||
switch (layout_option) {
|
||||
case Settings::LayoutOption::CustomLayout:
|
||||
return CustomFrameLayout(std::max(Settings::values.custom_top_x.GetValue() +
|
||||
Settings::values.custom_top_width.GetValue(),
|
||||
Settings::values.custom_bottom_x.GetValue() +
|
||||
Settings::values.custom_bottom_width.GetValue()),
|
||||
std::max(Settings::values.custom_top_y.GetValue() +
|
||||
Settings::values.custom_top_height.GetValue(),
|
||||
Settings::values.custom_bottom_y.GetValue() +
|
||||
Settings::values.custom_bottom_height.GetValue()),
|
||||
Settings::values.swap_screen.GetValue(), is_portrait);
|
||||
|
||||
case Settings::LayoutOption::LargeScreen:
|
||||
if (Settings::values.swap_screen.GetValue()) {
|
||||
width = (Core::kScreenBottomWidth +
|
||||
case Settings::LayoutOption::SingleScreen:
|
||||
#ifndef ANDROID
|
||||
case Settings::LayoutOption::SeparateWindows:
|
||||
#endif
|
||||
{
|
||||
const bool swap_screens = is_secondary || Settings::values.swap_screen.GetValue();
|
||||
if (swap_screens) {
|
||||
width = Core::kScreenBottomWidth * res_scale;
|
||||
height = Core::kScreenBottomHeight * res_scale;
|
||||
} else {
|
||||
width = Core::kScreenTopWidth * res_scale;
|
||||
height = Core::kScreenTopHeight * res_scale;
|
||||
}
|
||||
if (Settings::values.upright_screen.GetValue()) {
|
||||
std::swap(width, height);
|
||||
}
|
||||
return SingleFrameLayout(width, height, swap_screens,
|
||||
Settings::values.upright_screen.GetValue());
|
||||
}
|
||||
|
||||
case Settings::LayoutOption::LargeScreen:
|
||||
if (Settings::values.swap_screen.GetValue()) {
|
||||
width =
|
||||
(Core::kScreenBottomWidth +
|
||||
Core::kScreenTopWidth /
|
||||
static_cast<int>(Settings::values.large_screen_proportion.GetValue())) *
|
||||
res_scale;
|
||||
height = Core::kScreenBottomHeight * res_scale;
|
||||
} else {
|
||||
width = (Core::kScreenTopWidth +
|
||||
height = Core::kScreenBottomHeight * res_scale;
|
||||
} else {
|
||||
width =
|
||||
(Core::kScreenTopWidth +
|
||||
Core::kScreenBottomWidth /
|
||||
static_cast<int>(Settings::values.large_screen_proportion.GetValue())) *
|
||||
res_scale;
|
||||
height = Core::kScreenTopHeight * res_scale;
|
||||
}
|
||||
if (Settings::values.upright_screen.GetValue()) {
|
||||
std::swap(width, height);
|
||||
}
|
||||
return LargeFrameLayout(width, height, Settings::values.swap_screen.GetValue(),
|
||||
Settings::values.upright_screen.GetValue(),
|
||||
Settings::values.large_screen_proportion.GetValue(),
|
||||
VerticalAlignment::Bottom);
|
||||
|
||||
case Settings::LayoutOption::SideScreen:
|
||||
width = (Core::kScreenTopWidth + Core::kScreenBottomWidth) * res_scale;
|
||||
height = Core::kScreenTopHeight * res_scale;
|
||||
|
||||
if (Settings::values.upright_screen.GetValue()) {
|
||||
std::swap(width, height);
|
||||
}
|
||||
return LargeFrameLayout(width, height, Settings::values.swap_screen.GetValue(),
|
||||
Settings::values.upright_screen.GetValue(), 1,
|
||||
VerticalAlignment::Middle);
|
||||
|
||||
case Settings::LayoutOption::MobileLandscape: {
|
||||
constexpr float large_screen_proportion = 2.25f;
|
||||
if (Settings::values.swap_screen.GetValue()) {
|
||||
width = (Core::kScreenBottomWidth +
|
||||
static_cast<int>(Core::kScreenTopWidth / large_screen_proportion)) *
|
||||
res_scale;
|
||||
height = Core::kScreenBottomHeight * res_scale;
|
||||
} else {
|
||||
width = (Core::kScreenTopWidth +
|
||||
static_cast<int>(Core::kScreenBottomWidth / large_screen_proportion)) *
|
||||
res_scale;
|
||||
height = Core::kScreenTopHeight * res_scale;
|
||||
}
|
||||
return LargeFrameLayout(width, height, Settings::values.swap_screen.GetValue(), false,
|
||||
large_screen_proportion, VerticalAlignment::Top);
|
||||
}
|
||||
if (Settings::values.upright_screen.GetValue()) {
|
||||
std::swap(width, height);
|
||||
|
||||
case Settings::LayoutOption::Default:
|
||||
default:
|
||||
width = Core::kScreenTopWidth * res_scale;
|
||||
height = (Core::kScreenTopHeight + Core::kScreenBottomHeight) * res_scale;
|
||||
|
||||
if (Settings::values.upright_screen.GetValue()) {
|
||||
std::swap(width, height);
|
||||
}
|
||||
return DefaultFrameLayout(width, height, Settings::values.swap_screen.GetValue(),
|
||||
Settings::values.upright_screen.GetValue());
|
||||
}
|
||||
return LargeFrameLayout(width, height, Settings::values.swap_screen.GetValue(),
|
||||
Settings::values.upright_screen.GetValue(),
|
||||
Settings::values.large_screen_proportion.GetValue(),
|
||||
VerticalAlignment::Bottom);
|
||||
|
||||
case Settings::LayoutOption::SideScreen:
|
||||
width = (Core::kScreenTopWidth + Core::kScreenBottomWidth) * res_scale;
|
||||
height = Core::kScreenTopHeight * res_scale;
|
||||
|
||||
if (Settings::values.upright_screen.GetValue()) {
|
||||
std::swap(width, height);
|
||||
}
|
||||
return LargeFrameLayout(width, height, Settings::values.swap_screen.GetValue(),
|
||||
Settings::values.upright_screen.GetValue(), 1,
|
||||
VerticalAlignment::Middle);
|
||||
|
||||
case Settings::LayoutOption::MobilePortrait:
|
||||
width = Core::kScreenTopWidth * res_scale;
|
||||
height = (Core::kScreenTopHeight + Core::kScreenBottomHeight) * res_scale;
|
||||
return MobilePortraitFrameLayout(width, height, Settings::values.swap_screen.GetValue());
|
||||
|
||||
case Settings::LayoutOption::MobileLandscape: {
|
||||
constexpr float large_screen_proportion = 2.25f;
|
||||
if (Settings::values.swap_screen.GetValue()) {
|
||||
width = (Core::kScreenBottomWidth +
|
||||
static_cast<int>(Core::kScreenTopWidth / large_screen_proportion)) *
|
||||
res_scale;
|
||||
height = Core::kScreenBottomHeight * res_scale;
|
||||
} else {
|
||||
width = (Core::kScreenTopWidth +
|
||||
static_cast<int>(Core::kScreenBottomWidth / large_screen_proportion)) *
|
||||
res_scale;
|
||||
height = Core::kScreenTopHeight * res_scale;
|
||||
}
|
||||
return LargeFrameLayout(width, height, Settings::values.swap_screen.GetValue(), false,
|
||||
large_screen_proportion, VerticalAlignment::Top);
|
||||
}
|
||||
|
||||
case Settings::LayoutOption::Default:
|
||||
default:
|
||||
width = Core::kScreenTopWidth * res_scale;
|
||||
height = (Core::kScreenTopHeight + Core::kScreenBottomHeight) * res_scale;
|
||||
|
||||
if (Settings::values.upright_screen.GetValue()) {
|
||||
std::swap(width, height);
|
||||
}
|
||||
return DefaultFrameLayout(width, height, Settings::values.swap_screen.GetValue(),
|
||||
Settings::values.upright_screen.GetValue());
|
||||
}
|
||||
UNREACHABLE();
|
||||
}
|
||||
@ -529,11 +562,27 @@ FramebufferLayout GetCardboardSettings(const FramebufferLayout& layout) {
|
||||
|
||||
u32 cardboard_screen_width;
|
||||
u32 cardboard_screen_height;
|
||||
switch (Settings::values.layout_option.GetValue()) {
|
||||
case Settings::LayoutOption::MobileLandscape:
|
||||
case Settings::LayoutOption::SideScreen:
|
||||
// If orientation is portrait, only use MobilePortrait
|
||||
if (!is_portrait) {
|
||||
if (is_portrait) {
|
||||
switch (Settings::values.portrait_layout_option.GetValue()) {
|
||||
case Settings::PortraitLayoutOption::PortraitTopFullWidth:
|
||||
cardboard_screen_width = top_screen_width;
|
||||
cardboard_screen_height = top_screen_height + bottom_screen_height;
|
||||
bottom_screen_left += (top_screen_width - bottom_screen_width) / 2;
|
||||
if (is_swapped)
|
||||
top_screen_top += bottom_screen_height;
|
||||
else
|
||||
bottom_screen_top += top_screen_height;
|
||||
break;
|
||||
default:
|
||||
cardboard_screen_width = is_swapped ? bottom_screen_width : top_screen_width;
|
||||
cardboard_screen_height = is_swapped ? bottom_screen_height : top_screen_height;
|
||||
}
|
||||
} else {
|
||||
switch (Settings::values.layout_option.GetValue()) {
|
||||
case Settings::LayoutOption::MobileLandscape:
|
||||
case Settings::LayoutOption::SideScreen:
|
||||
// If orientation is portrait, only use MobilePortrait
|
||||
|
||||
cardboard_screen_width = top_screen_width + bottom_screen_width;
|
||||
cardboard_screen_height = is_swapped ? bottom_screen_height : top_screen_height;
|
||||
if (is_swapped)
|
||||
@ -541,28 +590,14 @@ FramebufferLayout GetCardboardSettings(const FramebufferLayout& layout) {
|
||||
else
|
||||
bottom_screen_left += top_screen_width;
|
||||
break;
|
||||
} else {
|
||||
[[fallthrough]];
|
||||
}
|
||||
case Settings::LayoutOption::SingleScreen:
|
||||
default:
|
||||
if (!is_portrait) {
|
||||
// Default values when using LayoutOption::SingleScreen
|
||||
|
||||
case Settings::LayoutOption::SingleScreen:
|
||||
default:
|
||||
|
||||
cardboard_screen_width = is_swapped ? bottom_screen_width : top_screen_width;
|
||||
cardboard_screen_height = is_swapped ? bottom_screen_height : top_screen_height;
|
||||
break;
|
||||
} else {
|
||||
[[fallthrough]];
|
||||
}
|
||||
case Settings::LayoutOption::MobilePortrait:
|
||||
cardboard_screen_width = top_screen_width;
|
||||
cardboard_screen_height = top_screen_height + bottom_screen_height;
|
||||
bottom_screen_left += (top_screen_width - bottom_screen_width) / 2;
|
||||
if (is_swapped)
|
||||
top_screen_top += bottom_screen_height;
|
||||
else
|
||||
bottom_screen_top += top_screen_height;
|
||||
break;
|
||||
}
|
||||
s32 cardboard_max_x_shift = (layout.width / 2 - cardboard_screen_width) / 2;
|
||||
s32 cardboard_user_x_shift =
|
||||
@ -596,6 +631,13 @@ FramebufferLayout GetCardboardSettings(const FramebufferLayout& layout) {
|
||||
return new_layout;
|
||||
}
|
||||
|
||||
std::pair<unsigned, unsigned> GetMinimumSizeFromPortraitLayout() {
|
||||
u32 min_width, min_height;
|
||||
min_width = Core::kScreenTopWidth;
|
||||
min_height = Core::kScreenTopHeight + Core::kScreenBottomHeight;
|
||||
return std::make_pair(min_width, min_height);
|
||||
}
|
||||
|
||||
std::pair<unsigned, unsigned> GetMinimumSizeFromLayout(Settings::LayoutOption layout,
|
||||
bool upright_screen) {
|
||||
u32 min_width, min_height;
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright 2016 Citra Emulator Project
|
||||
// Copyright Citra Emulator Project / Lime3DS Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -85,13 +85,14 @@ struct FramebufferLayout {
|
||||
FramebufferLayout DefaultFrameLayout(u32 width, u32 height, bool is_swapped, bool upright);
|
||||
|
||||
/**
|
||||
* Factory method for constructing a mobile portrait FramebufferLayout
|
||||
* Factory method for constructing the mobile Full Width Top layout
|
||||
* Two screens at top, full width, no gap between them
|
||||
* @param width Window framebuffer width in pixels
|
||||
* @param height Window framebuffer height in pixels
|
||||
* @param is_swapped if true, the bottom screen will be displayed above the top screen
|
||||
* @return Newly created FramebufferLayout object with mobile portrait screen regions initialized
|
||||
*/
|
||||
FramebufferLayout MobilePortraitFrameLayout(u32 width, u32 height, bool is_swapped);
|
||||
FramebufferLayout PortraitTopFullFrameLayout(u32 width, u32 height, bool is_swapped);
|
||||
|
||||
/**
|
||||
* Factory method for constructing a FramebufferLayout with only the top or bottom screen
|
||||
@ -145,14 +146,17 @@ FramebufferLayout SeparateWindowsLayout(u32 width, u32 height, bool is_secondary
|
||||
* @param height Window framebuffer height in pixels
|
||||
* @return Newly created FramebufferLayout object with default screen regions initialized
|
||||
*/
|
||||
FramebufferLayout CustomFrameLayout(u32 width, u32 height, bool is_swapped);
|
||||
FramebufferLayout CustomFrameLayout(u32 width, u32 height, bool is_swapped,
|
||||
bool is_portrait_mode = false);
|
||||
|
||||
/**
|
||||
* Convenience method to get frame layout by resolution scale
|
||||
* Read from the current settings to determine which layout to use.
|
||||
* @param res_scale resolution scale factor
|
||||
* @param is_portrait_mode defaults to false
|
||||
*/
|
||||
FramebufferLayout FrameLayoutFromResolutionScale(u32 res_scale, bool is_secondary = false);
|
||||
FramebufferLayout FrameLayoutFromResolutionScale(u32 res_scale, bool is_secondary = false,
|
||||
bool is_portrait_mode = false);
|
||||
|
||||
/**
|
||||
* Convenience method for transforming a frame layout when using Cardboard VR
|
||||
@ -164,4 +168,6 @@ FramebufferLayout GetCardboardSettings(const FramebufferLayout& layout);
|
||||
std::pair<unsigned, unsigned> GetMinimumSizeFromLayout(Settings::LayoutOption layout,
|
||||
bool upright_screen);
|
||||
|
||||
std::pair<unsigned, unsigned> GetMinimumSizeFromPortraitLayout();
|
||||
|
||||
} // namespace Layout
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright 2014 Citra Emulator Project
|
||||
// Copyright Citra Emulator Project / Lime3DS Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
@ -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);
|
||||
@ -183,6 +181,16 @@ void Config::ReadValues() {
|
||||
ReadSetting("Layout", Settings::values.screen_bottom_leftright_padding);
|
||||
ReadSetting("Layout", Settings::values.screen_bottom_topbottom_padding);
|
||||
|
||||
ReadSetting("Layout", Settings::values.portrait_layout_option);
|
||||
ReadSetting("Layout", Settings::values.custom_portrait_top_x);
|
||||
ReadSetting("Layout", Settings::values.custom_portrait_top_y);
|
||||
ReadSetting("Layout", Settings::values.custom_portrait_top_width);
|
||||
ReadSetting("Layout", Settings::values.custom_portrait_top_height);
|
||||
ReadSetting("Layout", Settings::values.custom_portrait_bottom_x);
|
||||
ReadSetting("Layout", Settings::values.custom_portrait_bottom_y);
|
||||
ReadSetting("Layout", Settings::values.custom_portrait_bottom_width);
|
||||
ReadSetting("Layout", Settings::values.custom_portrait_bottom_height);
|
||||
|
||||
// Utility
|
||||
ReadSetting("Utility", Settings::values.dump_textures);
|
||||
ReadSetting("Utility", Settings::values.custom_textures);
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright 2014 Citra Emulator Project
|
||||
// Copyright Citra Emulator Project / Lime3DS Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
@ -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 =
|
||||
|
@ -415,7 +415,7 @@ int main(int argc, char** argv) {
|
||||
return -1;
|
||||
case Core::System::ResultStatus::ErrorLoader_ErrorEncrypted:
|
||||
LOG_CRITICAL(Frontend, "The game that you are trying to load must be decrypted before "
|
||||
"being used with Lime. \n\n For more information on dumping and "
|
||||
"being used with Lime3DS. \n\n For more information on dumping and "
|
||||
"decrypting games, please refer to: "
|
||||
"https://web.archive.org/web/20240304210021/https://citra-emu.org/"
|
||||
"wiki/dumping-game-cartridges/");
|
||||
|
@ -28,9 +28,6 @@ add_executable(lime-qt
|
||||
camera/qt_multimedia_camera.cpp
|
||||
camera/qt_multimedia_camera.h
|
||||
lime-qt.rc
|
||||
compatdb.cpp
|
||||
compatdb.h
|
||||
compatdb.ui
|
||||
configuration/config.cpp
|
||||
configuration/config.h
|
||||
configuration/configure.ui
|
||||
@ -334,10 +331,6 @@ target_compile_definitions(lime-qt PRIVATE
|
||||
-DQT_NO_CAST_TO_ASCII
|
||||
)
|
||||
|
||||
if (CITRA_ENABLE_COMPATIBILITY_REPORTING)
|
||||
target_compile_definitions(lime-qt PRIVATE -DCITRA_ENABLE_COMPATIBILITY_REPORTING)
|
||||
endif()
|
||||
|
||||
if (USE_DISCORD_PRESENCE)
|
||||
target_sources(lime-qt PUBLIC
|
||||
discord_impl.cpp
|
||||
|
@ -1,81 +0,0 @@
|
||||
// Copyright 2017 Citra Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <QButtonGroup>
|
||||
#include <QMessageBox>
|
||||
#include <QPushButton>
|
||||
#include <QtConcurrent/qtconcurrentrun.h>
|
||||
#include "core/core.h"
|
||||
#include "lime_qt/compatdb.h"
|
||||
#include "ui_compatdb.h"
|
||||
|
||||
CompatDB::CompatDB(QWidget* parent)
|
||||
: QWizard(parent, Qt::WindowTitleHint | Qt::WindowCloseButtonHint | Qt::WindowSystemMenuHint),
|
||||
ui{std::make_unique<Ui::CompatDB>()} {
|
||||
ui->setupUi(this);
|
||||
connect(ui->radioButton_Perfect, &QRadioButton::clicked, this, &CompatDB::EnableNext);
|
||||
connect(ui->radioButton_Great, &QRadioButton::clicked, this, &CompatDB::EnableNext);
|
||||
connect(ui->radioButton_Okay, &QRadioButton::clicked, this, &CompatDB::EnableNext);
|
||||
connect(ui->radioButton_Bad, &QRadioButton::clicked, this, &CompatDB::EnableNext);
|
||||
connect(ui->radioButton_IntroMenu, &QRadioButton::clicked, this, &CompatDB::EnableNext);
|
||||
connect(ui->radioButton_WontBoot, &QRadioButton::clicked, this, &CompatDB::EnableNext);
|
||||
connect(button(NextButton), &QPushButton::clicked, this, &CompatDB::Submit);
|
||||
connect(&testcase_watcher, &QFutureWatcher<bool>::finished, this,
|
||||
&CompatDB::OnTestcaseSubmitted);
|
||||
}
|
||||
|
||||
CompatDB::~CompatDB() = default;
|
||||
|
||||
enum class CompatDBPage {
|
||||
Intro = 0,
|
||||
Selection = 1,
|
||||
Final = 2,
|
||||
};
|
||||
|
||||
void CompatDB::Submit() {
|
||||
QButtonGroup* compatibility = new QButtonGroup(this);
|
||||
compatibility->addButton(ui->radioButton_Perfect, 0);
|
||||
compatibility->addButton(ui->radioButton_Great, 1);
|
||||
compatibility->addButton(ui->radioButton_Okay, 2);
|
||||
compatibility->addButton(ui->radioButton_Bad, 3);
|
||||
compatibility->addButton(ui->radioButton_IntroMenu, 4);
|
||||
compatibility->addButton(ui->radioButton_WontBoot, 5);
|
||||
switch ((static_cast<CompatDBPage>(currentId()))) {
|
||||
case CompatDBPage::Selection:
|
||||
if (compatibility->checkedId() == -1) {
|
||||
button(NextButton)->setEnabled(false);
|
||||
}
|
||||
break;
|
||||
case CompatDBPage::Final:
|
||||
back();
|
||||
LOG_DEBUG(Frontend, "Compatibility Rating: {}", compatibility->checkedId());
|
||||
|
||||
button(NextButton)->setEnabled(false);
|
||||
button(NextButton)->setText(tr("Submitting"));
|
||||
button(CancelButton)->setVisible(false);
|
||||
|
||||
break;
|
||||
default:
|
||||
LOG_ERROR(Frontend, "Unexpected page: {}", currentId());
|
||||
}
|
||||
}
|
||||
|
||||
void CompatDB::OnTestcaseSubmitted() {
|
||||
if (!testcase_watcher.result()) {
|
||||
QMessageBox::critical(this, tr("Communication error"),
|
||||
tr("An error occurred while sending the Testcase"));
|
||||
button(NextButton)->setEnabled(true);
|
||||
button(NextButton)->setText(tr("Next"));
|
||||
button(CancelButton)->setVisible(true);
|
||||
} else {
|
||||
next();
|
||||
// older versions of QT don't support the "NoCancelButtonOnLastPage" option, this is a
|
||||
// workaround
|
||||
button(CancelButton)->setVisible(false);
|
||||
}
|
||||
}
|
||||
|
||||
void CompatDB::EnableNext() {
|
||||
button(NextButton)->setEnabled(true);
|
||||
}
|
@ -1,30 +0,0 @@
|
||||
// Copyright 2017 Citra Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <QFutureWatcher>
|
||||
#include <QWizard>
|
||||
|
||||
namespace Ui {
|
||||
class CompatDB;
|
||||
}
|
||||
|
||||
class CompatDB : public QWizard {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit CompatDB(QWidget* parent = nullptr);
|
||||
~CompatDB();
|
||||
|
||||
private:
|
||||
QFutureWatcher<bool> testcase_watcher;
|
||||
|
||||
std::unique_ptr<Ui::CompatDB> ui;
|
||||
|
||||
void Submit();
|
||||
void OnTestcaseSubmitted();
|
||||
void EnableNext();
|
||||
};
|
@ -1,215 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>CompatDB</class>
|
||||
<widget class="QWizard" name="CompatDB">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>600</width>
|
||||
<height>482</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>500</width>
|
||||
<height>410</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Report Compatibility</string>
|
||||
</property>
|
||||
<property name="options">
|
||||
<set>QWizard::DisabledBackButtonOnLastPage|QWizard::HelpButtonOnRight|QWizard::NoBackButtonOnStartPage</set>
|
||||
</property>
|
||||
<widget class="QWizardPage" name="wizard_Info">
|
||||
<property name="title">
|
||||
<string>Report Game Compatibility</string>
|
||||
</property>
|
||||
<attribute name="pageId">
|
||||
<string notr="true">0</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="lbl_Spiel">
|
||||
<property name="text">
|
||||
<string><html><head/><body><p><span style=" font-size:10pt;">Should you choose to submit a test case to the </span><a href="https://citra-emu.org/game/"><span style=" font-size:10pt; text-decoration: underline; color:#0000ff;">Lime3DS Compatibility List</span></a><span style=" font-size:10pt;">, The following information will be collected and displayed on the site:</span></p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Hardware Information (CPU / GPU / Operating System)</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Which version of Lime3DS you are running</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The connected Citra account</li></ul></body></html></string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="openExternalLinks">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWizardPage" name="wizard_Report">
|
||||
<property name="title">
|
||||
<string>Report Game Compatibility</string>
|
||||
</property>
|
||||
<attribute name="pageId">
|
||||
<string notr="true">1</string>
|
||||
</attribute>
|
||||
<layout class="QFormLayout" name="formLayout">
|
||||
<item row="2" column="0">
|
||||
<widget class="QRadioButton" name="radioButton_Perfect">
|
||||
<property name="text">
|
||||
<string>Perfect</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QLabel" name="lbl_Perfect">
|
||||
<property name="text">
|
||||
<string><html><head/><body><p>Game functions flawlessly with no audio or graphical glitches.</p></body></html></string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QRadioButton" name="radioButton_Great">
|
||||
<property name="text">
|
||||
<string>Great</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QLabel" name="lbl_Great">
|
||||
<property name="text">
|
||||
<string><html><head/><body><p>Game functions with minor graphical or audio glitches and is playable from start to finish. May require some workarounds.</p></body></html></string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QRadioButton" name="radioButton_Okay">
|
||||
<property name="text">
|
||||
<string>Okay</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<widget class="QLabel" name="lbl_Okay">
|
||||
<property name="text">
|
||||
<string><html><head/><body><p>Game functions with major graphical or audio glitches, but game is playable from start to finish with workarounds.</p></body></html></string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<widget class="QRadioButton" name="radioButton_Bad">
|
||||
<property name="text">
|
||||
<string>Bad</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="1">
|
||||
<widget class="QLabel" name="lbl_Bad">
|
||||
<property name="text">
|
||||
<string><html><head/><body><p>Game functions, but with major graphical or audio glitches. Unable to progress in specific areas due to glitches even with workarounds.</p></body></html></string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="0">
|
||||
<widget class="QRadioButton" name="radioButton_IntroMenu">
|
||||
<property name="text">
|
||||
<string>Intro/Menu</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="1">
|
||||
<widget class="QLabel" name="lbl_IntroMenu">
|
||||
<property name="text">
|
||||
<string><html><head/><body><p>Game is completely unplayable due to major graphical or audio glitches. Unable to progress past the Start Screen.</p></body></html></string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="0">
|
||||
<widget class="QRadioButton" name="radioButton_WontBoot">
|
||||
<property name="text">
|
||||
<string>Won't Boot</string>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="1">
|
||||
<widget class="QLabel" name="lbl_WontBoot">
|
||||
<property name="text">
|
||||
<string><html><head/><body><p>The game crashes when attempting to startup.</p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0" colspan="2">
|
||||
<widget class="QLabel" name="lbl_Independent">
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>10</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string><html><head/><body><p>Independent of speed or performance, how well does this game play from start to finish on this version of Lime?</p></body></html></string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0" colspan="2">
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWizardPage" name="wizard_ThankYou">
|
||||
<property name="title">
|
||||
<string>Thank you for your submission!</string>
|
||||
</property>
|
||||
<attribute name="pageId">
|
||||
<string notr="true">2</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
@ -1,4 +1,4 @@
|
||||
// Copyright 2014 Citra Emulator Project
|
||||
// Copyright Citra Emulator Project / Lime3DS Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
@ -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);
|
||||
@ -538,6 +536,15 @@ void Config::ReadLayoutValues() {
|
||||
ReadBasicSetting(Settings::values.screen_bottom_stretch);
|
||||
ReadBasicSetting(Settings::values.screen_bottom_leftright_padding);
|
||||
ReadBasicSetting(Settings::values.screen_bottom_topbottom_padding);
|
||||
ReadBasicSetting(Settings::values.portrait_layout_option);
|
||||
ReadBasicSetting(Settings::values.custom_portrait_top_x);
|
||||
ReadBasicSetting(Settings::values.custom_portrait_top_y);
|
||||
ReadBasicSetting(Settings::values.custom_portrait_top_width);
|
||||
ReadBasicSetting(Settings::values.custom_portrait_top_height);
|
||||
ReadBasicSetting(Settings::values.custom_portrait_bottom_x);
|
||||
ReadBasicSetting(Settings::values.custom_portrait_bottom_y);
|
||||
ReadBasicSetting(Settings::values.custom_portrait_bottom_width);
|
||||
ReadBasicSetting(Settings::values.custom_portrait_bottom_height);
|
||||
}
|
||||
|
||||
qt_config->endGroup();
|
||||
@ -1072,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);
|
||||
@ -1090,6 +1095,14 @@ void Config::SaveLayoutValues() {
|
||||
WriteBasicSetting(Settings::values.screen_bottom_stretch);
|
||||
WriteBasicSetting(Settings::values.screen_bottom_leftright_padding);
|
||||
WriteBasicSetting(Settings::values.screen_bottom_topbottom_padding);
|
||||
WriteBasicSetting(Settings::values.custom_portrait_top_x);
|
||||
WriteBasicSetting(Settings::values.custom_portrait_top_y);
|
||||
WriteBasicSetting(Settings::values.custom_portrait_top_width);
|
||||
WriteBasicSetting(Settings::values.custom_portrait_top_height);
|
||||
WriteBasicSetting(Settings::values.custom_portrait_bottom_x);
|
||||
WriteBasicSetting(Settings::values.custom_portrait_bottom_y);
|
||||
WriteBasicSetting(Settings::values.custom_portrait_bottom_width);
|
||||
WriteBasicSetting(Settings::values.custom_portrait_bottom_height);
|
||||
}
|
||||
|
||||
qt_config->endGroup();
|
||||
|
@ -46,7 +46,6 @@
|
||||
#include "lime_qt/bootmanager.h"
|
||||
#include "lime_qt/camera/qt_multimedia_camera.h"
|
||||
#include "lime_qt/camera/still_image_camera.h"
|
||||
#include "lime_qt/compatdb.h"
|
||||
#include "lime_qt/compatibility_list.h"
|
||||
#include "lime_qt/configuration/config.h"
|
||||
#include "lime_qt/configuration/configure_dialog.h"
|
||||
@ -97,7 +96,6 @@
|
||||
#include "core/savestate.h"
|
||||
#include "core/system_titles.h"
|
||||
#include "input_common/main.h"
|
||||
#include "network/network_settings.h"
|
||||
#include "ui_main.h"
|
||||
#include "video_core/gpu.h"
|
||||
#include "video_core/renderer_base.h"
|
||||
@ -339,9 +337,6 @@ GMainWindow::~GMainWindow() {
|
||||
}
|
||||
|
||||
void GMainWindow::InitializeWidgets() {
|
||||
#ifdef CITRA_ENABLE_COMPATIBILITY_REPORTING
|
||||
ui->action_Report_Compatibility->setVisible(true);
|
||||
#endif
|
||||
render_window = new GRenderWindow(this, emu_thread.get(), system, false);
|
||||
secondary_window = new GRenderWindow(this, emu_thread.get(), system, true);
|
||||
render_window->hide();
|
||||
@ -640,8 +635,6 @@ void GMainWindow::InitializeHotkeys() {
|
||||
link_action_shortcut(ui->action_Screen_Layout_Swap_Screens, QStringLiteral("Swap Screens"));
|
||||
link_action_shortcut(ui->action_Screen_Layout_Upright_Screens,
|
||||
QStringLiteral("Rotate Screens Upright"));
|
||||
link_action_shortcut(ui->action_Enable_Frame_Advancing,
|
||||
QStringLiteral("Toggle Frame Advancing"));
|
||||
link_action_shortcut(ui->action_Advance_Frame, QStringLiteral("Advance Frame"));
|
||||
link_action_shortcut(ui->action_Load_from_Newest_Slot, QStringLiteral("Load from Newest Slot"));
|
||||
link_action_shortcut(ui->action_Save_to_Oldest_Slot, QStringLiteral("Save to Oldest Slot"));
|
||||
@ -897,7 +890,10 @@ void GMainWindow::ConnectMenuEvents() {
|
||||
connect_menu(ui->action_Pause, &GMainWindow::OnPauseContinueGame);
|
||||
connect_menu(ui->action_Stop, &GMainWindow::OnStopGame);
|
||||
connect_menu(ui->action_Restart, [this] { BootGame(QString(game_path)); });
|
||||
connect_menu(ui->action_Report_Compatibility, &GMainWindow::OnMenuReportCompatibility);
|
||||
connect_menu(ui->action_Report_Compatibility, []() {
|
||||
QDesktopServices::openUrl(QUrl(QStringLiteral(
|
||||
"https://github.com/Lime3DS/compatibility-list/blob/master/CONTRIBUTING.md")));
|
||||
});
|
||||
connect_menu(ui->action_Configure, &GMainWindow::OnConfigure);
|
||||
connect_menu(ui->action_Configure_Current_Game, &GMainWindow::OnConfigurePerGame);
|
||||
|
||||
@ -937,16 +933,8 @@ void GMainWindow::ConnectMenuEvents() {
|
||||
connect_menu(ui->action_Save_Movie, &GMainWindow::OnSaveMovie);
|
||||
connect_menu(ui->action_Movie_Read_Only_Mode,
|
||||
[this](bool checked) { movie.SetReadOnly(checked); });
|
||||
connect_menu(ui->action_Enable_Frame_Advancing, [this] {
|
||||
if (emulation_running) {
|
||||
system.frame_limiter.SetFrameAdvancing(ui->action_Enable_Frame_Advancing->isChecked());
|
||||
ui->action_Advance_Frame->setEnabled(ui->action_Enable_Frame_Advancing->isChecked());
|
||||
}
|
||||
});
|
||||
connect_menu(ui->action_Advance_Frame, [this] {
|
||||
if (emulation_running && system.frame_limiter.IsFrameAdvancing()) {
|
||||
ui->action_Enable_Frame_Advancing->setChecked(true);
|
||||
ui->action_Advance_Frame->setEnabled(true);
|
||||
system.frame_limiter.AdvanceFrame();
|
||||
}
|
||||
});
|
||||
@ -971,7 +959,8 @@ void GMainWindow::ConnectMenuEvents() {
|
||||
}
|
||||
|
||||
void GMainWindow::UpdateMenuState() {
|
||||
const bool is_paused = !emu_thread || !emu_thread->IsRunning();
|
||||
const bool is_paused =
|
||||
!emu_thread || !emu_thread->IsRunning() || system.frame_limiter.IsFrameAdvancing();
|
||||
|
||||
const std::array running_actions{
|
||||
ui->action_Stop,
|
||||
@ -989,6 +978,7 @@ void GMainWindow::UpdateMenuState() {
|
||||
}
|
||||
|
||||
ui->action_Capture_Screenshot->setEnabled(emulation_running && !is_paused);
|
||||
ui->action_Advance_Frame->setEnabled(emulation_running && is_paused);
|
||||
|
||||
if (emulation_running && is_paused) {
|
||||
ui->action_Pause->setText(tr("&Continue"));
|
||||
@ -1408,12 +1398,7 @@ void GMainWindow::BootGame(const QString& filename) {
|
||||
movie_playback_path.clear();
|
||||
}
|
||||
|
||||
if (ui->action_Enable_Frame_Advancing->isChecked()) {
|
||||
ui->action_Advance_Frame->setEnabled(true);
|
||||
system.frame_limiter.SetFrameAdvancing(true);
|
||||
} else {
|
||||
ui->action_Advance_Frame->setEnabled(false);
|
||||
}
|
||||
ui->action_Advance_Frame->setEnabled(false);
|
||||
|
||||
if (video_dumping_on_start) {
|
||||
StartVideoDumping(video_dumping_path);
|
||||
@ -1770,9 +1755,9 @@ void GMainWindow::OnGameListRemovePlayTimeData(u64 program_id) {
|
||||
bool GMainWindow::CreateShortcutLink(const std::filesystem::path& shortcut_path,
|
||||
const std::string& comment,
|
||||
const std::filesystem::path& icon_path,
|
||||
const std::filesystem::path& command,
|
||||
const std::string& arguments, const std::string& categories,
|
||||
const std::string& keywords, const std::string& name) try {
|
||||
const std::string& command, const std::string& arguments,
|
||||
const std::string& categories, const std::string& keywords,
|
||||
const std::string& name, const bool& skip_tryexec) try {
|
||||
#if defined(__linux__) || defined(__FreeBSD__) // Linux and FreeBSD
|
||||
std::filesystem::path shortcut_path_full = shortcut_path / (name + ".desktop");
|
||||
std::ofstream shortcut_stream(shortcut_path_full, std::ios::binary | std::ios::trunc);
|
||||
@ -1791,8 +1776,10 @@ bool GMainWindow::CreateShortcutLink(const std::filesystem::path& shortcut_path,
|
||||
if (std::filesystem::is_regular_file(icon_path)) {
|
||||
fmt::print(shortcut_stream, "Icon={}\n", icon_path.string());
|
||||
}
|
||||
fmt::print(shortcut_stream, "TryExec={}\n", command.string());
|
||||
fmt::print(shortcut_stream, "Exec={} {}\n", command.string(), arguments);
|
||||
if (!skip_tryexec) {
|
||||
fmt::print(shortcut_stream, "TryExec={}\n", command);
|
||||
}
|
||||
fmt::print(shortcut_stream, "Exec={} {}\n", command, arguments);
|
||||
if (!categories.empty()) {
|
||||
fmt::print(shortcut_stream, "Categories={}\n", categories);
|
||||
}
|
||||
@ -1823,7 +1810,7 @@ bool GMainWindow::CreateShortcutLink(const std::filesystem::path& shortcut_path,
|
||||
LOG_ERROR(Frontend, "Failed to create IShellLinkW instance");
|
||||
return false;
|
||||
}
|
||||
hres = ps1->SetPath(command.c_str());
|
||||
hres = ps1->SetPath(Common::UTF8ToUTF16W(command).data());
|
||||
if (FAILED(hres)) {
|
||||
LOG_ERROR(Frontend, "Failed to set path");
|
||||
return false;
|
||||
@ -1902,16 +1889,16 @@ bool GMainWindow::CreateShortcutMessagesGUI(QWidget* parent, int message,
|
||||
|
||||
bool GMainWindow::MakeShortcutIcoPath(const u64 program_id, const std::string_view game_file_name,
|
||||
std::filesystem::path& out_icon_path) {
|
||||
// Get path to Citra icons directory & icon extension
|
||||
// Get path to Lime3DS icons directory & icon extension
|
||||
std::string ico_extension = "png";
|
||||
#if defined(_WIN32)
|
||||
out_icon_path = FileUtil::GetUserPath(FileUtil::UserPath::IconsDir);
|
||||
ico_extension = "ico";
|
||||
#elif defined(__linux__) || defined(__FreeBSD__)
|
||||
out_icon_path = FileUtil::GetUserDirectory("XDG_DATA_HOME") + "/icons/hicolor/256x256";
|
||||
out_icon_path = FileUtil::GetUserDirectory("XDG_DATA_HOME") + "/icons/hicolor/256x256/";
|
||||
#endif
|
||||
// Create icons directory if it doesn't exist
|
||||
if (!FileUtil::CreateDir(out_icon_path.string())) {
|
||||
if (!FileUtil::CreateFullPath(out_icon_path.string())) {
|
||||
QMessageBox::critical(
|
||||
this, tr("Create Icon"),
|
||||
tr("Cannot create icon file. Path \"%1\" does not exist and cannot be created.")
|
||||
@ -1922,19 +1909,27 @@ bool GMainWindow::MakeShortcutIcoPath(const u64 program_id, const std::string_vi
|
||||
}
|
||||
|
||||
// Create icon file path
|
||||
out_icon_path /= (program_id == 0 ? fmt::format("citra-{}.{}", game_file_name, ico_extension)
|
||||
: fmt::format("citra-{:016X}.{}", program_id, ico_extension));
|
||||
out_icon_path /= (program_id == 0 ? fmt::format("lime-{}.{}", game_file_name, ico_extension)
|
||||
: fmt::format("lime-{:016X}.{}", program_id, ico_extension));
|
||||
return true;
|
||||
}
|
||||
|
||||
void GMainWindow::OnGameListCreateShortcut(u64 program_id, const std::string& game_path,
|
||||
GameListShortcutTarget target) {
|
||||
// Get path to citra executable
|
||||
const QStringList args = QApplication::arguments();
|
||||
std::filesystem::path citra_command = args[0].toStdString();
|
||||
// If relative path, make it an absolute path
|
||||
if (citra_command.c_str()[0] == '.') {
|
||||
citra_command = FileUtil::GetCurrentDir().value_or("") + DIR_SEP + citra_command.string();
|
||||
std::string lime_command{};
|
||||
bool skip_tryexec = false;
|
||||
const char* env_flatpak_id = getenv("FLATPAK_ID");
|
||||
if (env_flatpak_id) {
|
||||
lime_command = fmt::format("flatpak run {}", env_flatpak_id);
|
||||
skip_tryexec = true;
|
||||
} else {
|
||||
// Get path to Lime3DS executable
|
||||
const QStringList args = QApplication::arguments();
|
||||
lime_command = args[0].toStdString();
|
||||
// If relative path, make it an absolute path
|
||||
if (lime_command.c_str()[0] == '.') {
|
||||
lime_command = FileUtil::GetCurrentDir().value_or("") + DIR_SEP + lime_command;
|
||||
}
|
||||
}
|
||||
|
||||
// Shortcut path
|
||||
@ -1943,8 +1938,7 @@ void GMainWindow::OnGameListCreateShortcut(u64 program_id, const std::string& ga
|
||||
shortcut_path =
|
||||
QStandardPaths::writableLocation(QStandardPaths::DesktopLocation).toStdString();
|
||||
} else if (target == GameListShortcutTarget::Applications) {
|
||||
shortcut_path =
|
||||
QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation).toStdString();
|
||||
shortcut_path = GetApplicationsDirectory();
|
||||
}
|
||||
|
||||
// Icon path and title
|
||||
@ -1990,8 +1984,7 @@ void GMainWindow::OnGameListCreateShortcut(u64 program_id, const std::string& ga
|
||||
// Warn once if we are making a shortcut to a volatile AppImage
|
||||
const std::string appimage_ending =
|
||||
std::string(Common::g_scm_rev).substr(0, 9).append(".AppImage");
|
||||
if (citra_command.string().ends_with(appimage_ending) &&
|
||||
!UISettings::values.shortcut_already_warned) {
|
||||
if (lime_command.ends_with(appimage_ending) && !UISettings::values.shortcut_already_warned) {
|
||||
if (CreateShortcutMessagesGUI(this, CREATE_SHORTCUT_MSGBOX_APPIMAGE_VOLATILE_WARNING,
|
||||
qt_game_title)) {
|
||||
return;
|
||||
@ -2004,12 +1997,12 @@ void GMainWindow::OnGameListCreateShortcut(u64 program_id, const std::string& ga
|
||||
if (CreateShortcutMessagesGUI(this, CREATE_SHORTCUT_MSGBOX_FULLSCREEN_PROMPT, qt_game_title)) {
|
||||
arguments = "-f " + arguments;
|
||||
}
|
||||
const std::string comment = fmt::format("Start {:s} with the Citra Emulator", game_title);
|
||||
const std::string comment = fmt::format("Start {:s} with the Lime3DS Emulator", game_title);
|
||||
const std::string categories = "Game;Emulator;Qt;";
|
||||
const std::string keywords = "3ds;Nintendo;";
|
||||
|
||||
if (CreateShortcutLink(shortcut_path, comment, out_icon_path, citra_command, arguments,
|
||||
categories, keywords, game_title)) {
|
||||
if (CreateShortcutLink(shortcut_path, comment, out_icon_path, lime_command, arguments,
|
||||
categories, keywords, game_title, skip_tryexec)) {
|
||||
CreateShortcutMessagesGUI(this, CREATE_SHORTCUT_MSGBOX_SUCCESS, qt_game_title);
|
||||
return;
|
||||
}
|
||||
@ -2200,7 +2193,7 @@ void GMainWindow::OnCIAInstallReport(Service::AM::InstallStatus status, QString
|
||||
case Service::AM::InstallStatus::ErrorEncrypted:
|
||||
QMessageBox::critical(this, tr("Encrypted File"),
|
||||
tr("%1 must be decrypted "
|
||||
"before being used with Lime. A real 3DS is required.")
|
||||
"before being used with Lime3DS. A real 3DS is required.")
|
||||
.arg(filename));
|
||||
break;
|
||||
case Service::AM::InstallStatus::ErrorFileNotFound:
|
||||
@ -2293,6 +2286,7 @@ void GMainWindow::OnStartGame() {
|
||||
PreventOSSleep();
|
||||
|
||||
emu_thread->SetRunning(true);
|
||||
system.frame_limiter.SetFrameAdvancing(false);
|
||||
graphics_api_button->setEnabled(false);
|
||||
qRegisterMetaType<Core::System::ResultStatus>("Core::System::ResultStatus");
|
||||
qRegisterMetaType<std::string>("std::string");
|
||||
@ -2322,7 +2316,7 @@ void GMainWindow::OnRestartGame() {
|
||||
}
|
||||
|
||||
void GMainWindow::OnPauseGame() {
|
||||
emu_thread->SetRunning(false);
|
||||
system.frame_limiter.SetFrameAdvancing(true);
|
||||
qt_cameras->PauseCameras();
|
||||
|
||||
play_time_manager->Stop();
|
||||
@ -2337,7 +2331,7 @@ void GMainWindow::OnPauseGame() {
|
||||
|
||||
void GMainWindow::OnPauseContinueGame() {
|
||||
if (emulation_running) {
|
||||
if (emu_thread->IsRunning()) {
|
||||
if (emu_thread->IsRunning() && !system.frame_limiter.IsFrameAdvancing()) {
|
||||
OnPauseGame();
|
||||
} else {
|
||||
OnStartGame();
|
||||
@ -2361,17 +2355,6 @@ void GMainWindow::OnLoadComplete() {
|
||||
UpdateSecondaryWindowVisibility();
|
||||
}
|
||||
|
||||
void GMainWindow::OnMenuReportCompatibility() {
|
||||
if (!NetSettings::values.citra_token.empty() && !NetSettings::values.citra_username.empty()) {
|
||||
CompatDB compatdb{this};
|
||||
compatdb.exec();
|
||||
} else {
|
||||
QMessageBox::critical(this, tr("Missing Citra Account"),
|
||||
tr("You must link your Citra account to submit test cases."
|
||||
"<br/>Go to Emulation > Configure... > Web to do so."));
|
||||
}
|
||||
}
|
||||
|
||||
void GMainWindow::ToggleFullscreen() {
|
||||
if (!emulation_running) {
|
||||
return;
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright 2014 Citra Emulator Project
|
||||
// Copyright Citra Emulator Project / Lime3DS Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
@ -217,10 +217,10 @@ private:
|
||||
bool MakeShortcutIcoPath(const u64 program_id, const std::string_view game_file_name,
|
||||
std::filesystem::path& out_icon_path);
|
||||
bool CreateShortcutLink(const std::filesystem::path& shortcut_path, const std::string& comment,
|
||||
const std::filesystem::path& icon_path,
|
||||
const std::filesystem::path& command, const std::string& arguments,
|
||||
const std::string& categories, const std::string& keywords,
|
||||
const std::string& name);
|
||||
const std::filesystem::path& icon_path, const std::string& command,
|
||||
const std::string& arguments, const std::string& categories,
|
||||
const std::string& keywords, const std::string& name,
|
||||
const bool& skip_tryexec);
|
||||
|
||||
private slots:
|
||||
void OnStartGame();
|
||||
@ -230,7 +230,6 @@ private slots:
|
||||
void OnStopGame();
|
||||
void OnSaveState();
|
||||
void OnLoadState();
|
||||
void OnMenuReportCompatibility();
|
||||
/// Called whenever a user selects a game in the game list widget.
|
||||
void OnGameListLoadFile(QString game_path);
|
||||
void OnGameListOpenFolder(u64 program_id, GameListOpenTarget target);
|
||||
|
@ -182,15 +182,8 @@
|
||||
<addaction name="action_Movie_Read_Only_Mode"/>
|
||||
<addaction name="action_Save_Movie"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menu_Frame_Advance">
|
||||
<property name="title">
|
||||
<string>Frame Advance</string>
|
||||
</property>
|
||||
<addaction name="action_Enable_Frame_Advancing"/>
|
||||
<addaction name="action_Advance_Frame"/>
|
||||
</widget>
|
||||
<addaction name="action_Advance_Frame"/>
|
||||
<addaction name="menu_Movie"/>
|
||||
<addaction name="menu_Frame_Advance"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="action_Capture_Screenshot"/>
|
||||
<addaction name="action_Dump_Video"/>
|
||||
@ -309,7 +302,7 @@
|
||||
</action>
|
||||
<action name="action_About">
|
||||
<property name="text">
|
||||
<string>About Lime</string>
|
||||
<string>About Lime3DS</string>
|
||||
</property>
|
||||
<property name="menuRole">
|
||||
<enum>QAction::AboutRole</enum>
|
||||
@ -404,14 +397,6 @@
|
||||
<string>Read-Only Mode</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="action_Enable_Frame_Advancing">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Enable Frame Advancing</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="action_Advance_Frame">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
@ -575,15 +560,9 @@
|
||||
</property>
|
||||
</action>
|
||||
<action name="action_Report_Compatibility">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Report Compatibility</string>
|
||||
</property>
|
||||
<property name="visible">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</action>
|
||||
<action name="action_Restart">
|
||||
<property name="enabled">
|
||||
|
@ -1,10 +1,13 @@
|
||||
// Copyright 2015 Citra Emulator Project
|
||||
// Copyright Citra Emulator Project / Lime3DS Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <array>
|
||||
#include <cmath>
|
||||
#include <QPainter>
|
||||
#include <QStandardPaths>
|
||||
#include "common/common_paths.h"
|
||||
#include "common/file_util.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "core/loader/smdh.h"
|
||||
#include "lime_qt/util/util.h"
|
||||
@ -160,3 +163,15 @@ bool SaveIconToFile(const std::filesystem::path& icon_path, const QImage& image)
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
const std::string GetApplicationsDirectory() {
|
||||
// This alternate method is required for Flatpak compatibility as
|
||||
// QStandardPaths::ApplicationsLocation returns a path inside the Flatpak data directory instead of
|
||||
// $HOME/.local/share
|
||||
#if defined(__linux__) || defined(__FreeBSD__)
|
||||
return FileUtil::GetHomeDirectory() + DIR_SEP + ".local" + DIR_SEP + "share" + DIR_SEP +
|
||||
"applications";
|
||||
#else
|
||||
return QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation).toStdString();
|
||||
#endif
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
// Copyright 2015 Citra Emulator Project
|
||||
// Copyright Citra Emulator Project / Lime3DS Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
@ -36,3 +36,8 @@ QPixmap GetQPixmapFromSMDH(const std::vector<u8>& smdh_data);
|
||||
* @return bool If the operation succeeded
|
||||
*/
|
||||
[[nodiscard]] bool SaveIconToFile(const std::filesystem::path& icon_path, const QImage& image);
|
||||
|
||||
/**
|
||||
* @return The user’s applications directory
|
||||
*/
|
||||
[[nodiscard]] const std::string GetApplicationsDirectory();
|
||||
|
@ -647,10 +647,11 @@ typename T::Surface& RasterizerCache<T>::GetTextureCube(const TextureCubeConfig&
|
||||
|
||||
Surface& cube_surface = slot_surfaces[cube.surface_id];
|
||||
for (u32 i = 0; i < addresses.size(); i++) {
|
||||
if (!addresses[i]) {
|
||||
const SurfaceId& face_id = cube.face_ids[i];
|
||||
if (!addresses[i] || !face_id) {
|
||||
continue;
|
||||
}
|
||||
Surface& surface = slot_surfaces[cube.face_ids[i]];
|
||||
Surface& surface = slot_surfaces[face_id];
|
||||
if (cube.ticks[i] == surface.modification_tick) {
|
||||
continue;
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright 2022 Citra Emulator Project
|
||||
// Copyright Citra Emulator Project / Lime3DS Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
@ -675,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();
|
||||
ApplySecondLayerOpacity(layout.is_portrait);
|
||||
DrawBottomScreen(layout, bottom_screen);
|
||||
} else {
|
||||
DrawBottomScreen(layout, bottom_screen);
|
||||
glUniform1i(uniform_layer, 0);
|
||||
ApplySecondLayerOpacity();
|
||||
ApplySecondLayerOpacity(layout.is_portrait);
|
||||
DrawTopScreen(layout, top_screen);
|
||||
}
|
||||
|
||||
@ -692,13 +692,14 @@ void RendererOpenGL::DrawScreens(const Layout::FramebufferLayout& layout, bool f
|
||||
DrawBottomScreen(layout, additional_screen);
|
||||
}
|
||||
}
|
||||
ResetSecondLayerOpacity();
|
||||
ResetSecondLayerOpacity(layout.is_portrait);
|
||||
}
|
||||
|
||||
void RendererOpenGL::ApplySecondLayerOpacity() {
|
||||
#ifndef ANDROID // TODO: Implement custom layouts on Android
|
||||
if ((Settings::values.layout_option.GetValue() == Settings::LayoutOption::CustomLayout ||
|
||||
Settings::values.custom_layout) &&
|
||||
void RendererOpenGL::ApplySecondLayerOpacity(bool isPortrait) {
|
||||
// TODO: Allow for second layer opacity in portrait mode android
|
||||
|
||||
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;
|
||||
@ -706,13 +707,11 @@ void RendererOpenGL::ApplySecondLayerOpacity() {
|
||||
state.blend.dst_rgb_func = GL_ONE_MINUS_CONSTANT_ALPHA;
|
||||
state.blend.color.alpha = Settings::values.custom_second_layer_opacity.GetValue() / 100.0f;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void RendererOpenGL::ResetSecondLayerOpacity() {
|
||||
#ifndef ANDROID // TODO: Implement custom layouts on Android
|
||||
if ((Settings::values.layout_option.GetValue() == Settings::LayoutOption::CustomLayout ||
|
||||
Settings::values.custom_layout) &&
|
||||
void RendererOpenGL::ResetSecondLayerOpacity(bool isPortrait) {
|
||||
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;
|
||||
@ -720,7 +719,6 @@ void RendererOpenGL::ResetSecondLayerOpacity() {
|
||||
state.blend.dst_a_func = GL_ZERO;
|
||||
state.blend.color.alpha = 0.0f;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void RendererOpenGL::DrawTopScreen(const Layout::FramebufferLayout& layout,
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright 2022 Citra Emulator Project
|
||||
// Copyright Citra Emulator Project / Lime3DS Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
@ -65,8 +65,8 @@ private:
|
||||
void ConfigureFramebufferTexture(TextureInfo& texture,
|
||||
const Pica::FramebufferConfig& framebuffer);
|
||||
void DrawScreens(const Layout::FramebufferLayout& layout, bool flipped);
|
||||
void ApplySecondLayerOpacity();
|
||||
void ResetSecondLayerOpacity();
|
||||
void ApplySecondLayerOpacity(bool isPortrait = false);
|
||||
void ResetSecondLayerOpacity(bool isPortrait = false);
|
||||
void DrawBottomScreen(const Layout::FramebufferLayout& layout,
|
||||
const Common::Rectangle<u32>& bottom_screen);
|
||||
void DrawTopScreen(const Layout::FramebufferLayout& layout,
|
||||
|
Loading…
Reference in New Issue
Block a user