blob: c12dce9c00ee4b26042ad7c23c8ff40e8103cd65 [file] [log] [blame]
package com.android.camera.ui;
import android.graphics.Rect;
import android.view.View.MeasureSpec;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.AnimationSet;
import android.view.animation.OvershootInterpolator;
import android.view.animation.ScaleAnimation;
import javax.microedition.khronos.opengles.GL11;
public class PopupWindow extends GLView {
protected Texture mAnchor;
protected int mAnchorOffset;
protected int mAnchorPosition;
private final RotatePane mRotatePane = new RotatePane();
private RawTexture mBackupTexture;
protected FrameTexture mBackground;
private boolean mUsingStencil;
public PopupWindow() {
super.addComponent(mRotatePane);
}
@Override
protected void onAttachToRoot(GLRootView root) {
super.onAttachToRoot(root);
mUsingStencil = root.getEGLConfigChooser().getStencilBits() > 0;
}
public void setBackground(FrameTexture background) {
if (background == mBackground) return;
mBackground = background;
if (background != null) {
setPaddings(mBackground.getPaddings());
} else {
setPaddings(0, 0, 0, 0);
}
invalidate();
}
public void setAnchor(Texture anchor, int offset) {
mAnchor = anchor;
mAnchorOffset = offset;
}
@Override
public void addComponent(GLView component) {
throw new UnsupportedOperationException("use setContent(GLView)");
}
@Override
protected void onMeasure(int widthSpec, int heightSpec) {
int widthMode = MeasureSpec.getMode(widthSpec);
if (widthMode != MeasureSpec.UNSPECIFIED) {
Rect p = mPaddings;
int width = MeasureSpec.getSize(widthSpec);
widthSpec = MeasureSpec.makeMeasureSpec(
Math.max(0, width - p.left - p.right
- mAnchor.getWidth() + mAnchorOffset), widthMode);
}
int heightMode = MeasureSpec.getMode(heightSpec);
if (heightMode != MeasureSpec.UNSPECIFIED) {
int height = MeasureSpec.getSize(widthSpec);
widthSpec = MeasureSpec.makeMeasureSpec(Math.max(
0, height - mPaddings.top - mPaddings.bottom), heightMode);
}
Rect p = mPaddings;
GLView child = mRotatePane;
child.measure(widthSpec, heightSpec);
setMeasuredSize(child.getMeasuredWidth()
+ p.left + p.right + mAnchor.getWidth() - mAnchorOffset,
child.getMeasuredHeight() + p.top + p.bottom);
}
@Override
protected void onLayout(
boolean change, int left, int top, int right, int bottom) {
Rect p = getPaddings();
GLView view = mRotatePane;
view.layout(p.left, p.top,
getWidth() - p.right - mAnchor.getWidth() + mAnchorOffset,
getHeight() - p.bottom);
}
public void setAnchorPosition(int yoffset) {
mAnchorPosition = yoffset;
}
private void renderBackgroundWithStencil(GLRootView root, GL11 gl) {
int width = getWidth();
int height = getHeight();
int aWidth = mAnchor.getWidth();
int aHeight = mAnchor.getHeight();
Rect p = mPaddings;
int aXoffset = width - aWidth;
int aYoffset = Math.max(p.top, mAnchorPosition - aHeight / 2);
aYoffset = Math.min(aYoffset, height - p.bottom - aHeight);
if (mAnchor != null) {
gl.glStencilOp(GL11.GL_KEEP, GL11.GL_KEEP, GL11.GL_REPLACE);
gl.glStencilFunc(GL11.GL_ALWAYS, 1, 1);
mAnchor.draw(root, aXoffset, aYoffset);
gl.glStencilFunc(GL11.GL_NOTEQUAL, 1, 1);
gl.glStencilOp(GL11.GL_KEEP, GL11.GL_KEEP, GL11.GL_KEEP);
}
if (mBackground != null) {
mBackground.setSize(width - aWidth + mAnchorOffset, height);
mBackground.draw(root, 0, 0);
}
}
private void renderBackgroundWithoutStencil(GLRootView root, GL11 gl) {
int width = getWidth();
int height = getHeight();
int aWidth = mAnchor.getWidth();
int aHeight = mAnchor.getHeight();
Rect p = mPaddings;
int aXoffset = width - aWidth;
int aYoffset = Math.max(p.top, mAnchorPosition - aHeight / 2);
aYoffset = Math.min(aYoffset, height - p.bottom - aHeight);
if (mAnchor != null) {
mAnchor.draw(root, aXoffset, aYoffset);
}
if (mBackupTexture == null || mBackupTexture.getBoundGL() != gl) {
mBackupTexture = RawTexture.newInstance(gl);
}
RawTexture backup = mBackupTexture;
try {
// Copy the current drawing results of the triangle area into
// "backup", so that we can restore the content after it is
// overlaid by the background.
root.copyTexture2D(backup, aXoffset, aYoffset, aWidth, aHeight);
} catch (GLOutOfMemoryException e) {
e.printStackTrace();
}
if (mBackground != null) {
mBackground.setSize(width - aWidth + mAnchorOffset, height);
mBackground.draw(root, 0, 0);
}
gl.glBlendFunc(GL11.GL_ONE, GL11.GL_ZERO);
backup.draw(root, aXoffset, aYoffset, aWidth, aHeight, 1);
gl.glBlendFunc(GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA);
}
@Override
protected void renderBackground(GLRootView root, GL11 gl) {
if (mUsingStencil) {
renderBackgroundWithStencil(root, gl);
} else {
renderBackgroundWithoutStencil(root, gl);
}
}
public void setContent(GLView content) {
mRotatePane.setContent(content);
}
@Override
public void clearComponents() {
throw new UnsupportedOperationException();
}
public void popup() {
setVisibility(GLView.VISIBLE);
AnimationSet set = new AnimationSet(false);
Animation scale = new ScaleAnimation(
0.7f, 1f, 0.7f, 1f, getWidth(), mAnchorPosition);
Animation alpha = new AlphaAnimation(0.5f, 1.0f);
set.addAnimation(scale);
set.addAnimation(alpha);
scale.setDuration(150);
alpha.setDuration(100);
scale.setInterpolator(new OvershootInterpolator());
startAnimation(set);
}
public void popoff() {
setVisibility(GLView.INVISIBLE);
Animation alpha = new AlphaAnimation(0.7f, 0.0f);
alpha.setDuration(100);
startAnimation(alpha);
}
public void setOrientation(int orientation) {
switch (orientation) {
case 90:
mRotatePane.setOrientation(RotatePane.LEFT);
break;
case 180:
mRotatePane.setOrientation(RotatePane.DOWN);
break;
case 270:
mRotatePane.setOrientation(RotatePane.RIGHT);
break;
default:
mRotatePane.setOrientation(RotatePane.UP);
break;
}
}
}