[pkg-java] r13103 - in branches/upstream: . timingframework timingframework/current timingframework/current/org timingframework/current/org/jdesktop timingframework/current/org/jdesktop/animation timingframework/current/org/jdesktop/animation/timing timingframework/current/org/jdesktop/animation/timing/interpolation timingframework/current/org/jdesktop/animation/timing/triggers
Andrew Ross
rockclimb-guest at alioth.debian.org
Sat Nov 27 19:08:00 UTC 2010
Author: rockclimb-guest
Date: 2010-11-27 19:07:53 +0000 (Sat, 27 Nov 2010)
New Revision: 13103
Added:
branches/upstream/timingframework/
branches/upstream/timingframework/current/
branches/upstream/timingframework/current/org/
branches/upstream/timingframework/current/org/jdesktop/
branches/upstream/timingframework/current/org/jdesktop/animation/
branches/upstream/timingframework/current/org/jdesktop/animation/timing/
branches/upstream/timingframework/current/org/jdesktop/animation/timing/Animator.java
branches/upstream/timingframework/current/org/jdesktop/animation/timing/TimingEventListener.java
branches/upstream/timingframework/current/org/jdesktop/animation/timing/TimingSource.java
branches/upstream/timingframework/current/org/jdesktop/animation/timing/TimingTarget.java
branches/upstream/timingframework/current/org/jdesktop/animation/timing/TimingTargetAdapter.java
branches/upstream/timingframework/current/org/jdesktop/animation/timing/interpolation/
branches/upstream/timingframework/current/org/jdesktop/animation/timing/interpolation/DiscreteInterpolator.java
branches/upstream/timingframework/current/org/jdesktop/animation/timing/interpolation/Evaluator.java
branches/upstream/timingframework/current/org/jdesktop/animation/timing/interpolation/Interpolator.java
branches/upstream/timingframework/current/org/jdesktop/animation/timing/interpolation/KeyFrames.java
branches/upstream/timingframework/current/org/jdesktop/animation/timing/interpolation/KeyInterpolators.java
branches/upstream/timingframework/current/org/jdesktop/animation/timing/interpolation/KeyTimes.java
branches/upstream/timingframework/current/org/jdesktop/animation/timing/interpolation/KeyValues.java
branches/upstream/timingframework/current/org/jdesktop/animation/timing/interpolation/LinearInterpolator.java
branches/upstream/timingframework/current/org/jdesktop/animation/timing/interpolation/PropertySetter.java
branches/upstream/timingframework/current/org/jdesktop/animation/timing/interpolation/SplineInterpolator.java
branches/upstream/timingframework/current/org/jdesktop/animation/timing/interpolation/package.html
branches/upstream/timingframework/current/org/jdesktop/animation/timing/package.html
branches/upstream/timingframework/current/org/jdesktop/animation/timing/triggers/
branches/upstream/timingframework/current/org/jdesktop/animation/timing/triggers/ActionTrigger.java
branches/upstream/timingframework/current/org/jdesktop/animation/timing/triggers/FocusTrigger.java
branches/upstream/timingframework/current/org/jdesktop/animation/timing/triggers/FocusTriggerEvent.java
branches/upstream/timingframework/current/org/jdesktop/animation/timing/triggers/MouseTrigger.java
branches/upstream/timingframework/current/org/jdesktop/animation/timing/triggers/MouseTriggerEvent.java
branches/upstream/timingframework/current/org/jdesktop/animation/timing/triggers/TimingTrigger.java
branches/upstream/timingframework/current/org/jdesktop/animation/timing/triggers/TimingTriggerEvent.java
branches/upstream/timingframework/current/org/jdesktop/animation/timing/triggers/Trigger.java
branches/upstream/timingframework/current/org/jdesktop/animation/timing/triggers/TriggerEvent.java
branches/upstream/timingframework/current/org/jdesktop/animation/timing/triggers/TriggerNotes
branches/upstream/timingframework/current/org/jdesktop/animation/timing/triggers/package.html
Log:
[svn-inject] Installing original source of timingframework (1.0)
Added: branches/upstream/timingframework/current/org/jdesktop/animation/timing/Animator.java
===================================================================
--- branches/upstream/timingframework/current/org/jdesktop/animation/timing/Animator.java (rev 0)
+++ branches/upstream/timingframework/current/org/jdesktop/animation/timing/Animator.java 2010-11-27 19:07:53 UTC (rev 13103)
@@ -0,0 +1,1045 @@
+/**
+ * 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.jdesktop.animation.timing;
+
+import javax.swing.Timer;
+import java.awt.event.*;
+import java.util.ArrayList;
+import org.jdesktop.animation.timing.interpolation.Interpolator;
+import org.jdesktop.animation.timing.interpolation.LinearInterpolator;
+
+/**
+ * This class controls animations. Its constructors and various
+ * set methods control the parameters under which animations are run,
+ * and the other methods support starting and stopping the animation.
+ * The parameters of this class use the concepts of a "cycle" (the base
+ * animation) and an "envelope" that controls how the cycle is started,
+ * ended, and repeated.
+ * <p>
+ * Most of the methods here are simle getters/setters for the properties
+ * used by Animator. Typical animations will simply use one of the
+ * two constructors (depending on whether you are constructing a repeating
+ * animation), optionally call any of the <code>set*</code> methods to alter
+ * any of the other parameters, and then call start() to run the animation.
+ * For example, this animation will run for 1 second, calling your
+ * {@link TimingTarget} with timing events when the animation is started,
+ * running, and stopped:
+ * <pre>
+ * Animator animator = new Animator(1000, myTarget);
+ * animator.start();
+ * </pre>
+ * The following variation will run a half-second animation 4 times,
+ * reversing direction each time:
+ * <pre>
+ * Animator animator = new Animator(500, 4, RepeatBehavior.REVERSE, myTarget);
+ * animator.start();
+ * </pre>
+ * More complex animations can be created through using the properties
+ * in Animator, such as {@link Animator#setAcceleration acceleration} and {@link
+ * Animator#setDeceleration}. More automated animations can be created and run
+ * using the {@link org.jdesktop.animation.timing.triggers triggers}
+ * package to control animations through events and {@link
+ * org.jdesktop.animation.timing.interpolation.PropertySetter} to
+ * handle animating object properties.
+ */
+public final class Animator {
+
+ private TimingSource timer; // Currently uses Swing timer. This could change
+ // in the future to use a more general mechanism
+ // (and one of better timing resolution). An
+ // important advantage to the Swing timer is that
+ // it ensures that we receive and send our timing
+ // events on the Event Dispatch Thread, which makes
+ // it easier to use the framework for GUI
+ // animations.
+ private TimingSource swingTimer;
+ private TimingSourceTarget timingSourceTarget;
+
+ private ArrayList<TimingTarget> targets = new ArrayList<TimingTarget>(); // Animators may have
+ // multiple targets
+
+ private long startTime; // Tracks original Animator start time
+ private long currentStartTime; // Tracks start time of current cycle
+ private int currentCycle = 0; // Tracks number of cycles so far
+ private boolean intRepeatCount = true; // for typical cases
+ // of repeated cycles
+ private boolean timeToStop = false; // This gets triggered during
+ // fraction calculation
+ private boolean hasBegun = false;
+ private long pauseBeginTime = 0; // Used for pause/resume
+ private boolean running = false; // Used for isRunning()
+
+ // Private variables to hold the internal "envelope" values that control
+ // how the cycle is started, ended, and repeated.
+ private double repeatCount = 1.0;
+ private int startDelay;
+ private RepeatBehavior repeatBehavior = RepeatBehavior.REVERSE;
+ private EndBehavior endBehavior = EndBehavior.HOLD;
+
+ // Private variables to hold the internal values of the base
+ // animation (the cycle)
+ private int duration;
+ private int resolution = 20;
+ private float acceleration = 0;
+ private float deceleration = 0.0f;
+ private float startFraction = 0.0f;
+ private Direction direction = Direction.FORWARD; // Direction of each cycle
+ private Interpolator interpolator = LinearInterpolator.getInstance();
+
+ /**
+ * EndBehavior determines what happens at the end of the animation.
+ * @see #setEndBehavior
+ */
+ public static enum EndBehavior {
+ /** Timing sequence will maintain its final value at the end */
+ HOLD,
+ /** Timing sequence should reset to the initial value at the end */
+ RESET,
+ };
+
+ /**
+ * Direction is used to set the initial direction in which the
+ * animation starts.
+ *
+ * @see #setStartDirection
+ */
+ public static enum Direction {
+ /**
+ * cycle proceeds forward
+ */
+ FORWARD,
+ /** cycle proceeds backward */
+ BACKWARD,
+ };
+
+ /**
+ * RepeatBehavior determines how each successive cycle will flow.
+ * @see #setRepeatBehavior
+ */
+ public static enum RepeatBehavior {
+ /**
+ * Each repeated cycle proceeds in the same direction as the
+ * previous one
+ */
+ LOOP,
+ /**
+ * Each cycle proceeds in the opposite direction as the
+ * previous one
+ */
+ REVERSE
+ };
+
+ /**
+ * Used to specify unending duration or repeatCount
+ * @see #setDuration
+ * @see #setRepeatCount
+ * */
+ public static final int INFINITE = -1;
+
+ private void validateRepeatCount(double repeatCount) {
+ if (repeatCount < 1 && repeatCount != INFINITE) {
+ throw new IllegalArgumentException("repeatCount (" + repeatCount +
+ ") cannot be <= 0");
+ }
+ }
+
+ /**
+ * Constructor: this is a utility constructor
+ * for a simple timing sequence that will run for
+ * <code>duration</code> length of time. This variant takes no
+ * TimingTarget, and is equivalent to calling {@link #Animator(int,
+ * TimingTarget)} with a TimingTarget of <code>null</code>.
+ *
+ * @param duration The length of time that this will run, in milliseconds.
+ */
+
+ public Animator(int duration) {
+ this(duration, null);
+ }
+
+ /**
+ * Constructor: this is a utility constructor
+ * for a simple timing sequence that will run for
+ * <code>duration</code> length of time.
+ *
+ * @param duration The length of time that this will run, in milliseconds.
+ * @param target TimingTarget object that will be called with
+ * all timing events. Null is acceptable, but no timingEvents will be
+ * sent to any targets without future calls to {@link #addTarget}.
+ */
+ public Animator(int duration, TimingTarget target) {
+ this.duration = duration;
+ addTarget(target);
+
+ /**
+ * hack workaround for starting the Toolkit thread before any Timer stuff
+ * javax.swing.Timer uses the Event Dispatch Thread, which is not
+ * created until the Toolkit thread starts up. Using the Swing
+ * Timer before starting this stuff starts up may get unexpected
+ * results (such as taking a long time before the first timer
+ * event).
+ */
+ java.awt.Toolkit tk = java.awt.Toolkit.getDefaultToolkit();
+
+ // Create internal Timer object
+ swingTimer = new SwingTimingSource();
+ timer = swingTimer;
+ }
+
+ /**
+ * Constructor that sets the most common properties of a
+ * repeating animation.
+ * @param duration the length of each animation cycle, in milliseconds.
+ * This value can also be {@link #INFINITE} for animations that have no
+ * end. Note that fractions sent out with such unending animations will
+ * be undefined since there is no fraction of an infinitely long cycle.
+ * @param repeatCount the number of times the animation cycle will repeat.
+ * This is a positive value, which allows a non-integral number
+ * of repetitions (allowing an animation to stop mid-cycle, for example).
+ * This value can also be {@link #INFINITE}, indicating that the animation
+ * will continue repeating forever, or until manually stopped.
+ * @param repeatBehavior {@link RepeatBehavior} of each successive
+ * cycle. A value of null is equivalent to RepeatBehavior.REVERSE.
+ * @param target TimingTarget object that will be called with
+ * all timing events. Null is acceptable, but no timingEvents will be
+ * sent to any targets without future calls to {@link #addTarget}.
+ * @throws IllegalArgumentException if any parameters have invalid
+ * values
+ * @see Animator#INFINITE
+ * @see Direction
+ * @see EndBehavior
+ */
+ public Animator(int duration, double repeatCount,
+ RepeatBehavior repeatBehavior, TimingTarget target) {
+ this(duration, target);
+ // First, check for bad parameters
+ validateRepeatCount(repeatCount);
+ this.repeatCount = repeatCount;
+ this.repeatBehavior = (repeatBehavior != null) ?
+ repeatBehavior : RepeatBehavior.REVERSE;
+
+ // Set convenience variable: do we have an integer number of cycles?
+ intRepeatCount = (Math.rint(repeatCount) == repeatCount);
+ }
+
+ /**
+ * Returns the initial direction for the animation.
+ * @return direction that the initial animation cycle will be moving
+ */
+ public Direction getStartDirection() {
+ return direction;
+ }
+
+ /**
+ * Sets the startDirection for the initial animation cycle. The default
+ * startDirection is {@link Direction#FORWARD FORWARD}.
+ *
+ * @param startDirection initial animation cycle direction
+ * @see #isRunning()
+ * @throws IllegalStateException if animation is already running; this
+ * parameter may only be changed prior to starting the animation or
+ * after the animation has ended
+ */
+ public void setStartDirection(Direction startDirection) {
+ throwExceptionIfRunning();
+ this.direction = startDirection;
+ }
+
+ /**
+ * Returns the interpolator for the animation.
+ * @return interpolator that the initial animation cycle uses
+ */
+ public Interpolator getInterpolator() {
+ return interpolator;
+ }
+
+ /**
+ * Sets the interpolator for the animation cycle. The default
+ * interpolator is {@link LinearInterpolator}.
+ * @param interpolator the interpolation to use each animation cycle
+ * @throws IllegalStateException if animation is already running; this
+ * parameter may only be changed prior to starting the animation or
+ * after the animation has ended
+ * @see #isRunning()
+ */
+ public void setInterpolator(Interpolator interpolator) {
+ throwExceptionIfRunning();
+ this.interpolator = interpolator;
+ }
+
+ /**
+ * Sets the fraction of the timing cycle that will be spent accelerating
+ * at the beginning. The default acceleration value is 0 (no acceleration).
+ * @param acceleration value from 0 to 1
+ * @throws IllegalArgumentException acceleration value must be between 0 and
+ * 1, inclusive.
+ * @throws IllegalArgumentException acceleration cannot be greater than
+ * (1 - deceleration)
+ * @throws IllegalStateException if animation is already running; this
+ * parameter may only be changed prior to starting the animation or
+ * after the animation has ended
+ * @see #isRunning()
+ * @see #setDeceleration(float)
+ */
+ public void setAcceleration(float acceleration) {
+ throwExceptionIfRunning();
+ if (acceleration < 0 || acceleration > 1.0f) {
+ throw new IllegalArgumentException("Acceleration value cannot lie" +
+ " outside [0,1] range");
+ }
+ if (acceleration > (1.0f - deceleration)) {
+ throw new IllegalArgumentException("Acceleration value cannot be" +
+ " greater than (1 - deceleration)");
+ }
+ this.acceleration = acceleration;
+ }
+
+ /**
+ * Sets the fraction of the timing cycle that will be spent decelerating
+ * at the end. The default deceleration value is 0 (no deceleration).
+ * @param deceleration value from 0 to 1
+ * @throws IllegalArgumentException deceleration value must be between 0 and
+ * 1, inclusive.
+ * @throws IllegalArgumentException deceleration cannot be greater than
+ * (1 - acceleration)
+ * @throws IllegalStateException if animation is already running; this
+ * parameter may only be changed prior to starting the animation or
+ * after the animation has ended
+ * @see #isRunning()
+ * @see #setAcceleration(float)
+ */
+ public void setDeceleration(float deceleration) {
+ throwExceptionIfRunning();
+ if (deceleration < 0 || deceleration > 1.0f) {
+ throw new IllegalArgumentException("Deceleration value cannot lie" +
+ " outside [0,1] range");
+ }
+ if (deceleration > (1.0f - acceleration)) {
+ throw new IllegalArgumentException("Deceleration value cannot be" +
+ " greater than (1 - acceleration)");
+ }
+ this.deceleration = deceleration;
+ }
+
+ /**
+ * Returns the current value of acceleration property
+ * @return acceleration value
+ */
+ public float getAcceleration() {
+ return acceleration;
+ }
+
+ /**
+ * Returns the current value of deceleration property
+ * @return deceleration value
+ */
+ public float getDeceleration() {
+ return deceleration;
+ }
+
+ /**
+ * Adds a TimingTarget to the list of targets that get notified of each
+ * timingEvent. This can be done at any time before, during, or after the
+ * animation has started or completed; the new target will begin
+ * having its TimingTarget methods called as soon as it is added.
+ * If <code>target</code> is already on the list of targets in this Animator, it
+ * is not added again (there will be only one instance of any given
+ * target in any Animator's list of targets).
+ * @param target TimingTarget to be added to the list of targets that
+ * get notified by this Animator of all timing events. Target cannot
+ * be null.
+ */
+ public void addTarget(TimingTarget target) {
+ if (target != null) {
+ synchronized (targets) {
+ if (!targets.contains(target)) {
+ targets.add(target);
+ }
+ }
+ }
+ }
+
+ /**
+ * Removes the specified TimingTarget from the list of targets that get
+ * notified of each timingEvent. This can be done at any time before,
+ * during, or after the animation has started or completed; the
+ * target will cease having its TimingTarget methods called as soon
+ * as it is removed.
+ * @param target TimingTarget to be removed from the list of targets that
+ * get notified by this Animator of all timing events.
+ */
+ public void removeTarget(TimingTarget target) {
+ synchronized (targets) {
+ targets.remove(target);
+ }
+ }
+
+ /**
+ * Private utility to throw an exception if the animation is running. This
+ * is used by all of the property-setting methods to ensure that the
+ * properties are not being changed mid-stream.
+ */
+ private void throwExceptionIfRunning() {
+ if (isRunning()) {
+ throw new IllegalStateException("Cannot perform this operation " +
+ "while Animator is running");
+ }
+ }
+
+ /**
+ * Returns the current resolution of the animation. This helps
+ * determine the maximum frame rate at which the animation will run.
+ * @return the resolution, in milliseconds, of the timer
+ */
+ public int getResolution() {
+ return resolution;
+ }
+
+ /**
+ * Sets the resolution of the animation
+ * @param resolution the amount of time between timing events of the
+ * animation, in milliseconds. Note that the actual resolution may vary,
+ * according to the resolution of the timer used by the framework as well
+ * as system load and configuration; this value should be seen more as a
+ * minimum resolution than a guaranteed resolution.
+ * @throws IllegalArgumentException resolution must be >= 0
+ * @throws IllegalStateException if animation is already running; this
+ * parameter may only be changed prior to starting the animation or
+ * after the animation has ended
+ * @see #isRunning()
+ */
+ public void setResolution(int resolution) {
+ if (resolution < 0) {
+ throw new IllegalArgumentException("resolution must be >= 0");
+ }
+ throwExceptionIfRunning();
+ this.resolution = resolution;
+ timer.setResolution(resolution);
+ }
+
+ /**
+ * Returns the duration of the animation.
+ * @return the length of the animation, in milliseconds. A
+ * return value of -1 indicates an {@link #INFINITE} duration.
+ */
+ public int getDuration() {
+ return duration;
+ }
+
+ /**
+ * Sets the duration for the animation
+ * @param duration the length of the animation, in milliseconds. This
+ * value can also be {@link #INFINITE}, meaning the animation will run
+ * until manually stopped.
+ * @throws IllegalStateException if animation is already running; this
+ * parameter may only be changed prior to starting the animation or
+ * after the animation has ended
+ * @see #isRunning()
+ * @see #stop()
+ */
+ public void setDuration(int duration) {
+ throwExceptionIfRunning();
+ this.duration = duration;
+ }
+
+ /**
+ * Returns the number of times the animation cycle will repeat.
+ * @return the number of times the animation cycle will repeat.
+ */
+ public double getRepeatCount() {
+ return repeatCount;
+ }
+
+ /**
+ * Sets the number of times the animation cycle will repeat. The default
+ * value is 1.
+ * @param repeatCount Number of times the animation cycle will repeat.
+ * This value may be >= 1 or {@link #INFINITE} for animations that repeat
+ * indefinitely. The value may be fractional if the animation should
+ * stop at some fractional point.
+ * @throws IllegalArgumentException if repeatCount is not >=1 or
+ * INFINITE.
+ * @throws IllegalStateException if animation is already running; this
+ * parameter may only be changed prior to starting the animation or
+ * after the animation has ended
+ * @see #isRunning()
+ */
+ public void setRepeatCount(double repeatCount) {
+ validateRepeatCount(repeatCount);
+ throwExceptionIfRunning();
+ this.repeatCount = repeatCount;
+ }
+
+ /**
+ * Returns the amount of delay prior to starting the first animation
+ * cycle after the call to {@link #start}.
+ * @return the duration, in milliseconds, between the call
+ * to start the animation and the first animation cycle actually
+ * starting.
+ * @see #start
+ */
+ public int getStartDelay() {
+ return startDelay;
+ }
+
+ /**
+ * Sets the duration of the initial delay between calling {@link #start}
+ * and the start of the first animation cycle. The default value is 0 (no
+ * delay).
+ * @param startDelay the duration, in milliseconds, between the call
+ * to start the animation and the first animation cycle actually
+ * starting. This value must be >= 0.
+ * @throws IllegalArgumentException if startDelay is < 0
+ * @throws IllegalStateException if animation is already running; this
+ * parameter may only be changed prior to starting the animation or
+ * after the animation has ended
+ * @see #isRunning()
+ */
+ public void setStartDelay(int startDelay) {
+ if (startDelay < 0) {
+ throw new IllegalArgumentException("startDelay (" + startDelay +
+ ") cannot be < 0");
+ }
+ throwExceptionIfRunning();
+ this.startDelay = startDelay;
+ timer.setStartDelay(startDelay);
+ }
+
+ /**
+ * Returns the {@link RepeatBehavior} of the animation. The default
+ * behavior is REVERSE, meaning that the animation will reverse direction
+ * at the end of each cycle.
+ * @return whether the animation will repeat in the same
+ * direction or will reverse direction each time.
+ */
+ public RepeatBehavior getRepeatBehavior() {
+ return repeatBehavior;
+ }
+
+ /**
+ * Sets the {@link RepeatBehavior} of the animation.
+ * @param repeatBehavior the behavior for each successive cycle in the
+ * animation. A null behavior is equivalent to specifying the default:
+ * REVERSE. The default behaviors is HOLD.
+ * @throws IllegalStateException if animation is already running; this
+ * parameter may only be changed prior to starting the animation or
+ * after the animation has ended
+ * @see #isRunning()
+ */
+ public void setRepeatBehavior(RepeatBehavior repeatBehavior) {
+ throwExceptionIfRunning();
+ this.repeatBehavior = (repeatBehavior != null) ?
+ repeatBehavior : RepeatBehavior.REVERSE;
+ }
+
+ /**
+ * Returns the {@link EndBehavior} of the animation, either HOLD to
+ * retain the final value or RESET to take on the initial value. The
+ * default behavior is HOLD.
+ * @return the behavior at the end of the animation
+ */
+ public EndBehavior getEndBehavior() {
+ return endBehavior;
+ }
+
+ /**
+ * Sets the behavior at the end of the animation.
+ * @param endBehavior the behavior at the end of the animation, either
+ * HOLD or RESET. A null value is equivalent to the default value of
+ * HOLD.
+ * @throws IllegalStateException if animation is already running; this
+ * parameter may only be changed prior to starting the animation or
+ * after the animation has ended
+ * @see #isRunning
+ */
+ public void setEndBehavior(EndBehavior endBehavior) {
+ throwExceptionIfRunning();
+ this.endBehavior = endBehavior;
+ }
+
+ /**
+ * Returns the fraction that the first cycle will start at.
+ * @return fraction between 0 and 1 at which the first cycle will start.
+ */
+ public float getStartFraction() {
+ return startFraction;
+ }
+
+ /**
+ * Sets the initial fraction at which the first animation cycle will
+ * begin. The default value is 0.
+ * @param startFraction
+ * @see #isRunning()
+ * @throws IllegalArgumentException if startFraction is less than 0
+ * or greater than 1
+ * @throws IllegalStateException if animation is already running; this
+ * parameter may only be changed prior to starting the animation or
+ * after the animation has ended
+ */
+ public void setStartFraction(float startFraction) {
+ if (startFraction < 0 || startFraction > 1.0f) {
+ throw new IllegalArgumentException("initialFraction must be " +
+ "between 0 and 1");
+ }
+ throwExceptionIfRunning();
+ this.startFraction = startFraction;
+ }
+
+ /**
+ * Starts the animation
+ * @throws IllegalStateException if animation is already running; this
+ * command may only be run prior to starting the animation or
+ * after the animation has ended
+ */
+ public void start() {
+ throwExceptionIfRunning();
+ hasBegun = false;
+ running = true;
+ // Initialize start time variables to current time
+ startTime = (System.nanoTime() / 1000000) + getStartDelay();
+ if (duration != INFINITE &&
+ ((direction == Direction.FORWARD && startFraction > 0.0f) ||
+ (direction == Direction.BACKWARD && startFraction < 1.0f))) {
+ float offsetFraction = (direction == Direction.FORWARD) ?
+ startFraction : (1.0f - startFraction);
+ long startDelta = (long)(duration * offsetFraction);
+ startTime -= startDelta;
+ }
+ currentStartTime = startTime;
+ timer.start();
+ }
+
+ /**
+ * Returns whether this Animator object is currently running
+ */
+ public boolean isRunning() {
+ return running;
+ }
+
+ /**
+ * This method is optional; animations will always stop on their own
+ * if Animator is provided with appropriate values for
+ * duration and repeatCount in the constructor. But if the application
+ * wants to stop the timer mid-stream, this is the method to call.
+ * This call will result in calls to the <code>end()</code> method
+ * of all TimingTargets of this Animator.
+ * @see #cancel()
+ */
+ public void stop() {
+ timer.stop();
+ end();
+ timeToStop = false;
+ running = false;
+ pauseBeginTime = 0;
+ }
+
+ /**
+ * This method is like the {@link #stop} method, only this one will
+ * not result in a calls to the <code>end()</code> method in all
+ * TimingTargets of this Animation; it simply cancels the Animator
+ * immediately.
+ * @see #stop()
+ */
+ public void cancel() {
+ timer.stop();
+ timeToStop = false;
+ running = false;
+ pauseBeginTime = 0;
+ }
+
+ /**
+ * This method pauses a running animation. No further events are sent to
+ * TimingTargets. A paused animation may be d again by calling the
+ * {@link #resume} method. Pausing a non-running animation has no effect.
+ *
+ * @see #resume()
+ * @see #isRunning()
+ */
+ public void pause() {
+ if (isRunning()) {
+ pauseBeginTime = System.nanoTime();
+ running = false;
+ timer.stop();
+ }
+ }
+
+ /**
+ * This method resumes a paused animation. Resuming an animation that
+ * is not paused has no effect.
+ *
+ * @see #pause()
+ */
+ public void resume() {
+ if (pauseBeginTime > 0) {
+ long pauseDelta = (System.nanoTime() - pauseBeginTime) / 1000000;
+ startTime += pauseDelta;
+ currentStartTime += pauseDelta;
+ timer.start();
+ pauseBeginTime = 0;
+ running = true;
+ }
+ }
+
+ //
+ // TimingTarget implementations
+ // Note that Animator does not actually implement TimingTarget directly;
+ // it does not want to make public methods of these events. But it uses
+ // the same methods internally to propagate the events to all of the
+ // Animator's targets.
+ //
+
+ /**
+ * Internal timingEvent method that sends out the event to all targets
+ */
+ private void timingEvent(float fraction) {
+ synchronized (targets) {
+ for (int i = 0; i < targets.size(); ++i) {
+ TimingTarget target = targets.get(i);
+ target.timingEvent(fraction);
+ }
+ }
+ if (timeToStop) {
+ stop();
+ }
+ }
+
+ /**
+ * Internal begin event that sends out the event to all targets
+ */
+ private void begin() {
+ synchronized (targets) {
+ for (int i = 0; i < targets.size(); ++i) {
+ TimingTarget target = targets.get(i);
+ target.begin();
+ }
+ }
+ }
+
+ /**
+ * Internal end event that sends out the event to all targets
+ */
+ private void end() {
+ synchronized (targets) {
+ for (int i = 0; i < targets.size(); ++i) {
+ TimingTarget target = targets.get(i);
+ target.end();
+ }
+ }
+ }
+
+ /**
+ * Internal repeat event that sends out the event to all targets
+ */
+ private void repeat() {
+ synchronized (targets) {
+ for (int i = 0; i < targets.size(); ++i) {
+ TimingTarget target = targets.get(i);
+ target.repeat();
+ }
+ }
+ }
+
+ /**
+ * This method calculates a new fraction value based on the
+ * acceleration and deceleration settings of Animator. It then
+ * passes this value through the interpolator (by default,
+ * a LinearInterpolator) before returning it to the caller (who
+ * will then call the timingEvent() methods in the TimingTargets
+ * with this fraction).
+ */
+ private float timingEventPreprocessor(float fraction) {
+ // First, take care of acceleration/deceleration factors
+ if (acceleration != 0 || deceleration != 0.0f) {
+ // See the SMIL 2.0 specification for details on this
+ // calculation
+ float oldFraction = fraction;
+ float runRate = 1.0f / (1.0f - acceleration/2.0f -
+ deceleration/2.0f);
+ if (fraction < acceleration) {
+ float averageRunRate = runRate * (fraction / acceleration) / 2;
+ fraction *= averageRunRate;
+ } else if (fraction > (1.0f - deceleration)) {
+ // time spent in deceleration portion
+ float tdec = fraction - (1.0f - deceleration);
+ // proportion of tdec to total deceleration time
+ float pdec = tdec / deceleration;
+ fraction = runRate * (1.0f - ( acceleration / 2) -
+ deceleration + tdec * (2 - pdec) / 2);
+ } else {
+ fraction = runRate * (fraction - (acceleration / 2));
+ }
+ // clamp fraction to [0,1] since above calculations may
+ // cause rounding errors
+ if (fraction < 0) {
+ fraction = 0;
+ } else if (fraction > 1.0f) {
+ fraction = 1.0f;
+ }
+ }
+ // run the result through the current interpolator
+ return interpolator.interpolate(fraction);
+ }
+
+ /**
+ * Returns the total elapsed time for the current animation.
+ * @param currentTime value of current time to use in calculating
+ * elapsed time.
+ * @return the total time elapsed between the time
+ * the Animator started and the supplied currentTime.
+ */
+ public long getTotalElapsedTime(long currentTime) {
+ return (currentTime - startTime);
+ }
+
+ /**
+ * Returns the total elapsed time for the current animation. Calculates
+ * current time.
+ * @return the total time elapsed between the time
+ * the Animator started and the current time.
+ */
+ public long getTotalElapsedTime() {
+ long currentTime = System.nanoTime() / 1000000;
+ return getTotalElapsedTime(currentTime);
+ }
+
+ /**
+ * Returns the elapsed time for the current animation cycle.
+ * @param currentTime value of current time to use in calculating
+ * elapsed time.
+ * @return the time elapsed between the time
+ * this cycle started and the supplied currentTime.
+ */
+ public long getCycleElapsedTime(long currentTime) {
+ return (currentTime - currentStartTime);
+ }
+
+ /**
+ * Returns the elapsed time for the current animation cycle. Calculates
+ * current time.
+ * @return the time elapsed between the time
+ * this cycle started and the current time.
+ */
+ public long getCycleElapsedTime() {
+ long currentTime = System.nanoTime() / 1000000;
+ return getCycleElapsedTime(currentTime);
+ }
+
+ /**
+ * This method calculates and returns the fraction elapsed of the current
+ * cycle based on the current time
+ * @return fraction elapsed of the current animation cycle
+ */
+ public float getTimingFraction() {
+ long currentTime = System.nanoTime() / 1000000;
+ long cycleElapsedTime = getCycleElapsedTime(currentTime);
+ long totalElapsedTime = getTotalElapsedTime(currentTime);
+ double currentCycle = (double)totalElapsedTime / duration;
+ float fraction;
+
+ if (!hasBegun) {
+ // Call begin() first time after calling start()
+ begin();
+ hasBegun = true;
+ }
+ if ((duration != INFINITE) && (repeatCount != INFINITE) &&
+ (currentCycle >= repeatCount)) {
+ // Envelope done: stop based on end behavior
+ switch (endBehavior) {
+ case HOLD:
+ // Make sure we send a final end value
+ if (intRepeatCount) {
+ // If supposed to run integer number of cycles, hold
+ // on integer boundary
+ if (direction == Direction.BACKWARD) {
+ // If we were traveling backward, hold on 0
+ fraction = 0.0f;
+ } else {
+ fraction = 1.0f;
+ }
+ } else {
+ // hold on final value instead
+ fraction = Math.min(1.0f,
+ ((float)cycleElapsedTime / duration));
+ }
+ break;
+ case RESET:
+ // RESET requires setting the final value to the start value
+ fraction = 0.0f;
+ break;
+ default:
+ fraction = 0.0f;
+ // should not reach here
+ break;
+ }
+ timeToStop = true;
+ } else if ((duration != INFINITE) && (cycleElapsedTime > duration)) {
+ // Cycle end: Time to stop or change the behavior of the timer
+ long actualCycleTime = cycleElapsedTime % duration;
+ fraction = (float)actualCycleTime / duration;
+ // Set new start time for this cycle
+ currentStartTime = currentTime - actualCycleTime;
+
+ if (repeatBehavior == RepeatBehavior.REVERSE) {
+ boolean oddCycles =
+ ((int)(cycleElapsedTime / duration) % 2)
+ > 0;
+ if (oddCycles) {
+ // reverse the direction
+ direction = (direction == Direction.FORWARD) ?
+ Direction.BACKWARD :
+ Direction.FORWARD;
+ }
+ if (direction == Direction.BACKWARD) {
+ fraction = 1.0f - fraction;
+ }
+ }
+ repeat();
+ } else {
+ // mid-stream: calculate fraction of animation between
+ // start and end times and send fraction to target
+ fraction = 0.0f;
+ if (duration != INFINITE) {
+ // Only limited duration animations need a fraction
+ fraction = (float)cycleElapsedTime / duration;
+ if (direction == Direction.BACKWARD) {
+ // If this is a reversing cycle, want to know inverse
+ // fraction; how much from start to finish, not
+ // finish to start
+ fraction = (1.0f - fraction);
+ }
+ // Clamp fraction in case timing mechanism caused out of
+ // bounds value
+ fraction = Math.min(fraction, 1.0f);
+ fraction = Math.max(fraction, 0.0f);
+ }
+ }
+ return timingEventPreprocessor(fraction);
+ }
+
+ /**
+ * Sets a new TimingSource that will supply the timing
+ * events to this Animator. Animator uses an internal
+ * TimingSource by default and most developers will probably not
+ * need to change this default behavior. But for those wishing to
+ * supply their own timer, this method can be called to
+ * tell Animator to use a different TimingSource instead. Setting a
+ * new TimingSource implicitly removes this Animator as a listener
+ * to any previously-set TimingSource object.
+ *
+ * @param timer the object that will provide the
+ * timing events to Animator. A value of <code>null</code> is
+ * equivalent to telling Animator to use its default internal
+ * TimingSource object.
+ * @throws IllegalStateException if animation is already running; this
+ * parameter may only be changed prior to starting the animation or
+ * after the animation has ended.
+ */
+ public synchronized void setTimer(TimingSource timer) {
+ throwExceptionIfRunning();
+ if (this.timer != swingTimer) {
+ // Remove this Animator from any previously-set external timer
+ this.timer.removeEventListener(timingSourceTarget);
+ }
+ if (timer == null) {
+ this.timer = swingTimer;
+ } else {
+ this.timer = timer;
+ if (timingSourceTarget == null) {
+ timingSourceTarget = new TimingSourceTarget();
+ }
+ timer.addEventListener(timingSourceTarget);
+ }
+ // sync this new timer with existing timer properties
+ this.timer.setResolution(resolution);
+ this.timer.setStartDelay(startDelay);
+ }
+
+ /**
+ * This package-private class will be called by TimingSource.timingEvent()
+ * when a timer sends in timing events to this Animator.
+ */
+ class TimingSourceTarget implements TimingEventListener {
+ public void timingSourceEvent(TimingSource timingSource) {
+ // Make sure that we are being called by the current timer
+ // and that the animation is actually running
+ if ((timer == timingSource) && running) {
+ timingEvent(getTimingFraction());
+ }
+ }
+ }
+
+ /**
+ * Implementation of internal timer, which uses the Swing Timer class.
+ * Note that we do not bother going through the TimingSource.timingEvent()
+ * class with our timing events; they go through the TimerTarget
+ * ActionListener implementation and then directly to timingEvent(fraction).
+ */
+ private class SwingTimingSource extends TimingSource {
+ Timer timer; // Swing timer
+
+ public SwingTimingSource() {
+ timer = new Timer(resolution, new TimerTarget());
+ timer.setInitialDelay(0);
+ }
+
+ public void start() {
+ timer.start();
+ }
+
+ public void stop() {
+ timer.stop();
+ }
+
+ public void setResolution(int resolution) {
+ timer.setDelay(resolution);
+ }
+
+ public void setStartDelay(int delay) {
+ timer.setInitialDelay(delay);
+ }
+ }
+
+ /**
+ * Internal implementation detail: we happen to use javax.swing.Timer
+ * currently, which sends its timing events to an ActionListener.
+ * This internal private class is our ActionListener that traps
+ * these calls and forwards them to the Animator.timingEvent(fraction)
+ * method.
+ */
+ private class TimerTarget implements ActionListener {
+ public void actionPerformed(ActionEvent e) {
+ timingEvent(getTimingFraction());
+ }
+ }
+
+}
Added: branches/upstream/timingframework/current/org/jdesktop/animation/timing/TimingEventListener.java
===================================================================
--- branches/upstream/timingframework/current/org/jdesktop/animation/timing/TimingEventListener.java (rev 0)
+++ branches/upstream/timingframework/current/org/jdesktop/animation/timing/TimingEventListener.java 2010-11-27 19:07:53 UTC (rev 13103)
@@ -0,0 +1,57 @@
+/**
+ * Copyright (c) 2007, 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.jdesktop.animation.timing;
+
+/**
+ * This interface is implemented by any object wishing to receive events from a
+ * {@link TimingSource} object. The TimingEventListener would be added as a
+ * listener to the TimingSource object via the {@link
+ * TimingSource#addEventListener(TimingEventListener)} method.
+ * <p>
+ * This functionality is handled automatically inside of {@link Animator}. To
+ * use a non-default TimingSource object for Animator, simply call
+ * {@link Animator#setTimer(TimingSource)} and the appropriate listeners
+ * will be set up internally.
+ *
+ * @author Chet
+ */
+public interface TimingEventListener {
+
+ /**
+ * This method is called by the {@link TimingSource} object while the
+ * timer is running.
+ *
+ * @param timingSource the object that generates the timing events.
+ */
+ public void timingSourceEvent(TimingSource timingSource);
+
+}
Added: branches/upstream/timingframework/current/org/jdesktop/animation/timing/TimingSource.java
===================================================================
--- branches/upstream/timingframework/current/org/jdesktop/animation/timing/TimingSource.java (rev 0)
+++ branches/upstream/timingframework/current/org/jdesktop/animation/timing/TimingSource.java 2010-11-27 19:07:53 UTC (rev 13103)
@@ -0,0 +1,137 @@
+/**
+ * Copyright (c) 2007, 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.jdesktop.animation.timing;
+
+import java.util.ArrayList;
+
+/**
+ * This class provides a generic wrapper for arbitrary
+ * Timers that may be used with the Timing Framework.
+ * Animator creates its own internal TimingSource by default,
+ * but an Animator can be directed to use a different
+ * TimingSource by calling {@link Animator#setTimer(TimingSource)}.
+ *
+ * The implementation details of any specific timer may
+ * vary widely, but any timer should be able to expose
+ * the basic capabilities used in this interface. Animator
+ * depends on these capabilities for starting, stopping,
+ * and running any TimingSource.
+ *
+ * The usage of an external TimingSource object for sending in timing
+ * events to an Animator is to implement this interface appropriately,
+ * pass in that object to {@link Animator#setTimer(TimingSource)},
+ * which adds the Animator as a listener to the TimingSource object,
+ * and then send in any later timing events from the object to the
+ * protected method {@link #timingEvent()}, which will send these timing
+ * events to all listeners.
+ *
+ * @author Chet
+ */
+public abstract class TimingSource {
+
+ // listeners that will receive timing events
+ private ArrayList<TimingEventListener> listeners =
+ new ArrayList<TimingEventListener>();
+
+ /**
+ * Starts the TimingSource
+ */
+ public abstract void start();
+
+ /**
+ * Stops the TimingSource
+ */
+ public abstract void stop();
+
+ /**
+ * Sets the delay between callback events. This
+ * will be called by Animator if its
+ * {@link Animator#setResolution(int) setResolution(int)}
+ * method is called. Note that the actual resolution may vary,
+ * according to the resolution of the timer used by the framework as well
+ * as system load and configuration; this value should be seen more as a
+ * minimum resolution than a guaranteed resolution.
+ * @param resolution delay, in milliseconds, between
+ * each timing event callback.
+ * @throws IllegalArgumentException resolution must be >= 0
+ * @see Animator#setResolution(int)
+ */
+ public abstract void setResolution(int resolution);
+
+ /**
+ * Sets delay which should be observed by the
+ * TimingSource after a call to {@link #start()}. Some timers may not be
+ * able to adhere to specific resolution requests
+ * @param delay delay, in milliseconds, to pause before
+ * starting timing events.
+ * @throws IllegalArgumentException resolution must be >= 0
+ * @see Animator#setStartDelay(int)
+ */
+ public abstract void setStartDelay(int delay);
+
+ /**
+ * Adds a TimingEventListener to the set of listeners that
+ * receive timing events from this TimingSource.
+ * @param listener the listener to be added.
+ */
+ public final void addEventListener(TimingEventListener listener) {
+ synchronized(listeners) {
+ if (!listeners.contains(listener)) {
+ listeners.add(listener);
+ }
+ }
+ }
+
+ /**
+ * Removes a TimingEventListener from the set of listeners that
+ * receive timing events from this TimingSource.
+ * @param listener the listener to be removed.
+ */
+ public final void removeEventListener(TimingEventListener listener) {
+ synchronized(listeners) {
+ listeners.remove(listener);
+ }
+ }
+
+
+ /**
+ * Subclasses call this method to post timing events to this
+ * object's {@link TimingEventListener} objects.
+ */
+ protected final void timingEvent() {
+ synchronized(listeners) {
+ for (TimingEventListener listener : listeners) {
+ listener.timingSourceEvent(this);
+ }
+ }
+ }
+}
Added: branches/upstream/timingframework/current/org/jdesktop/animation/timing/TimingTarget.java
===================================================================
--- branches/upstream/timingframework/current/org/jdesktop/animation/timing/TimingTarget.java (rev 0)
+++ branches/upstream/timingframework/current/org/jdesktop/animation/timing/TimingTarget.java 2010-11-27 19:07:53 UTC (rev 13103)
@@ -0,0 +1,78 @@
+/**
+ * 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.jdesktop.animation.timing;
+
+/**
+ * This interface provides the methods which
+ * are called by Animator during the course of a timing
+ * sequence. Applications
+ * that wish to receive timing events will either create a subclass
+ * of TimingTargetAdapter and override or they can create or use
+ * an implementation of TimingTarget. A TimingTarget can be passed
+ * into the constructor of Animator or set later with the
+ * {@link Animator#addTarget(TimingTarget)}
+ * method. Any Animator may have multiple TimingTargets.
+ */
+public interface TimingTarget {
+
+ /**
+ * This method will receive all of the timing events from an Animator
+ * during an animation. The fraction is the percent elapsed (0 to 1)
+ * of the current animation cycle.
+ * @param fraction the fraction of completion between the start and
+ * end of the current cycle. Note that on reversing cycles
+ * ({@link Animator.Direction#BACKWARD}) the fraction decreases
+ * from 1.0 to 0 on backwards-running cycles. Note also that animations
+ * with a duration of {@link Animator#INFINITE INFINITE} will call
+ * timingEvent with an undefined value for fraction, since there is
+ * no fraction that makes sense if the animation has no defined length.
+ * @see Animator.Direction
+ */
+ public void timingEvent(float fraction);
+
+ /**
+ * Called when the Animator's animation begins. This provides a chance
+ * for targets to perform any setup required at animation start time.
+ */
+ public void begin();
+
+ /**
+ * Called when the Animator's animation ends
+ */
+ public void end();
+
+ /**
+ * Called when the Animator repeats the animation cycle
+ */
+ public void repeat();
+
+}
Added: branches/upstream/timingframework/current/org/jdesktop/animation/timing/TimingTargetAdapter.java
===================================================================
--- branches/upstream/timingframework/current/org/jdesktop/animation/timing/TimingTargetAdapter.java (rev 0)
+++ branches/upstream/timingframework/current/org/jdesktop/animation/timing/TimingTargetAdapter.java 2010-11-27 19:07:53 UTC (rev 13103)
@@ -0,0 +1,78 @@
+/**
+ * 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.jdesktop.animation.timing;
+
+/**
+ * Implements the {@link TimingTarget} interface, providing stubs for all
+ * TimingTarget methods. Subclasses may extend this adapter rather than
+ * implementing the TimingTarget interface if they only care about a
+ * subset of the events that TimingTarget provides. For example,
+ * sequencing animations may only require monitoring the
+ * {@link TimingTarget#end} method, so subclasses of this adapter
+ * may ignore the other methods such as timingEvent.
+ *
+ * @author Chet
+ */
+public class TimingTargetAdapter implements TimingTarget {
+
+ /**
+ * This method will receive all of the timing events from an Animator
+ * during an animation. The fraction is the percent elapsed (0 to 1)
+ * of the current animation cycle.
+ * @param fraction the fraction of completion between the start and
+ * end of the current cycle. Note that on reversing cycles
+ * ({@link Animator.Direction#BACKWARD}) the fraction decreases
+ * from 1.0 to 0 on backwards-running cycles. Note also that animations
+ * with a duration of {@link Animator#INFINITE INFINITE} will call
+ * timingEvent with an undefined value for fraction, since there is
+ * no fraction that makes sense if the animation has no defined length.
+ * @see Animator.Direction
+ */
+ public void timingEvent(float fraction) {}
+
+ /**
+ * Called when the Animator's animation begins. This provides a chance
+ * for targets to perform any setup required at animation start time.
+ */
+ public void begin() {}
+
+ /**
+ * Called when the Animator's animation ends
+ */
+ public void end() {}
+
+ /**
+ * Called when the Animator repeats the animation cycle
+ */
+ public void repeat() {}
+
+}
Added: branches/upstream/timingframework/current/org/jdesktop/animation/timing/interpolation/DiscreteInterpolator.java
===================================================================
--- branches/upstream/timingframework/current/org/jdesktop/animation/timing/interpolation/DiscreteInterpolator.java (rev 0)
+++ branches/upstream/timingframework/current/org/jdesktop/animation/timing/interpolation/DiscreteInterpolator.java 2010-11-27 19:07:53 UTC (rev 13103)
@@ -0,0 +1,86 @@
+/**
+ * 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.jdesktop.animation.timing.interpolation;
+
+/**
+ * This class implements the Interpolator interface. It should
+ * be used in cases where a "discrete" animation is desired. A
+ * discrete animation is defined to be one where the values during
+ * an animation do not change smoothly between the boundary values,
+ * but suddenly, at the boundary points. For example, a discrete animation
+ * with KeyFrames where the KeyTimes are {0, .5, 1.0} and the KeyValues
+ * are (0, 1, 2} would, during the animation, retain the value of 0 until
+ * half-way through the animation and 1 through the rest of the animation.
+ * <p>
+ * Because there is no variation to this class, it is a singleton and
+ * is referenced by using the {@link #getInstance} static method.
+ *
+ * @author Chet
+ */
+public final class DiscreteInterpolator implements Interpolator {
+
+ private static DiscreteInterpolator instance = null;
+
+ private DiscreteInterpolator() {}
+
+ /**
+ * Returns the single DiscreteInterpolator object
+ */
+ public static DiscreteInterpolator getInstance() {
+ if (instance == null) {
+ instance = new DiscreteInterpolator();
+ }
+ return instance;
+ }
+
+ /**
+ * This method always returns 0 for inputs less than 1,
+ * which will force users of this
+ * interpolation to assign a value equal to the value at the beginning
+ * of this timing interval, which is the desired behavior for discrete
+ * animations. An input of 1 will return 1, since this means the
+ * end of the current interval (and start to the next interval).
+ * @param fraction a value between 0 and 1, representing the elapsed
+ * fraction of a time interval (either an entire animation cycle or an
+ * interval between two KeyTimes, depending on where this Interpolator has
+ * been set)
+ * @return number representing the start of the current interval, usually
+ * 0, but if <code>fracton == 0</code>, returns 1.
+ */
+ public float interpolate(float fraction) {
+ if (fraction < 1.0f) {
+ return 0;
+ }
+ return 1.0f;
+ }
+
+}
Added: branches/upstream/timingframework/current/org/jdesktop/animation/timing/interpolation/Evaluator.java
===================================================================
--- branches/upstream/timingframework/current/org/jdesktop/animation/timing/interpolation/Evaluator.java (rev 0)
+++ branches/upstream/timingframework/current/org/jdesktop/animation/timing/interpolation/Evaluator.java 2010-11-27 19:07:53 UTC (rev 13103)
@@ -0,0 +1,399 @@
+/**
+ * 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.jdesktop.animation.timing.interpolation;
+
+import java.awt.Color;
+import java.awt.geom.Arc2D;
+import java.awt.geom.CubicCurve2D;
+import java.awt.geom.Dimension2D;
+import java.awt.geom.Ellipse2D;
+import java.awt.geom.Line2D;
+import java.awt.geom.Point2D;
+import java.awt.geom.QuadCurve2D;
+import java.awt.geom.Rectangle2D;
+import java.awt.geom.RoundRectangle2D;
+import java.lang.reflect.Constructor;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * This class is used by KeyValues to calculate intermediate values for
+ * specific types.
+ * This class has built-in support for the following data types:
+ * <ul>
+ * <li> java.lang.Byte
+ * <li> java.lang.Short
+ * <li> java.lang.Integer
+ * <li> java.lang.Long
+ * <li> java.lang.Float
+ * <li> java.lang.Double
+ * <li> java.awt.Color
+ * <li> java.awt.geom.Point2D
+ * <li> java.awt.geom.Line2D
+ * <li> java.awt.geom.Dimension2D
+ * <li> java.awt.geom.Rectangle2D
+ * <li> java.awt.geom.RoundRectangle2D
+ * <li> java.awt.geom.Ellipse2D
+ * <li> java.awt.geom.Arc2D
+ * <li> java.awt.geom.QuadCurve2D
+ * <li> java.awt.geom.CubicCurve2D
+ * </ul>
+ *
+ * @author Chet
+ */
+public abstract class Evaluator<T> {
+
+ /**
+ * HashMap that holds all registered evaluators
+ */
+ private static final Map<Class<?>, Class<? extends Evaluator>>
+ impls = new HashMap<Class<?>,
+ Class<? extends Evaluator>>();
+
+ /**
+ * Static registration of pre-defined evaluators
+ */
+ static {
+ impls.put(Byte.class, EvaluatorByte.class);
+ impls.put(Short.class, EvaluatorShort.class);
+ impls.put(Integer.class, EvaluatorInteger.class);
+ impls.put(Long.class, EvaluatorLong.class);
+ impls.put(Float.class, EvaluatorFloat.class);
+ impls.put(Double.class, EvaluatorDouble.class);
+ impls.put(Color.class, EvaluatorColor.class);
+ impls.put(Point2D.class, EvaluatorPoint2D.class);
+ impls.put(Line2D.class, EvaluatorLine2D.class);
+ impls.put(Dimension2D.class, EvaluatorDimension2D.class);
+ impls.put(Rectangle2D.class, EvaluatorRectangle2D.class);
+ impls.put(RoundRectangle2D.class, EvaluatorRoundRectangle2D.class);
+ impls.put(Ellipse2D.class, EvaluatorEllipse2D.class);
+ impls.put(Arc2D.class, EvaluatorArc2D.class);
+ impls.put(QuadCurve2D.class, EvaluatorQuadCurve2D.class);
+ impls.put(CubicCurve2D.class, EvaluatorCubicCurve2D.class);
+ }
+
+ private static void register(Class<?> type,
+ Class<? extends Evaluator> impl)
+ {
+ impls.put(type, impl);
+ }
+
+ private static void deregister(Class<?> type) {
+ impls.remove(type);
+ }
+
+ static <T> Evaluator<T> create(Class<?> type) {
+ Class<? extends Evaluator> interpClass = null;
+ for (Class<?> klass : impls.keySet()) {
+ if (klass.isAssignableFrom(type)) {
+ interpClass = impls.get(klass);
+ break;
+ }
+ }
+ if (interpClass == null) {
+ throw new IllegalArgumentException("No Evaluator" +
+ " can be found for type " + type + "; consider using" +
+ " different types for your values or supplying a custom" +
+ " Evaluator");
+ }
+ try {
+ Constructor<? extends Evaluator> ctor =
+ interpClass.getConstructor();
+ return (Evaluator<T>)ctor.newInstance();
+ } catch (Exception e) {
+ throw new IllegalArgumentException("Problem constructing " +
+ "appropriate Evaluator for type " + type +
+ ":", e);
+ }
+ }
+
+ /**
+ * Abstract method to evaluate between two boundary values. Built-in
+ * implementations all use linear parametric evaluation:
+ * <pre>
+ * v = v0 + (v1 - v0) * fraction
+ * </pre>
+ * Extenders of Evaluator will need to override this method
+ * and do something similar for their own types. Note that this
+ * mechanism may be used to create non-linear interpolators for
+ * specific value types, although it may besimpler to just use
+ * the linear/parametric interpolation
+ * technique here and perform non-linear interpolation through
+ * custom Interpolators rather than perform custom calculations in
+ * this method; the point of this class is to allow calculations with
+ * new/unknown types, not to provide another mechanism for non-linear
+ * interpolation.
+ */
+ public abstract T evaluate(T v0, T v1, float fraction);
+}
+
+class EvaluatorByte extends Evaluator<Byte> {
+ public EvaluatorByte() {}
+ public Byte evaluate(Byte v0, Byte v1,
+ float fraction)
+ {
+ return (byte)(v0 + (byte)((v1 - v0) * fraction));
+ }
+}
+
+class EvaluatorShort extends Evaluator<Short> {
+ public EvaluatorShort() {}
+ public Short evaluate(Short v0, Short v1,
+ float fraction)
+ {
+ return (short)(v0 + (short)((v1 - v0) * fraction));
+ }
+}
+
+class EvaluatorInteger extends Evaluator<Integer> {
+ public EvaluatorInteger() {}
+ public Integer evaluate(Integer v0, Integer v1,
+ float fraction)
+ {
+ return v0 + (int)((v1 - v0) * fraction);
+ }
+}
+
+class EvaluatorLong extends Evaluator<Long> {
+ public EvaluatorLong() {}
+ public Long evaluate(Long v0, Long v1,
+ float fraction)
+ {
+ return v0 + (long)((v1 - v0) * fraction);
+ }
+}
+
+class EvaluatorFloat extends Evaluator<Float> {
+ public EvaluatorFloat() {}
+ public Float evaluate(Float v0, Float v1,
+ float fraction)
+ {
+ return v0 + ((v1 - v0) * fraction);
+ }
+}
+
+class EvaluatorDouble extends Evaluator<Double> {
+ public EvaluatorDouble() {}
+ public Double evaluate(Double v0, Double v1,
+ float fraction)
+ {
+ return v0 + ((v1 - v0) * fraction);
+ }
+}
+
+class EvaluatorColor extends Evaluator<Color> {
+ public EvaluatorColor() {}
+ public Color evaluate(Color v0, Color v1,
+ float fraction)
+ {
+ int r = v0.getRed() +
+ (int)((v1.getRed() - v0.getRed()) * fraction + 0.5f);
+ int g = v0.getGreen() +
+ (int)((v1.getGreen() - v0.getGreen()) * fraction + 0.5f);
+ int b = v0.getBlue() +
+ (int)((v1.getBlue() - v0.getBlue()) * fraction + 0.5f);
+ int a = v0.getAlpha() +
+ (int)((v1.getAlpha() - v0.getAlpha()) * fraction + 0.5f);
+ Color value = new Color(r, g, b, a);
+ return value;
+ }
+}
+
+class EvaluatorPoint2D extends Evaluator<Point2D> {
+ // REMIND: apply this technique to other classes...
+ private Point2D value;
+ public EvaluatorPoint2D() {}
+ public Point2D evaluate(Point2D v0, Point2D v1,
+ float fraction)
+ {
+ if (value == null) {
+ // TODO: Note that future calls to this Evaluator may
+ // use a different subclass of Point2D, so the precision of the
+ // result may vary because we are caching a clone of
+ // the first instance we received
+ value = (Point2D)v0.clone();
+ }
+ double x = v0.getX() + ((v1.getX() - v0.getX()) * fraction);
+ double y = v0.getY() + ((v1.getY() - v0.getY()) * fraction);
+ value.setLocation(x, y);
+ return value;
+ }
+}
+
+class EvaluatorLine2D extends Evaluator<Line2D> {
+ public EvaluatorLine2D() {}
+ public Line2D evaluate(Line2D v0, Line2D v1,
+ float fraction)
+ {
+ double x1 = v0.getX1() + ((v1.getX1() - v0.getX1()) * fraction);
+ double y1 = v0.getY1() + ((v1.getY1() - v0.getY1()) * fraction);
+ double x2 = v0.getX2() + ((v1.getX2() - v0.getX2()) * fraction);
+ double y2 = v0.getY2() + ((v1.getY2() - v0.getY2()) * fraction);
+ Line2D value = (Line2D)v0.clone();
+ value.setLine(x1, y1, x2, y2);
+ return value;
+ }
+}
+
+class EvaluatorDimension2D extends Evaluator<Dimension2D> {
+ public EvaluatorDimension2D() {}
+ public Dimension2D evaluate(Dimension2D v0, Dimension2D v1,
+ float fraction)
+ {
+ double w = v0.getWidth() +
+ ((v1.getWidth() - v0.getWidth()) * fraction);
+ double h = v0.getHeight() +
+ ((v1.getHeight() - v0.getHeight()) * fraction);
+ Dimension2D value = (Dimension2D)v0.clone();
+ value.setSize(w, h);
+ return value;
+ }
+}
+
+class EvaluatorRectangle2D extends Evaluator<Rectangle2D> {
+ public EvaluatorRectangle2D() {}
+ public Rectangle2D evaluate(Rectangle2D v0, Rectangle2D v1,
+ float fraction)
+ {
+ double x = v0.getX() + ((v1.getX() - v0.getX()) * fraction);
+ double y = v0.getY() + ((v1.getY() - v0.getY()) * fraction);
+ double w = v0.getWidth() +
+ ((v1.getWidth() - v0.getWidth()) * fraction);
+ double h = v0.getHeight() +
+ ((v1.getHeight() - v0.getHeight()) * fraction);
+ Rectangle2D value = (Rectangle2D)v0.clone();
+ value.setRect(x, y, w, h);
+ return value;
+ }
+}
+
+class EvaluatorRoundRectangle2D extends Evaluator<RoundRectangle2D> {
+ public EvaluatorRoundRectangle2D() {}
+ public RoundRectangle2D evaluate(RoundRectangle2D v0,
+ RoundRectangle2D v1,
+ float fraction)
+ {
+ double x = v0.getX() + ((v1.getX() - v0.getX()) * fraction);
+ double y = v0.getY() + ((v1.getY() - v0.getY()) * fraction);
+ double w = v0.getWidth() +
+ ((v1.getWidth() - v0.getWidth()) * fraction);
+ double h = v0.getHeight() +
+ ((v1.getHeight() - v0.getHeight()) * fraction);
+ double arcw = v0.getArcWidth() +
+ ((v1.getArcWidth() - v0.getArcWidth()) * fraction);
+ double arch = v0.getArcHeight() +
+ ((v1.getArcHeight() - v0.getArcHeight()) * fraction);
+ RoundRectangle2D value = (RoundRectangle2D)v0.clone();
+ value.setRoundRect(x, y, w, h, arcw, arch);
+ return value;
+ }
+}
+
+class EvaluatorEllipse2D extends Evaluator<Ellipse2D> {
+ public EvaluatorEllipse2D() {}
+ public Ellipse2D evaluate(Ellipse2D v0, Ellipse2D v1,
+ float fraction)
+ {
+ double x = v0.getX() + ((v1.getX() - v0.getX()) * fraction);
+ double y = v0.getY() + ((v1.getY() - v0.getY()) * fraction);
+ double w = v0.getWidth() +
+ ((v1.getWidth() - v0.getWidth()) * fraction);
+ double h = v0.getHeight() +
+ ((v1.getHeight() - v0.getHeight()) * fraction);
+ Ellipse2D value = (Ellipse2D)v0.clone();
+ value.setFrame(x, y, w, h);
+ return value;
+ }
+}
+
+class EvaluatorArc2D extends Evaluator<Arc2D> {
+ public EvaluatorArc2D() {}
+ public Arc2D evaluate(Arc2D v0, Arc2D v1,
+ float fraction)
+ {
+ double x = v0.getX() + ((v1.getX() - v0.getX()) * fraction);
+ double y = v0.getY() + ((v1.getY() - v0.getY()) * fraction);
+ double w = v0.getWidth() +
+ ((v1.getWidth() - v0.getWidth()) * fraction);
+ double h = v0.getHeight() +
+ ((v1.getHeight() - v0.getHeight()) * fraction);
+ double start = v0.getAngleStart() +
+ ((v1.getAngleStart() - v0.getAngleStart()) * fraction);
+ double extent = v0.getAngleExtent() +
+ ((v1.getAngleExtent() - v0.getAngleExtent()) * fraction);
+ Arc2D value = (Arc2D)v0.clone();
+ value.setArc(x, y, w, h, start, extent, v0.getArcType());
+ return value;
+ }
+}
+
+class EvaluatorQuadCurve2D extends Evaluator<QuadCurve2D> {
+ public EvaluatorQuadCurve2D() {}
+ public QuadCurve2D evaluate(QuadCurve2D v0, QuadCurve2D v1,
+ float fraction)
+ {
+ double x1 = v0.getX1() + ((v1.getX1() - v0.getX1()) * fraction);
+ double y1 = v0.getY1() + ((v1.getY1() - v0.getY1()) * fraction);
+ double x2 = v0.getX2() + ((v1.getX2() - v0.getX2()) * fraction);
+ double y2 = v0.getY2() + ((v1.getY2() - v0.getY2()) * fraction);
+ double ctrlx = v0.getCtrlX() +
+ ((v1.getCtrlX() - v0.getCtrlX()) * fraction);
+ double ctrly = v0.getCtrlY() +
+ ((v1.getCtrlY() - v0.getCtrlY()) * fraction);
+ QuadCurve2D value = (QuadCurve2D)v0.clone();
+ value.setCurve(x1, y1, ctrlx, ctrly, x2, y2);
+ return value;
+ }
+}
+
+class EvaluatorCubicCurve2D extends Evaluator<CubicCurve2D> {
+ public EvaluatorCubicCurve2D() {}
+ public CubicCurve2D evaluate(CubicCurve2D v0, CubicCurve2D v1,
+ float fraction)
+ {
+ double x1 = v0.getX1() + ((v1.getX1() - v0.getX1()) * fraction);
+ double y1 = v0.getY1() + ((v1.getY1() - v0.getY1()) * fraction);
+ double x2 = v0.getX2() + ((v1.getX2() - v0.getX2()) * fraction);
+ double y2 = v0.getY2() + ((v1.getY2() - v0.getY2()) * fraction);
+ double ctrlx1 = v0.getCtrlX1() +
+ ((v1.getCtrlX1() - v0.getCtrlX1()) * fraction);
+ double ctrly1 = v0.getCtrlY1() +
+ ((v1.getCtrlY1() - v0.getCtrlY1()) * fraction);
+ double ctrlx2 = v0.getCtrlX2() +
+ ((v1.getCtrlX2() - v0.getCtrlX2()) * fraction);
+ double ctrly2 = v0.getCtrlY2() +
+ ((v1.getCtrlY2() - v0.getCtrlY2()) * fraction);
+ CubicCurve2D value = (CubicCurve2D)v0.clone();
+ value.setCurve(x1, y1, ctrlx1, ctrly1, ctrlx2, ctrly2, x2, y2);
+ return value;
+ }
+}
Added: branches/upstream/timingframework/current/org/jdesktop/animation/timing/interpolation/Interpolator.java
===================================================================
--- branches/upstream/timingframework/current/org/jdesktop/animation/timing/interpolation/Interpolator.java (rev 0)
+++ branches/upstream/timingframework/current/org/jdesktop/animation/timing/interpolation/Interpolator.java 2010-11-27 19:07:53 UTC (rev 13103)
@@ -0,0 +1,59 @@
+/**
+ * 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.jdesktop.animation.timing.interpolation;
+
+/**
+ * Interface that defines the single {@link #interpolate(float)} method.
+ * This interface is implemented by built-in interpolators.
+ * Applications may choose to implement
+ * their own Interpolator to get custom interpolation behavior.
+ *
+ * @author Chet
+ */
+public interface Interpolator {
+
+ /**
+ * This function takes an input value between 0 and 1 and returns
+ * another value, also between 0 and 1. The purpose of the function
+ * is to define how time (represented as a (0-1) fraction of the
+ * duration of an animation) is altered to derive different value
+ * calculations during an animation.
+ * @param fraction a value between 0 and 1, representing the elapsed
+ * fraction of a time interval (either an entire animation cycle or an
+ * interval between two KeyTimes, depending on where this Interpolator has
+ * been set)
+ * @return a value between 0 and 1. Values outside of this boundary may
+ * be clamped to the interval [0,1] and cause undefined results.
+ */
+ public float interpolate(float fraction);
+
+}
Added: branches/upstream/timingframework/current/org/jdesktop/animation/timing/interpolation/KeyFrames.java
===================================================================
--- branches/upstream/timingframework/current/org/jdesktop/animation/timing/interpolation/KeyFrames.java (rev 0)
+++ branches/upstream/timingframework/current/org/jdesktop/animation/timing/interpolation/KeyFrames.java 2010-11-27 19:07:53 UTC (rev 13103)
@@ -0,0 +1,213 @@
+/**
+ * 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.jdesktop.animation.timing.interpolation;
+
+import java.lang.reflect.Method;
+import org.jdesktop.animation.timing.*;
+
+/**
+ *
+ * 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, (Interpolator)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, (Interpolator)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,
+ Interpolator... 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, Interpolator... interpolators) {
+ init(keyValues, null, interpolators);
+ }
+
+ /**
+ * Utility function called by constructors to perform common
+ * initialization chores
+ */
+ private void init(KeyValues keyValues, KeyTimes keyTimes,
+ Interpolator... 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);
+ }
+
+ 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].
+ */
+ 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);
+ }
+
+}
Added: branches/upstream/timingframework/current/org/jdesktop/animation/timing/interpolation/KeyInterpolators.java
===================================================================
--- branches/upstream/timingframework/current/org/jdesktop/animation/timing/interpolation/KeyInterpolators.java (rev 0)
+++ branches/upstream/timingframework/current/org/jdesktop/animation/timing/interpolation/KeyInterpolators.java 2010-11-27 19:07:53 UTC (rev 13103)
@@ -0,0 +1,67 @@
+/**
+ * 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.jdesktop.animation.timing.interpolation;
+
+import java.util.ArrayList;
+
+/**
+ *
+ * @author Chet
+ */
+class KeyInterpolators {
+
+ private ArrayList<Interpolator> interpolators = new ArrayList<Interpolator>();
+
+ /**
+ * Creates a new instance of KeyInterpolators
+ */
+ KeyInterpolators(int numIntervals, Interpolator... interpolators) {
+ if (interpolators == null || interpolators[0] == null) {
+ for (int i = 0; i < numIntervals; ++i) {
+ this.interpolators.add(LinearInterpolator.getInstance());
+ }
+ } 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).interpolate(fraction);
+ }
+
+}
Added: branches/upstream/timingframework/current/org/jdesktop/animation/timing/interpolation/KeyTimes.java
===================================================================
--- branches/upstream/timingframework/current/org/jdesktop/animation/timing/interpolation/KeyTimes.java (rev 0)
+++ branches/upstream/timingframework/current/org/jdesktop/animation/timing/interpolation/KeyTimes.java 2010-11-27 19:07:53 UTC (rev 13103)
@@ -0,0 +1,106 @@
+/**
+ * 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.jdesktop.animation.timing.interpolation;
+
+import java.util.ArrayList;
+import org.jdesktop.animation.timing.*;
+
+/**
+ * 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<Float> times = new ArrayList<Float>();
+
+ /**
+ * 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);
+ }
+}
\ No newline at end of file
Added: branches/upstream/timingframework/current/org/jdesktop/animation/timing/interpolation/KeyValues.java
===================================================================
--- branches/upstream/timingframework/current/org/jdesktop/animation/timing/interpolation/KeyValues.java (rev 0)
+++ branches/upstream/timingframework/current/org/jdesktop/animation/timing/interpolation/KeyValues.java 2010-11-27 19:07:53 UTC (rev 13103)
@@ -0,0 +1,188 @@
+/**
+ * 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.jdesktop.animation.timing.interpolation;
+
+import java.awt.Point;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * 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.
+ * <p>
+ * 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.
+ * <p>
+ * This class has built-in support for various known types, as defined
+ * in {@link Evaluator}.
+ * <p>
+ * 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<T> {
+
+ private final List<T> values = new ArrayList<T>();
+ private final Evaluator<T> 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 <T> KeyValues<T> 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 <T> KeyValues<T> create(Evaluator evaluator, T... params) {
+ return new KeyValues(evaluator, params);
+ }
+
+ /**
+ * Private constructor, called by factory method
+ */
+ private KeyValues(T... params) {
+ this(Evaluator.create(params.getClass().getComponentType()),
+ params);
+ }
+
+ /**
+ * Private constructor, called by factory method
+ */
+ private KeyValues(Evaluator 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.evaluate(v0, v1, fraction);
+ }
+ return value;
+ }
+}
Added: branches/upstream/timingframework/current/org/jdesktop/animation/timing/interpolation/LinearInterpolator.java
===================================================================
--- branches/upstream/timingframework/current/org/jdesktop/animation/timing/interpolation/LinearInterpolator.java (rev 0)
+++ branches/upstream/timingframework/current/org/jdesktop/animation/timing/interpolation/LinearInterpolator.java 2010-11-27 19:07:53 UTC (rev 13103)
@@ -0,0 +1,76 @@
+/**
+ * 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.jdesktop.animation.timing.interpolation;
+
+import org.jdesktop.animation.timing.*;
+
+/**
+ * This class implements the Interpolator interface by providing a
+ * simple interpolate function that simply returns the value that
+ * it was given. The net effect is that callers will end up calculating
+ * values linearly during intervals.
+ * <p>
+ * Because there is no variation to this class, it is a singleton and
+ * is referenced by using the {@link #getInstance} static method.
+ *
+ * @author Chet
+ */
+public final class LinearInterpolator implements Interpolator {
+
+ private static LinearInterpolator instance = null;
+
+ private LinearInterpolator() {}
+
+ /**
+ * Returns the single DiscreteInterpolator object
+ */
+ public static LinearInterpolator getInstance() {
+ if (instance == null) {
+ instance = new LinearInterpolator();
+ }
+ return instance;
+ }
+
+ /**
+ * This method always returns the value it was given, which will cause
+ * callers to calculate a linear interpolation between boundary values.
+ * @param fraction a value between 0 and 1, representing the elapsed
+ * fraction of a time interval (either an entire animation cycle or an
+ * interval between two KeyTimes, depending on where this Interpolator has
+ * been set)
+ * @return the same value passed in as <code>fraction</code>
+ */
+ public float interpolate(float fraction) {
+ return fraction;
+ }
+
+}
Added: branches/upstream/timingframework/current/org/jdesktop/animation/timing/interpolation/PropertySetter.java
===================================================================
--- branches/upstream/timingframework/current/org/jdesktop/animation/timing/interpolation/PropertySetter.java (rev 0)
+++ branches/upstream/timingframework/current/org/jdesktop/animation/timing/interpolation/PropertySetter.java 2010-11-27 19:07:53 UTC (rev 13103)
@@ -0,0 +1,376 @@
+/**
+ * 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.jdesktop.animation.timing.interpolation;
+
+import java.beans.PropertyDescriptor;
+import java.lang.reflect.Method;
+import org.jdesktop.animation.timing.Animator;
+import org.jdesktop.animation.timing.TimingTargetAdapter;
+
+/**
+ * This class enables automating animation of object properties.
+ * The class is a TimingTarget, and should be used as a target of
+ * timing events from an Animator. These events will be used to
+ * change a specified property over time, according to how the
+ * PropertySetter is constructed.
+ * <p>
+ * For example, here is an animation of the "background" property
+ * of some object "obj" from blue to red over a period of one second:
+ * <pre>
+ * PropertySetter ps = new PropertySetter(obj, "background", Color.BLUE,
+ * Color.RED);
+ * Animator anim = new Animator(1000, ps);
+ * anim.start();
+ * </pre>
+ * Here is the same animation, created using one of the utility
+ * factory methods that returns an animator:
+ * <pre>
+ * Animator animator = PropertySetter.createAnimator(1000, obj, "background",
+ * Color.BLUE, Color.RED);
+ * anim.start();
+ * </pre>
+ * <p>
+ * More complex animations can be created by passing in multiple values
+ * for the property to take on, for example:
+ * <pre>
+ * Animator animator = PropertySetter.createAnimator(1000, obj, "background",
+ * Color.BLUE, Color.RED,
+ * Color.GREEN);
+ * anim.start();
+ * </pre>
+ * It is also possible to define more involved and tightly-controlled
+ * steps in the animation, including the times between the values and
+ * how the values are interpolated by using the constructor that takes
+ * a {@link KeyFrames} object. KeyFrames defines the fractional times at which
+ * an object takes on specific values, the values to assume at those times,
+ * and the method of interpolation between those values. For example,
+ * here is the same animation as above, specified through KeyFrames, where the
+ * RED color will be set 10% of the way through the animation (note that
+ * we are not setting an Interpolator, so the timing intervals will use the
+ * default LinearInterpolator):
+ * <pre>
+ * KeyValues vals = KeyValues.create(Color.BLUE, Color.RED, Color.GREEN);
+ * KeyTimes times = new KeyTimes(0.0f, .1f, 1.0f);
+ * KeyFrames frames = new KeyFrames(vals, times);
+ * Animator animator = PropertySetter.createAnimator(1000, obj, "background",
+ * frames);
+ * anim.start();
+ * </pre>
+ *
+ * @author Chet
+ */
+public class PropertySetter extends TimingTargetAdapter {
+
+ private Object object;
+ private String propertyName;
+ private KeyFrames keyFrames;
+ private Method propertySetter;
+ private Method propertyGetter;
+
+ /**
+ * Utility method that constructs a PropertySetter and an Animator using
+ * that PropertySetter and returns the Animator
+ * @param duration the duration, in milliseconds, of the animation
+ * @param object the object whose property will be animated
+ * @param propertyName the name of the property to be animated. For
+ * any propertyName "foo" there must be an accessible "setFoo" method
+ * on the object. If only one value is supplied in creating the
+ * KeyValues for the keyFrames, the animation
+ * will also need a "getFoo" method.
+ * @param keyFrames the fractional times, values, and interpolation
+ * to be used in calculating the values set on the object's property.
+ * @throws IllegalArgumentException if appropriate set/get methods
+ * cannot be found for propertyName.
+ */
+ public static Animator createAnimator(int duration, Object object,
+ String propertyName, KeyFrames keyFrames) {
+ PropertySetter ps = new PropertySetter(object, propertyName, keyFrames);
+ Animator animator = new Animator(duration, ps);
+ return animator;
+ }
+
+ /**
+ * Utility method that constructs a PropertySetter and an Animator using
+ * that PropertySetter and returns the Animator
+ * @param duration the duration, in milliseconds, of the animation
+ * @param object the object whose property will be animated
+ * @param propertyName the name of the property to be animated. For
+ * any propertyName "foo" there must be an accessible "setFoo" method
+ * on the object. If only one value is supplied in creating the
+ * KeyValues for the keyFrames, the animation
+ * will also need a "getFoo" method.
+ * @param params the values that the object will take on during the
+ * animation. Internally, a KeyFrames object will be created that
+ * will use times that split the total duration evenly. Supplying
+ * only one value for params implies that this is a "to" animation
+ * whose intial value will be determined dynamically when the animation
+ * starts.
+ * @throws IllegalArgumentException if appropriate set/get methods
+ * cannot be found for propertyName.
+ */
+ public static <T> Animator createAnimator(int duration,
+ Object object, String propertyName, T... params) {
+ PropertySetter ps = new PropertySetter(object, propertyName, params);
+ Animator animator = new Animator(duration, ps);
+ return animator;
+ }
+
+ /**
+ * Utility method that constructs a PropertySetter and an Animator using
+ * that PropertySetter and returns the Animator
+ *
+ * @param duration the duration, in milliseconds, of the animation
+ * @param object the object whose property will be animated
+ * @param propertyName the name of the property to be animated. For
+ * any propertyName "foo" there must be an accessible "setFoo" method
+ * on the object. If only one value is supplied in creating the
+ * KeyValues for the keyFrames, the animation
+ * will also need a "getFoo" method.
+ * @param evaluator KeyValues knows how to calculate intermediate values
+ * for many built-in types, but if you want to supply values in
+ * types not understood by KeyValues, you will need to supply your
+ * own Evaluator.
+ * @param params the values that the object will take on during the
+ * animation. Internally, a KeyFrames object will be created that
+ * will use times that split the total duration evenly. Supplying
+ * only one value for params implies that this is a "to" animation
+ * whose intial value will be determined dynamically when the animation
+ * starts.
+ * @throws IllegalArgumentException if appropriate set/get methods
+ * cannot be found for propertyName.
+ */
+ public static <T> Animator createAnimator(int duration,
+ Object object, String propertyName,
+ Evaluator evaluator, T... params) {
+ PropertySetter ps = new PropertySetter(object, propertyName, evaluator,
+ params);
+ Animator animator = new Animator(duration, ps);
+ return animator;
+ }
+
+ /**
+ * Constructor for a PropertySetter where the values the propert
+ * takes on during the animation are specified in a {@link KeyFrames}
+ * object.
+ * @param object the object whose property will be animated
+ * @param propertyName the name of the property to be animated. For
+ * any propertyName "foo" there must be an accessible "setFoo" method
+ * on the object. If only one value is supplied in creating the
+ * KeyValues for the keyFrames, the animation
+ * will also need a "getFoo" method.
+ * @param keyFrames the fractional times, values, and interpolation
+ * to be used in calculating the values set on the object's property.
+ * @throws IllegalArgumentException if appropriate set/get methods
+ * cannot be found for propertyName.
+ */
+ public PropertySetter(Object object, String propertyName,
+ KeyFrames keyFrames) {
+ this.object = object;
+ this.propertyName = propertyName;
+ this.keyFrames = keyFrames;
+ try {
+ setupMethodInfo();
+ } catch (NoSuchMethodException e) {
+ throw new IllegalArgumentException("Bad property name (" +
+ propertyName +"): could not find " +
+ "an appropriate setter or getter method for that property");
+ }
+ }
+
+ /**
+ * Constructor for a PropertySetter where the values the propert
+ * takes on during the animation are specified in a {@link KeyFrames}
+ * object.
+ * @param object the object whose property will be animated
+ * @param propertyName the name of the property to be animated. For
+ * any propertyName "foo" there must be an accessible "setFoo" method
+ * on the object. If only one value is supplied in params, the animation
+ * will also need a "getFoo" method.
+ * @param params the values that the object will take on during the
+ * animation. Internally, a KeyFrames object will be created that
+ * will use times that split the total duration evenly. Supplying
+ * only one value for params implies that this is a "to" animation
+ * whose intial value will be determined dynamically when the animation
+ * starts.
+ * @throws IllegalArgumentException if appropriate set/get methods
+ * cannot be found for propertyName.
+ */
+ public <T> PropertySetter(Object object, String propertyName, T... params) {
+ this(object, propertyName, new KeyFrames(KeyValues.create(params)));
+ }
+
+ /**
+ * Constructor for a PropertySetter where the values the propert
+ * takes on during the animation are specified in a {@link KeyFrames}
+ * object.
+ *
+ * @param object the object whose property will be animated
+ * @param propertyName the name of the property to be animated. For
+ * any propertyName "foo" there must be an accessible "setFoo" method
+ * on the object. If only one value is supplied in params, the animation
+ * will also need a "getFoo" method.
+ * @param evaluator KeyValues knows how to calculate intermediate values
+ * for many built-in types, but if you want to supply values in
+ * types not understood by KeyValues, you will need to supply your
+ * own Evaluator.
+ * @param params the values that the object will take on during the
+ * animation. Internally, a KeyFrames object will be created that
+ * will use times that split the total duration evenly. Supplying
+ * only one value for params implies that this is a "to" animation
+ * whose intial value will be determined dynamically when the animation
+ * starts.
+ * @throws IllegalArgumentException if appropriate set/get methods
+ * cannot be found for propertyName.
+ */
+ public <T> PropertySetter(Object object, String propertyName,
+ Evaluator evaluator, T... params) {
+ this(object, propertyName,
+ new KeyFrames(KeyValues.create(evaluator, params)));
+ }
+
+ /**
+ * Translates the property name used in the PropertyRange object into
+ * the appropriate Method in the Object to be modified. This uses
+ * standard JavaBean naming convention (e.g., propertyName would
+ * become setPropertyName).
+ * @throws NoSuchMethodException if there is no method on the
+ * object with the appropriate name
+ * @throws SecurityException if the application does not have
+ * appropriate permissions to request access to the Method
+ */
+ private void setupMethodInfo() throws NoSuchMethodException {
+ try {
+ String firstChar = propertyName.substring(0, 1);
+ String remainder = propertyName.substring(1);
+ Class propertyType = getType();
+ String propertySetterName = "set" + firstChar.toUpperCase() + remainder;
+
+ PropertyDescriptor prop = new PropertyDescriptor(propertyName, object.getClass(),
+ null, propertySetterName);
+ propertySetter = prop.getWriteMethod();
+ if (isToAnimation()) {
+ // Only need the getter for "to" animations
+ String propertyGetterName = "get" + firstChar.toUpperCase() +
+ remainder;
+ prop = new PropertyDescriptor(propertyName,
+ object.getClass(), propertyGetterName, null);
+ propertyGetter = prop.getReadMethod();
+ }
+ } catch (Exception e) {
+ throw new NoSuchMethodException("Cannot find property methods: " + e);
+ }
+ }
+
+ //
+ // TimingTargetAdapter overrides
+ //
+
+ /**
+ * Called by Animator to signal that the timer is about to start.
+ * The only operation performed in this method is setting an initial
+ * value for the animation if appropriate; this accounts
+ * for "to" animations, which need to start from the current value.
+ * <p>
+ * This method is not intended for use by application code.
+ */
+ public void begin() {
+ if (isToAnimation()) {
+ try {
+ setStartValue(propertyGetter.invoke(object));
+ } catch (Exception e) {
+ System.out.println("Problem setting start value on object " +
+ object + ": " + e);
+ }
+ }
+ }
+
+ /**
+ * Called from Animator to signal a timing event. This
+ * causes PropertySetter to invoke the property-setting method (as
+ * specified by the propertyName in the constructor) with the
+ * appropriate value of the property given the range of values in the
+ * KeyValues object and the fraction of the timing cycle that has
+ * elapsed.
+ * <p>
+ * This method is not intended for use by application code.
+ */
+ public void timingEvent(float fraction) {
+ try {
+ setValue(object, propertySetter, fraction);
+ } catch (Exception e) {
+ System.out.println("Problem calling setValue in " +
+ "PropertySetter.timingEvent: " + e);
+ }
+ }
+
+ private String getPropertyName() {
+ return propertyName;
+ }
+
+ /**
+ * Called during begin() if this is a "to" animation, to set the start
+ * value of the animation to whatever the current value is.
+ */
+ private void setStartValue(Object object) {
+ keyFrames.getKeyValues().setStartValue(object);
+ }
+
+ /**
+ * Sets the appropriate value on the property given the current fraction
+ */
+ private void setValue(Object object, Method method, float fraction) {
+ try {
+ method.invoke(object, keyFrames.getValue(fraction));
+ } catch (Exception e) {
+ System.out.println("Problem invoking method " +
+ propertySetter + " in object " + object +
+ " in setValue" + e);
+ }
+ }
+
+ /**
+ * Returns the type used in this property setter (defers to KeyFrames
+ * for this information).
+ */
+ private Class getType() {
+ return keyFrames.getType();
+ }
+
+ /**
+ * Utility method for determining whether this is a "to" animation
+ * (true if the first value is null).
+ */
+ private boolean isToAnimation() {
+ return (keyFrames.getKeyValues().isToAnimation());
+ }
+
+}
Added: branches/upstream/timingframework/current/org/jdesktop/animation/timing/interpolation/SplineInterpolator.java
===================================================================
--- branches/upstream/timingframework/current/org/jdesktop/animation/timing/interpolation/SplineInterpolator.java (rev 0)
+++ branches/upstream/timingframework/current/org/jdesktop/animation/timing/interpolation/SplineInterpolator.java 2010-11-27 19:07:53 UTC (rev 13103)
@@ -0,0 +1,222 @@
+/**
+ * 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.jdesktop.animation.timing.interpolation;
+
+import java.awt.geom.Point2D;
+import java.util.ArrayList;
+import org.jdesktop.animation.timing.*;
+
+/**
+ * This class interpolates fractional values using Bezier splines. The anchor
+ * points * for the spline are assumed to be (0, 0) and (1, 1). Control points
+ * should all be in the range [0, 1].
+ * <p>
+ * For more information on how splines are used to interpolate, refer to the
+ * SMIL specification at http://w3c.org.
+ * <p>
+ * This class provides one simple built-in facility for non-linear
+ * interpolation. Applications are free to define their own Interpolator
+ * implementation and use that instead when particular non-linear
+ * effects are desired.
+ *
+ * @author Chet
+ */
+public final class SplineInterpolator implements Interpolator {
+
+ // 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 SplineInterpolator(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) {
+ Point2D.Float 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 Point2D.Float getXY(float t) {
+ Point2D.Float xy;
+ float invT = (1 - t);
+ float b1 = 3 * t * (invT * invT);
+ float b2 = 3 * (t * t) * invT;
+ float b3 = t * t * t;
+ xy = new Point2D.Float(
+ (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) {
+ Point2D.Float 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 interpolate(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;
+ }
+}
\ No newline at end of file
Added: branches/upstream/timingframework/current/org/jdesktop/animation/timing/interpolation/package.html
===================================================================
--- branches/upstream/timingframework/current/org/jdesktop/animation/timing/interpolation/package.html (rev 0)
+++ branches/upstream/timingframework/current/org/jdesktop/animation/timing/interpolation/package.html 2010-11-27 19:07:53 UTC (rev 13103)
@@ -0,0 +1,16 @@
+<HTML><HEAD>
+<META http-equiv=Content-Type content="text/html; charset=windows-1252">
+<META content="MSHTML 6.00.2900.2873" name=GENERATOR></HEAD>
+<BODY bgColor=white>
+Provides a mechanism for animating object properties between different values.
+<p>
+This package provides classes for defining object properties to animate,
+via the PropertySetter class. KeyFrames encapsulates the definition of
+the times (using KeyTimes) and values (using KeyValues)
+to interpolate between, as well as the
+type of interpolation to use between these values. Interpolator is an
+interface that is implemented by DiscreteInterpolator, LinearInterpolator,
+and SplineInterpolator for built-in interpolations, but applications can
+define their own custom interpolation as well.
+</p>
+</BODY></HTML>
Added: branches/upstream/timingframework/current/org/jdesktop/animation/timing/package.html
===================================================================
--- branches/upstream/timingframework/current/org/jdesktop/animation/timing/package.html (rev 0)
+++ branches/upstream/timingframework/current/org/jdesktop/animation/timing/package.html 2010-11-27 19:07:53 UTC (rev 13103)
@@ -0,0 +1,17 @@
+<HTML><HEAD>
+<META http-equiv=Content-Type content="text/html; charset=windows-1252">
+<META content="MSHTML 6.00.2900.2873" name=GENERATOR></HEAD>
+<BODY bgColor=white>
+Core classes of the Timing Framework; these classes provide the
+base functionality that all animations will use.
+<p>
+This package provides the fundamental capabilities of the Timing
+Framework. The core class of the entire framework is Animator, which
+is responsible for setting up and running animations. The other
+elements of this package are TimingTarget, which is the interface used
+by Animator to report timing events during the animation, and
+TimingTargetAdapter, which is a utility class that users may subclass
+to pick and choose the TimingTarget events they are interested in
+receiving.
+</p>
+</BODY></HTML>
Added: branches/upstream/timingframework/current/org/jdesktop/animation/timing/triggers/ActionTrigger.java
===================================================================
--- branches/upstream/timingframework/current/org/jdesktop/animation/timing/triggers/ActionTrigger.java (rev 0)
+++ branches/upstream/timingframework/current/org/jdesktop/animation/timing/triggers/ActionTrigger.java 2010-11-27 19:07:53 UTC (rev 13103)
@@ -0,0 +1,94 @@
+/**
+ * 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.jdesktop.animation.timing.triggers;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.lang.reflect.Method;
+import org.jdesktop.animation.timing.*;
+
+/**
+ * ActionTrigger handles action events and
+ * starts the animator when actions occur.
+ * For example, to have anim start when a button is clicked,
+ * one might write the following:
+ * <pre>
+ * ActionTrigger trigger = ActionTrigger.addTrigger(button, anim);
+ * </pre>
+ *
+ * @author Chet
+ */
+public class ActionTrigger extends Trigger implements ActionListener {
+
+ /**
+ * Creates an ActionTrigger and adds it as a listener to object.
+ *
+ * @param object an object that will be used as an event source for
+ * this trigger. This object must have the method addActionListener.
+ * @param animator the Animator that start when the event occurs
+ * @return ActionTrigger the resulting trigger
+ * @throws IllegalArgumentException if object has no
+ * <code>addActionListener()</code>
+ */
+ public static ActionTrigger addTrigger(Object object, Animator animator) {
+ ActionTrigger trigger = new ActionTrigger(animator);
+ try {
+ Method addListenerMethod =
+ object.getClass().getMethod("addActionListener",
+ ActionListener.class);
+ addListenerMethod.invoke(object, trigger);
+ } catch (Exception e) {
+ throw new IllegalArgumentException("Problem adding listener" +
+ " to object: " + e);
+ }
+ return trigger;
+ }
+
+ /**
+ * Creates an ActionTrigger that will start the animator upon receiving
+ * any ActionEvents. It should be added to any suitable object with
+ * an addActionListener method.
+ * @param animator the Animator that start when the event occurs
+ */
+ public ActionTrigger(Animator animator) {
+ super(animator);
+ }
+
+ /**
+ * Called by an object generating ActionEvents to which this
+ * trigger was added as an ActionListener. This starts the Animator.
+ */
+ public void actionPerformed(ActionEvent ae) {
+ fire();
+ }
+
+}
Added: branches/upstream/timingframework/current/org/jdesktop/animation/timing/triggers/FocusTrigger.java
===================================================================
--- branches/upstream/timingframework/current/org/jdesktop/animation/timing/triggers/FocusTrigger.java (rev 0)
+++ branches/upstream/timingframework/current/org/jdesktop/animation/timing/triggers/FocusTrigger.java 2010-11-27 19:07:53 UTC (rev 13103)
@@ -0,0 +1,130 @@
+/**
+ * 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.jdesktop.animation.timing.triggers;
+
+import java.awt.event.FocusEvent;
+import java.awt.event.FocusListener;
+import javax.swing.JComponent;
+import org.jdesktop.animation.timing.*;
+
+/**
+ * FocusTrigger handles focus events
+ * and triggers an animation based on those events.
+ * For example, to have anim start when component receives an
+ * IN event, one might write the following:
+ * <pre>
+ * FocusTrigger trigger =
+ * FocusTrigger.addTrigger(component, anim, FocusTriggerEvent.IN);
+ * </pre>
+ *
+ *
+ *
+ * @author Chet
+ */
+public class FocusTrigger extends Trigger implements FocusListener {
+
+ /**
+ * Creates a non-auto-reversing FocusTrigger and adds it as a FocusListener
+ * to the component.
+ *
+ * @param component component that will generate FocusEvents for this
+ * trigger
+ * @param animator the Animator that will start when the event occurs
+ * @param event the FocusTriggerEvent that will cause the action to fire
+ * @return FocusTrigger the resulting trigger
+ */
+ public static FocusTrigger addTrigger(JComponent component,
+ Animator animator, FocusTriggerEvent event) {
+ return addTrigger(component, animator, event, false);
+ }
+
+ /**
+ * Creates a FocusTrigger and adds it as a FocusListener
+ * to the component.
+ *
+ * @param component component that will generate FocusEvents for this
+ * trigger
+ * @param animator the Animator that will start when the event occurs
+ * @param event the FocusTriggerEvent that will cause the action to fire
+ * @param autoReverse flag to determine whether the animator should
+ * stop and reverse based on opposite triggerEvents.
+ * @return FocusTrigger the resulting trigger
+ */
+ public static FocusTrigger addTrigger(JComponent component,
+ Animator animator, FocusTriggerEvent event, boolean autoReverse) {
+ FocusTrigger trigger = new FocusTrigger(animator, event, autoReverse);
+ component.addFocusListener(trigger);
+ return trigger;
+ }
+
+ /**
+ * Creates a non-auto-reversing FocusTrigger, which should be added
+ * to a Component that will generate the focus events of interest.
+ * @param animator the Animator that will start when the event occurs
+ * @param event the FocusTriggerEvent that will cause the action to fire
+ */
+ public FocusTrigger(Animator animator, FocusTriggerEvent event) {
+ this(animator, event, false);
+ }
+
+ /**
+ * Creates a FocusTrigger, which should be added
+ * to a Component that will generate the focus events of interest.
+ * @param animator the Animator that will start when the event occurs
+ * @param event the FocusTriggerEvent that will cause the action to fire
+ * @param autoReverse flag to determine whether the animator should
+ * stop and reverse based on opposite triggerEvents.
+ */
+ public FocusTrigger(Animator animator, FocusTriggerEvent event,
+ boolean autoReverse) {
+ super(animator, event, autoReverse);
+ }
+
+ /**
+ * Called by the object which added this trigger as a FocusListener.
+ * This method starts the animator if the trigger is waiting for a
+ * IN event.
+ */
+ public void focusGained(FocusEvent e) {
+ fire(FocusTriggerEvent.IN);
+ }
+
+ /**
+ * Called by the object which added this trigger as a FocusListener.
+ * This method starts the animator if the trigger is waiting for a
+ * OUT event.
+ */
+ public void focusLost(FocusEvent e) {
+ fire(FocusTriggerEvent.OUT);
+ }
+
+}
Added: branches/upstream/timingframework/current/org/jdesktop/animation/timing/triggers/FocusTriggerEvent.java
===================================================================
--- branches/upstream/timingframework/current/org/jdesktop/animation/timing/triggers/FocusTriggerEvent.java (rev 0)
+++ branches/upstream/timingframework/current/org/jdesktop/animation/timing/triggers/FocusTriggerEvent.java 2010-11-27 19:07:53 UTC (rev 13103)
@@ -0,0 +1,72 @@
+/**
+ * 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.jdesktop.animation.timing.triggers;
+
+/**
+ * Focus In/Out events
+ *
+ * @author Chet
+ */
+public class FocusTriggerEvent extends TriggerEvent {
+ /**
+ * Event fired when Component receives focus
+ */
+ public static final FocusTriggerEvent IN =
+ new FocusTriggerEvent("FocusIn");
+ /**
+ * Event fired when Component loses focus
+ */
+ public static final FocusTriggerEvent OUT =
+ new FocusTriggerEvent("FocusOut");
+
+ /**
+ * Private constructor; this helps ensure type-safe use of
+ * pre-defined TriggerEvent objects.
+ */
+ private FocusTriggerEvent(String name) {
+ super(name);
+ }
+
+ /**
+ * This method finds the opposite of the current event.: IN ->
+ * OUT and OUT -> IN.
+ */
+ public TriggerEvent getOppositeEvent() {
+ if (this == FocusTriggerEvent.IN) {
+ return FocusTriggerEvent.OUT;
+ } else {
+ return FocusTriggerEvent.IN;
+ }
+ }
+
+};
+
Added: branches/upstream/timingframework/current/org/jdesktop/animation/timing/triggers/MouseTrigger.java
===================================================================
--- branches/upstream/timingframework/current/org/jdesktop/animation/timing/triggers/MouseTrigger.java (rev 0)
+++ branches/upstream/timingframework/current/org/jdesktop/animation/timing/triggers/MouseTrigger.java 2010-11-27 19:07:53 UTC (rev 13103)
@@ -0,0 +1,150 @@
+/**
+ * Copyright (c) 2007, 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.jdesktop.animation.timing.triggers;
+
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+import javax.swing.JComponent;
+import org.jdesktop.animation.timing.Animator;
+
+/**
+ * MouseTrigger handles mouse events
+ * and triggers an animation based on those events.
+ * For example, to have anim start when component receives an
+ * ENTER event, one might write the following:
+ * <pre>
+ * MouseTrigger trigger =
+ * MouseTrigger.addTrigger(component, anim, MouseTriggerEvent.ENTER);
+ * </pre>
+ *
+ *
+ *
+ * @author Chet
+ */
+public class MouseTrigger extends Trigger implements MouseListener {
+
+ /**
+ * Creates a non-auto-reversing MouseTrigger and adds it as a
+ * listener to component.
+ *
+ * @param component component that will generate MouseEvents for this
+ * trigger
+ * @param animator the Animator that will start when the event occurs
+ * @param event the MouseTriggerEvent that will cause the action to fire
+ * @return MouseTrigger the resulting trigger
+ */
+ public static MouseTrigger addTrigger(JComponent component,
+ Animator animator, MouseTriggerEvent event) {
+ return addTrigger(component, animator, event, false);
+ }
+
+ /**
+ * Creates a MouseTrigger and adds it as a listener to component.
+ *
+ * @param component component that will generate MouseEvents for this
+ * trigger
+ * @param animator the Animator that will start when the event occurs
+ * @param event the FocusTriggerEvent that will cause the action to fire
+ * @param autoReverse flag to determine whether the animator should
+ * stop and reverse based on opposite triggerEvents.
+ * @return FocusTrigger the resulting trigger
+ */
+ public static MouseTrigger addTrigger(JComponent component,
+ Animator animator, MouseTriggerEvent event, boolean autoReverse) {
+ MouseTrigger trigger = new MouseTrigger(animator, event, autoReverse);
+ component.addMouseListener(trigger);
+ return trigger;
+ }
+
+ /**
+ * Creates a non-auto-reversing MouseTrigger, which should be added
+ * to a Component that will generate the mouse events of interest
+ */
+ public MouseTrigger(Animator animator, MouseTriggerEvent event) {
+ this(animator, event, false);
+ }
+
+ /**
+ * Creates a MouseTrigger, which should be added
+ * to a Component that will generate the mouse events of interest
+ */
+ public MouseTrigger(Animator animator,
+ MouseTriggerEvent event, boolean autoReverse) {
+ super(animator, event, autoReverse);
+ }
+
+ /**
+ * Called by the object which added this trigger as a MouseListener.
+ * This method starts the animator if the trigger is waiting for an
+ * ENTER event.
+ */
+ public void mouseEntered(MouseEvent e) {
+ fire(MouseTriggerEvent.ENTER);
+ }
+
+ /**
+ * Called by the object which added this trigger as a MouseListener.
+ * This method starts the animator if the trigger is waiting for an
+ * EXIT event.
+ */
+ public void mouseExited(MouseEvent e) {
+ fire(MouseTriggerEvent.EXIT);
+ }
+
+ /**
+ * Called by the object which added this trigger as a MouseListener.
+ * This method starts the animator if the trigger is waiting for a
+ * PRESS event.
+ */
+ public void mousePressed(MouseEvent e) {
+ fire(MouseTriggerEvent.PRESS);
+ }
+
+ /**
+ * Called by the object which added this trigger as a MouseListener.
+ * This method starts the animator if the trigger is waiting for a
+ * RELEASE event.
+ */
+ public void mouseReleased(MouseEvent e) {
+ fire(MouseTriggerEvent.RELEASE);
+ }
+
+ /**
+ * Called by the object which added this trigger as a MouseListener.
+ * This method starts the animator if the trigger is waiting for a
+ * CLICK event.
+ */
+ public void mouseClicked(MouseEvent e) {
+ fire(MouseTriggerEvent.CLICK);
+ }
+
+}
Added: branches/upstream/timingframework/current/org/jdesktop/animation/timing/triggers/MouseTriggerEvent.java
===================================================================
--- branches/upstream/timingframework/current/org/jdesktop/animation/timing/triggers/MouseTriggerEvent.java (rev 0)
+++ branches/upstream/timingframework/current/org/jdesktop/animation/timing/triggers/MouseTriggerEvent.java 2010-11-27 19:07:53 UTC (rev 13103)
@@ -0,0 +1,99 @@
+/**
+ * Copyright (c) 2007, 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.jdesktop.animation.timing.triggers;
+
+/**
+ * Mouse Enter/Exit/Press/Release/Click events
+ *
+ * @author Chet
+ */
+public class MouseTriggerEvent extends TriggerEvent {
+ /**
+ * Event fired when mouse enters
+ */
+ public static final MouseTriggerEvent ENTER =
+ new MouseTriggerEvent("Entered");
+ /**
+ * Event fired when mouse exits
+ */
+ public static final MouseTriggerEvent EXIT =
+ new MouseTriggerEvent("Exit");
+ /**
+ * Event fired when mouse button is pressed
+ */
+ public static final MouseTriggerEvent PRESS =
+ new MouseTriggerEvent("Press");
+ /**
+ * Event fired when mouse button is released
+ */
+ public static final MouseTriggerEvent RELEASE =
+ new MouseTriggerEvent("Release");
+ /**
+ * Event fired when mouse is clicked
+ */
+ public static final MouseTriggerEvent CLICK =
+ new MouseTriggerEvent("Click");
+
+ /**
+ * Protected constructor; this helps ensure type-safe use of
+ * pre-define TriggerEvent objects.
+ */
+ private MouseTriggerEvent(String name) {
+ super(name);
+ }
+
+ /**
+ * This method finds the opposite of the current event.: <BR/>
+ * ENTER -> EXIT <BR/>
+ * EXIT -> ENTER <BR/>
+ * PRESS -> RELEASE <BR/>
+ * RELEASE -> PRESS <BR/>
+ * Note that CLICK has no obvious opposite so
+ * it simply returns CLICK (this method should probably not be called
+ * for that case).
+ *
+ */
+ public TriggerEvent getOppositeEvent() {
+ if (this == MouseTriggerEvent.ENTER) {
+ return MouseTriggerEvent.EXIT;
+ } else if (this == MouseTriggerEvent.EXIT) {
+ return MouseTriggerEvent.ENTER;
+ } else if (this == MouseTriggerEvent.PRESS) {
+ return MouseTriggerEvent.RELEASE;
+ } else if (this == MouseTriggerEvent.RELEASE) {
+ return MouseTriggerEvent.PRESS;
+ }
+ // Possible to reach here for REPEAT action (but probably should not
+ // have been called with this event)
+ return this;
+ }
+}
Added: branches/upstream/timingframework/current/org/jdesktop/animation/timing/triggers/TimingTrigger.java
===================================================================
--- branches/upstream/timingframework/current/org/jdesktop/animation/timing/triggers/TimingTrigger.java (rev 0)
+++ branches/upstream/timingframework/current/org/jdesktop/animation/timing/triggers/TimingTrigger.java 2010-11-27 19:07:53 UTC (rev 13103)
@@ -0,0 +1,148 @@
+/**
+ * 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.jdesktop.animation.timing.triggers;
+
+import org.jdesktop.animation.timing.*;
+
+/**
+ * TimingTrigger handles timing events and starts the animator
+ * when those events occur. This class can be useful in sequencing different
+ * Animators. For example, one Animator can be set to start when another
+ * ends using this Trigger. For example, to have anim2 start when anim1 ends,
+ * one might write the following:
+ * <pre>
+ * TimingTrigger trigger =
+ * TimingTrigger.addTrigger(anim1, anim2, TimingTriggerEvent.STOP);
+ * </pre>
+ *
+ *
+ *
+ * @author Chet
+ */
+public class TimingTrigger extends Trigger implements TimingTarget {
+
+ private Animator source;
+ private TimingTriggerEvent event;
+
+ /**
+ * Creates a non-auto-reversing TimingTrigger and adds it as a target
+ * to the source Animator.
+ *
+ * @param source the Animator that will be listened to for events
+ * to start the target Animator
+ * @param target the Animator that will start when the event occurs
+ * @param event the TimingTriggerEvent that will cause targetAnimator
+ * to start
+ * @return TimingTrigger the resulting trigger
+ * @see org.jdesktop.animation.timing.Animator#addTarget(TimingTarget)
+ */
+ public static TimingTrigger addTrigger(Animator source, Animator target,
+ TimingTriggerEvent event) {
+ return addTrigger(source, target, event, false);
+ }
+
+ /**
+ * Creates a TimingTrigger and adds it as a target
+ * to the source Animator.
+ *
+ *
+ * @param source the Animator that will be listened to for events
+ * to start the target Animator
+ * @param target the Animator that will start when the event occurs
+ * @param event the TimingTriggerEvent that will cause targetAnimator
+ * to start
+ * @param autoReverse flag to determine whether the animator should
+ * stop and reverse based on opposite triggerEvents.
+ * @return TimingTrigger the resulting trigger
+ * @see org.jdesktop.animation.timing.Animator#addTarget(TimingTarget)
+ */
+ public static TimingTrigger addTrigger(Animator source, Animator target,
+ TimingTriggerEvent event, boolean autoReverse) {
+ TimingTrigger trigger = new TimingTrigger(target, event, autoReverse);
+ source.addTarget(trigger);
+ return trigger;
+ }
+
+ /**
+ * Creates a non-auto-reversing TimingTrigger, which should be added
+ * to an Animator which will generate the events sent to the
+ * trigger.
+ */
+ public TimingTrigger(Animator animator, TimingTriggerEvent event) {
+ this(animator, event, false);
+ }
+
+ /**
+ * Creates a TimingTrigger, which should be added
+ * to an Animator which will generate the events sent to the
+ * trigger.
+ */
+ public TimingTrigger(Animator animator, TimingTriggerEvent event,
+ boolean autoReverse) {
+ super(animator, event, autoReverse);
+ }
+
+ //
+ // TimingTarget implementation methods
+ //
+
+ /**
+ * Implementation of TimingTarget method; this method does nothing
+ * in this implementation since the events of TimingTrigger are limited
+ * to START, STOP, and REPEAT
+ */
+ public void timingEvent(float fraction) {}
+
+ /**
+ * Called by Animator when starting. Sends the TimingTriggerEvent.START
+ * event to the Trigger.
+ */
+ public void begin() {
+ fire(TimingTriggerEvent.START);
+ }
+
+ /**
+ * Called by Animator when ending. Sends the TimingTriggerEvent.STOP
+ * event to the Trigger.
+ */
+ public void end() {
+ fire(TimingTriggerEvent.STOP);
+ }
+
+ /**
+ * Called by Animator when repeating. Sends the TimingTriggerEvent.REPEAT
+ * event to the Trigger.
+ */
+ public void repeat() {
+ fire(TimingTriggerEvent.REPEAT);
+ }
+}
Added: branches/upstream/timingframework/current/org/jdesktop/animation/timing/triggers/TimingTriggerEvent.java
===================================================================
--- branches/upstream/timingframework/current/org/jdesktop/animation/timing/triggers/TimingTriggerEvent.java (rev 0)
+++ branches/upstream/timingframework/current/org/jdesktop/animation/timing/triggers/TimingTriggerEvent.java 2010-11-27 19:07:53 UTC (rev 13103)
@@ -0,0 +1,73 @@
+/**
+ * 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.jdesktop.animation.timing.triggers;
+
+/**
+ * Timing events; TimingTriggers can be set to fire when an animator
+ * starts, stops, or repeats.
+ *
+ * @author Chet
+ */
+public class TimingTriggerEvent extends TriggerEvent {
+ /** Event fired when Animator starts */
+ public static final TimingTriggerEvent START =
+ new TimingTriggerEvent("Start");
+ /** Event fired when Animator stops */
+ public static final TimingTriggerEvent STOP =
+ new TimingTriggerEvent("Stop");
+ /**
+ * Event fired when Animator finishes one cycle and starts another
+ */
+ public static final TimingTriggerEvent REPEAT =
+ new TimingTriggerEvent("Repeat");
+
+ private TimingTriggerEvent(String name) {
+ super(name);
+ }
+
+ /**
+ * This method finds the opposite of the current event.: START -> STOP
+ * and STOP -> START. Note that REPEAT has no obvious opposite so
+ * it simply returns REPEAT (this method should probably not be called
+ * for that case).
+ */
+ public TriggerEvent getOppositeEvent() {
+ if (this.equals(TimingTriggerEvent.START)) {
+ return TimingTriggerEvent.STOP;
+ } else if (this.equals(TimingTriggerEvent.STOP)) {
+ return TimingTriggerEvent.START;
+ }
+ // Possible to reach here for REPEAT action (but probably should not
+ // have been called with this event)
+ return this;
+ }
+}
Added: branches/upstream/timingframework/current/org/jdesktop/animation/timing/triggers/Trigger.java
===================================================================
--- branches/upstream/timingframework/current/org/jdesktop/animation/timing/triggers/Trigger.java (rev 0)
+++ branches/upstream/timingframework/current/org/jdesktop/animation/timing/triggers/Trigger.java 2010-11-27 19:07:53 UTC (rev 13103)
@@ -0,0 +1,178 @@
+/**
+ * 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.jdesktop.animation.timing.triggers;
+
+import org.jdesktop.animation.timing.Animator;
+
+/**
+ * This abstract class should be overridden by any class wanting to
+ * implement a new Trigger. The subclass will define the events to trigger
+ * off of and any listeners to handle those events. That subclass will call
+ * either {@link #fire()} or {@link #fire(TriggerEvent)} to start the
+ * animator based on an event that occurred.
+ * <p>
+ * Subclasses should call one of the constructors in Trigger, according to
+ * whether they want Trigger to discern between different TriggerEvents
+ * and whether they want Trigger to auto-reverse the animation based on
+ * opposite TriggerEvents.
+ * <p>
+ * Subclasses should call one of the <code>fire</code> methods based on
+ * whether they want Trigger to perform any event logic or simply start
+ * the animation.
+ *
+ * @author Chet
+ */
+public abstract class Trigger {
+
+ private boolean disarmed = false;
+ private Animator animator, reverseAnimator;
+ private TriggerEvent triggerEvent;
+ private boolean autoReverse = false;
+
+ /**
+ * Creates a Trigger that will start the animator when {@link #fire()}
+ * is called. Subclasses call this method to set up a simple Trigger
+ * that will be started by calling {@link #fire()}, and will have
+ * no dependency upon the specific {@link TriggerEvent} that must have
+ * occurred to start the animator.
+ * @param animator the Animator that will start when the Trigger
+ * is fired
+ */
+ protected Trigger(Animator animator) {
+ this(animator, null);
+ }
+
+ /**
+ * Creates a Trigger that will start the animator when
+ * {@link #fire(TriggerEvent)} is called with an event that equals
+ * triggerEvent.
+ * @param animator the Animator that will start when the Trigger
+ * is fired
+ * @param triggerEvent the TriggerEvent that must occur for this
+ * Trigger to fire
+ */
+ protected Trigger(Animator animator, TriggerEvent triggerEvent) {
+ this(animator, triggerEvent, false);
+ }
+
+ /**
+ * Creates a Trigger that will start the animator when
+ * {@link #fire(TriggerEvent)} is called with an event that equals
+ * triggerEvent. Also, automatically stops and reverses animator when
+ * opposite event occurs, and stops reversing animator likewise
+ * when triggerEvent occurs.
+ * @param animator the Animator that will start when the Trigger
+ * is fired
+ * @param triggerEvent the TriggerEvent that must occur for this
+ * Trigger to fire
+ * @param autoReverse flag to determine whether the animator should
+ * stop and reverse based on opposite triggerEvents.
+ * @see TriggerEvent#getOppositeEvent()
+ */
+ protected Trigger(Animator animator, TriggerEvent triggerEvent,
+ boolean autoReverse) {
+ this.animator = animator;
+ this.triggerEvent = triggerEvent;
+ this.autoReverse = autoReverse;
+ }
+
+ /**
+ * This method disables this Trigger and effectively noop's any actions
+ * that would otherwise occur
+ */
+ public void disarm() {
+ disarmed = true;
+ }
+
+ /**
+ * Called by subclasses to start the animator if currentEvent equals
+ * the event that the Trigger is based upon. Also, if the Trigger is
+ * set to autoReverse, stops and reverses the animator running in the
+ * opposite direction as appropriate.
+ * @param currentEvent the {@link TriggerEvent} that just occurred, which
+ * will be compared with the TriggerEvent used to construct this Trigger
+ * and determine whether the animator should be started or reversed
+ */
+ protected void fire(TriggerEvent currentEvent) {
+ if (disarmed) {
+ return;
+ }
+ if (currentEvent == triggerEvent) {
+ // event occurred; fire the animation
+ if (autoReverse) {
+ if (animator.isRunning()) {
+ float f = animator.getTimingFraction();
+ animator.stop();
+ animator.setStartFraction(f);
+ } else {
+ animator.setStartFraction(0f);
+ }
+ }
+ if (animator.isRunning()) {
+ animator.stop();
+ }
+ animator.setStartDirection(Animator.Direction.FORWARD);
+ fire();
+ } else if (triggerEvent != null &&
+ currentEvent == triggerEvent.getOppositeEvent()) {
+ // Opposite event occurred - run reverse anim if autoReverse
+ if (autoReverse) {
+ if (animator.isRunning()) {
+ float f = animator.getTimingFraction();
+ animator.stop();
+ animator.setStartFraction(f);
+ } else {
+ animator.setStartFraction(1f -
+ animator.getStartFraction());
+ }
+ animator.setStartDirection(Animator.Direction.BACKWARD);
+ fire();
+ }
+ }
+ }
+
+ /**
+ * Utility method called by subclasses to start the animator. This variant
+ * assumes that there need be no check of the TriggerEvent that fired,
+ * which is useful for subclasses with simple events.
+ */
+ protected void fire() {
+ if (disarmed) {
+ return;
+ }
+ if (animator.isRunning()) {
+ animator.stop();
+ }
+ animator.start();
+ }
+
+}
Added: branches/upstream/timingframework/current/org/jdesktop/animation/timing/triggers/TriggerEvent.java
===================================================================
--- branches/upstream/timingframework/current/org/jdesktop/animation/timing/triggers/TriggerEvent.java (rev 0)
+++ branches/upstream/timingframework/current/org/jdesktop/animation/timing/triggers/TriggerEvent.java 2010-11-27 19:07:53 UTC (rev 13103)
@@ -0,0 +1,72 @@
+/**
+ * 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.jdesktop.animation.timing.triggers;
+
+/**
+ * Superclass for all TriggerEvents used in the Trigger classes. The methods
+ * here are mostly protected; it is expected that callers will not use this
+ * class directly, but will instead use subclasses with pre-defined event
+ * types. The purpose of this superclass is to provide the ability for
+ * {@link Trigger} to treat event types generically, rather than to have
+ * all even logic in the subclasses of Trigger.
+ *
+ * @author Chet
+ */
+public class TriggerEvent {
+
+ /**
+ * The ID of events are simple strings. It is expected that subclasses
+ * will define static objects that callers will use instead of users
+ * having to manually create TriggerEvent objects from strings directly
+ */
+ private String name;
+
+ /**
+ * Protected constructor; this helps ensure type-safe use of
+ * pre-define TriggerEvent objects.
+ */
+ protected TriggerEvent(String name) {
+ this.name = name;
+ }
+
+ /**
+ * This method returns the 'opposite' event from itself. This is used by
+ * {@link Trigger} in running an auto-reversing animation, to determine
+ * whether an opposite event has occurred (and whether to stop/reverse
+ * the animation). Note that some events may have no opposite.
+ * Default behavior returns same event; subclasses with multiple/opposite
+ * events must override to do the right thing here.
+ */
+ public TriggerEvent getOppositeEvent() {
+ return this;
+ }
+}
Added: branches/upstream/timingframework/current/org/jdesktop/animation/timing/triggers/TriggerNotes
===================================================================
--- branches/upstream/timingframework/current/org/jdesktop/animation/timing/triggers/TriggerNotes (rev 0)
+++ branches/upstream/timingframework/current/org/jdesktop/animation/timing/triggers/TriggerNotes 2010-11-27 19:07:53 UTC (rev 13103)
@@ -0,0 +1,135 @@
+Trigger Notes
+
+
+Want the ability to start/stop animations based on events, something like:
+
+"When X happens, start Anim1"
+
+"When Y happens, stop Anim2"
+
+Also want to start/stop animations based on other animations:
+
+"When Anim3 stops, start Anim4"
+
+Also want ability to auto-stop animations based on opposite events,
+and auto-start opposite animations likewise:
+
+"When X happens, start Anim1, stop Anim.
+When inverse(X) happens, stop Anim1
+
+Auto-reverse might be handleable through the new setDirection() API
+in Animator
+
+One of the problems with the current API is all these subclasses with
+essentially similar constructors. It seems like I should be able to
+have the main functionality of creating a Trigger in just the Trigger
+class itself, and then have the functionality of the event-specific
+actions and listeners embedded in some other structure.
+
+something like:
+
+Trigger myTrigger = new Trigger(myAnimator, ButtonAction.MOUSEOVER,
+ TriggerAction.START);
+
+----------------
+
+12/22/06
+
+Triggers revisit: wouldn't it be nice if I could make these things actually
+work (and have a simple API) for 1.0 (and the book)?
+
+It seems like I should be able to have a *really* simple generic interface, with
+most of the current details hidden. let's try it:
+
+
+abstract class Trigger {
+
+ protected Animator animator;
+
+ protected Trigger(Animator animator, TriggerAction action) {
+ this.animator = animator;
+ this.action = action;
+ }
+
+ protected void fire() {
+ if (action == TriggerAction.START) {
+ animator.start();
+ } else {
+ animator.stop();
+ }
+ }
+
+ public void disarm() {
+ // cancel Animator
+ // override to cancel any listeners
+ }
+}
+
+public class TimingTarget {
+
+ public TimingTarget(Animator source, TriggerAction action, TriggerEvent event,
+ Animator animator) {
+ super(animator, action);
+ // Setup private TimingListener
+
+ }
+
+ private class TimingTriggerListener extends TimingTargetAdapter {
+ TimingTriggerEvent event;
+ protected TimingTriggerListener(TriggerAction action, TimingTriggerEvent event) {
+ super(timer, action);
+ this.event = event;
+ }
+ public void timingEvent(float fraction) {}
+
+ public void begin() {
+ if (event == TimingTriggerEvent.START) {
+ pullTrigger();
+ }
+ }
+ public void end() {
+ if (event == TimingTriggerEvent.STOP) {
+ pullTrigger();
+ }
+ }
+ public void repeat() {
+ if (event == TimingTriggerEvent.REPEAT) {
+ pullTrigger();
+ }
+ }
+ }
+}
+
+........
+This is working so far, but I've hit a snag with the auto-reverse functionality.
+
+Previously, it was up to the developer to set up two separate animations that
+Trigger would then add with opposite events. In particular, it would do this:
+
+ - setup listener with animator, START, event
+ - setup listener with animator, STOP, event-opposite
+ - setup listener with reverseAnimator, START, event-opposite
+ - setup listener with reverseAnimator, STOP, event
+
+This was useful, but not particularly a great API.
+
+It seems like, with setDirection(), getFraction(), and setInitialFraction(),
+we should be able to create all of this stuff automatically.
+
+For any Trigger that wants to START on some EVENT, we should be able to do this:
+ - create an Animator (opp) that is a copy of the one supplied (anim), but with the
+ opposite direction
+ - when EVENT occurs:
+ - if (opp.isRunning()) {
+ - f = opp.getFraction()
+ - anim.setInitialFraction(f)
+ - opp.stop();
+ }
+ - anim.start()
+ - when !EVENT occurs:
+ - if (anim.isRunning()) {
+ - f = anim.getFraction()
+ - opp.setInitialFraction(f)
+ - anim.stop();
+ }
+ - opp.start()
Added: branches/upstream/timingframework/current/org/jdesktop/animation/timing/triggers/package.html
===================================================================
--- branches/upstream/timingframework/current/org/jdesktop/animation/timing/triggers/package.html (rev 0)
+++ branches/upstream/timingframework/current/org/jdesktop/animation/timing/triggers/package.html 2010-11-27 19:07:53 UTC (rev 13103)
@@ -0,0 +1,16 @@
+<HTML><HEAD>
+<META http-equiv=Content-Type content="text/html; charset=windows-1252">
+<META content="MSHTML 6.00.2900.2873" name=GENERATOR></HEAD>
+<BODY bgColor=white>
+Provides simple mechanism for starting Animators
+when specific events occur.
+<p>
+This package provides classes for both using and subclassing that
+simplify the process of associating animations with events.
+Trigger and its subclasses associate specific events (subclasses
+of TriggerEvent) with listeners (as defined in Trigger subclasses).
+These listeners are then added (by the application) to appropriate objects.
+The animations are started when a Trigger detects that a specified
+event has occurred (through its listener).
+</p>
+</BODY></HTML>
More information about the pkg-java-commits
mailing list