You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@royale.apache.org by yi...@apache.org on 2020/09/26 16:41:47 UTC
[royale-asjs] branch develop updated: Added some spark animation
infra
This is an automated email from the ASF dual-hosted git repository.
yishayw pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/royale-asjs.git
The following commit(s) were added to refs/heads/develop by this push:
new aee0907 Added some spark animation infra
aee0907 is described below
commit aee0907d93bbe6b8c7fa6cf2a64fbd27704b9f31
Author: Yishay Weiss <yi...@yell.com>
AuthorDate: Sat Sep 26 17:41:20 2020 +0100
Added some spark animation infra
---
.../MXRoyale/src/main/royale/mx/effects/Effect.as | 383 +-
.../src/main/royale/mx/effects/EffectInstance.as | 317 +-
.../src/main/royale/mx/effects/TweenEffect.as | 2 +-
.../src/main/royale/SparkRoyaleClasses.as | 2 +-
.../src/main/royale/spark/effects/Animate.as | 681 +++
.../royale/spark/effects/animation/Animation.as | 1415 ++++++
.../spark/effects/animation/IAnimationTarget.as | 113 +
.../royale/spark/effects/animation/Keyframe.as | 223 +
.../royale/spark/effects/animation/MotionPath.as | 288 ++
.../spark/effects/animation/RepeatBehavior.as | 58 +
.../spark/effects/animation/SimpleMotionPath.as | 192 +
.../royale/spark/effects/easing/EaseInOutBase.as | 188 +
.../royale/spark/effects/easing/EasingFraction.as | 72 +
.../src/main/royale/spark/effects/easing/Linear.as | 199 +
.../src/main/royale/spark/effects/easing/Sine.as | 113 +
.../spark/effects/interpolation/IInterpolator.as | 105 +
.../interpolation/MultiValueInterpolator.as | 208 +
.../effects/interpolation/NumberInterpolator.as | 145 +
.../spark/effects/interpolation/RGBInterpolator.as | 193 +
.../effects/supportClasses/AnimateColorInstance.as | 134 +
.../effects/supportClasses/AnimateInstance.as | 1166 +++++
.../main/royale/spark/filters/ColorMatrixFilter.as | 1 -
.../main/royale/spark/primitives/supportClasses | 4673 ++++++++++++++++++++
23 files changed, 10866 insertions(+), 5 deletions(-)
diff --git a/frameworks/projects/MXRoyale/src/main/royale/mx/effects/Effect.as b/frameworks/projects/MXRoyale/src/main/royale/mx/effects/Effect.as
index b7b431a..f016bdf 100644
--- a/frameworks/projects/MXRoyale/src/main/royale/mx/effects/Effect.as
+++ b/frameworks/projects/MXRoyale/src/main/royale/mx/effects/Effect.as
@@ -21,7 +21,8 @@ package mx.effects
{
import org.apache.royale.effects.Effect;
-
+import mx.core.mx_internal;
+use namespace mx_internal;
/**
* Effect is the base class for effects in Royale.
*
@@ -94,9 +95,389 @@ public class Effect extends org.apache.royale.effects.Effect
}
+ /**
+ * @copy mx.effects.IEffect#getAffectedProperties()
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function getAffectedProperties():Array /* of String */
+ {
+ // Every subclass should override this method.
+ return [];
+ }
+ /**
+ * @private
+ * Storage for the relevantStyles property.
+ */
+ private var _relevantStyles:Array /* of String */ = [];
+
+ /**
+ * @copy mx.effects.IEffect#relevantStyles
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function get relevantStyles():Array /* of String */
+ {
+ return _relevantStyles;
+ }
+
+ /**
+ * @private
+ */
+ public function set relevantStyles(value:Array /* of String */):void
+ {
+ _relevantStyles = value;
+ }
+ /**
+ * Copies properties of the effect to the effect instance.
+ *
+ * <p>Flex calls this method from the <code>Effect.createInstance()</code>
+ * method; you do not have to call it yourself. </p>
+ *
+ * <p>When you create a custom effect, override this method to
+ * copy properties from the Effect class to the effect instance class.
+ * In your override, call <code>super.initInstance()</code>. </p>
+ *
+ * @param EffectInstance The effect instance to initialize.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ protected function initInstance(instance:IEffectInstance):void
+ {
+ //instance.duration = duration;
+ //Object(instance).durationExplicitlySet = durationExplicitlySet;
+ //instance.effect = this;
+ //instance.effectTargetHost = effectTargetHost;
+ //instance.hideFocusRing = hideFocusRing;
+ //instance.repeatCount = repeatCount;
+ //instance.repeatDelay = repeatDelay;
+ //instance.startDelay = startDelay;
+ //instance.suspendBackgroundProcessing = suspendBackgroundProcessing;
+ }
+ /**
+ * Used internally by the Effect infrastructure.
+ * If <code>captureStartValues()</code> has been called,
+ * then when Flex calls the <code>play()</code> method, it uses this function
+ * to set the targets back to the starting state.
+ * The default behavior is to take the value captured
+ * using the <code>getValueFromTarget()</code> method
+ * and set it directly on the target's property. For example: <pre>
+ *
+ * target[property] = value;</pre>
+ *
+ * <p>Only override this method if you need to apply
+ * the captured values in a different way.
+ * Note that style properties of a target are set
+ * using a different mechanism.
+ * Use the <code>relevantStyles</code> property to specify
+ * which style properties to capture and apply. </p>
+ *
+ * @param target The effect target.
+ *
+ * @param property The target property.
+ *
+ * @param value The value of the property.
+ *
+ * @param props Array of Objects, where each Array element contains a
+ * <code>start</code> and <code>end</code> Object
+ * for the properties that the effect is monitoring.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ protected function applyValueToTarget(target:Object, property:String,
+ value:*, props:Object):void
+ {
+ //if (property in target)
+ //{
+ //// The "property in target" test only tells if the property exists
+ //// in the target, but does not distinguish between read-only and
+ //// read-write properties. Put a try/catch around the setter and
+ //// ignore any errors.
+ //try
+ //{
+ //
+ //if (applyActualDimensions &&
+ //target is IFlexDisplayObject &&
+ //property == "height")
+ //{
+ //target.setActualSize(target.width,value);
+ //}
+ //else if (applyActualDimensions &&
+ //target is IFlexDisplayObject &&
+ //property == "width")
+ //{
+ //target.setActualSize(value,target.height);
+ //}
+ //else
+ //{
+ //target[property] = value;
+ //}
+ //}
+ //catch(e:Error)
+ //{
+ //// Ignore errors
+ //}
+ //}
+ }
+
+ /**
+ * @private
+ * Used internally to grab the values of the relevant properties
+ */
+ mx_internal function captureValues(propChanges:Array,
+ setStartValues:Boolean,
+ targetsToCapture:Array = null):Array
+ {
+ //var n:int;
+ //var i:int;
+ //if (!propChanges)
+ //{
+ //propChanges = [];
+ //
+ //// Create a new PropertyChanges object for the sum of all targets.
+ //n = targets.length;
+ //for (i = 0; i < n; i++)
+ //propChanges.push(new PropertyChanges(targets[i]));
+ //}
+ //
+ //// Merge Effect.filterProperties and filterObject.filterProperties
+ //var effectProps:Array = !filterObject ?
+ //relevantProperties :
+ //mergeArrays(relevantProperties,
+ //filterObject.filterProperties);
+ //
+ //var valueMap:Object;
+ //var target:Object;
+ //var m:int;
+ //var j:int;
+ //
+ //// For each target, grab the property's value
+ //// and put it into the propChanges Array.
+ //// Walk the targets.
+ //if (effectProps && effectProps.length > 0)
+ //{
+ //n = propChanges.length;
+ //for (i = 0; i < n; i++)
+ //{
+ //target = propChanges[i].target;
+ //if (targetsToCapture == null || targetsToCapture.length == 0 ||
+ //targetsToCapture.indexOf(target) >= 0)
+ //{
+ //valueMap = setStartValues ? propChanges[i].start : propChanges[i].end;
+ //
+ //// Walk the properties in the target
+ //m = effectProps.length;
+ //for (j = 0; j < m; j++)
+ //{
+ //// Don't clobber values already set
+ //if (valueMap[effectProps[j]] === undefined)
+ //{
+ //valueMap[effectProps[j]] =
+ //getValueFromTarget(target,effectProps[j]);
+ //}
+ //}
+ //}
+ //}
+ //}
+ //
+ //var styles:Array = !filterObject ?
+ //relevantStyles :
+ //mergeArrays(relevantStyles,
+ //filterObject.filterStyles);
+ //
+ //if (styles && styles.length > 0)
+ //{
+ //n = propChanges.length;
+ //for (i = 0; i < n; i++)
+ //{
+ //target = propChanges[i].target;
+ //if (targetsToCapture == null || targetsToCapture.length == 0 ||
+ //targetsToCapture.indexOf(target) >= 0)
+ //{
+ //if (!(target is IStyleClient))
+ //continue;
+ //
+ //valueMap = setStartValues ? propChanges[i].start : propChanges[i].end;
+ //
+ //// Walk the properties in the target.
+ //m = styles.length;
+ //for (j = 0; j < m; j++)
+ //{
+ //// Don't clobber values set by relevantProperties
+ //if (valueMap[styles[j]] === undefined)
+ //{
+ //var value:* = target.getStyle(styles[j]);
+ //valueMap[styles[j]] = value;
+ //}
+ //}
+ //}
+ //}
+ //}
+ //
+ //return propChanges;
+ return [];
+ }
+ /**
+ * @private
+ * Applies the start values found in the array of PropertyChanges
+ * to the relevant targets.
+ */
+ mx_internal function applyStartValues(propChanges:Array,
+ targets:Array):void
+ {
+ //var effectProps:Array = relevantProperties;
+ //
+ //var n:int = propChanges.length;
+ //for (var i:int = 0; i < n; i++)
+ //{
+ //var m:int;
+ //var j:int;
+//
+ //var target:Object = propChanges[i].target;
+ //var apply:Boolean = false;
+ //
+ //m = targets.length;
+ //for (j = 0; j < m; j++)
+ //{
+ //if (targets[j] == target)
+ //{
+ //apply = filterInstance(propChanges, target);
+ //break;
+ //}
+ //}
+ //
+ //if (apply)
+ //{
+ //// Walk the properties in the target
+ //m = effectProps.length;
+ //for (j = 0; j < m; j++)
+ //{
+ //var propName:String = effectProps[j];
+ //var startVal:* = propChanges[i].start[propName];
+ //var endVal:* = propChanges[i].end[propName];
+ //if (propName in propChanges[i].start &&
+ //endVal != startVal &&
+ //(!(startVal is Number) ||
+ //!(isNaN(endVal) && isNaN(startVal))))
+ //{
+ //applyValueToTarget(target, effectProps[j],
+ //propChanges[i].start[effectProps[j]],
+ //propChanges[i].start);
+ //}
+ //}
+ //
+ //// Walk the styles in the target
+ //m = relevantStyles.length;
+ //for (j = 0; j < m; j++)
+ //{
+ //var styleName:String = relevantStyles[j];
+ //var startStyle:* = propChanges[i].start[styleName];
+ //var endStyle:* = propChanges[i].end[styleName];
+ //if (styleName in propChanges[i].start &&
+ //endStyle != startStyle &&
+ //(!(startStyle is Number) ||
+ //!(isNaN(endStyle) && isNaN(startStyle))) &&
+ //target is IStyleClient)
+ //{
+ //if (propChanges[i].end[relevantStyles[j]] !== undefined)
+ //target.setStyle(relevantStyles[j], propChanges[i].start[relevantStyles[j]]);
+ //else
+ //target.clearStyle(relevantStyles[j]);
+ //}
+ //}
+ //}
+ //}
+ }
+
+ /**
+ * @private
+ * Applies the start values found in the array of PropertyChanges
+ * to the relevant targets.
+ */
+ mx_internal function applyEndValues(propChanges:Array,
+ targets:Array):void
+ {
+ //// For now, only new Flex4 effects will apply end values when transitions
+ //// are over, to preserve the previous behavior of Flex3 effects
+ //if (!applyTransitionEndProperties)
+ //return;
+ //
+ //var effectProps:Array = relevantProperties;
+ //
+ //var n:int = propChanges.length;
+ //for (var i:int = 0; i < n; i++)
+ //{
+ //var m:int;
+ //var j:int;
+//
+ //var target:Object = propChanges[i].target;
+ //var apply:Boolean = false;
+ //
+ //m = targets.length;
+ //for (j = 0; j < m; j++)
+ //{
+ //if (targets[j] == target)
+ //{
+ //apply = filterInstance(propChanges, target);
+ //break;
+ //}
+ //}
+ //
+ //if (apply)
+ //{
+ //// Walk the properties in the target
+ //m = effectProps.length;
+ //for (j = 0; j < m; j++)
+ //{
+ //var propName:String = effectProps[j];
+ //var startVal:* = propChanges[i].start[propName];
+ //var endVal:* = propChanges[i].end[propName];
+ //if (propName in propChanges[i].end &&
+ //(!(endVal is Number) ||
+ //!(isNaN(endVal) && isNaN(startVal))))
+ //{
+ //applyValueToTarget(target, propName,
+ //propChanges[i].end[propName],
+ //propChanges[i].end);
+ //}
+ //}
+ //
+ //// Walk the styles in the target
+ //m = relevantStyles.length;
+ //for (j = 0; j < m; j++)
+ //{
+ //var styleName:String = relevantStyles[j];
+ //var startStyle:* = propChanges[i].start[styleName];
+ //var endStyle:* = propChanges[i].end[styleName];
+ //if (styleName in propChanges[i].end &&
+ //(!(endStyle is Number) ||
+ //!(isNaN(endStyle) && isNaN(startStyle))) &&
+ //target is IStyleClient)
+ //{
+ //if (propChanges[i].end[styleName] !== undefined)
+ //target.setStyle(styleName, propChanges[i].end[styleName]);
+ //else
+ //target.clearStyle(styleName);
+ //}
+ //}
+ //}
+ //}
+ }
}
}
diff --git a/frameworks/projects/MXRoyale/src/main/royale/mx/effects/EffectInstance.as b/frameworks/projects/MXRoyale/src/main/royale/mx/effects/EffectInstance.as
index 3a95608..fade0df 100644
--- a/frameworks/projects/MXRoyale/src/main/royale/mx/effects/EffectInstance.as
+++ b/frameworks/projects/MXRoyale/src/main/royale/mx/effects/EffectInstance.as
@@ -27,10 +27,10 @@ import flash.events.TimerEvent;
import flash.utils.Timer;
import flash.utils.getQualifiedClassName;
import flash.utils.getTimer;
-import mx.effects.effectClasses.PropertyChanges;
*/
+import mx.effects.effectClasses.PropertyChanges;
import mx.core.UIComponent;
import mx.core.mx_internal;
import mx.events.EffectEvent;
@@ -168,6 +168,32 @@ public class EffectInstance extends EventDispatcher implements IEffectInstance
}
+ /**
+ * @private
+ * Storage for the effect property.
+ */
+ private var _effect:IEffect;
+
+ /**
+ * @copy mx.effects.IEffectInstance#effect
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function get effect():IEffect
+ {
+ return _effect;
+ }
+
+ /**
+ * @private
+ */
+ public function set effect(value:IEffect):void
+ {
+ _effect = value;
+ }
//----------------------------------
// target
@@ -332,6 +358,295 @@ public class EffectInstance extends EventDispatcher implements IEffectInstance
}
}
+ /**
+ * Current time position of the effect.
+ * This property has a value between 0 and the total duration,
+ * which includes the Effect's <code>startDelay</code>,
+ * <code>repeatCount</code>, and <code>repeatDelay</code>.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function get playheadTime():Number
+ {
+ //return Math.max(playCount - 1, 0) * (duration + repeatDelay) +
+ //(playReversed ? 0 : startDelay);
+ return NaN;
+ }
+
+ /**
+ * @private
+ */
+ public function set playheadTime(value:Number):void
+ {
+ //if (delayTimer && delayTimer.running)
+ //{
+ //delayTimer.reset();
+ //if (value < startDelay)
+ //{
+ //delayTimer = new Timer(startDelay - value, 1);
+ //delayStartTime = getTimer();
+ //delayTimer.addEventListener(TimerEvent.TIMER, delayTimerHandler);
+ //delayTimer.start();
+ //}
+ //else
+ //{
+ //playCount = 0;
+ //play();
+ //}
+ //}
+ }
+
+ /**
+ * @copy mx.effects.IEffectInstance#pause()
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function pause():void
+ {
+ //if (delayTimer && delayTimer.running && !isNaN(delayStartTime))
+ //{
+ //delayTimer.stop(); // Pause the timer
+ //delayElapsedTime = getTimer() - delayStartTime;
+ //}
+ }
+
+ /**
+ * @copy mx.effects.IEffectInstance#stop()
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function stop():void
+ {
+ //if (delayTimer)
+ //delayTimer.reset();
+ //stopRepeat = true;
+ //// Dispatch STOP event in case listeners need to handle this situation
+ //// The Effect class may hinge setting final state values on whether
+ //// the effect was stopped or ended.
+ //dispatchEvent(new EffectEvent(EffectEvent.EFFECT_STOP,
+ //false, false, this));
+ //if (target && (target is IEventDispatcher))
+ //target.dispatchEvent(new EffectEvent(EffectEvent.EFFECT_STOP,
+ //false, false, this));
+ //finishEffect();
+ }
+
+ /**
+ * @copy mx.effects.IEffectInstance#resume()
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function resume():void
+ {
+ //if (delayTimer && !delayTimer.running && !isNaN(delayElapsedTime))
+ //{
+ //delayTimer.delay = !playReversed ? delayTimer.delay - delayElapsedTime : delayElapsedTime;
+ //delayStartTime = getTimer();
+ //delayTimer.start();
+ //}
+ }
+
+ /**
+ * @copy mx.effects.IEffectInstance#reverse()
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function reverse():void
+ {
+ //if (repeatCount > 0)
+ //playCount = repeatCount - playCount + 1;
+ }
+
+ /**
+ * @copy mx.effects.IEffectInstance#startEffect()
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function startEffect():void
+ {
+ //EffectManager.effectStarted(this);
+//
+ //if (target is UIComponent)
+ //{
+ //UIComponent(target).effectStarted(this);
+ //}
+ //
+ //if (startDelay > 0 && !playReversed)
+ //{
+ //delayTimer = new Timer(startDelay, 1);
+ //delayStartTime = getTimer();
+ //delayTimer.addEventListener(TimerEvent.TIMER, delayTimerHandler);
+ //delayTimer.start();
+ //}
+ //else
+ //{
+ //play();
+ //}
+ }
+
+ //----------------------------------
+ // playReversed
+ //----------------------------------
+
+ /**
+ * @private
+ * Storage for the playReversed property.
+ */
+ private var _playReversed:Boolean;
+
+ /**
+ * @private
+ * Used internally to specify whether or not this effect
+ * should be played in reverse.
+ * Set this value before you play the effect.
+ */
+ mx_internal function get playReversed():Boolean
+ {
+ return _playReversed;
+ }
+
+ //----------------------------------
+ // propertyChanges
+ //----------------------------------
+
+ /**
+ * @private
+ * Storage for the propertyChanges property.
+ */
+ private var _propertyChanges:PropertyChanges;
+
+ /**
+ * @copy mx.effects.IEffectInstance#propertyChanges
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function get propertyChanges():PropertyChanges
+ {
+ return _propertyChanges;
+ }
+
+ /**
+ * @private
+ */
+ public function set propertyChanges(value:PropertyChanges):void
+ {
+ _propertyChanges = value;
+ }
+
+
+ //----------------------------------
+ // repeatCount
+ //----------------------------------
+
+ /**
+ * @private
+ * Storage for the repeatCount property.
+ */
+ private var _repeatCount:int = 0;
+
+ /**
+ * @copy mx.effects.IEffectInstance#repeatCount
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function get repeatCount():int
+ {
+ return _repeatCount;
+ }
+
+ /**
+ * @private
+ */
+ public function set repeatCount(value:int):void
+ {
+ _repeatCount = value;
+ }
+
+ //----------------------------------
+ // repeatDelay
+ //----------------------------------
+
+ /**
+ * @private
+ * Storage for the repeatDelay property.
+ */
+ private var _repeatDelay:int = 0;
+
+ /**
+ * @copy mx.effects.IEffectInstance#repeatDelay
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function get repeatDelay():int
+ {
+ return _repeatDelay;
+ }
+
+ /**
+ * @private
+ */
+ public function set repeatDelay(value:int):void
+ {
+ _repeatDelay = value;
+ }
+
+ //----------------------------------
+ // startDelay
+ //----------------------------------
+
+ /**
+ * @private
+ * Storage for the startDelay property.
+ */
+ private var _startDelay:int = 0;
+
+ /**
+ * @copy mx.effects.IEffectInstance#startDelay
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function get startDelay():int
+ {
+ return _startDelay;
+ }
+
+ /**
+ * @private
+ */
+ public function set startDelay(value:int):void
+ {
+ _startDelay = value;
+ }
}
}
diff --git a/frameworks/projects/MXRoyale/src/main/royale/mx/effects/TweenEffect.as b/frameworks/projects/MXRoyale/src/main/royale/mx/effects/TweenEffect.as
index c9ff63f..2f2ab5b 100644
--- a/frameworks/projects/MXRoyale/src/main/royale/mx/effects/TweenEffect.as
+++ b/frameworks/projects/MXRoyale/src/main/royale/mx/effects/TweenEffect.as
@@ -205,7 +205,7 @@ public class TweenEffect extends Effect
/**
* @private
*/
- /* override */ protected function initInstance(instance:IEffectInstance):void
+ override protected function initInstance(instance:IEffectInstance):void
{
//super.initInstance(instance);
diff --git a/frameworks/projects/SparkRoyale/src/main/royale/SparkRoyaleClasses.as b/frameworks/projects/SparkRoyale/src/main/royale/SparkRoyaleClasses.as
index 8554576..b309abf 100644
--- a/frameworks/projects/SparkRoyale/src/main/royale/SparkRoyaleClasses.as
+++ b/frameworks/projects/SparkRoyale/src/main/royale/SparkRoyaleClasses.as
@@ -107,7 +107,7 @@ import spark.components.IItemRenderer; IItemRenderer;
//import spark.components.mediaClasses.ScrubBar; ScrubBar;
//import spark.components.mediaClasses.VolumeBar; VolumeBar;
import spark.components.supportClasses.ButtonBarHorizontalLayout; ButtonBarHorizontalLayout;
-//import spark.effects.AnimateColor; AnimateColor; // needed
+import spark.effects.AnimateColor; AnimateColor; // needed
import spark.effects.Fade; Fade;
//import spark.effects.Resize; Resize; // needed
//import spark.effects.SetAction; SetAction; // needed
diff --git a/frameworks/projects/SparkRoyale/src/main/royale/spark/effects/Animate.as b/frameworks/projects/SparkRoyale/src/main/royale/spark/effects/Animate.as
new file mode 100644
index 0000000..c8f2a13
--- /dev/null
+++ b/frameworks/projects/SparkRoyale/src/main/royale/spark/effects/Animate.as
@@ -0,0 +1,681 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+package spark.effects
+{
+import mx.core.mx_internal;
+import mx.effects.Effect;
+import mx.effects.IEffectInstance;
+import mx.events.EffectEvent;
+
+import spark.effects.animation.Animation;
+import spark.effects.animation.MotionPath;
+import spark.effects.animation.RepeatBehavior;
+import spark.effects.easing.IEaser;
+import spark.effects.easing.Sine;
+import spark.effects.interpolation.IInterpolator;
+import spark.effects.supportClasses.AnimateInstance;
+
+use namespace mx_internal;
+
+//--------------------------------------
+// Excluded APIs
+//--------------------------------------
+
+// Exclude suspendBackgroundProcessing for now because the Flex 4
+// effects depend on the layout validation work that the flag suppresses
+[Exclude(name="suspendBackgroundProcessing", kind="property")]
+
+
+[DefaultProperty("motionPaths")]
+
+/**
+ * Dispatched every time the effect updates the target.
+ *
+ * @eventType mx.events.EffectEvent.EFFECT_UPDATE
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+[Event(name="effectUpdate", type="mx.events.EffectEvent")]
+
+/**
+ * Dispatched when the effect begins a new repetition, for
+ * any effect that is repeated more than once.
+ * Flex also dispatches an <code>effectUpdate</code> event
+ * for the effect at the same time.
+ *
+ * @eventType mx.events.EffectEvent.EFFECT_REPEAT
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+[Event(name="effectRepeat", type="mx.events.EffectEvent")]
+
+
+/**
+ * This Animate effect animates an arbitrary set of properties between values.
+ * Specify the properties and values to animate by setting the <code>motionPaths</code> property.
+ *
+ * @mxml
+ *
+ * <p>The <code><s:Animate></code> tag
+ * inherits all of the tag attributes of its superclass,
+ * and adds the following tag attributes:</p>
+ *
+ * <pre>
+ * <s:Animate
+ * <b>Properties</b>
+ * id="ID"
+ * disableLayout="false"
+ * easer="{spark.effects.easing.Sine(.5)}"
+ * interpolator="NumberInterpolator"
+ * motionPaths="no default"
+ * repeatBehavior="loop"
+ * />
+ * </pre>
+ *
+ * @see spark.effects.supportClasses.AnimateInstance
+ *
+ * @includeExample examples/AnimateEffectExample.mxml
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+public class Animate extends Effect
+{
+ //include "../core/Version.as";
+
+ //--------------------------------------------------------------------------
+ //
+ // Constructor
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Constructor.
+ *
+ * @param target The Object to animate with this effect.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function Animate(target:Object = null)
+ {
+ super(target);
+
+ instanceClass = AnimateInstance;
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // Variables
+ //
+ //--------------------------------------------------------------------------
+
+ // Cached version of the affected properties. By default, we simply return
+ // the list of properties specified in the motionPaths Vector.
+ // Subclasses should override getAffectedProperties() if they wish to
+ // specify a different set.
+ private var affectedProperties:Array = null;
+
+ // Cached version of the relevant styles. By default, we simply return
+ // the list of properties specified in the motionPaths Vector.
+ // Subclasses should override relevantStyles() if they wish to
+ // specify a different set.
+ private var _relevantStyles:Array = null;
+
+ // Cached default easer. We only need one of these, so we cache this static
+ // object to be reused by any Animate instances that do not specify
+ // a custom easer.
+ private static var defaultEaser:IEaser = new Sine(.5);
+
+ // Used to optimize event dispatching: only send out updated events if
+ // there is someone listening
+ private var numUpdateListeners:int = 0;
+
+
+ //--------------------------------------------------------------------------
+ //
+ // Properties
+ //
+ //--------------------------------------------------------------------------
+
+ //----------------------------------
+ // motionPaths
+ //----------------------------------
+ /**
+ * @private
+ * Storage for the motionPaths property.
+ */
+ private var _motionPaths:Vector.<MotionPath>;
+ /**
+ * A Vector of MotionPath objects, each of which holds the
+ * name of a property being animated and the values that the property
+ * takes during the animation.
+ * This Vector takes precedence over
+ * any properties declared in subclasses of Animate.
+ * For example, if this Array is set directly on a Move effect,
+ * then any properties of the Move effect, such as <code>xFrom</code>, are ignored.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function get motionPaths():Vector.<MotionPath>
+ {
+ return _motionPaths;
+ }
+ /**
+ * @private
+ */
+ public function set motionPaths(value:Vector.<MotionPath>):void
+ {
+ _motionPaths = value;
+ }
+
+ //----------------------------------
+ // easer
+ //----------------------------------
+ /**
+ * @private
+ * Storage for the easer property.
+ */
+ private var _easer:IEaser = defaultEaser;
+ /**
+ * The easing behavior for this effect.
+ * This IEaser object is used to convert the elapsed fraction of
+ * the animation into an eased fraction, which is then used to
+ * calculate the value at that eased elapsed fraction.
+ *
+ * <p>Note that it is possible to have easing at both the effect
+ * level and the Keyframe level (where Keyframes hold the values/times
+ * used in the MotionPath structures).
+ * These easing behaviors build on each other.
+ * The <code>easer</code> controls the easing of the overall effect.
+ * The Keyframe controls the easing in any particular interval of the animation.
+ * By default, the easing for Animate is non-linear (Sine(.5)).
+ * The easing for Keyframes is linear. If you desire an effect with easing
+ * at the keyframe level instead, you can set the easing of the
+ * effect to linear, and then set the easing specifically on the Keyframes.</p>
+ *
+ * @default spark.effects.easing.Sine(.5)
+ *
+ * @see spark.effects.easing.Sine
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function get easer():IEaser
+ {
+ return _easer;
+ }
+ /**
+ * @private
+ */
+ public function set easer(value:IEaser):void
+ {
+ _easer = value;
+ }
+
+ //----------------------------------
+ // interpolator
+ //----------------------------------
+ /**
+ * @private
+ * Storage for the interpolator property.
+ */
+ private var _interpolator:IInterpolator = null;
+ /**
+ * The interpolator used by this effect to calculate values between
+ * the start and end values of a property.
+ * By default, the NumberInterpolator class handles interpolation
+ * or, in the case of the start
+ * and end values being Arrays or Vectors, by the
+ * MultiValueInterpolator class.
+ * Interpolation of other types, or of Numbers that should be interpolated
+ * differently, such as <code>uint</code> values that hold color
+ * channel information, can be handled by supplying a different
+ * interpolator.
+ *
+ * @see spark.effects.interpolation.NumberInterpolator
+ * @see spark.effects.interpolation.MultiValueInterpolator
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function get interpolator():IInterpolator
+ {
+ return _interpolator;
+ }
+ /**
+ * @private
+ */
+ public function set interpolator(value:IInterpolator):void
+ {
+ _interpolator = value;
+ }
+
+ //----------------------------------
+ // repeatBehavior
+ //----------------------------------
+ /**
+ * @private
+ * Storage for the repeatBehavior property.
+ */
+ private var _repeatBehavior:String = RepeatBehavior.LOOP;
+
+ [Inspectable(category="General", enumeration="loop,reverse", defaultValue="loop" )]
+
+ /**
+ * The behavior of a repeating effect, which means an effect
+ * with <code>repeatCount</code> equal to either 0 or > 1. This
+ * value should be either <code>RepeatBehavior.LOOP</code>, which means the animation
+ * repeats in the same order each time, or <code>RepeatBehavior.REVERSE</code>,
+ * which means the animation reverses direction on each iteration.
+ *
+ * @default RepeatBehavior.LOOP
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function get repeatBehavior():String
+ {
+ return _repeatBehavior;
+ }
+ /**
+ * @private
+ */
+ public function set repeatBehavior(value:String):void
+ {
+ _repeatBehavior = value;
+ }
+
+ //----------------------------------
+ // disableLayout
+ //----------------------------------
+ /**
+ * @private
+ * Storage for the disableLayout property.
+ */
+ private var _disableLayout:Boolean = false;
+ /**
+ * If <code>true</code>, the effect disables layout on its
+ * targets' parent containers, setting the containers <code>autoLayout</code>
+ * property to false, and also disables any layout constraints on the
+ * target objects. These properties are restored when the effect
+ * finishes.
+ *
+ * @default false
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function get disableLayout():Boolean
+ {
+ return _disableLayout;
+ }
+ /**
+ * @private
+ */
+ public function set disableLayout(value:Boolean):void
+ {
+ _disableLayout = value;
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // Methods
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ */
+ override public function getAffectedProperties():Array /* of String */
+ {
+ if (!affectedProperties)
+ {
+ if (motionPaths)
+ {
+ var horizontalMove:Boolean;
+ var verticalMove:Boolean;
+ affectedProperties = new Array();
+ for (var i:int = 0; i < motionPaths.length; ++i)
+ {
+ var effectHolder:MotionPath = MotionPath(motionPaths[i]);
+ affectedProperties.push(effectHolder.property);
+ // Some properties side-affect others: add them to the list
+ switch (effectHolder.property)
+ {
+ // left/right/top/bottom side-effect x/y/width/height
+ case "left":
+ case "right":
+ case "horizontalCenter":
+ horizontalMove = true;
+ break;
+ case "top":
+ case "bottom":
+ case "verticalCenter":
+ verticalMove = true;
+ break;
+ // The next two let us capture the explicit values, so that we
+ // can restore them if necessary when the effect ends
+ case "width":
+ if (affectedProperties.indexOf("explicitWidth") < 0)
+ affectedProperties.push("explicitWidth");
+ if (affectedProperties.indexOf("percentWidth") < 0)
+ affectedProperties.push("percentWidth");
+ break;
+ case "height":
+ if (affectedProperties.indexOf("explicitHeight") < 0)
+ affectedProperties.push("explicitHeight");
+ if (affectedProperties.indexOf("percentHeight") < 0)
+ affectedProperties.push("percentHeight");
+ break;
+ }
+ }
+ if (horizontalMove)
+ {
+ if (affectedProperties.indexOf("x") < 0)
+ affectedProperties.push("x");
+ if (affectedProperties.indexOf("width") < 0)
+ affectedProperties.push("width");
+ if (affectedProperties.indexOf("explicitWidth") < 0)
+ affectedProperties.push("explicitWidth");
+ }
+ if (verticalMove)
+ {
+ if (affectedProperties.indexOf("y") < 0)
+ affectedProperties.push("y");
+ if (affectedProperties.indexOf("height") < 0)
+ affectedProperties.push("height");
+ if (affectedProperties.indexOf("explicitHeight") < 0)
+ affectedProperties.push("explicitHeight");
+ }
+ }
+ else
+ {
+ affectedProperties = [];
+ }
+ }
+ return affectedProperties;
+ }
+
+ /**
+ * @private
+ */
+ override public function get relevantStyles():Array /* of String */
+ {
+ if (!_relevantStyles)
+ {
+ if (motionPaths)
+ {
+ _relevantStyles = new Array(motionPaths.length);
+ for (var i:int = 0; i < motionPaths.length; ++i)
+ {
+ var effectHolder:MotionPath = MotionPath(motionPaths[i]);
+ _relevantStyles[i] = effectHolder.property;
+ }
+ }
+ else
+ {
+ _relevantStyles = [];
+ }
+ }
+ return _relevantStyles;
+ }
+
+ /**
+ * @private
+ */
+ override protected function initInstance(instance:IEffectInstance):void
+ {
+ super.initInstance(instance);
+
+ var animateInstance:AnimateInstance = AnimateInstance(instance);
+
+ //animateInstance.addEventListener(EffectEvent.EFFECT_REPEAT, animationEventHandler);
+ // Optimization: don't bother listening for update events if we don't have
+ // any listeners for that event
+ //if (numUpdateListeners > 0)
+ //animateInstance.addEventListener(EffectEvent.EFFECT_UPDATE, animationEventHandler);
+
+ if (easer)
+ animateInstance.easer = easer;
+
+ if (interpolator)
+ animateInstance.interpolator = interpolator;
+
+ //if (isNaN(repeatCount))
+ //animateInstance.repeatCount = repeatCount;
+
+ animateInstance.repeatBehavior = repeatBehavior;
+ animateInstance.disableLayout = disableLayout;
+
+ if (motionPaths)
+ {
+ animateInstance.motionPaths = new Vector.<MotionPath>();
+ for (var i:int = 0; i < motionPaths.length; ++i)
+ animateInstance.motionPaths[i] = motionPaths[i].clone();
+ }
+ }
+
+
+ /**
+ * @private
+ */
+ override protected function applyValueToTarget(target:Object, property:String,
+ value:*, props:Object):void
+ {
+ if (property in target)
+ {
+ // The "property in target" test only tells if the property exists
+ // in the target, but does not distinguish between read-only and
+ // read-write properties. Put a try/catch around the setter and
+ // ignore any errors.
+ try
+ {
+ target[property] = value;
+ }
+ catch(e:Error)
+ {
+ // Ignore errors
+ }
+ }
+ }
+
+ /**
+ * @private
+ * Track number of listeners to update event for optimization purposes
+ */
+ override public function addEventListener(type:String, handler:Function, opt_capture:Boolean = false, opt_handlerScope:Object = null):void
+ {
+ super.addEventListener(type, handler, opt_capture, opt_handlerScope);
+ //if (type == EffectEvent.EFFECT_UPDATE)
+ //++numUpdateListeners;
+ }
+
+ /**
+ * @private
+ * Track number of listeners to update event for optimization purposes
+ */
+ override public function removeEventListener(type:String, handler:Function, opt_capture:Boolean = false, opt_handlerScope:Object = null):void
+ {
+ super.removeEventListener(type, handler, opt_capture, opt_handlerScope);
+ //if (type == EffectEvent.EFFECT_UPDATE)
+ //--numUpdateListeners;
+ }
+
+ /**
+ * @private
+ * Called when the AnimateInstance object dispatches an EffectEvent.
+ *
+ * @param event An event object of type EffectEvent.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ private function animationEventHandler(event:EffectEvent):void
+ {
+ dispatchEvent(event);
+ }
+
+ /**
+ * @private
+ * Tell the propertyChanges array to keep all values, unchanged or not.
+ * This enables us to check later, when the effect is finished, whether
+ * we need to restore explicit height/width values.
+ */
+ override mx_internal function captureValues(propChanges:Array,
+ setStartValues:Boolean,
+ targetsToCapture:Array = null):Array
+ {
+ var propertyChanges:Array =
+ super.captureValues(propChanges, setStartValues, targetsToCapture);
+
+ // If we're capturing explicitWidth/Height values, don't strip unchanging
+ // values from propertyChanges; we want to know whether these values should
+ // be restored when the effect ends
+ var explicitValuesCaptured:Boolean =
+ getAffectedProperties().indexOf("explicitWidth") >= 0 ||
+ getAffectedProperties().indexOf("explicitHeight") >= 0;
+ if (explicitValuesCaptured && setStartValues)
+ {
+ var n:int = propertyChanges.length;
+ for (var i:int = 0; i < n; i++)
+ {
+ if (targetsToCapture == null || targetsToCapture.length == 0 ||
+ targetsToCapture.indexOf(propertyChanges[i].target) >= 0)
+ {
+ propertyChanges[i].stripUnchangedValues = false;
+ }
+ }
+ }
+ return propertyChanges;
+ }
+
+ /**
+ * @private
+ * After applying start values, check to see whether the values
+ * contain percentWidth/percentHeight, which should be applied
+ * after any width/height/explicitWidth/explicitHeight values.
+ */
+ override mx_internal function applyStartValues(propChanges:Array,
+ targets:Array):void
+ {
+ super.applyStartValues(propChanges, targets);
+ // Special case for percentWidth/Height properties. If we are watching
+ // width/explicitWidth or height/explicitHeight values and also
+ // percentWidth/Height values, we have to make sure to apply the
+ // percent values last to avoid having them get clobbered by
+ // applying the width/height values. We could either sort the
+ // propChanges array or just make sure the re-apply the percent
+ // values here, after we're done with the rest.
+ if (propChanges)
+ {
+ var n:int = propChanges.length;
+ for (var i:int = 0; i < n; i++)
+ {
+ var target:Object = propChanges[i].target;
+ if (propChanges[i].start["percentWidth"] !== undefined &&
+ "percentWidth" in target)
+ {
+ target.percentWidth = propChanges[i].start["percentWidth"];
+ }
+ if (propChanges[i].start["percentHeight"] !== undefined &&
+ "percentHeight" in target)
+ {
+ target.percentHeight = propChanges[i].start["percentHeight"];
+ }
+ }
+ }
+ }
+
+ /**
+ * @private
+ * When we're done, check to see whether explicitWidth/Height values
+ * for the target are NaN in the end state. If so, we should restore
+ * them to that value. This ensures that the target will be sized by
+ * its layout manager instead of by the width/height set during
+ * the effect.
+ */
+ override mx_internal function applyEndValues(propChanges:Array,
+ targets:Array):void
+ {
+ super.applyEndValues(propChanges, targets);
+ // Special case for animating width/height during a transition, because
+ // we may have clobbered the explicitWidth/Height values which otherwise
+ // would not have been set. We need to restore these values plus any
+ // associated layout constraint values (percentWidth/Height)
+ if (propChanges)
+ {
+ var n:int = propChanges.length;
+ for (var i:int = 0; i < n; i++)
+ {
+ var target:Object = propChanges[i].target;
+ if (propChanges[i].end["explicitWidth"] !== undefined)
+ {
+ if (isNaN(propChanges[i].end["explicitWidth"]) &&
+ "explicitWidth" in target)
+ {
+ target.explicitWidth = NaN;
+ if (propChanges[i].end["percentWidth"] !== undefined &&
+ "percentWidth" in target)
+ {
+ target.percentWidth = propChanges[i].end["percentWidth"];
+ }
+ }
+ }
+ if (propChanges[i].end["explicitHeight"] !== undefined)
+ {
+ if (isNaN(propChanges[i].end["explicitHeight"]) &&
+ "explicitHeight" in target)
+ {
+ target.explicitHeight = NaN;
+ if (propChanges[i].end["percentHeight"] !== undefined &&
+ "percentHeight" in target)
+ {
+ target.percentHeight = propChanges[i].end["percentHeight"];
+ }
+ }
+ }
+ }
+ }
+ }
+}
+}
diff --git a/frameworks/projects/SparkRoyale/src/main/royale/spark/effects/animation/Animation.as b/frameworks/projects/SparkRoyale/src/main/royale/spark/effects/animation/Animation.as
new file mode 100644
index 0000000..917231a
--- /dev/null
+++ b/frameworks/projects/SparkRoyale/src/main/royale/spark/effects/animation/Animation.as
@@ -0,0 +1,1415 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+package spark.effects.animation
+{
+import org.apache.royale.events.Event;
+import org.apache.royale.utils.Timer;
+
+import mx.core.mx_internal;
+import mx.events.EffectEvent;
+import mx.resources.IResourceManager;
+import mx.resources.ResourceManager;
+
+import spark.effects.easing.IEaser;
+import spark.effects.easing.Linear;
+import spark.effects.easing.Sine;
+import spark.effects.interpolation.IInterpolator;
+
+use namespace mx_internal;
+
+[DefaultProperty("motionPaths")]
+
+//--------------------------------------
+// Other metadata
+//--------------------------------------
+
+[ResourceBundle("sparkEffects")]
+
+/**
+ * The Animation class defines an animation that happens between
+ * the start and end values of a property over a specified period of time.
+ * The animation can be a change in position, such as performed by
+ * the Move effect; a change in size, as performed by the Resize effect;
+ * a change in visibility, as performed by the Fade effect; or other
+ * types of animations used by effects or run directly with the Animation class.
+ *
+ * <p>This class defines the timing and value parts of the animation.
+ * Other code, either in effects or in application code, associates the animation
+ * with target objects and properties, such that the animated values produced by
+ * Animation class can then be applied to target objects and properties to actually
+ * cause these objects to animate.</p>
+ *
+ * <p>When defining animation effects, you typically create an
+ * instance of the Animate class, or of a subclass of Animate. This creates
+ * an Animation instance in the <code>play()</code> method. The Animation instance
+ * accepts start and end values, a duration, and optional parameters such as
+ * easer and interpolator objects.</p>
+ *
+ * <p>The Animation object calls event listeners at the start and end of the animation,
+ * when the animation repeats, and at regular update intervals during
+ * the animation. These calls pass values which the Animation instance calculated from
+ * the start and end values and the easer and interpolator objects. These
+ * values can then be used to set property values on target objects.</p>
+ *
+ * @see spark.effects.Animate
+ * @see spark.effects.supportClasses.AnimateInstance
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+public final class Animation
+{
+ //include "../../core/Version.as";
+
+ //--------------------------------------------------------------------------
+ //
+ // Class Constants
+ //
+ //--------------------------------------------------------------------------
+
+ private static const TIMER_RESOLUTION:Number = 1000 / 60; // 60 fps
+
+ //--------------------------------------------------------------------------
+ //
+ // Constructor
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Constructor.
+ * The optional <code>property</code>, <code>startValue</code>, and
+ * <code>endValue</code> parameters define a simple
+ * animation with a single MotionPath object with two Keyframes.
+ * If either value is non-null,
+ * <code>startValue</code> becomes the <code>value</code> of the
+ * first keyframe, at time=0, and
+ * <code>endValue</code> becomes the <code>value</code> of
+ * the second keyframe, at the end of the animation.
+ *
+ * @param duration The length of the animation, in milliseconds.
+ *
+ * @param property The property to animate.
+ *
+ * @param startValue The initial value of the property.
+ *
+ * @param endValue The final value of the property.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function Animation(duration:Number = 500, property:String = null,
+ startValue:Object = null, endValue:Object = null)
+ {
+ this.duration = duration;
+ if (property != null && (startValue !== null || endValue !== null))
+ {
+ motionPaths = new <MotionPath>[new MotionPath(property)];
+ motionPaths[0].keyframes = new <Keyframe>[new Keyframe(0, startValue),
+ new Keyframe(duration, endValue)];
+ }
+ }
+
+
+ //--------------------------------------------------------------------------
+ //
+ // Class variables
+ //
+ //--------------------------------------------------------------------------
+
+
+ /**
+ * @private
+ *
+ * The time being used in the current frame calculations. This time is
+ * shared by all active animations.
+ */
+ private static var intervalTime:Number = NaN;
+
+ // A single Timer object runs all animations in the process
+ private static var activeAnimations:Vector.<Animation> = new Vector.<Animation>;
+ private static var timer:Timer = null;
+
+ /**
+ * @private
+ * Default easer used if easer is set to null
+ */
+ private static var linearEaser:IEaser;
+
+ private var id:int = -1;
+ private var _doSeek:Boolean = false;
+ private var _isPlaying:Boolean = false;
+ private var _doReverse:Boolean = false;
+ private var _invertValues:Boolean = false;
+ // Original start time of animation
+ private var startTime:Number;
+ private var started:Boolean = false;
+ // Time when the current cycle started
+ private var cycleStartTime:Number;
+ // The amount of time that the animation should delay before
+ // starting. This is set to a non-negative number only when
+ // an Animation is paused during its startDelay phase
+ private var delayTime:Number = -1;
+ private static var defaultEaser:IEaser = new Sine(.5);
+ private static var delayedStartAnims:Vector.<Animation> =
+ new Vector.<Animation>();
+ private static var delayedStartTimes:Object = new Object();
+
+
+ /**
+ * @private
+ * Used for accessing localized Error messages.
+ */
+ private var resourceManager:IResourceManager =
+ ResourceManager.getInstance();
+
+
+ //--------------------------------------------------------------------------
+ //
+ // Properties
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * An Object containing the calculated values as of the current frame
+ * of the Animation.
+ * The values are stored as map values, using property names as the key.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public var currentValue:Object;
+
+ /**
+ * The set of MotionPath objects that define the properties and values
+ * that the Animation will animate over time.
+ *
+ * @see spark.effects.animation.MotionPath
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public var motionPaths:Vector.<MotionPath>;
+
+ //----------------------------------
+ // animationTarget
+ //----------------------------------
+ /**
+ * @private
+ * Storage for the animationTarget property.
+ */
+ private var _animationTarget:IAnimationTarget = null;
+ /**
+ * The IAnimationTarget object notified with all
+ * start, end, repeat, and update events for this animation.
+ * A value of <code>null</code> indicates that there is no target
+ * to notify.
+ *
+ * @default null
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function get animationTarget():IAnimationTarget
+ {
+ return _animationTarget;
+ }
+ public function set animationTarget(value:IAnimationTarget):void
+ {
+ _animationTarget = value;
+ }
+
+ //----------------------------------
+ // playheadTime
+ //----------------------------------
+ /**
+ * @private
+ * Storage for the animationTarget property.
+ */
+ private var _playheadTime:Number;
+
+ [Inspectable(minValue="0.0")]
+
+
+ /**
+ * The total elapsed time of the animation, including any start delay
+ * and repetitions. For an animation playing through its first cycle,
+ * this value will equal that of <code>cycleTime</code>.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function get playheadTime():Number
+ {
+ return _playheadTime + startDelay;
+ }
+ public function set playheadTime(value:Number):void
+ {
+ seek(value, true);
+ }
+ /**
+ * If <code>true</code>, the animation is currently playing.
+ * The value is <code>false</code> unless the animation
+ * has been played and not yet stopped (either programmatically or
+ * automatically) or paused.
+ *
+ * @default false
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function get isPlaying():Boolean
+ {
+ return _isPlaying;
+ }
+
+ [Inspectable(minValue="0.0")]
+
+ /**
+ * The length of time, in milliseconds, of the animation,
+ * not counting any repetitions defined by
+ * the <code>repeatCount</code> property.
+ *
+ * @default 500
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public var duration:Number = 500;
+
+ //----------------------------------
+ // repeatBehavior
+ //----------------------------------
+ /**
+ * @private
+ * Storage for the repeatBehavior property.
+ */
+ private var _repeatBehavior:String = RepeatBehavior.LOOP;
+ /**
+ * Sets the behavior of a repeating animation.
+ * A repeating animation has the
+ * <code>repeatCount</code> property set to 0 or to a value greater than 1.
+ * This value should be either <code>RepeatBehavior.LOOP</code>,
+ * meaning the animation repeats in the same order each time, or
+ * <code>RepeatBehavior.REVERSE</code>,
+ * meaning the animation reverses direction for each iteration.
+ *
+ * @default RepeatBehavior.LOOP
+ *
+ * @see spark.effects.animation.RepeatBehavior
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function get repeatBehavior():String
+ {
+ return _repeatBehavior;
+ }
+ public function set repeatBehavior(value:String):void
+ {
+ _repeatBehavior = value;
+ }
+
+ //----------------------------------
+ // repeatCount
+ //----------------------------------
+
+ /**
+ * @private
+ * Storage for the repeatCount property.
+ */
+ private var _repeatCount:int = 1;
+
+ [Inspectable(minValue="0")]
+
+ /**
+ * The number of times that this animation repeats.
+ * A value of 0 means that it repeats indefinitely.
+ *
+ * @default 1
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function set repeatCount(value:int):void
+ {
+ _repeatCount = value;
+ }
+ public function get repeatCount():int
+ {
+ return _repeatCount;
+ }
+
+ //----------------------------------
+ // repeatDelay
+ //----------------------------------
+
+ /**
+ * @private
+ * Storage for the repeatDelay property.
+ */
+ private var _repeatDelay:Number = 0;
+
+ [Inspectable(minValue="0.0")]
+
+ /**
+ * The amount of time, in milliseconds, to delay before each repetition cycle
+ * begins. Setting this value to a non-zero number
+ * ends previous animation cycle exactly at its end value
+ * However, non-delayed repetitions may skip over that
+ * value completely as the animation transitions smoothly from being
+ * near the end of one cycle to being past the beginning of the next.
+ * This property must be a value >= 0.
+ *
+ * <p>This property is used for the first repetition
+ * after the first animation cycle.
+ * To delay the first cycle of the animation, use
+ * the <code>startDelay</code> property. </p>
+ *
+ * @see #startDelay
+ *
+ * @default 0
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function set repeatDelay(value:Number):void
+ {
+ _repeatDelay = value;
+ }
+ public function get repeatDelay():Number
+ {
+ return _repeatDelay;
+ }
+
+ /**
+ * @private
+ * Storage for the startDelay property.
+ */
+ private var _startDelay:Number = 0;
+
+ [Inspectable(minValue="0.0")]
+
+ /**
+ * The amount of time spent waiting before the animation
+ * begins.
+ * This property must be a value >= 0.
+ *
+ * @default 0
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function set startDelay(value:Number):void
+ {
+ _startDelay = value;
+ }
+ public function get startDelay():Number
+ {
+ return _startDelay;
+ }
+
+ //----------------------------------
+ // interpolator
+ //----------------------------------
+
+ /**
+ * The interpolator used by the Animation instance
+ * to calculate values between
+ * the start and end values of the property.
+ * By default, the class uses the NumberInterpolator class or,
+ * in the case of the start and end values being arrays or Vectors,
+ * by the MultiValueInterpolator class.
+ * Interpolation of other data types, or
+ * of Numbers that should be interpolated
+ * differently, such as <code>uint</code> values that hold color
+ * channel information, can be handled by supplying a different
+ * interpolator.
+ *
+ * @see spark.effects.interpolation.NumberInterpolator
+ * @see spark.effects.interpolation.MultiValueInterpolator
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public var interpolator:IInterpolator = null;
+
+ //----------------------------------
+ // cycleTime
+ //----------------------------------
+
+ private var _cycleTime:Number = 0;
+ /**
+ * The current millisecond position in the current cycle animation.
+ * This value is between 0 and <code>duration</code>.
+ * An animation 'cycle' is defined as a single repetition of the animation,
+ * where the <code>repeatCount</code> property defines the number of
+ * cycles that will be played.
+ * Use the <code>seek()</code> method to change the position of the animation.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function get cycleTime():Number
+ {
+ return _cycleTime;
+ }
+
+
+ //----------------------------------
+ // cycleFraction
+ //----------------------------------
+
+ private var _cycleFraction:Number;
+ /**
+ * The current fraction elapsed in the animation, after easing
+ * has been applied. This value is between 0 and 1.
+ * An animation 'cycle' is defined as a single repetition of the animation,
+ * where the <code>repeatCount</code> property defines the number of
+ * cycles that will be played.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function get cycleFraction():Number
+ {
+ return _cycleFraction;
+ }
+
+ //----------------------------------
+ // easer
+ //----------------------------------
+
+ /**
+ * @private
+ * Storage for the easer property.
+ */
+ private var _easer:IEaser = defaultEaser;
+ /**
+ * The easing behavior for this effect.
+ * This IEaser object is used to convert the elapsed fraction of the animation
+ * into an eased fraction, which is then used to calculate
+ * the value at that eased elapsed fraction.
+ *
+ * <p>A value of <code>null</code> means no easing is
+ * used, which is equivalent to using a Linear ease, or
+ * <code>animation.easer = Linear.getInstance();</code>.</p>
+ *
+ * @default Sine(.5)
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function get easer():IEaser
+ {
+ return _easer;
+ }
+ /**
+ * @private
+ */
+ public function set easer(value:IEaser):void
+ {
+ if (!value)
+ {
+ if (!linearEaser)
+ linearEaser = new Linear();
+ value = linearEaser;
+ }
+ _easer = value;
+ }
+
+ //----------------------------------
+ // playReversed
+ //----------------------------------
+
+ /**
+ * @private
+ * Storage for the playReversed property
+ */
+ private var _playReversed:Boolean;
+ /**
+ * If <code>true</code>, play the animation in reverse.
+ * If the animation is currently playing in the opposite
+ * direction to the specified value of <code>playReversed</code>,
+ * the animation will change direction dynamically.
+ *
+ * @default false
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function get playReversed():Boolean
+ {
+ return _playReversed;
+ }
+ /**
+ * @private
+ */
+ public function set playReversed(value:Boolean):void
+ {
+ if (_isPlaying)
+ {
+ if (_invertValues != value)
+ {
+ _invertValues = value;
+ seek(duration - _cycleTime, true);
+ }
+ }
+ _doReverse = value;
+ _playReversed = value;
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // Methods
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Adds a new animation instance to the system.
+ * All animations run off the same Timer instance,
+ * so starting any one animation simply adds it onto the
+ * static list of active animations.
+ *
+ * @param animation The Animation object.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ private static function addAnimation(animation:Animation):void
+ {
+
+ // Because of how autoCenterTransform works, depending on the
+ // current size of the object for a correct calculation, we
+ // should ensure that any size-changing animations are processed
+ // first in each frame, so each new animation gets inserted at the
+ // front it if deals with width or height. Note that this will
+ // only work for Resize effects, which only animate width/height.
+ // We do not exhaustively search all motionPaths of any given animation.
+ if (animation.motionPaths && animation.motionPaths.length > 0 &&
+ animation.motionPaths[0] &&
+ (animation.motionPaths[0].property == "width" ||
+ animation.motionPaths[0].property == "height"))
+ {
+ activeAnimations.splice(0, 0, animation);
+ animation.id = 0;
+ for (var i:int = 1; i < activeAnimations.length; ++i)
+ Animation(activeAnimations[i]).id = i;
+ }
+ else
+ {
+ animation.id = activeAnimations.length;
+ activeAnimations.push(animation);
+ }
+
+ if (!timer)
+ {
+ //Timeline.pulse();
+ timer = new Timer(TIMER_RESOLUTION);
+ timer.addEventListener("timer", timerHandler);
+ timer.start();
+ }
+
+ //intervalTime = Timeline.currentTime;
+
+ animation.cycleStartTime = intervalTime;
+ }
+
+ private static function removeAnimationAt(index:int):void
+ {
+ if (index >= 0 && index < activeAnimations.length)
+ {
+ activeAnimations.splice(index, 1);
+
+ var n:int = activeAnimations.length;
+ for (var i:int = index; i < n; i++)
+ {
+ var curAnimation:Animation = Animation(activeAnimations[i]);
+ curAnimation.id--;
+ }
+ }
+ stopTimerIfDone();
+ }
+
+ /**
+ * @private
+ */
+ private static function removeAnimation(animation:Animation):void
+ {
+ removeAnimationAt(animation.id);
+ }
+
+ private static function timerHandler(event:Event):void
+ {
+ var oldTime:Number = intervalTime;
+ //intervalTime = Timeline.pulse();
+
+ var n:int = activeAnimations.length;
+ var i:int = 0;
+
+ while (i < activeAnimations.length)
+ {
+ // only increment index into array if no animation was stopped
+ // as a result to call to doInterval(). Stopped animations
+ // will be removed from the array and everything after them
+ // shifts down
+ var incrementIndex:Boolean = true;
+ var animation:Animation = Animation(activeAnimations[i]);
+ if (animation)
+ incrementIndex = !animation.doInterval();
+ if (incrementIndex)
+ ++i;
+ }
+
+ // Check to see whether it's time to start any delayed animations
+ while (delayedStartAnims.length > 0)
+ {
+ // This loop will either start() an animation, which removes it
+ // from delayedStartAnims, or it will break out. In either case,
+ // we only check against the first item in the list each time
+ // through because any previous iteration will have removed the
+ // item that was at index 0
+ var anim:Animation = Animation(delayedStartAnims[0]);
+ var animStartTime:Number = delayedStartTimes[anim];
+ // Keep starting animations unless our sorted lists return
+ // animations that start past the current time
+ //if (animStartTime < Timeline.currentTime)
+ //if (anim.playReversed)
+ //anim.end();
+ //else
+ //anim.start();
+ //else
+ //break;
+ }
+ //event.updateAfterEvent();
+ }
+
+ /**
+ * @private
+ *
+ * Calculates the time and elapsed fraction, then gets the
+ * appropriate interpolated value at that fraction, then sends out
+ * the animation event to all listeners.
+ *
+ * Returns true if the animation has ended.
+ */
+ private function doInterval():Boolean
+ {
+ var animationEnded:Boolean = false;
+ var repeated:Boolean = false;
+
+ if (_isPlaying || _doSeek)
+ {
+
+ var currentTime:Number = intervalTime - cycleStartTime;
+ _playheadTime = intervalTime - startTime;
+ if (currentTime >= duration)
+ {
+ // numRepeats reflects the current repetition cycle that we're going to
+ // be in, once we repeat.
+ var numRepeats:int = 2;
+ if ((duration + repeatDelay) > 0)
+ numRepeats += (_playheadTime - duration) / (duration + repeatDelay);
+ if (repeatCount == 0 || numRepeats <= repeatCount)
+ {
+ if (repeatDelay == 0)
+ {
+ _cycleTime = currentTime % duration;
+ cycleStartTime = intervalTime - _cycleTime;
+ currentTime = _cycleTime;
+ if (repeatBehavior == RepeatBehavior.REVERSE)
+ _invertValues = !_invertValues;
+ repeated = true;
+ }
+ else
+ {
+ if (_doSeek)
+ {
+ _cycleTime = currentTime % (duration + repeatDelay);
+ if (_cycleTime > duration)
+ _cycleTime = duration; // must be in repeatDelay phase
+ calculateValue(_cycleTime);
+ sendUpdateEvent();
+ return false;
+ }
+ else
+ {
+ // repeatDelay: send out a final update for this cycle with the
+ // end value, then schedule a timer to wake up and
+ // start the next cycle
+ _cycleTime = duration;
+ calculateValue(_cycleTime);
+ sendUpdateEvent();
+ removeAnimation(this);
+ var delayTimer:Timer = new Timer(repeatDelay, 1);
+ delayTimer.addEventListener("timer", repeat);
+ delayTimer.start();
+ return false;
+ }
+ }
+ }
+ else if (currentTime > duration)
+ {
+ currentTime = duration;
+ _playheadTime = duration;
+ }
+ }
+ _cycleTime = currentTime;
+
+ calculateValue(currentTime);
+
+ if (currentTime >= duration && !_doSeek)
+ {
+ if (!playReversed || startDelay == 0)
+ {
+ end();
+ animationEnded = true;
+ }
+ else
+ {
+ stopAnimation();
+ addToDelayedAnimations(startDelay);
+ }
+ }
+ else
+ {
+ //if (repeated)
+ //sendAnimationEvent(EffectEvent.EFFECT_REPEAT);
+ sendUpdateEvent();
+ }
+ }
+ return animationEnded;
+ }
+
+ /**
+ * Utility function for dispatching an update event to the
+ * animationTarget. This is a separate function for performance
+ * reasons; don't want to bother switching on the event type for the
+ * common case of update events.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ private function sendUpdateEvent():void
+ {
+ if (_animationTarget)
+ _animationTarget.animationUpdate(this);
+ }
+
+ /**
+ * Utility function for dispatching a specified event to
+ * the animationTarget.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ private function sendAnimationEvent(eventType:String):void
+ {
+ if (_animationTarget)
+ switch (eventType) {
+ case EffectEvent.EFFECT_START:
+ _animationTarget.animationStart(this);
+ break;
+ case EffectEvent.EFFECT_END:
+ _animationTarget.animationEnd(this);
+ break;
+ case EffectEvent.EFFECT_STOP:
+ _animationTarget.animationStop(this);
+ break;
+ //case EffectEvent.EFFECT_REPEAT:
+ //_animationTarget.animationRepeat(this);
+ //break;
+ //case EffectEvent.EFFECT_UPDATE:
+ //// here for completeness; usually handled in sendUpdateEvent
+ //_animationTarget.animationUpdate(this);
+ //break;
+ }
+ }
+
+ /**
+ * @private
+ *
+ * Calculates all values for this animation for the elapsed time
+ */
+ private function calculateValue(currentTime:Number):void
+ {
+ var i:int;
+
+ currentValue = new Object();
+ if (duration == 0)
+ {
+ for (i = 0; i < motionPaths.length; ++i)
+ {
+ currentValue[motionPaths[i].property] =
+ _invertValues ?
+ motionPaths[i].keyframes[0].value :
+ motionPaths[i].keyframes[motionPaths[i].keyframes.length - 1].value;
+ }
+ return;
+ }
+
+ if (_invertValues)
+ currentTime = duration - currentTime;
+
+ _cycleFraction = easer.ease(currentTime/duration);
+
+ if (motionPaths)
+ for (i = 0; i < motionPaths.length; ++i)
+ currentValue[motionPaths[i].property] =
+ motionPaths[i].getValue(_cycleFraction);
+ }
+
+ /**
+ * Remove this animation from the list of pending animations,
+ * as appropriate
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ private function removeFromDelayedAnimations():void
+ {
+ if (delayedStartTimes[this])
+ {
+ var animPendingTime:int = delayedStartTimes[this];
+ for (var i:int = 0; i < delayedStartAnims.length; ++i)
+ {
+ if (delayedStartAnims[i] == this)
+ {
+ delayedStartAnims.splice(i, 1);
+ break;
+ }
+ }
+ delete delayedStartTimes[this];
+ }
+ }
+
+ /**
+ * Interrupts the animation, jumps immediately to the end of the animation,
+ * and calls the animationEnd() function on the <code>animationTarget</code>.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function end():void
+ {
+ // TODO (chaase): call removal utility instead of this code
+ // Make sure to remove any references on the delayed lists
+ if (startDelay > 0 && delayedStartAnims.length > 0)
+ {
+ for (var i:int = 0; i < delayedStartAnims.length; ++i)
+ {
+ if (this == delayedStartAnims[i])
+ {
+ delete delayedStartTimes[this];
+ delayedStartAnims.splice(i, 1);
+ break;
+ }
+ }
+ }
+
+ // Note that we are potentially sending out this event to effects
+ // whose Animation is not yet running (for example, if we're autoReversing
+ // a transition and then skipping past the first effect).
+ // This could mean that the end value is not yet initialized, so
+ // interpolators should be written to just send back the end value
+ // instead of trying to calculate it for the end time.
+ if (!started)
+ sendAnimationEvent(EffectEvent.EFFECT_START);
+ if (repeatCount > 1 && repeatBehavior == "reverse" && (repeatCount % 2 == 0))
+ _invertValues = true;
+
+ // We don't want to update to final values when playing in
+ // reverse with a start delay.
+ if (!(_doReverse && startDelay > 0))
+ {
+ calculateValue(duration);
+ sendUpdateEvent();
+ }
+
+ sendAnimationEvent(EffectEvent.EFFECT_END);
+
+ // The rest of what we need to do is handled by stopAnimation()
+ if (isPlaying)
+ stopAnimation();
+ else
+ stopTimerIfDone();
+ }
+
+ /**
+ * @private
+ * If no more animations running or pending, stop the timer
+ */
+ private static function stopTimerIfDone():void
+ {
+ if (timer && activeAnimations.length == 0 && delayedStartAnims.length == 0)
+ {
+ intervalTime = NaN;
+ timer.reset();
+ timer = null;
+ }
+ }
+
+ private function addToDelayedAnimations(timeToDelay:Number):void
+ {
+ // Run timer if it's not currently running
+ if (!timer)
+ {
+ //Timeline.pulse();
+ timer = new Timer(TIMER_RESOLUTION);
+ timer.addEventListener("timer", timerHandler);
+ timer.start();
+ }
+ //var animStartTime:int = Timeline.currentTime + timeToDelay;
+ //var insertIndex:int = -1;
+ //for (var i:int = 0; i < delayedStartAnims.length; ++i)
+ //{
+ //var timeAtIndex:int =
+ //delayedStartTimes[delayedStartAnims[i]];
+ //if (animStartTime < timeAtIndex)
+ //{
+ //insertIndex = i;
+ //break;
+ //}
+ //}
+ //if (insertIndex >= 0)
+ //delayedStartAnims.splice(insertIndex, 0, this);
+ //else
+ //delayedStartAnims.push(this);
+ //delayedStartTimes[this] = animStartTime;
+ }
+
+ /**
+ * Start the animation.
+ * If the animation is already playing, it
+ * is stopped first, then played.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function play():void
+ {
+ // stop an already-playing animation first
+ stopAnimation();
+
+ // Make sure the time values in our motion paths are reasonable
+ // SimpleMotionPath objects may be set up with no time values, so
+ // we have to fill in those values from the duration when necessary
+ var i:int;
+ var j:int;
+ for (i = 0; i < motionPaths.length; ++i)
+ {
+ var keyframes:Vector.<Keyframe> = motionPaths[i].keyframes;
+ if (isNaN(keyframes[0].time))
+ keyframes[0].time = 0;
+ // Create an initial interval if necessary; this holds the property
+ // at it's current value until the first real keyframe is reached.
+ // This situation can occur when an effect has a startDelay that causes
+ // the first keyframe to have a nonzero time value.
+ else if (keyframes[0].time > 0)
+ {
+ var startTime:Number = keyframes[0].time;
+ keyframes.splice(0, 0, new Keyframe(0, null));
+ keyframes.splice(1, 0, new Keyframe(startTime-1, null));
+ if (playReversed)
+ {
+ // Want to hold *next* value when playing backwards
+ keyframes[0].value = keyframes[2].value;
+ keyframes[1].value = keyframes[2].value;
+ }
+ }
+ for (j = 1; j < keyframes.length; ++j)
+ {
+ if (isNaN(keyframes[j].time))
+ keyframes[j].time = duration;
+ }
+ }
+ for (i = 0; i < motionPaths.length; ++i)
+ motionPaths[i].scaleKeyframes(duration);
+
+ if (_doReverse)
+ _invertValues = true;
+
+ if (startDelay > 0 && !playReversed)
+ addToDelayedAnimations(startDelay);
+ else
+ start();
+ }
+
+ /**
+ * @private
+ *
+ * Advances the animation to the specified position.
+ *
+ * @param playheadTime The position, in milliseconds, between 0
+ * and the value of the <code>duration</code> property.
+ *
+ * @param includeStartDelay Set to <code>true</code> if there is
+ * a start delay on the effect, as defined by the
+ * <code>startDelay</code> property.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ private function seek(playheadTime:Number, includeStartDelay:Boolean = false):void
+ {
+ // Set value between 0 and duration
+ //playheadTime = Math.min(Math.max(playheadTime, 0), duration);
+
+ // Reset the start time
+ // TODO (chaase): Redundant for cases that set this again below
+ // Should only do this for playing animation, as the stopped animations
+ // do it for themselves
+ startTime = cycleStartTime = intervalTime - playheadTime;
+ _doSeek = true;
+
+ if (!_isPlaying || playReversed)
+ {
+ var isPlayingTmp:Boolean = _isPlaying;
+ //intervalTime = Timeline.currentTime;
+ if (includeStartDelay && startDelay > 0)
+ {
+ if (delayedStartTimes[this])
+ {
+ // TODO (chaase): refactor removal/addition into utility functions
+ // Still sleeping - reduce the delay time by the seek time
+ var animPendingTime:int = delayedStartTimes[this];
+ for (var i:int = 0; i < delayedStartAnims.length; ++i)
+ {
+ if (delayedStartAnims[i] == this)
+ {
+ delayedStartAnims.splice(i, 1);
+ break;
+ }
+ }
+ delete delayedStartTimes[this];
+ var postDelaySeekTime:Number = playheadTime - startDelay;
+ // also subtract out duration if playing in reverse because
+ if (playReversed)
+ postDelaySeekTime -= duration;
+ if (postDelaySeekTime < 0)
+ {
+ animPendingTime = intervalTime + (startDelay - playheadTime);
+ // add it back into the array in the proper order
+ var insertIndex:int = -1;
+ for (i = 0; i < delayedStartAnims.length; ++i)
+ {
+ if (animPendingTime < delayedStartTimes[delayedStartAnims[i]])
+ {
+ insertIndex = i;
+ break;
+ }
+ }
+ if (insertIndex >= 0)
+ delayedStartAnims.splice(insertIndex, 0, this);
+ else
+ delayedStartAnims.push(this);
+ delayedStartTimes[this] = animPendingTime;
+ return;
+ }
+ else
+ {
+ // reduce seek time by startTime; we will go ahead and
+ // seek into the now-playing animation by that much
+ playheadTime -= startDelay;
+ if (!isPlaying)
+ start();
+ startTime = cycleStartTime = intervalTime - playheadTime;
+ doInterval();
+ _doSeek = false;
+ return;
+ }
+ }
+ }
+ if (!isPlayingTmp)
+ {
+ // start/end values only valid after animation starts
+ sendAnimationEvent(EffectEvent.EFFECT_START);
+ setupInterpolation();
+ }
+ startTime = cycleStartTime = intervalTime - playheadTime;
+ }
+
+ doInterval();
+ _doSeek = false;
+ }
+
+ /**
+ * Sets up interpolation for the animation.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ private function setupInterpolation():void
+ {
+ if (interpolator && motionPaths)
+ for (var i:int = 0; i < motionPaths.length; ++i)
+ motionPaths[i].interpolator = interpolator;
+ }
+
+ // TODO (chaase): should eventually remove this function, since it
+ // overlaps with playReverse property. Just leaving it mx_internal
+ // for now to avoid perturbing the code too much
+ /**
+ * @private
+ *
+ * Plays the effect in reverse,if the effect is currently playing,
+ * starting from the current position of the effect.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ mx_internal function reverse():void
+ {
+ if (_isPlaying)
+ {
+ _doReverse = false;
+ seek(duration - _cycleTime);
+ _invertValues = !_invertValues;
+ }
+ else
+ {
+ _doReverse = !_doReverse;
+ }
+ }
+
+ /**
+ * @private
+ * Method is used to force the animation timeline to update its current
+ * time.
+ */
+ mx_internal static function pulse():void
+ {
+ //if (timer)
+ //Timeline.pulse();
+ }
+
+ /**
+ * Pauses the effect until the <code>resume()</code> method is called.
+ * If <code>stop()</code> is called before <code>resume()</code>, then
+ * the animation cannot be resumed.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function pause():void
+ {
+ var animPendingTime:Number = delayedStartTimes[this];
+ if (!isNaN(animPendingTime))
+ {
+ //delayTime = animPendingTime - Timeline.currentTime;
+ removeFromDelayedAnimations();
+ }
+ _isPlaying = false;
+ }
+
+ /**
+ * @private
+ *
+ * Called by stop(), but also other places where we simply
+ * want to stop the animation without sending out the stop()
+ * event.
+ */
+ private function stopAnimation():void
+ {
+ removeFromDelayedAnimations();
+ // If animation has been added, id >= 0
+ // but if duration = 0, this might not be the case.
+ if (id >= 0)
+ {
+ Animation.removeAnimationAt(id);
+ id = -1;
+ _invertValues = false;
+ _isPlaying = false;
+ }
+ }
+ /**
+ * Stops the animation, ending it without calling the <code>end()</code>
+ * method. The animationStop() function on the <code>animationTarget</code>
+ * will be called.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function stop():void
+ {
+ stopAnimation();
+ sendAnimationEvent(EffectEvent.EFFECT_STOP);
+ }
+
+ /**
+ * Resumes the effect after it has been paused
+ * by a call to the <code>pause()</code> method.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function resume():void
+ {
+ _isPlaying = true;
+
+ if (delayTime >= 0)
+ {
+ addToDelayedAnimations(delayTime);
+ }
+ else
+ {
+ cycleStartTime = intervalTime - _cycleTime;
+ startTime = intervalTime - _playheadTime;
+ if (_doReverse)
+ {
+ reverse();
+ _doReverse = false;
+ }
+ }
+ }
+
+
+ //--------------------------------------------------------------------------
+ //
+ // Event handlers
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ *
+ * Called by a Timer after repeatDelay has elapsed for a given
+ * repetition cycle. This causes the animation to send out an initial
+ * value at the starting point, just as if the animation were just starting
+ * out.
+ */
+ private function repeat(event:Event = null):void
+ {
+ if (repeatBehavior == RepeatBehavior.REVERSE)
+ _invertValues = !_invertValues;
+ calculateValue(0);
+ //sendAnimationEvent(EffectEvent.EFFECT_REPEAT);
+ //sendUpdateEvent();
+ Animation.addAnimation(this);
+ }
+
+ /**
+ * Called by play() or by a Timer, if startDelay is nonzero. This
+ * method initializes any necessary default state and adds the animation
+ * to the list of active animations, which starts it actually running.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ private function start(event:Event = null):void
+ {
+ // actualStartTime accounts for overrun in desired startDelay
+ var actualStartTime:int = 0;
+
+ // TODO (chaase): call removal utility instead of this code
+ // Make sure to remove any references on the delayed lists
+ if (!playReversed)
+ for (var i:int = 0; i < delayedStartAnims.length; ++i)
+ {
+ if (this == delayedStartAnims[i])
+ {
+ //var animStartTime:int = int(delayedStartTimes[this]);
+ //var overrun:int = Timeline.currentTime - animStartTime;
+ //if (overrun > 0)
+ //actualStartTime = Math.min(overrun, duration);
+ //delete delayedStartTimes[this];
+ //delayedStartAnims.splice(i, 1);
+ //break;
+ }
+ }
+ sendAnimationEvent(EffectEvent.EFFECT_START);
+
+ // start/end values may be changed by Animate (set dynamically),
+ // so now we set up our interpolator based on the real values
+ setupInterpolation();
+
+ calculateValue(0);
+
+ // TODO (rfrishbe): if the animation gets stopped() or ended() in
+ // the first update, then the animation never actually gets removed
+ sendUpdateEvent();
+ Animation.addAnimation(this);
+ startTime = cycleStartTime;
+ _isPlaying = true;
+ if (actualStartTime > 0)
+ seek(actualStartTime);
+
+ started = true;
+ }
+
+}
+}
diff --git a/frameworks/projects/SparkRoyale/src/main/royale/spark/effects/animation/IAnimationTarget.as b/frameworks/projects/SparkRoyale/src/main/royale/spark/effects/animation/IAnimationTarget.as
new file mode 100644
index 0000000..e326ca9
--- /dev/null
+++ b/frameworks/projects/SparkRoyale/src/main/royale/spark/effects/animation/IAnimationTarget.as
@@ -0,0 +1,113 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+package spark.effects.animation
+{
+/**
+ * The IAnimationTarget interface is implemented by classes that support
+ * the events for an Animation instance.
+ *
+ * @see spark.effects.animation.Animation
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+public interface IAnimationTarget
+{
+ /**
+ * Called when an Animation instance starts. If there
+ * is a <code>startDelay</code> on the Animation, this function is called
+ * after that delay.
+ *
+ * @param animation The Animation object.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ function animationStart(animation:Animation):void;
+
+ /**
+ * Called when an Animation instance stops.
+ * This is different than <code>animationEnd()</code> method,
+ * which is called when the animation ends,
+ * automatically setting the end values of the targets.
+ * The <code>animationStop()</code> method
+ * is called when an animation is stopped where it's at.
+ * Handling this event allows necessary cleanup when the animation
+ * is interrupted.
+ *
+ * @param animation The Animation object.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ function animationStop(animation:Animation):void;
+
+ /**
+ * Called when an Animation instance ends.
+ *
+ * @param animation The Animation object.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ function animationEnd(animation:Animation):void;
+
+ /**
+ * Called when an Animation instance repeats.
+ * The Animation instance must have a <code>repeatCount</code> equal to 0
+ * (infinitely repeating) or a value greater than 1.
+ *
+ * @param animation The Animation object.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ function animationRepeat(animation:Animation):void;
+
+ /**
+ * Called during every update of an Animation instance.
+ * If an implementation class is listening to an Animation specifically to
+ * be able to do something after the Animation values are calculated for
+ * a given time, this is the function in which those values should be used.
+ * The other methods in this interface are more informational.
+ * They tell the listeners when the Animation starts, stops, or repeats.
+ * This method is called when values have been calculated and something can be
+ * done with them.
+ *
+ * @param animation The Animation object.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ function animationUpdate(animation:Animation):void;
+
+}
+}
diff --git a/frameworks/projects/SparkRoyale/src/main/royale/spark/effects/animation/Keyframe.as b/frameworks/projects/SparkRoyale/src/main/royale/spark/effects/animation/Keyframe.as
new file mode 100644
index 0000000..b53c3f9
--- /dev/null
+++ b/frameworks/projects/SparkRoyale/src/main/royale/spark/effects/animation/Keyframe.as
@@ -0,0 +1,223 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package spark.effects.animation
+{
+import mx.core.mx_internal;
+
+import spark.effects.easing.IEaser;
+import spark.effects.easing.Linear;
+
+use namespace mx_internal;
+
+/**
+ * The Keyframe class defines the value of a property at a specific time during an effect.
+ * For example, you can create three keyframes that define the value of a property at
+ * the beginning of the effect, at the midpoint of the effect, and at the end of the effect.
+ * The effect animates the property change on the target from keyframe to keyframe
+ * over the effect duration.
+ *
+ * <p>The collection of keyframes for an effect is called the effect's motion path.
+ * A motion path can define any number of keyframes.
+ * The effect then calculates the value of the property by interpolating between
+ * the values specified by two key frames. </p>
+ *
+ * <p>Use the MotionPath class to hold the collection of Keyframe objects that
+ * represent the motion path of the effect.
+ * The MotionPath class specifies the name of the property on the target,
+ * and the collection of Keyframes objects specify the values of the property at different
+ * times during the effect.</p>
+ *
+ * @mxml
+ *
+ * <p>The <code><s:Keyframe></code> tag
+ * inherits the tag attributes of its superclass,
+ * and adds the following tag attributes:</p>
+ *
+ * <pre>
+ * <s:Keyframe
+ * id="ID"
+ * easier="Linear"
+ * time="val"
+ * value="val"
+ * valueBy="val"
+ * />
+ * </pre>
+ *
+ * @see MotionPath
+ *
+ * @includeExample examples/KeyFrameEffectExample.mxml
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+public class Keyframe
+{
+ //include "../../core/Version.as";
+
+ /**
+ * Constructor.
+ *
+ * @param time The time, in milliseconds, at which the effect target
+ * of this keyframe should have the value
+ * specified by the <code>value</code> parameter.
+ *
+ * @param value The value that the effect target should have
+ * at the given <code>time</code>.
+ *
+ * @param valueBy Optional parameter which, if provided,
+ * causes <code>value</code> to be calculated dynamically by
+ * adding <code>valueBy</code> to the <code>value</code> of
+ * the previous keyframe in the set of keyframes in a MotionPath
+ * object. This value is ignored if this is the first
+ * Keyframe in a sequence.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function Keyframe(time:Number = NaN,
+ value:Object = null, valueBy:Object = null)
+ {
+ this.value = value;
+ this.time = time;
+ this.valueBy = valueBy;
+ }
+
+ /**
+ * Returns a copy of this Keyframe object.
+ *
+ * @return A copy of this Keyframe object.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function clone():Keyframe
+ {
+ var kf:Keyframe = new Keyframe(time, value, valueBy);
+ kf.easer = easer;
+ kf.timeFraction = timeFraction;
+ return kf;
+ }
+
+ /**
+ * The value that the property of the effect target should have
+ * at the time specified by the <code>time</code> property.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public var value:Object;
+
+ [Inspectable(minValue="0.0")]
+
+ /**
+ * The time, in milliseconds, at which the effect target
+ * for this keyframe should have the value
+ * specified by the <code>value</code> property. This time
+ * is relative to the starting time of the effect defined
+ * with this keyframe.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public var time:Number;
+
+ /**
+ * @private
+ *
+ * The time, represented as a fraction of an animation's
+ * total duration. This value should be a value between 0
+ * and 1. This value is calculated automatically prior to
+ * playing the animation. It simplifies the API for users (who
+ * are able to use absolute time values) and the implementation
+ * (because we can work on fractional values directly) and is not
+ * to be used externally.
+ */
+ mx_internal var timeFraction:Number;
+
+ /**
+ * @private
+ * Default easer for keyframes
+ */
+ private static var linearEaser:IEaser = new Linear();
+ /**
+ * The easing behavior applied to the motion between the previous
+ * Keyframe object in motion path and this Keyframe object.
+ * By default, the easing is linear, or no easing at all.
+ *
+ * <p>Note that the parent effect
+ * might have easing applied already over the entire
+ * animation. Therefore, if easing per keyframe interval is desired
+ * instead, it is necessary to set the overall effect
+ * easer to linear easing (spark.effects.easing.Linear) and then
+ * set the <code>easer</code> on each Keyframe as appropriate.</p>
+ *
+ * <p>Because this property acts on the interval between the previous
+ * Keyframe object in a sequence and this Keyframe object, the <code>easer</code>
+ * property is ignored on the first Keyframe object in a sequence.</p>
+ *
+ * @default Linear
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public var easer:IEaser = linearEaser;
+
+ /**
+ * Optional parameter which, if specified, is used to
+ * calculate <code>value</code> in this keyframe or
+ * the previous one. If <code>value</code> is not set in
+ * the previous keyframe, but this keyframe defines both
+ * <code>value</code> and <code>valueBy</code>, then <code>value</code>
+ * in the previous keyframe is calculated as <code>value</code>
+ * in this keyframe minus <code>valueBy</code> in this keyframe.
+ *
+ * <p>Similarly, if <code>value</code> in this keyframe is not
+ * defined, but <code>valueBy</code> in this keyframe and
+ * <code>value</code> in the previous keyframe are both set,
+ * then <code>value</code> in this keyframe is calculated as
+ * <code>value</code> in the previous keyframe plus
+ * <code>valueBy</code> in this keyframe.</p>
+ *
+ * <p><code>valueBy</code> is ignored for the first
+ * keyframe in a sequence, since it applies only to the interval
+ * preceding a keyframe, and there is no preceding interval for the
+ * first keyframe.</p>
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public var valueBy:Object;
+
+}
+}
diff --git a/frameworks/projects/SparkRoyale/src/main/royale/spark/effects/animation/MotionPath.as b/frameworks/projects/SparkRoyale/src/main/royale/spark/effects/animation/MotionPath.as
new file mode 100644
index 0000000..ebcf800
--- /dev/null
+++ b/frameworks/projects/SparkRoyale/src/main/royale/spark/effects/animation/MotionPath.as
@@ -0,0 +1,288 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package spark.effects.animation
+{
+import __AS3__.vec.Vector;
+
+import mx.core.mx_internal;
+
+import spark.effects.easing.IEaser;
+import spark.effects.easing.Sine;
+import spark.effects.interpolation.IInterpolator;
+import spark.effects.interpolation.NumberInterpolator;
+
+use namespace mx_internal;
+
+[DefaultProperty("keyframes")]
+
+/**
+ * The MotionPath class defines the collection of Keyframes objects for an effect,
+ * and the name of the property on the target to animate.
+ * Each Keyframe object defines the value of the property at a specific time during an effect.
+ * The effect then calculates the value of the target property
+ * by interpolating between the values specified by two key frames.
+ *
+ * @mxml
+ *
+ * <p>The <code><s:MotionPath></code> tag
+ * inherits the tag attributes of its superclass,
+ * and adds the following tag attributes:</p>
+ *
+ * <pre>
+ * <s:MotionPath
+ * id="ID"
+ * interpolator="NumberInterpolator"
+ * keyframes="val"
+ * property="val"
+ * />
+ * </pre>
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ *
+ * @includeExample examples/KeyFrameEffectExample.mxml
+ *
+ * @see Keyframe
+ * @see spark.effects.interpolation.NumberInterpolator
+ */
+public class MotionPath
+{
+ //include "../../core/Version.as";
+
+ //--------------------------------------------------------------------------
+ //
+ // Constructor
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Constructor.
+ *
+ * @param property The name of the property on the target to animate.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function MotionPath(property:String = null)
+ {
+ this.property = property;
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // Properties
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * The name of the property on the effect target to be animated.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public var property:String;
+
+ /**
+ * The interpolator determines how in-between values in an animation
+ * are calculated. By default, the MotionPath class assumes that the values are
+ * of type Number and can calculate in-between Number values automatically.
+ * If the MotionPath class is given keyframes with non-Number values, or if the
+ * desired behavior should use a different approach to interpolation
+ * (such as per-channel color interpolation), then an interpolator
+ * should be supplied.
+ *
+ * <p>Flex supplies predefined interpolators in the spark.effects.interpolation package.</p>
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public var interpolator:IInterpolator = NumberInterpolator.getInstance();
+
+ /**
+ * A sequence of Keyframe objects that represent the time/value pairs
+ * that the property takes during the animation. Each successive
+ * pair of keyframes controls the animation during the time interval
+ * between them.
+ * The optional <code>easer</code> and <code>valueBy</code>
+ * properties of the later keyframe are used to determine the behavior
+ * during that interval. The sequence of keyframes must be sorted in
+ * order of increasing time values.
+ *
+ * <p>Animations always start at time=0 and lasts for a duration
+ * equal to the <code>time</code> value in the final keyframe.
+ * If no keyframe is defined at time=0,
+ * that keyframe is implicit, using the value of the
+ * target property at the time the animation begins. </p>
+ *
+ * <p>Because keyframes explicitly define the times involved in an animation,
+ * the duration for an effect using keyframes is set according to the maximum time
+ * of the final keyframe of all MotionPaths in the effect.
+ * For example, if an effect has keyframes
+ * at times 0, 500, 1000, and 2000, then the effective duration of that
+ * effect is 2000 ms, regardless of any <code>duration</code> property set on the
+ * effect itself.
+ * Because the final keyframe determines the duration, there
+ * must always be a final keyframe in any MotionPath. That is,
+ * it is implicit that the time in the final keyframe is the
+ * duration of the MotionPath.</p>
+ *
+ * <p>Any keyframe may leave its <code>value</code> undefined (either unset, set to
+ * <code>null</code>, or set to <code>NaN</code>).
+ * In that case, the value is determined dynamically when the animation starts.
+ * Any undefined value is determined as follows: </p>
+ * <ol>
+ * <li>If it is the first keyframe, it is calculated from the next keyframe
+ * if that keyframe has both a <code>value</code> and <code>valueBy</code> property set,
+ * as the difference of those values. Otherwise it gets the
+ * current value of the property from the target.</li>
+ * <li>If it is the final keyframe and the animation is running in a transition, it
+ * uses the value in the destination view state of the transition.</li>
+ * <li>Otherwise, any keyframe calculates its <code>value</code> by using the previous
+ * keyframe's <code>value</code> and adding the current keyframe's <code>valueBy</code>
+ * to it, if <code>valueBy</code> is set.</li>
+ * </ol>
+ *
+ * @see Keyframe
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public var keyframes:Vector.<Keyframe>;
+
+
+ /**
+ * Returns a copy of this MotionPath object, including copies
+ * of each keyframe.
+ *
+ * @return A copy of this MotionPath object, including copies
+ * of each keyframe.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function clone():MotionPath
+ {
+ var mp:MotionPath = new MotionPath(property);
+ mp.interpolator = interpolator;
+ if (keyframes !== null)
+ {
+ mp.keyframes = new Vector.<Keyframe>();
+ for (var i:int = 0; i < keyframes.length; ++i)
+ mp.keyframes[i] = keyframes[i].clone();
+ }
+ return mp;
+ }
+
+ /**
+ * @private
+ *
+ * Calculates the <code>timeFraction</code> values for
+ * each Keyframe in a MotionPath Keyframe sequence.
+ * To calculate these values, the time on each Keyframe
+ * is divided by the supplied <code>duration</code> parameter.
+ *
+ * @param duration the duration of the animation that the
+ * keyframes should be scaled against.
+ */
+ mx_internal function scaleKeyframes(duration:Number):void
+ {
+ var n:int = keyframes.length;
+ for (var i:int; i < n; ++i)
+ {
+ var kf:Keyframe = keyframes[i];
+ // TODO (chaase): Must be some way to allow callers
+ // to supply timeFraction, but currently we clobber it
+ // with this operation. But if we choose to clobber it
+ // only if it's not set already, then it only works the
+ // first time through, since an Effect will retain its
+ // MotionPath, which retains its Keyframes, etc.
+ kf.timeFraction = kf.time / duration;
+ }
+ }
+
+ /**
+ * Calculates and returns an interpolated value, given the elapsed
+ * time fraction. The function determines the keyframe interval
+ * that the fraction falls within and then interpolates within
+ * that interval between the values of the bounding keyframes on that
+ * interval.
+ *
+ * @param fraction The fraction of the overall duration of the effect,
+ * (a value from 0.0 to 1.0).
+ *
+ * @return The interpolated value.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function getValue(fraction:Number):Object
+ {
+ if (!keyframes)
+ return null;
+ var n:int = keyframes.length;
+ if (n == 2 && keyframes[1].timeFraction == 1)
+ {
+ // The common case where we are just animating from/to, as in the
+ // case of an SimpleMotionPath
+ var easedF:Number = (keyframes[1].easer) ?
+ keyframes[1].easer.ease(fraction) :
+ fraction;
+ return interpolator.interpolate(easedF, keyframes[0].value,
+ keyframes[1].value);
+ }
+ // if timeFraction on first keyframe is not set, call scaleKeyframes
+ // should not generally happen, but if getValue() is called before
+ // an owning effect is played, then timeFractions were not set
+ if (isNaN(keyframes[0].timeFraction))
+ scaleKeyframes(keyframes[keyframes.length-1].time);
+ var prevT:Number = 0;
+ var prevValue:Object = keyframes[0].value;
+ for (var i:int = 1; i < n; ++i)
+ {
+ var kf:Keyframe = keyframes[i];
+ if (fraction >= prevT && fraction < kf.timeFraction)
+ {
+ var t:Number = (fraction - prevT) / (kf.timeFraction - prevT);
+ var easedT:Number = (kf.easer) ? kf.easer.ease(t) : t;
+ return interpolator.interpolate(easedT, prevValue, kf.value);
+ }
+ prevT = kf.timeFraction;
+ prevValue = kf.value;
+ }
+ // Must be at the end of the animation
+ return keyframes[n-1].value;
+ }
+
+}
+}
diff --git a/frameworks/projects/SparkRoyale/src/main/royale/spark/effects/animation/RepeatBehavior.as b/frameworks/projects/SparkRoyale/src/main/royale/spark/effects/animation/RepeatBehavior.as
new file mode 100644
index 0000000..c41edeb
--- /dev/null
+++ b/frameworks/projects/SparkRoyale/src/main/royale/spark/effects/animation/RepeatBehavior.as
@@ -0,0 +1,58 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+package spark.effects.animation
+{
+/**
+ * The RepeatBehavior class defines constants for use with <code>repeatBehavior</code>
+ * property of the Animate and Animation classes.
+ *
+ * @see spark.effects.Animate#repeatBehavior
+ * @see Animation#repeatBehavior
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+public final class RepeatBehavior
+{
+ /**
+ * Specifies that a repeating animation should progress in a forward direction on
+ * every iteration.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public static const LOOP:String = "loop";
+
+ /**
+ * Specifies that a repeating animation should reverse direction on
+ * every iteration. For example, a reversing animation would play forward
+ * on the even iterations and in reverse on the odd iterations.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public static const REVERSE:String = "reverse";
+}
+}
diff --git a/frameworks/projects/SparkRoyale/src/main/royale/spark/effects/animation/SimpleMotionPath.as b/frameworks/projects/SparkRoyale/src/main/royale/spark/effects/animation/SimpleMotionPath.as
new file mode 100644
index 0000000..b4361a8
--- /dev/null
+++ b/frameworks/projects/SparkRoyale/src/main/royale/spark/effects/animation/SimpleMotionPath.as
@@ -0,0 +1,192 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package spark.effects.animation
+{
+import spark.effects.interpolation.MultiValueInterpolator;
+
+
+/**
+ * The SimpleMotionPath class specifies the name of a property, and the values that
+ * that property takes over time, for instances of the Animate
+ * effect.
+ *
+ * <p>This class is a simple subclass of MotionPath for defining
+ * two keyframes to hold the <code>valueFrom</code>, <code>valueTo</code>, and
+ * <code>valueBy</code> properties.
+ * The MotionPath class itself can define any number of keyframes.</p>
+ *
+ * @see MotionPath
+ *
+ * @includeExample examples/SimpleMotionPathEffectExample.mxml
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+public class SimpleMotionPath extends MotionPath
+{
+
+ //--------------------------------------------------------------------------
+ //
+ // Constructor
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Constructor. You can specify both the
+ * <code>valueFrom</code> and <code>valueTo</code> parameters,
+ * or specify the <code>valueBy</code> parameter and either the <code>valueFrom</code>
+ * or <code>valueTo</code> parameter.
+ * If you omit these parameters, Flex calculates them from the effect target.
+ *
+ * @param property The name of the property being animated.
+ *
+ * @param valueFrom The initial value of the property.
+ *
+ * @param valueTo The final value of the property.
+ *
+ * @param valueBy An optional parameter that specifies the delta with
+ * which to calculate either the from or to values, if one is omitted.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function SimpleMotionPath(property:String = null,
+ valueFrom:Object = null, valueTo:Object = null,
+ valueBy:Object = null)
+ {
+ super();
+ this.property = property;
+ keyframes = new <Keyframe>[new Keyframe(0, valueFrom),
+ new Keyframe(NaN, valueTo, valueBy)];
+ if (valueFrom !== null && valueTo !== null &&
+ ((valueFrom is Array && valueTo is Array) ||
+ (valueFrom is Vector.<Number> && valueTo is Vector.<Number>)))
+ {
+ if (!multiValueInterpolator)
+ multiValueInterpolator = new MultiValueInterpolator();
+ interpolator = multiValueInterpolator;
+ }
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // Variables
+ //
+ //--------------------------------------------------------------------------
+
+ private static var multiValueInterpolator:MultiValueInterpolator = null;
+
+ //--------------------------------------------------------------------------
+ //
+ // Properties
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * The starting value for the property during the animation.
+ *
+ * <p>A value of Null or NaN (in the case of Numbers) specifies that a
+ * value must be determined dynamically at runtime, either by
+ * getting the value from the target property directly or calculating
+ * it if the other value is valid and there is also a valid
+ * <code>valueBy</code> value supplied.</p>
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function get valueFrom():Object
+ {
+ return keyframes[0].value;
+ }
+ public function set valueFrom(value:Object):void
+ {
+ keyframes[0].value = value;
+ }
+
+ /**
+ * The value that the named property will animate to.
+ *
+ * <p>A value of Null or NaN (in the case of Numbers) element specifies that a
+ * value must be determined dynamically at runtime, either by
+ * getting the value from the target property directly or calculating
+ * it if the other value is valid and there is also a valid <code>valueBy</code>
+ * value supplied.</p>
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function get valueTo():Object
+ {
+ return keyframes[keyframes.length -1].value;
+ }
+ public function set valueTo(value:Object):void
+ {
+ keyframes[keyframes.length - 1].value = value;
+ }
+
+ /**
+ * Optional property which specifies the delta used to calculate
+ * either the <code>valueFrom</code> or <code>valueTo</code> value.
+ * Providing this optional property lets the effect
+ * calculate the necessary from/to values if either
+ * are not provided or are to be determined dynamically when the animation
+ * begins.
+ *
+ * <p>The way that the <code>valueBy</code> value is used depends on which of the
+ * other values are set. If neither are set, then the <code>valueFrom</code>
+ * value is determined from the current property value in the target,
+ * and the <code>valueTo</code> value is <code>valueFrom + valueBy</code>.
+ * If one or the other is set, but not both, then
+ * the unset value is calculated by the other value:
+ * <code>valueTo = valueFrom + valueBy</code> or
+ * <code>valueFrom = valueTo - valueBy</code>). If both are set, then the
+ * <code>valueBy</code> property is ignored.</p>
+ *
+ * <p>Note that since <code>valueBy</code> is of type
+ * Object, the effect cannot directly calculate the other values
+ * from it. It uses the effect's interpolator
+ * to calculate the values by calling the interpolator's <code>increment()</code>
+ * and <code>decrement()</code> methods.
+ * If no interpolator is set, then it will use NumberInterpolator by default.</p>
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function get valueBy():Object
+ {
+ return keyframes[keyframes.length - 1].valueBy;
+ }
+ public function set valueBy(value:Object):void
+ {
+ keyframes[keyframes.length - 1].valueBy = value;
+ }
+
+}
+}
diff --git a/frameworks/projects/SparkRoyale/src/main/royale/spark/effects/easing/EaseInOutBase.as b/frameworks/projects/SparkRoyale/src/main/royale/spark/effects/easing/EaseInOutBase.as
new file mode 100644
index 0000000..f0f3284
--- /dev/null
+++ b/frameworks/projects/SparkRoyale/src/main/royale/spark/effects/easing/EaseInOutBase.as
@@ -0,0 +1,188 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+package spark.effects.easing
+{
+/**
+ * The EaseInOutBase class is the base class that provide easing capability.
+ * The EaseInOutBase class defines easing as consisting of two phases:
+ * the acceleration, or ease in phase, followed by the deceleration, or ease out phase.
+ * The default behavior of this class returns a linear
+ * interpolation for both easing phases. You can create a subclass
+ * of EaseInOutBase to get more interesting behavior.
+ *
+ * @mxml
+ *
+ * <p>The <code><s:EaseInOutBase></code> tag
+ * inherits all of the tag attributes of its of its superclass,
+ * and adds the following tag attributes:</p>
+ *
+ * <pre>
+ * <s:EaseInOutBase
+ * id="ID"
+ * easeInFraction="0.5"
+ * />
+ * </pre>
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+public class EaseInOutBase implements IEaser
+{
+
+ /**
+ * Constructor.
+ *
+ * @param easeInFraction Sets the value of
+ * the <code>easeInFraction</code> property. The default value is
+ * <code>EasingFraction.IN_OUT</code>, which eases in for the first half
+ * of the time and eases out for the remainder.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function EaseInOutBase(easeInFraction:Number = EasingFraction.IN_OUT)
+ {
+ this.easeInFraction = easeInFraction;
+ }
+
+ /**
+ * Storage for the _easeInFraction property
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ private var _easeInFraction:Number = .5;
+
+ [Inspectable(minValue="0.0", maxValue="1.0")]
+
+ /**
+ * The percentage of an animation that should be spent accelerating.
+ * This factor sets an implicit
+ * "easeOut" parameter, equal to (1 - <code>easeIn</code>), so that any time not
+ * spent easing in is spent easing out. For example, to have an easing
+ * equation that spends half the time easing in and half easing out,
+ * set <code>easeIn</code> to .5.
+ *
+ * <p>Valid values are between 0.0 and 1.0.</p>
+ *
+ * @default .5
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function get easeInFraction():Number
+ {
+ return _easeInFraction;
+ }
+ public function set easeInFraction(value:Number):void
+ {
+ _easeInFraction = value;
+ }
+
+ /**
+ * Takes the fraction representing the elapsed duration of an animation
+ * (a value between 0.0 to 1.0) and returns a new elapsed value.
+ * This value is used to calculate animated property values.
+ * By changing the value of the elapsed fraction, you effectively change
+ * the animation of the property.
+ *
+ * For EaseInOutBase, this method calculates the eased fraction
+ * value based on the <code>easeInFraction</code> property. If
+ * <code>fraction</code> is less than <code>easeInFraction</code>,
+ * this method calls the <code>easeIn()</code> method. Otherwise it
+ * calls the <code>easeOut()</code> method.
+ * It is expected
+ * that these functions are overridden in a subclass.
+ *
+ * @param fraction The elapsed fraction of the animation.
+ *
+ * @return The eased fraction of the animation.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function ease(fraction:Number):Number
+ {
+ var easeOutFraction:Number = 1 - easeInFraction;
+
+ if (fraction <= easeInFraction && easeInFraction > 0)
+ return easeInFraction * easeIn(fraction/easeInFraction);
+ else
+ return easeInFraction + easeOutFraction *
+ easeOut((fraction - easeInFraction)/easeOutFraction);
+ }
+
+ /**
+ * Returns a value that represents the eased fraction during the
+ * ease in phase of the animation. The value returned by this class
+ * is simply the fraction itself, which represents a linear
+ * interpolation of the fraction. More interesting behavior is
+ * implemented by subclasses of EaseInOutBase.
+ *
+ * @param fraction The fraction elapsed of the easing in phase
+ * of the animation, between 0.0 and 1.0.
+ *
+ * @return A value that represents the eased value for this
+ * phase of the animation.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ protected function easeIn(fraction:Number):Number
+ {
+ return fraction;
+ }
+
+ /**
+ * Returns a value that represents the eased fraction during the
+ * ease out phase of the animation. The value returned by this class
+ * is simply the fraction itself, which represents a linear
+ * interpolation of the fraction. More interesting behavior is
+ * implemented by subclasses of EaseInOutBase.
+ *
+ * @param fraction The fraction elapsed of the easing out phase
+ * of the animation, between 0.0 and 1.0.
+ *
+ * @return A value that represents the eased value for this
+ * phase of the animation.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ protected function easeOut(fraction:Number):Number
+ {
+ return fraction;
+ }
+
+}
+}
diff --git a/frameworks/projects/SparkRoyale/src/main/royale/spark/effects/easing/EasingFraction.as b/frameworks/projects/SparkRoyale/src/main/royale/spark/effects/easing/EasingFraction.as
new file mode 100644
index 0000000..949fda1
--- /dev/null
+++ b/frameworks/projects/SparkRoyale/src/main/royale/spark/effects/easing/EasingFraction.as
@@ -0,0 +1,72 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+package spark.effects.easing
+{
+/**
+ * The EasingFraction class defines constants for
+ * the <code>easeInFraction</code> property of the EaseInOutBase class.
+ *
+ * @see EaseInOutBase
+ * @see EaseInOutBase#easeInFraction
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+public final class EasingFraction
+{
+ /**
+ * Specifies that the easing instance
+ * spends the entire animation easing in. This is equivalent
+ * to setting the <code>easeInFraction</code> property to 1.0.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public static const IN:Number = 1;
+
+ /**
+ * Specifies that the easing instance
+ * spends the entire animation easing out. This is equivalent
+ * to setting the <code>easeInFraction</code> property to 0.0.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public static const OUT:Number = 0;
+
+ /**
+ * Specifies that an easing instance
+ * that eases in for the first half and eases out for the
+ * remainder. This is equivalent
+ * to setting the <code>easeInFraction</code> property to 0.5.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public static const IN_OUT:Number = 0.5;
+}
+}
diff --git a/frameworks/projects/SparkRoyale/src/main/royale/spark/effects/easing/Linear.as b/frameworks/projects/SparkRoyale/src/main/royale/spark/effects/easing/Linear.as
new file mode 100644
index 0000000..fc9afa2
--- /dev/null
+++ b/frameworks/projects/SparkRoyale/src/main/royale/spark/effects/easing/Linear.as
@@ -0,0 +1,199 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+package spark.effects.easing
+{
+/**
+ * The Linear class defines an easing with three phases:
+ * acceleration, uniform motion, and deceleration.
+ * As the animation starts it accelerates through the period
+ * specified by the <code>easeInFraction</code> property, it
+ * then uses uniform (linear) motion through the next phase, and
+ * finally decelerates until the end during the period specified
+ * by the <code>easeOutFraction</code> property.
+ *
+ * <p>The easing values for the three phases are calculated
+ * such that the behavior of constant acceleration, linear motion,
+ * and constant deceleration all occur within the specified
+ * duration of the animation.</p>
+ *
+ * <p>Strict linear motion can be achieved by setting
+ * <code>easeInFraction</code> and <code>easeOutFraction</code> to 0.0.
+ * Note that if acceleration or
+ * deceleration are not 0.0, then the motion during the middle
+ * phase is not at the same speed as that of pure
+ * linear motion. The middle phase consists of
+ * uniform motion, but the speed of that motion is determined by
+ * the size of that phase relative to the overall animation.</p>
+ *
+ * @mxml
+ *
+ * <p>The <code><s:Linear></code> tag
+ * inherits all of the tag attributes of its of its superclass,
+ * and adds the following tag attributes:</p>
+ *
+ * <pre>
+ * <s:Linear
+ * id="ID"
+ * easeInFraction="0"
+ * easeOutFraction="0"
+ * />
+ * </pre>
+ *
+ * @includeExample examples/LinearEffectExample.mxml
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+public class Linear implements IEaser
+{
+ /**
+ * Constructor.
+ *
+ * @param easeInFraction The fraction of the overall duration
+ * in the acceleration phase, between 0.0 and 1.0.
+ *
+ * @param easeOutFraction The fraction of the overall duration
+ * in the deceleration phase, between 0.0 and 1.0.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function Linear(easeInFraction:Number = 0, easeOutFraction:Number = 0)
+ {
+ this.easeInFraction = easeInFraction;
+ this.easeOutFraction = easeOutFraction;
+ }
+
+ /**
+ * Storage for the _easeInFraction property
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ private var _easeInFraction:Number = 0;
+
+ /**
+ * The fraction an animation spent accelerating,
+ * between 0.0 and 1.0.
+ * The values of the <code>easeOutFraction</code> property
+ * and <code>easeInFraction</code> property must satisfy the
+ * equation <code>easeOutFraction + easeInFraction <= 1</code>
+ * where any remaining time is spent in the linear motion phase.
+ *
+ * @default 0
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function get easeInFraction():Number
+ {
+ return _easeInFraction;
+ }
+ public function set easeInFraction(value:Number):void
+ {
+ _easeInFraction = value;
+ }
+
+ /**
+ * Storage for the _easeInFraction property
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ private var _easeOutFraction:Number = 0;
+
+ /**
+ * The percentage an animation will spend decelerating,
+ * between 0.0 and 1.0.
+ * The values of the <code>easeOutFraction</code> property
+ * and <code>easeInFraction</code> property must satisfy the
+ * equation <code>easeOutFraction + easeInFraction <= 1</code>
+ * where any remaining time is spent in the linear motion phase.
+ *
+ * @default 0
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function get easeOutFraction():Number
+ {
+ return _easeOutFraction;
+ }
+ public function set easeOutFraction(value:Number):void
+ {
+ _easeOutFraction = value;
+ }
+
+
+ /**
+ * Calculates the eased fraction value based on the
+ * <code>easeInFraction</code> and <code>easeOutFraction</code>
+ * properties.
+ * If <code>fraction</code>
+ * is less than <code>easeInFraction</code>, it calculates a value
+ * based on accelerating up to the linear motion phase.
+ * If <code>fraction</code>
+ * is greater than <code>easeInFraction</code> and less than
+ * <code>(1-easeOutFraction)</code>, it calculates a value based
+ * on the linear motion phase between the easing in and easing out phases.
+ * Otherwise, it calculates a value based on constant deceleration
+ * between the linear motion phase and 0.0.
+ *
+ * @param fraction The elapsed fraction of the animation,
+ * between 0.0 and 1.0..
+ *
+ * @return The eased fraction of the animation.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function ease(fraction:Number):Number
+ {
+ // Handle the trivial case where no easing is requested
+ if (easeInFraction == 0 && easeOutFraction == 0)
+ return fraction;
+
+ var runRate:Number = 1 / (1 - easeInFraction/2 - easeOutFraction/2);
+ if (fraction < easeInFraction)
+ return fraction * runRate * (fraction / easeInFraction) / 2;
+ if (fraction > (1 - easeOutFraction))
+ {
+ var decTime:Number = fraction - (1 - easeOutFraction);
+ var decProportion:Number = decTime / easeOutFraction;
+ return runRate * (1 - easeInFraction/2 - easeOutFraction +
+ decTime * (2 - decProportion) / 2);
+ }
+ return runRate * (fraction - easeInFraction/2);
+ }
+}
+}
diff --git a/frameworks/projects/SparkRoyale/src/main/royale/spark/effects/easing/Sine.as b/frameworks/projects/SparkRoyale/src/main/royale/spark/effects/easing/Sine.as
new file mode 100644
index 0000000..73a1864
--- /dev/null
+++ b/frameworks/projects/SparkRoyale/src/main/royale/spark/effects/easing/Sine.as
@@ -0,0 +1,113 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+package spark.effects.easing
+{
+/**
+ * The Sine class defines easing functionality using a Sine function.
+ * Easing consists of two phases: the acceleration, or ease in phase,
+ * followed by the deceleration, or ease out phase.
+ * Use the <code>easeInFraction</code> property to specify
+ * the percentage of an animation accelerating.
+ *
+ * @mxml
+ *
+ * <p>The <code><s:Sine></code> tag
+ * inherits all of the tag attributes of its of its superclass,
+ * and adds the following tag attributes:</p>
+ *
+ * <pre>
+ * <s:Sine
+ * id="ID"
+ * />
+ * </pre>
+ *
+ * @includeExample examples/SinePowerEffectExample.mxml
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+public class Sine extends EaseInOutBase
+{
+ /**
+ * Constructor.
+ *
+ * @param easeInFraction Sets the value of
+ * the <code>easeInFraction</code> property. The default value is
+ * <code>EasingFraction.IN_OUT</code>, which eases in for the first half
+ * of the time and eases out for the remainder.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function Sine(easeInFraction:Number = 0.5)
+ {
+ super(easeInFraction);
+ }
+
+ /**
+ * @private
+ * Returns a value that represents the eased fraction during the
+ * ease in phase of the animation.
+ * The easing calculation for Sine is equal to
+ * <code>1 - cos(fraction*PI/2)</code>.
+ *
+ * @param fraction The fraction elapsed of the easing in phase
+ * of the animation, between 0.0 and 1.0.
+ *
+ * @return A value that represents the eased value for this
+ * phase of the animation.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ override protected function easeIn(fraction:Number):Number
+ {
+ return 1 - Math.cos(fraction * Math.PI/2);
+ }
+
+ /**
+ * @private
+ * Returns a value that represents the eased fraction during the
+ * ease out phase of the animation.
+ * The easing calculation for Sine is equal to
+ * <code>sin(fraction*PI/2)</code>.
+ *
+ * @param fraction The fraction elapsed of the easing out phase
+ * of the animation, between 0.0 and 1.0.
+ *
+ * @return A value that represents the eased value for this
+ * phase of the animation.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ override protected function easeOut(fraction:Number):Number
+ {
+ return Math.sin(fraction * Math.PI/2);
+ }
+}
+}
diff --git a/frameworks/projects/SparkRoyale/src/main/royale/spark/effects/interpolation/IInterpolator.as b/frameworks/projects/SparkRoyale/src/main/royale/spark/effects/interpolation/IInterpolator.as
new file mode 100644
index 0000000..3ce1d94
--- /dev/null
+++ b/frameworks/projects/SparkRoyale/src/main/royale/spark/effects/interpolation/IInterpolator.as
@@ -0,0 +1,105 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+package spark.effects.interpolation
+{
+/**
+ * The IInterpolator interface is implemented by classes that calculate
+ * values for the Animation class. The Animation class
+ * can handle parametric interpolation between Number values and
+ * arrays of Number values, but it cannot handle different types
+ * of interpolation, or interpolation between different types of
+ * values. Implementors of this interface can provide arbitrary
+ * interpolation capabilities so that Animations can be created between
+ * arbitrary values.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+public interface IInterpolator
+{
+ /**
+ * Given an elapsed fraction of an animation, between 0.0 and 1.0,
+ * and start and end values to interpolate, return the interpolated value.
+ *
+ * @param fraction The fraction elapsed of the
+ * animation, between 0.0 and 1.0.
+ *
+ * @param startValue The start value of the interpolation.
+ *
+ * @param endValue The end value of the interpolation.
+ *
+ * @return The interpolated value.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ function interpolate(fraction:Number,
+ startValue:Object, endValue:Object):Object;
+
+ /**
+ * Given a base value and a value to add to it,
+ * return the result of that operation.
+ * For example, if the objects are simple Numbers, the result is a
+ * <code>Number(baseValue) + Number(incrementValue)</code>.
+ * This method is called by the animation system when it
+ * needs to dynamically calculate a value given some starting
+ * value and a 'by' value that should be added to it. Both of
+ * the arguments are of type Object and cannot simply be added together.
+ *
+ * @param baseValue The start value of the interpolation.
+ *
+ * @param incrementValue The change to apply to the <code>baseValue</code>.
+ *
+ * @return The interpolated value.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ function increment(baseValue:Object, incrementValue:Object):Object;
+
+ /**
+ * Given a base value and a value to subtract from it,
+ * return the result of that decrement operation. For example,
+ * if the objects are simple Numbers, the result would be
+ * <code>Number(baseValue) - Number(incrementValue)</code>.
+ * This function is called by the animation system when it
+ * needs to dynamically calculate a value given some ending
+ * value and a 'by' value that should be subtracted from it. Both of
+ * the arguments are of type Object and cannot simply be added together.
+ *
+ * @param baseValue The start value of the interpolation.
+ *
+ * @param decrementValue The change to apply to the <code>baseValue</code>.
+ *
+ * @return The interpolated value.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ function decrement(baseValue:Object, decrementValue:Object):Object;
+}
+}
diff --git a/frameworks/projects/SparkRoyale/src/main/royale/spark/effects/interpolation/MultiValueInterpolator.as b/frameworks/projects/SparkRoyale/src/main/royale/spark/effects/interpolation/MultiValueInterpolator.as
new file mode 100644
index 0000000..a56ec1c
--- /dev/null
+++ b/frameworks/projects/SparkRoyale/src/main/royale/spark/effects/interpolation/MultiValueInterpolator.as
@@ -0,0 +1,208 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+package spark.effects.interpolation
+{
+
+import mx.resources.IResourceManager;
+import mx.resources.ResourceManager;
+
+//--------------------------------------
+// Other metadata
+//--------------------------------------
+
+[ResourceBundle("sparkEffects")]
+
+/**
+ * The MultiValueInterpolator class interpolates each element of Arrays or
+ * Vectors of start and end elements separately, using another interpolator
+ * to do the interpolation for each element.
+ * By default, the
+ * interpolation for each element uses the NumberInterpolator class, but you
+ * can construct a MultiValueInterpolator instance with a different interpolator.
+ *
+ * @see
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+public class MultiValueInterpolator implements IInterpolator
+{
+
+ /**
+ * Constructor.
+ *
+ * @param elementInterpolator The interpolator for each element
+ * of the Array.
+ * If no interpolator is specified, use the NumberInterpolator class.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function MultiValueInterpolator(elementInterpolator:IInterpolator = null)
+ {
+ if (elementInterpolator != null)
+ this.elementInterpolator = elementInterpolator;
+ }
+
+ /**
+ * @private
+ * Used for accessing localized Error messages.
+ */
+ private var resourceManager:IResourceManager =
+ ResourceManager.getInstance();
+
+ // The internal per-element interpolator
+ private var _elementInterpolator:IInterpolator = NumberInterpolator.getInstance();
+ /**
+ * The interpolator for each element of the input Array or Vector.
+ * A value of null specifies to use the NumberInterpolator class.
+ *
+ * @default NumberInterpolator
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function get elementInterpolator():IInterpolator
+ {
+ return _elementInterpolator;
+ }
+ /**
+ * @private
+ */
+ public function set elementInterpolator(value:IInterpolator):void
+ {
+ _elementInterpolator = value ?
+ value : (NumberInterpolator.getInstance());
+ }
+
+ /**
+ * Given an elapsed fraction of an animation, between 0.0 and 1.0,
+ * and start and end values to interpolate, return the interpolated value.
+ *
+ * Interpolation for MultiValueInterpolator consists of running a separate
+ * interpolation on each element of the startValue and endValue
+ * arrays or vectors, returning a new Array or Vector that holds those
+ * interpolated values. The returned object will be an Array if startValue
+ * and endValue are of type Array, otherwise the returned object will be
+ * of type Vector.
+ *
+ * @param fraction The fraction elapsed of the
+ * animation, between 0.0 and 1.0.
+ *
+ * @param startValue The start value of the interpolation.
+ *
+ * @param endValue The end value of the interpolation.
+ *
+ * @return The interpolated value.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function interpolate(fraction:Number, startValue:Object,
+ endValue:Object):Object
+ {
+ if (startValue.length != endValue.length)
+ throw new Error(resourceManager.getString("sparkEffects", "arraysNotOfEqualLength"));
+ var returnObject:Object;
+ if (startValue is Array)
+ returnObject = [];
+ else
+ // splice(0,0) seems to be the only way to create a Vector of the
+ // same type
+ returnObject = startValue.splice(0, 0);
+ for (var i:int = 0; i < startValue.length; i++)
+ returnObject[i] = _elementInterpolator.interpolate(fraction,
+ startValue[i], endValue[i]);
+
+ return returnObject;
+ }
+
+ /**
+ * @inheritDoc
+ *
+ * Incrementing for MultiValueInterpolator consists of running a separate
+ * increment operation on each element of the <code>baseValue</code> array,
+ * adding the same <code>incrementValue</code> to each one and
+ * returning a new Array or Vector that holds those incremented values.
+ * The returned object will be an Array if startValue
+ * and endValue are of type Array, otherwise the returned object will be
+ * of type Vector.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function increment(baseValue:Object, incrementValue:Object):Object
+ {
+ var returnObject:Object;
+ if (baseValue is Array)
+ returnObject = [];
+ else
+ // splice(0,0) seems to be the only way to create a Vector of the
+ // same type
+ returnObject = baseValue.splice(0, 0);
+ for (var i:int = 0; i < baseValue.length; i++)
+ returnObject[i] = _elementInterpolator.increment(
+ baseValue[i], incrementValue);
+
+ return returnObject;
+ }
+
+ /**
+ * @inheritDoc
+ *
+ * Decrementing for MultiValueInterpolator consists of running a separate
+ * decrement operation on each element of the <code>baseValue</code> object,
+ * subtracting the same <code>incrementValue</code> from each one and
+ * returning a new Array or Vector that holds those decremented values.
+ * The returned object will be an Array if startValue
+ * and endValue are of type Array, otherwise the returned object will be
+ * of type Vector.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function decrement(baseValue:Object, decrementValue:Object):Object
+ {
+ var returnObject:Object;
+ if (baseValue is Array)
+ returnObject = [];
+ else
+ // splice(0,0) seems to be the only way to create a Vector of the
+ // same type
+ returnObject = baseValue.splice(0, 0);
+ for (var i:int = 0; i < baseValue.length; i++)
+ returnObject[i] = _elementInterpolator.decrement(
+ baseValue[i], decrementValue);
+
+ return returnObject;
+ }
+
+}
+}
diff --git a/frameworks/projects/SparkRoyale/src/main/royale/spark/effects/interpolation/NumberInterpolator.as b/frameworks/projects/SparkRoyale/src/main/royale/spark/effects/interpolation/NumberInterpolator.as
new file mode 100644
index 0000000..6651f09
--- /dev/null
+++ b/frameworks/projects/SparkRoyale/src/main/royale/spark/effects/interpolation/NumberInterpolator.as
@@ -0,0 +1,145 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+package spark.effects.interpolation
+{
+
+import mx.resources.IResourceManager;
+import mx.resources.ResourceManager;
+
+//--------------------------------------
+// Other metadata
+//--------------------------------------
+
+[ResourceBundle("sparkEffects")]
+
+/**
+ * The NumberInterpolator class provides interpolation between
+ * start and end values represented as Number instances.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+public class NumberInterpolator implements IInterpolator
+{
+ private static var theInstance:NumberInterpolator;
+
+ /**
+ * Constructor.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function NumberInterpolator()
+ {
+ super();
+ }
+
+ /**
+ * @private
+ * Used for accessing localized Error messages.
+ */
+ private var resourceManager:IResourceManager =
+ ResourceManager.getInstance();
+
+ /**
+ * Returns the singleton of this class.
+ * Since all NumberInterpolators
+ * have the same behavior, there is no need for more than one instance.
+ *
+ * @return The singleton of this class.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public static function getInstance():NumberInterpolator
+ {
+ if (!theInstance)
+ theInstance = new NumberInterpolator();
+ return theInstance;
+ }
+
+ /**
+ * Interpolation for NumberInterpolator consists of a simple
+ * parametric calculation between <code>startValue</code> and
+ * <code>endValue</code>, using <code>fraction</code> as the
+ * fraction of the elapsed time from start to end:
+ *
+ * <pre>return startValue + fraction * (endValue - startValue);</pre>
+ *
+ * @param fraction The fraction elapsed of the
+ * animation, between 0.0 and 1.0.
+ *
+ * @param startValue The start value of the interpolation.
+ *
+ * @param endValue The end value of the interpolation.
+ *
+ * @return The interpolated value.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function interpolate(fraction:Number, startValue:Object,
+ endValue:Object):Object
+ {
+ // Quick test for 0 or 1 to avoid round-off error on either end
+ if (fraction == 0)
+ return startValue;
+ else if (fraction == 1)
+ return endValue;
+ if ((startValue is Number && isNaN(Number(startValue))) ||
+ (endValue is Number && isNaN(Number(endValue))))
+ throw new Error(resourceManager.getString("sparkEffects", "cannotCalculateValue", [startValue, endValue]));
+ return Number(startValue) + (fraction * (Number(endValue) - Number(startValue)));
+ }
+
+ /**
+ * @inheritDoc
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function increment(baseValue:Object, incrementValue:Object):Object
+ {
+ return Number(baseValue) + Number(incrementValue);
+ }
+
+ /**
+ * @inheritDoc
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function decrement(baseValue:Object, decrementValue:Object):Object
+ {
+ return Number(baseValue) - Number(decrementValue);
+ }
+}
+}
diff --git a/frameworks/projects/SparkRoyale/src/main/royale/spark/effects/interpolation/RGBInterpolator.as b/frameworks/projects/SparkRoyale/src/main/royale/spark/effects/interpolation/RGBInterpolator.as
new file mode 100644
index 0000000..50a5d64
--- /dev/null
+++ b/frameworks/projects/SparkRoyale/src/main/royale/spark/effects/interpolation/RGBInterpolator.as
@@ -0,0 +1,193 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+package spark.effects.interpolation
+{
+/**
+ * The RGBInterpolator class provides interpolation between
+ * <code>uint</code> start and end values that represent RGB colors.
+ * Interpolation is done by treating
+ * the start and end values as integers with color channel information in
+ * the least-significant 3 bytes, and then interpolating each of the channels
+ * separately.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+public class RGBInterpolator implements IInterpolator
+{
+ private static var theInstance:RGBInterpolator;
+
+ /**
+ * Constructor.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function RGBInterpolator()
+ {
+ super();
+ }
+
+ /**
+ * Returns the singleton of this class. Since all RGBInterpolators
+ * have the same behavior, there is no need for more than one instance.
+ *
+ * @return The singleton of this class.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public static function getInstance():RGBInterpolator
+ {
+ if (!theInstance)
+ theInstance = new RGBInterpolator();
+ return theInstance;
+ }
+
+ /**
+ * Interpolation for the RGBInterpolator class takes the form of parametric
+ * calculations on each of the bottom three bytes of
+ * <code>startValue</code> and <code>endValue</code>.
+ *
+ * @param fraction The fraction elapsed of the
+ * animation, between 0.0 and 1.0.
+ *
+ * @param startValue The start value of the interpolation.
+ *
+ * @param endValue The end value of the interpolation.
+ *
+ * @return The interpolated value.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function interpolate(fraction:Number, startValue:Object,
+ endValue:Object):Object
+ {
+ // Quick test for start or end
+ if (fraction == 0)
+ return startValue;
+ else if (fraction == 1)
+ return endValue;
+ var startR:int;
+ var startG:int;
+ var startB:int;
+ var endR:int;
+ var endG:int;
+ var endB:int;
+ var deltaR:int;
+ var deltaG:int;
+ var deltaB:int;
+ fraction = Math.min(1, Math.max(0, fraction));
+ startR = (uint(startValue) & 0xff0000) >> 16;
+ startG = (uint(startValue) & 0xff00) >> 8;
+ startB = uint(startValue) & 0xff;
+ endR = (uint(endValue) & 0xff0000) >> 16;
+ endG = (uint(endValue) & 0xff00) >> 8;
+ endB = uint(endValue) & 0xff;
+ deltaR = endR - startR;
+ deltaG = endG - startG;
+ deltaB = endB - startB;
+ var newR:uint = startR + deltaR * fraction;
+ var newG:uint = startG + deltaG * fraction;
+ var newB:uint = startB + deltaB * fraction;
+ return newR << 16 | newG << 8 | newB;
+ }
+
+ /**
+ * @private
+ *
+ * Utility function called by increment() and decrement()
+ */
+ private function combine(baseValue:uint, deltaValue:uint,
+ increment:Boolean):Object
+ {
+ var baseR:int = (baseValue & 0xff0000) >> 16;
+ var baseG:int = (baseValue & 0xff00) >> 8;
+ var baseB:int = baseValue & 0xff;
+ var deltaR:int = (deltaValue & 0xff0000) >> 16;
+ var deltaG:int = (deltaValue & 0xff00) >> 8;
+ var deltaB:int = deltaValue & 0xff;
+ var newR:uint, newG:uint, newB:uint;
+ if (increment)
+ {
+ newR = Math.min(baseR + deltaR, 255);
+ newG = Math.min(baseG + deltaG, 255);
+ newB = Math.min(baseB + deltaB, 255);
+ }
+ else
+ {
+ newR = Math.max(baseR - deltaR, 0);
+ newG = Math.max(baseG - deltaG, 0);
+ newB = Math.max(baseB - deltaB, 0);
+ }
+ return newR << 16 | newG << 8 | newB;
+ }
+
+ /**
+ * Returns the result of the two values added
+ * together on a per-channel basis. Each channel has a maximum
+ * value of 255 to avoid overflow problems.
+ *
+ * @param baseValue The start value of the interpolation.
+ *
+ * @param incrementValue The change to apply to the <code>baseValue</code>.
+ *
+ * @return The interpolated value.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function increment(baseValue:Object, incrementValue:Object):Object
+ {
+ return combine(uint(baseValue), uint(incrementValue), true);
+ }
+
+ /**
+ * Returns the result of the two values subtracted
+ * on a per-channel basis. Each channel has a minimum
+ * value of 0 to avoid underflow problems.
+ *
+ * @param baseValue The start value of the interpolation.
+ *
+ * @param decrementValue The change to apply to the <code>baseValue</code>.
+ *
+ * @return The interpolated value.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function decrement(baseValue:Object, decrementValue:Object):Object
+ {
+ return combine(uint(baseValue), uint(decrementValue), false);
+ }
+}
+}
diff --git a/frameworks/projects/SparkRoyale/src/main/royale/spark/effects/supportClasses/AnimateColorInstance.as b/frameworks/projects/SparkRoyale/src/main/royale/spark/effects/supportClasses/AnimateColorInstance.as
new file mode 100644
index 0000000..a0591c6
--- /dev/null
+++ b/frameworks/projects/SparkRoyale/src/main/royale/spark/effects/supportClasses/AnimateColorInstance.as
@@ -0,0 +1,134 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package spark.effects.supportClasses
+{
+import mx.styles.StyleManager;
+
+import spark.effects.animation.Keyframe;
+import spark.effects.animation.MotionPath;
+import spark.effects.animation.SimpleMotionPath;
+import spark.effects.interpolation.RGBInterpolator;
+
+/**
+ * The AnimateColorInstance class is the instance class of
+ * the AnimateColor effect, which animates a change in
+ * color by interpolating the from/to values per color channel.
+ * Flex creates an instance of this class when
+ * it plays a AnimateFilter effect; you do not create one yourself.
+ *
+ * @see spark.effects.AnimateColor
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+public class AnimateColorInstance extends AnimateInstance
+{
+ /**
+ * @copy spark.effects.AnimateColor#colorFrom
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public var colorFrom:uint;
+
+ /**
+ * @copy spark.effects.AnimateColor#colorTo
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public var colorTo:uint;
+
+ /**
+ * @copy spark.effects.AnimateColor#colorPropertyName
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public var colorPropertyName:String;
+
+ /**
+ * Constructor.
+ *
+ * @param target The Object to animate with this effect.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function AnimateColorInstance(target:Object)
+ {
+ super(target);
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // Overridden methods
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ */
+ override public function play():void
+ {
+ // The user may have supplied some combination of xFrom, xTo, and xBy.
+ // If either xFrom or xTo is not explicitly defined, calculate its
+ // value based on the other two values.
+ if (colorFrom == StyleManager.NOT_A_COLOR)
+ {
+ if (propertyChanges && propertyChanges.start[colorPropertyName] !== undefined)
+ colorFrom = propertyChanges.start[colorPropertyName];
+ else
+ colorFrom = getCurrentValue(colorPropertyName);
+ }
+ if (colorTo == StyleManager.NOT_A_COLOR)
+ {
+ if (propertyChanges &&
+ propertyChanges.end[colorPropertyName] !== undefined)
+ {
+ colorTo = propertyChanges.end[colorPropertyName];
+ }
+ else
+ {
+ colorTo = getCurrentValue(colorPropertyName);
+ }
+ }
+
+ motionPaths = new <MotionPath>[new MotionPath(colorPropertyName)];
+ motionPaths[0].keyframes = new <Keyframe>[new Keyframe(0, colorFrom),
+ new Keyframe(duration, colorTo)];
+
+ if (!interpolator)
+ interpolator = RGBInterpolator.getInstance();
+
+ super.play();
+ }
+}
+}
diff --git a/frameworks/projects/SparkRoyale/src/main/royale/spark/effects/supportClasses/AnimateInstance.as b/frameworks/projects/SparkRoyale/src/main/royale/spark/effects/supportClasses/AnimateInstance.as
new file mode 100644
index 0000000..42dba13
--- /dev/null
+++ b/frameworks/projects/SparkRoyale/src/main/royale/spark/effects/supportClasses/AnimateInstance.as
@@ -0,0 +1,1166 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package spark.effects.supportClasses
+{
+import org.apache.royale.utils.Timer;
+
+import mx.core.IVisualElement;
+import mx.core.IVisualElementContainer;
+import mx.core.UIComponent;
+import mx.core.mx_internal;
+import mx.effects.Effect;
+import mx.effects.EffectInstance;
+import mx.events.EffectEvent;
+import mx.managers.SystemManager;
+import mx.resources.IResourceManager;
+import mx.resources.ResourceManager;
+import mx.styles.IStyleClient;
+
+import spark.effects.animation.Animation;
+import spark.effects.animation.IAnimationTarget;
+import spark.effects.animation.Keyframe;
+import spark.effects.animation.MotionPath;
+import spark.effects.animation.SimpleMotionPath;
+import spark.effects.easing.IEaser;
+import spark.effects.interpolation.IInterpolator;
+//import spark.primitives.supportClasses.GraphicElement;
+
+use namespace mx_internal;
+
+//--------------------------------------
+// Other metadata
+//--------------------------------------
+
+[ResourceBundle("sparkEffects")]
+
+/**
+ * The AnimateInstance class implements the instance class for the
+ * Animate effect. Flex creates an instance of this class when
+ * it plays a Animate effect; you do not create one yourself.
+ *
+ * @see spark.effects.Animate
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+public class AnimateInstance extends EffectInstance implements IAnimationTarget
+{
+ /**
+ * @private
+ */
+ public var animation:Animation;
+
+ /**
+ * Constructor.
+ *
+ * @param target The Object to animate with this effect.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function AnimateInstance(target:Object)
+ {
+ super(target);
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // Variables
+ //
+ //--------------------------------------------------------------------------
+ /**
+ * Tracks whether each property of the target is an actual
+ * property or a style. We determine this dynamically by
+ * simply checking whether the property is 'in' the target.
+ * If not, we check whether it is a valid style, and otherwise
+ * throw an error.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ private var isStyleMap:Object = new Object();
+
+ /**
+ * @private.
+ * Used internally to hold the value of the new playhead position
+ * if the animation doesn't currently exist.
+ */
+ private var _seekTime:Number = 0;
+
+ private var reverseAnimation:Boolean;
+
+ private var needsRemoval:Boolean;
+
+ /**
+ * @private
+ * Track number of update listeners for optimization purposes
+ */
+ private var numUpdateListeners:int = 0;
+
+
+ /**
+ * @private
+ * Used for accessing localized Error messages.
+ */
+ private var resourceManager:IResourceManager =
+ ResourceManager.getInstance();
+
+ /**
+ * @private
+ * Cache these values when disabling constraints, to correctly reset
+ * width/height values when we finish
+ */
+ private var oldWidth:Number;
+ private var oldHeight:Number;
+
+ /**
+ * @private
+ * Used to selectively disable constraints that are being animated by
+ * their underlying values because the constraint values are not
+ * valid in both states of a transition. For example, if left is set
+ * in only one state, then we disable left and animate x instead,
+ * re-enabling left when the effect is finished.
+ */
+ private var disabledConstraintsMap:Object;
+
+ //--------------------------------------------------------------------------
+ //
+ // Properties
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ */
+ //override public function set suspendBackgroundProcessing(value:Boolean):void
+ //{
+ //// Noop: this flag causes Flex 4 effects to break because they
+ //// depend on the layout validation process that the flag suppresses
+ //}
+
+ private var _motionPaths:Vector.<MotionPath>;
+ /**
+ * @copy spark.effects.Animate#motionPaths
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function get motionPaths():Vector.<MotionPath>
+ {
+ return _motionPaths;
+ }
+ public function set motionPaths(value:Vector.<MotionPath>):void
+ {
+ // Only set the list to the given value if we have a
+ // null list to begin with. Otherwise, we've already
+ // set up the list once and don't need to do it again
+ // (for example, in a repeating effect).
+ if (!_motionPaths)
+ _motionPaths = value;
+ }
+
+ /**
+ * If <code>true</code>, the effect retains its target
+ * during a transition and removes it when finished.
+ * This capability applies specifically to effects like
+ * Fade which act on targets that go away at the end of the
+ * transition and removes the need to supply a RemoveAction or similar
+ * effect to manually keep the item around and remove it when the
+ * transition completes.
+ *
+ * <p>To use this capability, subclasses
+ * should set this variable to <code>true</code> and also expose the <code>parent</code>
+ * property in their <code>affectedProperties</code> Array so
+ * that the effect instance has enough information about the target
+ * and container to do the job.</p>
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ protected var autoRemoveTarget:Boolean = false;
+
+ /**
+ * @copy spark.effects.Animate#disableLayout
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public var disableLayout:Boolean;
+
+ private var _easer:IEaser;
+ /**
+ * @copy spark.effects.Animate#easer
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function set easer(value:IEaser):void
+ {
+ _easer = value;
+ }
+ /**
+ * @private
+ */
+ public function get easer():IEaser
+ {
+ return _easer;
+ }
+
+ private var _interpolator:IInterpolator;
+ /**
+ * @copy spark.effects.Animate#interpolator
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function set interpolator(value:IInterpolator):void
+ {
+ _interpolator = value;
+
+ }
+ /**
+ * @private
+ */
+ public function get interpolator():IInterpolator
+ {
+ return _interpolator;
+ }
+
+ private var _repeatBehavior:String;
+ /**
+ * @copy spark.effects.Animate#repeatBehavior
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function set repeatBehavior(value:String):void
+ {
+ _repeatBehavior = value;
+ }
+ /**
+ * @private
+ */
+ public function get repeatBehavior():String
+ {
+ return _repeatBehavior;
+ }
+
+ //----------------------------------
+ // playReversed
+ //----------------------------------
+
+ /**
+ * @private
+ */
+ //override mx_internal function set playReversed(value:Boolean):void
+ //{
+ //super.playReversed = value;
+ //
+ //if (value && animation)
+ //animation.reverse();
+ //
+ //reverseAnimation = value;
+ //}
+
+ //--------------------------------------------------------------------------
+ //
+ // Overridden methods
+ //
+ //--------------------------------------------------------------------------
+
+ //----------------------------------
+ // playheadTime
+ //----------------------------------
+
+ /**
+ * @inheritDoc
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ override public function get playheadTime():Number
+ {
+ return animation ? animation.playheadTime : _seekTime;
+ }
+ /**
+ * @private
+ */
+ override public function set playheadTime(value:Number):void
+ {
+ if (animation)
+ animation.playheadTime = value;
+ _seekTime = value;
+ }
+
+
+ /**
+ * @private
+ */
+ override public function pause():void
+ {
+ super.pause();
+
+ if (animation)
+ animation.pause();
+ }
+
+ /**
+ * @private
+ */
+ override public function stop():void
+ {
+ super.stop();
+
+ if (animation)
+ animation.stop();
+ }
+
+ /**
+ * @private
+ */
+ override public function resume():void
+ {
+ super.resume();
+
+ if (animation)
+ animation.resume();
+ }
+
+ /**
+ * @private
+ */
+ override public function reverse():void
+ {
+ super.reverse();
+
+ if (animation)
+ animation.reverse();
+
+ reverseAnimation = !reverseAnimation;
+ }
+
+ /**
+ * @private
+ * Interrupts an effect that is currently playing,
+ * and immediately jumps to the end of the effect.
+ * Calls the <code>Tween.endTween()</code> method
+ * on the <code>tween</code> property.
+ * This method implements the method of the superclass.
+ *
+ * <p>If you create a subclass of TweenEffectInstance,
+ * you can optionally override this method.</p>
+ *
+ * <p>The effect dispatches the <code>effectEnd</code> event.</p>
+ *
+ * @see mx.effects.EffectInstance#end()
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ override public function end():void
+ {
+ // Jump to the end of the animation.
+ if (animation)
+ {
+ animation.end();
+ animation = null;
+ }
+
+ super.end();
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // Methods
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ override public function startEffect():void
+ {
+ // This override removes EffectManager.effectStarted() to avoid use of
+ // mx_internal. New effects are not currently triggerable, so
+ // this should not matter
+
+ if (target is UIComponent)
+ {
+ //UIComponent(target).effectStarted(this);
+ }
+
+ if (autoRemoveTarget)
+ addDisappearingTarget();
+
+ play();
+ }
+
+ /**
+ * Starts this effect. Performs any final setup for each property
+ * from/to values and starts an Animation that will update that property.
+ *
+ * @private
+ */
+ override public function play():void
+ {
+ super.play();
+
+ if (!motionPaths || motionPaths.length == 0)
+ {
+ // nothing to do; at least schedule the effect to end after
+ // the specified duration
+ var timer:Timer = new Timer(duration, 1);
+ timer.addEventListener("timer", noopAnimationHandler);
+ timer.start();
+ return;
+ }
+
+ isStyleMap = new Array(motionPaths.length);
+
+ // TODO (chaase): avoid setting up animations on properties whose
+ // from/to values are the same. Not worth the cycles, but also want
+ // to avoid triggering any side effects when we're not actually changing
+ // values
+ var addWidthMP:Boolean;
+ var addHeightMP:Boolean;
+ var i:int;
+ var j:int;
+ for (i = 0; i < motionPaths.length; ++i)
+ {
+ var mp:MotionPath = MotionPath(motionPaths[i]);
+ var keyframes:Vector.<Keyframe> = mp.keyframes;
+ if (!keyframes)
+ continue;
+ // Account for animating constraints where one or both state values
+ // are invalid; use underlying properties of x, y, width, height
+ // instead, or in addition
+ if (propertyChanges != null &&
+ (mp.property == "left" || mp.property == "right" ||
+ mp.property == "top" || mp.property == "bottom" ||
+ mp.property == "percentWidth" || mp.property == "percentHeight" ||
+ mp.property == "horizontalCenter" || mp.property == "verticalCenter"))
+ {
+ // We need to substitute an underlying property if the animation is
+ // trying to automatically use and animate between the constraint
+ // values in the states, but one or both values are invalid
+ if (!isValidValue(propertyChanges.start[mp.property]) ||
+ !isValidValue(propertyChanges.end[mp.property]) &&
+ keyframes.length == 2 && !isValidValue(keyframes[0].value) &&
+ !isValidValue(keyframes[1].value))
+ {
+ if (mp.property == "percentWidth")
+ mp.property = "width";
+ else if (mp.property == "percentHeight")
+ mp.property = "height";
+ else if (mp.property == "left" || mp.property == "right" ||
+ mp.property == "horizontalCenter")
+ {
+ if (!disabledConstraintsMap)
+ disabledConstraintsMap = new Object();
+ disabledConstraintsMap[mp.property] = true;
+ mp.property = "x";
+ if (isValidValue(propertyChanges.start["width"]) &&
+ isValidValue(propertyChanges.end["width"]) &&
+ propertyChanges.start["width"] != propertyChanges.end["width"])
+ {
+ // add motionPath to account for width changing between states
+ addWidthMP = true;
+ }
+ }
+ else
+ {
+ if (!disabledConstraintsMap)
+ disabledConstraintsMap = new Object();
+ disabledConstraintsMap[mp.property] = true;
+ mp.property = "y";
+ if (isValidValue(propertyChanges.start["height"]) &&
+ isValidValue(propertyChanges.end["height"]) &&
+ propertyChanges.start["height"] != propertyChanges.end["height"])
+ {
+ // add motionPath to account for height changing between states
+ addHeightMP = true;
+ }
+ }
+ }
+ }
+ if (interpolator)
+ mp.interpolator = interpolator;
+ // adjust effect duration to be the max of all MotionPath keyframe times
+ // duration==0 is special-case, because the user (or an internal request)
+ // specifically asked the effect to be of zero duration
+ // TODO (chaase): Currently we do not adjust *down* for smaller duration
+ // MotionPaths. This is because we do not distinguish between
+ // SimpleMotionPath objects (which are created with fake durations of 1,
+ // knowing that they will derive their duration from their effects) and
+ // actual keyframe-based MotionPaths.
+ if (duration > 0)
+ for (j = 0; j < keyframes.length; ++j)
+ if (!isNaN(keyframes[j].time))
+ duration = Math.max(duration, keyframes[j].time);
+
+ }
+ if (addWidthMP)
+ motionPaths.push(new SimpleMotionPath("width"));
+ if (addHeightMP)
+ motionPaths.push(new SimpleMotionPath("height"));
+
+ animation = new Animation(duration);
+ animation.animationTarget = this;
+ animation.motionPaths = motionPaths;
+
+ if (reverseAnimation)
+ animation.playReversed = true;
+ animation.interpolator = interpolator;
+ animation.repeatCount = repeatCount;
+ animation.repeatDelay = repeatDelay;
+ animation.repeatBehavior = repeatBehavior;
+ animation.easer = easer;
+ animation.startDelay = startDelay;
+
+ animation.play();
+ if (_seekTime > 0)
+ animation.playheadTime = _seekTime;
+ }
+
+ /**
+ * @private
+ * Set the values in the given animation on the properties held in
+ * motionPaths. This is called by the update and end
+ * functions, which are called by the Animation during the animation.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ protected function applyValues(anim:Animation):void
+ {
+ for (var i:int = 0; i < motionPaths.length; ++i)
+ {
+ var prop:String = motionPaths[i].property;
+ setValue(prop, anim.currentValue[prop]);
+ }
+ }
+
+ // TODO (chaase): This function appears in multiple places. Maybe
+ // put it in some util class instead?
+ /**
+ * @private
+ *
+ * Utility function to determine whether a given value is 'valid',
+ * which means it's either a Number and it's not NaN, or it's not
+ * a Number and it's not null
+ */
+ private function isValidValue(value:Object):Boolean
+ {
+ return ((value is Number && !isNaN(Number(value))) ||
+ (!(value is Number) && value !== null));
+ }
+
+ /**
+ * Walk the motionPaths looking for null values. A null indicates
+ * that the value should be replaced by the current value or one that
+ * is calculated from the other value and a supplied delta value.
+ *
+ * @return Boolean whether this call changed any values in the list
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ private function finalizeValues():Boolean
+ {
+ var changedValues:Boolean = false;
+ var j:int;
+ var prevValue:Object;
+ for (var i:int = 0; i < motionPaths.length; ++i)
+ {
+ var motionPath:MotionPath =
+ MotionPath(motionPaths[i]);
+ // set the first value (if invalid) to the current value
+ // in the target
+ var keyframes:Vector.<Keyframe> = motionPath.keyframes;
+ if (!keyframes || keyframes.length == 0)
+ continue;
+ if (!isValidValue(keyframes[0].value))
+ {
+ if (keyframes.length > 0 &&
+ isValidValue(keyframes[1].valueBy) &&
+ isValidValue(keyframes[1].value))
+ {
+ keyframes[0].value = motionPath.interpolator.decrement(
+ keyframes[1].value, keyframes[1].valueBy);
+ }
+ else
+ {
+ // An interrupting transition effect should grab its start
+ // values from the propertyChanges array, which has been populated
+ // in UIComponent.commitCurrentState() with the values of target
+ // objects when the previous transition was interrupted. The
+ // current values of the objects, from getCurrentValue(), may be
+ // set to the end values of that previous transition, so we do not
+ // want those values for the animation
+ //if ((playReversed || Effect(effect).transitionInterruption) &&
+ if ((playReversed) &&
+ propertyChanges &&
+ propertyChanges.start[motionPath.property] !== undefined)
+ {
+ keyframes[0].value = propertyChanges.start[motionPath.property];
+ }
+ else
+ {
+ keyframes[0].value = getCurrentValue(motionPath.property);
+ }
+ }
+ }
+ // set any other invalid values based on information in surrounding
+ // keyframes
+ prevValue = keyframes[0].value;
+ for (j = 1; j < keyframes.length; ++j)
+ {
+ var kf:Keyframe = Keyframe(keyframes[j]);
+ if (!isValidValue(kf.value))
+ {
+ if (isValidValue(kf.valueBy))
+ kf.value = motionPath.interpolator.increment(prevValue, kf.valueBy);
+ else
+ {
+ // if next keyframe has value and valueBy, use them
+ if (j <= (keyframes.length - 2) &&
+ isValidValue(keyframes[j+1].value) &&
+ isValidValue(keyframes[j+1].valueBy))
+ {
+ kf.value = motionPath.interpolator.decrement(
+ keyframes[j+1].value, keyframes[j+1].valueBy);
+ }
+ else if (j == (keyframes.length - 1) &&
+ propertyChanges &&
+ propertyChanges.end[motionPath.property] !== undefined)
+ {
+ // special case for final keyframe - use state value if it exists
+ kf.value = propertyChanges.end[motionPath.property];
+ }
+ else
+ {
+ // otherwise, just use previous keyframe value
+ kf.value = prevValue;
+ }
+ }
+ }
+ prevValue = kf.value;
+ }
+ }
+ return changedValues;
+
+ }
+
+ /**
+ * @private
+ * This function is called by subclasses during the play() function
+ * to add an animation to the current set of <code>motionPaths</code>.
+ * The animation will be set up on the named constraint if the constraint
+ * is in the <code>propertyChanges</code> array (which is only true during
+ * transitions for properties/styles exposed by the effect) and the
+ * value of that constraint is different between the start and end states.
+ */
+ protected function setupConstraintAnimation(constraintName:String):void
+ {
+ var startVal:* = propertyChanges.start[constraintName];
+ var endVal:* = propertyChanges.end[constraintName];
+ if (startVal !== undefined && endVal !== undefined &&
+ startVal !== null && endVal !== null &&
+ !isNaN(startVal) && !isNaN(endVal) &&
+ startVal != endVal)
+ {
+ motionPaths.push(new SimpleMotionPath(constraintName, startVal, endVal));
+ }
+ }
+
+ /**
+ * @private
+ * Called internally to handle start events for the animation.
+ * If you override this method, ensure that you call the super method.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function animationStart(animation:Animation):void
+ {
+ // Wait until the underlying Animation actually starts (after
+ // any startDelay) to cache constraints and disable layout. This
+ // avoids problems with doing this too early and affecting other
+ // effects that are running before this one.
+ if (disableLayout)
+ {
+ setupParentLayout(false);
+ cacheConstraints();
+ }
+ else if (disabledConstraintsMap)
+ {
+ for (var constraint:String in disabledConstraintsMap)
+ cacheConstraint(constraint);
+ disabledConstraintsMap = null;
+ }
+
+ finalizeValues();
+ }
+
+ /**
+ * @private
+ * Called internally to handle update events for the animation.
+ * If you override this method, ensure that you call the super method.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function animationUpdate(animation:Animation):void
+ {
+ applyValues(animation);
+ if (numUpdateListeners > 0)
+ {
+ // Only bother dispatching this event if there are listeners. This avoids
+ // unnecessary overhead for the common case of no listeners on this frequent
+ // event
+ //var event:EffectEvent = new EffectEvent(EffectEvent.EFFECT_UPDATE);
+ //event.effectInstance = this;
+ //dispatchEvent(event);
+ }
+ }
+
+ /**
+ * @private
+ * Called internally to handle repeat events for the animation.
+ * If you override this method, ensure that you call the super method.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function animationRepeat(animation:Animation):void
+ {
+ //var event:EffectEvent = new EffectEvent(EffectEvent.EFFECT_REPEAT);
+ //event.effectInstance = this;
+ //dispatchEvent(event);
+ }
+
+ private function animationCleanup():void
+ {
+ if (disableLayout)
+ {
+ reenableConstraints();
+ if (disableLayout)
+ setupParentLayout(true);
+ }
+ }
+
+ /**
+ * @private
+ * Called internally to handle end events for the animation.
+ * If you override this method, ensure that you call the super method.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function animationEnd(animation:Animation):void
+ {
+ animationCleanup();
+ finishEffect();
+ }
+
+ /**
+ * @private
+ * Called internally to handle stop events for the animation.
+ * If you override this method, ensure that you call the super method.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function animationStop(animation:Animation):void
+ {
+ animationCleanup();
+ }
+
+ private function noopAnimationHandler(event:Event):void
+ {
+ finishEffect();
+ }
+
+ /**
+ * @private
+ * Track number of listeners to update event for optimization purposes
+ */
+ //override public function addEventListener(type:String, listener:Function,
+ //useCapture:Boolean=false, priority:int=0,
+ //useWeakReference:Boolean=false):void
+ //{
+ //super.addEventListener(type, listener, useCapture, priority,
+ //useWeakReference);
+ //if (type == EffectEvent.EFFECT_UPDATE)
+ //++numUpdateListeners;
+ //}
+ //
+ ///**
+ //* @private
+ //* Track number of listeners to update event for optimization purposes
+ //*/
+ //override public function removeEventListener(type:String, listener:Function,
+ //useCapture:Boolean=false):void
+ //{
+ //super.removeEventListener(type, listener, useCapture);
+ //if (type == EffectEvent.EFFECT_UPDATE)
+ //--numUpdateListeners;
+ //}
+
+ /**
+ * @private
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ override public function finishEffect():void
+ {
+ if (autoRemoveTarget)
+ removeDisappearingTarget();
+ super.finishEffect();
+ }
+
+ /**
+ * Adds a target which is not in the state we are transitioning
+ * to. This is the partner of removeDisappearingTarget(), which removes
+ * the target when this effect is finished if necessary.
+ * Note that if a RemoveAction effect is playing in a CompositeEffect,
+ * then the adding/removing is already happening and this function
+ * will noop the add.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ private function addDisappearingTarget():void
+ {
+ needsRemoval = false;
+ if (propertyChanges)
+ {
+ // Check for non-null parent ensures that we won't double-remove
+ // items, such as if there is a RemoveAction effect working on
+ // the same target
+ if ("parent" in target && !target.parent)
+ {
+ var parentStart:* = propertyChanges.start["parent"];
+ var parentEnd:* = propertyChanges.end["parent"];
+ if (playReversed)
+ {
+ var tmp:* = parentStart;
+ parentStart = parentEnd;
+ parentEnd = tmp;
+ }
+ if (parentStart && !parentEnd &&
+ (parentStart is IVisualElementContainer || parentStart is SystemManager))
+ {
+ var startIndex:* = !playReversed ?
+ propertyChanges.start["index"] :
+ propertyChanges.end["index"];
+ if (parentStart is IVisualElementContainer)
+ {
+ var startContainer:IVisualElementContainer =
+ IVisualElementContainer(parentStart);
+ if (startIndex !== undefined && startIndex <= (startContainer as UIComponent).numElements)
+ (startContainer as UIComponent).addElementAt(
+ target as UIComponent, int(startIndex));
+ else
+ (startContainer as UIComponent).addElement(target as UIComponent);
+ }
+ else
+ {
+ var startMgr:SystemManager = parentStart as SystemManager;
+ if (startIndex !== undefined && startIndex <= startMgr.numChildren)
+ startMgr.addChildAt(target as UIComponent, int(startIndex));
+ else
+ startMgr.addChild(target as UIComponent);
+ }
+ // GraphicElements may delay parenting their underlying displayObject until
+ // a layout pass, so let's force it to make sure we're ready to go
+ // TODO (chaase): this should probably happen as a part of applyStartValues()
+ // instead, then we already force the layout to happen. Also, this might
+ // enable this auto-add functionality to work for Sequence instead of just
+ // Parallel effects, since applyStartValues() is called at the outer effect
+ // start time, not just at the inner instance start time.
+ //if (target is GraphicElement)
+ //GraphicElement(target).validateNow();
+ needsRemoval = true;
+ }
+ }
+ }
+ }
+
+ /**
+ * Removes a target which is not in the state we are transitioning
+ * to. This is the partner of addDisappearingTarget(), which re-adds
+ * the target when this effect is played if necessary.
+ * Note that if a RemoveAction effect is playing in a CompositeEffect,
+ * then the adding/removing is already happening and this function
+ * will noop the removal.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ private function removeDisappearingTarget():void
+ {
+ if (needsRemoval && propertyChanges)
+ {
+ // Check for non-null parent ensures that we won't double-remove
+ // items, such as if there is a RemoveAction effect working on
+ // the same target
+ if ("parent" in target && target.parent)
+ {
+ var parentStart:* = propertyChanges.start["parent"];
+ var parentEnd:* = propertyChanges.end["parent"];
+ if (playReversed)
+ {
+ var tmp:* = parentStart;
+ parentStart = parentEnd;
+ parentEnd = tmp;
+ }
+ if (parentStart && !parentEnd)
+ {
+ if (parentStart is UIComponent)
+ UIComponent(parentStart).removeElement(target as UIComponent);
+ else
+ parentStart.removeChild(target);
+ }
+ }
+ }
+ }
+
+ private var constraintsHolder:Object;
+
+ // TODO (chaase): Use IConstraintClient for this
+ private function reenableConstraint(name:String):void
+ {
+ var value:* = constraintsHolder[name];
+ if (value !== undefined)
+ {
+ if (name in target)
+ target[name] = value;
+ else
+ target.setStyle(name, value);
+ delete constraintsHolder[name];
+ }
+ }
+
+ private function reenableConstraints():void
+ {
+ // Only bother if constraintsHolder is non-null; otherwise
+ // there must have been no constraints to worry about
+ if (constraintsHolder)
+ {
+ var left:* = reenableConstraint("left");
+ var right:* = reenableConstraint("right");
+ var top:* = reenableConstraint("top");
+ var bottom:* = reenableConstraint("bottom");
+ reenableConstraint("horizontalCenter");
+ reenableConstraint("verticalCenter");
+ reenableConstraint("baseline");
+ constraintsHolder = null;
+ if (left != undefined && right != undefined && "explicitWidth" in target)
+ target.explicitWidth = oldWidth;
+ if (top != undefined && bottom != undefined && "explicitHeight" in target)
+ target.explicitHeight = oldHeight;
+ }
+ }
+
+ // TODO (chaase): Use IConstraintClient for this
+ private function cacheConstraint(name:String):*
+ {
+ var isProperty:Boolean = (name in target);
+ var value:*;
+ if (isProperty)
+ value = target[name];
+ else
+ value = target.getStyle(name);
+ if (!isNaN(value) && value != null)
+ {
+ if (!constraintsHolder)
+ constraintsHolder = new Object();
+ constraintsHolder[name] = value;
+ // Now disable it - it will be re-enabled when effect finishes
+ if (isProperty)
+ target[name] = NaN;
+ else if (target is IStyleClient)
+ target.setStyle(name, undefined);
+ }
+ return value;
+ }
+
+ private function cacheConstraints():void
+ {
+ var left:* = cacheConstraint("left");
+ var right:* = cacheConstraint("right");
+ var top:* = cacheConstraint("top");
+ var bottom:* = cacheConstraint("bottom");
+ cacheConstraint("verticalCenter");
+ cacheConstraint("horizontalCenter");
+ cacheConstraint("baseline");
+ if (left != undefined && right != undefined && "explicitWidth" in target)
+ {
+ var w:Number = target.width;
+ oldWidth = target.explicitWidth;
+ target.width = w;
+ }
+ if (top != undefined && bottom != undefined && "explicitHeight" in target)
+ {
+ var h:Number = target.height;
+ oldHeight = target.explicitHeight;
+ target.height = h;
+ }
+ }
+
+ /**
+ * @private
+ * Utility function to handle situation where values may be queried or
+ * set on the target prior to completely setting up the effect's
+ * motionPaths data values (from which the styleMap is created)
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ protected function setupStyleMapEntry(property:String):void
+ {
+ // TODO (chaase): Find a better way to set this up just once
+ if (isStyleMap[property] == undefined)
+ {
+ if (property in target)
+ {
+ isStyleMap[property] = false;
+ }
+ else
+ {
+ try {
+ target.getStyle(property);
+ isStyleMap[property] = true;
+ }
+ catch (err:Error)
+ {
+ throw new Error(resourceManager.getString("sparkEffects",
+ "propNotPropOrStyle", [property, target, err]));
+ }
+ }
+ }
+ }
+
+ /**
+ * Utility function that sets the named property on the target to
+ * the given value. Handles setting the property as either a true
+ * property or a style.
+ * @private
+ */
+ protected function setValue(property:String, value:Object):void
+ {
+ // TODO (chaase): Find a better way to set this up just once
+ setupStyleMapEntry(property);
+ if (!isStyleMap[property])
+ target[property] = value;
+ else
+ target.setStyle(property, value);
+ }
+
+ /**
+ * Utility function that gets the value of the named property on
+ * the target. Handles getting the value of the property as either a true
+ * property or a style.
+ * @private
+ */
+ protected function getCurrentValue(property:String):*
+ {
+ // TODO (chaase): Find a better way to set this up just once
+ setupStyleMapEntry(property);
+ if (!isStyleMap[property])
+ return target[property];
+ else
+ return target.getStyle(property);
+ }
+
+ /**
+ * Enables or disables autoLayout in the target's container.
+ * This is used to disable layout during the course of an animation,
+ * and to re-enable it when the animation finishes.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ private function setupParentLayout(enable:Boolean):void
+ {
+ var parent:* = null;
+ if ("parent" in target && target.parent)
+ {
+ parent = target.parent;
+ }
+
+ if (parent && ("autoLayout" in parent))
+ parent.autoLayout = enable;
+ }
+}
+}
diff --git a/frameworks/projects/SparkRoyale/src/main/royale/spark/filters/ColorMatrixFilter.as b/frameworks/projects/SparkRoyale/src/main/royale/spark/filters/ColorMatrixFilter.as
index f7d6781..2deab36 100644
--- a/frameworks/projects/SparkRoyale/src/main/royale/spark/filters/ColorMatrixFilter.as
+++ b/frameworks/projects/SparkRoyale/src/main/royale/spark/filters/ColorMatrixFilter.as
@@ -19,7 +19,6 @@
package spark.filters
{
-import flash.filters.BitmapFilter;
//import flash.filters.ColorMatrixFilter;
import mx.filters.BaseFilter;
import mx.filters.IBitmapFilter;
diff --git a/frameworks/projects/SparkRoyale/src/main/royale/spark/primitives/supportClasses b/frameworks/projects/SparkRoyale/src/main/royale/spark/primitives/supportClasses
new file mode 100644
index 0000000..0a9eb0e
--- /dev/null
+++ b/frameworks/projects/SparkRoyale/src/main/royale/spark/primitives/supportClasses
@@ -0,0 +1,4673 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// ADOBE SYSTEMS INCORPORATED
+// Copyright 2008 Adobe Systems Incorporated
+// All Rights Reserved.
+//
+// NOTICE: Adobe permits you to use, modify, and distribute this file
+// in accordance with the terms of the license agreement accompanying it.
+//
+////////////////////////////////////////////////////////////////////////////////
+
+package spark.primitives.supportClasses
+{
+
+import flash.display.BitmapData;
+import flash.display.BlendMode;
+import flash.display.DisplayObject;
+import flash.display.DisplayObjectContainer;
+import flash.display.Shape;
+import flash.display.Sprite;
+import flash.events.Event;
+import flash.events.EventDispatcher;
+import flash.events.IEventDispatcher;
+import flash.geom.ColorTransform;
+import flash.geom.Matrix;
+import flash.geom.Matrix3D;
+import flash.geom.Point;
+import flash.geom.Rectangle;
+import flash.geom.Transform;
+import flash.geom.Vector3D;
+
+import mx.core.AdvancedLayoutFeatures;
+import mx.core.DesignLayer;
+import mx.core.IInvalidating;
+import mx.core.ILayoutDirectionElement;
+import mx.core.ILayoutElement;
+import mx.core.IMXMLObject;
+import mx.core.IUIComponent;
+import mx.core.IVisualElement;
+import mx.core.LayoutDirection;
+import mx.core.UIComponent;
+import mx.core.UIComponentGlobals;
+import mx.core.mx_internal;
+import mx.events.FlexEvent;
+import mx.events.PropertyChangeEvent;
+import mx.filters.BaseFilter;
+import mx.filters.IBitmapFilter;
+import mx.geom.Transform;
+import mx.geom.TransformOffsets;
+import mx.graphics.shaderClasses.ColorBurnShader;
+import mx.graphics.shaderClasses.ColorDodgeShader;
+import mx.graphics.shaderClasses.ColorShader;
+import mx.graphics.shaderClasses.ExclusionShader;
+import mx.graphics.shaderClasses.HueShader;
+import mx.graphics.shaderClasses.LuminosityShader;
+import mx.graphics.shaderClasses.SaturationShader;
+import mx.graphics.shaderClasses.SoftLightShader;
+import mx.managers.ILayoutManagerClient;
+import mx.utils.MatrixUtil;
+
+import spark.components.supportClasses.InvalidatingSprite;
+import spark.core.DisplayObjectSharingMode;
+import spark.core.IGraphicElement;
+import spark.core.IGraphicElementContainer;
+import spark.core.MaskType;
+import spark.utils.FTETextUtil;
+import spark.utils.MaskUtil;
+
+use namespace mx_internal;
+
+/**
+ * A base class for defining individual graphic elements. Types of graphic elements include:
+ * <ul>
+ * <li>Shapes</li>
+ * <li>Text</li>
+ * <li>Raster images</li>
+ * </ul>
+ *
+ * <p>When defining a graphic element, you specify an explicit size for the element;
+ * that is, you cannot use percentage sizing as you can when specifying the size of a control.</p>
+ *
+ * <p>The TBounds are the boundaries of an
+ * object in the object's parent coordinate space. The UBounds are the boundaries
+ * of an object in its own coordinate space.</p>
+ *
+ * <p>If you set the transform.matrix declaratively in MXML, then it will override
+ * the values of any transform properties (rotation, scaleX, scaleY, x, and y).
+ * If you set the transform.matrix or the transform properties in ActionScript, then
+ * the last value set will be used.</p>
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+public class GraphicElement extends EventDispatcher
+ implements IGraphicElement, IInvalidating, ILayoutElement, IVisualElement, IMXMLObject
+{
+ include "../../core/Version.as";
+
+ //--------------------------------------------------------------------------
+ //
+ // Class constants
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ * The default value for the <code>maxWidth</code> property.
+ */
+ private static const DEFAULT_MAX_WIDTH:Number = 10000;
+
+ /**
+ * @private
+ * The default value for the <code>maxHeight</code> property.
+ */
+ private static const DEFAULT_MAX_HEIGHT:Number = 10000;
+
+ /**
+ * @private
+ * The default value for the <code>minWidth</code> property.
+ */
+ private static const DEFAULT_MIN_WIDTH:Number = 0;
+
+ /**
+ * @private
+ * The default value for the <code>minHeight</code> property.
+ */
+ private static const DEFAULT_MIN_HEIGHT:Number = 0;
+
+ //--------------------------------------------------------------------------
+ //
+ // Constructor
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ */
+ public function GraphicElement()
+ {
+ super();
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // Variables
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ */
+ private var displayObjectChanged:Boolean;
+
+ /**
+ * @private
+ */
+ private var _colorTransform:ColorTransform;
+
+ private var colorTransformChanged:Boolean;
+
+ /**
+ * @private The Sprite to draw into.
+ * If null, then we just use displayObject or sharedDisplayObject
+ */
+ private var _drawnDisplayObject:InvalidatingSprite;
+
+ /**
+ * @private
+ * Whether this element needs to have its
+ * commitProperties() method called.
+ */
+ mx_internal var invalidatePropertiesFlag:Boolean = false;
+
+ /**
+ * @private
+ * Whether this element needs to have its
+ * measure() method called.
+ */
+ mx_internal var invalidateSizeFlag:Boolean = false;
+
+ /**
+ * @private
+ * Whether this element needs to be have its
+ * updateDisplayList() method called.
+ */
+ mx_internal var invalidateDisplayListFlag:Boolean = false;
+
+
+ /**
+ * Contain all of the implementation details of how the GraphicElement implements
+ * transform and layering support. In most cases, you should not have to modify this
+ * property.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ protected var layoutFeatures:AdvancedLayoutFeatures;
+
+
+ /**
+ * @private
+ * storage for the x property. This property is used when a GraphicElement has a simple transform.
+ */
+ private var _x:Number = 0;
+
+ /**
+ * @private
+ * storage for the y property. This property is used when a GraphicElement has a simple transform.
+ */
+ private var _y:Number = 0;
+
+ //--------------------------------------------------------------------------
+ //
+ // Properties
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * @copy mx.core.IVisualElement#postLayoutTransformOffsets
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function get postLayoutTransformOffsets():TransformOffsets
+ {
+ return (layoutFeatures == null)? null:layoutFeatures.postLayoutTransformOffsets;
+ }
+
+ /**
+ * @private
+ */
+ public function set postLayoutTransformOffsets(value:TransformOffsets):void
+ {
+ if (value != null)
+ allocateLayoutFeatures();
+
+ if (layoutFeatures.postLayoutTransformOffsets != null)
+ layoutFeatures.postLayoutTransformOffsets.removeEventListener(Event.CHANGE,transformOffsetsChangedHandler);
+ layoutFeatures.postLayoutTransformOffsets = value;
+ if (layoutFeatures.postLayoutTransformOffsets != null)
+ layoutFeatures.postLayoutTransformOffsets.addEventListener(Event.CHANGE,transformOffsetsChangedHandler);
+ }
+
+ /**
+ * @private
+ */
+ mx_internal function allocateLayoutFeatures():void
+ {
+ if (layoutFeatures != null)
+ return;
+ layoutFeatures = new AdvancedLayoutFeatures();
+ layoutFeatures.layoutX = _x;
+ layoutFeatures.layoutY = _y;
+ layoutFeatures.layoutWidth = _width; // for the mirror transform
+ }
+
+ /**
+ * @private
+ */
+ private function invalidateTransform(changeInvalidatesLayering:Boolean = true,
+ invalidateLayout:Boolean = true):void
+ {
+ if (changeInvalidatesLayering)
+ invalidateDisplayObjectSharing();
+
+ // Make sure we apply the transform
+ if (layoutFeatures != null)
+ layoutFeatures.updatePending = true;
+
+ // If we are sharing a display object we need to redraw
+ if (displayObjectSharingMode != DisplayObjectSharingMode.OWNS_UNSHARED_OBJECT)
+ invalidateDisplayList();
+ else
+ invalidateProperties(); // We apply the transform in commitProperties
+
+ // Trigger a layout pass
+ if (invalidateLayout)
+ invalidateParentSizeAndDisplayList();
+ }
+
+ /**
+ * @private
+ */
+ private function transformOffsetsChangedHandler(e:Event):void
+ {
+ invalidateTransform();
+ }
+
+ //----------------------------------
+ // alpha
+ //----------------------------------
+
+ /**
+ * @private
+ * Storage for the alpha property.
+ */
+ private var _alpha:Number = 1.0;
+ private var _effectiveAlpha:Number = 1.0;
+
+ /**
+ * @private
+ */
+ private var alphaChanged:Boolean = false;
+
+ [Inspectable(category="General", minValue="0.0", maxValue="1.0")]
+
+ /**
+ * The level of transparency of the graphic element. Valid values are decimal values between
+ * 0 (fully transparent) and 1 (fully opaque). For example, a value of .25 means that the
+ * element has 25% opacity.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function get alpha():Number
+ {
+ return _alpha;
+ }
+
+ /**
+ * @private
+ */
+ public function set alpha(value:Number):void
+ {
+ if (_alpha == value)
+ return;
+
+ var previous:Boolean = needsDisplayObject;
+ _alpha = value;
+
+ // The product of _alpha and the designLayer's
+ // alpha is the effectiveAlpha which is
+ // committed in commitProperties()
+ if (designLayer)
+ value = value * designLayer.effectiveAlpha;
+
+ if (_blendMode == "auto")
+ {
+ // If alpha changes from an opaque/transparent (1/0) and translucent
+ // (0 < value < 1), then trigger a blendMode change
+ if ((value > 0 && value < 1 && (_effectiveAlpha == 0 || _effectiveAlpha == 1)) ||
+ ((value == 0 || value == 1) && (_effectiveAlpha > 0 && _effectiveAlpha < 1)))
+ {
+ blendModeChanged = true;
+ }
+ }
+
+ _effectiveAlpha = value;
+
+ // Clear the colorTransform flag since alpha was explicitly set
+ var mxTransform:mx.geom.Transform = _transform as mx.geom.Transform;
+ if (mxTransform)
+ mxTransform.applyColorTransformAlpha = false;
+
+ if (previous != needsDisplayObject)
+ invalidateDisplayObjectSharing();
+
+ alphaChanged = true;
+ invalidateProperties();
+ }
+
+ //----------------------------------
+ // alwaysCreateDisplayObject
+ //----------------------------------
+
+ private var _alwaysCreateDisplayObject:Boolean;
+
+ /**
+ * Specifies that this GraphicElement is to be associated with and be rendered
+ * to its own DisplayObject.
+ *
+ * @default false
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4.5
+ */
+ public function get alwaysCreateDisplayObject():Boolean
+ {
+ return _alwaysCreateDisplayObject;
+ }
+
+ /**
+ * @private
+ */
+ public function set alwaysCreateDisplayObject(value:Boolean):void
+ {
+ if (value != _alwaysCreateDisplayObject)
+ {
+ var previous:Boolean = needsDisplayObject;
+ _alwaysCreateDisplayObject = value;
+ if (previous != needsDisplayObject)
+ invalidateDisplayObjectSharing();
+ }
+ }
+
+ //----------------------------------
+ // baseline
+ //----------------------------------
+
+ /**
+ * @private
+ * Storage for the baseline property.
+ */
+ private var _baseline:Object;
+
+ [Inspectable(category="General")]
+
+ /**
+ * @inheritDoc
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function get baseline():Object
+ {
+ return _baseline;
+ }
+
+ /**
+ * @private
+ */
+ public function set baseline(value:Object):void
+ {
+ if (_baseline == value)
+ return;
+
+ _baseline = value;
+ invalidateParentSizeAndDisplayList();
+ }
+
+ //----------------------------------
+ // baselinePosition
+ //----------------------------------
+
+ [Inspectable(category="General")]
+
+ /**
+ * The y-coordinate of the baseline
+ * of the first line of text of the component.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function get baselinePosition():Number
+ {
+ // Subclasses of GraphicElement should return something
+ // here as appropriate (e.g. text centric GraphicElements).
+ var parentUIC:UIComponent = parent as UIComponent;
+
+ if (parentUIC)
+ {
+ if (!parentUIC.validateBaselinePosition())
+ return NaN;
+
+ return FTETextUtil.calculateFontBaseline(parentUIC, height, parentUIC.moduleFactory);
+ }
+
+ return 0;
+ }
+
+ //----------------------------------
+ // blendMode
+ //----------------------------------
+
+ /**
+ * @private
+ * Storage for the blendMode property.
+ */
+ private var _blendMode:String = "auto";
+
+ /**
+ * @private
+ */
+ private var blendModeChanged:Boolean;
+ private var blendShaderChanged:Boolean;
+ private var blendModeExplicitlySet:Boolean = false;
+
+ [Inspectable(category="General", enumeration="auto,add,alpha,darken,difference,erase,hardlight,invert,layer,lighten,multiply,normal,subtract,screen,overlay,colordodge,colorburn,exclusion,softlight,hue,saturation,color,luminosity", defaultValue="auto")]
+
+ /**
+ * A value from the BlendMode class that specifies which blend mode to use.
+ *
+ * @default auto
+ *
+ * @see flash.display.DisplayObject#blendMode
+ * @see flash.display.BlendMode
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function get blendMode():String
+ {
+ return _blendMode;
+ }
+
+ /**
+ * @private
+ */
+ public function set blendMode(value:String):void
+ {
+ if (value == _blendMode)
+ return;
+
+ var oldValue:String = _blendMode;
+
+ _blendMode = value;
+ blendModeChanged = true;
+
+ // If one of the non-native Flash blendModes is set,
+ // record the new value and set the appropriate
+ // blendShader on the display object.
+ if (isAIMBlendMode(value))
+ {
+ blendShaderChanged = true;
+ }
+
+ // Only need to re-do display object assignment if blendmode was normal
+ // and is changing to something else, or the blend mode was something else
+ // and is going back to normal. This is because display object sharing
+ // only happens when blendMode is normal.
+ if ((oldValue == BlendMode.NORMAL || value == BlendMode.NORMAL) &&
+ !(oldValue == BlendMode.NORMAL && value == BlendMode.NORMAL))
+ {
+ invalidateDisplayObjectSharing();
+ }
+
+ invalidateProperties();
+ }
+
+ //----------------------------------
+ // bottom
+ //----------------------------------
+
+ /**
+ * @private
+ * Storage for the bottom property.
+ */
+ private var _bottom:Object;
+
+ [Inspectable(category="General")]
+
+ /**
+ * @inheritDoc
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function get bottom():Object
+ {
+ return _bottom;
+ }
+
+ /**
+ * @private
+ */
+ public function set bottom(value:Object):void
+ {
+ if (_bottom == value)
+ return;
+
+ _bottom = value;
+ invalidateParentSizeAndDisplayList();
+ }
+
+ //----------------------------------
+ // owner
+ //----------------------------------
+
+ /**
+ * @private
+ */
+ private var _owner:DisplayObjectContainer;
+
+ /**
+ * @inheritDoc
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function get owner():DisplayObjectContainer
+ {
+ return _owner ? _owner : parent;
+ }
+
+ public function set owner(value:DisplayObjectContainer):void
+ {
+ _owner = value;
+ }
+
+ //----------------------------------
+ // layer
+ //----------------------------------
+
+ /**
+ * @private
+ * Storage for the layer property.
+ */
+ private var _designLayer:DesignLayer;
+
+ [Inspectable (environment='none')]
+
+ /**
+ * @copy mx.core.IVisualElement#designLayer
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function get designLayer():DesignLayer
+ {
+ return _designLayer;
+ }
+
+ /**
+ * @private
+ */
+ public function set designLayer(value:DesignLayer):void
+ {
+ if (_designLayer)
+ _designLayer.removeEventListener("layerPropertyChange", layer_PropertyChange, false);
+
+ _designLayer = value;
+
+ if (_designLayer)
+ _designLayer.addEventListener("layerPropertyChange", layer_PropertyChange, false, 0, true);
+
+ _effectiveAlpha = _designLayer ? _alpha * _designLayer.effectiveAlpha : _alpha;
+ _effectiveVisibility = _designLayer ? _visible && _designLayer.effectiveVisibility : _visible;
+ alphaChanged = true;
+ visibleChanged = true;
+ invalidateProperties();
+ }
+
+ //----------------------------------
+ // parent
+ //----------------------------------
+
+ /**
+ * @private
+ * Storage for the parent property.
+ */
+ private var _parent:IGraphicElementContainer;
+
+ /**
+ * @inheritDoc
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function get parent():DisplayObjectContainer
+ {
+ return _parent as DisplayObjectContainer;
+ }
+
+ /**
+ * @inheritDoc
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function parentChanged(value:IGraphicElementContainer):void
+ {
+ _parent = value;
+ invalidateLayoutDirection();
+
+ // if we now have a parent and we need to do some invalidation, let our parent know
+ if (parent)
+ {
+ if (invalidatePropertiesFlag)
+ IGraphicElementContainer(parent).invalidateGraphicElementProperties(this);
+ if (invalidateSizeFlag)
+ IGraphicElementContainer(parent).invalidateGraphicElementSize(this);
+ if (invalidateDisplayListFlag)
+ IGraphicElementContainer(parent).invalidateGraphicElementDisplayList(this);
+ }
+ }
+
+ //----------------------------------
+ // explicitHeight
+ //----------------------------------
+
+ /**
+ * @private
+ * Storage for the explicitHeight property.
+ */
+ private var _explicitHeight:Number;
+
+ [Inspectable(category="General")]
+
+ /**
+ * Number that specifies the explicit height of the component,
+ * in pixels, in the component's coordinates.
+ *
+ * @see mx.core.UIComponent#explicitHeight
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function get explicitHeight():Number
+ {
+ return _explicitHeight;
+ }
+
+ /**
+ * @private
+ */
+ public function set explicitHeight(value:Number):void
+ {
+ if (_explicitHeight == value)
+ return;
+
+ // height can be pixel or percent, not both
+ if (!isNaN(value))
+ percentHeight = NaN;
+
+ _explicitHeight = value;
+
+ invalidateSize();
+ invalidateParentSizeAndDisplayList();
+ }
+
+ //----------------------------------
+ // explicitMaxHeight
+ //----------------------------------
+
+ /**
+ * The maximum recommended height of the component to be considered
+ * by the parent during layout. This value is in the
+ * component's coordinates, in pixels.
+ *
+ * @see mx.core.UIComponent#explicitMaxHeight
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function get explicitMaxHeight():Number { return maxHeight; }
+ public function set explicitMaxHeight(value:Number):void { maxHeight = value; }
+
+ //----------------------------------
+ // explicitMaxWidth
+ //----------------------------------
+
+ /**
+ * The maximum recommended width of the component to be considered
+ * by the parent during layout. This value is in the
+ * component's coordinates, in pixels.
+ *
+ * @see mx.core.UIComponent#explicitMaxWidth
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function get explicitMaxWidth():Number { return maxWidth; }
+ public function set explicitMaxWidth(value:Number):void { maxWidth = value; }
+
+ //----------------------------------
+ // explicitMinHeight
+ //----------------------------------
+
+ /**
+ * The minimum recommended height of the component to be considered
+ * by the parent during layout. This value is in the
+ * component's coordinates, in pixels.
+ *
+ * @see mx.core.UIComponent#explicitMinHeight
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function get explicitMinHeight():Number { return minHeight; }
+ public function set explicitMinHeight(value:Number):void { minHeight = value; }
+
+ //----------------------------------
+ // explicitMinWidth
+ //----------------------------------
+
+ /**
+ * The minimum recommended width of the component to be considered
+ * by the parent during layout. This value is in the
+ * component's coordinates, in pixels.
+ *
+ * @see mx.core.UIComponent#explicitMinWidth
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function get explicitMinWidth():Number { return minWidth; }
+ public function set explicitMinWidth(value:Number):void { minWidth = value; }
+
+ //----------------------------------
+ // explicitWidth
+ //----------------------------------
+
+ /**
+ * @private
+ * Storage for the explicitHeight property.
+ */
+ private var _explicitWidth:Number;
+
+ [Inspectable(category="General")]
+
+ /**
+ * Number that specifies the explicit width of the component,
+ * in pixels, in the component's coordinates.
+ *
+ * @see mx.core.UIComponent#explicitWidth
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function get explicitWidth():Number
+ {
+ return _explicitWidth;
+ }
+
+ /**
+ * @private
+ */
+ public function set explicitWidth(value:Number):void
+ {
+ if (_explicitWidth == value)
+ return;
+
+ // height can be pixel or percent, not both
+ if (!isNaN(value))
+ percentWidth = NaN;
+
+ _explicitWidth = value;
+
+ invalidateSize();
+ invalidateParentSizeAndDisplayList();
+ }
+
+ //----------------------------------
+ // filters
+ //----------------------------------
+
+ /**
+ * @private
+ * Storage for the filters property.
+ */
+ private var _filters:Array = [];
+
+ /**
+ * @private
+ */
+ private var filtersChanged:Boolean;
+
+ /**
+ * @private
+ */
+ private var _clonedFilters:Array;
+
+ [Inspectable(category="General")]
+
+ /**
+ * An indexed array that contains each filter object currently associated with the graphic element.
+ * The mx.filters package contains classes that define specific filters you can use.
+ *
+ * <p>The getter returns a copy of the filters array. The filters property value can only be changed
+ * via the setter.</p>
+ *
+ * @see spark.filters.BevelFilter
+ * @see spark.filters.BlurFilter
+ * @see spark.filters.ColorMatrixFilter
+ * @see spark.filters.ConvolutionFilter
+ * @see spark.filters.DisplacementMapFilter
+ * @see spark.filters.DropShadowFilter
+ * @see spark.filters.GlowFilter
+ * @see spark.filters.GradientBevelFilter
+ * @see spark.filters.GradientFilter
+ * @see spark.filters.GradientGlowFilter
+ * @see spark.filters.ShaderFilter
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function get filters():Array
+ {
+ // Return a copy of the filters to prevent it from being mutated.
+ // The only way to change the filters is through the setter.
+ return _filters.slice();
+ }
+
+ /**
+ * @private
+ */
+ public function set filters(value:Array):void
+ {
+ var i:int = 0;
+ var len:int = _filters ? _filters.length : 0;
+ var newLen:int = value ? value.length : 0;
+ var edFilter:IEventDispatcher;
+
+ if (len == 0 && newLen == 0)
+ return;
+
+ // Remove the event listeners on the previous filters
+ for (i = 0; i < len; i++)
+ {
+ edFilter = _filters[i] as IEventDispatcher;
+ if (edFilter)
+ edFilter.removeEventListener(BaseFilter.CHANGE, filterChangedHandler);
+ }
+
+ var previous:Boolean = needsDisplayObject;
+ _filters = value;
+ if (previous != needsDisplayObject)
+ invalidateDisplayObjectSharing();
+
+ _clonedFilters = [];
+
+ for (i = 0; i < newLen; i++)
+ {
+ if (value[i] is IBitmapFilter)
+ {
+ edFilter = value[i] as IEventDispatcher;
+ if (edFilter)
+ edFilter.addEventListener(BaseFilter.CHANGE, filterChangedHandler);
+ _clonedFilters.push(IBitmapFilter(value[i]).clone());
+ }
+ else
+ {
+ _clonedFilters.push(value[i]);
+ }
+ }
+
+ filtersChanged = true;
+ invalidateProperties();
+ }
+
+ //----------------------------------
+ // height
+ //----------------------------------
+
+ /**
+ * @private
+ * Storage for the height property.
+ */
+ mx_internal var _height:Number = 0;
+
+ [Bindable("propertyChange")]
+ [Inspectable(category="General")]
+ [PercentProxy("percentHeight")]
+
+ /**
+ * The height of the graphic element.
+ *
+ * @default 0
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function get height():Number
+ {
+ return _height;
+ }
+
+ /**
+ * @private
+ */
+
+ public function set height(value:Number):void
+ {
+ explicitHeight = value;
+
+ if (_height == value)
+ return;
+
+ var oldValue:Number = _height;
+ _height = value;
+ dispatchPropertyChangeEvent("height", oldValue, value);
+
+ // Invalidate the display list, since we're changing the actual height
+ // and we're not going to correctly detect whether the layout sets
+ // new actual height different from our previous value.
+ invalidateDisplayList();
+ }
+
+ //----------------------------------
+ // horizontalCenter
+ //----------------------------------
+
+ /**
+ * @private
+ * Storage for the horizontalCenter property.
+ */
+ private var _horizontalCenter:Object;
+
+ [Inspectable(category="General")]
+
+ /**
+ * @inheritDoc
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function get horizontalCenter():Object
+ {
+ return _horizontalCenter;
+ }
+
+ /**
+ * @private
+ */
+ public function set horizontalCenter(value:Object):void
+ {
+ if (_horizontalCenter == value)
+ return;
+
+ _horizontalCenter = value;
+ invalidateParentSizeAndDisplayList();
+ }
+
+ //----------------------------------
+ // id
+ //----------------------------------
+
+ /**
+ * @private
+ * Storage for the id property.
+ */
+ private var _id:String;
+
+ /**
+ * The identity of the component.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function get id():String
+ {
+ return _id;
+ }
+
+ /**
+ * @private
+ */
+ public function set id(value:String):void
+ {
+ _id = value;
+ }
+
+ //----------------------------------
+ // left
+ //----------------------------------
+
+ /**
+ * @private
+ * Storage for the left property.
+ */
+ private var _left:Object;
+
+ [Inspectable(category="General")]
+
+ /**
+ * @inheritDoc
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function get left():Object
+ {
+ return _left;
+ }
+
+ /**
+ * @private
+ */
+ public function set left(value:Object):void
+ {
+ if (_left == value)
+ return;
+
+ _left = value;
+ invalidateParentSizeAndDisplayList();
+ }
+
+ //----------------------------------
+ // mask
+ //----------------------------------
+
+ /**
+ * @private
+ * Storage for the mask property.
+ */
+ private var _mask:DisplayObject;
+
+ /**
+ * @private
+ */
+ private var maskChanged:Boolean;
+
+ [Inspectable(category="General")]
+
+ /**
+ * The calling display object is masked by the specified mask object.
+ * If, the mask display object is not on the display list, it will be added to the display list
+ * as a child of the displayObject. The mask object itself is not drawn.
+ * Set mask to null to remove the mask.
+ *
+ * To use another GraphicElement as a mask, wrap the GraphicElement in a Group or other container.
+ *
+ * @see flash.display.DisplayObject#mask
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function get mask():DisplayObject
+ {
+ return _mask;
+ }
+
+ /**
+ * @private
+ */
+ public function set mask(value:DisplayObject):void
+ {
+ if (_mask == value)
+ return;
+
+ var oldMask:UIComponent = _mask as UIComponent;
+
+ var previous:Boolean = needsDisplayObject;
+ _mask = value;
+
+ // If the old mask was attached by us, then we need to
+ // undo the attachment logic
+ if (oldMask && oldMask.$parent === displayObject)
+ {
+ if (oldMask.parent is UIComponent)
+ UIComponent(oldMask.parent).childRemoved(oldMask);
+ oldMask.$parent.removeChild(oldMask);
+ }
+
+ // Cleanup the drawnDisplayObject mask and _drawnDisplayObject here
+ // because displayObject (the parent of _drawnDisplayObject)
+ // might be null in commitProperties
+ if (!_mask || _mask.parent)
+ {
+ if (drawnDisplayObject)
+ drawnDisplayObject.mask = null;
+
+ if (_drawnDisplayObject)
+ {
+ if (_drawnDisplayObject.parent)
+ _drawnDisplayObject.parent.removeChild(_drawnDisplayObject);
+ _drawnDisplayObject = null;
+ }
+ }
+
+ maskChanged = true;
+ maskTypeChanged = true;
+ if (previous != needsDisplayObject)
+ invalidateDisplayObjectSharing();
+
+ invalidateProperties();
+ invalidateDisplayList();
+ }
+
+ //----------------------------------
+ // maskType
+ //----------------------------------
+
+ /**
+ * @private
+ * Storage for the maskType property.
+ */
+ private var _maskType:String = MaskType.CLIP;
+
+ /**
+ * @private
+ */
+ private var maskTypeChanged:Boolean;
+
+ [Inspectable(category="General", enumeration="clip,alpha,luminosity", defaultValue="clip")]
+
+ /**
+ * <p>Defines how the mask is applied to the GraphicElement.</p>
+ *
+ * <p>The possible values are <code>MaskType.CLIP</code>, <code>MaskType.ALPHA</code>, and
+ * <code>MaskType.LUMINOSITY</code>.</p>
+ *
+ * <p><strong>Clip Masking</strong></p>
+ *
+ * <p>When masking in clip mode, a clipping masks is reduced to 1-bit. This means that a mask will
+ * not affect the opacity of a pixel in the source content; it either leaves the value unmodified,
+ * if the corresponding pixel in the mask is has a non-zero alpha value, or makes it fully
+ * transparent, if the mask pixel value has an alpha value of zero.</p>
+ *
+ * <p>When clip masking is used, only the actual path and shape vectors and fills defined by the
+ * mask are used to determine the effect on the source content. strokes and bitmap filters
+ * defined on the mask are ignored. Any filled region in the mask is considered filled, and renders
+ * the source content. The type and parameters of the fill is irrelevant; a solid color fill,
+ * gradient fill, or bitmap fill in a mask will all render the underlying source content, regardless
+ * of the alpha values of the mask fill.</p>
+ *
+ * <p>BitmapGraphics are treated as bitmap filled rectangles when used in a clipping mask. As a
+ * result, the alpha channel of the source bitmap is irrelevant when part of a mask -- the bitmap
+ * affects the mask in the same manner as solid filled rectangle of equivalent dimensions.</p>
+ *
+ * <p><strong>Alpha Masking</strong></p>
+ *
+ * <p>In alpha mode, the opacity of each pixel in the source content is multiplied by the opacity
+ * of the corresponding region of the mask. i.e., a pixel in the source content with an opacity of
+ * 1 that is masked by a region of opacity of .5 will have a resulting opacity of .5. A source pixel
+ * with an opacity of .8 masked by a region with opacity of .5 will have a resulting opacity of .4.</p>
+ *
+ * <p>Conceptually, alpha masking is equivalent to rendering the transformed mask and source content
+ * into separate RGBA surfaces, and multiplying the alpha channel of the mask content into the alpha
+ * channel of the source content. All of the mask content is rendered into its surface before
+ * compositing into the source content's surface. As a result, all FXG features, such as strokes,
+ * bitmap filters, and fill opacity will affect the final composited content.</p>
+ *
+ * <p>When in alpha mode, the alpha channel of any bitmap data is composited normally into the mask
+ * alpha channel, and will affect the final rendered content. This holds true for both BitmapGraphics
+ * and bitmap filled shapes and paths.</p>
+ *
+ * <p><strong>Luminosity Masking</strong></p>
+ *
+ * <p>A luminosity mask, sometimes called a 'soft mask', works very similarly to an alpha mask
+ * except that both the opacity and RGB color value of a pixel in the source content is multiplied
+ * by the opacity and RGB color value of the corresponding region in the mask.</p>
+ *
+ * <p>Conceptually, luminosity masking is equivalent to rendering the transformed mask and source content
+ * into separate RGBA surfaces, and multiplying the alpha channel and the RGB color value of the mask
+ * content into the alpha channel and RGB color value of the source content. All of the mask content is
+ * rendered into its surface before compositing into the source content's surface. As a result, all FXG
+ * features, such as strokes, bitmap filters, and fill opacity will affect the final composited
+ * content.</p>
+ *
+ * <p>Luminosity masking is not native to Flash but is common in Adobe Creative Suite tools like Adobe
+ * Illustrator and Adobe Photoshop. In order to accomplish the visual effect of a luminosity mask in
+ * Flash-rendered content, a graphic element specifying a luminosity mask actually instantiates a shader
+ * filter that mimics the visual look of a luminosity mask as rendered in Adobe Creative Suite tools.</p>
+ *
+ * <p>Objects being masked by luminosity masks can set properties to control the RGB color value and
+ * clipping of the mask. See the luminosityInvert and luminosityClip attributes.</p>
+ *
+ * @default MaskType.CLIP
+ *
+ * @see spark.core.MarkType
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function get maskType():String
+ {
+ return _maskType;
+ }
+
+ /**
+ * @private
+ */
+ public function set maskType(value:String):void
+ {
+ if (_maskType == value)
+ return;
+
+ _maskType = value;
+ maskTypeChanged = true;
+ invalidateProperties();
+ }
+
+ //----------------------------------
+ // luminosityInvert
+ //----------------------------------
+
+ /**
+ * @private
+ * Storage for the luminosityInvert property.
+ */
+ private var _luminosityInvert:Boolean = false;
+
+ /**
+ * @private
+ */
+ private var luminositySettingsChanged:Boolean;
+
+ [Inspectable(category="General", enumeration="true,false", defaultValue="false")]
+
+ /**
+ * A property that controls the calculation of the RGB
+ * color value of a graphic element being masked by
+ * a luminosity mask. If true, the RGB color value of a
+ * pixel in the source content is inverted and multipled
+ * by the corresponding region in the mask. If false,
+ * the source content's pixel's RGB color value is used
+ * directly.
+ *
+ * @default false
+ * @see #maskType
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function get luminosityInvert():Boolean
+ {
+ return _luminosityInvert;
+ }
+
+ /**
+ * @private
+ */
+ public function set luminosityInvert(value:Boolean):void
+ {
+ if (_luminosityInvert == value)
+ return;
+
+ _luminosityInvert = value;
+ luminositySettingsChanged = true;
+ }
+
+ //----------------------------------
+ // luminosityClip
+ //----------------------------------
+
+ /**
+ * @private
+ * Storage for the luminosityClip property.
+ */
+ private var _luminosityClip:Boolean = false;
+
+ [Inspectable(category="General", enumeration="true,false", defaultValue="false")]
+
+ /**
+ * A property that controls whether the luminosity
+ * mask clips the masked content. This property can
+ * only have an effect if the graphic element has a
+ * mask applied to it that is of type
+ * MaskType.LUMINOSITY.
+ *
+ * @default false
+ * @see #maskType
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function get luminosityClip():Boolean
+ {
+ return _luminosityClip;
+ }
+
+ /**
+ * @private
+ */
+ public function set luminosityClip(value:Boolean):void
+ {
+ if (_luminosityClip == value)
+ return;
+
+ _luminosityClip = value;
+ luminositySettingsChanged = true;
+ }
+
+ //----------------------------------
+ // maxHeight
+ //----------------------------------
+
+ /**
+ * @private
+ * Storage for the maxHeight property.
+ */
+ private var _maxHeight:Number;
+
+ [Inspectable(category="General")]
+
+ /**
+ * @copy mx.core.UIComponent#maxHeight
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function get maxHeight():Number
+ {
+ return !isNaN(_maxHeight) ? _maxHeight : DEFAULT_MAX_HEIGHT;
+ }
+
+ /**
+ * @private
+ */
+ public function set maxHeight(value:Number):void
+ {
+ if (_maxHeight == value)
+ return;
+
+ _maxHeight = value;
+
+ invalidateSize();
+ invalidateParentSizeAndDisplayList();
+ }
+
+ //----------------------------------
+ // maxWidth
+ //----------------------------------
+
+ /**
+ * @private
+ * Storage for the maxHeight property.
+ */
+ mx_internal var _maxWidth:Number;
+
+ [Inspectable(category="General")]
+
+ /**
+ * @copy mx.core.UIComponent#maxWidth
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function get maxWidth():Number
+ {
+ return !isNaN(_maxWidth) ? _maxWidth : DEFAULT_MAX_WIDTH;
+ }
+
+ /**
+ * @private
+ */
+ public function set maxWidth(value:Number):void
+ {
+ if (_maxWidth == value)
+ return;
+
+ _maxWidth = value;
+
+ invalidateSize();
+ invalidateParentSizeAndDisplayList();
+ }
+
+ //----------------------------------
+ // measuredHeight
+ //----------------------------------
+
+ /**
+ * @private
+ * Storage for the measuredHeight property.
+ */
+ private var _measuredHeight:Number = 0;
+
+ /**
+ * @copy mx.core.UIComponent#measuredHeight
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function get measuredHeight():Number
+ {
+ return _measuredHeight;
+ }
+
+ /**
+ * @private
+ */
+ public function set measuredHeight(value:Number):void
+ {
+ _measuredHeight = value;
+ }
+
+ //----------------------------------
+ // measuredWidth
+ //----------------------------------
+
+ /**
+ * @private
+ * Storage for the measuredWidth property.
+ */
+ private var _measuredWidth:Number = 0;
+
+ /**
+ * @copy mx.core.UIComponent#measuredWidth
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function get measuredWidth():Number
+ {
+ return _measuredWidth;
+ }
+
+ /**
+ * @private
+ */
+ public function set measuredWidth(value:Number):void
+ {
+ _measuredWidth = value;
+ }
+
+ //----------------------------------
+ // measuredX
+ //----------------------------------
+
+ /**
+ * @private
+ * Storage for the measuredX property.
+ */
+ private var _measuredX:Number = 0;
+
+ /**
+ * The default measured bounds top-left corner relative to the origin of the element.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function get measuredX():Number
+ {
+ return _measuredX;
+ }
+
+ /**
+ * @private
+ */
+ public function set measuredX(value:Number):void
+ {
+ _measuredX = value;
+ }
+
+ //----------------------------------
+ // measuredY
+ //----------------------------------
+
+ /**
+ * @private
+ * Storage for the measuredY property.
+ */
+ private var _measuredY:Number = 0;
+
+ /**
+ * The default measured bounds top-left corner relative to the origin of the element.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function get measuredY():Number
+ {
+ return _measuredY;
+ }
+
+ /**
+ * @private
+ */
+ public function set measuredY(value:Number):void
+ {
+ _measuredY = value;
+ }
+
+ //----------------------------------
+ // minHeight
+ //----------------------------------
+
+ /**
+ * @private
+ * Storage for the minHeight property.
+ */
+ private var _minHeight:Number;
+
+ [Inspectable(category="General")]
+
+ /**
+ * @copy mx.core.UIComponent#minHeight
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function get minHeight():Number
+ {
+ return !isNaN(_minHeight) ? _minHeight : DEFAULT_MIN_HEIGHT;
+ }
+
+ /**
+ * @private
+ */
+ public function set minHeight(value:Number):void
+ {
+ if (_minHeight == value)
+ return;
+
+ _minHeight = value;
+
+ invalidateSize();
+ invalidateParentSizeAndDisplayList();
+ }
+
+ //----------------------------------
+ // minWidth
+ //----------------------------------
+
+ /**
+ * @private
+ * Storage for the minWidth property.
+ */
+ private var _minWidth:Number;
+
+ [Inspectable(category="General")]
+
+ /**
+ * @copy mx.core.UIComponent#minWidth
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function get minWidth():Number
+ {
+ return !isNaN(_minWidth) ? _minWidth : DEFAULT_MIN_WIDTH;
+ }
+
+ /**
+ * @private
+ */
+ public function set minWidth(value:Number):void
+ {
+ if (_minWidth == value)
+ return;
+
+ _minWidth = value;
+
+ invalidateSize();
+ invalidateParentSizeAndDisplayList();
+ }
+
+ //----------------------------------
+ // percentHeight
+ //----------------------------------
+
+ /**
+ * @private
+ * Storage for the percentHeight property.
+ */
+ private var _percentHeight:Number;
+
+ [Inspectable(category="General")]
+
+ /**
+ * @inheritDoc
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function get percentHeight():Number
+ {
+ return _percentHeight;
+ }
+
+ /**
+ * @private
+ */
+ public function set percentHeight(value:Number):void
+ {
+ if (_percentHeight == value)
+ return;
+
+ if (!isNaN(value))
+ explicitHeight = NaN;
+
+ _percentHeight = value;
+
+ invalidateParentSizeAndDisplayList();
+ }
+
+ //----------------------------------
+ // percentWidth
+ //----------------------------------
+
+ /**
+ * @private
+ * Storage for the percentWidth property.
+ */
+ private var _percentWidth:Number;
+
+ [Inspectable(category="General")]
+
+ /**
+ * @copy mx.core.UIComponent#percentWidth
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function get percentWidth():Number
+ {
+ return _percentWidth;
+ }
+
+ /**
+ * @private
+ */
+ public function set percentWidth(value:Number):void
+ {
+ if (_percentWidth == value)
+ return;
+
+ if (!isNaN(value))
+ explicitWidth = NaN;
+
+ _percentWidth = value;
+
+ invalidateParentSizeAndDisplayList();
+ }
+
+ //----------------------------------
+ // right
+ //----------------------------------
+
+ /**
+ * @private
+ * Storage for the right property.
+ */
+ private var _right:Object;
+
+ [Inspectable(category="General")]
+
+ /**
+ * @inheritDoc
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function get right():Object
+ {
+ return _right;
+ }
+
+ /**
+ * @private
+ */
+ public function set right(value:Object):void
+ {
+ if (_right == value)
+ return;
+
+ _right = value;
+ invalidateParentSizeAndDisplayList();
+ }
+
+ //----------------------------------
+ // rotation
+ //----------------------------------
+
+ [Inspectable(category="General")]
+
+ /**
+ * Indicates the x-axis rotation of the element instance, in degrees, from its original orientation
+ * relative to the 3D parent container. Values from 0 to 180 represent clockwise rotation; values
+ * from 0 to -180 represent counterclockwise rotation. Values outside this range are added to or subtracted from
+ * 360 to obtain a value within the range.
+ *
+ * This property is ignored during calculation by any of Flex's 2D layouts.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function get rotationX():Number
+ {
+ return (layoutFeatures == null)? 0:layoutFeatures.layoutRotationX;
+ }
+
+ /**
+ * @private
+ */
+ public function set rotationX(value:Number):void
+ {
+ if (rotationX == value)
+ return;
+
+ allocateLayoutFeatures();
+ var previous:Boolean = needsDisplayObject;
+ layoutFeatures.layoutRotationX = value;
+ invalidateTransform(previous != needsDisplayObject);
+ }
+
+ [Inspectable(category="General")]
+
+ /**
+ * Indicates the y-axis rotation of the DisplayObject instance, in degrees, from its original orientation
+ * relative to the 3D parent container. Values from 0 to 180 represent clockwise rotation; values
+ * from 0 to -180 represent counterclockwise rotation. Values outside this range are added to or subtracted from
+ * 360 to obtain a value within the range.
+ *
+ * This property is ignored during calculation by any of Flex's 2D layouts.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function get rotationY():Number
+ {
+ return (layoutFeatures == null)? 0:layoutFeatures.layoutRotationY;
+ }
+ /**
+ * @private
+ */
+ public function set rotationY(value:Number):void
+ {
+ if (rotationY == value)
+ return;
+
+ allocateLayoutFeatures();
+ var previous:Boolean = needsDisplayObject;
+ layoutFeatures.layoutRotationY = value;
+ invalidateTransform(previous != needsDisplayObject);
+ }
+
+ [Inspectable(category="General")]
+
+ /**
+ * Indicates the rotation of the element, in degrees,
+ * from the transform point.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function get rotationZ():Number
+ {
+ return (layoutFeatures == null)? 0:layoutFeatures.layoutRotationZ;
+ }
+
+ /**
+ * @private
+ */
+ public function set rotationZ(value:Number):void
+ {
+ if (rotationZ == value)
+ return;
+
+ allocateLayoutFeatures();
+ var previous:Boolean = needsDisplayObject;
+ layoutFeatures.layoutRotationZ = value;
+ invalidateTransform(previous != needsDisplayObject);
+ }
+
+ [Inspectable(category="General")]
+
+ /**
+ * Indicates the rotation of the element, in degrees,
+ * from the transform point.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function get rotation():Number
+ {
+ return (layoutFeatures == null)? 0:layoutFeatures.layoutRotationZ;
+ }
+
+ /**
+ * @private
+ */
+ public function set rotation(value:Number):void
+ {
+ rotationZ = value;
+ }
+
+ //----------------------------------
+ // scaleX
+ //----------------------------------
+
+ [Inspectable(category="General")]
+
+ /**
+ * The horizontal scale (percentage) of the element
+ * as applied from the transform point.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function get scaleX():Number
+ {
+ return (layoutFeatures == null)? 1:layoutFeatures.layoutScaleX;
+ }
+
+ /**
+ * @private
+ */
+ public function set scaleX(value:Number):void
+ {
+ if (scaleX == value)
+ return;
+
+ allocateLayoutFeatures();
+ var previous:Boolean = needsDisplayObject;
+ layoutFeatures.layoutScaleX = value;
+ invalidateTransform(previous != needsDisplayObject);
+ }
+
+ //----------------------------------
+ // scaleY
+ //----------------------------------
+
+ [Inspectable(category="General")]
+
+ /**
+ * The vertical scale (percentage) of the element
+ * as applied from the transform point.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function get scaleY():Number
+ {
+ return (layoutFeatures == null)? 1:layoutFeatures.layoutScaleY;
+ }
+
+ /**
+ * @private
+ */
+ public function set scaleY(value:Number):void
+ {
+ if (scaleY == value)
+ return;
+
+ allocateLayoutFeatures();
+ var previous:Boolean = needsDisplayObject;
+ layoutFeatures.layoutScaleY = value;
+ invalidateTransform(previous != needsDisplayObject);
+ }
+
+ //----------------------------------
+ // scaleZ
+ //----------------------------------
+
+ [Inspectable(category="General")]
+
+ /**
+ * The z scale (percentage) of the element
+ * as applied from the transform point.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function get scaleZ():Number
+ {
+ return (layoutFeatures == null)? 1:layoutFeatures.layoutScaleZ;
+ }
+
+ /**
+ * @private
+ */
+ public function set scaleZ(value:Number):void
+ {
+ if (scaleZ == value)
+ return;
+
+ allocateLayoutFeatures();
+ var previous:Boolean = needsDisplayObject;
+ layoutFeatures.layoutScaleZ = value;
+ invalidateTransform(previous != needsDisplayObject);
+ }
+
+ //----------------------------------
+ // top
+ //----------------------------------
+
+ /**
+ * @private
+ * Storage for the top property.
+ */
+ private var _top:Object;
+
+ [Inspectable(category="General")]
+
+ /**
+ * @inheritDoc
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function get top():Object
+ {
+ return _top;
+ }
+
+ /**
+ * @private
+ */
+ public function set top(value:Object):void
+ {
+ if (_top == value)
+ return;
+
+ _top = value;
+ invalidateParentSizeAndDisplayList();
+ }
+
+ //----------------------------------
+ // transform
+ //----------------------------------
+
+ /**
+ * @private
+ * Storage for the transform property.
+ */
+ private var _transform:flash.geom.Transform;
+
+ /**
+ * @copy mx.core.IFlexDisplayObject#transform
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function get transform():flash.geom.Transform
+ {
+ if (!_transform)
+ setTransform(new mx.geom.Transform());
+
+ return _transform;
+ }
+
+ /**
+ * @private
+ */
+ public function set transform(value:flash.geom.Transform):void
+ {
+ // TODO (jszeto): Add perspectiveProjection support
+ var matrix:Matrix = value && value.matrix ? value.matrix.clone() : null;
+ var matrix3D:Matrix3D = value && value.matrix3D ? value.matrix3D.clone() : null;
+ var colorTransform:ColorTransform = value ? value.colorTransform : null;
+
+ var mxTransform:mx.geom.Transform = value as mx.geom.Transform;
+ if (mxTransform)
+ {
+ if (!mxTransform.applyMatrix)
+ matrix = null;
+
+ if (!mxTransform.applyMatrix3D)
+ matrix3D = null;
+ }
+
+ setTransform(value);
+
+ var previous:Boolean = needsDisplayObject;
+
+ if (_transform)
+ {
+ allocateLayoutFeatures();
+
+ if (matrix != null)
+ {
+ layoutFeatures.layoutMatrix = matrix;
+ }
+ else if (matrix3D != null)
+ {
+ layoutFeatures.layoutMatrix3D = matrix3D;
+ }
+ }
+
+
+ applyColorTransform(colorTransform, mxTransform && mxTransform.applyColorTransformAlpha);
+
+ invalidateTransform(previous != needsDisplayObject);
+ }
+
+ /**
+ * @private
+ */
+ private function setTransform(value:flash.geom.Transform):void
+ {
+ // Clean up the old transform
+ var oldTransform:mx.geom.Transform = _transform as mx.geom.Transform;
+ if (oldTransform)
+ oldTransform.target = null;
+
+ var newTransform:mx.geom.Transform = value as mx.geom.Transform;
+
+ if (newTransform)
+ newTransform.target = this;
+
+ _transform = value;
+ }
+
+ /**
+ * @private
+ *
+ * Sets the colorTransform property of the transform. Called by mx.geom.Transform
+ * when its colorTransform property has been changed.
+ */
+ public function setColorTransform(value:ColorTransform):void
+ {
+ applyColorTransform(value, true);
+ }
+
+ /**
+ * @private
+ */
+ private function applyColorTransform(value:ColorTransform, updateAlpha:Boolean):void
+ {
+ if (_colorTransform != value)
+ {
+ var previous:Boolean = needsDisplayObject;
+ // Make a copy of the colorTransform
+ _colorTransform = new ColorTransform(value.redMultiplier, value.greenMultiplier, value.blueMultiplier, value.alphaMultiplier,
+ value.redOffset, value.greenOffset, value.blueOffset, value.alphaOffset);
+
+ if (updateAlpha)
+ {
+ _alpha = value.alphaMultiplier;
+ _effectiveAlpha = _alpha;
+ }
+
+ if (displayObject && displayObjectSharingMode == DisplayObjectSharingMode.OWNS_UNSHARED_OBJECT)
+ {
+ displayObject.transform.colorTransform = _colorTransform;
+ }
+ else
+ {
+ colorTransformChanged = true;
+ invalidateProperties();
+ if (previous != needsDisplayObject)
+ invalidateDisplayObjectSharing();
+ }
+ }
+ }
+
+ /**
+ * @private
+ */
+ private function isAIMBlendMode(value:String):Boolean
+ {
+ if (value == "colordodge" ||
+ value =="colorburn" || value =="exclusion" ||
+ value =="softlight" || value =="hue" ||
+ value =="saturation" || value =="color" ||
+ value =="luminosity")
+ return true;
+ else return false;
+ }
+
+ /**
+ * @copy mx.core.ILayoutElement#transformAround()
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function transformAround(transformCenter:Vector3D,
+ scale:Vector3D = null,
+ rotation:Vector3D = null,
+ translation:Vector3D = null,
+ postLayoutScale:Vector3D = null,
+ postLayoutRotation:Vector3D = null,
+ postLayoutTranslation:Vector3D = null,
+ invalidateLayout:Boolean = true):void
+ {
+ // TODO (egreenfi): optimize for simple translations
+ allocateLayoutFeatures();
+ var previous:Boolean = needsDisplayObject;
+ var prevX:Number = layoutFeatures.layoutX;
+ var prevY:Number = layoutFeatures.layoutY;
+ var prevZ:Number = layoutFeatures.layoutZ;
+ layoutFeatures.transformAround(transformCenter,scale,rotation,translation,postLayoutScale,postLayoutRotation,postLayoutTranslation);
+ invalidateTransform(previous != needsDisplayObject, invalidateLayout);
+ if (prevX != layoutFeatures.layoutX)
+ dispatchPropertyChangeEvent("x", prevX, layoutFeatures.layoutX);
+ if (prevY != layoutFeatures.layoutY)
+ dispatchPropertyChangeEvent("y", prevY, layoutFeatures.layoutY);
+ if (prevZ != layoutFeatures.layoutZ)
+ dispatchPropertyChangeEvent("z", prevZ, layoutFeatures.layoutZ);
+ }
+
+ /**
+ * A utility method to transform a point specified in the local
+ * coordinates of this object to its location in the object's parent's
+ * coordinates. The pre-layout and post-layout result will be set on
+ * the <code>position</code> and <code>postLayoutPosition</code>
+ * parameters, if they are non-null.
+ *
+ * @param localPosition The point to be transformed, specified in the
+ * local coordinates of the object.
+ * @param position A Vector3D point that will hold the pre-layout
+ * result. If null, the parameter is ignored.
+ * @param postLayoutPosition A Vector3D point that will hold the post-layout
+ * result. If null, the parameter is ignored.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function transformPointToParent(localPosition:Vector3D,
+ position:Vector3D,
+ postLayoutPosition:Vector3D):void
+ {
+ if (layoutFeatures != null)
+ {
+ layoutFeatures.transformPointToParent(true, localPosition, position,
+ postLayoutPosition);
+ }
+ else
+ {
+ var xformPt:Point = new Point();
+ if (localPosition)
+ {
+ xformPt.x = localPosition.x;
+ xformPt.y = localPosition.y;
+ }
+ if (position != null)
+ {
+ position.x = xformPt.x + _x;
+ position.y = xformPt.y + _y;
+ position.z = 0;
+ }
+ if (postLayoutPosition != null)
+ {
+ postLayoutPosition.x = xformPt.x + _x;
+ postLayoutPosition.y = xformPt.y + _y;
+ postLayoutPosition.z = 0;
+ }
+ }
+ }
+
+ //----------------------------------
+ // transformX
+ //----------------------------------
+
+ [Inspectable(category="General")]
+
+ /**
+ * The x position transform point of the element.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function get transformX():Number
+ {
+ return (layoutFeatures == null)? 0:layoutFeatures.transformX;
+ }
+
+ /**
+ * @private
+ */
+ public function set transformX(value:Number):void
+ {
+ if (transformX == value)
+ return;
+
+ allocateLayoutFeatures();
+ layoutFeatures.transformX = value;
+ invalidateTransform(false);
+ }
+
+ //----------------------------------
+ // transformY
+ //----------------------------------
+
+ [Inspectable(category="General")]
+
+ /**
+ * The y position transform point of the element.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function get transformY():Number
+ {
+ return (layoutFeatures == null)? 0:layoutFeatures.transformY;
+ }
+
+ /**
+ * @private
+ */
+ public function set transformY(value:Number):void
+ {
+ if (transformY == value)
+ return;
+
+ allocateLayoutFeatures();
+ layoutFeatures.transformY = value;
+ invalidateTransform(false);
+ }
+
+ //----------------------------------
+ // transformZ
+ //----------------------------------
+
+ [Inspectable(category="General")]
+
+ /**
+ * The z position transform point of the element.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function get transformZ():Number
+ {
+ return (layoutFeatures == null)? 0:layoutFeatures.transformZ;
+ }
+
+ /**
+ * @private
+ */
+ public function set transformZ(value:Number):void
+ {
+ if (transformZ == value)
+ return;
+
+ allocateLayoutFeatures();
+ var previous:Boolean = needsDisplayObject;
+ layoutFeatures.transformZ = value;
+ invalidateTransform(previous != needsDisplayObject);
+ }
+
+ //----------------------------------
+ // verticalCenter
+ //----------------------------------
+
+ /**
+ * @private
+ * Storage for the verticalCenter property.
+ */
+ private var _verticalCenter:Object;
+
+ [Inspectable(category="General")]
+
+ /**
+ * @inheritDoc
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function get verticalCenter():Object
+ {
+ return _verticalCenter;
+ }
+
+ /**
+ * @private
+ */
+ public function set verticalCenter(value:Object):void
+ {
+ if (_verticalCenter == value)
+ return;
+
+ _verticalCenter = value;
+ invalidateParentSizeAndDisplayList();
+ }
+
+ //----------------------------------
+ // width
+ //----------------------------------
+
+ /**
+ * @private
+ * Storage for the width property.
+ */
+ mx_internal var _width:Number = 0;
+
+ [Bindable("propertyChange")]
+ [Inspectable(category="General")]
+ [PercentProxy("percentWidth")]
+
+ /**
+ * The width of the graphic element.
+ *
+ * @default 0
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function get width():Number
+ {
+ return _width;
+ }
+
+ /**
+ * @private
+ */
+ public function set width(value:Number):void
+ {
+ explicitWidth = value;
+
+ if (_width == value)
+ return;
+
+ var oldValue:Number = _width;
+ _width = value;
+
+ // The width is needed for the mirroring transform.
+ if (layoutFeatures)
+ {
+ layoutFeatures.layoutWidth = value;
+ invalidateTransform();
+ }
+
+ dispatchPropertyChangeEvent("width", oldValue, value);
+
+ // Invalidate the display list, since we're changing the actual width
+ // and we're not going to correctly detect whether the layout sets
+ // new actual width different from our previous value.
+ invalidateDisplayList();
+ }
+
+ //----------------------------------
+ // depth
+ //----------------------------------
+
+ /**
+ * @inheritDoc
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function get depth():Number
+ {
+ return (layoutFeatures == null) ? 0 : layoutFeatures.depth;
+ }
+
+ /**
+ * @private
+ */
+ public function set depth(value:Number):void
+ {
+ if (value == depth)
+ return;
+
+ allocateLayoutFeatures();
+ layoutFeatures.depth = value;
+ if (_parent is UIComponent)
+ UIComponent(_parent).invalidateLayering();
+ invalidateProperties();
+ }
+
+ //----------------------------------
+ // x
+ //----------------------------------
+
+ [Bindable("propertyChange")]
+ [Inspectable(category="General")]
+
+ /**
+ * The x position of the graphic element.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function get x():Number
+ {
+ return (layoutFeatures == null)? _x:layoutFeatures.layoutX;
+ }
+
+ /**
+ * @private
+ */
+ public function set x(value:Number):void
+ {
+ var oldValue:Number = x;
+ if (oldValue == value)
+ return;
+
+ if (layoutFeatures != null)
+ layoutFeatures.layoutX = value;
+ else
+ _x = value;
+
+ dispatchPropertyChangeEvent("x", oldValue, value);
+ invalidateTransform(false);
+ }
+
+ //----------------------------------
+ // y
+ //----------------------------------
+
+ [Bindable("propertyChange")]
+ [Inspectable(category="General")]
+
+ /**
+ * The y position of the graphic element.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function get y():Number
+ {
+ return (layoutFeatures == null)? _y:layoutFeatures.layoutY;
+ }
+
+ /**
+ * @private
+ */
+ public function set y(value:Number):void
+ {
+ var oldValue:Number = y;
+ if (oldValue == value)
+ return;
+
+ if (layoutFeatures != null)
+ layoutFeatures.layoutY = value;
+ else
+ _y = value;
+ dispatchPropertyChangeEvent("y", oldValue, value);
+ invalidateTransform(false);
+ }
+
+ //----------------------------------
+ // z
+ //----------------------------------
+
+ [Bindable("propertyChange")]
+ [Inspectable(category="General")]
+
+ /**
+ * The z position of the graphic element.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function get z():Number
+ {
+ return (layoutFeatures == null)? 0:layoutFeatures.layoutZ;
+ }
+
+ /**
+ * @private
+ */
+ public function set z(value:Number):void
+ {
+ if (z == value)
+ return;
+ var oldValue:Number = z;
+
+ allocateLayoutFeatures();
+ var previous:Boolean = needsDisplayObject;
+ layoutFeatures.layoutZ = value;
+ invalidateTransform(previous != needsDisplayObject);
+ dispatchPropertyChangeEvent("z", oldValue, value);
+ }
+
+ //----------------------------------
+ // visible
+ //----------------------------------
+
+ /**
+ * @private
+ * Storage for the visible property.
+ */
+ private var _visible:Boolean = true;
+
+
+ /**
+ * @private
+ * The actual 'effective' visibility of this
+ * element, one that considers the visibility of
+ * the owning design layer parent (if any).
+ */
+ protected var _effectiveVisibility:Boolean = true;
+
+ /**
+ * @private
+ */
+ private var visibleChanged:Boolean;
+
+ [Inspectable(category="General")]
+
+ /**
+ * @inheritDoc
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function get visible():Boolean
+ {
+ return _visible;
+ }
+
+ /**
+ * @private
+ */
+ public function set visible(value:Boolean):void
+ {
+ _visible = value;
+
+ if (designLayer && !designLayer.effectiveVisibility)
+ value = false;
+
+ if (_effectiveVisibility == value)
+ return;
+
+ _effectiveVisibility = value;
+ visibleChanged = true;
+ invalidateProperties();
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // Properties: IDisplayObjectElement
+ //
+ //--------------------------------------------------------------------------
+
+ //----------------------------------
+ // displayObject
+ //----------------------------------
+
+ /**
+ * @private
+ * Storage for the displayObject property.
+ */
+ private var _displayObject:DisplayObject;
+
+ [Bindable("propertyChange")]
+ [Inspectable(category="General")]
+
+ /**
+ * @inheritDoc
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function get displayObject():DisplayObject
+ {
+ return _displayObject;
+ }
+
+ /**
+ * @private
+ */
+ protected function setDisplayObject(value:DisplayObject):void
+ {
+ if (_displayObject == value)
+ return;
+
+ var oldValue:DisplayObject = _displayObject;
+
+ // If we owned the old display object and we have assigned a 3D matrix,
+ // clear it from the display object so that we can set it in the new
+ // display object. A Matrix3D object can't be used simultaneously with
+ // more than one display object.
+ if (oldValue && displayObjectSharingMode == DisplayObjectSharingMode.OWNS_UNSHARED_OBJECT)
+ oldValue.transform.matrix3D = null;
+
+ _displayObject = value;
+ dispatchPropertyChangeEvent("displayObject", oldValue, value);
+
+ // We need to apply the display object related properties.
+ displayObjectChanged = true;
+ invalidateProperties();
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // Properties
+ //
+ //--------------------------------------------------------------------------
+
+ //----------------------------------
+ // drawX
+ //----------------------------------
+
+ /**
+ * The x position where the element should be drawn.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ protected function get drawX():Number
+ {
+ // If we don't share the display object, we will draw at 0,0
+ // since the display object will be positioned at x,y
+ if (displayObjectSharingMode == DisplayObjectSharingMode.OWNS_UNSHARED_OBJECT)
+ return 0;
+
+ // Otherwise we draw at x,y since the display object will be
+ // positioned at 0,0
+ if (layoutFeatures != null && layoutFeatures.postLayoutTransformOffsets != null)
+ return x + layoutFeatures.postLayoutTransformOffsets.x;
+
+ return x;
+ }
+
+ //----------------------------------
+ // drawY
+ //----------------------------------
+
+ /**
+ * The y position where the element should be drawn.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ protected function get drawY():Number
+ {
+ // If we don't share the display object, we will draw at 0,0
+ // since the display object will be positioned at x,y
+ if (displayObjectSharingMode == DisplayObjectSharingMode.OWNS_UNSHARED_OBJECT)
+ return 0;
+
+ // Otherwise we draw at x,y since the display object will be
+ // positioned at 0,0
+ if (layoutFeatures != null && layoutFeatures.postLayoutTransformOffsets != null)
+ return y + layoutFeatures.postLayoutTransformOffsets.y;
+
+ return y;
+ }
+
+ //----------------------------------
+ // hasComplexLayoutMatrix
+ //----------------------------------
+
+ /**
+ * Returns true if the GraphicElement has any non-translation (x,y) transform properties
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ protected function get hasComplexLayoutMatrix():Boolean
+ {
+ return (layoutFeatures == null ? false : !MatrixUtil.isDeltaIdentity(layoutFeatures.layoutMatrix));
+ }
+
+ //----------------------------------
+ // includeInLayout
+ //----------------------------------
+
+ /**
+ * @private
+ * Storage for the includeInLayout property.
+ */
+ private var _includeInLayout:Boolean = true;
+
+ [Inspectable(category="General", defaultValue="true")]
+
+ /**
+ * Specifies whether this element is included in the layout of the parent.
+ *
+ * @default true
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function get includeInLayout():Boolean
+ {
+ return _includeInLayout;
+ }
+
+ /**
+ * @private
+ */
+ public function set includeInLayout(value:Boolean):void
+ {
+ if (_includeInLayout == value)
+ return;
+
+ // Temporarily set includeInLayout to true so that
+ // invalidating the parent doesn't return early.
+ _includeInLayout = true;
+ invalidateParentSizeAndDisplayList();
+
+ _includeInLayout = value;
+ }
+
+ //----------------------------------
+ // displayObjectSharingMode
+ //----------------------------------
+
+ private var _displayObjectSharingMode:String;
+
+ [Inspectable(category="General", enumeration="ownsUnsharedObject,ownsSharedObject,usesSharedObject")]
+
+ /**
+ * @private
+ */
+ public function set displayObjectSharingMode(value:String):void
+ {
+ if (value == _displayObjectSharingMode)
+ return;
+
+ if (value != DisplayObjectSharingMode.USES_SHARED_OBJECT ||
+ _displayObjectSharingMode != DisplayObjectSharingMode.USES_SHARED_OBJECT)
+ {
+ // If the element was previously at the head of the shared sequence or
+ // it is assigned to be at the head, make sure to reapply the
+ // displayObject specific properties.
+ displayObjectChanged = true;
+ invalidateProperties();
+ }
+ _displayObjectSharingMode = value;
+ }
+
+ /**
+ * @inheritDoc
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function get displayObjectSharingMode():String
+ {
+ return _displayObjectSharingMode;
+ }
+
+ //----------------------------------
+ // layoutDirection
+ //----------------------------------
+
+ private var _layoutDirection:String = null;
+
+ [Inspectable(category="General", enumeration="ltr,rtl")]
+
+ /**
+ * @inheritDoc
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function get layoutDirection():String
+ {
+ if (_layoutDirection != null)
+ return _layoutDirection;
+
+ const parentElt:ILayoutDirectionElement = parent as ILayoutDirectionElement;
+ return (parentElt) ? parentElt.layoutDirection : LayoutDirection.LTR;
+ }
+
+ /**
+ * @private
+ */
+ public function set layoutDirection(value:String):void
+ {
+ if (_layoutDirection == value)
+ return;
+
+ _layoutDirection = value;
+ invalidateLayoutDirection();
+ }
+
+ /**
+ * @inheritDoc
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function invalidateLayoutDirection():void
+ {
+ const parentElt:ILayoutDirectionElement = parent as ILayoutDirectionElement;
+ if (!parentElt)
+ return;
+
+ // If this element's layoutDirection doesn't match its parent's, then
+ // set the layoutFeatures.mirror flag. Similarly, if mirroring isn't
+ // required, then clear the layoutFeatures.mirror flag.
+
+ const mirror:Boolean = (parentElt.layoutDirection != null && _layoutDirection != null)
+ && (_layoutDirection != parentElt.layoutDirection);
+
+ if ((layoutFeatures) ? (mirror != layoutFeatures.mirror) : mirror)
+ {
+ if (layoutFeatures == null)
+ allocateLayoutFeatures();
+ var previous:Boolean = needsDisplayObject;
+ layoutFeatures.mirror = mirror;
+ invalidateTransform(previous != needsDisplayObject);
+ }
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // Methods
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Called automatically by the MXML compiler when the GraphicElement
+ * is created using an MXML tag.
+ * If you create the GraphicElement through ActionScript you must set the
+ * <code>id</code> property manually.
+ *
+ * @param document The MXML document containing this GraphicElement (not used).
+ * @param id The MXML id for this GraphicElement.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function initialized(document:Object, id:String):void
+ {
+ this.id = id;
+ }
+
+ /**
+ * Converts the point object from the object's (local) coordinates
+ * to the Stage (global) coordinates.
+ *
+ * <p>This method allows you to convert any given x and y coordinates from
+ * values that are relative to the origin (0,0) of a specific object
+ * (local coordinates) to values that are relative to the origin
+ * of the Stage (global coordinates).</p>
+ *
+ * <p>To use this method, first create an instance of the Point class.
+ * The x and y values that you assign represent local coordinates
+ * because they relate to the origin of the object.</p>
+ *
+ * <p>You then pass the Point instance that you created as the parameter
+ * to the localToGlobal() method. The method returns a new Point object
+ * with x and y values that relate to the origin of the Stage instead of
+ * the origin of the object.</p>
+ *
+ * @param point The name or identifier of a point created with the Point
+ * class, specifying the x and y coordinates as properties.
+ *
+ * @return A Point object with coordinates relative to the Stage.
+ *
+ * @see flash.display.DisplayObject#localToGlobal
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function localToGlobal(point:Point):Point
+ {
+ // If there is not yet a displayObject or it's not parented, just
+ // return its local position
+ if (!displayObject || !displayObject.parent)
+ return new Point(x, y);
+
+ var returnVal:Point = displayObject.localToGlobal(point);
+
+ if (!needsDisplayObject)
+ {
+ // If we're sharing the displayObject, add in our offset
+ returnVal.x += drawX;
+ returnVal.y += drawY;
+ }
+
+ return returnVal;
+ }
+
+ /**
+ * @inheritDoc
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function createDisplayObject():DisplayObject
+ {
+ setDisplayObject(new InvalidatingSprite());
+ return displayObject;
+ }
+
+ /**
+ * True if the element requires an exclusive DisplayObject.
+ *
+ * Developers don't usually call this method directly, but override it in
+ * their subclasses to indicate that an exclusive DisplayObject is needed.
+ *
+ * Usually a subclass needs a DisplayObject when it has to set its properties.
+ *
+ * Some examples of such DisplayObject properties are <code>filters</code>,
+ * <code>blendMode</code>, <code>mask</code>,
+ * <code>rotation</code>, <code>alpha</code>.
+ *
+ * @return Returns true when the element requires an exclusive DisplayObject.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ protected function get needsDisplayObject():Boolean
+ {
+ var result:Boolean = (alwaysCreateDisplayObject ||
+ (_filters && _filters.length > 0) ||
+ (_blendMode != BlendMode.NORMAL && _blendMode != "auto") || _mask ||
+ (layoutFeatures != null && (layoutFeatures.layoutScaleX != 1 || layoutFeatures.layoutScaleY != 1 || layoutFeatures.layoutScaleZ != 1 ||
+ layoutFeatures.layoutRotationX != 0 || layoutFeatures.layoutRotationY != 0 || layoutFeatures.layoutRotationZ != 0 ||
+ layoutFeatures.layoutZ != 0 || layoutFeatures.mirror)) ||
+ _colorTransform != null ||
+ _effectiveAlpha != 1);
+
+ if (layoutFeatures != null && layoutFeatures.postLayoutTransformOffsets != null)
+ {
+ var o:TransformOffsets = layoutFeatures.postLayoutTransformOffsets;
+ result = result || (o.scaleX != 1 || o.scaleY != 1 || o.scaleZ != 1 ||
+ o.rotationX != 0 || o.rotationY != 0 || o.rotationZ != 0 || o.z != 0);
+ }
+
+ return result;
+ }
+
+ /**
+ * @inheritDoc
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function setSharedDisplayObject(sharedDisplayObject:DisplayObject):Boolean
+ {
+ if (!(sharedDisplayObject is Sprite) || _alwaysCreateDisplayObject || needsDisplayObject)
+ return false;
+ setDisplayObject(sharedDisplayObject);
+ return true;
+ }
+
+ /**
+ * @inheritDoc
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function canShareWithPrevious(element:IGraphicElement):Boolean
+ {
+ // No need to check _alwaysCreateDisplayObject or needsDisplayObject,
+ // as those will be checked in setSharedDisplayObject
+ return element is GraphicElement;
+ }
+
+ /**
+ * @inheritDoc
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function canShareWithNext(element:IGraphicElement):Boolean
+ {
+ return element is GraphicElement && !_alwaysCreateDisplayObject && !needsDisplayObject;
+ }
+
+ /**
+ * The actual DisplayObject that is drawn into by the GraphicElement. Typically this is
+ * equivalent to the <code>displayObject</code> property. Subclasses should perform drawing commands on
+ * this property instead of on <code>displayObject</code>.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ protected function get drawnDisplayObject():DisplayObject
+ {
+ // _drawnDisplayObject is non-null if we needed to create a mask
+ return _drawnDisplayObject ? _drawnDisplayObject : displayObject;
+ }
+
+ /**
+ * Returns a bitmap snapshot of the GraphicElement.
+ * The bitmap contains all transformations and is reduced
+ * to fit the visual bounds of the object.
+ *
+ * @param transparent Whether or not the bitmap image supports per-pixel transparency.
+ * The default value is true (transparent). To create a fully transparent bitmap, set the value of the
+ * transparent parameter to true and the value of the fillColor parameter to 0x00000000 (or to 0).
+ * Setting the transparent property to false can result in minor improvements in rendering performance.
+ *
+ * @param fillColor A 32-bit ARGB color value that you use to fill the bitmap image area.
+ * The default value is 0xFFFFFFFF (solid white).
+ *
+ * @param useLocalSpace Whether or not the bitmap shows the GraphicElement in the local or global
+ * coordinate space. If true, then the snapshot is in the local space. The default value is true.
+ *
+ * @param clipRect A Rectangle object that defines the area of the source object to draw.
+ * If you do not supply this value, no clipping occurs and the entire source object is drawn.
+ * The clipRect should be defined in the coordinate space specified by useLocalSpace
+ *
+ * @return A bitmap snapshot of the GraphicElement or null if the input element has no visible bounds.
+ *
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ mx_internal function captureBitmapData(transparent:Boolean = true, fillColor:uint = 0xFFFFFFFF, useLocalSpace:Boolean = true, clipRect:Rectangle = null):BitmapData
+ {
+ if (!layoutFeatures || !layoutFeatures.is3D)
+ {
+ var restoreDisplayObject:Boolean = false;
+ var oldDisplayObject:DisplayObject;
+
+ if (!displayObject || displayObjectSharingMode != DisplayObjectSharingMode.OWNS_UNSHARED_OBJECT)
+ {
+ restoreDisplayObject = true;
+ oldDisplayObject = displayObject;
+ setDisplayObject(new InvalidatingSprite());
+ if (parent is UIComponent)
+ UIComponent(parent).$addChild(displayObject);
+ else
+ parent.addChild(displayObject);
+ invalidateDisplayList();
+ validateDisplayList();
+ }
+
+ var topLevel:Sprite = Sprite(IUIComponent(parent).systemManager.getSandboxRoot());
+ var rectBounds:Rectangle = useLocalSpace ?
+ new Rectangle(getLayoutBoundsX(), getLayoutBoundsY(), getLayoutBoundsWidth(), getLayoutBoundsHeight()) :
+ displayObject.getBounds(topLevel);
+
+ if (rectBounds.width == 0 || rectBounds.height == 0)
+ return null;
+
+ var bitmapData:BitmapData = new BitmapData(Math.ceil(rectBounds.width), Math.ceil(rectBounds.height), transparent, fillColor);
+
+ // Can't use target's concatenatedMatrix, as it is sometimes wrong
+ var m:Matrix = useLocalSpace ?
+ displayObject.transform.matrix :
+ MatrixUtil.getConcatenatedMatrix(displayObject, null);
+
+ if (m)
+ m.translate(-rectBounds.x, -rectBounds.y);
+
+ bitmapData.draw(displayObject, m, null, null, clipRect);
+
+ if (restoreDisplayObject)
+ {
+ if (parent is UIComponent)
+ UIComponent(parent).$removeChild(displayObject);
+ else
+ parent.removeChild(displayObject);
+ setDisplayObject(oldDisplayObject);
+ }
+ return bitmapData;
+
+ }
+ else
+ {
+ return get3DSnapshot(transparent, fillColor, useLocalSpace);
+ }
+ }
+
+ /**
+ * @private
+ * Returns a bitmap snapshot of a 3D transformed displayObject. Since BitmapData.draw ignores
+ * the transform matrix of its target when it draws, we need to parent the target in a temporary
+ * sprite and call BitmapData.draw on that temp sprite. We can't take a bitmap snapshot of the
+ * real parent because it might have other children.
+ */
+ private function get3DSnapshot(transparent:Boolean = true, fillColor:uint = 0xFFFFFFFF, useLocalSpace:Boolean = true):BitmapData
+ {
+ var topLevel:Sprite = Sprite(IUIComponent(parent).systemManager);
+ var dispObjParent:DisplayObjectContainer = displayObject.parent;
+ var drawSprite:Sprite = new Sprite();
+
+ // Get the visual bounds of the target in both local and global coordinates
+ var topLevelRect:Rectangle = displayObject.getBounds(topLevel);
+ var displayObjectRect:Rectangle = displayObject.getBounds(dispObjParent);
+
+ // Keep a reference to the original 3D matrix. We will restore this later.
+ var oldMat3D:Matrix3D = displayObject.transform.matrix3D.clone();
+
+ // Get the concatenated 3D matrix which we will use to position the target when we reparent it
+ var globalMat3D:Matrix3D = displayObject.transform.getRelativeMatrix3D(topLevel);
+ var newMat3D:Matrix3D = oldMat3D.clone();
+
+
+ // Remove the target from its current parent, making sure to store the child index
+ var displayObjectIndex:int = parent.getChildIndex(displayObject);
+ if (parent is UIComponent)
+ UIComponent(parent).$removeChild(displayObject);
+ else
+ parent.removeChild(displayObject);
+
+ // Parent the target to the drawSprite and then attach the drawSprite to the stage
+ topLevel.addChild(drawSprite);
+ drawSprite.addChild(displayObject);
+
+ // Assign the globally translated matrix to the target
+ if (useLocalSpace)
+ {
+ newMat3D.position = globalMat3D.position;
+ displayObject.transform.matrix3D = newMat3D;
+ }
+ else
+ {
+ displayObject.transform.matrix3D = globalMat3D;
+ }
+ // Translate the bitmap so that the left-top bounds ends up at (0,0)
+ var m:Matrix = new Matrix();
+ m.translate(-topLevelRect.left, - topLevelRect.top);
+
+ // Draw to the bitmapData
+ var snapshot:BitmapData = new BitmapData( topLevelRect.width, topLevelRect.height, transparent, fillColor);
+ snapshot.draw(drawSprite, m, null, null, null, true);
+
+ // Remove target from temporary sprite and remove temp sprite from stage
+ drawSprite.removeChild(displayObject);
+ topLevel.removeChild(drawSprite);
+
+ // Reattach the target to its original parent at its original child position
+ if (parent is UIComponent)
+ UIComponent(parent).$addChildAt(displayObject, displayObjectIndex);
+ else
+ parent.addChildAt(displayObject, displayObjectIndex);
+
+ // Restore the original 3D matrix
+ displayObject.transform.matrix3D = oldMat3D;
+
+ return snapshot;
+ }
+
+ /**
+ * @private
+ */
+ protected function layer_PropertyChange(event:PropertyChangeEvent):void
+ {
+ switch (event.property)
+ {
+ case "effectiveVisibility":
+ {
+ var newValue:Boolean = (event.newValue && _visible);
+
+ if (newValue != _effectiveVisibility)
+ {
+ _effectiveVisibility = newValue;
+ visibleChanged = true;
+ invalidateProperties();
+ }
+ break;
+ }
+ case "effectiveAlpha":
+ {
+ var newAlpha:Number = Number(event.newValue) * _alpha;
+ if (newAlpha != _effectiveAlpha)
+ {
+ _effectiveAlpha = newAlpha;
+ alphaChanged = true;
+
+ var mxTransform:mx.geom.Transform = _transform as mx.geom.Transform;
+ if (mxTransform)
+ mxTransform.applyColorTransformAlpha = false;
+
+ invalidateDisplayObjectSharing();
+ invalidateProperties();
+ }
+ break;
+ }
+ }
+ }
+
+ /**
+ * Dispatches a propertyChange event.
+ *
+ * @param prop The property that changed.
+ *
+ * @param oldValue The previous value of the property.
+ *
+ * @param value The new value of the property.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ mx_internal function dispatchPropertyChangeEvent(prop:String, oldValue:*,
+ value:*):void
+ {
+ if (hasEventListener("propertyChange"))
+ dispatchEvent(PropertyChangeEvent.createUpdateEvent(
+ this, prop, oldValue, value));
+
+ }
+
+ /**
+ * Utility method that notifies the host that this element has changed and needs
+ * its layer to be updated.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ protected function invalidateDisplayObjectSharing():void
+ {
+ if (parent)
+ IGraphicElementContainer(parent).invalidateGraphicElementSharing(this);
+ }
+
+ /**
+ * Calling this method results in a call to the elements's
+ * <code>validateProperties()</code> method
+ * before the display list is rendered.
+ *
+ * <p>Subclasses should do their work in
+ * <code>commitProperties()</code>.</p>
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function invalidateProperties():void
+ {
+ if (invalidatePropertiesFlag)
+ return;
+ invalidatePropertiesFlag = true;
+
+ if (parent)
+ IGraphicElementContainer(parent).invalidateGraphicElementProperties(this);
+ }
+
+ /**
+ * Calling this method results in a call to the elements's
+ * <code>validateSize()</code> method
+ * before the display list is rendered.
+ *
+ * <p>Subclasses should override and do their measurement in
+ * <code>measure()</code>.
+ * By default when <code>explicitWidth</code> and <code>explicitHeight</code>
+ * are set, <code>measure()</code> will not be called. To override this
+ * default behavior subclasses should override <code>skipMeasure()</code>.</p>
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function invalidateSize():void
+ {
+ if (invalidateSizeFlag)
+ return;
+ invalidateSizeFlag = true;
+
+ if (parent)
+ IGraphicElementContainer(parent).invalidateGraphicElementSize(this);
+ }
+
+ /**
+ * Helper method to invalidate parent size and display list if
+ * this object affects its layout (includeInLayout is true).
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ protected function invalidateParentSizeAndDisplayList():void
+ {
+ if (!includeInLayout)
+ return;
+
+ // We want to invalidate both the parent size and parent display list.
+ if (parent && parent is IInvalidating)
+ {
+ IInvalidating(parent).invalidateSize();
+ IInvalidating(parent).invalidateDisplayList();
+ }
+ }
+
+ /**
+ * Calling this method results in a call to the elements's
+ * <code>validateDisplayList()</code> method
+ * before the display list is rendered.
+ *
+ * <p>Subclasses should override and do their work in
+ * <code>updateDisplayList()</code>.</p>
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function invalidateDisplayList():void
+ {
+ if (invalidateDisplayListFlag)
+ return;
+ invalidateDisplayListFlag = true;
+
+ // The IGraphicElementContainer will take care of redrawing all graphic elements that
+ // share the display object with this element.
+ if (parent)
+ IGraphicElementContainer(parent).invalidateGraphicElementDisplayList(this);
+ }
+
+ /**
+ * Validates and updates the properties and layout of this object
+ * by immediately calling <code>validateProperties()</code>,
+ * <code>validateSize()</code>, and <code>validateDisplayList()</code>,
+ * if necessary.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function validateNow():void
+ {
+ if (parent)
+ {
+ UIComponentGlobals.layoutManager.validateClient(
+ ILayoutManagerClient(parent));
+ }
+ }
+
+ /**
+ * Used by layout logic to validate the properties of a component
+ * by calling the <code>commitProperties()</code> method.
+ * In general, subclasses should
+ * override the <code>commitProperties()</code> method and not this method.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ public function validateProperties():void
+ {
+ if (!invalidatePropertiesFlag)
+ return;
+ commitProperties();
+ invalidatePropertiesFlag = false;
+
+ // If we aren't doing any more invalidation, send out an UpdateComplete event
+ if (!invalidatePropertiesFlag && !invalidateSizeFlag && !invalidateDisplayListFlag)
+ dispatchUpdateComplete();
+ }
+
+ /**
+ * Processes the properties set on the element.
+ * This is an advanced method that you might override
+ * when creating a subclass.
+ *
+ * <p>You do not call this method directly.
+ * Flex calls the <code>commitProperties()</code> method when you
+ * use the <code>addElement()</code> method to add an element to an
+ * <code>IGraphicElementContainer</code> container such as Group,
+ * or when you call the <code>invalidateProperties()</code> method of the element.
+ * Calls to the <code>commitProperties()</code> method occur before calls to the
+ * <code>measure()</code> method. This lets you set property values that might
+ * be used by the <code>measure()</code> method.</p>
+ *
+ * <p>Some elements have properties that
+ * interact with each other.
+ * It is often best at startup time to process all of these
+ * properties at one time to avoid duplicating work.</p>
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 1.5
+ * @productversion Flex 4
+ */
+ protected function commitProperties():void
+ {
+ //trace("GraphicElement.commitProperties displayObject",displayObject,"this",this);
+ var updateTransform:Boolean = false;
+ var mxTransform:mx.geom.Transform;
+
+ // If we are the first in the sequence, setup the displayObject properties
+ if (displayObjectSharingMode != DisplayObjectSharingMode.USES_SHARED_OBJECT && displayObject)
+ {
+ if (colorTransformChanged || displayObjectChanged)
+ {
+ colorTransformChanged = false;
+ if (_colorTransform)
+ displayObject.transform.colorTransform = _colorTransform;
+ }
... 1096 lines suppressed ...