| 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; |
| } |
| } |
| } |