I'm trying to get a spark tab bar to have a selected tab that does not change color on mouseover. I'm trying to implement this by working with a skin based on the skin spark.skins.spark.TabBarButtonSkin, but despite turning off the shadows on the selected and overAndSelected states, it still shows a dark color on mouseover.
Here's the relevant skin:
<?xml version="1.0" encoding="utf-8"?>
<s:SparkSkin
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.disabledStates="0.5">
<fx:Metadata>[HostComponent("spark.components.ButtonBarButton")]</fx:Metadata>
<!-- host component -->
<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
{
var path:String = createPathData(true);
borderTop.data = path;
}
/**
* @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.5; // assuming stroke weight is 1.0
var right:Number = width - 0.5;
var path:String = createPathData(false);
selectedHighlightV.data = path;
// Configure the left/right sides of the two horizontal lines, defined with
// s:Rects, that appear at the top of the selected highlight.
selectedHighlightH1.x = selectedHighlightH2.x = left + cornerRadius;
selectedHighlightH1.width = selectedHighlightH2.width = (right - left) - (2 * cornerRadius);
}
/**
* @private
* This function creates the path data used by borderTop and selectedHighlight.
*/
private function createPathData(isBorder:Boolean):String
{
var left:Number = -0.5; // assuming stroke weight is 1.0
var right:Number = width - 0.5;
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="69" height="21">
<s:fill>
<s:LinearGradient rotation="90">
<s:GradientEntry color="0xFFFFFF"
color.selectedStates="0xFFFFFF"
color.over="0xBBBDBD"
color.down="0xAAAAAA"
alpha="0.85"
alpha.overAndSelected="1" />
<s:GradientEntry color="0xD8D8D8"
color.selectedStates="0xFFFFFF"
color.over="0x9FA0A1"
color.down="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.0"
alpha.downStates="0.12"/>
<s:GradientEntry color="0xFFFFFF"
ratio="0.48"
alpha="0.33"
alpha.selectedUpStates="0.22"
alpha.overStates="0.0"
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 @private -->
<s:Path id="selectedHighlightV" left="1" right="1" top="1" bottom="1" width="69" height="21">
<s:stroke>
<s:SolidColorStroke weight="1" color="0x000000" alpha="0.0"
alpha.downStates="0.15"
alpha.selectedUpStates="0.00"
alpha.overAndSelected="0.00" />
</s:stroke>
</s:Path>
<!--- @private -->
<s:Rect id="selectedHighlightH1" top="1" height="1">
<s:fill>
<s:SolidColor color="0x000000" alpha="0.0"
alpha.downStates="0.25"
alpha.selectedUpStates="0.0"
alpha.overAndSelected="0.0" />
</s:fill>
</s:Rect>
<!--- @private -->
<s:Rect id="selectedHighlightH2" top="2" height="1">
<s:fill>
<s:SolidColor color="0x000000" alpha="0.0"
alpha.downStates="0.15"
alpha.selectedUpStates="0.0"
alpha.overAndSelected="0.00" />
</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" excludeFrom="selectedStates">
<s:stroke>
<s:SolidColorStroke weight="1"
color="0x000000"
color.selectedStates="0x434343"
alpha="0.75"
alpha.down="0.85"/>
</s:stroke>
</s:Line>
<!--- @private -->
<s:Path id="borderTop" left="0" right="0" top="0" bottom="0" width="69" height="21">
<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="7" right="7" top="2" bottom="2">
</s:Label>
</s:SparkSkin>