diff dwtx/draw2d/Animation.d @ 98:95307ad235d9

Added Draw2d code, still work in progress
author Frank Benoit <benoit@tionex.de>
date Sun, 03 Aug 2008 00:52:14 +0200
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwtx/draw2d/Animation.d	Sun Aug 03 00:52:14 2008 +0200
@@ -0,0 +1,278 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2006 IBM Corporation 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:
+ *     IBM Corporation - initial API and implementation
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
+ *******************************************************************************/
+
+module dwtx.draw2d.Animation;
+
+import dwt.dwthelper.utils;
+import dwtx.dwtxhelper.Collection;
+
+import dwtx.draw2d.Animator;
+import dwtx.draw2d.IFigure;
+import dwtx.draw2d.UpdateManager;
+
+
+/**
+ * A utility for coordinating figure animations. During animation, multiple
+ * <i>animators</i> are employed to capture the <em>initial</em> and <em>final</em> states
+ * for one or more figures. The animators then playback the animation by interpolating the
+ * intermediate states for each figure using the initial and final "keyframes".
+ * <P>
+ * An animator is usually stateless and represents an specific technique. Any state
+ * information is stored by the Animation utility. Therefore, one instance can be used
+ * with multiple figures. Animators hook into the validation mechanism for figures and
+ * connections. These hooks are used to capture the states, and to intercept the typical
+ * layout process to insert the interpolated state.
+ * <P>
+ * To indicate that animation is desired, clients must call {@link #markBegin()} prior to
+ * invalidating any figures that are to be included in the animation. After this method is
+ * called, changes are made, and {@link #run()} is invoked. The run method will force a
+ * validation pass to capture the final states, and then commence the animation. The
+ * animation is synchronous and the method does not return until the animation has
+ * completed.
+ * @see LayoutAnimator
+ * @since 3.2
+ */
+public class Animation {
+
+static class AnimPair {
+
+    const Animator animator;
+    const IFigure figure;
+
+    this(Animator animator, IFigure figure) {
+        this.animator = animator;
+        this.figure = figure;
+    }
+
+    public override int opEquals(Object obj) {
+        AnimPair pair = cast(AnimPair)obj;
+        return pair.animator is animator && pair.figure is figure;
+    }
+
+    public override hash_t toHash() {
+        return (cast(Object)animator).toHash() ^ (cast(Object)figure).toHash();
+    }
+}
+private static const int DEFAULT_DELAY = 250;
+private static Set figureAnimators;
+private static Map finalStates;
+
+private static Map initialStates;
+private static const int PLAYBACK = 3;
+private static float progress;
+private static const int RECORD_FINAL = 2;
+
+private static const int RECORD_INITIAL = 1;
+private static long startTime;
+private static int state;
+private static Set toCapture;
+
+private static UpdateManager updateManager;
+
+private static void capture() {
+    Iterator keys = figureAnimators.iterator();
+    while (keys.hasNext()) {
+        AnimPair pair = cast(AnimPair) keys.next();
+        if (toCapture.contains(pair))
+            pair.animator.capture(pair.figure);
+        else
+            keys.remove();
+    }
+}
+
+static void cleanup() {
+    if (figureAnimators !is null) {
+        Iterator keys = figureAnimators.iterator();
+        while (keys.hasNext()) {
+            AnimPair pair = cast(AnimPair) keys.next();
+            pair.animator.tearDown(pair.figure);
+        }
+    }
+
+    state = 0;
+    step();
+    //Allow layout to occur normally
+    //updateManager.performUpdate();
+
+    initialStates = null;
+    finalStates = null;
+    figureAnimators = null;
+    updateManager = null;
+    toCapture = null;
+    state = 0;
+}
+
+private static void doRun(int duration) {
+    state = RECORD_FINAL;
+    findUpdateManager();
+    updateManager.performValidation();
+    capture();
+    state = PLAYBACK;
+    progress = 0.1f;
+    startTime = System.currentTimeMillis();
+
+    notifyPlaybackStarting();
+
+    while (progress !is 0) {
+        step();
+        updateManager.performUpdate();
+        if (progress is 1.0)
+            progress = 0;
+        else {
+            int delta = cast(int)(System.currentTimeMillis() - startTime);
+            if (delta >= duration)
+                progress = 1f;
+            else
+                progress = 0.1f + 0.9f * delta / duration;
+        }
+    }
+}
+
+private static void findUpdateManager() {
+    AnimPair pair = cast(AnimPair) figureAnimators.iterator().next();
+    updateManager = pair.figure.getUpdateManager();
+}
+
+/**
+ * Returns the final animation state for the given figure.
+ * @param animator the animator for the figure
+ * @param figure the figure being animated
+ * @return the final state
+ * @since 3.2
+ */
+public static Object getFinalState(Animator animator, IFigure figure) {
+    return finalStates.get(new AnimPair(animator, figure));
+}
+
+/**
+ * Returns the initial animation state for the given animator and figure. If no state was
+ * recorded, <code>null</code> is returned.
+ * @param animator the animator for the figure
+ * @param figure the figure being animated
+ * @return the initial state
+ * @since 3.2
+ */
+public static Object getInitialState(Animator animator, IFigure figure) {
+    return initialStates.get(new AnimPair(animator, figure));
+}
+
+/**
+ * Returns the animation progress, where 0.0 < progress &#8804; 1.0.
+ * @return the progress of the animation
+ * @since 3.2
+ */
+public static float getProgress() {
+    return progress;
+}
+
+static void hookAnimator(IFigure figure, Animator animator) {
+    AnimPair pair = new AnimPair(animator, figure);
+    if (figureAnimators.add(pair))
+        animator.init(figure);
+}
+
+static void hookNeedsCapture(IFigure figure, Animator animator) {
+    AnimPair pair = new AnimPair(animator, figure);
+    if (figureAnimators.contains(pair))
+        toCapture.add(pair);
+}
+
+static bool hookPlayback(IFigure figure, Animator animator) {
+    if (toCapture.contains(new AnimPair(animator, figure)))
+        return animator.playback_package(figure);
+    return false;
+}
+
+/**
+ * Returns <code>true</code> if animation is in progress.
+ * @return <code>true</code> when animating
+ * @since 3.2
+ */
+public static bool isAnimating() {
+    return state is PLAYBACK;
+}
+
+static bool isFinalRecording() {
+    return state is RECORD_FINAL;
+}
+
+static bool isInitialRecording() {
+    return state is RECORD_INITIAL;
+}
+
+/**
+ * Marks the beginning of the animation process. If the beginning has already been marked,
+ * this has no effect.
+ * @return returns <code>true</code> if beginning was not previously marked
+ * @since 3.2
+ */
+public static bool markBegin() {
+    if (state is 0) {
+        state = RECORD_INITIAL;
+        initialStates = new HashMap();
+        finalStates = new HashMap();
+        figureAnimators = new HashSet();
+        toCapture = new HashSet();
+        return true;
+    }
+    return false;
+}
+
+private static void notifyPlaybackStarting() {
+    Iterator keys = figureAnimators.iterator();
+    while (keys.hasNext()) {
+        AnimPair pair = cast(AnimPair) keys.next();
+        pair.animator.playbackStarting(pair.figure);
+    }
+}
+
+static void putFinalState(Animator animator, IFigure key, Object state) {
+    finalStates.put(new AnimPair(animator, key), state);
+}
+
+static void putInitialState(Animator animator, IFigure key, Object state) {
+    initialStates.put(new AnimPair(animator, key), state);
+}
+
+/**
+ * Runs animation using the recommended duration: 250 milliseconds.
+ * @see #run(int)
+ * @since 3.2
+ */
+public static void run() {
+    run(DEFAULT_DELAY);
+}
+
+/**
+ * Captures the final states for the animation and then plays the animation.
+ * @param duration the length of animation in milliseconds
+ * @since 3.2
+ */
+public static void run(int duration) {
+    if (state is 0)
+        return;
+    try {
+        if (!figureAnimators.isEmpty())
+            doRun(duration);
+    } finally {
+        cleanup();
+    }
+}
+
+private static void step() {
+    Iterator iter = initialStates.keySet().iterator();
+    while (iter.hasNext())
+        (cast(AnimPair)iter.next()).figure.revalidate();
+}
+
+}