pineapple-src/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlayDrawableButton.kt

152 lines
4.8 KiB
Kotlin
Executable File

// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
package org.yuzu.yuzu_emu.overlay
import android.content.res.Resources
import android.graphics.Bitmap
import android.graphics.Canvas
import android.graphics.Rect
import android.graphics.drawable.BitmapDrawable
import android.view.MotionEvent
import org.yuzu.yuzu_emu.features.input.NativeInput.ButtonState
import org.yuzu.yuzu_emu.features.input.model.NativeButton
import org.yuzu.yuzu_emu.overlay.model.OverlayControlData
/**
* Custom [BitmapDrawable] that is capable
* of storing it's own ID.
*
* @param res [Resources] instance.
* @param defaultStateBitmap [Bitmap] to use with the default state Drawable.
* @param pressedStateBitmap [Bitmap] to use with the pressed state Drawable.
* @param button [NativeButton] for this type of button.
*/
class InputOverlayDrawableButton(
res: Resources,
defaultStateBitmap: Bitmap,
pressedStateBitmap: Bitmap,
val button: NativeButton,
val overlayControlData: OverlayControlData
) {
// The ID value what motion event is tracking
var trackId: Int
// The drawable position on the screen
private var buttonPositionX = 0
private var buttonPositionY = 0
val width: Int
val height: Int
private val defaultStateBitmap: BitmapDrawable
private val pressedStateBitmap: BitmapDrawable
private var pressedState = false
private var previousTouchX = 0
private var previousTouchY = 0
var controlPositionX = 0
var controlPositionY = 0
init {
this.defaultStateBitmap = BitmapDrawable(res, defaultStateBitmap)
this.pressedStateBitmap = BitmapDrawable(res, pressedStateBitmap)
trackId = -1
width = this.defaultStateBitmap.intrinsicWidth
height = this.defaultStateBitmap.intrinsicHeight
}
/**
* Updates button status based on the motion event.
*
* @return true if value was changed
*/
fun updateStatus(event: MotionEvent): Boolean {
val pointerIndex = event.actionIndex
val xPosition = event.getX(pointerIndex).toInt()
val yPosition = event.getY(pointerIndex).toInt()
val pointerId = event.getPointerId(pointerIndex)
val motionEvent = event.action and MotionEvent.ACTION_MASK
val isActionDown =
motionEvent == MotionEvent.ACTION_DOWN || motionEvent == MotionEvent.ACTION_POINTER_DOWN
val isActionUp =
motionEvent == MotionEvent.ACTION_UP || motionEvent == MotionEvent.ACTION_POINTER_UP
if (isActionDown) {
if (!bounds.contains(xPosition, yPosition)) {
return false
}
pressedState = true
trackId = pointerId
return true
}
if (isActionUp) {
if (trackId != pointerId) {
return false
}
pressedState = false
trackId = -1
return true
}
return false
}
fun setPosition(x: Int, y: Int) {
buttonPositionX = x
buttonPositionY = y
}
fun draw(canvas: Canvas?) {
currentStateBitmapDrawable.draw(canvas!!)
}
private val currentStateBitmapDrawable: BitmapDrawable
get() = if (pressedState) pressedStateBitmap else defaultStateBitmap
fun onConfigureTouch(event: MotionEvent): Boolean {
val pointerIndex = event.actionIndex
val fingerPositionX = event.getX(pointerIndex).toInt()
val fingerPositionY = event.getY(pointerIndex).toInt()
when (event.action) {
MotionEvent.ACTION_DOWN -> {
previousTouchX = fingerPositionX
previousTouchY = fingerPositionY
controlPositionX = fingerPositionX - (width / 2)
controlPositionY = fingerPositionY - (height / 2)
}
MotionEvent.ACTION_MOVE -> {
controlPositionX += fingerPositionX - previousTouchX
controlPositionY += fingerPositionY - previousTouchY
setBounds(
controlPositionX,
controlPositionY,
width + controlPositionX,
height + controlPositionY
)
previousTouchX = fingerPositionX
previousTouchY = fingerPositionY
}
}
return true
}
fun setBounds(left: Int, top: Int, right: Int, bottom: Int) {
defaultStateBitmap.setBounds(left, top, right, bottom)
pressedStateBitmap.setBounds(left, top, right, bottom)
}
fun setOpacity(value: Int) {
defaultStateBitmap.alpha = value
pressedStateBitmap.alpha = value
}
val status: Int
get() = if (pressedState) ButtonState.PRESSED else ButtonState.RELEASED
val bounds: Rect
get() = defaultStateBitmap.bounds
}