//////////////////////////////////////////////////////////////////////////////// // // 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 mx.effects { import flash.events.Event; import flash.events.EventDispatcher; import flash.events.IEventDispatcher; import flash.events.TimerEvent; import flash.utils.Timer; import flash.utils.getQualifiedClassName; import flash.utils.getTimer; import mx.core.UIComponent; import mx.core.mx_internal; import mx.effects.effectClasses.PropertyChanges; import mx.events.EffectEvent; import mx.events.FlexEvent; import mx.utils.NameUtil; use namespace mx_internal; /** * The EffectInstance class represents an instance of an effect * playing on a target. * Each target has a separate effect instance associated with it. * An effect instance's lifetime is transitory. * An instance is created when the effect is played on a target * and is destroyed when the effect has finished playing. * If there are multiple effects playing on a target at the same time * (for example, a Parallel effect), there is a separate effect instance * for each effect. * *

Effect developers must create an instance class * for their custom effects.

* * @see mx.effects.Effect * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ public class EffectInstance extends EventDispatcher implements IEffectInstance { include "../core/Version.as"; //-------------------------------------------------------------------------- // // Constructor // //-------------------------------------------------------------------------- /** * Constructor. * * @param target UIComponent object to animate with this effect. * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ public function EffectInstance(target:Object) { super(); this.target = target; } //-------------------------------------------------------------------------- // // Variables // //-------------------------------------------------------------------------- /** * @private * Timer used to track startDelay and repeatDelay. */ mx_internal var delayTimer:Timer; /** * @private * Starting time of delayTimer. */ private var delayStartTime:Number = 0; /** * @private * Elapsed time of delayTimer when paused. * Used by resume() to figure out amount of time remaining. */ private var delayElapsedTime:Number = 0; /** * @private * Internal flag remembering whether the user * explicitly specified a duration or not. */ mx_internal var durationExplicitlySet:Boolean = false; /** * @private * If this is a "hide" effect, the EffectManager sets this flag * as a reminder to hide the object when the effect finishes. */ mx_internal var hideOnEffectEnd:Boolean = false; /** * @private * Pointer back to the CompositeEffect that created this instance. * Value is null if we are not the child of a CompositeEffect */ mx_internal var parentCompositeEffectInstance:EffectInstance; /** * Number of times that the instance has been played. * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ protected var playCount:int = 0; /** * @private * Used internally to prevent the effect from repeating * once the effect has been ended by calling end(). */ mx_internal var stopRepeat:Boolean = false; //-------------------------------------------------------------------------- // // Properties // //-------------------------------------------------------------------------- //---------------------------------- // actualDuration //---------------------------------- /** * @private * Used internally to determine the duration * including the startDelay, repeatDelay, and repeatCount values. */ mx_internal function get actualDuration():Number { var value:Number = NaN; if (repeatCount > 0) { value = duration * repeatCount + (repeatDelay * (repeatCount - 1)) + startDelay; } return value; } //---------------------------------- // className //---------------------------------- /** * @copy mx.effects.IEffectInstance#className * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ public function get className():String { return NameUtil.getUnqualifiedClassName(this); } //---------------------------------- // duration //---------------------------------- /** * @private * Storage for the duration property. */ private var _duration:Number = 500; [Inspectable(category="General", defaultValue="500")] /** * @copy mx.effects.IEffectInstance#duration * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ public function get duration():Number { if (!durationExplicitlySet && parentCompositeEffectInstance) { return parentCompositeEffectInstance.duration; } else { return _duration; } } /** * @private */ public function set duration(value:Number):void { durationExplicitlySet = true; _duration = value; } //---------------------------------- // effect //---------------------------------- /** * @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; } //---------------------------------- // effectTargetHost //---------------------------------- /** * @private * Storage for the effectTargetHost property. */ private var _effectTargetHost:IEffectTargetHost; /** * @copy mx.effects.IEffectInstance#effectTargetHost * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ public function get effectTargetHost():IEffectTargetHost { return _effectTargetHost; } /** * @private */ public function set effectTargetHost(value:IEffectTargetHost):void { _effectTargetHost = value; } //---------------------------------- // hideFocusRing //---------------------------------- /** * @private * Storage for the hideFocusRing property. */ private var _hideFocusRing:Boolean; /** * @copy mx.effects.IEffectInstance#hideFocusRing * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ public function get hideFocusRing():Boolean { return _hideFocusRing; } /** * @private */ public function set hideFocusRing(value:Boolean):void { _hideFocusRing = value; } //---------------------------------- // playheadTime //---------------------------------- /** * Current time position of the effect. * This property has a value between 0 and the total duration, * which includes the Effect's startDelay, * repeatCount, and repeatDelay. * * @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); } /** * @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(); } } } //---------------------------------- // 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; } /** * @private */ mx_internal function set playReversed(value:Boolean):void { _playReversed = value; } //---------------------------------- // 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; } //---------------------------------- // suspendBackgroundProcessing //---------------------------------- /** * @private * Storage for the suspendBackgroundProcessing property. */ private var _suspendBackgroundProcessing:Boolean = false; /** * @copy mx.effects.IEffectInstance#suspendBackgroundProcessing * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ public function get suspendBackgroundProcessing():Boolean { return _suspendBackgroundProcessing; } /** * @private */ public function set suspendBackgroundProcessing(value:Boolean):void { _suspendBackgroundProcessing = value; } //---------------------------------- // target //---------------------------------- /** * @private * Storage for the target property. */ private var _target:Object; /** * @copy mx.effects.IEffectInstance#target * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ public function get target():Object { return _target; } /** * @private */ public function set target(value:Object):void { _target = value; } //---------------------------------- // triggerEvent //---------------------------------- /** * @private * Storage for the triggerEvent property. */ private var _triggerEvent:Event; /** * @copy mx.effects.IEffectInstance#triggerEvent * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ public function get triggerEvent():Event { return _triggerEvent; } /** * @private */ public function set triggerEvent(value:Event):void { _triggerEvent = value; } //-------------------------------------------------------------------------- // // Methods // //-------------------------------------------------------------------------- /** * @copy mx.effects.IEffectInstance#initEffect() * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ public function initEffect(event:Event):void { triggerEvent = event; switch (event.type) { case "resizeStart": case "resizeEnd": { if (!durationExplicitlySet) duration = 250; break; } case FlexEvent.HIDE: { target.setVisible(true, true); hideOnEffectEnd = true; // If somebody else shows us, then cancel the hide when the effect ends target.addEventListener(FlexEvent.SHOW, eventHandler); break; } } } /** * @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(); } } /** * @copy mx.effects.IEffectInstance#play() * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ public function play():void { playCount++; dispatchEvent(new EffectEvent(EffectEvent.EFFECT_START, false, false, this)); if (target && (target is IEventDispatcher)) { target.dispatchEvent(new EffectEvent(EffectEvent.EFFECT_START, false, false, this)); } } /** * @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#end() * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ public function end():void { if (delayTimer) delayTimer.reset(); stopRepeat = true; finishEffect(); } /** * @copy mx.effects.IEffectInstance#finishEffect() * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ public function finishEffect():void { playCount = 0; dispatchEvent(new EffectEvent(EffectEvent.EFFECT_END, false, false, this)); if (target && (target is IEventDispatcher)) { target.dispatchEvent(new EffectEvent(EffectEvent.EFFECT_END, false, false, this)); } if (target is UIComponent) { UIComponent(target).effectFinished(this); } EffectManager.effectFinished(this); } /** * @copy mx.effects.IEffectInstance#finishRepeat() * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ public function finishRepeat():void { if (!stopRepeat && playCount != 0 && (playCount < repeatCount || repeatCount == 0)) { if (repeatDelay > 0) { delayTimer = new Timer(repeatDelay, 1); delayStartTime = getTimer(); delayTimer.addEventListener(TimerEvent.TIMER, delayTimerHandler); delayTimer.start(); } else { play(); } } else { finishEffect(); } } /** * @private */ mx_internal function playWithNoDuration():void { duration = 0; repeatCount = 1; repeatDelay = 0; startDelay = 0; startEffect(); } //-------------------------------------------------------------------------- // // Event handlers // //-------------------------------------------------------------------------- /** * @private * If someone explicitly sets the visibility of the target object * to true, clear the flag that is remembering to hide the * target when this effect ends. */ mx_internal function eventHandler(event:Event):void { if (event.type == FlexEvent.SHOW && hideOnEffectEnd == true) { hideOnEffectEnd = false; event.target.removeEventListener(FlexEvent.SHOW, eventHandler); } } /** * @private */ private function delayTimerHandler(event:TimerEvent):void { delayTimer.reset(); delayStartTime = NaN; delayElapsedTime = NaN; play(); } } }