Android: Implement touch controls opacity option.

This commit is contained in:
Gamer64ytb 2024-04-09 09:31:24 +02:00 committed by OpenSauce
parent 85f0036ac0
commit 0dc86bab3c
8 changed files with 95 additions and 9 deletions

View file

@ -624,6 +624,11 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram
true true
} }
R.id.menu_emulation_adjust_opacity -> {
showAdjustOpacityDialog()
true
}
R.id.menu_emulation_joystick_rel_center -> { R.id.menu_emulation_joystick_rel_center -> {
EmulationMenuSettings.joystickRelCenter = EmulationMenuSettings.joystickRelCenter =
!EmulationMenuSettings.joystickRelCenter !EmulationMenuSettings.joystickRelCenter
@ -800,6 +805,37 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram
.show() .show()
} }
private fun showAdjustOpacityDialog() {
val sliderBinding = DialogSliderBinding.inflate(layoutInflater)
sliderBinding.apply {
slider.valueTo = 100f
slider.value = preferences.getInt("controlOpacity", 100).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 = "%"
}
val previousProgress = sliderBinding.slider.value.toInt()
MaterialAlertDialogBuilder(requireContext())
.setTitle(R.string.emulation_control_opacity)
.setView(sliderBinding.root)
.setNegativeButton(android.R.string.cancel) { _: DialogInterface?, _: Int ->
setControlOpacity(previousProgress)
}
.setPositiveButton(android.R.string.ok) { _: DialogInterface?, _: Int ->
setControlOpacity(sliderBinding.slider.value.toInt())
}
.setNeutralButton(R.string.slider_default) { _: DialogInterface?, _: Int ->
setControlOpacity(100)
}
.show()
}
private fun setControlScale(scale: Int) { private fun setControlScale(scale: Int) {
preferences.edit() preferences.edit()
.putInt("controlScale", scale) .putInt("controlScale", scale)
@ -807,6 +843,13 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram
binding.surfaceInputOverlay.refreshControls() binding.surfaceInputOverlay.refreshControls()
} }
private fun setControlOpacity(opacity: Int) {
preferences.edit()
.putInt("controlOpacity", opacity)
.apply()
binding.surfaceInputOverlay.refreshControls()
}
private fun showResetOverlayDialog() { private fun showResetOverlayDialog() {
MaterialAlertDialogBuilder(requireContext()) MaterialAlertDialogBuilder(requireContext())
.setTitle(getString(R.string.emulation_touch_overlay_reset)) .setTitle(getString(R.string.emulation_touch_overlay_reset))
@ -820,6 +863,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram
private fun resetInputOverlay() { private fun resetInputOverlay() {
preferences.edit() preferences.edit()
.putInt("controlScale", 50) .putInt("controlScale", 50)
.putInt("controlOpacity", 100)
.apply() .apply()
val editor = preferences.edit() val editor = preferences.edit()

View file

@ -939,11 +939,13 @@ class InputOverlay(context: Context?, attrs: AttributeSet?) : SurfaceView(contex
scale *= (preferences.getInt("controlScale", 50) + 50).toFloat() scale *= (preferences.getInt("controlScale", 50) + 50).toFloat()
scale /= 100f scale /= 100f
val opacity: Int = preferences.getInt("controlOpacity", 100) * 255 / 100
// Initialize the InputOverlayDrawableButton. // Initialize the InputOverlayDrawableButton.
val defaultStateBitmap = getBitmap(context, defaultResId, scale) val defaultStateBitmap = getBitmap(context, defaultResId, scale)
val pressedStateBitmap = getBitmap(context, pressedResId, scale) val pressedStateBitmap = getBitmap(context, pressedResId, scale)
val overlayDrawable = val overlayDrawable =
InputOverlayDrawableButton(res, defaultStateBitmap, pressedStateBitmap, buttonId) InputOverlayDrawableButton(res, defaultStateBitmap, pressedStateBitmap, buttonId, opacity)
// The X and Y coordinates of the InputOverlayDrawableButton on the InputOverlay. // The X and Y coordinates of the InputOverlayDrawableButton on the InputOverlay.
// These were set in the input overlay configuration menu. // These were set in the input overlay configuration menu.
@ -995,6 +997,8 @@ class InputOverlay(context: Context?, attrs: AttributeSet?) : SurfaceView(contex
scale *= (preferences.getInt("controlScale", 50) + 50).toFloat() scale *= (preferences.getInt("controlScale", 50) + 50).toFloat()
scale /= 100f scale /= 100f
val opacity: Int = preferences.getInt("controlOpacity", 100) * 255 / 100
// Initialize the InputOverlayDrawableDpad. // Initialize the InputOverlayDrawableDpad.
val defaultStateBitmap = getBitmap(context, defaultResId, scale) val defaultStateBitmap = getBitmap(context, defaultResId, scale)
val pressedOneDirectionStateBitmap = getBitmap(context, pressedOneDirectionResId, scale) val pressedOneDirectionStateBitmap = getBitmap(context, pressedOneDirectionResId, scale)
@ -1007,7 +1011,8 @@ class InputOverlay(context: Context?, attrs: AttributeSet?) : SurfaceView(contex
buttonUp, buttonUp,
buttonDown, buttonDown,
buttonLeft, buttonLeft,
buttonRight buttonRight,
opacity
) )
// The X and Y coordinates of the InputOverlayDrawableDpad on the InputOverlay. // The X and Y coordinates of the InputOverlayDrawableDpad on the InputOverlay.
@ -1052,6 +1057,8 @@ class InputOverlay(context: Context?, attrs: AttributeSet?) : SurfaceView(contex
scale *= (preferences.getInt("controlScale", 50) + 50).toFloat() scale *= (preferences.getInt("controlScale", 50) + 50).toFloat()
scale /= 100f scale /= 100f
val opacity: Int = preferences.getInt("controlOpacity", 100) * 255 / 100
// Initialize the InputOverlayDrawableJoystick. // Initialize the InputOverlayDrawableJoystick.
val bitmapOuter = getBitmap(context, resOuter, scale) val bitmapOuter = getBitmap(context, resOuter, scale)
val bitmapInnerDefault = getBitmap(context, defaultResInner, scale) val bitmapInnerDefault = getBitmap(context, defaultResInner, scale)
@ -1088,7 +1095,8 @@ class InputOverlay(context: Context?, attrs: AttributeSet?) : SurfaceView(contex
bitmapInnerPressed, bitmapInnerPressed,
outerRect, outerRect,
innerRect, innerRect,
joystick joystick,
opacity
) )
// Need to set the image's position // Need to set the image's position

View file

@ -26,7 +26,8 @@ class InputOverlayDrawableButton(
res: Resources, res: Resources,
defaultStateBitmap: Bitmap, defaultStateBitmap: Bitmap,
pressedStateBitmap: Bitmap, pressedStateBitmap: Bitmap,
val id: Int val id: Int,
val opacity: Int
) { ) {
var trackId: Int var trackId: Int
private var previousTouchX = 0 private var previousTouchX = 0
@ -35,6 +36,7 @@ class InputOverlayDrawableButton(
private var controlPositionY = 0 private var controlPositionY = 0
val width: Int val width: Int
val height: Int val height: Int
private val opacityId: Int
private val defaultStateBitmap: BitmapDrawable private val defaultStateBitmap: BitmapDrawable
private val pressedStateBitmap: BitmapDrawable private val pressedStateBitmap: BitmapDrawable
private var pressedState = false private var pressedState = false
@ -42,6 +44,7 @@ class InputOverlayDrawableButton(
init { init {
this.defaultStateBitmap = BitmapDrawable(res, defaultStateBitmap) this.defaultStateBitmap = BitmapDrawable(res, defaultStateBitmap)
this.pressedStateBitmap = BitmapDrawable(res, pressedStateBitmap) this.pressedStateBitmap = BitmapDrawable(res, pressedStateBitmap)
this.opacityId = this.opacity
trackId = -1 trackId = -1
width = this.defaultStateBitmap.intrinsicWidth width = this.defaultStateBitmap.intrinsicWidth
height = this.defaultStateBitmap.intrinsicHeight height = this.defaultStateBitmap.intrinsicHeight
@ -114,7 +117,11 @@ class InputOverlayDrawableButton(
controlPositionY = y controlPositionY = y
} }
fun draw(canvas: Canvas) = currentStateBitmapDrawable.draw(canvas) fun draw(canvas: Canvas) {
val bitmapDrawable: BitmapDrawable = currentStateBitmapDrawable
bitmapDrawable.alpha = opacityId
bitmapDrawable.draw(canvas)
}
private val currentStateBitmapDrawable: BitmapDrawable private val currentStateBitmapDrawable: BitmapDrawable
get() = if (pressedState) pressedStateBitmap else defaultStateBitmap get() = if (pressedState) pressedStateBitmap else defaultStateBitmap

View file

@ -25,6 +25,7 @@ import io.github.lime3ds.android.NativeLibrary
* @param downId Identifier for the down button. * @param downId Identifier for the down button.
* @param leftId Identifier for the left button. * @param leftId Identifier for the left button.
* @param rightId Identifier for the right button. * @param rightId Identifier for the right button.
* @param opacity 0-255 alpha value
*/ */
class InputOverlayDrawableDpad( class InputOverlayDrawableDpad(
res: Resources, res: Resources,
@ -34,7 +35,8 @@ class InputOverlayDrawableDpad(
val upId: Int, val upId: Int,
val downId: Int, val downId: Int,
val leftId: Int, val leftId: Int,
val rightId: Int val rightId: Int,
val opacity: Int
) { ) {
var trackId: Int var trackId: Int
private var previousTouchX = 0 private var previousTouchX = 0
@ -43,6 +45,7 @@ class InputOverlayDrawableDpad(
private var controlPositionY = 0 private var controlPositionY = 0
val width: Int val width: Int
val height: Int val height: Int
private val opacityId: Int
private val defaultStateBitmap: BitmapDrawable private val defaultStateBitmap: BitmapDrawable
private val pressedOneDirectionStateBitmap: BitmapDrawable private val pressedOneDirectionStateBitmap: BitmapDrawable
private val pressedTwoDirectionsStateBitmap: BitmapDrawable private val pressedTwoDirectionsStateBitmap: BitmapDrawable
@ -55,6 +58,7 @@ class InputOverlayDrawableDpad(
this.defaultStateBitmap = BitmapDrawable(res, defaultStateBitmap) this.defaultStateBitmap = BitmapDrawable(res, defaultStateBitmap)
this.pressedOneDirectionStateBitmap = BitmapDrawable(res, pressedOneDirectionStateBitmap) this.pressedOneDirectionStateBitmap = BitmapDrawable(res, pressedOneDirectionStateBitmap)
this.pressedTwoDirectionsStateBitmap = BitmapDrawable(res, pressedTwoDirectionsStateBitmap) this.pressedTwoDirectionsStateBitmap = BitmapDrawable(res, pressedTwoDirectionsStateBitmap)
this.opacityId = this.opacity
width = this.defaultStateBitmap.intrinsicWidth width = this.defaultStateBitmap.intrinsicWidth
height = this.defaultStateBitmap.intrinsicHeight height = this.defaultStateBitmap.intrinsicHeight
trackId = -1 trackId = -1
@ -137,6 +141,7 @@ class InputOverlayDrawableDpad(
// Pressed up // Pressed up
if (upButtonState && !leftButtonState && !rightButtonState) { if (upButtonState && !leftButtonState && !rightButtonState) {
pressedOneDirectionStateBitmap.alpha = opacityId
pressedOneDirectionStateBitmap.draw(canvas) pressedOneDirectionStateBitmap.draw(canvas)
return return
} }
@ -145,6 +150,7 @@ class InputOverlayDrawableDpad(
if (downButtonState && !leftButtonState && !rightButtonState) { if (downButtonState && !leftButtonState && !rightButtonState) {
canvas.save() canvas.save()
canvas.rotate(180f, px.toFloat(), py.toFloat()) canvas.rotate(180f, px.toFloat(), py.toFloat())
pressedOneDirectionStateBitmap.alpha = opacityId
pressedOneDirectionStateBitmap.draw(canvas) pressedOneDirectionStateBitmap.draw(canvas)
canvas.restore() canvas.restore()
return return
@ -154,6 +160,7 @@ class InputOverlayDrawableDpad(
if (leftButtonState && !upButtonState && !downButtonState) { if (leftButtonState && !upButtonState && !downButtonState) {
canvas.save() canvas.save()
canvas.rotate(270f, px.toFloat(), py.toFloat()) canvas.rotate(270f, px.toFloat(), py.toFloat())
pressedOneDirectionStateBitmap.alpha = opacityId
pressedOneDirectionStateBitmap.draw(canvas) pressedOneDirectionStateBitmap.draw(canvas)
canvas.restore() canvas.restore()
return return
@ -163,6 +170,7 @@ class InputOverlayDrawableDpad(
if (rightButtonState && !upButtonState && !downButtonState) { if (rightButtonState && !upButtonState && !downButtonState) {
canvas.save() canvas.save()
canvas.rotate(90f, px.toFloat(), py.toFloat()) canvas.rotate(90f, px.toFloat(), py.toFloat())
pressedOneDirectionStateBitmap.alpha = opacityId
pressedOneDirectionStateBitmap.draw(canvas) pressedOneDirectionStateBitmap.draw(canvas)
canvas.restore() canvas.restore()
return return
@ -170,6 +178,7 @@ class InputOverlayDrawableDpad(
// Pressed up left // Pressed up left
if (upButtonState && leftButtonState && !rightButtonState) { if (upButtonState && leftButtonState && !rightButtonState) {
pressedTwoDirectionsStateBitmap.alpha = opacityId
pressedTwoDirectionsStateBitmap.draw(canvas) pressedTwoDirectionsStateBitmap.draw(canvas)
return return
} }
@ -178,6 +187,7 @@ class InputOverlayDrawableDpad(
if (upButtonState && !leftButtonState && rightButtonState) { if (upButtonState && !leftButtonState && rightButtonState) {
canvas.save() canvas.save()
canvas.rotate(90f, px.toFloat(), py.toFloat()) canvas.rotate(90f, px.toFloat(), py.toFloat())
pressedTwoDirectionsStateBitmap.alpha = opacityId
pressedTwoDirectionsStateBitmap.draw(canvas) pressedTwoDirectionsStateBitmap.draw(canvas)
canvas.restore() canvas.restore()
return return
@ -187,6 +197,7 @@ class InputOverlayDrawableDpad(
if (downButtonState && leftButtonState && !rightButtonState) { if (downButtonState && leftButtonState && !rightButtonState) {
canvas.save() canvas.save()
canvas.rotate(270f, px.toFloat(), py.toFloat()) canvas.rotate(270f, px.toFloat(), py.toFloat())
pressedTwoDirectionsStateBitmap.alpha = opacityId
pressedTwoDirectionsStateBitmap.draw(canvas) pressedTwoDirectionsStateBitmap.draw(canvas)
canvas.restore() canvas.restore()
return return
@ -196,12 +207,14 @@ class InputOverlayDrawableDpad(
if (downButtonState && !leftButtonState && rightButtonState) { if (downButtonState && !leftButtonState && rightButtonState) {
canvas.save() canvas.save()
canvas.rotate(180f, px.toFloat(), py.toFloat()) canvas.rotate(180f, px.toFloat(), py.toFloat())
pressedTwoDirectionsStateBitmap.alpha = opacityId
pressedTwoDirectionsStateBitmap.draw(canvas) pressedTwoDirectionsStateBitmap.draw(canvas)
canvas.restore() canvas.restore()
return return
} }
// Not pressed // Not pressed
defaultStateBitmap.alpha = opacityId
defaultStateBitmap.draw(canvas) defaultStateBitmap.draw(canvas)
} }

View file

@ -29,6 +29,7 @@ import kotlin.math.sqrt
* @param rectOuter [Rect] which represents the outer joystick bounds. * @param rectOuter [Rect] which represents the outer joystick bounds.
* @param rectInner [Rect] which represents the inner joystick bounds. * @param rectInner [Rect] which represents the inner joystick bounds.
* @param joystickId Identifier for which joystick this is. * @param joystickId Identifier for which joystick this is.
* @param opacity 0-255 alpha value
*/ */
class InputOverlayDrawableJoystick( class InputOverlayDrawableJoystick(
res: Resources, res: Resources,
@ -37,7 +38,8 @@ class InputOverlayDrawableJoystick(
bitmapInnerPressed: Bitmap, bitmapInnerPressed: Bitmap,
rectOuter: Rect, rectOuter: Rect,
rectInner: Rect, rectInner: Rect,
val joystickId: Int val joystickId: Int,
val opacity: Int
) { ) {
var trackId = -1 var trackId = -1
var xAxis = 0f var xAxis = 0f
@ -50,6 +52,7 @@ class InputOverlayDrawableJoystick(
private var previousTouchY = 0 private var previousTouchY = 0
val width: Int val width: Int
val height: Int val height: Int
private val opacityId: Int
private var virtBounds: Rect private var virtBounds: Rect
private var origBounds: Rect private var origBounds: Rect
private val outerBitmap: BitmapDrawable private val outerBitmap: BitmapDrawable
@ -72,6 +75,7 @@ class InputOverlayDrawableJoystick(
width = bitmapOuter.width width = bitmapOuter.width
height = bitmapOuter.height height = bitmapOuter.height
bounds = rectOuter bounds = rectOuter
opacityId = opacity
defaultStateInnerBitmap.bounds = rectInner defaultStateInnerBitmap.bounds = rectInner
pressedStateInnerBitmap.bounds = rectInner pressedStateInnerBitmap.bounds = rectInner
virtBounds = bounds virtBounds = bounds
@ -79,10 +83,14 @@ class InputOverlayDrawableJoystick(
boundsBoxBitmap.alpha = 0 boundsBoxBitmap.alpha = 0
boundsBoxBitmap.bounds = virtBounds boundsBoxBitmap.bounds = virtBounds
setInnerBounds() setInnerBounds()
defaultStateInnerBitmap.alpha = opacity
pressedStateInnerBitmap.alpha = opacity
outerBitmap.alpha = opacity
} }
fun draw(canvas: Canvas?) { fun draw(canvas: Canvas?) {
outerBitmap.draw(canvas!!) outerBitmap.draw(canvas!!)
currentStateBitmapDrawable.alpha = opacityId
currentStateBitmapDrawable.draw(canvas) currentStateBitmapDrawable.draw(canvas)
boundsBoxBitmap.draw(canvas) boundsBoxBitmap.draw(canvas)
} }
@ -103,7 +111,7 @@ class InputOverlayDrawableJoystick(
} }
pressedState = true pressedState = true
outerBitmap.alpha = 0 outerBitmap.alpha = 0
boundsBoxBitmap.alpha = 255 boundsBoxBitmap.alpha = opacityId
if (EmulationMenuSettings.joystickRelCenter) { if (EmulationMenuSettings.joystickRelCenter) {
virtBounds.offset( virtBounds.offset(
xPosition - virtBounds.centerX(), xPosition - virtBounds.centerX(),
@ -123,7 +131,7 @@ class InputOverlayDrawableJoystick(
yAxis = 0.0f yAxis = 0.0f
angle = 0.0f angle = 0.0f
radius = 0.0f radius = 0.0f
outerBitmap.alpha = 255 outerBitmap.alpha = opacityId
boundsBoxBitmap.alpha = 0 boundsBoxBitmap.alpha = 0
virtBounds = Rect(origBounds.left, origBounds.top, origBounds.right, origBounds.bottom) virtBounds = Rect(origBounds.left, origBounds.top, origBounds.right, origBounds.bottom)
bounds = Rect(origBounds.left, origBounds.top, origBounds.right, origBounds.bottom) bounds = Rect(origBounds.left, origBounds.top, origBounds.right, origBounds.bottom)

View file

@ -28,6 +28,10 @@
android:id="@+id/menu_emulation_adjust_scale" android:id="@+id/menu_emulation_adjust_scale"
android:title="@string/emulation_control_scale" /> android:title="@string/emulation_control_scale" />
<item
android:id="@+id/menu_emulation_adjust_opacity"
android:title="@string/emulation_control_opacity" />
<group android:checkableBehavior="all"> <group android:checkableBehavior="all">
<item <item
android:id="@+id/menu_emulation_joystick_rel_center" android:id="@+id/menu_emulation_joystick_rel_center"

View file

@ -315,6 +315,7 @@ Se esperan fallos gráficos temporales cuando ésta esté activado.</string>
<string name="emulation_done">Hecho</string> <string name="emulation_done">Hecho</string>
<string name="emulation_toggle_controls">Activar Controles</string> <string name="emulation_toggle_controls">Activar Controles</string>
<string name="emulation_control_scale">Ajustar Escala</string> <string name="emulation_control_scale">Ajustar Escala</string>
<string name="emulation_control_opacity">Ajustar Opacidad</string>
<string name="emulation_control_joystick_rel_center">Posición central relativa del stick</string> <string name="emulation_control_joystick_rel_center">Posición central relativa del stick</string>
<string name="emulation_control_dpad_slide_enable">Deslizamiento de la Cruceta</string> <string name="emulation_control_dpad_slide_enable">Deslizamiento de la Cruceta</string>
<string name="emulation_open_settings">Abrir Configuración</string> <string name="emulation_open_settings">Abrir Configuración</string>

View file

@ -331,6 +331,7 @@
<string name="emulation_done">Done</string> <string name="emulation_done">Done</string>
<string name="emulation_toggle_controls">Toggle Controls</string> <string name="emulation_toggle_controls">Toggle Controls</string>
<string name="emulation_control_scale">Adjust Scale</string> <string name="emulation_control_scale">Adjust Scale</string>
<string name="emulation_control_opacity">Adjust Opacity</string>
<string name="emulation_control_joystick_rel_center">Relative Stick Center</string> <string name="emulation_control_joystick_rel_center">Relative Stick Center</string>
<string name="emulation_control_dpad_slide_enable">D-Pad Sliding</string> <string name="emulation_control_dpad_slide_enable">D-Pad Sliding</string>
<string name="emulation_open_settings">Open Settings</string> <string name="emulation_open_settings">Open Settings</string>