Mercurial > projects > dwt-addons
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 ≤ 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 } |