1666ea1b28a76aeba74744148b15099254d918671Owen Lin/* 2666ea1b28a76aeba74744148b15099254d918671Owen Lin * Copyright (C) 2007 The Android Open Source Project 3666ea1b28a76aeba74744148b15099254d918671Owen Lin * 4666ea1b28a76aeba74744148b15099254d918671Owen Lin * Licensed under the Apache License, Version 2.0 (the "License"); 5666ea1b28a76aeba74744148b15099254d918671Owen Lin * you may not use this file except in compliance with the License. 6666ea1b28a76aeba74744148b15099254d918671Owen Lin * You may obtain a copy of the License at 7666ea1b28a76aeba74744148b15099254d918671Owen Lin * 8666ea1b28a76aeba74744148b15099254d918671Owen Lin * http://www.apache.org/licenses/LICENSE-2.0 9666ea1b28a76aeba74744148b15099254d918671Owen Lin * 10666ea1b28a76aeba74744148b15099254d918671Owen Lin * Unless required by applicable law or agreed to in writing, software 11666ea1b28a76aeba74744148b15099254d918671Owen Lin * distributed under the License is distributed on an "AS IS" BASIS, 12666ea1b28a76aeba74744148b15099254d918671Owen Lin * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13666ea1b28a76aeba74744148b15099254d918671Owen Lin * See the License for the specific language governing permissions and 14666ea1b28a76aeba74744148b15099254d918671Owen Lin * limitations under the License. 15666ea1b28a76aeba74744148b15099254d918671Owen Lin */ 16666ea1b28a76aeba74744148b15099254d918671Owen Lin 17666ea1b28a76aeba74744148b15099254d918671Owen Linpackage com.android.camera; 18666ea1b28a76aeba74744148b15099254d918671Owen Lin 19d6c2fb7a38fcdb58742fcfffd67a4594487ec71cOwen Linimport com.android.gallery.R; 20d6c2fb7a38fcdb58742fcfffd67a4594487ec71cOwen Lin 21666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.graphics.Canvas; 22666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.graphics.Matrix; 23666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.graphics.Paint; 24666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.graphics.Path; 25666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.graphics.Rect; 26666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.graphics.RectF; 27666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.graphics.Region; 28666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.graphics.drawable.Drawable; 29666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.view.View; 30666ea1b28a76aeba74744148b15099254d918671Owen Lin 31666ea1b28a76aeba74744148b15099254d918671Owen Lin// This class is used by CropImage to display a highlighted cropping rectangle 32666ea1b28a76aeba74744148b15099254d918671Owen Lin// overlayed with the image. There are two coordinate spaces in use. One is 33666ea1b28a76aeba74744148b15099254d918671Owen Lin// image, another is screen. computeLayout() uses mMatrix to map from image 34666ea1b28a76aeba74744148b15099254d918671Owen Lin// space to screen space. 35666ea1b28a76aeba74744148b15099254d918671Owen Linclass HighlightView { 36666ea1b28a76aeba74744148b15099254d918671Owen Lin 37666ea1b28a76aeba74744148b15099254d918671Owen Lin @SuppressWarnings("unused") 38666ea1b28a76aeba74744148b15099254d918671Owen Lin private static final String TAG = "HighlightView"; 39666ea1b28a76aeba74744148b15099254d918671Owen Lin View mContext; // The View displaying the image. 40666ea1b28a76aeba74744148b15099254d918671Owen Lin 41666ea1b28a76aeba74744148b15099254d918671Owen Lin public static final int GROW_NONE = (1 << 0); 42666ea1b28a76aeba74744148b15099254d918671Owen Lin public static final int GROW_LEFT_EDGE = (1 << 1); 43666ea1b28a76aeba74744148b15099254d918671Owen Lin public static final int GROW_RIGHT_EDGE = (1 << 2); 44666ea1b28a76aeba74744148b15099254d918671Owen Lin public static final int GROW_TOP_EDGE = (1 << 3); 45666ea1b28a76aeba74744148b15099254d918671Owen Lin public static final int GROW_BOTTOM_EDGE = (1 << 4); 46666ea1b28a76aeba74744148b15099254d918671Owen Lin public static final int MOVE = (1 << 5); 47666ea1b28a76aeba74744148b15099254d918671Owen Lin 48666ea1b28a76aeba74744148b15099254d918671Owen Lin public HighlightView(View ctx) { 49666ea1b28a76aeba74744148b15099254d918671Owen Lin mContext = ctx; 50666ea1b28a76aeba74744148b15099254d918671Owen Lin } 51666ea1b28a76aeba74744148b15099254d918671Owen Lin 52666ea1b28a76aeba74744148b15099254d918671Owen Lin private void init() { 53666ea1b28a76aeba74744148b15099254d918671Owen Lin android.content.res.Resources resources = mContext.getResources(); 54666ea1b28a76aeba74744148b15099254d918671Owen Lin mResizeDrawableWidth = 55666ea1b28a76aeba74744148b15099254d918671Owen Lin resources.getDrawable(R.drawable.camera_crop_width); 56666ea1b28a76aeba74744148b15099254d918671Owen Lin mResizeDrawableHeight = 57666ea1b28a76aeba74744148b15099254d918671Owen Lin resources.getDrawable(R.drawable.camera_crop_height); 58666ea1b28a76aeba74744148b15099254d918671Owen Lin mResizeDrawableDiagonal = 59666ea1b28a76aeba74744148b15099254d918671Owen Lin resources.getDrawable(R.drawable.indicator_autocrop); 60666ea1b28a76aeba74744148b15099254d918671Owen Lin } 61666ea1b28a76aeba74744148b15099254d918671Owen Lin 62666ea1b28a76aeba74744148b15099254d918671Owen Lin boolean mIsFocused; 63666ea1b28a76aeba74744148b15099254d918671Owen Lin boolean mHidden; 64666ea1b28a76aeba74744148b15099254d918671Owen Lin 65666ea1b28a76aeba74744148b15099254d918671Owen Lin public boolean hasFocus() { 66666ea1b28a76aeba74744148b15099254d918671Owen Lin return mIsFocused; 67666ea1b28a76aeba74744148b15099254d918671Owen Lin } 68666ea1b28a76aeba74744148b15099254d918671Owen Lin 69666ea1b28a76aeba74744148b15099254d918671Owen Lin public void setFocus(boolean f) { 70666ea1b28a76aeba74744148b15099254d918671Owen Lin mIsFocused = f; 71666ea1b28a76aeba74744148b15099254d918671Owen Lin } 72666ea1b28a76aeba74744148b15099254d918671Owen Lin 73666ea1b28a76aeba74744148b15099254d918671Owen Lin public void setHidden(boolean hidden) { 74666ea1b28a76aeba74744148b15099254d918671Owen Lin mHidden = hidden; 75666ea1b28a76aeba74744148b15099254d918671Owen Lin } 76666ea1b28a76aeba74744148b15099254d918671Owen Lin 77666ea1b28a76aeba74744148b15099254d918671Owen Lin protected void draw(Canvas canvas) { 78666ea1b28a76aeba74744148b15099254d918671Owen Lin if (mHidden) { 79666ea1b28a76aeba74744148b15099254d918671Owen Lin return; 80666ea1b28a76aeba74744148b15099254d918671Owen Lin } 81666ea1b28a76aeba74744148b15099254d918671Owen Lin canvas.save(); 82666ea1b28a76aeba74744148b15099254d918671Owen Lin Path path = new Path(); 83666ea1b28a76aeba74744148b15099254d918671Owen Lin if (!hasFocus()) { 84666ea1b28a76aeba74744148b15099254d918671Owen Lin mOutlinePaint.setColor(0xFF000000); 85666ea1b28a76aeba74744148b15099254d918671Owen Lin canvas.drawRect(mDrawRect, mOutlinePaint); 86666ea1b28a76aeba74744148b15099254d918671Owen Lin } else { 87666ea1b28a76aeba74744148b15099254d918671Owen Lin Rect viewDrawingRect = new Rect(); 88666ea1b28a76aeba74744148b15099254d918671Owen Lin mContext.getDrawingRect(viewDrawingRect); 89666ea1b28a76aeba74744148b15099254d918671Owen Lin if (mCircle) { 90666ea1b28a76aeba74744148b15099254d918671Owen Lin float width = mDrawRect.width(); 91666ea1b28a76aeba74744148b15099254d918671Owen Lin float height = mDrawRect.height(); 92666ea1b28a76aeba74744148b15099254d918671Owen Lin path.addCircle(mDrawRect.left + (width / 2), 93666ea1b28a76aeba74744148b15099254d918671Owen Lin mDrawRect.top + (height / 2), 94666ea1b28a76aeba74744148b15099254d918671Owen Lin width / 2, 95666ea1b28a76aeba74744148b15099254d918671Owen Lin Path.Direction.CW); 96666ea1b28a76aeba74744148b15099254d918671Owen Lin mOutlinePaint.setColor(0xFFEF04D6); 97666ea1b28a76aeba74744148b15099254d918671Owen Lin } else { 98666ea1b28a76aeba74744148b15099254d918671Owen Lin path.addRect(new RectF(mDrawRect), Path.Direction.CW); 99666ea1b28a76aeba74744148b15099254d918671Owen Lin mOutlinePaint.setColor(0xFFFF8A00); 100666ea1b28a76aeba74744148b15099254d918671Owen Lin } 101666ea1b28a76aeba74744148b15099254d918671Owen Lin canvas.clipPath(path, Region.Op.DIFFERENCE); 102666ea1b28a76aeba74744148b15099254d918671Owen Lin canvas.drawRect(viewDrawingRect, 103666ea1b28a76aeba74744148b15099254d918671Owen Lin hasFocus() ? mFocusPaint : mNoFocusPaint); 104666ea1b28a76aeba74744148b15099254d918671Owen Lin 105666ea1b28a76aeba74744148b15099254d918671Owen Lin canvas.restore(); 106666ea1b28a76aeba74744148b15099254d918671Owen Lin canvas.drawPath(path, mOutlinePaint); 107666ea1b28a76aeba74744148b15099254d918671Owen Lin 108666ea1b28a76aeba74744148b15099254d918671Owen Lin if (mMode == ModifyMode.Grow) { 109666ea1b28a76aeba74744148b15099254d918671Owen Lin if (mCircle) { 110666ea1b28a76aeba74744148b15099254d918671Owen Lin int width = mResizeDrawableDiagonal.getIntrinsicWidth(); 111666ea1b28a76aeba74744148b15099254d918671Owen Lin int height = mResizeDrawableDiagonal.getIntrinsicHeight(); 112666ea1b28a76aeba74744148b15099254d918671Owen Lin 113666ea1b28a76aeba74744148b15099254d918671Owen Lin int d = (int) Math.round(Math.cos(/*45deg*/Math.PI / 4D) 114666ea1b28a76aeba74744148b15099254d918671Owen Lin * (mDrawRect.width() / 2D)); 115666ea1b28a76aeba74744148b15099254d918671Owen Lin int x = mDrawRect.left 116666ea1b28a76aeba74744148b15099254d918671Owen Lin + (mDrawRect.width() / 2) + d - width / 2; 117666ea1b28a76aeba74744148b15099254d918671Owen Lin int y = mDrawRect.top 118666ea1b28a76aeba74744148b15099254d918671Owen Lin + (mDrawRect.height() / 2) - d - height / 2; 119666ea1b28a76aeba74744148b15099254d918671Owen Lin mResizeDrawableDiagonal.setBounds(x, y, 120666ea1b28a76aeba74744148b15099254d918671Owen Lin x + mResizeDrawableDiagonal.getIntrinsicWidth(), 121666ea1b28a76aeba74744148b15099254d918671Owen Lin y + mResizeDrawableDiagonal.getIntrinsicHeight()); 122666ea1b28a76aeba74744148b15099254d918671Owen Lin mResizeDrawableDiagonal.draw(canvas); 123666ea1b28a76aeba74744148b15099254d918671Owen Lin } else { 124666ea1b28a76aeba74744148b15099254d918671Owen Lin int left = mDrawRect.left + 1; 125666ea1b28a76aeba74744148b15099254d918671Owen Lin int right = mDrawRect.right + 1; 126666ea1b28a76aeba74744148b15099254d918671Owen Lin int top = mDrawRect.top + 4; 127666ea1b28a76aeba74744148b15099254d918671Owen Lin int bottom = mDrawRect.bottom + 3; 128666ea1b28a76aeba74744148b15099254d918671Owen Lin 129666ea1b28a76aeba74744148b15099254d918671Owen Lin int widthWidth = 130666ea1b28a76aeba74744148b15099254d918671Owen Lin mResizeDrawableWidth.getIntrinsicWidth() / 2; 131666ea1b28a76aeba74744148b15099254d918671Owen Lin int widthHeight = 132666ea1b28a76aeba74744148b15099254d918671Owen Lin mResizeDrawableWidth.getIntrinsicHeight() / 2; 133666ea1b28a76aeba74744148b15099254d918671Owen Lin int heightHeight = 134666ea1b28a76aeba74744148b15099254d918671Owen Lin mResizeDrawableHeight.getIntrinsicHeight() / 2; 135666ea1b28a76aeba74744148b15099254d918671Owen Lin int heightWidth = 136666ea1b28a76aeba74744148b15099254d918671Owen Lin mResizeDrawableHeight.getIntrinsicWidth() / 2; 137666ea1b28a76aeba74744148b15099254d918671Owen Lin 138666ea1b28a76aeba74744148b15099254d918671Owen Lin int xMiddle = mDrawRect.left 139666ea1b28a76aeba74744148b15099254d918671Owen Lin + ((mDrawRect.right - mDrawRect.left) / 2); 140666ea1b28a76aeba74744148b15099254d918671Owen Lin int yMiddle = mDrawRect.top 141666ea1b28a76aeba74744148b15099254d918671Owen Lin + ((mDrawRect.bottom - mDrawRect.top) / 2); 142666ea1b28a76aeba74744148b15099254d918671Owen Lin 143666ea1b28a76aeba74744148b15099254d918671Owen Lin mResizeDrawableWidth.setBounds(left - widthWidth, 144666ea1b28a76aeba74744148b15099254d918671Owen Lin yMiddle - widthHeight, 145666ea1b28a76aeba74744148b15099254d918671Owen Lin left + widthWidth, 146666ea1b28a76aeba74744148b15099254d918671Owen Lin yMiddle + widthHeight); 147666ea1b28a76aeba74744148b15099254d918671Owen Lin mResizeDrawableWidth.draw(canvas); 148666ea1b28a76aeba74744148b15099254d918671Owen Lin 149666ea1b28a76aeba74744148b15099254d918671Owen Lin mResizeDrawableWidth.setBounds(right - widthWidth, 150666ea1b28a76aeba74744148b15099254d918671Owen Lin yMiddle - widthHeight, 151666ea1b28a76aeba74744148b15099254d918671Owen Lin right + widthWidth, 152666ea1b28a76aeba74744148b15099254d918671Owen Lin yMiddle + widthHeight); 153666ea1b28a76aeba74744148b15099254d918671Owen Lin mResizeDrawableWidth.draw(canvas); 154666ea1b28a76aeba74744148b15099254d918671Owen Lin 155666ea1b28a76aeba74744148b15099254d918671Owen Lin mResizeDrawableHeight.setBounds(xMiddle - heightWidth, 156666ea1b28a76aeba74744148b15099254d918671Owen Lin top - heightHeight, 157666ea1b28a76aeba74744148b15099254d918671Owen Lin xMiddle + heightWidth, 158666ea1b28a76aeba74744148b15099254d918671Owen Lin top + heightHeight); 159666ea1b28a76aeba74744148b15099254d918671Owen Lin mResizeDrawableHeight.draw(canvas); 160666ea1b28a76aeba74744148b15099254d918671Owen Lin 161666ea1b28a76aeba74744148b15099254d918671Owen Lin mResizeDrawableHeight.setBounds(xMiddle - heightWidth, 162666ea1b28a76aeba74744148b15099254d918671Owen Lin bottom - heightHeight, 163666ea1b28a76aeba74744148b15099254d918671Owen Lin xMiddle + heightWidth, 164666ea1b28a76aeba74744148b15099254d918671Owen Lin bottom + heightHeight); 165666ea1b28a76aeba74744148b15099254d918671Owen Lin mResizeDrawableHeight.draw(canvas); 166666ea1b28a76aeba74744148b15099254d918671Owen Lin } 167666ea1b28a76aeba74744148b15099254d918671Owen Lin } 168666ea1b28a76aeba74744148b15099254d918671Owen Lin } 169666ea1b28a76aeba74744148b15099254d918671Owen Lin } 170666ea1b28a76aeba74744148b15099254d918671Owen Lin 171666ea1b28a76aeba74744148b15099254d918671Owen Lin public void setMode(ModifyMode mode) { 172666ea1b28a76aeba74744148b15099254d918671Owen Lin if (mode != mMode) { 173666ea1b28a76aeba74744148b15099254d918671Owen Lin mMode = mode; 174666ea1b28a76aeba74744148b15099254d918671Owen Lin mContext.invalidate(); 175666ea1b28a76aeba74744148b15099254d918671Owen Lin } 176666ea1b28a76aeba74744148b15099254d918671Owen Lin } 177666ea1b28a76aeba74744148b15099254d918671Owen Lin 178666ea1b28a76aeba74744148b15099254d918671Owen Lin // Determines which edges are hit by touching at (x, y). 179666ea1b28a76aeba74744148b15099254d918671Owen Lin public int getHit(float x, float y) { 180666ea1b28a76aeba74744148b15099254d918671Owen Lin Rect r = computeLayout(); 181666ea1b28a76aeba74744148b15099254d918671Owen Lin final float hysteresis = 20F; 182666ea1b28a76aeba74744148b15099254d918671Owen Lin int retval = GROW_NONE; 183666ea1b28a76aeba74744148b15099254d918671Owen Lin 184666ea1b28a76aeba74744148b15099254d918671Owen Lin if (mCircle) { 185666ea1b28a76aeba74744148b15099254d918671Owen Lin float distX = x - r.centerX(); 186666ea1b28a76aeba74744148b15099254d918671Owen Lin float distY = y - r.centerY(); 187666ea1b28a76aeba74744148b15099254d918671Owen Lin int distanceFromCenter = 188666ea1b28a76aeba74744148b15099254d918671Owen Lin (int) Math.sqrt(distX * distX + distY * distY); 189666ea1b28a76aeba74744148b15099254d918671Owen Lin int radius = mDrawRect.width() / 2; 190666ea1b28a76aeba74744148b15099254d918671Owen Lin int delta = distanceFromCenter - radius; 191666ea1b28a76aeba74744148b15099254d918671Owen Lin if (Math.abs(delta) <= hysteresis) { 192666ea1b28a76aeba74744148b15099254d918671Owen Lin if (Math.abs(distY) > Math.abs(distX)) { 193666ea1b28a76aeba74744148b15099254d918671Owen Lin if (distY < 0) { 194666ea1b28a76aeba74744148b15099254d918671Owen Lin retval = GROW_TOP_EDGE; 195666ea1b28a76aeba74744148b15099254d918671Owen Lin } else { 196666ea1b28a76aeba74744148b15099254d918671Owen Lin retval = GROW_BOTTOM_EDGE; 197666ea1b28a76aeba74744148b15099254d918671Owen Lin } 198666ea1b28a76aeba74744148b15099254d918671Owen Lin } else { 199666ea1b28a76aeba74744148b15099254d918671Owen Lin if (distX < 0) { 200666ea1b28a76aeba74744148b15099254d918671Owen Lin retval = GROW_LEFT_EDGE; 201666ea1b28a76aeba74744148b15099254d918671Owen Lin } else { 202666ea1b28a76aeba74744148b15099254d918671Owen Lin retval = GROW_RIGHT_EDGE; 203666ea1b28a76aeba74744148b15099254d918671Owen Lin } 204666ea1b28a76aeba74744148b15099254d918671Owen Lin } 205666ea1b28a76aeba74744148b15099254d918671Owen Lin } else if (distanceFromCenter < radius) { 206666ea1b28a76aeba74744148b15099254d918671Owen Lin retval = MOVE; 207666ea1b28a76aeba74744148b15099254d918671Owen Lin } else { 208666ea1b28a76aeba74744148b15099254d918671Owen Lin retval = GROW_NONE; 209666ea1b28a76aeba74744148b15099254d918671Owen Lin } 210666ea1b28a76aeba74744148b15099254d918671Owen Lin } else { 211666ea1b28a76aeba74744148b15099254d918671Owen Lin // verticalCheck makes sure the position is between the top and 212666ea1b28a76aeba74744148b15099254d918671Owen Lin // the bottom edge (with some tolerance). Similar for horizCheck. 213666ea1b28a76aeba74744148b15099254d918671Owen Lin boolean verticalCheck = (y >= r.top - hysteresis) 214666ea1b28a76aeba74744148b15099254d918671Owen Lin && (y < r.bottom + hysteresis); 215666ea1b28a76aeba74744148b15099254d918671Owen Lin boolean horizCheck = (x >= r.left - hysteresis) 216666ea1b28a76aeba74744148b15099254d918671Owen Lin && (x < r.right + hysteresis); 217666ea1b28a76aeba74744148b15099254d918671Owen Lin 218666ea1b28a76aeba74744148b15099254d918671Owen Lin // Check whether the position is near some edge(s). 219666ea1b28a76aeba74744148b15099254d918671Owen Lin if ((Math.abs(r.left - x) < hysteresis) && verticalCheck) { 220666ea1b28a76aeba74744148b15099254d918671Owen Lin retval |= GROW_LEFT_EDGE; 221666ea1b28a76aeba74744148b15099254d918671Owen Lin } 222666ea1b28a76aeba74744148b15099254d918671Owen Lin if ((Math.abs(r.right - x) < hysteresis) && verticalCheck) { 223666ea1b28a76aeba74744148b15099254d918671Owen Lin retval |= GROW_RIGHT_EDGE; 224666ea1b28a76aeba74744148b15099254d918671Owen Lin } 225666ea1b28a76aeba74744148b15099254d918671Owen Lin if ((Math.abs(r.top - y) < hysteresis) && horizCheck) { 226666ea1b28a76aeba74744148b15099254d918671Owen Lin retval |= GROW_TOP_EDGE; 227666ea1b28a76aeba74744148b15099254d918671Owen Lin } 228666ea1b28a76aeba74744148b15099254d918671Owen Lin if ((Math.abs(r.bottom - y) < hysteresis) && horizCheck) { 229666ea1b28a76aeba74744148b15099254d918671Owen Lin retval |= GROW_BOTTOM_EDGE; 230666ea1b28a76aeba74744148b15099254d918671Owen Lin } 231666ea1b28a76aeba74744148b15099254d918671Owen Lin 232666ea1b28a76aeba74744148b15099254d918671Owen Lin // Not near any edge but inside the rectangle: move. 233666ea1b28a76aeba74744148b15099254d918671Owen Lin if (retval == GROW_NONE && r.contains((int) x, (int) y)) { 234666ea1b28a76aeba74744148b15099254d918671Owen Lin retval = MOVE; 235666ea1b28a76aeba74744148b15099254d918671Owen Lin } 236666ea1b28a76aeba74744148b15099254d918671Owen Lin } 237666ea1b28a76aeba74744148b15099254d918671Owen Lin return retval; 238666ea1b28a76aeba74744148b15099254d918671Owen Lin } 239666ea1b28a76aeba74744148b15099254d918671Owen Lin 240666ea1b28a76aeba74744148b15099254d918671Owen Lin // Handles motion (dx, dy) in screen space. 241666ea1b28a76aeba74744148b15099254d918671Owen Lin // The "edge" parameter specifies which edges the user is dragging. 242666ea1b28a76aeba74744148b15099254d918671Owen Lin void handleMotion(int edge, float dx, float dy) { 243666ea1b28a76aeba74744148b15099254d918671Owen Lin Rect r = computeLayout(); 244666ea1b28a76aeba74744148b15099254d918671Owen Lin if (edge == GROW_NONE) { 245666ea1b28a76aeba74744148b15099254d918671Owen Lin return; 246666ea1b28a76aeba74744148b15099254d918671Owen Lin } else if (edge == MOVE) { 247666ea1b28a76aeba74744148b15099254d918671Owen Lin // Convert to image space before sending to moveBy(). 248666ea1b28a76aeba74744148b15099254d918671Owen Lin moveBy(dx * (mCropRect.width() / r.width()), 249666ea1b28a76aeba74744148b15099254d918671Owen Lin dy * (mCropRect.height() / r.height())); 250666ea1b28a76aeba74744148b15099254d918671Owen Lin } else { 251666ea1b28a76aeba74744148b15099254d918671Owen Lin if (((GROW_LEFT_EDGE | GROW_RIGHT_EDGE) & edge) == 0) { 252666ea1b28a76aeba74744148b15099254d918671Owen Lin dx = 0; 253666ea1b28a76aeba74744148b15099254d918671Owen Lin } 254666ea1b28a76aeba74744148b15099254d918671Owen Lin 255666ea1b28a76aeba74744148b15099254d918671Owen Lin if (((GROW_TOP_EDGE | GROW_BOTTOM_EDGE) & edge) == 0) { 256666ea1b28a76aeba74744148b15099254d918671Owen Lin dy = 0; 257666ea1b28a76aeba74744148b15099254d918671Owen Lin } 258666ea1b28a76aeba74744148b15099254d918671Owen Lin 259666ea1b28a76aeba74744148b15099254d918671Owen Lin // Convert to image space before sending to growBy(). 260666ea1b28a76aeba74744148b15099254d918671Owen Lin float xDelta = dx * (mCropRect.width() / r.width()); 261666ea1b28a76aeba74744148b15099254d918671Owen Lin float yDelta = dy * (mCropRect.height() / r.height()); 262666ea1b28a76aeba74744148b15099254d918671Owen Lin growBy((((edge & GROW_LEFT_EDGE) != 0) ? -1 : 1) * xDelta, 263666ea1b28a76aeba74744148b15099254d918671Owen Lin (((edge & GROW_TOP_EDGE) != 0) ? -1 : 1) * yDelta); 264666ea1b28a76aeba74744148b15099254d918671Owen Lin } 265666ea1b28a76aeba74744148b15099254d918671Owen Lin } 266666ea1b28a76aeba74744148b15099254d918671Owen Lin 267666ea1b28a76aeba74744148b15099254d918671Owen Lin // Grows the cropping rectange by (dx, dy) in image space. 268666ea1b28a76aeba74744148b15099254d918671Owen Lin void moveBy(float dx, float dy) { 269666ea1b28a76aeba74744148b15099254d918671Owen Lin Rect invalRect = new Rect(mDrawRect); 270666ea1b28a76aeba74744148b15099254d918671Owen Lin 271666ea1b28a76aeba74744148b15099254d918671Owen Lin mCropRect.offset(dx, dy); 272666ea1b28a76aeba74744148b15099254d918671Owen Lin 273666ea1b28a76aeba74744148b15099254d918671Owen Lin // Put the cropping rectangle inside image rectangle. 274666ea1b28a76aeba74744148b15099254d918671Owen Lin mCropRect.offset( 275666ea1b28a76aeba74744148b15099254d918671Owen Lin Math.max(0, mImageRect.left - mCropRect.left), 276666ea1b28a76aeba74744148b15099254d918671Owen Lin Math.max(0, mImageRect.top - mCropRect.top)); 277666ea1b28a76aeba74744148b15099254d918671Owen Lin 278666ea1b28a76aeba74744148b15099254d918671Owen Lin mCropRect.offset( 279666ea1b28a76aeba74744148b15099254d918671Owen Lin Math.min(0, mImageRect.right - mCropRect.right), 280666ea1b28a76aeba74744148b15099254d918671Owen Lin Math.min(0, mImageRect.bottom - mCropRect.bottom)); 281666ea1b28a76aeba74744148b15099254d918671Owen Lin 282666ea1b28a76aeba74744148b15099254d918671Owen Lin mDrawRect = computeLayout(); 283666ea1b28a76aeba74744148b15099254d918671Owen Lin invalRect.union(mDrawRect); 284666ea1b28a76aeba74744148b15099254d918671Owen Lin invalRect.inset(-10, -10); 285666ea1b28a76aeba74744148b15099254d918671Owen Lin mContext.invalidate(invalRect); 286666ea1b28a76aeba74744148b15099254d918671Owen Lin } 287666ea1b28a76aeba74744148b15099254d918671Owen Lin 288666ea1b28a76aeba74744148b15099254d918671Owen Lin // Grows the cropping rectange by (dx, dy) in image space. 289666ea1b28a76aeba74744148b15099254d918671Owen Lin void growBy(float dx, float dy) { 290666ea1b28a76aeba74744148b15099254d918671Owen Lin if (mMaintainAspectRatio) { 291666ea1b28a76aeba74744148b15099254d918671Owen Lin if (dx != 0) { 292666ea1b28a76aeba74744148b15099254d918671Owen Lin dy = dx / mInitialAspectRatio; 293666ea1b28a76aeba74744148b15099254d918671Owen Lin } else if (dy != 0) { 294666ea1b28a76aeba74744148b15099254d918671Owen Lin dx = dy * mInitialAspectRatio; 295666ea1b28a76aeba74744148b15099254d918671Owen Lin } 296666ea1b28a76aeba74744148b15099254d918671Owen Lin } 297666ea1b28a76aeba74744148b15099254d918671Owen Lin 298666ea1b28a76aeba74744148b15099254d918671Owen Lin // Don't let the cropping rectangle grow too fast. 299666ea1b28a76aeba74744148b15099254d918671Owen Lin // Grow at most half of the difference between the image rectangle and 300666ea1b28a76aeba74744148b15099254d918671Owen Lin // the cropping rectangle. 301666ea1b28a76aeba74744148b15099254d918671Owen Lin RectF r = new RectF(mCropRect); 302666ea1b28a76aeba74744148b15099254d918671Owen Lin if (dx > 0F && r.width() + 2 * dx > mImageRect.width()) { 303666ea1b28a76aeba74744148b15099254d918671Owen Lin float adjustment = (mImageRect.width() - r.width()) / 2F; 304666ea1b28a76aeba74744148b15099254d918671Owen Lin dx = adjustment; 305666ea1b28a76aeba74744148b15099254d918671Owen Lin if (mMaintainAspectRatio) { 306666ea1b28a76aeba74744148b15099254d918671Owen Lin dy = dx / mInitialAspectRatio; 307666ea1b28a76aeba74744148b15099254d918671Owen Lin } 308666ea1b28a76aeba74744148b15099254d918671Owen Lin } 309666ea1b28a76aeba74744148b15099254d918671Owen Lin if (dy > 0F && r.height() + 2 * dy > mImageRect.height()) { 310666ea1b28a76aeba74744148b15099254d918671Owen Lin float adjustment = (mImageRect.height() - r.height()) / 2F; 311666ea1b28a76aeba74744148b15099254d918671Owen Lin dy = adjustment; 312666ea1b28a76aeba74744148b15099254d918671Owen Lin if (mMaintainAspectRatio) { 313666ea1b28a76aeba74744148b15099254d918671Owen Lin dx = dy * mInitialAspectRatio; 314666ea1b28a76aeba74744148b15099254d918671Owen Lin } 315666ea1b28a76aeba74744148b15099254d918671Owen Lin } 316666ea1b28a76aeba74744148b15099254d918671Owen Lin 317666ea1b28a76aeba74744148b15099254d918671Owen Lin r.inset(-dx, -dy); 318666ea1b28a76aeba74744148b15099254d918671Owen Lin 319666ea1b28a76aeba74744148b15099254d918671Owen Lin // Don't let the cropping rectangle shrink too fast. 320666ea1b28a76aeba74744148b15099254d918671Owen Lin final float widthCap = 25F; 321666ea1b28a76aeba74744148b15099254d918671Owen Lin if (r.width() < widthCap) { 322666ea1b28a76aeba74744148b15099254d918671Owen Lin r.inset(-(widthCap - r.width()) / 2F, 0F); 323666ea1b28a76aeba74744148b15099254d918671Owen Lin } 324666ea1b28a76aeba74744148b15099254d918671Owen Lin float heightCap = mMaintainAspectRatio 325666ea1b28a76aeba74744148b15099254d918671Owen Lin ? (widthCap / mInitialAspectRatio) 326666ea1b28a76aeba74744148b15099254d918671Owen Lin : widthCap; 327666ea1b28a76aeba74744148b15099254d918671Owen Lin if (r.height() < heightCap) { 328666ea1b28a76aeba74744148b15099254d918671Owen Lin r.inset(0F, -(heightCap - r.height()) / 2F); 329666ea1b28a76aeba74744148b15099254d918671Owen Lin } 330666ea1b28a76aeba74744148b15099254d918671Owen Lin 331666ea1b28a76aeba74744148b15099254d918671Owen Lin // Put the cropping rectangle inside the image rectangle. 332666ea1b28a76aeba74744148b15099254d918671Owen Lin if (r.left < mImageRect.left) { 333666ea1b28a76aeba74744148b15099254d918671Owen Lin r.offset(mImageRect.left - r.left, 0F); 334666ea1b28a76aeba74744148b15099254d918671Owen Lin } else if (r.right > mImageRect.right) { 335666ea1b28a76aeba74744148b15099254d918671Owen Lin r.offset(-(r.right - mImageRect.right), 0); 336666ea1b28a76aeba74744148b15099254d918671Owen Lin } 337666ea1b28a76aeba74744148b15099254d918671Owen Lin if (r.top < mImageRect.top) { 338666ea1b28a76aeba74744148b15099254d918671Owen Lin r.offset(0F, mImageRect.top - r.top); 339666ea1b28a76aeba74744148b15099254d918671Owen Lin } else if (r.bottom > mImageRect.bottom) { 340666ea1b28a76aeba74744148b15099254d918671Owen Lin r.offset(0F, -(r.bottom - mImageRect.bottom)); 341666ea1b28a76aeba74744148b15099254d918671Owen Lin } 342666ea1b28a76aeba74744148b15099254d918671Owen Lin 343666ea1b28a76aeba74744148b15099254d918671Owen Lin mCropRect.set(r); 344666ea1b28a76aeba74744148b15099254d918671Owen Lin mDrawRect = computeLayout(); 345666ea1b28a76aeba74744148b15099254d918671Owen Lin mContext.invalidate(); 346666ea1b28a76aeba74744148b15099254d918671Owen Lin } 347666ea1b28a76aeba74744148b15099254d918671Owen Lin 348666ea1b28a76aeba74744148b15099254d918671Owen Lin // Returns the cropping rectangle in image space. 349666ea1b28a76aeba74744148b15099254d918671Owen Lin public Rect getCropRect() { 350666ea1b28a76aeba74744148b15099254d918671Owen Lin return new Rect((int) mCropRect.left, (int) mCropRect.top, 351666ea1b28a76aeba74744148b15099254d918671Owen Lin (int) mCropRect.right, (int) mCropRect.bottom); 352666ea1b28a76aeba74744148b15099254d918671Owen Lin } 353666ea1b28a76aeba74744148b15099254d918671Owen Lin 354666ea1b28a76aeba74744148b15099254d918671Owen Lin // Maps the cropping rectangle from image space to screen space. 355666ea1b28a76aeba74744148b15099254d918671Owen Lin private Rect computeLayout() { 356666ea1b28a76aeba74744148b15099254d918671Owen Lin RectF r = new RectF(mCropRect.left, mCropRect.top, 357666ea1b28a76aeba74744148b15099254d918671Owen Lin mCropRect.right, mCropRect.bottom); 358666ea1b28a76aeba74744148b15099254d918671Owen Lin mMatrix.mapRect(r); 359666ea1b28a76aeba74744148b15099254d918671Owen Lin return new Rect(Math.round(r.left), Math.round(r.top), 360666ea1b28a76aeba74744148b15099254d918671Owen Lin Math.round(r.right), Math.round(r.bottom)); 361666ea1b28a76aeba74744148b15099254d918671Owen Lin } 362666ea1b28a76aeba74744148b15099254d918671Owen Lin 363666ea1b28a76aeba74744148b15099254d918671Owen Lin public void invalidate() { 364666ea1b28a76aeba74744148b15099254d918671Owen Lin mDrawRect = computeLayout(); 365666ea1b28a76aeba74744148b15099254d918671Owen Lin } 366666ea1b28a76aeba74744148b15099254d918671Owen Lin 367666ea1b28a76aeba74744148b15099254d918671Owen Lin public void setup(Matrix m, Rect imageRect, RectF cropRect, boolean circle, 368666ea1b28a76aeba74744148b15099254d918671Owen Lin boolean maintainAspectRatio) { 369666ea1b28a76aeba74744148b15099254d918671Owen Lin if (circle) { 370666ea1b28a76aeba74744148b15099254d918671Owen Lin maintainAspectRatio = true; 371666ea1b28a76aeba74744148b15099254d918671Owen Lin } 372666ea1b28a76aeba74744148b15099254d918671Owen Lin mMatrix = new Matrix(m); 373666ea1b28a76aeba74744148b15099254d918671Owen Lin 374666ea1b28a76aeba74744148b15099254d918671Owen Lin mCropRect = cropRect; 375666ea1b28a76aeba74744148b15099254d918671Owen Lin mImageRect = new RectF(imageRect); 376666ea1b28a76aeba74744148b15099254d918671Owen Lin mMaintainAspectRatio = maintainAspectRatio; 377666ea1b28a76aeba74744148b15099254d918671Owen Lin mCircle = circle; 378666ea1b28a76aeba74744148b15099254d918671Owen Lin 379666ea1b28a76aeba74744148b15099254d918671Owen Lin mInitialAspectRatio = mCropRect.width() / mCropRect.height(); 380666ea1b28a76aeba74744148b15099254d918671Owen Lin mDrawRect = computeLayout(); 381666ea1b28a76aeba74744148b15099254d918671Owen Lin 382666ea1b28a76aeba74744148b15099254d918671Owen Lin mFocusPaint.setARGB(125, 50, 50, 50); 383666ea1b28a76aeba74744148b15099254d918671Owen Lin mNoFocusPaint.setARGB(125, 50, 50, 50); 384666ea1b28a76aeba74744148b15099254d918671Owen Lin mOutlinePaint.setStrokeWidth(3F); 385666ea1b28a76aeba74744148b15099254d918671Owen Lin mOutlinePaint.setStyle(Paint.Style.STROKE); 386666ea1b28a76aeba74744148b15099254d918671Owen Lin mOutlinePaint.setAntiAlias(true); 387666ea1b28a76aeba74744148b15099254d918671Owen Lin 388666ea1b28a76aeba74744148b15099254d918671Owen Lin mMode = ModifyMode.None; 389666ea1b28a76aeba74744148b15099254d918671Owen Lin init(); 390666ea1b28a76aeba74744148b15099254d918671Owen Lin } 391666ea1b28a76aeba74744148b15099254d918671Owen Lin 392666ea1b28a76aeba74744148b15099254d918671Owen Lin enum ModifyMode { None, Move, Grow } 393666ea1b28a76aeba74744148b15099254d918671Owen Lin 394666ea1b28a76aeba74744148b15099254d918671Owen Lin private ModifyMode mMode = ModifyMode.None; 395666ea1b28a76aeba74744148b15099254d918671Owen Lin 396666ea1b28a76aeba74744148b15099254d918671Owen Lin Rect mDrawRect; // in screen space 397666ea1b28a76aeba74744148b15099254d918671Owen Lin private RectF mImageRect; // in image space 398666ea1b28a76aeba74744148b15099254d918671Owen Lin RectF mCropRect; // in image space 399666ea1b28a76aeba74744148b15099254d918671Owen Lin Matrix mMatrix; 400666ea1b28a76aeba74744148b15099254d918671Owen Lin 401666ea1b28a76aeba74744148b15099254d918671Owen Lin private boolean mMaintainAspectRatio = false; 402666ea1b28a76aeba74744148b15099254d918671Owen Lin private float mInitialAspectRatio; 403666ea1b28a76aeba74744148b15099254d918671Owen Lin private boolean mCircle = false; 404666ea1b28a76aeba74744148b15099254d918671Owen Lin 405666ea1b28a76aeba74744148b15099254d918671Owen Lin private Drawable mResizeDrawableWidth; 406666ea1b28a76aeba74744148b15099254d918671Owen Lin private Drawable mResizeDrawableHeight; 407666ea1b28a76aeba74744148b15099254d918671Owen Lin private Drawable mResizeDrawableDiagonal; 408666ea1b28a76aeba74744148b15099254d918671Owen Lin 409666ea1b28a76aeba74744148b15099254d918671Owen Lin private final Paint mFocusPaint = new Paint(); 410666ea1b28a76aeba74744148b15099254d918671Owen Lin private final Paint mNoFocusPaint = new Paint(); 411666ea1b28a76aeba74744148b15099254d918671Owen Lin private final Paint mOutlinePaint = new Paint(); 412666ea1b28a76aeba74744148b15099254d918671Owen Lin} 413