blob: 4e2cc7ffe1999193de612cb12977a5b1f49f33ab [file] [log] [blame]
////////////////////////////////////////////////////////////////////////////////
//
// 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.
*
* <p>Effect developers must create an instance class
* for their custom effects.</p>
*
* @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 <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);
}
/**
* @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();
}
}
}