package com.openrobot.common;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Handler;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
public class ThumbBall extends View implements OnTouchListener {
public final static int FRAME_WIDTH = 250;
public final static int FRAME_HEIGHT = 250;
private float x;
private float y;
private int r;
private boolean isTouching = false;
private Paint circlePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
private Paint linePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
private Handler reboundHandler = new Handler();
private Runnable mUpdateTimeTask;
private ThumbBallListener delegate;
public ThumbBall(Context context, float x, float y, int r) {
super(context);
constructUpdateTimeTask();
this.setOnTouchListener(this);
circlePaint.setColor(Color.CYAN);
linePaint.setColor(Color.MAGENTA);
this.x = x;
this.y = y;
this.r = r;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawCircle(x, y, r, circlePaint);
canvas.drawLine(FRAME_WIDTH / 2, 0, FRAME_WIDTH / 2, FRAME_HEIGHT, linePaint);
canvas.drawLine(0, FRAME_HEIGHT / 2, FRAME_WIDTH, FRAME_HEIGHT / 2, linePaint);
}
public boolean onTouch(View v, MotionEvent e) {
float touchX = e.getX();
float touchY = e.getY();
switch (e.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
reboundHandler.removeCallbacks(mUpdateTimeTask);
break;
case MotionEvent.ACTION_UP:
//case MotionEvent.ACTION_POINTER_UP:
if (isTouching) {
reboundHandler.removeCallbacks(mUpdateTimeTask);
reboundHandler.postDelayed(mUpdateTimeTask, 100);
}
isTouching = false;
break;
case MotionEvent.ACTION_MOVE:
isTouching = true;
if (GeometryHelper.inCircle(this.x, this.y, this.r, touchX, touchY) &&
touchX >= 0 &&
touchX <= FRAME_WIDTH &&
touchY >= 0 &&
touchY <= FRAME_HEIGHT) {
this.x = touchX;
this.y = touchY;
this.invalidate();
updateDelegate();
}
break;
}
return true;
}
public void zeroThumbBallPosition() {
this.x = boxCenterX();
this.y = boxCenterY();
}
private void updateDelegate() {
if (delegate != null) {
delegate.thumbBallPositionChanged(this);
}
}
private void constructUpdateTimeTask() {
mUpdateTimeTask = new Runnable() {
public void run() {
int transX = translatedX((int)getX());
int transY = translatedY((int)getY());
if (GeometryHelper.dist(0, 0, transX, transY) > getR() / 3) {
int newTransX = transX -= transX / 10;
int newTransY = transY -= transY / 10;
setX(reTranslatedX(newTransX));
setY(reTranslatedY(newTransY));
invalidate(); // given the scope does this get called on the proper instance of ThumbBall???
reboundHandler.postDelayed(mUpdateTimeTask, 50);
} else {
reboundHandler.removeCallbacks(mUpdateTimeTask);
setX(reTranslatedX(0));
setY(reTranslatedY(0));
invalidate(); // given the scope does this get called on the proper instance of ThumbBall???
}
updateDelegate();
}
};
}
public ThumbBallListener getDelegate() {
return delegate;
}
public void setDelegate(ThumbBallListener delegate) {
this.delegate = delegate;
}
public float getScaledY(float scale) {
return y * scale;
}
public float getX() {
return x;
}
public void setX(float x) {
this.x = x;
}
public float getY() {
return y;
}
public void setY(float y) {
this.y = y;
}
public int getR() {
return r;
}
public void setR(int r) {
this.r = r;
}
public boolean isTouching() {
return isTouching;
}
public void setTouching(boolean isTouching) {
this.isTouching = isTouching;
}
public Paint getCirclePaint() {
return circlePaint;
}
public void setCirclePaint(Paint circlePaint) {
this.circlePaint = circlePaint;
}
public Paint getLinePaint() {
return linePaint;
}
public void setLinePaint(Paint linePaint) {
this.linePaint = linePaint;
}
private int boxCenterX() {
return FRAME_WIDTH / 2;
}
private int boxCenterY() {
return FRAME_HEIGHT / 2;
}
public int translatedX() {
return this.translatedX((int)this.x);
}
public int translatedY() {
return this.translatedY((int)this.y);
}
public int translatedX(int oldX) {
return oldX - this.boxCenterX();
}
public int translatedY(int oldY) {
return oldY - this.boxCenterY();
}
public int reTranslatedX(int newX) {
return newX + this.boxCenterX();
}
public int reTranslatedY(int newY) {
return newY + this.boxCenterY();
}
public float translatedX(float oldX) {
return oldX - ((float)this.boxCenterX());
}
public float translatedY(float oldY) {
return oldY - ((float)this.boxCenterY());
}
public float reTranslatedX(float newX) {
return newX + this.boxCenterX();
}
public float reTranslatedY(float newY) {
return newY + this.boxCenterY();
}
}