package transition;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.CTabFolder;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.ImageData;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Canvas;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.TabFolder;
/**
* 2007
* @author Ahmed Mahran (ahmahran)
* ahmahran@gmail.com
*/
public class Transition {
public static final int HORIZONTAL_ROTATION = 0;
public static final int VERTICAL_ROTATION = 1;
public static final int HORIZONTAL_LINEAR = 2;
public static final int VERTICAL_LINEAR = 3;
public static final int FADE = 4;
private static final int LAST_TRANSITION = FADE;
public static final int RANDOM = 5;
public static final int RANDOM_ROTATION = 6;
public static final int RANDOM_LINEAR = 7;
private int finalDest = -1;
private boolean isProcessFinalDest = false;
private int lastItem = -1;
private int transition = RANDOM;
private Color backgroundColor;
private Image backgroundImage;
private boolean isAnyTransitionInProgress = false;
private boolean isCurrentTransitionCanceled = false;
private Transitionable transitionable;
private List<TransitionListener> listeners;
public Transition(final Transitionable transitionable) {
final Transition thisTransitionObject = this;
this.transitionable = transitionable;
listeners = new ArrayList<TransitionListener>();
backgroundColor = Display.getCurrent().getSystemColor(SWT.COLOR_WIDGET_BACKGROUND);
//the selected item before the one to be transitioned to
lastItem = transitionable.getSelection();
transitionable.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent event) {
try {
//if any transition is in progress, cancel it and
//start the most recent one to catch up with the
//user's selections
if(isAnyTransitionInProgress) {
isCurrentTransitionCanceled = true;
finalDest = transitionable.getSelection();
isProcessFinalDest = true;
return;
}
isCurrentTransitionCanceled = false;
//when this event is fired, the current selected item
//is the item to be transitioned to and the previously
//selected one is the item to start the transition from
//the item to be transitioned to
int currentItem = transitionable.getSelection();
//reselect the older item to start transition from
transitionable.setSelection(lastItem);
//capture the an image of the "from" view
Control from = transitionable.getControl(lastItem);
Rectangle size = from.getBounds();
Image imgFrom = new Image(from.getDisplay(), size.width, size.height);
GC gcfrom = new GC(from);
from.update();
gcfrom.copyArea(imgFrom, 0, 0);
gcfrom.dispose();
//capture an image of the "to" view
Control to = transitionable.getControl(currentItem);
transitionable.setSelection(currentItem);
Image imgTo = ImageCapture.getImage(to, size.width, size.height, true);
transitionable.setSelection(lastItem);
//create and show the canvas that the transition will be showed on
Canvas canvas = new Canvas(transitionable.getComposite(), SWT.DOUBLE_BUFFERED);
canvas.moveAbove(null);
canvas.setBounds(to.getBounds());
//make the transition
GC gcOn = new GC(canvas);
switch(transition) {
case HORIZONTAL_ROTATION:
case VERTICAL_ROTATION:
case HORIZONTAL_LINEAR:
case VERTICAL_LINEAR:
case FADE:
translate(transition, imgFrom, imgTo, gcOn
, transitionable.compare(currentItem, lastItem) == currentItem);
break;
case RANDOM:
case RANDOM_LINEAR:
case RANDOM_ROTATION:
randomTransition(transition, imgFrom, imgTo, gcOn
, transitionable.compare(currentItem, lastItem) == currentItem);
break;
}
transitionable.setSelection(currentItem);
gcOn.dispose();
//dispose the transition canvas
canvas.dispose();
//now the item transition ends on will be used
//to start transition from next time
lastItem = currentItem;
//if the current transition was canceled to process
//a new recent one, show the new selection and make
//a new transition to it
if(isProcessFinalDest) {
isProcessFinalDest = false;
transitionable.setSelection(finalDest);
widgetSelected(event);
} else {
for(TransitionListener tl: listeners)
tl.transitionFinished(thisTransitionObject);
}
} catch(Exception e) { e.printStackTrace(); }
}});
}
public Transition(final CTabFolder tabFolder) {
this(new Transitionable(){
public void addSelectionListener(SelectionListener listener) {
tabFolder.addSelectionListener(listener);
}
public Control getControl(int index) {
return tabFolder.getItem(index).getControl();
}
public Composite getComposite() {
return tabFolder;
}
public int getSelection() {
return tabFolder.getSelectionIndex();
}
public void setSelection(int index) {
tabFolder.setSelection(index);
}
public int compare(int index1, int index2) {
return index1 > index2 ? index1 : index2;
}
});
}
public Transition(final TabFolder tabFolder) {
this(new Transitionable(){
public void addSelectionListener(SelectionListener listener) {
tabFolder.addSelectionListener(listener);
}
public Control getControl(int index) {
return tabFolder.getItem(index).getControl();
}
public Composite getComposite() {
return tabFolder;
}
public int getSelection() {
return tabFolder.getSelectionIndex();
}
public void setSelection(int index) {
tabFolder.setSelection(index);
}
public int compare(int index1, int index2) {
return index1 > index2 ? index1 : index2;
}
});
}
public void translate(int transition, final Image from, final Image to, final GC gc, final boolean toRight) {
switch(transition) {
case HORIZONTAL_ROTATION:
hRotate(from, to, gc, toRight);
break;
case VERTICAL_ROTATION:
vRotate(from, to, gc, toRight);
break;
case HORIZONTAL_LINEAR:
hLinear(from, to, gc, toRight);
break;
case VERTICAL_LINEAR:
vLinear(from, to, gc, toRight);
break;
case FADE:
fade(from, to, gc, toRight);
break;
}
}
public void setTransition(int type) {
switch(type) {
case HORIZONTAL_ROTATION:
case VERTICAL_ROTATION:
case FADE:
case HORIZONTAL_LINEAR:
case VERTICAL_LINEAR:
case RANDOM:
case RANDOM_LINEAR:
case RANDOM_ROTATION:
transition = type;
}
}
public int getTransition() {
return transition;
}
public void setBackground(Color color) {
backgroundColor = color;
}
public Color getBackground() {
return backgroundColor;
}
public void setBackgroundImage(Image image) {
backgroundImage = image;
}
public Image getBackgroundImage() {
return backgroundImage;
}
public Transitionable getTransitionable() {
return transitionable;
}
public void addTransitionListener(TransitionListener transitionListener) {
listeners.add(transitionListener);
}
public void removeTransitionListener(TransitionListener transitionListener) {
listeners.remove(transitionListener);
}
public void transformX(Image srcImage, GC destGc, int destX, int destY, int destWidth, int destHeight, boolean toLeft) {
double x = 0, y = 0;
int h = srcImage.getImageData().height;
int w = srcImage.getImageData().width;
double dy = Math.abs(h - destHeight) / (2.0 * w);
double dx = 1;
double widthRatio = 1.0 * destWidth / w;
if (toLeft)
for (x = 0; x <= w; x += dx) {
try {
destGc.drawImage(srcImage, (int) x, 0, (int) dx, h,
destX + (int) (x * widthRatio), destY + (int) y, (int) dx,
(int) (h - 2.0 * y));
y += dx * dy * 1.0;
} catch (Exception e) {
}
doEvents();
}
else
for (x = w; x >= 0; x -= dx) {
try {
destGc.drawImage(srcImage, (int) x, 0, (int) dx, h,
destX + (int) (x * widthRatio), destY + (int) y, (int) dx,
(int) (h - 2.0 * y));
y += dx * dy * 1.0;
} catch (Exception e) {
}
doEvents();
}
}
public void hRotate(final Image from, final Image to, final GC gc, final boolean toRight) {
isAnyTransitionInProgress = true;
final ImageData fromData = from.getImageData();
//Thread thread = new Thread(new Runnable() {
// public void run() {
double dx = 0;
double a = 1;
double time = 0;
double dy = fromData.height * dx / fromData.width;
double destHeight = 0;
int h = from.getImageData().height;
int w = from.getImageData().width;
Image im = new Image(Display.getCurrent(), fromData.width, fromData.height);
GC imgc = new GC(im);
imgc.setBackground(backgroundColor);
imgc.fillRectangle(0, 0, fromData.width, fromData.height);
if( null != backgroundImage ) {
ImageData imgData = backgroundImage.getImageData();
imgc.drawImage(backgroundImage, 0, 0, imgData.width, imgData.height, 0, 0, w, h);
}
imgc.dispose();
Image tmp = new Image(Display.getCurrent(), fromData.width, fromData.height);
imgc = new GC(tmp);
imgc.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_BLACK));
if( toRight ) {
for( int t = fromData.width; !isCurrentTransitionCanceled && t >= 0; t -= (int)(dx) ) {
imgc.drawImage(im, 0, 0);
//transformX(from, imgc, fromData.width - t, 0, t, (int)(fromData.height - destHeight), true);
//transformX(to, imgc, 0, 0, fromData.width - t, (int)destHeight, !true);
double x1 = 0, y1 = 0;
double dy1 = Math.abs(destHeight) / (2.0 * w);
double dx1 = 1;
double widthRatio1 = 1.0 * t / w;
double x2 = 0, y2 = 0;
double dy2 = Math.abs(h - destHeight) / (2.0 * w);
double dx2 = 1;
double widthRatio2 = 1.0 * (w-t) / w;
for (x1 = 0; x1 <= w; x1 += dx1) {
try {
x2 = w - x1;
imgc.drawImage(from, (int) x1, 0, (int) dx1, h,
(w-t) + (int) (x1 * widthRatio1), (int) y1, (int) dx1,
(int) (h - 2.0 * y1));
imgc.drawImage(to, (int)x2, 0, (int)dx2, h,
(int) (x2 * widthRatio2), (int) y2, (int) dx2,
(int) (h - 2.0 * y2));
y1 += dx1 * dy1 * 1.0;
y2 += dx2 * dy2 * 1.0;
} catch (Exception e) {
}
doEvents();
}
gc.drawImage(tmp, 0, 0);
time += 1;
dx = 0.5 * a * time * time;
dy = fromData.height * dx / fromData.width;
destHeight += dy;
}
} else {
for( int t = 0; !isCurrentTransitionCanceled && t <= fromData.width; t += (int)(dx) ) {
imgc.drawImage(im, 0, 0);
//transformX(from, imgc, 0, 0, fromData.width - t, (int)(fromData.height - destHeight), !true);
//transformX(to, imgc, fromData.width - t, 0, t, (int)destHeight, true);
double x1 = 0, y1 = 0;
double dy1 = Math.abs(destHeight) / (2.0 * w);
double dx1 = 1;
double widthRatio1 = 1.0 * (w-t) / w;
double x2 = 0, y2 = 0;
double dy2 = Math.abs(h - destHeight) / (2.0 * w);
double dx2 = 1;
double widthRatio2 = 1.0 * t / w;
for (x1 = w; x1 >= 0; x1 -= dx1) {
try {
x2 = w - x1;
imgc.drawImage(from, (int) x1, 0, (int) dx1, h,
(int) (x1 * widthRatio1), (int) y1, (int) dx1,
(int) (h - 2.0 * y1));
imgc.drawImage(to, (int) x2, 0, (int) dx2, h,
(w-t) + (int) (x2 * widthRatio2), (int) y2, (int) dx2,
(int) (h - 2.0 * y2));
y1 += dx1 * dy1 * 1.0;
y2 += dx2 * dy2 * 1.0;
} catch(Exception e) {
}
doEvents();
}
gc.drawImage(tmp, 0, 0);
time += 1;
dx = 0.5 * a * time * time;
dy = fromData.height * dx / fromData.width;
destHeight += dy;
}
}
imgc.dispose();
im.dispose();
tmp.dispose();
// }
//});
//Display.getCurrent().syncExec(thread);
isAnyTransitionInProgress = false;
}
public void vRotate(final Image from, final Image to, final GC gc, final boolean toRight) {
isAnyTransitionInProgress = true;
final ImageData fromData = from.getImageData();
//Thread thread = new Thread(new Runnable() {
// public void run() {
double dy = 0;
double a = 1;
double time = 0;
double dx = fromData.width * dy / fromData.height;
double destWidth = 0;
int h = from.getImageData().height;
int w = from.getImageData().width;
Image im = new Image(Display.getCurrent(), fromData.width, fromData.height);
GC imgc = new GC(im);
imgc.setBackground(backgroundColor);
imgc.fillRectangle(0, 0, fromData.width, fromData.height);
if( null != backgroundImage ) {
ImageData imgData = backgroundImage.getImageData();
imgc.drawImage(backgroundImage, 0, 0, imgData.width, imgData.height, 0, 0, w, h);
}
imgc.dispose();
Image tmp = new Image(Display.getCurrent(), fromData.width, fromData.height);
imgc = new GC(tmp);
if( toRight ) {
for( int t = h; !isCurrentTransitionCanceled && t >= 0; t -= (int)(dy) ) {
imgc.drawImage(im, 0, 0);
//transformX(from, imgc, fromData.height - t, 0, t, (int)(fromData.width - destWidth), true);
//transformX(to, imgc, 0, 0, fromData.height - t, (int)destWidth, !true);
double y1 = 0, x1 = 0;
double dx1 = Math.abs(destWidth) / (2.0 * h);
double dy1 = 1;
double heightRatio1 = 1.0 * t / h;
double y2 = 0, x2 = 0;
double dx2 = Math.abs(w - destWidth) / (2.0 * h);
double dy2 = 1;
double heightRatio2 = 1.0 * (h-t) / h;
for (y1 = 0; y1 <= h; y1 += dy1) {
try {
y2 = h - y1;
imgc.drawImage(from, 0, (int)y1, w, (int)dy1
, (int)x1, (h-t) + (int) (y1 * heightRatio1)
, (int)(w - 2.0 * x1), (int)dy1);
imgc.drawImage(to, 0, (int)y2, w, (int)dy2
, (int)x2, (int)(y2 * heightRatio2)
, (int)(w - 2.0 * x2), (int)dy2);
x1 += dy1 * dx1 * 1.0;
x2 += dy2 * dx2 * 1.0;
} catch (Exception e) {
}
doEvents();
}
gc.drawImage(tmp, 0, 0);
time += 1;
dy = 0.5 * a * time * time;
dx = w * dy / h;
destWidth += dx;
}
} else {
for( int t = 0; !isCurrentTransitionCanceled && t <= h; t += (int)(dy) ) {
imgc.drawImage(im, 0, 0);
//transformX(from, imgc, 0, 0, fromData.width - t, (int)(fromData.height - destHeight), !true);
//transformX(to, imgc, fromData.width - t, 0, t, (int)destHeight, true);
double y1 = 0, x1 = 0;
double dx1 = Math.abs(destWidth) / (2.0 * h);
double dy1 = 1;
double heightRatio1 = 1.0 * (h-t) / h;
double y2 = 0, x2 = 0;
double dx2 = Math.abs(w - destWidth) / (2.0 * h);
double dy2 = 1;
double heightRatio2 = 1.0 * t / h;
for (y1 = h; y1 >= 0; y1 -= dy1) {
try {
y2 = h - y1;
imgc.drawImage(from, 0, (int)y1, w, (int)dy1
, (int)x1, (int)(y1 * heightRatio1)
, (int)(w - 2.0 * x1), (int) dy1);
imgc.drawImage(to, 0, (int)y2, w, (int)dy2
, (int)x2, (h-t) + (int)(y2 * heightRatio2)
, (int)(w - 2.0 * x2), (int)dy2);
x1 += dy1 * dx1 * 1.0;
x2 += dy2 * dx2 * 1.0;
} catch(Exception e) {
}
doEvents();
}
gc.drawImage(tmp, 0, 0);
time += 1;
dy = 0.5 * a * time * time;
dx = w * dy / h;
destWidth += dx;
}
}
imgc.dispose();
im.dispose();
tmp.dispose();
// }
//});
//Display.getCurrent().syncExec(thread);
isAnyTransitionInProgress = false;
}
public void hLinear(final Image from, final Image to, final GC gc, final boolean toRight) {
isAnyTransitionInProgress = true;
final ImageData fromData = from.getImageData();
//Thread thread = new Thread(new Runnable() {
// public void run() {
int w = fromData.width;
int halfWidth = w/2;
int t = 0;
double a = 2.0 / halfWidth;
int factor = 1;
if( toRight ) factor = 1;
else factor = -1;
double x = 0;
for( t = 0; !isCurrentTransitionCanceled && t <= halfWidth; t++ ) {
gc.drawImage(from, (int)(factor*x), 0);
gc.drawImage(to, (int)(factor*(x-w)), 0);
x = 0.5 * a * t * t;
doEvents();
}
double x0 = x;
double v0 = a * t;
a *= -1.0;
for( t = 0; !isCurrentTransitionCanceled && t <= halfWidth; t++ ) {
gc.drawImage(from, (int)(factor*x), 0);
gc.drawImage(to, (int)(factor*(x-w)), 0);
x = x0 + v0 * t + 0.5 * a * t * t;
doEvents();
}
// }
//});
//Display.getCurrent().syncExec(thread);
isAnyTransitionInProgress = false;
}
public void vLinear(final Image from, final Image to, final GC gc, final boolean toDown) {
isAnyTransitionInProgress = true;
final ImageData fromData = from.getImageData();
//Thread thread = new Thread(new Runnable() {
// public void run() {
int h = fromData.height;
int halfHeight = h/2;
int t = 0;
double a = 2.0 / halfHeight;
int factor = 1;
if( toDown ) factor = 1;
else factor = -1;
double y = 0;
for( t = 0; !isCurrentTransitionCanceled && t <= halfHeight; t++ ) {
gc.drawImage(from, 0, (int)(factor*y));
gc.drawImage(to, 0, (int)(factor*(y-h)));
y = 0.5 * a * t * t;
doEvents();
}
double y0 = y;
double v0 = a * t;
a *= -1.0;
for( t = 0; !isCurrentTransitionCanceled && t <= halfHeight; t++ ) {
gc.drawImage(from, 0, (int)(factor*y));
gc.drawImage(to, 0, (int)(factor*(y-h)));
y = y0 + v0 * t + 0.5 * a * t * t;
doEvents();
}
// }
//});
//Display.getCurrent().syncExec(thread);
isAnyTransitionInProgress = false;
}
public void fade(final Image from, final Image to, final GC gc, final boolean toDown) {
isAnyTransitionInProgress = true;
final ImageData fromData = from.getImageData();
//Thread thread = new Thread(new Runnable() {
// public void run() {
int w = fromData.width;
int h = fromData.height;
int alpha = 255;
int t = 0;
double a = -2.0 / alpha;
//int factor = 1;
//if( toDown ) factor = 1;
//else factor = -1;
double f = alpha;
Image imgBuffer = new Image(from.getDevice(), w, h);
GC gcBuffer = new GC(imgBuffer);
gcBuffer.setBackground(backgroundColor);
for( t = 0; !isCurrentTransitionCanceled && t <= alpha; t+=20 ) {
gcBuffer.setAlpha(alpha);
gcBuffer.fillRectangle(0, 0, w, h);
if( null != backgroundImage ) {
ImageData imgData = backgroundImage.getImageData();
gcBuffer.drawImage(backgroundImage, 0, 0, imgData.width, imgData.height, 0, 0, w, h);
}
gcBuffer.setAlpha((int)(f));
gcBuffer.drawImage(from, 0, 0);
gc.drawImage(imgBuffer, 0, 0);
f = alpha + 0.5 * a * t * t;
doEvents();
}
double f0 = f;
a *= -1.0;
for( t = 0; !isCurrentTransitionCanceled && t <= alpha; t+=20 ) {
gcBuffer.setAlpha(alpha);
gcBuffer.fillRectangle(0, 0, w, h);
if( null != backgroundImage ) {
ImageData imgData = backgroundImage.getImageData();
gcBuffer.drawImage(backgroundImage, 0, 0, imgData.width, imgData.height, 0, 0, w, h);
}
gcBuffer.setAlpha((int)(f));
gcBuffer.drawImage(to, 0, 0);
gc.drawImage(imgBuffer, 0, 0);
f = f0 + 0.5 * a * t * t;
doEvents();
}
gcBuffer.dispose();
imgBuffer.dispose();
// }
//});
//Display.getCurrent().syncExec(thread);
isAnyTransitionInProgress = false;
}
private int randomTransition;
public void randomTransition(int random, final Image from, final Image to, final GC gc, final boolean toRight) {
java.util.Random random2 = new Random(System.currentTimeMillis());
switch(random) {
case RANDOM:
randomTransition = (int)(random2.nextInt((LAST_TRANSITION+1)));
translate(randomTransition, from, to, gc, toRight);
break;
case RANDOM_LINEAR:
randomTransition = Math.random() > 0.5 ? HORIZONTAL_LINEAR : VERTICAL_LINEAR;
translate(randomTransition, from, to, gc, toRight);
break;
case RANDOM_ROTATION:
randomTransition = Math.random() > 0.5 ? HORIZONTAL_ROTATION : VERTICAL_ROTATION;
translate(randomTransition, from, to, gc, toRight);
break;
}
}
private void doEvents() {
Display.getCurrent().readAndDispatch();
}
public void translate(final Composite from, final Composite to, final Composite on) {
Rectangle size = from.getClientArea();
Canvas canvas = new Canvas(on, SWT.DOUBLE_BUFFERED);
canvas.moveAbove(null);
canvas.setBounds(from.getBounds());
Image imgFrom = new Image(Display.getCurrent(), size.width, size.height);
GC gcfrom = new GC(from);
System.out.println("from: " + from.getData());
gcfrom.copyArea(imgFrom, 0, 0);
// ImageLoader loader = new ImageLoader();
// loader.data = new ImageData[]{imgFrom.getImageData()};
// loader.save("E:\\from.bmp", SWT.IMAGE_BMP);
gcfrom.dispose();
Image imgTo = new Image(Display.getCurrent(), size.width, size.height);
GC gcto = new GC(to);
System.out.println("to: " + to.getData());
gcto.copyArea(imgTo, 0, 0);
// loader.data = new ImageData[]{imgTo.getImageData()};
// loader.save("E:\\to.bmp", SWT.IMAGE_BMP);
gcto.dispose();
GC gcOn = new GC(canvas);
//hRotate(imgFrom, imgTo, gcOn);
gcOn.dispose();
canvas.dispose();
}
}