1////////////////////////////////////////////////////////////////////////////////
2//
3//  ADOBE SYSTEMS INCORPORATED
4//  Copyright 2010 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 spark.transitions
13{
14
15import flash.display.BlendMode;
16import flash.display.DisplayObjectContainer;
17import flash.events.Event;
18import flash.geom.Point;
19
20import mx.core.UIComponent;
21import mx.core.mx_internal;
22import mx.effects.Fade;
23import mx.effects.IEffect;
24import mx.effects.Parallel;
25
26import spark.components.Group;
27import spark.effects.Scale;
28import spark.primitives.BitmapImage;
29
30use namespace mx_internal;
31
32/**
33 *  The ZoomViewTransition class performs a zoom in or out transition for views.
34 *  It performs its transition by zooming out the existing view to reveal
35 *  the new view, or by zooming in the new view to cover the existing view.
36 *
37 *  <p>The default duration of a ZoomViewTransition is 350ms.
38 *  Also, by default it transitions the control bar and view content
39 *  as one as if <code>transitionControlsWithContent</code> is  <code>true</code>. </p>
40 *
41 *  <p><strong>Note:</strong>Create and configure view transitions in ActionScript;
42 *  you cannot create them in MXML.</p>
43 *
44 *  @see ZoomViewTransitionMode
45 *
46 *  @langversion 3.0
47 *  @playerversion AIR 2.5
48 *  @productversion Flex 4.5
49 */
50[Deprecated(since="4.6")]
51public class ZoomViewTransition extends ViewTransitionBase
52{
53    //--------------------------------------------------------------------------
54    //
55    //  Constructor
56    //
57    //--------------------------------------------------------------------------
58
59    /**
60     *  Constructor.
61     *
62     *  @langversion 3.0
63     *  @playerversion AIR 2.5
64     *  @productversion Flex 4.5
65     */
66    public function ZoomViewTransition()
67    {
68        super();
69
70        // Default duration of 350 yields a smoother result.
71        duration = 350;
72
73        // Default to transitioning control bars with our views.
74        transitionControlsWithContent = true;
75    }
76
77    //--------------------------------------------------------------------------
78    //
79    //  Variables
80    //
81    //--------------------------------------------------------------------------
82
83    /**
84     *  @private
85     *  Property bag used to save any start view properties that
86     *  are then restored after the transition is complete.
87     */
88    private var startViewProps:Object;
89
90    /**
91     *  @private
92     *  Property bag used to save any end view properties that
93     *  are then restored after the transition is complete.
94     */
95    private var endViewProps:Object;
96
97    /**
98     *  @private
99     */
100    private var transitionGroup:Group;
101
102    /**
103     *  @private
104     */
105    private var savedCacheAsBitmap:Boolean;
106
107    /**
108     *  @private
109     */
110    private var scaleEffect:Scale;
111
112    /**
113     *  @private
114     */
115    private var targetSnapshot:BitmapImage;
116
117    /**
118     *  @private
119     *  Stores the location of the cached navigator in the global coordinate space
120     *  so that the transition can properly position it when added to the display list.
121     */
122    private var targetSnapshotGlobalPosition:Point = new Point();
123
124    /**
125     *  @private
126     */
127    private var cachedNavigatorGroup:Group;
128
129    //--------------------------------------------------------------------------
130    //
131    //  Properties
132    //
133    //--------------------------------------------------------------------------
134
135    //---------------------------------
136    // minimumScale
137    //---------------------------------
138
139    private var _minimumScale:Number = .25;
140
141    /**
142     *  Specifies the minimum scale of the zoomed view (represents when the
143     *  view is first visible when zooming in or last visible when zooming
144     *  out).
145     *
146     *  @default .25
147     *
148     *  @langversion 3.0
149     *  @playerversion AIR 2.5
150     *  @productversion Flex 4.5
151     */
152    public function get minimumScale():Number
153    {
154        return _minimumScale;
155    }
156
157    /**
158     *  @private
159     */
160    public function set minimumScale(value:Number):void
161    {
162        _minimumScale = value;
163    }
164
165    //---------------------------------
166    // mode
167    //---------------------------------
168
169    private var _mode:String = "out"; // avoid deprecation warning for ZoomViewTransitionMode.OUT;
170
171    [Inspectable(category="General", enumeration="in,out", defaultValue="out")]
172    /**
173     *  Specifies the type of zoom transition to perform.
174     *
175     *  @default ZoomTransitionMode.OUT
176     *
177     *  @langversion 3.0
178     *  @playerversion AIR 2.5
179     *  @productversion Flex 4.5
180     */
181    public function get mode():String
182    {
183        return _mode;
184    }
185
186    /**
187     *  @private
188     */
189    public function set mode(value:String):void
190    {
191        _mode = value;
192    }
193
194    //--------------------------------------------------------------------------
195    //
196    //  Methods
197    //
198    //--------------------------------------------------------------------------
199
200    /**
201     *  @private
202     *
203     *  @langversion 3.0
204     *  @playerversion AIR 2.5
205     *  @productversion Flex 4.5
206     */
207    override public function captureStartValues():void
208    {
209        // Suppress the default action bar transition, not really
210        // appropriate for the zoom.
211        actionBarTransitionMode = ViewTransitionBase.ACTION_BAR_MODE_NONE;
212
213        super.captureStartValues();
214
215        var oldVisibility:Boolean = endView.visible;
216        endView.visible = false;
217        cachedNavigator = getSnapshot(targetNavigator, 0, cachedNavigatorGlobalPosition);
218        endView.visible = oldVisibility;
219    }
220
221    /**
222     *  @private
223     *
224     *  @langversion 3.0
225     *  @playerversion AIR 2.5
226     *  @productversion Flex 4.5
227     */
228    override public function captureEndValues():void
229    {
230        super.captureEndValues();
231
232        // Set targetSnapshot to the snapshot that we will be
233        // transitioning in or out.
234        if (consolidatedTransition)
235        {
236            if (mode == "out") // avoid deprecation warning for ZoomViewTransitionMode.OUT
237            {
238                targetSnapshot = cachedNavigator;
239                targetSnapshotGlobalPosition = cachedNavigationGroupGlobalPosition.clone();
240            }
241            else
242            {
243                targetSnapshot = getSnapshot(targetNavigator.skin, 0, targetSnapshotGlobalPosition);
244            }
245        }
246        else
247        {
248            if (mode == "out") // avoid deprecation warning for ZoomViewTransitionMode.OUT
249            {
250                targetSnapshot = getSnapshot(startView, 0, targetSnapshotGlobalPosition);
251            }
252            else
253            {
254                targetSnapshot = getSnapshot(endView, 0, targetSnapshotGlobalPosition);
255            }
256        }
257    }
258
259    /**
260     *  @private
261     *
262     *  @langversion 3.0
263     *  @playerversion AIR 2.5
264     *  @productversion Flex 4.5
265     */
266    override protected function createViewEffect():IEffect
267    {
268        // Add a group to contain targetSnapshot.
269        transitionGroup = new Group();
270        transitionGroup.includeInLayout = false;
271        addComponentToContainer(transitionGroup, DisplayObjectContainer(navigator) as UIComponent);
272
273        // Disable layout and visibility of our start view as necessary
274        if (startView)
275        {
276            startViewProps = {includeInLayout:startView.includeInLayout,
277                visible:startView.visible};
278            startView.includeInLayout = false;
279
280            if (mode == "out") // avoid deprecation warning for ZoomViewTransitionMode.OUT
281                startView.visible = false;
282        }
283
284        // Disable layout and visibility of our start end as necessary
285        if (endView)
286        {
287            endViewProps = {includeInLayout:endView.includeInLayout,
288                visible:endView.visible};
289            endView.includeInLayout = false;
290
291            if (mode == "in") // avoid deprecation warning for ZoomViewTransitionMode.IN
292                endView.visible = false;
293        }
294
295        if (targetSnapshot)
296            addCachedElementToGroup(transitionGroup, targetSnapshot, targetSnapshotGlobalPosition);
297
298        transitionGroup.validateNow();
299
300        // Initialize our target's transform center.
301        transitionGroup.transformX = endView.width / 2;
302        transitionGroup.transformY = endView.height / 2;
303
304        // Ensure our alpha is initialized to 0 prior to the start
305        // of our transition so that the view isn't displayed briefly
306        // after validation.
307        if (mode == "in") // avoid deprecation warning for ZoomViewTransitionMode.IN
308            transitionGroup.alpha = 0;
309
310        // Set our blendMode to 'normal' for performance reasons.
311        transitionGroup.blendMode = BlendMode.NORMAL;
312
313        return createZoomEffect(transitionGroup);
314    }
315
316    /**
317     *  @private
318     *
319     *  @langversion 3.0
320     *  @playerversion AIR 2.5
321     *  @productversion Flex 4.5
322     */
323    override protected function createConsolidatedEffect():IEffect
324    {
325        // If we have no cachedNavigator then there is not much we can do.
326        if (!cachedNavigator && mode == "out") // avoid deprecation warning for ZoomViewTransitionMode.OUT
327            return null;
328
329        // Add a group to contain our snapshot view of the original navigator.
330        cachedNavigatorGroup = new Group();
331        cachedNavigatorGroup.includeInLayout = false;
332
333        // On zoom out, place the cachedNavigator above the targetNavigator
334        var index:int = getComponentChildIndex(targetNavigator, targetNavigator.parent as UIComponent);
335        if (mode == "out") // avoid deprecation warning for ZoomViewTransitionMode.OUT
336            index++;
337        addComponentToContainerAt(cachedNavigatorGroup, DisplayObjectContainer(targetNavigator).parent as UIComponent, index);
338
339        cachedNavigator.includeInLayout = false;
340        addCachedElementToGroup(cachedNavigatorGroup, cachedNavigator, cachedNavigatorGlobalPosition);
341
342        // Add our temporary transition group to our target navigator's parent
343        // so we can make it and the original navigator siblings.
344        if (mode == "out") // avoid deprecation warning for ZoomViewTransitionMode.OUT
345        {
346            // We'll be zooming out our cachedNavigatorGroup.
347            transitionGroup = cachedNavigatorGroup;
348        }
349        else
350        {
351            transitionGroup = new Group();
352            transitionGroup.includeInLayout = false;
353
354            // We'll be zooming in our snapshot of the new navigator. Host our
355            // snapshot and make sure it's rendered.
356            cachedNavigatorGroup.addElement(transitionGroup);
357            addCachedElementToGroup(transitionGroup, targetSnapshot, targetSnapshotGlobalPosition);
358            cachedNavigatorGroup.validateNow();
359
360            // Hide our real navigator.
361            endViewProps = {visible:targetNavigator.skin.visible}
362            targetNavigator.skin.visible = false;
363        }
364
365        transitionGroup.validateNow();
366
367        // Initialize our target's transform center.
368        transitionGroup.transformX = cachedNavigator.getLayoutBoundsWidth(true) / 2 + targetNavigator.getLayoutBoundsX(true);
369        transitionGroup.transformY = cachedNavigator.getLayoutBoundsHeight(true) / 2 + targetNavigator.getLayoutBoundsY(true);
370
371        // Ensure our alpha is initialized to 0 prior to the start
372        // of our transition so that the view isn't displayed briefly
373        // after validation.
374        if (mode == "in") // avoid deprecation warning for ZoomViewTransitionMode.IN
375            transitionGroup.alpha = 0;
376
377        // Set our blendMode to 'normal' for performance reasons.
378        transitionGroup.blendMode = BlendMode.NORMAL;
379
380        return createZoomEffect(transitionGroup);
381    }
382
383    /**
384     *  @private
385     *
386     *  @langversion 3.0
387     *  @playerversion AIR 2.5
388     *  @productversion Flex 4.5
389     */
390    override protected function cleanUp():void
391    {
392        if (!consolidatedTransition)
393        {
394            if (startView)
395            {
396                startView.includeInLayout = startViewProps.includeInLayout;
397                startView.visible = startViewProps.visible;
398            }
399
400            if (endView)
401            {
402                endView.includeInLayout = endViewProps.includeInLayout;
403                endView.visible = endViewProps.visible;;
404            }
405
406            if (transitionGroup)
407                removeComponentFromContainer(transitionGroup, UIComponent(DisplayObjectContainer(navigator)));
408        }
409        else
410        {
411            if (cachedNavigatorGroup)
412                removeComponentFromContainer(cachedNavigatorGroup, UIComponent(DisplayObjectContainer(targetNavigator).parent));
413
414            if (endViewProps)
415                targetNavigator.skin.visible = endViewProps.visible;
416        }
417
418        transitionGroup = null;
419        cachedNavigator = null;
420        cachedNavigatorGroup = null;
421        endViewProps = null;
422        startViewProps = null;
423
424        scaleEffect.removeEventListener("effectUpdate", scaleEffectUpdateHandler);
425        scaleEffect = null;
426
427        super.cleanUp();
428    }
429
430    //--------------------------------------------------------------------------
431    //
432    //  Private Methods
433    //
434    //--------------------------------------------------------------------------
435
436    /**
437     *  @private
438     *  Shared helper routine which serves as our effect factory for both standard
439     *  and consolidated transitions.
440     */
441    protected function createZoomEffect(zoomTarget:Object):IEffect
442    {
443        // This will be a composite control, initialized with the appropriate target
444        // depending on the transition mode (in/out).
445        var parallel:Parallel = new Parallel;
446        parallel.target = zoomTarget;
447
448        // Create fade effect to gradually fade our zoom target, we don't fade for the
449        // duration of the effect as this degrades overall transition performance, we
450        // simply fade near the point of first appearance or disappearance.
451        var fadeEffect:Fade = new Fade();
452        fadeEffect.duration = (mode == "in") ? // avoid deprecation warning for ZoomViewTransitionMode.IN
453            duration * .4 : duration * .6;
454        if (mode == "out") // avoid deprecation warning for ZoomViewTransitionMode.OUT
455            fadeEffect.startDelay = duration * .4;
456        fadeEffect.alphaTo = (mode == "out") ? // avoid deprecation warning for ZoomViewTransitionMode.OUT
457            0 : 1;
458        fadeEffect.alphaFrom = (mode == "out") ? // avoid deprecation warning forZoomViewTransitionMode.OUT
459            1 : 0;
460
461        // Create scale effect to zoom in/our our target from or to our
462        // specified minimum scale.
463        scaleEffect = new Scale();
464        scaleEffect.duration = duration;
465        scaleEffect.easer = easer;
466        scaleEffect.scaleXFrom = scaleEffect.scaleYFrom =
467            (mode == "out") ? // avoid deprecation warning for ZoomViewTransitionMode.OUT
468            1 : minimumScale;
469        scaleEffect.scaleXTo = scaleEffect.scaleYTo =
470            (mode == "out") ? // avoid deprecation warning for ZoomViewTransitionMode.OUT
471            minimumScale : 1;
472        scaleEffect.addEventListener("effectUpdate", scaleEffectUpdateHandler);
473
474        parallel.addChild(fadeEffect);
475        parallel.addChild(scaleEffect);
476
477        return parallel;
478    }
479
480    /**
481     *  @private
482     *  Ensures transform matrix is updated even if layout is disabled.
483     */
484    private function scaleEffectUpdateHandler(e:Event):void
485    {
486        transitionGroup.validateDisplayList();
487    }
488
489}
490}
491