| //////////////////////////////////////////////////////////////////////////////// |
| // |
| // 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.display.DisplayObject; |
| import flash.display.DisplayObjectContainer; |
| import flash.events.Event; |
| import flash.events.EventDispatcher; |
| import flash.events.FocusEvent; |
| import flash.system.ApplicationDomain; |
| import flash.utils.Dictionary; |
| |
| import mx.core.EventPriority; |
| import mx.core.FlexGlobals; |
| import mx.core.IDeferredInstantiationUIComponent; |
| import mx.core.IFlexDisplayObject; |
| import mx.core.IUIComponent; |
| import mx.core.UIComponent; |
| import mx.core.UIComponentCachePolicy; |
| import mx.core.mx_internal; |
| import mx.events.EffectEvent; |
| import mx.events.FlexEvent; |
| import mx.events.MoveEvent; |
| import mx.events.ResizeEvent; |
| import mx.managers.ISystemManager; |
| import mx.managers.SystemManager; |
| import mx.resources.IResourceManager; |
| import mx.resources.ResourceManager; |
| import mx.core.IVisualElementContainer; |
| import mx.core.IVisualElement; |
| |
| use namespace mx_internal; |
| |
| [ResourceBundle("effects")] |
| |
| /** |
| * The EffectManager class listens for events, such as the <code>show</code> |
| * and <code>move</code> events, dispatched by objects in a Flex application. |
| * For each event, corresponding to an event trigger, it determines if |
| * there is an effect assigned to the object. |
| * If an effect is defined, it plays the effect. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public class EffectManager extends EventDispatcher |
| { |
| include "../core/Version.as"; |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Class variables |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * @private |
| * Keeps track of all the triggered effects that are currently playing. |
| */ |
| mx_internal static var effectsPlaying:Array /* of EffectNode */ = []; |
| |
| /** |
| * @private |
| * Map with event type as key and effectTrigger as value. |
| */ |
| private static var effectTriggersForEvent:Object = {}; |
| |
| /** |
| * @private |
| * Map with effectTrigger as key and event type as value. |
| */ |
| private static var eventsForEffectTriggers:Object = {}; |
| |
| /** |
| * @private |
| * Array containing miscellaneous info about effect targets. |
| * An element in the array is an Object with three fields: |
| * target - reference to the target |
| * bitmapEffectsCount - number of bitmap effects |
| * currently playing on the target |
| * vectorEffectsCount - number of vector effects |
| * currently playing on the target |
| */ |
| private static var targetsInfo:Array /* of Object */ = []; |
| |
| /** |
| * @private |
| * Remember when suspendEventHandling() has been called |
| * without a matching resumeEventHandling(). |
| */ |
| private static var eventHandlingSuspendCount:Number = 0; |
| |
| /** |
| * @private |
| * Weak backing storage for the lastEffectCreated instance. |
| */ |
| private static var weakKeys:Dictionary; |
| |
| /** |
| * @private |
| * This internal property is currently only used by the ViewStack |
| * component in order to coordinate the hideEffect completion with |
| * ViewStack change logic. It would be best to find a better way |
| * to do this (localized to ViewStack) in the future however. |
| */ |
| mx_internal static function set lastEffectCreated(effect:Effect):void |
| { |
| // We just regenerate our dictionary instead of finding and deleting |
| // the previous key. Faster. |
| weakKeys = new Dictionary(true); |
| weakKeys[effect] = true; |
| } |
| |
| /** |
| * @private |
| */ |
| mx_internal static function get lastEffectCreated():Effect |
| { |
| for (var item:* in weakKeys) |
| return item; |
| |
| return null; |
| } |
| |
| /** |
| * @private |
| * Storage for the resourceManager getter. |
| * This gets initialized on first access, |
| * not at static initialization time, in order to ensure |
| * that the Singleton registry has already been initialized. |
| */ |
| private static var _resourceManager:IResourceManager; |
| |
| /** |
| * @private |
| * A reference to the object which manages |
| * all of the application's localized resources. |
| * This is a singleton instance which implements |
| * the IResourceManager interface. |
| */ |
| private static function get resourceManager():IResourceManager |
| { |
| if (!_resourceManager) |
| _resourceManager = ResourceManager.getInstance(); |
| |
| return _resourceManager; |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Class methods |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * After this method is called, the EffectManager class ignores |
| * all events, and no effects are triggered, until a call to |
| * <code>resumeEventHandling()</code>. |
| * Used internally so that an effect that is updating the screen |
| * does not cause another effect to be triggered. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public static function suspendEventHandling():void |
| { |
| eventHandlingSuspendCount++; |
| } |
| |
| /** |
| * Allows the EffectManager class to resume processing events |
| * after a call to the <code>suspendEventHandling()</code> method. |
| * Used internally in conjunction with the |
| * <code>suspendEventHandling()</code> method |
| * so that an effect that is updating the screen |
| * does not cause another effect to be triggered. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public static function resumeEventHandling():void |
| { |
| eventHandlingSuspendCount--; |
| } |
| |
| /** |
| * Immediately ends any effects currently playing on a target. |
| * |
| * @param target The target component on which to end all effects. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public static function endEffectsForTarget(target:IUIComponent):void |
| { |
| // Iterate through the array backward, because calling end() |
| // may cause the element to be removed from the array. |
| var n:int = effectsPlaying.length; |
| for (var i:int = n - 1; i >= 0; i--) |
| { |
| var otherInst:EffectInstance = |
| effectsPlaying[i].instance; |
| if (otherInst.target == target) |
| otherInst.end(); |
| } |
| } |
| |
| /** |
| * @private |
| */ |
| mx_internal static function setStyle(styleProp:String, target:*):void |
| { |
| // Anytime that any UIComponent's style is changed, |
| // check to see if the styleProp that's changing |
| // is an effect trigger (e.g., showEffect). |
| |
| var eventName:String = eventsForEffectTriggers[styleProp]; |
| if (eventName != null && eventName != "") |
| { |
| target.addEventListener(eventName, |
| EffectManager.eventHandler, |
| false, EventPriority.EFFECT); |
| } |
| } |
| |
| /** |
| * @private |
| * Internal function used to instantiate an effect |
| */ |
| mx_internal static function createEffectForType(target:Object, |
| type:String):Effect |
| { |
| var trigger:String = effectTriggersForEvent[type]; |
| |
| if (trigger == "") |
| trigger = type + "Effect"; // For backwards compatibility |
| |
| var value:Object = target.getStyle(trigger); |
| |
| if (!value) |
| return null; |
| |
| if (value is Class) |
| { |
| var cls:Class = Class(value); |
| return new cls(target); |
| } |
| |
| // If we don't find the ID on the parent document, then just move on. |
| try |
| { |
| var effectObj:Effect; |
| if (value is String) |
| { |
| var doc:Object = target.parentDocument; |
| // The main Application doesn't have a parentDocument. |
| if (!doc) |
| doc = FlexGlobals.topLevelApplication; |
| effectObj = doc[value]; |
| } |
| else if (value is Effect) |
| { |
| effectObj = Effect(value); |
| } |
| |
| if (effectObj) |
| { |
| effectObj.target = target; |
| return effectObj; |
| } |
| } |
| catch(e:Error) |
| { |
| } |
| |
| var effectClass:Class; |
| if (target is UIComponent && target.moduleFactory) |
| { |
| // only UIComponents have moduleFactories |
| var appDomain:ApplicationDomain = |
| target.moduleFactory.info()["currentDomain"]; |
| if (appDomain.hasDefinition("mx.effects." + value)) |
| effectClass = Class(appDomain.getDefinition("mx.effects." + value)); |
| } |
| if (!effectClass) |
| effectClass = Class(target.systemManager.getDefinitionByName( |
| "mx.effects." + value)); |
| |
| if (effectClass) |
| return new effectClass(target); |
| |
| return null; |
| } |
| |
| /** |
| * @private |
| * Internal function used while playing effects |
| */ |
| private static function animateSameProperty(a:Effect, b:Effect, |
| c:EffectInstance):Boolean |
| { |
| // This function returns true if "a" and "b" animate |
| // the same property of the same object. |
| |
| if (a.target == c.target) |
| { |
| var aProps:Array = a.getAffectedProperties(); |
| var bProps:Array = b.getAffectedProperties(); |
| |
| var n:int = aProps.length; |
| var m:int = bProps.length; |
| |
| for (var i:int = 0; i < n; i++) |
| { |
| for (var j:int = 0; j < m; j++) |
| { |
| if (aProps[i] == bProps[j]) |
| return true; |
| } |
| } |
| } |
| |
| return false; |
| } |
| |
| /** |
| * @private |
| * Should be called by an effect instance before it starts playing, |
| * to suggest bitmap caching on the target. |
| * E.g. Fade calls this function in its play(). |
| */ |
| mx_internal static function startBitmapEffect(target:IUIComponent):void |
| { |
| cacheOrUncacheTargetAsBitmap(target, true, true); |
| } |
| |
| /** |
| * @private |
| * Should be called by an effect instance after it has finished playing, |
| * to suggest that the cached bitmap for the target can be freed. |
| * E.g. Fade calls this function in its onTweenEnd(). |
| */ |
| mx_internal static function endBitmapEffect(target:IUIComponent):void |
| { |
| cacheOrUncacheTargetAsBitmap(target, false, true); |
| } |
| |
| /** |
| * @private |
| * Should be called by an effect instance before it starts playing, to |
| * suggest that bitmap caching should be turned off on the target. |
| * E.g. Resize calls this function in its play(). |
| */ |
| mx_internal static function startVectorEffect(target:IUIComponent):void |
| { |
| cacheOrUncacheTargetAsBitmap(target, true, false); |
| } |
| |
| /** |
| * @private |
| * Should be called by an effect instance after it has finished playing, |
| * to suggest that bitmap caching may be turned back on on the target. |
| * E.g. Resize calls this function in its onTweenEnd(). |
| */ |
| mx_internal static function endVectorEffect(target:IUIComponent):void |
| { |
| cacheOrUncacheTargetAsBitmap(target, false, false); |
| } |
| |
| /** |
| * @private |
| * Cache or uncache the target as a bitmap depending on which effects are |
| * currently playing on the target. |
| * |
| * @param target The effect target. |
| * |
| * @param effectStart Whether this is the starting of the effect. |
| * false means it's the ending of the effect. |
| * |
| * @param bitmapEffect Whether this is a bitmap effect. |
| * false means it's a vector effect (like resize, zoom, etc.) |
| * that wants the target object to be uncached. |
| */ |
| private static function cacheOrUncacheTargetAsBitmap( |
| target:IUIComponent, |
| effectStart:Boolean = true, |
| bitmapEffect:Boolean = true):void |
| { |
| var n:int; |
| var i:int; |
| |
| // Object containing information about the target. |
| var info:Object = null; |
| |
| n = targetsInfo.length; |
| for (i = 0; i < n; i++) |
| { |
| if (targetsInfo[i].target == target) |
| { |
| info = targetsInfo[i]; |
| break; |
| } |
| } |
| |
| // If no info object is available, create an object and push it |
| // into the array. |
| if (!info) |
| { |
| info = |
| { |
| target: target, |
| bitmapEffectsCount: 0, |
| vectorEffectsCount: 0 |
| }; |
| |
| targetsInfo.push(info); |
| } |
| |
| if (effectStart) |
| { |
| if (bitmapEffect) |
| { |
| info.bitmapEffectsCount++; |
| |
| // If no vector effects are currently playing, |
| // cache the target. |
| if (info.vectorEffectsCount == 0 && |
| target is IDeferredInstantiationUIComponent) |
| { |
| IDeferredInstantiationUIComponent(target).cacheHeuristic = true; |
| } |
| } |
| else |
| { |
| // If a vector effect started playing, forcibly uncache |
| // the target regardless of anything else. |
| if (info.vectorEffectsCount++ == 0 && |
| target is IDeferredInstantiationUIComponent && |
| IDeferredInstantiationUIComponent(target).cachePolicy == UIComponentCachePolicy.AUTO) |
| { |
| target.cacheAsBitmap = false; |
| } |
| } |
| } |
| else // effect end |
| { |
| if (bitmapEffect) |
| { |
| if (info.bitmapEffectsCount != 0) |
| info.bitmapEffectsCount--; |
| |
| if (target is IDeferredInstantiationUIComponent) |
| IDeferredInstantiationUIComponent(target).cacheHeuristic = false; |
| } |
| else |
| { |
| if (info.vectorEffectsCount != 0) |
| { |
| // If no more vector effects are playing but bitmap |
| // effects are still playing, cache the target. |
| if (--info.vectorEffectsCount == 0 && |
| info.bitmapEffectsCount != 0) |
| { |
| // Crank up the counter. |
| n = info.bitmapEffectsCount; |
| for (i = 0; i < n; i++) |
| { |
| if (target is IDeferredInstantiationUIComponent) |
| IDeferredInstantiationUIComponent(target).cacheHeuristic = true; |
| } |
| } |
| } |
| } |
| |
| if (info.bitmapEffectsCount == 0 && info.vectorEffectsCount == 0) |
| { |
| // No more effects are playing on this target, so discard the |
| // info object (should speed up lookups). |
| n = targetsInfo.length; |
| for (i = 0; i < n; i++) |
| { |
| if (targetsInfo[i].target == target) |
| { |
| targetsInfo.splice(i, 1); |
| break; |
| } |
| } |
| } |
| } |
| } |
| |
| /** |
| * @private |
| * Called in code generated by MXML compiler. |
| */ |
| mx_internal static function registerEffectTrigger(name:String, |
| event:String):void |
| { |
| if (name != "") |
| { |
| if (event == "") |
| { |
| // For backwards compatibility. |
| var strLen:Number = name.length; |
| if (strLen > 6 && name.substring(strLen - 6) == "Effect") |
| event = name.substring(0, strLen - 6); |
| } |
| |
| if (event != "") |
| { |
| effectTriggersForEvent[event] = name; |
| eventsForEffectTriggers[name] = event; |
| } |
| } |
| } |
| |
| /** |
| * @private |
| */ |
| mx_internal static function getEventForEffectTrigger(effectTrigger:String):String |
| { |
| if (eventsForEffectTriggers) |
| { |
| try |
| { |
| return eventsForEffectTriggers[effectTrigger]; |
| } |
| catch(e:Error) {} |
| } |
| |
| return ""; |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Class event handlers |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * @private |
| */ |
| mx_internal static function eventHandler(eventObj:Event):void |
| { |
| // If this event fired because an effect is currently playing |
| // (in other words, if an effect was the source of this event), |
| // then don't listen to the effect. |
| if (!(eventObj.currentTarget is IFlexDisplayObject)) |
| return; |
| |
| if (eventHandlingSuspendCount > 0) |
| return; |
| |
| if (eventObj is FocusEvent && |
| (eventObj.type == FocusEvent.FOCUS_OUT || |
| eventObj.type == FocusEvent.FOCUS_IN)) |
| { |
| var focusEventObj:FocusEvent = FocusEvent(eventObj); |
| if (focusEventObj.relatedObject && |
| (focusEventObj.currentTarget.contains(focusEventObj.relatedObject) || |
| focusEventObj.currentTarget == focusEventObj.relatedObject)) |
| { |
| return; |
| } |
| } |
| |
| // Only trigger the event for added and removed if the current target is the same as the target. |
| if ((eventObj.type == Event.ADDED || eventObj.type == Event.REMOVED) && eventObj.target != eventObj.currentTarget) |
| return; |
| |
| if (eventObj.type == Event.REMOVED) |
| { |
| if (eventObj.target is UIComponent) |
| { |
| if (UIComponent(eventObj.target).initialized == false) |
| { |
| return; |
| } |
| else if (UIComponent(eventObj.target).isEffectStarted) |
| { |
| for (var i:int = 0; i < UIComponent(eventObj.target)._effectsStarted.length; i++) |
| { |
| // Don't allow removedEffect to trigger more than one effect at a time |
| if (UIComponent(eventObj.target)._effectsStarted[i].triggerEvent.type == Event.REMOVED) |
| return; |
| } |
| } |
| } |
| |
| var targ:DisplayObject = eventObj.target as DisplayObject; |
| |
| if (targ != null) |
| { |
| var parent:DisplayObjectContainer = targ.parent as DisplayObjectContainer; |
| |
| if (parent != null) |
| { |
| var index:int = parent.getChildIndex(targ); |
| if (index >= 0) |
| { |
| if (targ is UIComponent) |
| { |
| // Since we get the "removed" event before the child is actually removed, |
| // we need to delay adding back the child. We must exit the current |
| // script block must exit before the child can be removed. |
| UIComponent(targ).callLater(removedEffectHandler, [targ, parent, index, eventObj]); |
| } |
| } |
| } |
| } |
| } |
| else |
| { |
| createAndPlayEffect(eventObj, eventObj.currentTarget); |
| } |
| } |
| |
| /** |
| * @private |
| */ |
| private static function createAndPlayEffect(eventObj:Event, target:Object):void |
| { |
| |
| var effectInst:Effect = createEffectForType(target, eventObj.type); |
| if (!effectInst) |
| return; |
| |
| if (effectInst is Zoom && eventObj.type == MoveEvent.MOVE) |
| { |
| var message:String = resourceManager.getString( |
| "effects", "incorrectTrigger"); |
| throw new Error(message); |
| } |
| |
| // If this is a "move" or "resize" event that was caused by |
| // the layout manager doing an initial layout, then don't |
| // play any effects. |
| // Ditto for "show" or "hide" effects triggered by ViewStack.doLayout. |
| if (target.initialized == false) |
| { |
| var type:String = eventObj.type; |
| if (type == MoveEvent.MOVE || |
| type == ResizeEvent.RESIZE || |
| type == FlexEvent.SHOW || |
| type == FlexEvent.HIDE || |
| type == Event.CHANGE) |
| { |
| effectInst = null; |
| return; |
| } |
| } |
| |
| var n:int; |
| var i:int; |
| var m:int; |
| var j:int; |
| |
| // Some components contain built-in tweens, which are not managed by |
| // the EffectManager. If one of those tweens is currently playing, |
| // and if it's animating a conflicting property, then don't play this |
| // tween. |
| if (effectInst.target is IUIComponent) |
| { |
| var tweeningProperties:Array = |
| IUIComponent(effectInst.target).tweeningProperties; |
| if (tweeningProperties && tweeningProperties.length > 0) |
| { |
| var effectProperties:Array = effectInst.getAffectedProperties(); |
| |
| n = tweeningProperties.length; |
| m = effectProperties.length; |
| |
| for (i = 0; i < n; i++) |
| { |
| for (j = 0; j < m; j++) |
| { |
| if (tweeningProperties[i] == effectProperties[j]) |
| { |
| effectInst = null; |
| return; |
| } |
| } |
| } |
| } |
| } |
| |
| // At any given time, only one effect may be animating a given |
| // property of a given target object. If some other effect was |
| // previously animating the same properties of my target object, |
| // then finish the other effect before starting this new one. |
| // |
| if (effectInst.target is UIComponent && |
| UIComponent(effectInst.target).isEffectStarted) |
| { |
| var affectedProps:Array = effectInst.getAffectedProperties(); |
| for (i = 0; i < affectedProps.length; i++) |
| { |
| var runningInstances:Array = |
| effectInst.target.getEffectsForProperty(affectedProps[i]); |
| if (runningInstances.length > 0) |
| { |
| if (eventObj.type == ResizeEvent.RESIZE) |
| return; |
| |
| for (j = 0; j < runningInstances.length; j++) |
| { |
| var otherInst:EffectInstance = runningInstances[j]; |
| if (eventObj.type == FlexEvent.SHOW && otherInst.hideOnEffectEnd) |
| { |
| otherInst.target.removeEventListener( |
| FlexEvent.SHOW, otherInst.eventHandler); |
| otherInst.hideOnEffectEnd = false; |
| |
| } |
| |
| /* |
| if (eventObj.type == MoveEvent.MOVE && |
| ((affectedProps[i] == "width") || |
| (affectedProps[i] == "height") || |
| (affectedProps[i] == "x") || |
| (affectedProps[i] == "y")) && |
| effectInst.target.getStyle("moveEffect") != undefined) |
| { |
| trace("EM Got Move and ignoring"); |
| return; |
| } |
| |
| if (eventObj.type == ResizeEvent.RESIZE && |
| ((affectedProps[i] == "width") || |
| (affectedProps[i] == "height")) && |
| effectInst.target.getStyle("resizeEffect") != undefined) |
| { |
| return; |
| } |
| */ |
| |
| otherInst.end(); |
| } |
| } |
| } |
| } |
| |
| // Pass in event data for effect initialization |
| effectInst.triggerEvent = eventObj; |
| |
| // Tell the effectInst that I'm the listener, so that my "onEffectEnd" |
| // method is called when the effect finishes playing. The |
| // onEffectEnd handler will remove this effect from the effectsPlaying |
| // array. |
| effectInst.addEventListener(EffectEvent.EFFECT_END, |
| EffectManager.effectEndHandler); |
| |
| lastEffectCreated = effectInst; |
| |
| var instances:Array = effectInst.play(); |
| n = instances.length; |
| for (i = 0; i < n; i++) |
| { |
| effectsPlaying.push( |
| new EffectNode(effectInst, instances[i])); |
| } |
| |
| // Block all layout, responses from web services, and other background |
| // processing until the effect finishes executing. |
| if (effectInst.suspendBackgroundProcessing) |
| UIComponent.suspendBackgroundProcessing(); |
| } |
| |
| /** |
| * @private |
| * Delayed function call when effect is triggered by "removed" event |
| */ |
| private static function removedEffectHandler(target:DisplayObject, parent:DisplayObjectContainer, index:int, eventObj:Event):void |
| { |
| suspendEventHandling(); |
| // Add the child back to the parent so the effect can play upon it |
| if (parent is IVisualElementContainer && target is IVisualElement) |
| (IVisualElementContainer(parent).addElementAt(target as IVisualElement, index)); |
| else |
| parent.addChildAt(target, index); |
| resumeEventHandling(); |
| // Use target because the player assigns the Stage to the currentTarget when we leave the scope of the event handler function |
| createAndPlayEffect(eventObj, target); |
| } |
| |
| /** |
| * @private |
| * Internal function used while playing effects |
| */ |
| mx_internal static function effectEndHandler(event:EffectEvent):void |
| { |
| var effectInst:IEffectInstance = event.effectInstance; |
| // This function is called when an effect, which was started |
| // earlier by this effect manager, finishes playing. Remove |
| // this effect from the "effectPlaying" list |
| var n:int = effectsPlaying.length; |
| for (var i:int = n - 1; i >= 0; i--) |
| { |
| if (effectsPlaying[i].instance == effectInst) |
| { |
| effectsPlaying.splice(i, 1); |
| break; |
| } |
| } |
| |
| // If the event that caused this effect was "hide", then the |
| // eventHandler() method set the object's visiblity to true. |
| // Now that the effect is finished playing, set visiblity to false. |
| if (Object(effectInst).hideOnEffectEnd == true) |
| { |
| effectInst.target.removeEventListener( |
| FlexEvent.SHOW, Object(effectInst).eventHandler); |
| effectInst.target.setVisible(false, true); |
| } |
| |
| if (effectInst.triggerEvent && effectInst.triggerEvent.type == Event.REMOVED) |
| { |
| var targ:DisplayObject = effectInst.target as DisplayObject; |
| |
| if (targ != null) |
| { |
| var parent:DisplayObjectContainer = targ.parent as DisplayObjectContainer; |
| |
| if (parent != null) |
| { |
| // Since we added the child back to the parent when the effect began, |
| // we need to remove it once the effect has finished. |
| suspendEventHandling(); |
| if (parent is IVisualElementContainer && targ is IVisualElement) |
| (IVisualElementContainer(parent).removeElement(targ as IVisualElement)); |
| else |
| parent.removeChild(targ); |
| resumeEventHandling(); |
| } |
| } |
| } |
| |
| // Resume the background processing that was suspended earlier |
| if (effectInst.suspendBackgroundProcessing) |
| UIComponent.resumeBackgroundProcessing(); |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Diagnostics |
| // |
| //-------------------------------------------------------------------------- |
| private static var effects:Dictionary = new Dictionary(true); |
| |
| mx_internal static function effectStarted(effect:EffectInstance):void |
| { |
| effects[effect] = 1; |
| } |
| |
| mx_internal static function effectFinished(effect:EffectInstance):void |
| { |
| delete effects[effect]; |
| } |
| |
| mx_internal static function effectsInEffect():Boolean |
| { |
| for (var i:* in effects) |
| { |
| return true; |
| } |
| return false; |
| } |
| } |
| |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // |
| // Helper class: EffectNode |
| // |
| //////////////////////////////////////////////////////////////////////////////// |
| |
| import mx.effects.Effect; |
| import mx.effects.EffectInstance; |
| |
| /** |
| * @private |
| */ |
| class EffectNode |
| { |
| //-------------------------------------------------------------------------- |
| // |
| // Constructor |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * Constructor. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public function EffectNode(factory:Effect, instance:EffectInstance) |
| { |
| super(); |
| |
| this.factory = factory; |
| this.instance = instance; |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Properties |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * @private |
| */ |
| public var factory:Effect; |
| |
| /** |
| * @private |
| */ |
| public var instance:EffectInstance; |
| } |