/* * Copyright (c) 2012, Codename One and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Codename One designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Codename One through http://www.codenameone.com/ if you * need additional information or have any questions. */ package com.codename1.ui.util; import com.codename1.ui.Display; import com.codename1.ui.Form; import com.codename1.ui.Graphics; import com.codename1.ui.Painter; import com.codename1.ui.animations.Animation; import com.codename1.ui.animations.CommonTransitions; import com.codename1.ui.animations.Motion; import com.codename1.ui.animations.Transition; import com.codename1.ui.events.ActionEvent; import com.codename1.ui.events.ActionListener; import com.codename1.ui.geom.Rectangle; import com.codename1.util.LazyValue; /** * Allows binding a swipe listener to the form that enables the user to swipe back to the previous * form. * * @author Shai Almog */ public class SwipeBackSupport { boolean sideSwipePotential; int initialDragY; int initialDragX; boolean dragActivated; boolean transitionRunning; int currentX; ActionListener pointerDragged; ActionListener pointerPressed; ActionListener pointerReleased; Form destinationForm; /** * Binds support for swiping to the given forms * * @param currentForm the current form * @param destination the destination form which can be created lazily */ public static void bindBack(Form currentForm, LazyValue<Form> destination) { new SwipeBackSupport().bind(currentForm, destination); } /** * Binds support for swiping to the current form * * @param destination the destination form which can be created lazily */ public static void bindBack(LazyValue<Form> destination) { new SwipeBackSupport().bind(Display.getInstance().getCurrent(), destination); } /** * Binds support for swiping to the given forms * * @param currentForm the current form * @param destination the destination form which can be created lazily */ protected void bind(final Form currentForm, final LazyValue<Form> destination) { pointerDragged = new ActionListener() { public void actionPerformed(ActionEvent evt) { if (sideSwipePotential) { final int x = evt.getX(); final int y = evt.getY(); if (Math.abs(y - initialDragY) > x - initialDragX) { sideSwipePotential = false; return; } evt.consume(); if(dragActivated) { currentX = x; Display.getInstance().getCurrent().repaint(); } else { if (x - initialDragX > Display.getInstance().convertToPixels(currentForm.getUIManager().getThemeConstant("backGestureThresholdInt", 5), true)) { dragActivated = true; destinationForm = destination.get(); startBackTransition(currentForm, destinationForm); } } } } }; pointerReleased = new ActionListener() { public void actionPerformed(ActionEvent evt) { if(dragActivated) { int destNumberX = Display.getInstance().getDisplayWidth(); int incrementsX = Display.getInstance().convertToPixels(3, true); if(currentX < destNumberX / 2) { destinationForm = currentForm; destNumberX = 0; incrementsX *= -1; } final int destNumber = destNumberX; final int increments = incrementsX; Display.getInstance().getCurrent().registerAnimated(new Animation() { public boolean animate() { currentX += increments; if(currentX > 0 && currentX >= destNumber || currentX < 0 && currentX <= destNumber) { currentX = destNumber; Transition t = destinationForm.getTransitionInAnimator(); destinationForm.setTransitionInAnimator(CommonTransitions.createEmpty()); destinationForm.show(); destinationForm.setTransitionInAnimator(t); destinationForm = null; dragActivated = false; return false; } return true; } public void paint(Graphics g) { } }); } } }; pointerPressed = new ActionListener() { public void actionPerformed(ActionEvent evt) { sideSwipePotential = false; int displayWidth = Display.getInstance().getDisplayWidth(); sideSwipePotential = !transitionRunning && evt.getX() < displayWidth / currentForm.getUIManager().getThemeConstant("sideSwipeSensitiveInt", 10); initialDragX = evt.getX(); initialDragY = evt.getY(); /*if (sideSwipePotential) { Component c = Display.getInstance().getCurrent().getComponentAt(initialDragX, initialDragY); if (c != null && c.shouldBlockSideSwipe()) { sideSwipePotential = false; } }*/ } }; currentForm.addPointerDraggedListener(pointerDragged); currentForm.addPointerReleasedListener(pointerReleased); currentForm.addPointerPressedListener(pointerPressed); } void startBackTransition(final Form currentForm, Form destination) { final Transition t = destination.getTransitionOutAnimator().copy(true); if(t instanceof CommonTransitions) { Transition originalTransition = currentForm.getTransitionOutAnimator(); currentForm.setTransitionOutAnimator(CommonTransitions.createEmpty()); Form blank = new Form() { protected boolean shouldSendPointerReleaseToOtherForm() { return true; } }; blank.addPointerDraggedListener(pointerDragged); blank.addPointerReleasedListener(pointerReleased); blank.addPointerPressedListener(pointerPressed); blank.setTransitionInAnimator(CommonTransitions.createEmpty()); blank.setTransitionOutAnimator(CommonTransitions.createEmpty()); blank.show(); currentForm.setTransitionOutAnimator(originalTransition); ((CommonTransitions)t).setMotion(new LazyValue<Motion>() { public Motion get(Object... args) { return new ManualMotion(((Integer)args[0]).intValue(), ((Integer)args[1]).intValue(), ((Integer)args[2]).intValue()); } }); t.init(currentForm, destination); t.initTransition(); blank.setGlassPane(new Painter() { public void paint(Graphics g, Rectangle rect) { t.animate(); t.paint(g); } }); } } class ManualMotion extends Motion { protected ManualMotion(int sourceValue, int destinationValue, int duration) { super(sourceValue, destinationValue, duration); } public int getValue() { int destinationValue = getDestinationValue(); int sourceValue = getSourceValue(); float ratio = ((float)currentX) / ((float)Display.getInstance().getDisplayWidth()); int dis = destinationValue - sourceValue; int val = (int)(sourceValue + (ratio * dis)); if(destinationValue < sourceValue) { return Math.max(destinationValue, val); } else { return Math.min(destinationValue, val); } } public boolean isFinished() { return false; } } }