<?xml version="1.0" encoding="utf-8"?>

<!--

ADOBE SYSTEMS INCORPORATED
Copyright 2008 Adobe Systems Incorporated
All Rights Reserved.

NOTICE: Adobe permits you to use, modify, and distribute this file
in accordance with the terms of the license agreement accompanying it.

-->

<!--- 
The default skin class for Spark TabBar buttons.  

@see spark.components.TabBar
@see spark.skins.spark.TabBarSkin

@langversion 3.0
@playerversion Flash 10
@playerversion AIR 1.5
@productversion Flex 4
-->

<s:SparkButtonSkin xmlns:fx="http://ns.adobe.com/mxml/2009" 
                   xmlns:s="library://ns.adobe.com/flex/spark" 
                   xmlns:fb="http://ns.adobe.com/flashbuilder/2009"
                   minWidth="21" minHeight="21" 
                   alpha.disabled="0.5">
    
    <!-- host component -->
    <fx:Metadata>
        <![CDATA[ 
        /** 
         * @copy spark.skins.spark.ApplicationSkin#hostComponent
         */
        [HostComponent("spark.components.ButtonBarButton")]
        ]]>
    </fx:Metadata>
    
    <fx:Script fb:purpose="styling" >
        
        import spark.components.TabBar;

        static private const exclusions:Array = ["labelDisplay"];
        
        /** 
         * @private
         */     
        override public function get colorizeExclusions():Array {return exclusions;}
        
        /**
         * @private
         */
        override protected function initializationComplete():void
        {
            useChromeColor = true;
            super.initializationComplete();
        }

        private var cornerRadius:Number = 4
        
        /**
         *  @private
         *  The borderTop s:Path is just a s:Rect with the bottom edge left out.
         *  Given the rounded corners per the cornerRadius style, the result is 
         *  roughly an inverted U with the specified width, height, and cornerRadius.
         * 
         *  Circular arcs are drawn with two curves per flash.display.Graphics.GraphicsUtil.
        */        
        private function updateBorderTop(width:Number, height:Number):void
        {
            // Generate path data and lay it out. The path is not being layout by the default BasicLayout of this skin
            // since we excluded it from the layout.
            var path:String = createPathData(true);
            borderTop.data = path;
            borderTop.setLayoutBoundsSize(width, height, false);
            borderTop.setLayoutBoundsPosition(0, 0, false);
        }
        
        /**
         *  @private
         *  Draw the selected highlight strokes.  The highlight is the same shape as the tab's
         *  border and is inset just within the border.   It must be rendererd with three separate paths, 
         *  since the top leg is rendered with two horizontal lines, with different stroke 
         *  alpha values, and the left and right vertical legs are rendered with a third alpha value.
         *  
         *  Circular arcs are drawn with two curves per flash.display.Graphics.GraphicsUtil.
         */    
        private function updateSelectedHighlight(width:Number, height:Number):void
        {
            if (!selectedHighlightV)
                return;
            
            var left:Number = 0;
            var right:Number = width;
            
            // Generate path data and lay it out. The path is not being layout by the default BasicLayout of this skin
            // since we excluded it from the layout.
            var path:String = createPathData(false);
            selectedHighlightV.data = path;
            selectedHighlightV.setLayoutBoundsSize(width - 2, height - 2, false);
            selectedHighlightV.setLayoutBoundsPosition(1, 1, false);
            
            // Configure the left/right sides of the two horizontal lines, defined with
            // s:Rects, that appear at the top of the selected highlight.
            
            // SDK-26127: Use the ILayoutElement APIs, instead of setting explicitly x/y/width/height as
            // this method is called from updateDisplayList() and it should not affect the 
            // explicit sizes (and therefore the measured sizes) or trigger a new layout pass.
            selectedHighlightH1.setLayoutBoundsSize(width - (2 * cornerRadius), 
                                                    1, false);
            selectedHighlightH1.setLayoutBoundsPosition(cornerRadius, 1, false);

            selectedHighlightH2.setLayoutBoundsSize(width - (2 * cornerRadius), 
                                                    1, false);
            selectedHighlightH2.setLayoutBoundsPosition(cornerRadius, 2, false);
         }  
        
        /**
         *  @private
         *  This function creates the path data used by borderTop and selectedHighlight.
         */
        private function createPathData(isBorder:Boolean):String
        {
            var left:Number = 0;
            var right:Number = width;
            var top:Number = 0.5;
            var bottom:Number = height;
            
            var a:Number = cornerRadius * 0.292893218813453;
            var s:Number = cornerRadius * 0.585786437626905;
            
            // If the path is for the highlight,
            // Draw the vertical part of the selected tab highlight that's rendered 
            // with alpha=0.07.  The s:Path is configured to include only the left and 
            // right edges of an s:Rect, along with the top left,right rounded corners. 
            // Otherwise, we draw a full path.
            var path:String = "";
            path +=  "M " + left + " " + bottom;
            path += " L " + left + " " + (top + cornerRadius);
            path += " Q " + left + " " + (top + s) + " " + (left + a) + " " + (top + a);
            path += " Q " + (left + s) + " " + top + " " + (left + cornerRadius) + " " + top;
            
            if (isBorder)
                path += " L " + (right - cornerRadius) + " " + top;
            else
                path += " M " + (right - cornerRadius) + " " + top;
            
            path += " Q " + (right - s) + " " + top + " " + (right - a) + " " + (top + a);
            path += " Q " + right + " " + (top + s) + " " + right + " " + (top + cornerRadius);
            path += " L " + right + " " + bottom;
            
            return path;
        }
        
        /**
         *  @private
         *  The cornerRadius style is specified by the TabBar, not the button itself.   
         * 
         *  Rather than bind the corner radius properties of the s:Rect's in the markup 
         *  below to hostComponent.owner.getStyle("cornerRadius"), we reset them here, 
         *  each time a change in the value of the style is detected.  Note that each 
         *  corner radius property is explicitly initialized to the default value of 
         *  the style; the initial value of the private cornerRadius property.
         */
        private function updateCornerRadius():void
        {
            var cr:Number = getStyle("cornerRadius");
            if (cornerRadius != cr)
            {
                cornerRadius = cr;
                fill.topLeftRadiusX = cornerRadius;
                fill.topRightRadiusX = cornerRadius;
                lowlight.topLeftRadiusX = cornerRadius;
                lowlight.topRightRadiusX = cornerRadius;
                highlight.topLeftRadiusX = cornerRadius;
                highlight.topRightRadiusX = cornerRadius;
                highlightStroke.topLeftRadiusX = cornerRadius;
                highlightStroke.topRightRadiusX = cornerRadius;
            }
        }

        /**
         *  @private
         */
        override protected function updateDisplayList(unscaledWidth:Number, unscaleHeight:Number):void
        {
            updateCornerRadius();
            updateSelectedHighlight(unscaledWidth, unscaledHeight); 
            updateBorderTop(unscaledWidth, unscaledHeight);
            super.updateDisplayList(unscaledWidth, unscaledHeight);
        }
    </fx:Script>
    
    <!-- states -->
    <s:states>
        <s:State name="up" />
        <s:State name="over" stateGroups="overStates" />
        <s:State name="down" stateGroups="downStates" />
        <s:State name="disabled" stateGroups="disabledStates" />
        <s:State name="upAndSelected" stateGroups="selectedStates, selectedUpStates" />
        <s:State name="overAndSelected" stateGroups="overStates, selectedStates" />
        <s:State name="downAndSelected" stateGroups="downStates, selectedStates" />
        <s:State name="disabledAndSelected" stateGroups="selectedUpStates, disabledStates, selectedStates" />
    </s:states>

    <!--- layer 2: fill @private-->
    <s:Rect id="fill" left="1" right="1" top="1" bottom="1" topLeftRadiusX="4" topRightRadiusX="4" width="70" height="22">
        <s:fill>
            <s:LinearGradient rotation="90">
                <s:GradientEntry color="0xFFFFFF" 
                                 color.selectedUpStates="0xBBBDBD"
                                 color.overStates="0xBBBDBD" 
                                 color.downStates="0xAAAAAA" 
                                 alpha="0.85" 
                                 alpha.overAndSelected="1" />
                <s:GradientEntry color="0xD8D8D8" 
                                 color.selectedUpStates="0x9FA0A1"
                                 color.over="0x9FA0A1" 
                                 color.overAndSelected="0x8E8F90"
                                 color.downStates="0x929496" 
                                 alpha="0.85"
                                 alpha.overAndSelected="1" />
            </s:LinearGradient>
        </s:fill>
    </s:Rect>
    
    <!--- layer 3: fill lowlight @private-->
    <s:Rect id="lowlight" left="1" right="1" top="1" bottom="1" topLeftRadiusX="4" topRightRadiusX="4">
        <s:fill>
            <s:LinearGradient rotation="270">
                <s:GradientEntry color="0x000000" ratio="0.0" alpha="0.0627" />
                <s:GradientEntry color="0x000000" ratio="0.48" alpha="0.0099" />
                <s:GradientEntry color="0x000000" ratio="0.48001" alpha="0" />
            </s:LinearGradient>
        </s:fill>
    </s:Rect>
    
    <!--- layer 4: fill highlight @private-->
    <s:Rect id="highlight" left="1" right="1" top="1" bottom="1" topLeftRadiusX="4" topRightRadiusX="4">
        <s:fill>
            <s:LinearGradient rotation="90">
                <s:GradientEntry color="0xFFFFFF"
                                 ratio="0.0"
                                 alpha="0.33" 
                                 alpha.selectedUpStates="0.22"
                                 alpha.overStates="0.22" 
                                 alpha.downStates="0.12"/>
                <s:GradientEntry color="0xFFFFFF"
                                 ratio="0.48"
                                 alpha="0.33" 
                                 alpha.selectedUpStates="0.22"
                                 alpha.overStates="0.22" 
                                 alpha.downStates="0.12" />
                <s:GradientEntry color="0xFFFFFF"
                                 ratio="0.48001"
                                 alpha="0" />
            </s:LinearGradient>
        </s:fill>
    </s:Rect>
    
    <!--- layer 5: highlight stroke (all states except down) @private -->
    <s:Rect id="highlightStroke" left="1" right="1" top="1" bottom="1" topLeftRadiusX="4" topRightRadiusX="4"
            excludeFrom="downStates">
        <s:stroke>
            <s:LinearGradientStroke rotation="90" weight="1">
                <s:GradientEntry color="0xFFFFFF" alpha.overStates="0.22" alpha.selectedUpStates="0.33" />
                <s:GradientEntry color="0xD8D8D8" alpha.overStates="0.22" alpha.selectedUpStates="0.33" />
            </s:LinearGradientStroke>
        </s:stroke>
    </s:Rect>
    
    <!--- layer 6: highlight stroke, selected tab, alpha=0.0 when not selected.
          Set includeInLayout="false" as we regenerate the path data and lay out the path in
          the updateDisplayList() override and we don't want it to affect measurement. @private
    -->
    <s:Path id="selectedHighlightV" left="1" right="1" top="1" bottom="1" includeInLayout="false">
        <s:stroke>
            <s:SolidColorStroke weight="1" color="0x000000" alpha="0.0" 
                                alpha.downStates="0.15" 
                                alpha.selectedUpStates="0.15" 
                                alpha.overAndSelected="0.15" />
        </s:stroke>
    </s:Path>
    <!--- @private -->
    <s:Rect id="selectedHighlightH1" top="1" height="1" includeInLayout="false">
        <s:fill>
            <s:SolidColor color="0x000000" alpha="0.0"
                                alpha.downStates="0.25" 
                                alpha.selectedUpStates="0.25" 
                                alpha.overAndSelected="0.25" />                                    
        </s:fill>
    </s:Rect>
    <!--- @private -->
    <s:Rect id="selectedHighlightH2" top="2" height="1" includeInLayout="false">
        <s:fill>
            <s:SolidColor color="0x000000" alpha="0.0"
                                alpha.downStates="0.15" 
                                alpha.selectedUpStates="0.15" 
                                alpha.overAndSelected="0.15" />  
        </s:fill>
    </s:Rect>  

    <!--- layer 7: border - put on top of the fill so it doesn't disappear when scale is less than 1 @private -->
    <s:Line id="borderBottom" left="0" right="0" bottom="0">
        <s:stroke>
            <s:SolidColorStroke weight="1" 
                                color="0x000000" 
                                color.selectedStates="0x434343"
                                alpha="0.75" 
                                alpha.down="0.85"
                                alpha.selectedStates="0.5" />
        </s:stroke>
    </s:Line>
    <!--- Set includeInLayout="false" as we regenerate the path data and lay out the path in
          the updateDisplayList() override and we don't want it to affect measurement. @private
    -->
    <s:Path id="borderTop" left="0" right="0" top="0" bottom="0" includeInLayout="false">
        <s:stroke>
            <s:LinearGradientStroke rotation="90" weight="1">
                <s:GradientEntry color="0x000000" 
                                 alpha="0.5625"
                                 alpha.down="0.6375"
                                 alpha.selectedStates="0.6375" />
                <s:GradientEntry color="0x000000" 
                                 alpha="0.75" 
                                 alpha.down="0.85"
                                 alpha.selectedStates="0.85" />
            </s:LinearGradientStroke>
        </s:stroke>
    </s:Path>
    
    <!-- layer 8: text -->
    <!--- @copy spark.components.supportClasses.ButtonBase#labelDisplay -->
    <s:Label id="labelDisplay"
             textAlign="center"
             verticalAlign="middle"
             maxDisplayedLines="1"
             horizontalCenter="0" verticalCenter="1"
             left="10" right="10" top="2" bottom="2">
    </s:Label>
    
</s:SparkButtonSkin>
