mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2024-11-14 13:27:45 -07:00
Merge pull request #11884 from t895/kotlin-overlay
Android: Convert InputOverlay to Kotlin
This commit is contained in:
commit
04fab7f2b2
@ -238,7 +238,7 @@ public final class EmulationFragment extends Fragment implements SurfaceHolder.C
|
||||
if (mInputOverlay != null)
|
||||
{
|
||||
mBinding.doneControlConfig.setVisibility(View.VISIBLE);
|
||||
mInputOverlay.setIsInEditMode(true);
|
||||
mInputOverlay.setEditMode(true);
|
||||
}
|
||||
}
|
||||
|
||||
@ -247,7 +247,7 @@ public final class EmulationFragment extends Fragment implements SurfaceHolder.C
|
||||
if (mInputOverlay != null)
|
||||
{
|
||||
mBinding.doneControlConfig.setVisibility(View.GONE);
|
||||
mInputOverlay.setIsInEditMode(false);
|
||||
mInputOverlay.setEditMode(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,144 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013 Dolphin Emulator Project
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
package org.dolphinemu.dolphinemu.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;
|
||||
|
||||
/**
|
||||
* Custom {@link BitmapDrawable} that is capable
|
||||
* of storing it's own ID.
|
||||
*/
|
||||
public final class InputOverlayDrawableButton
|
||||
{
|
||||
// The legacy ID identifying what type of button this Drawable represents.
|
||||
private int mLegacyId;
|
||||
private int mControl;
|
||||
private int mTrackId;
|
||||
private int mPreviousTouchX, mPreviousTouchY;
|
||||
private int mControlPositionX, mControlPositionY;
|
||||
private int mWidth;
|
||||
private int mHeight;
|
||||
private BitmapDrawable mDefaultStateBitmap;
|
||||
private BitmapDrawable mPressedStateBitmap;
|
||||
private boolean mPressedState = false;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param res {@link Resources} instance.
|
||||
* @param defaultStateBitmap {@link Bitmap} to use with the default state Drawable.
|
||||
* @param pressedStateBitmap {@link Bitmap} to use with the pressed state Drawable.
|
||||
* @param legacyId Legacy identifier (ButtonType) for this type of button.
|
||||
* @param control Control ID for this type of button.
|
||||
*/
|
||||
public InputOverlayDrawableButton(Resources res, Bitmap defaultStateBitmap,
|
||||
Bitmap pressedStateBitmap, int legacyId, int control)
|
||||
{
|
||||
mTrackId = -1;
|
||||
mDefaultStateBitmap = new BitmapDrawable(res, defaultStateBitmap);
|
||||
mPressedStateBitmap = new BitmapDrawable(res, pressedStateBitmap);
|
||||
mLegacyId = legacyId;
|
||||
mControl = control;
|
||||
|
||||
mWidth = mDefaultStateBitmap.getIntrinsicWidth();
|
||||
mHeight = mDefaultStateBitmap.getIntrinsicHeight();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets this InputOverlayDrawableButton's legacy button ID.
|
||||
*/
|
||||
public int getLegacyId()
|
||||
{
|
||||
return mLegacyId;
|
||||
}
|
||||
|
||||
public int getControl()
|
||||
{
|
||||
return mControl;
|
||||
}
|
||||
|
||||
public void setTrackId(int trackId)
|
||||
{
|
||||
mTrackId = trackId;
|
||||
}
|
||||
|
||||
public int getTrackId()
|
||||
{
|
||||
return mTrackId;
|
||||
}
|
||||
|
||||
public void onConfigureTouch(MotionEvent event)
|
||||
{
|
||||
switch (event.getAction())
|
||||
{
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
mPreviousTouchX = (int) event.getX();
|
||||
mPreviousTouchY = (int) event.getY();
|
||||
break;
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
mControlPositionX += (int) event.getX() - mPreviousTouchX;
|
||||
mControlPositionY += (int) event.getY() - mPreviousTouchY;
|
||||
setBounds(mControlPositionX, mControlPositionY, getWidth() + mControlPositionX,
|
||||
getHeight() + mControlPositionY);
|
||||
mPreviousTouchX = (int) event.getX();
|
||||
mPreviousTouchY = (int) event.getY();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void setPosition(int x, int y)
|
||||
{
|
||||
mControlPositionX = x;
|
||||
mControlPositionY = y;
|
||||
}
|
||||
|
||||
public void draw(Canvas canvas)
|
||||
{
|
||||
getCurrentStateBitmapDrawable().draw(canvas);
|
||||
}
|
||||
|
||||
private BitmapDrawable getCurrentStateBitmapDrawable()
|
||||
{
|
||||
return mPressedState ? mPressedStateBitmap : mDefaultStateBitmap;
|
||||
}
|
||||
|
||||
public void setBounds(int left, int top, int right, int bottom)
|
||||
{
|
||||
mDefaultStateBitmap.setBounds(left, top, right, bottom);
|
||||
mPressedStateBitmap.setBounds(left, top, right, bottom);
|
||||
}
|
||||
|
||||
public void setOpacity(int value)
|
||||
{
|
||||
mDefaultStateBitmap.setAlpha(value);
|
||||
mPressedStateBitmap.setAlpha(value);
|
||||
}
|
||||
|
||||
public Rect getBounds()
|
||||
{
|
||||
return mDefaultStateBitmap.getBounds();
|
||||
}
|
||||
|
||||
public int getWidth()
|
||||
{
|
||||
return mWidth;
|
||||
}
|
||||
|
||||
public int getHeight()
|
||||
{
|
||||
return mHeight;
|
||||
}
|
||||
|
||||
public void setPressedState(boolean isPressed)
|
||||
{
|
||||
mPressedState = isPressed;
|
||||
}
|
||||
}
|
@ -0,0 +1,97 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
package org.dolphinemu.dolphinemu.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
|
||||
|
||||
/**
|
||||
* 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 legacyId Legacy identifier (ButtonType) for this type of button.
|
||||
* @param control Control ID for this type of button.
|
||||
*/
|
||||
class InputOverlayDrawableButton(
|
||||
res: Resources,
|
||||
defaultStateBitmap: Bitmap,
|
||||
pressedStateBitmap: Bitmap,
|
||||
val legacyId: Int,
|
||||
val control: Int
|
||||
) {
|
||||
var trackId: Int = -1
|
||||
private var previousTouchX = 0
|
||||
private var previousTouchY = 0
|
||||
private var controlPositionX = 0
|
||||
private var controlPositionY = 0
|
||||
val width: Int
|
||||
val height: Int
|
||||
private val defaultStateBitmap: BitmapDrawable
|
||||
private val pressedStateBitmap: BitmapDrawable
|
||||
private var pressedState = false
|
||||
|
||||
init {
|
||||
this.defaultStateBitmap = BitmapDrawable(res, defaultStateBitmap)
|
||||
this.pressedStateBitmap = BitmapDrawable(res, pressedStateBitmap)
|
||||
width = this.defaultStateBitmap.intrinsicWidth
|
||||
height = this.defaultStateBitmap.intrinsicHeight
|
||||
}
|
||||
|
||||
fun onConfigureTouch(event: MotionEvent) {
|
||||
when (event.action) {
|
||||
MotionEvent.ACTION_DOWN -> {
|
||||
previousTouchX = event.x.toInt()
|
||||
previousTouchY = event.y.toInt()
|
||||
}
|
||||
|
||||
MotionEvent.ACTION_MOVE -> {
|
||||
controlPositionX += event.x.toInt() - previousTouchX
|
||||
controlPositionY += event.y.toInt() - previousTouchY
|
||||
setBounds(
|
||||
controlPositionX,
|
||||
controlPositionY,
|
||||
width + controlPositionX,
|
||||
height + controlPositionY
|
||||
)
|
||||
previousTouchX = event.x.toInt()
|
||||
previousTouchY = event.y.toInt()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun setPosition(x: Int, y: Int) {
|
||||
controlPositionX = x
|
||||
controlPositionY = y
|
||||
}
|
||||
|
||||
fun draw(canvas: Canvas) {
|
||||
currentStateBitmapDrawable.draw(canvas)
|
||||
}
|
||||
|
||||
private val currentStateBitmapDrawable: BitmapDrawable
|
||||
get() = if (pressedState) pressedStateBitmap else defaultStateBitmap
|
||||
|
||||
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 bounds: Rect
|
||||
get() = defaultStateBitmap.bounds
|
||||
|
||||
fun setPressedState(isPressed: Boolean) {
|
||||
pressedState = isPressed
|
||||
}
|
||||
}
|
@ -1,211 +0,0 @@
|
||||
/*
|
||||
* Copyright 2016 Dolphin Emulator Project
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
package org.dolphinemu.dolphinemu.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;
|
||||
|
||||
/**
|
||||
* Custom {@link BitmapDrawable} that is capable
|
||||
* of storing it's own ID.
|
||||
*/
|
||||
public final class InputOverlayDrawableDpad
|
||||
{
|
||||
// The legacy ID identifying what type of button this Drawable represents.
|
||||
private int mLegacyId;
|
||||
private int[] mControls = new int[4];
|
||||
private int mTrackId;
|
||||
private int mPreviousTouchX, mPreviousTouchY;
|
||||
private int mControlPositionX, mControlPositionY;
|
||||
private int mWidth;
|
||||
private int mHeight;
|
||||
private BitmapDrawable mDefaultStateBitmap;
|
||||
private BitmapDrawable mPressedOneDirectionStateBitmap;
|
||||
private BitmapDrawable mPressedTwoDirectionsStateBitmap;
|
||||
private int mPressState = STATE_DEFAULT;
|
||||
|
||||
public static final int STATE_DEFAULT = 0;
|
||||
public static final int STATE_PRESSED_UP = 1;
|
||||
public static final int STATE_PRESSED_DOWN = 2;
|
||||
public static final int STATE_PRESSED_LEFT = 3;
|
||||
public static final int STATE_PRESSED_RIGHT = 4;
|
||||
public static final int STATE_PRESSED_UP_LEFT = 5;
|
||||
public static final int STATE_PRESSED_UP_RIGHT = 6;
|
||||
public static final int STATE_PRESSED_DOWN_LEFT = 7;
|
||||
public static final int STATE_PRESSED_DOWN_RIGHT = 8;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param res {@link Resources} instance.
|
||||
* @param defaultStateBitmap {@link Bitmap} of the default state.
|
||||
* @param pressedOneDirectionStateBitmap {@link Bitmap} of the pressed state in one direction.
|
||||
* @param pressedTwoDirectionsStateBitmap {@link Bitmap} of the pressed state in two direction.
|
||||
* @param legacyId Legacy identifier (ButtonType) for the up button.
|
||||
* @param upControl Control identifier for the up button.
|
||||
* @param downControl Control identifier for the down button.
|
||||
* @param leftControl Control identifier for the left button.
|
||||
* @param rightControl Control identifier for the right button.
|
||||
*/
|
||||
public InputOverlayDrawableDpad(Resources res, Bitmap defaultStateBitmap,
|
||||
Bitmap pressedOneDirectionStateBitmap, Bitmap pressedTwoDirectionsStateBitmap,
|
||||
int legacyId, int upControl, int downControl, int leftControl, int rightControl)
|
||||
{
|
||||
mTrackId = -1;
|
||||
mDefaultStateBitmap = new BitmapDrawable(res, defaultStateBitmap);
|
||||
mPressedOneDirectionStateBitmap = new BitmapDrawable(res, pressedOneDirectionStateBitmap);
|
||||
mPressedTwoDirectionsStateBitmap = new BitmapDrawable(res, pressedTwoDirectionsStateBitmap);
|
||||
|
||||
mWidth = mDefaultStateBitmap.getIntrinsicWidth();
|
||||
mHeight = mDefaultStateBitmap.getIntrinsicHeight();
|
||||
|
||||
mLegacyId = legacyId;
|
||||
mControls[0] = upControl;
|
||||
mControls[1] = downControl;
|
||||
mControls[2] = leftControl;
|
||||
mControls[3] = rightControl;
|
||||
}
|
||||
|
||||
public void draw(Canvas canvas)
|
||||
{
|
||||
int px = mControlPositionX + (getWidth() / 2);
|
||||
int py = mControlPositionY + (getHeight() / 2);
|
||||
switch (mPressState)
|
||||
{
|
||||
case STATE_DEFAULT:
|
||||
mDefaultStateBitmap.draw(canvas);
|
||||
break;
|
||||
case STATE_PRESSED_UP:
|
||||
mPressedOneDirectionStateBitmap.draw(canvas);
|
||||
break;
|
||||
case STATE_PRESSED_RIGHT:
|
||||
canvas.save();
|
||||
canvas.rotate(90, px, py);
|
||||
mPressedOneDirectionStateBitmap.draw(canvas);
|
||||
canvas.restore();
|
||||
break;
|
||||
case STATE_PRESSED_DOWN:
|
||||
canvas.save();
|
||||
canvas.rotate(180, px, py);
|
||||
mPressedOneDirectionStateBitmap.draw(canvas);
|
||||
canvas.restore();
|
||||
break;
|
||||
case STATE_PRESSED_LEFT:
|
||||
canvas.save();
|
||||
canvas.rotate(270, px, py);
|
||||
mPressedOneDirectionStateBitmap.draw(canvas);
|
||||
canvas.restore();
|
||||
break;
|
||||
case STATE_PRESSED_UP_LEFT:
|
||||
mPressedTwoDirectionsStateBitmap.draw(canvas);
|
||||
break;
|
||||
case STATE_PRESSED_UP_RIGHT:
|
||||
canvas.save();
|
||||
canvas.rotate(90, px, py);
|
||||
mPressedTwoDirectionsStateBitmap.draw(canvas);
|
||||
canvas.restore();
|
||||
break;
|
||||
case STATE_PRESSED_DOWN_RIGHT:
|
||||
canvas.save();
|
||||
canvas.rotate(180, px, py);
|
||||
mPressedTwoDirectionsStateBitmap.draw(canvas);
|
||||
canvas.restore();
|
||||
break;
|
||||
case STATE_PRESSED_DOWN_LEFT:
|
||||
canvas.save();
|
||||
canvas.rotate(270, px, py);
|
||||
mPressedTwoDirectionsStateBitmap.draw(canvas);
|
||||
canvas.restore();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public int getLegacyId()
|
||||
{
|
||||
return mLegacyId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets one of the InputOverlayDrawableDpad's control IDs.
|
||||
*/
|
||||
public int getControl(int direction)
|
||||
{
|
||||
return mControls[direction];
|
||||
}
|
||||
|
||||
public void setTrackId(int trackId)
|
||||
{
|
||||
mTrackId = trackId;
|
||||
}
|
||||
|
||||
public int getTrackId()
|
||||
{
|
||||
return mTrackId;
|
||||
}
|
||||
|
||||
public void onConfigureTouch(MotionEvent event)
|
||||
{
|
||||
switch (event.getAction())
|
||||
{
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
mPreviousTouchX = (int) event.getX();
|
||||
mPreviousTouchY = (int) event.getY();
|
||||
break;
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
mControlPositionX += (int) event.getX() - mPreviousTouchX;
|
||||
mControlPositionY += (int) event.getY() - mPreviousTouchY;
|
||||
setBounds(mControlPositionX, mControlPositionY, getWidth() + mControlPositionX,
|
||||
getHeight() + mControlPositionY);
|
||||
mPreviousTouchX = (int) event.getX();
|
||||
mPreviousTouchY = (int) event.getY();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void setPosition(int x, int y)
|
||||
{
|
||||
mControlPositionX = x;
|
||||
mControlPositionY = y;
|
||||
}
|
||||
|
||||
public void setBounds(int left, int top, int right, int bottom)
|
||||
{
|
||||
mDefaultStateBitmap.setBounds(left, top, right, bottom);
|
||||
mPressedOneDirectionStateBitmap.setBounds(left, top, right, bottom);
|
||||
mPressedTwoDirectionsStateBitmap.setBounds(left, top, right, bottom);
|
||||
}
|
||||
|
||||
public void setOpacity(int value)
|
||||
{
|
||||
mDefaultStateBitmap.setAlpha(value);
|
||||
mPressedOneDirectionStateBitmap.setAlpha(value);
|
||||
mPressedTwoDirectionsStateBitmap.setAlpha(value);
|
||||
}
|
||||
|
||||
public Rect getBounds()
|
||||
{
|
||||
return mDefaultStateBitmap.getBounds();
|
||||
}
|
||||
|
||||
public int getWidth()
|
||||
{
|
||||
return mWidth;
|
||||
}
|
||||
|
||||
public int getHeight()
|
||||
{
|
||||
return mHeight;
|
||||
}
|
||||
|
||||
public void setState(int pressState)
|
||||
{
|
||||
mPressState = pressState;
|
||||
}
|
||||
}
|
@ -0,0 +1,189 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
package org.dolphinemu.dolphinemu.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
|
||||
|
||||
/**
|
||||
* Custom [BitmapDrawable] that is capable
|
||||
* of storing it's own ID.
|
||||
*
|
||||
* @param res [Resources] instance.
|
||||
* @param defaultStateBitmap [Bitmap] of the default state.
|
||||
* @param pressedOneDirectionStateBitmap [Bitmap] of the pressed state in one direction.
|
||||
* @param pressedTwoDirectionsStateBitmap [Bitmap] of the pressed state in two direction.
|
||||
* @param legacyId Legacy identifier (ButtonType) for the up button.
|
||||
* @param upControl Control identifier for the up button.
|
||||
* @param downControl Control identifier for the down button.
|
||||
* @param leftControl Control identifier for the left button.
|
||||
* @param rightControl Control identifier for the right button.
|
||||
*/
|
||||
class InputOverlayDrawableDpad(
|
||||
res: Resources,
|
||||
defaultStateBitmap: Bitmap,
|
||||
pressedOneDirectionStateBitmap: Bitmap,
|
||||
pressedTwoDirectionsStateBitmap: Bitmap,
|
||||
val legacyId: Int,
|
||||
upControl: Int,
|
||||
downControl: Int,
|
||||
leftControl: Int,
|
||||
rightControl: Int
|
||||
) {
|
||||
private val controls = IntArray(4)
|
||||
var trackId: Int = -1
|
||||
private var previousTouchX = 0
|
||||
private var previousTouchY = 0
|
||||
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 pressState = STATE_DEFAULT
|
||||
|
||||
init {
|
||||
this.defaultStateBitmap = BitmapDrawable(res, defaultStateBitmap)
|
||||
this.pressedOneDirectionStateBitmap = BitmapDrawable(res, pressedOneDirectionStateBitmap)
|
||||
this.pressedTwoDirectionsStateBitmap = BitmapDrawable(res, pressedTwoDirectionsStateBitmap)
|
||||
|
||||
width = this.defaultStateBitmap.intrinsicWidth
|
||||
height = this.defaultStateBitmap.intrinsicHeight
|
||||
|
||||
controls[0] = upControl
|
||||
controls[1] = downControl
|
||||
controls[2] = leftControl
|
||||
controls[3] = rightControl
|
||||
}
|
||||
|
||||
fun draw(canvas: Canvas) {
|
||||
val px = controlPositionX + width / 2
|
||||
val py = controlPositionY + height / 2
|
||||
when (pressState) {
|
||||
STATE_DEFAULT -> defaultStateBitmap.draw(canvas)
|
||||
STATE_PRESSED_UP -> pressedOneDirectionStateBitmap.draw(canvas)
|
||||
STATE_PRESSED_RIGHT -> {
|
||||
canvas.apply {
|
||||
save()
|
||||
rotate(90f, px.toFloat(), py.toFloat())
|
||||
pressedOneDirectionStateBitmap.draw(canvas)
|
||||
restore()
|
||||
}
|
||||
}
|
||||
|
||||
STATE_PRESSED_DOWN -> {
|
||||
canvas.apply {
|
||||
save()
|
||||
rotate(180f, px.toFloat(), py.toFloat())
|
||||
pressedOneDirectionStateBitmap.draw(canvas)
|
||||
restore()
|
||||
}
|
||||
}
|
||||
|
||||
STATE_PRESSED_LEFT -> {
|
||||
canvas.apply {
|
||||
save()
|
||||
rotate(270f, px.toFloat(), py.toFloat())
|
||||
pressedOneDirectionStateBitmap.draw(canvas)
|
||||
restore()
|
||||
}
|
||||
}
|
||||
|
||||
STATE_PRESSED_UP_LEFT -> pressedTwoDirectionsStateBitmap.draw(canvas)
|
||||
STATE_PRESSED_UP_RIGHT -> {
|
||||
canvas.apply {
|
||||
save()
|
||||
rotate(90f, px.toFloat(), py.toFloat())
|
||||
pressedTwoDirectionsStateBitmap.draw(canvas)
|
||||
restore()
|
||||
}
|
||||
}
|
||||
|
||||
STATE_PRESSED_DOWN_RIGHT -> {
|
||||
canvas.apply {
|
||||
save()
|
||||
rotate(180f, px.toFloat(), py.toFloat())
|
||||
pressedTwoDirectionsStateBitmap.draw(canvas)
|
||||
restore()
|
||||
}
|
||||
}
|
||||
|
||||
STATE_PRESSED_DOWN_LEFT -> {
|
||||
canvas.apply {
|
||||
save()
|
||||
rotate(270f, px.toFloat(), py.toFloat())
|
||||
pressedTwoDirectionsStateBitmap.draw(canvas)
|
||||
restore()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets one of the InputOverlayDrawableDpad's control IDs.
|
||||
*/
|
||||
fun getControl(direction: Int): Int {
|
||||
return controls[direction]
|
||||
}
|
||||
|
||||
fun onConfigureTouch(event: MotionEvent) {
|
||||
when (event.action) {
|
||||
MotionEvent.ACTION_DOWN -> {
|
||||
previousTouchX = event.x.toInt()
|
||||
previousTouchY = event.y.toInt()
|
||||
}
|
||||
|
||||
MotionEvent.ACTION_MOVE -> {
|
||||
controlPositionX += event.x.toInt() - previousTouchX
|
||||
controlPositionY += event.y.toInt() - previousTouchY
|
||||
setBounds(
|
||||
controlPositionX, controlPositionY, width + controlPositionX,
|
||||
height + controlPositionY
|
||||
)
|
||||
previousTouchX = event.x.toInt()
|
||||
previousTouchY = event.y.toInt()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun setPosition(x: Int, y: Int) {
|
||||
controlPositionX = x
|
||||
controlPositionY = y
|
||||
}
|
||||
|
||||
fun setBounds(left: Int, top: Int, right: Int, bottom: Int) {
|
||||
defaultStateBitmap.setBounds(left, top, right, bottom)
|
||||
pressedOneDirectionStateBitmap.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
|
||||
get() = defaultStateBitmap.bounds
|
||||
|
||||
fun setState(pressState: Int) {
|
||||
this.pressState = pressState
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val STATE_DEFAULT = 0
|
||||
const val STATE_PRESSED_UP = 1
|
||||
const val STATE_PRESSED_DOWN = 2
|
||||
const val STATE_PRESSED_LEFT = 3
|
||||
const val STATE_PRESSED_RIGHT = 4
|
||||
const val STATE_PRESSED_UP_LEFT = 5
|
||||
const val STATE_PRESSED_UP_RIGHT = 6
|
||||
const val STATE_PRESSED_DOWN_LEFT = 7
|
||||
const val STATE_PRESSED_DOWN_RIGHT = 8
|
||||
}
|
||||
}
|
@ -1,318 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013 Dolphin Emulator Project
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
package org.dolphinemu.dolphinemu.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.dolphinemu.dolphinemu.features.input.model.InputOverrider;
|
||||
import org.dolphinemu.dolphinemu.features.settings.model.BooleanSetting;
|
||||
|
||||
/**
|
||||
* Custom {@link BitmapDrawable} that is capable
|
||||
* of storing it's own ID.
|
||||
*/
|
||||
public final class InputOverlayDrawableJoystick
|
||||
{
|
||||
private float mCurrentX = 0.0f;
|
||||
private float mCurrentY = 0.0f;
|
||||
private int trackId = -1;
|
||||
private final int mJoystickLegacyId;
|
||||
private final int mJoystickXControl;
|
||||
private final int mJoystickYControl;
|
||||
private int mControlPositionX, mControlPositionY;
|
||||
private int mPreviousTouchX, mPreviousTouchY;
|
||||
private final int mWidth;
|
||||
private final int mHeight;
|
||||
private final int mControllerIndex;
|
||||
private Rect mVirtBounds;
|
||||
private Rect mOrigBounds;
|
||||
private int mOpacity;
|
||||
private final BitmapDrawable mOuterBitmap;
|
||||
private final BitmapDrawable mDefaultStateInnerBitmap;
|
||||
private final BitmapDrawable mPressedStateInnerBitmap;
|
||||
private final BitmapDrawable mBoundsBoxBitmap;
|
||||
private boolean mPressedState = false;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param res {@link Resources} instance.
|
||||
* @param bitmapOuter {@link Bitmap} which represents the outer non-movable part of the joystick.
|
||||
* @param bitmapInnerDefault {@link Bitmap} which represents the default inner movable part of the joystick.
|
||||
* @param bitmapInnerPressed {@link Bitmap} which represents the pressed inner movable part of the joystick.
|
||||
* @param rectOuter {@link Rect} which represents the outer joystick bounds.
|
||||
* @param rectInner {@link Rect} which represents the inner joystick bounds.
|
||||
* @param legacyId Legacy identifier (ButtonType) for which joystick this is.
|
||||
* @param xControl The control which the x value of the joystick will be written to.
|
||||
* @param yControl The control which the y value of the joystick will be written to.
|
||||
*/
|
||||
public InputOverlayDrawableJoystick(Resources res, Bitmap bitmapOuter, Bitmap bitmapInnerDefault,
|
||||
Bitmap bitmapInnerPressed, Rect rectOuter, Rect rectInner, int legacyId, int xControl,
|
||||
int yControl, int controllerIndex)
|
||||
{
|
||||
mJoystickLegacyId = legacyId;
|
||||
mJoystickXControl = xControl;
|
||||
mJoystickYControl = yControl;
|
||||
|
||||
mOuterBitmap = new BitmapDrawable(res, bitmapOuter);
|
||||
mDefaultStateInnerBitmap = new BitmapDrawable(res, bitmapInnerDefault);
|
||||
mPressedStateInnerBitmap = new BitmapDrawable(res, bitmapInnerPressed);
|
||||
mBoundsBoxBitmap = new BitmapDrawable(res, bitmapOuter);
|
||||
mWidth = bitmapOuter.getWidth();
|
||||
mHeight = bitmapOuter.getHeight();
|
||||
|
||||
if (controllerIndex < 0 || controllerIndex >= 4)
|
||||
throw new IllegalArgumentException("controllerIndex must be 0-3");
|
||||
mControllerIndex = controllerIndex;
|
||||
|
||||
setBounds(rectOuter);
|
||||
mDefaultStateInnerBitmap.setBounds(rectInner);
|
||||
mPressedStateInnerBitmap.setBounds(rectInner);
|
||||
mVirtBounds = getBounds();
|
||||
mOrigBounds = mOuterBitmap.copyBounds();
|
||||
mBoundsBoxBitmap.setAlpha(0);
|
||||
mBoundsBoxBitmap.setBounds(getVirtBounds());
|
||||
SetInnerBounds();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets this InputOverlayDrawableJoystick's legacy ID.
|
||||
*
|
||||
* @return this InputOverlayDrawableJoystick's legacy ID.
|
||||
*/
|
||||
public int getLegacyId()
|
||||
{
|
||||
return mJoystickLegacyId;
|
||||
}
|
||||
|
||||
public void draw(Canvas canvas)
|
||||
{
|
||||
mOuterBitmap.draw(canvas);
|
||||
getCurrentStateBitmapDrawable().draw(canvas);
|
||||
mBoundsBoxBitmap.draw(canvas);
|
||||
}
|
||||
|
||||
public boolean TrackEvent(MotionEvent event)
|
||||
{
|
||||
boolean reCenter = BooleanSetting.MAIN_JOYSTICK_REL_CENTER.getBoolean();
|
||||
int action = event.getActionMasked();
|
||||
boolean firstPointer = action != MotionEvent.ACTION_POINTER_DOWN &&
|
||||
action != MotionEvent.ACTION_POINTER_UP;
|
||||
int pointerIndex = firstPointer ? 0 : event.getActionIndex();
|
||||
boolean pressed = false;
|
||||
|
||||
switch (action)
|
||||
{
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
case MotionEvent.ACTION_POINTER_DOWN:
|
||||
if (getBounds().contains((int) event.getX(pointerIndex), (int) event.getY(pointerIndex)))
|
||||
{
|
||||
mPressedState = pressed = true;
|
||||
mOuterBitmap.setAlpha(0);
|
||||
mBoundsBoxBitmap.setAlpha(mOpacity);
|
||||
if (reCenter)
|
||||
{
|
||||
getVirtBounds().offset((int) event.getX(pointerIndex) - getVirtBounds().centerX(),
|
||||
(int) event.getY(pointerIndex) - getVirtBounds().centerY());
|
||||
}
|
||||
mBoundsBoxBitmap.setBounds(getVirtBounds());
|
||||
trackId = event.getPointerId(pointerIndex);
|
||||
}
|
||||
break;
|
||||
case MotionEvent.ACTION_UP:
|
||||
case MotionEvent.ACTION_POINTER_UP:
|
||||
if (trackId == event.getPointerId(pointerIndex))
|
||||
{
|
||||
pressed = true;
|
||||
mPressedState = false;
|
||||
mCurrentX = mCurrentY = 0.0f;
|
||||
mOuterBitmap.setAlpha(mOpacity);
|
||||
mBoundsBoxBitmap.setAlpha(0);
|
||||
setVirtBounds(new Rect(mOrigBounds.left, mOrigBounds.top, mOrigBounds.right,
|
||||
mOrigBounds.bottom));
|
||||
setBounds(new Rect(mOrigBounds.left, mOrigBounds.top, mOrigBounds.right,
|
||||
mOrigBounds.bottom));
|
||||
SetInnerBounds();
|
||||
trackId = -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (trackId == -1)
|
||||
return pressed;
|
||||
|
||||
for (int i = 0; i < event.getPointerCount(); i++)
|
||||
{
|
||||
if (trackId == event.getPointerId(i))
|
||||
{
|
||||
float touchX = event.getX(i);
|
||||
float touchY = event.getY(i);
|
||||
float maxY = getVirtBounds().bottom;
|
||||
float maxX = getVirtBounds().right;
|
||||
touchX -= getVirtBounds().centerX();
|
||||
maxX -= getVirtBounds().centerX();
|
||||
touchY -= getVirtBounds().centerY();
|
||||
maxY -= getVirtBounds().centerY();
|
||||
mCurrentX = touchX / maxX;
|
||||
mCurrentY = touchY / maxY;
|
||||
|
||||
SetInnerBounds();
|
||||
}
|
||||
}
|
||||
return pressed;
|
||||
}
|
||||
|
||||
public void onConfigureTouch(MotionEvent event)
|
||||
{
|
||||
switch (event.getAction())
|
||||
{
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
mPreviousTouchX = (int) event.getX();
|
||||
mPreviousTouchY = (int) event.getY();
|
||||
break;
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
int deltaX = (int) event.getX() - mPreviousTouchX;
|
||||
int deltaY = (int) event.getY() - mPreviousTouchY;
|
||||
mControlPositionX += deltaX;
|
||||
mControlPositionY += deltaY;
|
||||
setBounds(new Rect(mControlPositionX, mControlPositionY,
|
||||
mOuterBitmap.getIntrinsicWidth() + mControlPositionX,
|
||||
mOuterBitmap.getIntrinsicHeight() + mControlPositionY));
|
||||
setVirtBounds(new Rect(mControlPositionX, mControlPositionY,
|
||||
mOuterBitmap.getIntrinsicWidth() + mControlPositionX,
|
||||
mOuterBitmap.getIntrinsicHeight() + mControlPositionY));
|
||||
SetInnerBounds();
|
||||
setOrigBounds(new Rect(new Rect(mControlPositionX, mControlPositionY,
|
||||
mOuterBitmap.getIntrinsicWidth() + mControlPositionX,
|
||||
mOuterBitmap.getIntrinsicHeight() + mControlPositionY)));
|
||||
mPreviousTouchX = (int) event.getX();
|
||||
mPreviousTouchY = (int) event.getY();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public float getX()
|
||||
{
|
||||
return mCurrentX;
|
||||
}
|
||||
|
||||
public float getY()
|
||||
{
|
||||
return mCurrentY;
|
||||
}
|
||||
|
||||
public int getXControl()
|
||||
{
|
||||
return mJoystickXControl;
|
||||
}
|
||||
|
||||
public int getYControl()
|
||||
{
|
||||
return mJoystickYControl;
|
||||
}
|
||||
|
||||
private void SetInnerBounds()
|
||||
{
|
||||
double x = mCurrentX;
|
||||
double y = mCurrentY;
|
||||
|
||||
double angle = Math.atan2(y, x) + Math.PI + Math.PI;
|
||||
double radius = Math.hypot(y, x);
|
||||
double maxRadius = InputOverrider.getGateRadiusAtAngle(mControllerIndex, mJoystickXControl,
|
||||
angle);
|
||||
if (radius > maxRadius)
|
||||
{
|
||||
y = maxRadius * Math.sin(angle);
|
||||
x = maxRadius * Math.cos(angle);
|
||||
mCurrentY = (float) y;
|
||||
mCurrentX = (float) x;
|
||||
}
|
||||
|
||||
int pixelX = getVirtBounds().centerX() + (int) (x * (getVirtBounds().width() / 2));
|
||||
int pixelY = getVirtBounds().centerY() + (int) (y * (getVirtBounds().height() / 2));
|
||||
|
||||
int width = mPressedStateInnerBitmap.getBounds().width() / 2;
|
||||
int height = mPressedStateInnerBitmap.getBounds().height() / 2;
|
||||
mDefaultStateInnerBitmap.setBounds(pixelX - width, pixelY - height, pixelX + width,
|
||||
pixelY + height);
|
||||
mPressedStateInnerBitmap.setBounds(mDefaultStateInnerBitmap.getBounds());
|
||||
}
|
||||
|
||||
public void setPosition(int x, int y)
|
||||
{
|
||||
mControlPositionX = x;
|
||||
mControlPositionY = y;
|
||||
}
|
||||
|
||||
private BitmapDrawable getCurrentStateBitmapDrawable()
|
||||
{
|
||||
return mPressedState ? mPressedStateInnerBitmap : mDefaultStateInnerBitmap;
|
||||
}
|
||||
|
||||
public void setBounds(Rect bounds)
|
||||
{
|
||||
mOuterBitmap.setBounds(bounds);
|
||||
}
|
||||
|
||||
public void setOpacity(int value)
|
||||
{
|
||||
mOpacity = value;
|
||||
|
||||
mDefaultStateInnerBitmap.setAlpha(value);
|
||||
mPressedStateInnerBitmap.setAlpha(value);
|
||||
|
||||
if (trackId == -1)
|
||||
{
|
||||
mOuterBitmap.setAlpha(value);
|
||||
mBoundsBoxBitmap.setAlpha(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
mOuterBitmap.setAlpha(0);
|
||||
mBoundsBoxBitmap.setAlpha(value);
|
||||
}
|
||||
}
|
||||
|
||||
public Rect getBounds()
|
||||
{
|
||||
return mOuterBitmap.getBounds();
|
||||
}
|
||||
|
||||
private void setVirtBounds(Rect bounds)
|
||||
{
|
||||
mVirtBounds = bounds;
|
||||
}
|
||||
|
||||
private void setOrigBounds(Rect bounds)
|
||||
{
|
||||
mOrigBounds = bounds;
|
||||
}
|
||||
|
||||
private Rect getVirtBounds()
|
||||
{
|
||||
return mVirtBounds;
|
||||
}
|
||||
|
||||
public int getWidth()
|
||||
{
|
||||
return mWidth;
|
||||
}
|
||||
|
||||
public int getHeight()
|
||||
{
|
||||
return mHeight;
|
||||
}
|
||||
|
||||
public int getTrackId()
|
||||
{
|
||||
return trackId;
|
||||
}
|
||||
}
|
@ -0,0 +1,258 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
package org.dolphinemu.dolphinemu.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.dolphinemu.dolphinemu.features.input.model.InputOverrider
|
||||
import org.dolphinemu.dolphinemu.features.settings.model.BooleanSetting
|
||||
import kotlin.math.atan2
|
||||
import kotlin.math.cos
|
||||
import kotlin.math.hypot
|
||||
import kotlin.math.sin
|
||||
|
||||
/**
|
||||
* Custom [BitmapDrawable] that is capable
|
||||
* of storing it's own ID.
|
||||
*
|
||||
* @param res [Resources] instance.
|
||||
* @param bitmapOuter [Bitmap] which represents the outer non-movable part of the joystick.
|
||||
* @param bitmapInnerDefault [Bitmap] which represents the default inner movable part of the joystick.
|
||||
* @param bitmapInnerPressed [Bitmap] which represents the pressed inner movable part of the joystick.
|
||||
* @param rectOuter [Rect] which represents the outer joystick bounds.
|
||||
* @param rectInner [Rect] which represents the inner joystick bounds.
|
||||
* @param legacyId Legacy identifier (ButtonType) for which joystick this is.
|
||||
* @param xControl The control which the x value of the joystick will be written to.
|
||||
* @param yControl The control which the y value of the joystick will be written to.
|
||||
*/
|
||||
class InputOverlayDrawableJoystick(
|
||||
res: Resources,
|
||||
bitmapOuter: Bitmap,
|
||||
bitmapInnerDefault: Bitmap,
|
||||
bitmapInnerPressed: Bitmap,
|
||||
rectOuter: Rect,
|
||||
rectInner: Rect,
|
||||
val legacyId: Int,
|
||||
val xControl: Int,
|
||||
val yControl: Int,
|
||||
private val controllerIndex: Int
|
||||
) {
|
||||
var x = 0.0f
|
||||
private set
|
||||
var y = 0.0f
|
||||
private set
|
||||
var trackId = -1
|
||||
private set
|
||||
private var controlPositionX = 0
|
||||
private var controlPositionY = 0
|
||||
private var previousTouchX = 0
|
||||
private var previousTouchY = 0
|
||||
val width: Int
|
||||
val height: Int
|
||||
private var virtBounds: Rect
|
||||
private var origBounds: Rect
|
||||
private var opacity = 0
|
||||
private val outerBitmap: BitmapDrawable
|
||||
private val defaultStateInnerBitmap: BitmapDrawable
|
||||
private val pressedStateInnerBitmap: BitmapDrawable
|
||||
private val boundsBoxBitmap: BitmapDrawable
|
||||
private var pressedState = false
|
||||
|
||||
var bounds: Rect
|
||||
get() = outerBitmap.bounds
|
||||
set(bounds) {
|
||||
outerBitmap.bounds = bounds
|
||||
}
|
||||
|
||||
init {
|
||||
outerBitmap = BitmapDrawable(res, bitmapOuter)
|
||||
defaultStateInnerBitmap = BitmapDrawable(res, bitmapInnerDefault)
|
||||
pressedStateInnerBitmap = BitmapDrawable(res, bitmapInnerPressed)
|
||||
boundsBoxBitmap = BitmapDrawable(res, bitmapOuter)
|
||||
width = bitmapOuter.width
|
||||
height = bitmapOuter.height
|
||||
|
||||
require(!(controllerIndex < 0 || controllerIndex >= 4)) { "controllerIndex must be 0-3" }
|
||||
|
||||
bounds = rectOuter
|
||||
defaultStateInnerBitmap.bounds = rectInner
|
||||
pressedStateInnerBitmap.bounds = rectInner
|
||||
virtBounds = bounds
|
||||
origBounds = outerBitmap.copyBounds()
|
||||
boundsBoxBitmap.alpha = 0
|
||||
boundsBoxBitmap.bounds = virtBounds
|
||||
setInnerBounds()
|
||||
}
|
||||
|
||||
fun draw(canvas: Canvas) {
|
||||
outerBitmap.draw(canvas)
|
||||
currentStateBitmapDrawable.draw(canvas)
|
||||
boundsBoxBitmap.draw(canvas)
|
||||
}
|
||||
|
||||
fun trackEvent(event: MotionEvent): Boolean {
|
||||
val reCenter = BooleanSetting.MAIN_JOYSTICK_REL_CENTER.boolean
|
||||
val action = event.actionMasked
|
||||
val firstPointer = action != MotionEvent.ACTION_POINTER_DOWN &&
|
||||
action != MotionEvent.ACTION_POINTER_UP
|
||||
val pointerIndex = if (firstPointer) 0 else event.actionIndex
|
||||
var pressed = false
|
||||
|
||||
when (action) {
|
||||
MotionEvent.ACTION_DOWN,
|
||||
MotionEvent.ACTION_POINTER_DOWN -> {
|
||||
if (bounds.contains(
|
||||
event.getX(pointerIndex).toInt(),
|
||||
event.getY(pointerIndex).toInt()
|
||||
)
|
||||
) {
|
||||
pressed = true
|
||||
pressedState = true
|
||||
outerBitmap.alpha = 0
|
||||
boundsBoxBitmap.alpha = opacity
|
||||
if (reCenter) {
|
||||
virtBounds.offset(
|
||||
event.getX(pointerIndex).toInt() - virtBounds.centerX(),
|
||||
event.getY(pointerIndex).toInt() - virtBounds.centerY()
|
||||
)
|
||||
}
|
||||
boundsBoxBitmap.bounds = virtBounds
|
||||
trackId = event.getPointerId(pointerIndex)
|
||||
}
|
||||
}
|
||||
|
||||
MotionEvent.ACTION_UP,
|
||||
MotionEvent.ACTION_POINTER_UP -> {
|
||||
if (trackId == event.getPointerId(pointerIndex)) {
|
||||
pressed = true
|
||||
pressedState = false
|
||||
y = 0f
|
||||
x = y
|
||||
outerBitmap.alpha = opacity
|
||||
boundsBoxBitmap.alpha = 0
|
||||
virtBounds =
|
||||
Rect(origBounds.left, origBounds.top, origBounds.right, origBounds.bottom)
|
||||
bounds =
|
||||
Rect(origBounds.left, origBounds.top, origBounds.right, origBounds.bottom)
|
||||
setInnerBounds()
|
||||
trackId = -1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (trackId == -1)
|
||||
return pressed
|
||||
|
||||
for (i in 0 until event.pointerCount) {
|
||||
if (trackId == event.getPointerId(i)) {
|
||||
var touchX = event.getX(i)
|
||||
var touchY = event.getY(i)
|
||||
var maxY = virtBounds.bottom.toFloat()
|
||||
var maxX = virtBounds.right.toFloat()
|
||||
touchX -= virtBounds.centerX().toFloat()
|
||||
maxX -= virtBounds.centerX().toFloat()
|
||||
touchY -= virtBounds.centerY().toFloat()
|
||||
maxY -= virtBounds.centerY().toFloat()
|
||||
x = touchX / maxX
|
||||
y = touchY / maxY
|
||||
|
||||
setInnerBounds()
|
||||
}
|
||||
}
|
||||
return pressed
|
||||
}
|
||||
|
||||
fun onConfigureTouch(event: MotionEvent) {
|
||||
when (event.action) {
|
||||
MotionEvent.ACTION_DOWN -> {
|
||||
previousTouchX = event.x.toInt()
|
||||
previousTouchY = event.y.toInt()
|
||||
}
|
||||
|
||||
MotionEvent.ACTION_MOVE -> {
|
||||
val deltaX = event.x.toInt() - previousTouchX
|
||||
val deltaY = event.y.toInt() - previousTouchY
|
||||
controlPositionX += deltaX
|
||||
controlPositionY += deltaY
|
||||
bounds = Rect(
|
||||
controlPositionX,
|
||||
controlPositionY,
|
||||
outerBitmap.intrinsicWidth + controlPositionX,
|
||||
outerBitmap.intrinsicHeight + controlPositionY
|
||||
)
|
||||
virtBounds = Rect(
|
||||
controlPositionX,
|
||||
controlPositionY,
|
||||
outerBitmap.intrinsicWidth + controlPositionX,
|
||||
outerBitmap.intrinsicHeight + controlPositionY
|
||||
)
|
||||
setInnerBounds()
|
||||
origBounds = Rect(
|
||||
Rect(
|
||||
controlPositionX,
|
||||
controlPositionY,
|
||||
outerBitmap.intrinsicWidth + controlPositionX,
|
||||
outerBitmap.intrinsicHeight + controlPositionY
|
||||
)
|
||||
)
|
||||
previousTouchX = event.x.toInt()
|
||||
previousTouchY = event.y.toInt()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun setInnerBounds() {
|
||||
var x = x.toDouble()
|
||||
var y = y.toDouble()
|
||||
|
||||
val angle = atan2(y, x) + Math.PI + Math.PI
|
||||
val radius = hypot(y, x)
|
||||
val maxRadius = InputOverrider.getGateRadiusAtAngle(controllerIndex, xControl, angle)
|
||||
if (radius > maxRadius) {
|
||||
x = maxRadius * cos(angle)
|
||||
y = maxRadius * sin(angle)
|
||||
this.x = x.toFloat()
|
||||
this.y = y.toFloat()
|
||||
}
|
||||
|
||||
val pixelX = virtBounds.centerX() + (x * (virtBounds.width() / 2)).toInt()
|
||||
val pixelY = virtBounds.centerY() + (y * (virtBounds.height() / 2)).toInt()
|
||||
|
||||
val width = pressedStateInnerBitmap.bounds.width() / 2
|
||||
val height = pressedStateInnerBitmap.bounds.height() / 2
|
||||
defaultStateInnerBitmap.setBounds(
|
||||
pixelX - width,
|
||||
pixelY - height,
|
||||
pixelX + width,
|
||||
pixelY + height
|
||||
)
|
||||
pressedStateInnerBitmap.bounds = defaultStateInnerBitmap.bounds
|
||||
}
|
||||
|
||||
fun setPosition(x: Int, y: Int) {
|
||||
controlPositionX = x
|
||||
controlPositionY = y
|
||||
}
|
||||
|
||||
private val currentStateBitmapDrawable: BitmapDrawable
|
||||
get() = if (pressedState) pressedStateInnerBitmap else defaultStateInnerBitmap
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
@ -1,180 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
package org.dolphinemu.dolphinemu.overlay;
|
||||
|
||||
import android.graphics.Rect;
|
||||
import android.os.Handler;
|
||||
import android.view.MotionEvent;
|
||||
|
||||
import org.dolphinemu.dolphinemu.NativeLibrary;
|
||||
import org.dolphinemu.dolphinemu.features.input.model.InputOverrider;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class InputOverlayPointer
|
||||
{
|
||||
public static final int MODE_DISABLED = 0;
|
||||
public static final int MODE_FOLLOW = 1;
|
||||
public static final int MODE_DRAG = 2;
|
||||
|
||||
private float mCurrentX = 0.0f;
|
||||
private float mCurrentY = 0.0f;
|
||||
private float mOldX = 0.0f;
|
||||
private float mOldY = 0.0f;
|
||||
|
||||
private float mGameCenterX;
|
||||
private float mGameCenterY;
|
||||
private float mGameWidthHalfInv;
|
||||
private float mGameHeightHalfInv;
|
||||
|
||||
private float mTouchStartX;
|
||||
private float mTouchStartY;
|
||||
|
||||
private int mMode;
|
||||
private boolean mRecenter;
|
||||
private int mControllerIndex;
|
||||
|
||||
private boolean doubleTap = false;
|
||||
private int mDoubleTapControl;
|
||||
private int trackId = -1;
|
||||
|
||||
public static ArrayList<Integer> DOUBLE_TAP_OPTIONS = new ArrayList<>();
|
||||
|
||||
static
|
||||
{
|
||||
DOUBLE_TAP_OPTIONS.add(NativeLibrary.ButtonType.WIIMOTE_BUTTON_A);
|
||||
DOUBLE_TAP_OPTIONS.add(NativeLibrary.ButtonType.WIIMOTE_BUTTON_B);
|
||||
DOUBLE_TAP_OPTIONS.add(NativeLibrary.ButtonType.WIIMOTE_BUTTON_2);
|
||||
DOUBLE_TAP_OPTIONS.add(NativeLibrary.ButtonType.CLASSIC_BUTTON_A);
|
||||
}
|
||||
|
||||
public InputOverlayPointer(Rect surfacePosition, int doubleTapControl, int mode, boolean recenter,
|
||||
int controllerIndex)
|
||||
{
|
||||
mDoubleTapControl = doubleTapControl;
|
||||
mMode = mode;
|
||||
mRecenter = recenter;
|
||||
mControllerIndex = controllerIndex;
|
||||
|
||||
mGameCenterX = (surfacePosition.left + surfacePosition.right) / 2.0f;
|
||||
mGameCenterY = (surfacePosition.top + surfacePosition.bottom) / 2.0f;
|
||||
|
||||
float gameWidth = surfacePosition.right - surfacePosition.left;
|
||||
float gameHeight = surfacePosition.bottom - surfacePosition.top;
|
||||
|
||||
// Adjusting for device's black bars.
|
||||
float surfaceAR = gameWidth / gameHeight;
|
||||
float gameAR = NativeLibrary.GetGameAspectRatio();
|
||||
|
||||
if (gameAR <= surfaceAR)
|
||||
{
|
||||
// Black bars on left/right
|
||||
gameWidth = gameHeight * gameAR;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Black bars on top/bottom
|
||||
gameHeight = gameWidth / gameAR;
|
||||
}
|
||||
|
||||
mGameWidthHalfInv = 1.0f / (gameWidth * 0.5f);
|
||||
mGameHeightHalfInv = 1.0f / (gameHeight * 0.5f);
|
||||
}
|
||||
|
||||
public void onTouch(MotionEvent event)
|
||||
{
|
||||
int action = event.getActionMasked();
|
||||
boolean firstPointer = action != MotionEvent.ACTION_POINTER_DOWN &&
|
||||
action != MotionEvent.ACTION_POINTER_UP;
|
||||
int pointerIndex = firstPointer ? 0 : event.getActionIndex();
|
||||
|
||||
switch (action)
|
||||
{
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
case MotionEvent.ACTION_POINTER_DOWN:
|
||||
trackId = event.getPointerId(pointerIndex);
|
||||
mTouchStartX = event.getX(pointerIndex);
|
||||
mTouchStartY = event.getY(pointerIndex);
|
||||
touchPress();
|
||||
break;
|
||||
case MotionEvent.ACTION_UP:
|
||||
case MotionEvent.ACTION_POINTER_UP:
|
||||
if (trackId == event.getPointerId(pointerIndex))
|
||||
trackId = -1;
|
||||
if (mMode == MODE_DRAG)
|
||||
updateOldAxes();
|
||||
if (mRecenter)
|
||||
reset();
|
||||
break;
|
||||
}
|
||||
|
||||
int eventPointerIndex = event.findPointerIndex(trackId);
|
||||
if (trackId == -1 || eventPointerIndex == -1)
|
||||
return;
|
||||
|
||||
if (mMode == MODE_FOLLOW)
|
||||
{
|
||||
mCurrentX = (event.getX(eventPointerIndex) - mGameCenterX) * mGameWidthHalfInv;
|
||||
mCurrentY = (event.getY(eventPointerIndex) - mGameCenterY) * mGameHeightHalfInv;
|
||||
}
|
||||
else if (mMode == MODE_DRAG)
|
||||
{
|
||||
mCurrentX = mOldX +
|
||||
(event.getX(eventPointerIndex) - mTouchStartX) * mGameWidthHalfInv;
|
||||
mCurrentY = mOldY +
|
||||
(event.getY(eventPointerIndex) - mTouchStartY) * mGameHeightHalfInv;
|
||||
}
|
||||
}
|
||||
|
||||
private void touchPress()
|
||||
{
|
||||
if (mMode != MODE_DISABLED)
|
||||
{
|
||||
if (doubleTap)
|
||||
{
|
||||
InputOverrider.setControlState(mControllerIndex, mDoubleTapControl, 1.0);
|
||||
new Handler().postDelayed(() -> InputOverrider.setControlState(mControllerIndex,
|
||||
mDoubleTapControl, 0.0),
|
||||
50);
|
||||
}
|
||||
else
|
||||
{
|
||||
doubleTap = true;
|
||||
new Handler().postDelayed(() -> doubleTap = false, 300);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void updateOldAxes()
|
||||
{
|
||||
mOldX = mCurrentX;
|
||||
mOldY = mCurrentY;
|
||||
}
|
||||
|
||||
private void reset()
|
||||
{
|
||||
mCurrentX = mCurrentY = mOldX = mOldY = 0.0f;
|
||||
}
|
||||
|
||||
public float getX()
|
||||
{
|
||||
return mCurrentX;
|
||||
}
|
||||
|
||||
public float getY()
|
||||
{
|
||||
return mCurrentY;
|
||||
}
|
||||
|
||||
public void setMode(int mode)
|
||||
{
|
||||
mMode = mode;
|
||||
if (mode == MODE_DRAG)
|
||||
updateOldAxes();
|
||||
}
|
||||
|
||||
public void setRecenter(boolean recenter)
|
||||
{
|
||||
mRecenter = recenter;
|
||||
}
|
||||
}
|
@ -0,0 +1,148 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
package org.dolphinemu.dolphinemu.overlay
|
||||
|
||||
import android.graphics.Rect
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.view.MotionEvent
|
||||
import org.dolphinemu.dolphinemu.NativeLibrary
|
||||
import org.dolphinemu.dolphinemu.features.input.model.InputOverrider
|
||||
|
||||
class InputOverlayPointer(
|
||||
surfacePosition: Rect,
|
||||
private val doubleTapControl: Int,
|
||||
private var mode: Int,
|
||||
private var recenter: Boolean,
|
||||
private val controllerIndex: Int
|
||||
) {
|
||||
var x = 0.0f
|
||||
var y = 0.0f
|
||||
private var oldX = 0.0f
|
||||
private var oldY = 0.0f
|
||||
|
||||
private val gameCenterX: Float
|
||||
private val gameCenterY: Float
|
||||
private val gameWidthHalfInv: Float
|
||||
private val gameHeightHalfInv: Float
|
||||
|
||||
private var touchStartX = 0f
|
||||
private var touchStartY = 0f
|
||||
|
||||
private var doubleTap = false
|
||||
private var trackId = -1
|
||||
|
||||
init {
|
||||
gameCenterX = (surfacePosition.left + surfacePosition.right) / 2f
|
||||
gameCenterY = (surfacePosition.top + surfacePosition.bottom) / 2f
|
||||
|
||||
var gameWidth = (surfacePosition.right - surfacePosition.left).toFloat()
|
||||
var gameHeight = (surfacePosition.bottom - surfacePosition.top).toFloat()
|
||||
|
||||
// Adjusting for device's black bars.
|
||||
val surfaceAR = gameWidth / gameHeight
|
||||
val gameAR = NativeLibrary.GetGameAspectRatio()
|
||||
if (gameAR <= surfaceAR) {
|
||||
// Black bars on left/right
|
||||
gameWidth = gameHeight * gameAR
|
||||
} else {
|
||||
// Black bars on top/bottom
|
||||
gameHeight = gameWidth / gameAR
|
||||
}
|
||||
|
||||
gameWidthHalfInv = 1f / (gameWidth * 0.5f)
|
||||
gameHeightHalfInv = 1f / (gameHeight * 0.5f)
|
||||
}
|
||||
|
||||
fun onTouch(event: MotionEvent) {
|
||||
val action = event.actionMasked
|
||||
val firstPointer = action != MotionEvent.ACTION_POINTER_DOWN &&
|
||||
action != MotionEvent.ACTION_POINTER_UP
|
||||
val pointerIndex = if (firstPointer) 0 else event.actionIndex
|
||||
|
||||
when (action) {
|
||||
MotionEvent.ACTION_DOWN,
|
||||
MotionEvent.ACTION_POINTER_DOWN -> {
|
||||
trackId = event.getPointerId(pointerIndex)
|
||||
touchStartX = event.getX(pointerIndex)
|
||||
touchStartY = event.getY(pointerIndex)
|
||||
touchPress()
|
||||
}
|
||||
|
||||
MotionEvent.ACTION_UP,
|
||||
MotionEvent.ACTION_POINTER_UP -> {
|
||||
if (trackId == event.getPointerId(pointerIndex))
|
||||
trackId = -1
|
||||
if (mode == MODE_DRAG)
|
||||
updateOldAxes()
|
||||
if (recenter)
|
||||
reset()
|
||||
}
|
||||
}
|
||||
|
||||
val eventPointerIndex = event.findPointerIndex(trackId)
|
||||
if (trackId == -1 || eventPointerIndex == -1)
|
||||
return
|
||||
|
||||
if (mode == MODE_FOLLOW) {
|
||||
x = (event.getX(eventPointerIndex) - gameCenterX) * gameWidthHalfInv
|
||||
y = (event.getY(eventPointerIndex) - gameCenterY) * gameHeightHalfInv
|
||||
} else if (mode == MODE_DRAG) {
|
||||
x = oldX + (event.getX(eventPointerIndex) - touchStartX) * gameWidthHalfInv
|
||||
y = oldY + (event.getY(eventPointerIndex) - touchStartY) * gameHeightHalfInv
|
||||
}
|
||||
}
|
||||
|
||||
private fun touchPress() {
|
||||
if (mode != MODE_DISABLED) {
|
||||
if (doubleTap) {
|
||||
InputOverrider.setControlState(controllerIndex, doubleTapControl, 1.0)
|
||||
Handler(Looper.myLooper()!!).postDelayed(
|
||||
{
|
||||
InputOverrider.setControlState(controllerIndex, doubleTapControl, 0.0)
|
||||
},
|
||||
50
|
||||
)
|
||||
} else {
|
||||
doubleTap = true
|
||||
Handler(Looper.myLooper()!!).postDelayed({ doubleTap = false }, 300)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateOldAxes() {
|
||||
oldX = x
|
||||
oldY = y
|
||||
}
|
||||
|
||||
private fun reset() {
|
||||
oldY = 0.0f
|
||||
oldX = 0.0f
|
||||
y = 0.0f
|
||||
x = 0.0f
|
||||
}
|
||||
|
||||
fun setMode(mode: Int) {
|
||||
this.mode = mode
|
||||
if (mode == MODE_DRAG)
|
||||
updateOldAxes()
|
||||
}
|
||||
|
||||
fun setRecenter(recenter: Boolean) {
|
||||
this.recenter = recenter
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val MODE_DISABLED = 0
|
||||
const val MODE_FOLLOW = 1
|
||||
const val MODE_DRAG = 2
|
||||
|
||||
@JvmField
|
||||
var DOUBLE_TAP_OPTIONS = arrayListOf(
|
||||
NativeLibrary.ButtonType.WIIMOTE_BUTTON_A,
|
||||
NativeLibrary.ButtonType.WIIMOTE_BUTTON_B,
|
||||
NativeLibrary.ButtonType.WIIMOTE_BUTTON_2,
|
||||
NativeLibrary.ButtonType.CLASSIC_BUTTON_A
|
||||
)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user