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