/* Original code taken from https://github.com/efficientisoceles/JoystickView Licenced under the terms of the GNU General Public License version 3 Copyright (C) Daniel Su */ package nodomain.freeyourgadget.gadgetbridge.devices.supercars; import android.content.Context; import android.graphics.Canvas; import android.graphics.Paint; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.SurfaceHolder; import android.view.SurfaceView; import android.view.View; import nodomain.freeyourgadget.gadgetbridge.GBApplication; import nodomain.freeyourgadget.gadgetbridge.R; public class JoystickView extends SurfaceView implements SurfaceHolder.Callback, View.OnTouchListener { private float centerX; private float centerY; private float baseRadius; private float hatRadius; private JoystickListener joystickCallback; private final int ratio = 5; private void setupDimensions() { centerX = getWidth() / 2; centerY = getHeight() / 2; baseRadius = Math.min(getWidth(), getHeight()) / 3; hatRadius = Math.min(getWidth(), getHeight()) / 5; } public JoystickView(Context context) { super(context); getHolder().addCallback(this); setOnTouchListener(this); if (context instanceof JoystickListener) joystickCallback = (JoystickListener) context; } public JoystickView(Context context, AttributeSet attributes, int style) { super(context, attributes, style); getHolder().addCallback(this); setOnTouchListener(this); if (context instanceof JoystickListener) joystickCallback = (JoystickListener) context; } public JoystickView(Context context, AttributeSet attributes) { super(context, attributes); getHolder().addCallback(this); setOnTouchListener(this); if (context instanceof JoystickListener) joystickCallback = (JoystickListener) context; } private void drawJoystick(float newX, float newY) { if (getHolder().getSurface().isValid()) { Canvas myCanvas = this.getHolder().lockCanvas(); Paint colors = new Paint(); myCanvas.drawColor(GBApplication.getWindowBackgroundColor(getContext())); float hypotenuse = (float) Math.sqrt(Math.pow(newX - centerX, 2) + Math.pow(newY - centerY, 2)); float sin = (newY - centerY) / hypotenuse; //sin = o/h float cos = (newX - centerX) / hypotenuse; //cos = a/h colors.setColor(this.getResources().getColor(R.color.primarydark_light)); myCanvas.drawCircle(centerX, centerY, baseRadius, colors); colors.setColor(this.getResources().getColor(R.color.chart_deep_sleep_light)); myCanvas.drawCircle(newX - cos * hypotenuse * (ratio / baseRadius) * 30, newY - sin * hypotenuse * (ratio / baseRadius) * 30, 100, colors); colors.setColor(this.getResources().getColor(R.color.accent)); myCanvas.drawCircle(newX, newY, hatRadius, colors); getHolder().unlockCanvasAndPost(myCanvas); } } @Override public void surfaceCreated(SurfaceHolder holder) { setupDimensions(); drawJoystick(centerX, centerY); } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { } @Override public void surfaceDestroyed(SurfaceHolder holder) { } public boolean onTouch(View v, MotionEvent e) { if (v.equals(this)) { if (e.getAction() != MotionEvent.ACTION_UP) { float displacement = (float) Math.sqrt((Math.pow(e.getX() - centerX, 2)) + Math.pow(e.getY() - centerY, 2)); if (displacement < baseRadius) { drawJoystick(e.getX(), e.getY()); joystickCallback.onJoystickMoved((e.getX() - centerX) / baseRadius, (e.getY() - centerY) / baseRadius, getId()); } else { float ratio = baseRadius / displacement; float constrainedX = centerX + (e.getX() - centerX) * ratio; float constrainedY = centerY + (e.getY() - centerY) * ratio; drawJoystick(constrainedX, constrainedY); joystickCallback.onJoystickMoved((constrainedX - centerX) / baseRadius, (constrainedY - centerY) / baseRadius, getId()); } } else if (e.getAction() == MotionEvent.ACTION_UP) { drawJoystick(centerX, centerY); joystickCallback.onJoystickMoved(0, 0, getId()); } else drawJoystick(centerX, centerY); //joystickCallback.onJoystickMoved(0, 0, getId()); } return true; } public interface JoystickListener { void onJoystickMoved(float xPercent, float yPercent, int id); } }