001: /*
002: * Copyright (c) 2006-2007 Valerio Proietti
003: *
004: * Permission is hereby granted, free of charge, to any person obtaining a copy
005: * of this software and associated documentation files (the "Software"), to deal
006: * in the Software without restriction, including without limitation the rights
007: * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
008: * copies of the Software, and to permit persons to whom the Software is
009: * furnished to do so, subject to the following conditions:
010: *
011: * The above copyright notice and this permission notice shall be included in
012: * all copies or substantial portions of the Software.
013: *
014: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
015: * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
016: * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
017: * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
018: * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
019: * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
020: * THE SOFTWARE.
021: *
022: * Contributors:
023: * Valerio Proietti - initial API and implementation
024: * MyGWT - derived implementation
025: */
026: package net.mygwt.ui.client.fx;
027:
028: import java.util.Date;
029:
030: import net.mygwt.ui.client.Events;
031: import net.mygwt.ui.client.event.EffectListener;
032: import net.mygwt.ui.client.event.TypedListener;
033: import net.mygwt.ui.client.util.Observable;
034:
035: import com.google.gwt.user.client.Timer;
036:
037: /**
038: * Base class for animation effects.
039: *
040: * <p>
041: * This code is based on code from the MooTools Project by Valerio Proietti.
042: * </p>
043: *
044: * <dl>
045: * <dt><b>Events:</b></dt>
046: *
047: * <dd><b>EffectStart</b> : (source this)<br>
048: * <div>Fires after an effect is started.</div>
049: * <ul>
050: * <li>source : this</li>
051: * </ul>
052: * </dd>
053: *
054: * <dd><b>EffecCancel</b> : (source this)<br>
055: * <div>Fires after an effect has been cancelled.</div>
056: * <ul>
057: * <li>source : this</li>
058: * </ul>
059: * </dd>
060: *
061: * <dd><b>EffecComplete</b> : (source this)<br>
062: * <div>Fires after an effect has been completed</div>
063: * <ul>
064: * <li>source : this</li>
065: * </ul>
066: * </dd>
067: * </dl>
068: * <dl>
069: *
070: * This class is partially based on the Fx package in the MooTools framework, see
071: * http://mootools.net.
072: * </p>
073: */
074: public class FX extends Observable {
075:
076: /**
077: * The duration of the effect in ms. Default value is 500.
078: */
079: public int duration = 500;
080:
081: /**
082: * The frames per second for the transition. Default is 50.
083: */
084: public int fps = 50;
085:
086: /**
087: * To wait or not to wait for a current transition to end before running
088: * another of the same instance. Default value is <code>true</code>.
089: */
090: public boolean wait = true;
091:
092: /**
093: * The effect transition. Default values is Transition.LINEAR;
094: */
095: public Transition transition = Transition.LINEAR;
096:
097: /**
098: * <code>true</code> to hide the element after the effect using the css
099: * 'display' attribute.
100: */
101: public boolean hideOnComplete = false;
102:
103: protected Effect[] effects;
104: protected Timer timer;
105: protected boolean running;
106:
107: private long time;
108: private double delta;
109:
110: /**
111: * Adds a listener to be notified of effect events.
112: *
113: * @param listener the listener to be added
114: */
115: public void addEffectListener(EffectListener listener) {
116: TypedListener tl = new TypedListener(listener);
117: addListener(Events.EffectStart, tl);
118: addListener(Events.EffectCancel, tl);
119: addListener(Events.EffectComplete, tl);
120: }
121:
122: /**
123: * Cancels the animation.
124: */
125: public void cancel() {
126: if (!running)
127: return;
128: timer.cancel();
129: timer = null;
130: running = false;
131: fireEvent(Events.EffectCancel);
132: }
133:
134: /**
135: * Returns the current effects.
136: *
137: * @return the effect array
138: */
139: public Effect[] getEffects() {
140: return effects;
141: }
142:
143: /**
144: * Returns <code>true</code> if any effects are running.
145: *
146: * @return the running state
147: */
148: public boolean isRunning() {
149: return running;
150: }
151:
152: /**
153: * Removes a previously added effect listener.
154: *
155: * @param listener the listener to be removed
156: */
157: public void removeEffectListener(EffectListener listener) {
158: if (eventTable == null)
159: return;
160: eventTable.unhook(Events.EffectStart, listener);
161: eventTable.unhook(Events.EffectCancel, listener);
162: eventTable.unhook(Events.EffectComplete, listener);
163: }
164:
165: /**
166: * Runs the effect.
167: *
168: * @param effect the effect to be run
169: */
170: public void start(Effect effect) {
171: start(new Effect[] { effect });
172: }
173:
174: /**
175: * Runs the list of effects.
176: *
177: * @param effects the effects to be run
178: */
179: public void start(Effect[] effects) {
180: if (!wait) {
181: stop();
182: } else if (running) {
183: return;
184: }
185: running = true;
186: this .effects = effects;
187: this .time = new Date().getTime();
188:
189: for (int i = 0; i < effects.length; i++) {
190: Effect effect = effects[i];
191: effect.onStart();
192: }
193:
194: timer = new Timer() {
195: public void run() {
196: step();
197: }
198: };
199: timer.scheduleRepeating(Math.round(1000 / fps));
200:
201: fireEvent(Events.EffectStart);
202: }
203:
204: /**
205: * Stops the animation.
206: */
207: public void stop() {
208: if (!running)
209: return;
210: timer.cancel();
211: timer = null;
212: running = false;
213: for (int i = 0; i < effects.length; i++) {
214: Effect effect = effects[i];
215: effect.increase(effect.to);
216: effect.onComplete();
217: }
218: fireEvent(Events.EffectComplete);
219: }
220:
221: protected double compute(double from, double to) {
222: return (to - from) * delta + from;
223: }
224:
225: protected double getNow(Effect effect) {
226: return compute(effect.from, effect.to);
227: }
228:
229: protected void onComplete() {
230:
231: }
232:
233: protected void onStart() {
234:
235: }
236:
237: protected void step() {
238: long time = new Date().getTime();
239: if (time < this .time + duration) {
240: double diff = time - this .time;
241: delta = transition.compute(diff / duration);
242: for (int i = 0; i < effects.length; i++) {
243: Effect effect = effects[i];
244: effect.increase(getNow(effect));
245: }
246: } else {
247: stop();
248: onComplete();
249: }
250: }
251:
252: }
|