001: /*
002: * Copyright (c) 2001-2006 JGoodies Karsten Lentzsch. All Rights Reserved.
003: *
004: * Redistribution and use in source and binary forms, with or without
005: * modification, are permitted provided that the following conditions are met:
006: *
007: * o Redistributions of source code must retain the above copyright notice,
008: * this list of conditions and the following disclaimer.
009: *
010: * o Redistributions in binary form must reproduce the above copyright notice,
011: * this list of conditions and the following disclaimer in the documentation
012: * and/or other materials provided with the distribution.
013: *
014: * o Neither the name of JGoodies Karsten Lentzsch nor the names of
015: * its contributors may be used to endorse or promote products derived
016: * from this software without specific prior written permission.
017: *
018: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
019: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
020: * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
021: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
022: * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
023: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
024: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
025: * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
026: * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
027: * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
028: * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
029: */
030:
031: package com.jgoodies.animation;
032:
033: import java.util.Arrays;
034: import java.util.Collections;
035: import java.util.Iterator;
036: import java.util.LinkedList;
037: import java.util.List;
038:
039: /**
040: * This class consists only of static methods that either
041: * operate on animations or create useful standard animations.
042: *
043: * @author Karsten Lentzsch
044: * @version $Revision: 1.1 $
045: */
046: public final class Animations {
047:
048: private Animations() {
049: // Overrides the default constructor; prevents instantiation.
050: }
051:
052: /**
053: * Creates and returns an animation that is defined by a given
054: * animation and offset; the resulting animation applies
055: * the original effect shifted in time.
056: *
057: * @param beginTime the time to begin the shifted animation
058: * @param animation the animation to shift
059: * @return the shifted animation
060: */
061: public static Animation offset(long beginTime, Animation animation) {
062: return new OffsetAnimation(beginTime, animation);
063: }
064:
065: /**
066: * Creates and returns a parallel time container, that is an animation
067: * that applies the effect of the given animations all at the same time.
068: *
069: * @param animations a <code>List</code> of animations
070: * @return a parallel time container for the given animations
071: */
072: public static Animation parallel(List animations) {
073: return new ParallelAnimation(animations);
074: }
075:
076: /**
077: * Creates and returns a parallel time container for the given animations,
078: * that is an animation that applies the effect of the given animations
079: * at the same time.
080: *
081: * @param animation1 one of the animations to parallelize
082: * @param animation2 the other animation to parallelize
083: * @return the parallelized animation
084: */
085: public static Animation parallel(Animation animation1,
086: Animation animation2) {
087: List list = new LinkedList();
088: list.add(animation1);
089: list.add(animation2);
090: return parallel(list);
091: }
092:
093: /**
094: * Creates and returns a pausing animation that has no effect
095: * but a duration. It is useful in combination with sequenced
096: * and parallel time containers.
097: *
098: * @param duration the pause duration
099: * @return an animation that has no effect
100: */
101: public static Animation pause(long duration) {
102: return new PauseAnimation(duration);
103: }
104:
105: /**
106: * Creates and answers an animation that is defined by repeating
107: * the given animation. The result's duration is the
108: * duration times repeatCount.
109: *
110: * @param repeatCount the number of repetitions
111: * @param animation the animation to repeat
112: * @return the repeated animation
113: */
114: public static Animation repeat(float repeatCount,
115: Animation animation) {
116: long duration = (long) (animation.duration() * repeatCount);
117: return new RepeatedAnimation(duration, animation);
118: }
119:
120: /**
121: * Creates and returns an animation that is defined by reverting
122: * the given animation over the time.
123: *
124: * @param animation the animation to reverse
125: * @return the reversed animation
126: */
127: public static Animation reverse(Animation animation) {
128: return new ReversedAnimation(animation);
129: }
130:
131: /**
132: * Creates and returns a sequenced time container that is an animation,
133: * that concatenates the given list of animations over the time.
134: *
135: * @param animations a <code>List</code> of animations
136: * @return the sequenced animation
137: */
138: public static Animation sequential(List animations) {
139: return new SequencedAnimation(animations);
140: }
141:
142: /**
143: * Creates and returns a sequenced time container that is an animation,
144: * that concatenates the given array of animations over the time.
145: *
146: * @param animations an array of animations
147: * @return the sequenced animation
148: */
149: public static Animation sequential(Animation[] animations) {
150: return sequential(Arrays.asList(animations));
151: }
152:
153: /**
154: * Creates and returns an animation that is defined by concatenating
155: * the two given animations.
156: *
157: * @param first the first animation in the sequence
158: * @param second the second animation in the sequence
159: * @return a sequenced animation
160: */
161: public static Animation sequential(Animation first, Animation second) {
162: List sequence = new LinkedList();
163: sequence.add(first);
164: sequence.add(second);
165: return sequential(sequence);
166: }
167:
168: // Helper Classes *********************************************************
169:
170: /**
171: * Helper class that wraps an animation to give it a time offset.
172: */
173: private static final class OffsetAnimation extends
174: AbstractAnimation {
175: private final Animation animation;
176: private final long beginTime;
177:
178: private OffsetAnimation(long beginTime, Animation animation) {
179: super (beginTime + animation.duration(), true);
180: this .animation = animation;
181: this .beginTime = beginTime;
182: }
183:
184: protected void applyEffect(long time) {
185: long relativeTime = time - beginTime;
186: if (relativeTime >= 0)
187: animation.animate(relativeTime);
188: }
189:
190: }
191:
192: /**
193: * Used to apply an effect one-time only.
194: */
195: public abstract static class OneTimeAnimation extends
196: AbstractAnimation {
197:
198: private boolean effectApplied;
199:
200: /**
201: * Constructs a <code>OneTimeAnimation</code>.
202: */
203: public OneTimeAnimation() {
204: super (0, true);
205: effectApplied = false;
206: }
207:
208: /**
209: * Applies the effect to the animation target,
210: * only if is hasn't been applied before.
211: *
212: * @param time the time used to determine the animation effect
213: */
214: public void animate(long time) {
215: if (effectApplied)
216: return;
217:
218: fireAnimationStarted(time);
219: applyEffect(time);
220: fireAnimationStopped(time);
221: effectApplied = true;
222: }
223: }
224:
225: /**
226: * Helper class to parallelize animations.
227: */
228: private static final class ParallelAnimation extends
229: AbstractAnimation {
230: private final List animations;
231:
232: private ParallelAnimation(List animations) {
233: super (maxDuration(animations), true);
234: this .animations = animations;
235: }
236:
237: private static long maxDuration(List animations) {
238: long maxDuration = 0;
239: for (Iterator i = animations.iterator(); i.hasNext();) {
240: Animation animation = (Animation) i.next();
241: long duration = animation.duration();
242: if (duration > maxDuration)
243: maxDuration = duration;
244: }
245: return maxDuration;
246: }
247:
248: protected void applyEffect(long time) {
249: for (Iterator i = animations.iterator(); i.hasNext();) {
250: Animation animation = (Animation) i.next();
251: animation.animate(time);
252: }
253: }
254:
255: }
256:
257: /**
258: * Helper class for a pause, an animation, that has no effect.
259: */
260: private static final class PauseAnimation extends AbstractAnimation {
261: PauseAnimation(long duration) {
262: super (duration, true);
263: }
264:
265: protected void applyEffect(long time) {
266: // Just pause, do nothing.
267: }
268: }
269:
270: /**
271: * Helper class to repeat an animation.
272: */
273: private static final class RepeatedAnimation extends
274: AbstractAnimation {
275: private final Animation animation;
276: private final long simpleDuration;
277:
278: private RepeatedAnimation(long duration, Animation animation) {
279: super (duration, true);
280: this .animation = animation;
281: this .simpleDuration = animation.duration();
282: }
283:
284: protected void applyEffect(long time) {
285: animation.animate(time % simpleDuration);
286: }
287: }
288:
289: /**
290: * Helper class to reverse an animation over the time.
291: */
292: private static final class ReversedAnimation extends
293: AbstractAnimation {
294: private final Animation animation;
295:
296: private ReversedAnimation(Animation animation) {
297: super (animation.duration(), true);
298: this .animation = animation;
299: }
300:
301: protected void applyEffect(long time) {
302: long reversedTime = duration() - time;
303: if (reversedTime < 0)
304: throw new IllegalArgumentException(
305: "The time is outside the valid time interval.");
306:
307: animation.animate(reversedTime);
308: }
309: }
310:
311: /**
312: * Helper class to create a sequence of animations.
313: */
314: private static final class SequencedAnimation extends
315: AbstractAnimation {
316: private final List animations;
317:
318: private SequencedAnimation(List animations) {
319: super (cumulatedDuration(animations), true);
320: this .animations = Collections.unmodifiableList(animations);
321: if (this .animations.isEmpty())
322: throw new IllegalArgumentException(
323: "The list of animations must not be empty.");
324: }
325:
326: private static long cumulatedDuration(List animations) {
327: long cumulatedDuration = 0;
328: for (Iterator i = animations.iterator(); i.hasNext();) {
329: Animation animation = (Animation) i.next();
330: cumulatedDuration += animation.duration();
331: }
332: return cumulatedDuration;
333: }
334:
335: protected void applyEffect(long time) {
336: long startTime = 0;
337: for (Iterator i = animations.iterator(); i.hasNext();) {
338: Animation animation = (Animation) i.next();
339: long relativeTime = time - startTime;
340: if (relativeTime > 0)
341: animation.animate(relativeTime);
342: startTime += animation.duration();
343: }
344: }
345:
346: }
347:
348: }
|