You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@flex.apache.org by bi...@apache.org on 2014/11/24 22:13:20 UTC

[30/44] git commit: [flex-sdk] [refs/heads/develop] - New iOS7+ specific skins for BusyIndicator. Update the Android skin for BusyIndicator.

New iOS7+ specific skins for BusyIndicator.
Update the Android skin for BusyIndicator.


Project: http://git-wip-us.apache.org/repos/asf/flex-sdk/repo
Commit: http://git-wip-us.apache.org/repos/asf/flex-sdk/commit/7bdae1a7
Tree: http://git-wip-us.apache.org/repos/asf/flex-sdk/tree/7bdae1a7
Diff: http://git-wip-us.apache.org/repos/asf/flex-sdk/diff/7bdae1a7

Branch: refs/heads/develop
Commit: 7bdae1a7d5b07fe7c6cc12ea5b259a5f306e1a96
Parents: 0dd7d82
Author: OmPrakash Muppirala <bi...@gmail.com>
Authored: Tue Nov 4 16:25:07 2014 -0800
Committer: OmPrakash Muppirala <bi...@gmail.com>
Committed: Tue Nov 4 16:25:07 2014 -0800

----------------------------------------------------------------------
 frameworks/projects/mobiletheme/defaults.css    |  13 +-
 .../spark/skins/android4/BusyIndicatorSkin.as   |  38 +-
 .../src/spark/skins/ios7/BusyIndicatorSkin.as   |  58 +-
 .../spark/skins/ios7/assets/BusyIndicator.fxg   | 191 ++++-
 .../spark/src/spark/components/BusyIndicator.as | 852 ++++---------------
 5 files changed, 416 insertions(+), 736 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/flex-sdk/blob/7bdae1a7/frameworks/projects/mobiletheme/defaults.css
----------------------------------------------------------------------
diff --git a/frameworks/projects/mobiletheme/defaults.css b/frameworks/projects/mobiletheme/defaults.css
index b0c9a5d..b65e915 100644
--- a/frameworks/projects/mobiletheme/defaults.css
+++ b/frameworks/projects/mobiletheme/defaults.css
@@ -986,6 +986,12 @@ global
 		skinClass: ClassReference("spark.skins.ios7.ButtonSkin");
 	}
 	
+	BusyIndicator
+	{
+		skinClass: ClassReference("spark.skins.ios7.BusyIndicatorSkin");
+		rotationInterval: 30;  /* Must be multiples of 30 */
+	}	
+	
 	Button
 	{
 		skinClass: ClassReference("spark.skins.ios7.ButtonSkin");
@@ -1176,11 +1182,6 @@ global
 		skinClass : ClassReference("spark.skins.ios7.ViewMenuItemSkin");
 	}
 	
-	MobileBusyIndicator
-	{
-		skinClass: ClassReference("spark.skins.ios7.BusyIndicatorSkin");
-	}
-	
 	ViewNavigator
 	{
 		skinClass: ClassReference("spark.skins.mobile.ViewNavigatorSkin");
@@ -1452,7 +1453,7 @@ application-dpi=240.
 		skinClass: ClassReference("spark.skins.android4.TransparentActionButtonSkin");
 	}
 	
-	MobileBusyIndicator
+	BusyIndicator
 	{
 		skinClass: ClassReference("spark.skins.android4.BusyIndicatorSkin");
 	}

http://git-wip-us.apache.org/repos/asf/flex-sdk/blob/7bdae1a7/frameworks/projects/mobiletheme/src/spark/skins/android4/BusyIndicatorSkin.as
----------------------------------------------------------------------
diff --git a/frameworks/projects/mobiletheme/src/spark/skins/android4/BusyIndicatorSkin.as b/frameworks/projects/mobiletheme/src/spark/skins/android4/BusyIndicatorSkin.as
index dd3aa44..964b8cf 100644
--- a/frameworks/projects/mobiletheme/src/spark/skins/android4/BusyIndicatorSkin.as
+++ b/frameworks/projects/mobiletheme/src/spark/skins/android4/BusyIndicatorSkin.as
@@ -27,7 +27,7 @@ package spark.skins.android4
 	import spark.skins.android4.assets.BusyIndicator;
 	import spark.skins.mobile.supportClasses.MobileSkin;
 	
-	import spark.components.MobileBusyIndicator;
+	import spark.components.BusyIndicator;
 	
 	public class BusyIndicatorSkin extends MobileSkin
 	{
@@ -43,6 +43,8 @@ package spark.skins.android4
 		 *  Current rotation of this component in degrees.
 		 */   
 		private var currentRotation:Number = 0;
+		private var symbolColor:uint;
+		private var symbolColorChanged:Boolean = false;		
 		
 		public function BusyIndicatorSkin()
 		{
@@ -90,14 +92,14 @@ package spark.skins.android4
 			}
 		}
 		
-		private var _hostComponent:spark.components.MobileBusyIndicator;
+		private var _hostComponent:spark.components.BusyIndicator;
 		
-		public function get hostComponent():spark.components.MobileBusyIndicator
+		public function get hostComponent():spark.components.BusyIndicator
 		{
 			return _hostComponent;
 		}
 		
-		public function set hostComponent(value:spark.components.MobileBusyIndicator):void 
+		public function set hostComponent(value:spark.components.BusyIndicator):void 
 		{
 			_hostComponent = value;
 		}
@@ -131,6 +133,34 @@ package spark.skins.android4
 			}
 		}
 		
+		override public function styleChanged(styleProp:String):void
+		{
+			var allStyles:Boolean = !styleProp || styleProp == "styleName";
+			
+			if (allStyles || styleProp == "symbolColor")
+			{
+				symbolColor = getStyle("symbolColor");
+				symbolColorChanged = true;
+				invalidateDisplayList();
+			}
+			super.styleChanged(styleProp);
+		}
+		
+		override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
+		{
+			super.updateDisplayList(unscaledWidth,unscaledHeight);
+			if(symbolColorChanged)
+			{
+				colorizeSymbol();	
+				symbolColorChanged = false;
+			}
+		}
+		
+		private function colorizeSymbol():void
+		{
+			super.applyColorTransform(this.busyIndicator, 0x000000, symbolColor);
+		}		
+		
 		private function startRotation():void
 		{
 			rotationTimer = new Timer(rotationInterval);

http://git-wip-us.apache.org/repos/asf/flex-sdk/blob/7bdae1a7/frameworks/projects/mobiletheme/src/spark/skins/ios7/BusyIndicatorSkin.as
----------------------------------------------------------------------
diff --git a/frameworks/projects/mobiletheme/src/spark/skins/ios7/BusyIndicatorSkin.as b/frameworks/projects/mobiletheme/src/spark/skins/ios7/BusyIndicatorSkin.as
index 62f4a8d..16620d4 100644
--- a/frameworks/projects/mobiletheme/src/spark/skins/ios7/BusyIndicatorSkin.as
+++ b/frameworks/projects/mobiletheme/src/spark/skins/ios7/BusyIndicatorSkin.as
@@ -23,26 +23,31 @@ package spark.skins.ios7
 	import flash.events.TimerEvent;
 	import flash.geom.Matrix;
 	import flash.utils.Timer;
+	
 	import mx.core.DPIClassification;
+	
+	import spark.components.BusyIndicator;
 	import spark.skins.ios7.assets.BusyIndicator;
 	import spark.skins.mobile.supportClasses.MobileSkin;
 	
-	import spark.components.MobileBusyIndicator;
-	
 	public class BusyIndicatorSkin extends MobileSkin
 	{
-		static private const DEFAULT_ROTATION_INTERVAL:Number = 50;
+		static private const DEFAULT_ROTATION_INTERVAL:Number = 30;
 		private var busyIndicatorClass:Class;
 		private var busyIndicator:DisplayObject;
+		private var busyIndicatorBackground:DisplayObject;
 		private var busyIndicatorDiameter:Number;
 		private var rotationTimer:Timer;
 		private var rotationInterval:Number;
+		private var rotationSpeed:Number;
 		/**
 		 *  @private
 		 * 
 		 *  Current rotation of this component in degrees.
 		 */   
 		private var currentRotation:Number = 0;
+		private var symbolColor:uint;
+		private var symbolColorChanged:Boolean = false;
 		
 		public function BusyIndicatorSkin()
 		{
@@ -52,8 +57,9 @@ package spark.skins.ios7
 			rotationInterval = getStyle("rotationInterval");
 			if (isNaN(rotationInterval))
 				rotationInterval = DEFAULT_ROTATION_INTERVAL;
-			if (rotationInterval < 16.6)
-				rotationInterval = 16.6;
+			if (rotationInterval < 30) //Spokes are at 30 degree angle to each other. 
+				rotationInterval = 30;
+			rotationSpeed = 60;
 			
 			switch(applicationDPI) 
 			{	
@@ -90,21 +96,27 @@ package spark.skins.ios7
 			}
 		}
 		
-		private var _hostComponent:spark.components.MobileBusyIndicator;
+		private var _hostComponent:spark.components.BusyIndicator;
 		
-		public function get hostComponent():spark.components.MobileBusyIndicator
+		public function get hostComponent():spark.components.BusyIndicator
 		{
 			return _hostComponent;
 		}
 		
-		public function set hostComponent(value:spark.components.MobileBusyIndicator):void 
+		public function set hostComponent(value:spark.components.BusyIndicator):void 
 		{
 			_hostComponent = value;
 		}
 		
 		override protected function createChildren():void
 		{
+			//This layer stays still in the background
+			busyIndicatorBackground = new busyIndicatorClass();
+			busyIndicatorBackground.width = busyIndicatorBackground.height = busyIndicatorDiameter;
+			addChild(busyIndicatorBackground);
+			//This layer rotates in the foreground to give the required effect
 			busyIndicator = new busyIndicatorClass();
+			busyIndicator.alpha = 0.3;
 			busyIndicator.width = busyIndicator.height = busyIndicatorDiameter;
 			addChild(busyIndicator);
 		}
@@ -131,9 +143,37 @@ package spark.skins.ios7
 			}
 		}
 		
+		override public function styleChanged(styleProp:String):void
+		{
+			var allStyles:Boolean = !styleProp || styleProp == "styleName";
+			
+			if (allStyles || styleProp == "symbolColor")
+			{
+				symbolColor = getStyle("symbolColor");
+				symbolColorChanged = true;
+				invalidateDisplayList();
+			}
+			super.styleChanged(styleProp);
+		}
+		
+		override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
+		{
+			super.updateDisplayList(unscaledWidth,unscaledHeight);
+			if(symbolColorChanged)
+			{
+				colorizeSymbol();	
+				symbolColorChanged = false;
+			}
+		}
+		
+		private function colorizeSymbol():void
+		{
+			super.applyColorTransform(this.busyIndicator, 0x000000, symbolColor);
+		}
+		
 		private function startRotation():void
 		{
-			rotationTimer = new Timer(rotationInterval);
+			rotationTimer = new Timer(rotationSpeed);
 			if (!rotationTimer.hasEventListener(TimerEvent.TIMER))
 			{
 				rotationTimer.addEventListener(TimerEvent.TIMER, timerHandler);

http://git-wip-us.apache.org/repos/asf/flex-sdk/blob/7bdae1a7/frameworks/projects/mobiletheme/src/spark/skins/ios7/assets/BusyIndicator.fxg
----------------------------------------------------------------------
diff --git a/frameworks/projects/mobiletheme/src/spark/skins/ios7/assets/BusyIndicator.fxg b/frameworks/projects/mobiletheme/src/spark/skins/ios7/assets/BusyIndicator.fxg
index e04248f..f6930b9 100644
--- a/frameworks/projects/mobiletheme/src/spark/skins/ios7/assets/BusyIndicator.fxg
+++ b/frameworks/projects/mobiletheme/src/spark/skins/ios7/assets/BusyIndicator.fxg
@@ -18,47 +18,200 @@
 
 -->
 
-<Graphic version="2.0" xmlns="http://ns.adobe.com/fxg/2008" viewWidth="36" viewHeight="36">
+<Graphic version="2.0" xmlns="http://ns.adobe.com/fxg/2008">
   <Group>
-    <Group x="-12.8125" y="-6.73926">
+    <Group x="26">
       <mask>
-        <Group x="12.8496" y="6.6665">
-          <Path winding="nonZero" data="M0 18.0117C0 27.9429 6.96289 35.9961 17.9629 36.0239L17.9629 33.0127C8.96289 32.9858 3.01074 26.2813 3.01074 18.0117 3.01074 9.74316 8.96289 3.03809 17.9629 3.00977L17.9629 0C6.96289 0.027832 0 8.08008 0 18.0117Z">
+        <Group>
+          <Path winding="nonZero" data="M4 14 0 14 0 0 4 0 4 14Z">
             <fill>
               <SolidColor color="#FFFFFF"/>
             </fill>
           </Path>
         </Group>
       </mask>
-      <Path winding="nonZero" data="M0 36.7485 16.332 0 44.7012 12.6084 28.3691 49.3569 0 36.7485Z">
+      <Path winding="nonZero" data="M4 12C4 13.1006 3.09961 14 2 14 0.900391 14 0 13.1006 0 12L0 2C0 0.899414 0.900391 0 2 0 3.09961 0 4 0.899414 4 2L4 12Z">
         <fill>
-          <LinearGradient x="13.4458" y="44.7148" scaleX="27.8603" rotation="293.962">
-            <GradientEntry ratio="0" color="#FFFFFF"/>
-            <GradientEntry ratio="0.576638" color="#B4B4B3"/>
-            <GradientEntry ratio="0.820765" color="#9C9C9B"/>
-            <GradientEntry ratio="1" color="#919190"/>
-          </LinearGradient>
+          <SolidColor color="#EEEEEE"/>
         </fill>
       </Path>
     </Group>
-    <Group x="2.61719" y="-8">
+    <Group x="12.4971" y="2.60596">
       <mask>
-        <Group x="15.3828" y="7.92773">
-          <Path winding="nonZero" data="M0 3.00977C8 3.03809 14.9512 9.74316 14.9512 18.0117 14.9512 26.2813 8 32.9858 0 33.0127L0 36.0239C10 35.9961 17.9629 27.9429 17.9629 18.0117 17.9629 8.08008 10 0.027832 0 0L0 3.00977Z">
+        <Group>
+          <Path winding="nonZero" data="M10.4639 12.1245 7 14.1245 0 2 3.46387 0 10.4639 12.1245Z">
             <fill>
               <SolidColor color="#FFFFFF"/>
             </fill>
           </Path>
         </Group>
       </mask>
-      <Path winding="nonZero" data="M49.7617 34.4028 29.1016 0 0 17.4766 20.6621 51.8799 49.7617 34.4028Z">
+      <Path x="0.733521" y="0.733643" winding="nonZero" data="M8.73035 9.65894C9.28064 10.6121 8.95056 11.8411 7.99841 12.3909 7.04626 12.9407 5.81677 12.6121 5.26648 11.6589L0.266479 2.99878C-0.283813 2.04565 0.0462646 0.816162 0.998413 0.266357 1.95056 -0.283447 3.18005 0.0456543 3.73035 0.998779L8.73035&#xD;&#xA; 9.65894Z">
         <fill>
-          <LinearGradient x="37.6406" y="47.1841" scaleX="27.7241" rotation="239.012">
-            <GradientEntry ratio="0" color="#919190"/>
-            <GradientEntry ratio="1" color="#FFFFFF"/>
-          </LinearGradient>
+          <SolidColor color="#333333"/>
         </fill>
       </Path>
     </Group>
+    <Group x="3.10596" y="11.8823">
+      <mask>
+        <Group>
+          <Path winding="nonZero" data="M14.1245 7.00049 12.1245 10.4644 0 3.46436 2 0 14.1245 7.00049Z">
+            <fill>
+              <SolidColor color="#FFFFFF"/>
+            </fill>
+          </Path>
+        </Group>
+      </mask>
+      <Path x="0.733643" y="0.733887" winding="nonZero" data="M11.6589 5.2666C12.6121 5.81689 12.9407 7.04639 12.3909 7.99854 11.8411 8.95068 10.6121 9.28076 9.65894 8.73047L0.998779 3.73047C0.0456543 3.18018 -0.283447 1.95068 0.266357 0.998047 0.816162 0.0458984 2.04517 -0.283691 2.99829 0.266602L11.6589&#xD;&#xA; 5.2666Z">
+        <fill>
+          <SolidColor color="#444444"/>
+        </fill>
+      </Path>
+    </Group>
+    <Group x="0.343262" y="25.3438">
+      <mask>
+        <Group>
+          <Path winding="nonZero" data="M14.0005 0 14.0005 4 0 4 0 0 14.0005 0Z">
+            <fill>
+              <SolidColor color="#FFFFFF"/>
+            </fill>
+          </Path>
+        </Group>
+      </mask>
+      <Path winding="nonZero" data="M12.0005 0C13.1011 0 14.0005 0.900391 14.0005 2 14.0005 3.09961 13.1011 4 12.0005 4L2.00049 4C0.899902 4 0 3.09961 0 1.99951 0 0.900391 0.899902 0.000488281 2 0.000488281L12.0005 0Z">
+        <fill>
+          <SolidColor color="#555555"/>
+        </fill>
+      </Path>
+    </Group>
+    <Group x="2.94922" y="32.3828">
+      <mask>
+        <Group>
+          <Path winding="nonZero" data="M12.125 0 14.125 3.46387 2 10.4639 0 7 12.125 0Z">
+            <fill>
+              <SolidColor color="#FFFFFF"/>
+            </fill>
+          </Path>
+        </Group>
+      </mask>
+      <Path x="0.733765" y="0.733215" winding="nonZero" data="M9.6593 0.266785C10.6124 -0.283997 11.8414 0.0460815 12.3912 0.99823 12.941 1.95135 12.6124 3.17987 11.6593 3.73065L2.99915 8.73065C2.04602 9.28046 0.81604 8.95135 0.266235 7.99823 -0.283569 7.04608 0.0460205 5.81757 0.998657 5.26678L9.6593 0.266785Z">
+        <fill>
+          <SolidColor color="#666666"/>
+        </fill>
+      </Path>
+    </Group>
+    <Group x="12.2256" y="38.1133">
+      <mask>
+        <Group>
+          <Path winding="nonZero" data="M7.00098 0 10.4648 2 3.46436 14.125 0 12.125 7.00098 0Z">
+            <fill>
+              <SolidColor color="#FFFFFF"/>
+            </fill>
+          </Path>
+        </Group>
+      </mask>
+      <Path x="0.734314" y="0.733459" winding="nonZero" data="M5.26666 0.998962C5.81647 0.0448608 7.04596 -0.283264 7.99811 0.266541 8.95074 0.816345 9.28082 2.04486 8.73053 2.99799L3.73053 11.6581C3.18024 12.6113 1.95026 12.9413 0.99762 12.3906 0.0454712 11.8408 -0.283142 10.6122 0.266174 9.65912L5.26666&#xD;&#xA; 0.998962Z">
+        <fill>
+          <SolidColor color="#777777"/>
+        </fill>
+      </Path>
+    </Group>
+    <Group x="25.6875" y="41">
+      <mask>
+        <Group>
+          <Path winding="nonZero" data="M0 0 4 0 4 14.001 0 14.001 0 0Z">
+            <fill>
+              <SolidColor color="#FFFFFF"/>
+            </fill>
+          </Path>
+        </Group>
+      </mask>
+      <Path winding="nonZero" data="M0 2C-0.000976563 0.899414 0.900391 0 2 0 3.09961 0 4 0.898438 4 1.99902L4 11.999C4 13.0996 3.09961 14.001 1.99902 14 0.899414 14 0.000976563 13.1006 0 12L0 2Z">
+        <fill>
+          <SolidColor color="#888888"/>
+        </fill>
+      </Path>
+    </Group>
+    <Group x="32.7266" y="38.2695">
+      <mask>
+        <Group>
+          <Path winding="nonZero" data="M0 2 3.46387 0 10.4648 12.125 7 14.125 0 2Z">
+            <fill>
+              <SolidColor color="#FFFFFF"/>
+            </fill>
+          </Path>
+        </Group>
+      </mask>
+      <Path x="0.732788" y="0.733398" winding="nonZero" data="M0.267212 2.99805C-0.284546 2.0459 0.0465088 0.816406 0.998657 0.266602 1.95178 -0.283203 3.1803 0.0449219 3.73108 0.998047L8.73108 9.6582C9.28088 10.6113 8.95178 11.8418 7.99866 12.3916 7.04553 12.9414 5.81799 12.6113 5.26721 11.6592L0.267212&#xD;&#xA; 2.99805Z">
+        <fill>
+          <SolidColor color="#999999"/>
+        </fill>
+      </Path>
+    </Group>
+    <Group x="38.457" y="32.6533">
+      <mask>
+        <Group>
+          <Path winding="nonZero" data="M0 3.46387 2 0 14.125 7 12.125 10.4648 0 3.46387Z">
+            <fill>
+              <SolidColor color="#FFFFFF"/>
+            </fill>
+          </Path>
+        </Group>
+      </mask>
+      <Path x="0.733398" y="0.73291" winding="nonZero" data="M0.998047 3.73096C0.0449219 3.18213 -0.283203 1.95166 0.266602 0.999512 0.816406 0.0463867 2.04492 -0.283691 2.99805 0.266113L11.6582 5.26611C12.6113 5.81689 12.9414 7.04736 12.3906 7.99951 11.8398 8.95264 10.6123 9.28076 9.65918 8.73096L0.998047&#xD;&#xA; 3.73096Z">
+        <fill>
+          <SolidColor color="#AAAAAA"/>
+        </fill>
+      </Path>
+    </Group>
+    <Group x="41.3438" y="25.6558">
+      <mask>
+        <Group>
+          <Path winding="nonZero" data="M0 4.00049 0 0.000488281 14.001 0 14.001 4.00049 0 4.00049Z">
+            <fill>
+              <SolidColor color="#FFFFFF"/>
+            </fill>
+          </Path>
+        </Group>
+      </mask>
+      <Path winding="nonZero" data="M1.99902 4.00049C0.899414 4.00146 0 3.1001 0 2.00098 0 0.900391 0.898438 0.000488281 1.99902 0L11.999 0C13.0996 0.000488281 14.001 0.900879 14 2.00098 13.999 3.10156 13.1006 3.99951 12 4.00049L1.99902 4.00049Z">
+        <fill>
+          <SolidColor color="#BBBBBB"/>
+        </fill>
+      </Path>
+    </Group>
+    <Group x="38.6133" y="12.1523">
+      <mask>
+        <Group>
+          <Path winding="nonZero" data="M2 10.4648 0 7.00098 12.125 0 14.125 3.46436 2 10.4648Z">
+            <fill>
+              <SolidColor color="#FFFFFF"/>
+            </fill>
+          </Path>
+        </Group>
+      </mask>
+      <Path x="0.733398" y="0.734619" winding="nonZero" data="M2.99805 8.73071C2.0459 9.28149 0.816406 8.95044 0.266602 7.99878 -0.283203 7.04565 0.0449219 5.81714 0.99707 5.26636L9.65723 0.266357C10.6113 -0.283447 11.8418 0.0456543 12.3906 0.998779 12.9404 1.95239 12.6113 3.17944 11.6592 3.73022L2.99805&#xD;&#xA; 8.73071Z">
+        <fill>
+          <SolidColor color="#CCCCCC"/>
+        </fill>
+      </Path>
+    </Group>
+    <Group x="32.9971" y="2.76123">
+      <mask>
+        <Group>
+          <Path winding="nonZero" data="M3.46387 14.1255 0 12.1255 7 0 10.4639 2 3.46387 14.1255Z">
+            <fill>
+              <SolidColor color="#FFFFFF"/>
+            </fill>
+          </Path>
+        </Group>
+      </mask>
+      <Path x="0.73291" y="0.73468" winding="nonZero" data="M3.73096 11.6594C3.18115 12.6125 1.95166 12.9406 0.999512 12.3913 0.0463867 11.8405 -0.283691 10.6125 0.266113 9.65936L5.26514 0.999207C5.81689 0.0460815 7.04736 -0.283997 7.99854 0.266785 8.95166 0.818054 9.28076 2.0451 8.73096 2.99823L3.73096&#xD;&#xA; 11.6594Z">
+        <fill>
+          <SolidColor color="#DDDDDD"/>
+        </fill>
+      </Path>
+    </Group>
+    <Path visible="false" winding="nonZero" data="M0 0 53 0 53 53 0 53 0 0Z"/>
   </Group>
 </Graphic>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/flex-sdk/blob/7bdae1a7/frameworks/projects/spark/src/spark/components/BusyIndicator.as
----------------------------------------------------------------------
diff --git a/frameworks/projects/spark/src/spark/components/BusyIndicator.as b/frameworks/projects/spark/src/spark/components/BusyIndicator.as
index c47c9cf..8230525 100644
--- a/frameworks/projects/spark/src/spark/components/BusyIndicator.as
+++ b/frameworks/projects/spark/src/spark/components/BusyIndicator.as
@@ -19,33 +19,17 @@
 
 package spark.components
 {
-
-import flash.display.CapsStyle;
-import flash.display.Graphics;
-import flash.display.LineScaleMode;
-import flash.display.Shape;
-import flash.display.Sprite;
-import flash.events.Event;
-import flash.events.TimerEvent;
-import flash.geom.Matrix;
-import flash.geom.Matrix3D;
-import flash.geom.Point;
-import flash.geom.Transform;
-import flash.geom.Vector3D;
-import flash.utils.Timer;
-
-import mx.core.DesignLayer;
-import mx.core.DPIClassification;
-import mx.core.FlexGlobals;
-import mx.core.IUIComponent;
-import mx.core.IVisualElement;
-import mx.core.UIComponent;
-import mx.core.mx_internal;
-import mx.events.FlexEvent;
-import mx.events.PropertyChangeEvent;
-import mx.geom.TransformOffsets;
-
-use namespace mx_internal;
+	import flash.events.Event;
+	
+	import mx.core.IUIComponent;
+	import mx.core.IVisualElement;
+	import mx.events.FlexEvent;
+	import mx.states.State;
+	
+	import spark.components.supportClasses.SkinnableComponent;
+	
+	[SkinState("rotatingState")]
+	[SkinState("notRotatingState")]
 
 //--------------------------------------
 //  Styles
@@ -138,683 +122,155 @@ use namespace mx_internal;
  *  @langversion 3.0
  *  @playerversion AIR 2.5
  *  @productversion Flex 4.5
- */
-public class BusyIndicator extends UIComponent
-{
-
-    //--------------------------------------------------------------------------
-    //
-    //  Class constants
-    //
-    //--------------------------------------------------------------------------
-    
-    /**
-     *  @private
-     */ 
-    static private const DEFAULT_ROTATION_INTERVAL:Number = 50;
-
-    /**
-     *  @private
-     */ 
-    static private const DEFAULT_MINIMUM_SIZE:Number = 20;
-
-    /**
-     *  @private
-     */ 
-    static private const RADIANS_PER_DEGREE:Number = Math.PI / 180;
-    
-    //--------------------------------------------------------------------------
-    //
-    //  Constructor
-    //
-    //--------------------------------------------------------------------------
-    
-    /**
-     *  Constructor.
-     *  
-     *  @langversion 3.0
-     *  @playerversion AIR 2.5
-     *  @productversion Flex 4.5
-     */
-    public function BusyIndicator()
-    {
-        super();
-        
-        alpha = 0.60;       // default alpha
-        
-        // Listen to added to stage and removed from stage.
-        // Start rotating when we are on the stage and stop
-        // when we are removed from the stage.
-        addEventListener(Event.ADDED_TO_STAGE, addedToStageHandler);
-        addEventListener(Event.REMOVED_FROM_STAGE, removedFromStageHandler);
-    }
-    
-    //--------------------------------------------------------------------------
-    //
-    //  Variables
-    //
-    //--------------------------------------------------------------------------
-    
-    /**
-     *  @private
-     */
-    private var effectiveVisibility:Boolean = false;
-    
-    /**
-     *  @private
-     */
-    private var effectiveVisibilityChanged:Boolean = true;
-    
-    /**
-     *  @private
-     */   
-    private var oldUnscaledHeight:Number;
-
-    /**
-     *  @private
-     */   
-    private var oldUnscaledWidth:Number;
-    
-    /**
-     *  @private
-     */   
-    private var rotationTimer:Timer;
-
-    /**
-     *  @private
-     * 
-     *  Current rotation of this component in degrees.
-     */   
-    private var currentRotation:Number = 0;
-    
-    /**
-     *  @private
-     * 
-     *  Diameter of the spinner for this component.
-     */ 
-    private var spinnerDiameter:int;
-
-    /**
-     *  @private
-     * 
-     *  Cached value of the spoke color.
-     */ 
-    private var spokeColor:uint;
-
-    //--------------------------------------------------------------------------
-    //
-    //  Private Properties 
-    //
-    //--------------------------------------------------------------------------
-
-    /**
-     *  @private
-     *  Cache the last value of applicationDPI.
-     */ 
-    private var _applicationDPI:Number;
-    
-    /**
-     *  @private
-     * 
-     *  Get the applicationDPI in use.
-     */ 
-    private function get applicationDPI():Number
-    {
-        if (_applicationDPI)
-            return _applicationDPI;
-        
-        var application:Object = FlexGlobals.topLevelApplication;
-        
-        if ("applicationDPI" in application)
-            _applicationDPI = application["applicationDPI"];
-
-        return _applicationDPI; 
-    }
-    
-    //--------------------------------------------------------------------------
-    //
-    //  Overridden properties: UIComponent
-    //
-    //--------------------------------------------------------------------------
-    
-    /**
-     *  @private
-     */
-    override public function set designLayer(value:DesignLayer):void
-    {
-        super.designLayer = value;
-
-        effectiveVisibilityChanged = true;
-        invalidateProperties();
-    }
-    
-    //--------------------------------------------------------------------------
-    //
-    //  Overridden methods: UIComponent
-    //
-    //--------------------------------------------------------------------------
-    
-    /**
-     *  @private
-     */
-    override protected function commitProperties():void
-    {
-        super.commitProperties();
-        
-        if (effectiveVisibilityChanged)
-        {
-            // if visibility changed, re-compute them here
-            computeEffectiveVisibility();
-            
-            if (canRotate())
-                startRotation();
-            else
-                stopRotation();
-            
-            effectiveVisibilityChanged = false;
-        }
-    }
-
-    /**
-     *  @private
-     */
-    override protected function measure():void
-    {
-        super.measure();
-        
-        // Set the default measured size depending on the
-        // applicationDPI
-		if (applicationDPI == DPIClassification.DPI_640)
+ */	
+	public class BusyIndicator extends SkinnableComponent
+	{
+		private var effectiveVisibility:Boolean = false;
+		private var effectiveVisibilityChanged:Boolean = true;
+		
+		public function BusyIndicator()
 		{
-			measuredWidth = 104;
-			measuredHeight = 104;
+			super();
+			// Listen to added to stage and removed from stage.
+			// Start rotating when we are on the stage and stop
+			// when we are removed from the stage.
+			addEventListener(Event.ADDED_TO_STAGE, addedToStageHandler);
+			addEventListener(Event.REMOVED_FROM_STAGE, removedFromStageHandler);
+			states = 	[
+				new State({name:"notRotatingState"}),
+				new State({name:"rotatingState"})
+			];
 		}
-		else if (applicationDPI == DPIClassification.DPI_480)
+		
+		override protected function getCurrentSkinState():String
 		{
-			measuredWidth = 80;
-			measuredHeight = 80;
+			return currentState;
+		} 
+		
+		private function addedToStageHandler(event:Event):void
+		{
+			// Check our visibility here since we haven't added
+			// visibility listeners yet.
+			computeEffectiveVisibility();
+			
+			if (canRotate())
+				currentState = "rotatingState";
+			
+			addVisibilityListeners();
+			invalidateSkinState();
 		}
-		else if (applicationDPI == DPIClassification.DPI_320)
-        {
-            measuredWidth = 52;
-            measuredHeight = 52;
-        }
-        else if (applicationDPI == DPIClassification.DPI_240)
-        {
-            measuredWidth = 40;
-            measuredHeight = 40;
-        }
-		else if (applicationDPI == DPIClassification.DPI_160)
+		
+		private function removedFromStageHandler(event:Event):void
 		{
-			measuredWidth = 26;
-			measuredHeight = 26;
+			currentState = "notRotatingState";
+			
+			removeVisibilityListeners();
+			invalidateSkinState();
 		}
-		else if (applicationDPI == DPIClassification.DPI_120)
+		
+		private function computeEffectiveVisibility():void
 		{
-			measuredWidth = 20;
-			measuredHeight = 20;
+			
+			// Check our design layer first.
+			if (designLayer && !designLayer.effectiveVisibility)
+			{
+				effectiveVisibility = false;
+				return;
+			}
+			
+			// Start out with true visibility and enablement
+			// then loop up parent-chain to see if any of them are false.
+			effectiveVisibility = true;
+			var current:IVisualElement = this;
+			
+			while (current)
+			{
+				if (!current.visible)
+				{
+					if (!(current is IUIComponent) || !IUIComponent(current).isPopUp)
+					{
+						// Treat all pop ups as if they were visible. This is to 
+						// fix a bug where the BusyIndicator does not spin when it 
+						// is inside modal popup. The problem is in we do not get 
+						// an event when the modal window is made visible in 
+						// PopUpManagerImpl.fadeInEffectEndHandler(). When the modal
+						// window is made visible, setVisible() is passed "true" so 
+						// as to not send an event. When do get events when the 
+						// non-modal windows are popped up. Only modal windows are
+						// a problem.
+						// The downside of this fix is BusyIndicator components that are
+						// inside of hidden, non-modal, popup windows will paint themselves
+						// on a timer.
+						effectiveVisibility = false;
+						break;                  
+					}
+				}
+				
+				current = current.parent as IVisualElement;
+			}
 		}
-        else
-        {
-            measuredWidth = DEFAULT_MINIMUM_SIZE;
-            measuredHeight = DEFAULT_MINIMUM_SIZE;
-        }
-
-        measuredMinWidth = DEFAULT_MINIMUM_SIZE;
-        measuredMinHeight = DEFAULT_MINIMUM_SIZE;
-    }
-    
-    /**
-     *  @private
-     *  Override so we know when visibility is set. The initialized
-     *  property calls setVisible() with noEvent == true
-     *  so we wouldn't get a visibility event if we just listened
-     *  for events.
-     */
-    override public function setVisible(value:Boolean,
-                               noEvent:Boolean = false):void
-    {
-        super.setVisible(value, noEvent);
-        
-        effectiveVisibilityChanged = true;
-        invalidateProperties();
-    }
-    
-    /**
-     *  @private
-     */
-    override public function styleChanged(styleProp:String):void
-    {
-        super.styleChanged(styleProp);
-        
-        var allStyles:Boolean = !styleName || styleName == "styleName";
-
-        // Check for skin/icon changes here.
-        // We could only throw out any skins that change,
-        // but since dynamic re-skinning is uncommon, we'll take
-        // the simpler approach of throwing out all skins.
-        if (allStyles || styleName == "rotationInterval")
-        {
-            // Update the timer if the rotation interval has changed.
-            if (isRotating())
-            {
-                stopRotation();
-                startRotation();
-            }
-        }
-        
-        if (allStyles || styleName == "symbolColor")
-        {
-            updateSpinner(spinnerDiameter);
-        }
-    }
-
-    /**
-     *  @private
-     */
-    override protected function updateDisplayList(unscaledWidth:Number,
-                                                  unscaledHeight:Number):void
-    {
-        super.updateDisplayList(unscaledWidth, unscaledHeight);
-
-        // If the size changed, then create a new spinner.
-        if (oldUnscaledWidth != unscaledWidth ||
-            oldUnscaledHeight != unscaledHeight)
-        {
-            var newDiameter:Number;
-            
-            newDiameter = calculateSpinnerDiameter(unscaledWidth, unscaledHeight);
-            updateSpinner(newDiameter);
-
-            oldUnscaledWidth = unscaledWidth;
-            oldUnscaledHeight = unscaledHeight;
-        }
-    }
-    
-    //--------------------------------------------------------------------------
-    //
-    //  Methods
-    //
-    //--------------------------------------------------------------------------
-
-    /**
-     *   @private
-     *
-     *   Apply the rules to calculate the spinner diameter from the width
-     *   and height.
-     *  
-     *   @param width new width of this component
-     *   @param height new height of this component
-     *    
-     *   @return true if the spinner's diameter changes, false otherwise.
-     */
-    private function calculateSpinnerDiameter(width:Number, height:Number):Number
-    {
-        var diameter:Number = Math.min(width, height);
-        diameter = Math.max(DEFAULT_MINIMUM_SIZE, diameter);
-        if (diameter % 2 != 0)
-            diameter--;
-        
-        return diameter;
-    }
-    
-   /**
-    *   @private
-    * 
-    *   Update the spinner properties and redraw.
-    */
-    private function updateSpinner(diameter:Number):void
-    {
-        var isRotating:Boolean = isRotating();
-        
-        if (isRotating)
-            stopRotation();
-       
-        spinnerDiameter = diameter;
-        spokeColor = getStyle("symbolColor");
-        
-        drawSpinner();
-        
-        if (isRotating)
-            startRotation();
-    }
-
-    /**
-     *  @private
-     * 
-     *  Draw the spinner using the graphics property of this component.
-     */ 
-    mx_internal function drawSpinner():void 
-    {
-        var g:Graphics = graphics;
-        var spinnerRadius:int = spinnerDiameter / 2;
-        var spinnerWidth:int = spinnerDiameter;
-        var spokeHeight:Number = spinnerDiameter / 3.7;
-        var insideDiameter:Number = spinnerDiameter - (spokeHeight * 2); 
-        var spokeWidth:Number = insideDiameter / 5;
-        var eHeight:Number = spokeWidth / 2;
-        var spinnerPadding:Number = 0;
-
-        // Undocumented styles to modified the spokeWidth
-        // and spokeHeight.
-//        if (getStyle("spokeWidth") !== undefined)
-//        {
-//            spokeWidth = getStyle("spokeWidth");
-//            eHeight = spokeWidth / 2;
-//        }
-//        
-//        if (getStyle("spokeHeight") !== undefined)
-//            spokeHeight = getStyle("spokeHeight");
-//        
-//        // spinnerPadding is the padding between the outside
-//        // edge of the circle and the edge of a spoke. 
-//        if (getStyle("spinnerPadding") !== undefined)
-//            spinnerPadding = getStyle("spinnerPadding");
-//
-//        trace("spoke height = " + spokeHeight);
-//        trace("spoke width = " + spokeWidth);
-//        trace("center = " + center);
-        
-        g.clear();
-        
-        // 1
-        drawSpoke(0.20, currentRotation + 300, spokeWidth, spokeHeight, spokeColor, spinnerRadius, eHeight, spinnerPadding);
-        
-        // 2
-        drawSpoke(0.25, currentRotation + 330, spokeWidth, spokeHeight, spokeColor, spinnerRadius, eHeight, spinnerPadding);
-        
-        // 3
-        drawSpoke(0.30, currentRotation, spokeWidth, spokeHeight, spokeColor, spinnerRadius, eHeight, spinnerPadding);
-        
-        // 4
-        drawSpoke(0.35, currentRotation + 30, spokeWidth, spokeHeight, spokeColor, spinnerRadius, eHeight, spinnerPadding);
-        
-        // 5
-        drawSpoke(0.40, currentRotation + 60, spokeWidth, spokeHeight, spokeColor, spinnerRadius, eHeight, spinnerPadding);
-        
-        // 6
-        drawSpoke(0.45, currentRotation + 90, spokeWidth, spokeHeight, spokeColor, spinnerRadius, eHeight, spinnerPadding);
-        
-        // 7
-        drawSpoke(0.50, currentRotation + 120, spokeWidth, spokeHeight, spokeColor, spinnerRadius, eHeight, spinnerPadding);
-
-        // 8
-        drawSpoke(0.60, currentRotation + 150, spokeWidth, spokeHeight, spokeColor, spinnerRadius, eHeight, spinnerPadding);
-
-        // 9
-        drawSpoke(0.70, currentRotation + 180, spokeWidth, spokeHeight, spokeColor, spinnerRadius, eHeight, spinnerPadding);
-        
-        // 10
-        drawSpoke(0.80, currentRotation + 210, spokeWidth, spokeHeight, spokeColor, spinnerRadius, eHeight, spinnerPadding);
-        
-        // 11
-        drawSpoke(0.90, currentRotation + 240, spokeWidth, spokeHeight, spokeColor, spinnerRadius, eHeight, spinnerPadding);
-        
-        // 12
-        drawSpoke(1.0, currentRotation + 270, spokeWidth, spokeHeight, spokeColor, spinnerRadius, eHeight, spinnerPadding);
-    }
-    
-    
-    /**
-     *  @private
-     * 
-     *  @param spokeAlpha: alpha value of the spoke.
-     *  @param spokeWidth: width of the spoke in points.
-     *  @param spokeHeight: the lenght of the spoke in pixels.
-     *  @param spokeColor: the color of the spoke.
-     *  @param spinnerRadius: radius of the spinner.
-     *  @param eHeight: estimated height of the rounded end of the spinner.
-     *  @param spinnerPadding: number of pixels between the outside
-     *  radius of the spinner and the spokes. This is used to make 
-     *  spinners with skinny spokes look better by moving them
-     *  closer to the center of the spinner.
-     */ 
-    private function drawSpoke(spokeAlpha:Number, degrees:int,
-                               spokeWidth:Number, 
-                               spokeHeight:Number, 
-                               spokeColor:uint, 
-                               spinnerRadius:Number, 
-                               eHeight:Number,
-                               spinnerPadding:Number):void
-    {
-        var g:Graphics = graphics;
-        
-        g.lineStyle(spokeWidth, spokeColor, spokeAlpha, false, LineScaleMode.NORMAL, CapsStyle.ROUND);
-        var outsidePoint:Point = calculatePointOnCircle(spinnerRadius, spinnerRadius - eHeight - spinnerPadding, degrees);
-        var insidePoint:Point = calculatePointOnCircle(spinnerRadius, spinnerRadius - spokeHeight + eHeight - spinnerPadding, degrees);
-        g.moveTo(outsidePoint.x, outsidePoint.y);
-        g.lineTo(insidePoint.x,  insidePoint.y);
-            
-    }
-    
-    /**
-     *  @private
-     */ 
-    private function calculatePointOnCircle(center:Number, radius:Number, degrees:Number):Point
-    {
-        var point:Point = new Point();
-        var radians:Number = degrees * RADIANS_PER_DEGREE;
-        point.x = center + radius * Math.cos(radians);
-        point.y = center + radius * Math.sin(radians);
-        
-        return point;
-    }
-    
-    /**
-     *  @private
-     */
-    private function startRotation():void
-    {
-        if (!rotationTimer)
-        {
-            var rotationInterval:Number = getStyle("rotationInterval");
-            if (isNaN(rotationInterval))
-                rotationInterval = DEFAULT_ROTATION_INTERVAL;
-            
-            if (rotationInterval < 16.6)
-                rotationInterval = 16.6;
-            
-            rotationTimer = new Timer(rotationInterval);
-        }
-        
-        if (!rotationTimer.hasEventListener(TimerEvent.TIMER))
-        {
-            rotationTimer.addEventListener(TimerEvent.TIMER, timerHandler);
-            rotationTimer.start();
-        }
-        
-    }
-    
-    /**
-     *  @private
-     */
-    private function stopRotation():void
-    {
-        if (rotationTimer)
-        {
-            rotationTimer.removeEventListener(TimerEvent.TIMER, timerHandler);
-            rotationTimer.stop();
-            rotationTimer = null;
-        }
-    }
- 
-    /**
-     *  @private
-     */
-    private function isRotating():Boolean
-    {
-        return rotationTimer != null;
-    }
-    
-    /**
-     *  The BusyIndicator can be rotated if it is both on the display list and 
-     *  visible.
-     * 
-     *  @returns true if the BusyIndicator can be rotated, false otherwise.
-     */ 
-    private function canRotate():Boolean
-    {
-        if (effectiveVisibility && stage != null)
-            return true;
-        
-        return false;
-    }
-    
-    /**
-     *  @private
-     */
-    private function computeEffectiveVisibility():void
-    {
-        
-        // Check our design layer first.
-        if (designLayer && !designLayer.effectiveVisibility)
-        {
-            effectiveVisibility = false;
-            return;
-        }
-        
-        // Start out with true visibility and enablement
-        // then loop up parent-chain to see if any of them are false.
-        effectiveVisibility = true;
-        var current:IVisualElement = this;
-        
-        while (current)
-        {
-            if (!current.visible)
-            {
-                if (!(current is IUIComponent) || !IUIComponent(current).isPopUp)
-                {
-                    // Treat all pop ups as if they were visible. This is to 
-                    // fix a bug where the BusyIndicator does not spin when it 
-                    // is inside modal popup. The problem is in we do not get 
-                    // an event when the modal window is made visible in 
-                    // PopUpManagerImpl.fadeInEffectEndHandler(). When the modal
-                    // window is made visible, setVisible() is passed "true" so 
-                    // as to not send an event. When do get events when the 
-                    // non-modal windows are popped up. Only modal windows are
-                    // a problem.
-                    // The downside of this fix is BusyIndicator components that are
-                    // inside of hidden, non-modal, popup windows will paint themselves
-                    // on a timer.
-                    effectiveVisibility = false;
-                    break;                  
-                }
-            }
-            
-            current = current.parent as IVisualElement;
-        }
-    }
-    
-    /**
-     *  @private
-     *  Add event listeners for SHOW and HIDE on all the ancestors up the parent chain.
-     *  Adding weak event listeners just to be safe.
-     */
-    private function addVisibilityListeners():void
-    {
-        var current:IVisualElement = this.parent as IVisualElement;
-        while (current)
-        {
-            // add visibility listeners to the parent
-            current.addEventListener(FlexEvent.HIDE, visibilityChangedHandler, false, 0, true);
-            current.addEventListener(FlexEvent.SHOW, visibilityChangedHandler, false, 0, true);
-            
-            current = current.parent as IVisualElement;
-        }
-    }
-
-    /**
-     *  @private
-     *  Remove event listeners for SHOW and HIDE on all the ancestors up the parent chain.
-     */
-    private function removeVisibilityListeners():void
-    {
-        var current:IVisualElement = this;
-        while (current)
-        {
-            current.removeEventListener(FlexEvent.HIDE, visibilityChangedHandler, false);
-            current.removeEventListener(FlexEvent.SHOW, visibilityChangedHandler, false);
-            
-            current = current.parent as IVisualElement;
-        }
-    }
-    
-    //--------------------------------------------------------------------------
-    //
-    //  Overridden event handlers: UIComponent
-    //
-    //--------------------------------------------------------------------------
-    
-    /**
-     *  @private
-     */
-    override protected function layer_PropertyChange(event:PropertyChangeEvent):void
-    {
-        super.layer_PropertyChange(event);
-        
-        if (event.property == "effectiveVisibility")
-        {
-            effectiveVisibilityChanged = true;
-            invalidateProperties();
-        }
-    }
-    
-    //--------------------------------------------------------------------------
-    //
-    //  Event Handlers
-    //
-    //--------------------------------------------------------------------------
- 
-    /**
-     *  @private
-     */
-    private function addedToStageHandler(event:Event):void
-    {
-        // Check our visibility here since we haven't added
-        // visibility listeners yet.
-        computeEffectiveVisibility();
-        
-        if (canRotate())
-            startRotation();
-        
-        addVisibilityListeners();
-    }
-   
-    /**
-     *  @private
-     */
-    private function removedFromStageHandler(event:Event):void
-    {
-        stopRotation();
-        
-        removeVisibilityListeners();
-    }
-    
-    /**
-     *  @private
-     *  Event call back whenever the visibility of us or one of our ancestors 
-     *  changes
-     */
-    private function visibilityChangedHandler(event:FlexEvent):void
-    {
-        effectiveVisibilityChanged = true;
-        invalidateProperties();
-    }
-    
-    /**
-     *  @private
-     * 
-     *  Rotate the spinner once for each timer event.
-     */
-    private function timerHandler(event:TimerEvent):void
-    {
-        currentRotation += 30;
-        if (currentRotation >= 360)
-            currentRotation = 0;
-        
-        drawSpinner();
-        event.updateAfterEvent();
-    }
-  
-}
+		
+		/**
+		 *  The BusyIndicator can be rotated if it is both on the display list and 
+		 *  visible.
+		 * 
+		 *  @returns true if the BusyIndicator can be rotated, false otherwise.
+		 */ 
+		private function canRotate():Boolean
+		{
+			if (effectiveVisibility && stage != null)
+				return true;
+			
+			return false;
+		}
+		
+		
+		/**
+		 *  @private
+		 *  Add event listeners for SHOW and HIDE on all the ancestors up the parent chain.
+		 *  Adding weak event listeners just to be safe.
+		 */
+		private function addVisibilityListeners():void
+		{
+			var current:IVisualElement = this.parent as IVisualElement;
+			while (current)
+			{
+				// add visibility listeners to the parent
+				current.addEventListener(FlexEvent.HIDE, visibilityChangedHandler, false, 0, true);
+				current.addEventListener(FlexEvent.SHOW, visibilityChangedHandler, false, 0, true);
+				
+				current = current.parent as IVisualElement;
+			}
+		}
+		
+		/**
+		 *  @private
+		 *  Remove event listeners for SHOW and HIDE on all the ancestors up the parent chain.
+		 */
+		private function removeVisibilityListeners():void
+		{
+			var current:IVisualElement = this;
+			while (current)
+			{
+				current.removeEventListener(FlexEvent.HIDE, visibilityChangedHandler, false);
+				current.removeEventListener(FlexEvent.SHOW, visibilityChangedHandler, false);
+				
+				current = current.parent as IVisualElement;
+			}
+		}
+		
+		/**
+		 *  @private
+		 *  Event call back whenever the visibility of us or one of our ancestors 
+		 *  changes
+		 */
+		private function visibilityChangedHandler(event:FlexEvent):void
+		{
+			effectiveVisibilityChanged = true;
+			invalidateProperties();
+		}
+		
+		
+	}
 }
+