android: Enable overlay scale/opacity dialog

This commit is contained in:
Charles Lombardo 2023-06-01 17:30:27 -04:00 committed by bunnei
parent 1957b7e6cc
commit ca4b07a2d7
10 changed files with 182 additions and 65 deletions

View File

@ -252,39 +252,6 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
View.SYSTEM_UI_FLAG_IMMERSIVE View.SYSTEM_UI_FLAG_IMMERSIVE
} }
private fun editControlsPlacement() {
if (emulationFragment!!.isConfiguringControls) {
emulationFragment!!.stopConfiguringControls()
} else {
emulationFragment!!.startConfiguringControls()
}
}
private fun adjustScale() {
val sliderBinding = DialogSliderBinding.inflate(layoutInflater)
sliderBinding.slider.valueTo = 150F
sliderBinding.slider.value =
PreferenceManager.getDefaultSharedPreferences(applicationContext)
.getInt(Settings.PREF_CONTROL_SCALE, 50).toFloat()
sliderBinding.slider.addOnChangeListener(OnChangeListener { _, value, _ ->
sliderBinding.textValue.text = value.toString()
setControlScale(value.toInt())
})
sliderBinding.textValue.text = sliderBinding.slider.value.toString()
sliderBinding.textUnits.text = "%"
MaterialAlertDialogBuilder(this)
.setTitle(R.string.emulation_control_scale)
.setView(sliderBinding.root)
.setNegativeButton(android.R.string.cancel, null)
.setPositiveButton(android.R.string.ok) { _: DialogInterface?, _: Int ->
setControlScale(sliderBinding.slider.value.toInt())
}
.setNeutralButton(R.string.slider_default) { _: DialogInterface?, _: Int ->
setControlScale(50)
}
.show()
}
private fun startMotionSensorListener() { private fun startMotionSensorListener() {
val sensorManager = this.getSystemService(Context.SENSOR_SERVICE) as SensorManager val sensorManager = this.getSystemService(Context.SENSOR_SERVICE) as SensorManager
val gyroSensor = sensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE) val gyroSensor = sensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE)
@ -302,22 +269,6 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
sensorManager.unregisterListener(this, accelSensor) sensorManager.unregisterListener(this, accelSensor)
} }
private fun setControlScale(scale: Int) {
PreferenceManager.getDefaultSharedPreferences(applicationContext).edit()
.putInt(Settings.PREF_CONTROL_SCALE, scale)
.apply()
emulationFragment!!.refreshInputOverlay()
}
private fun resetOverlay() {
MaterialAlertDialogBuilder(this)
.setTitle(getString(R.string.emulation_touch_overlay_reset))
.setPositiveButton(android.R.string.ok) { _: DialogInterface?, _: Int -> emulationFragment!!.resetInputOverlay() }
.setNegativeButton(android.R.string.cancel, null)
.create()
.show()
}
companion object { companion object {
const val EXTRA_SELECTED_GAME = "SelectedGame" const val EXTRA_SELECTED_GAME = "SelectedGame"

View File

@ -111,6 +111,7 @@ class Settings {
const val PREF_OVERLAY_INIT = "OverlayInit" const val PREF_OVERLAY_INIT = "OverlayInit"
const val PREF_CONTROL_SCALE = "controlScale" const val PREF_CONTROL_SCALE = "controlScale"
const val PREF_CONTROL_OPACITY = "controlOpacity"
const val PREF_TOUCH_ENABLED = "isTouchEnabled" const val PREF_TOUCH_ENABLED = "isTouchEnabled"
const val PREF_BUTTON_TOGGLE_0 = "buttonToggle0" const val PREF_BUTTON_TOGGLE_0 = "buttonToggle0"
const val PREF_BUTTON_TOGGLE_1 = "buttonToggle1" const val PREF_BUTTON_TOGGLE_1 = "buttonToggle1"

View File

@ -3,8 +3,10 @@
package org.yuzu.yuzu_emu.fragments package org.yuzu.yuzu_emu.fragments
import android.annotation.SuppressLint
import android.app.AlertDialog import android.app.AlertDialog
import android.content.Context import android.content.Context
import android.content.DialogInterface
import android.content.SharedPreferences import android.content.SharedPreferences
import android.graphics.Color import android.graphics.Color
import android.os.Bundle import android.os.Bundle
@ -21,10 +23,12 @@ import androidx.core.view.WindowInsetsCompat
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.preference.PreferenceManager import androidx.preference.PreferenceManager
import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.slider.Slider
import org.yuzu.yuzu_emu.NativeLibrary import org.yuzu.yuzu_emu.NativeLibrary
import org.yuzu.yuzu_emu.R import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.YuzuApplication import org.yuzu.yuzu_emu.YuzuApplication
import org.yuzu.yuzu_emu.activities.EmulationActivity import org.yuzu.yuzu_emu.activities.EmulationActivity
import org.yuzu.yuzu_emu.databinding.DialogOverlayAdjustBinding
import org.yuzu.yuzu_emu.databinding.FragmentEmulationBinding import org.yuzu.yuzu_emu.databinding.FragmentEmulationBinding
import org.yuzu.yuzu_emu.features.settings.model.Settings import org.yuzu.yuzu_emu.features.settings.model.Settings
import org.yuzu.yuzu_emu.features.settings.ui.SettingsActivity import org.yuzu.yuzu_emu.features.settings.ui.SettingsActivity
@ -168,14 +172,14 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
super.onDetach() super.onDetach()
} }
fun refreshInputOverlay() { private fun refreshInputOverlay() {
binding.surfaceInputOverlay.refreshControls() binding.surfaceInputOverlay.refreshControls()
} }
fun resetInputOverlay() { private fun resetInputOverlay() {
// Reset button scale
preferences.edit() preferences.edit()
.putInt(Settings.PREF_CONTROL_SCALE, 50) .remove(Settings.PREF_CONTROL_SCALE)
.remove(Settings.PREF_CONTROL_OPACITY)
.apply() .apply()
binding.surfaceInputOverlay.post { binding.surfaceInputOverlay.resetButtonPlacement() } binding.surfaceInputOverlay.post { binding.surfaceInputOverlay.resetButtonPlacement() }
} }
@ -251,6 +255,11 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
true true
} }
R.id.menu_adjust_overlay -> {
adjustOverlay()
true
}
R.id.menu_toggle_controls -> { R.id.menu_toggle_controls -> {
val preferences = val preferences =
PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext) PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext)
@ -278,9 +287,9 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
// Override normal behaviour so the dialog doesn't close // Override normal behaviour so the dialog doesn't close
dialog.getButton(AlertDialog.BUTTON_NEUTRAL) dialog.getButton(AlertDialog.BUTTON_NEUTRAL)
.setOnClickListener { .setOnClickListener {
val isChecked = !optionsArray[0]; val isChecked = !optionsArray[0]
for (i in 0..14) { for (i in 0..14) {
optionsArray[i] = isChecked; optionsArray[i] = isChecked
dialog.listView.setItemChecked(i, isChecked) dialog.listView.setItemChecked(i, isChecked)
preferences.edit() preferences.edit()
.putBoolean("buttonToggle$i", isChecked) .putBoolean("buttonToggle$i", isChecked)
@ -328,18 +337,64 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
popup.show() popup.show()
} }
fun startConfiguringControls() { private fun startConfiguringControls() {
binding.doneControlConfig.visibility = View.VISIBLE binding.doneControlConfig.visibility = View.VISIBLE
binding.surfaceInputOverlay.setIsInEditMode(true) binding.surfaceInputOverlay.setIsInEditMode(true)
} }
fun stopConfiguringControls() { private fun stopConfiguringControls() {
binding.doneControlConfig.visibility = View.GONE binding.doneControlConfig.visibility = View.GONE
binding.surfaceInputOverlay.setIsInEditMode(false) binding.surfaceInputOverlay.setIsInEditMode(false)
} }
val isConfiguringControls: Boolean @SuppressLint("SetTextI18n")
get() = binding.surfaceInputOverlay.isInEditMode private fun adjustOverlay() {
val adjustBinding = DialogOverlayAdjustBinding.inflate(layoutInflater)
adjustBinding.apply {
inputScaleSlider.apply {
valueTo = 150F
value = preferences.getInt(Settings.PREF_CONTROL_SCALE, 50).toFloat()
addOnChangeListener(Slider.OnChangeListener { _, value, _ ->
inputScaleValue.text = "${value.toInt()}%"
setControlScale(value.toInt())
})
}
inputOpacitySlider.apply {
valueTo = 100F
value = preferences.getInt(Settings.PREF_CONTROL_OPACITY, 100).toFloat()
addOnChangeListener(Slider.OnChangeListener { _, value, _ ->
inputOpacityValue.text = "${value.toInt()}%"
setControlOpacity(value.toInt())
})
}
inputScaleValue.text = "${inputScaleSlider.value.toInt()}%"
inputOpacityValue.text = "${inputOpacitySlider.value.toInt()}%"
}
MaterialAlertDialogBuilder(requireContext())
.setTitle(R.string.emulation_control_adjust)
.setView(adjustBinding.root)
.setPositiveButton(android.R.string.ok, null)
.setNeutralButton(R.string.slider_default) { _: DialogInterface?, _: Int ->
setControlScale(50)
setControlOpacity(100)
}
.show()
}
private fun setControlScale(scale: Int) {
preferences.edit()
.putInt(Settings.PREF_CONTROL_SCALE, scale)
.apply()
refreshInputOverlay()
}
private fun setControlOpacity(opacity: Int) {
preferences.edit()
.putInt(Settings.PREF_CONTROL_OPACITY, opacity)
.apply()
refreshInputOverlay()
}
private fun setInsets() { private fun setInsets() {
ViewCompat.setOnApplyWindowInsetsListener(binding.inGameMenu) { v: View, windowInsets: WindowInsetsCompat -> ViewCompat.setOnApplyWindowInsetsListener(binding.inGameMenu) { v: View, windowInsets: WindowInsetsCompat ->

View File

@ -49,9 +49,6 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : SurfaceView(context
private var dpadBeingConfigured: InputOverlayDrawableDpad? = null private var dpadBeingConfigured: InputOverlayDrawableDpad? = null
private var joystickBeingConfigured: InputOverlayDrawableJoystick? = null private var joystickBeingConfigured: InputOverlayDrawableJoystick? = null
private val preferences: SharedPreferences =
PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext)
private lateinit var windowInsets: WindowInsets private lateinit var windowInsets: WindowInsets
override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) { override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
@ -709,6 +706,9 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : SurfaceView(context
} }
companion object { companion object {
private val preferences: SharedPreferences =
PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext)
/** /**
* Resizes a [Bitmap] by a given scale factor * Resizes a [Bitmap] by a given scale factor
* *
@ -899,6 +899,8 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : SurfaceView(context
drawableX - (width / 2), drawableX - (width / 2),
drawableY - (height / 2) drawableY - (height / 2)
) )
val savedOpacity = preferences.getInt(Settings.PREF_CONTROL_OPACITY, 100)
overlayDrawable.setOpacity(savedOpacity * 255 / 100)
return overlayDrawable return overlayDrawable
} }
@ -973,6 +975,8 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : SurfaceView(context
// Need to set the image's position // Need to set the image's position
overlayDrawable.setPosition(drawableX - (width / 2), drawableY - (height / 2)) overlayDrawable.setPosition(drawableX - (width / 2), drawableY - (height / 2))
val savedOpacity = preferences.getInt(Settings.PREF_CONTROL_OPACITY, 100)
overlayDrawable.setOpacity(savedOpacity * 255 / 100)
return overlayDrawable return overlayDrawable
} }
@ -1052,6 +1056,8 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : SurfaceView(context
// Need to set the image's position // Need to set the image's position
overlayDrawable.setPosition(drawableX, drawableY) overlayDrawable.setPosition(drawableX, drawableY)
val savedOpacity = preferences.getInt(Settings.PREF_CONTROL_OPACITY, 100)
overlayDrawable.setOpacity(savedOpacity * 255 / 100)
return overlayDrawable return overlayDrawable
} }
} }

View File

@ -114,6 +114,7 @@ class InputOverlayDrawableButton(
controlPositionX = fingerPositionX - (width / 2) controlPositionX = fingerPositionX - (width / 2)
controlPositionY = fingerPositionY - (height / 2) controlPositionY = fingerPositionY - (height / 2)
} }
MotionEvent.ACTION_MOVE -> { MotionEvent.ACTION_MOVE -> {
controlPositionX += fingerPositionX - previousTouchX controlPositionX += fingerPositionX - previousTouchX
controlPositionY += fingerPositionY - previousTouchY controlPositionY += fingerPositionY - previousTouchY
@ -135,6 +136,11 @@ class InputOverlayDrawableButton(
pressedStateBitmap.setBounds(left, top, right, bottom) pressedStateBitmap.setBounds(left, top, right, bottom)
} }
fun setOpacity(value: Int) {
defaultStateBitmap.alpha = value
pressedStateBitmap.alpha = value
}
val status: Int val status: Int
get() = if (pressedState) ButtonState.PRESSED else ButtonState.RELEASED get() = if (pressedState) ButtonState.PRESSED else ButtonState.RELEASED
val bounds: Rect val bounds: Rect

View File

@ -231,6 +231,7 @@ class InputOverlayDrawableDpad(
previousTouchX = fingerPositionX previousTouchX = fingerPositionX
previousTouchY = fingerPositionY previousTouchY = fingerPositionY
} }
MotionEvent.ACTION_MOVE -> { MotionEvent.ACTION_MOVE -> {
controlPositionX += fingerPositionX - previousTouchX controlPositionX += fingerPositionX - previousTouchX
controlPositionY += fingerPositionY - previousTouchY controlPositionY += fingerPositionY - previousTouchY
@ -258,6 +259,12 @@ class InputOverlayDrawableDpad(
pressedTwoDirectionsStateBitmap.setBounds(left, top, right, bottom) pressedTwoDirectionsStateBitmap.setBounds(left, top, right, bottom)
} }
fun setOpacity(value: Int) {
defaultStateBitmap.alpha = value
pressedOneDirectionStateBitmap.alpha = value
pressedTwoDirectionsStateBitmap.alpha = value
}
val bounds: Rect val bounds: Rect
get() = defaultStateBitmap.bounds get() = defaultStateBitmap.bounds

View File

@ -48,6 +48,8 @@ class InputOverlayDrawableJoystick(
val width: Int val width: Int
val height: Int val height: Int
private var opacity: Int = 0
private var virtBounds: Rect private var virtBounds: Rect
private var origBounds: Rect private var origBounds: Rect
@ -121,7 +123,7 @@ class InputOverlayDrawableJoystick(
} }
pressedState = true pressedState = true
outerBitmap.alpha = 0 outerBitmap.alpha = 0
boundsBoxBitmap.alpha = 255 boundsBoxBitmap.alpha = opacity
if (EmulationMenuSettings.joystickRelCenter) { if (EmulationMenuSettings.joystickRelCenter) {
virtBounds.offset( virtBounds.offset(
xPosition - virtBounds.centerX(), xPosition - virtBounds.centerX(),
@ -139,7 +141,7 @@ class InputOverlayDrawableJoystick(
pressedState = false pressedState = false
xAxis = 0.0f xAxis = 0.0f
yAxis = 0.0f yAxis = 0.0f
outerBitmap.alpha = 255 outerBitmap.alpha = opacity
boundsBoxBitmap.alpha = 0 boundsBoxBitmap.alpha = 0
virtBounds = Rect( virtBounds = Rect(
origBounds.left, origBounds.left,
@ -203,6 +205,7 @@ class InputOverlayDrawableJoystick(
controlPositionX = fingerPositionX - (width / 2) controlPositionX = fingerPositionX - (width / 2)
controlPositionY = fingerPositionY - (height / 2) controlPositionY = fingerPositionY - (height / 2)
} }
MotionEvent.ACTION_MOVE -> { MotionEvent.ACTION_MOVE -> {
controlPositionX += fingerPositionX - previousTouchX controlPositionX += fingerPositionX - previousTouchX
controlPositionY += fingerPositionY - previousTouchY controlPositionY += fingerPositionY - previousTouchY
@ -261,4 +264,19 @@ class InputOverlayDrawableJoystick(
controlPositionX = x controlPositionX = x
controlPositionY = y controlPositionY = y
} }
fun setOpacity(value: Int) {
opacity = value
defaultStateInnerBitmap.alpha = value
pressedStateInnerBitmap.alpha = value
if (trackId == -1) {
outerBitmap.alpha = value
boundsBoxBitmap.alpha = 0
} else {
outerBitmap.alpha = 0
boundsBoxBitmap.alpha = value
}
}
} }

View File

@ -0,0 +1,67 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
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:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/input_scale_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="@string/emulation_control_scale"
android:textAlignment="viewStart"
android:textSize="16sp"
app:layout_constraintStart_toStartOf="@+id/input_scale_slider"
app:layout_constraintTop_toTopOf="parent" />
<com.google.android.material.slider.Slider
android:id="@+id/input_scale_slider"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginHorizontal="24dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/input_scale_name" />
<TextView
android:id="@+id/input_scale_value"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="end"
app:layout_constraintBottom_toTopOf="@+id/input_scale_slider"
app:layout_constraintEnd_toEndOf="@+id/input_scale_slider"
tools:text="100%" />
<TextView
android:id="@+id/input_opacity_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="@string/emulation_control_opacity"
android:textAlignment="viewStart"
android:textSize="16sp"
app:layout_constraintStart_toStartOf="@+id/input_opacity_slider"
app:layout_constraintTop_toBottomOf="@+id/input_scale_slider" />
<com.google.android.material.slider.Slider
android:id="@+id/input_opacity_slider"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginHorizontal="24dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/input_opacity_name" />
<TextView
android:id="@+id/input_opacity_value"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="end"
app:layout_constraintBottom_toTopOf="@+id/input_opacity_slider"
app:layout_constraintEnd_toEndOf="@+id/input_opacity_slider"
tools:text="100%" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -10,6 +10,10 @@
android:id="@+id/menu_edit_overlay" android:id="@+id/menu_edit_overlay"
android:title="@string/emulation_touch_overlay_edit" /> android:title="@string/emulation_touch_overlay_edit" />
<item
android:id="@+id/menu_adjust_overlay"
android:title="@string/emulation_control_adjust" />
<item <item
android:id="@+id/menu_toggle_controls" android:id="@+id/menu_toggle_controls"
android:title="@string/emulation_toggle_controls" /> android:title="@string/emulation_toggle_controls" />

View File

@ -204,7 +204,9 @@
<string name="emulation_haptics">Haptics</string> <string name="emulation_haptics">Haptics</string>
<string name="emulation_show_overlay">Show Overlay</string> <string name="emulation_show_overlay">Show Overlay</string>
<string name="emulation_toggle_all">Toggle All</string> <string name="emulation_toggle_all">Toggle All</string>
<string name="emulation_control_scale">Adjust Scale</string> <string name="emulation_control_adjust">Adjust Overlay</string>
<string name="emulation_control_scale">Scale</string>
<string name="emulation_control_opacity">Opacity</string>
<string name="emulation_touch_overlay_reset">Reset Overlay</string> <string name="emulation_touch_overlay_reset">Reset Overlay</string>
<string name="emulation_touch_overlay_edit">Edit Overlay</string> <string name="emulation_touch_overlay_edit">Edit Overlay</string>
<string name="emulation_pause">Pause Emulation</string> <string name="emulation_pause">Pause Emulation</string>