1/*
2 * Copyright (C) 2009 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.cooliris.media;
18
19import javax.microedition.khronos.opengles.GL11;
20
21import android.os.SystemClock;
22import android.view.MotionEvent;
23
24import com.cooliris.app.Res;
25import com.cooliris.media.RenderView.Lists;
26
27public final class ImageButton extends Layer {
28    private static final float TRACKING_MARGIN = 30.0f;
29
30    // Images for the normal and pressed states.
31    private int mImage = 0;
32    private int mPressedImage = 0;
33
34    // The action to be invoked when a single tap occurs on the button.
35    private Runnable mAction = null;
36
37    // Animation state for button crossfades.
38    private final FloatAnim mFade = new FloatAnim(1f);
39    private int mCurrentImage = 0;
40    private int mPreviousImage = 0;
41    private boolean mPressed = false;
42
43    private final int mTransparent = Res.drawable.transparent;
44
45    public void setImages(int image, int pressedImage) {
46        mImage = image;
47        mPressedImage = pressedImage;
48        if (!mPressed) {
49            setImage(image, true);
50        }
51    }
52
53    public final void setAction(Runnable action) {
54        mAction = action;
55    }
56
57    private boolean containsPoint(float x, float y, boolean addTrackingMargin) {
58        if (mImage != 0) {
59            float minX = mX;
60            float minY = mY;
61            float maxX = minX + mWidth;
62            float maxY = minY + mHeight;
63            if (addTrackingMargin) {
64                minX -= TRACKING_MARGIN;
65                minY -= TRACKING_MARGIN;
66                maxX += TRACKING_MARGIN;
67                maxY += TRACKING_MARGIN;
68            }
69            return x >= minX && y >= minY && x < maxX && y < maxY;
70        }
71        return false;
72    }
73
74    @Override
75    public void generate(RenderView view, Lists lists) {
76        lists.updateList.add(this);
77        lists.blendedList.add(this);
78        lists.hitTestList.add(this);
79    }
80
81    @Override
82    public void renderBlended(RenderView view, GL11 gl) {
83        // Get the value of the animation.
84        final float ratio = mFade.getValue(view.getFrameTime());
85        Texture currentImage = view.getResource(mCurrentImage);
86        Texture previousImage = view.getResource(mPreviousImage);
87        Texture transparent = view.getResource(mTransparent);
88        if (currentImage == null) {
89            currentImage = transparent;
90        }
91        if (previousImage == null) {
92            previousImage = transparent;
93        }
94        if (ratio >= 0.99f) {
95            view.draw2D(currentImage, mX, mY);
96        } else {
97            view.drawMixed2D(previousImage, currentImage, ratio, mX, mY, 0f, currentImage.getWidth(), currentImage.getHeight());
98        }
99    }
100
101    @Override
102    public boolean onTouchEvent(MotionEvent e) {
103        final int action = e.getAction();
104        switch (action) {
105        case MotionEvent.ACTION_DOWN:
106        case MotionEvent.ACTION_MOVE:
107            final boolean hit = containsPoint(e.getX(), e.getY(), true);
108            mPressed = hit;
109            if (hit) {
110                setImage(mPressedImage, false);
111            } else {
112                setImage(mImage, true);
113            }
114            break;
115        case MotionEvent.ACTION_UP:
116            if (mPressed) {
117                if (mAction != null)
118                    mAction.run();
119            }
120        case MotionEvent.ACTION_CANCEL:
121            mPressed = false;
122            setImage(mImage, true);
123            break;
124        default:
125            break;
126        }
127        return true;
128    }
129
130    private void setImage(int image, boolean animate) {
131        if (mCurrentImage != image) {
132            if (animate) {
133                mFade.setValue(0f);
134                mFade.animateValue(1f, 0.25f, SystemClock.uptimeMillis()); // TODO:
135                                                                           // use
136                                                                           // frame
137                                                                           // clock.
138                mPreviousImage = mCurrentImage;
139            } else {
140                mFade.setValue(1f);
141            }
142            mCurrentImage = image;
143        }
144    }
145}
146