com.codename1.ui.animations.MorphTransition Maven / Gradle / Ivy
/*
* 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.animations;
import com.codename1.ui.Component;
import com.codename1.ui.Container;
import com.codename1.ui.Form;
import com.codename1.ui.Graphics;
import com.codename1.ui.Label;
import com.codename1.ui.geom.Dimension;
import java.util.HashMap;
import java.util.Iterator;
/**
* A transition inspired by the Android L release morph activity effect allowing
* a set of components in one form/container to morph into another in a different
* container/form.
*
* @author Shai Almog
*/
public class MorphTransition extends Transition {
private int duration;
private HashMap fromTo = new HashMap();
private CC[] fromToComponents;
private Motion animationMotion;
private boolean finished;
private MorphTransition() {}
/**
* {@inheritDoc}
*/
public Transition copy(boolean reverse){
MorphTransition m = create(duration);
if(reverse) {
Iterator keyIterator = fromTo.keySet().iterator();
while(keyIterator.hasNext()) {
String k = keyIterator.next();
String v = fromTo.get(k);
m.fromTo.put(v, k);
}
} else {
m.fromTo.putAll(fromTo);
}
return m;
}
/**
* Creates a transition with the given duration, this transition should be modified with the
* builder methods such as morph
* @param duration the duration of the transition
* @return a new Morph transition instance
*/
public static MorphTransition create(int duration) {
MorphTransition mt = new MorphTransition();
mt.duration = duration;
return mt;
}
/**
* Morphs the component with the given source name in the source container hierarchy
* to the component with the same name in the destination hierarchy
* @param cmp the compoennt name
* @return this so morph operations can be chained as MorphTransition t = MorphTransition.create(300).morph("a").("c");
*/
public MorphTransition morph(String cmp) {
fromTo.put(cmp, cmp);
return this;
}
/**
* Morphs the component with the given source name in the source container hierarchy
* to the component with the given name in the destination hierarchy
* @param source
* @param to
* @return this so morph operations can be chained as MorphTransition t = MorphTransition.create(300).morph("a", "b").("c", "d");
*/
public MorphTransition morph(String source, String to) {
fromTo.put(source, to);
return this;
}
/**
* {@inheritDoc}
*/
public final void initTransition() {
animationMotion = Motion.createEaseInOutMotion(0, 255, duration);
animationMotion.start();
Container s = (Container)getSource();
Container d = (Container)getDestination();
Iterator keyIterator = fromTo.keySet().iterator();
int size = fromTo.size();
fromToComponents = new CC[size];
Form destForm = d.getComponentForm();
destForm.forceRevalidate();
Form sourceForm = s.getComponentForm();
for(int iter = 0 ; iter < size ; iter++) {
String k = keyIterator.next();
String v = fromTo.get(k);
Component sourceCmp = findByName(s, k);
Component destCmp = findByName(d, v);
if(sourceCmp == null || destCmp == null) {
continue;
}
CC cc = new CC(sourceCmp, destCmp, sourceForm, destForm);
fromToComponents[iter] = cc;
cc.placeholderDest = new Label();
cc.placeholderDest.setVisible(false);
Container destParent = cc.dest.getParent();
cc.placeholderDest.setX(cc.dest.getX());
cc.placeholderDest.setY(cc.dest.getY() - destForm.getContentPane().getY());
cc.placeholderDest.setWidth(cc.dest.getWidth());
cc.placeholderDest.setHeight(cc.dest.getHeight());
cc.placeholderDest.setPreferredSize(new Dimension(cc.dest.getWidth(), cc.dest.getHeight()));
destParent.replace(cc.dest, cc.placeholderDest, null);
destForm.getLayeredPane().addComponent(cc.dest);
cc.placeholderSrc = new Label();
cc.placeholderSrc.setVisible(false);
cc.placeholderSrc.setX(cc.source.getX());
cc.placeholderSrc.setY(cc.source.getY() - sourceForm.getContentPane().getY());
cc.placeholderSrc.setWidth(cc.source.getWidth());
cc.placeholderSrc.setHeight(cc.source.getHeight());
cc.placeholderSrc.setPreferredSize(new Dimension(cc.source.getWidth(), cc.source.getHeight()));
cc.originalContainer = cc.source.getParent();
cc.originalConstraint = cc.originalContainer.getLayout().getComponentConstraint(cc.source);
cc.originalOffset = cc.originalContainer.getComponentIndex(cc.source);
cc.originalContainer.replace(cc.source, cc.placeholderSrc, null);
cc.originalContainer.getComponentForm().getLayeredPane().addComponent(cc.source);
}
}
private static Component findByName(Container root, String componentName) {
int count = root.getComponentCount();
for(int iter = 0 ; iter < count ; iter++) {
Component c = root.getComponentAt(iter);
String n = c.getName();
if(n != null && n.equals(componentName)) {
return c;
}
if(c instanceof Container) {
c = findByName((Container)c, componentName);
if(c != null) {
return c;
}
}
}
return null;
}
/**
* {@inheritDoc}
*/
public boolean animate() {
if(!finished) {
// animate one last time
if(animationMotion.isFinished()) {
finished = true;
// restore forms to orignial states
for(CC c : fromToComponents) {
if(c == null) {
continue;
}
Container p = c.placeholderDest.getParent();
c.dest.getParent().removeComponent(c.dest);
p.replace(c.placeholderDest, c.dest, null);
p = c.placeholderSrc.getParent();
c.source.getParent().removeComponent(c.source);
p.replace(c.placeholderSrc, c.source, null);
}
// remove potential memory leak
fromToComponents = null;
return true;
}
for(CC c : fromToComponents) {
if(c == null) {
continue;
}
int x = c.xMotion.getValue();
int y = c.yMotion.getValue();
int w = c.wMotion.getValue();
int h = c.hMotion.getValue();
c.source.setX(x);
c.source.setY(y);
c.source.setWidth(w);
c.source.setHeight(h);
c.dest.setX(x);
c.dest.setY(y);
c.dest.setWidth(w);
c.dest.setHeight(h);
}
return true;
}
return false;
}
/**
* {@inheritDoc}
*/
public void paint(Graphics g) {
int oldAlpha = g.getAlpha();
int alpha = animationMotion.getValue();
if(alpha < 255) {
g.setAlpha(255 - alpha);
getSource().paintComponent(g);
g.setAlpha(alpha);
byte bgT = getDestination().getUnselectedStyle().getBgTransparency();
getDestination().getUnselectedStyle().setBgTransparency(0);
getDestination().paintComponent(g, false);
getDestination().getUnselectedStyle().setBgTransparency(bgT);
g.setAlpha(oldAlpha);
} else {
getDestination().paintComponent(g);
}
}
class CC {
public CC(Component source, Component dest, Form sourceForm, Form destForm) {
this.source = source;
this.dest = dest;
xMotion = Motion.createEaseInOutMotion(positionRelativeToScreen(source, false), positionRelativeToScreen(dest, false), duration);
xMotion.start();
yMotion = Motion.createEaseInOutMotion(positionRelativeToScreen(source, true), positionRelativeToScreen(dest, true), duration);
yMotion.start();
hMotion = Motion.createEaseInOutMotion(source.getHeight(), dest.getHeight(), duration);
hMotion.start();
wMotion = Motion.createEaseInOutMotion(source.getWidth(), dest.getWidth(), duration);
wMotion.start();
}
Component source;
Component dest;
Label placeholderSrc;
Label placeholderDest;
Motion xMotion;
Motion yMotion;
Motion wMotion;
Motion hMotion;
Object originalConstraint;
Container originalContainer;
int originalOffset;
private int positionRelativeToScreen(Component cmp, boolean yAxis){
int retVal = 0;
if(yAxis){
int titleHeight = cmp.getComponentForm().getContentPane().getAbsoluteY();
retVal = cmp.getAbsoluteY() - titleHeight;
}else{
retVal = cmp.getAbsoluteX();
}
return retVal;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy