| //////////////////////////////////////////////////////////////////////////////// |
| // |
| // Licensed to the Apache Software Foundation (ASF) under one or more |
| // contributor license agreements. See the NOTICE file distributed with |
| // this work for additional information regarding copyright ownership. |
| // The ASF licenses this file to You under the Apache License, Version 2.0 |
| // (the "License"); you may not use this file except in compliance with |
| // the License. You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // |
| //////////////////////////////////////////////////////////////////////////////// |
| |
| package spark.components |
| { |
| import flash.display.GradientType; |
| import flash.events.Event; |
| import flash.geom.Matrix; |
| import flash.text.TextLineMetrics; |
| |
| import mx.controls.listClasses.*; |
| import mx.core.DPIClassification; |
| import mx.core.FlexGlobals; |
| import mx.core.IDataRenderer; |
| import mx.core.IFlexDisplayObject; |
| import mx.core.ILayoutElement; |
| import mx.core.UIComponent; |
| import mx.core.mx_internal; |
| import mx.events.FlexEvent; |
| |
| import spark.components.supportClasses.InteractionState; |
| import spark.components.supportClasses.InteractionStateDetector; |
| import spark.components.supportClasses.StyleableTextField; |
| |
| use namespace mx_internal; |
| |
| //-------------------------------------- |
| // Events |
| //-------------------------------------- |
| |
| /** |
| * Dispatched when the <code>data</code> property changes. |
| * |
| * <p>When you use a component as an item renderer, |
| * the <code>data</code> property contains the data to display. |
| * You can listen for this event and update the component |
| * when the <code>data</code> property changes.</p> |
| * |
| * @eventType mx.events.FlexEvent.DATA_CHANGE |
| * |
| * @langversion 3.0 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| [Event(name="dataChange", type="mx.events.FlexEvent")] |
| |
| //-------------------------------------- |
| // Styles |
| //-------------------------------------- |
| |
| include "../styles/metadata/PaddingStyles.as" |
| include "../styles/metadata/StyleableTextFieldTextStyles.as" |
| |
| /** |
| * @copy spark.components.supportClasses.GroupBase#style:alternatingItemColors |
| * |
| * @langversion 3.0 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| [Style(name="alternatingItemColors", type="Array", arrayType="uint", format="Color", inherit="yes", theme="spark, mobile")] |
| |
| /** |
| * @copy spark.components.supportClasses.GroupBase#style:chromeColor |
| * |
| * @default 0xCCCCCC |
| * |
| * @langversion 3.0 |
| * @playerversion AIR 1.5 |
| * @productversion Flex 4 |
| */ |
| [Style(name="chromeColor", type="uint", format="Color", inherit="yes", theme="spark, mobile")] |
| |
| /** |
| * @copy spark.components.supportClasses.GroupBase#style:downColor |
| * |
| * @langversion 3.0 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| [Style(name="downColor", type="uint", format="Color", inherit="yes", theme="spark, mobile")] |
| |
| /** |
| * @copy spark.components.supportClasses.GroupBase#style:focusColor |
| * |
| * @langversion 3.0 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| [Style(name="focusColor", type="uint", format="Color", inherit="yes", theme="spark, mobile")] |
| |
| /** |
| * Number of pixels between the bottom border and the text component |
| * of the item renderer. |
| * |
| * @default 5 |
| * |
| * @langversion 3.0 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| [Style(name="paddingBottom", type="Number", format="Length", inherit="no")] |
| |
| /** |
| * Number of pixels between the top border and the text component |
| * of the item renderer. |
| * |
| * @default 5 |
| * |
| * @langversion 3.0 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| [Style(name="paddingTop", type="Number", format="Length", inherit="no")] |
| |
| /** |
| * @copy spark.components.supportClasses.GroupBase#style:rollOverColor |
| * |
| * @langversion 3.0 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| [Style(name="rollOverColor", type="uint", format="Color", inherit="yes")] |
| |
| /** |
| * @copy spark.components.List#style:selectionColor |
| * |
| * @langversion 3.0 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| [Style(name="selectionColor", type="uint", format="Color", inherit="yes")] |
| |
| /** |
| * @copy spark.components.supportClasses.GroupBase#style:symbolColor |
| * |
| * @langversion 3.0 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| [Style(name="symbolColor", type="uint", format="Color", inherit="yes", theme="spark,mobile")] |
| |
| /** |
| * The vertical alignment of the content when it does not have |
| * a one-to-one aspect ratio. |
| * Possible values are <code>"top"</code>, <code>"center"</code>, |
| * and <code>"bottom"</code>. |
| * |
| * @default "center" |
| * |
| * @langversion 3.0 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| [Style(name="verticalAlign", type="String", enumeration="bottom,middle,top", inherit="no")] |
| |
| /** |
| * Option to use an opaqueBackground property for this renderer. This can improve scrolling speed. |
| * Since opaqueBackground adds space around the text proportional to the font's size, |
| * you might need to turn it off when using large fonts to avoid background overflow. |
| * @default true |
| * |
| * @langversion 3.0 |
| * @playerversion AIR 3.0 |
| * @productversion Flex 4.12 |
| */ |
| |
| [Style(name="useOpaqueBackground", type="Boolean", inherit="yes")] |
| |
| //-------------------------------------- |
| // Excluded APIs |
| //-------------------------------------- |
| |
| [Exclude(name="focusBlendMode", kind="style")] |
| [Exclude(name="focusThickness", kind="style")] |
| |
| /** |
| * The LabelItemRenderer class defines the default item renderer |
| * for a list-based control in the mobile theme. |
| * This is a simple item renderer with a single text component. |
| * |
| * <p>The item renderer creates a single StyleableTextField control |
| * to display a String. |
| * The name of the StyleableTextField control in the item renderer is <code>labelDisplay</code>. |
| * Use the <code>labelField</code> property of the list-based control to specify |
| * a field of the data item to display in the StyleableTextField control.</p> |
| * |
| * <p>To create a custom item renderer for use on mobile devices, |
| * Adobe recommends that you create a new ActionScript item renderer |
| * that extends this class.</p> |
| * |
| * @mxml |
| * |
| * <p>The <code><s:LabelItemRenderer></code> tag inherits all of the tag |
| * attributes of its superclass and adds the following tag attributes:</p> |
| * |
| * <pre> |
| * <s:LabelItemRenderer |
| * <strong>Properties</strong> |
| * label="" |
| * |
| * <strong>Common Styles</strong> |
| * color="<i>Theme dependent</i>" |
| * downColor="<i>Theme dependent</i>" |
| * fontFamily="<i>Theme dependent</i>" |
| * fontSize="<i>Theme dependent</i>" |
| * fontStyle="normal" |
| * fontWeight="normal" |
| * leading="0" |
| * letterSpacing="0" |
| * paddingBottom="0" |
| * paddingLeft="0" |
| * paddingRight="0" |
| * paddingTop="5" |
| * rollOverColor="0xCEDBEF" |
| * selectionColor="0xB2B2B2" |
| * textAlign="left" |
| * textDecoration="none" |
| * textIndent="0" |
| * verticalAlign="center" |
| * |
| * <strong>Spark Styles</strong> |
| * alternatingItemColors="undefined" |
| * focusColor="0x70B2EE" |
| * symbolColor="0x000000" |
| * |
| * <strong>Mobile Styles</strong> |
| * alternatingItemColors="undefined" |
| * focusColor="0x70B2EE" |
| * symbolColor="0x000000" |
| * |
| * <b>Events</b> |
| * dataChange="<i>No default</i>" |
| * |
| * > |
| * </pre> |
| * |
| * @see spark.components.IconItemRenderer |
| * @see spark.components.List |
| * @see mx.core.IDataRenderer |
| * @see spark.components.IItemRenderer |
| * @see spark.components.supportClasses.ItemRenderer |
| * @includeExample examples/LabelItemRendererExample.mxml -noswf |
| * |
| * @langversion 3.0 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public class LabelItemRenderer extends UIComponent |
| implements IDataRenderer, IItemRenderer |
| { |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Constructor |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * Constructor. |
| * |
| * @langversion 3.0 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function LabelItemRenderer() |
| { |
| super(); |
| |
| switch (applicationDPI) |
| { |
| case DPIClassification.DPI_640: |
| { |
| minHeight = 176; |
| break; |
| } |
| case DPIClassification.DPI_480: |
| { |
| minHeight = 132; |
| break; |
| } |
| case DPIClassification.DPI_320: |
| { |
| minHeight = 88; |
| break; |
| } |
| case DPIClassification.DPI_240: |
| { |
| minHeight = 66; |
| break; |
| } |
| case DPIClassification.DPI_120: |
| { |
| minHeight = 33; |
| break; |
| } |
| default: |
| { |
| // default PPI160 |
| minHeight = 44; |
| break; |
| } |
| } |
| |
| interactionStateDetector = new InteractionStateDetector(this); |
| interactionStateDetector.addEventListener(Event.CHANGE, interactionStateDetector_changeHandler); |
| |
| cacheAsBitmap = true; |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Private Properties |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * @private |
| * Helper class to help determine when we are in the hovered or down states |
| */ |
| private var interactionStateDetector:InteractionStateDetector; |
| |
| /** |
| * @private |
| * Whether or not we're the last element in the list |
| */ |
| mx_internal var isLastItem:Boolean = false; |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Overridden properties: UIComponent |
| // |
| //-------------------------------------------------------------------------- |
| |
| //---------------------------------- |
| // baselinePosition |
| //---------------------------------- |
| |
| /** |
| * @private |
| */ |
| override public function get baselinePosition():Number |
| { |
| // The text styles aren't known until there is a parent. |
| if (!parent) |
| return NaN; |
| |
| return labelDisplay.baselinePosition; |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Public Properties |
| // |
| //-------------------------------------------------------------------------- |
| |
| //---------------------------------- |
| // data |
| //---------------------------------- |
| |
| /** |
| * @private |
| */ |
| private var _data:Object; |
| |
| [Bindable("dataChange")] |
| |
| /** |
| * The implementation of the <code>data</code> property |
| * as defined by the IDataRenderer interface. |
| * When set, it stores the value and invalidates the component |
| * to trigger a relayout of the component. |
| * |
| * @see mx.core.IDataRenderer |
| * |
| * @langversion 3.0 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function get data():Object |
| { |
| return _data; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set data(value:Object):void |
| { |
| _data = value; |
| |
| if (hasEventListener(FlexEvent.DATA_CHANGE)) |
| dispatchEvent(new FlexEvent(FlexEvent.DATA_CHANGE)); |
| } |
| |
| //---------------------------------- |
| // down |
| //---------------------------------- |
| /** |
| * @private |
| * storage for the down property |
| */ |
| private var _down:Boolean = false; |
| |
| /** |
| * Set to <code>true</code> when the user is pressing down on an item renderer. |
| * |
| * @default false |
| * |
| * @langversion 3.0 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| protected function get down():Boolean |
| { |
| return _down; |
| } |
| |
| /** |
| * @private |
| */ |
| protected function set down(value:Boolean):void |
| { |
| if (value == _down) |
| return; |
| |
| _down = value; |
| invalidateDisplayList(); |
| } |
| |
| //---------------------------------- |
| // hovered |
| //---------------------------------- |
| /** |
| * @private |
| * storage for the hovered property |
| */ |
| private var _hovered:Boolean = false; |
| |
| /** |
| * Set to <code>true</code> when the user is hovered over the item renderer. |
| * |
| * @default false |
| * |
| * @langversion 3.0 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| protected function get hovered():Boolean |
| { |
| return _hovered; |
| } |
| |
| /** |
| * @private |
| */ |
| protected function set hovered(value:Boolean):void |
| { |
| if (value == _hovered) |
| return; |
| |
| _hovered = value; |
| invalidateDisplayList(); |
| } |
| |
| //---------------------------------- |
| // itemIndex |
| //---------------------------------- |
| |
| /** |
| * @private |
| * storage for the itemIndex property |
| */ |
| private var _itemIndex:int; |
| |
| /** |
| * @inheritDoc |
| * |
| * @default 0 |
| * |
| * @langversion 3.0 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function get itemIndex():int |
| { |
| return _itemIndex; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set itemIndex(value:int):void |
| { |
| var wasLastItem:Boolean = isLastItem; |
| var dataGroup:DataGroup = parent as DataGroup; |
| isLastItem = (dataGroup && (value == dataGroup.numElements - 1)); |
| |
| // if whether or not we are the last item in the last has changed then |
| // invalidate our display. note: even if our new index has not changed, |
| // whether or not we're the last item may have so we perform this check |
| // before the value == _itemIndex check below |
| if (wasLastItem != isLastItem) |
| invalidateDisplayList(); |
| |
| if (value == _itemIndex) |
| return; |
| |
| _itemIndex = value; |
| |
| // only invalidateDisplayList() if this causes use to redraw which |
| // is only if alternatingItemColors are defined (and technically also |
| // only if we are not selected or down, etc..., but we'll ignore those |
| // as this will shortcut 95% of the time anyways) |
| if (getStyle("alternatingItemColors") !== undefined) |
| invalidateDisplayList(); |
| } |
| |
| //---------------------------------- |
| // label |
| //---------------------------------- |
| |
| /** |
| * @private |
| * Storage var for label |
| */ |
| private var _label:String = ""; |
| |
| /** |
| * The text component used to |
| * display the label data of the item renderer. |
| * |
| * @langversion 3.0 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| protected var labelDisplay:StyleableTextField; |
| |
| /** |
| * @inheritDoc |
| * |
| * @default "" |
| * |
| * @langversion 3.0 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function get label():String |
| { |
| return _label; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set label(value:String):void |
| { |
| if (value == _label) |
| return; |
| |
| _label = value; |
| |
| // Push the label down into the labelTextField, |
| // if it exists |
| if (labelDisplay) |
| { |
| labelDisplay.text = _label; |
| invalidateSize(); |
| } |
| } |
| |
| //---------------------------------- |
| // showsCaret |
| //---------------------------------- |
| |
| /** |
| * @private |
| * Storage for the showsCaret property |
| */ |
| private var _showsCaret:Boolean = false; |
| |
| /** |
| * @inheritDoc |
| * |
| * @default false |
| * |
| * @langversion 3.0 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function get showsCaret():Boolean |
| { |
| return _showsCaret; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set showsCaret(value:Boolean):void |
| { |
| if (value == _showsCaret) |
| return; |
| |
| _showsCaret = value; |
| invalidateDisplayList(); |
| } |
| |
| //---------------------------------- |
| // selected |
| //---------------------------------- |
| |
| /** |
| * @private |
| * storage for the selected property |
| */ |
| private var _selected:Boolean = false; |
| |
| /** |
| * @inheritDoc |
| * |
| * @default false |
| * |
| * @langversion 3.0 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function get selected():Boolean |
| { |
| return _selected; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set selected(value:Boolean):void |
| { |
| if (value == _selected) |
| return; |
| |
| _selected = value; |
| invalidateDisplayList(); |
| } |
| |
| //---------------------------------- |
| // dragging |
| //---------------------------------- |
| |
| /** |
| * @private |
| * Storage for the dragging property. |
| */ |
| private var _dragging:Boolean = false; |
| |
| /** |
| * @inheritDoc |
| * |
| * @langversion 3.0 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function get dragging():Boolean |
| { |
| return _dragging; |
| } |
| |
| /** |
| * @private |
| */ |
| public function set dragging(value:Boolean):void |
| { |
| _dragging = value; |
| } |
| |
| |
| //---------------------------------- |
| // authorDensity |
| //---------------------------------- |
| /** |
| * Returns the DPI of the application. |
| * |
| * @langversion 3.0 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| public function get applicationDPI():Number |
| { |
| return FlexGlobals.topLevelApplication.applicationDPI; |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Overridden methods: UIComponent |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * @private |
| */ |
| override protected function createChildren():void |
| { |
| super.createChildren(); |
| |
| if (!labelDisplay) |
| { |
| createLabelDisplay(); |
| labelDisplay.text = _label; |
| } |
| } |
| |
| /** |
| * Creates the labelDisplay component |
| * |
| * @langversion 3.0 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| protected function createLabelDisplay():void |
| { |
| labelDisplay = StyleableTextField(createInFontContext(StyleableTextField)); |
| labelDisplay.styleName = this; |
| labelDisplay.editable = false; |
| labelDisplay.selectable = false; |
| labelDisplay.multiline = false; |
| labelDisplay.wordWrap = false; |
| |
| addChild(labelDisplay); |
| } |
| |
| /** |
| * Destroys the labelDisplay component |
| * |
| * @langversion 3.0 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| protected function destroyLabelDisplay():void |
| { |
| removeChild(labelDisplay); |
| labelDisplay = null; |
| } |
| |
| /** |
| * @private |
| */ |
| override protected function measure():void |
| { |
| super.measure(); |
| |
| if (labelDisplay) |
| { |
| // reset text if it was truncated before. |
| if (labelDisplay.isTruncated) |
| labelDisplay.text = label; |
| |
| var horizontalPadding:Number = getStyle("paddingLeft") + getStyle("paddingRight"); |
| var verticalPadding:Number = getStyle("paddingTop") + getStyle("paddingBottom"); |
| |
| // Text respects padding right, left, top, and bottom |
| labelDisplay.commitStyles(); |
| measuredWidth = getElementPreferredWidth(labelDisplay) + horizontalPadding; |
| // We only care about the "real" ascent |
| measuredHeight = getElementPreferredHeight(labelDisplay) + verticalPadding; |
| } |
| |
| measuredMinWidth = 0; |
| } |
| |
| /** |
| * @private |
| */ |
| override protected function updateDisplayList(unscaledWidth:Number, |
| unscaledHeight:Number):void |
| { |
| // clear the graphics before calling super.updateDisplayList() |
| graphics.clear(); |
| |
| super.updateDisplayList(unscaledWidth, unscaledHeight); |
| |
| drawBackground(unscaledWidth, unscaledHeight); |
| |
| layoutContents(unscaledWidth, unscaledHeight); |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Methods |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * Renders a background for the item renderer. |
| * |
| * <p>This method, along with <code>layoutContents()</code>, is called |
| * by the <code>updateDisplayList()</code> method.</p> |
| * |
| * <p>This method draws the background and the outline for this item renderer. |
| * It knows how to appropriately handle the selected, down, or caretted states. |
| * However, when <code>alternatingItemColors</code> is set to <code>undefined</code>, |
| * the default background is transparent. |
| * Override this method to change the appearance of the background of |
| * the item renderer.</p> |
| * |
| * @param unscaledWidth Specifies the width of the component, in pixels, |
| * in the component's coordinates, regardless of the value of the |
| * <code>scaleX</code> property of the component. |
| * |
| * @param unscaledHeight Specifies the height of the component, in pixels, |
| * in the component's coordinates, regardless of the value of the |
| * <code>scaleY</code> property of the component. |
| * |
| * @langversion 3.0 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| protected function drawBackground(unscaledWidth:Number, |
| unscaledHeight:Number):void |
| { |
| // figure out backgroundColor |
| var backgroundColor:*; |
| var downColor:* = getStyle("downColor"); |
| var drawBackground:Boolean = true; |
| var opaqueBackgroundColor:* = undefined; |
| |
| if (down && downColor !== undefined) |
| { |
| backgroundColor = downColor; |
| } |
| else if (selected) |
| { |
| backgroundColor = getStyle("selectionColor"); |
| } |
| else if (hovered) |
| { |
| backgroundColor = getStyle("rollOverColor"); |
| } |
| else if (showsCaret) |
| { |
| backgroundColor = getStyle("selectionColor"); |
| } |
| else |
| { |
| var alternatingColors:Array; |
| var alternatingColorsStyle:Object = getStyle("alternatingItemColors"); |
| |
| if (alternatingColorsStyle) |
| alternatingColors = (alternatingColorsStyle is Array) ? (alternatingColorsStyle as Array) : [alternatingColorsStyle]; |
| |
| if (alternatingColors && alternatingColors.length > 0) |
| { |
| // translate these colors into uints |
| styleManager.getColorNames(alternatingColors); |
| |
| backgroundColor = alternatingColors[itemIndex % alternatingColors.length]; |
| } |
| else |
| { |
| // don't draw background if it is the contentBackgroundColor. The |
| // list skin handles the background drawing for us. |
| drawBackground = false; |
| } |
| |
| } |
| |
| // draw backgroundColor |
| // the reason why we draw it in the case of drawBackground == 0 is for |
| // mouse hit testing purposes |
| graphics.beginFill(backgroundColor, drawBackground ? 1 : 0); |
| graphics.lineStyle(); |
| graphics.drawRect(0, 0, unscaledWidth, unscaledHeight); |
| graphics.endFill(); |
| |
| // Selected and down states have a gradient overlay as well |
| // as different separators colors/alphas |
| if (selected || down) |
| { |
| var colors:Array = [0x000000, 0x000000 ]; |
| var alphas:Array = [.2, .1]; |
| var ratios:Array = [0, 255]; |
| var matrix:Matrix = new Matrix(); |
| |
| // gradient overlay |
| matrix.createGradientBox(unscaledWidth, unscaledHeight, Math.PI / 2, 0, 0 ); |
| graphics.beginGradientFill(GradientType.LINEAR, colors, alphas, ratios, matrix); |
| graphics.drawRect(0, 0, unscaledWidth, unscaledHeight); |
| graphics.endFill(); |
| } |
| else if (drawBackground) |
| { |
| // If our background is a solid color, use it as the opaqueBackground property |
| // for this renderer. This makes scrolling considerably faster. |
| var useOpaqueBackground: * = getStyle("useOpaqueBackground") ; // if not defined, then true |
| if (useOpaqueBackground == undefined || useOpaqueBackground == true ) |
| opaqueBackgroundColor = backgroundColor; |
| } |
| |
| // Draw the separator for the item renderer |
| drawBorder(unscaledWidth, unscaledHeight); |
| |
| opaqueBackground = opaqueBackgroundColor; |
| } |
| |
| /** |
| * Renders the border for the item renderer. |
| * |
| * <p>This method is called by <code>drawBackground</code> after the |
| * background has been rendered.</p> |
| * |
| * <p>Override this method to change the appearance of the separator or |
| * border of the item renderer.</p> |
| * |
| * @param unscaledWidth Specifies the width of the component, in pixels, |
| * in the component's coordinates, regardless of the value of the |
| * <code>scaleX</code> property of the component. |
| * |
| * @param unscaledHeight Specifies the height of the component, in pixels, |
| * in the component's coordinates, regardless of the value of the |
| * <code>scaleY</code> property of the component. |
| * |
| * @langversion 3.0 |
| * @playerversion AIR 3.0 |
| * @productversion Flex 4.6 |
| */ |
| protected function drawBorder(unscaledWidth:Number, unscaledHeight:Number):void |
| { |
| var topSeparatorColor:uint; |
| var topSeparatorAlpha:Number; |
| var bottomSeparatorColor:uint; |
| var bottomSeparatorAlpha:Number; |
| |
| // separators are a highlight on the top and shadow on the bottom |
| topSeparatorColor = 0xFFFFFF; |
| topSeparatorAlpha = .3; |
| bottomSeparatorColor = 0x000000; |
| bottomSeparatorAlpha = .3; |
| |
| |
| // draw separators |
| // don't draw top separator for down and selected states |
| if (!(selected || down)) |
| { |
| graphics.beginFill(topSeparatorColor, topSeparatorAlpha); |
| graphics.drawRect(0, 0, unscaledWidth, 1); |
| graphics.endFill(); |
| } |
| |
| graphics.beginFill(bottomSeparatorColor, bottomSeparatorAlpha); |
| graphics.drawRect(0, unscaledHeight - (isLastItem ? 0 : 1), unscaledWidth, 1); |
| graphics.endFill(); |
| |
| |
| // add extra separators to the first and last items so that |
| // the list looks correct during the scrolling bounce/pull effect |
| // top |
| if (itemIndex == 0) |
| { |
| graphics.beginFill(bottomSeparatorColor, bottomSeparatorAlpha); |
| graphics.drawRect(0, -1, unscaledWidth, 1); |
| graphics.endFill(); |
| } |
| |
| // bottom |
| if (isLastItem) |
| { |
| // we want to offset the bottom by 1 so that we don't get |
| // a double line at the bottom of the list if there's a |
| // border |
| graphics.beginFill(topSeparatorColor, topSeparatorAlpha); |
| graphics.drawRect(0, unscaledHeight + 1, unscaledWidth, 1); |
| graphics.endFill(); |
| } |
| } |
| |
| /** |
| * Positions the children for this item renderer. |
| * |
| * <p>This method, along with <code>drawBackground()</code>, is called |
| * by the <code>updateDisplayList()</code> method.</p> |
| * |
| * <p>This method positions the <code>labelDisplay</code> component. |
| * Subclasses should override this to position their children.</p> |
| * |
| * @param unscaledWidth Specifies the width of the component, in pixels, |
| * in the component's coordinates, regardless of the value of the |
| * <code>scaleX</code> property of the component. |
| * |
| * @param unscaledHeight Specifies the height of the component, in pixels, |
| * in the component's coordinates, regardless of the value of the |
| * <code>scaleY</code> property of the component. |
| * |
| * @langversion 3.0 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| protected function layoutContents(unscaledWidth:Number, |
| unscaledHeight:Number):void |
| { |
| if (!labelDisplay) |
| return; |
| |
| var paddingLeft:Number = getStyle("paddingLeft"); |
| var paddingRight:Number = getStyle("paddingRight"); |
| var paddingTop:Number = getStyle("paddingTop"); |
| var paddingBottom:Number = getStyle("paddingBottom"); |
| var verticalAlign:String = getStyle("verticalAlign"); |
| |
| var viewWidth:Number = unscaledWidth - paddingLeft - paddingRight; |
| var viewHeight:Number = unscaledHeight - paddingTop - paddingBottom; |
| |
| var vAlign:Number; |
| if (verticalAlign == "top") |
| vAlign = 0; |
| else if (verticalAlign == "bottom") |
| vAlign = 1; |
| else // if (verticalAlign == "middle") |
| vAlign = 0.5; |
| |
| // measure the label component |
| // text should take up the rest of the space width-wise, but only let it take up |
| // its measured textHeight so we can position it later based on verticalAlign |
| var labelWidth:Number = Math.max(viewWidth, 0); |
| var labelHeight:Number = 0; |
| |
| if (label != "") |
| { |
| labelDisplay.commitStyles(); |
| |
| // reset text if it was truncated before. |
| if (labelDisplay.isTruncated) |
| labelDisplay.text = label; |
| |
| labelHeight = getElementPreferredHeight(labelDisplay); |
| } |
| |
| setElementSize(labelDisplay, labelWidth, labelHeight); |
| |
| // We want to center using the "real" ascent |
| var labelY:Number = Math.round(vAlign * (viewHeight - labelHeight)) + paddingTop; |
| setElementPosition(labelDisplay, paddingLeft, labelY); |
| |
| // attempt to truncate the text now that we have its official width |
| labelDisplay.truncateToFit(); |
| |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Methods: Layout Helpers |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * @copy spark.skins.mobile.supportClasses.MobileSkin#setElementPosition() |
| * |
| * @see #setElementSize |
| * |
| * @langversion 3.0 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| protected function setElementPosition(element:Object, x:Number, y:Number):void |
| { |
| if (element is ILayoutElement) |
| { |
| ILayoutElement(element).setLayoutBoundsPosition(x, y, false); |
| } |
| else if (element is IFlexDisplayObject) |
| { |
| IFlexDisplayObject(element).move(x, y); |
| } |
| else |
| { |
| element.x = x; |
| element.y = y; |
| } |
| } |
| |
| /** |
| * @copy spark.skins.mobile.supportClasses.MobileSkin#setElementSize() |
| * |
| * @see #setElementPosition |
| * |
| * @langversion 3.0 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| protected function setElementSize(element:Object, width:Number, height:Number):void |
| { |
| if (element is ILayoutElement) |
| { |
| ILayoutElement(element).setLayoutBoundsSize(width, height, false); |
| } |
| else if (element is IFlexDisplayObject) |
| { |
| IFlexDisplayObject(element).setActualSize(width, height); |
| } |
| else |
| { |
| element.width = width; |
| element.height = height; |
| } |
| } |
| |
| /** |
| * @copy spark.skins.mobile.supportClasses.MobileSkin#getElementPreferredWidth() |
| * |
| * @see #setElementPosition |
| * @see #setElementSize |
| * @see #getElementPreferredHeight |
| * |
| * @langversion 3.0 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| protected function getElementPreferredWidth(element:Object):Number |
| { |
| var result:Number; |
| |
| if (element is ILayoutElement) |
| { |
| result = ILayoutElement(element).getPreferredBoundsWidth(); |
| } |
| else if (element is IFlexDisplayObject) |
| { |
| result = IFlexDisplayObject(element).measuredWidth; |
| } |
| else |
| { |
| result = element.width; |
| } |
| |
| return Math.round(result); |
| } |
| |
| /** |
| * @copy spark.skins.mobile.supportClasses.MobileSkin#getElementPreferredHeight() |
| * |
| * @see #setElementPosition |
| * @see #setElementSize |
| * @see #getElementPreferredWidth |
| * |
| * @langversion 3.0 |
| * @playerversion AIR 2.5 |
| * @productversion Flex 4.5 |
| */ |
| protected function getElementPreferredHeight(element:Object):Number |
| { |
| var result:Number; |
| |
| if (element is ILayoutElement) |
| { |
| result = ILayoutElement(element).getPreferredBoundsHeight(); |
| } |
| else if (element is IFlexDisplayObject) |
| { |
| result = IFlexDisplayObject(element).measuredHeight; |
| } |
| else |
| { |
| result = element.height; |
| } |
| |
| return Math.ceil(result); |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Event Handlers |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * @private |
| */ |
| private function interactionStateDetector_changeHandler(event:Event):void |
| { |
| down = (interactionStateDetector.state == InteractionState.DOWN); |
| hovered = (interactionStateDetector.state == InteractionState.OVER); |
| } |
| |
| |
| } |
| } |