Android: Merge dpad into one button

This commit is contained in:
Connor McLaughlin 2021-04-03 13:42:04 +10:00
parent acff275f6b
commit 17707525dc
4 changed files with 250 additions and 99 deletions

View file

@ -0,0 +1,166 @@
package com.github.stenzek.duckstation;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.View;
public final class TouchscreenControllerDPadView extends View {
private static final int NUM_DIRECTIONS = 4;
private static final int NUM_POSITIONS = 8;
private static final int DIRECTION_UP = 0;
private static final int DIRECTION_RIGHT = 1;
private static final int DIRECTION_DOWN = 2;
private static final int DIRECTION_LEFT = 3;
private final Drawable[] mUnpressedDrawables = new Drawable[NUM_DIRECTIONS];
private final Drawable[] mPressedDrawables = new Drawable[NUM_DIRECTIONS];
private final int[] mDirectionCodes = new int[] { -1, -1, -1, -1 };
private final boolean[] mDirectionStates = new boolean[NUM_DIRECTIONS];
private boolean mPressed = false;
private int mPointerId = 0;
private int mPointerX = 0;
private int mPointerY = 0;
private String mConfigName;
private boolean mDefaultVisibility = true;
private int mControllerIndex = -1;
private static final int[][] DRAWABLES = {
{R.drawable.ic_controller_up_button,R.drawable.ic_controller_up_button_pressed},
{R.drawable.ic_controller_right_button,R.drawable.ic_controller_right_button_pressed},
{R.drawable.ic_controller_down_button,R.drawable.ic_controller_down_button_pressed},
{R.drawable.ic_controller_left_button,R.drawable.ic_controller_left_button_pressed},
};
public TouchscreenControllerDPadView(Context context) {
super(context);
init();
}
public TouchscreenControllerDPadView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public TouchscreenControllerDPadView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
private void init() {
for (int i = 0; i < NUM_DIRECTIONS; i++) {
mUnpressedDrawables[i] = getContext().getDrawable(DRAWABLES[i][0]);
mPressedDrawables[i] = getContext().getDrawable(DRAWABLES[i][1]);
}
}
public String getConfigName() {
return mConfigName;
}
public void setConfigName(String configName) {
mConfigName = configName;
}
public boolean getDefaultVisibility() { return mDefaultVisibility; }
public void setDefaultVisibility(boolean visibility) { mDefaultVisibility = visibility; }
public void setControllerButtons(int controllerIndex, int leftCode, int rightCode, int upCode, int downCode) {
mControllerIndex = controllerIndex;
mDirectionCodes[DIRECTION_LEFT] = leftCode;
mDirectionCodes[DIRECTION_RIGHT] = rightCode;
mDirectionCodes[DIRECTION_UP] = upCode;
mDirectionCodes[DIRECTION_DOWN] = downCode;
}
public void setUnpressed() {
if (!mPressed && mPointerX == 0 && mPointerY == 0)
return;
mPressed = false;
mPointerX = 0;
mPointerY = 0;
updateControllerState();
invalidate();
}
public void setPressed(int pointerId, float pointerX, float pointerY) {
final int posX = (int)(pointerX - getX());
final int posY = (int)(pointerY - getY());
boolean doUpdate = (pointerId != mPointerId || !mPressed || (posX != mPointerX || posY != mPointerY));
mPointerId = pointerId;
mPointerX = posX;
mPointerY = posY;
mPressed = true;
if (doUpdate) {
updateControllerState();
invalidate();
}
}
private void updateControllerState() {
final int subX = mPointerX / (getWidth() / 3);
final int subY = mPointerY / (getWidth() / 3);
mDirectionStates[DIRECTION_UP] = (mPressed && subY == 0);
mDirectionStates[DIRECTION_RIGHT] = (mPressed && subX == 2);
mDirectionStates[DIRECTION_DOWN] = (mPressed && subY == 2);
mDirectionStates[DIRECTION_LEFT] = (mPressed && subX == 0);
AndroidHostInterface hostInterface = AndroidHostInterface.getInstance();
for (int i = 0; i < NUM_DIRECTIONS; i++) {
if (mDirectionCodes[i] >= 0)
hostInterface.setControllerButtonState(mControllerIndex, mDirectionCodes[i], mDirectionStates[i]);
}
}
private void drawDirection(int direction, int subX, int subY, Canvas canvas, int buttonWidth, int buttonHeight) {
final int leftBounds = subX * buttonWidth;
final int rightBounds = leftBounds + buttonWidth;
final int topBounds = subY * buttonHeight;
final int bottomBounds = topBounds + buttonHeight;
final Drawable drawable = mDirectionStates[direction] ? mPressedDrawables[direction] : mUnpressedDrawables[direction];
drawable.setBounds(leftBounds, topBounds, rightBounds, bottomBounds);
drawable.draw(canvas);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
final int width = getWidth();
final int height = getHeight();
// Divide it into thirds - draw between.
final int buttonWidth = width / 3;
final int buttonHeight = height / 3;
drawDirection(DIRECTION_UP, 1, 0, canvas, buttonWidth, buttonHeight);
drawDirection(DIRECTION_RIGHT, 2, 1, canvas, buttonWidth, buttonHeight);
drawDirection(DIRECTION_DOWN, 1, 2, canvas, buttonWidth, buttonHeight);
drawDirection(DIRECTION_LEFT, 0, 1, canvas, buttonWidth, buttonHeight);
}
public boolean isPressed() {
return mPressed;
}
public boolean hasPointerId() {
return mPointerId >= 0;
}
public int getPointerId() {
return mPointerId;
}
public void setPointerId(int mPointerId) {
this.mPointerId = mPointerId;
}
}

View file

@ -35,6 +35,7 @@ public class TouchscreenControllerView extends FrameLayout {
private View mMainView; private View mMainView;
private ArrayList<TouchscreenControllerButtonView> mButtonViews = new ArrayList<>(); private ArrayList<TouchscreenControllerButtonView> mButtonViews = new ArrayList<>();
private ArrayList<TouchscreenControllerAxisView> mAxisViews = new ArrayList<>(); private ArrayList<TouchscreenControllerAxisView> mAxisViews = new ArrayList<>();
private TouchscreenControllerDPadView mDPadView = null;
private boolean mHapticFeedback; private boolean mHapticFeedback;
private String mLayoutOrientation; private String mLayoutOrientation;
private boolean mEditingLayout = false; private boolean mEditingLayout = false;
@ -105,6 +106,13 @@ public class TouchscreenControllerView extends FrameLayout {
axisView.setTranslationY(0.0f); axisView.setTranslationY(0.0f);
} }
if (mDPadView != null) {
editor.remove(getConfigKeyForXTranslation(mDPadView.getConfigName()));
editor.remove(getConfigKeyForYTranslation(mDPadView.getConfigName()));
mDPadView.setTranslationX(0.0f);
mDPadView.setTranslationY(0.0f);
}
editor.commit(); editor.commit();
requestLayout(); requestLayout();
} }
@ -137,6 +145,18 @@ public class TouchscreenControllerView extends FrameLayout {
} }
} }
if (mDPadView != null) {
try {
mDPadView.setTranslationX(prefs.getFloat(getConfigKeyForXTranslation(mDPadView.getConfigName()), 0.0f));
mDPadView.setTranslationY(prefs.getFloat(getConfigKeyForYTranslation(mDPadView.getConfigName()), 0.0f));
final boolean visible = prefs.getBoolean(getConfigKeyForVisibility(mDPadView.getConfigName()), mDPadView.getDefaultVisibility());
mDPadView.setVisibility(visible ? VISIBLE : INVISIBLE);
} catch (ClassCastException ex) {
}
}
} }
private void setOpacity(int opacity) { private void setOpacity(int opacity) {
@ -160,6 +180,8 @@ public class TouchscreenControllerView extends FrameLayout {
for (TouchscreenControllerAxisView axisView : mAxisViews) { for (TouchscreenControllerAxisView axisView : mAxisViews) {
axisView.setAlpha(alpha); axisView.setAlpha(alpha);
} }
if (mDPadView != null)
mDPadView.setAlpha(alpha);
} }
private String getOrientationString() { private String getOrientationString() {
@ -232,10 +254,7 @@ public class TouchscreenControllerView extends FrameLayout {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getContext()); SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getContext());
linkButton(mMainView, R.id.controller_button_up, "UpButton", "Up", true, false); linkDPadToButtons(mMainView, R.id.controller_dpad, "DPad", "", true);
linkButton(mMainView, R.id.controller_button_right, "RightButton", "Right", true, false);
linkButton(mMainView, R.id.controller_button_down, "DownButton", "Down", true, false);
linkButton(mMainView, R.id.controller_button_left, "LeftButton", "Left", true, false);
linkButton(mMainView, R.id.controller_button_l1, "L1Button", "L1", true, gliding); linkButton(mMainView, R.id.controller_button_l1, "L1Button", "L1", true, gliding);
linkButton(mMainView, R.id.controller_button_l2, "L2Button", "L2", true, gliding); linkButton(mMainView, R.id.controller_button_l2, "L2Button", "L2", true, gliding);
linkButton(mMainView, R.id.controller_button_select, "SelectButton", "Select", true, gliding); linkButton(mMainView, R.id.controller_button_select, "SelectButton", "Select", true, gliding);
@ -320,6 +339,27 @@ public class TouchscreenControllerView extends FrameLayout {
return true; return true;
} }
private boolean linkDPadToButtons(View view, int id, String configName, String buttonPrefix, boolean defaultVisibility) {
TouchscreenControllerDPadView dpadView = (TouchscreenControllerDPadView) view.findViewById(id);
if (dpadView == null)
return false;
dpadView.setConfigName(configName);
dpadView.setDefaultVisibility(defaultVisibility);
mDPadView = dpadView;
int leftCode = AndroidHostInterface.getControllerButtonCode(mControllerType, buttonPrefix + "Left");
int rightCode = AndroidHostInterface.getControllerButtonCode(mControllerType, buttonPrefix + "Right");
int upCode = AndroidHostInterface.getControllerButtonCode(mControllerType, buttonPrefix + "Up");
int downCode = AndroidHostInterface.getControllerButtonCode(mControllerType, buttonPrefix + "Down");
Log.i("TouchscreenController", String.format("%s(DPad) -> %d,%d,%d,%d", buttonPrefix, leftCode, rightCode, upCode, downCode));
if (leftCode < 0 && rightCode < 0 && upCode < 0 && downCode < 0)
return false;
dpadView.setControllerButtons(mControllerIndex, leftCode, rightCode, upCode, downCode);
return true;
}
private void linkHotkeyButton(View view, int id, String configName, TouchscreenControllerButtonView.Hotkey hotkey, boolean defaultVisibility) { private void linkHotkeyButton(View view, int id, String configName, TouchscreenControllerButtonView.Hotkey hotkey, boolean defaultVisibility) {
TouchscreenControllerButtonView buttonView = (TouchscreenControllerButtonView) view.findViewById(id); TouchscreenControllerButtonView buttonView = (TouchscreenControllerButtonView) view.findViewById(id);
if (buttonView == null) if (buttonView == null)
@ -410,6 +450,17 @@ public class TouchscreenControllerView extends FrameLayout {
} }
} }
if (mDPadView != null) {
mDPadView.getHitRect(rect);
if (rect.contains((int) x, (int) y)) {
mMovingView = mDPadView;
mMovingName = mDPadView.getConfigName();
mMovingLastX = x;
mMovingLastY = y;
return true;
}
}
// nothing.. // nothing..
return true; return true;
} }
@ -502,6 +553,23 @@ public class TouchscreenControllerView extends FrameLayout {
axisView.setUnpressed(); axisView.setUnpressed();
} }
if (mDPadView != null && mDPadView.getVisibility() == VISIBLE) {
mDPadView.getHitRect(rect);
boolean pressed = false;
for (int i = 0; i < pointerCount; i++) {
final int x = (int) event.getX(i);
final int y = (int) event.getY(i);
if (rect.contains(x, y)) {
mDPadView.setPressed(event.getPointerId(i), x, y);
pressed = true;
}
}
if (!pressed)
mDPadView.setUnpressed();
}
return true; return true;
} }
@ -521,6 +589,9 @@ public class TouchscreenControllerView extends FrameLayout {
axisView.setUnpressed(); axisView.setUnpressed();
} }
if (mDPadView != null)
mDPadView.setUnpressed();
return true; return true;
} }

View file

@ -147,57 +147,14 @@
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" /> app:layout_constraintEnd_toEndOf="parent" />
<com.github.stenzek.duckstation.TouchscreenControllerButtonView <com.github.stenzek.duckstation.TouchscreenControllerDPadView
android:id="@+id/controller_button_left" android:id="@+id/controller_dpad"
android:layout_width="50dp" android:layout_width="150dp"
android:layout_height="150dp" android:layout_height="150dp"
android:layout_marginStart="20dp" android:layout_marginStart="20dp"
android:layout_marginBottom="300dp" android:layout_marginBottom="300dp"
android:paddingTop="50dp"
android:paddingBottom="50dp"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent" />
app:pressedDrawable="@drawable/ic_controller_left_button_pressed"
app:unpressedDrawable="@drawable/ic_controller_left_button" />
<com.github.stenzek.duckstation.TouchscreenControllerButtonView
android:id="@+id/controller_button_down"
android:layout_width="150dp"
android:layout_height="50dp"
android:layout_marginStart="20dp"
android:layout_marginBottom="300dp"
android:paddingStart="50dp"
android:paddingEnd="50dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:pressedDrawable="@drawable/ic_controller_down_button_pressed"
app:unpressedDrawable="@drawable/ic_controller_down_button" />
<com.github.stenzek.duckstation.TouchscreenControllerButtonView
android:id="@+id/controller_button_right"
android:layout_width="50dp"
android:layout_height="150dp"
android:layout_marginStart="120dp"
android:layout_marginBottom="300dp"
android:paddingTop="50dp"
android:paddingBottom="50dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:pressedDrawable="@drawable/ic_controller_right_button_pressed"
app:unpressedDrawable="@drawable/ic_controller_right_button" />
<com.github.stenzek.duckstation.TouchscreenControllerButtonView
android:id="@+id/controller_button_up"
android:layout_width="150dp"
android:layout_height="50dp"
android:layout_marginStart="20dp"
android:layout_marginBottom="400dp"
android:paddingStart="50dp"
android:paddingEnd="50dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:pressedDrawable="@drawable/ic_controller_up_button_pressed"
app:unpressedDrawable="@drawable/ic_controller_up_button" />
<com.github.stenzek.duckstation.TouchscreenControllerButtonView <com.github.stenzek.duckstation.TouchscreenControllerButtonView
android:id="@+id/controller_button_fast_forward" android:id="@+id/controller_button_fast_forward"

View file

@ -29,31 +29,14 @@
app:pressedDrawable="@drawable/ic_controller_r1_button_pressed" app:pressedDrawable="@drawable/ic_controller_r1_button_pressed"
app:unpressedDrawable="@drawable/ic_controller_r1_button" /> app:unpressedDrawable="@drawable/ic_controller_r1_button" />
<com.github.stenzek.duckstation.TouchscreenControllerButtonView <com.github.stenzek.duckstation.TouchscreenControllerDPadView
android:id="@+id/controller_button_right" android:id="@+id/controller_dpad"
android:layout_width="50dp"
android:layout_height="150dp"
android:layout_marginStart="120dp"
android:layout_marginBottom="30dp"
android:paddingTop="50dp"
android:paddingBottom="50dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:pressedDrawable="@drawable/ic_controller_right_button_pressed"
app:unpressedDrawable="@drawable/ic_controller_right_button" />
<com.github.stenzek.duckstation.TouchscreenControllerButtonView
android:id="@+id/controller_button_up"
android:layout_width="150dp" android:layout_width="150dp"
android:layout_height="50dp" android:layout_height="150dp"
android:layout_marginStart="20dp" android:layout_marginStart="20dp"
android:layout_marginBottom="130dp" android:layout_marginBottom="30dp"
android:paddingStart="50dp"
android:paddingEnd="50dp"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent" />
app:pressedDrawable="@drawable/ic_controller_up_button_pressed"
app:unpressedDrawable="@drawable/ic_controller_up_button" />
<com.github.stenzek.duckstation.TouchscreenControllerButtonView <com.github.stenzek.duckstation.TouchscreenControllerButtonView
android:id="@+id/controller_button_l1" android:id="@+id/controller_button_l1"
@ -77,32 +60,6 @@
app:pressedDrawable="@drawable/ic_controller_l2_button_pressed" app:pressedDrawable="@drawable/ic_controller_l2_button_pressed"
app:unpressedDrawable="@drawable/ic_controller_l2_button" /> app:unpressedDrawable="@drawable/ic_controller_l2_button" />
<com.github.stenzek.duckstation.TouchscreenControllerButtonView
android:id="@+id/controller_button_left"
android:layout_width="50dp"
android:layout_height="150dp"
android:layout_marginStart="20dp"
android:layout_marginBottom="30dp"
android:paddingTop="50dp"
android:paddingBottom="50dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:pressedDrawable="@drawable/ic_controller_left_button_pressed"
app:unpressedDrawable="@drawable/ic_controller_left_button" />
<com.github.stenzek.duckstation.TouchscreenControllerButtonView
android:id="@+id/controller_button_down"
android:layout_width="150dp"
android:layout_height="50dp"
android:layout_marginStart="20dp"
android:layout_marginBottom="30dp"
android:paddingStart="50dp"
android:paddingEnd="50dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:pressedDrawable="@drawable/ic_controller_down_button_pressed"
app:unpressedDrawable="@drawable/ic_controller_down_button" />
<com.github.stenzek.duckstation.TouchscreenControllerButtonView <com.github.stenzek.duckstation.TouchscreenControllerButtonView
android:id="@+id/controller_button_start" android:id="@+id/controller_button_start"
android:layout_width="40dp" android:layout_width="40dp"