comparison 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
comparison
equal deleted inserted replaced
96:b492ba44e44d 98:95307ad235d9
1 /*******************************************************************************
2 * Copyright (c) 2005, 2006 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
7 *
8 * Contributors:
9 * IBM Corporation - initial API and implementation
10 * Port to the D programming language:
11 * Frank Benoit <benoit@tionex.de>
12 *******************************************************************************/
13
14 module dwtx.draw2d.Animation;
15
16 import dwt.dwthelper.utils;
17 import dwtx.dwtxhelper.Collection;
18
19 import dwtx.draw2d.Animator;
20 import dwtx.draw2d.IFigure;
21 import dwtx.draw2d.UpdateManager;
22
23
24 /**
25 * A utility for coordinating figure animations. During animation, multiple
26 * <i>animators</i> are employed to capture the <em>initial</em> and <em>final</em> states
27 * for one or more figures. The animators then playback the animation by interpolating the
28 * intermediate states for each figure using the initial and final "keyframes".
29 * <P>
30 * An animator is usually stateless and represents an specific technique. Any state
31 * information is stored by the Animation utility. Therefore, one instance can be used
32 * with multiple figures. Animators hook into the validation mechanism for figures and
33 * connections. These hooks are used to capture the states, and to intercept the typical
34 * layout process to insert the interpolated state.
35 * <P>
36 * To indicate that animation is desired, clients must call {@link #markBegin()} prior to
37 * invalidating any figures that are to be included in the animation. After this method is
38 * called, changes are made, and {@link #run()} is invoked. The run method will force a
39 * validation pass to capture the final states, and then commence the animation. The
40 * animation is synchronous and the method does not return until the animation has
41 * completed.
42 * @see LayoutAnimator
43 * @since 3.2
44 */
45 public class Animation {
46
47 static class AnimPair {
48
49 const Animator animator;
50 const IFigure figure;
51
52 this(Animator animator, IFigure figure) {
53 this.animator = animator;
54 this.figure = figure;
55 }
56
57 public override int opEquals(Object obj) {
58 AnimPair pair = cast(AnimPair)obj;
59 return pair.animator is animator && pair.figure is figure;
60 }
61
62 public override hash_t toHash() {
63 return (cast(Object)animator).toHash() ^ (cast(Object)figure).toHash();
64 }
65 }
66 private static const int DEFAULT_DELAY = 250;
67 private static Set figureAnimators;
68 private static Map finalStates;
69
70 private static Map initialStates;
71 private static const int PLAYBACK = 3;
72 private static float progress;
73 private static const int RECORD_FINAL = 2;
74
75 private static const int RECORD_INITIAL = 1;
76 private static long startTime;
77 private static int state;
78 private static Set toCapture;
79
80 private static UpdateManager updateManager;
81
82 private static void capture() {
83 Iterator keys = figureAnimators.iterator();
84 while (keys.hasNext()) {
85 AnimPair pair = cast(AnimPair) keys.next();
86 if (toCapture.contains(pair))
87 pair.animator.capture(pair.figure);
88 else
89 keys.remove();
90 }
91 }
92
93 static void cleanup() {
94 if (figureAnimators !is null) {
95 Iterator keys = figureAnimators.iterator();
96 while (keys.hasNext()) {
97 AnimPair pair = cast(AnimPair) keys.next();
98 pair.animator.tearDown(pair.figure);
99 }
100 }
101
102 state = 0;
103 step();
104 //Allow layout to occur normally
105 //updateManager.performUpdate();
106
107 initialStates = null;
108 finalStates = null;
109 figureAnimators = null;
110 updateManager = null;
111 toCapture = null;
112 state = 0;
113 }
114
115 private static void doRun(int duration) {
116 state = RECORD_FINAL;
117 findUpdateManager();
118 updateManager.performValidation();
119 capture();
120 state = PLAYBACK;
121 progress = 0.1f;
122 startTime = System.currentTimeMillis();
123
124 notifyPlaybackStarting();
125
126 while (progress !is 0) {
127 step();
128 updateManager.performUpdate();
129 if (progress is 1.0)
130 progress = 0;
131 else {
132 int delta = cast(int)(System.currentTimeMillis() - startTime);
133 if (delta >= duration)
134 progress = 1f;
135 else
136 progress = 0.1f + 0.9f * delta / duration;
137 }
138 }
139 }
140
141 private static void findUpdateManager() {
142 AnimPair pair = cast(AnimPair) figureAnimators.iterator().next();
143 updateManager = pair.figure.getUpdateManager();
144 }
145
146 /**
147 * Returns the final animation state for the given figure.
148 * @param animator the animator for the figure
149 * @param figure the figure being animated
150 * @return the final state
151 * @since 3.2
152 */
153 public static Object getFinalState(Animator animator, IFigure figure) {
154 return finalStates.get(new AnimPair(animator, figure));
155 }
156
157 /**
158 * Returns the initial animation state for the given animator and figure. If no state was
159 * recorded, <code>null</code> is returned.
160 * @param animator the animator for the figure
161 * @param figure the figure being animated
162 * @return the initial state
163 * @since 3.2
164 */
165 public static Object getInitialState(Animator animator, IFigure figure) {
166 return initialStates.get(new AnimPair(animator, figure));
167 }
168
169 /**
170 * Returns the animation progress, where 0.0 < progress &#8804; 1.0.
171 * @return the progress of the animation
172 * @since 3.2
173 */
174 public static float getProgress() {
175 return progress;
176 }
177
178 static void hookAnimator(IFigure figure, Animator animator) {
179 AnimPair pair = new AnimPair(animator, figure);
180 if (figureAnimators.add(pair))
181 animator.init(figure);
182 }
183
184 static void hookNeedsCapture(IFigure figure, Animator animator) {
185 AnimPair pair = new AnimPair(animator, figure);
186 if (figureAnimators.contains(pair))
187 toCapture.add(pair);
188 }
189
190 static bool hookPlayback(IFigure figure, Animator animator) {
191 if (toCapture.contains(new AnimPair(animator, figure)))
192 return animator.playback_package(figure);
193 return false;
194 }
195
196 /**
197 * Returns <code>true</code> if animation is in progress.
198 * @return <code>true</code> when animating
199 * @since 3.2
200 */
201 public static bool isAnimating() {
202 return state is PLAYBACK;
203 }
204
205 static bool isFinalRecording() {
206 return state is RECORD_FINAL;
207 }
208
209 static bool isInitialRecording() {
210 return state is RECORD_INITIAL;
211 }
212
213 /**
214 * Marks the beginning of the animation process. If the beginning has already been marked,
215 * this has no effect.
216 * @return returns <code>true</code> if beginning was not previously marked
217 * @since 3.2
218 */
219 public static bool markBegin() {
220 if (state is 0) {
221 state = RECORD_INITIAL;
222 initialStates = new HashMap();
223 finalStates = new HashMap();
224 figureAnimators = new HashSet();
225 toCapture = new HashSet();
226 return true;
227 }
228 return false;
229 }
230
231 private static void notifyPlaybackStarting() {
232 Iterator keys = figureAnimators.iterator();
233 while (keys.hasNext()) {
234 AnimPair pair = cast(AnimPair) keys.next();
235 pair.animator.playbackStarting(pair.figure);
236 }
237 }
238
239 static void putFinalState(Animator animator, IFigure key, Object state) {
240 finalStates.put(new AnimPair(animator, key), state);
241 }
242
243 static void putInitialState(Animator animator, IFigure key, Object state) {
244 initialStates.put(new AnimPair(animator, key), state);
245 }
246
247 /**
248 * Runs animation using the recommended duration: 250 milliseconds.
249 * @see #run(int)
250 * @since 3.2
251 */
252 public static void run() {
253 run(DEFAULT_DELAY);
254 }
255
256 /**
257 * Captures the final states for the animation and then plays the animation.
258 * @param duration the length of animation in milliseconds
259 * @since 3.2
260 */
261 public static void run(int duration) {
262 if (state is 0)
263 return;
264 try {
265 if (!figureAnimators.isEmpty())
266 doRun(duration);
267 } finally {
268 cleanup();
269 }
270 }
271
272 private static void step() {
273 Iterator iter = initialStates.keySet().iterator();
274 while (iter.hasNext())
275 (cast(AnimPair)iter.next()).figure.revalidate();
276 }
277
278 }