/*
* Copyright 2013, Edmodo, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this work except in compliance with the License.
* You may obtain a copy of the License in the LICENSE file, or at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS"
* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language
* governing permissions and limitations under the License.
*/
package com.smartandroid.sa.cropper;
import android.graphics.Rect;
/**
* Abstract helper class to handle operations on a crop window Handle.
*/
abstract class HandleHelper {
// Member Variables ////////////////////////////////////////////////////////
private static final float UNFIXED_ASPECT_RATIO_CONSTANT = 1;
private Edge mHorizontalEdge;
private Edge mVerticalEdge;
// Save the Pair object as a member variable to avoid having to instantiate
// a new Object every time getActiveEdges() is called.
private EdgePair mActiveEdges;
// Constructor /////////////////////////////////////////////////////////////
/**
* Constructor.
*
* @param horizontalEdge
* the horizontal edge associated with this handle; may be null
* @param verticalEdge
* the vertical edge associated with this handle; may be null
*/
HandleHelper(Edge horizontalEdge, Edge verticalEdge) {
mHorizontalEdge = horizontalEdge;
mVerticalEdge = verticalEdge;
mActiveEdges = new EdgePair(mHorizontalEdge, mVerticalEdge);
}
// Package-Private Methods /////////////////////////////////////////////////
/**
* Updates the crop window by directly setting the Edge coordinates.
*
* @param x
* the new x-coordinate of this handle
* @param y
* the new y-coordinate of this handle
* @param imageRect
* the bounding rectangle of the image
* @param parentView
* the parent View containing the image
* @param snapRadius
* the maximum distance (in pixels) at which the crop window
* should snap to the image
*/
void updateCropWindow(float x, float y, Rect imageRect, float snapRadius) {
final EdgePair activeEdges = getActiveEdges();
final Edge primaryEdge = activeEdges.primary;
final Edge secondaryEdge = activeEdges.secondary;
if (primaryEdge != null)
primaryEdge.adjustCoordinate(x, y, imageRect, snapRadius,
UNFIXED_ASPECT_RATIO_CONSTANT);
if (secondaryEdge != null)
secondaryEdge.adjustCoordinate(x, y, imageRect, snapRadius,
UNFIXED_ASPECT_RATIO_CONSTANT);
}
/**
* Updates the crop window by directly setting the Edge coordinates; this
* method maintains a given aspect ratio.
*
* @param x
* the new x-coordinate of this handle
* @param y
* the new y-coordinate of this handle
* @param targetAspectRatio
* the aspect ratio to maintain
* @param imageRect
* the bounding rectangle of the image
* @param parentView
* the parent View containing the image
* @param snapRadius
* the maximum distance (in pixels) at which the crop window
* should snap to the image
*/
abstract void updateCropWindow(float x, float y, float targetAspectRatio,
Rect imageRect, float snapRadius);
/**
* Gets the Edges associated with this handle (i.e. the Edges that should be
* moved when this handle is dragged). This is used when we are not
* maintaining the aspect ratio.
*
* @return the active edge as a pair (the pair may contain null values for
* the <code>primary</code>, <code>secondary</code> or both fields)
*/
EdgePair getActiveEdges() {
return mActiveEdges;
}
/**
* Gets the Edges associated with this handle as an ordered Pair. The
* <code>primary</code> Edge in the pair is the determining side. This
* method is used when we need to maintain the aspect ratio.
*
* @param x
* the x-coordinate of the touch point
* @param y
* the y-coordinate of the touch point
* @param targetAspectRatio
* the aspect ratio that we are maintaining
* @return the active edges as an ordered pair
*/
EdgePair getActiveEdges(float x, float y, float targetAspectRatio) {
// Calculate the aspect ratio if this handle were dragged to the given
// x-y coordinate.
final float potentialAspectRatio = getAspectRatio(x, y);
// If the touched point is wider than the aspect ratio, then x
// is the determining side. Else, y is the determining side.
if (potentialAspectRatio > targetAspectRatio) {
mActiveEdges.primary = mVerticalEdge;
mActiveEdges.secondary = mHorizontalEdge;
} else {
mActiveEdges.primary = mHorizontalEdge;
mActiveEdges.secondary = mVerticalEdge;
}
return mActiveEdges;
}
// Private Methods /////////////////////////////////////////////////////////
/**
* Gets the aspect ratio of the resulting crop window if this handle were
* dragged to the given point.
*
* @param x
* the x-coordinate
* @param y
* the y-coordinate
* @return the aspect ratio
*/
private float getAspectRatio(float x, float y) {
// Replace the active edge coordinate with the given touch coordinate.
final float left = (mVerticalEdge == Edge.LEFT) ? x : Edge.LEFT
.getCoordinate();
final float top = (mHorizontalEdge == Edge.TOP) ? y : Edge.TOP
.getCoordinate();
final float right = (mVerticalEdge == Edge.RIGHT) ? x : Edge.RIGHT
.getCoordinate();
final float bottom = (mHorizontalEdge == Edge.BOTTOM) ? y : Edge.BOTTOM
.getCoordinate();
final float aspectRatio = AspectRatioUtil.calculateAspectRatio(left,
top, right, bottom);
return aspectRatio;
}
}