incubator-flex-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From t...@apache.org
Subject svn commit: r1228400 [4/6] - in /incubator/flex/whiteboard/navigators: ./ .settings/ src/ src/ws/ src/ws/tink/ src/ws/tink/spark/ src/ws/tink/spark/containers/ src/ws/tink/spark/containers/supportClasses/ src/ws/tink/spark/controls/ src/ws/tink/spark/c...
Date Fri, 06 Jan 2012 20:58:45 GMT
Added: incubator/flex/whiteboard/navigators/src/ws/tink/spark/layouts/AccordionLayout.as
URL: http://svn.apache.org/viewvc/incubator/flex/whiteboard/navigators/src/ws/tink/spark/layouts/AccordionLayout.as?rev=1228400&view=auto
==============================================================================
--- incubator/flex/whiteboard/navigators/src/ws/tink/spark/layouts/AccordionLayout.as (added)
+++ incubator/flex/whiteboard/navigators/src/ws/tink/spark/layouts/AccordionLayout.as Fri Jan  6 20:58:43 2012
@@ -0,0 +1,1433 @@
+/*
+Copyright (c) 2011 Tink Ltd - http://www.tink.ws
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+documentation files (the "Software"), to deal in the Software without restriction, including without limitation 
+the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
+to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions
+of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO 
+THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+*/
+
+package ws.tink.spark.layouts
+{
+	import flash.display.DisplayObject;
+	import flash.geom.Matrix;
+	import flash.geom.Rectangle;
+	
+	import mx.core.ILayoutElement;
+	import mx.core.ISelectableList;
+	import mx.core.IVisualElement;
+	import mx.core.mx_internal;
+	
+	import spark.components.supportClasses.ButtonBarBase;
+	import spark.components.supportClasses.GroupBase;
+	import spark.effects.animation.Animation;
+	
+	import ws.tink.spark.layouts.supportClasses.AnimationNavigatorLayoutBase;
+	import ws.tink.spark.layouts.supportClasses.LayoutAxis;
+
+	use namespace mx_internal;
+	
+	/**
+	 *  An AccordionLayout class arranges the layout elements in a vertical
+	 *  or horizontal sequence, with one of them at a time fully visible.
+	 * 
+	 *  <p>The position of the elements is determined by arranging them
+	 *  in a sequence, top to bottom or left to right depending on the
+	 *  value or <code>duration</code>.</p>
+	 * 
+	 *  <p>If the <code>target</code> of the layout implements ISelectable list,
+	 *  a ButtonBarBase can be set using the <code>buttonBar</code> property and the layout
+	 *  will connect the <code>target</code> and ButtonBarBase together so that the 
+	 *  ButtonBarBase can be used to navigate through the elements.</p>
+	 *
+	 *  @mxml
+	 *
+	 *  <p>The <code>&lt;st:Accordion&gt;</code> tag inherits all of the
+	 *  tag attributes of its superclass, and adds the following tag attributes:</p>
+	 *
+	 *  <pre>
+	 *  &lt;st:AccordionLayout
+	 *    <strong>Properties</strong>
+	 *    buttonRotation="none|left|right"
+	 *    direction="vertical|horizontal"
+	 *    duration="700"
+	 *    easer=""<i>IEaser</i>""
+	 *    labelField="label"
+	 *    labelFunction="null"
+	 *    layoutAllButtonBarBounds="true"
+	 *    minElementSize="0"
+	 *    useScrollRect"true"
+	 *  /&gt;
+	 *  </pre>
+	 *
+	 *  @includeExample examples/AccordionExample.mxml
+	 *
+	 *  @see ws.tink.spark.layouts.AccordionLayout
+	 *
+	 *  @langversion 3.0
+	 *  @playerversion Flash 10
+	 *  @playerversion AIR 1.5
+	 *  @productversion Flex 4
+	 */
+	public class AccordionLayout extends AnimationNavigatorLayoutBase
+	{
+		
+		
+		//--------------------------------------------------------------------------
+		//
+		//  Constructor
+		//
+		//--------------------------------------------------------------------------
+		
+		/**
+		 *  Constructor. 
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 1.5
+		 *  @productversion Flex 4
+		 */  
+		public function AccordionLayout()
+		{
+			super( AnimationNavigatorLayoutBase.DIRECT );
+			_measuredCache = new MeasuredCache();
+			_buttonLayout = new ButtonLayout( this );
+		}
+		
+		
+		//--------------------------------------------------------------------------
+		//
+		//  Variables
+		//
+		//--------------------------------------------------------------------------
+		
+		/**
+		 *  @private
+		 */
+		private var _proposedSelectedIndexOffset	: Number = 0;
+		
+		/**
+		 *  @private
+		 */
+		private var _buttonLayout:ButtonLayout;
+		
+		/**
+		 *  @private
+		 */
+		private var _elementSizes:Vector.<ElementSize> = new Vector.<ElementSize>();
+		
+		/**
+		 *  @private
+		 */
+		private var _animator:Animation;
+		
+		/**
+		 *  @private
+		 */
+		private var _measuredCache:MeasuredCache;
+		
+		/**
+		 *  @private
+		 *  Flag to indicate the size and positioning of the buttonBar have changed.
+		 */
+		private var _buttonBarChanged:Boolean;
+		
+		
+		//--------------------------------------------------------------------------
+		//
+		//  Properties
+		//
+		//--------------------------------------------------------------------------
+		
+		//----------------------------------
+		//  buttonRotation
+		//----------------------------------    
+		
+		/**
+		 *  @private
+		 *  Storage property for buttonRotation.
+		 */
+		private var _buttonRotation:String = "none";
+		
+		[Inspectable(category="General", enumeration="none,left,right", defaultValue="none")]
+		
+		/** 
+		 *  rotateButtonBar.
+		 * 
+		 *  @default "vertical"
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 1.5
+		 *  @productversion Flex 4
+		 */
+		public function get buttonRotation():String
+		{
+			return _buttonRotation;
+		}
+		/**
+		 *  @private
+		 */
+		public function set buttonRotation( value:String ):void
+		{
+			if( value == _buttonRotation ) return;
+			
+			_buttonRotation = value;
+			
+			_buttonBarChanged = true;
+			_elementSizesInvalid = true;
+			_buttonLayout.invalidateTargetDisplayList();
+			invalidateTargetDisplayList();
+			invalidateTargetSize();
+		}
+		
+		
+		//----------------------------------
+		//  direction
+		//----------------------------------    
+		
+		/**
+		 *  @private
+		 *  Storage property for direction.
+		 */
+		private var _direction:String = LayoutAxis.VERTICAL;
+		
+		[Inspectable(category="General", enumeration="vertical,horizontal", defaultValue="vertical")]
+		
+		/** 
+		 *  direction.
+		 * 
+		 *  @default "vertical"
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 1.5
+		 *  @productversion Flex 4
+		 */
+		public function get direction():String
+		{
+			return _direction;
+		}
+		/**
+		 *  @private
+		 */
+		public function set direction( value:String ):void
+		{
+			if( value == _direction ) return;
+			
+			_direction = value;
+			
+			_buttonBarChanged = true;
+			_elementSizesInvalid = true;
+			_buttonLayout.invalidateTargetDisplayList();
+			_buttonLayout.invalidateTargetSize();
+			invalidateTargetDisplayList();
+			invalidateTargetSize();
+		}
+		
+		
+		//----------------------------------
+		//  overlayButtonBar
+		//----------------------------------    
+		
+		/**
+		 *  @private
+		 *  Storage property for overlayButtonBar.
+		 */
+		private var _layoutAllButtonBarBounds:Boolean = false;
+		
+		[Inspectable(category="General", enumeration="true,false", defaultValue="true")]
+		
+		/** 
+		 *  overlayButtonBar.
+		 * 
+		 *  @default "vertical"
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 1.5
+		 *  @productversion Flex 4
+		 */
+		public function get layoutAllButtonBarBounds():Boolean
+		{
+			return _layoutAllButtonBarBounds;
+		}
+		/**
+		 *  @private
+		 */
+		public function set layoutAllButtonBarBounds( value:Boolean ):void
+		{
+			if( value == _layoutAllButtonBarBounds ) return;
+			
+			_layoutAllButtonBarBounds = value;
+			
+			_buttonBarChanged = true;
+			_buttonLayout.invalidateTargetDisplayList();
+			_buttonLayout.invalidateTargetSize();
+			invalidateTargetDisplayList();
+			invalidateTargetSize();
+		}
+		
+		//----------------------------------
+		//  minElementSize
+		//----------------------------------    
+		
+		/**
+		 *  @private
+		 *  Storage property for minElementSize.
+		 */
+		private var _minElementSize:Number = 0;
+		
+		/** 
+		 *  The minumm size of an element when it's element index isn't the
+		 *  selectedIndex of the layout.
+		 * 
+		 *  @default 0
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 1.5
+		 *  @productversion Flex 4
+		 */
+		public function get minElementSize():Number
+		{
+			return _minElementSize;
+		}
+		/**
+		 *  @private
+		 */
+		public function set minElementSize( value:Number ):void
+		{
+			if( value == _minElementSize ) return;
+			
+			_minElementSize = value;
+			
+			_elementSizesInvalid = true;
+			invalidateTargetDisplayList();
+			if( target ) target.invalidateSize();
+		}
+		
+		
+//		//----------------------------------
+//		//  verticalAlign
+//		//----------------------------------    
+//		
+//		/**
+//		 *  @private
+//		 *  Storage property for verticalAlign.
+//		 */
+//		private var _verticalAlign:String = VerticalAlign.JUSTIFY;
+//		
+//		[Inspectable(category="General", enumeration="justify", defaultValue="justify")]
+//		
+//		/** 
+//		 *  The vertical alignment of layout elements.
+//		 * 
+//		 *  <p>If the value is <code>"bottom"</code>, <code>"middle"</code>, 
+//		 *  or <code>"top"</code> then the layout elements are aligned relative 
+//		 *  to the container's <code>contentHeight</code> property.</p>
+//		 * 
+//		 *  <p>If the value is <code>"contentJustify"</code> then the actual
+//		 *  height of the layout element is set to 
+//		 *  the container's <code>contentHeight</code> property. 
+//		 *  The content height of the container is the height of the largest layout element. 
+//		 *  If all layout elements are smaller than the height of the container, 
+//		 *  then set the height of all the layout elements to the height of the container.</p>
+//		 * 
+//		 *  <p>If the value is <code>"justify"</code> then the actual height
+//		 *  of the layout elements is set to the container's height.</p>
+//		 *
+//		 *  <p>This property does not affect the layout's measured size.</p>
+//		 *  
+//		 *  @default "justify"
+//		 *  
+//		 *  @langversion 3.0
+//		 *  @playerversion Flash 10
+//		 *  @playerversion AIR 1.5
+//		 *  @productversion Flex 4
+//		 */
+//		public function get verticalAlign():String
+//		{
+//			return _verticalAlign;
+//		}
+//		/**
+//		 *  @private
+//		 */
+//		public function set verticalAlign( value:String ):void
+//		{
+////			if( value == _verticalAlign ) return;
+////			
+////			_verticalAlign = value;
+////			
+////			invalidateTargetDisplayList();
+//		}
+//		
+//		
+//		//----------------------------------
+//		//  horizontalAlign
+//		//----------------------------------  
+//		
+//		/**
+//		 *  @private
+//		 *  Storage property for horizontalAlign.
+//		 */
+//		private var _horizontalAlign:String = HorizontalAlign.JUSTIFY;
+//		
+//		[Inspectable(category="General", enumeration="justify", defaultValue="justify")]
+//		
+//		/** 
+//		 *  The horizontal alignment of layout elements.
+//		 *  If the value is <code>"left"</code>, <code>"right"</code>, or <code>"center"</code> then the 
+//		 *  layout element is aligned relative to the container's <code>contentWidth</code> property.
+//		 * 
+//		 *  <p>If the value is <code>"contentJustify"</code>, then the layout element's actual
+//		 *  width is set to the <code>contentWidth</code> of the container.
+//		 *  The <code>contentWidth</code> of the container is the width of the largest layout element. 
+//		 *  If all layout elements are smaller than the width of the container, 
+//		 *  then set the width of all layout elements to the width of the container.</p>
+//		 * 
+//		 *  <p>If the value is <code>"justify"</code> then the layout element's actual width
+//		 *  is set to the container's width.</p>
+//		 *
+//		 *  <p>This property does not affect the layout's measured size.</p>
+//		 *  
+//		 *  @default "justify"
+//		 *  
+//		 *  @langversion 3.0
+//		 *  @playerversion Flash 10
+//		 *  @playerversion AIR 1.5
+//		 *  @productversion Flex 4
+//		 */
+//		public function get horizontalAlign():String
+//		{
+//			return _horizontalAlign;
+//		}
+//		/**
+//		 *  @private
+//		 */
+//		public function set horizontalAlign( value:String ):void
+//		{
+////			if( value == _horizontalAlign ) return;
+////			
+////			_horizontalAlign = value;
+////			
+////			invalidateTargetDisplayList();
+//		}
+		
+		
+		//----------------------------------
+		//  buttonBar
+		//----------------------------------    
+		
+		/**
+		 *  @private
+		 *  Storage property for buttonBar.
+		 */
+		private var _buttonBar:ButtonBarBase;
+		
+		/**
+		 *  useScrollRect
+		 * 
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 1.5
+		 *  @productversion Flex 4
+		 */
+		public function get buttonBar():ButtonBarBase
+		{
+			return _buttonBar;
+		}
+		/**
+		 *  @private
+		 */
+		public function set buttonBar( value:ButtonBarBase ):void
+		{
+			if( _buttonBar == value ) return;
+			_buttonBar = value;
+			
+			if( _buttonBar )
+			{
+				_buttonBar.layout = _buttonLayout;
+				if( _buttonBar && target is ISelectableList ) _buttonBar.dataProvider = ISelectableList( target );
+				if( target ) target.invalidateSize();
+			}
+		}
+		
+		
+		//----------------------------------
+		//  useScrollRect
+		//----------------------------------    
+		
+		/**
+		 *  @private
+		 *  Storage property for useScrollRect.
+		 */
+		private var _useScrollRect:Boolean = true;
+		
+		/**
+		 *  useScrollRect
+		 * 
+		 *  @default true
+		 *
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 1.5
+		 *  @productversion Flex 4
+		 */
+		public function get useScrollRect():Boolean
+		{
+			return _useScrollRect;
+		}
+		/**
+		 *  @private
+		 */
+		public function set useScrollRect( value:Boolean ):void
+		{
+			if( _useScrollRect == value ) return;
+			
+			_useScrollRect = value;
+		}
+		
+		
+		
+		//--------------------------------------------------------------------------
+		//
+		//  Overridden Properties
+		//
+		//--------------------------------------------------------------------------
+		
+		//----------------------------------
+		//  target
+		//----------------------------------    
+		
+		/**
+		 *  @inheritDoc
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 1.5
+		 *  @productversion Flex 4
+		 */
+		override public function set target(value:GroupBase):void
+		{
+			if( target == value ) return;
+
+			super.target = value;
+			
+			if( _buttonBar && target is ISelectableList ) _buttonBar.dataProvider = ISelectableList( target );
+		}
+		
+		
+		
+		
+		//--------------------------------------------------------------------------
+		//
+		//  Methods
+		//
+		//--------------------------------------------------------------------------
+		
+		
+		
+		/**
+		 *  @private
+		 *  Sort function used to store the list of element sizes in display list order.
+		 */
+		private function sortElementSizes( a:ElementSize, b:ElementSize ):int
+		{
+			if( a.displayListIndex < b.displayListIndex ) return -1;
+			if( a.displayListIndex > b.displayListIndex ) return 1;
+			return 0;
+		}
+		
+		
+		
+		//--------------------------------------------------------------------------
+		//
+		//  Overridden Methods
+		//
+		//--------------------------------------------------------------------------
+		
+		private var _elementSizesInvalid:Boolean;
+		
+		public function invalidateElementSizes():void
+		{
+			_elementSizesInvalid = true;
+			invalidateTargetDisplayList();
+		}
+		
+		
+		/**
+		 *  @inheritDoc
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 1.5
+		 *  @productversion Flex 4
+		 */
+		
+		override protected function updateDisplayListBetween():void
+		{
+			if( sizeChangedInLayoutPass || _buttonBarChanged )
+			{
+				_buttonBarChanged = false;
+				
+				// TODO I think this should solve the issue of animating when resizing.
+				// If we are resizing due to an index change we want to animate,
+				// if its not due to an index change we do not want to animate.
+				if( !animationValue ) clearVirtualLayoutCache();
+					
+				_elementSizesInvalid = true;
+				_buttonLayout.invalidateTargetDisplayList();
+				if( _buttonBar && target )
+				{
+					_buttonBar.includeInLayout = !layoutAllButtonBarBounds;
+					
+					if( _layoutAllButtonBarBounds && !isNaN( unscaledWidth ) && !isNaN( unscaledHeight ) )
+					{
+						_buttonBar.setLayoutBoundsSize( unscaledWidth, unscaledHeight );
+						_buttonBar.setLayoutBoundsPosition( target.x, target.y );
+					}
+				}
+			}
+		}
+		
+		
+		
+		override public function measure():void
+		{
+			super.measure();
+
+			if( !target ) return;
+			
+			if( !indicesInLayout || !indicesInLayout.length )
+			{
+				target.measuredWidth = target.measuredMinWidth;
+				target.measuredHeight = target.measuredMinHeight;
+				return;
+			}  
+			
+			var i:int
+			var element:ILayoutElement;
+			
+			if( _buttonBarChanged ) _measuredCache.reset();
+			
+			if( !useVirtualLayout )
+			{
+				// If we are not using a virtual layout, reset the measured cache
+				// and measure all elements again.
+				_measuredCache.reset();
+				for each( i in indicesInLayout )
+				{
+					_measuredCache.cache( target.getElementAt( indicesInLayout[ i ] ) );
+				}
+			}
+			else if( selectedIndex != -1 )
+			{
+				// If we are using a virtual layout, cache the size of the selected item.
+				_measuredCache.cache( target.getElementAt( indicesInLayout[ selectedIndex ] ) );
+			}
+			
+			const prevButtonSize:Number = _buttonLayout._totalSize;
+			_buttonLayout._totalSize = 0;
+			_buttonLayout._buttonSizes = new Vector.<int>();
+			
+			if( _buttonBar )
+			{
+				
+				var matrix:Matrix = new Matrix();
+				var rotation:Number = buttonRotation == "none" ? 0 : buttonRotation == "left" ? -90 : 90;
+				if( rotation ) matrix.rotate( rotation * ( Math.PI / 180 ) );
+
+				var size:Number;
+				const numElements:int = target.numElements;
+				var s:Number = 0;
+				for( i = 0; i < numElements; i++ )
+				{
+					element = _buttonLayout.target.getElementAt( i );
+					
+					if( !element ) continue;
+					if( matrix ) element.setLayoutMatrix( matrix, true );
+					
+					if( direction == LayoutAxis.VERTICAL  )
+					{
+						size = element.getPreferredBoundsHeight();
+						if( i < numElements - 1 ) size--;
+						_buttonLayout._totalSize += size;
+					}
+					else
+					{
+						size = element.getPreferredBoundsWidth();
+						if( i < numElements - 1 ) size--;
+						_buttonLayout._totalSize += size;
+					}
+					
+					_buttonLayout._buttonSizes[ i ] = size;
+				}
+			}
+			
+			var w:Number = 0;
+			var h:Number = 0;
+			switch( direction )
+			{
+				case  LayoutAxis.VERTICAL :
+				{
+					if( minElementSize ) h += minElementSize * ( numElementsInLayout - 1 );
+					if( _buttonBar ) h += _buttonLayout._totalSize;
+					break;
+				}
+				case  LayoutAxis.HORIZONTAL :
+				{
+					if( minElementSize ) w += minElementSize * ( numElementsInLayout - 1 );
+					if( _buttonBar ) w += _buttonLayout._totalSize;
+					break;
+				}
+			}
+			
+			
+			target.measuredWidth = _measuredCache.measuredWidth + w;
+			target.measuredHeight = _measuredCache.measuredHeight + h;
+			target.measuredMinWidth = target.measuredWidth;
+			target.measuredMinHeight = target.measuredHeight;
+			
+			// Use Math.ceil() to make sure that if the content partially occupies
+			// the last pixel, we'll count it as if the whole pixel is occupied.
+			target.measuredWidth = Math.ceil( target.measuredWidth );    
+			target.measuredHeight = Math.ceil( target.measuredHeight );    
+			target.measuredMinWidth = Math.ceil( target.measuredMinWidth );    
+			target.measuredMinHeight = Math.ceil( target.measuredMinHeight );  
+			
+			if( _buttonBar )
+			{
+				_buttonBar.invalidateSize();
+				_buttonBar.validateNow();
+				
+				if( target.measuredWidth < _buttonBar.measuredWidth ) target.measuredWidth = Math.ceil( _buttonBar.measuredWidth );
+				if( target.measuredMinWidth < _buttonBar.measuredMinWidth ) target.measuredMinWidth = Math.ceil( _buttonBar.measuredMinWidth );
+				
+				if( target.measuredHeight < _buttonBar.measuredHeight ) target.measuredHeight = Math.ceil( _buttonBar.measuredHeight );
+				if( target.measuredMinHeight < _buttonBar.measuredMinHeight ) target.measuredMinHeight = Math.ceil( _buttonBar.measuredMinHeight );
+			}
+			
+			if( prevButtonSize != _buttonLayout._totalSize ) 
+			{
+				invalidateElementSizes();
+				invalidateTargetDisplayList();
+			}
+		}
+		
+		
+		/**
+		 *  @inheritDoc
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 1.5
+		 *  @productversion Flex 4
+		 */
+		override public function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
+		{
+			super.updateDisplayList( unscaledWidth, unscaledHeight );
+			
+			_elementSizesInvalid = false;
+			updateDisplayListElements();
+		}
+		
+		
+		/**
+		 *  @inheritDoc
+		 *
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 1.5
+		 *  @productversion Flex 4
+		 */
+		override public function clearVirtualLayoutCache():void
+		{
+			super.clearVirtualLayoutCache();
+			
+			// At this point we don't want animation so we clear out the element sizes.
+			_elementSizes = new Vector.<ElementSize>();
+			
+			_measuredCache.reset();
+		}
+		
+		
+		
+		/**
+		 *  @private
+		 */
+		private function updateDisplayListElements():void
+		{
+			var prevSize:Number;
+			var elementSize:ElementSize;
+			var element:IVisualElement;
+			var elementPos:Number = 0;
+			const offsetMultiplier:Number = 1 - animationValue;
+			const numElements:int = _elementSizes.length;
+			for( var i:int = 0; i < numElements; i++ )
+			{
+				if( _buttonLayout._buttonSizes.length > i )
+				{
+					element = _buttonLayout.target.getElementAt( i );
+					if( direction == LayoutAxis.VERTICAL )
+					{
+						element.setLayoutBoundsPosition( 0, elementPos );
+					}
+					else
+					{
+						element.setLayoutBoundsPosition( elementPos, 0 );
+					}
+					elementPos += _buttonLayout._buttonSizes[ i ];
+				}
+				
+				elementSize = _elementSizes[ i ];
+				prevSize = elementSize.size;
+				elementSize.size = elementSize.start + ( elementSize.diff * offsetMultiplier );
+				
+				if( elementSize.elementChanged )
+				{
+					if( direction == LayoutAxis.VERTICAL )
+					{
+						if( _useScrollRect && elementSize.element is DisplayObject )
+						{
+							DisplayObject( elementSize.element ).scrollRect = new Rectangle( 0, 0, unscaledWidth, elementSize.size );
+							
+							elementSize.element.setLayoutBoundsSize( unscaledWidth, unscaledHeight - _buttonLayout._totalSize );
+						}
+						else
+						{
+							elementSize.element.setLayoutBoundsSize( unscaledWidth, elementSize.size );
+						}
+						
+						elementSize.element.setLayoutBoundsPosition( 0, elementPos );
+					}
+					else
+					{
+						if( _useScrollRect && elementSize.element is DisplayObject )
+						{
+							DisplayObject( elementSize.element ).scrollRect = new Rectangle( 0, 0, elementSize.size, unscaledHeight );
+							elementSize.element.setLayoutBoundsSize( unscaledWidth - _buttonLayout._totalSize, unscaledHeight );
+						}
+						else
+						{
+							elementSize.element.setLayoutBoundsSize( elementSize.size, unscaledHeight );
+						}
+						
+						elementSize.element.setLayoutBoundsPosition( elementPos, 0 );
+					}
+					
+					elementPos += elementSize.size;
+				}
+			}
+		}
+		
+		
+		private function update( e:ElementSize, selectedSize:Number, creatingAll:Boolean ):void
+		{
+			if( creatingAll )
+			{
+				e.size = e.layoutIndex == selectedIndex ? selectedSize : minElementSize;
+				e.start = e.size;
+			}
+			else
+			{
+				e.start = e.size;
+				e.diff = e.layoutIndex == selectedIndex ? selectedSize - e.start : minElementSize - e.start;
+			}
+		}
+		
+		
+		
+		
+		/**
+		 *  @inheritDoc
+		 *
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 1.5
+		 *  @productversion Flex 4
+		 */
+		override protected function updateDisplayListVirtual():void
+		{
+			super.updateDisplayListVirtual();		
+			
+			if( !indicesInLayout.length ) return;
+			
+			var i:int;
+			var elementSize:ElementSize;
+			const numElementSizes:int = _elementSizes.length;
+			const creatingAll:Boolean = numElementSizes == 0;
+			
+			if( _elementSizesInvalid )
+			{
+				// We use this vector to store a reference to the element index
+				// of any item that is currently in the display list.
+				// If we are creating a new elementSize, we must make sure that this element
+				// is actually added (i.e. not worry about being virtual as it's already created).
+				const indicesCreated:Vector.<int> = new Vector.<int>();
+				const size:Number = direction == LayoutAxis.VERTICAL ? unscaledHeight : unscaledWidth;
+				const selectedSize:Number = size - _buttonLayout._totalSize - ( minElementSize * ( numElementsInLayout - 1 ) );
+				
+				// Store a reference to the indices that we need ElementSize items for.
+				var indicesRequired:Vector.<int>;
+				var indicesRequiredIndex:int;
+				var element:IVisualElement;
+				
+				if( buttonBar || minElementSize )
+				{
+					indicesRequired = indicesInLayout.concat()
+				}
+				else
+				{
+					if( target.numChildren > 1 )
+					{
+						for( i = 0; i < target.numChildren; i++ )
+						{
+							element =  IVisualElement( target.getChildAt( i ) );
+							if( element.includeInLayout )
+							{
+								// Store a reference to the the element index of all children.
+								indicesCreated.push( target.getElementIndex( element ) );
+								
+							}
+						}
+					}
+					
+					// Also add this as an index that is required.
+					indicesRequired = indicesCreated.concat();
+					
+					// Make sure we always push the selectedIndex
+					var selected:int = indicesInLayout[ selectedIndex ];
+					if( indicesRequired.indexOf( selected ) == -1 ) indicesRequired.push( selected );
+				}
+				
+				
+				for( i = numElementSizes - 1; i >= 0; i-- )
+				{
+					elementSize = _elementSizes[ i ];
+					
+					// Remove ElementSize items that are not in the layout.
+					indicesRequiredIndex = indicesRequired.indexOf( elementSize.displayListIndex );
+					if( indicesRequiredIndex == -1 && !elementSize.size )
+					{
+						_elementSizes.splice( i, 1 );
+					}
+					// Update ElementSize items.
+					else
+					{
+						if( indicesRequiredIndex != -1 ) indicesRequired.splice( indicesRequiredIndex, 1 )
+						
+						// Only get the virtual element if it is the selectedIndex,
+						// its start size is bigger than 0, or its diff in size is bigger than 0.
+						if( elementSize.displayListIndex == selectedIndex || elementSize.start || elementSize.diff ) elementSize.element = target.getVirtualElementAt( elementSize.displayListIndex );
+						
+						update( elementSize, selectedSize, creatingAll );
+					}
+				}
+				
+				
+				// If we need to create some ElementSize items.
+				const numElementsRequired:int = indicesRequired.length;
+				for( i = 0; i < numElementsRequired; i++ )
+				{
+					elementSize = new ElementSize();
+					elementSize.diff = 0;
+					elementSize.size = minElementSize;
+					elementSize.displayListIndex = indicesRequired[ i ];
+					elementSize.layoutIndex = indicesInLayout.indexOf( elementSize.displayListIndex );
+					
+					// Only get the virtual element if it is the selectedIndex,
+					// its start size is bigger than 0.
+					if( elementSize.displayListIndex == selectedIndex || elementSize.start || 
+					indicesCreated.indexOf( elementSize.displayListIndex ) != -1 )
+					{
+						elementSize.element = target.getVirtualElementAt( elementSize.displayListIndex );
+					}
+					
+					_elementSizes.push( elementSize );
+					
+					update( elementSize, selectedSize, creatingAll );
+				}
+				
+				// If we've added items we now need to do a sort.
+				if( numElementsRequired ) _elementSizes.sort( sortElementSizes );
+			}
+			else
+			{
+				for( i = 0; i < numElementSizes; i++ )
+				{
+					elementSize = _elementSizes[ i ];
+					
+					// Only get the virtual element if its size is bigger than 0,
+					// or it is the selectedIndex.
+					if( selectedIndex == elementSize.layoutIndex || elementSize.size ) elementSize.element = target.getVirtualElementAt( elementSize.displayListIndex );
+				}
+			}
+		}
+		
+		
+		
+		/**
+		 *  @inheritDoc
+		 *
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 1.5
+		 *  @productversion Flex 4
+		 */
+		override protected function updateDisplayListReal():void
+		{
+			super.updateDisplayListReal();
+
+			if( !indicesInLayout.length ) return;
+			
+			var i:int;
+			var elementSize:ElementSize;
+			const numElementSizes:int = _elementSizes.length;
+			const creatingAll:Boolean = numElementSizes == 0;
+			
+			if( _elementSizesInvalid )
+			{
+				var indicesRequiredIndex:int;
+				
+				const size:Number = direction == LayoutAxis.VERTICAL ? unscaledHeight : unscaledWidth;
+				const selectedSize:Number = size - _buttonLayout._totalSize - ( minElementSize * ( numElementsInLayout - 1 ) );
+				
+				// Store a reference to the indices that we need ElementSize items for.
+				//const indicesRequired:Vector.<int> = buttonBar || minElementSize ? indicesInLayout.concat() : Vector.<int>( [ indicesInLayout[ selectedIndex ] ] );
+				const indicesRequired:Vector.<int> = indicesInLayout.concat();
+				
+				for( i = numElementSizes - 1; i >= 0; i-- )
+				{
+					elementSize = _elementSizes[ i ];
+					
+					// Remove ElementSize items that are not in the layout.
+					indicesRequiredIndex = indicesRequired.indexOf( elementSize.displayListIndex );
+					if( indicesRequiredIndex == -1 && !elementSize.size )
+					{
+						_elementSizes.splice( i, 1 );
+					}
+						// Update ElementSize items.
+					else
+					{
+						if( indicesRequiredIndex != -1 ) indicesRequired.splice( indicesRequiredIndex, 1 )
+						elementSize.element = target.getElementAt( elementSize.displayListIndex );
+						
+						update( elementSize, selectedSize, creatingAll );
+					}
+				}
+				
+				
+				// If we need to create some ElementSize items.
+				const numElementsRequired:int = indicesRequired.length;
+				for( i = 0; i < numElementsRequired; i++ )
+				{
+					elementSize = new ElementSize();
+					elementSize.diff = 0;
+					elementSize.size = minElementSize;
+					elementSize.displayListIndex = indicesRequired[ i ];
+					elementSize.layoutIndex = indicesInLayout.indexOf( elementSize.displayListIndex );
+					
+					elementSize.element = target.getElementAt( elementSize.displayListIndex );
+					
+					_elementSizes.push( elementSize );
+					
+					update( elementSize, selectedSize, creatingAll );
+				}
+				
+				// If we've added items we now need to do a sort.
+				if( numElementsRequired ) _elementSizes.sort( sortElementSizes );
+			}
+			else
+			{
+				for( i = 0; i < numElementSizes; i++ )
+				{
+					elementSize = _elementSizes[ i ];
+					elementSize.element = target.getElementAt( elementSize.displayListIndex );
+				}
+			}
+			
+		}
+		
+		/**
+		 *  @private
+		 */
+		override protected function invalidateSelectedIndex( index:int, offset:Number ):void
+		{
+			super.invalidateSelectedIndex( index, offset );
+			invalidateElementSizes();
+		}
+		
+		/**
+		 *  @private
+		 */
+		override protected function updateIndicesInView():void
+		{
+			super.updateIndicesInView();
+			indicesInView( 0, numElementsInLayout );
+		}
+		
+		/**
+		 *  @inheritDoc
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 1.5
+		 *  @productversion Flex 4
+		 */
+		override protected function restoreElement( element:IVisualElement ):void
+		{
+			super.restoreElement( element );
+			
+			if( element is DisplayObject ) DisplayObject( element ).scrollRect = null;
+		}
+        
+    }
+}
+import flash.geom.Matrix;
+
+import mx.core.ILayoutElement;
+import mx.core.IVisualElement;
+
+import spark.components.supportClasses.GroupBase;
+import spark.layouts.supportClasses.LayoutBase;
+
+import ws.tink.spark.layouts.AccordionLayout;
+import ws.tink.spark.layouts.supportClasses.LayoutAxis;
+
+
+internal class ElementSize
+{
+	public var start:Number;
+	public var diff:Number;
+	
+	public var displayListIndex:uint;
+	public var layoutIndex:uint;
+	
+	
+	
+	public function ElementSize()
+	{
+	}
+	
+	public function toString():String
+	{
+		return "start: " + start.toString() + " size: " + size.toString() + " displayListIndex: " + displayListIndex.toString() + " element: " + ( element == null ).toString() + "!!!!";
+	}
+	
+	private var _element:IVisualElement;
+	public function get element():IVisualElement
+	{
+		return _element;
+	}
+	public function set element( value:IVisualElement ):void
+	{
+		if( _element == value ) return;
+		
+		_element = value;
+		if( _element ) _elementChanged = true;
+	}
+	
+	private var _size:Number;
+	public function get size():Number
+	{
+		return _size;
+	}
+	public function set size( value:Number ):void
+	{
+		if( _size == value ) return;
+		
+		if( ( _size + value > 0 ) && _element ) _elementChanged = true;
+		_size = value;
+//		if( _size ) _elementChanged = true;
+	}
+	
+	private var _elementChanged:Boolean;
+	public function get elementChanged():Boolean
+	{
+		return _elementChanged;
+	}
+}
+
+internal class MeasuredCache
+{
+	
+	
+	
+	//--------------------------------------------------------------------------
+	//
+	//  Constructor
+	//
+	//--------------------------------------------------------------------------
+	
+	/**
+	 *  Constructor. 
+	 *  
+	 *  @langversion 3.0
+	 *  @playerversion Flash 10
+	 *  @playerversion AIR 1.5
+	 *  @productversion Flex 4
+	 */ 
+	public function MeasuredCache()
+	{
+		reset();
+	}
+	
+	
+	//--------------------------------------------------------------------------
+	//
+	//  Properties
+	//
+	//--------------------------------------------------------------------------
+	
+	//----------------------------------
+	//  measuredWidth
+	//----------------------------------
+	
+	/**
+	 *  @private
+	 *	Storage property for measuredWidth.
+	 */
+	private var _measuredWidth:Number;
+	
+	/**
+	 *  measuredWidth
+	 *  
+	 *  @langversion 3.0
+	 *  @playerversion Flash 10
+	 *  @playerversion AIR 1.5
+	 *  @productversion Flex 4
+	 */
+	public function get measuredWidth():Number
+	{
+		return _measuredWidth;
+	}
+	
+	
+	//----------------------------------
+	//  measuredHeight
+	//----------------------------------
+	
+	/**
+	 *  @private
+	 *	Storage property for measuredHeight.
+	 */
+	private var _measuredHeight:Number;
+	
+	/**
+	 *  measuredHeight
+	 *  
+	 *  @langversion 3.0
+	 *  @playerversion Flash 10
+	 *  @playerversion AIR 1.5
+	 *  @productversion Flex 4
+	 */
+	public function get measuredHeight():Number
+	{
+		return _measuredHeight;
+	}
+	
+	
+	//----------------------------------
+	//  measuredMinWidth
+	//----------------------------------
+	
+	/**
+	 *  @private
+	 *	Storage property for measuredMinWidth.
+	 */
+	private var _measuredMinWidth:Number;
+	
+	/**
+	 *  measuredMinWidth
+	 *  
+	 *  @langversion 3.0
+	 *  @playerversion Flash 10
+	 *  @playerversion AIR 1.5
+	 *  @productversion Flex 4
+	 */
+	public function get measuredMinWidth():Number
+	{
+		return _measuredMinWidth;
+	}
+	
+	
+	//----------------------------------
+	//  measuredMinHeight
+	//----------------------------------
+	
+	/**
+	 *  @private
+	 *	Storage property for measuredMinHeight.
+	 */
+	private var _measuredMinHeight:Number;
+	
+	/**
+	 *  measuredMinHeight
+	 *  
+	 *  @langversion 3.0
+	 *  @playerversion Flash 10
+	 *  @playerversion AIR 1.5
+	 *  @productversion Flex 4
+	 */
+	public function get measuredMinHeight():Number
+	{
+		return _measuredMinHeight;
+	}
+
+	public function cache( elt:ILayoutElement ):void
+	{
+		var preferred:Number;
+		var min:Number;
+		
+		// Calculate preferred width first, as it's being used to calculate min width
+		preferred = Math.ceil(elt.getPreferredBoundsWidth());
+		// Calculate min width
+		min = !isNaN(elt.percentWidth) ? Math.ceil(elt.getMinBoundsWidth()) : preferred;
+		_measuredWidth = Math.max( _measuredWidth, preferred );
+		_measuredMinWidth = Math.max( _measuredMinWidth, min );
+		
+		// Calculate preferred width first, as it's being used to calculate min width
+		preferred = Math.ceil(elt.getPreferredBoundsHeight());
+		// Calculate min width
+		min = !isNaN(elt.percentHeight) ? Math.ceil(elt.getMinBoundsHeight()) : preferred;
+		_measuredHeight = Math.max( _measuredHeight, preferred );
+		_measuredMinHeight = Math.max( _measuredMinHeight, min );
+		
+	}
+	
+	public function reset():void
+	{
+		_measuredWidth = 0;
+		_measuredMinWidth = 0;
+		_measuredHeight = 0;
+		_measuredMinHeight = 0;
+	}
+}
+
+
+internal class ButtonLayout extends LayoutBase
+{
+	
+	private var _parentLayout:AccordionLayout;
+	public var _buttonSizes:Vector.<int> = new Vector.<int>();
+	public var _totalSize:int = 0;
+	public var _rotation:Number;
+	
+	public function ButtonLayout( parentLayout:AccordionLayout ):void
+	{
+		_parentLayout = parentLayout;
+	}
+	
+	override public function measure():void
+	{
+		if( !_parentLayout.target ) return;
+		var matrix:Matrix;
+		var rotation:Number = _parentLayout.buttonRotation == "none" ? 0 : _parentLayout.buttonRotation == "left" ? -90 : 90;
+		if( rotation != _rotation )
+		{
+			_rotation = rotation;
+			matrix = new Matrix();
+			matrix.rotate( _rotation * ( Math.PI / 180 ) );
+		}
+
+		var element:IVisualElement;
+		var size:Number;
+		const numElements:int = target.numElements;
+		var s:Number = 0;
+		for( var i:int = 0; i < numElements; i++ )
+		{
+			element = target.getElementAt( i );
+			
+			if( matrix ) element.setLayoutMatrix( matrix, true );
+			
+			if( _parentLayout.direction == LayoutAxis.VERTICAL  )
+			{
+				
+				s = Math.max( s, element.getPreferredBoundsWidth() );
+			}
+			else
+			{
+				s = Math.max( s, element.getPreferredBoundsHeight() );
+			}
+			
+		}
+		
+		if( _parentLayout.direction == LayoutAxis.VERTICAL  )
+		{
+			target.measuredWidth = target.measuredMinWidth = s;
+			target.measuredHeight = _parentLayout.target.measuredHeight;
+			target.measuredMinHeight = _parentLayout.target.measuredMinHeight;
+		}
+		else
+		{
+			target.measuredWidth = _parentLayout.target.measuredWidth
+			target.measuredMinWidth = _parentLayout.target.measuredWidth;
+			target.measuredHeight = target.measuredMinHeight = s;
+		}
+	}
+	
+	public function invalidateTargetDisplayList() : void
+	{
+		if( !target ) return;
+		target.invalidateDisplayList();
+	}
+	
+	public function invalidateTargetSize() : void
+	{
+		if( !target ) return;
+		target.invalidateSize();
+	}
+	
+	override public function set target( value:GroupBase ):void
+	{
+		_totalSize = 0;
+		_buttonSizes.splice( 0, _buttonSizes.length );
+		super.target = value;
+	}
+	override public function updateDisplayList( unscaledWidth:Number, unscaledHeight:Number ):void
+	{
+		super.updateDisplayList( unscaledWidth, unscaledHeight );
+		
+		if( !target || !_parentLayout.target ) return;
+		
+		var matrix:Matrix;
+		var rotation:Number = _parentLayout.buttonRotation == "none" ? 0 : _parentLayout.buttonRotation == "left" ? -90 : 90;
+		if( rotation != _rotation )
+		{
+			_rotation = rotation;
+			matrix = new Matrix();
+			matrix.rotate( _rotation * ( Math.PI / 180 ) );
+		}
+			
+		var element:IVisualElement;
+		const numElements:int = target.numElements;
+		for( var i:int = 0; i < numElements; i++ )
+		{
+			element = target.getElementAt( i );
+			
+			if( matrix ) element.setLayoutMatrix( matrix, true );
+			
+			if( _parentLayout.direction == LayoutAxis.VERTICAL  )
+			{
+				element.setLayoutBoundsSize( unscaledWidth, element.getPreferredBoundsHeight() );
+			}
+			else
+			{
+				element.setLayoutBoundsSize( element.getPreferredBoundsWidth(), unscaledHeight );
+			}
+		}
+		
+		_parentLayout.invalidateElementSizes();
+	}
+	
+}

Added: incubator/flex/whiteboard/navigators/src/ws/tink/spark/layouts/CarouselLayout.as
URL: http://svn.apache.org/viewvc/incubator/flex/whiteboard/navigators/src/ws/tink/spark/layouts/CarouselLayout.as?rev=1228400&view=auto
==============================================================================
--- incubator/flex/whiteboard/navigators/src/ws/tink/spark/layouts/CarouselLayout.as (added)
+++ incubator/flex/whiteboard/navigators/src/ws/tink/spark/layouts/CarouselLayout.as Fri Jan  6 20:58:43 2012
@@ -0,0 +1,1757 @@
+/*
+Copyright (c) 2011 Tink Ltd - http://www.tink.ws
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+documentation files (the "Software"), to deal in the Software without restriction, including without limitation 
+the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
+to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions
+of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO 
+THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+*/
+
+package ws.tink.spark.layouts
+{
+	
+	import flash.geom.ColorTransform;
+	import flash.geom.Point;
+	import flash.geom.Vector3D;
+	
+	import mx.core.IVisualElement;
+	import mx.core.UIComponent;
+	
+	import spark.layouts.HorizontalAlign;
+	import spark.layouts.VerticalAlign;
+	import spark.primitives.supportClasses.GraphicElement;
+	
+	import ws.tink.spark.layouts.supportClasses.PerspectiveAnimationNavigatorLayoutBase;
+
+	/**
+	 *  A CarouselLayout class arranges the layout elements in a
+	 *  sequence along an arc, with one of them at a time selected.
+	 * 
+	 *  <p>The position of the elements is determined by the radii
+	 *  <code>radiusX</code>, <code>radiusY</code> and <code>radiusZ</code>.
+	 *  These can be properties can be set the negative values to produce
+	 *  a ring of elements surrounding the view point.</p>
+	 * 
+	 *  <p>The rotation of the elements is determined by the
+	 *  <code>rotationX</code> and <code>rotationY</code> properties.</p>
+	 *  <ul>
+	 *    <li>If a value of <code>"none"</code> is used for a rotation property, 
+	 *    no rotation is applied to the element around the corresponding axis.</li>
+	 *
+	 *    <li>If a value of <code>"standard"</code> is used for a rotation property, 
+	 *    the element will be rotated so that it faces outwards around the arc.</li>
+	 *
+	 *    <li>If a value of <code>"reversed"</code> is used for a rotation property, 
+	 *    the element will be rotated so that it faces inwards around the arc.</li>
+	 *  </ul>
+	 * 
+	 *  @mxml
+	 *
+	 *  <p>The <code>&lt;st:CarouselLayout&gt;</code> tag inherits all of the
+	 *  tag attributes of its superclass, and adds the following tag attributes:</p>
+	 *
+	 *  <pre>
+	 *  &lt;st:AccordionLayout
+	 *    <strong>Properties</strong>
+	 *    angle="360"
+	 *    depthColor="-1"
+	 *    depthColorAlpha="1"
+	 *    horizontalAlign="center|left|right"
+	 *    horizontalAlignOffset="0"
+	 *    horizontalAlignOffsetPercent="0"
+	 *    numUnselectedElements="-1"
+	 *    radiusX="100"
+	 *    radiusY="0"
+	 *    radiusZ="NaN"
+	 *    rotateX="none|reversed|standard"
+	 *    rotateY="none|reversed|standard"
+	 *    verticalAlign="bottom|middle|top"
+	 *    verticalAlignOffset="0"
+	 *    verticalAlignOffsetPercent="0"
+	 *  /&gt;
+	 *  </pre>
+	 *
+	 *  @includeExample examples/CarouselLayoutExample.mxml
+	 *
+	 *  @langversion 3.0
+	 *  @playerversion Flash 10
+	 *  @playerversion AIR 1.5
+	 *  @productversion Flex 4
+	 */
+	public class CarouselLayout extends PerspectiveAnimationNavigatorLayoutBase
+	{
+			
+		
+		
+		//--------------------------------------------------------------------------
+		//
+		//  Constructor
+		//
+		//--------------------------------------------------------------------------
+		
+		/**
+		 *  Constructor.
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 1.5
+		 *  @productversion Flex 4
+		 */
+		public function CarouselLayout()
+		{
+			super( INDIRECT );
+			_transformCalculator = new TransformValues( this );
+		}
+
+		
+		
+		//--------------------------------------------------------------------------
+		//
+		//  Variables
+		//
+		//--------------------------------------------------------------------------
+		
+		/**
+		 *  @private
+		 */
+		private var _transformCalculator				: TransformValues;
+		
+		/**
+		 *  @private
+		 */
+		private var _horizontalCenterMultiplier			: Number;
+		
+		/**
+		 *  @private
+		 */
+		private var _verticalCenterMultiplier			: Number;
+		
+		/**
+		 *  @private
+		 */
+		private var _elementHorizontalCenterMultiplier	: Number;
+		
+		/**
+		 *  @private
+		 */
+		private var _elementVerticalCenterMultiplier	: Number;
+		
+		/**
+		 *  @private
+		 */
+		private var _displayedElements					: Vector.<IVisualElement>	
+		
+		
+		
+		//--------------------------------------------------------------------------
+		//
+		//  Properties
+		//
+		//--------------------------------------------------------------------------
+		
+		//----------------------------------
+		//  angle
+		//---------------------------------- 
+		
+		/**
+		 *  @private
+		 *  Storage property for angle.
+		 */
+		private var _angle:Number = 360;
+		
+		/**
+		 *	The segment of a circle to rotate the elements around.
+		 * 
+		 *  @default 360
+		 * 
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 1.5
+		 *  @productversion Flex 4
+		 */
+		public function get angle():Number
+		{
+			return _angle;
+		}
+		/**
+		 *  @private
+		 */
+		public function set angle( value:Number ) : void
+		{
+			if( _angle == value ) return;
+			
+			_angle = value;
+			invalidateTargetDisplayList();
+		}
+		
+		
+		//----------------------------------
+		//  rotateX
+		//---------------------------------- 
+		
+		/**
+		 *  @private
+		 *  Storage property for rotateX.
+		 */
+		private var _rotateX:int = 0;
+		
+		[Inspectable(category="General", enumeration="none,reversed,standard", defaultValue="none")]
+		/**
+		 *	Whether rotation should be applied to the x axis of elements.
+		 * 
+		 *  @default true
+		 * 
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 1.5
+		 *  @productversion Flex 4
+		 */
+		public function get rotateX():String
+		{
+			return _rotateX ? _rotateX < 0 ? "reversed" : "standard" : "none";
+		}
+		/**
+		 *  @private
+		 */
+		public function set rotateX( value:String ) : void
+		{
+			var r:int;
+			
+			switch( value )
+			{
+				case "reversed" :
+				{
+					r = -1;
+					break;
+				}
+				case "standard" :
+				{
+					r = 1;
+					break;
+				}
+				default :
+				{
+					r = 0;
+				}
+					
+			}
+			
+			if( _rotateX == r ) return;
+
+			_rotateX = r;
+			invalidateTargetDisplayList();
+		}
+		
+		
+		//----------------------------------
+		//  rotateY
+		//---------------------------------- 
+		
+		/**
+		 *  @private
+		 *  Storage property for rotateY.
+		 */
+		private var _rotateY:int = 1;
+		
+		[Inspectable(category="General", enumeration="none,reversed,standard", defaultValue="standard")]
+		/**
+		 *	Whether rotation should be applied to the y axis of elements.
+		 * 
+		 *  @default true
+		 * 
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 1.5
+		 *  @productversion Flex 4
+		 */
+		public function get rotateY():String
+		{
+			return _rotateY ? _rotateY < 0 ? "reversed" : "standard" : "none";
+		}
+		/**
+		 *  @private
+		 */
+		public function set rotateY( value:String ) : void
+		{
+			var r:int;
+			
+			switch( value )
+			{
+				case "reversed" :
+				{
+					r = -1;
+					break;
+				}
+				case "standard" :
+				{
+					r = 1;
+					break;
+				}
+				default :
+				{
+					r = 0;
+				}
+					
+			}
+			
+			if( r == _rotateY ) return;
+			
+			_rotateY = r;
+			invalidateTargetDisplayList();
+		}
+		
+		
+		//----------------------------------
+		//  depthColor
+		//----------------------------------  
+		
+		/**
+		 *  @private
+		 *  Storage property for depthColor.
+		 */
+		private var _depthColor		: int = -1;
+		
+		[Inspectable(category="General", defaultValue="-1")]
+		/**
+		 *	The color tint to apply to elements as their are moved back on the z axis.
+		 * 
+		 *	<p>If a valid color is added to elements are tinted as they are moved
+		 *	back on the z axis taking into account the <code>depthColorAlpha</code>
+		 *	specified. If a value of -1 is set for the color no tinting is applied.</p>
+		 * 
+		 *  @default -1
+		 * 
+		 * 	@see #depthColorAlpha
+		 * 
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 1.5
+		 *  @productversion Flex 4
+		 */
+		public function get depthColor():int
+		{
+			return _depthColor;
+		}
+		/**
+		 *  @private
+		 */
+		public function set depthColor( value:int ) : void
+		{
+			if( _depthColor == value ) return;
+			
+			_depthColor = value;
+			invalidateTargetDisplayList();
+		}
+		
+		
+		//----------------------------------
+		//  depthColorAlpha
+		//----------------------------------  
+		
+		/**
+		 *  @private
+		 *  Storage property for depthColorAlpha.
+		 */
+		private var _depthColorAlpha		: Number = 1;
+		
+		[Inspectable(category="General", defaultValue="1")]
+		
+		/**
+		 *	The alpha to be used for the color tint that is applied to elements
+		 *	as their are moved back on the z axis.
+		 * 
+		 *  @default 1
+		 * 
+		 * 	@see #depthColor
+		 * 
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 1.5
+		 *  @productversion Flex 4
+		 */
+		public function get depthColorAlpha():Number
+		{
+			return _depthColorAlpha;
+		}
+		/**
+		 *  @private
+		 */
+		public function set depthColorAlpha( value:Number ) : void
+		{
+			if( _depthColorAlpha == value ) return;
+			
+			_depthColorAlpha = value;
+			invalidateTargetDisplayList();
+		}
+		
+		
+		//----------------------------------
+		//  numUnselectedElements
+		//----------------------------------  
+		
+		/**
+		 *  @private
+		 *  Storage property for numUnselectedElements.
+		 */
+		private var _numUnselectedElements	: int = -1;
+		
+		[Inspectable(category="General", defaultValue="-1")]
+		/**
+		 *	The number of items to show either side of the selected item
+		 *	are positioned around this element.
+		 * 
+		 *	<p>Valid values are <code>HorizontalAlign.LEFT</code>, <code>HorizontalAlign.CENTER</code>
+		 *	and <code>HorizontalAlign.RIGHT</code>.</p>
+		 * 
+		 *  @default 2
+		 * 
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 1.5
+		 *  @productversion Flex 4
+		 */
+		
+		public function get numUnselectedElements():int
+		{
+			return _numUnselectedElements;
+		}
+		/**
+		 *  @private
+		 */
+		public function set numUnselectedElements( value:int ) : void
+		{
+			if( _numUnselectedElements == value ) return;
+			
+			_numUnselectedElements = value;
+			invalidateTargetDisplayList();
+		}
+		
+		
+		//----------------------------------
+		//  horizontalAlign
+		//----------------------------------  
+		
+		/**
+		 *  @private
+		 *  Storage property for horizontalAlign.
+		 */
+		private var _horizontalAlign:String = HorizontalAlign.CENTER;
+		
+		/**
+		 *  @private
+		 *  Flag to indicate the horizontalAlign property has changed.
+		 */
+		private var _horizontalAlignChange:Boolean = true;
+		
+		[Inspectable(category="General", enumeration="left,right,center", defaultValue="center")]
+		/**
+		 *	The horizontal position of the selected element in the viewport. All other elements
+		 *	are positioned around this element.
+		 * 
+		 *	<p>Valid values are <code>HorizontalAlign.LEFT</code>, <code>HorizontalAlign.CENTER</code>
+		 *	and <code>HorizontalAlign.RIGHT</code>.</p>
+		 * 
+		 *  @default "center"
+		 * 
+		 * 	@see #horizontalAlignOffset
+		 * 	@see #horizontalAlignOffsetPercent
+		 * 	@see spark.layouts.HorizontalAlign
+		 * 
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 1.5
+		 *  @productversion Flex 4
+		 */
+		public function get horizontalAlign():String
+		{
+			return _horizontalAlign;
+		}
+		/**
+		 *  @private
+		 */
+		public function set horizontalAlign(value:String):void
+		{
+			if( value == _horizontalAlign ) return;
+			
+			_horizontalAlign = value;
+			_horizontalAlignChange = true;
+			invalidateTargetDisplayList();
+		}
+		
+		
+		//----------------------------------
+		//  verticalAlign
+		//----------------------------------  
+		
+		/**
+		 *  @private
+		 *  Storage property for verticalAlign.
+		 */
+		private var _verticalAlign:String = VerticalAlign.MIDDLE;
+		
+		/**
+		 *  @private
+		 *  Flag to indicate the verticalAlign property has changed.
+		 */
+		private var _verticalAlignChange:Boolean = true;
+		
+		[Inspectable(category="General", enumeration="top,bottom,middle", defaultValue="middle")]
+		/**
+		 *	The vertical position of the selected element in the viewport. All other elements
+		 *	are positioned around this element.
+		 * 
+		 *	<p>Valid values are <code>VerticalAlign.TOP</code>, <code>VerticalAlign.MIDDLE</code>
+		 *	and <code>VerticalAlign.BOTTOM</code>.</p>
+		 * 
+		 *  @default "middle"
+		 * 
+		 * 	@see #verticalAlignOffset
+		 * 	@see #verticalAlignOffsetPercent
+		 * 	@see spark.layouts.VerticalAlign
+		 * 
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 1.5
+		 *  @productversion Flex 4
+		 */
+		public function get verticalAlign():String
+		{
+			return _verticalAlign;
+		}
+		/**
+		 *  @private
+		 */
+		public function set verticalAlign(value:String):void
+		{
+			if( value == _verticalAlign ) return;
+			
+			_verticalAlign = value;
+			_verticalAlignChange = true;
+			invalidateTargetDisplayList();
+		}
+		
+		
+		//----------------------------------
+		//  horizontalAlignOffset
+		//----------------------------------  
+		
+		/**
+		 *  @private
+		 *  Storage property for horizontalAlignOffset.
+		 */
+		private var _horizontalAlignOffset:Number = 0;
+		
+		[Inspectable(category="General", defaultValue="0")]
+		/**
+		 *	The offset in pixels to be used in conjunction with <code>horizontalAlign</code>
+		 *	to set the horizontal position of the selected element in the viewport. All other elements
+		 *	are positioned around this element.
+		 * 
+		 *	<p>If <code>horizontalAlignOffsetPercent</code> is set after this property,
+		 *	this property is set automatically depending on the value of <code>horizontalAlignOffsetPercent</code>.</p>
+		 * 
+		 *  @default 0
+		 * 
+		 * 	@see #horizontalAlign
+		 * 	@see #horizontalAlignOffsetPercent
+		 * 	@see spark.layouts.HorizontalAlign
+		 * 
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 1.5
+		 *  @productversion Flex 4
+		 */
+		public function get horizontalAlignOffset():Number
+		{
+			return _horizontalAlignOffset;
+		}
+		/**
+		 *  @private
+		 */
+		public function set horizontalAlignOffset(value:Number):void
+		{
+			if( _horizontalAlignOffset == value ) return;
+			
+			_horizontalAlignOffset = value;
+			_horizontalAlignOffsetPercent = NaN;
+			invalidateTargetDisplayList();
+		}    
+		
+		
+		//----------------------------------
+		//  verticalAlignOffset
+		//----------------------------------  
+		
+		/**
+		 *  @private
+		 *  Storage property for verticalAlignOffset.
+		 */
+		private var _verticalAlignOffset:Number = 0;
+		
+		[Inspectable(category="General", defaultValue="0")]
+		/**
+		 *	The offset in pixels to be used in conjunction with <code>verticalAlign</code>
+		 *	to set the vertical position of the selected element in the viewport. All other elements
+		 *	are positioned around this element.
+		 * 
+		 *	<p>If <code>verticalAlignOffsetPercent</code> is set after this property,
+		 *	this property is set automatically depending on the value of <code>verticalAlignOffsetPercent</code>.</p>
+		 * 
+		 *  @default 0
+		 * 
+		 * 	@see #verticalAlign
+		 * 	@see #verticalAlignOffsetPercent
+		 * 	@see spark.layouts.VerticalAlign
+		 * 
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 1.5
+		 *  @productversion Flex 4
+		 */
+		public function get verticalAlignOffset():Number
+		{
+			return _verticalAlignOffset;
+		}
+		/**
+		 *  @private
+		 */
+		public function set verticalAlignOffset(value:Number):void
+		{
+			if( _verticalAlignOffset == value ) return;
+			
+			_verticalAlignOffset = value;
+			_verticalAlignOffsetPercent = NaN;
+//			_indicesInViewChanged = true;
+			invalidateTargetDisplayList();
+		}
+		
+		
+		//----------------------------------
+		//  horizontalAlignOffsetPercent
+		//----------------------------------  
+		
+		/**
+		 *  @private
+		 *  Storage property for horizontalAlignOffsetPercent.
+		 */
+		private var _horizontalAlignOffsetPercent:Number = 0;
+		
+		[Inspectable(category="General", defaultValue="0")]
+		/**
+		 *	The offset as a percentage of the unscaled width of the viewport
+		 *  to be used in conjunction with <code>horizontalAlign</code> to set the horizontal
+		 *	position of the selected element in the viewport. All other elements are
+		 * 	positioned around this element.
+		 * 
+		 *	<p>Setting this property overrides any value set on <code>horizontalAlignOffset</code>.</p>
+		 * 
+		 *  @default 0
+		 * 
+		 * 	@see #horizontalAlign
+		 * 	@see #horizontalAlignOffset
+		 * 	@see spark.layouts.HorizontalAlign
+		 * 
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 1.5
+		 *  @productversion Flex 4
+		 */
+		public function get horizontalAlignOffsetPercent():Number
+		{
+			return _horizontalAlignOffsetPercent;
+		}
+		/**
+		 *  @private
+		 */
+		public function set horizontalAlignOffsetPercent(value:Number):void
+		{
+			if( _horizontalAlignOffsetPercent == value ) return;
+			
+			_horizontalAlignOffsetPercent = value;
+			if( !isNaN( _horizontalAlignOffsetPercent ) ) _horizontalAlignOffset = unscaledHeight * ( _horizontalAlignOffsetPercent / 100 );
+//			_indicesInViewChanged = true;
+			invalidateTargetDisplayList();
+		}    
+		
+		
+		//----------------------------------
+		//  verticalAlignOffsetPercent
+		//----------------------------------  
+		
+		/**
+		 *  @private
+		 *  Storage property for verticalAlignOffsetPercent.
+		 */
+		private var _verticalAlignOffsetPercent:Number = 0;
+		
+		[Inspectable(category="General", defaultValue="0")]
+		/**
+		 *	The offset as a percentage of the unscaled height of the viewport
+		 *  to be used in conjunction with <code>verticalAlign</code> to set the vertical
+		 *	position of the selected element in the viewport. All other elements are
+		 * 	positioned around this element.
+		 * 
+		 *	<p>Setting this property overrides any value set on <code>verticalAlignOffset</code>.</p>
+		 * 
+		 *  @default 0
+		 * 
+		 * 	@see #verticalAlign
+		 * 	@see #verticalAlignOffset
+		 * 	@see spark.layouts.VerticalAlign
+		 * 
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 1.5
+		 *  @productversion Flex 4
+		 */
+		public function get verticalAlignOffsetPercent():Number
+		{
+			return _verticalAlignOffsetPercent;
+		}
+		/**
+		 *  @private
+		 */
+		public function set verticalAlignOffsetPercent(value:Number):void
+		{
+			if( _verticalAlignOffsetPercent == value ) return;
+			
+			_verticalAlignOffsetPercent = value;
+			if( !isNaN( _verticalAlignOffsetPercent ) ) _verticalAlignOffset = unscaledHeight * ( _verticalAlignOffsetPercent / 100 );
+//			_indicesInViewChanged = true;
+			invalidateTargetDisplayList();
+		}
+		
+		
+		//----------------------------------
+		//  elementHorizontalAlign
+		//----------------------------------  
+		
+		/**
+		 *  @private
+		 *  Storage property for elementHorizontalAlign.
+		 */
+		private var _elementHorizontalAlign:String = HorizontalAlign.CENTER;
+		
+		/**
+		 *  @private
+		 *  Flag to indicate the elementHorizontalAlign property has changed.
+		 */
+		private var _elementHorizontalAlignChange		: Boolean = true;
+		
+		[Inspectable(category="General", enumeration="left,right,center", defaultValue="center")]
+		/**
+		 *	The horizontal transform point of elements.
+		 * 
+		 *	<p>Valid values are <code>HorizontalAlign.LEFT</code>, <code>HorizontalAlign.CENTER</code>
+		 *	and <code>HorizontalAlign.RIGHT</code>.</p>
+		 * 
+		 *  @default "center"
+		 * 
+		 * 	@see spark.layouts.HorizontalAlign
+		 * 
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 1.5
+		 *  @productversion Flex 4
+		 */
+		public function get elementHorizontalAlign():String
+		{
+			return _elementHorizontalAlign;
+		}
+		/**
+		 *  @private
+		 */
+		public function set elementHorizontalAlign(value:String):void
+		{
+			if( value == _elementHorizontalAlign ) return;
+			
+			_elementHorizontalAlign = value;
+			_elementHorizontalAlignChange = true;
+			invalidateTargetDisplayList();
+		}
+		
+		
+		//----------------------------------
+		//  elementVerticalAlign
+		//----------------------------------  
+		
+		/**
+		 *  @private
+		 *  Storage property for elementVerticalAlign.
+		 */
+		private var _elementVerticalAlign:String = VerticalAlign.MIDDLE;
+		
+		/**
+		 *  @private
+		 *  Flag to indicate the elementVerticalAlign property has changed.
+		 */
+		private var _elementVerticalAlignChange			: Boolean = true;
+		
+		[Inspectable(category="General", enumeration="top,bottom,middle", defaultValue="middle")]
+		/**
+		 *	The vertical transform point of elements.
+		 * 
+		 *	<p>Valid values are <code>VerticalAlign.TOP</code>, <code>VerticalAlign.MIDDLE</code>
+		 *	and <code>VerticalAlign.BOTTOM</code>.</p>
+		 * 
+		 *  @default "middle"
+		 * 
+		 * 	@see spark.layouts.VerticalAlign
+		 * 
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 1.5
+		 *  @productversion Flex 4
+		 */
+		public function get elementVerticalAlign():String
+		{
+			return _elementVerticalAlign;
+		}
+		/**
+		 *  @private
+		 */
+		public function set elementVerticalAlign(value:String):void
+		{
+			if( value == _elementVerticalAlign ) return;
+			
+			_elementVerticalAlign = value;
+			_elementVerticalAlignChange = true;
+			invalidateTargetDisplayList();
+		}
+		
+		
+		//----------------------------------
+		//  radiusX
+		//----------------------------------  
+		
+		/**
+		 *  @private
+		 *  Storage property for radiusX.
+		 */
+		private var _radiusX	: Number = 100;
+		
+		[Inspectable(category="General", type="Number", defaultValue="100")]
+		/**
+		 *	The radius to be used on the x axis for the SemiCarouselLayout.
+		 * 
+		 *  @default 100
+		 * 
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 1.5
+		 *  @productversion Flex 4
+		 */
+		public function get radiusX():Number
+		{
+			return _radiusX;
+		}
+		/**
+		 *  @private
+		 */
+		public function set radiusX( value:Number ):void
+		{
+			if( value == _radiusX ) return;
+			
+			_radiusX = value;
+			invalidateTargetDisplayList();
+		}
+		
+		
+		//----------------------------------
+		//  radiusY
+		//----------------------------------  
+		
+		/**
+		 *  @private
+		 *  Storage property for radiusY.
+		 */
+		private var _radiusY	: Number = 0;
+		
+		[Inspectable(category="General", type="Number", defaultValue="0")]
+		/**
+		 *	The radius to be used on the y axis for the SemiCarouselLayout.
+		 * 
+		 *  @default 0
+		 * 
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 1.5
+		 *  @productversion Flex 4
+		 */
+		public function get radiusY():Number
+		{
+			return _radiusY;
+		}
+		/**
+		 *  @private
+		 */
+		public function set radiusY( value:Number ):void
+		{
+			if( value == _radiusY ) return;
+			
+			_radiusY = value;
+			invalidateTargetDisplayList();
+		}
+		
+		
+		//----------------------------------
+		//  radiusZ
+		//----------------------------------  
+		
+		/**
+		 *  @private
+		 *  Storage property for radiusZ.
+		 */
+		private var _radiusZ	: Number;
+		
+		[Inspectable(category="General", type="Number", defaultValue="NaN")]
+		/**
+		 *	The radius to be used on the z axis for the SemiCarouselLayout.
+		 * 
+		 * 	<p>If a value of NaN is passed the largest of <code>radiusX</code>
+		 *	or <code>radiusY</code> is used.</p>
+		 * 
+		 *  @default NaN
+		 * 
+		 * 	@see #radiusX
+		 *	@see #radiusY
+		 *
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 1.5
+		 *  @productversion Flex 4
+		 */
+		public function get radiusZ():Number
+		{
+			return _radiusZ;
+		}
+		/**
+		 *  @private
+		 */
+		public function set radiusZ( value:Number ):void
+		{
+			if( value == _radiusZ ) return;
+			
+			_radiusZ = value;
+			invalidateTargetDisplayList();
+		}
+		
+		
+		
+		//--------------------------------------------------------------------------
+		//
+		//  Methods
+		//
+		//--------------------------------------------------------------------------
+		
+		/**
+		 *	@private
+		 * 
+		 *	Positions, transforms and sets the size of an element
+		 *  that will be visible in the layout.
+		 */
+		protected function updateVisibleElementAt( element:IVisualElement, index:int ):void
+		{
+			_displayedElements.push( element );
+			
+			setElementLayoutBoundsSize( element, false );
+			
+			_transformCalculator.updateForIndex( index, element, element.width, element.height, _elementHorizontalCenterMultiplier, _elementVerticalCenterMultiplier );
+			
+//			elementTransformAround( element );
+			applyColorTransformToElement( element, _transformCalculator.colorTransform );
+			element.visible = true;
+		}
+		
+		/**
+		 *	@private
+		 */
+		private function sortElementsByZ( a:IVisualElement, b:IVisualElement ):int
+		{
+			if( getZ( a ) > getZ( b ) )
+			{
+				return -1;
+			}
+			else if( getZ( a ) < getZ( b ) )
+			{
+				return 1;
+			}
+			
+			return 0;
+		}
+		
+		/**
+		 *	@private
+		 * 
+		 *	Util function to return the value of the z property
+		 *  on an element.
+		 */
+		private function getZ( e:IVisualElement ):Number
+		{
+			if( e is GraphicElement )
+			{
+				return GraphicElement( e ).z;
+			}
+			else
+			{
+				return UIComponent( e ).z;
+			}
+		}
+		
+		/**
+		 *	@private
+		 * 
+		 *	Sets the depth of elements inlcuded in the layout at depths
+		 *	to display correctly for the z position set with transformAround.
+		 * 
+		 *	Also sets the depth of elements that are not included in the layout.
+		 *	The depth of these is dependent on whether their element index is before
+		 *	or after the index of the selected element.
+		 * 
+		 *	- If their element index is before the selected elements index
+		 *   they appear beneath all items included in the layout.
+		 * 
+		 *	- If their element index is after the selected elements index
+		 *   they appear above all items included in the layout
+		 */
+		private function updateDepths( depths:Vector.<int> ):void
+		{
+			if( !depths || !depths.length ) return;
+			
+			var animationIndex:int = Math.max( 0, Math.min( Math.round( animationValue ), numElementsInLayout - 1 ) );
+			
+			var element:IVisualElement;
+			var index:int;
+			var i:int
+			var numBeforeMinDepth:int = 0;
+			var minDepth:int = depths[ 0 ] - 1;
+			var maxDepth:int = depths[ depths.length - 1 ] + 1;
+			
+			const elements:Vector.<IVisualElement> = new Vector.<IVisualElement>();
+			for( i = firstIndexInView; i <= lastIndexInView; i++ )
+			{
+				index = indicesInLayout[ i ];
+				element = target.getElementAt( index );
+				if( !element ) continue;
+				elements.push( element );
+			}
+			
+			elements.sort( sortElementsByZ );
+			var num:int = elements.length;
+			for( i = 0; i < num; i++ )
+			{
+				elements[ i ].depth = depths[ i ];
+			}
+			
+//			target.validateNow();
+//			for( i = firstIndexInView; i <= lastIndexInView; i++ )
+//			{
+//				index = indicesInLayout[ i ];
+//				element = target.getElementAt( index );
+//				if( !element ) continue;
+//				if( index <  indicesInLayout[ animationIndex ] )
+//				{
+//					element.depth = _transformCalculator.radiusZ > -1 ? depths.shift() : depths.pop();
+//				}
+////				else if ( index > indicesInLayout[ animationIndex ] )
+////				{
+////					element.depth = _direction == SemiCarouselLayoutDirection.CONVEX ? depths.pop() : depths.shift();
+////				}
+//				else
+//				{
+//					element.depth = _transformCalculator.radiusZ > -1 ? depths.pop() : depths.shift();
+//				}
+//			}
+//			
+//			
+//			var numElementsNotInLayout:int = indicesNotInLayout.length;
+//			for( i = 0; i < numElementsNotInLayout; i++ )
+//			{
+//				if( indicesNotInLayout[ i ] > indicesInLayout[ animationIndex ] )
+//				{
+//					break;
+//				}
+//				else
+//				{
+//					numBeforeMinDepth++;
+//				}
+//			}
+//			
+//			minDepth -= numBeforeMinDepth - 1;
+//			for( i = 0; i < numElementsNotInLayout; i++ )
+//			{
+//				element = target.getElementAt( indicesNotInLayout[ i ] );
+//				if( !element ) continue;
+//				if( indicesNotInLayout[ i ] > indicesInLayout[ animationIndex ] )
+//				{
+//					element.depth = maxDepth;
+//					maxDepth++;
+//				}
+//				else
+//				{
+//					element.depth = minDepth;
+//					minDepth++;
+//				}
+//			}
+//			
+//			target.validateNow();
+		}
+		
+		/**
+		 *	@private
+		 * 
+		 *	A convenience method used to transform an element by applying
+		 *  the current values if the TransforCalulator instance.
+		 */
+//		private function elementTransformAround( element:IVisualElement ):void
+//		{
+//			var halfWidth:Number = element.width / 2;
+//			var halfHeight:Number = element.height / 2;
+//			var offsetX:Number = halfWidth * ( _elementHorizontalCenterMultiplier - 0.5 ) * 2;
+//			var offsetY:Number = halfHeight * ( _elementVerticalCenterMultiplier - 0.5 ) * 2;
+//			
+//			element.transformAround( new Vector3D( element.width / 2, element.height / 2, 0 ),
+//				null,
+//				null,
+//				new Vector3D( _transformCalculator.x - offsetX, _transformCalculator.y - offsetY, _transformCalculator.z ),
+//				null,
+//				new Vector3D( _transformCalculator.xRotation, _transformCalculator.yRotation, 0 ),
+//				new Vector3D( _transformCalculator.x - offsetX, _transformCalculator.y - offsetY, _transformCalculator.z ),
+//				false );
+//			
+//		}
+		
+		
+		
+		//--------------------------------------------------------------------------
+		//
+		//  Overridden Methods
+		//
+		//--------------------------------------------------------------------------
+		
+		/**
+		 *  @inheritDoc
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 1.5
+		 *  @productversion Flex 4
+		 */
+		override public function updateDisplayList( unscaledWidth:Number, unscaledHeight:Number):void
+		{
+//			if( this.unscaledWidth != unscaledWidth || this.unscaledHeight != unscaledHeight ) _sizeChanged = true;
+			
+			if( _horizontalAlignChange )
+			{
+				_horizontalAlignChange = false;
+//				_indicesInViewChanged = true;
+				
+				switch( _horizontalAlign )
+				{
+					case HorizontalAlign.LEFT :
+					{
+						_horizontalCenterMultiplier = 0;
+						break;
+					}
+					case HorizontalAlign.RIGHT :
+					{
+						_horizontalCenterMultiplier = 1;
+						break;
+					}
+					default :
+					{
+						_horizontalCenterMultiplier = 0.5;
+					}
+				}
+			}
+			
+			if( _verticalAlignChange )
+			{
+				_verticalAlignChange = false;
+//				_indicesInViewChanged = true;
+				
+				switch( _verticalAlign )
+				{
+					case VerticalAlign.TOP :
+					{
+						_verticalCenterMultiplier = 0;
+						break;
+					}
+					case VerticalAlign.BOTTOM :
+					{
+						_verticalCenterMultiplier = 1;
+						break;
+					}
+					default :
+					{
+						_verticalCenterMultiplier = 0.5;
+					}
+				}
+			}
+			
+			if( _elementHorizontalAlignChange )
+			{
+				_elementHorizontalAlignChange = false;
+//				_indicesInViewChanged = true;
+				
+				switch( _elementHorizontalAlign )
+				{
+					case HorizontalAlign.LEFT :
+					{
+						_elementHorizontalCenterMultiplier = 0;
+						break;
+					}
+					case HorizontalAlign.RIGHT :
+					{
+						_elementHorizontalCenterMultiplier = 1;
+						break;
+					}
+					default :
+					{
+						_elementHorizontalCenterMultiplier = 0.5;
+					}
+				}
+			}
+			
+			if( _elementVerticalAlignChange )
+			{
+				_elementVerticalAlignChange = false;
+//				_indicesInViewChanged = true;
+				
+				switch( _elementVerticalAlign )
+				{
+					case VerticalAlign.TOP :
+					{
+						_elementVerticalCenterMultiplier = 0;
+						break;
+					}
+					case VerticalAlign.BOTTOM :
+					{
+						_elementVerticalCenterMultiplier = 1;
+						break;
+					}
+					default :
+					{
+						_elementVerticalCenterMultiplier = 0.5;
+					}
+				}
+			}
+			
+			super.updateDisplayList( unscaledWidth, unscaledHeight );
+		}
+		
+		/**
+		 *  @inheritDoc
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 1.5
+		 *  @productversion Flex 4
+		 */
+		override protected function updateDisplayListBetween():void
+		{
+			super.updateDisplayListBetween();
+			
+			if( sizeChangedInLayoutPass )
+			{
+//				_indicesInViewChanged = true;
+				if( !isNaN( _horizontalAlignOffsetPercent ) ) _horizontalAlignOffset = unscaledHeight * ( _horizontalAlignOffsetPercent / 100 );
+				if( !isNaN( _verticalAlignOffsetPercent ) ) _verticalAlignOffset = unscaledHeight * ( _verticalAlignOffsetPercent / 100 );
+			}
+			
+			_transformCalculator.updateForLayoutPass( _horizontalCenterMultiplier, _verticalCenterMultiplier, _rotateX, _rotateY );
+		}
+		
+		/**
+		 *  @inheritDoc
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 1.5
+		 *  @productversion Flex 4
+		 */
+		override protected function updateDisplayListVirtual():void
+		{
+			super.updateDisplayListVirtual();
+			
+			var element:IVisualElement;
+			var depths:Vector.<int> = new Vector.<int>();
+			
+			for each( element in _displayedElements )
+			{
+				element.visible = false;
+			}
+			
+			_displayedElements = new Vector.<IVisualElement>();
+			
+			for( var i:int = firstIndexInView; i <= lastIndexInView; i++ )
+			{
+				element = target.getVirtualElementAt( indicesInLayout[ i ] );
+				depths.push( indicesInLayout[ i ] );
+				updateVisibleElementAt( element, i );
+			}
+			
+			updateDepths( depths );
+		}
+		
+		/**
+		 *  @inheritDoc
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 1.5
+		 *  @productversion Flex 4
+		 */
+		override protected function updateDisplayListReal():void
+		{
+			super.updateDisplayListReal();
+
+			var element:IVisualElement;
+			var depths:Vector.<int> = new Vector.<int>();
+			
+			_displayedElements = new Vector.<IVisualElement>();
+			
+			for( var i:int = 0; i < numElementsInLayout; i++ )
+			{
+				element = target.getElementAt( indicesInLayout[ i ] );
+				if( i >= firstIndexInView && i <= lastIndexInView )
+				{
+					depths.push( indicesInLayout[ i ] );
+					updateVisibleElementAt( element, i);
+				}
+				else
+				{
+					element.visible = false;
+				}
+			}
+			
+			updateDepths( depths );
+		}
+		
+		/**
+		 *  @inheritDoc
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 1.5
+		 *  @productversion Flex 4
+		 */
+		override protected function restoreElement( element:IVisualElement ):void
+		{
+			super.restoreElement( element );
+			
+			var vector:Vector3D = new Vector3D( 0, 0, 0 );
+			element.visible = true;
+			element.depth = 0;
+			element.transformAround( vector, null, null, vector, null, vector, vector, false );
+			applyColorTransformToElement( element, new ColorTransform() );
+		}
+		
+		/**
+		 *  @inheritDoc
+		 *  
+		 *  @langversion 3.0
+		 *  @playerversion Flash 10
+		 *  @playerversion AIR 1.5
+		 *  @productversion Flex 4
+		 */
+		override protected function updateIndicesInView():void
+		{
+			super.updateIndicesInView();
+			
+			if( _numUnselectedElements > 0 )
+			{
+				const ceilIndex:int = Math.ceil( animationValue );
+				const floorIndex:int = Math.floor( animationValue );
+				const firstIndexInView:int = Math.max( ceilIndex - _numUnselectedElements, 0 );
+				
+				var numIndicesInView:int = ( _numUnselectedElements * 2 ) + 1; 
+				// If the number of elements on the left are less than _numUnselectedElements
+				if( floorIndex < _numUnselectedElements )
+				{
+					numIndicesInView -= _numUnselectedElements - floorIndex;
+				}
+				// If we are mid transition, we don't need the last item
+				else if( floorIndex != animationValue )
+				{
+					numIndicesInView -= 1;
+				}
+				
+				// If we are at the end of the list of elements
+				if( floorIndex + _numUnselectedElements >= numElementsInLayout )
+				{
+					numIndicesInView -= _numUnselectedElements - ( ( numElementsInLayout - 1 ) - floorIndex );
+				}
+				
+				indicesInView( firstIndexInView, numIndicesInView );
+			}
+			else
+			{
+				indicesInView( 0, numElementsInLayout );
+			}
+		}
+		
+		
+	}
+}
+
+
+
+import flash.geom.ColorTransform;
+import flash.geom.Point;
+import flash.geom.Vector3D;
+
+import mx.core.IVisualElement;
+
+import ws.tink.spark.layouts.CarouselLayout;
+
+
+internal class TransformValues
+{
+	
+	
+	
+	//--------------------------------------------------------------------------
+	//
+	//  Constructor
+	//
+	//--------------------------------------------------------------------------
+	
+	/**
+	 *  Constructor.
+	 *  
+	 *  @langversion 3.0
+	 *  @playerversion Flash 10
+	 *  @playerversion AIR 1.5
+	 *  @productversion Flex 4
+	 */
+	public function TransformValues( layout:CarouselLayout )
+	{
+		_layout = layout;
+		_colorTransform = new ColorTransform();
+	}
+	
+	
+	
+	//--------------------------------------------------------------------------
+	//
+	//  Variables
+	//
+	//--------------------------------------------------------------------------
+	
+	private var _layout			: CarouselLayout;
+	
+	private var _index			: int;
+	private var _indexOffset	: Number;
+	
+	// Center
+	private var _cx				: Number;
+	private var _cy				: Number;
+	
+	// AlignOffset
+	private var _ho				: Number;
+	private var _vo				: Number;
+	
+	private var _rx				: Number;
+	private var _ry				: Number;
+	private var _rz				: Number;
+	
+	// Number of items
+	private var _ni				: Number;
+	private var _an				: Number;
+	
+	private var _c				: int;
+	private var _ca				: Number;
+	
+	private var _rotY				: int;
+	private var _rotX				: int;
+	
+	private var _oy:Number;
+	private var _ox:Number;
+	
+	//--------------------------------------------------------------------------
+	//
+	//  Properties
+	//
+	//--------------------------------------------------------------------------
+	
+	//----------------------------------
+	//  x
+	//----------------------------------  
+	
+	/**
+	 *  @private
+	 *  Storage property for x.
+	 */
+	private var _x:Number;
+	
+//	/**
+//	 *	x
+//	 * 
+//	 *  @langversion 3.0
+//	 *  @playerversion Flash 10
+//	 *  @playerversion AIR 1.5
+//	 *  @productversion Flex 4
+//	 */
+//	public function get x():Number
+//	{
+//		return _x;
+//	}
+	
+	
+	//----------------------------------
+	//  y
+	//----------------------------------  
+	
+	/**
+	 *  @private
+	 *  Storage property for y.
+	 */
+	private var _y:Number;
+	
+//	/**
+//	 *	y
+//	 * 
+//	 *  @langversion 3.0
+//	 *  @playerversion Flash 10
+//	 *  @playerversion AIR 1.5
+//	 *  @productversion Flex 4
+//	 */
+//	public function get y():Number
+//	{
+//		return _y;
+//	}
+	
+	
+	//----------------------------------
+	//  z
+	//----------------------------------  
+	
+	/**
+	 *  @private
+	 *  Storage property for z.
+	 */
+	private var _z:Number;
+	
+//	/**
+//	 *	z
+//	 * 
+//	 *  @langversion 3.0
+//	 *  @playerversion Flash 10
+//	 *  @playerversion AIR 1.5
+//	 *  @productversion Flex 4
+//	 */
+//	public function get z():Number
+//	{
+//		return _z;
+//	}
+	
+	
+	//----------------------------------
+	//  xRotation
+	//----------------------------------  
+	
+	/**
+	 *  @private
+	 *  Storage property for xRotation.
+	 */
+	private var _xRotation:Number;
+	
+//	/**
+//	 *	xRotation
+//	 * 
+//	 *  @langversion 3.0
+//	 *  @playerversion Flash 10
+//	 *  @playerversion AIR 1.5
+//	 *  @productversion Flex 4
+//	 */
+//	public function get xRotation():Number
+//	{
+//		return _xRotation;
+//	}
+	
+	
+	//----------------------------------
+	//  yRotation
+	//----------------------------------  
+	
+	/**
+	 *  @private
+	 *  Storage property for yRotation.
+	 */
+	private var _yRotation:Number;
+	
+	/**
+	 *	yRotation
+	 * 
+	 *  @langversion 3.0
+	 *  @playerversion Flash 10
+	 *  @playerversion AIR 1.5
+	 *  @productversion Flex 4
+	 */
+//	public function get yRotation():Number
+//	{
+//		return _yRotation;
+//	}
+//	
+//	
+	public function get radiusZ():Number
+	{
+		return _rz;
+	}
+	
+	
+	//----------------------------------
+	//  colorTransform
+	//----------------------------------  
+	
+	/**
+	 *  @private
+	 *  Storage property for colorTransform.
+	 */
+	private var _colorTransform:ColorTransform;
+	
+	/**
+	 *	colorTransform
+	 * 
+	 *  @langversion 3.0
+	 *  @playerversion Flash 10
+	 *  @playerversion AIR 1.5
+	 *  @productversion Flex 4
+	 */
+	public function get colorTransform():ColorTransform
+	{
+		return _colorTransform;
+	}
+	
+	
+	
+	//--------------------------------------------------------------------------
+	//
+	//  Methods
+	//
+	//--------------------------------------------------------------------------
+	
+	/**
+	 *	updateForLayoutPass
+	 * 
+	 *  @langversion 3.0
+	 *  @playerversion Flash 10
+	 *  @playerversion AIR 1.5
+	 *  @productversion Flex 4
+	 */
+	public function updateForLayoutPass( centerMultiplierX:Number, centerMultiplierY:Number, rotX:int, rotY:int ):void
+	{
+		_index = Math.floor( _layout.animationValue );
+		_indexOffset = _layout.animationValue - _index;
+		
+		
+		_cx = _layout.unscaledWidth * centerMultiplierX;
+		_cy = _layout.unscaledHeight * centerMultiplierY;
+		
+		_ho = _layout.horizontalAlignOffset;
+		_vo = _layout.verticalAlignOffset;
+		
+		_c = _layout.depthColor;
+		_ca = _layout.depthColorAlpha / 100;
+		
+		if( _c < 0 )
+		{
+			_colorTransform.redMultiplier = _colorTransform.greenMultiplier = _colorTransform.blueMultiplier = 1;
+			_colorTransform.redOffset = _colorTransform.greenOffset = _colorTransform.blueOffset = _colorTransform.alphaOffset = 0;
+		}
+		
+		_rx = _layout.radiusX;
+		_ry = _layout.radiusY;
+		_rz = _layout.radiusZ;
+		
+		if( isNaN( _rz ) ) _rz = Math.abs( ( Math.abs( _rx ) > Math.abs( _ry ) ) ? _rx : _ry );
+		
+		_rotY = rotY;
+		_rotX = rotX;
+		
+		const numElements:int = _layout.numUnselectedElements < 0 ? 0 : _layout.numUnselectedElements;
+
+		_an = numElements ? _layout.angle / ( numElements * 2 ) : _layout.angle / _layout.numElementsInLayout;
+	}
+	
+	/**
+	 *	circular
+	 * 
+	 *  @langversion 3.0
+	 *  @playerversion Flash 10
+	 *  @playerversion AIR 1.5
+	 *  @productversion Flex 4
+	 */
+	private function layout( index:Number ):void
+	{
+		const degree:Number = _an * index;
+		const radian:Number = degree * Math.PI / 180;
+		
+		_x = _cx + _ho + ( Math.sin( radian ) * _rx );
+		_y = _cy + _vo + ( Math.sin( radian ) * _ry );
+		_z = _rz - ( Math.cos( radian ) * _rz );
+		
+		_yRotation = _rx && _rotY != 0 ? -( angle( _x, _z, _cx + _ho, _rz ) - 90 ) * _rotY : 0;
+		_xRotation = _ry && _rotX != 0 ? ( angle( _y , _z, _cy + _vo, _rz ) - 90 ) * _rotX : 0;
+		
+		if( _rz < 0 )
+		{
+			if( _yRotation ) _yRotation += 180;
+			if( _xRotation ) _xRotation += 180;
+		}
+	}
+	
+	public function angle( x1:Number, y1:Number, x2:Number, y2:Number ):Number
+	{
+		return Math.atan2( y2 - y1, x2 - x1 ) * ( 180 / Math.PI );
+	}
+	
+	
+	/**
+	 *	updateForIndex
+	 * 
+	 *  @langversion 3.0
+	 *  @playerversion Flash 10
+	 *  @playerversion AIR 1.5
+	 *  @productversion Flex 4
+	 */
+	public function updateForIndex( i:int, element:IVisualElement, width:Number, height:Number, hMultiplier:Number, vMultiplier:Number ):void
+	{
+		_ox = ( width / 2 ) * ( hMultiplier - 0.5 ) * 2;
+		_oy = ( height / 2 ) * ( vMultiplier - 0.5 ) * 2;
+		
+		layout( ( i - _index ) - _indexOffset );
+		
+		if( _c > -1 )
+		{
+			const radian:Number = ( _layout.angle / 2 ) * Math.PI / 180;
+			const maxDepth:Number = _rz - ( Math.cos( radian ) * _rz )
+			const v:Number = ( _z / maxDepth ) * _ca;
+			
+			_colorTransform.color = _c;
+			_colorTransform.redOffset *= v;
+			_colorTransform.greenOffset *= v;
+			_colorTransform.blueOffset *= v;
+			_colorTransform.redMultiplier = _colorTransform.greenMultiplier = _colorTransform.blueMultiplier = 1 - v;
+		}
+		
+		element.transformAround( new Vector3D( width / 2, height / 2, 0 ),
+			null,
+			null,
+			new Vector3D( _x - _ox, _y - _oy, _z ),
+			null,
+			new Vector3D( _xRotation, _yRotation, 0 ),
+			new Vector3D( _x - _ox, _y - _oy, _z ),
+			false );
+	}
+}
\ No newline at end of file



Mime
View raw message