Added Joy stick classes and resources
Signed-off-by: Ricky Barrette <rickbarrette@gmail.com>
This commit is contained in:
@@ -4,6 +4,5 @@
|
|||||||
<classpathentry kind="src" path="gen"/>
|
<classpathentry kind="src" path="gen"/>
|
||||||
<classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
|
<classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
|
||||||
<classpathentry kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>
|
<classpathentry kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>
|
||||||
<classpathentry kind="lib" path="/home/ricky/App/android-sdk-linux_86/extras/android-support-v4-r6-googlemaps.jar"/>
|
|
||||||
<classpathentry kind="output" path="bin/classes"/>
|
<classpathentry kind="output" path="bin/classes"/>
|
||||||
</classpath>
|
</classpath>
|
||||||
|
|||||||
@@ -9,6 +9,6 @@
|
|||||||
|
|
||||||
# Project target.
|
# Project target.
|
||||||
target=Google Inc.:Google APIs:17
|
target=Google Inc.:Google APIs:17
|
||||||
android.library.reference.3=../ioiolib/IOIOLib
|
|
||||||
android.library.reference.1=../../exception_handler_library/ExceptionHandlerLib
|
android.library.reference.1=../../exception_handler_library/ExceptionHandlerLib
|
||||||
android.library.reference.2=../../location_library/LocationLib
|
android.library.reference.2=../ioiolib/IOIOLib
|
||||||
|
android.library.reference.3=../../location_library/LocationLib
|
||||||
|
|||||||
37
IOIOTruck/res/layout/dualjoystick.xml
Normal file
37
IOIOTruck/res/layout/dualjoystick.xml
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:orientation="vertical" android:layout_width="fill_parent"
|
||||||
|
android:layout_height="fill_parent">
|
||||||
|
|
||||||
|
<com.MobileAnarchy.Android.Widgets.Joystick.DualJoystickView
|
||||||
|
android:id="@+id/dualjoystickView" android:layout_gravity="center_horizontal"
|
||||||
|
android:layout_marginTop="5dip" android:layout_width="fill_parent"
|
||||||
|
android:layout_height="175dip" />
|
||||||
|
|
||||||
|
<TableLayout android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content" android:layout_gravity="center_horizontal"
|
||||||
|
android:layout_marginTop="10dip">
|
||||||
|
<TableRow>
|
||||||
|
<TextView android:text="X" android:layout_width="50dip"
|
||||||
|
android:layout_height="wrap_content"></TextView>
|
||||||
|
<TextView android:text="" android:id="@+id/TextViewX1"
|
||||||
|
android:layout_width="150dip" android:layout_height="wrap_content"></TextView>
|
||||||
|
|
||||||
|
<TextView android:text="X" android:layout_width="50dip"
|
||||||
|
android:layout_height="wrap_content"></TextView>
|
||||||
|
<TextView android:text="" android:id="@+id/TextViewX2"
|
||||||
|
android:layout_width="100dip" android:layout_height="wrap_content"></TextView>
|
||||||
|
</TableRow>
|
||||||
|
<TableRow>
|
||||||
|
<TextView android:text="Y" android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"></TextView>
|
||||||
|
<TextView android:text="" android:id="@+id/TextViewY1"
|
||||||
|
android:layout_width="wrap_content" android:layout_height="wrap_content"></TextView>
|
||||||
|
|
||||||
|
<TextView android:text="Y" android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"></TextView>
|
||||||
|
<TextView android:text="" android:id="@+id/TextViewY2"
|
||||||
|
android:layout_width="wrap_content" android:layout_height="wrap_content"></TextView>
|
||||||
|
</TableRow>
|
||||||
|
</TableLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
28
IOIOTruck/res/layout/joystick.xml
Normal file
28
IOIOTruck/res/layout/joystick.xml
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:orientation="vertical" android:layout_width="fill_parent"
|
||||||
|
android:layout_height="fill_parent">
|
||||||
|
|
||||||
|
<com.MobileAnarchy.Android.Widgets.Joystick.JoystickView
|
||||||
|
android:id="@+id/joystickView" android:layout_gravity="center_horizontal"
|
||||||
|
android:layout_marginTop="20dip" android:layout_width="175dip"
|
||||||
|
android:layout_height="175dip" />
|
||||||
|
|
||||||
|
<TableLayout android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content" android:layout_gravity="center_horizontal"
|
||||||
|
android:layout_marginTop="10dip">
|
||||||
|
<TableRow>
|
||||||
|
<TextView android:text="X" android:layout_width="50dip"
|
||||||
|
android:layout_height="wrap_content"></TextView>
|
||||||
|
<TextView android:text="" android:id="@+id/TextViewX"
|
||||||
|
android:layout_width="100dip" android:layout_height="wrap_content"></TextView>
|
||||||
|
</TableRow>
|
||||||
|
<TableRow>
|
||||||
|
<TextView android:text="Y" android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"></TextView>
|
||||||
|
<TextView android:text="" android:id="@+id/TextViewY"
|
||||||
|
android:layout_width="wrap_content" android:layout_height="wrap_content"></TextView>
|
||||||
|
</TableRow>
|
||||||
|
</TableLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
17
IOIOTruck/res/values/attr.xml
Normal file
17
IOIOTruck/res/values/attr.xml
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
|
||||||
|
<declare-styleable name="DockPanel">
|
||||||
|
<attr name="handleButtonDrawableId" format="reference" />
|
||||||
|
<attr name="contentLayoutId" format="reference" />
|
||||||
|
<attr name="dockPosition" format="enum" />
|
||||||
|
<attr name="isOpen" format="boolean" />
|
||||||
|
<attr name="animationDuration" format="integer" />
|
||||||
|
</declare-styleable>
|
||||||
|
|
||||||
|
<declare-styleable name="ThresholdEditText">
|
||||||
|
<attr name="threshold" format="integer" />
|
||||||
|
<attr name="disableThresholdOnEmptyInput" format="boolean" />
|
||||||
|
</declare-styleable>
|
||||||
|
|
||||||
|
</resources>
|
||||||
19
IOIOTruck/res/values/dimen.xml
Normal file
19
IOIOTruck/res/values/dimen.xml
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
Copyright (C) 2009 The Android Open Source Project Licensed under the
|
||||||
|
Apache License, Version 2.0 (the "License"); you may not use this file
|
||||||
|
except in compliance with the License. You may obtain a copy of the
|
||||||
|
License at http://www.apache.org/licenses/LICENSE-2.0 Unless required
|
||||||
|
by applicable law or agreed to in writing, software distributed under
|
||||||
|
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||||
|
CONDITIONS OF ANY KIND, either express or implied. See the License for
|
||||||
|
the specific language governing permissions and limitations under the
|
||||||
|
License.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<resources>
|
||||||
|
<!-- height of a normal list item in edit playlist mode -->
|
||||||
|
<dimen name="normal_height">66dip</dimen>
|
||||||
|
<!-- height of an expanded list item in edit playlist mode -->
|
||||||
|
<dimen name="expanded_height">132dip</dimen>
|
||||||
|
</resources>
|
||||||
@@ -0,0 +1,156 @@
|
|||||||
|
package com.MobileAnarchy.Android.Widgets.Joystick;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.graphics.Canvas;
|
||||||
|
import android.graphics.Color;
|
||||||
|
import android.graphics.Paint;
|
||||||
|
import android.util.AttributeSet;
|
||||||
|
import android.view.MotionEvent;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.LinearLayout;
|
||||||
|
|
||||||
|
public class DualJoystickView extends LinearLayout {
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
private static final String TAG = DualJoystickView.class.getSimpleName();
|
||||||
|
|
||||||
|
private final boolean D = false;
|
||||||
|
private Paint dbgPaint1;
|
||||||
|
|
||||||
|
private JoystickView stickL;
|
||||||
|
private JoystickView stickR;
|
||||||
|
|
||||||
|
private View pad;
|
||||||
|
|
||||||
|
public DualJoystickView(Context context) {
|
||||||
|
super(context);
|
||||||
|
stickL = new JoystickView(context);
|
||||||
|
stickR = new JoystickView(context);
|
||||||
|
initDualJoystickView();
|
||||||
|
}
|
||||||
|
|
||||||
|
public DualJoystickView(Context context, AttributeSet attrs) {
|
||||||
|
super(context, attrs);
|
||||||
|
stickL = new JoystickView(context, attrs);
|
||||||
|
stickR = new JoystickView(context, attrs);
|
||||||
|
initDualJoystickView();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initDualJoystickView() {
|
||||||
|
setOrientation(LinearLayout.HORIZONTAL);
|
||||||
|
|
||||||
|
if (D) {
|
||||||
|
dbgPaint1 = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||||
|
dbgPaint1.setColor(Color.CYAN);
|
||||||
|
dbgPaint1.setStrokeWidth(1);
|
||||||
|
dbgPaint1.setStyle(Paint.Style.STROKE);
|
||||||
|
}
|
||||||
|
|
||||||
|
pad = new View(getContext());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||||
|
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||||
|
removeView(stickL);
|
||||||
|
removeView(stickR);
|
||||||
|
|
||||||
|
float padW = getMeasuredWidth() - (getMeasuredHeight() * 2);
|
||||||
|
int joyWidth = (int) ((getMeasuredWidth() - padW) / 2);
|
||||||
|
LayoutParams joyLParams = new LayoutParams(joyWidth,
|
||||||
|
getMeasuredHeight());
|
||||||
|
|
||||||
|
stickL.setLayoutParams(joyLParams);
|
||||||
|
stickR.setLayoutParams(joyLParams);
|
||||||
|
|
||||||
|
stickL.TAG = "L";
|
||||||
|
stickR.TAG = "R";
|
||||||
|
stickL.setPointerId(JoystickView.INVALID_POINTER_ID);
|
||||||
|
stickR.setPointerId(JoystickView.INVALID_POINTER_ID);
|
||||||
|
|
||||||
|
addView(stickL);
|
||||||
|
|
||||||
|
ViewGroup.LayoutParams padLParams = new ViewGroup.LayoutParams(
|
||||||
|
(int) padW, getMeasuredHeight());
|
||||||
|
removeView(pad);
|
||||||
|
pad.setLayoutParams(padLParams);
|
||||||
|
addView(pad);
|
||||||
|
|
||||||
|
addView(stickR);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onLayout(boolean changed, int l, int t, int r, int b) {
|
||||||
|
super.onLayout(changed, l, t, r, b);
|
||||||
|
stickR.setTouchOffset(stickR.getLeft(), stickR.getTop());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAutoReturnToCenter(boolean left, boolean right) {
|
||||||
|
stickL.setAutoReturnToCenter(left);
|
||||||
|
stickR.setAutoReturnToCenter(right);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOnJostickMovedListener(JoystickMovedListener left,
|
||||||
|
JoystickMovedListener right) {
|
||||||
|
stickL.setOnJostickMovedListener(left);
|
||||||
|
stickR.setOnJostickMovedListener(right);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOnJostickClickedListener(JoystickClickedListener left,
|
||||||
|
JoystickClickedListener right) {
|
||||||
|
stickL.setOnJostickClickedListener(left);
|
||||||
|
stickR.setOnJostickClickedListener(right);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setYAxisInverted(boolean leftYAxisInverted,
|
||||||
|
boolean rightYAxisInverted) {
|
||||||
|
stickL.setYAxisInverted(leftYAxisInverted);
|
||||||
|
stickL.setYAxisInverted(rightYAxisInverted);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMovementConstraint(int movementConstraint) {
|
||||||
|
stickL.setMovementConstraint(movementConstraint);
|
||||||
|
stickR.setMovementConstraint(movementConstraint);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMovementRange(float movementRangeLeft,
|
||||||
|
float movementRangeRight) {
|
||||||
|
stickL.setMovementRange(movementRangeLeft);
|
||||||
|
stickR.setMovementRange(movementRangeRight);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMoveResolution(float leftMoveResolution,
|
||||||
|
float rightMoveResolution) {
|
||||||
|
stickL.setMoveResolution(leftMoveResolution);
|
||||||
|
stickR.setMoveResolution(rightMoveResolution);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUserCoordinateSystem(int leftCoordinateSystem,
|
||||||
|
int rightCoordinateSystem) {
|
||||||
|
stickL.setUserCoordinateSystem(leftCoordinateSystem);
|
||||||
|
stickR.setUserCoordinateSystem(rightCoordinateSystem);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void dispatchDraw(Canvas canvas) {
|
||||||
|
super.dispatchDraw(canvas);
|
||||||
|
if (D) {
|
||||||
|
canvas.drawRect(1, 1, getMeasuredWidth() - 1,
|
||||||
|
getMeasuredHeight() - 1, dbgPaint1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean dispatchTouchEvent(MotionEvent ev) {
|
||||||
|
boolean l = stickL.dispatchTouchEvent(ev);
|
||||||
|
boolean r = stickR.dispatchTouchEvent(ev);
|
||||||
|
return l || r;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onTouchEvent(MotionEvent ev) {
|
||||||
|
boolean l = stickL.onTouchEvent(ev);
|
||||||
|
boolean r = stickR.onTouchEvent(ev);
|
||||||
|
return l || r;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package com.MobileAnarchy.Android.Widgets.Joystick;
|
||||||
|
|
||||||
|
public interface JoystickClickedListener {
|
||||||
|
public void OnClicked();
|
||||||
|
|
||||||
|
public void OnReleased();
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package com.MobileAnarchy.Android.Widgets.Joystick;
|
||||||
|
|
||||||
|
public interface JoystickMovedListener {
|
||||||
|
public void OnMoved(int pan, int tilt);
|
||||||
|
|
||||||
|
public void OnReleased();
|
||||||
|
|
||||||
|
public void OnReturnedToCenter();
|
||||||
|
}
|
||||||
@@ -0,0 +1,542 @@
|
|||||||
|
package com.MobileAnarchy.Android.Widgets.Joystick;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.graphics.Canvas;
|
||||||
|
import android.graphics.Color;
|
||||||
|
import android.graphics.Paint;
|
||||||
|
import android.util.AttributeSet;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.view.HapticFeedbackConstants;
|
||||||
|
import android.view.MotionEvent;
|
||||||
|
import android.view.View;
|
||||||
|
|
||||||
|
public class JoystickView extends View {
|
||||||
|
public static final int INVALID_POINTER_ID = -1;
|
||||||
|
|
||||||
|
// =========================================
|
||||||
|
// Private Members
|
||||||
|
// =========================================
|
||||||
|
private final boolean D = false;
|
||||||
|
String TAG = "JoystickView";
|
||||||
|
|
||||||
|
private Paint dbgPaint1;
|
||||||
|
private Paint dbgPaint2;
|
||||||
|
|
||||||
|
private Paint bgPaint;
|
||||||
|
private Paint handlePaint;
|
||||||
|
|
||||||
|
private int innerPadding;
|
||||||
|
private int bgRadius;
|
||||||
|
private int handleRadius;
|
||||||
|
private int movementRadius;
|
||||||
|
private int handleInnerBoundaries;
|
||||||
|
|
||||||
|
private JoystickMovedListener moveListener;
|
||||||
|
private JoystickClickedListener clickListener;
|
||||||
|
|
||||||
|
// # of pixels movement required between reporting to the listener
|
||||||
|
private float moveResolution;
|
||||||
|
|
||||||
|
private boolean yAxisInverted;
|
||||||
|
private boolean autoReturnToCenter;
|
||||||
|
|
||||||
|
// Max range of movement in user coordinate system
|
||||||
|
public final static int CONSTRAIN_BOX = 0;
|
||||||
|
public final static int CONSTRAIN_CIRCLE = 1;
|
||||||
|
private int movementConstraint;
|
||||||
|
private float movementRange;
|
||||||
|
|
||||||
|
public final static int COORDINATE_CARTESIAN = 0; // Regular cartesian
|
||||||
|
// coordinates
|
||||||
|
public final static int COORDINATE_DIFFERENTIAL = 1; // Uses polar rotation
|
||||||
|
// of 45 degrees to
|
||||||
|
// calc differential
|
||||||
|
// drive paramaters
|
||||||
|
private int userCoordinateSystem;
|
||||||
|
|
||||||
|
// Records touch pressure for click handling
|
||||||
|
private float touchPressure;
|
||||||
|
private boolean clicked;
|
||||||
|
private float clickThreshold;
|
||||||
|
|
||||||
|
// Last touch point in view coordinates
|
||||||
|
private int pointerId = INVALID_POINTER_ID;
|
||||||
|
private float touchX, touchY;
|
||||||
|
|
||||||
|
// Last reported position in view coordinates (allows different reporting
|
||||||
|
// sensitivities)
|
||||||
|
private float reportX, reportY;
|
||||||
|
|
||||||
|
// Handle center in view coordinates
|
||||||
|
private float handleX, handleY;
|
||||||
|
|
||||||
|
// Center of the view in view coordinates
|
||||||
|
private int cX, cY;
|
||||||
|
|
||||||
|
// Size of the view in view coordinates
|
||||||
|
private int dimX;
|
||||||
|
|
||||||
|
// Cartesian coordinates of last touch point - joystick center is (0,0)
|
||||||
|
private int cartX, cartY;
|
||||||
|
|
||||||
|
// Polar coordinates of the touch point from joystick center
|
||||||
|
private double radial;
|
||||||
|
private double angle;
|
||||||
|
|
||||||
|
// User coordinates of last touch point
|
||||||
|
private int userX, userY;
|
||||||
|
|
||||||
|
// Offset co-ordinates (used when touch events are received from parent's
|
||||||
|
// coordinate origin)
|
||||||
|
private int offsetX;
|
||||||
|
private int offsetY;
|
||||||
|
|
||||||
|
// =========================================
|
||||||
|
// Constructors
|
||||||
|
// =========================================
|
||||||
|
|
||||||
|
public JoystickView(Context context) {
|
||||||
|
super(context);
|
||||||
|
initJoystickView();
|
||||||
|
}
|
||||||
|
|
||||||
|
public JoystickView(Context context, AttributeSet attrs) {
|
||||||
|
super(context, attrs);
|
||||||
|
initJoystickView();
|
||||||
|
}
|
||||||
|
|
||||||
|
public JoystickView(Context context, AttributeSet attrs, int defStyle) {
|
||||||
|
super(context, attrs, defStyle);
|
||||||
|
initJoystickView();
|
||||||
|
}
|
||||||
|
|
||||||
|
// =========================================
|
||||||
|
// Initialization
|
||||||
|
// =========================================
|
||||||
|
|
||||||
|
private void initJoystickView() {
|
||||||
|
setFocusable(true);
|
||||||
|
|
||||||
|
dbgPaint1 = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||||
|
dbgPaint1.setColor(Color.RED);
|
||||||
|
dbgPaint1.setStrokeWidth(1);
|
||||||
|
dbgPaint1.setStyle(Paint.Style.STROKE);
|
||||||
|
|
||||||
|
dbgPaint2 = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||||
|
dbgPaint2.setColor(Color.GREEN);
|
||||||
|
dbgPaint2.setStrokeWidth(1);
|
||||||
|
dbgPaint2.setStyle(Paint.Style.STROKE);
|
||||||
|
|
||||||
|
bgPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||||
|
bgPaint.setColor(Color.GRAY);
|
||||||
|
bgPaint.setStrokeWidth(1);
|
||||||
|
bgPaint.setAlpha(80);
|
||||||
|
bgPaint.setStyle(Paint.Style.FILL_AND_STROKE);
|
||||||
|
|
||||||
|
handlePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||||
|
handlePaint.setColor(Color.DKGRAY);
|
||||||
|
handlePaint.setStrokeWidth(1);
|
||||||
|
handlePaint.setStyle(Paint.Style.FILL_AND_STROKE);
|
||||||
|
|
||||||
|
innerPadding = 10;
|
||||||
|
|
||||||
|
setMovementRange(10);
|
||||||
|
setMoveResolution(1.0f);
|
||||||
|
setClickThreshold(0.4f);
|
||||||
|
setYAxisInverted(true);
|
||||||
|
setUserCoordinateSystem(COORDINATE_CARTESIAN);
|
||||||
|
setAutoReturnToCenter(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAutoReturnToCenter(boolean autoReturnToCenter) {
|
||||||
|
this.autoReturnToCenter = autoReturnToCenter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isAutoReturnToCenter() {
|
||||||
|
return autoReturnToCenter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUserCoordinateSystem(int userCoordinateSystem) {
|
||||||
|
if (userCoordinateSystem < COORDINATE_CARTESIAN
|
||||||
|
|| movementConstraint > COORDINATE_DIFFERENTIAL)
|
||||||
|
Log.e(TAG, "invalid value for userCoordinateSystem");
|
||||||
|
else
|
||||||
|
this.userCoordinateSystem = userCoordinateSystem;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getUserCoordinateSystem() {
|
||||||
|
return userCoordinateSystem;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMovementConstraint(int movementConstraint) {
|
||||||
|
if (movementConstraint < CONSTRAIN_BOX
|
||||||
|
|| movementConstraint > CONSTRAIN_CIRCLE)
|
||||||
|
Log.e(TAG, "invalid value for movementConstraint");
|
||||||
|
else
|
||||||
|
this.movementConstraint = movementConstraint;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getMovementConstraint() {
|
||||||
|
return movementConstraint;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isYAxisInverted() {
|
||||||
|
return yAxisInverted;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setYAxisInverted(boolean yAxisInverted) {
|
||||||
|
this.yAxisInverted = yAxisInverted;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the pressure sensitivity for registering a click
|
||||||
|
*
|
||||||
|
* @param clickThreshold
|
||||||
|
* threshold 0...1.0f inclusive. 0 will cause clicks to never be
|
||||||
|
* reported, 1.0 is a very hard click
|
||||||
|
*/
|
||||||
|
public void setClickThreshold(float clickThreshold) {
|
||||||
|
if (clickThreshold < 0 || clickThreshold > 1.0f)
|
||||||
|
Log.e(TAG, "clickThreshold must range from 0...1.0f inclusive");
|
||||||
|
else
|
||||||
|
this.clickThreshold = clickThreshold;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getClickThreshold() {
|
||||||
|
return clickThreshold;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMovementRange(float movementRange) {
|
||||||
|
this.movementRange = movementRange;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getMovementRange() {
|
||||||
|
return movementRange;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMoveResolution(float moveResolution) {
|
||||||
|
this.moveResolution = moveResolution;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getMoveResolution() {
|
||||||
|
return moveResolution;
|
||||||
|
}
|
||||||
|
|
||||||
|
// =========================================
|
||||||
|
// Public Methods
|
||||||
|
// =========================================
|
||||||
|
|
||||||
|
public void setOnJostickMovedListener(JoystickMovedListener listener) {
|
||||||
|
this.moveListener = listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOnJostickClickedListener(JoystickClickedListener listener) {
|
||||||
|
this.clickListener = listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
// =========================================
|
||||||
|
// Drawing Functionality
|
||||||
|
// =========================================
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||||
|
// Here we make sure that we have a perfect circle
|
||||||
|
int measuredWidth = measure(widthMeasureSpec);
|
||||||
|
int measuredHeight = measure(heightMeasureSpec);
|
||||||
|
setMeasuredDimension(measuredWidth, measuredHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onLayout(boolean changed, int left, int top, int right,
|
||||||
|
int bottom) {
|
||||||
|
super.onLayout(changed, left, top, right, bottom);
|
||||||
|
|
||||||
|
int d = Math.min(getMeasuredWidth(), getMeasuredHeight());
|
||||||
|
|
||||||
|
dimX = d;
|
||||||
|
// dimY = d;
|
||||||
|
|
||||||
|
cX = d / 2;
|
||||||
|
cY = d / 2;
|
||||||
|
|
||||||
|
bgRadius = dimX / 2 - innerPadding;
|
||||||
|
handleRadius = (int) (d * 0.25);
|
||||||
|
handleInnerBoundaries = handleRadius;
|
||||||
|
movementRadius = Math.min(cX, cY) - handleInnerBoundaries;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int measure(int measureSpec) {
|
||||||
|
int result = 0;
|
||||||
|
// Decode the measurement specifications.
|
||||||
|
int specMode = MeasureSpec.getMode(measureSpec);
|
||||||
|
int specSize = MeasureSpec.getSize(measureSpec);
|
||||||
|
if (specMode == MeasureSpec.UNSPECIFIED) {
|
||||||
|
// Return a default size of 200 if no bounds are specified.
|
||||||
|
result = 200;
|
||||||
|
} else {
|
||||||
|
// As you want to fill the available space
|
||||||
|
// always return the full available bounds.
|
||||||
|
result = specSize;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onDraw(Canvas canvas) {
|
||||||
|
canvas.save();
|
||||||
|
// Draw the background
|
||||||
|
canvas.drawCircle(cX, cY, bgRadius, bgPaint);
|
||||||
|
|
||||||
|
// Draw the handle
|
||||||
|
handleX = touchX + cX;
|
||||||
|
handleY = touchY + cY;
|
||||||
|
canvas.drawCircle(handleX, handleY, handleRadius, handlePaint);
|
||||||
|
|
||||||
|
if (D) {
|
||||||
|
canvas.drawRect(1, 1, getMeasuredWidth() - 1,
|
||||||
|
getMeasuredHeight() - 1, dbgPaint1);
|
||||||
|
|
||||||
|
canvas.drawCircle(handleX, handleY, 3, dbgPaint1);
|
||||||
|
|
||||||
|
if (movementConstraint == CONSTRAIN_CIRCLE) {
|
||||||
|
canvas.drawCircle(cX, cY, this.movementRadius, dbgPaint1);
|
||||||
|
} else {
|
||||||
|
canvas.drawRect(cX - movementRadius, cY - movementRadius, cX
|
||||||
|
+ movementRadius, cY + movementRadius, dbgPaint1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Origin to touch point
|
||||||
|
canvas.drawLine(cX, cY, handleX, handleY, dbgPaint2);
|
||||||
|
|
||||||
|
int baseY = (int) (touchY < 0 ? cY + handleRadius : cY
|
||||||
|
- handleRadius);
|
||||||
|
canvas.drawText(
|
||||||
|
String.format("%s (%.0f,%.0f)", TAG, touchX, touchY),
|
||||||
|
handleX - 20, baseY - 7, dbgPaint2);
|
||||||
|
canvas.drawText(
|
||||||
|
"("
|
||||||
|
+ String.format("%.0f, %.1f", radial,
|
||||||
|
angle * 57.2957795) + (char) 0x00B0 + ")",
|
||||||
|
handleX - 20, baseY + 15, dbgPaint2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Log.d(TAG, String.format("touch(%f,%f)", touchX, touchY));
|
||||||
|
// Log.d(TAG, String.format("onDraw(%.1f,%.1f)\n\n", handleX, handleY));
|
||||||
|
canvas.restore();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Constrain touch within a box
|
||||||
|
private void constrainBox() {
|
||||||
|
touchX = Math.max(Math.min(touchX, movementRadius), -movementRadius);
|
||||||
|
touchY = Math.max(Math.min(touchY, movementRadius), -movementRadius);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Constrain touch within a circle
|
||||||
|
private void constrainCircle() {
|
||||||
|
float diffX = touchX;
|
||||||
|
float diffY = touchY;
|
||||||
|
double radial = Math.sqrt((diffX * diffX) + (diffY * diffY));
|
||||||
|
if (radial > movementRadius) {
|
||||||
|
touchX = (int) ((diffX / radial) * movementRadius);
|
||||||
|
touchY = (int) ((diffY / radial) * movementRadius);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPointerId(int id) {
|
||||||
|
this.pointerId = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getPointerId() {
|
||||||
|
return pointerId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onTouchEvent(MotionEvent ev) {
|
||||||
|
final int action = ev.getAction();
|
||||||
|
switch (action & MotionEvent.ACTION_MASK) {
|
||||||
|
case MotionEvent.ACTION_MOVE: {
|
||||||
|
return processMoveEvent(ev);
|
||||||
|
}
|
||||||
|
case MotionEvent.ACTION_CANCEL:
|
||||||
|
case MotionEvent.ACTION_UP: {
|
||||||
|
if (pointerId != INVALID_POINTER_ID) {
|
||||||
|
// Log.d(TAG, "ACTION_UP");
|
||||||
|
returnHandleToCenter();
|
||||||
|
setPointerId(INVALID_POINTER_ID);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case MotionEvent.ACTION_POINTER_UP: {
|
||||||
|
if (pointerId != INVALID_POINTER_ID) {
|
||||||
|
final int pointerIndex = (action & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
|
||||||
|
final int pointerId = ev.getPointerId(pointerIndex);
|
||||||
|
if (pointerId == this.pointerId) {
|
||||||
|
// Log.d(TAG, "ACTION_POINTER_UP: " + pointerId);
|
||||||
|
returnHandleToCenter();
|
||||||
|
setPointerId(INVALID_POINTER_ID);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case MotionEvent.ACTION_DOWN: {
|
||||||
|
if (pointerId == INVALID_POINTER_ID) {
|
||||||
|
int x = (int) ev.getX();
|
||||||
|
if (x >= offsetX && x < offsetX + dimX) {
|
||||||
|
setPointerId(ev.getPointerId(0));
|
||||||
|
// Log.d(TAG, "ACTION_DOWN: " + getPointerId());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case MotionEvent.ACTION_POINTER_DOWN: {
|
||||||
|
if (pointerId == INVALID_POINTER_ID) {
|
||||||
|
final int pointerIndex = (action & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
|
||||||
|
final int pointerId = ev.getPointerId(pointerIndex);
|
||||||
|
int x = (int) ev.getX(pointerId);
|
||||||
|
if (x >= offsetX && x < offsetX + dimX) {
|
||||||
|
// Log.d(TAG, "ACTION_POINTER_DOWN: " + pointerId);
|
||||||
|
setPointerId(pointerId);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean processMoveEvent(MotionEvent ev) {
|
||||||
|
if (pointerId != INVALID_POINTER_ID) {
|
||||||
|
final int pointerIndex = ev.findPointerIndex(pointerId);
|
||||||
|
|
||||||
|
// Translate touch position to center of view
|
||||||
|
float x = ev.getX(pointerIndex);
|
||||||
|
touchX = x - cX - offsetX;
|
||||||
|
float y = ev.getY(pointerIndex);
|
||||||
|
touchY = y - cY - offsetY;
|
||||||
|
|
||||||
|
// Log.d(TAG,
|
||||||
|
// String.format("ACTION_MOVE: (%03.0f, %03.0f) => (%03.0f, %03.0f)",
|
||||||
|
// x, y, touchX, touchY));
|
||||||
|
|
||||||
|
reportOnMoved();
|
||||||
|
invalidate();
|
||||||
|
|
||||||
|
touchPressure = ev.getPressure(pointerIndex);
|
||||||
|
reportOnPressure();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void reportOnMoved() {
|
||||||
|
if (movementConstraint == CONSTRAIN_CIRCLE)
|
||||||
|
constrainCircle();
|
||||||
|
else
|
||||||
|
constrainBox();
|
||||||
|
|
||||||
|
calcUserCoordinates();
|
||||||
|
|
||||||
|
if (moveListener != null) {
|
||||||
|
boolean rx = Math.abs(touchX - reportX) >= moveResolution;
|
||||||
|
boolean ry = Math.abs(touchY - reportY) >= moveResolution;
|
||||||
|
if (rx || ry) {
|
||||||
|
this.reportX = touchX;
|
||||||
|
this.reportY = touchY;
|
||||||
|
|
||||||
|
// Log.d(TAG, String.format("moveListener.OnMoved(%d,%d)",
|
||||||
|
// (int)userX, (int)userY));
|
||||||
|
moveListener.OnMoved(userX, userY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void calcUserCoordinates() {
|
||||||
|
// First convert to cartesian coordinates
|
||||||
|
cartX = (int) (touchX / movementRadius * movementRange);
|
||||||
|
cartY = (int) (touchY / movementRadius * movementRange);
|
||||||
|
|
||||||
|
radial = Math.sqrt((cartX * cartX) + (cartY * cartY));
|
||||||
|
angle = Math.atan2(cartY, cartX);
|
||||||
|
|
||||||
|
// Invert Y axis if requested
|
||||||
|
if (!yAxisInverted)
|
||||||
|
cartY *= -1;
|
||||||
|
|
||||||
|
if (userCoordinateSystem == COORDINATE_CARTESIAN) {
|
||||||
|
userX = cartX;
|
||||||
|
userY = cartY;
|
||||||
|
} else if (userCoordinateSystem == COORDINATE_DIFFERENTIAL) {
|
||||||
|
userX = cartY + cartX / 4;
|
||||||
|
userY = cartY - cartX / 4;
|
||||||
|
|
||||||
|
if (userX < -movementRange)
|
||||||
|
userX = (int) -movementRange;
|
||||||
|
if (userX > movementRange)
|
||||||
|
userX = (int) movementRange;
|
||||||
|
|
||||||
|
if (userY < -movementRange)
|
||||||
|
userY = (int) -movementRange;
|
||||||
|
if (userY > movementRange)
|
||||||
|
userY = (int) movementRange;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Simple pressure click
|
||||||
|
private void reportOnPressure() {
|
||||||
|
// Log.d(TAG, String.format("touchPressure=%.2f", this.touchPressure));
|
||||||
|
if (clickListener != null) {
|
||||||
|
if (clicked && touchPressure < clickThreshold) {
|
||||||
|
clickListener.OnReleased();
|
||||||
|
this.clicked = false;
|
||||||
|
// Log.d(TAG, "reset click");
|
||||||
|
invalidate();
|
||||||
|
} else if (!clicked && touchPressure >= clickThreshold) {
|
||||||
|
clicked = true;
|
||||||
|
clickListener.OnClicked();
|
||||||
|
// Log.d(TAG, "click");
|
||||||
|
invalidate();
|
||||||
|
performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void returnHandleToCenter() {
|
||||||
|
if (autoReturnToCenter) {
|
||||||
|
final int numberOfFrames = 5;
|
||||||
|
final double intervalsX = (0 - touchX) / numberOfFrames;
|
||||||
|
final double intervalsY = (0 - touchY) / numberOfFrames;
|
||||||
|
|
||||||
|
for (int i = 0; i < numberOfFrames; i++) {
|
||||||
|
final int j = i;
|
||||||
|
postDelayed(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
touchX += intervalsX;
|
||||||
|
touchY += intervalsY;
|
||||||
|
|
||||||
|
reportOnMoved();
|
||||||
|
invalidate();
|
||||||
|
|
||||||
|
if (moveListener != null && j == numberOfFrames - 1) {
|
||||||
|
moveListener.OnReturnedToCenter();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, i * 40);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (moveListener != null) {
|
||||||
|
moveListener.OnReleased();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTouchOffset(int x, int y) {
|
||||||
|
offsetX = x;
|
||||||
|
offsetY = y;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user