diff options
author | Michael Kolb <kolby@google.com> | 2012-04-10 10:50:06 -0700 |
---|---|---|
committer | Michael Kolb <kolby@google.com> | 2012-04-11 16:22:56 -0700 |
commit | 80f750852edf43c6b09e5633f2c6ebdb2ed94a5b (patch) | |
tree | 03c7221422487fe91567b270200de3768a9bf800 /src/com/android/browser/view | |
parent | 9faa676ad7191d746b186c6b86a727c8fc9241f2 (diff) | |
download | packages_apps_Browser-80f750852edf43c6b09e5633f2c6ebdb2ed94a5b.zip packages_apps_Browser-80f750852edf43c6b09e5633f2c6ebdb2ed94a5b.tar.gz packages_apps_Browser-80f750852edf43c6b09e5633f2c6ebdb2ed94a5b.tar.bz2 |
Submenus in QuickControls
Change-Id: I5d4fe7fdac1fb58e2e89afe00c468eed632428db
Diffstat (limited to 'src/com/android/browser/view')
-rw-r--r-- | src/com/android/browser/view/PieItem.java | 72 | ||||
-rw-r--r-- | src/com/android/browser/view/PieMenu.java | 285 | ||||
-rw-r--r-- | src/com/android/browser/view/PieStackView.java | 2 |
3 files changed, 293 insertions, 66 deletions
diff --git a/src/com/android/browser/view/PieItem.java b/src/com/android/browser/view/PieItem.java index 3674447..9e04ecb 100644 --- a/src/com/android/browser/view/PieItem.java +++ b/src/com/android/browser/view/PieItem.java @@ -16,10 +16,12 @@ package com.android.browser.view; +import android.view.View; + import com.android.browser.view.PieMenu.PieView; -import android.graphics.Path; -import android.view.View; +import java.util.ArrayList; +import java.util.List; /** * Pie menu item @@ -31,20 +33,66 @@ public class PieItem { private int level; private float start; private float sweep; + private float animate; private int inner; private int outer; private boolean mSelected; - private Path mPath; + private boolean mEnabled; + private List<PieItem> mItems; public PieItem(View view, int level) { mView = view; this.level = level; + mEnabled = true; + setAnimationAngle(getAnimationAngle()); + setAlpha(getAlpha()); } public PieItem(View view, int level, PieView sym) { mView = view; this.level = level; mPieView = sym; + mEnabled = false; + } + + public boolean hasItems() { + return mItems != null; + } + + public List<PieItem> getItems() { + return mItems; + } + + public void addItem(PieItem item) { + if (mItems == null) { + mItems = new ArrayList<PieItem>(); + } + mItems.add(item); + } + + public void setAlpha(float alpha) { + if (mView != null) { + mView.setAlpha(alpha); + } + } + + public float getAlpha() { + if (mView != null) { + return mView.getAlpha(); + } + return 1; + } + + public void setAnimationAngle(float a) { + animate = a; + } + + public float getAnimationAngle() { + return animate; + } + + public void setEnabled(boolean enabled) { + mEnabled = enabled; } public void setSelected(boolean s) { @@ -62,18 +110,21 @@ public class PieItem { return level; } - public void setGeometry(float st, float sw, int inside, int outside, Path p) { + public void setGeometry(float st, float sw, int inside, int outside) { start = st; sweep = sw; inner = inside; outer = outside; - mPath = p; } - public float getStartAngle() { + public float getStart() { return start; } + public float getStartAngle() { + return start + animate; + } + public float getSweep() { return sweep; } @@ -99,11 +150,10 @@ public class PieItem { } public PieView getPieView() { - return mPieView; - } - - public Path getPath() { - return mPath; + if (mEnabled) { + return mPieView; + } + return null; } } diff --git a/src/com/android/browser/view/PieMenu.java b/src/com/android/browser/view/PieMenu.java index 7f8dd6b..1fd0e99 100644 --- a/src/com/android/browser/view/PieMenu.java +++ b/src/com/android/browser/view/PieMenu.java @@ -16,8 +16,11 @@ package com.android.browser.view; -import com.android.browser.R; - +import android.animation.Animator; +import android.animation.Animator.AnimatorListener; +import android.animation.AnimatorListenerAdapter; +import android.animation.ValueAnimator; +import android.animation.ValueAnimator.AnimatorUpdateListener; import android.content.Context; import android.content.res.Resources; import android.graphics.Canvas; @@ -34,12 +37,15 @@ import android.view.View; import android.view.ViewGroup; import android.widget.FrameLayout; +import com.android.browser.R; + import java.util.ArrayList; import java.util.List; public class PieMenu extends FrameLayout { private static final int MAX_LEVELS = 5; + private static final long ANIMATION = 80; public interface PieController { /** @@ -47,6 +53,8 @@ public class PieMenu extends FrameLayout { * returns if pie state has been changed */ public boolean onOpen(); + public void stopEditingUrl(); + } /** @@ -74,6 +82,7 @@ public class PieMenu extends FrameLayout { private int mRadiusInc; private int mSlop; private int mTouchOffset; + private Path mPath; private boolean mOpen; private PieController mController; @@ -83,14 +92,20 @@ public class PieMenu extends FrameLayout { private int[] mCounts; private PieView mPieView = null; + // sub menus + private List<PieItem> mCurrentItems; + private PieItem mOpenItem; + private Drawable mBackground; private Paint mNormalPaint; private Paint mSelectedPaint; + private Paint mSubPaint; // touch handling - PieItem mCurrentItem; + private PieItem mCurrentItem; private boolean mUseBackground; + private boolean mAnimating; /** * @param context @@ -139,6 +154,9 @@ public class PieMenu extends FrameLayout { mSelectedPaint = new Paint(); mSelectedPaint.setColor(res.getColor(R.color.qc_selected)); mSelectedPaint.setAntiAlias(true); + mSubPaint = new Paint(); + mSubPaint.setAntiAlias(true); + mSubPaint.setColor(res.getColor(R.color.qc_sub)); } public void setController(PieController ctl) { @@ -176,18 +194,39 @@ public class PieMenu extends FrameLayout { private void show(boolean show) { mOpen = show; if (mOpen) { + mController.stopEditingUrl(); + mCurrentItems = mItems; if (mController != null) { boolean changed = mController.onOpen(); } layoutPie(); + animateOpen(); } if (!show) { + mAnimating = false; mCurrentItem = null; + mOpenItem = null; mPieView = null; } invalidate(); } + private void animateOpen() { + ValueAnimator anim = ValueAnimator.ofFloat(0, 1); + anim.addUpdateListener(new AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animation) { + for (PieItem item : mCurrentItems) { + item.setAnimationAngle((1 - animation.getAnimatedFraction()) * (- item.getStart())); + } + invalidate(); + } + + }); + anim.setDuration(2*ANIMATION); + anim.start(); + } + private void setCenter(int x, int y) { if (x < mSlop) { mCenter.x = 0; @@ -202,33 +241,32 @@ public class PieMenu extends FrameLayout { int rgap = 2; int inner = mRadius + rgap; int outer = mRadius + mRadiusInc - rgap; - int radius = mRadius; int gap = 1; for (int i = 0; i < mLevels; i++) { int level = i + 1; float sweep = (float) (Math.PI - 2 * emptyangle) / mCounts[level]; float angle = emptyangle + sweep / 2; - for (PieItem item : mItems) { + mPath = makeSlice(getDegrees(0) - gap, getDegrees(sweep) + gap, outer, inner, mCenter); + for (PieItem item : mCurrentItems) { if (item.getLevel() == level) { View view = item.getView(); - view.measure(view.getLayoutParams().width, - view.getLayoutParams().height); - int w = view.getMeasuredWidth(); - int h = view.getMeasuredHeight(); - int r = inner + (outer - inner) * 2 / 3; - int x = (int) (r * Math.sin(angle)); - int y = mCenter.y - (int) (r * Math.cos(angle)) - h / 2; - if (onTheLeft()) { - x = mCenter.x + x - w / 2; - } else { - x = mCenter.x - x - w / 2; + if (view != null) { + view.measure(view.getLayoutParams().width, + view.getLayoutParams().height); + int w = view.getMeasuredWidth(); + int h = view.getMeasuredHeight(); + int r = inner + (outer - inner) * 2 / 3; + int x = (int) (r * Math.sin(angle)); + int y = mCenter.y - (int) (r * Math.cos(angle)) - h / 2; + if (onTheLeft()) { + x = mCenter.x + x - w / 2; + } else { + x = mCenter.x - x - w / 2; + } + view.layout(x, y, x + w, y + h); } - view.layout(x, y, x + w, y + h); float itemstart = angle - sweep / 2; - Path slice = makeSlice(getDegrees(itemstart) - gap, - getDegrees(itemstart + sweep) + gap, - outer, inner, mCenter); - item.setGeometry(itemstart, sweep, inner, outer, slice); + item.setGeometry(itemstart, sweep, inner, outer); angle += sweep; } } @@ -266,15 +304,18 @@ public class PieMenu extends FrameLayout { mBackground.draw(canvas); canvas.restoreToCount(state); } - for (PieItem item : mItems) { - Paint p = item.isSelected() ? mSelectedPaint : mNormalPaint; - state = canvas.save(); - if (onTheLeft()) { - canvas.scale(-1, 1); + // draw base menu + PieItem last = mCurrentItem; + if (mOpenItem != null) { + last = mOpenItem; + } + for (PieItem item : mCurrentItems) { + if (item != last) { + drawItem(canvas, item); } - drawPath(canvas, item.getPath(), p); - canvas.restoreToCount(state); - drawItem(canvas, item); + } + if (last != null) { + drawItem(canvas, last); } if (mPieView != null) { mPieView.draw(canvas); @@ -283,19 +324,26 @@ public class PieMenu extends FrameLayout { } private void drawItem(Canvas canvas, PieItem item) { - int outer = item.getOuterRadius(); - int left = mCenter.x - outer; - int top = mCenter.y - outer; - // draw the item view - View view = item.getView(); - int state = canvas.save(); - canvas.translate(view.getX(), view.getY()); - view.draw(canvas); - canvas.restoreToCount(state); - } - - private void drawPath(Canvas canvas, Path path, Paint paint) { - canvas.drawPath(path, paint); + if (item.getView() != null) { + Paint p = item.isSelected() ? mSelectedPaint : mNormalPaint; + if (!mItems.contains(item)) { + p = item.isSelected() ? mSelectedPaint : mSubPaint; + } + int state = canvas.save(); + if (onTheLeft()) { + canvas.scale(-1, 1); + } + float r = getDegrees(item.getStartAngle()) - 270; // degrees(0) + canvas.rotate(r, mCenter.x, mCenter.y); + canvas.drawPath(mPath, p); + canvas.restoreToCount(state); + // draw the item view + View view = item.getView(); + state = canvas.save(); + canvas.translate(view.getX(), view.getY()); + view.draw(canvas); + canvas.restoreToCount(state); + } } private Path makeSlice(float start, float end, int outer, int inner, Point center) { @@ -332,9 +380,11 @@ public class PieMenu extends FrameLayout { handled = mPieView.onTouchEvent(evt); } PieItem item = mCurrentItem; - deselect(); + if (!mAnimating) { + deselect(); + } show(false); - if (!handled && (item != null)) { + if (!mAnimating && !handled && (item != null) && (item.getView() != null)) { item.getView().performClick(); } return true; @@ -343,9 +393,13 @@ public class PieMenu extends FrameLayout { if (mOpen) { show(false); } - deselect(); + if (!mAnimating) { + deselect(); + invalidate(); + } return false; } else if (MotionEvent.ACTION_MOVE == action) { + if (mAnimating) return false; boolean handled = false; PointF polar = getPolar(x, y); int maxr = mRadius + mLevels * mRadiusInc + 50; @@ -356,6 +410,15 @@ public class PieMenu extends FrameLayout { invalidate(); return false; } + if (polar.y < mRadius) { + if (mOpenItem != null) { + closeSub(); + } else if (!mAnimating) { + deselect(); + invalidate(); + } + return false; + } if (polar.y > maxr) { deselect(); show(false); @@ -366,9 +429,10 @@ public class PieMenu extends FrameLayout { return false; } PieItem item = findItem(polar); - if (mCurrentItem != item) { + if (item == null) { + } else if (mCurrentItem != item) { onEnter(item); - if ((item != null) && item.isPieView()) { + if ((item != null) && item.isPieView() && (item.getView() != null)) { int cx = item.getView().getLeft() + (onTheLeft() ? item.getView().getWidth() : 0); int cy = item.getView().getTop(); @@ -402,14 +466,125 @@ public class PieMenu extends FrameLayout { playSoundEffect(SoundEffectConstants.CLICK); item.setSelected(true); mPieView = null; + mCurrentItem = item; + if ((mCurrentItem != mOpenItem) && mCurrentItem.hasItems()) { + openSub(mCurrentItem); + mOpenItem = item; + } + } else { + mCurrentItem = null; } - mCurrentItem = item; + + } + + private void animateOut(final PieItem fixed, AnimatorListener listener) { + if ((mCurrentItems == null) || (fixed == null)) return; + final float target = fixed.getStartAngle(); + ValueAnimator anim = ValueAnimator.ofFloat(0, 1); + anim.addUpdateListener(new AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animation) { + for (PieItem item : mCurrentItems) { + if (item != fixed) { + item.setAnimationAngle(animation.getAnimatedFraction() + * (target - item.getStart())); + } + } + invalidate(); + } + }); + anim.setDuration(ANIMATION); + anim.addListener(listener); + anim.start(); + } + + private void animateIn(final PieItem fixed, AnimatorListener listener) { + if ((mCurrentItems == null) || (fixed == null)) return; + final float target = fixed.getStartAngle(); + ValueAnimator anim = ValueAnimator.ofFloat(0, 1); + anim.addUpdateListener(new AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animation) { + for (PieItem item : mCurrentItems) { + if (item != fixed) { + item.setAnimationAngle((1 - animation.getAnimatedFraction()) + * (target - item.getStart())); + } + } + invalidate(); + + } + + }); + anim.setDuration(ANIMATION); + anim.addListener(listener); + anim.start(); + } + + private void openSub(final PieItem item) { + mAnimating = true; + animateOut(item, new AnimatorListenerAdapter() { + public void onAnimationEnd(Animator a) { + for (PieItem item : mCurrentItems) { + item.setAnimationAngle(0); + } + mCurrentItems = new ArrayList<PieItem>(mItems.size()); + int i = 0, j = 0; + while (i < mItems.size()) { + if (mItems.get(i) == item) { + mCurrentItems.add(item); + } else { + mCurrentItems.add(item.getItems().get(j++)); + } + i++; + } + layoutPie(); + animateIn(item, new AnimatorListenerAdapter() { + public void onAnimationEnd(Animator a) { + for (PieItem item : mCurrentItems) { + item.setAnimationAngle(0); + } + mAnimating = false; + } + }); + } + }); + } + + private void closeSub() { + mAnimating = true; + if (mCurrentItem != null) { + mCurrentItem.setSelected(false); + } + animateOut(mOpenItem, new AnimatorListenerAdapter() { + public void onAnimationEnd(Animator a) { + for (PieItem item : mCurrentItems) { + item.setAnimationAngle(0); + } + mCurrentItems = mItems; + mPieView = null; + animateIn(mOpenItem, new AnimatorListenerAdapter() { + public void onAnimationEnd(Animator a) { + for (PieItem item : mCurrentItems) { + item.setAnimationAngle(0); + } + mAnimating = false; + mOpenItem = null; + mCurrentItem = null; + } + }); + } + }); } private void deselect() { if (mCurrentItem != null) { mCurrentItem.setSelected(false); } + if (mOpenItem != null) { + mOpenItem = null; + mCurrentItems = mItems; + } mCurrentItem = null; mPieView = null; } @@ -439,15 +614,19 @@ public class PieMenu extends FrameLayout { */ private PieItem findItem(PointF polar) { // find the matching item: - for (PieItem item : mItems) { - if ((item.getInnerRadius() - mTouchOffset < polar.y) - && (item.getOuterRadius() - mTouchOffset > polar.y) - && (item.getStartAngle() < polar.x) - && (item.getStartAngle() + item.getSweep() > polar.x)) { + for (PieItem item : mCurrentItems) { + if (inside(polar, mTouchOffset, item)) { return item; } } return null; } + private boolean inside(PointF polar, float offset, PieItem item) { + return (item.getInnerRadius() - offset < polar.y) + && (item.getOuterRadius() - offset > polar.y) + && (item.getStartAngle() < polar.x) + && (item.getStartAngle() + item.getSweep() > polar.x); + } + } diff --git a/src/com/android/browser/view/PieStackView.java b/src/com/android/browser/view/PieStackView.java index 16d42cb..e1f41bd 100644 --- a/src/com/android/browser/view/PieStackView.java +++ b/src/com/android/browser/view/PieStackView.java @@ -50,8 +50,6 @@ public class PieStackView extends BasePieView { super.setCurrent(ix); if (mCurrentListener != null) { mCurrentListener.onSetCurrent(ix); - buildViews(); - layoutChildrenLinear(); } } |