/******************************************************************************* * Copyright (c) 2010 Ahmed Mahran and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Ahmed Mahran - initial API and implementation *******************************************************************************/ package org.eclipse.nebula.effects.stw; import org.eclipse.swt.events.PaintEvent; import org.eclipse.swt.events.PaintListener; import org.eclipse.swt.graphics.GC; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.ImageData; import org.eclipse.swt.widgets.Canvas; import org.eclipse.swt.widgets.Display; /** * An abstract class handling the basic actions required for whatever transition effect. * These actions are like the transition loop.<br/><br/> * * To implement a new transition effect, this class should be extended by the new transition * class and only the three methods {@link Transition#initTransition(Image, Image, GC, double)} * , {@link Transition#stepTransition(long, Image, Image, GC, double)} and * {@link Transition#endTransition(Image, Image, GC, double)} must be implemented.<br/><br/> * * The transition loop: * <code><pre> * xitionImgGC.drawImage(from, 0, 0); * initTransition(from, to, xitionImgGC, direction); * render(xitionImgGC); * while(t <= T) { * if(t <= T) { * stepTransition(t, from, to, xitionImgGC, direction); * } else { * xitionImgGC.drawImage(to, 0, 0); * endTransition(from, to, xitionImgGC, direction); * } * render(xitionImgGC); * t += dt; * } * </code></pre> * * The <code>initTransition</code> method initializes the transition variables and draws the initial/first * frame of the transition effect at time 0. The <code>stepTransition</code> * method calculates the new transition variables values based on the time parameter <code>t</code> * and draws the transition effect at time instance t. Finally, the <code>endTransition</code> method * finalizes the transition and draws the last frame at instance T. * * @author Ahmed Mahran (ahmahran@gmail.com) */ public abstract class Transition { /** * The default fps (frames per second) is 60 */ public static final long DEFAULT_FPS = 60; /** * The default transition time is 1000 ms */ public static final long DEFAULT_T = 1000; /** * The Right direction, 0 degrees */ public static final double DIR_RIGHT = 0; /** * The Up direction, 90 degrees */ public static final double DIR_UP = 90; /** * The Left direction, 180 degrees */ public static final double DIR_LEFT = 180; /** * The Down direction, 270 degrees */ public static final double DIR_DOWN = 270; /** * Flag to indicate if this OS is a MacOS X or not. */ protected static final boolean IS_MAC_OS = System.getProperty("os.name") .toLowerCase().indexOf("mac") >= 0; /** * Flag to indicate if this OS is a Linux OS or not. */ protected static final boolean IS_LINUX_OS = System.getProperty("os.name") .toLowerCase().indexOf("nux") >= 0; protected TransitionManager _transitionManager; protected long _fps; //frames per second protected long _T; //total transition time in milliseconds private long _dt; //time step private long _t; //time counter /** * Constructs a new transition object * @param transitionManager the transition manager to be used to manage transitions * @param fps number of frames per second * @param T the total time the transition effect will take */ public Transition(TransitionManager transitionManager, long fps, long T) { _transitionManager = transitionManager; _fps = fps; _T = T; _t = 0; _dt = (long) (1000.0 / _fps); } /** * This constructor is similar to new Transition(transitionManager, {@link Transition#DEFAULT_FPS}, {@link Transition#DEFAULT_T}) * @param transitionManager the transition manager to be used to manage transitions */ public Transition(TransitionManager transitionManager) { this(transitionManager, DEFAULT_FPS, DEFAULT_T); } /** * Sets the maximum fps (number of frames per second) for the transition. * The actual number of frames displayed will vary depending on the current * workload on the machine. * * @param fps maximum number of frames per second */ public final void setFPS(long fps) { _fps = fps; _dt = (long) (1000.0 / fps); } /** * Returns the maximum number of frames per second * @return the maximum number of frames per second */ public final long getFPS() { return _fps; } /** * Sets the total time of the transition effect in milliseconds. * * @param T total time of the transition effect in milliseconds */ public final void setTotalTransitionTime(long T) { _T = T; } /** * Returns the total time of the transition effect in millisecond * @return the total time of the transition effect in millisecond */ public final double getTotalTransitionTime() { return _T; } /** * Starts the transition from the <i>from</i> image to the <i>to</i> image * drawing the effect on the graphics context object <i>gc</i>. The <i>direction</i> * parameter determines the direction of the transition in degrees starting from 0 * as the right direction and increasing in counter clock wise direction. * * @param from is the image to start the transition from * @param to is the image to end the transition to * @param canvas is the canvas object to draw the transition on * @param direction determines the direction of the transition in degrees */ public final void start(final Image from, final Image to, final Canvas canvas, final double direction) { //_transitionManager.isAnyTransitionInProgress.setValue(true); boolean flag = true; long t0 = System.currentTimeMillis(); long dt = 0; long ttemp = 0; _t = 0; //prepare transition background ImageData fromData = from.getImageData(); final Image xitionBg = new Image(Display.getCurrent(), fromData.width, fromData.height); GC xitionBgGC = new GC(xitionBg); xitionBgGC.setBackground(_transitionManager.backgroundColor); xitionBgGC.fillRectangle(0, 0, fromData.width, fromData.height); if( null != _transitionManager.backgroundImage ) { ImageData imgData = _transitionManager.backgroundImage.getImageData(); xitionBgGC.drawImage(_transitionManager.backgroundImage , 0, 0, imgData.width, imgData.height , 0, 0, fromData.width, fromData.height); } xitionBgGC.dispose(); final TransitionPainter transitionPainter = new TransitionPainter(canvas, from, to, direction, xitionBg); transitionPainter.paintTransition( TransitionPainter.TRANSITION_INIT); //while(!_transitionManager.isCurrentTransitionCanceled.get() // && _t <= _T) { while(_t <= _T) { ttemp = System.currentTimeMillis() - t0; dt = ttemp - _t; if(flag) _t = ttemp; //this condition is to make sure that the //required fps (or less) is satisfied and //not more if(dt >= _dt) { if(_t <= _T) { transitionPainter.paintTransition( TransitionPainter.TRANSITION_STEP); } else { transitionPainter.paintTransition( TransitionPainter.TRANSITION_END); } flag = true; doEvents(); } else { try { flag = false; Thread.sleep(_dt - dt); } catch (InterruptedException e) { e.printStackTrace(); } } } xitionBg.dispose(); //_transitionManager.isAnyTransitionInProgress.setValue(false); } protected void doEvents() { Display.getCurrent().readAndDispatch(); } protected abstract void initTransition(final Image from, final Image to, final GC gc, final double direction); protected abstract void stepTransition(long t, final Image from, final Image to, final GC gc, final double direction); protected abstract void endTransition(final Image from, final Image to, final GC gc, final double direction); /** * Listener to paint the canvas object, where the transition is visualized. * @author Rodrigo Cantu Polo (cantupolo@yahoo.com.br) */ private class TransitionPainter implements PaintListener { /** Initial transition to paint. */ private static final int TRANSITION_INIT = 0; /** Step transition to paint. */ private static final int TRANSITION_STEP = 1; /** End transition to paint. */ private static final int TRANSITION_END = 2; /** Indicate that this object is enabled to paint the canvas. */ private boolean _isEnabled = false; /** Transition to paint. */ private int _transition = -1; /** GC for the canvas object. */ private GC _gc; /** Canvas where to paint the transitions. */ private Canvas _canvas; /** From image to paint in the canvas. */ private final Image _from; /** To image to paint in the canvas. */ private final Image _to; /** Direction of the animation effect. */ private final double _direction; /** Initial background of the transition paint. */ private final Image _xitionBg; /** Image to draw the transition. */ private Image _xitionImg; /** Graphics context object for the _xitionImg object. */ private GC _xitionImgGC; /** * Constructor. * @param canvas Canvas where to paint the transitions. * @param from From image to paint in the canvas. * @param to To image to paint in the canvas. * @param direction Direction of the animation effect. * @param xitionBg Initial background of the transition paint. */ private TransitionPainter(Canvas canvas, final Image from, final Image to, final double direction, final Image xitionBg) { _canvas = canvas; _from = from; _to = to; _direction = direction; _xitionBg = xitionBg; } /** * Initialize the transition image objects. * @param display Display to use for the objects. */ private void initXitionImg(Display display) { _xitionImg = new Image(display, _from.getBounds().width, _from.getBounds().height); _xitionImgGC = new GC(_xitionImg); } /** * Dispose the transition image objects. */ private void disposeXitionImg() { _xitionImg.dispose(); _xitionImgGC.dispose(); } /** * Paint a transition. * @param transition Transition to paint. */ public void paintTransition(int transition) { _transition = transition; if (!IS_LINUX_OS) { if (_transition == TRANSITION_INIT) { _canvas.addPaintListener(this); } _isEnabled = true; _canvas.redraw(); _canvas.getDisplay().update(); _canvas.getDisplay().readAndDispatch(); _isEnabled = false; if (_transition == TRANSITION_END) { _canvas.removePaintListener(this); } } else { if (_transition == TRANSITION_INIT) { initXitionImg(_canvas.getDisplay()); _gc = new GC(_canvas); } paintTransition(_xitionImgGC, _transition); _gc.drawImage(_xitionImg, 0, 0); if (_transition == TRANSITION_END) { disposeXitionImg(); _gc.dispose(); } } } @Override public void paintControl(PaintEvent e) { if (_isEnabled) { initXitionImg(e.display); paintTransition(_xitionImgGC, _transition); e.gc.drawImage(_xitionImg, 0, 0); disposeXitionImg(); } } /** * Paint a transition. * @param gc GC object to paint. * @param transition Transition to paint. */ private void paintTransition(GC gc, int transition) { switch (transition) { case TRANSITION_INIT: gc.drawImage(_xitionBg, 0, 0); gc.drawImage(_from, 0, 0); initTransition(_from, _to, gc, _direction); break; case TRANSITION_STEP: gc.drawImage(_xitionBg, 0, 0); stepTransition(_t, _from, _to, gc, _direction); break; case TRANSITION_END: gc.drawImage(_xitionBg, 0, 0); gc.drawImage(_to, 0, 0); endTransition(_from, _to, gc, _direction); break; default: break; } } } }