Просмотр исходного кода

android: Re-implement overlay editing

Charles Lombardo 3 лет назад
Родитель
Сommit
b0a434b99f

+ 0 - 1
src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt

@@ -90,7 +90,6 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.Fram
         binding.doneControlConfig.setOnClickListener { stopConfiguringControls() }
 
         // Setup overlay.
-        resetInputOverlay()
         updateShowFpsOverlay()
 
         binding.inGameMenu.getHeaderView(0).findViewById<TextView>(R.id.text_game_title).text =

+ 110 - 3
src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlay.kt

@@ -45,9 +45,15 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : SurfaceView(context
     private val overlayButtons: MutableSet<InputOverlayDrawableButton> = HashSet()
     private val overlayDpads: MutableSet<InputOverlayDrawableDpad> = HashSet()
     private val overlayJoysticks: MutableSet<InputOverlayDrawableJoystick> = HashSet()
+
     private var inEditMode = false
+    private var buttonBeingConfigured: InputOverlayDrawableButton? = null
+    private var dpadBeingConfigured: InputOverlayDrawableDpad? = null
+    private var joystickBeingConfigured: InputOverlayDrawableJoystick? = null
+
     private val preferences: SharedPreferences =
         PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext)
+
     private val gyro = FloatArray(3)
     private val accel = FloatArray(3)
     private var motionTimestamp: Long = 0
@@ -114,7 +120,7 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : SurfaceView(context
             }
             NativeLibrary.onGamePadButtonEvent(
                 NativeLibrary.Player1Device,
-                button.id,
+                button.buttonId,
                 button.status
             )
             shouldUpdateView = true
@@ -224,8 +230,109 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : SurfaceView(context
         return false
     }
 
-    private fun onTouchWhileEditing(event: MotionEvent?): Boolean {
-        // TODO: Reimplement this
+    private fun onTouchWhileEditing(event: MotionEvent): Boolean {
+        val pointerIndex = event.actionIndex
+        val fingerPositionX = event.getX(pointerIndex).toInt()
+        val fingerPositionY = event.getY(pointerIndex).toInt()
+
+        // TODO: Provide support for portrait layout
+        //val orientation =
+        //    if (resources.configuration.orientation == Configuration.ORIENTATION_PORTRAIT) "-Portrait" else ""
+
+        for (button in overlayButtons) {
+            // Determine the button state to apply based on the MotionEvent action flag.
+            when (event.action and MotionEvent.ACTION_MASK) {
+                MotionEvent.ACTION_DOWN,
+                MotionEvent.ACTION_POINTER_DOWN ->
+                    // If no button is being moved now, remember the currently touched button to move.
+                    if (buttonBeingConfigured == null &&
+                        button.bounds.contains(
+                            fingerPositionX,
+                            fingerPositionY
+                        )
+                    ) {
+                        buttonBeingConfigured = button
+                        buttonBeingConfigured!!.onConfigureTouch(event)
+                    }
+                MotionEvent.ACTION_MOVE -> if (buttonBeingConfigured != null) {
+                    buttonBeingConfigured!!.onConfigureTouch(event)
+                    invalidate()
+                    return true
+                }
+                MotionEvent.ACTION_UP,
+                MotionEvent.ACTION_POINTER_UP -> if (buttonBeingConfigured === button) {
+                    // Persist button position by saving new place.
+                    saveControlPosition(
+                        buttonBeingConfigured!!.buttonId,
+                        buttonBeingConfigured!!.bounds.centerX(),
+                        buttonBeingConfigured!!.bounds.centerY(),
+                        ""
+                    )
+                    buttonBeingConfigured = null
+                }
+            }
+        }
+
+        for (dpad in overlayDpads) {
+            // Determine the button state to apply based on the MotionEvent action flag.
+            when (event.action and MotionEvent.ACTION_MASK) {
+                MotionEvent.ACTION_DOWN,
+                MotionEvent.ACTION_POINTER_DOWN ->
+                    // If no button is being moved now, remember the currently touched button to move.
+                    if (buttonBeingConfigured == null &&
+                        dpad.bounds.contains(fingerPositionX, fingerPositionY)
+                    ) {
+                        dpadBeingConfigured = dpad
+                        dpadBeingConfigured!!.onConfigureTouch(event)
+                    }
+                MotionEvent.ACTION_MOVE -> if (dpadBeingConfigured != null) {
+                    dpadBeingConfigured!!.onConfigureTouch(event)
+                    invalidate()
+                    return true
+                }
+                MotionEvent.ACTION_UP,
+                MotionEvent.ACTION_POINTER_UP -> if (dpadBeingConfigured === dpad) {
+                    // Persist button position by saving new place.
+                    saveControlPosition(
+                        dpadBeingConfigured!!.upId,
+                        dpadBeingConfigured!!.bounds.centerX(),
+                        dpadBeingConfigured!!.bounds.centerY(),
+                        ""
+                    )
+                    dpadBeingConfigured = null
+                }
+            }
+        }
+
+        for (joystick in overlayJoysticks) {
+            when (event.action) {
+                MotionEvent.ACTION_DOWN,
+                MotionEvent.ACTION_POINTER_DOWN -> if (joystickBeingConfigured == null &&
+                    joystick.bounds.contains(
+                        fingerPositionX,
+                        fingerPositionY
+                    )
+                ) {
+                    joystickBeingConfigured = joystick
+                    joystickBeingConfigured!!.onConfigureTouch(event)
+                }
+                MotionEvent.ACTION_MOVE -> if (joystickBeingConfigured != null) {
+                    joystickBeingConfigured!!.onConfigureTouch(event)
+                    invalidate()
+                }
+                MotionEvent.ACTION_UP,
+                MotionEvent.ACTION_POINTER_UP -> if (joystickBeingConfigured != null) {
+                    saveControlPosition(
+                        joystickBeingConfigured!!.buttonId,
+                        joystickBeingConfigured!!.bounds.centerX(),
+                        joystickBeingConfigured!!.bounds.centerY(),
+                        ""
+                    )
+                    joystickBeingConfigured = null
+                }
+            }
+        }
+
         return true
     }
 

+ 37 - 11
src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlayDrawableButton.kt

@@ -24,32 +24,30 @@ class InputOverlayDrawableButton(
     res: Resources,
     defaultStateBitmap: Bitmap,
     pressedStateBitmap: Bitmap,
-    buttonId: Int
+    val buttonId: Int
 ) {
-    /**
-     * Gets this InputOverlayDrawableButton's button ID.
-     *
-     * @return this InputOverlayDrawableButton's button ID.
-     */
-    // The ID value what type of button this Drawable represents.
-    val id: Int
-
     // 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)
-        id = buttonId
         trackId = -1
         width = this.defaultStateBitmap.intrinsicWidth
         height = this.defaultStateBitmap.intrinsicHeight
@@ -104,6 +102,34 @@ class InputOverlayDrawableButton(
     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)
@@ -111,6 +137,6 @@ class InputOverlayDrawableButton(
 
     val status: Int
         get() = if (pressedState) ButtonState.PRESSED else ButtonState.RELEASED
-    private val bounds: Rect
+    val bounds: Rect
         get() = defaultStateBitmap.bounds
 }

+ 34 - 2
src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlayDrawableDpad.kt

@@ -45,13 +45,19 @@ class InputOverlayDrawableDpad(
     val leftId: Int
     val rightId: Int
     var trackId: Int
-    private var controlPositionX = 0
-    private var controlPositionY = 0
+
     val width: Int
     val height: Int
+
     private val defaultStateBitmap: BitmapDrawable
     private val pressedOneDirectionStateBitmap: BitmapDrawable
     private val pressedTwoDirectionsStateBitmap: BitmapDrawable
+
+    private var previousTouchX = 0
+    private var previousTouchY = 0
+    private var controlPositionX = 0
+    private var controlPositionY = 0
+
     private var upButtonState = false
     private var downButtonState = false
     private var leftButtonState = false
@@ -215,6 +221,32 @@ class InputOverlayDrawableDpad(
     val rightStatus: Int
         get() = if (rightButtonState) ButtonState.PRESSED else ButtonState.RELEASED
 
+    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
+            }
+            MotionEvent.ACTION_MOVE -> {
+                controlPositionX += fingerPositionX - previousTouchX
+                controlPositionY += fingerPositionY - previousTouchY
+                setBounds(
+                    controlPositionX,
+                    controlPositionY,
+                    width + controlPositionX,
+                    height + controlPositionY
+                )
+                previousTouchX = fingerPositionX
+                previousTouchY = fingerPositionY
+            }
+        }
+        return true
+    }
+
     fun setPosition(x: Int, y: Int) {
         controlPositionX = x
         controlPositionY = y

+ 64 - 8
src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlayDrawableJoystick.kt

@@ -39,31 +39,39 @@ class InputOverlayDrawableJoystick(
     val joystickId: Int,
     val buttonId: Int
 ) {
-
     // The ID value what motion event is tracking
     var trackId = -1
+
     var xAxis = 0f
     private var yAxis = 0f
-    private var controlPositionX = 0
-    private var controlPositionY = 0
+
     val width: Int
     val height: Int
+
     private var virtBounds: Rect
-    private val origBounds: Rect
+    private var origBounds: Rect
+
     private val outerBitmap: BitmapDrawable
     private val defaultStateInnerBitmap: BitmapDrawable
     private val pressedStateInnerBitmap: BitmapDrawable
+
+    private var previousTouchX = 0
+    private var previousTouchY = 0
+    var controlPositionX = 0
+    var controlPositionY = 0
+
     private val boundsBoxBitmap: BitmapDrawable
+
     private var pressedState = false
 
     // TODO: Add button support
     val buttonStatus: Int
         get() =
             NativeLibrary.ButtonState.RELEASED
-    var bounds: Rect?
+    var bounds: Rect
         get() = outerBitmap.bounds
         set(bounds) {
-            outerBitmap.bounds = bounds!!
+            outerBitmap.bounds = bounds
         }
 
     // Nintendo joysticks have y axis inverted
@@ -83,7 +91,7 @@ class InputOverlayDrawableJoystick(
         bounds = rectOuter
         defaultStateInnerBitmap.bounds = rectInner
         pressedStateInnerBitmap.bounds = rectInner
-        virtBounds = bounds!!
+        virtBounds = bounds
         origBounds = outerBitmap.copyBounds()
         boundsBoxBitmap.alpha = 0
         boundsBoxBitmap.bounds = virtBounds
@@ -106,8 +114,9 @@ class InputOverlayDrawableJoystick(
             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)) {
+            if (!bounds.contains(xPosition, yPosition)) {
                 return false
             }
             pressedState = true
@@ -122,6 +131,7 @@ class InputOverlayDrawableJoystick(
             boundsBoxBitmap.bounds = virtBounds
             trackId = pointerId
         }
+
         if (isActionUp) {
             if (trackId != pointerId) {
                 return false
@@ -147,7 +157,9 @@ class InputOverlayDrawableJoystick(
             trackId = -1
             return true
         }
+
         if (trackId == -1) return false
+
         for (i in 0 until event.pointerCount) {
             if (trackId != event.getPointerId(i)) {
                 continue
@@ -179,6 +191,50 @@ class InputOverlayDrawableJoystick(
         return false
     }
 
+    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
+                bounds = Rect(
+                    controlPositionX,
+                    controlPositionY,
+                    outerBitmap.intrinsicWidth + controlPositionX,
+                    outerBitmap.intrinsicHeight + controlPositionY
+                )
+                virtBounds = Rect(
+                    controlPositionX,
+                    controlPositionY,
+                    outerBitmap.intrinsicWidth + controlPositionX,
+                    outerBitmap.intrinsicHeight + controlPositionY
+                )
+                setInnerBounds()
+                bounds = Rect(
+                    Rect(
+                        controlPositionX,
+                        controlPositionY,
+                        outerBitmap.intrinsicWidth + controlPositionX,
+                        outerBitmap.intrinsicHeight + controlPositionY
+                    )
+                )
+                previousTouchX = fingerPositionX
+                previousTouchY = fingerPositionY
+            }
+        }
+        origBounds = outerBitmap.copyBounds()
+        return true
+    }
+
     private fun setInnerBounds() {
         var x = virtBounds.centerX() + (xAxis * (virtBounds.width() / 2)).toInt()
         var y = virtBounds.centerY() + (yAxis * (virtBounds.height() / 2)).toInt()