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