1/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.gallery3d.ui;
18
19import android.content.Context;
20import android.opengl.Matrix;
21
22import com.android.gallery3d.glrenderer.GLCanvas;
23
24// EdgeView draws EdgeEffect (blue glow) at four sides of the view.
25public class EdgeView extends GLView {
26    @SuppressWarnings("unused")
27    private static final String TAG = "EdgeView";
28
29    public static final int INVALID_DIRECTION = -1;
30    public static final int TOP = 0;
31    public static final int LEFT = 1;
32    public static final int BOTTOM = 2;
33    public static final int RIGHT = 3;
34
35    // Each edge effect has a transform matrix, and each matrix has 16 elements.
36    // We put all the elements in one array. These constants specify the
37    // starting index of each matrix.
38    private static final int TOP_M = TOP * 16;
39    private static final int LEFT_M = LEFT * 16;
40    private static final int BOTTOM_M = BOTTOM * 16;
41    private static final int RIGHT_M = RIGHT * 16;
42
43    private EdgeEffect[] mEffect = new EdgeEffect[4];
44    private float[] mMatrix = new float[4 * 16];
45
46    public EdgeView(Context context) {
47        for (int i = 0; i < 4; i++) {
48            mEffect[i] = new EdgeEffect(context);
49        }
50    }
51
52    @Override
53    protected void onLayout(
54            boolean changeSize, int left, int top, int right, int bottom) {
55        if (!changeSize) return;
56
57        int w = right - left;
58        int h = bottom - top;
59        for (int i = 0; i < 4; i++) {
60            if ((i & 1) == 0) {  // top or bottom
61                mEffect[i].setSize(w, h);
62            } else {  // left or right
63                mEffect[i].setSize(h, w);
64            }
65        }
66
67        // Set up transforms for the four edges. Without transforms an
68        // EdgeEffect draws the TOP edge from (0, 0) to (w, Y * h) where Y
69        // is some factor < 1. For other edges we need to move, rotate, and
70        // flip the effects into proper places.
71        Matrix.setIdentityM(mMatrix, TOP_M);
72        Matrix.setIdentityM(mMatrix, LEFT_M);
73        Matrix.setIdentityM(mMatrix, BOTTOM_M);
74        Matrix.setIdentityM(mMatrix, RIGHT_M);
75
76        Matrix.rotateM(mMatrix, LEFT_M, 90, 0, 0, 1);
77        Matrix.scaleM(mMatrix, LEFT_M, 1, -1, 1);
78
79        Matrix.translateM(mMatrix, BOTTOM_M, 0, h, 0);
80        Matrix.scaleM(mMatrix, BOTTOM_M, 1, -1, 1);
81
82        Matrix.translateM(mMatrix, RIGHT_M, w, 0, 0);
83        Matrix.rotateM(mMatrix, RIGHT_M, 90, 0, 0, 1);
84    }
85
86    @Override
87    protected void render(GLCanvas canvas) {
88        super.render(canvas);
89        boolean more = false;
90        for (int i = 0; i < 4; i++) {
91            canvas.save(GLCanvas.SAVE_FLAG_MATRIX);
92            canvas.multiplyMatrix(mMatrix, i * 16);
93            more |= mEffect[i].draw(canvas);
94            canvas.restore();
95        }
96        if (more) {
97            invalidate();
98        }
99    }
100
101    // Called when the content is pulled away from the edge.
102    // offset is in pixels. direction is one of {TOP, LEFT, BOTTOM, RIGHT}.
103    public void onPull(int offset, int direction) {
104        int fullLength = ((direction & 1) == 0) ? getWidth() : getHeight();
105        mEffect[direction].onPull((float)offset / fullLength);
106        if (!mEffect[direction].isFinished()) {
107            invalidate();
108        }
109    }
110
111    // Call when the object is released after being pulled.
112    public void onRelease() {
113        boolean more = false;
114        for (int i = 0; i < 4; i++) {
115            mEffect[i].onRelease();
116            more |= !mEffect[i].isFinished();
117        }
118        if (more) {
119            invalidate();
120        }
121    }
122
123    // Call when the effect absorbs an impact at the given velocity.
124    // Used when a fling reaches the scroll boundary. velocity is in pixels
125    // per second. direction is one of {TOP, LEFT, BOTTOM, RIGHT}.
126    public void onAbsorb(int velocity, int direction) {
127        mEffect[direction].onAbsorb(velocity);
128        if (!mEffect[direction].isFinished()) {
129            invalidate();
130        }
131    }
132}
133