Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Unverified Commit a5906f29 authored by Cosmin Tanislav's avatar Cosmin Tanislav Committed by Michael Bestas
Browse files

SystemUI: screenshot: add extra crop boundaries

Add corner boundaries that allow resizing in both vertical and
horizontal directions at the same time.

To handle corner boundaries, split every boundary into vertical
and horizontal boundaries, and handle both vertical and horizontal
changes for all boundaries. If the boundary is a purely vertical
(top, bottom) or purely horizontal (left, right) boundary, the
opposite direction boundary will be none, and the selection won't
be changed on that selection.

Also, add a middle boundary that allows moving the current selection.

To achieve this, treat the middle boundary as composed of top and
left boundaries, and when trying to change either the top or the
left boundary while the currently dragged boundary is the middle
one, reposition the opposite boundary too.

Change-Id: I6dd703733b3d161f5979d91a124350fb1a8d52ae
parent ea5bbf9f
Loading
Loading
Loading
Loading
+101 −13
Original line number Original line Diff line number Diff line
@@ -57,7 +57,10 @@ public class CropView extends View {
    private static final String TAG = "CropView";
    private static final String TAG = "CropView";


    public enum CropBoundary {
    public enum CropBoundary {
        NONE, TOP, BOTTOM, LEFT, RIGHT
        NONE, TOP, BOTTOM, LEFT, RIGHT,
        TOP_LEFT, TOP_RIGHT, BOTTOM_LEFT, BOTTOM_RIGHT,
        // Middle crop boundary is used for dragging
        MIDDLE,
    }
    }


    private final float mCropTouchMargin;
    private final float mCropTouchMargin;
@@ -75,7 +78,8 @@ public class CropView extends View {
    private CropBoundary mCurrentDraggingBoundary = CropBoundary.NONE;
    private CropBoundary mCurrentDraggingBoundary = CropBoundary.NONE;
    private int mActivePointerId;
    private int mActivePointerId;
    // The starting value of mCurrentDraggingBoundary's crop, used to compute touch deltas.
    // The starting value of mCurrentDraggingBoundary's crop, used to compute touch deltas.
    private float mMovementStartValue;
    private float mMovementStartValueX;
    private float mMovementStartValueY;
    private float mStartingY;  // y coordinate of ACTION_DOWN
    private float mStartingY;  // y coordinate of ACTION_DOWN
    private float mStartingX;
    private float mStartingX;


@@ -168,7 +172,10 @@ public class CropView extends View {
                    mActivePointerId = event.getPointerId(0);
                    mActivePointerId = event.getPointerId(0);
                    mStartingY = event.getY();
                    mStartingY = event.getY();
                    mStartingX = event.getX();
                    mStartingX = event.getX();
                    mMovementStartValue = getBoundaryPosition(mCurrentDraggingBoundary);
                    CropBoundary hBoundary = getHorizontalBoundary(mCurrentDraggingBoundary);
                    CropBoundary vBoundary = getVerticalBoundary(mCurrentDraggingBoundary);
                    mMovementStartValueX = getBoundaryPosition(hBoundary);
                    mMovementStartValueY = getBoundaryPosition(vBoundary);
                    updateListener(MotionEvent.ACTION_DOWN, event.getX());
                    updateListener(MotionEvent.ACTION_DOWN, event.getX());
                }
                }
                return true;
                return true;
@@ -177,12 +184,14 @@ public class CropView extends View {
                    int pointerIndex = event.findPointerIndex(mActivePointerId);
                    int pointerIndex = event.findPointerIndex(mActivePointerId);
                    if (pointerIndex >= 0) {
                    if (pointerIndex >= 0) {
                        // Original pointer still active, do the move.
                        // Original pointer still active, do the move.
                        float deltaPx = isVertical(mCurrentDraggingBoundary)
                        CropBoundary hBoundary = getHorizontalBoundary(mCurrentDraggingBoundary);
                                ? event.getY(pointerIndex) - mStartingY
                        CropBoundary vBoundary = getVerticalBoundary(mCurrentDraggingBoundary);
                                : event.getX(pointerIndex) - mStartingX;
                        float deltaPxX = event.getX(pointerIndex) - mStartingX;
                        float delta = pixelDistanceToFraction((int) deltaPx,
                        float deltaPxY = event.getY(pointerIndex) - mStartingY;
                                mCurrentDraggingBoundary);
                        float deltaX = pixelDistanceToFraction((int) deltaPxX, hBoundary);
                        setBoundaryPosition(mCurrentDraggingBoundary, mMovementStartValue + delta);
                        float deltaY = pixelDistanceToFraction((int) deltaPxY, vBoundary);
                        setBoundaryPosition(hBoundary, mMovementStartValueX + deltaX);
                        setBoundaryPosition(vBoundary, mMovementStartValueY + deltaY);
                        updateListener(MotionEvent.ACTION_MOVE, event.getX(pointerIndex));
                        updateListener(MotionEvent.ACTION_MOVE, event.getX(pointerIndex));
                        invalidate();
                        invalidate();
                    }
                    }
@@ -238,15 +247,29 @@ public class CropView extends View {
     * Set the given boundary to the given value without animation.
     * Set the given boundary to the given value without animation.
     */
     */
    public void setBoundaryPosition(CropBoundary boundary, float position) {
    public void setBoundaryPosition(CropBoundary boundary, float position) {
        if (boundary == CropBoundary.NONE) {
            return;
        }

        position = (float) getAllowedValues(boundary).clamp(position);
        position = (float) getAllowedValues(boundary).clamp(position);
        switch (boundary) {
        switch (boundary) {
            case TOP:
            case TOP:
                if (mCurrentDraggingBoundary == CropBoundary.MIDDLE) {
                    // If the current dragging boundary is the middle, reposition the bottom side of
                    // the selection too, so that the selection appears to be moving.
                    mCrop.bottom = position + (mCrop.bottom - mCrop.top);
                }
                mCrop.top = position;
                mCrop.top = position;
                break;
                break;
            case BOTTOM:
            case BOTTOM:
                mCrop.bottom = position;
                mCrop.bottom = position;
                break;
                break;
            case LEFT:
            case LEFT:
                if (mCurrentDraggingBoundary == CropBoundary.MIDDLE) {
                    // If the current dragging boundary is the middle, reposition the right side of
                    // the selection too, so that the selection appears to be moving.
                    mCrop.right = position + (mCrop.right - mCrop.left);
                }
                mCrop.left = position;
                mCrop.left = position;
                break;
                break;
            case RIGHT:
            case RIGHT:
@@ -274,6 +297,38 @@ public class CropView extends View {
        return 0;
        return 0;
    }
    }


    private CropBoundary getVerticalBoundary(CropBoundary boundary) {
        switch (boundary) {
            case TOP:
            case TOP_LEFT:
            case TOP_RIGHT:
            case MIDDLE:
                return CropBoundary.TOP;
            case BOTTOM:
            case BOTTOM_LEFT:
            case BOTTOM_RIGHT:
                return CropBoundary.BOTTOM;
            default:
                return CropBoundary.NONE;
        }
    }

    private CropBoundary getHorizontalBoundary(CropBoundary boundary) {
        switch (boundary) {
            case LEFT:
            case TOP_LEFT:
            case BOTTOM_LEFT:
            case MIDDLE:
                return CropBoundary.LEFT;
            case RIGHT:
            case TOP_RIGHT:
            case BOTTOM_RIGHT:
                return CropBoundary.RIGHT;
            default:
                return CropBoundary.NONE;
        }
    }

    private static boolean isVertical(CropBoundary boundary) {
    private static boolean isVertical(CropBoundary boundary) {
        return boundary == CropBoundary.TOP || boundary == CropBoundary.BOTTOM;
        return boundary == CropBoundary.TOP || boundary == CropBoundary.BOTTOM;
    }
    }
@@ -349,6 +404,11 @@ public class CropView extends View {
    private Range getAllowedValues(CropBoundary boundary) {
    private Range getAllowedValues(CropBoundary boundary) {
        switch (boundary) {
        switch (boundary) {
            case TOP:
            case TOP:
                if (mCurrentDraggingBoundary == CropBoundary.MIDDLE) {
                    // When the current dragging boundary is the middle, do not let the user move
                    // the selection past the bottom edge.
                    return new Range<>(0f, 1f - (mCrop.bottom - mCrop.top));
                }
                return new Range<>(0f,
                return new Range<>(0f,
                        mCrop.bottom - pixelDistanceToFraction(mCropTouchMargin,
                        mCrop.bottom - pixelDistanceToFraction(mCropTouchMargin,
                                CropBoundary.BOTTOM));
                                CropBoundary.BOTTOM));
@@ -357,6 +417,11 @@ public class CropView extends View {
                        mCrop.top + pixelDistanceToFraction(mCropTouchMargin,
                        mCrop.top + pixelDistanceToFraction(mCropTouchMargin,
                                CropBoundary.TOP), 1f);
                                CropBoundary.TOP), 1f);
            case LEFT:
            case LEFT:
                if (mCurrentDraggingBoundary == CropBoundary.MIDDLE) {
                    // When the current dragging boundary is the middle, do not let the user move
                    // the selection past the right edge.
                    return new Range<>(0f, 1f - (mCrop.right - mCrop.left));
                }
                return new Range<>(0f,
                return new Range<>(0f,
                        mCrop.right - pixelDistanceToFraction(mCropTouchMargin,
                        mCrop.right - pixelDistanceToFraction(mCropTouchMargin,
                                CropBoundary.RIGHT));
                                CropBoundary.RIGHT));
@@ -373,16 +438,17 @@ public class CropView extends View {
     * @param x coordinate of the relevant pointer.
     * @param x coordinate of the relevant pointer.
     */
     */
    private void updateListener(int action, float x) {
    private void updateListener(int action, float x) {
        if (mCropInteractionListener != null && isVertical(mCurrentDraggingBoundary)) {
        CropBoundary boundary = getVerticalBoundary(mCurrentDraggingBoundary);
            float boundaryPosition = getBoundaryPosition(mCurrentDraggingBoundary);
        if (mCropInteractionListener != null && boundary != CropBoundary.NONE) {
            float boundaryPosition = getBoundaryPosition(boundary);
            switch (action) {
            switch (action) {
                case MotionEvent.ACTION_DOWN:
                case MotionEvent.ACTION_DOWN:
                    mCropInteractionListener.onCropDragStarted(mCurrentDraggingBoundary,
                    mCropInteractionListener.onCropDragStarted(boundary,
                            boundaryPosition, fractionToVerticalPixels(boundaryPosition),
                            boundaryPosition, fractionToVerticalPixels(boundaryPosition),
                            (mCrop.left + mCrop.right) / 2, x);
                            (mCrop.left + mCrop.right) / 2, x);
                    break;
                    break;
                case MotionEvent.ACTION_MOVE:
                case MotionEvent.ACTION_MOVE:
                    mCropInteractionListener.onCropDragMoved(mCurrentDraggingBoundary,
                    mCropInteractionListener.onCropDragMoved(boundary,
                            boundaryPosition, fractionToVerticalPixels(boundaryPosition),
                            boundaryPosition, fractionToVerticalPixels(boundaryPosition),
                            (mCrop.left + mCrop.right) / 2, x);
                            (mCrop.left + mCrop.right) / 2, x);
                    break;
                    break;
@@ -462,10 +528,25 @@ public class CropView extends View {


    private CropBoundary nearestBoundary(MotionEvent event, int topPx, int bottomPx, int leftPx,
    private CropBoundary nearestBoundary(MotionEvent event, int topPx, int bottomPx, int leftPx,
            int rightPx) {
            int rightPx) {
        boolean isCloseToLeft = Math.abs(event.getX() - leftPx) < mCropTouchMargin;
        boolean isCloseToRight = Math.abs(event.getX() - rightPx) < mCropTouchMargin;

        if (Math.abs(event.getY() - topPx) < mCropTouchMargin) {
        if (Math.abs(event.getY() - topPx) < mCropTouchMargin) {
            if (isCloseToLeft) {
                return CropBoundary.TOP_LEFT;
            }
            if (isCloseToRight) {
                return CropBoundary.TOP_RIGHT;
            }
            return CropBoundary.TOP;
            return CropBoundary.TOP;
        }
        }
        if (Math.abs(event.getY() - bottomPx) < mCropTouchMargin) {
        if (Math.abs(event.getY() - bottomPx) < mCropTouchMargin) {
            if (isCloseToLeft) {
                return CropBoundary.BOTTOM_LEFT;
            }
            if (isCloseToRight) {
                return CropBoundary.BOTTOM_RIGHT;
            }
            return CropBoundary.BOTTOM;
            return CropBoundary.BOTTOM;
        }
        }
        if (event.getY() > topPx || event.getY() < bottomPx) {
        if (event.getY() > topPx || event.getY() < bottomPx) {
@@ -476,6 +557,13 @@ public class CropView extends View {
                return CropBoundary.RIGHT;
                return CropBoundary.RIGHT;
            }
            }
        }
        }

        float x = event.getX();
        float y = event.getY();
        if (x > leftPx && x < rightPx && y > topPx && y < bottomPx) {
            return CropBoundary.MIDDLE;
        }

        return CropBoundary.NONE;
        return CropBoundary.NONE;
    }
    }