1////////////////////////////////////////////////////////////////////////////////
2//
3//  ADOBE SYSTEMS INCORPORATED
4//  Copyright 2005-2007 Adobe Systems Incorporated
5//  All Rights Reserved.
6//
7//  NOTICE: Adobe permits you to use, modify, and distribute this file
8//  in accordance with the terms of the license agreement accompanying it.
9//
10////////////////////////////////////////////////////////////////////////////////
11
12package mx.effects.effectClasses
13{
14
15import flash.display.BitmapData;
16import flash.display.DisplayObject;
17import flash.display.Graphics;
18import flash.display.Shape;
19import flash.events.Event;
20import flash.filters.DropShadowFilter;
21import flash.geom.Matrix;
22import flash.geom.Rectangle;
23import flash.utils.getTimer;
24import mx.controls.SWFLoader;
25import mx.core.Container;
26import mx.core.FlexShape;
27import mx.core.IInvalidating;
28import mx.core.IUIComponent;
29import mx.core.mx_internal;
30import mx.effects.EffectInstance;
31import mx.effects.EffectManager;
32import mx.effects.Tween;
33import mx.events.FlexEvent;
34import mx.events.ResizeEvent;
35import mx.events.TweenEvent;
36
37use namespace mx_internal;
38
39/**
40 *  The MaskEffectInstance class is an abstract base class
41 *  that implements the instance class for
42 *  the MaskEffect class.
43 *  <p>Every effect class that is a subclass of the TweenEffect class
44 *  supports the following events:</p>
45 *
46 *  <ul>
47 *    <li><code>tweenEnd</code>: Dispatched when the tween effect ends. </li>
48 *
49 *    <li><code>tweenUpdate</code>: Dispatched every time a TweenEffect
50 *      class calculates a new value.</li>
51 *  </ul>
52 *
53 *  <p>The event object passed to the event listener for these events is of type TweenEvent.
54 *  The TweenEvent class defines the property <code>value</code>, which contains
55 *  the tween value calculated by the effect.
56 *  For the Mask effect,
57 *  the <code>TweenEvent.value</code> property contains a 4-item Array, where: </p>
58 *  <ul>
59 *    <li>value[0]:Number  The value of the target's <code>x</code> property.</li>
60 *
61 *    <li>value[1]:Number  The value of the target's <code>y</code> property.</li>
62 *
63 *    <li>value[2]:Number  The value of the target's <code>scaleX</code> property.</li>
64 *
65 *    <li>value[3]:Number  The value of the target's <code>scaleY</code> property.</li>
66 *  </ul>
67 *
68 *  @see mx.effects.MaskEffect
69 *  @see mx.events.TweenEvent
70 */
71public class MaskEffectInstance extends EffectInstance
72{
73    include "../../core/Version.as";
74
75	//--------------------------------------------------------------------------
76	//
77	//  Constructor
78	//
79	//--------------------------------------------------------------------------
80
81	/**
82	 *  Constructor.
83	 *
84	 *  @param target The Object to animate with this effect.
85	 */
86	public function MaskEffectInstance(target:Object)
87	{
88		super(target);
89	}
90
91	//--------------------------------------------------------------------------
92	//
93	//  Variables
94	//
95	//--------------------------------------------------------------------------
96
97	/**
98	 *  Contains the effect mask, either the default mask created
99	 *  by the <code>defaultCreateMask()</code> method,
100	 *  or the one specified by the function passed to the
101	 *  <code>createMaskFunction</code> property.
102	 */
103	protected var effectMask:Shape;
104
105	/**
106	 *  The actual size of the effect target, including any drop shadows.
107	 *  Flex calculates the value of this property; you do not have to set it.
108	 */
109	protected var targetVisualBounds:Rectangle;
110
111	/**
112	 *  @private
113	 */
114	private var effectMaskRefCount:Number = 0;
115
116	/**
117	 *  @private
118	 */
119	private var invalidateBorder:Boolean = false;
120
121	/**
122	 *  @private
123	 */
124	private var moveTween:Tween;
125
126	/**
127	 *  @private
128	 */
129	private var origMask:DisplayObject;
130
131	/**
132	 *  @private
133	 */
134	private var origScrollRect:Rectangle;
135
136	/**
137	 *  @private
138	 */
139	private var scaleTween:Tween;
140
141	/**
142	 *  @private
143	 */
144	private var tweenCount:int = 0;
145
146	/**
147	 *  @private
148	 */
149	private var currentMoveTweenValue:Object;
150
151	/**
152	 *  @private
153	 */
154	private var currentScaleTweenValue:Object;
155
156	/**
157	 *  @private
158	 */
159	private var MASK_NAME:String = "_maskEffectMask";
160
161	/**
162	 *  @private
163	 */
164	private var dispatchedStartEvent:Boolean = false;
165
166	/**
167	 *  @private
168	 */
169	private var useSnapshotBounds:Boolean = true;
170
171	/**
172	 *  @private
173	 */
174	private var stoppedEarly:Boolean = false;
175
176	/**
177	 *  @private
178	 */
179	mx_internal var persistAfterEnd:Boolean = false;
180
181	//--------------------------------------------------------------------------
182	//
183	//  Properties
184	//
185	//--------------------------------------------------------------------------
186
187	//--------------------------------------------------------------------------
188	//  createMaskFunction
189	//--------------------------------------------------------------------------
190
191	/**
192	 *  @private
193	 *  Storage for the createMaskFunction property.
194	 */
195	private var _createMaskFunction:Function;
196
197	/**
198	 *  Function called when the effect creates the mask.
199	 *  The default value is a function that returns a Rectangle
200	 *  with the same dimensions as the effect target.
201	 *
202	 *  <p>You can use this property to specify your own callback function to draw the mask.
203	 *  The function must have the following signature:</p>
204	 *
205	 *  <pre>
206	 *  public function createLargeMask(targ:Object, bounds:Rectangle):Shape {
207	 *    var myMask:Shape = new Shape();
208	 *    // Create mask.
209	 *
210	 *    return myMask;
211	 *  }
212	 *  </pre>
213	 *
214	 *  <p>You set this property to the name of the function,
215	 *  as the following example shows for the WipeLeft effect:</p>
216	 *
217	 *  <pre>
218	 *    &lt;mx:WipeLeft id="showWL" createMaskFunction="createLargeMask" showTarget="false"/&gt;</pre>
219	 */
220	public function get createMaskFunction():Function
221	{
222		return _createMaskFunction != null ?
223			   _createMaskFunction :
224			   defaultCreateMask;
225	}
226
227	/**
228	 *  @private
229	 */
230	public function set createMaskFunction(value:Function):void
231	{
232		_createMaskFunction = value;
233	}
234
235	//----------------------------------
236	//  moveEasingFunction
237	//----------------------------------
238
239	/**
240	 *  Easing function to use for moving the mask.
241	 */
242	public var moveEasingFunction:Function;
243
244	//--------------------------------------------------------------------------
245	//  playheadTime
246	//--------------------------------------------------------------------------
247
248	/**
249	 *  @private
250	 */
251	override public function get playheadTime():Number
252	{
253		var value:Number;
254
255		if (moveTween)
256			value = moveTween.mx_internal::playheadTime;
257
258		else if (scaleTween)
259			value = scaleTween.mx_internal::playheadTime;
260
261		else
262			return 0;
263
264		return value + super.playheadTime;
265
266	}
267
268	//--------------------------------------------------------------------------
269	//  playReversed
270	//--------------------------------------------------------------------------
271
272	/**
273	 *  @private
274	 */
275	override mx_internal function set playReversed(value:Boolean):void
276	{
277		if (moveTween)
278			moveTween.playReversed = value;
279
280		if (scaleTween)
281			scaleTween.playReversed = value;
282
283		super.playReversed = value;
284	}
285
286	//----------------------------------
287	//  scaleEasingFunction
288	//----------------------------------
289
290	/**
291	 *  Easing function to use for scaling the mask.
292	 */
293	public var scaleEasingFunction:Function;
294
295	//----------------------------------
296	//  scaleXFrom
297	//----------------------------------
298
299	/**
300	 *  Initial scaleX for mask.
301	 */
302	public var scaleXFrom:Number;
303
304	//----------------------------------
305	//  scaleXTo
306	//----------------------------------
307
308	/**
309	 *  Ending scaleX for mask.
310	 */
311	public var scaleXTo:Number;
312
313	//----------------------------------
314	//  scaleYFrom
315	//----------------------------------
316
317	/**
318	 *  Initial scaleY for mask.
319	 */
320	public var scaleYFrom:Number;
321
322	//----------------------------------
323	//  scaleYTo
324	//----------------------------------
325
326	/**
327	 *  Ending scaleY for mask.
328	 */
329	public var scaleYTo:Number;
330
331	//----------------------------------
332	//  showTarget
333	//----------------------------------
334
335	[Inspectable(category="General", defaultValue="true")]
336
337	/**
338	 *  @private
339	 *  Storage for the showTarget property.
340	 */
341	private var _showTarget:Boolean = true;
342
343	/**
344	 *  @private
345	 */
346	private var _showExplicitlySet:Boolean = false;
347
348	/**
349     *  Specifies that the target component is becoming visible,
350     *  <code>false</code>, or invisible, <code>true</code>.
351	 *
352	 *  @default true
353	 */
354	public function get showTarget():Boolean
355	{
356		return _showTarget;
357	}
358
359	/**
360	 *  @private
361	 */
362	public function set showTarget(value:Boolean):void
363	{
364		_showTarget = value;
365		_showExplicitlySet = true;
366	}
367
368	//----------------------------------
369	//  targetArea
370	//----------------------------------
371
372	/**
373	 *  The area where the mask is applied on the target.
374	 *  The dimensions are relative to the target itself.
375	 *  By default, the area is the entire target and is created like this:
376	 *  <code>new Rectangle(0, 0, target.width, target.height);</code>
377	 */
378	public var targetArea:Rectangle;
379
380	//----------------------------------
381	//  xFrom
382	//----------------------------------
383
384	/**
385	 *  Initial position's x coordinate for mask.
386	 */
387	public var xFrom:Number;
388
389	//----------------------------------
390	//  xTo
391	//----------------------------------
392
393	/**
394	 *  Destination position's x coordinate for mask.
395	 */
396	public var xTo:Number;
397
398	//----------------------------------
399	//  yFrom
400	//----------------------------------
401
402	/**
403	 *  Initial position's y coordinate for mask.
404	 */
405	public var yFrom:Number;
406
407	//----------------------------------
408	//  yTo
409	//----------------------------------
410
411	/**
412	 *  Destination position's y coordinate for mask.
413	 */
414	public var yTo:Number;
415
416	//--------------------------------------------------------------------------
417	//
418	//  Overridden methods
419	//
420	//--------------------------------------------------------------------------
421
422	/**
423	 *  @private
424	 */
425	override public function initEffect(event:Event):void
426	{
427		super.initEffect(event);
428
429		switch (event.type)
430		{
431			case "childrenCreationComplete":
432			case FlexEvent.CREATION_COMPLETE:
433			case FlexEvent.SHOW:
434			case Event.ADDED:
435			case "resizeEnd":
436			{
437				showTarget = true;
438				break;
439			}
440
441			case FlexEvent.HIDE:
442			case Event.REMOVED:
443			case "resizeStart":
444			{
445				showTarget = false;
446				break;
447			}
448			case Event.RESIZE:
449			{
450				// don't use the snapshot because it will be the wrong size
451				useSnapshotBounds = false;
452				break;
453			}
454		}
455	}
456
457	/**
458	 *  @private
459	 */
460	override public function startEffect():void
461	{
462		// Init the mask only once when the effect is played.
463		initMask();
464
465		// Register to be notified if the target object is resized.
466		target.addEventListener(ResizeEvent.RESIZE, eventHandler);
467
468		// This will call playEffect eventually.
469		super.startEffect();
470	}
471
472	/**
473	 *  @private
474	 */
475	override public function play():void
476	{
477		super.play();
478
479		// This allows the MaskEffect subclass to set the effect properties.
480		initMaskEffect();
481
482		EffectManager.mx_internal::startVectorEffect(IUIComponent(target));
483
484		//EffectManager.mx_internal::startBitmapEffect(target);
485
486		// Move Tween
487
488		if (!isNaN(xFrom) &&
489			!isNaN(yFrom) &&
490			!isNaN(xTo) &&
491			!isNaN(yTo))
492		{
493			tweenCount++;
494
495			moveTween = new Tween(this, [ xFrom, yFrom ],
496								  [ xTo, yTo ], duration,
497								  -1, onMoveTweenUpdate, onMoveTweenEnd);
498
499			moveTween.playReversed = playReversed;
500
501			// If the caller supplied their own easing equation, override the
502			// one that's baked into Tween.
503			if (moveEasingFunction != null)
504				moveTween.easingFunction = moveEasingFunction;
505
506
507		}
508
509		// Scale Tween
510
511		if (!isNaN(scaleXFrom) &&
512			!isNaN(scaleYFrom) &&
513			!isNaN(scaleXTo) &&
514			!isNaN(scaleYTo))
515		{
516			tweenCount++;
517
518			scaleTween = new Tween(this, [ scaleXFrom, scaleYFrom ],
519								   [ scaleXTo, scaleYTo ], duration,
520								   -1, onScaleTweenUpdate, onScaleTweenEnd);
521
522			scaleTween.playReversed = playReversed;
523
524			// If the caller supplied their own easing equation, override the
525			// one that's baked into Tween.
526			if (scaleEasingFunction != null)
527				scaleTween.easingFunction = scaleEasingFunction;
528		}
529
530		dispatchedStartEvent = false;
531
532		// Call these after tween creation so that saveTweenValues knows which values to dispatch
533		if (moveTween)
534		{
535			// Set the animation to the initial value
536			// before the screen refreshes.
537			onMoveTweenUpdate(moveTween.mx_internal::getCurrentValue(0));
538		}
539
540		if (scaleTween)
541		{
542			// Set the animation to the initial value
543			// before the screen refreshes.
544			onScaleTweenUpdate(scaleTween.mx_internal::getCurrentValue(0));
545		}
546	}
547
548	/**
549	 *  Pauses the effect until you call the <code>resume()</code> method.
550	 */
551	override public function pause():void
552	{
553		super.pause();
554
555		if (moveTween)
556			moveTween.pause();
557
558		if (scaleTween)
559			scaleTween.pause();
560	}
561
562	/**
563	 *  @private
564	 */
565	override public function stop():void
566	{
567		stoppedEarly = true;
568		super.stop();
569
570		if (moveTween)
571			moveTween.stop();
572
573		if (scaleTween)
574			scaleTween.stop();
575	}
576
577	/**
578	 *  Resumes the effect after it has been paused
579	 *  by a call to the <code>pause()</code> method.
580	 */
581	override public function resume():void
582	{
583		super.resume();
584
585		if (moveTween)
586			moveTween.resume();
587
588		if (scaleTween)
589			scaleTween.resume();
590	}
591
592	/**
593	 *  Plays the effect in reverse,
594	 *  starting from the current position of the effect.
595	 */
596	override public function reverse():void
597	{
598		super.reverse();
599
600		if (moveTween)
601			moveTween.reverse();
602
603		if (scaleTween)
604			scaleTween.reverse();
605
606		super.playReversed = !playReversed;
607	}
608
609	/**
610	 *  @private
611	 */
612	override public function end():void
613	{
614		stopRepeat = true;
615
616		if (moveTween)
617			moveTween.endTween();
618
619		if (scaleTween)
620			scaleTween.endTween();
621	}
622
623	/**
624	 *  @private
625	 */
626	override public function finishEffect():void
627	{
628		target.removeEventListener(ResizeEvent.RESIZE, eventHandler);
629
630		if (!persistAfterEnd && !stoppedEarly)
631			removeMask();
632
633		super.finishEffect();
634	}
635
636	//--------------------------------------------------------------------------
637	//
638	//  Methods
639	//
640	//--------------------------------------------------------------------------
641
642	/**
643	 *  @private
644	 */
645	private function initMask():void
646	{
647		if (!effectMask)
648		{
649			if (useSnapshotBounds)
650				targetVisualBounds = getVisibleBounds(DisplayObject(target));
651			else
652				targetVisualBounds = new Rectangle(0, 0, target.width, target.height);
653			effectMask = createMaskFunction(target, targetVisualBounds);
654
655			// For Containers we need to add the mask
656			// to the "allChildren" collection so it doesn't get
657			// treated as a content child.
658			if (target is Container)
659				target.rawChildren.addChild(effectMask);
660			else
661				target.addChild(effectMask);
662
663			effectMask.name = MASK_NAME;
664			effectMaskRefCount = 0;
665		}
666
667		effectMask.x = 0;
668		effectMask.y = 0;
669		effectMask.alpha = .3;
670		effectMask.visible = false;
671
672		// If this object already had a transparency mask, then save off
673		// the original mask, so that we can restore it when we're done.
674		if (effectMaskRefCount++ == 0)
675		{
676			if (target.mask)
677				origMask = target.mask;
678
679			target.mask = effectMask;
680
681			if (target.scrollRect)
682			{
683				origScrollRect = target.scrollRect;
684				target.scrollRect = null;
685			}
686		}
687
688		invalidateBorder = target is Container &&
689						   Container(target).border != null &&
690						   Container(target).border is IInvalidating &&
691						   DisplayObject(Container(target).border).filters != null;
692	}
693
694	/**
695	 *  Creates the default mask for the effect.
696	 *
697	 *  @param targ The effect target.
698	 *  @param bounds The actual visual bounds of the target which includes drop shadows
699	 *
700	 *  @return A Shape object that defines the mask.
701	 */
702	protected function defaultCreateMask(targ:Object, bounds:Rectangle):Shape
703	{
704		// By default, create a mask that is the shape of the target.
705		var targetWidth:Number = bounds.width / Math.abs(targ.scaleX);
706		var targetHeight:Number = bounds.height / Math.abs(targ.scaleY);
707
708		if (targ is SWFLoader)
709		{
710			// Make sure the loader's content has been sized
711			targ.validateDisplayList();
712			if (targ.content)
713			{
714				targetWidth = targ.contentWidth;
715				targetHeight = targ.contentHeight;
716			}
717		}
718
719		var newMask:Shape = new FlexShape();
720
721		var g:Graphics = newMask.graphics;
722		g.beginFill(0xFFFF00);
723		g.drawRect(0, 0, targetWidth, targetHeight);
724		g.endFill();
725
726		if (target.rotation == 0)
727		{
728			newMask.width = targetWidth;
729			newMask.height = targetHeight;
730		}
731		else
732		{
733			var angle:Number = targ.rotation * Math.PI / 180;
734
735			var sin:Number = Math.sin(angle);
736			var cos:Number = Math.cos(angle);
737
738			newMask.width =  Math.abs(targetWidth * cos - targetHeight * sin);
739			newMask.height = Math.abs(targetWidth * sin + targetHeight * cos);
740		}
741
742		return newMask;
743	}
744
745	/**
746	 *  Initializes the <code>move</code> and <code>scale</code>
747	 *  properties of the effect.
748	 *  All subclasses should override this function.
749	 *  Flex calls it after the mask has been created,
750	 *  but before the tweens are created.
751	 */
752	protected function initMaskEffect():void
753	{
754		if (!_showExplicitlySet &&
755			propertyChanges &&
756			propertyChanges.start["visible"] !== undefined)
757		{
758			_showTarget = !propertyChanges.start["visible"];
759		}
760	}
761
762	/**
763	 *  @private
764	 *  Returns a rectangle that describes the visible region of the component, including any dropshadows
765	 */
766	private function getVisibleBounds(targ:DisplayObject):Rectangle
767	{
768		var bitmap:BitmapData = new BitmapData(targ.width + 200, targ.height + 200, true, 0x00000000);
769		var m:Matrix = new Matrix();
770		m.translate(100, 100);
771		bitmap.draw(targ, m);
772		var actualBounds:Rectangle = bitmap.getColorBoundsRect(0xFF000000, 0x00000000, false);
773
774		actualBounds.x = actualBounds.x - 100;
775		actualBounds.y = actualBounds.y - 100;
776
777		bitmap.dispose();
778
779		if (actualBounds.width < targ.width)
780		{
781			actualBounds.width = targ.width;
782			actualBounds.x = 0;
783		}
784		if (actualBounds.height < targ.height)
785		{
786			actualBounds.height = targ.height;
787			actualBounds.y = 0;
788		}
789
790		return actualBounds;
791	}
792
793	/**
794	 *  Callback method that is called when the x and y position
795	 *  of the mask should be updated by the effect.
796	 *  You do not call this method directly.
797     *  This method implements the method of the superclass.
798     *
799 	 *  @param value Contains an interpolated
800	 *  x and y value for the mask position, where <code>value[0]</code>
801	 *  contains the new x position of the mask,
802	 *  and <code>value[1]</code> contains the new y position.
803	 */
804	protected function onMoveTweenUpdate(value:Object):void
805	{
806		saveTweenValue(value,null);
807
808		if (effectMask)
809		{
810			effectMask.x = value[0];
811			effectMask.y = value[1];
812		}
813
814		if (invalidateBorder)
815			IInvalidating(Container(target).border).invalidateDisplayList();
816	}
817
818	/**
819	 *  Callback method that is called when the x and y position
820	 *  of the mask should be updated by the effect for the last time.
821	 *  You do not call this method directly.
822     *  This method implements the method of the superclass.
823     *
824 	 *  @param value Contains the final
825	 *  x and y value for the mask position, where <code>value[0]</code>
826	 *  contains the x position of the mask,
827	 *  and <code>value[1]</code> contains the y position.
828	 */
829	protected function onMoveTweenEnd(value:Object):void
830	{
831		onMoveTweenUpdate(value);
832
833		finishTween();
834	}
835
836	/**
837	 *  Callback method that is called when the
838	 *  <code>scaleX</code> and <code>scaleY</code> properties
839	 *  of the mask should be updated by the effect.
840	 *  You do not call this method directly.
841     *  This method implements the method of the superclass.
842     *
843 	 *  @param value Contains an interpolated
844	 *  <code>scaleX</code> and <code>scaleY</code> value for the mask,
845	 *  where <code>value[0]</code>
846	 *  contains the new <code>scaleX</code> value of the mask,
847	 *  and <code>value[1]</code> contains the new <code>scaleY</code> value.
848	 */
849	protected function onScaleTweenUpdate(value:Object):void
850	{
851		saveTweenValue(null, value);
852
853		if (effectMask)
854		{
855			effectMask.scaleX = value[0];
856			effectMask.scaleY = value[1];
857		}
858	}
859
860	/**
861	 *  Callback method that is called when the
862	 *  <code>scaleX</code> and <code>scaleY</code> properties
863	 *  of the mask should be updated by the effect for the last time.
864	 *  You do not call this method directly.
865     *  This method implements the method of the superclass.
866     *
867 	 *  @param value Contains the final
868	 *  <code>scaleX</code> and <code>scaleY</code> value for the mask,
869	 *  where <code>value[0]</code>
870	 *  contains the <code>scaleX</code> value of the mask,
871	 *  and <code>value[1]</code> contains the <code>scaleY</code> value.
872	 */
873	protected function onScaleTweenEnd(value:Object):void
874	{
875		onScaleTweenUpdate(value);
876
877		finishTween();
878	}
879
880	/**
881	 *  @private
882	 */
883	private function finishTween():void
884	{
885		if (tweenCount == 0 || --tweenCount == 0)
886		{
887			EffectManager.mx_internal::endVectorEffect(IUIComponent(target));
888
889			var values:Array = [];
890			var value:Object;
891			if (moveTween)
892			{
893				value = moveTween.getCurrentValue(duration);
894				values.push(value[0]);
895				values.push(value[1]);
896			}
897			else
898			{
899				values.push(null);
900				values.push(null);
901			}
902
903			if (scaleTween)
904			{
905				value = scaleTween.getCurrentValue(duration);
906				values.push(value[0]);
907				values.push(value[1]);
908			}
909			else
910			{
911				values.push(null);
912				values.push(null);
913			}
914
915			dispatchEvent(new TweenEvent(TweenEvent.TWEEN_END, false, false, values));
916
917			finishRepeat();
918		}
919	}
920
921	/**
922	 *  @private
923	 */
924	private function removeMask():void
925	{
926		// Although it wasn't the original intended design, it turns out that
927		// two mask effects can play simultaneously inside a <parallel> effect.
928		// The only gotcha is that we shouldn't clear the mask until both
929		// effects are done.  The solution: a reference count.
930		if (--effectMaskRefCount == 0)
931		{
932			if (origMask == null || (origMask && origMask.name != MASK_NAME))
933				target.mask = origMask;
934
935			if (origScrollRect)
936			{
937				target.scrollRect = origScrollRect;
938			}
939
940			if (target is Container)
941				target.rawChildren.removeChild(effectMask);
942			else
943				target.removeChild(effectMask);
944
945			effectMask = null;
946		}
947	}
948
949	/**
950	 *  @private
951	 */
952	private function saveTweenValue(moveValue:Object, scaleValue:Object):void
953	{
954		if (moveValue != null)
955		{
956			currentMoveTweenValue = moveValue;
957		}
958		else if (scaleValue != null)
959		{
960			currentScaleTweenValue = scaleValue;
961		}
962
963		if ((moveTween == null || currentMoveTweenValue != null)
964			&& (scaleTween == null || currentScaleTweenValue != null))
965		{
966			var values:Array = [];
967			if (currentMoveTweenValue)
968			{
969				values.push(currentMoveTweenValue[0]);
970				values.push(currentMoveTweenValue[1]);
971			}
972			else
973			{
974				values.push(null);
975				values.push(null);
976			}
977
978			if (currentScaleTweenValue)
979			{
980				values.push(currentScaleTweenValue[0]);
981				values.push(currentScaleTweenValue[1]);
982			}
983			else
984			{
985				values.push(null);
986				values.push(null);
987			}
988
989			if (!dispatchedStartEvent)
990			{
991				dispatchEvent(new TweenEvent(TweenEvent.TWEEN_START));
992				dispatchedStartEvent = true;
993			}
994
995			dispatchEvent(new TweenEvent(TweenEvent.TWEEN_UPDATE, false, false, values));
996
997			currentMoveTweenValue = null;
998			currentScaleTweenValue = null;
999		}
1000	}
1001
1002	//--------------------------------------------------------------------------
1003	//
1004	//  Overridden event handlers
1005	//
1006	//--------------------------------------------------------------------------
1007
1008	/**
1009	 *  @private
1010	 */
1011	override mx_internal function eventHandler(event:Event):void
1012	{
1013		super.eventHandler(event);
1014
1015		// This function is called if the target object is resized.
1016		if (event.type == ResizeEvent.RESIZE)
1017		{
1018			var tween:Tween = moveTween;
1019			if (!tween && scaleTween)
1020				tween = scaleTween;
1021
1022			if (tween)
1023			{
1024				// Remember the amount of the effect that has already been
1025				// played.
1026				var elapsed:Number = getTimer() - tween.mx_internal::startTime;
1027
1028				// Destroy the old tween object. Set its listener to a dummy
1029				// object, so that the onTweenEnd function is not called.
1030				if (moveTween)
1031					Tween.mx_internal::removeTween(moveTween);
1032
1033				if (scaleTween)
1034					Tween.mx_internal::removeTween(scaleTween);
1035
1036				// Reset the tween count
1037				tweenCount = 0;
1038				removeMask();
1039
1040				// The onTweenEnd function wasn't called, so decrement the
1041				// effectMaskRefCount here to keep it in balance.
1042				//effectMaskRefCount--;
1043				// Restart the effect and create a new mask.  This is necessary
1044				// so that the mask's size matches the target object's new size.
1045				initMask();
1046				play();
1047
1048				// Set the tween's clock, so that it thinks 'elapsed'
1049				// milliseconds of the animation have already played.
1050				if (moveTween)
1051				{
1052					moveTween.mx_internal::startTime -= elapsed;
1053					// Update the screen before a repaint occurs
1054					moveTween.mx_internal::doInterval();
1055				}
1056
1057				if (scaleTween)
1058				{
1059					scaleTween.mx_internal::startTime -= elapsed;
1060					// Update the screen before a repaint occurs
1061					scaleTween.mx_internal::doInterval();
1062				}
1063			}
1064		}
1065	}
1066}
1067
1068}
1069