1/*
2 * Copyright (C) 2010 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.videoeditor.widgets;
18
19import com.android.videoeditor.R;
20
21import android.content.Context;
22import android.content.res.Resources;
23import android.graphics.Canvas;
24import android.graphics.drawable.Drawable;
25import android.util.AttributeSet;
26import android.view.MotionEvent;
27import android.widget.ImageView;
28
29/**
30 * The view that represents a resize handle
31 */
32public class HandleView extends ImageView {
33    // Instance variables
34    private final Drawable mIconDragClipLeft;
35    private final Drawable mIconDragClipRight;
36    private MoveListener mListener;
37    private float mStartMoveX, mLastMoveX;
38    private boolean mMoveStarted;
39    private boolean mBeginLimitReached, mEndLimitReached;
40    private int mLastDeltaX;
41
42    /**
43     * Move listener
44     */
45    public interface MoveListener {
46        /**
47         * The move begins
48         *
49         * @param view The view
50         */
51        public void onMoveBegin(HandleView view);
52
53        /**
54         * Move is in progress
55         *
56         * @param view The view
57         * @param left The left edge left position
58         * @param delta The offset relative to the left of the view
59         */
60        public boolean onMove(HandleView view, int left, int delta);
61
62        /**
63         * The move ended
64         *
65         * @param view The view
66         * @param left The left edge left position
67         * @param delta The offset relative to the left of the view
68         */
69        public void onMoveEnd(HandleView view, int left, int delta);
70    }
71
72    public HandleView(Context context, AttributeSet attrs, int defStyle) {
73        super(context, attrs, defStyle);
74
75        // Prepare the handle arrows
76        final Resources resources = getResources();
77        mIconDragClipLeft = resources.getDrawable(R.drawable.ic_drag_clip_left);
78        mIconDragClipRight = resources.getDrawable(R.drawable.ic_drag_clip_right);
79    }
80
81    public HandleView(Context context, AttributeSet attrs) {
82        this(context, attrs, 0);
83    }
84
85    public HandleView(Context context) {
86        this(context, null, 0);
87    }
88
89    /**
90     * @param listener The listener
91     */
92    public void setListener(MoveListener listener) {
93        mListener = listener;
94    }
95
96    /**
97     * Set the movement limits
98     *
99     * @param beginLimitReached true if the begin limit was reached
100     * @param endLimitReached true if the end limit was reached
101     */
102    public void setLimitReached(boolean beginLimitReached, boolean endLimitReached) {
103        // Check if anything has changed
104        if (beginLimitReached == mBeginLimitReached && endLimitReached == mEndLimitReached) {
105            return;
106        }
107
108        mBeginLimitReached = beginLimitReached;
109        mEndLimitReached = endLimitReached;
110
111        invalidate();
112    }
113
114    /**
115     * End the move
116     */
117    public void endMove() {
118        if (mMoveStarted) {
119            endActionMove(mLastMoveX);
120        }
121    }
122
123    @Override
124    public boolean onTouchEvent(MotionEvent ev) {
125        super.onTouchEvent(ev);
126
127        switch (ev.getAction()) {
128            case MotionEvent.ACTION_DOWN: {
129                if (isEnabled()) {
130                    // The ScrollView will not get the touch events
131                    getParent().requestDisallowInterceptTouchEvent(true);
132                    if (mListener != null) {
133                        mListener.onMoveBegin(this);
134                    }
135
136                    mStartMoveX = ev.getX();
137                    mMoveStarted = true;
138                } else {
139                    mMoveStarted = false;
140                }
141
142                mLastDeltaX = -10000;
143                break;
144            }
145
146            case MotionEvent.ACTION_MOVE: {
147                if (mMoveStarted && isEnabled()) {
148                    final int deltaX = Math.round((ev.getX() - mStartMoveX));
149                    if (deltaX != mLastDeltaX) {
150                        mLastDeltaX = deltaX;
151
152                        if (mListener != null) {
153                            if (getId() == R.id.handle_left) {
154                                mListener.onMove(this, getLeft(), deltaX + getWidth());
155                            } else {
156                                mListener.onMove(this, getLeft(), deltaX);
157                            }
158                        }
159
160                        mLastMoveX = ev.getX();
161                    }
162                }
163                break;
164            }
165
166            case MotionEvent.ACTION_CANCEL:
167            case MotionEvent.ACTION_UP: {
168                endActionMove(ev.getX());
169                break;
170            }
171
172            default: {
173                break;
174            }
175        }
176
177        return true;
178    }
179
180    /**
181     * End the move (if it was in progress)
182     *
183     * @param eventX The event horizontal position
184     */
185    private void endActionMove(float eventX) {
186        if (mMoveStarted) {
187            mMoveStarted = false;
188
189            if (mListener != null) {
190                final int deltaX = Math.round((eventX - mStartMoveX));
191                if (getId() == R.id.handle_left) {
192                    mListener.onMoveEnd(this, getLeft(), deltaX + getWidth());
193                } else {
194                    mListener.onMoveEnd(this, getLeft(), deltaX);
195                }
196            }
197        }
198    }
199
200    @Override
201    protected void onDraw(Canvas canvas) {
202        super.onDraw(canvas);
203
204        final int top = (getHeight() - mIconDragClipLeft.getIntrinsicHeight()) / 2;
205        if (!mBeginLimitReached) {
206            mIconDragClipLeft.setBounds(0,
207                    top,
208                    mIconDragClipLeft.getIntrinsicWidth(),
209                    top + mIconDragClipLeft.getIntrinsicHeight());
210            mIconDragClipLeft.draw(canvas);
211        }
212
213        if (!mEndLimitReached) {
214            mIconDragClipRight.setBounds(
215                    mIconDragClipRight.getIntrinsicWidth(),
216                    top,
217                    2 * mIconDragClipRight.getIntrinsicWidth(),
218                    top + mIconDragClipRight.getIntrinsicHeight());
219            mIconDragClipRight.draw(canvas);
220        }
221    }
222}
223