// Created by plusminus on 11:52:08 - 29.08.2008
package org.androad.ui.common.views;
import org.androad.util.constants.Constants;
import android.content.Context;
import android.graphics.Camera;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
public class RotateView extends ViewGroup implements Constants{
// ===========================================================
// Constants
// ===========================================================
// ===========================================================
// Fields
// ===========================================================
protected static final float SQ2 = 1.414213562373095f;
protected final SmoothCanvas mCanvas = new SmoothCanvas();
protected float mHeading = Constants.NOT_SET;
private final Camera mCamera = new Camera();
private float mLastRefreshPerspectiveAngle = Constants.NOT_SET;
private float mLastRefreshWidth = Constants.NOT_SET;
private float mPerspectiveAngle = 0f;
private final Matrix mPerspectiveMatrix = new Matrix();
// ===========================================================
// Constructors
// ===========================================================
public RotateView(final Context context) {
super(context);
refreshPerspectiveMatrix();
}
public RotateView(final Context context, final AttributeSet attrs) {
super(context, attrs);
refreshPerspectiveMatrix();
}
// ===========================================================
// Getter & Setter
// ===========================================================
public void setPerspectiveEnabled(final boolean pEnable){
this.mPerspectiveAngle = (pEnable) ? -45f : 0f;
}
public boolean setPerspectiveEnabled(){
return this.mPerspectiveAngle == -45f;
}
public void setRotationDegree(final float aHeading) {
this.mHeading = aHeading;
}
public void setPerspectiveAngle(final float pAngle) {
this.mPerspectiveAngle = pAngle;
refreshPerspectiveMatrix();
}
// ===========================================================
// Methods from SuperClass/Interfaces
// ===========================================================
private void refreshPerspectiveMatrix() {
final float w_2 = getWidth() * 0.5f;
final float perspectiveAngle = this.mPerspectiveAngle;
/* Avoid unnecessary updates. */
if(this.mLastRefreshPerspectiveAngle == perspectiveAngle && this.mLastRefreshWidth == w_2) {
return;
}
final float h_2 = getHeight() * 0.5f;
this.mLastRefreshWidth = w_2;
this.mLastRefreshPerspectiveAngle = perspectiveAngle;
final Matrix perspectiveMatrix = this.mPerspectiveMatrix;
final Camera camera = this.mCamera;
// Save the current Camera matrix
camera.save();
// Setup the camera rotations
camera.rotateX(-perspectiveAngle);
// Output the camera rotations to a matrix
camera.getMatrix(perspectiveMatrix);
camera.restore();
if(perspectiveAngle != 0f){
// Perform some other transforms on the matrix
perspectiveMatrix.preTranslate(-w_2, -h_2);
perspectiveMatrix.postTranslate(w_2, h_2);
perspectiveMatrix.postScale(1.3f, 1.3f, w_2, h_2);
}
}
@Override
protected void dispatchDraw(final Canvas canvas) {
canvas.save(Canvas.MATRIX_SAVE_FLAG);
refreshPerspectiveMatrix();
if(this.mPerspectiveAngle != 0f){
// Apply the matrix to the canvas
canvas.concat(this.mPerspectiveMatrix);
}
final float w_2 = getWidth() * 0.5f;
final float h_2 = getHeight() * 0.5f;
if(this.mHeading != Constants.NOT_SET) {
canvas.rotate(-this.mHeading, w_2, h_2); // (this.getRight() - this.getLeft()) * 0.5f, (this.getBottom() - this.getTop()) * 0.5f);
}
this.mCanvas.delegate = canvas;
super.dispatchDraw(this.mCanvas);
canvas.restore();
}
@Override
protected void onLayout(final boolean changed, final int l, final int t, final int r, final int b) {
final int width = this.getRight() - this.getLeft();
final int height = this.getBottom() - this.getTop();
final int count = getChildCount();
for (int i = 0; i < count; i++) {
final View view = getChildAt(i);
final int childWidth = view.getMeasuredWidth();
final int childHeight = view.getMeasuredHeight();
final int childLeft = (width - childWidth) / 2;
final int childTop = (height - childHeight) / 2;
view.layout(childLeft, childTop, childLeft + childWidth, childTop + childHeight);
}
}
@Override
protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) {
final int w = getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec);
final int h = getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec);
final int sizeSpec;
if (w > h) {
sizeSpec = MeasureSpec.makeMeasureSpec((int) (w * SQ2), MeasureSpec.EXACTLY);
} else {
sizeSpec = MeasureSpec.makeMeasureSpec((int) (h * SQ2), MeasureSpec.EXACTLY);
}
final int count = getChildCount();
for (int i = 0; i < count; i++) {
getChildAt(i).measure(sizeSpec, sizeSpec);
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
private static final int X = 0;
private static final int Y = 1;
@Override
public boolean dispatchTouchEvent(final MotionEvent ev) {
if(this.mHeading == Constants.NOT_SET) {
return super.dispatchTouchEvent(ev);
}
final float[] pts = {ev.getX(), ev.getY()};
final Matrix m = new Matrix();
m.setRotate(this.mHeading);
m.mapPoints(pts);
ev.setLocation(pts[X], pts[Y]);
return super.dispatchTouchEvent(ev);
}
// ===========================================================
// Methods
// ===========================================================
// ===========================================================
// Inner and Anonymous Classes
// ===========================================================
}