package totalcross.ui.anim; import totalcross.sys.*; import totalcross.ui.*; import totalcross.ui.event.*; /** Abstract class used to create and handle animations * @since TotalCross 3.03 */ public abstract class ControlAnimation implements TimerListener { protected Control c; protected int totalTime; private TimerEvent teFrame, teDelay; private ControlAnimation with,then; private AnimationFinished animFinish; private int initialTime; private boolean slave; protected boolean releaseScreenShot=true; public static int frameRate = Settings.platform.equals(Settings.WINDOWSPHONE) ? 30 : 20; /** A delay issued right after the animation finishes */ public int delayAfterFinish; public static interface AnimationFinished { public void onAnimationFinished(ControlAnimation anim); } public ControlAnimation(Control c, AnimationFinished animFinish, int totalTime) { this.c = c; this.animFinish = animFinish; this.totalTime = totalTime <= 0 ? 800 : totalTime; } public ControlAnimation(Control c, AnimationFinished animFinish) { this(c, animFinish, -1); } public ControlAnimation(Control c) { this(c,null); } public void start() throws Exception { if (!slave) { if (teFrame == null) { teFrame = c.addTimer(frameRate); c.addTimerListener(this); } if (c.offscreen == null) { Window.enableUpdateScreen = false; // removes flick when clicking outside the TopMenu c.takeScreenShot(); Window.needsPaint = true; } } if (with != null) with.start(); initialTime = Vm.getTimeStamp(); } public void stop(boolean abort) { if (teFrame != null) { c.removeTimer(teFrame); teFrame = null; if (releaseScreenShot) c.releaseScreenShot(); } if (animFinish != null) animFinish.onAnimationFinished(this); if (abort) ; else if (delayAfterFinish > 0) teDelay = c.addTimer(delayAfterFinish); else handleThen(); } private void handleThen() { if (then != null) try {then.start();} catch (Exception e) {if (Settings.onJavaSE) e.printStackTrace();} } protected double computeSpeed(double distance) { int remaining = totalTime-(Vm.getTimeStamp()-initialTime); if (remaining <= 0) return 0; return distance * frameRate / remaining; } public ControlAnimation with(ControlAnimation other) { this.with = other; other.slave = true; return this; } public ControlAnimation then(ControlAnimation other) { this.then = other; return this; } public void timerTriggered(TimerEvent e) { if (teFrame != null && teFrame.triggered) animatePriv(); else if (teDelay != null && teDelay.triggered) { c.removeTimer(teDelay); teDelay = null; MainWindow.getMainWindow().runOnMainThread(new Runnable() { public void run() { handleThen(); } }); } } private void animatePriv() { animate(); if (with != null) with.animatePriv(); Window.enableUpdateScreen = true; } protected abstract void animate(); }