/** * Copyright (c) 2006, Sun Microsystems, Inc * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided * with the distribution. * * Neither the name of the TimingFramework project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.pushingpixels.trident.interpolator; import java.util.*; import org.pushingpixels.trident.TridentConfig; import org.pushingpixels.trident.TimelinePropertyBuilder.PropertySetter; /** * Stores a list of values that correspond to the times in a {@link KeyTimes} * object. These structures are then used to create a {@link KeyFrames} object, * which is then used to create a {@link PropertySetter} for the purposes of * modifying an object's property over time. * <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 PropertyInterpolator<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(PropertyInterpolator evaluator, T... params) { return new KeyValues(evaluator, params); } /** * Private constructor, called by factory method */ private KeyValues(T... params) { this(TridentConfig.getInstance().getPropertyInterpolator(params), params); } /** * Private constructor, called by factory method */ private KeyValues(PropertyInterpolator evaluator, T... params) { if (params == null) { throw new IllegalArgumentException("params array cannot be null"); } else if (params.length == 0) { throw new IllegalArgumentException( "params array must have at least one element"); } if (params.length == 1) { // this is a "to" animation; set first element to null values.add(null); } Collections.addAll(values, params); this.type = params.getClass().getComponentType(); this.evaluator = evaluator; } /** * Returns the number of values stored in this object. * * @return the number of values stored in this object */ int getSize() { return values.size(); } /** * Returns the data type of the values stored in this object. * * @return a Class value representing the type of values stored in this * object */ Class<?> getType() { return this.type; } /** * Called at start of animation; sets starting value in simple "to" * animations. */ void setStartValue(T startValue) { if (isToAnimation()) { this.startValue = startValue; } } /** * Utility method for determining whether this is a "to" animation (true if * the first value is null). */ boolean isToAnimation() { return (values.get(0) == null); } /** * Returns value calculated from the value at the lower index, the value at * the upper index, the fraction elapsed between these endpoints, and the * evaluator set up by this object at construction time. */ T getValue(int i0, int i1, float fraction) { T value; T lowerValue = values.get(i0); if (lowerValue == null) { // "to" animation lowerValue = startValue; } if (i0 == i1) { // trivial case value = lowerValue; } else { T v0 = lowerValue; T v1 = values.get(i1); value = evaluator.interpolate(v0, v1, fraction); } return value; } }