| //////////////////////////////////////////////////////////////////////////////// |
| // |
| // 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 mx.controls |
| { |
| |
| import flash.display.DisplayObject; |
| import flash.events.MouseEvent; |
| import mx.core.ClassFactory; |
| import mx.core.EdgeMetrics; |
| import mx.core.IFlexDisplayObject; |
| import mx.core.mx_internal; |
| import mx.events.ChildExistenceChangedEvent; |
| import mx.events.FlexEvent; |
| import mx.events.ItemClickEvent; |
| import mx.styles.ISimpleStyleClient; |
| import mx.styles.StyleProxy; |
| |
| use namespace mx_internal; |
| |
| //-------------------------------------- |
| // Styles |
| //-------------------------------------- |
| |
| /** |
| * Number of pixels between the LinkButton controls in the horizontal direction. |
| * |
| * @default 8 |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| [Style(name="horizontalGap", type="Number", format="Length", inherit="no")] |
| |
| /** |
| * Name of CSS style declaration that specifies the styles to use for the link |
| * button navigation items. |
| * |
| * @default "" |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| [Style(name="linkButtonStyleName", type="String", inherit="no")] |
| |
| /** |
| * Number of pixels between the bottom border and the LinkButton controls. |
| * |
| * @default 2 |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| [Style(name="paddingBottom", type="Number", format="Length", inherit="no")] |
| |
| /** |
| * Number of pixels between the top border and the LinkButton controls. |
| * |
| * @default 2 |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| [Style(name="paddingTop", type="Number", format="Length", inherit="no")] |
| |
| /** |
| * Color of links as you roll the mouse pointer over them. |
| * The default value is based on the current <code>themeColor</code>. |
| * |
| * The default value for the Halo theme is <code>0xB2E1FF</code>. |
| * The default value for the Spark theme is <code>0xCEDBEF</code>. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| [Style(name="rollOverColor", type="uint", format="Color", inherit="yes")] |
| |
| /** |
| * Background color of the LinkButton control as you press it. |
| * |
| * The default value for the Halo theme is <code>0x7FCEFF</code>. |
| * The default value for the Spark theme is <code>0xA8C6EE</code>. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| [Style(name="selectionColor", type="uint", format="Color", inherit="yes")] |
| |
| /** |
| * Separator color used by the default separator skin. |
| * |
| * @default 0xC4CCCC |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| [Style(name="separatorColor", type="uint", format="Color", inherit="yes")] |
| |
| /** |
| * Seperator symbol between LinkButton controls in the LinkBar. |
| * |
| * @default mx.skins.halo.LinkSeparator (for both Halo and Spark themes) |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| [Style(name="separatorSkin", type="Class", inherit="no")] |
| |
| /** |
| * Separator pixel width, in pixels. |
| * |
| * @default 1 |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| [Style(name="separatorWidth", type="Number", format="Length", inherit="yes")] |
| |
| /** |
| * Text color of the link as you move the mouse pointer over it. |
| * |
| * The default value for the Halo theme is <code>0x2B333C</code>. |
| * The default value for the Spark theme is <code>0x000000</code>. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| [Style(name="textRollOverColor", type="uint", format="Color", inherit="yes")] |
| |
| /** |
| * Text color of the link as you press it. |
| * |
| * The default value for the Halo theme is <code>0x2B333C</code>. |
| * The default for the Spark theme is <code>0x000000</code>. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| [Style(name="textSelectedColor", type="uint", format="Color", inherit="yes")] |
| |
| /** |
| * Number of pixels between children in the vertical direction. |
| * |
| * @default 8 |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| [Style(name="verticalGap", type="Number", format="Length", inherit="no")] |
| |
| //-------------------------------------- |
| // Excluded APIs |
| //-------------------------------------- |
| |
| [Exclude(name="horizontalLineScrollSize", kind="property")] |
| [Exclude(name="horizontalPageScrollSize", kind="property")] |
| [Exclude(name="horizontalScrollBar", kind="property")] |
| [Exclude(name="horizontalScrollPolicy", kind="property")] |
| [Exclude(name="horizontalScrollPosition", kind="property")] |
| [Exclude(name="maxHorizontalScrollPosition", kind="property")] |
| [Exclude(name="maxVerticalScrollPosition", kind="property")] |
| [Exclude(name="verticalLineScrollSize", kind="property")] |
| [Exclude(name="verticalPageScrollSize", kind="property")] |
| [Exclude(name="verticalScrollBar", kind="property")] |
| [Exclude(name="verticalScrollPolicy", kind="property")] |
| [Exclude(name="verticalScrollPosition", kind="property")] |
| |
| [Exclude(name="scroll", kind="event")] |
| [Exclude(name="click", kind="event")] |
| |
| [Exclude(name="horizontalScrollBarStyleName", kind="style")] |
| [Exclude(name="verticalScrollBarStyleName", kind="style")] |
| |
| //-------------------------------------- |
| // Other metadata |
| //-------------------------------------- |
| |
| [DefaultProperty("dataProvider")] |
| |
| [IconFile("LinkBar.png")] |
| |
| [MaxChildren(0)] |
| |
| /** |
| * A LinkBar control defines a horizontal or vertical row of LinkButton controls |
| * that designate a series of link destinations. |
| * You typically use a LinkBar control to control |
| * the active child container of a ViewStack container, |
| * or to create a stand-alone set of links. |
| * |
| * <p>The LinkBar control creates LinkButton controls based on the value of |
| * its <code>dataProvider</code> property. |
| * Even though LinkBar is a subclass of Container, do not use methods such as |
| * <code>Container.addChild()</code> and <code>Container.removeChild()</code> |
| * to add or remove LinkButton controls. |
| * Instead, use methods such as <code>addItem()</code> and <code>removeItem()</code> |
| * to manipulate the <code>dataProvider</code> property. |
| * The LinkBar control automatically adds or removes the necessary children based on |
| * changes to the <code>dataProvider</code> property.</p> |
| * |
| * <p>A LinkBar control has the following default characteristics:</p> |
| * <table class="innertable"> |
| * <tr> |
| * <th>Characteristic</th> |
| * <th>Description</th> |
| * </tr> |
| * <tr> |
| * <td>Preferred size</td> |
| * <td>A width wide enough to contain all label text, plus any padding and separators, and the height of the tallest child.</td> |
| * </tr> |
| * <tr> |
| * <td>Control resizing rules</td> |
| * <td>LinkBar controls do not resize by default. Specify percentage sizes if you want your LinkBar to resize based on the size of its parent container.</td> |
| * </tr> |
| * <tr> |
| * <td>Padding</td> |
| * <td>2 pixels for the top, bottom, left, and right properties.</td> |
| * </tr> |
| * </table> |
| * |
| * @mxml |
| * <p>The <code><mx:LinkBar></code> tag inherits all of the tag |
| * attributes of its superclass, and adds the following tag attributes:</p> |
| * |
| * <pre> |
| * <mx:LinkBar |
| * <b>Properties</b> |
| * selectedIndex="-1" |
| * |
| * <b>Styles</b> |
| * linkButtonStyleName="" |
| * horizontalGap="8" |
| * paddingBottom="2" |
| * paddingTop="2" |
| * rollOverColor="0xEEFEE6" |
| * selectionColor="0xCDFFC1" |
| * separatorColor="<i>No default</i>" |
| * separatorSkin="0x000000" |
| * separatorWidth="1" |
| * textRollOverColor="0x2B333C" |
| * textSelectedColor="0x000000" |
| * verticalGap="8" |
| * > |
| * ... |
| * <i>child tags</i> |
| * ... |
| * </mx:LinkBar> |
| * </pre> |
| * |
| * @includeExample examples/LinkBarExample.mxml |
| * |
| * @see mx.controls.NavBar |
| * @see mx.containers.ViewStack |
| * @see mx.controls.LinkButton |
| * @see mx.controls.ToggleButtonBar |
| * @see mx.controls.ButtonBar |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public class LinkBar extends NavBar |
| { |
| include "../core/Version.as"; |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Class constants |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * @private |
| */ |
| private static const SEPARATOR_NAME:String = "_separator"; |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Constructor |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * Constructor. |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| public function LinkBar() |
| { |
| super(); |
| |
| navItemFactory = new ClassFactory(LinkButton); |
| |
| addEventListener(MouseEvent.CLICK, defaultClickHandler); |
| addEventListener(ChildExistenceChangedEvent.CHILD_REMOVE, |
| childRemoveHandler); |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Overridden properties |
| // |
| //-------------------------------------------------------------------------- |
| |
| //---------------------------------- |
| // selectedIndex |
| //---------------------------------- |
| |
| /** |
| * @private |
| * Storage for the selectedIndex property. |
| */ |
| private var _selectedIndex:int = -1; |
| |
| /** |
| * @private |
| */ |
| private var _selectedIndexChanged:Boolean = false; |
| |
| [Bindable("valueCommit")] |
| [Inspectable(category="General")] |
| |
| /** |
| * The index of the last selected LinkButton control if the LinkBar |
| * control uses a ViewStack container as its data provider. |
| * |
| * @default -1 |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| override public function get selectedIndex():int |
| { |
| return super.selectedIndex; |
| } |
| |
| /** |
| * @private |
| */ |
| override public function set selectedIndex(value:int):void |
| { |
| if (value == selectedIndex) |
| return; |
| |
| _selectedIndex = value; |
| |
| _selectedIndexChanged = true; |
| |
| invalidateProperties(); |
| |
| dispatchEvent(new FlexEvent(FlexEvent.VALUE_COMMIT)); |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Overridden methods: UIComponent |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * @inheritDoc |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| override public function styleChanged(styleProp:String):void |
| { |
| super.styleChanged(styleProp); |
| |
| var navItemStyleName:Object; |
| |
| if (styleProp == "linkButtonStyleName") |
| navItemStyleName = getStyle("linkButtonStyleName"); |
| |
| if (navItemStyleName) |
| { |
| var n:int = numChildren; |
| for (var i:int = 0; i < n; i++) |
| { |
| LinkButton(getChildAt(i)).styleName = navItemStyleName; |
| } |
| } |
| } |
| |
| /** |
| * @private |
| */ |
| override protected function commitProperties():void |
| { |
| super.commitProperties(); |
| |
| if (_selectedIndexChanged) |
| { |
| hiliteSelectedNavItem(_selectedIndex); |
| |
| // Update parent index. |
| super.selectedIndex = _selectedIndex; |
| |
| _selectedIndexChanged = false; |
| } |
| } |
| |
| /** |
| * Responds to size changes by setting the positions and sizes |
| * of this LinkBar control's children. |
| * For more information about the <code>updateDisplayList()</code> method, |
| * see the <code>UIComponent.updateDisplayList()</code> method. |
| * |
| * <p>The <code>LinkBar.updateDisplayList()</code> method first calls |
| * the <code>Box.updateDisplayList()</code> method to position the LinkButton controls. |
| * For more details, see the <code>Box.updateDisplayList()</code> method. |
| * After laying out the LinkButton controls, the separators are positioned |
| * between them.</p> |
| * |
| * @param unscaledWidth Specifies the width of the component, in pixels, |
| * of 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. |
| * |
| * @see mx.core.UIComponent#updateDisplayList() |
| * @see mx.containers.Box#updateDisplayList() |
| * |
| * |
| * @langversion 3.0 |
| * @playerversion Flash 9 |
| * @playerversion AIR 1.1 |
| * @productversion Flex 3 |
| */ |
| override protected function updateDisplayList(unscaledWidth:Number, |
| unscaledHeight:Number):void |
| { |
| // The super method will lay out the Links. |
| super.updateDisplayList(unscaledWidth, unscaledHeight); |
| |
| var vm:EdgeMetrics = viewMetricsAndPadding; |
| |
| var horizontalGap:Number = getStyle("horizontalGap"); |
| var verticalGap:Number = getStyle("verticalGap"); |
| |
| var separatorHeight:Number = unscaledHeight - (vm.top + vm.bottom); |
| var separatorWidth:Number = unscaledWidth - (vm.left + vm.right); |
| |
| // Lay out the separators. |
| var n:int = numChildren; |
| for (var i:int = 0; i < n; i++) |
| { |
| var child:IFlexDisplayObject = IFlexDisplayObject(getChildAt(i)); |
| |
| var separator:IFlexDisplayObject = IFlexDisplayObject( |
| rawChildren.getChildByName(SEPARATOR_NAME + i)); |
| |
| if (separator) |
| { |
| separator.visible = false; |
| |
| // The 0th separator is to the left of the first link. |
| // It should always be invisible, and doesn't need |
| // to be laid out. |
| if (i == 0) |
| continue; |
| |
| if (isVertical()) |
| { |
| separator.move(vm.left, child.y - verticalGap); |
| separator.setActualSize(separatorWidth, verticalGap); |
| |
| // The separators don't get clipped. |
| // (In general, chrome elements |
| // don't get automatically clipped.) |
| // So show a separator only if it is completely visible. |
| if (separator.y + separator.height < |
| unscaledHeight - vm.bottom) |
| { |
| separator.visible = true; |
| } |
| } |
| else |
| { |
| separator.move(child.x - horizontalGap, vm.top); |
| separator.setActualSize(horizontalGap, separatorHeight); |
| |
| if (separator.x + separator.width < |
| unscaledWidth - vm.right) |
| { |
| separator.visible = true; |
| } |
| } |
| } |
| } |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Overridden methods: NavBar |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * @private |
| */ |
| override protected function createNavItem( |
| label:String, |
| icon:Class = null):IFlexDisplayObject |
| { |
| // Create the new LinkButton. |
| |
| var newLink:Button = Button(navItemFactory.newInstance()); |
| |
| var linkButtonStyleName:String = getStyle("linkButtonStyleName"); |
| if (linkButtonStyleName) |
| newLink.styleName = linkButtonStyleName; |
| |
| if (label && label.length > 0) |
| newLink.label = label; |
| else |
| newLink.label = " "; |
| |
| if (icon) |
| newLink.setStyle("icon", icon); |
| |
| addChild(newLink); |
| |
| newLink.addEventListener(MouseEvent.CLICK, clickHandler); |
| |
| // Create the new separator to the left of the LinkButton. |
| |
| var separatorClass:Class = Class(getStyle("separatorSkin")); |
| var separator:DisplayObject = DisplayObject(new separatorClass()); |
| |
| separator.name = SEPARATOR_NAME + (numChildren - 1); |
| if (separator is ISimpleStyleClient) |
| ISimpleStyleClient(separator).styleName = this; |
| |
| rawChildren.addChild(separator); |
| |
| return newLink; |
| } |
| |
| /** |
| * @private |
| */ |
| override protected function hiliteSelectedNavItem(index:int):void |
| { |
| var child:Button; |
| |
| // Un-hilite the current selection. |
| if (selectedIndex != -1 && selectedIndex < numChildren) |
| { |
| child = Button(getChildAt(selectedIndex)); |
| child.enabled = true; |
| } |
| |
| // Set new index. |
| super.selectedIndex = index; |
| |
| if (index != -1) |
| { |
| // Hilite the new selection. |
| child = Button(getChildAt(selectedIndex)); |
| child.enabled = false; |
| } |
| } |
| |
| /** |
| * @private |
| */ |
| override protected function resetNavItems():void |
| { |
| // Reset the index values and selection state. |
| var n:int = numChildren; |
| for (var i:int = 0; i < n; i++) |
| { |
| var child:Button = Button(getChildAt(i)); |
| child.enabled = !(i == selectedIndex); |
| } |
| |
| invalidateDisplayList(); |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Event handlers |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * @private |
| */ |
| private function childRemoveHandler(event:ChildExistenceChangedEvent):void |
| { |
| var child:DisplayObject = event.relatedObject; |
| var index:int = getChildIndex(child); |
| var separator:DisplayObject = |
| rawChildren.getChildByName(SEPARATOR_NAME + index); |
| rawChildren.removeChild(separator); |
| |
| // Shuffle the separators down. |
| var n:int = numChildren - 1; |
| for (var i:int = index; i < n; i++) |
| { |
| rawChildren.getChildByName(SEPARATOR_NAME + (i + 1)).name = |
| SEPARATOR_NAME + i; |
| } |
| |
| } |
| |
| /** |
| * @private |
| */ |
| private function defaultClickHandler(event:MouseEvent):void |
| { |
| // We do not want to propagate a MouseEvent.CLICK event up. |
| if (!(event is ItemClickEvent)) |
| event.stopImmediatePropagation(); |
| } |
| |
| //-------------------------------------------------------------------------- |
| // |
| // Overridden event handlers: NavBar |
| // |
| //-------------------------------------------------------------------------- |
| |
| /** |
| * @private |
| */ |
| override protected function clickHandler(event:MouseEvent):void |
| { |
| var index:int = getChildIndex(Button(event.currentTarget)); |
| |
| if (targetStack) |
| { |
| if (index == selectedIndex) |
| hiliteSelectedNavItem(-1); |
| |
| else |
| hiliteSelectedNavItem(index); |
| } |
| |
| super.clickHandler(event); |
| } |
| |
| } |
| |
| } |