Allow clients to draw carousel cards clockwise
This consists of the following:
- Plumb the new fillDirection parameter
- Set the slotPosition (and consequently the cardPosition)
at the appropriate points
- Compute motion and overscroll based not on first and last
bias but on lowest and highest bias.
- Let cullCards() allow thetaFirst > thetaLast
Bug: 3177563
Change-Id: I2bb7b3f906726db5ced2ea5bad0e5395f5821d1d
diff --git a/carousel/java/com/android/ex/carousel/CarouselController.java b/carousel/java/com/android/ex/carousel/CarouselController.java
index d61e2a7..6a3f3a1 100644
--- a/carousel/java/com/android/ex/carousel/CarouselController.java
+++ b/carousel/java/com/android/ex/carousel/CarouselController.java
@@ -89,6 +89,7 @@
private Bitmap mDetailLoadingBitmap = Bitmap.createBitmap(
new int[] {0}, 0, 1, 1, 1, Bitmap.Config.ARGB_4444);
private int mDragModel = CarouselRS.DRAG_MODEL_SCREEN_DELTA;
+ private int mFillDirection = CarouselRS.FILL_DIRECTION_CCW;
public CarouselController() {
boolean useDepthBuffer = true;
@@ -128,6 +129,7 @@
setFrictionCoefficient(mFrictionCoefficient);
setDragFactor(mDragFactor);
setDragModel(mDragModel);
+ setFillDirection(mFillDirection);
setLookAt(mEye, mAt, mUp);
setRezInCardCount(mRezInCardCount);
setFadeInDuration(mFadeInDuration);
@@ -552,6 +554,18 @@
}
}
+ /** Sets the direction to fill in cards around the carousel.
+ *
+ * @param direction Either {@link CarouselRS#FILL_DIRECTION_CCW} or
+ * {@link CarouselRS#FILL_DIRECTION_CW}.
+ */
+ public void setFillDirection(int direction) {
+ mFillDirection = direction;
+ if (mRenderScript != null) {
+ mRenderScript.setFillDirection(direction);
+ }
+ }
+
public void setCardRotation(float cardRotation) {
mCardRotation = cardRotation;
if (mRenderScript != null) {
diff --git a/carousel/java/com/android/ex/carousel/CarouselRS.java b/carousel/java/com/android/ex/carousel/CarouselRS.java
index b59c0eb..5f99250 100644
--- a/carousel/java/com/android/ex/carousel/CarouselRS.java
+++ b/carousel/java/com/android/ex/carousel/CarouselRS.java
@@ -54,6 +54,9 @@
public static final int DRAG_MODEL_CYLINDER_INSIDE = 2;
public static final int DRAG_MODEL_CYLINDER_OUTSIDE = 3;
+ public static final int FILL_DIRECTION_CCW = +1;
+ public static final int FILL_DIRECTION_CW = -1;
+
private static final String TAG = "CarouselRS";
private static final int DEFAULT_SLOT_COUNT = 10;
private static final boolean MIPMAP = false;
@@ -293,6 +296,10 @@
mScript.set_dragModel(model);
}
+ public void setFillDirection(int direction) {
+ mScript.set_fillDirection(direction);
+ }
+
private void initVertexProgram() {
ProgramVertex.Builder pvb = new ProgramVertex.Builder(mRS, null, null);
mVertexProgram = pvb.create();
diff --git a/carousel/java/com/android/ex/carousel/CarouselView.java b/carousel/java/com/android/ex/carousel/CarouselView.java
index b995060..623fdfc 100644
--- a/carousel/java/com/android/ex/carousel/CarouselView.java
+++ b/carousel/java/com/android/ex/carousel/CarouselView.java
@@ -56,6 +56,10 @@
// Drag relative to projected point on outside (near point) of cylinder centered around carousel
public static final int DRAG_MODEL_CYLINDER_OUTSIDE = CarouselRS.DRAG_MODEL_CYLINDER_OUTSIDE;
+ // Draw cards counterclockwise around the carousel
+ public static final int FILL_DIRECTION_CCW = CarouselRS.FILL_DIRECTION_CCW;
+ // Draw cards clockwise around the carousel
+ public static final int FILL_DIRECTION_CW = CarouselRS.FILL_DIRECTION_CW;
// Note: remember to update carousel.rs when changing the values below
public static class DetailAlignment {
diff --git a/carousel/java/com/android/ex/carousel/carousel.rs b/carousel/java/com/android/ex/carousel/carousel.rs
index 79798b0..73d6bc6 100644
--- a/carousel/java/com/android/ex/carousel/carousel.rs
+++ b/carousel/java/com/android/ex/carousel/carousel.rs
@@ -173,6 +173,7 @@
float rowSpacing; // spacing between rows of cards
int dragModel = DRAG_MODEL_SCREEN_DELTA;
+int fillDirection; // the order in which to lay out cards: +1 for CCW (default), -1 for CW
rs_program_store programStoreAlphaZ;
rs_program_store programStoreAlphaNoZ;
rs_program_store programStoreNoAlphaZ;
@@ -342,7 +343,7 @@
// Return angle of slot in position p.
static float slotPosition(int p)
{
- return startAngle + wedgeAngle(p);
+ return startAngle + wedgeAngle(p) * fillDirection;
}
// Return angle for card in position p.
@@ -351,6 +352,25 @@
return bias + slotPosition(p / rowCount);
}
+// Return the lowest possible bias value, based on the fill direction
+static float minimumBias()
+{
+ const int totalSlots = (cardCount + rowCount - 1) / rowCount;
+ return (fillDirection > 0) ?
+ -max(0.0f, wedgeAngle(totalSlots - visibleDetailCount)) :
+ wedgeAngle(0.0f);
+}
+
+// Return the highest possible bias value, based on the fill direction
+static float maximumBias()
+{
+ const int totalSlots = (cardCount + rowCount - 1) / rowCount;
+ return (fillDirection > 0) ?
+ wedgeAngle(0.0f) :
+ max(0.0f, wedgeAngle(totalSlots - visibleDetailCount));
+}
+
+
// convert from carousel rotation angle (in card slot units) to radians.
static float carouselRotationAngleToRadians(float carouselRotationAngle)
{
@@ -1016,14 +1036,13 @@
void doMotion(float x, float y, long eventTime)
{
- const int totalSlots = (cardCount + rowCount - 1) / rowCount;
- const float firstBias = wedgeAngle(0.0f);
- const float lastBias = -max(0.0f, wedgeAngle(totalSlots - visibleDetailCount));
+ const float highBias = maximumBias();
+ const float lowBias = minimumBias();
float deltaOmega = dragFunction(x, y);
if (!enableSelection) {
bias += deltaOmega;
- bias = clamp(bias, lastBias - wedgeAngle(OVERSCROLL_SLOTS),
- firstBias + wedgeAngle(OVERSCROLL_SLOTS));
+ bias = clamp(bias, lowBias - wedgeAngle(OVERSCROLL_SLOTS),
+ highBias + wedgeAngle(OVERSCROLL_SLOTS));
}
const float2 delta = (float2) { x, y } - touchPosition;
float distance = sqrt(dot(delta, delta));
@@ -1303,22 +1322,21 @@
return true;
}
- const int totalSlots = (cardCount + rowCount - 1) / rowCount;
- const float firstBias = wedgeAngle(0.0f);
- const float lastBias = -max(0.0f, wedgeAngle(totalSlots - visibleDetailCount));
+ const float highBias = maximumBias();
+ const float lowBias = minimumBias();
bool stillAnimating = false;
if (overscroll) {
- if (bias > firstBias) {
- bias -= 4.0f * dt * easeOut((bias - firstBias) * 2.0f);
- if (fabs(bias - firstBias) < biasMin) {
- bias = firstBias;
+ if (bias > highBias) {
+ bias -= 4.0f * dt * easeOut((bias - highBias) * 2.0f);
+ if (fabs(bias - highBias) < biasMin) {
+ bias = highBias;
} else {
stillAnimating = true;
}
- } else if (bias < lastBias) {
- bias += 4.0f * dt * easeOut((lastBias - bias) * 2.0f);
- if (fabs(bias - lastBias) < biasMin) {
- bias = lastBias;
+ } else if (bias < lowBias) {
+ bias += 4.0f * dt * easeOut((lowBias - bias) * 2.0f);
+ if (fabs(bias - lowBias) < biasMin) {
+ bias = lowBias;
} else {
stillAnimating = true;
}
@@ -1327,13 +1345,13 @@
}
} else {
stillAnimating = doPhysics(dt);
- overscroll = bias > firstBias || bias < lastBias;
+ overscroll = bias > highBias || bias < lowBias;
if (overscroll) {
velocity = 0.0f; // prevent bouncing due to v > 0 after overscroll animation.
}
}
- float newbias = clamp(bias, lastBias - wedgeAngle(OVERSCROLL_SLOTS),
- firstBias + wedgeAngle(OVERSCROLL_SLOTS));
+ float newbias = clamp(bias, lowBias - wedgeAngle(OVERSCROLL_SLOTS),
+ highBias + wedgeAngle(OVERSCROLL_SLOTS));
if (newbias != bias) { // we clamped
velocity = 0.0f;
overscroll = true;
@@ -1363,7 +1381,7 @@
if (visibleSlotCount > 0) {
// If visibleSlotCount is specified, then only show up to visibleSlotCount cards.
float p = cardPosition(i);
- if (p >= thetaFirst && p < thetaLast) {
+ if (p >= thetaFirst && p < thetaLast || p <= thetaFirst && p > thetaLast) {
cards[i].cardVisible = true;
// cards[i].detailVisible will be set at draw time
count++;