Repository: flex-utilities
Updated Branches:
  refs/heads/develop 9835c32ea -> 84e898f48


http://git-wip-us.apache.org/repos/asf/flex-utilities/blob/051a1e55/TourDeFlex/TourDeFlex3/src/spark/layouts/NumberInterpolatorWrapping.as
----------------------------------------------------------------------
diff --git 
a/TourDeFlex/TourDeFlex3/src/spark/layouts/NumberInterpolatorWrapping.as 
b/TourDeFlex/TourDeFlex3/src/spark/layouts/NumberInterpolatorWrapping.as
new file mode 100644
index 0000000..8613d7b
--- /dev/null
+++ b/TourDeFlex/TourDeFlex3/src/spark/layouts/NumberInterpolatorWrapping.as
@@ -0,0 +1,110 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  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
+{
+import spark.effects.interpolation.IInterpolator;
+    
+public class NumberInterpolatorWrapping implements IInterpolator
+{
+    private var _rangeBegin:Number;
+    private var _rangeEnd:Number;
+    public function NumberInterpolatorWrapping(rangeBegin:Number, 
rangeEnd:Number)
+    {
+        _rangeBegin = rangeBegin;
+        _rangeEnd = rangeEnd;
+    }
+        
+    /**
+     * Returns the type that an implementor can handle
+     */
+    public function get interpolatedType():Class
+    {
+        return Number;
+    }
+    
+    /**
+     * Given an elapsed fraction of an animation between 0 and 1,
+     * and start and end values, this function returns some value
+     * based on whatever interpolation the implementor chooses to
+     * provide.
+     */
+    public function interpolate(fraction:Number, startValue:Object, 
endValue:Object):Object
+    {
+        if (fraction == 0)
+            return startValue;
+        else if (fraction == 1)
+            return endValue;
+        var start:Number = Number(startValue);
+        var end:Number = Number(endValue);
+
+        if (Math.abs(end - start) < Math.abs(_rangeEnd - _rangeBegin) - 
Math.abs(end - start))
+        {
+            return start + fraction * (end - start);
+        }
+        else
+        {
+            var result:Number;
+            if (start < end)
+            {
+                result = start - fraction * (_rangeEnd - _rangeBegin - 
Math.abs(start - end));
+                if (result < _rangeBegin)
+                    result += _rangeEnd - _rangeBegin;
+                return result;
+            }
+            else
+            {
+                result = start + fraction * (_rangeEnd - _rangeBegin - 
Math.abs(start - end));
+                if (result > _rangeEnd)
+                    result -= _rangeEnd - _rangeBegin;
+                return result;
+            }
+        }        
+    }
+    
+    public function increment(baseValue:Object, incrementValue:Object):Object
+    {
+        var result:Number = Number(baseValue) + Number(incrementValue);
+        // This won't handle situations where we're adding more than
+        // the range itself, but since this will only be called when
+        // the user submits a 'byValue' that large, it seems unlikely
+        // at the very least
+        if (result > _rangeEnd)
+            result = _rangeBegin + (result - _rangeEnd);
+        return result;
+    }
+    
+    public function decrement(baseValue:Object, decrementValue:Object):Object
+    {
+        var result:Number = Number(baseValue) - Number(decrementValue);
+        // This won't handle situations where we're subtracting more than
+        // the range itself, but since this will only be called when
+        // the user submits a 'byValue' that large, it seems unlikely
+        // at the very least
+        if (result < _rangeBegin)
+            result = _rangeEnd + (_rangeBegin - result);
+        return result;
+    }
+    
+    public function getLength(startValue:Number, endValue:Number):Number
+    {
+        return Math.min( Math.abs(startValue - endValue), Math.abs(_rangeEnd - 
_rangeBegin - Math.abs(startValue - endValue)));
+    }   
+
+}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/flex-utilities/blob/051a1e55/TourDeFlex/TourDeFlex3/src/spark/layouts/WheelLayout.as
----------------------------------------------------------------------
diff --git a/TourDeFlex/TourDeFlex3/src/spark/layouts/WheelLayout.as 
b/TourDeFlex/TourDeFlex3/src/spark/layouts/WheelLayout.as
new file mode 100644
index 0000000..1ce4bb6
--- /dev/null
+++ b/TourDeFlex/TourDeFlex3/src/spark/layouts/WheelLayout.as
@@ -0,0 +1,516 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  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
+{
+
+import flash.geom.Matrix;
+import flash.geom.Matrix3D;
+import flash.geom.Point;
+import flash.geom.Rectangle;
+import flash.geom.Vector3D;
+
+import mx.core.ILayoutElement;
+import mx.core.IVisualElement;
+
+import spark.components.supportClasses.GroupBase;
+import spark.core.NavigationUnit;
+import spark.layouts.supportClasses.LayoutBase;
+
+public class WheelLayout extends LayoutBase
+{
+    
//--------------------------------------------------------------------------
+    //
+    //  Constructor
+    //
+    
//--------------------------------------------------------------------------
+
+    public function WheelLayout()
+    {
+        super();
+    }
+    
+    
//--------------------------------------------------------------------------
+    //
+    //  Properties
+    //
+    
//--------------------------------------------------------------------------
+
+    //----------------------------------
+    //  gap
+    //----------------------------------
+
+    private var _gap:Number = 0;
+
+    /**
+     *  The gap between the items
+     */
+    public function get gap():Number
+    {
+        return _gap;
+    }
+    
+    public function set gap(value:Number):void
+    {
+        _gap = value;
+        var layoutTarget:GroupBase = target;
+        if (layoutTarget)
+        {
+            layoutTarget.invalidateSize();
+            layoutTarget.invalidateDisplayList();
+        }
+    }
+    
+    //----------------------------------
+    //  axisAngle
+    //----------------------------------
+
+    /**
+     *  @private  
+     *  The total width of all items, including gap space.
+     */
+    private var _totalWidth:Number;
+
+    /**
+     *  @private  
+     *  Cache which item is currently in view, to facilitate scrollposition 
delta calculations
+     */
+    private var _centeredItemIndex:int = 0;
+    private var _centeredItemCircumferenceBegin:Number = 0;
+    private var _centeredItemCircumferenceEnd:Number = 0;
+    private var _centeredItemDegrees:Number = 0;
+
+    /**
+     *  The axis to tilt the 3D wheel 
+     */
+    private var _axis:Vector3D = new Vector3D(0, 1, 0.1);
+    
+    /**
+     *  The angle to tilt the axis of the wheel
+     */
+    public function set axisAngle(value:Number):void
+    {
+        _axis = new Vector3D(0, Math.cos(Math.PI * value /180), 
Math.sin(Math.PI * value /180));
+        var layoutTarget:GroupBase = target;
+        if (layoutTarget)
+        {
+            layoutTarget.invalidateSize();
+            layoutTarget.invalidateDisplayList();
+        }
+    }
+    
+    /**
+     *  @private 
+     *  Given the radius of the sphere, return the radius of the
+     *  projected sphere. Uses the projection matrix of the
+     *  layout target to calculate.
+     */    
+    private function projectSphere(radius:Number, radius1:Number):Number
+    {
+        var fl:Number = target.transform.perspectiveProjection.focalLength;
+        var alpha:Number = Math.asin( radius1 / (radius + fl) );
+        return fl * Math.tan(alpha) * 2;
+    }
+    
+    /**
+     *  @private
+     *  Given the totalWidth, maxHeight and maxHalfWidthDiagonal, calculate 
the bounds of the items
+     *  on screen.  Uses the projection matrix of the layout target to 
calculate. 
+     */
+    private function projectBounds(totalWidth:Number, maxWidth:Number, 
maxHeight:Number, maxHalfWidthDiagonal:Number):Point
+    {
+        // Use the the total width as a circumference of an imaginary circle 
which we will use to
+        // align the items in 3D:
+        var radius:Number = _totalWidth * 0.5 / Math.PI;
+        
+        // Now since we are going to arrange all the items along circle, 
middle of the item being the tangent point,
+        // we need to calculate the minimum bounding circle. It is easily 
calculated from the maximum width item:
+        var boundingRadius:Number = Math.sqrt(radius * radius + 0.25 * 
maxWidth * maxWidth);
+                                      
+        var projectedBoundsW:Number = _axis.z * _axis.z * 
(maxHalfWidthDiagonal + 2 * radius) + 
+                                      projectSphere(radius, boundingRadius ) * 
_axis.y * _axis.y;
+                                      
+        var projectedBoundsH:Number = Math.abs(_axis.z) * 
(maxHalfWidthDiagonal + 2 * radius) +
+                                      maxHeight * _axis.y * _axis.y;
+                                      
+        return new Point(projectedBoundsW + 10, projectedBoundsH + 10);
+    }
+
+    /**
+     *  @private 
+     *  Iterates through all the items, calculates the projected bounds on 
screen, updates _totalWidth member variable.
+     */    
+    private function calculateBounds():Point
+    {
+        // Calculate total width:
+        _totalWidth = 0;
+     
+        var maxHeight:Number = 0;
+        var maxWidth:Number = 0;
+        var maxD:Number = 0;
+   
+        // Add up all the widths
+        var iter:LayoutIterator = new LayoutIterator(target);
+        var el:ILayoutElement;
+        while (el = iter.nextElement())
+        {
+            var preferredWidth:Number = el.getPreferredBoundsWidth(false 
/*postTransform*/);
+            var preferredHeight:Number = el.getPreferredBoundsHeight(false 
/*postTransform*/);
+
+            // Add up item width
+            _totalWidth += preferredWidth;
+            
+            // Max up item size
+            maxWidth = Math.max(maxWidth, preferredWidth);
+            maxHeight = Math.max(maxHeight, preferredHeight);
+            
+            maxD = Math.max(maxD, Math.sqrt(preferredWidth * preferredWidth / 
4 + 
+                                            preferredHeight * 
preferredHeight));    
+        }
+        
+        // Add up the gap
+        _totalWidth += gap * iter.numVisited;
+
+        // Project        
+        return projectBounds(_totalWidth, maxWidth, maxHeight, maxD);
+    }
+    
+    
//--------------------------------------------------------------------------
+    //
+    //  Overridden methods: LayoutBase
+    //
+    
//--------------------------------------------------------------------------
+    
+    /**
+     * @private
+     */
+    override public function set target(value:GroupBase):void
+    {
+        // Make sure that if layout is swapped out, we clean up
+        if (!value && target)
+        {
+            target.maintainProjectionCenter = false;
+
+            var iter:LayoutIterator = new LayoutIterator(target);
+            var el:ILayoutElement;
+            while (el = iter.nextElement())
+            {
+                el.setLayoutMatrix(new Matrix(), false /*triggerLayout*/);
+            }
+        }
+        
+        super.target = value;
+
+        // Make sure we turn on projection the first time the layout
+        // gets assigned to the group
+        if (target)
+            target.maintainProjectionCenter = true;
+    }
+    
+    override public function measure():void
+    {
+        var bounds:Point = calculateBounds();
+        
+        target.measuredWidth = bounds.x;
+        target.measuredHeight = bounds.y;
+    }
+    
+    override public function updateDisplayList(unscaledWidth:Number, 
unscaledHeight:Number):void
+    {
+        // Get the bounds, this will also update _totalWidth
+        var bounds:Point = calculateBounds();
+
+        // Update the content size
+        target.setContentSize(_totalWidth + unscaledWidth, bounds.y); 
+        var radius:Number = _totalWidth * 0.5 / Math.PI;
+        var gap:Number = this.gap;
+        _centeredItemDegrees = Number.MAX_VALUE;
+        
+        var scrollPosition:Number = target.horizontalScrollPosition;
+        var totalWidthSoFar:Number = 0;
+        // Subtract the half width of the first element from totalWidthSoFar: 
+        var iter:LayoutIterator = new LayoutIterator(target);
+        var el:ILayoutElement = iter.nextElement();
+        if (!el)
+            return;
+        totalWidthSoFar -= el.getPreferredBoundsWidth(false /*postTransform*/) 
/ 2;
+        
+        // Set the 3D Matrix for all the elements:
+        iter.reset();
+        while (el = iter.nextElement())
+        { 
+            // Size the item, no need to position it, since we'd set the 
computed matrix
+            // which defines the position.
+            el.setLayoutBoundsSize(NaN, NaN, false /*postTransform*/);
+            var elementWidth:Number = el.getLayoutBoundsWidth(false 
/*postTransform*/);
+            var elementHeight:Number = el.getLayoutBoundsHeight(false 
/*postTransform*/); 
+            var degrees:Number = 360 * (totalWidthSoFar + elementWidth/2 - 
scrollPosition) / _totalWidth; 
+
+            // Remember which item is centered, this is used during scrolling
+            var curDegrees:Number = degrees % 360;
+            if (Math.abs(curDegrees) < Math.abs(_centeredItemDegrees))
+            {
+                _centeredItemDegrees = curDegrees;
+                _centeredItemIndex = iter.curIndex;
+                _centeredItemCircumferenceBegin = totalWidthSoFar - gap;
+                _centeredItemCircumferenceEnd = totalWidthSoFar + elementWidth 
+ gap;
+            }
+
+            // Calculate and set the 3D Matrix 
+            var m:Matrix3D = new Matrix3D();
+            m.appendTranslation(-elementWidth/2, -elementHeight/2 + radius * 
_axis.z, -radius * _axis.y );
+            m.appendRotation(-degrees, _axis);
+            m.appendTranslation(unscaledWidth/2, unscaledHeight/2, radius * 
_axis.y);
+            el.setLayoutMatrix3D(m, false /*triggerLayout*/);
+            
+            // Update the layer for a correct z-order
+            if (el is IVisualElement)
+                IVisualElement(el).depth = Math.abs( Math.floor(180 - 
Math.abs(degrees % 360)) );
+
+            // Move on to next item
+            totalWidthSoFar += elementWidth + gap;
+        }
+    }
+    
+    private function scrollPositionFromCenterToNext(next:Boolean):Number
+    {
+        var iter:LayoutIterator = new LayoutIterator(target, 
_centeredItemIndex);
+        var el:ILayoutElement = next ? iter.nextElementWrapped() : 
iter.prevElementWrapped();
+        if (!el)
+            return 0;
+        
+        var elementWidth:Number = el.getLayoutBoundsWidth(false 
/*postTransform*/);
+        
+        var value:Number; 
+        if (next)
+        {
+            if (_centeredItemDegrees > 0.1)
+                return (_centeredItemCircumferenceEnd + 
_centeredItemCircumferenceBegin) / 2;
+            
+            value = _centeredItemCircumferenceEnd + elementWidth/2;
+            if (value > _totalWidth)
+                value -= _totalWidth;
+        }
+        else
+        {
+            if (_centeredItemDegrees < -0.1)
+                return (_centeredItemCircumferenceEnd + 
_centeredItemCircumferenceBegin) / 2;
+
+            value = _centeredItemCircumferenceBegin - elementWidth/2;
+            if (value < 0)
+                value += _totalWidth;
+        }
+        return value;     
+    }
+    
+    override protected function scrollPositionChanged():void
+    {
+        if (target)
+            target.invalidateDisplayList();
+    }
+
+    override public function 
getHorizontalScrollPositionDelta(navigationUnit:uint):Number
+    {
+        var g:GroupBase = target;
+        if (!g || g.numElements == 0)
+            return 0;
+            
+        var value:Number;     
+
+        switch (navigationUnit)
+        {
+            case NavigationUnit.LEFT:
+            {
+                value = target.horizontalScrollPosition - 30;
+                if (value < 0)
+                    value += _totalWidth;
+                return value - target.horizontalScrollPosition;
+            }
+                
+            case NavigationUnit.RIGHT:
+            {
+                value = target.horizontalScrollPosition + 30;
+                if (value > _totalWidth)
+                    value -= _totalWidth;
+                return value - target.horizontalScrollPosition;
+            }
+                
+            case NavigationUnit.PAGE_LEFT:
+                return scrollPositionFromCenterToNext(false) - 
target.horizontalScrollPosition;
+                
+            case NavigationUnit.PAGE_RIGHT:
+                return scrollPositionFromCenterToNext(true) - 
target.horizontalScrollPosition;
+                
+            case NavigationUnit.HOME: 
+                return 0;
+                
+            case NavigationUnit.END: 
+                return _totalWidth;
+                
+            default:
+                return 0;
+        }       
+    }
+    
+    /**
+     *  @private
+     */ 
+    override public function getScrollPositionDeltaToElement(index:int):Point
+    {
+        var layoutTarget:GroupBase = target;
+        if (!layoutTarget)
+            return null;
+       
+        var gap:Number = this.gap;     
+        var totalWidthSoFar:Number = 0;
+        var iter:LayoutIterator = new LayoutIterator(layoutTarget);
+
+        var el:ILayoutElement = iter.nextElement();
+        if (!el)
+            return null;
+        totalWidthSoFar -= el.getLayoutBoundsWidth(false /*postTransform*/) / 
2;
+
+        iter.reset();
+        while (null != (el = iter.nextElement()) && iter.curIndex <= index)
+        {    
+            var elementWidth:Number = el.getLayoutBoundsWidth(false 
/*postTransform*/);
+            totalWidthSoFar += gap + elementWidth;
+        }
+        return new Point(totalWidthSoFar - elementWidth / 2 -gap - 
layoutTarget.horizontalScrollPosition, 0);
+    }
+
+    /**
+     *  @private
+     */ 
+    override public function updateScrollRect(w:Number, h:Number):void
+    {
+        var g:GroupBase = target;
+        if (!g)
+            return;
+            
+        if (clipAndEnableScrolling)
+        {
+            // Since scroll position is reflected in our 3D calculations,
+            // always set the top-left of the srcollRect to (0,0).
+            g.scrollRect = new Rectangle(0, verticalScrollPosition, w, h);
+        }
+        else
+            g.scrollRect = null;
+    } 
+}
+}
+
+import mx.core.ILayoutElement;
+
+import spark.components.supportClasses.GroupBase;
+    
+class LayoutIterator 
+{
+    private var _curIndex:int;
+    private var _numVisited:int = 0;
+    private var totalElements:int;
+    private var _target:GroupBase;
+    private var _loopIndex:int = -1;
+       private var _useVirtual:Boolean;
+
+    public function get curIndex():int
+    {
+        return _curIndex;
+    }
+
+    public function LayoutIterator(target:GroupBase, index:int=-1):void
+    {
+        totalElements = target.numElements;
+        _target = target;
+        _curIndex = index;
+               _useVirtual = _target.layout.useVirtualLayout;
+    }
+
+    public function nextElement():ILayoutElement
+    {
+        while (_curIndex < totalElements - 1)
+        {
+            var el:ILayoutElement = _useVirtual ? 
_target.getVirtualElementAt(++_curIndex) :
+                                                                               
                  _target.getElementAt(++_curIndex);
+            if (el && el.includeInLayout)
+            {
+                ++_numVisited;
+                return el;
+            }
+        }
+        return null;
+    }
+    
+    public function prevElement():ILayoutElement
+    {
+        while (_curIndex > 0)
+        {
+            var el:ILayoutElement = _useVirtual ? 
_target.getVirtualElementAt(--_curIndex) :
+                                                                               
                  _target.getElementAt(--_curIndex);
+            if (el && el.includeInLayout)
+            {
+                ++_numVisited;
+                return el;
+            }
+        }
+        return null;
+    }
+
+    public function nextElementWrapped():ILayoutElement
+    {
+        if (_loopIndex == -1)
+            _loopIndex = _curIndex;
+        else if (_loopIndex == _curIndex)
+            return null;
+
+        var el:ILayoutElement = nextElement();
+        if (el)
+            return el;
+        else if (_curIndex == totalElements - 1)
+            _curIndex = -1;
+        return nextElement();
+    }
+    
+    public function prevElementWrapped():ILayoutElement
+    {
+        if (_loopIndex == -1)
+            _loopIndex = _curIndex;
+        else if (_loopIndex == _curIndex)
+            return null;
+
+        var el:ILayoutElement = prevElement();
+        if (el)
+            return el;
+        else if (_curIndex == 0)
+            _curIndex = totalElements;
+        return prevElement();
+    }
+
+    public function reset():void
+    {
+        _curIndex = -1;
+        _numVisited = 0;
+        _loopIndex = -1;
+    }
+
+    public function get numVisited():int
+    {
+        return _numVisited;
+    }
+}
+    

http://git-wip-us.apache.org/repos/asf/flex-utilities/blob/051a1e55/TourDeFlex/TourDeFlex3/src/spark/layouts/assets/xdslider.png
----------------------------------------------------------------------
diff --git a/TourDeFlex/TourDeFlex3/src/spark/layouts/assets/xdslider.png 
b/TourDeFlex/TourDeFlex3/src/spark/layouts/assets/xdslider.png
new file mode 100644
index 0000000..8d49a7a
Binary files /dev/null and 
b/TourDeFlex/TourDeFlex3/src/spark/layouts/assets/xdslider.png differ

http://git-wip-us.apache.org/repos/asf/flex-utilities/blob/051a1e55/TourDeFlex/TourDeFlex3/src/spark/layouts/data/catalog.xml
----------------------------------------------------------------------
diff --git a/TourDeFlex/TourDeFlex3/src/spark/layouts/data/catalog.xml 
b/TourDeFlex/TourDeFlex3/src/spark/layouts/data/catalog.xml
new file mode 100644
index 0000000..ecf9bc6
--- /dev/null
+++ b/TourDeFlex/TourDeFlex3/src/spark/layouts/data/catalog.xml
@@ -0,0 +1,193 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+
+  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.
+
+-->
+
+<catalog>
+
+    <product productId="1">
+        <name>Nokia 6010</name>
+        <color></color>
+        <description>Easy to use without sacrificing style, the Nokia 6010 
phone offers functional voice communication supported by text messaging, 
multimedia messaging, mobile internet, games and more</description>
+        <price>99.99</price>
+        <image>assets/pic/Nokia_6010.gif</image>
+        <series>6000</series>
+        <triband>false</triband>
+        <camera>false</camera>
+        <video>false</video>
+        <highlight1>MMS</highlight1>
+               <highlight2>Large color display</highlight2>
+    </product>
+
+    <product productId="2">
+        <name>Nokia 3100</name>
+        <color>Blue</color>
+        <description>Light up the night with a glow-in-the-dark cover - when 
it's charged with light you can easily find your phone in the dark. When you 
get a call, the Nokia 3100 phone flashes in tune with your ringing tone. And 
when you snap on a Nokia Xpress-on™ gaming cover*, you'll get luminescent 
light effects in time to the gaming action.</description>
+        <price>139</price>
+        <image>assets/pic/Nokia_3100_blue.gif</image>
+        <series>3000</series>
+        <triband>true</triband>
+        <camera>false</camera>
+        <video>false</video>
+        <highlight1>Glow-in-the-dark</highlight1>
+               <highlight2>Flashing lights</highlight2>
+    </product>
+
+    <product productId="3">
+        <name>Nokia 3100</name>
+        <color>Pink</color>
+        <description>Light up the night with a glow-in-the-dark cover - when 
it's charged with light you can easily find your phone in the dark. When you 
get a call, the Nokia 3100 phone flashes in tune with your ringing tone. And 
when you snap on a Nokia Xpress-on™ gaming cover*, you'll get luminescent 
light effects in time to the gaming action.</description>
+        <price>139</price>
+        <image>assets/pic/Nokia_3100_pink.gif</image>
+        <series>3000</series>
+        <triband>true</triband>
+        <camera>false</camera>
+        <video>false</video>
+        <highlight1>Glow-in-the-dark</highlight1>
+               <highlight2>Flashing lights</highlight2>
+    </product>
+
+    <product productId="4">
+        <name>Nokia 3120</name>
+        <color></color>
+        <description>Designed for both business and pleasure, the elegant 
Nokia 3120 phone offers a pleasing mix of features. Enclosed within its chic, 
compact body, you will discover the benefits of tri-band compatibility, a color 
screen, MMS, XHTML browsing, cheerful screensavers, and much more.</description>
+        <price>159.99</price>
+        <image>assets/pic/Nokia_3120.gif</image>
+        <series>3000</series>
+        <triband>true</triband>
+        <camera>false</camera>
+        <video>false</video>
+        <highlight1>Multimedia messaging</highlight1>
+               <highlight2>Animated screensavers</highlight2>
+    </product>
+
+    <product productId="5">
+        <name>Nokia 3220</name>
+        <color></color>
+        <description>The Nokia 3220 phone is a fresh new cut on some familiar 
ideas - animate your MMS messages with cute characters, see the music with 
lights that flash in time with your ringing tone, download wallpapers and 
screensavers with matching color schemes for the interface.</description>
+        <price>159.99</price>
+        <image>assets/pic/Nokia_3220.gif</image>
+        <series>3000</series>
+        <triband>false</triband>
+        <camera>true</camera>
+        <video>false</video>
+        <highlight1>MIDI tones</highlight1>
+               <highlight2>Cut-out covers</highlight2>
+    </product>
+
+    <product productId="6">
+        <name>Nokia 3650</name>
+        <color></color>
+        <description>Messaging is more personal, versatile and fun with the 
Nokia 3650 camera phone.  Capture experiences as soon as you see them and send 
the photos you take to you friends and family.</description>
+        <price>199.99</price>
+        <image>assets/pic/Nokia_3650.gif</image>
+        <series>3000</series>
+        <triband>false</triband>
+        <camera>true</camera>
+        <video>true</video>
+        <highlight1>Infrared or Bluetooth</highlight1>
+               <highlight2>Built-in XHTML browser</highlight2>
+    </product>
+
+    <product productId="7">
+        <name>Nokia 6820</name>
+        <color></color>
+        <description>Messaging just got a whole lot smarter. The Nokia 6820 
messaging device puts the tools you need for rich communication - full 
messaging keyboard, digital camera, mobile email, MMS, SMS, and Instant 
Messaging - right at your fingertips, in a small, sleek device.</description>
+        <price>299.99</price>
+        <image>assets/pic/Nokia_6820.gif</image>
+        <series>6000</series>
+        <triband>true</triband>
+        <camera>true</camera>
+        <video>false</video>
+        <highlight1>Messaging keyboard</highlight1>
+               <highlight2>Bluetooth </highlight2>
+    </product>
+
+    <product productId="8">
+        <name>Nokia 6670</name>
+        <color></color>
+        <description>Classic business tools meet your creative streak in the 
Nokia 6670 imaging smartphone. It has a Netfront Web browser with PDF support, 
document viewer applications for email attachments, a direct printing 
application, and a megapixel still camera that also shoots up to 10 minutes of 
video.</description>
+        <price>309.99</price>
+        <image>assets/pic/Nokia_6670.gif</image>
+        <series>6000</series>
+        <triband>false</triband>
+        <camera>true</camera>
+        <video>true</video>
+        <highlight1>PDF support</highlight1>
+               <highlight2>4x digital zoom</highlight2>
+    </product>
+
+    <product productId="9">
+        <name>Nokia 6620</name>
+        <color></color>
+        <description>Shoot a basket. Shoot a movie. Video phones from Nokia... 
the perfect way to save and share life’s playful moments. Feel 
connected.</description>
+        <price>329.99</price>
+        <image>assets/pic/Nokia_6620.gif</image>
+        <series>6000</series>
+        <triband>false</triband>
+        <camera>true</camera>
+        <video>true</video>
+        <highlight1>Bluetooth technology</highlight1>
+               <highlight2>Up to 10 minutes video</highlight2>
+    </product>
+
+    <product productId="10">
+        <name>Nokia 3230</name>
+        <color>Silver</color>
+        <description>Get creative with the Nokia 3230 smartphone. Create your 
own ringing tones, print your mobile images, play multiplayer games over a 
wireless Bluetooth connection, and browse HTML and xHTML Web pages. Plus, with 
a 32 MB MMC card and expandable memory, you'll have lots of space to be 
creative.</description>
+        <price>369</price>
+        <image>assets/pic/Nokia_3230_black.gif</image>
+        <series>3000</series>
+        <triband>false</triband>
+        <camera>true</camera>
+        <video>true</video>
+        <highlight1>1.3 megapixel</highlight1>
+               <highlight2>Expandable memory</highlight2>
+    </product>
+
+    <product productId="11">
+        <name>Nokia 3230</name>
+        <color>Bronze</color>
+        <description>Get creative with the Nokia 3230 smartphone. Create your 
own ringing tones, print your mobile images, play multiplayer games over a 
wireless Bluetooth connection, and browse HTML and xHTML Web pages. Plus, with 
a 32 MB MMC card and expandable memory, you'll have lots of space to be 
creative.</description>
+        <price>369</price>
+        <image>assets/pic/Nokia_3230_bronze.gif</image>
+        <series>3000</series>
+        <triband>false</triband>
+        <camera>true</camera>
+        <video>true</video>
+        <highlight1>1.3 megapixel</highlight1>
+               <highlight2>Expandable memory</highlight2>
+    </product>
+
+    <product productId="12">
+        <name>Nokia 6630</name>
+        <color></color>
+        <description>Not only is the Nokia 6630 imaging smartphone a 1.3 
megapixel digital imaging device (1.3 megapixel camera sensor, effective 
resolution 1.23 megapixels for image capture, image size 1280 x 960 pixels), 
it's also a portable office and a modern rich-media machine.</description>
+        <price>379</price>
+        <image>assets/pic/Nokia_6630.gif</image>
+        <series>6000</series>
+        <triband>false</triband>
+        <camera>true</camera>
+        <video>true</video>
+        <highlight1>1.3 megapixel</highlight1>
+               <highlight2>6x smooth digital zoom</highlight2>
+    </product>
+
+    
+   
+</catalog>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/flex-utilities/blob/051a1e55/TourDeFlex/TourDeFlex3/src/spark/layouts/layouts/FilteredTileLayout.as
----------------------------------------------------------------------
diff --git 
a/TourDeFlex/TourDeFlex3/src/spark/layouts/layouts/FilteredTileLayout.as 
b/TourDeFlex/TourDeFlex3/src/spark/layouts/layouts/FilteredTileLayout.as
new file mode 100644
index 0000000..6c01c2c
--- /dev/null
+++ b/TourDeFlex/TourDeFlex3/src/spark/layouts/layouts/FilteredTileLayout.as
@@ -0,0 +1,260 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  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 layouts
+{
+       import mx.collections.ICollectionView;
+       import mx.effects.Parallel;
+       import mx.events.EffectEvent;
+       
+       import spark.components.supportClasses.GroupBase;
+       import spark.components.supportClasses.ItemRenderer;
+       import spark.effects.Fade;
+       import spark.effects.Move;
+       import spark.layouts.supportClasses.LayoutBase;
+
+       public class FilteredTileLayout extends LayoutBase
+       {
+               public var filteredItems:ICollectionView;
+               
+               public var fadeOutDuration:Number = 400;
+               
+               public var moveDuration:Number = 400;
+               
+               public var fadeInDuration:Number = 400;
+
+               private var _target:GroupBase;
+
+               private var _containerWidth:Number;
+               
+               private var fadeOutEffects:Parallel;
+               private var fadeInEffects:Parallel;
+               private var moveEffects:Parallel;
+               
+               private var _horizontalGap:Number = 10;
+
+               private var _verticalGap:Number = 10;
+
+               private var _tileWidth:Number = 100;
+
+               private var _tileHeight:Number = 100;
+
+               public function set     horizontalGap(value:Number):void
+               {
+                       _horizontalGap = value;
+                       if (target)     target.invalidateDisplayList();
+               }
+
+               public function set     verticalGap(value:Number):void
+               {
+                       _verticalGap = value;
+                       if (target)     target.invalidateDisplayList();
+               }
+               
+               public function set     tileWidth(value:Number):void
+               {
+                       _tileWidth = value;
+                       if (target)     target.invalidateDisplayList();
+               }
+               
+               public function set     tileHeight(value:Number):void
+               {
+                       _tileHeight = value;
+                       if (target)     target.invalidateDisplayList();
+               }
+               
+               public function filter():void
+               {
+                       // Prevent updateDisplayList() from being executed 
while we are animating tiles
+                       _target.autoLayout = false;
+
+                       // No filter has been applied. Keep showing all the 
items in the dataProvider
+                       if (filteredItems == null) return;
+                       
+                       var count:int = _target.numElements;
+                       
+                       // No items in the dataProvider: Nothing to show.
+                       if (count == 0) return;
+                       
+                       var x:int = 0;
+                       var y:int = 0;
+                       
+                       fadeOutEffects = new Parallel();
+                       fadeInEffects = new Parallel();
+                       moveEffects = new Parallel();
+
+                       for (var i:int = 0; i < count; i++)
+                       {
+                               var itemRenderer:ItemRenderer = 
_target.getElementAt(i) as ItemRenderer;
+                               
+                               if (filteredItems.contains(itemRenderer.data))
+                               {
+                                       // The element is part of the 
selection: calculate its x and y values
+                                       if (x + _tileWidth > _containerWidth)
+                                       {
+                                               x = 0;
+                                               y += _tileHeight + _verticalGap;
+                                       } 
+
+                                       if (itemRenderer.visible == false)
+                                       {
+                                               trace("FadeIn: " + 
itemRenderer.data.name);
+                                               // if the element was hidden, 
set its new x and y values (without Move animation) and register it for FadeIn 
animation
+                                               itemRenderer.visible = true;
+                                               
itemRenderer.setLayoutBoundsPosition(x, y);
+                                               var fadeIn:Fade = new 
Fade(itemRenderer);
+                                               fadeIn.alphaTo = 1;
+                                               fadeInEffects.addChild(fadeIn);
+                                       }  
+                                       else
+                                       {
+                                               trace("Move: " + 
itemRenderer.data.name);
+                                               // the element was already 
visible: register it for Move animation
+                                               if (itemRenderer.x != x || 
itemRenderer.y != y)
+                                               {
+                                                       var move:Move = new 
Move(itemRenderer);
+                                                       move.xTo = x;
+                                                       move.yTo = y;
+                                                       
moveEffects.addChild(move);
+                                               }
+                                       }
+                                       x += _tileWidth + _horizontalGap;
+                               }                                       
+                               else
+                               {
+                                       if (itemRenderer.alpha == 1)
+                                       {
+                                               trace("FadeOut: " + 
itemRenderer.data.name);
+                                               // the element is filtered out: 
register it for FadeOut animation
+                                               var fadeOut:Fade = new 
Fade(itemRenderer);
+                                               fadeOut.alphaTo = 0;
+                                               
fadeOutEffects.addChild(fadeOut);
+                                       }
+                               }
+                       }
+                       fadeOutTiles();                 
+               }
+
+               private function fadeOutTiles(event:EffectEvent = null):void
+               {
+                       trace("fadeOutTiles");
+                       if (fadeOutEffects.children.length > 0) {
+                               fadeOutEffects.duration = fadeOutDuration;
+                               
fadeOutEffects.addEventListener(EffectEvent.EFFECT_END, moveTiles)
+                               fadeOutEffects.play();
+                       }
+                       else
+                       {
+                               moveTiles();    
+                       }
+               }
+               
+               private function moveTiles(event:EffectEvent = null):void
+               {
+                       // Undesired behaviors may happen if we leave tiles 
with alpha=0 in the display list while performing other animations 
+                       setInvisibleTiles();
+                       
+                       trace("moveTiles");
+                       if (moveEffects.children.length > 0) {
+                               moveEffects.duration = moveDuration;
+                               
moveEffects.addEventListener(EffectEvent.EFFECT_END, fadeInTiles)
+                               moveEffects.play();
+                       }
+                       else
+                       {
+                               fadeInTiles();  
+                       }
+               }
+
+               private function fadeInTiles(event:EffectEvent = null):void
+               {
+                       trace("fadeInTiles");
+                       if (fadeInEffects.children.length > 0) {
+                               fadeInEffects.duration = fadeInDuration;
+                               
moveEffects.addEventListener(EffectEvent.EFFECT_END, fadeInTilesEnd)
+                               fadeInEffects.play();
+                       }
+                       else
+                       {
+                               fadeInTilesEnd();       
+                       }
+               }
+               
+               private function fadeInTilesEnd(event:EffectEvent = null):void
+               {
+                       _target.autoLayout = true; 
+               }
+               
+               private function setInvisibleTiles():void
+               {
+                       var count:int = _target.numElements;
+                       
+                       if (count == 0) return;
+                       
+                       for (var i:int = 0; i < count; i++)
+                       {
+                               var itemRenderer:ItemRenderer = 
_target.getElementAt(i) as ItemRenderer;
+                               if (!filteredItems.contains(itemRenderer.data))
+                               {       
+                                       trace("Removing from layout: " + 
itemRenderer.data.name);                                       
+                                       itemRenderer.visible = false;
+                               }               
+                       }
+               }
+       
+               override public function 
updateDisplayList(containerWidth:Number, containerHeight:Number):void
+               {
+                       trace("updateDisplaylist");
+
+                       _target = target;
+                       _containerWidth = containerWidth;
+
+                       var count:int = target.numElements;
+                       if (count == 0) return;
+                       
+                       var x:int=0;
+                       var y:int=0;
+                       
+                       for (var i:int = 0; i < count; i++)
+                       {
+                               var itemRenderer:ItemRenderer = 
_target.getElementAt(i) as ItemRenderer;
+
+                               itemRenderer.setLayoutBoundsSize(_tileWidth, 
_tileHeight);
+                               
+                               if (filteredItems && 
filteredItems.contains(itemRenderer.data))
+                               {
+                                       // The element is part of the 
selection: calculate its x and y values
+                                       if (x + _tileWidth > containerWidth)
+                                       {
+                                               x = 0;
+                                               y += _tileHeight + _verticalGap;
+                                       } 
+                                       itemRenderer.setLayoutBoundsPosition(x, 
y);     
+                                       itemRenderer.alpha = 1;
+                                       x += _tileWidth + _horizontalGap;
+                               }                                       
+                               else
+                               {
+                                       itemRenderer.alpha = 0;
+                               }
+                               
+                       }
+               }
+
+       }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/flex-utilities/blob/051a1e55/TourDeFlex/TourDeFlex3/src/spark/layouts/renderers/PhoneRenderer.mxml
----------------------------------------------------------------------
diff --git 
a/TourDeFlex/TourDeFlex3/src/spark/layouts/renderers/PhoneRenderer.mxml 
b/TourDeFlex/TourDeFlex3/src/spark/layouts/renderers/PhoneRenderer.mxml
new file mode 100644
index 0000000..9e17279
--- /dev/null
+++ b/TourDeFlex/TourDeFlex3/src/spark/layouts/renderers/PhoneRenderer.mxml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+
+  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.
+
+-->
+<s:ItemRenderer xmlns:fx="http://ns.adobe.com/mxml/2009";
+                               xmlns:s="library://ns.adobe.com/flex/spark"
+                               xmlns:mx="library://ns.adobe.com/flex/mx" 
+                               autoDrawBackground="false" width="100" 
height="100" clipAndEnableScrolling="false"
+                               depth="0" depth.hovered="1">
+       
+       <fx:Declarations>
+               <mx:CurrencyFormatter id="cf"/>
+       </fx:Declarations>
+       
+       <s:states>
+               <s:State name="normal" />
+               <s:State name="hovered" />
+       </s:states>
+
+       <s:transitions>
+               <s:Transition fromState="normal" toState="hovered" 
autoReverse="true">
+                               <s:Parallel>
+                                       <s:Rotate3D target="{image}" 
angleXFrom="0" angleXTo="0" angleZFrom="0" autoCenterTransform="true" 
angleYTo="360" angleYFrom="0" autoCenterProjection="true" angleZTo="0"/>
+                                       <s:Fade target="{group}" 
startDelay="320"/>
+                               </s:Parallel>
+               </s:Transition>
+       </s:transitions>
+       
+       <mx:Image id="image" source="{data.image}" horizontalCenter="0"
+                         width="50" height="94"/>
+
+       <s:Group id="group" top="0" bottom="0" left="0" right="0" 
visible.normal="false">
+
+               <s:Rect id="rect" left="0" right="0" top="0" bottom="0" 
radiusX="4" radiusY="4">
+                       <s:fill>
+                               <s:SolidColor color="black" alpha="0.5"/>
+                       </s:fill>
+               </s:Rect>
+               
+               <s:Label text="{data.name}" verticalCenter="-20" 
horizontalCenter="0" color="white"/> 
+               <s:Label text="{data.color}" verticalCenter="0" 
horizontalCenter="0" color="white"/> 
+               <s:Label text="{cf.format(data.price)}" verticalCenter="20" 
horizontalCenter="0" color="white"/>
+               
+       </s:Group>
+
+</s:ItemRenderer>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/flex-utilities/blob/051a1e55/TourDeFlex/TourDeFlex3/src/spark/layouts/skins/TDFPanelSkin.mxml
----------------------------------------------------------------------
diff --git a/TourDeFlex/TourDeFlex3/src/spark/layouts/skins/TDFPanelSkin.mxml 
b/TourDeFlex/TourDeFlex3/src/spark/layouts/skins/TDFPanelSkin.mxml
new file mode 100644
index 0000000..f9151dc
--- /dev/null
+++ b/TourDeFlex/TourDeFlex3/src/spark/layouts/skins/TDFPanelSkin.mxml
@@ -0,0 +1,171 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+
+  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.
+
+-->
+
+
+<!--- Custom Spark Panel Skin created for Tour de Flex.  
+
+@langversion 3.0
+@playerversion Flash 10
+@playerversion AIR 1.5
+@productversion Flex 4
+-->
+<s:SparkSkin xmlns:fx="http://ns.adobe.com/mxml/2009"; 
xmlns:s="library://ns.adobe.com/flex/spark" alpha.disabled="0.5"
+                        blendMode.disabled="layer">
+       
+       <fx:Metadata>
+               <![CDATA[ 
+               /** 
+               * @copy spark.skins.spark.ApplicationSkin#hostComponent
+               */
+               [HostComponent("spark.components.Panel")]
+               ]]>
+       </fx:Metadata> 
+       
+       <fx:Script>
+               /* Define the skin elements that should not be colorized. 
+               For panel, border and title backround are skinned, but the 
content area and title text are not. */
+               static private const exclusions:Array = ["background", 
"titleDisplay", "contentGroup", "bgFill"];
+               
+               /** 
+                * @copy spark.skins.SparkSkin#colorizeExclusions
+                */     
+               override public function get colorizeExclusions():Array {return 
exclusions;}
+               
+               /* Define the content fill items that should be colored by the 
"contentBackgroundColor" style. */
+               static private const contentFill:Array = [];
+               
+               /**
+                * @inheritDoc
+                */
+               override public function get contentItems():Array {return 
contentFill};
+       </fx:Script>
+       
+       <s:states>
+               <s:State name="normal" />
+               <s:State name="disabled" />
+               <s:State name="normalWithControlBar" />
+               <s:State name="disabledWithControlBar" />
+       </s:states>
+       
+       <!-- drop shadow -->
+       <s:RectangularDropShadow id="shadow" blurX="20" blurY="20" alpha="0.32" 
distance="11" 
+                                                        angle="90" 
color="#000000" left="0" top="0" right="0" bottom="0"/>
+       
+       <!-- layer 1: border -->
+       <s:Rect left="0" right="0" top="0" bottom="0">
+               <s:stroke>
+                       <s:SolidColorStroke color="0" alpha="0.50" weight="1" />
+               </s:stroke>
+       </s:Rect>
+       
+       
+       <!-- layer 2: background fill -->
+       <!-- This layer was modified for Tour de Flex samples to have a 
gradient border at the bottom. -->
+       <s:Rect left="0" right="0" bottom="0" height="15">
+               <s:fill>
+                       <s:LinearGradient rotation="90">
+                               <s:GradientEntry color="0xE2E2E2" />
+                               <s:GradientEntry color="0x000000" />
+                       </s:LinearGradient>
+               </s:fill>
+       </s:Rect>
+       
+       <!-- layer 3: contents -->
+       <!--- contains the vertical stack of titlebar content and controlbar -->
+       <s:Group left="1" right="1" top="1" bottom="1" >
+               <s:layout>
+                       <s:VerticalLayout gap="0" horizontalAlign="justify" />
+               </s:layout>
+               
+               <s:Group id="topGroup" >
+                       <!-- layer 0: title bar fill -->
+                       <!-- Note: We have custom skinned the title bar to be 
solid black for Tour de Flex -->
+                       <s:Rect id="tbFill" left="0" right="0" top="0" 
bottom="1" >
+                               <s:fill>
+                                       <s:SolidColor color="0x000000" />
+                               </s:fill>
+                       </s:Rect>
+                       
+                       <!-- layer 1: title bar highlight -->
+                       <s:Rect id="tbHilite" left="0" right="0" top="0" 
bottom="0" >
+                               <s:stroke>
+                                       <s:LinearGradientStroke rotation="90" 
weight="1">
+                                               <s:GradientEntry 
color="0xEAEAEA" />
+                                               <s:GradientEntry 
color="0xD9D9D9" />
+                                       </s:LinearGradientStroke>
+                               </s:stroke>
+                       </s:Rect>
+                       
+                       <!-- layer 2: title bar divider -->
+                       <s:Rect id="tbDiv" left="0" right="0" height="1" 
bottom="0">
+                               <s:fill>
+                                       <s:SolidColor color="0xC0C0C0" />
+                               </s:fill>
+                       </s:Rect>
+                       
+                       <!-- layer 3: text -->
+                       <!--- Defines the appearance of the PanelSkin class's 
title bar. -->
+                       <!-- Note: The title text display has been slightly 
modified for Tour de Flex. -->
+                       <s:Label id="titleDisplay" lineBreak="explicit"
+                                                 left="9" top="1" bottom="0" 
minHeight="30"
+                                                 verticalAlign="middle" 
fontWeight="bold" color="#E2E2E2">
+                       </s:Label>
+               </s:Group>
+               
+               <!--
+               Note: setting the minimum size to 0 here so that changes to the 
host component's
+               size will not be thwarted by this skin part's minimum size.   
This is a compromise,
+               more about it here: http://bugs.adobe.com/jira/browse/SDK-21143
+               -->
+               <s:Group id="contentGroup" width="100%" height="100%" 
minWidth="0" minHeight="0">
+               </s:Group>
+               
+               <s:Group id="bottomGroup" minWidth="0" minHeight="0"
+                                includeIn="normalWithControlBar, 
disabledWithControlBar" >
+                       
+                       <!-- layer 0: control bar background -->
+                       <!-- Note: We are skinning this to be the gradient in 
case we do specify control
+                       bar content, but it will only display if there's a 
controlBarContent
+                       property specified.-->
+                       <s:Rect left="0" right="0" bottom="0" top="0" 
height="15">
+                               <s:fill>
+                                       <s:LinearGradient rotation="90">
+                                               <s:GradientEntry 
color="0xE2E2E2" />
+                                               <s:GradientEntry 
color="0x000000" />
+                                       </s:LinearGradient>
+                               </s:fill>
+                       </s:Rect>
+                       
+                       <!-- layer 1: control bar divider line -->
+                       <s:Rect left="0" right="0" top="0" height="1" >
+                               <s:fill>
+                                       <s:SolidColor color="0xCDCDCD" />
+                               </s:fill>
+                       </s:Rect>
+                       
+                       <!-- layer 2: control bar -->
+                       <s:Group id="controlBarGroup" left="0" right="0" 
top="1" bottom="0" minWidth="0" minHeight="0">
+                               <s:layout>
+                                       <s:HorizontalLayout paddingLeft="10" 
paddingRight="10" paddingTop="10" paddingBottom="10" />
+                               </s:layout>
+                       </s:Group>
+               </s:Group>
+       </s:Group>
+</s:SparkSkin>

http://git-wip-us.apache.org/repos/asf/flex-utilities/blob/051a1e55/TourDeFlex/TourDeFlex3/src/spark/states/AnimateShaderTransitionEffect.mxml
----------------------------------------------------------------------
diff --git 
a/TourDeFlex/TourDeFlex3/src/spark/states/AnimateShaderTransitionEffect.mxml 
b/TourDeFlex/TourDeFlex3/src/spark/states/AnimateShaderTransitionEffect.mxml
new file mode 100644
index 0000000..22397bd
--- /dev/null
+++ b/TourDeFlex/TourDeFlex3/src/spark/states/AnimateShaderTransitionEffect.mxml
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+
+  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.
+
+-->
+<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"; 
+                          xmlns:s="library://ns.adobe.com/flex/spark" 
+                          xmlns:mx="library://ns.adobe.com/flex/mx" 
+                          backgroundColor="0x000000" 
viewSourceURL="srcview/index.html">
+       
+       <s:states>
+               <s:State name="default"/>
+               <s:State name="flipped"/>
+       </s:states>
+       
+       <s:transitions>
+               <s:Transition id="t1">
+                       <s:AnimateTransitionShader
+                               target="{holder}"
+                               duration="1000" 
+                               
shaderByteCode="@Embed(source='assets/twist.pbj', 
mimeType='application/octet-stream')"/>
+               </s:Transition>
+       </s:transitions>
+       
+       <s:HGroup left="190" top="7">
+               <s:Group id="holder">
+                       <s:BitmapImage
+                               source="@Embed('assets/back.png')"
+                               visible="true" visible.flipped="false"/>
+                       <s:BitmapImage
+                               source="@Embed('assets/c1.png')"
+                               visible="false" visible.flipped="true"/>
+               </s:Group>
+       </s:HGroup>
+       <s:VGroup top="10" right="5" width="30%">
+               <s:Label text="AnimateShaderTransition Sample" fontSize="18" 
color="#B7B6B6"/>
+               <s:Label color="#FFFFFF" width="200" verticalAlign="justify"
+                                text="AnimateShaderTransition animates a 
shader between two images. Click the button below to see the effect."/>
+               <s:Button id="playButton"
+                                 label="Play Animation"
+                                 click="currentState = (currentState == 
'flipped') ? 'default' : 'flipped';" />
+       </s:VGroup>
+       
+</s:Application>

http://git-wip-us.apache.org/repos/asf/flex-utilities/blob/051a1e55/TourDeFlex/TourDeFlex3/src/spark/states/assets/back.png
----------------------------------------------------------------------
diff --git a/TourDeFlex/TourDeFlex3/src/spark/states/assets/back.png 
b/TourDeFlex/TourDeFlex3/src/spark/states/assets/back.png
new file mode 100644
index 0000000..19367fb
Binary files /dev/null and 
b/TourDeFlex/TourDeFlex3/src/spark/states/assets/back.png differ

Reply via email to