Home | History | Annotate | Download | only in imageshow
      1 /*
      2  * Copyright (C) 2012 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 
     17 package com.android.gallery3d.filtershow.imageshow;
     18 
     19 import android.content.Context;
     20 import android.content.res.Resources;
     21 import android.graphics.Bitmap;
     22 import android.graphics.Canvas;
     23 import android.graphics.Color;
     24 import android.graphics.Matrix;
     25 import android.graphics.Paint;
     26 import android.graphics.RectF;
     27 import android.graphics.drawable.Drawable;
     28 import android.util.AttributeSet;
     29 import android.view.LayoutInflater;
     30 import android.view.MenuItem;
     31 import android.view.View;
     32 import android.widget.LinearLayout;
     33 import android.widget.PopupMenu;
     34 
     35 import com.android.gallery3d.R;
     36 import com.android.gallery3d.filtershow.crop.BoundedRect;
     37 import com.android.gallery3d.filtershow.crop.CropExtras;
     38 import com.android.gallery3d.filtershow.crop.CropMath;
     39 import com.android.gallery3d.filtershow.editors.EditorCrop;
     40 import com.android.gallery3d.filtershow.ui.FramedTextButton;
     41 
     42 public class ImageCrop extends ImageGeometry {
     43     private static final boolean LOGV = false;
     44 
     45     // Sides
     46     private static final int MOVE_LEFT = 1;
     47     private static final int MOVE_TOP = 2;
     48     private static final int MOVE_RIGHT = 4;
     49     private static final int MOVE_BOTTOM = 8;
     50     private static final int MOVE_BLOCK = 16;
     51 
     52     // Corners
     53     private static final int TOP_LEFT = MOVE_TOP | MOVE_LEFT;
     54     private static final int TOP_RIGHT = MOVE_TOP | MOVE_RIGHT;
     55     private static final int BOTTOM_RIGHT = MOVE_BOTTOM | MOVE_RIGHT;
     56     private static final int BOTTOM_LEFT = MOVE_BOTTOM | MOVE_LEFT;
     57 
     58     private static int mMinSideSize = 100;
     59     private static int mTouchTolerance = 45;
     60 
     61     private boolean mFirstDraw = true;
     62     private float mAspectWidth = 1;
     63     private float mAspectHeight = 1;
     64     private boolean mFixAspectRatio = false;
     65 
     66     private float mLastRot = 0;
     67 
     68     private BoundedRect mBounded = null;
     69     private int movingEdges;
     70     private final Drawable cropIndicator;
     71     private final int indicatorSize;
     72     private final int mBorderColor = Color.argb(128, 255, 255, 255);
     73 
     74     // Offset between crop center and photo center
     75     private float[] mOffset = {
     76             0, 0
     77     };
     78     private CropExtras mCropExtras = null;
     79     private boolean mDoingCropIntentAction = false;
     80 
     81     private static final String LOGTAG = "ImageCrop";
     82 
     83     private String mAspect = "";
     84     private static int mAspectTextSize = 24;
     85 
     86     private boolean mFixedAspect = false;
     87 
     88     private EditorCrop mEditorCrop;
     89 
     90     public static void setAspectTextSize(int textSize) {
     91         mAspectTextSize = textSize;
     92     }
     93 
     94     public void setAspectString(String a) {
     95         mAspect = a;
     96     }
     97 
     98     private static final Paint gPaint = new Paint();
     99 
    100     public ImageCrop(Context context) {
    101         super(context);
    102         Resources resources = context.getResources();
    103         cropIndicator = resources.getDrawable(R.drawable.camera_crop);
    104         indicatorSize = (int) resources.getDimension(R.dimen.crop_indicator_size);
    105     }
    106 
    107     public ImageCrop(Context context, AttributeSet attrs) {
    108         super(context, attrs);
    109         Resources resources = context.getResources();
    110         cropIndicator = resources.getDrawable(R.drawable.camera_crop);
    111         indicatorSize = (int) resources.getDimension(R.dimen.crop_indicator_size);
    112     }
    113 
    114     @Override
    115     public String getName() {
    116         return getContext().getString(R.string.crop);
    117     }
    118 
    119     private void swapAspect() {
    120         if (mDoingCropIntentAction) {
    121             return;
    122         }
    123         float temp = mAspectWidth;
    124         mAspectWidth = mAspectHeight;
    125         mAspectHeight = temp;
    126     }
    127 
    128     /**
    129      * Set tolerance for crop marker selection (in pixels)
    130      */
    131     public static void setTouchTolerance(int tolerance) {
    132         mTouchTolerance = tolerance;
    133     }
    134 
    135     /**
    136      * Set minimum side length for crop box (in pixels)
    137      */
    138     public static void setMinCropSize(int minHeightWidth) {
    139         mMinSideSize = minHeightWidth;
    140     }
    141 
    142     public void setExtras(CropExtras e) {
    143         mCropExtras = e;
    144     }
    145 
    146     public void setCropActionFlag(boolean f) {
    147         mDoingCropIntentAction = f;
    148     }
    149 
    150     public void apply(float w, float h) {
    151         mFixAspectRatio = true;
    152         mAspectWidth = w;
    153         mAspectHeight = h;
    154         setLocalCropBounds(getUntranslatedStraightenCropBounds(getLocalPhotoBounds(),
    155                 getLocalStraighten()));
    156         cropSetup();
    157         saveAndSetPreset();
    158         invalidate();
    159     }
    160 
    161     public void applyOriginal() {
    162         mFixAspectRatio = true;
    163         RectF photobounds = getLocalPhotoBounds();
    164         float w = photobounds.width();
    165         float h = photobounds.height();
    166         float scale = Math.min(w, h);
    167         mAspectWidth = w / scale;
    168         mAspectHeight = h / scale;
    169         setLocalCropBounds(getUntranslatedStraightenCropBounds(photobounds,
    170                 getLocalStraighten()));
    171         cropSetup();
    172         saveAndSetPreset();
    173         invalidate();
    174     }
    175 
    176     public void applyClear() {
    177         mFixAspectRatio = false;
    178         mAspectWidth = 1;
    179         mAspectHeight = 1;
    180         setLocalCropBounds(getUntranslatedStraightenCropBounds(getLocalPhotoBounds(),
    181                 getLocalStraighten()));
    182         cropSetup();
    183         saveAndSetPreset();
    184         invalidate();
    185     }
    186 
    187     public void clear() {
    188         if (mCropExtras != null) {
    189             int x = mCropExtras.getAspectX();
    190             int y = mCropExtras.getAspectY();
    191             if (mDoingCropIntentAction && x > 0 && y > 0) {
    192                 apply(x, y);
    193             }
    194         } else {
    195             applyClear();
    196         }
    197     }
    198 
    199     private Matrix getPhotoBoundDisplayedMatrix() {
    200         float[] displayCenter = new float[2];
    201         RectF scaledCrop = new RectF();
    202         RectF scaledPhoto = new RectF();
    203         float scale = getTransformState(scaledPhoto, scaledCrop, displayCenter);
    204         Matrix m = GeometryMetadata.buildCenteredPhotoMatrix(scaledPhoto, scaledCrop,
    205                 getLocalRotation(), getLocalStraighten(), getLocalFlip(), displayCenter);
    206         m.preScale(scale, scale);
    207         return m;
    208     }
    209 
    210     private Matrix getCropBoundDisplayedMatrix() {
    211         float[] displayCenter = new float[2];
    212         RectF scaledCrop = new RectF();
    213         RectF scaledPhoto = new RectF();
    214         float scale = getTransformState(scaledPhoto, scaledCrop, displayCenter);
    215         Matrix m1 = GeometryMetadata.buildWanderingCropMatrix(scaledPhoto, scaledCrop,
    216                 getLocalRotation(), getLocalStraighten(), getLocalFlip(), displayCenter);
    217         m1.preScale(scale, scale);
    218         return m1;
    219     }
    220 
    221     /**
    222      * Takes the rotated corners of a rectangle and returns the angle; sets
    223      * unrotated to be the unrotated version of the rectangle.
    224      */
    225     private static float getUnrotated(float[] rotatedRect, float[] center, RectF unrotated) {
    226         float dy = rotatedRect[1] - rotatedRect[3];
    227         float dx = rotatedRect[0] - rotatedRect[2];
    228         float angle = (float) (Math.atan(dy / dx) * 180 / Math.PI);
    229         Matrix m = new Matrix();
    230         m.setRotate(-angle, center[0], center[1]);
    231         float[] unrotatedRect = new float[rotatedRect.length];
    232         m.mapPoints(unrotatedRect, rotatedRect);
    233         unrotated.set(CropMath.trapToRect(unrotatedRect));
    234         return angle;
    235     }
    236 
    237     /**
    238      * Sets cropped bounds; modifies the bounds if it's smaller than the allowed
    239      * dimensions.
    240      */
    241     public boolean setCropBounds(RectF bounds) {
    242         RectF cbounds = new RectF(bounds);
    243         Matrix mc = getCropBoundDisplayedMatrix();
    244         Matrix mcInv = new Matrix();
    245         mc.invert(mcInv);
    246         mcInv.mapRect(cbounds);
    247         // Avoid cropping smaller than minimum
    248         float newWidth = cbounds.width();
    249         float newHeight = cbounds.height();
    250         float scale = getTransformState(null, null, null);
    251         float minWidthHeight = mMinSideSize / scale;
    252         RectF pbounds = getLocalPhotoBounds();
    253 
    254         // if photo is smaller than minimum, refuse to set crop bounds
    255         if (pbounds.width() < minWidthHeight || pbounds.height() < minWidthHeight) {
    256             return false;
    257         }
    258 
    259         // if incoming crop is smaller than minimum, refuse to set crop bounds
    260         if (newWidth < minWidthHeight || newHeight < minWidthHeight) {
    261             return false;
    262         }
    263 
    264         float newX = bounds.centerX() - (getWidth() / 2f);
    265         float newY = bounds.centerY() - (getHeight() / 2f);
    266         mOffset[0] = newX;
    267         mOffset[1] = newY;
    268 
    269         setLocalCropBounds(cbounds);
    270         invalidate();
    271         return true;
    272     }
    273 
    274     private BoundedRect getBoundedCrop(RectF crop) {
    275         RectF photo = getLocalPhotoBounds();
    276         Matrix mp = getPhotoBoundDisplayedMatrix();
    277         float[] photoCorners = CropMath.getCornersFromRect(photo);
    278         float[] photoCenter = {
    279                 photo.centerX(), photo.centerY()
    280         };
    281         mp.mapPoints(photoCorners);
    282         mp.mapPoints(photoCenter);
    283         RectF scaledPhoto = new RectF();
    284         float angle = getUnrotated(photoCorners, photoCenter, scaledPhoto);
    285         return new BoundedRect(angle, scaledPhoto, crop);
    286     }
    287 
    288     private void detectMovingEdges(float x, float y) {
    289         Matrix m = getCropBoundDisplayedMatrix();
    290         RectF cropped = getLocalCropBounds();
    291         m.mapRect(cropped);
    292         mBounded = getBoundedCrop(cropped);
    293         movingEdges = 0;
    294 
    295         float left = Math.abs(x - cropped.left);
    296         float right = Math.abs(x - cropped.right);
    297         float top = Math.abs(y - cropped.top);
    298         float bottom = Math.abs(y - cropped.bottom);
    299 
    300         // Check left or right.
    301         if ((left <= mTouchTolerance) && ((y + mTouchTolerance) >= cropped.top)
    302                 && ((y - mTouchTolerance) <= cropped.bottom) && (left < right)) {
    303             movingEdges |= MOVE_LEFT;
    304         }
    305         else if ((right <= mTouchTolerance) && ((y + mTouchTolerance) >= cropped.top)
    306                 && ((y - mTouchTolerance) <= cropped.bottom)) {
    307             movingEdges |= MOVE_RIGHT;
    308         }
    309 
    310         // Check top or bottom.
    311         if ((top <= mTouchTolerance) && ((x + mTouchTolerance) >= cropped.left)
    312                 && ((x - mTouchTolerance) <= cropped.right) && (top < bottom)) {
    313             movingEdges |= MOVE_TOP;
    314         }
    315         else if ((bottom <= mTouchTolerance) && ((x + mTouchTolerance) >= cropped.left)
    316                 && ((x - mTouchTolerance) <= cropped.right)) {
    317             movingEdges |= MOVE_BOTTOM;
    318         }
    319         if (movingEdges == 0) {
    320             movingEdges = MOVE_BLOCK;
    321         }
    322         if (mFixAspectRatio && (movingEdges != MOVE_BLOCK)) {
    323             movingEdges = fixEdgeToCorner(movingEdges);
    324         }
    325         invalidate();
    326     }
    327 
    328     private int fixEdgeToCorner(int moving_edges) {
    329         if (moving_edges == MOVE_LEFT) {
    330             moving_edges |= MOVE_TOP;
    331         }
    332         if (moving_edges == MOVE_TOP) {
    333             moving_edges |= MOVE_LEFT;
    334         }
    335         if (moving_edges == MOVE_RIGHT) {
    336             moving_edges |= MOVE_BOTTOM;
    337         }
    338         if (moving_edges == MOVE_BOTTOM) {
    339             moving_edges |= MOVE_RIGHT;
    340         }
    341         return moving_edges;
    342     }
    343 
    344     private RectF fixedCornerResize(RectF r, int moving_corner, float dx, float dy) {
    345         RectF newCrop = null;
    346         // Fix opposite corner in place and move sides
    347         if (moving_corner == BOTTOM_RIGHT) {
    348             newCrop = new RectF(r.left, r.top, r.left + r.width() + dx, r.top + r.height()
    349                     + dy);
    350         } else if (moving_corner == BOTTOM_LEFT) {
    351             newCrop = new RectF(r.right - r.width() + dx, r.top, r.right, r.top + r.height()
    352                     + dy);
    353         } else if (moving_corner == TOP_LEFT) {
    354             newCrop = new RectF(r.right - r.width() + dx, r.bottom - r.height() + dy,
    355                     r.right, r.bottom);
    356         } else if (moving_corner == TOP_RIGHT) {
    357             newCrop = new RectF(r.left, r.bottom - r.height() + dy, r.left
    358                     + r.width() + dx, r.bottom);
    359         }
    360         return newCrop;
    361     }
    362 
    363     private void moveEdges(float dX, float dY) {
    364         RectF crop = mBounded.getInner();
    365 
    366         Matrix mc = getCropBoundDisplayedMatrix();
    367 
    368         RectF photo = getLocalPhotoBounds();
    369         Matrix mp = getPhotoBoundDisplayedMatrix();
    370         float[] photoCorners = CropMath.getCornersFromRect(photo);
    371         float[] photoCenter = {
    372                 photo.centerX(), photo.centerY()
    373         };
    374         mp.mapPoints(photoCorners);
    375         mp.mapPoints(photoCenter);
    376 
    377         float minWidthHeight = mMinSideSize;
    378 
    379         if (movingEdges == MOVE_BLOCK) {
    380             mBounded.moveInner(-dX, -dY);
    381             RectF r = mBounded.getInner();
    382             setCropBounds(r);
    383             return;
    384         } else {
    385             float dx = 0;
    386             float dy = 0;
    387 
    388             if ((movingEdges & MOVE_LEFT) != 0) {
    389                 dx = Math.min(crop.left + dX, crop.right - minWidthHeight) - crop.left;
    390             }
    391             if ((movingEdges & MOVE_TOP) != 0) {
    392                 dy = Math.min(crop.top + dY, crop.bottom - minWidthHeight) - crop.top;
    393             }
    394             if ((movingEdges & MOVE_RIGHT) != 0) {
    395                 dx = Math.max(crop.right + dX, crop.left + minWidthHeight)
    396                         - crop.right;
    397             }
    398             if ((movingEdges & MOVE_BOTTOM) != 0) {
    399                 dy = Math.max(crop.bottom + dY, crop.top + minWidthHeight)
    400                         - crop.bottom;
    401             }
    402 
    403             if (mFixAspectRatio) {
    404                 float[] l1 = {
    405                         crop.left, crop.bottom
    406                 };
    407                 float[] l2 = {
    408                         crop.right, crop.top
    409                 };
    410                 if (movingEdges == TOP_LEFT || movingEdges == BOTTOM_RIGHT) {
    411                     l1[1] = crop.top;
    412                     l2[1] = crop.bottom;
    413                 }
    414                 float[] b = {
    415                         l1[0] - l2[0], l1[1] - l2[1]
    416                 };
    417                 float[] disp = {
    418                         dx, dy
    419                 };
    420                 float[] bUnit = GeometryMath.normalize(b);
    421                 float sp = GeometryMath.scalarProjection(disp, bUnit);
    422                 dx = sp * bUnit[0];
    423                 dy = sp * bUnit[1];
    424                 RectF newCrop = fixedCornerResize(crop, movingEdges, dx, dy);
    425 
    426                 mBounded.fixedAspectResizeInner(newCrop);
    427                 newCrop = mBounded.getInner();
    428                 setCropBounds(newCrop);
    429                 return;
    430             } else {
    431                 if ((movingEdges & MOVE_LEFT) != 0) {
    432                     crop.left += dx;
    433                 }
    434                 if ((movingEdges & MOVE_TOP) != 0) {
    435                     crop.top += dy;
    436                 }
    437                 if ((movingEdges & MOVE_RIGHT) != 0) {
    438                     crop.right += dx;
    439                 }
    440                 if ((movingEdges & MOVE_BOTTOM) != 0) {
    441                     crop.bottom += dy;
    442                 }
    443             }
    444         }
    445         mBounded.resizeInner(crop);
    446         crop = mBounded.getInner();
    447         setCropBounds(crop);
    448     }
    449 
    450     private void drawIndicator(Canvas canvas, Drawable indicator, float centerX, float centerY) {
    451         int left = (int) centerX - indicatorSize / 2;
    452         int top = (int) centerY - indicatorSize / 2;
    453         indicator.setBounds(left, top, left + indicatorSize, top + indicatorSize);
    454         indicator.draw(canvas);
    455     }
    456 
    457     @Override
    458     protected void setActionDown(float x, float y) {
    459         super.setActionDown(x, y);
    460         detectMovingEdges(x + mOffset[0], y + mOffset[1]);
    461 
    462     }
    463 
    464     @Override
    465     protected void setActionUp() {
    466         super.setActionUp();
    467         movingEdges = 0;
    468     }
    469 
    470     @Override
    471     protected void setActionMove(float x, float y) {
    472 
    473         if (movingEdges != 0) {
    474             moveEdges(x - mCurrentX, y - mCurrentY);
    475         }
    476         super.setActionMove(x, y);
    477 
    478     }
    479 
    480     @Override
    481     protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    482         setActionUp();
    483         cropSetup();
    484         invalidate();
    485     }
    486 
    487     private void cropSetup() {
    488         RectF crop = getLocalCropBounds();
    489         Matrix m = getCropBoundDisplayedMatrix();
    490         m.mapRect(crop);
    491         if (mFixAspectRatio) {
    492             CropMath.fixAspectRatio(crop, mAspectWidth, mAspectHeight);
    493         }
    494         float dCentX = getWidth() / 2;
    495         float dCentY = getHeight() / 2;
    496 
    497         BoundedRect r = getBoundedCrop(crop);
    498         crop = r.getInner();
    499         if (!setCropBounds(crop)) {
    500             float h = mMinSideSize / 2;
    501             float wScale = 1;
    502             float hScale = mAspectHeight / mAspectWidth;
    503             if (hScale < 1) {
    504                 wScale = mAspectWidth / mAspectHeight;
    505                 hScale = 1;
    506             }
    507             crop.set(dCentX - h * wScale, dCentY - h * hScale, dCentX + h * wScale, dCentY + h
    508                     * hScale);
    509             if (mFixAspectRatio) {
    510                 CropMath.fixAspectRatio(crop, mAspectWidth, mAspectHeight);
    511             }
    512             r.setInner(crop);
    513             crop = r.getInner();
    514             if (!setCropBounds(crop)) {
    515                 crop.set(dCentX - h, dCentY - h, dCentX + h, dCentY + h);
    516                 r.setInner(crop);
    517                 crop = r.getInner();
    518                 setCropBounds(crop);
    519             }
    520         }
    521     }
    522 
    523     @Override
    524     public void imageLoaded() {
    525         super.imageLoaded();
    526         syncLocalToMasterGeometry();
    527         clear();
    528         invalidate();
    529     }
    530 
    531     @Override
    532     protected void gainedVisibility() {
    533         float rot = getLocalRotation();
    534         // if has changed orientation via rotate
    535         if (((int) ((rot - mLastRot) / 90)) % 2 != 0) {
    536             swapAspect();
    537         }
    538         cropSetup();
    539         mFirstDraw = true;
    540     }
    541 
    542     @Override
    543     public void resetParameter() {
    544         super.resetParameter();
    545     }
    546 
    547     @Override
    548     protected void lostVisibility() {
    549         mLastRot = getLocalRotation();
    550     }
    551 
    552     private void drawRuleOfThird(Canvas canvas, RectF bounds, Paint p) {
    553         float stepX = bounds.width() / 3.0f;
    554         float stepY = bounds.height() / 3.0f;
    555         float x = bounds.left + stepX;
    556         float y = bounds.top + stepY;
    557         for (int i = 0; i < 2; i++) {
    558             canvas.drawLine(x, bounds.top, x, bounds.bottom, p);
    559             x += stepX;
    560         }
    561         for (int j = 0; j < 2; j++) {
    562             canvas.drawLine(bounds.left, y, bounds.right, y, p);
    563             y += stepY;
    564         }
    565     }
    566 
    567     @Override
    568     protected void drawShape(Canvas canvas, Bitmap image) {
    569         gPaint.setAntiAlias(true);
    570         gPaint.setARGB(255, 255, 255, 255);
    571 
    572         if (mFirstDraw) {
    573             cropSetup();
    574             mFirstDraw = false;
    575         }
    576 
    577         RectF crop = drawTransformed(canvas, image, gPaint, mOffset);
    578         gPaint.setColor(mBorderColor);
    579         gPaint.setStrokeWidth(3);
    580         gPaint.setStyle(Paint.Style.STROKE);
    581 
    582         boolean doThirds = true;
    583 
    584         if (mFixAspectRatio) {
    585             float spotlightX = 0;
    586             float spotlightY = 0;
    587             if (mCropExtras != null) {
    588                 spotlightX = mCropExtras.getSpotlightX();
    589                 spotlightY = mCropExtras.getSpotlightY();
    590             }
    591             if (mDoingCropIntentAction && spotlightX > 0 && spotlightY > 0) {
    592                 float sx = crop.width() * spotlightX;
    593                 float sy = crop.height() * spotlightY;
    594                 float cx = crop.centerX();
    595                 float cy = crop.centerY();
    596                 RectF r1 = new RectF(cx - sx / 2, cy - sy / 2, cx + sx / 2, cy + sy / 2);
    597                 float temp = sx;
    598                 sx = sy;
    599                 sy = temp;
    600                 RectF r2 = new RectF(cx - sx / 2, cy - sy / 2, cx + sx / 2, cy + sy / 2);
    601                 canvas.drawRect(r1, gPaint);
    602                 canvas.drawRect(r2, gPaint);
    603                 doThirds = false;
    604             } else {
    605                 float w = crop.width();
    606                 float h = crop.height();
    607                 float diag = (float) Math.sqrt(w * w + h * h);
    608 
    609                 float dash_len = 20;
    610                 int num_intervals = (int) (diag / dash_len);
    611                 float[] tl = {
    612                         crop.left, crop.top
    613                 };
    614                 float centX = tl[0] + w / 2;
    615                 float centY = tl[1] + h / 2 + 5;
    616                 float[] br = {
    617                         crop.right, crop.bottom
    618                 };
    619                 float[] vec = GeometryMath.getUnitVectorFromPoints(tl, br);
    620 
    621                 float[] counter = tl;
    622                 for (int x = 0; x < num_intervals; x++) {
    623                     float tempX = counter[0] + vec[0] * dash_len;
    624                     float tempY = counter[1] + vec[1] * dash_len;
    625                     if ((x % 2) == 0 && Math.abs(x - num_intervals / 2) > 2) {
    626                         canvas.drawLine(counter[0], counter[1], tempX, tempY, gPaint);
    627                     }
    628                     counter[0] = tempX;
    629                     counter[1] = tempY;
    630                 }
    631 
    632                 gPaint.setTextAlign(Paint.Align.CENTER);
    633                 gPaint.setTextSize(mAspectTextSize);
    634                 canvas.drawText(mAspect, centX, centY, gPaint);
    635             }
    636         }
    637 
    638         if (doThirds) {
    639             drawRuleOfThird(canvas, crop, gPaint);
    640 
    641         }
    642 
    643         RectF scaledCrop = crop;
    644         boolean notMoving = (movingEdges == 0);
    645         if (mFixAspectRatio) {
    646             if ((movingEdges == TOP_LEFT) || notMoving) {
    647                 drawIndicator(canvas, cropIndicator, scaledCrop.left, scaledCrop.top);
    648             }
    649             if ((movingEdges == TOP_RIGHT) || notMoving) {
    650                 drawIndicator(canvas, cropIndicator, scaledCrop.right, scaledCrop.top);
    651             }
    652             if ((movingEdges == BOTTOM_LEFT) || notMoving) {
    653                 drawIndicator(canvas, cropIndicator, scaledCrop.left, scaledCrop.bottom);
    654             }
    655             if ((movingEdges == BOTTOM_RIGHT) || notMoving) {
    656                 drawIndicator(canvas, cropIndicator, scaledCrop.right, scaledCrop.bottom);
    657             }
    658         } else {
    659             if (((movingEdges & MOVE_TOP) != 0) || notMoving) {
    660                 drawIndicator(canvas, cropIndicator, scaledCrop.centerX(), scaledCrop.top);
    661             }
    662             if (((movingEdges & MOVE_BOTTOM) != 0) || notMoving) {
    663                 drawIndicator(canvas, cropIndicator, scaledCrop.centerX(), scaledCrop.bottom);
    664             }
    665             if (((movingEdges & MOVE_LEFT) != 0) || notMoving) {
    666                 drawIndicator(canvas, cropIndicator, scaledCrop.left, scaledCrop.centerY());
    667             }
    668             if (((movingEdges & MOVE_RIGHT) != 0) || notMoving) {
    669                 drawIndicator(canvas, cropIndicator, scaledCrop.right, scaledCrop.centerY());
    670             }
    671         }
    672     }
    673 
    674     public void setAspectButton(int itemId) {
    675         switch (itemId) {
    676             case R.id.crop_menu_1to1: {
    677                 String t = getActivity().getString(R.string.aspect1to1_effect);
    678                 apply(1, 1);
    679                 setAspectString(t);
    680                 break;
    681             }
    682             case R.id.crop_menu_4to3: {
    683                 String t = getActivity().getString(R.string.aspect4to3_effect);
    684                 apply(4, 3);
    685                 setAspectString(t);
    686                 break;
    687             }
    688             case R.id.crop_menu_3to4: {
    689                 String t = getActivity().getString(R.string.aspect3to4_effect);
    690                 apply(3, 4);
    691                 setAspectString(t);
    692                 break;
    693             }
    694             case R.id.crop_menu_5to7: {
    695                 String t = getActivity().getString(R.string.aspect5to7_effect);
    696                 apply(5, 7);
    697                 setAspectString(t);
    698                 break;
    699             }
    700             case R.id.crop_menu_7to5: {
    701                 String t = getActivity().getString(R.string.aspect7to5_effect);
    702                 apply(7, 5);
    703                 setAspectString(t);
    704                 break;
    705             }
    706             case R.id.crop_menu_none: {
    707                 String t = getActivity().getString(R.string.aspectNone_effect);
    708                 applyClear();
    709                 setAspectString(t);
    710                 break;
    711             }
    712             case R.id.crop_menu_original: {
    713                 String t = getActivity().getString(R.string.aspectOriginal_effect);
    714                 applyOriginal();
    715                 setAspectString(t);
    716                 break;
    717             }
    718         }
    719         invalidate();
    720     }
    721 
    722     public void setFixedAspect(boolean fixedAspect) {
    723         mFixedAspect = fixedAspect;
    724     }
    725 
    726     @Override
    727     public boolean useUtilityPanel() {
    728         // Only shows the aspect ratio popup if we are not fixed
    729         return !mFixedAspect;
    730     }
    731 
    732     public void setEditor(EditorCrop editorCrop) {
    733         mEditorCrop = editorCrop;
    734     }
    735 
    736 }
    737