Merge pull request #4040 from Ironthighs/master
Android: Configurable Control Placement
This commit is contained in:
commit
0e7b10064d
|
@ -9,6 +9,10 @@ android {
|
|||
// This is important as it will run lint but not abort on error
|
||||
// Lint has some overly obnoxious "errors" that should really be warnings
|
||||
abortOnError false
|
||||
|
||||
//Uncomment disable lines for test builds...
|
||||
//disable 'MissingTranslation'
|
||||
//disable 'ExtraTranslation'
|
||||
}
|
||||
|
||||
defaultConfig {
|
||||
|
|
|
@ -394,6 +394,18 @@ public final class EmulationActivity extends AppCompatActivity
|
|||
return;
|
||||
}
|
||||
|
||||
case R.id.menu_emulation_configure_controls:
|
||||
EmulationFragment emulationFragment = (EmulationFragment) getFragmentManager().findFragmentById(R.id.frame_emulation_fragment);
|
||||
if (emulationFragment.isConfiguringControls())
|
||||
{
|
||||
emulationFragment.stopConfiguringControls();
|
||||
}
|
||||
else
|
||||
{
|
||||
emulationFragment.startConfiguringControls();
|
||||
}
|
||||
break;
|
||||
|
||||
case R.id.menu_refresh_wiimotes:
|
||||
NativeLibrary.RefreshWiimotes();
|
||||
return;
|
||||
|
|
|
@ -10,6 +10,7 @@ import android.view.SurfaceHolder;
|
|||
import android.view.SurfaceView;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Button;
|
||||
|
||||
import org.dolphinemu.dolphinemu.BuildConfig;
|
||||
import org.dolphinemu.dolphinemu.NativeLibrary;
|
||||
|
@ -86,7 +87,6 @@ public final class EmulationFragment extends Fragment implements SurfaceHolder.C
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
if (savedInstanceState == null)
|
||||
{
|
||||
mEmulationThread = new Thread(mEmulationRunner);
|
||||
|
@ -101,6 +101,20 @@ public final class EmulationFragment extends Fragment implements SurfaceHolder.C
|
|||
return contents;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(View view, Bundle savedInstanceState)
|
||||
{
|
||||
Button doneButton = (Button) view.findViewById(R.id.done_control_config);
|
||||
doneButton.setOnClickListener(new View.OnClickListener()
|
||||
{
|
||||
@Override
|
||||
public void onClick(View v)
|
||||
{
|
||||
stopConfiguringControls();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart()
|
||||
{
|
||||
|
@ -224,4 +238,21 @@ public final class EmulationFragment extends Fragment implements SurfaceHolder.C
|
|||
NativeLibrary.Run();
|
||||
}
|
||||
};
|
||||
|
||||
public void startConfiguringControls()
|
||||
{
|
||||
getView().findViewById(R.id.done_control_config).setVisibility(View.VISIBLE);
|
||||
mInputOverlay.setIsInEditMode(true);
|
||||
}
|
||||
|
||||
public void stopConfiguringControls()
|
||||
{
|
||||
getView().findViewById(R.id.done_control_config).setVisibility(View.GONE);
|
||||
mInputOverlay.setIsInEditMode(false);
|
||||
}
|
||||
|
||||
public boolean isConfiguringControls()
|
||||
{
|
||||
return mInputOverlay.isInEditMode();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,6 +39,10 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener
|
|||
private final Set<InputOverlayDrawableButton> overlayButtons = new HashSet<>();
|
||||
private final Set<InputOverlayDrawableJoystick> overlayJoysticks = new HashSet<>();
|
||||
|
||||
private boolean mIsInEditMode = false;
|
||||
private InputOverlayDrawableButton mButtonBeingConfigured;
|
||||
private InputOverlayDrawableJoystick mJoystickBeingConfigured;
|
||||
|
||||
/**
|
||||
* Resizes a {@link Bitmap} by a given scale factor
|
||||
*
|
||||
|
@ -111,25 +115,34 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener
|
|||
@Override
|
||||
public boolean onTouch(View v, MotionEvent event)
|
||||
{
|
||||
if (isInEditMode())
|
||||
{
|
||||
return onTouchWhileEditing(v, event);
|
||||
}
|
||||
|
||||
int pointerIndex = event.getActionIndex();
|
||||
|
||||
for (InputOverlayDrawableButton button : overlayButtons)
|
||||
{
|
||||
// Determine the button state to apply based on the MotionEvent action flag.
|
||||
switch(event.getAction() & MotionEvent.ACTION_MASK)
|
||||
switch (event.getAction() & MotionEvent.ACTION_MASK)
|
||||
{
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
case MotionEvent.ACTION_POINTER_DOWN:
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
// If a pointer enters the bounds of a button, press that button.
|
||||
if (button.getBounds().contains((int)event.getX(pointerIndex), (int)event.getY(pointerIndex)))
|
||||
{
|
||||
NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, button.getId(), ButtonState.PRESSED);
|
||||
}
|
||||
break;
|
||||
case MotionEvent.ACTION_UP:
|
||||
case MotionEvent.ACTION_POINTER_UP:
|
||||
// If a pointer ends, release the button it was pressing.
|
||||
if (button.getBounds().contains((int)event.getX(pointerIndex), (int)event.getY(pointerIndex)))
|
||||
NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, button.getId(), ButtonState.RELEASED);
|
||||
{
|
||||
NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, button.getId(), ButtonState.RELEASED);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -142,12 +155,103 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener
|
|||
float[] axises = joystick.getAxisValues();
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
NativeLibrary.onGamePadMoveEvent(NativeLibrary.TouchScreenDevice, axisIDs[i], axises[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean onTouchWhileEditing(View v, MotionEvent event)
|
||||
{
|
||||
int pointerIndex = event.getActionIndex();
|
||||
int fingerPositionX = (int)event.getX(pointerIndex);
|
||||
int fingerPositionY = (int)event.getY(pointerIndex);
|
||||
|
||||
//Maybe combine Button and Joystick as subclasses of the same parent?
|
||||
//Or maybe create an interface like IMoveableHUDControl?
|
||||
|
||||
for (InputOverlayDrawableButton button : overlayButtons)
|
||||
{
|
||||
// Determine the button state to apply based on the MotionEvent action flag.
|
||||
switch (event.getAction() & MotionEvent.ACTION_MASK)
|
||||
{
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
case MotionEvent.ACTION_POINTER_DOWN:
|
||||
// If no button is being moved now, remember the currently touched button to move.
|
||||
if (mButtonBeingConfigured == null && button.getBounds().contains(fingerPositionX, fingerPositionY))
|
||||
{
|
||||
mButtonBeingConfigured = button;
|
||||
mButtonBeingConfigured.onConfigureTouch(v, event);
|
||||
}
|
||||
break;
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
if (mButtonBeingConfigured != null)
|
||||
{
|
||||
mButtonBeingConfigured.onConfigureTouch(v, event);
|
||||
invalidate();
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
case MotionEvent.ACTION_UP:
|
||||
case MotionEvent.ACTION_POINTER_UP:
|
||||
if (mButtonBeingConfigured == button)
|
||||
{
|
||||
//Persist button position by saving new place.
|
||||
saveControlPosition(mButtonBeingConfigured.getSharedPrefsId(), mButtonBeingConfigured.getBounds().left, mButtonBeingConfigured.getBounds().top);
|
||||
mButtonBeingConfigured = null;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for (InputOverlayDrawableJoystick joystick : overlayJoysticks)
|
||||
{
|
||||
switch (event.getAction())
|
||||
{
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
case MotionEvent.ACTION_POINTER_DOWN:
|
||||
if (mJoystickBeingConfigured == null && joystick.getBounds().contains(fingerPositionX, fingerPositionY))
|
||||
{
|
||||
mJoystickBeingConfigured = joystick;
|
||||
mJoystickBeingConfigured.onConfigureTouch(v, event);
|
||||
}
|
||||
break;
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
if (mJoystickBeingConfigured != null)
|
||||
{
|
||||
mJoystickBeingConfigured.onConfigureTouch(v, event);
|
||||
invalidate();
|
||||
}
|
||||
break;
|
||||
case MotionEvent.ACTION_UP:
|
||||
case MotionEvent.ACTION_POINTER_UP:
|
||||
if (mJoystickBeingConfigured != null)
|
||||
{
|
||||
saveControlPosition(mJoystickBeingConfigured.getSharedPrefsId(), mJoystickBeingConfigured.getBounds().left, mJoystickBeingConfigured.getBounds().right);
|
||||
mJoystickBeingConfigured = null;
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void saveControlPosition(String sharedPrefsId, int x, int y)
|
||||
{
|
||||
final SharedPreferences sPrefs = PreferenceManager.getDefaultSharedPreferences(getContext());
|
||||
SharedPreferences.Editor sPrefsEditor = sPrefs.edit();
|
||||
sPrefsEditor.putFloat(sharedPrefsId+"-X", x);
|
||||
sPrefsEditor.putFloat(sharedPrefsId+"-Y", y);
|
||||
sPrefsEditor.apply();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes an InputOverlayDrawableButton, given by resId, with all of the
|
||||
* parameters set for it to be properly shown on the InputOverlay.
|
||||
|
@ -212,11 +316,10 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener
|
|||
|
||||
// Initialize the InputOverlayDrawableButton.
|
||||
final Bitmap bitmap = resizeBitmap(context, BitmapFactory.decodeResource(res, resId), scale);
|
||||
final InputOverlayDrawableButton overlayDrawable = new InputOverlayDrawableButton(res, bitmap, buttonId);
|
||||
|
||||
// String ID of the Drawable. This is what is passed into SharedPreferences
|
||||
// to check whether or not a value has been set.
|
||||
// to check whether or not a value has been set. Send to button so it can be referenced.
|
||||
final String drawableId = res.getResourceEntryName(resId);
|
||||
final InputOverlayDrawableButton overlayDrawable = new InputOverlayDrawableButton(res, bitmap, buttonId, drawableId);
|
||||
|
||||
// The X and Y coordinates of the InputOverlayDrawableButton on the InputOverlay.
|
||||
// These were set in the input overlay configuration menu.
|
||||
|
@ -233,6 +336,9 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener
|
|||
// This will dictate where on the screen (and the what the size) the InputOverlayDrawableButton will be.
|
||||
overlayDrawable.setBounds(drawableX, drawableY, drawableX+intrinWidth, drawableY+intrinHeight);
|
||||
|
||||
// Need to set the image's position
|
||||
overlayDrawable.setPosition(drawableX, drawableY);
|
||||
|
||||
return overlayDrawable;
|
||||
}
|
||||
|
||||
|
@ -276,14 +382,27 @@ public final class InputOverlay extends SurfaceView implements OnTouchListener
|
|||
Rect outerRect = new Rect(drawableX, drawableY, drawableX + outerSize, drawableY + outerSize);
|
||||
Rect innerRect = new Rect(0, 0, outerSize / 4, outerSize / 4);
|
||||
|
||||
// Send the drawableId to the joystick so it can be referenced when saving control position.
|
||||
final InputOverlayDrawableJoystick overlayDrawable
|
||||
= new InputOverlayDrawableJoystick(res,
|
||||
bitmapOuter, bitmapInner,
|
||||
outerRect, innerRect,
|
||||
joystick);
|
||||
joystick, drawableId);
|
||||
|
||||
// Need to set the image's position
|
||||
overlayDrawable.setPosition(drawableX, drawableY);
|
||||
|
||||
return overlayDrawable;
|
||||
}
|
||||
|
||||
public void setIsInEditMode(boolean isInEditMode)
|
||||
{
|
||||
mIsInEditMode = isInEditMode;
|
||||
}
|
||||
|
||||
public boolean isInEditMode()
|
||||
{
|
||||
return mIsInEditMode;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -8,7 +8,10 @@ package org.dolphinemu.dolphinemu.overlay;
|
|||
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
|
||||
/**
|
||||
* Custom {@link BitmapDrawable} that is capable
|
||||
|
@ -17,7 +20,10 @@ import android.graphics.drawable.BitmapDrawable;
|
|||
public final class InputOverlayDrawableButton extends BitmapDrawable
|
||||
{
|
||||
// The ID identifying what type of button this Drawable represents.
|
||||
private int buttonType;
|
||||
private int mButtonType;
|
||||
private int mPreviousTouchX, mPreviousTouchY;
|
||||
private int mControlPositionX, mControlPositionY;
|
||||
private String mSharedPrefsId;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
|
@ -25,12 +31,13 @@ public final class InputOverlayDrawableButton extends BitmapDrawable
|
|||
* @param res {@link Resources} instance.
|
||||
* @param bitmap {@link Bitmap} to use with this Drawable.
|
||||
* @param buttonType Identifier for this type of button.
|
||||
* @param sharedPrefsId Identifier for getting X and Y control positions from Shared Preferences.
|
||||
*/
|
||||
public InputOverlayDrawableButton(Resources res, Bitmap bitmap, int buttonType)
|
||||
public InputOverlayDrawableButton(Resources res, Bitmap bitmap, int buttonType, String sharedPrefsId)
|
||||
{
|
||||
super(res, bitmap);
|
||||
|
||||
this.buttonType = buttonType;
|
||||
mButtonType = buttonType;
|
||||
mSharedPrefsId = sharedPrefsId;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -40,6 +47,40 @@ public final class InputOverlayDrawableButton extends BitmapDrawable
|
|||
*/
|
||||
public int getId()
|
||||
{
|
||||
return buttonType;
|
||||
return mButtonType;
|
||||
}
|
||||
|
||||
public boolean onConfigureTouch(View v, MotionEvent event)
|
||||
{
|
||||
int pointerIndex = event.getActionIndex();
|
||||
int fingerPositionX = (int)event.getX(pointerIndex);
|
||||
int fingerPositionY = (int)event.getY(pointerIndex);
|
||||
switch (event.getAction())
|
||||
{
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
mPreviousTouchX = fingerPositionX;
|
||||
mPreviousTouchY = fingerPositionY;
|
||||
break;
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
mControlPositionX += fingerPositionX - mPreviousTouchX;
|
||||
mControlPositionY += fingerPositionY - mPreviousTouchY;
|
||||
setBounds(new Rect(mControlPositionX, mControlPositionY, getBitmap().getWidth() + mControlPositionX, getBitmap().getHeight() + mControlPositionY));
|
||||
mPreviousTouchX = fingerPositionX;
|
||||
mPreviousTouchY = fingerPositionY;
|
||||
break;
|
||||
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public String getSharedPrefsId()
|
||||
{
|
||||
return mSharedPrefsId;
|
||||
}
|
||||
|
||||
public void setPosition(int x, int y)
|
||||
{
|
||||
mControlPositionX = x;
|
||||
mControlPositionY = y;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ import android.graphics.Canvas;
|
|||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
|
||||
/**
|
||||
* Custom {@link BitmapDrawable} that is capable
|
||||
|
@ -23,6 +24,9 @@ public final class InputOverlayDrawableJoystick extends BitmapDrawable
|
|||
private final float[] axises = {0f, 0f};
|
||||
private final BitmapDrawable ringInner;
|
||||
private int trackId = -1;
|
||||
private String mSharedPrefsId;
|
||||
private int mControlPositionX, mControlPositionY;
|
||||
private int mPreviousTouchX, mPreviousTouchY;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
|
@ -33,11 +37,12 @@ public final class InputOverlayDrawableJoystick extends BitmapDrawable
|
|||
* @param rectOuter {@link Rect} which represents the outer joystick bounds.
|
||||
* @param rectInner {@link Rect} which represents the inner joystick bounds.
|
||||
* @param joystick Identifier for which joystick this is.
|
||||
* @param sharedPrefsId Identifier for getting X and Y control positions from Shared Preferences.
|
||||
*/
|
||||
public InputOverlayDrawableJoystick(Resources res,
|
||||
Bitmap bitmapOuter, Bitmap bitmapInner,
|
||||
Rect rectOuter, Rect rectInner,
|
||||
int joystick)
|
||||
int joystick, String sharedPrefsId)
|
||||
{
|
||||
super(res, bitmapOuter);
|
||||
this.setBounds(rectOuter);
|
||||
|
@ -49,13 +54,13 @@ public final class InputOverlayDrawableJoystick extends BitmapDrawable
|
|||
this.axisIDs[1] = joystick + 2;
|
||||
this.axisIDs[2] = joystick + 3;
|
||||
this.axisIDs[3] = joystick + 4;
|
||||
mSharedPrefsId = sharedPrefsId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Canvas canvas)
|
||||
{
|
||||
super.draw(canvas);
|
||||
|
||||
ringInner.draw(canvas);
|
||||
}
|
||||
|
||||
|
@ -106,6 +111,33 @@ public final class InputOverlayDrawableJoystick extends BitmapDrawable
|
|||
}
|
||||
}
|
||||
|
||||
public boolean onConfigureTouch(View v, MotionEvent event)
|
||||
{
|
||||
int pointerIndex = event.getActionIndex();
|
||||
int fingerPositionX = (int)event.getX(pointerIndex);
|
||||
int fingerPositionY = (int)event.getY(pointerIndex);
|
||||
switch (event.getAction())
|
||||
{
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
mPreviousTouchX = fingerPositionX;
|
||||
mPreviousTouchY = fingerPositionY;
|
||||
break;
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
int deltaX = fingerPositionX - mPreviousTouchX;
|
||||
int deltaY = fingerPositionY - mPreviousTouchY;
|
||||
mControlPositionX += deltaX;
|
||||
mControlPositionY += deltaY;
|
||||
setBounds(new Rect(mControlPositionX, mControlPositionY, getBitmap().getWidth() + mControlPositionX, getBitmap().getHeight() + mControlPositionY));
|
||||
SetInnerBounds();
|
||||
mPreviousTouchX = fingerPositionX;
|
||||
mPreviousTouchY = fingerPositionY;
|
||||
break;
|
||||
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public float[] getAxisValues()
|
||||
{
|
||||
float[] joyaxises = {0f, 0f, 0f, 0f};
|
||||
|
@ -133,5 +165,17 @@ public final class InputOverlayDrawableJoystick extends BitmapDrawable
|
|||
int height = this.ringInner.getBounds().height() / 2;
|
||||
this.ringInner.setBounds(X - width, Y - height,
|
||||
X + width, Y + height);
|
||||
ringInner.invalidateSelf();
|
||||
}
|
||||
|
||||
public String getSharedPrefsId()
|
||||
{
|
||||
return mSharedPrefsId;
|
||||
}
|
||||
|
||||
public void setPosition(int x, int y)
|
||||
{
|
||||
mControlPositionX = x;
|
||||
mControlPositionY = y;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,4 +20,16 @@
|
|||
android:layout_width="match_parent"
|
||||
android:focusable="true"
|
||||
android:focusableInTouchMode="true"/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/done_control_config"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:padding="@dimen/spacing_small"
|
||||
android:background="@color/dolphin_blue"
|
||||
android:textColor="@color/lb_tv_white"
|
||||
android:text="@string/emulation_done"
|
||||
android:visibility="gone"/>
|
||||
|
||||
</FrameLayout>
|
||||
|
|
|
@ -31,6 +31,12 @@
|
|||
android:showAsAction="never"
|
||||
android:title="@string/emulation_toggle_input"/>
|
||||
|
||||
<item
|
||||
android:id="@+id/menu_emulation_configure_controls"
|
||||
android:showAsAction="never"
|
||||
android:title="@string/emulation_configure_controls">
|
||||
</item>
|
||||
|
||||
<!-- Save State Slots -->
|
||||
<item
|
||||
android:id="@+id/menu_emulation_save_root"
|
||||
|
|
|
@ -359,6 +359,8 @@
|
|||
<string name="emulation_quicksave">Quick Save</string>
|
||||
<string name="emulation_quickload">Quick Load</string>
|
||||
<string name="emulation_refresh_wiimotes">Refresh Wiimotes</string>
|
||||
<string name="emulation_configure_controls">Configure Controls</string>
|
||||
<string name="emulation_done">Done</string>
|
||||
|
||||
<!-- GC Adapter Menu-->
|
||||
<string name="gc_adapter_rumble">Enable Vibration</string>
|
||||
|
|
Loading…
Reference in New Issue