trident-1.3/0000755000175000017500000000000011515134130012342 5ustar andrewandrewtrident-1.3/src/0000755000175000017500000000000011515134130013131 5ustar andrewandrewtrident-1.3/src/org/0000755000175000017500000000000011346133506013730 5ustar andrewandrewtrident-1.3/src/org/pushingpixels/0000755000175000017500000000000011346133506016632 5ustar andrewandrewtrident-1.3/src/org/pushingpixels/trident/0000755000175000017500000000000011403126554020302 5ustar andrewandrewtrident-1.3/src/org/pushingpixels/trident/Timeline.java0000644000175000017500000004414711403126554022725 0ustar andrewandrew/* * Copyright (c) 2005-2010 Trident Kirill Grouchnikov. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * o Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * o Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * o Neither the name of Trident Kirill Grouchnikov nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.pushingpixels.trident; import java.util.*; import org.pushingpixels.trident.TimelineEngine.FullObjectID; import org.pushingpixels.trident.TimelineEngine.TimelineOperationKind; import org.pushingpixels.trident.TimelinePropertyBuilder.AbstractFieldInfo; import org.pushingpixels.trident.callback.*; import org.pushingpixels.trident.ease.Linear; import org.pushingpixels.trident.ease.TimelineEase; import org.pushingpixels.trident.interpolator.KeyFrames; public class Timeline implements TimelineScenario.TimelineScenarioActor { Object mainObject; Comparable secondaryId; FullObjectID fullObjectID; long duration; long initialDelay; long cycleDelay; boolean isLooping; int repeatCount; RepeatBehavior repeatBehavior; UIToolkitHandler uiToolkitHandler; Chain callback; String name; List propertiesToInterpolate; /** * Is used to create unique value for the {@link #id} field. */ static long counter; /** * Unique ID. */ protected long id; /** * Timeline position. */ float durationFraction; /** * Timeline position. */ float timelinePosition; long timeUntilPlay; /** * Indication whether the looping timeline should stop at reaching the end * of the cycle. Relevant only when {@link #isLooping} is true. */ boolean toCancelAtCycleBreak; Stack stateStack; TimelineEase ease; private int doneCount; public enum RepeatBehavior { LOOP, REVERSE } public enum TimelineState { IDLE(false), READY(false), PLAYING_FORWARD(true), PLAYING_REVERSE(true), SUSPENDED( false), CANCELLED(false), DONE(false); private boolean isActive; private TimelineState(boolean isActive) { this.isActive = isActive; } } private class Setter extends TimelineCallbackAdapter { @Override public void onTimelineStateChanged(TimelineState oldState, TimelineState newState, float durationFraction, float timelinePosition) { if (newState == TimelineState.READY) { for (AbstractFieldInfo fInfo : propertiesToInterpolate) { // check whether the object is in the ready state if ((uiToolkitHandler != null) && !uiToolkitHandler.isInReadyState(fInfo.object)) continue; fInfo.onStart(); } } // Fix for issue 5 - update field values only when // either old or new state (or both) are active. Otherwise // it's a transition between inactive states (such as from // DONE to IDLE) that shouldn't trigger the property changes if (oldState.isActive || newState.isActive) { for (AbstractFieldInfo fInfo : propertiesToInterpolate) { // check whether the object is in the ready state if ((uiToolkitHandler != null) && !uiToolkitHandler.isInReadyState(fInfo.object)) continue; fInfo.updateFieldValue(timelinePosition); } } } @Override public void onTimelinePulse(float durationFraction, float timelinePosition) { for (AbstractFieldInfo fInfo : propertiesToInterpolate) { // check whether the object is in the ready state if ((uiToolkitHandler != null) && !uiToolkitHandler.isInReadyState(fInfo.object)) continue; // System.err.println("Timeline @" + Timeline.this.hashCode() // + " at position " + timelinePosition); fInfo.updateFieldValue(timelinePosition); } } } @RunOnUIThread private class UISetter extends Setter { } class Chain implements TimelineCallback { private List callbacks; public Chain(TimelineCallback... callbacks) { this.callbacks = new ArrayList(); for (TimelineCallback callback : callbacks) this.callbacks.add(callback); } public void addCallback(TimelineCallback callback) { this.callbacks.add(callback); } public void removeCallback(TimelineCallback callback) { this.callbacks.remove(callback); } @Override public void onTimelineStateChanged(final TimelineState oldState, final TimelineState newState, final float durationFraction, final float timelinePosition) { if ((uiToolkitHandler != null) && !uiToolkitHandler.isInReadyState(mainObject)) return; for (int i = this.callbacks.size() - 1; i >= 0; i--) { final TimelineCallback callback = this.callbacks.get(i); // special handling for chained callbacks not running on UI // thread boolean shouldRunOnUIThread = false; Class clazz = callback.getClass(); while ((clazz != null) && !shouldRunOnUIThread) { shouldRunOnUIThread = clazz .isAnnotationPresent(RunOnUIThread.class); clazz = clazz.getSuperclass(); } if (shouldRunOnUIThread && (Timeline.this.uiToolkitHandler != null)) { Timeline.this.uiToolkitHandler.runOnUIThread(mainObject, new Runnable() { public void run() { callback.onTimelineStateChanged(oldState, newState, durationFraction, timelinePosition); } }); } else { callback.onTimelineStateChanged(oldState, newState, durationFraction, timelinePosition); } } } @Override public void onTimelinePulse(final float durationFraction, final float timelinePosition) { if ((uiToolkitHandler != null) && !uiToolkitHandler.isInReadyState(mainObject)) return; for (int i = this.callbacks.size() - 1; i >= 0; i--) { final TimelineCallback callback = this.callbacks.get(i); // special handling for chained callbacks not running on UI // thread boolean shouldRunOnUIThread = false; Class clazz = callback.getClass(); while ((clazz != null) && !shouldRunOnUIThread) { shouldRunOnUIThread = clazz .isAnnotationPresent(RunOnUIThread.class); clazz = clazz.getSuperclass(); } if (shouldRunOnUIThread && (Timeline.this.uiToolkitHandler != null)) { Timeline.this.uiToolkitHandler.runOnUIThread(mainObject, new Runnable() { public void run() { if (Timeline.this.getState() == TimelineState.CANCELLED) return; // System.err.println("Timeline @" // + Timeline.this.hashCode()); callback.onTimelinePulse(durationFraction, timelinePosition); } }); } else { // System.err.println("Timeline @" + // Timeline.this.hashCode()); callback .onTimelinePulse(durationFraction, timelinePosition); } } } } public Timeline() { this(null); } public Timeline(Object mainTimelineObject) { this.mainObject = mainTimelineObject; for (UIToolkitHandler uiToolkitHandler : TridentConfig.getInstance() .getUIToolkitHandlers()) { if (uiToolkitHandler.isHandlerFor(mainTimelineObject)) { this.uiToolkitHandler = uiToolkitHandler; break; } } // if the main timeline object is handled by a UI toolkit handler, // the setters registered with the different addProperty // APIs need to run with the matching threading policy TimelineCallback setterCallback = (this.uiToolkitHandler != null) ? new UISetter() : new Setter(); this.callback = new Chain(setterCallback); this.duration = 500; this.propertiesToInterpolate = new ArrayList(); this.id = Timeline.getId(); // this.loopsToLive = -1; this.stateStack = new Stack(); this.stateStack.push(TimelineState.IDLE); this.doneCount = 0; this.ease = new Linear(); } public final void setSecondaryID(Comparable secondaryId) { if (this.getState() != TimelineState.IDLE) { throw new IllegalArgumentException( "Cannot change state of non-idle timeline [" + this.toString() + "]"); } this.secondaryId = secondaryId; } public final void setDuration(long durationMs) { if (this.getState() != TimelineState.IDLE) { throw new IllegalArgumentException( "Cannot change state of non-idle timeline [" + this.toString() + "]"); } this.duration = durationMs; } public final void setInitialDelay(long initialDelay) { if (this.getState() != TimelineState.IDLE) { throw new IllegalArgumentException( "Cannot change state of non-idle timeline [" + this.toString() + "]"); } this.initialDelay = initialDelay; } public final void setCycleDelay(long cycleDelay) { if (this.getState() != TimelineState.IDLE) { throw new IllegalArgumentException( "Cannot change state of non-idle timeline [" + this.toString() + "]"); } this.cycleDelay = cycleDelay; } public final void addCallback(TimelineCallback callback) { if (this.getState() != TimelineState.IDLE) { throw new IllegalArgumentException( "Cannot change state of non-idle timeline [" + this.toString() + "]"); } this.callback.addCallback(callback); } public final void removeCallback(TimelineCallback callback) { if (this.getState() != TimelineState.IDLE) { throw new IllegalArgumentException( "Cannot change state of non-idle timeline [" + this.toString() + "]"); } this.callback.removeCallback(callback); } public static TimelinePropertyBuilder property(String propertyName) { return new TimelinePropertyBuilder(propertyName); } public final void addPropertyToInterpolate( TimelinePropertyBuilder propertyBuilder) { this.propertiesToInterpolate.add(propertyBuilder.getFieldInfo(this)); } public final void addPropertyToInterpolate(String propName, KeyFrames keyFrames) { this.addPropertyToInterpolate(Timeline. property(propName) .goingThrough(keyFrames)); } public final void addPropertyToInterpolate(String propName, T from, T to) { this.addPropertyToInterpolate(Timeline. property(propName) .from(from).to(to)); } public void play() { this.playSkipping(0); } public void playSkipping(final long msToSkip) { if ((this.initialDelay + this.duration) < msToSkip) { throw new IllegalArgumentException( "Required skip longer than initial delay + duration"); } TimelineEngine.getInstance().runTimelineOperation(this, TimelineOperationKind.PLAY, new Runnable() { @Override public void run() { Timeline.this.isLooping = false; TimelineEngine.getInstance().play(Timeline.this, false, msToSkip); } }); } public void playReverse() { playReverseSkipping(0); } public void playReverseSkipping(final long msToSkip) { if ((this.initialDelay + this.duration) < msToSkip) { throw new IllegalArgumentException( "Required skip longer than initial delay + duration"); } TimelineEngine.getInstance().runTimelineOperation(this, TimelineOperationKind.PLAY, new Runnable() { @Override public void run() { Timeline.this.isLooping = false; TimelineEngine.getInstance().playReverse(Timeline.this, false, msToSkip); } }); } public void replay() { TimelineEngine.getInstance().runTimelineOperation(this, TimelineOperationKind.PLAY, new Runnable() { @Override public void run() { Timeline.this.isLooping = false; TimelineEngine.getInstance().play(Timeline.this, true, 0); } }); } public void replayReverse() { TimelineEngine.getInstance().runTimelineOperation(this, TimelineOperationKind.PLAY, new Runnable() { @Override public void run() { Timeline.this.isLooping = false; TimelineEngine.getInstance().playReverse(Timeline.this, true, 0); } }); } public void playLoop(RepeatBehavior repeatBehavior) { this.playLoop(-1, repeatBehavior); } public void playLoopSkipping(RepeatBehavior repeatBehavior, final long msToSkip) { this.playLoopSkipping(-1, repeatBehavior, msToSkip); } public void playLoop(int loopCount, RepeatBehavior repeatBehavior) { this.playLoopSkipping(loopCount, repeatBehavior, 0); } public void playLoopSkipping(final int loopCount, final RepeatBehavior repeatBehavior, final long msToSkip) { if ((this.initialDelay + this.duration) < msToSkip) { throw new IllegalArgumentException( "Required skip longer than initial delay + duration"); } TimelineEngine.getInstance().runTimelineOperation(this, TimelineOperationKind.PLAY, new Runnable() { @Override public void run() { Timeline.this.isLooping = true; Timeline.this.repeatCount = loopCount; Timeline.this.repeatBehavior = repeatBehavior; TimelineEngine.getInstance().playLoop(Timeline.this, msToSkip); } }); } /** * Cancels this timeline. The timeline transitions to the * {@link TimelineState#CANCELLED} state, preserving its current timeline * position. After application callbacks and field interpolations are done * on the {@link TimelineState#CANCELLED} state, the timeline transitions to * the {@link TimelineState#IDLE} state. Application callbacks and field * interpolations are done on this state as well. * * @see #end() * @see #abort() */ public void cancel() { TimelineEngine.getInstance().runTimelineOperation(this, TimelineOperationKind.CANCEL, null); } /** * Ends this timeline. The timeline transitions to the * {@link TimelineState#DONE} state, with the timeline position set to 0.0 * or 1.0 - based on the direction of the timeline. After application * callbacks and field interpolations are done on the * {@link TimelineState#DONE} state, the timeline transitions to the * {@link TimelineState#IDLE} state. Application callbacks and field * interpolations are done on this state as well. * * @see #cancel() * @see #abort() */ public void end() { TimelineEngine.getInstance().runTimelineOperation(this, TimelineOperationKind.END, null); } /** * Aborts this timeline. The timeline transitions to the * {@link TimelineState#IDLE} state. No application callbacks or field * interpolations are done. * * @see #cancel() * @see #end() */ public void abort() { TimelineEngine.getInstance().runTimelineOperation(this, TimelineOperationKind.ABORT, null); } public void suspend() { TimelineEngine.getInstance().runTimelineOperation(this, TimelineOperationKind.SUSPEND, null); } public void resume() { TimelineEngine.getInstance().runTimelineOperation(this, TimelineOperationKind.RESUME, null); } /** * Requests that the specified timeline should stop at the end of the cycle. * This method should be called only on looping timelines. */ public void cancelAtCycleBreak() { if (!this.isLooping) throw new IllegalArgumentException( "Can only be called on looping timelines"); this.toCancelAtCycleBreak = true; } /** * Returns a unique ID. * * @return Unique ID. */ protected static synchronized long getId() { return counter++; } public final float getTimelinePosition() { return this.timelinePosition; } public final float getDurationFraction() { return this.durationFraction; } public final TimelineState getState() { return this.stateStack.peek(); } public final void setEase(TimelineEase ease) { if (this.getState() != TimelineState.IDLE) { throw new IllegalArgumentException( "Cannot change state of non-idle timeline"); } this.ease = ease; } @Override public boolean isDone() { return (this.doneCount > 0); } @Override public boolean supportsReplay() { return true; } @Override public void resetDoneFlag() { this.doneCount = 0; } @Override public String toString() { StringBuffer res = new StringBuffer(); if (this.name != null) { res.append(this.name); } if (this.mainObject != null) { res.append(":" + this.mainObject.getClass().getName()); } if (this.secondaryId != null) { res.append(":" + this.secondaryId.toString()); } res.append(" " + this.getState().name()); res.append(":" + this.timelinePosition); return res.toString(); } void replaceState(TimelineState state) { this.stateStack.pop(); this.pushState(state); } void pushState(TimelineState state) { if (state == TimelineState.DONE) this.doneCount++; this.stateStack.add(state); } TimelineState popState() { return this.stateStack.pop(); } public final long getDuration() { return this.duration; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Object getMainObject() { return this.mainObject; } }trident-1.3/src/org/pushingpixels/trident/android/0000755000175000017500000000000011346133506021723 5ustar andrewandrewtrident-1.3/src/org/pushingpixels/trident/android/AndroidPropertyInterpolators.java0000644000175000017500000001356011346133506030506 0ustar andrewandrew/* * Copyright (c) 2005-2010 Trident Kirill Grouchnikov. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * o Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * o Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * o Neither the name of Trident Kirill Grouchnikov nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.pushingpixels.trident.android; import java.util.*; import org.pushingpixels.trident.interpolator.PropertyInterpolator; import org.pushingpixels.trident.interpolator.PropertyInterpolatorSource; import android.graphics.*; /** * Built-in interpolators for Android classes. * * @author Kirill Grouchnikov */ public class AndroidPropertyInterpolators implements PropertyInterpolatorSource { private Set interpolators; public static final PropertyInterpolator COLOR_INTERPOLATOR = new ColorInterpolator(); public AndroidPropertyInterpolators() { this.interpolators = new HashSet(); this.interpolators.add(COLOR_INTERPOLATOR); this.interpolators.add(new PointInterpolator()); this.interpolators.add(new RectInterpolator()); this.interpolators.add(new RectFInterpolator()); } @Override public Set getPropertyInterpolators() { return Collections.unmodifiableSet(this.interpolators); } static class ColorInterpolator implements PropertyInterpolator { @Override public Class getBasePropertyClass() { return Color.class; } @Override public Integer interpolate(Integer from, Integer to, float timelinePosition) { return getInterpolatedRGB(from, to, 1.0f - timelinePosition); } int getInterpolatedRGB(Integer color1, Integer color2, float color1Likeness) { if ((color1Likeness < 0.0) || (color1Likeness > 1.0)) throw new IllegalArgumentException( "Color likeness should be in 0.0-1.0 range [is " + color1Likeness + "]"); if (color1.equals(color2)) return color1; if (color1Likeness == 1.0) return color1; if (color1Likeness == 0.0) return color2; int lr = Color.red(color1); int lg = Color.green(color1); int lb = Color.blue(color1); int la = Color.alpha(color1); int dr = Color.red(color2); int dg = Color.green(color2); int db = Color.blue(color2); int da = Color.alpha(color2); // using some interpolation values (such as 0.29 from issue 401) // results in an incorrect final value without Math.round. int r = (lr == dr) ? lr : (int) Math.round(color1Likeness * lr + (1.0 - color1Likeness) * dr); int g = (lg == dg) ? lg : (int) Math.round(color1Likeness * lg + (1.0 - color1Likeness) * dg); int b = (lb == db) ? lb : (int) Math.round(color1Likeness * lb + (1.0 - color1Likeness) * db); int a = (la == da) ? la : (int) Math.round(color1Likeness * la + (1.0 - color1Likeness) * da); return Color.argb(a, r, g, b); } } static class PointInterpolator implements PropertyInterpolator { public Point interpolate(Point from, Point to, float timelinePosition) { int x = from.x + (int) (timelinePosition * (to.x - from.x)); int y = from.y + (int) (timelinePosition * (to.y - from.y)); return new Point(x, y); } @Override public Class getBasePropertyClass() { return Point.class; } } static class RectInterpolator implements PropertyInterpolator { public Rect interpolate(Rect from, Rect to, float timelinePosition) { int left = from.left + (int) (timelinePosition * (to.left - from.left)); int top = from.top + (int) (timelinePosition * (to.top - from.top)); int right = from.right + (int) (timelinePosition * (to.right - from.right)); int bottom = from.bottom + (int) (timelinePosition * (to.bottom - from.bottom)); return new Rect(left, top, right, bottom); } @Override public Class getBasePropertyClass() { return Rect.class; } } static class RectFInterpolator implements PropertyInterpolator { public RectF interpolate(RectF from, RectF to, float timelinePosition) { float left = from.left + (int) (timelinePosition * (to.left - from.left)); float top = from.top + (int) (timelinePosition * (to.top - from.top)); float right = from.right + (int) (timelinePosition * (to.right - from.right)); float bottom = from.bottom + (int) (timelinePosition * (to.bottom - from.bottom)); return new RectF(left, top, right, bottom); } @Override public Class getBasePropertyClass() { return RectF.class; } } } trident-1.3/src/org/pushingpixels/trident/android/AndroidRepaintCallback.java0000644000175000017500000000551511346133506027114 0ustar andrewandrew/* * Copyright (c) 2005-2010 Trident Kirill Grouchnikov. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * o Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * o Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * o Neither the name of Trident Kirill Grouchnikov nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.pushingpixels.trident.android; import org.pushingpixels.trident.Timeline.TimelineState; import org.pushingpixels.trident.callback.RunOnUIThread; import org.pushingpixels.trident.callback.TimelineCallback; import android.graphics.Rect; import android.view.View; @RunOnUIThread public class AndroidRepaintCallback implements TimelineCallback { private View view; private Rect rect; public AndroidRepaintCallback(View view) { this(view, null); } public AndroidRepaintCallback(View view, Rect rect) { if (view == null) { throw new NullPointerException("View must be non-null"); } this.view = view; this.rect = rect; } @Override public void onTimelinePulse(float durationFraction, float timelinePosition) { if (this.rect == null) this.view.invalidate(); else this.view.invalidate(this.rect.left, this.rect.top, this.rect.right, this.rect.bottom); } @Override public void onTimelineStateChanged(TimelineState oldState, TimelineState newState, float durationFraction, float timelinePosition) { if (this.rect == null) this.view.invalidate(); else this.view.invalidate(this.rect.left, this.rect.top, this.rect.right, this.rect.bottom); } } trident-1.3/src/org/pushingpixels/trident/android/TimelineAsyncTask.java0000644000175000017500000000416211346133506026160 0ustar andrewandrew/* * Copyright (c) 2005-2010 Trident Kirill Grouchnikov. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * o Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * o Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * o Neither the name of Trident Kirill Grouchnikov nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.pushingpixels.trident.android; import org.pushingpixels.trident.TimelineScenario; import android.os.AsyncTask; public abstract class TimelineAsyncTask extends AsyncTask implements TimelineScenario.TimelineScenarioActor { @Override public void play() { this.execute(); } @Override public boolean supportsReplay() { return false; } @Override public void resetDoneFlag() { throw new UnsupportedOperationException(); } } trident-1.3/src/org/pushingpixels/trident/android/AndroidRepaintTimeline.java0000644000175000017500000000562011346133506027163 0ustar andrewandrew/* * Copyright (c) 2005-2010 Trident Kirill Grouchnikov. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * o Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * o Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * o Neither the name of Trident Kirill Grouchnikov nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.pushingpixels.trident.android; import org.pushingpixels.trident.Timeline; import android.graphics.Rect; import android.view.View; public class AndroidRepaintTimeline extends Timeline { public AndroidRepaintTimeline(View mainTimelineView) { this(mainTimelineView, null); } public AndroidRepaintTimeline(View mainTimelineView, Rect toRepaint) { super(mainTimelineView); this .addCallback(new AndroidRepaintCallback(mainTimelineView, toRepaint)); } @Override public void play() { throw new UnsupportedOperationException( "Only infinite looping is supported"); } @Override public void playReverse() { throw new UnsupportedOperationException( "Only infinite looping is supported"); } @Override public void replay() { throw new UnsupportedOperationException( "Only infinite looping is supported"); } @Override public void replayReverse() { throw new UnsupportedOperationException( "Only infinite looping is supported"); } @Override public void playLoop(int loopCount, RepeatBehavior repeatBehavior) { if (loopCount >= 0) { throw new UnsupportedOperationException( "Only infinite looping is supported"); } super.playLoop(loopCount, repeatBehavior); } }trident-1.3/src/org/pushingpixels/trident/android/AndroidToolkitHandler.java0000644000175000017500000000427111346133506027016 0ustar andrewandrew/* * Copyright (c) 2005-2010 Trident Kirill Grouchnikov. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * o Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * o Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * o Neither the name of Trident Kirill Grouchnikov nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.pushingpixels.trident.android; import org.pushingpixels.trident.UIToolkitHandler; import android.view.View; public class AndroidToolkitHandler implements UIToolkitHandler { @Override public boolean isHandlerFor(Object mainTimelineObject) { return (mainTimelineObject instanceof View); } @Override public boolean isInReadyState(Object mainTimelineObject) { return true; } @Override public void runOnUIThread(Object mainTimelineObject, final Runnable runnable) { ((View) mainTimelineObject).post(runnable); } } trident-1.3/src/org/pushingpixels/trident/ease/0000755000175000017500000000000011346133506021220 5ustar andrewandrewtrident-1.3/src/org/pushingpixels/trident/ease/Spline.java0000644000175000017500000001630511346133506023322 0ustar andrewandrew/* * Copyright (c) 2005-2010 Trident Kirill Grouchnikov. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * o Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * o Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * o Neither the name of Trident Kirill Grouchnikov nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.pushingpixels.trident.ease; import java.util.ArrayList; /** * Spline easer. Is based on the code from TimingFramework by Chet Haase * and Romain Guy. * * @author Kirill Grouchnikov */ public class Spline implements TimelineEase { // private float easeAmount; public Spline(float easeAmount) { this(easeAmount, 0, 1 - easeAmount, 1); // this.easeAmount = easeAmount; } private static class FloatPoint { public float x; public float y; public FloatPoint(float x, float y) { this.x = x; this.y = y; } } // Note: (x0,y0) and (x1,y1) are implicitly (0, 0) and (1,1) respectively private float x1, y1, x2, y2; private ArrayList lengths = new ArrayList(); /** * Creates a new instance of SplineInterpolator with the control points * defined by (x1, y1) and (x2, y2). The anchor points are implicitly * defined as (0, 0) and (1, 1). * * @throws IllegalArgumentException * This exception is thrown when values beyond the allowed [0,1] * range are passed in */ public Spline(float x1, float y1, float x2, float y2) { if (x1 < 0 || x1 > 1.0f || y1 < 0 || y1 > 1.0f || x2 < 0 || x2 > 1.0f || y2 < 0 || y2 > 1.0f) { throw new IllegalArgumentException("Control points must be in " + "the range [0, 1]:"); } this.x1 = x1; this.y1 = y1; this.x2 = x2; this.y2 = y2; // Now contruct the array of all lengths to t in [0, 1.0] float prevX = 0.0f; float prevY = 0.0f; float prevLength = 0.0f; // cumulative length for (float t = 0.01f; t <= 1.0f; t += .01f) { FloatPoint xy = getXY(t); float length = prevLength + (float) Math.sqrt((xy.x - prevX) * (xy.x - prevX) + (xy.y - prevY) * (xy.y - prevY)); LengthItem lengthItem = new LengthItem(length, t); lengths.add(lengthItem); prevLength = length; prevX = xy.x; prevY = xy.y; } // Now calculate the fractions so that we can access the lengths // array with values in [0,1]. prevLength now holds the total // length of the spline. for (int i = 0; i < lengths.size(); ++i) { LengthItem lengthItem = (LengthItem) lengths.get(i); lengthItem.setFraction(prevLength); } } /** * Calculates the XY point for a given t value. * * The general spline equation is: x = b0*x0 + b1*x1 + b2*x2 + b3*x3 y = * b0*y0 + b1*y1 + b2*y2 + b3*y3 where: b0 = (1-t)^3 b1 = 3 * t * (1-t)^2 b2 * = 3 * t^2 * (1-t) b3 = t^3 We know that (x0,y0) == (0,0) and (x1,y1) == * (1,1) for our splines, so this simplifies to: x = b1*x1 + b2*x2 + b3 y = * b1*x1 + b2*x2 + b3 * * @param t * parametric value for spline calculation */ private FloatPoint getXY(float t) { FloatPoint xy; float invT = (1 - t); float b1 = 3 * t * (invT * invT); float b2 = 3 * (t * t) * invT; float b3 = t * t * t; xy = new FloatPoint((b1 * x1) + (b2 * x2) + b3, (b1 * y1) + (b2 * y2) + b3); return xy; } /** * Utility function: When we are evaluating the spline, we only care about * the Y values. See {@link getXY getXY} for the details. */ private float getY(float t) { FloatPoint xy; float invT = (1 - t); float b1 = 3 * t * (invT * invT); float b2 = 3 * (t * t) * invT; float b3 = t * t * t; return (b1 * y1) + (b2 * y2) + b3; } /** * Given a fraction of time along the spline (which we can interpret as the * length along a spline), return the interpolated value of the spline. We * first calculate the t value for the length (by doing a lookup in our * array of previousloy calculated values and then linearly interpolating * between the nearest values) and then calculate the Y value for this t. * * @param lengthFraction * Fraction of time in a given time interval. * @return interpolated fraction between 0 and 1 */ public float map(float lengthFraction) { // REMIND: speed this up with binary search float interpolatedT = 1.0f; float prevT = 0.0f; float prevLength = 0.0f; for (int i = 0; i < lengths.size(); ++i) { LengthItem lengthItem = (LengthItem) lengths.get(i); float fraction = lengthItem.getFraction(); float t = lengthItem.getT(); if (lengthFraction <= fraction) { // answer lies between last item and this one float proportion = (lengthFraction - prevLength) / (fraction - prevLength); interpolatedT = prevT + proportion * (t - prevT); return getY(interpolatedT); } prevLength = fraction; prevT = t; } return getY(interpolatedT); } } /** * Struct used to store information about length values. Specifically, each item * stores the "length" (which can be thought of as the time elapsed along the * spline path), the "t" value at this length (used to calculate the (x,y) point * along the spline), and the "fraction" which is equal to the length divided by * the total absolute length of the spline. After we calculate all LengthItems * for a give spline, we have a list of entries which can return the t values * for fractional lengths from 0 to 1. */ class LengthItem { float length; float t; float fraction; LengthItem(float length, float t, float fraction) { this.length = length; this.t = t; this.fraction = fraction; } LengthItem(float length, float t) { this.length = length; this.t = t; } public float getLength() { return length; } public float getT() { return t; } public float getFraction() { return fraction; } void setFraction(float totalLength) { fraction = length / totalLength; } } trident-1.3/src/org/pushingpixels/trident/ease/Linear.java0000644000175000017500000000343211346133506023277 0ustar andrewandrew/* * Copyright (c) 2005-2010 Trident Kirill Grouchnikov. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * o Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * o Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * o Neither the name of Trident Kirill Grouchnikov nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.pushingpixels.trident.ease; public class Linear implements TimelineEase { @Override public float map(float durationFraction) { return durationFraction; } } trident-1.3/src/org/pushingpixels/trident/ease/Sine.java0000644000175000017500000000347211346133506022767 0ustar andrewandrew/* * Copyright (c) 2005-2010 Trident Kirill Grouchnikov. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * o Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * o Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * o Neither the name of Trident Kirill Grouchnikov nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.pushingpixels.trident.ease; public class Sine implements TimelineEase { @Override public float map(float durationFraction) { return (float) Math.sin(durationFraction * Math.PI / 2.0); } } trident-1.3/src/org/pushingpixels/trident/ease/TimelineEase.java0000644000175000017500000000340111346133506024425 0ustar andrewandrew/* * Copyright (c) 2005-2010 Trident Kirill Grouchnikov. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * o Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * o Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * o Neither the name of Trident Kirill Grouchnikov nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.pushingpixels.trident.ease; public interface TimelineEase { public float map(float durationFraction); } trident-1.3/src/org/pushingpixels/trident/UIToolkitHandler.java0000644000175000017500000000363111346133506024332 0ustar andrewandrew/* * Copyright (c) 2005-2010 Trident Kirill Grouchnikov. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * o Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * o Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * o Neither the name of Trident Kirill Grouchnikov nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.pushingpixels.trident; public interface UIToolkitHandler { public boolean isHandlerFor(Object mainTimelineObject); public boolean isInReadyState(Object mainTimelineObject); public void runOnUIThread(Object mainTimelineObject, Runnable runnable); } trident-1.3/src/org/pushingpixels/trident/swing/0000755000175000017500000000000011346133506021432 5ustar andrewandrewtrident-1.3/src/org/pushingpixels/trident/swing/SwingRepaintTimeline.java0000644000175000017500000000647411402213312026374 0ustar andrewandrew/* * Copyright (c) 2005-2010 Trident Kirill Grouchnikov. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * o Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * o Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * o Neither the name of Trident Kirill Grouchnikov nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.pushingpixels.trident.swing; import java.awt.Component; import java.awt.Rectangle; import org.pushingpixels.trident.Timeline; public class SwingRepaintTimeline extends Timeline { private SwingRepaintCallback repaintCallback; public SwingRepaintTimeline(Component mainTimelineComp) { this(mainTimelineComp, null); } public SwingRepaintTimeline(Component mainTimelineComp, Rectangle toRepaint) { super(mainTimelineComp); this.repaintCallback = new SwingRepaintCallback(mainTimelineComp, toRepaint); this.addCallback(this.repaintCallback); } public void forceRepaintOnNextPulse() { this.repaintCallback.forceRepaintOnNextPulse(); } public void setAutoRepaintMode(boolean autoRepaintMode) { this.repaintCallback.setAutoRepaintMode(autoRepaintMode); } public void setRepaintRectangle(Rectangle rect) { this.repaintCallback.setRepaintRectangle(rect); } @Override public void play() { throw new UnsupportedOperationException( "Only infinite looping is supported"); } @Override public void playReverse() { throw new UnsupportedOperationException( "Only infinite looping is supported"); } @Override public void replay() { throw new UnsupportedOperationException( "Only infinite looping is supported"); } @Override public void replayReverse() { throw new UnsupportedOperationException( "Only infinite looping is supported"); } @Override public void playLoop(int loopCount, RepeatBehavior repeatBehavior) { if (loopCount >= 0) { throw new UnsupportedOperationException( "Only infinite looping is supported"); } super.playLoop(loopCount, repeatBehavior); } }trident-1.3/src/org/pushingpixels/trident/swing/SwingToolkitHandler.java0000644000175000017500000000451511346133506026235 0ustar andrewandrew/* * Copyright (c) 2005-2010 Trident Kirill Grouchnikov. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * o Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * o Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * o Neither the name of Trident Kirill Grouchnikov nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.pushingpixels.trident.swing; import java.awt.Component; import javax.swing.SwingUtilities; import org.pushingpixels.trident.UIToolkitHandler; public class SwingToolkitHandler implements UIToolkitHandler { @Override public boolean isHandlerFor(Object mainTimelineObject) { return (mainTimelineObject instanceof Component); } @Override public boolean isInReadyState(Object mainTimelineObject) { return ((Component) mainTimelineObject).isDisplayable(); } @Override public void runOnUIThread(Object mainTimelineObject, Runnable runnable) { if (SwingUtilities.isEventDispatchThread()) runnable.run(); else SwingUtilities.invokeLater(runnable); } } trident-1.3/src/org/pushingpixels/trident/swing/AWTPropertyInterpolators.java0000644000175000017500000001337211346133506027271 0ustar andrewandrew/* * Copyright (c) 2005-2010 Trident Kirill Grouchnikov. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * o Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * o Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * o Neither the name of Trident Kirill Grouchnikov nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.pushingpixels.trident.swing; import java.awt.*; import java.util.*; import org.pushingpixels.trident.interpolator.PropertyInterpolator; import org.pushingpixels.trident.interpolator.PropertyInterpolatorSource; /** * Built-in interpolators for Swing / AWT / Java2D classes. * * @author Kirill Grouchnikov */ public class AWTPropertyInterpolators implements PropertyInterpolatorSource { private Set interpolators; public AWTPropertyInterpolators() { this.interpolators = new HashSet(); this.interpolators.add(new ColorInterpolator()); this.interpolators.add(new PointInterpolator()); this.interpolators.add(new RectangleInterpolator()); this.interpolators.add(new DimensionInterpolator()); } @Override public Set getPropertyInterpolators() { return Collections.unmodifiableSet(this.interpolators); } static class ColorInterpolator implements PropertyInterpolator { @Override public Class getBasePropertyClass() { return Color.class; } @Override public Color interpolate(Color from, Color to, float timelinePosition) { return getInterpolatedColor(from, to, 1.0f - timelinePosition); } int getInterpolatedRGB(Color color1, Color color2, float color1Likeness) { if ((color1Likeness < 0.0) || (color1Likeness > 1.0)) throw new IllegalArgumentException( "Color likeness should be in 0.0-1.0 range [is " + color1Likeness + "]"); int lr = color1.getRed(); int lg = color1.getGreen(); int lb = color1.getBlue(); int la = color1.getAlpha(); int dr = color2.getRed(); int dg = color2.getGreen(); int db = color2.getBlue(); int da = color2.getAlpha(); // using some interpolation values (such as 0.29 from issue 401) // results in an incorrect final value without Math.round. int r = (lr == dr) ? lr : (int) Math.round(color1Likeness * lr + (1.0 - color1Likeness) * dr); int g = (lg == dg) ? lg : (int) Math.round(color1Likeness * lg + (1.0 - color1Likeness) * dg); int b = (lb == db) ? lb : (int) Math.round(color1Likeness * lb + (1.0 - color1Likeness) * db); int a = (la == da) ? la : (int) Math.round(color1Likeness * la + (1.0 - color1Likeness) * da); return (a << 24) | (r << 16) | (g << 8) | b; } Color getInterpolatedColor(Color color1, Color color2, float color1Likeness) { if (color1.equals(color2)) return color1; if (color1Likeness == 1.0) return color1; if (color1Likeness == 0.0) return color2; return new Color( getInterpolatedRGB(color1, color2, color1Likeness), true); } } static class PointInterpolator implements PropertyInterpolator { public Point interpolate(Point from, Point to, float timelinePosition) { int x = from.x + (int) (timelinePosition * (to.x - from.x)); int y = from.y + (int) (timelinePosition * (to.y - from.y)); return new Point(x, y); } @Override public Class getBasePropertyClass() { return Point.class; } } static class RectangleInterpolator implements PropertyInterpolator { public Rectangle interpolate(Rectangle from, Rectangle to, float timelinePosition) { int x = from.x + (int) (timelinePosition * (to.x - from.x)); int y = from.y + (int) (timelinePosition * (to.y - from.y)); int w = from.width + (int) (timelinePosition * (to.width - from.width)); int h = from.height + (int) (timelinePosition * (to.height - from.height)); return new Rectangle(x, y, w, h); } @Override public Class getBasePropertyClass() { return Rectangle.class; } } static class DimensionInterpolator implements PropertyInterpolator { public Dimension interpolate(Dimension from, Dimension to, float timelinePosition) { int w = from.width + (int) (timelinePosition * (to.width - from.width)); int h = from.height + (int) (timelinePosition * (to.height - from.height)); return new Dimension(w, h); } public Class getBasePropertyClass() { return Dimension.class; } } } trident-1.3/src/org/pushingpixels/trident/swing/SwingRepaintCallback.java0000644000175000017500000000715611402215050026321 0ustar andrewandrew/* * Copyright (c) 2005-2010 Trident Kirill Grouchnikov. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * o Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * o Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * o Neither the name of Trident Kirill Grouchnikov nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.pushingpixels.trident.swing; import java.awt.Component; import java.awt.Rectangle; import java.util.concurrent.atomic.AtomicBoolean; import org.pushingpixels.trident.Timeline.TimelineState; import org.pushingpixels.trident.callback.TimelineCallbackAdapter; public class SwingRepaintCallback extends TimelineCallbackAdapter { private Component comp; private Rectangle rect; private AtomicBoolean repaintGuard; public SwingRepaintCallback(Component comp) { this(comp, null); } public SwingRepaintCallback(Component comp, Rectangle rect) { if (comp == null) { throw new NullPointerException("Component must be non-null"); } this.comp = comp; if (rect != null) { this.rect = new Rectangle(rect); } } public synchronized void setAutoRepaintMode(boolean autoRepaintMode) { if (autoRepaintMode) { this.repaintGuard = null; } else { this.repaintGuard = new AtomicBoolean(false); } } public synchronized void forceRepaintOnNextPulse() { if (this.repaintGuard == null) { throw new IllegalArgumentException( "This method cannot be called on auto-repaint callback"); } this.repaintGuard.set(true); } public synchronized void setRepaintRectangle(Rectangle rect) { if (rect == null) { this.rect = null; } else { this.rect = new Rectangle(rect); } } @Override public synchronized void onTimelinePulse(float durationFraction, float timelinePosition) { repaintAsNecessary(); } @Override public synchronized void onTimelineStateChanged(TimelineState oldState, TimelineState newState, float durationFraction, float timelinePosition) { repaintAsNecessary(); } private void repaintAsNecessary() { if (this.repaintGuard != null) { if (!this.repaintGuard.compareAndSet(true, false)) { // no need to repaint return; } } if (this.rect == null) this.comp.repaint(); else this.comp.repaint(this.rect.x, this.rect.y, this.rect.width, this.rect.height); } } trident-1.3/src/org/pushingpixels/trident/swing/TimelineSwingWorker.java0000644000175000017500000000416111346133506026247 0ustar andrewandrew/* * Copyright (c) 2005-2010 Trident Kirill Grouchnikov. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * o Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * o Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * o Neither the name of Trident Kirill Grouchnikov nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.pushingpixels.trident.swing; import javax.swing.SwingWorker; import org.pushingpixels.trident.TimelineScenario; public abstract class TimelineSwingWorker extends SwingWorker implements TimelineScenario.TimelineScenarioActor { @Override public void play() { this.execute(); } @Override public boolean supportsReplay() { return false; } @Override public void resetDoneFlag() { throw new UnsupportedOperationException(); } } trident-1.3/src/org/pushingpixels/trident/TimelineEngine.java0000644000175000017500000007246211401140300024033 0ustar andrewandrew/* * Copyright (c) 2005-2010 Trident Kirill Grouchnikov. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * o Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * o Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * o Neither the name of Trident Kirill Grouchnikov nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.pushingpixels.trident; import java.util.*; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; import org.pushingpixels.trident.Timeline.TimelineState; import org.pushingpixels.trident.TimelineScenario.TimelineScenarioState; import org.pushingpixels.trident.callback.RunOnUIThread; /** * The Trident timeline engine. This is the main entry point to play * {@link Timeline}s and {@link TimelineScenario}s. Use the * {@link #getInstance()} method to get the timeline engine. * * @author Kirill Grouchnikov */ class TimelineEngine { /** * Debug mode indicator. Set to true to have trace messages on * console. */ public static boolean DEBUG_MODE = false; /** * Single instance of this class. */ private static TimelineEngine instance; /** * All currently running timelines. */ private Set runningTimelines; enum TimelineOperationKind { PLAY, CANCEL, RESUME, SUSPEND, ABORT, END } class TimelineOperation { public TimelineOperationKind operationKind; Runnable operationRunnable; public TimelineOperation(TimelineOperationKind operationKind, Runnable operationRunnable) { this.operationKind = operationKind; this.operationRunnable = operationRunnable; } } private Set runningScenarios; long lastIterationTimeStamp; /** * Identifies a main object and an optional secondary ID. * * @author Kirill Grouchnikov */ static class FullObjectID { /** * Main object for the timeline. */ public Object mainObj; /** * ID to distinguish between different sub-components of * {@link #mainObj}. For example, the tabbed pane uses this field to * make tab-specific animations. */ @SuppressWarnings("unchecked") public Comparable subID; /** * Creates a new object ID. * * @param mainObj * The main object. * @param subID * ID to distinguish between different sub-components of * mainObj. Can be null. */ @SuppressWarnings("unchecked") public FullObjectID(Object mainObj, Comparable subID) { this.mainObj = mainObj; this.subID = subID; } /* * (non-Javadoc) * * @see java.lang.Object#hashCode() */ @Override public int hashCode() { int result = this.mainObj.hashCode(); if (this.subID != null) result &= (this.subID.hashCode()); return result; } /* * (non-Javadoc) * * @see java.lang.Object#equals(java.lang.Object) */ @Override @SuppressWarnings("unchecked") public boolean equals(Object obj) { if (obj instanceof FullObjectID) { FullObjectID cid = (FullObjectID) obj; try { boolean result = (this.mainObj == cid.mainObj); if (this.subID == null) { result = result && (cid.subID == null); } else { result = result && (this.subID.compareTo(cid.subID) == 0); } return result; } catch (Exception exc) { return false; } } return false; } @Override public String toString() { return this.mainObj.getClass().getSimpleName() + ":" + this.subID; } } /** * The timeline thread. */ TridentAnimationThread animatorThread; private BlockingQueue callbackQueue; private TimelineCallbackThread callbackThread; class TridentAnimationThread extends Thread { public TridentAnimationThread() { super(); this.setName("Trident pulse source thread"); this.setDaemon(true); } /* * (non-Javadoc) * * @see java.lang.Thread#run() */ @Override public final void run() { TridentConfig.PulseSource pulseSource = TridentConfig.getInstance() .getPulseSource(); lastIterationTimeStamp = System.currentTimeMillis(); while (true) { pulseSource.waitUntilNextPulse(); updateTimelines(); // engine.currLoopId++; } } @Override public void interrupt() { System.err.println("Interrupted"); super.interrupt(); } } private class TimelineCallbackThread extends Thread { public TimelineCallbackThread() { super(); this.setName("Trident callback thread"); this.setDaemon(true); } @Override public void run() { while (true) { try { Runnable runnable = callbackQueue.take(); runnable.run(); } catch (Throwable t) { t.printStackTrace(); } } } } /** * Simple constructor. Defined private for singleton. * * @see #getInstance() */ private TimelineEngine() { this.runningTimelines = new HashSet(); this.runningScenarios = new HashSet(); this.callbackQueue = new LinkedBlockingQueue(); this.callbackThread = this.getCallbackThread(); } /** * Gets singleton instance. * * @return Singleton instance. */ public synchronized static TimelineEngine getInstance() { if (TimelineEngine.instance == null) { TimelineEngine.instance = new TimelineEngine(); } return TimelineEngine.instance; } /** * Updates all timelines that are currently registered with * this tracker. */ void updateTimelines() { synchronized (LOCK) { if ((this.runningTimelines.size() == 0) && (this.runningScenarios.size() == 0)) { this.lastIterationTimeStamp = System.currentTimeMillis(); return; } long passedSinceLastIteration = (System.currentTimeMillis() - this.lastIterationTimeStamp); if (passedSinceLastIteration < 0) { // ??? passedSinceLastIteration = 0; } if (DEBUG_MODE) { System.out.println("Elapsed since last iteration: " + passedSinceLastIteration + "ms"); } // System.err.println("Periodic update on " // + this.runningTimelines.size() + " timelines; " // + passedSinceLastIteration + " ms passed since last"); // for (Timeline t : runningTimelines) { // if (t.mainObject != null // && t.mainObject.getClass().getName().indexOf( // "ProgressBar") >= 0) { // continue; // } // System.err.println("\tTimeline @" // + t.hashCode() // + " [" // + t.getName() // + "] on " // + (t.mainObject == null ? "null" : t.mainObject // .getClass().getName())); // } for (Iterator itTimeline = this.runningTimelines .iterator(); itTimeline.hasNext();) { Timeline timeline = itTimeline.next(); if (timeline.getState() == TimelineState.SUSPENDED) continue; boolean timelineWasInReadyState = false; if (timeline.getState() == TimelineState.READY) { if ((timeline.timeUntilPlay - passedSinceLastIteration) > 0) { // still needs to wait in the READY state timeline.timeUntilPlay -= passedSinceLastIteration; continue; } // can go from READY to PLAYING timelineWasInReadyState = true; timeline.popState(); this.callbackCallTimelineStateChanged(timeline, TimelineState.READY); } boolean hasEnded = false; if (DEBUG_MODE) { System.out.println("Processing " + timeline.id + "[" + timeline.mainObject.getClass().getSimpleName() + "] from " + timeline.durationFraction + ". Callback - " + (timeline.callback == null ? "no" : "yes")); } // Component comp = entry.getKey(); // at this point, the timeline must be playing switch (timeline.getState()) { case PLAYING_FORWARD: if (!timelineWasInReadyState) { timeline.durationFraction = timeline.durationFraction + (float) passedSinceLastIteration / (float) timeline.duration; } timeline.timelinePosition = timeline.ease .map(timeline.durationFraction); if (DEBUG_MODE) { System.out .println("Timeline position: " + ((long) (timeline.durationFraction * timeline.duration)) + "/" + timeline.duration + " = " + timeline.durationFraction); } if (timeline.durationFraction > 1.0f) { timeline.durationFraction = 1.0f; timeline.timelinePosition = 1.0f; if (timeline.isLooping) { boolean stopLoopingAnimation = timeline.toCancelAtCycleBreak; int loopsToLive = timeline.repeatCount; if (loopsToLive > 0) { loopsToLive--; stopLoopingAnimation = stopLoopingAnimation || (loopsToLive == 0); timeline.repeatCount = loopsToLive; } if (stopLoopingAnimation) { // end looping animation hasEnded = true; itTimeline.remove(); } else { if (timeline.repeatBehavior == Timeline.RepeatBehavior.REVERSE) { timeline .replaceState(TimelineState.PLAYING_REVERSE); if (timeline.cycleDelay > 0) { timeline.pushState(TimelineState.READY); timeline.timeUntilPlay = timeline.cycleDelay; } this.callbackCallTimelineStateChanged( timeline, TimelineState.PLAYING_FORWARD); } else { timeline.durationFraction = 0.0f; timeline.timelinePosition = 0.0f; if (timeline.cycleDelay > 0) { timeline.pushState(TimelineState.READY); timeline.timeUntilPlay = timeline.cycleDelay; this.callbackCallTimelineStateChanged( timeline, TimelineState.PLAYING_FORWARD); } else { // it's still playing forward, but lets // the app code know // that the new loop has begun this.callbackCallTimelineStateChanged( timeline, TimelineState.PLAYING_FORWARD); } } } } else { hasEnded = true; itTimeline.remove(); } } break; case PLAYING_REVERSE: if (!timelineWasInReadyState) { timeline.durationFraction = timeline.durationFraction - (float) passedSinceLastIteration / (float) timeline.duration; } timeline.timelinePosition = timeline.ease .map(timeline.durationFraction); // state.timelinePosition = state.timelinePosition // - stepFactor // * state.fadeStep.getNextStep(state.timelineKind, // state.timelinePosition, // state.isPlayingForward, state.isLooping); if (DEBUG_MODE) { System.out .println("Timeline position: " + ((long) (timeline.durationFraction * timeline.duration)) + "/" + timeline.duration + " = " + timeline.durationFraction); } if (timeline.durationFraction < 0) { timeline.durationFraction = 0.0f; timeline.timelinePosition = 0.0f; if (timeline.isLooping) { boolean stopLoopingAnimation = timeline.toCancelAtCycleBreak; int loopsToLive = timeline.repeatCount; if (loopsToLive > 0) { loopsToLive--; stopLoopingAnimation = stopLoopingAnimation || (loopsToLive == 0); timeline.repeatCount = loopsToLive; } if (stopLoopingAnimation) { // end looping animation hasEnded = true; itTimeline.remove(); } else { timeline .replaceState(TimelineState.PLAYING_FORWARD); if (timeline.cycleDelay > 0) { timeline.pushState(TimelineState.READY); timeline.timeUntilPlay = timeline.cycleDelay; } this.callbackCallTimelineStateChanged(timeline, TimelineState.PLAYING_REVERSE); } } else { hasEnded = true; itTimeline.remove(); } } break; default: throw new IllegalStateException("Timeline cannot be in " + timeline.getState() + " state"); } if (hasEnded) { if (DEBUG_MODE) { System.out.println("Ending " + timeline.id + " on " // + timeline.timelineKind.toString() + " in state " + timeline.getState().name() + " at position " + timeline.durationFraction); } TimelineState oldState = timeline.getState(); timeline.replaceState(TimelineState.DONE); this.callbackCallTimelineStateChanged(timeline, oldState); timeline.popState(); if (timeline.getState() != TimelineState.IDLE) { throw new IllegalStateException( "Timeline should be IDLE at this point"); } this.callbackCallTimelineStateChanged(timeline, TimelineState.DONE); } else { if (DEBUG_MODE) { System.out.println("Calling " + timeline.id + " on " // + timeline.timelineKind.toString() + " at " + timeline.durationFraction); } this.callbackCallTimelinePulse(timeline); } } if (this.runningScenarios.size() > 0) { // System.err.println(Thread.currentThread().getName() // + " : updating"); for (Iterator it = this.runningScenarios .iterator(); it.hasNext();) { TimelineScenario scenario = it.next(); if (scenario.state == TimelineScenarioState.DONE) { it.remove(); this.callbackCallTimelineScenarioEnded(scenario); continue; } Set readyActors = scenario .getReadyActors(); if (readyActors != null) { // if (readyActors.size() > 0) // System.out.println("Scenario : " + scenario.state + // ":" // + readyActors.size()); for (TimelineScenario.TimelineScenarioActor readyActor : readyActors) { readyActor.play(); } } } } // System.err.println("Periodic update done"); // this.nothingTracked = (this.runningTimelines.size() == 0); this.lastIterationTimeStamp = System.currentTimeMillis(); } } private void callbackCallTimelineStateChanged(final Timeline timeline, final TimelineState oldState) { final TimelineState newState = timeline.getState(); final float durationFraction = timeline.durationFraction; final float timelinePosition = timeline.timelinePosition; Runnable callbackRunnable = new Runnable() { @Override public void run() { boolean shouldRunOnUIThread = false; Class clazz = timeline.callback.getClass(); while ((clazz != null) && !shouldRunOnUIThread) { shouldRunOnUIThread = clazz .isAnnotationPresent(RunOnUIThread.class); clazz = clazz.getSuperclass(); } if (shouldRunOnUIThread && (timeline.uiToolkitHandler != null)) { timeline.uiToolkitHandler.runOnUIThread( timeline.mainObject, new Runnable() { public void run() { timeline.callback.onTimelineStateChanged( oldState, newState, durationFraction, timelinePosition); } }); } else { timeline.callback.onTimelineStateChanged(oldState, newState, durationFraction, timelinePosition); } } }; this.callbackQueue.add(callbackRunnable); } private void callbackCallTimelinePulse(final Timeline timeline) { final float durationFraction = timeline.durationFraction; final float timelinePosition = timeline.timelinePosition; Runnable callbackRunnable = new Runnable() { @Override public void run() { boolean shouldRunOnUIThread = false; Class clazz = timeline.callback.getClass(); while ((clazz != null) && !shouldRunOnUIThread) { shouldRunOnUIThread = clazz .isAnnotationPresent(RunOnUIThread.class); clazz = clazz.getSuperclass(); } if (shouldRunOnUIThread && (timeline.uiToolkitHandler != null)) { timeline.uiToolkitHandler.runOnUIThread( timeline.mainObject, new Runnable() { public void run() { // System.err.println("Timeline @" // + timeline.hashCode()); timeline.callback.onTimelinePulse( durationFraction, timelinePosition); } }); } else { // System.err.println("Timeline @" + timeline.hashCode()); timeline.callback.onTimelinePulse(durationFraction, timelinePosition); } } }; this.callbackQueue.add(callbackRunnable); } private void callbackCallTimelineScenarioEnded( final TimelineScenario timelineScenario) { Runnable callbackRunnable = new Runnable() { @Override public void run() { timelineScenario.callback.onTimelineScenarioDone(); } }; this.callbackQueue.offer(callbackRunnable); } /** * Returns an existing running timeline that matches the specified * parameters. * * @param timelineKind * Timeline kind. * @param object * Component. * @param secondaryId * Secondary id. Relevant for such components as tabbed panes * (where animation is performed on different tabs). * @return An existing running timeline that matches the specified * parameters. */ private Timeline getRunningTimeline(Timeline timeline) { synchronized (LOCK) { if (this.runningTimelines.contains(timeline)) return timeline; return null; } } /** * Adds the specified timeline. * * @param timeline * Timeline to add. */ private void addTimeline(Timeline timeline) { synchronized (LOCK) { FullObjectID cid = new FullObjectID(timeline.mainObject, timeline.secondaryId); timeline.fullObjectID = cid; this.runningTimelines.add(timeline); // this.nothingTracked = false; if (DEBUG_MODE) { System.out.println("Added (" + timeline.id + ") on " + timeline.fullObjectID + "]. Fade " // + timeline.timelineKind.toString() + " with state " + timeline.getState().name() + ". Callback - " + (timeline.callback == null ? "no" : "yes")); } } } void play(Timeline timeline, boolean reset, long msToSkip) { synchronized (LOCK) { getAnimatorThread(); // see if it's already tracked Timeline existing = this.getRunningTimeline(timeline); if (existing == null) { TimelineState oldState = timeline.getState(); timeline.timeUntilPlay = timeline.initialDelay - msToSkip; if (timeline.timeUntilPlay < 0) { timeline.durationFraction = (float) -timeline.timeUntilPlay / (float) timeline.duration; timeline.timelinePosition = timeline.ease .map(timeline.durationFraction); timeline.timeUntilPlay = 0; } else { timeline.durationFraction = 0.0f; timeline.timelinePosition = 0.0f; } timeline.pushState(TimelineState.PLAYING_FORWARD); timeline.pushState(TimelineState.READY); this.addTimeline(timeline); this.callbackCallTimelineStateChanged(timeline, oldState); } else { TimelineState oldState = existing.getState(); if (oldState == TimelineState.READY) { // the timeline remains READY, but after that it will be // PLAYING_FORWARD existing.popState(); existing.replaceState(TimelineState.PLAYING_FORWARD); existing.pushState(TimelineState.READY); } else { // change the timeline state existing.replaceState(TimelineState.PLAYING_FORWARD); if (oldState != existing.getState()) { this.callbackCallTimelineStateChanged(timeline, oldState); } } if (reset) { existing.durationFraction = 0.0f; existing.timelinePosition = 0.0f; this.callbackCallTimelinePulse(existing); } } } } void playScenario(TimelineScenario scenario) { synchronized (LOCK) { getAnimatorThread(); Set readyActors = scenario .getReadyActors(); // System.err.println(Thread.currentThread().getName() + // " : adding"); this.runningScenarios.add(scenario); for (TimelineScenario.TimelineScenarioActor readyActor : readyActors) { readyActor.play(); } } } void playReverse(Timeline timeline, boolean reset, long msToSkip) { synchronized (LOCK) { getAnimatorThread(); if (timeline.isLooping) { throw new IllegalArgumentException( "Timeline must not be marked as looping"); } // see if it's already tracked Timeline existing = this.getRunningTimeline(timeline); if (existing == null) { TimelineState oldState = timeline.getState(); timeline.timeUntilPlay = timeline.initialDelay - msToSkip; if (timeline.timeUntilPlay < 0) { timeline.durationFraction = 1.0f - (float) -timeline.timeUntilPlay / (float) timeline.duration; timeline.timelinePosition = timeline.ease .map(timeline.durationFraction); timeline.timeUntilPlay = 0; } else { timeline.durationFraction = 1.0f; timeline.timelinePosition = 1.0f; } timeline.pushState(TimelineState.PLAYING_REVERSE); timeline.pushState(TimelineState.READY); this.addTimeline(timeline); this.callbackCallTimelineStateChanged(timeline, oldState); } else { TimelineState oldState = existing.getState(); if (oldState == TimelineState.READY) { // the timeline remains READY, but after that it will be // PLAYING_REVERSE existing.popState(); existing.replaceState(TimelineState.PLAYING_REVERSE); existing.pushState(TimelineState.READY); } else { // change the timeline state existing.replaceState(TimelineState.PLAYING_REVERSE); if (oldState != existing.getState()) { this.callbackCallTimelineStateChanged(timeline, oldState); } } if (reset) { existing.durationFraction = 1.0f; existing.timelinePosition = 1.0f; this.callbackCallTimelinePulse(existing); } } } } void playLoop(Timeline timeline, long msToSkip) { synchronized (LOCK) { getAnimatorThread(); if (!timeline.isLooping) { throw new IllegalArgumentException( "Timeline must be marked as looping"); } // see if it's already tracked Timeline existing = this.getRunningTimeline(timeline); if (existing == null) { TimelineState oldState = timeline.getState(); timeline.timeUntilPlay = timeline.initialDelay - msToSkip; if (timeline.timeUntilPlay < 0) { timeline.durationFraction = (float) -timeline.timeUntilPlay / (float) timeline.duration; timeline.timelinePosition = timeline.ease .map(timeline.durationFraction); timeline.timeUntilPlay = 0; } else { timeline.durationFraction = 0.0f; timeline.timelinePosition = 0.0f; } timeline.pushState(TimelineState.PLAYING_FORWARD); timeline.pushState(TimelineState.READY); timeline.toCancelAtCycleBreak = false; this.addTimeline(timeline); this.callbackCallTimelineStateChanged(timeline, oldState); } else { existing.toCancelAtCycleBreak = false; existing.repeatCount = timeline.repeatCount; } } } /** * Stops tracking of all timelines. Note that this function does not * stop the timeline engine thread ({@link #animatorThread}) and the * timeline callback thread ({@link #callbackThread}). */ public void cancelAllTimelines() { synchronized (LOCK) { getAnimatorThread(); for (Timeline timeline : this.runningTimelines) { TimelineState oldState = timeline.getState(); while (timeline.getState() != TimelineState.IDLE) timeline.popState(); timeline.pushState(TimelineState.CANCELLED); this.callbackCallTimelineStateChanged(timeline, oldState); timeline.popState(); this.callbackCallTimelineStateChanged(timeline, TimelineState.CANCELLED); } this.runningTimelines.clear(); this.runningScenarios.clear(); } } /** * Returns an instance of the animator thread. * * @return The animator thread. */ private TridentAnimationThread getAnimatorThread() { if (this.animatorThread == null) { this.animatorThread = new TridentAnimationThread(); this.animatorThread.start(); } return this.animatorThread; } /** * Returns an instance of the callback thread. * * @return The animator thread. */ private TimelineCallbackThread getCallbackThread() { if (this.callbackThread == null) { this.callbackThread = new TimelineCallbackThread(); this.callbackThread.start(); } return this.callbackThread; } /** * Cancels the specified timeline instance. * * @param timeline * Timeline to cancel. */ private void cancelTimeline(Timeline timeline) { getAnimatorThread(); if (this.runningTimelines.contains(timeline)) { this.runningTimelines.remove(timeline); TimelineState oldState = timeline.getState(); while (timeline.getState() != TimelineState.IDLE) timeline.popState(); timeline.pushState(TimelineState.CANCELLED); this.callbackCallTimelineStateChanged(timeline, oldState); timeline.popState(); this.callbackCallTimelineStateChanged(timeline, TimelineState.CANCELLED); } } /** * Ends the specified timeline instance. * * @param timeline * Timeline to end. */ private void endTimeline(Timeline timeline) { getAnimatorThread(); if (this.runningTimelines.contains(timeline)) { this.runningTimelines.remove(timeline); TimelineState oldState = timeline.getState(); float endPosition = timeline.timelinePosition; while (timeline.getState() != TimelineState.IDLE) { TimelineState state = timeline.popState(); if (state == TimelineState.PLAYING_FORWARD) endPosition = 1.0f; if (state == TimelineState.PLAYING_REVERSE) endPosition = 0.0f; } timeline.durationFraction = endPosition; timeline.timelinePosition = endPosition; timeline.pushState(TimelineState.DONE); this.callbackCallTimelineStateChanged(timeline, oldState); timeline.popState(); this.callbackCallTimelineStateChanged(timeline, TimelineState.DONE); } } /** * Cancels the specified timeline instance. * * @param timeline * Timeline to cancel. */ private void abortTimeline(Timeline timeline) { getAnimatorThread(); if (this.runningTimelines.contains(timeline)) { this.runningTimelines.remove(timeline); while (timeline.getState() != TimelineState.IDLE) timeline.popState(); } } /** * Suspends the specified timeline instance. * * @param timeline * Timeline to suspend. */ private void suspendTimeline(Timeline timeline) { getAnimatorThread(); if (this.runningTimelines.contains(timeline)) { TimelineState oldState = timeline.getState(); if ((oldState != TimelineState.PLAYING_FORWARD) && (oldState != TimelineState.PLAYING_REVERSE) && (oldState != TimelineState.READY)) { return; } timeline.pushState(TimelineState.SUSPENDED); this.callbackCallTimelineStateChanged(timeline, oldState); } } /** * Resume the specified timeline instance. * * @param timeline * Timeline to resume. */ private void resumeTimeline(Timeline timeline) { getAnimatorThread(); if (this.runningTimelines.contains(timeline)) { TimelineState oldState = timeline.getState(); if (oldState != TimelineState.SUSPENDED) return; timeline.popState(); this.callbackCallTimelineStateChanged(timeline, oldState); } } void runTimelineOperation(Timeline timeline, TimelineOperationKind operationKind, Runnable operationRunnable) { synchronized (LOCK) { this.getAnimatorThread(); switch (operationKind) { case CANCEL: this.cancelTimeline(timeline); return; case END: this.endTimeline(timeline); return; case RESUME: this.resumeTimeline(timeline); return; case SUSPEND: this.suspendTimeline(timeline); return; case ABORT: this.abortTimeline(timeline); return; } operationRunnable.run(); } } void runTimelineScenario(TimelineScenario timelineScenario, Runnable timelineScenarioRunnable) { synchronized (LOCK) { this.getAnimatorThread(); timelineScenarioRunnable.run(); } } static final Object LOCK = new Object(); } trident-1.3/src/org/pushingpixels/trident/TridentConfig.java0000644000175000017500000001747111346133506023717 0ustar andrewandrew/* * Copyright (c) 2005-2010 Trident Kirill Grouchnikov. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * o Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * o Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * o Neither the name of Trident Kirill Grouchnikov nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.pushingpixels.trident; import java.io.*; import java.net.URL; import java.util.*; import org.pushingpixels.trident.TimelineEngine.TridentAnimationThread; import org.pushingpixels.trident.interpolator.PropertyInterpolator; import org.pushingpixels.trident.interpolator.PropertyInterpolatorSource; public class TridentConfig { private static TridentConfig config; private Set uiToolkitHandlers; private Set propertyInterpolators; private TridentConfig.PulseSource pulseSource; public interface PulseSource { public void waitUntilNextPulse(); } public static class FixedRatePulseSource implements TridentConfig.PulseSource { private int msDelay; public FixedRatePulseSource(int msDelay) { this.msDelay = msDelay; } @Override public void waitUntilNextPulse() { try { Thread.sleep(this.msDelay); } catch (InterruptedException ie) { ie.printStackTrace(); } } } private class DefaultPulseSource extends FixedRatePulseSource { DefaultPulseSource() { super(40); } } private TridentConfig() { this.pulseSource = new DefaultPulseSource(); this.uiToolkitHandlers = new HashSet(); this.propertyInterpolators = new HashSet(); ClassLoader classLoader = Thread.currentThread() .getContextClassLoader(); try { Enumeration urls = classLoader .getResources("META-INF/trident-plugin.properties"); while (urls.hasMoreElements()) { URL pluginUrl = (URL) urls.nextElement(); BufferedReader reader = null; try { reader = new BufferedReader(new InputStreamReader(pluginUrl .openStream())); while (true) { String line = reader.readLine(); if (line == null) break; String[] parts = line.split("="); if (parts.length != 2) continue; String key = parts[0]; String value = parts[1]; if ("UIToolkitHandler".compareTo(key) == 0) { try { Class pluginClass = classLoader .loadClass(value); if (pluginClass == null) continue; if (UIToolkitHandler.class .isAssignableFrom(pluginClass)) { UIToolkitHandler uiToolkitHandler = (UIToolkitHandler) pluginClass .newInstance(); uiToolkitHandler.isHandlerFor(new Object()); this.uiToolkitHandlers .add(uiToolkitHandler); } } catch (NoClassDefFoundError ncdfe) { // trying to initialize a plugin with a missing // class } } if ("PropertyInterpolatorSource".compareTo(key) == 0) { try { Class piSourceClass = classLoader .loadClass(value); if (piSourceClass == null) continue; if (PropertyInterpolatorSource.class .isAssignableFrom(piSourceClass)) { PropertyInterpolatorSource piSource = (PropertyInterpolatorSource) piSourceClass .newInstance(); Set interpolators = piSource .getPropertyInterpolators(); for (PropertyInterpolator pi : interpolators) { try { Class basePropertyClass = pi .getBasePropertyClass(); // is in classpath? basePropertyClass.getClass(); this.propertyInterpolators.add(pi); } catch (NoClassDefFoundError ncdfe) { // trying to initialize a plugin // with a missing // class - just skip } } // this.propertyInterpolators.addAll(piSource // .getPropertyInterpolators()); } } catch (NoClassDefFoundError ncdfe) { // trying to initialize a plugin with a missing // class } } } } finally { if (reader != null) { try { reader.close(); } catch (IOException ioe) { } } } } } catch (Exception exc) { exc.printStackTrace(); } } public static synchronized TridentConfig getInstance() { if (config == null) config = new TridentConfig(); return config; } public synchronized Collection getUIToolkitHandlers() { return Collections.unmodifiableSet(this.uiToolkitHandlers); } public synchronized Collection getPropertyInterpolators() { return Collections.unmodifiableSet(this.propertyInterpolators); } public synchronized PropertyInterpolator getPropertyInterpolator( Object... values) { for (PropertyInterpolator interpolator : this.propertyInterpolators) { try { Class basePropertyClass = interpolator.getBasePropertyClass(); boolean hasMatch = true; for (Object value : values) { if (!basePropertyClass.isAssignableFrom(value.getClass())) { hasMatch = false; continue; } } if (hasMatch) return interpolator; } catch (NoClassDefFoundError ncdfe) { continue; } } return null; } public synchronized void addPropertyInterpolator( PropertyInterpolator pInterpolator) { this.propertyInterpolators.add(pInterpolator); } public synchronized void addPropertyInterpolatorSource( PropertyInterpolatorSource pInterpolatorSource) { this.propertyInterpolators.addAll(pInterpolatorSource .getPropertyInterpolators()); } public synchronized void removePropertyInterpolator( PropertyInterpolator pInterpolator) { this.propertyInterpolators.remove(pInterpolator); } public synchronized void addUIToolkitHandler( UIToolkitHandler uiToolkitHandler) { this.uiToolkitHandlers.add(uiToolkitHandler); } public synchronized void removeUIToolkitHandler( UIToolkitHandler uiToolkitHandler) { this.uiToolkitHandlers.remove(uiToolkitHandler); } public synchronized void setPulseSource(PulseSource pulseSource) { TridentAnimationThread current = TimelineEngine.getInstance().animatorThread; if ((current != null) && current.isAlive()) throw new IllegalStateException( "Cannot replace the pulse source thread once it's running"); this.pulseSource = pulseSource; } public synchronized TridentConfig.PulseSource getPulseSource() { return pulseSource; } } trident-1.3/src/org/pushingpixels/trident/callback/0000755000175000017500000000000011346133506022037 5ustar andrewandrewtrident-1.3/src/org/pushingpixels/trident/callback/UIThreadTimelineCallbackAdapter.java0000644000175000017500000000366211346133506030763 0ustar andrewandrew/* * Copyright (c) 2005-2010 Trident Kirill Grouchnikov. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * o Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * o Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * o Neither the name of Trident Kirill Grouchnikov nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.pushingpixels.trident.callback; /** * Empty implementation of {@link TimelineCallback} that does nothing but is * marked to run on the EDT. * * @author Kirill Grouchnikov */ @RunOnUIThread public class UIThreadTimelineCallbackAdapter extends TimelineCallbackAdapter { } trident-1.3/src/org/pushingpixels/trident/callback/TimelineScenarioCallback.java0000644000175000017500000000403111346133506027547 0ustar andrewandrew/* * Copyright (c) 2005-2010 Trident Kirill Grouchnikov. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * o Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * o Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * o Neither the name of Trident Kirill Grouchnikov nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.pushingpixels.trident.callback; import org.pushingpixels.trident.TimelineScenario; /** * Callback for tracking the {@link TimelineScenario}s. * * @author Kirill Grouchnikov */ public interface TimelineScenarioCallback { /** * Indicates that the all timelines and swing workers in the timeline * scenario have finished. */ public void onTimelineScenarioDone(); }trident-1.3/src/org/pushingpixels/trident/callback/TimelineCallback.java0000644000175000017500000000724511346133506026075 0ustar andrewandrew/* * Copyright (c) 2005-2010 Trident Kirill Grouchnikov. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * o Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * o Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * o Neither the name of Trident Kirill Grouchnikov nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.pushingpixels.trident.callback; import org.pushingpixels.trident.Timeline; import org.pushingpixels.trident.Timeline.TimelineState; /** * Callback for the fade tracker. Is used when the application (some UI * delegate) wishes to execute some code on the fade. * * @author Kirill Grouchnikov */ public interface TimelineCallback { /** * Indicates that the timeline state has changed. * * @param oldState * The old timeline state. * @param newState * The new timeline state. * @param durationFraction * The current timeline duration fraction.Is guaranteed to be in * 0.0-1.0 range. The rate of change of this value is linear, and * the value is proportional to * {@link Timeline#setDuration(long)}. * @param timelinePosition * The current timeline position. Is guaranteed to be in 0.0-1.0 * range. The rate of change of this value is not necessarily * linear and is affected by the * {@link Timeline#setEase(org.pushingpixels.trident.ease.TimelineEase)} * . */ public void onTimelineStateChanged(TimelineState oldState, TimelineState newState, float durationFraction, float timelinePosition); /** * Indicates that the timeline pulse has happened. * * @param durationFraction * The current timeline duration fraction.Is guaranteed to be in * 0.0-1.0 range. The rate of change of this value is linear, and * the value is proportional to * {@link Timeline#setDuration(long)}. * @param timelinePosition * The current timeline position. Is guaranteed to be in 0.0-1.0 * range. The rate of change of this value is not necessarily * linear and is affected by the * {@link Timeline#setEase(org.pushingpixels.trident.ease.TimelineEase)} * . */ public void onTimelinePulse(float durationFraction, float timelinePosition); }trident-1.3/src/org/pushingpixels/trident/callback/RunOnUIThread.java0000644000175000017500000000364311346133506025337 0ustar andrewandrew/* * Copyright (c) 2005-2010 Trident Kirill Grouchnikov. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * o Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * o Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * o Neither the name of Trident Kirill Grouchnikov nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.pushingpixels.trident.callback; import java.lang.annotation.*; /** * Annotation to mark code that should run on UI thread. * * @author Kirill Grouchnikov */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface RunOnUIThread { }trident-1.3/src/org/pushingpixels/trident/callback/TimelineCallbackAdapter.java0000644000175000017500000000426111346133506027371 0ustar andrewandrew/* * Copyright (c) 2005-2010 Trident Kirill Grouchnikov. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * o Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * o Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * o Neither the name of Trident Kirill Grouchnikov nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.pushingpixels.trident.callback; import org.pushingpixels.trident.Timeline.TimelineState; /** * Default implementation of {@link TimelineCallback} that does nothing. * * @author Kirill Grouchnikov */ public class TimelineCallbackAdapter implements TimelineCallback { @Override public void onTimelineStateChanged(TimelineState oldState, TimelineState newState, float durationFraction, float timelinePosition) { } @Override public void onTimelinePulse(float durationFraction, float timelinePosition) { } } trident-1.3/src/org/pushingpixels/trident/TimelineScenario.java0000644000175000017500000002525111401140302024365 0ustar andrewandrew/* * Copyright (c) 2005-2010 Trident Kirill Grouchnikov. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * o Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * o Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * o Neither the name of Trident Kirill Grouchnikov nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.pushingpixels.trident; import java.util.*; import org.pushingpixels.trident.callback.TimelineScenarioCallback; public class TimelineScenario { private Set waitingActors; private Set runningActors; private Set doneActors; private Map> dependencies; Chain callback; TimelineScenarioState state; TimelineScenarioState statePriorToSuspension; boolean isLooping; public enum TimelineScenarioState { DONE, PLAYING, IDLE, SUSPENDED } class Chain implements TimelineScenarioCallback { private List callbacks; public Chain(TimelineScenarioCallback... callbacks) { this.callbacks = new ArrayList(); for (TimelineScenarioCallback callback : callbacks) this.callbacks.add(callback); } public void addCallback(TimelineScenarioCallback callback) { this.callbacks.add(callback); } @Override public void onTimelineScenarioDone() { for (TimelineScenarioCallback callback : this.callbacks) callback.onTimelineScenarioDone(); } } public static interface TimelineScenarioActor { public boolean isDone(); public boolean supportsReplay(); public void resetDoneFlag(); public void play(); } public TimelineScenario() { this.waitingActors = new HashSet(); this.runningActors = new HashSet(); this.doneActors = new HashSet(); this.dependencies = new HashMap>(); this.callback = new Chain(); this.state = TimelineScenarioState.IDLE; } public void addScenarioActor(TimelineScenarioActor actor) { if (actor.isDone()) { throw new IllegalArgumentException("Already finished"); } this.waitingActors.add(actor); } public void addCallback(TimelineScenarioCallback callback) { if (this.doneActors.size() > 0) { throw new IllegalArgumentException( "Cannot change state of non-idle timeline scenario"); } this.callback.addCallback(callback); } private void checkDependencyParam(TimelineScenarioActor actor) { if (!waitingActors.contains(actor)) { throw new IllegalArgumentException( "Must be first added with addScenarioActor() API"); } } public void addDependency(TimelineScenarioActor actor, TimelineScenarioActor... waitFor) { // check params this.checkDependencyParam(actor); for (TimelineScenarioActor wait : waitFor) { this.checkDependencyParam(wait); } if (!this.dependencies.containsKey(actor)) this.dependencies.put(actor, new HashSet()); this.dependencies.get(actor).addAll(Arrays.asList(waitFor)); } private void checkDoneActors() { synchronized (TimelineEngine.LOCK) { for (Iterator itRunning = this.runningActors .iterator(); itRunning.hasNext();) { TimelineScenarioActor stillRunning = itRunning.next(); if (stillRunning.isDone()) { itRunning.remove(); this.doneActors.add(stillRunning); } } } } Set getReadyActors() { synchronized (TimelineEngine.LOCK) { if (this.state == TimelineScenarioState.SUSPENDED) return new HashSet(); this.checkDoneActors(); Set result = new HashSet(); for (Iterator itWaiting = this.waitingActors .iterator(); itWaiting.hasNext();) { TimelineScenarioActor waitingActor = itWaiting.next(); boolean canRun = true; Set toWaitFor = this.dependencies .get(waitingActor); if (toWaitFor != null) { for (TimelineScenarioActor actorToWaitFor : toWaitFor) { if (!doneActors.contains(actorToWaitFor)) { canRun = false; break; } } } if (canRun) { runningActors.add(waitingActor); itWaiting.remove(); result.add(waitingActor); } } if (this.waitingActors.isEmpty() && this.runningActors.isEmpty()) { if (!this.isLooping) { this.state = TimelineScenarioState.DONE; } else { for (TimelineScenarioActor done : this.doneActors) done.resetDoneFlag(); this.waitingActors.addAll(this.doneActors); this.doneActors.clear(); } } return result; } } public void cancel() { synchronized (TimelineEngine.LOCK) { TimelineScenarioState oldState = this.state; if (oldState != TimelineScenarioState.PLAYING) return; this.state = TimelineScenarioState.DONE; for (TimelineScenarioActor waiting : this.waitingActors) { if (waiting instanceof Timeline) { ((Timeline) waiting).cancel(); } } for (TimelineScenarioActor running : this.runningActors) { if (running instanceof Timeline) { ((Timeline) running).cancel(); } } } } public void suspend() { synchronized (TimelineEngine.LOCK) { TimelineScenarioState oldState = this.state; if (oldState != TimelineScenarioState.PLAYING) return; this.statePriorToSuspension = oldState; this.state = TimelineScenarioState.SUSPENDED; for (TimelineScenarioActor running : this.runningActors) { if (running instanceof Timeline) { ((Timeline) running).suspend(); } } } } public void resume() { synchronized (TimelineEngine.LOCK) { TimelineScenarioState oldState = this.state; if (oldState != TimelineScenarioState.SUSPENDED) return; this.state = this.statePriorToSuspension; for (TimelineScenarioActor running : this.runningActors) { if (running instanceof Timeline) { ((Timeline) running).resume(); } } } } public void play() { this.isLooping = false; this.state = TimelineScenarioState.PLAYING; TimelineEngine.getInstance().runTimelineScenario(this, new Runnable() { @Override public void run() { TimelineEngine.getInstance() .playScenario(TimelineScenario.this); } }); } public void playLoop() { for (TimelineScenarioActor actor : this.waitingActors) { if (!actor.supportsReplay()) throw new UnsupportedOperationException( "Can't loop scenario with actor(s) that don't support replay"); } this.isLooping = true; this.state = TimelineScenarioState.PLAYING; TimelineEngine.getInstance().runTimelineScenario(this, new Runnable() { @Override public void run() { TimelineEngine.getInstance() .playScenario(TimelineScenario.this); } }); } public static class Parallel extends TimelineScenario { @Override public void addDependency(TimelineScenarioActor actor, TimelineScenarioActor... waitFor) { throw new UnsupportedOperationException( "Explicit dependencies not supported"); } } public static class Sequence extends TimelineScenario { private TimelineScenarioActor lastActor; @Override public void addDependency(TimelineScenarioActor actor, TimelineScenarioActor... waitFor) { throw new UnsupportedOperationException( "Explicit dependencies not supported"); } @Override public void addScenarioActor(TimelineScenarioActor actor) { super.addScenarioActor(actor); if (this.lastActor != null) { super.addDependency(actor, this.lastActor); } this.lastActor = actor; } } public static class RendezvousSequence extends TimelineScenario { private Set addedSinceLastRendezvous; private Set addedPriorToLastRendezvous; public RendezvousSequence() { this.addedSinceLastRendezvous = new HashSet(); this.addedPriorToLastRendezvous = new HashSet(); } @Override public void addDependency(TimelineScenarioActor actor, TimelineScenarioActor... waitFor) { throw new UnsupportedOperationException( "Explicit dependencies not supported"); } @Override public void addScenarioActor(TimelineScenarioActor actor) { super.addScenarioActor(actor); this.addedSinceLastRendezvous.add(actor); } public void rendezvous() { // make all actors added since last rendezvous to wait for // all actors added prior to last rendezvous if (this.addedPriorToLastRendezvous.size() > 0) { for (TimelineScenarioActor sinceLast : this.addedSinceLastRendezvous) { for (TimelineScenarioActor beforeLast : this.addedPriorToLastRendezvous) { super.addDependency(sinceLast, beforeLast); } } } this.addedPriorToLastRendezvous.clear(); this.addedPriorToLastRendezvous .addAll(this.addedSinceLastRendezvous); this.addedSinceLastRendezvous.clear(); } @Override public void play() { // add last implicit rendezvous this.rendezvous(); super.play(); } @Override public void playLoop() { // add last implicit rendezvous this.rendezvous(); super.playLoop(); } } public final TimelineScenarioState getState() { return this.state; } } trident-1.3/src/org/pushingpixels/trident/TimelineRunnable.java0000644000175000017500000000464011401140302024367 0ustar andrewandrew/* * Copyright (c) 2005-2010 Trident Kirill Grouchnikov. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * o Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * o Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * o Neither the name of Trident Kirill Grouchnikov nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.pushingpixels.trident; import java.util.concurrent.*; import org.pushingpixels.trident.TimelineScenario.TimelineScenarioActor; public abstract class TimelineRunnable implements Runnable, TimelineScenarioActor { private static ExecutorService service = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 10L, TimeUnit.SECONDS, new SynchronousQueue()); private Future future; @Override public void play() { this.future = service.submit(this); } @Override public boolean isDone() { if (this.future == null) return false; return this.future.isDone(); } @Override public boolean supportsReplay() { return false; } @Override public void resetDoneFlag() { throw new UnsupportedOperationException(); } } trident-1.3/src/org/pushingpixels/trident/swt/0000755000175000017500000000000011346133506021120 5ustar andrewandrewtrident-1.3/src/org/pushingpixels/trident/swt/SWTRepaintCallback.java0000644000175000017500000000745611402215740025406 0ustar andrewandrew/* * Copyright (c) 2005-2010 Trident Kirill Grouchnikov. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * o Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * o Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * o Neither the name of Trident Kirill Grouchnikov nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.pushingpixels.trident.swt; import java.util.concurrent.atomic.AtomicBoolean; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.widgets.Control; import org.pushingpixels.trident.Timeline.TimelineState; import org.pushingpixels.trident.callback.RunOnUIThread; import org.pushingpixels.trident.callback.TimelineCallback; @RunOnUIThread public class SWTRepaintCallback implements TimelineCallback { private Control control; private Rectangle rect; private AtomicBoolean repaintGuard; public SWTRepaintCallback(Control control) { this(control, null); } public SWTRepaintCallback(Control control, Rectangle rect) { if (control == null) { throw new NullPointerException("Control must be non-null"); } this.control = control; if (rect != null) { this.rect = new Rectangle(rect.x, rect.y, rect.width, rect.height); } } public synchronized void setAutoRepaintMode(boolean autoRepaintMode) { if (autoRepaintMode) { this.repaintGuard = null; } else { this.repaintGuard = new AtomicBoolean(false); } } public synchronized void forceRepaintOnNextPulse() { if (this.repaintGuard == null) { throw new IllegalArgumentException( "This method cannot be called on auto-repaint callback"); } this.repaintGuard.set(true); } public synchronized void setRepaintRectangle(Rectangle rect) { if (rect == null) { this.rect = null; } else { this.rect = new Rectangle(rect.x, rect.y, rect.width, rect.height); } } @Override public void onTimelinePulse(float durationFraction, float timelinePosition) { redrawAsNecessary(); } @Override public void onTimelineStateChanged(TimelineState oldState, TimelineState newState, float durationFraction, float timelinePosition) { redrawAsNecessary(); } private void redrawAsNecessary() { if (this.control.isDisposed()) return; if (this.repaintGuard != null) { if (!this.repaintGuard.compareAndSet(true, false)) { // no need to repaint return; } } if (this.rect == null) this.control.redraw(); else this.control.redraw(this.rect.x, this.rect.y, this.rect.width, this.rect.height, true); } } trident-1.3/src/org/pushingpixels/trident/swt/SWTRepaintTimeline.java0000644000175000017500000000650711402215426025455 0ustar andrewandrew/* * Copyright (c) 2005-2010 Trident Kirill Grouchnikov. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * o Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * o Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * o Neither the name of Trident Kirill Grouchnikov nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.pushingpixels.trident.swt; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.widgets.Control; import org.pushingpixels.trident.Timeline; public class SWTRepaintTimeline extends Timeline { private SWTRepaintCallback repaintCallback; public SWTRepaintTimeline(Control mainTimelineComp) { this(mainTimelineComp, null); } public SWTRepaintTimeline(Control mainTimelineComp, Rectangle toRepaint) { super(mainTimelineComp); this.repaintCallback = new SWTRepaintCallback(mainTimelineComp, toRepaint); this.addCallback(this.repaintCallback); } public void forceRepaintOnNextPulse() { this.repaintCallback.forceRepaintOnNextPulse(); } public void setAutoRepaintMode(boolean autoRepaintMode) { this.repaintCallback.setAutoRepaintMode(autoRepaintMode); } public void setRepaintRectangle(Rectangle rect) { this.repaintCallback.setRepaintRectangle(rect); } @Override public void play() { throw new UnsupportedOperationException( "Only infinite looping is supported"); } @Override public void playReverse() { throw new UnsupportedOperationException( "Only infinite looping is supported"); } @Override public void replay() { throw new UnsupportedOperationException( "Only infinite looping is supported"); } @Override public void replayReverse() { throw new UnsupportedOperationException( "Only infinite looping is supported"); } @Override public void playLoop(int loopCount, RepeatBehavior repeatBehavior) { if (loopCount >= 0) { throw new UnsupportedOperationException( "Only infinite looping is supported"); } super.playLoop(loopCount, repeatBehavior); } }trident-1.3/src/org/pushingpixels/trident/swt/SWTPropertyInterpolators.java0000644000175000017500000001215111346133506026773 0ustar andrewandrew/* * Copyright (c) 2005-2010 Trident Kirill Grouchnikov. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * o Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * o Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * o Neither the name of Trident Kirill Grouchnikov nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.pushingpixels.trident.swt; import java.util.*; import org.eclipse.swt.graphics.*; import org.eclipse.swt.widgets.Display; import org.pushingpixels.trident.interpolator.PropertyInterpolator; import org.pushingpixels.trident.interpolator.PropertyInterpolatorSource; /** * Built-in interpolators for SWT classes. * * @author Kirill Grouchnikov */ public class SWTPropertyInterpolators implements PropertyInterpolatorSource { private Set interpolators; public SWTPropertyInterpolators() { this.interpolators = new HashSet(); this.interpolators.add(new ColorInterpolator()); this.interpolators.add(new PointInterpolator()); this.interpolators.add(new RectangleInterpolator()); } @Override public Set getPropertyInterpolators() { return Collections.unmodifiableSet(this.interpolators); } static class ColorInterpolator implements PropertyInterpolator { @Override public Class getBasePropertyClass() { return Color.class; } @Override public Color interpolate(Color from, Color to, float timelinePosition) { return getInterpolatedColor(from, to, 1.0f - timelinePosition); } RGB getInterpolatedRGB(Color color1, Color color2, float color1Likeness) { if ((color1Likeness < 0.0) || (color1Likeness > 1.0)) throw new IllegalArgumentException( "Color likeness should be in 0.0-1.0 range [is " + color1Likeness + "]"); int lr = color1.getRed(); int lg = color1.getGreen(); int lb = color1.getBlue(); int dr = color2.getRed(); int dg = color2.getGreen(); int db = color2.getBlue(); // using some interpolation values (such as 0.29 from issue 401) // results in an incorrect final value without Math.round. int r = (lr == dr) ? lr : (int) Math.round(color1Likeness * lr + (1.0 - color1Likeness) * dr); int g = (lg == dg) ? lg : (int) Math.round(color1Likeness * lg + (1.0 - color1Likeness) * dg); int b = (lb == db) ? lb : (int) Math.round(color1Likeness * lb + (1.0 - color1Likeness) * db); return new RGB(r, g, b); } Color getInterpolatedColor(Color color1, Color color2, float color1Likeness) { if (color1.equals(color2)) return color1; if (color1Likeness == 1.0) return color1; if (color1Likeness == 0.0) return color2; return new Color(Display.getDefault(), getInterpolatedRGB(color1, color2, color1Likeness)); } } static class PointInterpolator implements PropertyInterpolator { public Point interpolate(Point from, Point to, float timelinePosition) { int x = from.x + (int) (timelinePosition * (to.x - from.x)); int y = from.y + (int) (timelinePosition * (to.y - from.y)); return new Point(x, y); } @Override public Class getBasePropertyClass() { return Point.class; } } static class RectangleInterpolator implements PropertyInterpolator { public Rectangle interpolate(Rectangle from, Rectangle to, float timelinePosition) { int x = from.x + (int) (timelinePosition * (to.x - from.x)); int y = from.y + (int) (timelinePosition * (to.y - from.y)); int w = from.width + (int) (timelinePosition * (to.width - from.width)); int h = from.height + (int) (timelinePosition * (to.height - from.height)); return new Rectangle(x, y, w, h); } @Override public Class getBasePropertyClass() { return Rectangle.class; } } } trident-1.3/src/org/pushingpixels/trident/swt/SWTToolkitHandler.java0000644000175000017500000000436311346133506025312 0ustar andrewandrew/* * Copyright (c) 2005-2010 Trident Kirill Grouchnikov. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * o Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * o Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * o Neither the name of Trident Kirill Grouchnikov nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.pushingpixels.trident.swt; import org.eclipse.swt.widgets.Widget; import org.pushingpixels.trident.UIToolkitHandler; public class SWTToolkitHandler implements UIToolkitHandler { @Override public boolean isHandlerFor(Object mainTimelineObject) { return (mainTimelineObject instanceof Widget); } @Override public boolean isInReadyState(Object mainTimelineObject) { return !((Widget) mainTimelineObject).isDisposed(); } @Override public void runOnUIThread(Object mainTimelineObject, Runnable runnable) { ((Widget) mainTimelineObject).getDisplay().asyncExec(runnable); } } trident-1.3/src/org/pushingpixels/trident/TimelinePropertyBuilder.java0000644000175000017500000003207111401140302025753 0ustar andrewandrew/* * Copyright (c) 2005-2010 Trident Kirill Grouchnikov. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * o Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * o Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * o Neither the name of Trident Kirill Grouchnikov nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.pushingpixels.trident; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import org.pushingpixels.trident.interpolator.KeyFrames; import org.pushingpixels.trident.interpolator.PropertyInterpolator; public class TimelinePropertyBuilder { /** * Defines how to set a property. */ public static interface PropertySetter { public void set(Object obj, String fieldName, T value); } /** * Defines how to get a property. */ public static interface PropertyGetter { public T get(Object obj, String fieldName); } /** * Defines how to access a property. */ public static interface PropertyAccessor extends PropertyGetter, PropertySetter { } /** * Default property setter. */ public static class DefaultPropertySetter implements PropertySetter { private Method setterMethod; public DefaultPropertySetter(Object obj, String fieldName) { setterMethod = getSetter(obj, fieldName); } public void set(Object obj, String fieldName, T value) { try { setterMethod.invoke(obj, value); } catch (Throwable t) { throw new RuntimeException( "Unable to set the value of the field '" + fieldName + "'", t); } } } /** * Default property getter. */ public static class DefaultPropertyGetter implements PropertyGetter { private Method getterMethod; public DefaultPropertyGetter(Object obj, String fieldName) { getterMethod = getGetter(obj, fieldName); } public T get(Object obj, String fieldName) { try { return (T) getterMethod.invoke(obj); } catch (Throwable t) { throw new RuntimeException( "Unable to get the value of the field '" + fieldName + "'", t); } } } private Object target; // may be null private final String propertyName; // required private T from; // optional private boolean isFromCurrent; private T to; // must be optional because of KeyFrames private PropertyInterpolator interpolator; // optional private PropertyGetter getter; // optional private PropertySetter setter; // optional private KeyFrames keyFrames; // optional TimelinePropertyBuilder(String propertyName) { this.propertyName = propertyName; this.isFromCurrent = false; } public TimelinePropertyBuilder from(T startValue) { if (this.from != null) { throw new IllegalArgumentException("from() can only be called once"); } if (this.isFromCurrent) { throw new IllegalArgumentException( "from() cannot be called after fromCurrent()"); } if (this.keyFrames != null) { throw new IllegalArgumentException( "from() cannot be called after goingThrough()"); } this.from = startValue; return this; } public TimelinePropertyBuilder fromCurrent() { if (this.isFromCurrent) { throw new IllegalArgumentException( "fromCurrent() can only be called once"); } if (this.from != null) { throw new IllegalArgumentException( "fromCurrent() cannot be called after from()"); } if (this.keyFrames != null) { throw new IllegalArgumentException( "fromCurrent() cannot be called after goingThrough()"); } this.isFromCurrent = true; return this; } public TimelinePropertyBuilder to(T endValue) { if (this.to != null) { throw new IllegalArgumentException("to() can only be called once"); } if (this.keyFrames != null) { throw new IllegalArgumentException( "to() cannot be called after goingThrough()"); } this.to = endValue; return this; } public TimelinePropertyBuilder on(Object object) { this.target = object; return this; } public TimelinePropertyBuilder interpolatedWith( PropertyInterpolator pInterpolator) { if (this.interpolator != null) { throw new IllegalArgumentException( "interpolateWith() can only be called once"); } this.interpolator = pInterpolator; return this; } public TimelinePropertyBuilder setWith(PropertySetter pSetter) { if (this.setter != null) { throw new IllegalArgumentException( "setWith() can only be called once"); } this.setter = pSetter; return this; } public TimelinePropertyBuilder getWith(PropertyGetter pGetter) { if (this.getter != null) { throw new IllegalArgumentException( "getWith() can only be called once"); } this.getter = pGetter; return this; } public TimelinePropertyBuilder accessWith(PropertyAccessor pAccessor) { if (this.setter != null || this.getter != null) { throw new IllegalArgumentException( "accessWith() can only be called once"); } this.setter = pAccessor; this.getter = pAccessor; return this; } public TimelinePropertyBuilder goingThrough(KeyFrames keyFrames) { if (this.keyFrames != null) { throw new IllegalArgumentException( "goingThrough() can only be called once"); } if (this.isFromCurrent) { throw new IllegalArgumentException( "goingThrough() cannot be called after fromCurrent()"); } if (this.from != null) { throw new IllegalArgumentException( "goingThrough() cannot be called after from()"); } if (this.to != null) { throw new IllegalArgumentException( "goingThrough() cannot be called after to()"); } this.keyFrames = keyFrames; return this; } AbstractFieldInfo getFieldInfo(Timeline timeline) { if (this.target == null) { this.target = timeline.mainObject; } if (this.keyFrames != null) { return new KeyFramesFieldInfo(this.target, this.propertyName, this.keyFrames, this.setter); } if (this.isFromCurrent) { if (this.interpolator == null) { this.interpolator = TridentConfig.getInstance() .getPropertyInterpolator(this.to); if (this.interpolator == null) { throw new IllegalArgumentException( "No interpolator found for " + this.to.getClass().getName()); } } return new GenericFieldInfoTo(this.target, this.propertyName, this.to, this.interpolator, this.getter, this.setter); } if (this.interpolator == null) { this.interpolator = TridentConfig.getInstance() .getPropertyInterpolator(this.from, this.to); if (this.interpolator == null) { throw new IllegalArgumentException("No interpolator found for " + this.from.getClass().getName() + ":" + this.to.getClass().getName()); } } return new GenericFieldInfo(this.target, this.propertyName, this.from, this.to, this.interpolator, this.setter); } abstract class AbstractFieldInfo { protected Object object; protected String fieldName; protected PropertyGetter getter; protected PropertySetter setter; protected T from; protected T to; AbstractFieldInfo(Object obj, String fieldName, PropertyGetter pGetter, PropertySetter pSetter) { this.object = obj; this.fieldName = fieldName; this.getter = pGetter; this.setter = pSetter; } void setValues(T from, T to) { this.from = from; this.to = to; } abstract void onStart(); abstract void updateFieldValue(float timelinePosition); } private static PropertyGetter getPropertyGetter(Object obj, String fieldName, PropertyGetter pGetter) { if (pGetter != null) return pGetter; return new DefaultPropertyGetter(obj, fieldName); } private static PropertySetter getPropertySetter(Object obj, String fieldName, PropertySetter pSetter) { if (pSetter != null) return pSetter; return new DefaultPropertySetter(obj, fieldName); } private class GenericFieldInfoTo extends AbstractFieldInfo { private PropertyInterpolator propertyInterpolator; private Object to; GenericFieldInfoTo(Object obj, String fieldName, Object to, PropertyInterpolator propertyInterpolator, PropertyGetter propertyGetter, PropertySetter propertySetter) { super(obj, fieldName, getPropertyGetter(obj, fieldName, propertyGetter), getPropertySetter(obj, fieldName, propertySetter)); this.propertyInterpolator = propertyInterpolator; this.to = to; } @Override void onStart() { this.from = getter.get(object, fieldName); } @Override void updateFieldValue(float timelinePosition) { try { Object value = this.propertyInterpolator.interpolate(from, to, timelinePosition); this.setter.set(this.object, this.fieldName, value); } catch (Throwable exc) { System.err.println("Exception occurred in updating field '" + this.fieldName + "' of object " + this.object.getClass().getCanonicalName() + " at timeline position " + timelinePosition); exc.printStackTrace(); } } } private class GenericFieldInfo extends AbstractFieldInfo { private PropertyInterpolator propertyInterpolator; GenericFieldInfo(Object obj, String fieldName, Object from, Object to, PropertyInterpolator propertyInterpolator, PropertySetter propertySetter) { super(obj, fieldName, null, getPropertySetter(obj, fieldName, propertySetter)); this.propertyInterpolator = propertyInterpolator; this.setValues(from, to); } @Override void onStart() { } @Override void updateFieldValue(float timelinePosition) { try { Object value = this.propertyInterpolator.interpolate(from, to, timelinePosition); this.setter.set(this.object, this.fieldName, value); } catch (Throwable exc) { System.err.println("Exception occurred in updating field '" + this.fieldName + "' of object " + this.object.getClass().getCanonicalName() + " at timeline position " + timelinePosition); exc.printStackTrace(); } } } private class KeyFramesFieldInfo extends AbstractFieldInfo { KeyFrames keyFrames; KeyFramesFieldInfo(Object obj, String fieldName, KeyFrames keyFrames, PropertySetter propertySetter) { super(obj, fieldName, null, getPropertySetter(obj, fieldName, propertySetter)); this.keyFrames = keyFrames; } @Override void onStart() { } @Override void updateFieldValue(float timelinePosition) { if (this.setter != null) { try { Object value = this.keyFrames.getValue(timelinePosition); this.setter.set(this.object, this.fieldName, value); } catch (Throwable exc) { exc.printStackTrace(); } } } } private static Method getSetter(Object object, String propertyName) { String setterMethodName = "set" + Character.toUpperCase(propertyName.charAt(0)) + propertyName.substring(1); Class oClazz = object.getClass(); while (oClazz != null) { for (Method m : oClazz.getMethods()) { if (setterMethodName.equals(m.getName()) && (m.getParameterTypes().length == 1) && (m.getReturnType() == Void.TYPE) && (!Modifier.isStatic(m.getModifiers()))) { return m; } } oClazz = oClazz.getSuperclass(); } return null; } private static Method getGetter(Object object, String propertyName) { String getterMethodName = "get" + Character.toUpperCase(propertyName.charAt(0)) + propertyName.substring(1); Class oClazz = object.getClass(); while (oClazz != null) { for (Method m : oClazz.getMethods()) { if (getterMethodName.equals(m.getName()) && (m.getParameterTypes().length == 0) && (!Modifier.isStatic(m.getModifiers()))) { return m; } } oClazz = oClazz.getSuperclass(); } return null; } } trident-1.3/src/org/pushingpixels/trident/interpolator/0000755000175000017500000000000011346133506023025 5ustar andrewandrewtrident-1.3/src/org/pushingpixels/trident/interpolator/KeyInterpolators.java0000644000175000017500000000536611346133506027220 0ustar andrewandrew/** * Copyright (c) 2006, Sun Microsystems, Inc * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided * with the distribution. * * Neither the name of the TimingFramework project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.pushingpixels.trident.interpolator; import java.util.ArrayList; import org.pushingpixels.trident.ease.Linear; import org.pushingpixels.trident.ease.TimelineEase; /** * * @author Chet */ class KeyInterpolators { private ArrayList interpolators = new ArrayList(); /** * Creates a new instance of KeyInterpolators */ KeyInterpolators(int numIntervals, TimelineEase... interpolators) { if (interpolators == null || interpolators[0] == null) { for (int i = 0; i < numIntervals; ++i) { this.interpolators.add(new Linear()); } } else if (interpolators.length < numIntervals) { for (int i = 0; i < numIntervals; ++i) { this.interpolators.add(interpolators[0]); } } else { for (int i = 0; i < numIntervals; ++i) { this.interpolators.add(interpolators[i]); } } } float interpolate(int interval, float fraction) { return interpolators.get(interval).map(fraction); } } trident-1.3/src/org/pushingpixels/trident/interpolator/KeyTimes.java0000644000175000017500000000763711346133506025437 0ustar andrewandrew/** * Copyright (c) 2005-2006, Sun Microsystems, Inc * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided * with the distribution. * * Neither the name of the TimingFramework project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.pushingpixels.trident.interpolator; import java.util.ArrayList; /** * Stores a list of times from 0 to 1 (the elapsed fraction of an animation * cycle) that are used in calculating interpolated * values for PropertySetter given a matching set of KeyValues and * Interpolators for those time intervals. In the simplest case, a * KeyFrame will consist of just two times in KeyTimes: 0 and 1. * * @author Chet */ public class KeyTimes { private ArrayList times = new ArrayList(); /** * Creates a new instance of KeyTimes. Times should be in increasing * order and should all be in the range [0,1], with the first value * being zero and the last being 1 * @throws IllegalArgumentException Time values must be ordered in * increasing value, the first value must be 0 and the last value * must be 1 */ public KeyTimes(float... times) { if (times[0] != 0) { throw new IllegalArgumentException("First time value must" + " be zero"); } if (times[times.length - 1] != 1.0f) { throw new IllegalArgumentException("Last time value must" + " be one"); } float prevTime = 0; for (float time : times) { if (time < prevTime) { throw new IllegalArgumentException("Time values must be" + " in increasing order"); } this.times.add(time); prevTime = time; } } ArrayList getTimes() { return times; } int getSize() { return times.size(); } /** * Returns time interval that contains this time fraction */ int getInterval(float fraction) { int prevIndex = 0; for (int i = 1; i < times.size(); ++i) { float time = times.get(i); if (time >= fraction) { // inclusive of start time at next interval. So fraction==1 // will return the final interval (times.size() - 1) return prevIndex; } prevIndex = i; } return prevIndex; } float getTime(int index) { return times.get(index); } }trident-1.3/src/org/pushingpixels/trident/interpolator/CorePropertyInterpolators.java0000644000175000017500000000720511346133506031117 0ustar andrewandrew/* * Copyright (c) 2005-2010 Trident Kirill Grouchnikov. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * o Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * o Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * o Neither the name of Trident Kirill Grouchnikov nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.pushingpixels.trident.interpolator; import java.util.*; public class CorePropertyInterpolators implements PropertyInterpolatorSource { private Set interpolators; public CorePropertyInterpolators() { this.interpolators = new HashSet(); this.interpolators.add(new IntegerPropertyInterpolator()); this.interpolators.add(new FloatPropertyInterpolator()); this.interpolators.add(new DoublePropertyInterpolator()); this.interpolators.add(new LongPropertyInterpolator()); } @Override public Set getPropertyInterpolators() { return Collections.unmodifiableSet(this.interpolators); } private static class FloatPropertyInterpolator implements PropertyInterpolator { @Override public Class getBasePropertyClass() { return Float.class; } @Override public Float interpolate(Float from, Float to, float timelinePosition) { return from + (to - from) * timelinePosition; } } private static class DoublePropertyInterpolator implements PropertyInterpolator { @Override public Class getBasePropertyClass() { return Double.class; } @Override public Double interpolate(Double from, Double to, float timelinePosition) { return from + (to - from) * timelinePosition; } } private static class IntegerPropertyInterpolator implements PropertyInterpolator { @Override public Class getBasePropertyClass() { return Integer.class; } @Override public Integer interpolate(Integer from, Integer to, float timelinePosition) { return (int) (from + (to - from) * timelinePosition); } } private static class LongPropertyInterpolator implements PropertyInterpolator { @Override public Class getBasePropertyClass() { return Long.class; } @Override public Long interpolate(Long from, Long to, float timelinePosition) { return (long) (from + (to - from) * timelinePosition); } } } trident-1.3/src/org/pushingpixels/trident/interpolator/KeyValues.java0000644000175000017500000001452111346133506025603 0ustar andrewandrew/** * Copyright (c) 2006, Sun Microsystems, Inc * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided * with the distribution. * * Neither the name of the TimingFramework project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.pushingpixels.trident.interpolator; import java.util.*; import org.pushingpixels.trident.TridentConfig; import org.pushingpixels.trident.TimelinePropertyBuilder.PropertySetter; /** * Stores a list of values that correspond to the times in a {@link KeyTimes} * object. These structures are then used to create a {@link KeyFrames} object, * which is then used to create a {@link PropertySetter} for the purposes of * modifying an object's property over time. *

* At each of the times in {@link KeyTimes}, the property will take on the * corresponding value in the KeyValues object. Between these times, the * property will take on a value based on the interpolation information stored * in the KeyFrames object and the {@link Evaluator} for the type of the values * in KeyValues. *

* This class has built-in support for various known types, as defined in * {@link Evaluator}. *

* For a simple example using KeyValues to create a KeyFrames and PropertySetter * object, see the class header comments in {@link PropertySetter}. * * * @author Chet */ public class KeyValues { private final List values = new ArrayList(); private final PropertyInterpolator evaluator; private final Class type; private T startValue; /** * Constructs a KeyValues object from one or more values. The internal * Evaluator is automatically determined by the type of the parameters. * * @param params * the values to interpolate between. If there is only one * parameter, this is assumed to be a "to" animation where the * first value is dynamically determined at runtime when the * animation is started. * @throws IllegalArgumentException * if an {@link Evaluator} cannot be found that can interpolate * between the value types supplied */ public static KeyValues create(T... params) { return new KeyValues(params); } /** * Constructs a KeyValues object from a Evaluator and one or more values. * * @param params * the values to interpolate between. If there is only one * parameter, this is assumed to be a "to" animation where the * first value is dynamically determined at runtime when the * animation is started. * @throws IllegalArgumentException * if params does not have at least one value. */ public static KeyValues create(PropertyInterpolator evaluator, T... params) { return new KeyValues(evaluator, params); } /** * Private constructor, called by factory method */ private KeyValues(T... params) { this(TridentConfig.getInstance().getPropertyInterpolator(params), params); } /** * Private constructor, called by factory method */ private KeyValues(PropertyInterpolator evaluator, T... params) { if (params == null) { throw new IllegalArgumentException("params array cannot be null"); } else if (params.length == 0) { throw new IllegalArgumentException( "params array must have at least one element"); } if (params.length == 1) { // this is a "to" animation; set first element to null values.add(null); } Collections.addAll(values, params); this.type = params.getClass().getComponentType(); this.evaluator = evaluator; } /** * Returns the number of values stored in this object. * * @return the number of values stored in this object */ int getSize() { return values.size(); } /** * Returns the data type of the values stored in this object. * * @return a Class value representing the type of values stored in this * object */ Class getType() { return this.type; } /** * Called at start of animation; sets starting value in simple "to" * animations. */ void setStartValue(T startValue) { if (isToAnimation()) { this.startValue = startValue; } } /** * Utility method for determining whether this is a "to" animation (true if * the first value is null). */ boolean isToAnimation() { return (values.get(0) == null); } /** * Returns value calculated from the value at the lower index, the value at * the upper index, the fraction elapsed between these endpoints, and the * evaluator set up by this object at construction time. */ T getValue(int i0, int i1, float fraction) { T value; T lowerValue = values.get(i0); if (lowerValue == null) { // "to" animation lowerValue = startValue; } if (i0 == i1) { // trivial case value = lowerValue; } else { T v0 = lowerValue; T v1 = values.get(i1); value = evaluator.interpolate(v0, v1, fraction); } return value; } } trident-1.3/src/org/pushingpixels/trident/interpolator/PropertyInterpolatorSource.java0000644000175000017500000000350311346133506031301 0ustar andrewandrew/* * Copyright (c) 2005-2010 Trident Kirill Grouchnikov. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * o Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * o Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * o Neither the name of Trident Kirill Grouchnikov nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.pushingpixels.trident.interpolator; import java.util.Set; public interface PropertyInterpolatorSource { public Set getPropertyInterpolators(); } trident-1.3/src/org/pushingpixels/trident/interpolator/PropertyInterpolator.java0000644000175000017500000000351711346133506030125 0ustar andrewandrew/* * Copyright (c) 2005-2010 Trident Kirill Grouchnikov. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * o Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * o Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * o Neither the name of Trident Kirill Grouchnikov nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.pushingpixels.trident.interpolator; public interface PropertyInterpolator { public Class getBasePropertyClass(); public T interpolate(T from, T to, float timelinePosition); } trident-1.3/src/org/pushingpixels/trident/interpolator/KeyFrames.java0000644000175000017500000002210711346133506025560 0ustar andrewandrew/** * Copyright (c) 2006, Sun Microsystems, Inc * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided * with the distribution. * * Neither the name of the TimingFramework project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.pushingpixels.trident.interpolator; import org.pushingpixels.trident.ease.TimelineEase; /** * * KeyFrames holds information about the times at which values are sampled * (KeyTimes) and the values at those times (KeyValues). It also holds * information about how to interpolate between these values for times that lie * between the sampling points. * * @author Chet */ public class KeyFrames { private KeyValues keyValues; private KeyTimes keyTimes; private KeyInterpolators interpolators; /** * Simplest variation; determine keyTimes based on even division of 0-1 * range based on number of keyValues. This constructor assumes LINEAR * interpolation. * * @param keyValues * values that will be assumed at each time in keyTimes */ public KeyFrames(KeyValues keyValues) { init(keyValues, null, (TimelineEase) null); } /** * This variant takes both keyValues (values at each point in time) and * keyTimes (times at which values are sampled). * * @param keyValues * values that the animation will assume at each of the * corresponding times in keyTimes * @param keyTimes * times at which the animation will assume the corresponding * values in keyValues * @throws IllegalArgumentException * keyTimes and keySizes must have the same number of elements * since these structures are meant to have corresponding * entries; an exception is thrown otherwise. */ public KeyFrames(KeyValues keyValues, KeyTimes keyTimes) { init(keyValues, keyTimes, (TimelineEase) null); } /** * Full constructor: caller provides an instance of all key* structures * which will be used to calculate between all times in the keyTimes list. A * null interpolator parameter is equivalent to calling * {@link KeyFrames#KeyFrames(KeyValues, KeyTimes)}. * * @param keyValues * values that the animation will assume at each of the * corresponding times in keyTimes * @param keyTimes * times at which the animation will assume the corresponding * values in keyValues * @param interpolators * collection of Interpolators that control the calculation of * values in each of the intervals defined by keyFrames. If this * value is null, a {@link LinearInterpolator} will be used for * all intervals. If there is only one interpolator, that * interpolator will be used for all intervals. Otherwise, there * must be a number of interpolators equal to the number of * intervals (which is one less than the number of keyTimes). * @throws IllegalArgumentException * keyTimes and keyValues must have the same number of elements * since these structures are meant to have corresponding * entries; an exception is thrown otherwise. * @throws IllegalArgumentException * The number of interpolators must either be zero * (interpolators == null), one, or one less than the size of * keyTimes. */ public KeyFrames(KeyValues keyValues, KeyTimes keyTimes, TimelineEase... interpolators) { init(keyValues, keyTimes, interpolators); } /** * Utility constructor that assumes even division of times according to size * of keyValues and interpolation according to interpolators parameter. * * @param keyValues * values that the animation will assume at each of the * corresponding times in keyTimes * @param interpolators * collection of Interpolators that control the calculation of * values in each of the intervals defined by keyFrames. If this * value is null, a {@link LinearInterpolator} will be used for * all intervals. If there is only one interpolator, that * interpolator will be used for all intervals. Otherwise, there * must be a number of interpolators equal to the number of * intervals (which is one less than the number of keyTimes). * @throws IllegalArgumentException * The number of interpolators must either be zero * (interpolators == null), one, or one less than the size of * keyTimes. */ public KeyFrames(KeyValues keyValues, TimelineEase... interpolators) { init(keyValues, null, interpolators); } /** * Utility function called by constructors to perform common initialization * chores */ private void init(KeyValues keyValues, KeyTimes keyTimes, TimelineEase... interpolators) { int numFrames = keyValues.getSize(); // If keyTimes null, create our own if (keyTimes == null) { float keyTimesArray[] = new float[numFrames]; float timeVal = 0.0f; keyTimesArray[0] = timeVal; for (int i = 1; i < (numFrames - 1); ++i) { timeVal += (1.0f / (numFrames - 1)); keyTimesArray[i] = timeVal; } keyTimesArray[numFrames - 1] = 1.0f; this.keyTimes = new KeyTimes(keyTimesArray); } else { this.keyTimes = keyTimes; } this.keyValues = keyValues; if (numFrames != this.keyTimes.getSize()) { throw new IllegalArgumentException("keyValues and keyTimes" + " must be of equal size"); } if (interpolators != null && (interpolators.length != (numFrames - 1)) && (interpolators.length != 1)) { throw new IllegalArgumentException( "interpolators must be " + "either null (implying interpolation for all intervals), " + "a single interpolator (which will be used for all " + "intervals), or a number of interpolators equal to " + "one less than the number of times."); } this.interpolators = new KeyInterpolators(numFrames - 1, interpolators); } public Class getType() { return keyValues.getType(); } KeyValues getKeyValues() { return keyValues; } KeyTimes getKeyTimes() { return keyTimes; } /** * Returns time interval that contains this time fraction */ public int getInterval(float fraction) { return keyTimes.getInterval(fraction); } /** * Returns a value for the given fraction elapsed of the animation cycle. * Given the fraction, this method will determine what interval the fraction * lies within, how much of that interval has elapsed, what the boundary * values are (from KeyValues), what the interpolated fraction is (from the * Interpolator for the interval), and what the final interpolated * intermediate value is (using the appropriate Evaluator). This method will * call into the Interpolator for the time interval to get the interpolated * method. To ensure that future operations succeed, the value received from * the interpolation will be clamped to the interval [0,1]. */ public Object getValue(float fraction) { // First, figure out the real fraction to use, given the // interpolation type and keyTimes int interval = getInterval(fraction); float t0 = keyTimes.getTime(interval); float t1 = keyTimes.getTime(interval + 1); float t = (fraction - t0) / (t1 - t0); float interpolatedT = interpolators.interpolate(interval, t); // clamp to avoid problems with buggy Interpolators if (interpolatedT < 0f) { interpolatedT = 0f; } else if (interpolatedT > 1f) { interpolatedT = 1f; } return keyValues.getValue(interval, (interval + 1), interpolatedT); } } trident-1.3/src/META-INF/0000755000175000017500000000000011346133506014301 5ustar andrewandrewtrident-1.3/src/META-INF/trident-plugin.properties0000644000175000017500000000106611346133506021367 0ustar andrewandrewUIToolkitHandler=org.pushingpixels.trident.swing.SwingToolkitHandler PropertyInterpolatorSource=org.pushingpixels.trident.swing.AWTPropertyInterpolators UIToolkitHandler=org.pushingpixels.trident.swt.SWTToolkitHandler PropertyInterpolatorSource=org.pushingpixels.trident.swt.SWTPropertyInterpolators UIToolkitHandler=org.pushingpixels.trident.android.AndroidToolkitHandler PropertyInterpolatorSource=org.pushingpixels.trident.android.AndroidPropertyInterpolators PropertyInterpolatorSource=org.pushingpixels.trident.interpolator.CorePropertyInterpolatorstrident-1.3/build.properties0000644000175000017500000000033311346133506015566 0ustar andrewandrewjdk.home=/System/Library/Frameworks/JavaVM.framework/Versions/1.6.0/Home javac.source=1.6 javac.target=1.6 javac.encoding=ISO-8859-1 javac.debug=on javac.generate.no.warnings=off javac.args= javac.max.memory=128mtrident-1.3/build.xml0000644000175000017500000001735111427732010014175 0ustar andrewandrew