diff options
Diffstat (limited to 'src/com/android/gallery3d/photoeditor/actions/FlipView.java')
-rw-r--r-- | src/com/android/gallery3d/photoeditor/actions/FlipView.java | 147 |
1 files changed, 147 insertions, 0 deletions
diff --git a/src/com/android/gallery3d/photoeditor/actions/FlipView.java b/src/com/android/gallery3d/photoeditor/actions/FlipView.java new file mode 100644 index 000000000..17c4343ad --- /dev/null +++ b/src/com/android/gallery3d/photoeditor/actions/FlipView.java @@ -0,0 +1,147 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License 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.android.gallery3d.photoeditor.actions; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.MotionEvent; + +/** + * View that handles touch-events to track flipping directions and angles. + */ +class FlipView extends FullscreenToolView { + + /** + * Listens to flip changes. + */ + public interface OnFlipChangeListener { + + void onAngleChanged(float horizontalDegrees, float verticalDegrees, boolean fromUser); + + void onStartTrackingTouch(); + + void onStopTrackingTouch(); + } + + private static final float FIXED_DIRECTION_THRESHOLD = 20; + + private OnFlipChangeListener listener; + private float maxFlipSpan; + private float touchStartX; + private float touchStartY; + private float currentHorizontalDegrees; + private float currentVerticalDegrees; + private float lastHorizontalDegrees; + private float lastVerticalDegrees; + private boolean fixedDirection; + private boolean fixedDirectionHorizontal; + + public FlipView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public void setOnFlipChangeListener(OnFlipChangeListener listener) { + this.listener = listener; + } + + public void setFlippedAngles(float horizontalDegrees, float verticalDegrees) { + refreshAngle(horizontalDegrees, verticalDegrees, false); + } + + /** + * Sets allowed degrees for every flip before flipping the view. + */ + public void setFlipSpan(float degrees) { + // Flip-span limits allowed flipping degrees of every flip for usability purpose; the max. + // flipped angles could be accumulated and larger than allowed flip-span. + maxFlipSpan = degrees; + } + + private float calculateAngle(boolean flipHorizontal, float x, float y) { + // Use partial length along the moving direction to calculate the flip angle. + float maxDistance = (flipHorizontal ? getWidth() : getHeight()) * 0.35f; + float moveDistance = flipHorizontal ? (x - touchStartX) : (touchStartY - y); + + if (Math.abs(moveDistance) > maxDistance) { + moveDistance = (moveDistance > 0) ? maxDistance : -maxDistance; + + if (flipHorizontal) { + touchStartX = x - moveDistance; + } else { + touchStartY = moveDistance + y; + } + } + return (moveDistance / maxDistance) * maxFlipSpan; + } + + @Override + public boolean onTouchEvent(MotionEvent ev) { + super.onTouchEvent(ev); + + if (isEnabled()) { + switch (ev.getAction()) { + case MotionEvent.ACTION_DOWN: + fixedDirection = false; + lastHorizontalDegrees = currentHorizontalDegrees; + lastVerticalDegrees = currentVerticalDegrees; + touchStartX = ev.getX(); + touchStartY = ev.getY(); + + if (listener != null) { + listener.onStartTrackingTouch(); + } + break; + + case MotionEvent.ACTION_MOVE: + // Allow only one direction for flipping during movements, and make the + // direction fixed once it exceeds threshold. + float x = ev.getX(); + float y = ev.getY(); + boolean flipHorizontal = fixedDirection ? fixedDirectionHorizontal + : (Math.abs(x - touchStartX) >= Math.abs(y - touchStartY)); + float degrees = calculateAngle(flipHorizontal, x, y); + if (!fixedDirection && (Math.abs(degrees) > FIXED_DIRECTION_THRESHOLD)) { + fixedDirection = true; + fixedDirectionHorizontal = flipHorizontal; + } + + if (flipHorizontal) { + refreshAngle(lastHorizontalDegrees + degrees, lastVerticalDegrees, true); + } else { + refreshAngle(lastHorizontalDegrees, lastVerticalDegrees + degrees, true); + } + break; + + case MotionEvent.ACTION_CANCEL: + case MotionEvent.ACTION_UP: + if (listener != null) { + listener.onStopTrackingTouch(); + } + break; + } + } + return true; + } + + private void refreshAngle(float horizontalDegrees, float verticalDegrees, boolean fromUser) { + currentHorizontalDegrees = horizontalDegrees; + currentVerticalDegrees = verticalDegrees; + if (listener != null) { + listener.onAngleChanged(horizontalDegrees, verticalDegrees, fromUser); + } + } +} |